Import Geant4 11.0.0.beta source tree
This commit is contained in:
@@ -0,0 +1,643 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
|
||||
#include "G4ios.hh"
|
||||
#include "G4Clebsch.hh"
|
||||
#include "G4Pow.hh"
|
||||
#include "G4Exp.hh"
|
||||
#include "G4Log.hh"
|
||||
#include "Randomize.hh"
|
||||
|
||||
const G4int G4POWLOGFACTMAX = 512;
|
||||
|
||||
using namespace std;
|
||||
|
||||
G4double G4Clebsch::ClebschGordanCoeff(G4int twoJ1, G4int twoM1,
|
||||
G4int twoJ2, G4int twoM2,
|
||||
G4int twoJ)
|
||||
{
|
||||
if(twoJ1 < 0 || twoJ2 < 0 || twoJ < 0 ||
|
||||
((twoJ1-twoM1) % 2) || ((twoJ2-twoM2) % 2)) { return 0; }
|
||||
|
||||
G4int twoM = twoM1 + twoM2;
|
||||
if(twoM1 > twoJ1 || twoM1 < -twoJ1 ||
|
||||
twoM2 > twoJ2 || twoM2 < -twoJ2 ||
|
||||
twoM > twoJ || twoM < -twoJ) { return 0; }
|
||||
|
||||
// Checks limits on J1, J2, J3
|
||||
G4double triangle = TriangleCoeff(twoJ1, twoJ2, twoJ);
|
||||
if(triangle == 0) { return 0; }
|
||||
|
||||
G4Pow* g4pow = G4Pow::GetInstance();
|
||||
G4double factor = g4pow->logfactorial((twoJ1 + twoM1)/2) +
|
||||
g4pow->logfactorial((twoJ1 - twoM1)/2);
|
||||
factor += g4pow->logfactorial((twoJ2 + twoM2)/2) +
|
||||
g4pow->logfactorial((twoJ2 - twoM2)/2);
|
||||
factor += g4pow->logfactorial((twoJ + twoM)/2) +
|
||||
g4pow->logfactorial((twoJ - twoM)/2);
|
||||
factor *= 0.5;
|
||||
|
||||
G4int kMin = 0;
|
||||
G4int sum1 = (twoJ1 - twoM1)/2;
|
||||
G4int kMax = sum1;
|
||||
G4int sum2 = (twoJ - twoJ2 + twoM1)/2;
|
||||
if(-sum2 > kMin) kMin = -sum2;
|
||||
G4int sum3 = (twoJ2 + twoM2)/2;
|
||||
if(sum3 < kMax) kMax = sum3;
|
||||
G4int sum4 = (twoJ - twoJ1 - twoM2)/2;
|
||||
if(-sum4 > kMin) kMin = -sum4;
|
||||
G4int sum5 = (twoJ1 + twoJ2 - twoJ)/2;
|
||||
if(sum5 < kMax) kMax = sum5;
|
||||
|
||||
// sanity / boundary checks
|
||||
if(kMin < 0) {
|
||||
G4Exception("G4Clebsch::ClebschGordanCoeff()", "Clebsch001",
|
||||
JustWarning, "kMin < 0");
|
||||
return 0;
|
||||
}
|
||||
if(kMax < kMin) {
|
||||
G4Exception("G4Clebsch::ClebschGordanCoeff()", "Clebsch002",
|
||||
JustWarning, "kMax < kMin");
|
||||
return 0;
|
||||
}
|
||||
if(kMax >= G4POWLOGFACTMAX) {
|
||||
G4Exception("G4Clebsch::ClebschGordanCoeff()", "Clebsch003",
|
||||
JustWarning, "kMax too big for G4Pow");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Now do the sum over k
|
||||
G4double kSum = 0.;
|
||||
for(G4int k = kMin; k <= kMax; k++) {
|
||||
G4double sign = (k % 2) ? -1 : 1;
|
||||
kSum += sign * G4Exp(factor - g4pow->logfactorial(sum1-k) -
|
||||
g4pow->logfactorial(sum2+k) -
|
||||
g4pow->logfactorial(sum3-k) -
|
||||
g4pow->logfactorial(sum4+k) -
|
||||
g4pow->logfactorial(k) -
|
||||
g4pow->logfactorial(sum5-k));
|
||||
}
|
||||
|
||||
return triangle*sqrt(twoJ+1)*kSum;
|
||||
}
|
||||
|
||||
G4double G4Clebsch::ClebschGordan(G4int twoJ1, G4int twoM1,
|
||||
G4int twoJ2, G4int twoM2,
|
||||
G4int twoJ)
|
||||
{
|
||||
// ClebschGordanCoeff() will do all input checking
|
||||
G4double clebsch = ClebschGordanCoeff(twoJ1, twoM1, twoJ2, twoM2, twoJ);
|
||||
return clebsch*clebsch;
|
||||
}
|
||||
|
||||
std::vector<G4double>
|
||||
G4Clebsch::GenerateIso3(G4int twoJ1, G4int twoM1,
|
||||
G4int twoJ2, G4int twoM2,
|
||||
G4int twoJOut1, G4int twoJOut2)
|
||||
{
|
||||
std::vector<G4double> temp;
|
||||
|
||||
// ---- Special cases first ----
|
||||
|
||||
// Special case, both Jin are zero
|
||||
if (twoJ1 == 0 && twoJ2 == 0) {
|
||||
G4Exception("G4Clebsch::GenerateIso3()", "Clebsch010",
|
||||
JustWarning, "both twoJ are zero");
|
||||
temp.push_back(0.);
|
||||
temp.push_back(0.);
|
||||
return temp;
|
||||
}
|
||||
|
||||
G4int twoM3 = twoM1 + twoM2;
|
||||
|
||||
// Special case, either Jout is zero
|
||||
if (twoJOut1 == 0) {
|
||||
temp.push_back(0.);
|
||||
temp.push_back(twoM3);
|
||||
return temp;
|
||||
}
|
||||
if (twoJOut2 == 0) {
|
||||
temp.push_back(twoM3);
|
||||
temp.push_back(0.);
|
||||
return temp;
|
||||
}
|
||||
|
||||
// Number of possible states, in
|
||||
G4int twoJMinIn = std::max(std::abs(twoJ1 - twoJ2), std::abs(twoM3));
|
||||
G4int twoJMaxIn = twoJ1 + twoJ2;
|
||||
|
||||
// Number of possible states, out
|
||||
G4int twoJMinOut = 9999;
|
||||
for(G4int i=-1; i<=1; i+=2) {
|
||||
for(G4int j=-1; j<=1; j+=2) {
|
||||
G4int twoJTmp= std::abs(i*twoJOut1 + j*twoJOut2);
|
||||
if(twoJTmp < twoJMinOut) twoJMinOut = twoJTmp;
|
||||
}
|
||||
}
|
||||
twoJMinOut = std::max(twoJMinOut, std::abs(twoM3));
|
||||
G4int twoJMaxOut = twoJOut1 + twoJOut2;
|
||||
|
||||
// Possible in and out common states
|
||||
G4int twoJMin = std::max(twoJMinIn, twoJMinOut);
|
||||
G4int twoJMax = std::min(twoJMaxIn, twoJMaxOut);
|
||||
if (twoJMin > twoJMax) {
|
||||
G4Exception("G4Clebsch::GenerateIso3()", "Clebsch020",
|
||||
JustWarning, "twoJMin > twoJMax");
|
||||
return temp;
|
||||
}
|
||||
|
||||
// Number of possible isospins
|
||||
G4int nJ = (twoJMax - twoJMin) / 2 + 1;
|
||||
|
||||
// A few consistency checks
|
||||
|
||||
if ( (twoJ1 == 0 || twoJ2 == 0) && twoJMin != twoJMax ) {
|
||||
G4Exception("G4Clebsch::GenerateIso3()", "Clebsch021",
|
||||
JustWarning, "twoJ1 or twoJ2 = 0, but twoJMin != JMax");
|
||||
return temp;
|
||||
}
|
||||
|
||||
// MGP ---- Shall it be a warning or an exception?
|
||||
if (nJ == 0) {
|
||||
G4Exception("G4Clebsch::GenerateIso3()", "Clebsch022",
|
||||
JustWarning, "nJ is zero, no overlap between in and out");
|
||||
return temp;
|
||||
}
|
||||
|
||||
// Loop over all possible combinations of twoJ1, twoJ2, twoM11, twoM2, twoJTot
|
||||
// to get the probability of each of the in-channel couplings
|
||||
|
||||
std::vector<G4double> clebsch;
|
||||
G4double sum = 0.0;
|
||||
for(G4int twoJ=twoJMin; twoJ<=twoJMax; twoJ+=2) {
|
||||
sum += ClebschGordan(twoJ1, twoM1, twoJ2, twoM2, twoJ);
|
||||
clebsch.push_back(sum);
|
||||
}
|
||||
|
||||
// Consistency check
|
||||
if (static_cast<G4int>(clebsch.size()) != nJ) {
|
||||
G4Exception("G4Clebsch::GenerateIso3()", "Clebsch023",
|
||||
JustWarning, "nJ inconsistency");
|
||||
return temp;
|
||||
}
|
||||
|
||||
// Consistency check
|
||||
if (sum <= 0.) {
|
||||
G4Exception("G4Clebsch::GenerateIso3()", "Clebsch024",
|
||||
JustWarning, "Sum of Clebsch-Gordan probabilities <=0");
|
||||
return temp;
|
||||
}
|
||||
|
||||
// Generate a random twoJTot according to the Clebsch-Gordan pdf
|
||||
sum *= G4UniformRand();
|
||||
G4int twoJTot = twoJMin;
|
||||
for (G4int i=0; i<nJ; ++i) {
|
||||
if (sum < clebsch[i]) {
|
||||
twoJTot += 2*i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate twoM3Out
|
||||
|
||||
std::vector<G4double> mMin;
|
||||
mMin.push_back(-twoJOut1);
|
||||
mMin.push_back(-twoJOut2);
|
||||
|
||||
std::vector<G4double> mMax;
|
||||
mMax.push_back(twoJOut1);
|
||||
mMax.push_back(twoJOut2);
|
||||
|
||||
// Calculate the possible |J_i M_i> combinations and their probability
|
||||
|
||||
std::vector<G4double> m1Out;
|
||||
std::vector<G4double> m2Out;
|
||||
|
||||
const G4int size = 20;
|
||||
G4double prbout[size][size];
|
||||
|
||||
G4int m1pos(0), m2pos(0);
|
||||
G4int j12;
|
||||
G4int m1pr(0), m2pr(0);
|
||||
|
||||
sum = 0.;
|
||||
for(j12 = std::abs(twoJOut1-twoJOut2); j12<=(twoJOut1+twoJOut2); j12+=2)
|
||||
{
|
||||
m1pos = -1;
|
||||
for (m1pr = static_cast<G4int>(mMin[0]+.00001); m1pr <= mMax[0]; m1pr+=2)
|
||||
{
|
||||
m1pos++;
|
||||
if (m1pos >= size) {
|
||||
G4Exception("G4Clebsch::GenerateIso3()", "Clebsch025",
|
||||
JustWarning, "m1pos > size");
|
||||
return temp;
|
||||
}
|
||||
m1Out.push_back(m1pr);
|
||||
m2pos = -1;
|
||||
for (m2pr = static_cast<G4int>(mMin[1]+.00001); m2pr <= mMax[1]; m2pr+=2)
|
||||
{
|
||||
m2pos++;
|
||||
if (m2pos >= size)
|
||||
{
|
||||
G4Exception("G4Clebsch::GenerateIso3()", "Clebsch026",
|
||||
JustWarning, "m2pos > size");
|
||||
return temp;
|
||||
}
|
||||
m2Out.push_back(m2pr);
|
||||
|
||||
if(m1pr + m2pr == twoM3)
|
||||
{
|
||||
G4int m12 = m1pr + m2pr;
|
||||
G4double c12 = ClebschGordan(twoJOut1, m1pr, twoJOut2,m2pr, j12);
|
||||
G4double c34 = ClebschGordan(0,0,0,0,0);
|
||||
G4double ctot = ClebschGordan(j12, m12, 0, 0, twoJTot);
|
||||
G4double cleb = c12*c34*ctot;
|
||||
prbout[m1pos][m2pos] = cleb;
|
||||
sum += cleb;
|
||||
}
|
||||
else
|
||||
{
|
||||
prbout[m1pos][m2pos] = 0.;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sum <= 0.) {
|
||||
G4Exception("G4Clebsch::GenerateIso3()", "Clebsch027",
|
||||
JustWarning, "sum (out) <=0");
|
||||
return temp;
|
||||
}
|
||||
|
||||
for (G4int i=0; i<size; i++) {
|
||||
for (G4int j=0; j<size; j++) {
|
||||
prbout[i][j] /= sum;
|
||||
}
|
||||
}
|
||||
|
||||
G4double rand = G4UniformRand();
|
||||
|
||||
G4int m1p, m2p;
|
||||
|
||||
for (m1p=0; m1p<m1pos; m1p++) {
|
||||
for (m2p=0; m2p<m2pos; m2p++) {
|
||||
if (rand < prbout[m1p][m2p]) {
|
||||
temp.push_back(m1Out[m1p]);
|
||||
temp.push_back(m2Out[m2p]);
|
||||
return temp;
|
||||
}
|
||||
else rand -= prbout[m1p][m2p];
|
||||
}
|
||||
}
|
||||
|
||||
G4Exception("G4Clebsch::GenerateIso3()", "Clebsch028",
|
||||
JustWarning, "Should never get here");
|
||||
return temp;
|
||||
}
|
||||
|
||||
G4double G4Clebsch::Weight(G4int twoJ1, G4int twoM1,
|
||||
G4int twoJ2, G4int twoM2,
|
||||
G4int twoJOut1, G4int twoJOut2)
|
||||
{
|
||||
G4double value = 0.;
|
||||
|
||||
G4int twoM = twoM1 + twoM2;
|
||||
|
||||
G4int twoJMinIn = std::max(std::abs(twoJ1 - twoJ2), std::abs(twoM));
|
||||
G4int twoJMaxIn = twoJ1 + twoJ2;
|
||||
|
||||
G4int twoJMinOut = std::max(std::abs(twoJOut1 - twoJOut2), std::abs(twoM));
|
||||
G4int twoJMaxOut = twoJOut1 + twoJOut2;
|
||||
|
||||
G4int twoJMin = std::max(twoJMinIn,twoJMinOut);
|
||||
G4int twoJMax = std::min(twoJMaxIn,twoJMaxOut);
|
||||
|
||||
for (G4int twoJ=twoJMin; twoJ<=twoJMax; twoJ+=2) {
|
||||
// ClebschGordan() will do all input checking
|
||||
value += ClebschGordan(twoJ1, twoM1, twoJ2, twoM2, twoJ);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
G4double G4Clebsch::Wigner3J(G4double j1, G4double j2, G4double j3,
|
||||
G4double m1, G4double m2, G4double m3)
|
||||
{
|
||||
// G4Exception("G4Clebsch::Wigner3J()", "Clebsch030", JustWarning,
|
||||
// "G4Clebsch::Wigner3J with double arguments is deprecated. Please use G4int version.");
|
||||
G4int twoJ1 = (G4int) (2.*j1);
|
||||
G4int twoJ2 = (G4int) (2.*j2);
|
||||
G4int twoJ3 = (G4int) (2.*j3);
|
||||
G4int twoM1 = (G4int) (2.*m1);
|
||||
G4int twoM2 = (G4int) (2.*m2);
|
||||
G4int twoM3 = (G4int) (2.*m3);
|
||||
return Wigner3J(twoJ1, twoM1, twoJ2, twoM2, twoJ3, twoM3);
|
||||
}
|
||||
|
||||
G4double G4Clebsch::Wigner3J(G4int twoJ1, G4int twoM1,
|
||||
G4int twoJ2, G4int twoM2,
|
||||
G4int twoJ3)
|
||||
{
|
||||
G4double clebsch = ClebschGordanCoeff(twoJ1, twoM1, twoJ2, twoM2, twoJ3);
|
||||
if(clebsch == 0) return clebsch;
|
||||
if( (twoJ1-twoJ2+twoM1+twoM2)/2 % 2) clebsch = -clebsch;
|
||||
return clebsch / sqrt(twoJ3+1);
|
||||
}
|
||||
|
||||
G4double G4Clebsch::Wigner3J(G4int twoJ1, G4int twoM1,
|
||||
G4int twoJ2, G4int twoM2,
|
||||
G4int twoJ3, G4int twoM3)
|
||||
{
|
||||
if(twoM1 + twoM2 != -twoM3) return 0;
|
||||
G4double clebsch = ClebschGordanCoeff(twoJ1, twoM1, twoJ2, twoM2, twoJ3);
|
||||
if(clebsch == 0) return clebsch;
|
||||
if( (twoJ1-twoJ2-twoM3)/2 % 2) clebsch = -clebsch;
|
||||
return clebsch / sqrt(twoJ3+1);
|
||||
}
|
||||
|
||||
G4double G4Clebsch::NormalizedClebschGordan(G4int twoJ, G4int twoM,
|
||||
G4int twoJ1, G4int twoJ2,
|
||||
G4int twoM1, G4int twoM2)
|
||||
{
|
||||
// Calculate the normalized Clebsch-Gordan coefficient, that is the prob
|
||||
// of isospin decomposition of (J,m) into J1, J2, m1, m2
|
||||
|
||||
G4double cleb = 0.;
|
||||
if(twoJ1 == 0 || twoJ2 == 0) return cleb;
|
||||
|
||||
// Loop over all J1,J2,Jtot,m1,m2 combinations
|
||||
G4double sum = 0.0;
|
||||
for(G4int twoM1Current=-twoJ1; twoM1Current<=twoJ1; twoM1Current+=2) {
|
||||
G4int twoM2Current = twoM - twoM1Current;
|
||||
// ClebschGordan() will do all further input checking
|
||||
G4double prob = ClebschGordan(twoJ1, twoM1Current, twoJ2,
|
||||
twoM2Current, twoJ);
|
||||
sum += prob;
|
||||
if (twoM2Current == twoM2 && twoM1Current == twoM1) cleb += prob;
|
||||
}
|
||||
|
||||
// Normalize probs to 1
|
||||
if (sum > 0.) cleb /= sum;
|
||||
|
||||
return cleb;
|
||||
}
|
||||
|
||||
G4double G4Clebsch::TriangleCoeff(G4int twoA, G4int twoB, G4int twoC)
|
||||
{
|
||||
// TC(ABC) = sqrt[ (A+B-C)! (A-B+C)! (-A+B+C)! / (A+B+C+1)! ]
|
||||
// return 0 if the triad does not satisfy the triangle inequalities
|
||||
G4Pow* g4pow = G4Pow::GetInstance();
|
||||
|
||||
double val = 0;
|
||||
G4int i = twoA+twoB-twoC;
|
||||
// only have to check that i is even the first time
|
||||
if(i<0 || (i%2)) return 0;
|
||||
else val += g4pow->logfactorial(i/2);
|
||||
|
||||
i = twoA-twoB+twoC;
|
||||
if(i<0) return 0;
|
||||
else val += g4pow->logfactorial(i/2);
|
||||
|
||||
i = -twoA+twoB+twoC;
|
||||
if(i<0) return 0;
|
||||
else val += g4pow->logfactorial(i/2);
|
||||
|
||||
i = twoA+twoB+twoC+2;
|
||||
if(i<0) return 0;
|
||||
return G4Exp(0.5*(val - g4pow->logfactorial(i/2)));
|
||||
}
|
||||
|
||||
G4double G4Clebsch::Wigner6J(G4int twoJ1, G4int twoJ2, G4int twoJ3,
|
||||
G4int twoJ4, G4int twoJ5, G4int twoJ6)
|
||||
{
|
||||
if(twoJ1 < 0 || twoJ2 < 0 || twoJ3 < 0 ||
|
||||
twoJ4 < 0 || twoJ5 < 0 || twoJ6 < 0) return 0;
|
||||
|
||||
// There is a fast calculation (no sums or exps) when twoJ6 = 0,
|
||||
// so permute to use it when possible
|
||||
if(twoJ6 == 0) {
|
||||
if(twoJ1 != twoJ5) return 0;
|
||||
if(twoJ2 != twoJ4) return 0;
|
||||
if(twoJ1+twoJ2 < twoJ3) return 0;
|
||||
if((twoJ1 > twoJ2) && (twoJ3 < (twoJ1-twoJ2))) return 0;
|
||||
if((twoJ2 > twoJ1) && (twoJ3 < (twoJ2-twoJ1))) return 0;
|
||||
if((twoJ1+twoJ2+twoJ3) % 2) return 0;
|
||||
return (((twoJ1+twoJ2+twoJ3)/2) % 2 ? -1. : 1.) /sqrt((twoJ1+1)*(twoJ2+1));
|
||||
}
|
||||
if(twoJ1 == 0) return Wigner6J(twoJ6, twoJ2, twoJ4, twoJ3, twoJ5, 0);
|
||||
if(twoJ2 == 0) return Wigner6J(twoJ1, twoJ6, twoJ5, twoJ4, twoJ3, 0);
|
||||
if(twoJ3 == 0) return Wigner6J(twoJ4, twoJ2, twoJ6, twoJ1, twoJ5, 0);
|
||||
if(twoJ4 == 0) return Wigner6J(twoJ3, twoJ2, twoJ1, twoJ6, twoJ5, 0);
|
||||
if(twoJ5 == 0) return Wigner6J(twoJ1, twoJ3, twoJ2, twoJ4, twoJ6, 0);
|
||||
|
||||
// Check triangle inequalities and calculate triangle coefficients.
|
||||
// Also check evenness of sums
|
||||
G4Pow* g4pow = G4Pow::GetInstance();
|
||||
double triangles = 0;
|
||||
G4int i;
|
||||
i = twoJ1+twoJ2-twoJ3; if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
|
||||
i = twoJ1-twoJ2+twoJ3; if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
|
||||
i = -twoJ1+twoJ2+twoJ3; if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
|
||||
i = twoJ1+twoJ2+twoJ3+2; if(i<0 || i%2) return 0; else triangles -= g4pow->logfactorial(i/2);
|
||||
i = twoJ1+twoJ5-twoJ6; if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
|
||||
i = twoJ1-twoJ5+twoJ6; if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
|
||||
i = -twoJ1+twoJ5+twoJ6; if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
|
||||
i = twoJ1+twoJ5+twoJ6+2; if(i<0 || i%2) return 0; else triangles -= g4pow->logfactorial(i/2);
|
||||
i = twoJ4+twoJ2-twoJ6; if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
|
||||
i = twoJ4-twoJ2+twoJ6; if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
|
||||
i = -twoJ4+twoJ2+twoJ6; if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
|
||||
i = twoJ4+twoJ2+twoJ6+2; if(i<0 || i%2) return 0; else triangles -= g4pow->logfactorial(i/2);
|
||||
i = twoJ4+twoJ5-twoJ3; if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
|
||||
i = twoJ4-twoJ5+twoJ3; if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
|
||||
i = -twoJ4+twoJ5+twoJ3; if(i<0 || i%2) return 0; else triangles += g4pow->logfactorial(i/2);
|
||||
i = twoJ4+twoJ5+twoJ3+2; if(i<0 || i%2) return 0; else triangles -= g4pow->logfactorial(i/2);
|
||||
triangles = G4Exp(0.5*triangles);
|
||||
|
||||
// Prepare to sum over k. If we have made it this far, all of the following
|
||||
// sums must be non-negative and divisible by two
|
||||
|
||||
// k must be >= all of the following sums:
|
||||
G4int sum1 = (twoJ1 + twoJ2 + twoJ3)/2;
|
||||
G4int kMin = sum1;
|
||||
G4int sum2 = (twoJ1 + twoJ5 + twoJ6)/2;
|
||||
if(sum2 > kMin) kMin = sum2;
|
||||
G4int sum3 = (twoJ4 + twoJ2 + twoJ6)/2;
|
||||
if(sum3 > kMin) kMin = sum3;
|
||||
G4int sum4 = (twoJ4 + twoJ5 + twoJ3)/2;
|
||||
if(sum4 > kMin) kMin = sum4;
|
||||
|
||||
// and k must be <= all of the following sums:
|
||||
G4int sum5 = (twoJ1 + twoJ2 + twoJ4 + twoJ5)/2;
|
||||
G4int kMax = sum5;
|
||||
G4int sum6 = (twoJ2 + twoJ3 + twoJ5 + twoJ6)/2;
|
||||
if(sum6 < kMax) kMax = sum6;
|
||||
G4int sum7 = (twoJ1 + twoJ3 + twoJ4 + twoJ6)/2;
|
||||
if(sum7 < kMax) kMax = sum7;
|
||||
|
||||
// sanity / boundary checks
|
||||
if(kMin < 0) {
|
||||
G4Exception("G4Clebsch::Wigner6J()", "Clebsch040",
|
||||
JustWarning, "kMin < 0");
|
||||
return 0;
|
||||
}
|
||||
if(kMax < kMin) {
|
||||
G4Exception("G4Clebsch::Wigner6J()", "Clebsch041",
|
||||
JustWarning, "kMax < kMin");
|
||||
return 0;
|
||||
}
|
||||
if(kMax >= G4POWLOGFACTMAX) {
|
||||
G4Exception("G4Clebsch::Wigner6J()", "Clebsch041",
|
||||
JustWarning, "kMax too big for G4Pow");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Now do the sum over k
|
||||
G4double kSum = 0.;
|
||||
G4double sign = (kMin % 2) ? -1 : 1;
|
||||
for(G4int k = kMin; k <= kMax; k++) {
|
||||
kSum += sign * G4Exp(g4pow->logfactorial(k+1) -
|
||||
g4pow->logfactorial(k-sum1) -
|
||||
g4pow->logfactorial(k-sum2) -
|
||||
g4pow->logfactorial(k-sum3) -
|
||||
g4pow->logfactorial(k-sum4) -
|
||||
g4pow->logfactorial(sum5-k) -
|
||||
g4pow->logfactorial(sum6-k) -
|
||||
g4pow->logfactorial(sum7-k));
|
||||
sign *= -1;
|
||||
}
|
||||
return triangles*kSum;
|
||||
}
|
||||
|
||||
G4double G4Clebsch::Wigner9J(G4int twoJ1, G4int twoJ2, G4int twoJ3,
|
||||
G4int twoJ4, G4int twoJ5, G4int twoJ6,
|
||||
G4int twoJ7, G4int twoJ8, G4int twoJ9)
|
||||
{
|
||||
if(twoJ1 < 0 || twoJ2 < 0 || twoJ3 < 0 ||
|
||||
twoJ4 < 0 || twoJ5 < 0 || twoJ6 < 0 ||
|
||||
twoJ7 < 0 || twoJ8 < 0 || twoJ9 < 0) return 0;
|
||||
|
||||
if(twoJ9 == 0) {
|
||||
if(twoJ3 != twoJ6) return 0;
|
||||
if(twoJ7 != twoJ8) return 0;
|
||||
G4double sixJ = Wigner6J(twoJ1, twoJ2, twoJ3, twoJ5, twoJ4, twoJ7);
|
||||
if(sixJ == 0) return 0;
|
||||
if((twoJ2+twoJ3+twoJ4+twoJ7)/2 % 2) sixJ = -sixJ;
|
||||
return sixJ/sqrt((twoJ3+1)*(twoJ7+1));
|
||||
}
|
||||
if(twoJ1 == 0) return Wigner9J(twoJ9, twoJ6, twoJ3, twoJ8, twoJ5, twoJ2, twoJ7, twoJ4, twoJ1);
|
||||
if(twoJ2 == 0) return Wigner9J(twoJ7, twoJ9, twoJ8, twoJ4, twoJ6, twoJ5, twoJ1, twoJ3, twoJ2);
|
||||
if(twoJ4 == 0) return Wigner9J(twoJ3, twoJ2, twoJ1, twoJ9, twoJ8, twoJ7, twoJ6, twoJ5, twoJ4);
|
||||
if(twoJ5 == 0) return Wigner9J(twoJ1, twoJ3, twoJ2, twoJ7, twoJ9, twoJ8, twoJ4, twoJ6, twoJ5);
|
||||
G4int twoS = twoJ1+twoJ2+twoJ3+twoJ4+twoJ5+twoJ6+twoJ7+twoJ8+twoJ9;
|
||||
if(twoS % 2) return 0;
|
||||
G4double sign = (twoS/2 % 2) ? -1 : 1;
|
||||
if(twoJ3 == 0) return sign*Wigner9J(twoJ7, twoJ8, twoJ9, twoJ4, twoJ5, twoJ6, twoJ1, twoJ2, twoJ3);
|
||||
if(twoJ6 == 0) return sign*Wigner9J(twoJ1, twoJ2, twoJ3, twoJ7, twoJ8, twoJ9, twoJ4, twoJ5, twoJ6);
|
||||
if(twoJ7 == 0) return sign*Wigner9J(twoJ3, twoJ2, twoJ1, twoJ6, twoJ5, twoJ4, twoJ9, twoJ8, twoJ7);
|
||||
if(twoJ8 == 0) return sign*Wigner9J(twoJ1, twoJ3, twoJ2, twoJ4, twoJ6, twoJ5, twoJ7, twoJ9, twoJ8);
|
||||
|
||||
// No element is zero: check triads now for speed
|
||||
G4int i;
|
||||
i = twoJ1+twoJ2-twoJ3; if(i<0 || i%2) return 0;
|
||||
i = twoJ1-twoJ2+twoJ3; if(i<0 || i%2) return 0;
|
||||
i = -twoJ1+twoJ2+twoJ3; if(i<0 || i%2) return 0;
|
||||
i = twoJ4+twoJ5-twoJ6; if(i<0 || i%2) return 0;
|
||||
i = twoJ4-twoJ5+twoJ6; if(i<0 || i%2) return 0;
|
||||
i = -twoJ4+twoJ5+twoJ6; if(i<0 || i%2) return 0;
|
||||
i = twoJ7+twoJ8-twoJ9; if(i<0 || i%2) return 0;
|
||||
i = twoJ7-twoJ8+twoJ9; if(i<0 || i%2) return 0;
|
||||
i = -twoJ7+twoJ8+twoJ9; if(i<0 || i%2) return 0;
|
||||
i = twoJ1+twoJ4-twoJ7; if(i<0 || i%2) return 0;
|
||||
i = twoJ1-twoJ4+twoJ7; if(i<0 || i%2) return 0;
|
||||
i = -twoJ1+twoJ4+twoJ7; if(i<0 || i%2) return 0;
|
||||
i = twoJ2+twoJ5-twoJ8; if(i<0 || i%2) return 0;
|
||||
i = twoJ2-twoJ5+twoJ8; if(i<0 || i%2) return 0;
|
||||
i = -twoJ2+twoJ5+twoJ8; if(i<0 || i%2) return 0;
|
||||
i = twoJ3+twoJ6-twoJ9; if(i<0 || i%2) return 0;
|
||||
i = twoJ3-twoJ6+twoJ9; if(i<0 || i%2) return 0;
|
||||
i = -twoJ3+twoJ6+twoJ9; if(i<0 || i%2) return 0;
|
||||
|
||||
// Okay, have to do the full sum over 6J's
|
||||
// Find limits for K sum
|
||||
G4int twoKMax = twoJ1+twoJ9;
|
||||
if(twoJ4+twoJ8 < twoKMax) twoKMax = twoJ4+twoJ8;
|
||||
if(twoJ2+twoJ6 < twoKMax) twoKMax = twoJ2+twoJ6;
|
||||
G4int twoKMin = twoJ1-twoJ9;
|
||||
if(twoJ9-twoJ1 > twoKMin) twoKMin = twoJ9-twoJ1;
|
||||
if(twoJ4-twoJ8 > twoKMin) twoKMin = twoJ4-twoJ8;
|
||||
if(twoJ8-twoJ4 > twoKMin) twoKMin = twoJ8-twoJ4;
|
||||
if(twoJ2-twoJ6 > twoKMin) twoKMin = twoJ2-twoJ6;
|
||||
if(twoJ6-twoJ2 > twoKMin) twoKMin = twoJ6-twoJ2;
|
||||
if(twoKMin > twoKMax) return 0;
|
||||
|
||||
G4double sum = 0;
|
||||
for(G4int twoK = twoKMin; twoK <= twoKMax; twoK += 2) {
|
||||
G4double value = Wigner6J(twoJ1, twoJ4, twoJ7, twoJ8, twoJ9, twoK);
|
||||
if(value == 0) continue;
|
||||
value *= Wigner6J(twoJ2, twoJ5, twoJ8, twoJ4, twoK, twoJ6);
|
||||
if(value == 0) continue;
|
||||
value *= Wigner6J(twoJ3, twoJ6, twoJ9, twoK, twoJ1, twoJ2);
|
||||
if(value == 0) continue;
|
||||
if(twoK % 2) value = -value;
|
||||
sum += value*G4double(twoK+1);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
G4double G4Clebsch::WignerLittleD(G4int twoJ, G4int twoM, G4int twoN,
|
||||
G4double cosTheta)
|
||||
{
|
||||
if(twoM < -twoJ || twoM > twoJ || twoN < -twoJ || twoN > twoJ
|
||||
|| ((twoM % 2) != (twoJ % 2)) || ((twoN % 2) != (twoJ % 2)))
|
||||
{ return 0; }
|
||||
|
||||
if(cosTheta == 1.0) { return G4double(twoM == twoN); }
|
||||
|
||||
G4int kMin = 0;
|
||||
if(twoM > twoN) kMin = (twoM-twoN)/2;
|
||||
G4int kMax = (twoJ + twoM)/2;
|
||||
if((twoJ-twoN)/2 < kMax) kMax = (twoJ-twoN)/2;
|
||||
|
||||
G4double lnCosHalfTheta = G4Log((cosTheta+1.)*0.5) * 0.5;
|
||||
G4double lnSinHalfTheta = G4Log((1.-cosTheta)*0.5) * 0.5;
|
||||
|
||||
G4Pow* g4pow = G4Pow::GetInstance();
|
||||
G4double d = 0;
|
||||
for(G4int k = kMin; k <= kMax; k++) {
|
||||
G4double logSum = 0.5*(g4pow->logfactorial((twoJ+twoM)/2) +
|
||||
g4pow->logfactorial((twoJ-twoM)/2) +
|
||||
g4pow->logfactorial((twoJ+twoN)/2) +
|
||||
g4pow->logfactorial((twoJ-twoN)/2));
|
||||
logSum += -g4pow->logfactorial((twoJ+twoM)/2 - k) -
|
||||
g4pow->logfactorial((twoJ-twoN)/2 - k) -
|
||||
g4pow->logfactorial(k) -
|
||||
g4pow->logfactorial(k+(twoN-twoM)/2);
|
||||
logSum += (twoJ+(twoM-twoN)/2 - 2*k)*lnCosHalfTheta +
|
||||
(2*k + (twoN-twoM)/2)*lnSinHalfTheta;
|
||||
G4double sign = (k % 2) ? -1 : 1;
|
||||
d += sign * G4Exp(logSum);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
+35
-51
@@ -23,62 +23,46 @@
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//#ifndef G4HadSignalHandler_off
|
||||
#if 0
|
||||
#include "G4HadSignalHandler.hh"
|
||||
// Utility class to process contents of G4KineticTrackVector (input to
|
||||
// models' ::Propagate() interface) and decay any short-lived resonances.
|
||||
// Resulting daughters are added to vector (no function or return needed).
|
||||
//
|
||||
// Author: Michael Kelsey <kelsey@slac.stanford.edu>
|
||||
|
||||
namespace G4HadSignalHandler_local
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
void HandleIt(int i);
|
||||
static void (*G4HadSignalHandler_initial)(int);
|
||||
}
|
||||
#include "G4DecayKineticTracks.hh"
|
||||
#include "G4KineticTrackVector.hh"
|
||||
#include "G4KineticTrack.hh"
|
||||
|
||||
|
||||
// Decay all input tracks, put daughters onto end of list
|
||||
|
||||
G4DecayKineticTracks::G4DecayKineticTracks(G4KineticTrackVector *tracks) {
|
||||
|
||||
if (tracks) Decay(tracks);
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
void G4DecayKineticTracks::Decay(G4KineticTrackVector *tracks) const {
|
||||
|
||||
G4ThreadLocal std::vector<sighandler_t> *G4HadSignalHandler::theCache = 0;
|
||||
G4ThreadLocal bool G4HadSignalHandler::registered = false;
|
||||
if (!tracks) return;
|
||||
|
||||
G4HadSignalHandler::G4HadSignalHandler(sighandler_t aNew)
|
||||
{
|
||||
if (!theCache) theCache = new std::vector<sighandler_t>;
|
||||
if(!registered)
|
||||
{
|
||||
G4HadSignalHandler_local::G4HadSignalHandler_initial =
|
||||
signal(SIGSEGV, G4HadSignalHandler_local::HandleIt);
|
||||
registered = true;
|
||||
G4KineticTrackVector* daughters = 0;
|
||||
for (size_t i=0; i<tracks->size(); ++i) {
|
||||
G4KineticTrack* track = (*tracks)[i];
|
||||
if (!track) continue;
|
||||
|
||||
// Select decay of current track, put daughters at end of vector
|
||||
daughters = track->GetDefinition()->IsShortLived() ? track->Decay() : 0;
|
||||
|
||||
if (daughters) {
|
||||
tracks->insert(tracks->end(), daughters->begin(), daughters->end());
|
||||
delete track; // Remove parent track
|
||||
delete daughters;
|
||||
(*tracks)[i] = NULL; // Flag parent's slot for removal
|
||||
}
|
||||
theCache->push_back(aNew);
|
||||
}
|
||||
|
||||
G4HadSignalHandler::~G4HadSignalHandler()
|
||||
{
|
||||
theCache->clear();
|
||||
signal (SIGSEGV, G4HadSignalHandler_local::G4HadSignalHandler_initial);
|
||||
registered = false;
|
||||
}
|
||||
|
||||
void G4HadSignalHandler_local::HandleIt(int i)
|
||||
{
|
||||
static G4ThreadLocal int *iii_p = 0 ;
|
||||
if (!iii_p)
|
||||
{
|
||||
iii_p = new int ;
|
||||
*iii_p = G4HadSignalHandler::theCache->size()-1 ;
|
||||
}
|
||||
int &iii = *iii_p;
|
||||
for(int c=iii; c!=-1; c--)
|
||||
{
|
||||
iii--;
|
||||
//Andrea Dotti (13Jan2013): change for G4MT
|
||||
(G4HadSignalHandler::theCache->operator[](c))(i);
|
||||
//G4HadSignalHandler::theCache[c](i);
|
||||
}
|
||||
std::cerr << "callback to user-defined or default signal handler"<<endl;
|
||||
signal (SIGSEGV, G4HadSignalHandler_local::G4HadSignalHandler_initial);
|
||||
raise(i);
|
||||
}
|
||||
|
||||
#endif
|
||||
// Find and remove null pointers created by decays above
|
||||
for (int j=tracks->size()-1; j>=0; --j) {
|
||||
if (NULL == (*tracks)[j]) tracks->erase(tracks->begin()+j);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// -------------------------------------------------------------------
|
||||
//
|
||||
// GEANT4 Class file
|
||||
//
|
||||
// File name: G4DecayStrongResonances
|
||||
//
|
||||
// Modified:
|
||||
// 02.11.2010 V.Ivanchenko moved constructor and destructor to source
|
||||
// 07.27.2011 M.Kelsey -- Use new decay utility to process input list
|
||||
|
||||
#include "G4DecayStrongResonances.hh"
|
||||
|
||||
#include "G4DecayKineticTracks.hh"
|
||||
#include "G4HadTmpUtil.hh"
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
G4DecayStrongResonances::G4DecayStrongResonances() {}
|
||||
|
||||
G4DecayStrongResonances::~G4DecayStrongResonances() {}
|
||||
|
||||
G4ReactionProductVector*
|
||||
G4DecayStrongResonances::Propagate(G4KineticTrackVector* theSecondaries,
|
||||
G4V3DNucleus* ) {
|
||||
G4DecayKineticTracks decay(theSecondaries); // Changes input list in situ
|
||||
|
||||
// translate to ReactionProducts
|
||||
G4ReactionProductVector * theResult;
|
||||
try { theResult = new G4ReactionProductVector; }
|
||||
catch(...) {
|
||||
throw G4HadronicException(__FILE__, __LINE__, "DecayStrongRes: out of memory ");
|
||||
}
|
||||
|
||||
G4ReactionProduct * it = NULL;
|
||||
|
||||
G4KineticTrackVector::iterator secIter = theSecondaries->begin();
|
||||
for(; secIter != theSecondaries->end(); ++secIter) {
|
||||
G4KineticTrack* aSecondary = *secIter;
|
||||
if (!aSecondary) continue; // Skip null pointers
|
||||
|
||||
try { it = new G4ReactionProduct(); }
|
||||
catch(...) {
|
||||
throw G4HadronicException(__FILE__, __LINE__, "DecayStrongRes: out of memory ");
|
||||
}
|
||||
|
||||
it->SetDefinition(aSecondary->GetDefinition());
|
||||
it->SetMass(aSecondary->GetDefinition()->GetPDGMass());
|
||||
it->SetTotalEnergy(aSecondary->Get4Momentum().t());
|
||||
it->SetMomentum(aSecondary->Get4Momentum().vect());
|
||||
delete aSecondary;
|
||||
try { theResult->push_back(it); }
|
||||
catch(...){
|
||||
throw G4HadronicException(__FILE__, __LINE__, "DecayStrongRes: push to result failed - out of mem.");
|
||||
}
|
||||
}
|
||||
delete theSecondaries;
|
||||
|
||||
return theResult;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// GEANT 4 class implementation file
|
||||
//
|
||||
// ---------------- G4ExcitedString ----------------
|
||||
// by Gunter Folger, June 1998.
|
||||
// class for an excited string used by Parton String Models
|
||||
// ------------------------------------------------------------
|
||||
|
||||
|
||||
// G4ExcitedString
|
||||
#include "G4ExcitedString.hh"
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
G4ExcitedString::G4ExcitedString(G4Parton* Color, G4Parton* AntiColor, G4int Direction)
|
||||
{
|
||||
thePartons.push_back(Color);
|
||||
thePartons.push_back(AntiColor);
|
||||
theTimeOfCreation = 0.; // Uzhi 15.05.08
|
||||
thePosition = Color->GetPosition();
|
||||
theDirection = Direction;
|
||||
theTrack=0;
|
||||
}
|
||||
|
||||
G4ExcitedString::G4ExcitedString(G4Parton* Color, G4Parton* Gluon, G4Parton* AntiColor, G4int Direction)
|
||||
{
|
||||
thePartons.push_back(Color);
|
||||
thePartons.push_back(Gluon);
|
||||
thePartons.push_back(AntiColor);
|
||||
theTimeOfCreation = 0.; // Uzhi 15.05.08
|
||||
thePosition = Color->GetPosition();
|
||||
theDirection = Direction;
|
||||
theTrack=0;
|
||||
}
|
||||
|
||||
G4ExcitedString::G4ExcitedString(G4KineticTrack * track)
|
||||
{
|
||||
theTimeOfCreation = track->GetFormationTime(); // Uzhi 15.05.08
|
||||
thePosition = track->GetPosition();
|
||||
theTrack= track;
|
||||
theDirection=0;
|
||||
}
|
||||
|
||||
G4ExcitedString::~G4ExcitedString()
|
||||
{
|
||||
std::for_each(thePartons.begin(), thePartons.end(), DeleteParton());
|
||||
if ( theTrack ) {
|
||||
delete theTrack;
|
||||
theTrack=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//const G4ExcitedString & G4ExcitedString::operator=(const G4ExcitedString &right)
|
||||
//{}
|
||||
|
||||
|
||||
//G4bool G4ExcitedString::operator==(const G4ExcitedString &right) const
|
||||
//{}
|
||||
|
||||
//G4bool G4ExcitedString::operator!=(const G4ExcitedString &right) const
|
||||
//{}
|
||||
|
||||
|
||||
|
||||
// Additional Declarations
|
||||
|
||||
|
||||
void G4ExcitedString::Boost(G4ThreeVector& Velocity)
|
||||
{
|
||||
for(unsigned int cParton = 0; cParton < thePartons.size() ; cParton++ )
|
||||
{
|
||||
G4LorentzVector Mom = thePartons[cParton]->Get4Momentum();
|
||||
Mom.boost(Velocity);
|
||||
thePartons[cParton]->Set4Momentum(Mom);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
|
||||
G4Parton* G4ExcitedString::GetColorParton(void) const
|
||||
{
|
||||
G4Parton * start = *(thePartons.begin());
|
||||
G4Parton * end = *(thePartons.end()-1);
|
||||
G4int Encoding = start->GetPDGcode();
|
||||
if (Encoding < -1000 || ((Encoding < 1000) && (Encoding > 0)))
|
||||
return start;
|
||||
return end;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
|
||||
G4Parton* G4ExcitedString::GetGluon(void) const
|
||||
{
|
||||
return thePartons[1];
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
|
||||
G4Parton* G4ExcitedString::GetGluon(G4int GluonPos) const
|
||||
{
|
||||
return thePartons[1 + GluonPos];
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
|
||||
G4Parton* G4ExcitedString::GetAntiColorParton(void) const
|
||||
{
|
||||
G4Parton * start = *(thePartons.begin());
|
||||
G4Parton * end = *(thePartons.end()-1);
|
||||
G4int Encoding = start->GetPDGcode();
|
||||
if (Encoding < -1000 || ((Encoding < 1000) && (Encoding > 0)))
|
||||
return end;
|
||||
return start;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
|
||||
G4bool G4ExcitedString::IsItKinkyString(void) const
|
||||
{
|
||||
return (thePartons.size() > 2);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
|
||||
G4int G4ExcitedString::GetDirection(void) const
|
||||
{
|
||||
return theDirection;
|
||||
}
|
||||
|
||||
//*********************************************************************************
|
||||
|
||||
G4Parton* G4ExcitedString::GetLeftParton(void) const
|
||||
{
|
||||
return *thePartons.begin();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
|
||||
G4Parton* G4ExcitedString::GetRightParton(void) const
|
||||
{
|
||||
return *(thePartons.end()-1);
|
||||
}
|
||||
|
||||
//*********************************************************************************
|
||||
@@ -0,0 +1,599 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
// ------------------------------------------------------------
|
||||
// GEANT 4 class implementation file
|
||||
//
|
||||
// ---------------- G4Fancy3DNucleus ----------------
|
||||
// by Gunter Folger, May 1998.
|
||||
// class for a 3D nucleus, arranging nucleons in space and momentum.
|
||||
// ------------------------------------------------------------
|
||||
// 20110805 M. Kelsey -- Remove C-style array (pointer) of G4Nucleons,
|
||||
// make vector a container of objects. Move Helper class
|
||||
// to .hh. Move testSums, places, momentum and fermiM to
|
||||
// class data members for reuse.
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "G4Fancy3DNucleus.hh"
|
||||
#include "G4Fancy3DNucleusHelper.hh"
|
||||
#include "G4NuclearFermiDensity.hh"
|
||||
#include "G4NuclearShellModelDensity.hh"
|
||||
#include "G4NucleiProperties.hh"
|
||||
#include "G4Nucleon.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
#include "Randomize.hh"
|
||||
#include "G4ios.hh"
|
||||
#include "G4Pow.hh"
|
||||
#include "G4HadronicException.hh"
|
||||
|
||||
#include "Randomize.hh"
|
||||
#include "G4ThreeVector.hh"
|
||||
#include "G4RandomDirection.hh"
|
||||
#include "G4LorentzRotation.hh"
|
||||
#include "G4RotationMatrix.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
|
||||
G4Fancy3DNucleus::G4Fancy3DNucleus()
|
||||
: myA(0), myZ(0), theNucleons(250), currentNucleon(-1), theDensity(0),
|
||||
nucleondistance(0.8*fermi),excitationEnergy(0.),
|
||||
places(250), momentum(250), fermiM(250), testSums(250)
|
||||
{
|
||||
}
|
||||
|
||||
G4Fancy3DNucleus::~G4Fancy3DNucleus()
|
||||
{
|
||||
if(theDensity) delete theDensity;
|
||||
}
|
||||
|
||||
#if defined(NON_INTEGER_A_Z)
|
||||
void G4Fancy3DNucleus::Init(G4double theA, G4double theZ)
|
||||
{
|
||||
G4int intZ = G4int(theZ);
|
||||
G4int intA= ( G4UniformRand()>theA-G4int(theA) ) ? G4int(theA) : G4int(theA)+1;
|
||||
// forward to integer Init()
|
||||
Init(intA, intZ);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void G4Fancy3DNucleus::Init(G4int theA, G4int theZ)
|
||||
{
|
||||
currentNucleon=-1;
|
||||
theNucleons.clear();
|
||||
nucleondistance = 0.8*fermi;
|
||||
places.clear();
|
||||
momentum.clear();
|
||||
fermiM.clear();
|
||||
testSums.clear();
|
||||
|
||||
myZ = theZ;
|
||||
myA= theA;
|
||||
excitationEnergy=0;
|
||||
|
||||
theNucleons.resize(myA); // Pre-loads vector with empty elements
|
||||
|
||||
if(theDensity) delete theDensity;
|
||||
if ( myA < 17 ) {
|
||||
theDensity = new G4NuclearShellModelDensity(myA, myZ);
|
||||
if( myA == 12 ) nucleondistance=0.9*fermi;
|
||||
} else {
|
||||
theDensity = new G4NuclearFermiDensity(myA, myZ);
|
||||
}
|
||||
|
||||
theFermi.Init(myA, myZ);
|
||||
|
||||
ChooseNucleons();
|
||||
|
||||
ChoosePositions();
|
||||
|
||||
if( myA == 12 ) CenterNucleons(); // This would introduce a bias
|
||||
|
||||
ChooseFermiMomenta();
|
||||
|
||||
G4double Ebinding= BindingEnergy()/myA;
|
||||
|
||||
for (G4int aNucleon=0; aNucleon < myA; aNucleon++)
|
||||
{
|
||||
theNucleons[aNucleon].SetBindingEnergy(Ebinding);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
G4bool G4Fancy3DNucleus::StartLoop()
|
||||
{
|
||||
currentNucleon=0;
|
||||
return (theNucleons.size()>0);
|
||||
}
|
||||
|
||||
// Returns by pointer; null pointer indicates end of loop
|
||||
G4Nucleon * G4Fancy3DNucleus::GetNextNucleon()
|
||||
{
|
||||
return ( (currentNucleon>=0 && currentNucleon<myA) ?
|
||||
&theNucleons[currentNucleon++] : 0 );
|
||||
}
|
||||
|
||||
const std::vector<G4Nucleon> & G4Fancy3DNucleus::GetNucleons()
|
||||
{
|
||||
return theNucleons;
|
||||
}
|
||||
|
||||
|
||||
// Class-scope function to sort nucleons by Z coordinate
|
||||
bool G4Fancy3DNucleusHelperForSortInZ(const G4Nucleon& nuc1, const G4Nucleon& nuc2)
|
||||
{
|
||||
return nuc1.GetPosition().z() < nuc2.GetPosition().z();
|
||||
}
|
||||
|
||||
void G4Fancy3DNucleus::SortNucleonsIncZ()
|
||||
{
|
||||
if (theNucleons.size() < 2 ) return; // Avoid unnecesary work
|
||||
|
||||
std::sort(theNucleons.begin(), theNucleons.end(),
|
||||
G4Fancy3DNucleusHelperForSortInZ);
|
||||
}
|
||||
|
||||
void G4Fancy3DNucleus::SortNucleonsDecZ()
|
||||
{
|
||||
if (theNucleons.size() < 2 ) return; // Avoid unnecessary work
|
||||
SortNucleonsIncZ();
|
||||
|
||||
std::reverse(theNucleons.begin(), theNucleons.end());
|
||||
}
|
||||
|
||||
|
||||
G4double G4Fancy3DNucleus::BindingEnergy()
|
||||
{
|
||||
return G4NucleiProperties::GetBindingEnergy(myA,myZ);
|
||||
}
|
||||
|
||||
|
||||
G4double G4Fancy3DNucleus::GetNuclearRadius()
|
||||
{
|
||||
return GetNuclearRadius(0.5);
|
||||
}
|
||||
|
||||
G4double G4Fancy3DNucleus::GetNuclearRadius(const G4double maxRelativeDensity)
|
||||
{
|
||||
return theDensity->GetRadius(maxRelativeDensity);
|
||||
}
|
||||
|
||||
G4double G4Fancy3DNucleus::GetOuterRadius()
|
||||
{
|
||||
G4double maxradius2=0;
|
||||
|
||||
for (int i=0; i<myA; i++)
|
||||
{
|
||||
if ( theNucleons[i].GetPosition().mag2() > maxradius2 )
|
||||
{
|
||||
maxradius2=theNucleons[i].GetPosition().mag2();
|
||||
}
|
||||
}
|
||||
return std::sqrt(maxradius2)+nucleondistance;
|
||||
}
|
||||
|
||||
G4double G4Fancy3DNucleus::GetMass()
|
||||
{
|
||||
return myZ*G4Proton::Proton()->GetPDGMass() +
|
||||
(myA-myZ)*G4Neutron::Neutron()->GetPDGMass() -
|
||||
BindingEnergy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void G4Fancy3DNucleus::DoLorentzBoost(const G4LorentzVector & theBoost)
|
||||
{
|
||||
for (G4int i=0; i<myA; i++){
|
||||
theNucleons[i].Boost(theBoost);
|
||||
}
|
||||
}
|
||||
|
||||
void G4Fancy3DNucleus::DoLorentzBoost(const G4ThreeVector & theBeta)
|
||||
{
|
||||
for (G4int i=0; i<myA; i++){
|
||||
theNucleons[i].Boost(theBeta);
|
||||
}
|
||||
}
|
||||
|
||||
void G4Fancy3DNucleus::DoLorentzContraction(const G4ThreeVector & theBeta)
|
||||
{
|
||||
G4double beta2=theBeta.mag2();
|
||||
if (beta2 > 0) {
|
||||
G4double factor=(1-std::sqrt(1-beta2))/beta2; // (gamma-1)/gamma/beta**2
|
||||
G4ThreeVector rprime;
|
||||
for (G4int i=0; i< myA; i++) {
|
||||
rprime = theNucleons[i].GetPosition() -
|
||||
factor * (theBeta*theNucleons[i].GetPosition()) * theBeta;
|
||||
theNucleons[i].SetPosition(rprime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void G4Fancy3DNucleus::DoLorentzContraction(const G4LorentzVector & theBoost)
|
||||
{
|
||||
if (theBoost.e() !=0 ) {
|
||||
G4ThreeVector beta = theBoost.vect()/theBoost.e();
|
||||
DoLorentzContraction(beta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void G4Fancy3DNucleus::CenterNucleons()
|
||||
{
|
||||
G4ThreeVector center;
|
||||
|
||||
for (G4int i=0; i<myA; i++ )
|
||||
{
|
||||
center+=theNucleons[i].GetPosition();
|
||||
}
|
||||
center /= -myA;
|
||||
DoTranslation(center);
|
||||
}
|
||||
|
||||
void G4Fancy3DNucleus::DoTranslation(const G4ThreeVector & theShift)
|
||||
{
|
||||
G4ThreeVector tempV;
|
||||
for (G4int i=0; i<myA; i++ )
|
||||
{
|
||||
tempV = theNucleons[i].GetPosition() + theShift;
|
||||
theNucleons[i].SetPosition(tempV);
|
||||
}
|
||||
}
|
||||
|
||||
const G4VNuclearDensity * G4Fancy3DNucleus::GetNuclearDensity() const
|
||||
{
|
||||
return theDensity;
|
||||
}
|
||||
|
||||
//----------------------- private Implementation Methods-------------
|
||||
|
||||
void G4Fancy3DNucleus::ChooseNucleons()
|
||||
{
|
||||
G4int protons=0,nucleons=0;
|
||||
|
||||
while (nucleons < myA ) /* Loop checking, 30-Oct-2015, G.Folger */
|
||||
{
|
||||
if ( protons < myZ && G4UniformRand() < (G4double)(myZ-protons)/(G4double)(myA-nucleons) )
|
||||
{
|
||||
protons++;
|
||||
theNucleons[nucleons++].SetParticleType(G4Proton::Proton());
|
||||
}
|
||||
else if ( (nucleons-protons) < (myA-myZ) )
|
||||
{
|
||||
theNucleons[nucleons++].SetParticleType(G4Neutron::Neutron());
|
||||
}
|
||||
else G4cout << "G4Fancy3DNucleus::ChooseNucleons not efficient" << G4endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void G4Fancy3DNucleus::ChoosePositions()
|
||||
{
|
||||
if( myA != 12) {
|
||||
|
||||
G4int i=0;
|
||||
G4ThreeVector aPos, delta;
|
||||
G4bool freeplace;
|
||||
const G4double nd2=sqr(nucleondistance);
|
||||
G4double maxR=GetNuclearRadius(0.001); // there are no nucleons at a
|
||||
// relative Density of 0.01
|
||||
G4int jr=0;
|
||||
G4int jx,jy;
|
||||
G4double arand[600];
|
||||
G4double *prand=arand;
|
||||
places.clear(); // Reset data buffer
|
||||
G4int interationsLeft=1000*myA;
|
||||
while ( (i < myA) && (--interationsLeft>0)) /* Loop checking, 30-Oct-2015, G.Folger */
|
||||
{
|
||||
do
|
||||
{
|
||||
if ( jr < 3 )
|
||||
{
|
||||
jr=std::min(600,9*(myA - i));
|
||||
G4RandFlat::shootArray(jr,prand);
|
||||
//CLHEP::RandFlat::shootArray(jr, prand );
|
||||
}
|
||||
jx=--jr;
|
||||
jy=--jr;
|
||||
aPos.set((2*arand[jx]-1.), (2*arand[jy]-1.), (2*arand[--jr]-1.));
|
||||
} while (aPos.mag2() > 1. ); /* Loop checking, 30-Oct-2015, G.Folger */
|
||||
aPos *=maxR;
|
||||
G4double density=theDensity->GetRelativeDensity(aPos);
|
||||
if (G4UniformRand() < density)
|
||||
{
|
||||
freeplace= true;
|
||||
std::vector<G4ThreeVector>::iterator iplace;
|
||||
for( iplace=places.begin(); iplace!=places.end() && freeplace;++iplace)
|
||||
{
|
||||
delta = *iplace - aPos;
|
||||
freeplace= delta.mag2() > nd2;
|
||||
}
|
||||
if ( freeplace ) {
|
||||
G4double pFermi=theFermi.GetFermiMomentum(theDensity->GetDensity(aPos));
|
||||
// protons must at least have binding energy of CoulombBarrier, so
|
||||
// assuming the Fermi energy corresponds to a potential, we must place these such
|
||||
// that the Fermi Energy > CoulombBarrier
|
||||
if (theNucleons[i].GetDefinition() == G4Proton::Proton())
|
||||
{
|
||||
G4double nucMass = theNucleons[i].GetDefinition()->GetPDGMass();
|
||||
G4double eFermi= std::sqrt( sqr(pFermi) + sqr(nucMass) ) - nucMass;
|
||||
if (eFermi <= CoulombBarrier() ) freeplace=false;
|
||||
}
|
||||
}
|
||||
if ( freeplace ) {
|
||||
theNucleons[i].SetPosition(aPos);
|
||||
places.push_back(aPos);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (interationsLeft<=0) {
|
||||
G4Exception("model/util/G4Fancy3DNucleus.cc", "mod_util001", FatalException,
|
||||
"Problem to place nucleons");
|
||||
}
|
||||
|
||||
} else {
|
||||
// Start insertion
|
||||
// Alpha cluster structure of carbon nuclei, C-12, is implemented according to
|
||||
// P. Bozek, W. Broniowski, E.R. Arriola and M. Rybczynski
|
||||
// Phys. Rev. C90, 064902 (2014)
|
||||
const G4double Lbase=3.05*fermi;
|
||||
const G4double Disp=0.552; // 0.91^2*2/3 fermi^2
|
||||
const G4double nd2=sqr(nucleondistance);
|
||||
const G4ThreeVector Corner1=G4ThreeVector( Lbase/2., 0., 0.);
|
||||
const G4ThreeVector Corner2=G4ThreeVector(-Lbase/2., 0., 0.);
|
||||
const G4ThreeVector Corner3=G4ThreeVector( 0.,Lbase*0.866, 0.); // 0.866=sqrt(3)/2
|
||||
G4ThreeVector R1;
|
||||
R1=G4ThreeVector(G4RandGauss::shoot(0.,Disp), G4RandGauss::shoot(0.,Disp), G4RandGauss::shoot(0.,Disp))*fermi + Corner1;
|
||||
theNucleons[0].SetPosition(R1); // First nucleon of the first He-4
|
||||
G4int loopCounterLeft = 10000;
|
||||
for(G4int ii=1; ii<4; ii++) // 2 - 4 nucleons of the first He-4
|
||||
{
|
||||
G4bool Continue;
|
||||
do
|
||||
{
|
||||
R1=G4ThreeVector(G4RandGauss::shoot(0.,Disp), G4RandGauss::shoot(0.,Disp), G4RandGauss::shoot(0.,Disp))*fermi + Corner1;
|
||||
theNucleons[ii].SetPosition(R1);
|
||||
Continue=false;
|
||||
for(G4int jj=0; jj < ii; jj++)
|
||||
{
|
||||
if( (theNucleons[ii].GetPosition() - theNucleons[jj].GetPosition()).mag2() <= nd2 ) {Continue = true; break;}
|
||||
}
|
||||
} while( Continue && --loopCounterLeft > 0 ); /* Loop checking, 12-Dec-2017, A.Ribon */
|
||||
}
|
||||
if ( loopCounterLeft <= 0 ) {
|
||||
G4Exception("model/util/G4Fancy3DNucleus.cc", "mod_util002", FatalException,
|
||||
"Unable to find a good position for the first alpha cluster");
|
||||
}
|
||||
loopCounterLeft = 10000;
|
||||
for(G4int ii=4; ii<8; ii++) // 5 - 8 nucleons of the second He-4
|
||||
{
|
||||
G4bool Continue;
|
||||
do
|
||||
{
|
||||
R1=G4ThreeVector(G4RandGauss::shoot(0.,Disp), G4RandGauss::shoot(0.,Disp), G4RandGauss::shoot(0.,Disp))*fermi + Corner2;
|
||||
theNucleons[ii].SetPosition(R1);
|
||||
Continue=false;
|
||||
for(G4int jj=0; jj < ii; jj++)
|
||||
{
|
||||
if( (theNucleons[ii].GetPosition() - theNucleons[jj].GetPosition()).mag2() <= nd2 ) {Continue = true; break;}
|
||||
}
|
||||
} while( Continue && --loopCounterLeft > 0 ); /* Loop checking, 12-Dec-2017, A.Ribon */
|
||||
}
|
||||
if ( loopCounterLeft <= 0 ) {
|
||||
G4Exception("model/util/G4Fancy3DNucleus.cc", "mod_util003", FatalException,
|
||||
"Unable to find a good position for the second alpha cluster");
|
||||
}
|
||||
loopCounterLeft = 10000;
|
||||
for(G4int ii=8; ii<12; ii++) // 9 - 12 nucleons of the third He-4
|
||||
{
|
||||
G4bool Continue;
|
||||
do
|
||||
{
|
||||
R1=G4ThreeVector(G4RandGauss::shoot(0.,Disp), G4RandGauss::shoot(0.,Disp), G4RandGauss::shoot(0.,Disp))*fermi + Corner3;
|
||||
theNucleons[ii].SetPosition(R1);
|
||||
Continue=false;
|
||||
for(G4int jj=0; jj < ii; jj++)
|
||||
{
|
||||
if( (theNucleons[ii].GetPosition() - theNucleons[jj].GetPosition()).mag2() <= nd2 ) {Continue = true; break;}
|
||||
}
|
||||
} while( Continue && --loopCounterLeft > 0 ); /* Loop checking, 12-Dec-2017, A.Ribon */
|
||||
}
|
||||
if ( loopCounterLeft <= 0 ) {
|
||||
G4Exception("model/util/G4Fancy3DNucleus.cc", "mod_util004", FatalException,
|
||||
"Unable to find a good position for the third alpha cluster");
|
||||
}
|
||||
G4LorentzRotation RandomRotation;
|
||||
RandomRotation.rotateZ(2.*pi*G4UniformRand());
|
||||
RandomRotation.rotateY(std::acos(2.*G4UniformRand()-1.));
|
||||
// Randomly rotation of the created nucleus
|
||||
G4LorentzVector Pos;
|
||||
for(G4int ii=0; ii<myA; ii++ )
|
||||
{
|
||||
Pos=G4LorentzVector(theNucleons[ii].GetPosition(),0.); Pos *=RandomRotation;
|
||||
G4ThreeVector NewPos = Pos.vect();
|
||||
theNucleons[ii].SetPosition(NewPos);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void G4Fancy3DNucleus::ChooseFermiMomenta()
|
||||
{
|
||||
G4int i;
|
||||
G4double density;
|
||||
|
||||
// Pre-allocate buffers for filling by index
|
||||
momentum.resize(myA, G4ThreeVector(0.,0.,0.));
|
||||
fermiM.resize(myA, 0.*GeV);
|
||||
|
||||
for (G4int ntry=0; ntry<1 ; ntry ++ )
|
||||
{
|
||||
for (i=0; i < myA; i++ ) // momenta for all, including last, in case we swap nucleons
|
||||
{
|
||||
density = theDensity->GetDensity(theNucleons[i].GetPosition());
|
||||
fermiM[i] = theFermi.GetFermiMomentum(density);
|
||||
G4ThreeVector mom=theFermi.GetMomentum(density);
|
||||
if (theNucleons[i].GetDefinition() == G4Proton::Proton())
|
||||
{
|
||||
G4double eMax = std::sqrt(sqr(fermiM[i]) +sqr(theNucleons[i].GetDefinition()->GetPDGMass()) )
|
||||
- CoulombBarrier();
|
||||
if ( eMax > theNucleons[i].GetDefinition()->GetPDGMass() )
|
||||
{
|
||||
G4double pmax2= sqr(eMax) - sqr(theNucleons[i].GetDefinition()->GetPDGMass());
|
||||
fermiM[i] = std::sqrt(pmax2);
|
||||
while ( mom.mag2() > pmax2 ) /* Loop checking, 30-Oct-2015, G.Folger */
|
||||
{
|
||||
mom=theFermi.GetMomentum(density, fermiM[i]);
|
||||
}
|
||||
} else
|
||||
{
|
||||
//AR-21Dec2017 : emit a "JustWarning" exception instead of writing on the error stream.
|
||||
//G4cerr << "G4Fancy3DNucleus: difficulty finding proton momentum" << G4endl;
|
||||
G4ExceptionDescription ed;
|
||||
ed << "Nucleus Z A " << myZ << " " << myA << G4endl;
|
||||
ed << "proton with eMax=" << eMax << G4endl;
|
||||
G4Exception( "G4Fancy3DNucleus::ChooseFermiMomenta(): difficulty finding proton momentum, set it to (0,0,0)",
|
||||
"HAD_FANCY3DNUCLEUS_001", JustWarning, ed );
|
||||
mom=G4ThreeVector(0,0,0);
|
||||
}
|
||||
|
||||
}
|
||||
momentum[i]= mom;
|
||||
}
|
||||
|
||||
if ( ReduceSum() ) break;
|
||||
// G4cout <<" G4FancyNucleus: iterating to find momenta: "<< ntry<< G4endl;
|
||||
}
|
||||
|
||||
// G4ThreeVector sum;
|
||||
// for (G4int index=0; index<myA;sum+=momentum[index++])
|
||||
// ;
|
||||
// G4cout << "final sum / mag() " << sum << " / " << sum.mag() << G4endl;
|
||||
|
||||
G4double energy;
|
||||
for ( i=0; i< myA ; i++ )
|
||||
{
|
||||
energy = theNucleons[i].GetParticleType()->GetPDGMass()
|
||||
- BindingEnergy()/myA;
|
||||
G4LorentzVector tempV(momentum[i],energy);
|
||||
theNucleons[i].SetMomentum(tempV);
|
||||
// GF 11-05-2011: set BindingEnergy to be T of Nucleon with p , ~ p**2/2m
|
||||
//theNucleons[i].SetBindingEnergy(
|
||||
// 0.5*sqr(fermiM[i])/theNucleons[i].GetParticleType()->GetPDGMass());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
G4bool G4Fancy3DNucleus::ReduceSum()
|
||||
{
|
||||
G4ThreeVector sum;
|
||||
G4double PFermi=fermiM[myA-1];
|
||||
|
||||
for (G4int i=0; i < myA-1 ; i++ )
|
||||
{ sum+=momentum[i]; }
|
||||
|
||||
// check if have to do anything at all..
|
||||
if ( sum.mag() <= PFermi )
|
||||
{
|
||||
momentum[myA-1]=-sum;
|
||||
return true;
|
||||
}
|
||||
|
||||
// find all possible changes in momentum, changing only the component parallel to sum
|
||||
G4ThreeVector testDir=sum.unit();
|
||||
testSums.clear();
|
||||
testSums.resize(myA-1); // Allocate block for filling below
|
||||
|
||||
G4ThreeVector delta;
|
||||
for (G4int aNucleon=0; aNucleon < myA-1; aNucleon++) {
|
||||
delta = 2.*((momentum[aNucleon]*testDir)*testDir);
|
||||
|
||||
testSums[aNucleon].Fill(delta, delta.mag(), aNucleon);
|
||||
}
|
||||
|
||||
std::sort(testSums.begin(), testSums.end());
|
||||
|
||||
// reduce Momentum Sum until the next would be allowed.
|
||||
G4int index=testSums.size();
|
||||
while ( (sum-testSums[--index].Vector).mag()>PFermi && index>0) /* Loop checking, 30-Oct-2015, G.Folger */
|
||||
{
|
||||
// Only take one which improve, ie. don't change sign and overshoot...
|
||||
if ( sum.mag() > (sum-testSums[index].Vector).mag() ) {
|
||||
momentum[testSums[index].Index]-=testSums[index].Vector;
|
||||
sum-=testSums[index].Vector;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (sum-testSums[index].Vector).mag() <= PFermi )
|
||||
{
|
||||
G4int best=-1;
|
||||
G4double pBest=2*PFermi; // anything larger than PFermi
|
||||
for ( G4int aNucleon=0; aNucleon<=index; aNucleon++)
|
||||
{
|
||||
// find the momentum closest to choosen momentum for last Nucleon.
|
||||
G4double pTry=(testSums[aNucleon].Vector-sum).mag();
|
||||
if ( pTry < PFermi
|
||||
&& std::abs(momentum[myA-1].mag() - pTry ) < pBest )
|
||||
{
|
||||
pBest=std::abs(momentum[myA-1].mag() - pTry );
|
||||
best=aNucleon;
|
||||
}
|
||||
}
|
||||
if ( best < 0 )
|
||||
{
|
||||
G4String text = "G4Fancy3DNucleus.cc: Logic error in ReduceSum()";
|
||||
throw G4HadronicException(__FILE__, __LINE__, text);
|
||||
}
|
||||
momentum[testSums[best].Index]-=testSums[best].Vector;
|
||||
momentum[myA-1]=testSums[best].Vector-sum;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// try to compensate momentum using another Nucleon....
|
||||
G4int swapit=-1;
|
||||
while (swapit<myA-1) /* Loop checking, 30-Oct-2015, G.Folger */
|
||||
{
|
||||
if ( fermiM[++swapit] > PFermi ) break;
|
||||
}
|
||||
if (swapit == myA-1 ) return false;
|
||||
|
||||
// Now we have a nucleon with a bigger Fermi Momentum.
|
||||
// Exchange with last nucleon.. and iterate.
|
||||
std::swap(theNucleons[swapit], theNucleons[myA-1]);
|
||||
std::swap(momentum[swapit], momentum[myA-1]);
|
||||
std::swap(fermiM[swapit], fermiM[myA-1]);
|
||||
return ReduceSum();
|
||||
}
|
||||
|
||||
G4double G4Fancy3DNucleus::CoulombBarrier()
|
||||
{
|
||||
static const G4double cfactor = (1.44/1.14) * MeV;
|
||||
return cfactor*myZ/(1.0 + G4Pow::GetInstance()->Z13(myA));
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
//
|
||||
#include "G4FermiMomentum.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
|
||||
G4FermiMomentum::G4FermiMomentum() :
|
||||
theA(0), theZ(0),
|
||||
constofpmax(hbarc*cbrt(3.*pi2))
|
||||
{}
|
||||
|
||||
G4FermiMomentum::~G4FermiMomentum(){}
|
||||
@@ -0,0 +1,258 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
//---------------------------------------------------------------------
|
||||
//
|
||||
// Geant4 class G4Fragment
|
||||
//
|
||||
// Hadronic Process: Nuclear De-excitations
|
||||
// by V. Lara (May 1998)
|
||||
//
|
||||
// Modifications:
|
||||
// 03.05.2010 V.Ivanchenko General cleanup; moved obsolete methods from
|
||||
// inline to source
|
||||
// 25.09.2010 M. Kelsey -- Change "setprecision" to "setwidth" in printout,
|
||||
// add null pointer check.
|
||||
|
||||
#include "G4Fragment.hh"
|
||||
#include "G4HadronicException.hh"
|
||||
#include "G4ios.hh"
|
||||
#include <iomanip>
|
||||
|
||||
G4Allocator<G4Fragment>*& pFragmentAllocator()
|
||||
{
|
||||
G4ThreadLocalStatic G4Allocator<G4Fragment>* _instance = nullptr;
|
||||
return _instance;
|
||||
}
|
||||
|
||||
const G4double G4Fragment::minFragExcitation = 10.*CLHEP::eV;
|
||||
|
||||
// Default constructor
|
||||
G4Fragment::G4Fragment() :
|
||||
theA(0),
|
||||
theZ(0),
|
||||
theExcitationEnergy(0.0),
|
||||
theGroundStateMass(0.0),
|
||||
theMomentum(G4LorentzVector(0,0,0,0)),
|
||||
thePolarization(nullptr),
|
||||
creatorModel(-1),
|
||||
numberOfParticles(0),
|
||||
numberOfCharged(0),
|
||||
numberOfHoles(0),
|
||||
numberOfChargedHoles(0),
|
||||
numberOfShellElectrons(0),
|
||||
xLevel(0),
|
||||
theParticleDefinition(nullptr),
|
||||
spin(0.0),
|
||||
theCreationTime(0.0)
|
||||
{}
|
||||
|
||||
// Copy Constructor
|
||||
G4Fragment::G4Fragment(const G4Fragment &right) :
|
||||
theA(right.theA),
|
||||
theZ(right.theZ),
|
||||
theExcitationEnergy(right.theExcitationEnergy),
|
||||
theGroundStateMass(right.theGroundStateMass),
|
||||
theMomentum(right.theMomentum),
|
||||
thePolarization(right.thePolarization),
|
||||
creatorModel(right.creatorModel),
|
||||
numberOfParticles(right.numberOfParticles),
|
||||
numberOfCharged(right.numberOfCharged),
|
||||
numberOfHoles(right.numberOfHoles),
|
||||
numberOfChargedHoles(right.numberOfChargedHoles),
|
||||
numberOfShellElectrons(right.numberOfShellElectrons),
|
||||
xLevel(right.xLevel),
|
||||
theParticleDefinition(right.theParticleDefinition),
|
||||
spin(right.spin),
|
||||
theCreationTime(right.theCreationTime)
|
||||
{}
|
||||
|
||||
G4Fragment::~G4Fragment()
|
||||
{}
|
||||
|
||||
G4Fragment::G4Fragment(G4int A, G4int Z, const G4LorentzVector& aMomentum, G4bool warning) :
|
||||
theA(A),
|
||||
theZ(Z),
|
||||
theExcitationEnergy(0.0),
|
||||
theGroundStateMass(0.0),
|
||||
theMomentum(aMomentum),
|
||||
thePolarization(nullptr),
|
||||
creatorModel(-1),
|
||||
numberOfParticles(0),
|
||||
numberOfCharged(0),
|
||||
numberOfHoles(0),
|
||||
numberOfChargedHoles(0),
|
||||
numberOfShellElectrons(0),
|
||||
xLevel(0),
|
||||
theParticleDefinition(nullptr),
|
||||
spin(0.0),
|
||||
theCreationTime(0.0)
|
||||
{
|
||||
if(theA > 0) {
|
||||
CalculateGroundStateMass();
|
||||
CalculateExcitationEnergy(warning);
|
||||
}
|
||||
}
|
||||
|
||||
// This constructor is for initialize photons or electrons
|
||||
G4Fragment::G4Fragment(const G4LorentzVector& aMomentum,
|
||||
const G4ParticleDefinition * aParticleDefinition) :
|
||||
theA(0),
|
||||
theZ(0),
|
||||
theExcitationEnergy(0.0),
|
||||
theMomentum(aMomentum),
|
||||
thePolarization(nullptr),
|
||||
creatorModel(-1),
|
||||
numberOfParticles(0),
|
||||
numberOfCharged(0),
|
||||
numberOfHoles(0),
|
||||
numberOfChargedHoles(0),
|
||||
numberOfShellElectrons(0),
|
||||
xLevel(0),
|
||||
theParticleDefinition(aParticleDefinition),
|
||||
spin(0.0),
|
||||
theCreationTime(0.0)
|
||||
{
|
||||
if(aParticleDefinition->GetPDGEncoding() != 22 &&
|
||||
aParticleDefinition->GetPDGEncoding() != 11) {
|
||||
G4String text = "G4Fragment::G4Fragment constructor for gamma used for "
|
||||
+ aParticleDefinition->GetParticleName();
|
||||
throw G4HadronicException(__FILE__, __LINE__, text);
|
||||
}
|
||||
theGroundStateMass = aParticleDefinition->GetPDGMass();
|
||||
}
|
||||
|
||||
G4Fragment & G4Fragment::operator=(const G4Fragment &right)
|
||||
{
|
||||
if (this != &right) {
|
||||
theA = right.theA;
|
||||
theZ = right.theZ;
|
||||
theExcitationEnergy = right.theExcitationEnergy;
|
||||
theGroundStateMass = right.theGroundStateMass;
|
||||
theMomentum = right.theMomentum;
|
||||
thePolarization = right.thePolarization;
|
||||
creatorModel = right.creatorModel;
|
||||
numberOfParticles = right.numberOfParticles;
|
||||
numberOfCharged = right.numberOfCharged;
|
||||
numberOfHoles = right.numberOfHoles;
|
||||
numberOfChargedHoles = right.numberOfChargedHoles;
|
||||
numberOfShellElectrons = right.numberOfShellElectrons;
|
||||
xLevel = right.xLevel;
|
||||
theParticleDefinition = right.theParticleDefinition;
|
||||
spin = right.spin;
|
||||
theCreationTime = right.theCreationTime;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
G4bool G4Fragment::operator==(const G4Fragment &right) const
|
||||
{
|
||||
return (this == (G4Fragment *) &right);
|
||||
}
|
||||
|
||||
G4bool G4Fragment::operator!=(const G4Fragment &right) const
|
||||
{
|
||||
return (this != (G4Fragment *) &right);
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream &out, const G4Fragment &theFragment)
|
||||
{
|
||||
std::ios::fmtflags old_floatfield = out.flags();
|
||||
out.setf(std::ios::floatfield);
|
||||
|
||||
out << "Fragment: A = " << std::setw(3) << theFragment.theA
|
||||
<< ", Z = " << std::setw(3) << theFragment.theZ ;
|
||||
out.setf(std::ios::scientific,std::ios::floatfield);
|
||||
|
||||
// Store user's precision setting and reset to (3) here: back-compatibility
|
||||
std::streamsize floatPrec = out.precision();
|
||||
|
||||
out << std::setprecision(3)
|
||||
<< ", U = " << theFragment.GetExcitationEnergy()/CLHEP::MeV
|
||||
<< " MeV ";
|
||||
if(theFragment.GetCreatorModelType() >= 0) {
|
||||
out << " creatorModelType= " << theFragment.GetCreatorModelType();
|
||||
}
|
||||
if(theFragment.GetCreationTime() > 0.0) {
|
||||
out << " Time= " << theFragment.GetCreationTime()/CLHEP::ns << " ns";
|
||||
}
|
||||
out << G4endl
|
||||
<< " P = ("
|
||||
<< theFragment.GetMomentum().x()/CLHEP::MeV << ","
|
||||
<< theFragment.GetMomentum().y()/CLHEP::MeV << ","
|
||||
<< theFragment.GetMomentum().z()/CLHEP::MeV
|
||||
<< ") MeV E = "
|
||||
<< theFragment.GetMomentum().t()/CLHEP::MeV << " MeV"
|
||||
<< G4endl;
|
||||
|
||||
out << " #spin= " << theFragment.GetSpin()
|
||||
<< " #floatLevelNo= " << theFragment.GetFloatingLevelNumber() << " ";
|
||||
|
||||
if (theFragment.GetNumberOfExcitons() != 0) {
|
||||
out << " "
|
||||
<< "#Particles= " << theFragment.GetNumberOfParticles()
|
||||
<< ", #Charged= " << theFragment.GetNumberOfCharged()
|
||||
<< ", #Holes= " << theFragment.GetNumberOfHoles()
|
||||
<< ", #ChargedHoles= " << theFragment.GetNumberOfChargedHoles();
|
||||
}
|
||||
out << G4endl;
|
||||
if(theFragment.GetNuclearPolarization()) {
|
||||
out << *(theFragment.GetNuclearPolarization());
|
||||
}
|
||||
//out << G4endl;
|
||||
out.setf(old_floatfield,std::ios::floatfield);
|
||||
out.precision(floatPrec);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void G4Fragment::ExcitationEnergyWarning()
|
||||
{
|
||||
#ifdef G4VERBOSE
|
||||
G4cout << "G4Fragment::CalculateExcitationEnergy(): WARNING "<<G4endl;
|
||||
G4cout << *this << G4endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void G4Fragment::NumberOfExitationWarning(const G4String& value)
|
||||
{
|
||||
G4cout << "G4Fragment::"<< value << " ERROR "
|
||||
<< G4endl;
|
||||
G4cout << this << G4endl;
|
||||
G4String text = "G4Fragment::G4Fragment wrong exciton number ";
|
||||
throw G4HadronicException(__FILE__, __LINE__, text);
|
||||
}
|
||||
|
||||
void G4Fragment::SetAngularMomentum(const G4ThreeVector& v)
|
||||
{
|
||||
spin = v.mag();
|
||||
}
|
||||
|
||||
G4ThreeVector G4Fragment::GetAngularMomentum() const
|
||||
{
|
||||
G4ThreeVector v(0.0,0.0,spin);
|
||||
return v;
|
||||
}
|
||||
@@ -0,0 +1,569 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// ----------------------------------------------------------------
|
||||
// GEANT 4 class header file
|
||||
//
|
||||
// History: first implementation, A. Feliciello, 21st May 1998
|
||||
//
|
||||
// Note: this class is a generalization of the
|
||||
// G4PhaseSpaceDecayChannel one
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
#include "G4ParticleDefinition.hh"
|
||||
#include "G4DecayProducts.hh"
|
||||
#include "G4VDecayChannel.hh"
|
||||
#include "G4GeneralPhaseSpaceDecay.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
#include "Randomize.hh"
|
||||
#include "G4LorentzVector.hh"
|
||||
#include "G4LorentzRotation.hh"
|
||||
#include "G4ios.hh"
|
||||
|
||||
|
||||
G4GeneralPhaseSpaceDecay::G4GeneralPhaseSpaceDecay(G4int Verbose) :
|
||||
G4VDecayChannel("Phase Space", Verbose),
|
||||
parentmass(0.), theDaughterMasses(0)
|
||||
{
|
||||
if (GetVerboseLevel()>1) G4cout << "G4GeneralPhaseSpaceDecay:: constructor " << G4endl;
|
||||
}
|
||||
|
||||
G4GeneralPhaseSpaceDecay::G4GeneralPhaseSpaceDecay(const G4String& theParentName,
|
||||
G4double theBR,
|
||||
G4int theNumberOfDaughters,
|
||||
const G4String& theDaughterName1,
|
||||
const G4String& theDaughterName2,
|
||||
const G4String& theDaughterName3) :
|
||||
G4VDecayChannel("Phase Space",
|
||||
theParentName,theBR,
|
||||
theNumberOfDaughters,
|
||||
theDaughterName1,
|
||||
theDaughterName2,
|
||||
theDaughterName3),
|
||||
theDaughterMasses(0)
|
||||
{
|
||||
if (GetVerboseLevel()>1) G4cout << "G4GeneralPhaseSpaceDecay:: constructor " << G4endl;
|
||||
|
||||
// Set the parent particle (resonance) mass to the (default) PDG vale
|
||||
if (G4MT_parent != NULL)
|
||||
{
|
||||
parentmass = G4MT_parent->GetPDGMass();
|
||||
} else {
|
||||
parentmass=0.;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
G4GeneralPhaseSpaceDecay::G4GeneralPhaseSpaceDecay(const G4String& theParentName,
|
||||
G4double theParentMass,
|
||||
G4double theBR,
|
||||
G4int theNumberOfDaughters,
|
||||
const G4String& theDaughterName1,
|
||||
const G4String& theDaughterName2,
|
||||
const G4String& theDaughterName3) :
|
||||
G4VDecayChannel("Phase Space",
|
||||
theParentName,theBR,
|
||||
theNumberOfDaughters,
|
||||
theDaughterName1,
|
||||
theDaughterName2,
|
||||
theDaughterName3),
|
||||
parentmass(theParentMass),
|
||||
theDaughterMasses(0)
|
||||
{
|
||||
if (GetVerboseLevel()>1) G4cout << "G4GeneralPhaseSpaceDecay:: constructor " << G4endl;
|
||||
}
|
||||
|
||||
G4GeneralPhaseSpaceDecay::G4GeneralPhaseSpaceDecay(const G4String& theParentName,
|
||||
G4double theParentMass,
|
||||
G4double theBR,
|
||||
G4int theNumberOfDaughters,
|
||||
const G4String& theDaughterName1,
|
||||
const G4String& theDaughterName2,
|
||||
const G4String& theDaughterName3,
|
||||
const G4double *masses) :
|
||||
G4VDecayChannel("Phase Space",
|
||||
theParentName,theBR,
|
||||
theNumberOfDaughters,
|
||||
theDaughterName1,
|
||||
theDaughterName2,
|
||||
theDaughterName3),
|
||||
parentmass(theParentMass),
|
||||
theDaughterMasses(masses)
|
||||
{
|
||||
if (GetVerboseLevel()>1) G4cout << "G4GeneralPhaseSpaceDecay:: constructor " << G4endl;
|
||||
}
|
||||
|
||||
G4GeneralPhaseSpaceDecay::G4GeneralPhaseSpaceDecay(const G4String& theParentName,
|
||||
G4double theParentMass,
|
||||
G4double theBR,
|
||||
G4int theNumberOfDaughters,
|
||||
const G4String& theDaughterName1,
|
||||
const G4String& theDaughterName2,
|
||||
const G4String& theDaughterName3,
|
||||
const G4String& theDaughterName4,
|
||||
const G4double *masses) :
|
||||
G4VDecayChannel("Phase Space",
|
||||
theParentName,theBR,
|
||||
theNumberOfDaughters,
|
||||
theDaughterName1,
|
||||
theDaughterName2,
|
||||
theDaughterName3,
|
||||
theDaughterName4),
|
||||
parentmass(theParentMass),
|
||||
theDaughterMasses(masses)
|
||||
{
|
||||
if (GetVerboseLevel()>1) G4cout << "G4GeneralPhaseSpaceDecay:: constructor " << G4endl;
|
||||
}
|
||||
|
||||
G4GeneralPhaseSpaceDecay::~G4GeneralPhaseSpaceDecay()
|
||||
{
|
||||
}
|
||||
|
||||
G4DecayProducts *G4GeneralPhaseSpaceDecay::DecayIt(G4double)
|
||||
{
|
||||
if (GetVerboseLevel()>1) G4cout << "G4GeneralPhaseSpaceDecay::DecayIt ";
|
||||
G4DecayProducts * products = NULL;
|
||||
|
||||
CheckAndFillParent();
|
||||
CheckAndFillDaughters();
|
||||
|
||||
switch (numberOfDaughters){
|
||||
case 0:
|
||||
if (GetVerboseLevel()>0) {
|
||||
G4cout << "G4GeneralPhaseSpaceDecay::DecayIt ";
|
||||
G4cout << " daughters not defined " <<G4endl;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
products = OneBodyDecayIt();
|
||||
break;
|
||||
case 2:
|
||||
products = TwoBodyDecayIt();
|
||||
break;
|
||||
case 3:
|
||||
products = ThreeBodyDecayIt();
|
||||
break;
|
||||
default:
|
||||
products = ManyBodyDecayIt();
|
||||
break;
|
||||
}
|
||||
if ((products == NULL) && (GetVerboseLevel()>0)) {
|
||||
G4cout << "G4GeneralPhaseSpaceDecay::DecayIt ";
|
||||
G4cout << *parent_name << " can not decay " << G4endl;
|
||||
DumpInfo();
|
||||
}
|
||||
return products;
|
||||
}
|
||||
|
||||
G4DecayProducts *G4GeneralPhaseSpaceDecay::OneBodyDecayIt()
|
||||
{
|
||||
if (GetVerboseLevel()>1) G4cout << "G4GeneralPhaseSpaceDecay::OneBodyDecayIt()"<<G4endl;
|
||||
|
||||
// G4double daughtermass = daughters[0]->GetPDGMass();
|
||||
|
||||
//create parent G4DynamicParticle at rest
|
||||
G4ParticleMomentum dummy;
|
||||
G4DynamicParticle * parentparticle = new G4DynamicParticle(G4MT_parent, dummy, 0.0);
|
||||
|
||||
//create G4Decayproducts
|
||||
G4DecayProducts *products = new G4DecayProducts(*parentparticle);
|
||||
delete parentparticle;
|
||||
|
||||
//create daughter G4DynamicParticle at rest
|
||||
G4DynamicParticle * daughterparticle = new G4DynamicParticle(G4MT_daughters[0], dummy, 0.0);
|
||||
products->PushProducts(daughterparticle);
|
||||
|
||||
if (GetVerboseLevel()>1)
|
||||
{
|
||||
G4cout << "G4GeneralPhaseSpaceDecay::OneBodyDecayIt ";
|
||||
G4cout << " create decay products in rest frame " <<G4endl;
|
||||
products->DumpInfo();
|
||||
}
|
||||
return products;
|
||||
}
|
||||
|
||||
G4DecayProducts *G4GeneralPhaseSpaceDecay::TwoBodyDecayIt()
|
||||
{
|
||||
if (GetVerboseLevel()>1) G4cout << "G4GeneralPhaseSpaceDecay::TwoBodyDecayIt()"<<G4endl;
|
||||
|
||||
//daughters'mass
|
||||
G4double daughtermass[2];
|
||||
G4double daughtermomentum;
|
||||
if ( theDaughterMasses )
|
||||
{
|
||||
daughtermass[0]= *(theDaughterMasses);
|
||||
daughtermass[1] = *(theDaughterMasses+1);
|
||||
} else {
|
||||
daughtermass[0] = G4MT_daughters[0]->GetPDGMass();
|
||||
daughtermass[1] = G4MT_daughters[1]->GetPDGMass();
|
||||
}
|
||||
|
||||
// G4double sumofdaughtermass = daughtermass[0] + daughtermass[1];
|
||||
|
||||
//create parent G4DynamicParticle at rest
|
||||
G4ParticleMomentum dummy;
|
||||
G4DynamicParticle * parentparticle = new G4DynamicParticle( G4MT_parent, dummy, 0.0);
|
||||
|
||||
//create G4Decayproducts @@GF why dummy parentparticle?
|
||||
G4DecayProducts *products = new G4DecayProducts(*parentparticle);
|
||||
delete parentparticle;
|
||||
|
||||
//calculate daughter momentum
|
||||
daughtermomentum = Pmx(parentmass,daughtermass[0],daughtermass[1]);
|
||||
G4double costheta = 2.*G4UniformRand()-1.0;
|
||||
G4double sintheta = std::sqrt((1.0 - costheta)*(1.0 + costheta));
|
||||
G4double phi = twopi*G4UniformRand()*rad;
|
||||
G4ParticleMomentum direction(sintheta*std::cos(phi),sintheta*std::sin(phi),costheta);
|
||||
|
||||
//create daughter G4DynamicParticle
|
||||
G4double Etotal= std::sqrt(daughtermass[0]*daughtermass[0] + daughtermomentum*daughtermomentum);
|
||||
G4DynamicParticle * daughterparticle = new G4DynamicParticle( G4MT_daughters[0],Etotal, direction*daughtermomentum);
|
||||
products->PushProducts(daughterparticle);
|
||||
Etotal= std::sqrt(daughtermass[1]*daughtermass[1] + daughtermomentum*daughtermomentum);
|
||||
daughterparticle = new G4DynamicParticle( G4MT_daughters[1],Etotal, direction*(-1.0*daughtermomentum));
|
||||
products->PushProducts(daughterparticle);
|
||||
|
||||
if (GetVerboseLevel()>1)
|
||||
{
|
||||
G4cout << "G4GeneralPhaseSpaceDecay::TwoBodyDecayIt ";
|
||||
G4cout << " create decay products in rest frame " <<G4endl;
|
||||
products->DumpInfo();
|
||||
}
|
||||
return products;
|
||||
}
|
||||
|
||||
G4DecayProducts *G4GeneralPhaseSpaceDecay::ThreeBodyDecayIt()
|
||||
// algorism of this code is originally written in GDECA3 of GEANT3
|
||||
{
|
||||
if (GetVerboseLevel()>1) G4cout << "G4GeneralPhaseSpaceDecay::ThreeBodyDecayIt()"<<G4endl;
|
||||
|
||||
//daughters'mass
|
||||
G4double daughtermass[3];
|
||||
G4double sumofdaughtermass = 0.0;
|
||||
for (G4int index=0; index<3; index++)
|
||||
{
|
||||
if ( theDaughterMasses )
|
||||
{
|
||||
daughtermass[index]= *(theDaughterMasses+index);
|
||||
} else {
|
||||
daughtermass[index] = G4MT_daughters[index]->GetPDGMass();
|
||||
}
|
||||
sumofdaughtermass += daughtermass[index];
|
||||
}
|
||||
|
||||
//create parent G4DynamicParticle at rest
|
||||
G4ParticleMomentum dummy;
|
||||
G4DynamicParticle * parentparticle = new G4DynamicParticle( G4MT_parent, dummy, 0.0);
|
||||
|
||||
//create G4Decayproducts
|
||||
G4DecayProducts *products = new G4DecayProducts(*parentparticle);
|
||||
delete parentparticle;
|
||||
|
||||
//calculate daughter momentum
|
||||
// Generate two
|
||||
G4double rd1, rd2, rd;
|
||||
G4double daughtermomentum[3];
|
||||
G4double momentummax=0.0, momentumsum = 0.0;
|
||||
G4double energy;
|
||||
const G4int maxNumberOfLoops = 10000;
|
||||
G4int loopCounter = 0;
|
||||
|
||||
do
|
||||
{
|
||||
rd1 = G4UniformRand();
|
||||
rd2 = G4UniformRand();
|
||||
if (rd2 > rd1)
|
||||
{
|
||||
rd = rd1;
|
||||
rd1 = rd2;
|
||||
rd2 = rd;
|
||||
}
|
||||
momentummax = 0.0;
|
||||
momentumsum = 0.0;
|
||||
// daughter 0
|
||||
|
||||
energy = rd2*(parentmass - sumofdaughtermass);
|
||||
daughtermomentum[0] = std::sqrt(energy*energy + 2.0*energy* daughtermass[0]);
|
||||
if ( daughtermomentum[0] >momentummax )momentummax = daughtermomentum[0];
|
||||
momentumsum += daughtermomentum[0];
|
||||
|
||||
// daughter 1
|
||||
energy = (1.-rd1)*(parentmass - sumofdaughtermass);
|
||||
daughtermomentum[1] = std::sqrt(energy*energy + 2.0*energy* daughtermass[1]);
|
||||
if ( daughtermomentum[1] >momentummax )momentummax = daughtermomentum[1];
|
||||
momentumsum += daughtermomentum[1];
|
||||
|
||||
// daughter 2
|
||||
energy = (rd1-rd2)*(parentmass - sumofdaughtermass);
|
||||
daughtermomentum[2] = std::sqrt(energy*energy + 2.0*energy* daughtermass[2]);
|
||||
if ( daughtermomentum[2] >momentummax )momentummax = daughtermomentum[2];
|
||||
momentumsum += daughtermomentum[2];
|
||||
} while ( ( momentummax > momentumsum - momentummax ) && /* Loop checking, 02.11.2015, A.Ribon */
|
||||
++loopCounter < maxNumberOfLoops );
|
||||
if ( loopCounter >= maxNumberOfLoops ) {
|
||||
G4ExceptionDescription ed;
|
||||
ed << " Failed sampling after maxNumberOfLoops attempts : forced exit" << G4endl;
|
||||
G4Exception( " G4GeneralPhaseSpaceDecay::ThreeBodyDecayIt ", "HAD_PHASESPACE_001", FatalException, ed );
|
||||
}
|
||||
|
||||
// output message
|
||||
if (GetVerboseLevel()>1) {
|
||||
G4cout << " daughter 0:" << daughtermomentum[0]/GeV << "[GeV/c]" <<G4endl;
|
||||
G4cout << " daughter 1:" << daughtermomentum[1]/GeV << "[GeV/c]" <<G4endl;
|
||||
G4cout << " daughter 2:" << daughtermomentum[2]/GeV << "[GeV/c]" <<G4endl;
|
||||
G4cout << " momentum sum:" << momentumsum/GeV << "[GeV/c]" <<G4endl;
|
||||
}
|
||||
|
||||
//create daughter G4DynamicParticle
|
||||
G4double costheta, sintheta, phi, sinphi, cosphi;
|
||||
G4double costhetan, sinthetan, phin, sinphin, cosphin;
|
||||
costheta = 2.*G4UniformRand()-1.0;
|
||||
sintheta = std::sqrt((1.0-costheta)*(1.0+costheta));
|
||||
phi = twopi*G4UniformRand()*rad;
|
||||
sinphi = std::sin(phi);
|
||||
cosphi = std::cos(phi);
|
||||
G4ParticleMomentum direction0(sintheta*cosphi,sintheta*sinphi,costheta);
|
||||
G4double Etotal=std::sqrt( daughtermass[0]*daughtermass[0] + daughtermomentum[0]*daughtermomentum[0]);
|
||||
G4DynamicParticle * daughterparticle
|
||||
= new G4DynamicParticle( G4MT_daughters[0], Etotal, direction0*daughtermomentum[0]);
|
||||
products->PushProducts(daughterparticle);
|
||||
|
||||
costhetan = (daughtermomentum[1]*daughtermomentum[1]-daughtermomentum[2]*daughtermomentum[2]-daughtermomentum[0]*daughtermomentum[0])/(2.0*daughtermomentum[2]*daughtermomentum[0]);
|
||||
sinthetan = std::sqrt((1.0-costhetan)*(1.0+costhetan));
|
||||
phin = twopi*G4UniformRand()*rad;
|
||||
sinphin = std::sin(phin);
|
||||
cosphin = std::cos(phin);
|
||||
G4ParticleMomentum direction2;
|
||||
direction2.setX( sinthetan*cosphin*costheta*cosphi - sinthetan*sinphin*sinphi + costhetan*sintheta*cosphi);
|
||||
direction2.setY( sinthetan*cosphin*costheta*sinphi + sinthetan*sinphin*cosphi + costhetan*sintheta*sinphi);
|
||||
direction2.setZ( -sinthetan*cosphin*sintheta + costhetan*costheta);
|
||||
Etotal=std::sqrt( daughtermass[2]*daughtermass[2] + daughtermomentum[2]*daughtermomentum[2]/direction2.mag2());
|
||||
daughterparticle = new G4DynamicParticle( G4MT_daughters[2],Etotal, direction2*(daughtermomentum[2]/direction2.mag()));
|
||||
products->PushProducts(daughterparticle);
|
||||
G4ThreeVector mom=(direction0*daughtermomentum[0] + direction2*(daughtermomentum[2]/direction2.mag()))*(-1.0);
|
||||
Etotal= std::sqrt( daughtermass[1]*daughtermass[1] + mom.mag2() );
|
||||
daughterparticle =
|
||||
new G4DynamicParticle(G4MT_daughters[1], Etotal, mom);
|
||||
products->PushProducts(daughterparticle);
|
||||
|
||||
if (GetVerboseLevel()>1) {
|
||||
G4cout << "G4GeneralPhaseSpaceDecay::ThreeBodyDecayIt ";
|
||||
G4cout << " create decay products in rest frame " <<G4endl;
|
||||
products->DumpInfo();
|
||||
}
|
||||
return products;
|
||||
}
|
||||
|
||||
G4DecayProducts *G4GeneralPhaseSpaceDecay::ManyBodyDecayIt()
|
||||
// algorism of this code is originally written in FORTRAN by M.Asai
|
||||
//*****************************************************************
|
||||
// NBODY
|
||||
// N-body phase space Monte-Carlo generator
|
||||
// Makoto Asai
|
||||
// Hiroshima Institute of Technology
|
||||
// (asai@kekvax.kek.jp)
|
||||
// Revised release : 19/Apr/1995
|
||||
//
|
||||
{
|
||||
//return value
|
||||
G4DecayProducts *products;
|
||||
|
||||
if (GetVerboseLevel()>1) G4cout << "G4GeneralPhaseSpaceDecay::ManyBodyDecayIt()"<<G4endl;
|
||||
|
||||
//daughters'mass
|
||||
G4double *daughtermass = new G4double[numberOfDaughters];
|
||||
G4double sumofdaughtermass = 0.0;
|
||||
for (G4int index=0; index<numberOfDaughters; index++){
|
||||
daughtermass[index] = G4MT_daughters[index]->GetPDGMass();
|
||||
sumofdaughtermass += daughtermass[index];
|
||||
}
|
||||
|
||||
//Calculate daughter momentum
|
||||
G4double *daughtermomentum = new G4double[numberOfDaughters];
|
||||
G4ParticleMomentum direction;
|
||||
G4DynamicParticle **daughterparticle;
|
||||
G4double *sm = new G4double[numberOfDaughters];
|
||||
G4double tmas;
|
||||
G4double weight = 1.0;
|
||||
G4int numberOfTry = 0;
|
||||
G4int index1;
|
||||
|
||||
do {
|
||||
//Generate rundom number in descending order
|
||||
G4double temp;
|
||||
G4double *rd = new G4double[numberOfDaughters];
|
||||
rd[0] = 1.0;
|
||||
for(index1 =1; index1 < numberOfDaughters -1; index1++)
|
||||
rd[index1] = G4UniformRand();
|
||||
rd[ numberOfDaughters -1] = 0.0;
|
||||
for(index1 =1; index1 < numberOfDaughters -1; index1++) {
|
||||
for(G4int index2 = index1+1; index2 < numberOfDaughters; index2++) {
|
||||
if (rd[index1] < rd[index2]){
|
||||
temp = rd[index1];
|
||||
rd[index1] = rd[index2];
|
||||
rd[index2] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//calcurate virtual mass
|
||||
tmas = parentmass - sumofdaughtermass;
|
||||
temp = sumofdaughtermass;
|
||||
for(index1 =0; index1 < numberOfDaughters; index1++) {
|
||||
sm[index1] = rd[index1]*tmas + temp;
|
||||
temp -= daughtermass[index1];
|
||||
if (GetVerboseLevel()>1) {
|
||||
G4cout << index1 << " rundom number:" << rd[index1];
|
||||
G4cout << " virtual mass:" << sm[index1]/GeV << "[GeV/c/c]" <<G4endl;
|
||||
}
|
||||
}
|
||||
delete [] rd;
|
||||
|
||||
//Calculate daughter momentum
|
||||
weight = 1.0;
|
||||
index1 =numberOfDaughters-1;
|
||||
daughtermomentum[index1]= Pmx( sm[index1-1],daughtermass[index1-1],sm[index1]);
|
||||
if (GetVerboseLevel()>1) {
|
||||
G4cout << " daughter " << index1 << ":" << *daughters_name[index1];
|
||||
G4cout << " momentum:" << daughtermomentum[index1]/GeV << "[GeV/c]" <<G4endl;
|
||||
}
|
||||
for(index1 =numberOfDaughters-2; index1>=0; index1--) {
|
||||
// calculate
|
||||
daughtermomentum[index1]= Pmx( sm[index1],daughtermass[index1], sm[index1 +1]);
|
||||
if(daughtermomentum[index1] < 0.0) {
|
||||
// !!! illegal momentum !!!
|
||||
if (GetVerboseLevel()>0) {
|
||||
G4cout << "G4GeneralPhaseSpaceDecay::ManyBodyDecayIt ";
|
||||
G4cout << " can not calculate daughter momentum " <<G4endl;
|
||||
G4cout << " parent:" << *parent_name;
|
||||
G4cout << " mass:" << parentmass/GeV << "[GeV/c/c]" <<G4endl;
|
||||
G4cout << " daughter " << index1 << ":" << *daughters_name[index1];
|
||||
G4cout << " mass:" << daughtermass[index1]/GeV << "[GeV/c/c]" ;
|
||||
G4cout << " mass:" << daughtermomentum[index1]/GeV << "[GeV/c]" <<G4endl;
|
||||
}
|
||||
delete [] sm;
|
||||
delete [] daughtermass;
|
||||
delete [] daughtermomentum;
|
||||
return NULL; // Error detection
|
||||
|
||||
} else {
|
||||
// calculate weight of this events
|
||||
weight *= daughtermomentum[index1]/sm[index1];
|
||||
if (GetVerboseLevel()>1) {
|
||||
G4cout << " daughter " << index1 << ":" << *daughters_name[index1];
|
||||
G4cout << " momentum:" << daughtermomentum[index1]/GeV << "[GeV/c]" <<G4endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (GetVerboseLevel()>1) {
|
||||
G4cout << " weight: " << weight <<G4endl;
|
||||
}
|
||||
|
||||
// exit if number of Try exceeds 100
|
||||
if (numberOfTry++ >100) {
|
||||
if (GetVerboseLevel()>0) {
|
||||
G4cout << "G4GeneralPhaseSpaceDecay::ManyBodyDecayIt: ";
|
||||
G4cout << " can not determine Decay Kinematics " << G4endl;
|
||||
}
|
||||
delete [] sm;
|
||||
delete [] daughtermass;
|
||||
delete [] daughtermomentum;
|
||||
return NULL; // Error detection
|
||||
}
|
||||
} while ( weight > G4UniformRand()); /* Loop checking, 02.11.2015, A.Ribon */
|
||||
if (GetVerboseLevel()>1) {
|
||||
G4cout << "Start calculation of daughters momentum vector "<<G4endl;
|
||||
}
|
||||
|
||||
G4double costheta, sintheta, phi;
|
||||
G4double beta;
|
||||
daughterparticle = new G4DynamicParticle*[numberOfDaughters];
|
||||
|
||||
index1 = numberOfDaughters -2;
|
||||
costheta = 2.*G4UniformRand()-1.0;
|
||||
sintheta = std::sqrt((1.0-costheta)*(1.0+costheta));
|
||||
phi = twopi*G4UniformRand()*rad;
|
||||
direction.setZ(costheta);
|
||||
direction.setY(sintheta*std::sin(phi));
|
||||
direction.setX(sintheta*std::cos(phi));
|
||||
daughterparticle[index1] = new G4DynamicParticle( G4MT_daughters[index1], direction*daughtermomentum[index1] );
|
||||
daughterparticle[index1+1] = new G4DynamicParticle( G4MT_daughters[index1+1], direction*(-1.0*daughtermomentum[index1]) );
|
||||
|
||||
for (index1 = numberOfDaughters -3; index1 >= 0; index1--) {
|
||||
//calculate momentum direction
|
||||
costheta = 2.*G4UniformRand()-1.0;
|
||||
sintheta = std::sqrt((1.0-costheta)*(1.0+costheta));
|
||||
phi = twopi*G4UniformRand()*rad;
|
||||
direction.setZ(costheta);
|
||||
direction.setY(sintheta*std::sin(phi));
|
||||
direction.setX(sintheta*std::cos(phi));
|
||||
|
||||
// boost already created particles
|
||||
beta = daughtermomentum[index1];
|
||||
beta /= std::sqrt( daughtermomentum[index1]*daughtermomentum[index1] + sm[index1+1]*sm[index1+1] );
|
||||
for (G4int index2 = index1+1; index2<numberOfDaughters; index2++) {
|
||||
G4LorentzVector p4;
|
||||
// make G4LorentzVector for secondaries
|
||||
p4 = daughterparticle[index2]->Get4Momentum();
|
||||
|
||||
// boost secondaries to new frame
|
||||
p4.boost( direction.x()*beta, direction.y()*beta, direction.z()*beta);
|
||||
|
||||
// change energy/momentum
|
||||
daughterparticle[index2]->Set4Momentum(p4);
|
||||
}
|
||||
//create daughter G4DynamicParticle
|
||||
daughterparticle[index1]= new G4DynamicParticle( G4MT_daughters[index1], direction*(-1.0*daughtermomentum[index1]));
|
||||
}
|
||||
|
||||
//create G4Decayproducts
|
||||
G4DynamicParticle *parentparticle;
|
||||
direction.setX(1.0); direction.setY(0.0); direction.setZ(0.0);
|
||||
parentparticle = new G4DynamicParticle( G4MT_parent, direction, 0.0);
|
||||
products = new G4DecayProducts(*parentparticle);
|
||||
delete parentparticle;
|
||||
for (index1 = 0; index1<numberOfDaughters; index1++) {
|
||||
products->PushProducts(daughterparticle[index1]);
|
||||
}
|
||||
if (GetVerboseLevel()>1) {
|
||||
G4cout << "G4GeneralPhaseSpaceDecay::ManyBodyDecayIt ";
|
||||
G4cout << " create decay products in rest frame " << G4endl;
|
||||
products->DumpInfo();
|
||||
}
|
||||
|
||||
delete [] daughterparticle;
|
||||
delete [] daughtermomentum;
|
||||
delete [] daughtermass;
|
||||
delete [] sm;
|
||||
|
||||
return products;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// Multibody "phase space" generator, which provides multiple algorithms
|
||||
// for sampling. Momentum vectors are generated in the center-of-mass
|
||||
// frame of the decay, and returned in a user-supplied buffer. A sampling
|
||||
// algorithm is specified via constructor argument.
|
||||
//
|
||||
// Author: Michael Kelsey (SLAC) <kelsey@slac.stanford.edu>
|
||||
|
||||
#include "G4HadDecayGenerator.hh"
|
||||
#include "G4VHadDecayAlgorithm.hh"
|
||||
#include "G4HadPhaseSpaceKopylov.hh"
|
||||
#include "G4HadPhaseSpaceGenbod.hh"
|
||||
#include "G4HadPhaseSpaceNBodyAsai.hh"
|
||||
#include "G4HadronicException.hh"
|
||||
#include "G4LorentzVector.hh"
|
||||
#include "G4ParticleDefinition.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
#include "G4ThreeVector.hh"
|
||||
#include "Randomize.hh"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <iterator>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
// Constructors and destructor
|
||||
|
||||
G4HadDecayGenerator::G4HadDecayGenerator(Algorithm alg, G4int verbose)
|
||||
: verboseLevel(verbose), theAlgorithm(0) {
|
||||
switch (alg) {
|
||||
case Kopylov: theAlgorithm = new G4HadPhaseSpaceKopylov(verboseLevel); break;
|
||||
case GENBOD: theAlgorithm = new G4HadPhaseSpaceGenbod(verboseLevel); break;
|
||||
case NBody: theAlgorithm = new G4HadPhaseSpaceNBodyAsai(verboseLevel); break;
|
||||
case NONE: theAlgorithm = 0; break; // User may explicitly set no algorithm
|
||||
default: ReportInvalidAlgorithm(alg);
|
||||
}
|
||||
|
||||
if (verboseLevel) {
|
||||
G4cout << " >>> G4HadDecayGenerator";
|
||||
if (theAlgorithm) G4cout << " using " << theAlgorithm->GetName();
|
||||
G4cout << G4endl;
|
||||
}
|
||||
}
|
||||
|
||||
G4HadDecayGenerator::G4HadDecayGenerator(G4VHadDecayAlgorithm* alg,
|
||||
G4int verbose)
|
||||
: verboseLevel(verbose), theAlgorithm(alg) {
|
||||
if (verboseLevel) {
|
||||
G4cout << " >>> G4HadDecayGenerator";
|
||||
if (theAlgorithm) G4cout << " using " << theAlgorithm->GetName();
|
||||
G4cout << G4endl;
|
||||
}
|
||||
}
|
||||
|
||||
G4HadDecayGenerator::~G4HadDecayGenerator() {
|
||||
delete theAlgorithm;
|
||||
theAlgorithm = 0;
|
||||
}
|
||||
|
||||
|
||||
// Sanity checks -- throws exception if no algorithm chosen
|
||||
|
||||
void G4HadDecayGenerator::ReportInvalidAlgorithm(Algorithm alg) const {
|
||||
if (verboseLevel)
|
||||
G4cerr << "G4HadDecayGenerator: bad algorithm code " << alg << G4endl;
|
||||
|
||||
throw G4HadronicException(__FILE__, __LINE__, "Invalid algorithm code");
|
||||
}
|
||||
|
||||
void G4HadDecayGenerator::ReportMissingAlgorithm() const {
|
||||
if (verboseLevel)
|
||||
G4cerr << "G4HadDecayGenerator: no algorithm specified" << G4endl;
|
||||
|
||||
throw G4HadronicException(__FILE__, __LINE__, "Null algorithm pointer");
|
||||
}
|
||||
|
||||
|
||||
// Enable (or disable if 0) diagnostic messages
|
||||
void G4HadDecayGenerator::SetVerboseLevel(G4int verbose) {
|
||||
verboseLevel = verbose;
|
||||
if (theAlgorithm) theAlgorithm->SetVerboseLevel(verbose);
|
||||
}
|
||||
|
||||
const G4String& G4HadDecayGenerator::GetAlgorithmName() const {
|
||||
static const G4String& none = "NONE";
|
||||
return (theAlgorithm ? theAlgorithm->GetName() : none);
|
||||
}
|
||||
|
||||
|
||||
// Initial state (rest mass) and list of final masses
|
||||
|
||||
G4bool
|
||||
G4HadDecayGenerator::Generate(G4double initialMass,
|
||||
const std::vector<G4double>& masses,
|
||||
std::vector<G4LorentzVector>& finalState) {
|
||||
if (verboseLevel)
|
||||
G4cout << " >>> G4HadDecayGenerator::Generate (mass)" << G4endl;
|
||||
|
||||
if (!theAlgorithm) ReportMissingAlgorithm();
|
||||
|
||||
if (masses.size() == 1U)
|
||||
return GenerateOneBody(initialMass, masses, finalState);
|
||||
|
||||
theAlgorithm->Generate(initialMass, masses, finalState);
|
||||
return !finalState.empty(); // Generator failure returns empty state
|
||||
}
|
||||
|
||||
// Initial state particle and list of final masses
|
||||
|
||||
G4bool
|
||||
G4HadDecayGenerator::Generate(const G4ParticleDefinition* initialPD,
|
||||
const std::vector<G4double>& masses,
|
||||
std::vector<G4LorentzVector>& finalState) {
|
||||
if (verboseLevel)
|
||||
G4cout << " >>> G4HadDecayGenerator::Generate (particle)" << G4endl;
|
||||
|
||||
return (initialPD && Generate(initialPD->GetPDGMass(), masses, finalState));
|
||||
}
|
||||
|
||||
// Final state particles will be boosted to initial-state frame
|
||||
|
||||
G4bool
|
||||
G4HadDecayGenerator::Generate(const G4LorentzVector& initialState,
|
||||
const std::vector<G4double>& masses,
|
||||
std::vector<G4LorentzVector>& finalState) {
|
||||
if (verboseLevel)
|
||||
G4cout << " >>> G4HadDecayGenerator::Generate (frame)" << G4endl;
|
||||
|
||||
G4bool good = Generate(initialState.m(), masses, finalState);
|
||||
if (good) {
|
||||
G4ThreeVector bv = initialState.boostVector();
|
||||
for (size_t i=0; i<finalState.size(); i++) {
|
||||
finalState[i].boost(bv);
|
||||
}
|
||||
}
|
||||
|
||||
return good;
|
||||
}
|
||||
|
||||
|
||||
// Handle special case of "one body decay" (used for kaon mixing)
|
||||
|
||||
G4bool G4HadDecayGenerator::
|
||||
GenerateOneBody(G4double initialMass,
|
||||
const std::vector<G4double>& masses,
|
||||
std::vector<G4LorentzVector>& finalState) const {
|
||||
if (verboseLevel>1)
|
||||
G4cout << " >>> G4HadDecayGenerator::GenerateOneBody" << G4endl;
|
||||
|
||||
// Initialization and sanity checks
|
||||
finalState.clear();
|
||||
|
||||
if (masses.size() != 1U) return false; // Should not have been called
|
||||
if (std::fabs(initialMass-masses[0]) > eV) return false;
|
||||
|
||||
if (verboseLevel>2) G4cout << " finalState mass = " << masses[0] << G4endl;
|
||||
|
||||
finalState.push_back(G4LorentzVector(0.,0.,0.,masses[0]));
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// Multibody "phase space" generator using GENBOD (CERNLIB W515) method.
|
||||
//
|
||||
// Author: Michael Kelsey (SLAC) <kelsey@slac.stanford.edu>
|
||||
|
||||
#include "G4HadPhaseSpaceGenbod.hh"
|
||||
#include "G4LorentzVector.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4ThreeVector.hh"
|
||||
#include "Randomize.hh"
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace {
|
||||
// Wrap #define in a true function, for passing to std::fill
|
||||
G4double uniformRand() { return G4UniformRand(); }
|
||||
}
|
||||
|
||||
|
||||
// Constructor initializes everything to zero
|
||||
|
||||
G4HadPhaseSpaceGenbod::G4HadPhaseSpaceGenbod(G4int verbose)
|
||||
: G4VHadPhaseSpaceAlgorithm("G4HadPhaseSpaceGenbod",verbose),
|
||||
nFinal(0), totalMass(0.), massExcess(0.), weightMax(0.), nTrials(0) {;}
|
||||
|
||||
|
||||
// C++ re-implementation of GENBOD.F (Raubold-Lynch method)
|
||||
|
||||
void G4HadPhaseSpaceGenbod::
|
||||
GenerateMultiBody(G4double initialMass,
|
||||
const std::vector<G4double>& masses,
|
||||
std::vector<G4LorentzVector>& finalState) {
|
||||
if (GetVerboseLevel()) G4cout << GetName() << "::GenerateMultiBody" << G4endl;
|
||||
|
||||
finalState.clear();
|
||||
|
||||
Initialize(initialMass, masses);
|
||||
|
||||
const G4int maxNumberOfLoops = 10000;
|
||||
nTrials = 0;
|
||||
do { // Apply accept/reject to get distribution
|
||||
++nTrials;
|
||||
FillRandomBuffer();
|
||||
FillEnergySteps(initialMass, masses);
|
||||
} while ( (!AcceptEvent()) && nTrials < maxNumberOfLoops ); /* Loop checking, 02.11.2015, A.Ribon */
|
||||
if ( nTrials >= maxNumberOfLoops ) {
|
||||
G4ExceptionDescription ed;
|
||||
ed << " Failed sampling after maxNumberOfLoops attempts : forced exit" << G4endl;
|
||||
G4Exception( " G4HadPhaseSpaceGenbod::GenerateMultiBody ", "HAD_GENBOD_001", FatalException, ed );
|
||||
}
|
||||
GenerateMomenta(masses, finalState);
|
||||
}
|
||||
|
||||
void G4HadPhaseSpaceGenbod::
|
||||
Initialize(G4double initialMass, const std::vector<G4double>& masses) {
|
||||
if (GetVerboseLevel()>1) G4cout << GetName() << "::Initialize" << G4endl;
|
||||
|
||||
nFinal = masses.size();
|
||||
msum.resize(nFinal, 0.); // Initialize buffers for filling
|
||||
msq.resize(nFinal, 0.);
|
||||
|
||||
std::partial_sum(masses.begin(), masses.end(), msum.begin());
|
||||
std::transform(masses.begin(), masses.end(), masses.begin(), msq.begin(),
|
||||
std::multiplies<G4double>());
|
||||
totalMass = msum.back();
|
||||
massExcess = initialMass - totalMass;
|
||||
|
||||
if (GetVerboseLevel()>2) {
|
||||
PrintVector(msum, "msum", G4cout);
|
||||
PrintVector(msq, "msq", G4cout);
|
||||
G4cout << " totalMass " << totalMass << " massExcess " << massExcess
|
||||
<< G4endl;
|
||||
}
|
||||
|
||||
ComputeWeightScale(masses);
|
||||
}
|
||||
|
||||
|
||||
// Generate ordered list of random numbers
|
||||
|
||||
void G4HadPhaseSpaceGenbod::FillRandomBuffer() {
|
||||
if (GetVerboseLevel()>1) G4cout << GetName() << "::FillRandomBuffer" << G4endl;
|
||||
|
||||
rndm.resize(nFinal-2,0.); // Final states generated in sorted order
|
||||
std::generate(rndm.begin(), rndm.end(), uniformRand);
|
||||
std::sort(rndm.begin(), rndm.end());
|
||||
if (GetVerboseLevel()>2) PrintVector(rndm, "rndm", G4cout);
|
||||
}
|
||||
|
||||
|
||||
// Final state effective masses, min to max
|
||||
|
||||
void
|
||||
G4HadPhaseSpaceGenbod::FillEnergySteps(G4double initialMass,
|
||||
const std::vector<G4double>& masses) {
|
||||
if (GetVerboseLevel()>1) G4cout << GetName() << "::FillEnergySteps" << G4endl;
|
||||
|
||||
meff.clear();
|
||||
pd.clear();
|
||||
|
||||
meff.push_back(masses[0]);
|
||||
for (size_t i=1; i<nFinal-1; i++) {
|
||||
meff.push_back(rndm[i-1]*massExcess + msum[i]);
|
||||
pd.push_back(TwoBodyMomentum(meff[i], meff[i-1], masses[i]));
|
||||
}
|
||||
meff.push_back(initialMass);
|
||||
pd.push_back(TwoBodyMomentum(meff[nFinal-1], meff[nFinal-2], masses[nFinal-1]));
|
||||
|
||||
if (GetVerboseLevel()>2) {
|
||||
PrintVector(meff,"meff",G4cout);
|
||||
PrintVector(pd,"pd",G4cout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Maximum possible weight for final state (used with accept/reject)
|
||||
|
||||
void
|
||||
G4HadPhaseSpaceGenbod::ComputeWeightScale(const std::vector<G4double>& masses) {
|
||||
if (GetVerboseLevel()>1)
|
||||
G4cout << GetName() << "::ComputeWeightScale" << G4endl;
|
||||
|
||||
weightMax = 1.;
|
||||
for (size_t i=1; i<nFinal; i++) {
|
||||
weightMax *= TwoBodyMomentum(massExcess+msum[i], msum[i-1], masses[i]);
|
||||
}
|
||||
|
||||
if (GetVerboseLevel()>2) G4cout << " weightMax = " << weightMax << G4endl;
|
||||
}
|
||||
|
||||
|
||||
// Event weight computed as either constant or Fermi-dependent cross-section
|
||||
|
||||
G4double G4HadPhaseSpaceGenbod::ComputeWeight() const {
|
||||
if (GetVerboseLevel()>1) G4cout << GetName() << "::ComputeWeight" << G4endl;
|
||||
|
||||
return (std::accumulate(pd.begin(), pd.end(), 1./weightMax,
|
||||
std::multiplies<G4double>()));
|
||||
}
|
||||
|
||||
G4bool G4HadPhaseSpaceGenbod::AcceptEvent() const {
|
||||
if (GetVerboseLevel()>1)
|
||||
G4cout << GetName() << "::AcceptEvent? " << nTrials << G4endl;
|
||||
|
||||
return (G4UniformRand() <= ComputeWeight());
|
||||
}
|
||||
|
||||
|
||||
// Final state momentum vectors in CMS system, using Raubold-Lynch method
|
||||
|
||||
void G4HadPhaseSpaceGenbod::
|
||||
GenerateMomenta(const std::vector<G4double>& masses,
|
||||
std::vector<G4LorentzVector>& finalState) {
|
||||
if (GetVerboseLevel()>1) G4cout << GetName() << "::GenerateMomenta" << G4endl;
|
||||
|
||||
finalState.resize(nFinal); // Preallocate vectors for convenience below
|
||||
|
||||
for (size_t i=0; i<nFinal; i++) {
|
||||
AccumulateFinalState(i, masses, finalState);
|
||||
if (GetVerboseLevel()>2)
|
||||
G4cout << " finalState[" << i << "] " << finalState[i] << G4endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Process final state daughters up to current index
|
||||
|
||||
void G4HadPhaseSpaceGenbod::
|
||||
AccumulateFinalState(size_t i,
|
||||
const std::vector<G4double>& masses,
|
||||
std::vector<G4LorentzVector>& finalState) {
|
||||
if (GetVerboseLevel()>2)
|
||||
G4cout << GetName() << "::AccumulateFinalState " << i << G4endl;
|
||||
|
||||
if (i==0) { // First final state particle left alone
|
||||
finalState[i].setVectM(G4ThreeVector(0.,pd[i],0.),masses[i]);
|
||||
return;
|
||||
}
|
||||
|
||||
finalState[i].setVectM(G4ThreeVector(0.,-pd[i-1],0.),masses[i]);
|
||||
G4double phi = G4UniformRand() * twopi;
|
||||
G4double theta = std::acos(2.*G4UniformRand() - 1.);
|
||||
|
||||
if (GetVerboseLevel() > 2) {
|
||||
G4cout << " initialized Py " << -pd[i-1] << " phi " << phi
|
||||
<< " theta " << theta << G4endl;
|
||||
}
|
||||
|
||||
G4double esys=0.,beta=0.,gamma=1.;
|
||||
if (i < nFinal-1) { // Do not boost final particle
|
||||
esys = std::sqrt(pd[i]*pd[i]+meff[i]*meff[i]);
|
||||
beta = pd[i] / esys;
|
||||
gamma = esys / meff[i];
|
||||
|
||||
if (GetVerboseLevel()>2)
|
||||
G4cout << " esys " << esys << " beta " << beta << " gamma " << gamma
|
||||
<< G4endl;
|
||||
}
|
||||
|
||||
for (size_t j=0; j<=i; j++) { // Accumulate rotations
|
||||
finalState[j].rotateZ(theta).rotateY(phi);
|
||||
finalState[j].setY(gamma*(finalState[j].y() + beta*finalState[j].e()));
|
||||
if (GetVerboseLevel()>2) G4cout << " j " << j << " " << finalState[j] << G4endl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// Multibody "phase space" generator using Kopylov's algorithm
|
||||
//
|
||||
// Author: Michael Kelsey (SLAC) <kelsey@slac.stanford.edu>
|
||||
|
||||
#include "G4HadPhaseSpaceKopylov.hh"
|
||||
#include "G4LorentzVector.hh"
|
||||
#include "G4Pow.hh"
|
||||
#include "Randomize.hh"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
// Generator
|
||||
|
||||
void G4HadPhaseSpaceKopylov::
|
||||
GenerateMultiBody(G4double initialMass,
|
||||
const std::vector<G4double>& masses,
|
||||
std::vector<G4LorentzVector>& finalState) {
|
||||
if (GetVerboseLevel()) G4cout << GetName() << "::GenerateMultiBody" << G4endl;
|
||||
|
||||
finalState.clear();
|
||||
|
||||
size_t N = masses.size();
|
||||
finalState.resize(N);
|
||||
|
||||
G4double mtot = std::accumulate(masses.begin(), masses.end(), 0.0);
|
||||
G4double mu = mtot;
|
||||
G4double PFragMagCM = 0.0;
|
||||
G4double Mass = initialMass;
|
||||
G4double T = Mass-mtot;
|
||||
G4LorentzVector PFragCM(0.0,0.0,0.0,0.0);
|
||||
G4LorentzVector PRestCM(0.0,0.0,0.0,0.0);
|
||||
G4LorentzVector PRestLab(0.0,0.0,0.0,Mass);
|
||||
|
||||
for (size_t k=N-1; k>0; --k) {
|
||||
mu -= masses[k];
|
||||
T *= (k>1) ? BetaKopylov(k) : 0.;
|
||||
|
||||
G4double RestMass = mu + T;
|
||||
|
||||
PFragMagCM = TwoBodyMomentum(Mass,masses[k],RestMass);
|
||||
|
||||
// Create a unit vector with a random direction isotropically distributed
|
||||
G4ThreeVector RandVector = UniformVector(PFragMagCM);
|
||||
|
||||
PFragCM.setVectM(RandVector,masses[k]);
|
||||
PRestCM.setVectM(-RandVector,RestMass);
|
||||
|
||||
G4ThreeVector BoostV = PRestLab.boostVector();
|
||||
|
||||
PFragCM.boost(BoostV);
|
||||
PRestCM.boost(BoostV);
|
||||
PRestLab = PRestCM;
|
||||
Mass = RestMass;
|
||||
finalState[k] = PFragCM;
|
||||
}
|
||||
|
||||
finalState[0] = PRestLab;
|
||||
}
|
||||
|
||||
|
||||
// Generate scale factor for final state particle
|
||||
|
||||
G4double G4HadPhaseSpaceKopylov::BetaKopylov(G4int K) const {
|
||||
G4Pow* g4pow = G4Pow::GetInstance();
|
||||
|
||||
G4int N = 3*K - 5;
|
||||
G4double xN = G4double(N);
|
||||
G4double Fmax = std::sqrt(g4pow->powN(xN/(xN+1.),N)/(xN+1.));
|
||||
|
||||
G4double F, chi;
|
||||
const G4int maxNumberOfLoops = 10000;
|
||||
G4int loopCounter = 0;
|
||||
do {
|
||||
chi = G4UniformRand();
|
||||
F = std::sqrt(g4pow->powN(chi,N)*(1.-chi));
|
||||
} while ( ( Fmax*G4UniformRand() > F ) && ++loopCounter < maxNumberOfLoops ); /* Loop checking, 02.11.2015, A.Ribon */
|
||||
if ( loopCounter >= maxNumberOfLoops ) {
|
||||
G4ExceptionDescription ed;
|
||||
ed << " Failed sampling after maxNumberOfLoops attempts : forced exit" << G4endl;
|
||||
G4Exception( " G4HadPhaseSpaceKopylov::BetaKopylov ", "HAD_KOPYLOV_001", JustWarning, ed );
|
||||
}
|
||||
|
||||
return chi;
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// Multibody "phase space" generator using Makoto Asai's NBody method.
|
||||
//
|
||||
// Author: Michael Kelsey (SLAC) <kelsey@slac.stanford.edu>
|
||||
|
||||
#include "G4HadPhaseSpaceNBodyAsai.hh"
|
||||
#include "G4LorentzVector.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
#include "G4ThreeVector.hh"
|
||||
#include "Randomize.hh"
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace {
|
||||
// This wraps the existing #define in a true function
|
||||
G4double uniformRand() { return G4UniformRand(); }
|
||||
}
|
||||
|
||||
|
||||
void G4HadPhaseSpaceNBodyAsai::
|
||||
GenerateMultiBody(G4double initialMass,
|
||||
const std::vector<G4double>& masses,
|
||||
std::vector<G4LorentzVector>& finalState) {
|
||||
if (GetVerboseLevel()) G4cout << GetName() << "::GenerateMultiBody" << G4endl;
|
||||
|
||||
finalState.clear();
|
||||
|
||||
//daughters' mass
|
||||
G4int numberOfDaughters = masses.size();
|
||||
G4double sumofmasses =
|
||||
std::accumulate(masses.begin(), masses.end(), 0.);
|
||||
|
||||
//Calculate daughter momentum
|
||||
std::vector<G4double> daughtermomentum(numberOfDaughters);
|
||||
std::vector<G4double> sm(numberOfDaughters);
|
||||
G4double tmas;
|
||||
G4double weight = 1.0;
|
||||
G4int numberOfTry = 0;
|
||||
G4int i;
|
||||
|
||||
std::vector<G4double> rd(numberOfDaughters);
|
||||
do {
|
||||
//Generate random number in descending order
|
||||
rd[0] = 1.0;
|
||||
std::generate(rd.begin()+1, rd.end(), uniformRand);
|
||||
std::sort(rd.begin(), rd.end(), std::greater<G4double>());
|
||||
|
||||
if (GetVerboseLevel()>1) PrintVector(rd,"rd",G4cout);
|
||||
|
||||
//calcurate virtual mass
|
||||
tmas = initialMass - sumofmasses;
|
||||
G4double temp = sumofmasses;
|
||||
for(i =0; i < numberOfDaughters; i++) {
|
||||
sm[i] = rd[i]*tmas + temp;
|
||||
temp -= masses[i];
|
||||
if (GetVerboseLevel()>1) {
|
||||
G4cout << i << " random number:" << rd[i]
|
||||
<< " virtual mass:" << sm[i]/GeV << " GeV/c2" <<G4endl;
|
||||
}
|
||||
}
|
||||
|
||||
//Calculate daughter momentum
|
||||
weight = 1.0;
|
||||
i = numberOfDaughters-1;
|
||||
daughtermomentum[i] = TwoBodyMomentum(sm[i-1],masses[i-1],sm[i]);
|
||||
if (GetVerboseLevel()>1) {
|
||||
G4cout << " daughter " << i << ": momentum "
|
||||
<< daughtermomentum[i]/GeV << " GeV/c" <<G4endl;
|
||||
}
|
||||
for(i =numberOfDaughters-2; i>=0; i--) {
|
||||
// calculate
|
||||
daughtermomentum[i] = TwoBodyMomentum(sm[i],masses[i],sm[i+1]);
|
||||
if(daughtermomentum[i] < 0.0) {
|
||||
// !!! illegal momentum !!!
|
||||
if (GetVerboseLevel()>0) {
|
||||
G4cout << "G4HadPhaseSpaceNBodyAsai::Generate "
|
||||
<< " can not calculate daughter momentum "
|
||||
<< "\n initialMass " << initialMass/GeV << " GeV/c2"
|
||||
<< "\n daughter " << i << ": mass "
|
||||
<< masses[i]/GeV << " GeV/c2; momentum "
|
||||
<< daughtermomentum[i]/GeV << " GeV/c" << G4endl;
|
||||
}
|
||||
return; // Error detection
|
||||
}
|
||||
|
||||
// calculate weight of this events
|
||||
weight *= daughtermomentum[i]/sm[i];
|
||||
if (GetVerboseLevel()>1) {
|
||||
G4cout << " daughter " << i << ": momentum "
|
||||
<< daughtermomentum[i]/GeV << " GeV/c" <<G4endl;
|
||||
}
|
||||
}
|
||||
if (GetVerboseLevel()>1) {
|
||||
G4cout << " weight: " << weight <<G4endl;
|
||||
}
|
||||
|
||||
// exit if number of Try exceeds 100
|
||||
if (numberOfTry++ > 100) {
|
||||
if (GetVerboseLevel()>0) {
|
||||
G4cout << "G4HadPhaseSpaceNBodyAsai::Generate "
|
||||
<< " can not determine Decay Kinematics " << G4endl;
|
||||
}
|
||||
return; // Error detection
|
||||
}
|
||||
} while (weight > G4UniformRand()); /* Loop checking, 02.11.2015, A.Ribon */
|
||||
|
||||
if (GetVerboseLevel()>1) {
|
||||
G4cout << "Start calculation of daughters momentum vector "<<G4endl;
|
||||
}
|
||||
|
||||
G4double beta;
|
||||
|
||||
finalState.resize(numberOfDaughters);
|
||||
|
||||
i = numberOfDaughters-2;
|
||||
|
||||
G4ThreeVector direction = UniformVector(daughtermomentum[i]);
|
||||
|
||||
finalState[i].setVectM(direction, masses[i]);
|
||||
finalState[i+1].setVectM(-direction, masses[i+1]);
|
||||
|
||||
for (i = numberOfDaughters-3; i >= 0; i--) {
|
||||
direction = UniformVector();
|
||||
|
||||
//create daughter particle
|
||||
finalState[i].setVectM(-daughtermomentum[i]*direction, masses[i]);
|
||||
|
||||
// boost already created particles
|
||||
beta = daughtermomentum[i];
|
||||
beta /= std::sqrt(beta*beta + sm[i+1]*sm[i+1]);
|
||||
for (G4int j = i+1; j<numberOfDaughters; j++) {
|
||||
finalState[j].boost(beta*direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,846 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// GEANT 4 class implementation file
|
||||
//
|
||||
// History: first implementation, A. Feliciello, 20th May 1998
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include "globals.hh"
|
||||
#include "G4ios.hh"
|
||||
//#include <cmath>
|
||||
|
||||
#include "Randomize.hh"
|
||||
#include "G4SimpleIntegration.hh"
|
||||
#include "G4ThreeVector.hh"
|
||||
#include "G4LorentzVector.hh"
|
||||
#include "G4KineticTrack.hh"
|
||||
#include "G4KineticTrackVector.hh"
|
||||
#include "G4ParticleDefinition.hh"
|
||||
#include "G4DecayTable.hh"
|
||||
#include "G4GeneralPhaseSpaceDecay.hh"
|
||||
#include "G4DecayProducts.hh"
|
||||
#include "G4LorentzRotation.hh"
|
||||
#include "G4SampleResonance.hh"
|
||||
#include "G4Integrator.hh"
|
||||
#include "G4KaonZero.hh"
|
||||
#include "G4KaonZeroShort.hh"
|
||||
#include "G4KaonZeroLong.hh"
|
||||
#include "G4AntiKaonZero.hh"
|
||||
|
||||
#include "G4HadTmpUtil.hh"
|
||||
|
||||
//
|
||||
// Some static clobal for integration
|
||||
//
|
||||
|
||||
static G4ThreadLocal G4double G4KineticTrack_Gmass, G4KineticTrack_xmass1;
|
||||
|
||||
//
|
||||
// Default constructor
|
||||
//
|
||||
|
||||
G4KineticTrack::G4KineticTrack() :
|
||||
theDefinition(0),
|
||||
theFormationTime(0),
|
||||
thePosition(0),
|
||||
the4Momentum(0),
|
||||
theFermi3Momentum(0),
|
||||
theTotal4Momentum(0),
|
||||
theNucleon(0),
|
||||
nChannels(0),
|
||||
theActualMass(0),
|
||||
theActualWidth(0),
|
||||
theDaughterMass(0),
|
||||
theDaughterWidth(0),
|
||||
theStateToNucleus(undefined),
|
||||
theProjectilePotential(0)
|
||||
{
|
||||
////////////////
|
||||
// DEBUG //
|
||||
////////////////
|
||||
|
||||
/*
|
||||
G4cerr << G4endl << G4endl << G4endl;
|
||||
G4cerr << " G4KineticTrack default constructor invoked! \n";
|
||||
G4cerr << " =========================================== \n" << G4endl;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Copy constructor
|
||||
//
|
||||
|
||||
G4KineticTrack::G4KineticTrack(const G4KineticTrack &right) : G4VKineticNucleon()
|
||||
{
|
||||
theDefinition = right.GetDefinition();
|
||||
theFormationTime = right.GetFormationTime();
|
||||
thePosition = right.GetPosition();
|
||||
the4Momentum = right.GetTrackingMomentum();
|
||||
theFermi3Momentum = right.theFermi3Momentum;
|
||||
theTotal4Momentum = right.theTotal4Momentum;
|
||||
theNucleon=right.theNucleon;
|
||||
nChannels = right.GetnChannels();
|
||||
theActualMass = right.GetActualMass();
|
||||
theActualWidth = new G4double[nChannels];
|
||||
for (G4int i = 0; i < nChannels; i++)
|
||||
{
|
||||
theActualWidth[i] = right.theActualWidth[i];
|
||||
}
|
||||
theDaughterMass = 0;
|
||||
theDaughterWidth = 0;
|
||||
theStateToNucleus=right.theStateToNucleus;
|
||||
theProjectilePotential=right.theProjectilePotential;
|
||||
|
||||
////////////////
|
||||
// DEBUG //
|
||||
////////////////
|
||||
|
||||
/*
|
||||
G4cerr << G4endl << G4endl << G4endl;
|
||||
G4cerr << " G4KineticTrack copy constructor invoked! \n";
|
||||
G4cerr << " ======================================== \n" <<G4endl;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// By argument constructor
|
||||
//
|
||||
|
||||
G4KineticTrack::G4KineticTrack(const G4ParticleDefinition* aDefinition,
|
||||
G4double aFormationTime,
|
||||
const G4ThreeVector& aPosition,
|
||||
const G4LorentzVector& a4Momentum) :
|
||||
theDefinition(aDefinition),
|
||||
theFormationTime(aFormationTime),
|
||||
thePosition(aPosition),
|
||||
the4Momentum(a4Momentum),
|
||||
theFermi3Momentum(0),
|
||||
theTotal4Momentum(a4Momentum),
|
||||
theNucleon(0),
|
||||
theStateToNucleus(undefined),
|
||||
theProjectilePotential(0)
|
||||
{
|
||||
if(G4KaonZero::KaonZero() == theDefinition ||
|
||||
G4AntiKaonZero::AntiKaonZero() == theDefinition)
|
||||
{
|
||||
if(G4UniformRand()<0.5)
|
||||
{
|
||||
theDefinition = G4KaonZeroShort::KaonZeroShort();
|
||||
}
|
||||
else
|
||||
{
|
||||
theDefinition = G4KaonZeroLong::KaonZeroLong();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Get the number of decay channels
|
||||
//
|
||||
|
||||
G4DecayTable* theDecayTable = theDefinition->GetDecayTable();
|
||||
if (theDecayTable != 0)
|
||||
{
|
||||
nChannels = theDecayTable->entries();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
nChannels = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the actual mass value
|
||||
//
|
||||
|
||||
theActualMass = GetActualMass();
|
||||
|
||||
//
|
||||
// Create an array to Store the actual partial widths
|
||||
// of the decay channels
|
||||
//
|
||||
|
||||
theDaughterMass = 0;
|
||||
theDaughterWidth = 0;
|
||||
theActualWidth = 0;
|
||||
G4bool * theDaughterIsShortLived = 0;
|
||||
|
||||
if(nChannels!=0) theActualWidth = new G4double[nChannels];
|
||||
|
||||
// cout << " ****CONSTR*** ActualMass ******* " << theActualMass << G4endl;
|
||||
G4int index;
|
||||
for (index = nChannels - 1; index >= 0; --index)
|
||||
{
|
||||
G4VDecayChannel* theChannel = theDecayTable->GetDecayChannel(index);
|
||||
G4int nDaughters = theChannel->GetNumberOfDaughters();
|
||||
G4double theMotherWidth;
|
||||
if (nDaughters == 2 || nDaughters == 3)
|
||||
{
|
||||
G4double thePoleMass = theDefinition->GetPDGMass();
|
||||
theMotherWidth = theDefinition->GetPDGWidth();
|
||||
G4double thePoleWidth = theChannel->GetBR()*theMotherWidth;
|
||||
const G4ParticleDefinition* aDaughter;
|
||||
theDaughterMass = new G4double[nDaughters];
|
||||
theDaughterWidth = new G4double[nDaughters];
|
||||
theDaughterIsShortLived = new G4bool[nDaughters];
|
||||
for (G4int n = 0; n < nDaughters; ++n)
|
||||
{
|
||||
aDaughter = theChannel->GetDaughter(n);
|
||||
theDaughterMass[n] = aDaughter->GetPDGMass();
|
||||
theDaughterWidth[n] = aDaughter->GetPDGWidth();
|
||||
theDaughterIsShortLived[n] = aDaughter->IsShortLived();
|
||||
}
|
||||
|
||||
//
|
||||
// Check whether both the decay products are stable
|
||||
//
|
||||
|
||||
G4double theActualMom = 0.0;
|
||||
G4double thePoleMom = 0.0;
|
||||
G4SampleResonance aSampler;
|
||||
if (nDaughters==2)
|
||||
{
|
||||
if ( !theDaughterIsShortLived[0] && !theDaughterIsShortLived[1] )
|
||||
{
|
||||
|
||||
// G4cout << G4endl << "Both the " << nDaughters <<
|
||||
// " decay products are stable!";
|
||||
// cout << " LB: Both decay products STABLE !" << G4endl;
|
||||
// cout << " parent: " << theChannel->GetParentName() << G4endl;
|
||||
// cout << " particle1: " << theChannel->GetDaughterName(0) << G4endl;
|
||||
// cout << " particle2: " << theChannel->GetDaughterName(1) << G4endl;
|
||||
|
||||
theActualMom = EvaluateCMMomentum(theActualMass,
|
||||
theDaughterMass);
|
||||
thePoleMom = EvaluateCMMomentum(thePoleMass,
|
||||
theDaughterMass);
|
||||
// cout << G4endl;
|
||||
// cout << " LB: ActualMass/DaughterMass " << theActualMass << " " << theDaughterMass << G4endl;
|
||||
// cout << " LB: ActualMom " << theActualMom << G4endl;
|
||||
// cout << " LB: PoleMom " << thePoleMom << G4endl;
|
||||
// cout << G4endl;
|
||||
}
|
||||
else if ( !theDaughterIsShortLived[0] && theDaughterIsShortLived[1] )
|
||||
{
|
||||
|
||||
// G4cout << G4endl << "Only the first of the " << nDaughters <<" decay products is stable!";
|
||||
// cout << " LB: only the first decay product is STABLE !" << G4endl;
|
||||
// cout << " parent: " << theChannel->GetParentName() << G4endl;
|
||||
// cout << " particle1: " << theChannel->GetDaughterName(0) << G4endl;
|
||||
// cout << " particle2: " << theChannel->GetDaughterName(1) << G4endl;
|
||||
|
||||
// global variable definition
|
||||
G4double lowerLimit = aSampler.GetMinimumMass(theChannel->GetDaughter(1));
|
||||
theActualMom = IntegrateCMMomentum(lowerLimit);
|
||||
thePoleMom = IntegrateCMMomentum(lowerLimit, thePoleMass);
|
||||
// cout << " LB Parent Mass = " << G4KineticTrack_Gmass << G4endl;
|
||||
// cout << " LB Actual Mass = " << theActualMass << G4endl;
|
||||
// cout << " LB Daughter1 Mass = " << G4KineticTrack_Gmass1 << G4endl;
|
||||
// cout << " LB Daughter2 Mass = " << G4KineticTrack_Gmass2 << G4endl;
|
||||
// cout << " The Actual Momentum = " << theActualMom << G4endl;
|
||||
// cout << " The Pole Momentum = " << thePoleMom << G4endl;
|
||||
// cout << G4endl;
|
||||
|
||||
}
|
||||
else if ( theDaughterIsShortLived[0] && !theDaughterIsShortLived[1] )
|
||||
{
|
||||
|
||||
// G4cout << G4endl << "Only the second of the " << nDaughters <<
|
||||
// " decay products is stable!";
|
||||
// cout << " LB: only the second decay product is STABLE !" << G4endl;
|
||||
// cout << " parent: " << theChannel->GetParentName() << G4endl;
|
||||
// cout << " particle1: " << theChannel->GetDaughterName(0) << G4endl;
|
||||
// cout << " particle2: " << theChannel->GetDaughterName(1) << G4endl;
|
||||
|
||||
//
|
||||
// Swap the content of the theDaughterMass and theDaughterWidth arrays!!!
|
||||
//
|
||||
|
||||
G4SwapObj(theDaughterMass, theDaughterMass + 1);
|
||||
G4SwapObj(theDaughterWidth, theDaughterWidth + 1);
|
||||
|
||||
// global variable definition
|
||||
G4double lowerLimit = aSampler.GetMinimumMass(theChannel->GetDaughter(0));
|
||||
theActualMom = IntegrateCMMomentum(lowerLimit);
|
||||
thePoleMom = IntegrateCMMomentum(lowerLimit, thePoleMass);
|
||||
// cout << " LB Parent Mass = " << G4KineticTrack_Gmass << G4endl;
|
||||
// cout << " LB Actual Mass = " << theActualMass << G4endl;
|
||||
// cout << " LB Daughter1 Mass = " << G4KineticTrack_Gmass1 << G4endl;
|
||||
// cout << " LB Daughter2 Mass = " << G4KineticTrack_Gmass2 << G4endl;
|
||||
// cout << " The Actual Momentum = " << theActualMom << G4endl;
|
||||
// cout << " The Pole Momentum = " << thePoleMom << G4endl;
|
||||
// cout << G4endl;
|
||||
|
||||
}
|
||||
else if ( theDaughterIsShortLived[0] && theDaughterIsShortLived[1] )
|
||||
{
|
||||
|
||||
// G4cout << G4endl << "Both the " << nDaughters <<
|
||||
// " decay products are resonances!";
|
||||
// cout << " LB: both decay products are RESONANCES !" << G4endl;
|
||||
// cout << " parent: " << theChannel->GetParentName() << G4endl;
|
||||
// cout << " particle1: " << theChannel->GetDaughterName(0) << G4endl;
|
||||
// cout << " particle2: " << theChannel->GetDaughterName(1) << G4endl;
|
||||
|
||||
// global variable definition
|
||||
G4KineticTrack_Gmass = theActualMass;
|
||||
theActualMom = IntegrateCMMomentum2();
|
||||
G4KineticTrack_Gmass = thePoleMass;
|
||||
thePoleMom = IntegrateCMMomentum2();
|
||||
// cout << " LB Parent Mass = " << G4KineticTrack_Gmass << G4endl;
|
||||
// cout << " LB Daughter1 Mass = " << G4KineticTrack_Gmass1 << G4endl;
|
||||
// cout << " LB Daughter2 Mass = " << G4KineticTrack_Gmass2 << G4endl;
|
||||
// cout << " The Actual Momentum = " << theActualMom << G4endl;
|
||||
// cout << " The Pole Momentum = " << thePoleMom << G4endl;
|
||||
// cout << G4endl;
|
||||
|
||||
}
|
||||
}
|
||||
else // (nDaughter==3)
|
||||
{
|
||||
|
||||
G4int nShortLived = 0;
|
||||
if ( theDaughterIsShortLived[0] )
|
||||
{
|
||||
++nShortLived;
|
||||
}
|
||||
if ( theDaughterIsShortLived[1] )
|
||||
{
|
||||
++nShortLived;
|
||||
G4SwapObj(theDaughterMass, theDaughterMass + 1);
|
||||
G4SwapObj(theDaughterWidth, theDaughterWidth + 1);
|
||||
}
|
||||
if ( theDaughterIsShortLived[2] )
|
||||
{
|
||||
++nShortLived;
|
||||
G4SwapObj(theDaughterMass, theDaughterMass + 2);
|
||||
G4SwapObj(theDaughterWidth, theDaughterWidth + 2);
|
||||
}
|
||||
if ( nShortLived == 0 )
|
||||
{
|
||||
theDaughterMass[1]+=theDaughterMass[2];
|
||||
theActualMom = EvaluateCMMomentum(theActualMass,
|
||||
theDaughterMass);
|
||||
thePoleMom = EvaluateCMMomentum(thePoleMass,
|
||||
theDaughterMass);
|
||||
}
|
||||
// else if ( nShortLived == 1 )
|
||||
else if ( nShortLived >= 1 )
|
||||
{
|
||||
// need the shortlived particle in slot 1! (very bad style...)
|
||||
G4SwapObj(theDaughterMass, theDaughterMass + 1);
|
||||
G4SwapObj(theDaughterWidth, theDaughterWidth + 1);
|
||||
theDaughterMass[0] += theDaughterMass[2];
|
||||
theActualMom = IntegrateCMMomentum(0.0);
|
||||
thePoleMom = IntegrateCMMomentum(0.0, thePoleMass);
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// throw G4HadronicException(__FILE__, __LINE__, ("can't handle more than one shortlived in 3 particle output channel");
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
//if(nDaughters<3) theChannel->GetAngularMomentum();
|
||||
G4double theMassRatio = thePoleMass / theActualMass;
|
||||
G4double theMomRatio = theActualMom / thePoleMom;
|
||||
// VI 11.06.2015: for l=0 one not need use pow
|
||||
//G4double l=0;
|
||||
//theActualWidth[index] = thePoleWidth * theMassRatio *
|
||||
// std::pow(theMomRatio, (2 * l + 1)) *
|
||||
// (1.2 / (1+ 0.2*std::pow(theMomRatio, (2 * l))));
|
||||
theActualWidth[index] = thePoleWidth * theMassRatio *
|
||||
theMomRatio;
|
||||
delete [] theDaughterMass;
|
||||
theDaughterMass = 0;
|
||||
delete [] theDaughterWidth;
|
||||
theDaughterWidth = 0;
|
||||
delete [] theDaughterIsShortLived;
|
||||
theDaughterIsShortLived = 0;
|
||||
}
|
||||
|
||||
else // nDaughter = 1 ( e.g. K0 decays 50% to Kshort, 50% Klong
|
||||
{
|
||||
theMotherWidth = theDefinition->GetPDGWidth();
|
||||
theActualWidth[index] = theChannel->GetBR()*theMotherWidth;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////
|
||||
// DEBUG //
|
||||
////////////////
|
||||
|
||||
// for (G4int y = nChannels - 1; y >= 0; --y)
|
||||
// {
|
||||
// G4cout << G4endl << theActualWidth[y];
|
||||
// }
|
||||
// G4cout << G4endl << G4endl << G4endl;
|
||||
|
||||
/*
|
||||
G4cerr << G4endl << G4endl << G4endl;
|
||||
G4cerr << " G4KineticTrack by argument constructor invoked! \n";
|
||||
G4cerr << " =============================================== \n" << G4endl;
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
G4KineticTrack::G4KineticTrack(G4Nucleon * nucleon,
|
||||
const G4ThreeVector& aPosition,
|
||||
const G4LorentzVector& a4Momentum)
|
||||
: theDefinition(nucleon->GetDefinition()),
|
||||
theFormationTime(0),
|
||||
thePosition(aPosition),
|
||||
the4Momentum(a4Momentum),
|
||||
theFermi3Momentum(nucleon->GetMomentum()),
|
||||
theNucleon(nucleon),
|
||||
nChannels(0),
|
||||
theActualMass(nucleon->GetDefinition()->GetPDGMass()),
|
||||
theActualWidth(0),
|
||||
theDaughterMass(0),
|
||||
theDaughterWidth(0),
|
||||
theStateToNucleus(undefined),
|
||||
theProjectilePotential(0)
|
||||
{
|
||||
theFermi3Momentum.setE(0);
|
||||
Set4Momentum(a4Momentum);
|
||||
}
|
||||
|
||||
|
||||
G4KineticTrack::~G4KineticTrack()
|
||||
{
|
||||
if (theActualWidth != 0) delete [] theActualWidth;
|
||||
if (theDaughterMass != 0) delete [] theDaughterMass;
|
||||
if (theDaughterWidth != 0) delete [] theDaughterWidth;
|
||||
}
|
||||
|
||||
|
||||
|
||||
G4KineticTrack& G4KineticTrack::operator=(const G4KineticTrack& right)
|
||||
{
|
||||
if (this != &right)
|
||||
{
|
||||
theDefinition = right.GetDefinition();
|
||||
theFormationTime = right.GetFormationTime();
|
||||
the4Momentum = right.the4Momentum;
|
||||
the4Momentum = right.GetTrackingMomentum();
|
||||
theFermi3Momentum = right.theFermi3Momentum;
|
||||
theTotal4Momentum = right.theTotal4Momentum;
|
||||
theNucleon=right.theNucleon;
|
||||
theStateToNucleus=right.theStateToNucleus;
|
||||
if (theActualWidth != 0) delete [] theActualWidth;
|
||||
nChannels = right.GetnChannels();
|
||||
theActualWidth = new G4double[nChannels];
|
||||
for (G4int i = 0; i < nChannels; ++i) theActualWidth[i] = right.theActualWidth[i];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
G4bool G4KineticTrack::operator==(const G4KineticTrack& right) const
|
||||
{
|
||||
return (this == & right);
|
||||
}
|
||||
|
||||
|
||||
|
||||
G4bool G4KineticTrack::operator!=(const G4KineticTrack& right) const
|
||||
{
|
||||
return (this != & right);
|
||||
}
|
||||
|
||||
|
||||
|
||||
G4KineticTrackVector* G4KineticTrack::Decay()
|
||||
{
|
||||
//
|
||||
// Select a possible decay channel
|
||||
//
|
||||
/*
|
||||
G4int index1;
|
||||
for (index1 = nChannels - 1; index1 >= 0; --index1)
|
||||
G4cout << "DECAY Actual Width IND/ActualW " << index1 << " " << theActualWidth[index1] << G4endl;
|
||||
G4cout << "DECAY Actual Mass " << theActualMass << G4endl;
|
||||
*/
|
||||
const G4ParticleDefinition* thisDefinition = this->GetDefinition();
|
||||
if(!thisDefinition)
|
||||
{
|
||||
G4cerr << "Error condition encountered in G4KineticTrack::Decay()"<<G4endl;
|
||||
G4cerr << " track has no particle definition associated."<<G4endl;
|
||||
return 0;
|
||||
}
|
||||
G4DecayTable* theDecayTable = thisDefinition->GetDecayTable();
|
||||
if(!theDecayTable)
|
||||
{
|
||||
G4cerr << "Error condition encountered in G4KineticTrack::Decay()"<<G4endl;
|
||||
G4cerr << " particle definition has no decay table associated."<<G4endl;
|
||||
G4cerr << " particle was "<<thisDefinition->GetParticleName()<<G4endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
G4int chargeBalance = G4lrint(theDefinition->GetPDGCharge() );
|
||||
G4int baryonBalance = G4lrint(theDefinition->GetBaryonNumber() );
|
||||
G4LorentzVector energyMomentumBalance(Get4Momentum());
|
||||
G4double theTotalActualWidth = this->EvaluateTotalActualWidth();
|
||||
if (theTotalActualWidth !=0)
|
||||
{
|
||||
|
||||
//AR-16Aug2016 : Repeat the sampling of the decay channel until is
|
||||
// kinematically above threshold or a max number of attempts is reached
|
||||
G4bool isChannelBelowThreshold = true;
|
||||
const G4int maxNumberOfLoops = 10000;
|
||||
G4int loopCounter = 0;
|
||||
|
||||
G4int chosench;
|
||||
G4String theParentName;
|
||||
G4double theParentMass;
|
||||
G4double theBR;
|
||||
G4int theNumberOfDaughters;
|
||||
G4String theDaughtersName1;
|
||||
G4String theDaughtersName2;
|
||||
G4String theDaughtersName3;
|
||||
G4String theDaughtersName4;
|
||||
G4double masses[4]={0.,0.,0.,0.};
|
||||
|
||||
do {
|
||||
|
||||
G4double theSumActualWidth = 0.0;
|
||||
G4double* theCumActualWidth = new G4double[nChannels]{};
|
||||
for (G4int index = nChannels - 1; index >= 0; --index)
|
||||
{
|
||||
theSumActualWidth += theActualWidth[index];
|
||||
theCumActualWidth[index] = theSumActualWidth;
|
||||
// cout << "DECAY Cum. Width " << index << " " << theCumActualWidth[index] << G4endl;
|
||||
}
|
||||
// cout << "DECAY Total Width " << theSumActualWidth << G4endl;
|
||||
// cout << "DECAY Total Width " << theTotalActualWidth << G4endl;
|
||||
G4double r = theTotalActualWidth * G4UniformRand();
|
||||
G4VDecayChannel* theDecayChannel(0);
|
||||
chosench=-1;
|
||||
for (G4int index = nChannels - 1; index >= 0; --index)
|
||||
{
|
||||
if (r < theCumActualWidth[index])
|
||||
{
|
||||
theDecayChannel = theDecayTable->GetDecayChannel(index);
|
||||
// cout << "DECAY SELECTED CHANNEL" << index << G4endl;
|
||||
chosench=index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete [] theCumActualWidth;
|
||||
|
||||
if(!theDecayChannel)
|
||||
{
|
||||
G4cerr << "Error condition encountered in G4KineticTrack::Decay()"<<G4endl;
|
||||
G4cerr << " decay channel has 0x0 channel associated."<<G4endl;
|
||||
G4cerr << " particle was "<<thisDefinition->GetParticleName()<<G4endl;
|
||||
G4cerr << " channel index "<< chosench << "of "<<nChannels<<"channels"<<G4endl;
|
||||
return 0;
|
||||
}
|
||||
theParentName = theDecayChannel->GetParentName();
|
||||
theParentMass = this->GetActualMass();
|
||||
theBR = theActualWidth[chosench];
|
||||
// cout << "**BR*** DECAYNEW " << theBR << G4endl;
|
||||
theNumberOfDaughters = theDecayChannel->GetNumberOfDaughters();
|
||||
theDaughtersName1 = "";
|
||||
theDaughtersName2 = "";
|
||||
theDaughtersName3 = "";
|
||||
theDaughtersName4 = "";
|
||||
|
||||
for (G4int i=0; i < 4; ++i) masses[i]=0.;
|
||||
G4int shortlivedDaughters[4];
|
||||
G4int numberOfShortliveds(0);
|
||||
G4double SumLongLivedMass(0);
|
||||
for (G4int aD=0; aD < theNumberOfDaughters ; ++aD)
|
||||
{
|
||||
const G4ParticleDefinition* aDaughter = theDecayChannel->GetDaughter(aD);
|
||||
masses[aD] = aDaughter->GetPDGMass();
|
||||
if ( aDaughter->IsShortLived() )
|
||||
{
|
||||
shortlivedDaughters[numberOfShortliveds]=aD;
|
||||
++numberOfShortliveds;
|
||||
} else {
|
||||
SumLongLivedMass += aDaughter->GetPDGMass();
|
||||
}
|
||||
|
||||
}
|
||||
switch (theNumberOfDaughters)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
theDaughtersName1 = theDecayChannel->GetDaughterName(0);
|
||||
theDaughtersName2 = "";
|
||||
theDaughtersName3 = "";
|
||||
theDaughtersName4 = "";
|
||||
break;
|
||||
case 2:
|
||||
theDaughtersName1 = theDecayChannel->GetDaughterName(0);
|
||||
theDaughtersName2 = theDecayChannel->GetDaughterName(1);
|
||||
theDaughtersName3 = "";
|
||||
theDaughtersName4 = "";
|
||||
if ( numberOfShortliveds == 1)
|
||||
{ G4SampleResonance aSampler;
|
||||
G4double massmax=theParentMass - SumLongLivedMass;
|
||||
const G4ParticleDefinition * aDaughter=theDecayChannel->GetDaughter(shortlivedDaughters[0]);
|
||||
masses[shortlivedDaughters[0]]= aSampler.SampleMass(aDaughter,massmax);
|
||||
} else if ( numberOfShortliveds == 2) {
|
||||
// choose masses one after the other, start with randomly choosen
|
||||
G4int zero= (G4UniformRand() > 0.5) ? 0 : 1;
|
||||
G4int one = 1-zero;
|
||||
G4SampleResonance aSampler;
|
||||
G4double massmax=theParentMass - aSampler.GetMinimumMass(theDecayChannel->GetDaughter(shortlivedDaughters[one]));
|
||||
const G4ParticleDefinition * aDaughter=theDecayChannel->GetDaughter(shortlivedDaughters[zero]);
|
||||
masses[shortlivedDaughters[zero]]=aSampler.SampleMass(aDaughter,massmax);
|
||||
massmax=theParentMass - masses[shortlivedDaughters[zero]];
|
||||
aDaughter=theDecayChannel->GetDaughter(shortlivedDaughters[one]);
|
||||
masses[shortlivedDaughters[one]]=aSampler.SampleMass(aDaughter,massmax);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
theDaughtersName1 = theDecayChannel->GetDaughterName(0);
|
||||
theDaughtersName2 = theDecayChannel->GetDaughterName(1);
|
||||
theDaughtersName3 = theDecayChannel->GetDaughterName(2);
|
||||
theDaughtersName4 = "";
|
||||
if ( numberOfShortliveds == 1)
|
||||
{ G4SampleResonance aSampler;
|
||||
G4double massmax=theParentMass - SumLongLivedMass;
|
||||
const G4ParticleDefinition * aDaughter=theDecayChannel->GetDaughter(shortlivedDaughters[0]);
|
||||
masses[shortlivedDaughters[0]]= aSampler.SampleMass(aDaughter,massmax);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
theDaughtersName1 = theDecayChannel->GetDaughterName(0);
|
||||
theDaughtersName2 = theDecayChannel->GetDaughterName(1);
|
||||
theDaughtersName3 = theDecayChannel->GetDaughterName(2);
|
||||
theDaughtersName4 = theDecayChannel->GetDaughterName(3);
|
||||
if ( numberOfShortliveds == 1)
|
||||
{ G4SampleResonance aSampler;
|
||||
G4double massmax=theParentMass - SumLongLivedMass;
|
||||
const G4ParticleDefinition * aDaughter=theDecayChannel->GetDaughter(shortlivedDaughters[0]);
|
||||
masses[shortlivedDaughters[0]]= aSampler.SampleMass(aDaughter,massmax);
|
||||
}
|
||||
if ( theNumberOfDaughters > 4 ) {
|
||||
G4ExceptionDescription ed;
|
||||
ed << "More than 4 decay daughters: kept only the first 4" << G4endl;
|
||||
G4Exception( "G4KineticTrack::Decay()", "KINTRK5", JustWarning, ed );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//AR-16Aug2016 : Check whether the sum of the masses of the daughters is smaller than the parent mass.
|
||||
// If this is still not the case, but the max number of attempts has been reached,
|
||||
// then the subsequent call thePhaseSpaceDecayChannel.DecayIt() will throw an exception.
|
||||
G4double sumDaughterMasses = 0.0;
|
||||
for (G4int i=0; i < 4; ++i) sumDaughterMasses += masses[i];
|
||||
if ( theParentMass - sumDaughterMasses > 0.0 ) isChannelBelowThreshold = false;
|
||||
|
||||
} while ( isChannelBelowThreshold && ++loopCounter < maxNumberOfLoops ); /* Loop checking, 16.08.2016, A.Ribon */
|
||||
|
||||
//
|
||||
// Get the decay products List
|
||||
//
|
||||
|
||||
G4GeneralPhaseSpaceDecay thePhaseSpaceDecayChannel(theParentName,
|
||||
theParentMass,
|
||||
theBR,
|
||||
theNumberOfDaughters,
|
||||
theDaughtersName1,
|
||||
theDaughtersName2,
|
||||
theDaughtersName3,
|
||||
theDaughtersName4,
|
||||
masses);
|
||||
G4DecayProducts* theDecayProducts = thePhaseSpaceDecayChannel.DecayIt();
|
||||
if(!theDecayProducts)
|
||||
{
|
||||
G4ExceptionDescription ed;
|
||||
ed << "Error condition encountered: phase-space decay failed." << G4endl
|
||||
<< "\t the decaying particle is: " << thisDefinition->GetParticleName() << G4endl
|
||||
<< "\t the channel index is: "<< chosench << " of "<< nChannels << "channels" << G4endl
|
||||
<< "\t " << theNumberOfDaughters << " daughter particles: "
|
||||
<< theDaughtersName1 << " " << theDaughtersName2 << " " << theDaughtersName3 << " "
|
||||
<< theDaughtersName4 << G4endl;
|
||||
G4Exception( "G4KineticTrack::Decay ", "HAD_KINTRACK_001", JustWarning, ed );
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Create the kinetic track List associated to the decay products
|
||||
//
|
||||
G4LorentzRotation toMoving(Get4Momentum().boostVector());
|
||||
G4DynamicParticle* theDynamicParticle;
|
||||
G4double formationTime = 0.0;
|
||||
G4ThreeVector position = this->GetPosition();
|
||||
G4LorentzVector momentum;
|
||||
G4LorentzVector momentumBalanceCMS(0);
|
||||
G4KineticTrackVector* theDecayProductList = new G4KineticTrackVector;
|
||||
G4int dEntries = theDecayProducts->entries();
|
||||
const G4ParticleDefinition * aProduct = 0;
|
||||
for (G4int i=dEntries; i > 0; --i)
|
||||
{
|
||||
theDynamicParticle = theDecayProducts->PopProducts();
|
||||
aProduct = theDynamicParticle->GetDefinition();
|
||||
chargeBalance -= G4lrint(aProduct->GetPDGCharge() );
|
||||
baryonBalance -= G4lrint(aProduct->GetBaryonNumber() );
|
||||
momentumBalanceCMS += theDynamicParticle->Get4Momentum();
|
||||
momentum = toMoving*theDynamicParticle->Get4Momentum();
|
||||
energyMomentumBalance -= momentum;
|
||||
theDecayProductList->push_back(new G4KineticTrack (aProduct,
|
||||
formationTime,
|
||||
position,
|
||||
momentum));
|
||||
delete theDynamicParticle;
|
||||
}
|
||||
delete theDecayProducts;
|
||||
if(std::getenv("DecayEnergyBalanceCheck"))
|
||||
std::cout << "DEBUGGING energy balance in cms and lab, charge baryon balance : "
|
||||
<< momentumBalanceCMS << " "
|
||||
<<energyMomentumBalance << " "
|
||||
<<chargeBalance<<" "
|
||||
<<baryonBalance<<" "
|
||||
<<G4endl;
|
||||
return theDecayProductList;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
G4double G4KineticTrack::IntegrandFunction1(G4double xmass) const
|
||||
{
|
||||
G4double mass = theActualMass; /* the actual mass value */
|
||||
G4double mass1 = theDaughterMass[0];
|
||||
G4double mass2 = theDaughterMass[1];
|
||||
G4double gamma2 = theDaughterWidth[1];
|
||||
|
||||
G4double result = (1. / (2 * mass)) *
|
||||
std::sqrt(std::max((((mass * mass) - (mass1 + xmass) * (mass1 + xmass)) *
|
||||
((mass * mass) - (mass1 - xmass) * (mass1 - xmass))),0.0)) *
|
||||
BrWig(gamma2, mass2, xmass);
|
||||
return result;
|
||||
}
|
||||
|
||||
G4double G4KineticTrack::IntegrandFunction2(G4double xmass) const
|
||||
{
|
||||
G4double mass = theDefinition->GetPDGMass(); /* the pole mass value */
|
||||
G4double mass1 = theDaughterMass[0];
|
||||
G4double mass2 = theDaughterMass[1];
|
||||
G4double gamma2 = theDaughterWidth[1];
|
||||
G4double result = (1. / (2 * mass)) *
|
||||
std::sqrt(std::max((((mass * mass) - (mass1 + xmass) * (mass1 + xmass)) *
|
||||
((mass * mass) - (mass1 - xmass) * (mass1 - xmass))),0.0)) *
|
||||
BrWig(gamma2, mass2, xmass);
|
||||
return result;
|
||||
}
|
||||
|
||||
G4double G4KineticTrack::IntegrandFunction3(G4double xmass) const
|
||||
{
|
||||
const G4double mass = G4KineticTrack_Gmass; /* the actual mass value */
|
||||
// const G4double mass1 = theDaughterMass[0];
|
||||
const G4double mass2 = theDaughterMass[1];
|
||||
const G4double gamma2 = theDaughterWidth[1];
|
||||
|
||||
const G4double result = (1. / (2 * mass)) *
|
||||
std::sqrt(((mass * mass) - (G4KineticTrack_xmass1 + xmass) * (G4KineticTrack_xmass1 + xmass)) *
|
||||
((mass * mass) - (G4KineticTrack_xmass1 - xmass) * (G4KineticTrack_xmass1 - xmass))) *
|
||||
BrWig(gamma2, mass2, xmass);
|
||||
return result;
|
||||
}
|
||||
|
||||
G4double G4KineticTrack::IntegrandFunction4(G4double xmass) const
|
||||
{
|
||||
const G4double mass = G4KineticTrack_Gmass;
|
||||
const G4double mass1 = theDaughterMass[0];
|
||||
const G4double gamma1 = theDaughterWidth[0];
|
||||
// const G4double mass2 = theDaughterMass[1];
|
||||
|
||||
G4KineticTrack_xmass1 = xmass;
|
||||
|
||||
const G4double theLowerLimit = 0.0;
|
||||
const G4double theUpperLimit = mass - xmass;
|
||||
const G4int nIterations = 100;
|
||||
|
||||
G4Integrator<const G4KineticTrack, G4double(G4KineticTrack::*)(G4double) const> integral;
|
||||
G4double result = BrWig(gamma1, mass1, xmass)*
|
||||
integral.Simpson(this, &G4KineticTrack::IntegrandFunction3, theLowerLimit, theUpperLimit, nIterations);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
G4double G4KineticTrack::IntegrateCMMomentum(const G4double theLowerLimit) const
|
||||
{
|
||||
const G4double theUpperLimit = theActualMass - theDaughterMass[0];
|
||||
const G4int nIterations = 100;
|
||||
|
||||
if (theLowerLimit>=theUpperLimit) return 0.0;
|
||||
|
||||
G4Integrator<const G4KineticTrack, G4double(G4KineticTrack::*)(G4double) const> integral;
|
||||
G4double theIntegralOverMass2 = integral.Simpson(this, &G4KineticTrack::IntegrandFunction1,
|
||||
theLowerLimit, theUpperLimit, nIterations);
|
||||
return theIntegralOverMass2;
|
||||
}
|
||||
|
||||
G4double G4KineticTrack::IntegrateCMMomentum(const G4double theLowerLimit, const G4double poleMass) const
|
||||
{
|
||||
const G4double theUpperLimit = poleMass - theDaughterMass[0];
|
||||
const G4int nIterations = 100;
|
||||
|
||||
if (theLowerLimit>=theUpperLimit) return 0.0;
|
||||
|
||||
G4Integrator<const G4KineticTrack, G4double(G4KineticTrack::*)(G4double) const> integral;
|
||||
const G4double theIntegralOverMass2 = integral.Simpson(this, &G4KineticTrack::IntegrandFunction2,
|
||||
theLowerLimit, theUpperLimit, nIterations);
|
||||
return theIntegralOverMass2;
|
||||
}
|
||||
|
||||
|
||||
G4double G4KineticTrack::IntegrateCMMomentum2() const
|
||||
{
|
||||
const G4double theLowerLimit = 0.0;
|
||||
const G4double theUpperLimit = theActualMass;
|
||||
const G4int nIterations = 100;
|
||||
|
||||
if (theLowerLimit>=theUpperLimit) return 0.0;
|
||||
|
||||
G4Integrator<const G4KineticTrack, G4double(G4KineticTrack::*)(G4double) const> integral;
|
||||
G4double theIntegralOverMass2 = integral.Simpson(this, &G4KineticTrack::IntegrandFunction4,
|
||||
theLowerLimit, theUpperLimit, nIterations);
|
||||
return theIntegralOverMass2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
#include "G4KineticTrackVector.hh"
|
||||
|
||||
G4KineticTrackVector::G4KineticTrackVector()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//****************************************************************************************************************
|
||||
// These methods were implemented by Maxim Komogorov
|
||||
// Maxim.Komogorov@cern.ch
|
||||
|
||||
void G4KineticTrackVector::BoostBeam(G4ThreeVector& BeamMom)
|
||||
{
|
||||
for(unsigned int c1 = 0; c1 < size(); c1++)
|
||||
{
|
||||
G4KineticTrack& KT =**(begin()+c1);
|
||||
G4LorentzVector Mom = KT.Get4Momentum();
|
||||
G4ThreeVector Velocity = (1/std::sqrt(BeamMom.mag2() + sqr(KT.GetDefinition()->GetPDGMass())))*BeamMom;
|
||||
Mom.boost(Velocity);
|
||||
KT.Set4Momentum(Mom);
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void G4KineticTrackVector::Boost(G4ThreeVector& Velocity)
|
||||
{
|
||||
for(unsigned int c1 = 0; c1 < size(); c1++)
|
||||
{
|
||||
G4KineticTrack& KT =**(begin()+c1);
|
||||
G4LorentzVector Mom = KT.Get4Momentum();
|
||||
Mom.boost(Velocity);
|
||||
KT.Set4Momentum(Mom);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void G4KineticTrackVector::Shift(G4ThreeVector& Pos)
|
||||
{
|
||||
for(unsigned int c1 = 0; c1 < size(); c1++)
|
||||
{
|
||||
G4KineticTrack& KT =**(begin()+c1);
|
||||
KT.SetPosition(KT.GetPosition() + Pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//****************************************************************************************************************
|
||||
@@ -0,0 +1,148 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
|
||||
#include "G4ios.hh"
|
||||
#include "G4LegendrePolynomial.hh"
|
||||
#include "G4Pow.hh"
|
||||
#include "G4Exp.hh"
|
||||
#include "G4Log.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
G4double G4LegendrePolynomial::GetCoefficient(size_t i, size_t order)
|
||||
{
|
||||
if(order >= fCoefficients.size()) BuildUpToOrder(order);
|
||||
if(order >= fCoefficients.size() ||
|
||||
i/2 >= fCoefficients[order].size() ||
|
||||
(i%2) != order %2) return 0;
|
||||
return fCoefficients[order][i/2];
|
||||
}
|
||||
|
||||
G4double G4LegendrePolynomial::EvalLegendrePoly(G4int order, G4double x)
|
||||
{
|
||||
// Call EvalAssocLegendrePoly with m=0
|
||||
return (EvalAssocLegendrePoly(order,0,x));
|
||||
}
|
||||
|
||||
G4double G4LegendrePolynomial::EvalAssocLegendrePoly(G4int l, G4int m, G4double x,
|
||||
map<G4int, map<G4int, G4double> >* cache)
|
||||
{
|
||||
// Calculate P_l^m(x).
|
||||
// If cache ptr is non-null, use cache[l][m] if it exists, otherwise compute
|
||||
// P_l^m(x) and cache it in that position. The cache speeds up calculations
|
||||
// where many P_l^m computations are need at the same value of x.
|
||||
|
||||
if(l<0 || m<-l || m>l) return 0;
|
||||
G4Pow* g4pow = G4Pow::GetInstance();
|
||||
|
||||
// Use non-log factorial for low l, m: it is more efficient until
|
||||
// l and m get above 10 or so.
|
||||
// FIXME: G4Pow doesn't check whether the argument gets too large,
|
||||
// which is unsafe! Max is 512; VI: It is assume that Geant4 does not
|
||||
// need higher order
|
||||
if(m<0) {
|
||||
G4double value = (m%2 ? -1. : 1.) * EvalAssocLegendrePoly(l, -m, x);
|
||||
if(l < 10) return value * g4pow->factorial(l+m)/g4pow->factorial(l-m);
|
||||
else { return value * G4Exp(g4pow->logfactorial(l+m) - g4pow->logfactorial(l-m));
|
||||
}
|
||||
}
|
||||
|
||||
// hard-code the first few orders for speed
|
||||
if(l==0) return 1;
|
||||
if(l==1) {
|
||||
if(m==0){return x;}
|
||||
/*m==1*/ return -sqrt(1.-x*x);
|
||||
}
|
||||
if(l<5) {
|
||||
G4double x2 = x*x;
|
||||
if(l==2) {
|
||||
if(m==0){return 0.5*(3.*x2 - 1.);}
|
||||
if(m==1){return -3.*x*sqrt(1.-x2);}
|
||||
/*m==2*/ return 3.*(1.-x2);
|
||||
}
|
||||
if(l==3) {
|
||||
if(m==0){return 0.5*(5.*x*x2 - 3.*x);}
|
||||
if(m==1){return -1.5*(5.*x2-1.)*sqrt(1.-x2);}
|
||||
if(m==2){return 15.*x*(1.-x2);}
|
||||
/*m==3*/ return -15.*(1.-x2)*sqrt(1.-x2);
|
||||
}
|
||||
if(l==4) {
|
||||
if(m==0){return 0.125*(35.*x2*x2 - 30.*x2 + 3.);}
|
||||
if(m==1){return -2.5*(7.*x*x2-3.*x)*sqrt(1.-x2);}
|
||||
if(m==2){return 7.5*(7.*x2-1.)*(1.-x2);}
|
||||
if(m==3){return -105.*x*(1.-x2)*sqrt(1.-x2);}
|
||||
/*m==4*/ return 105.*(1. - 2.*x2 + x2*x2);
|
||||
}
|
||||
}
|
||||
|
||||
// Easy special cases
|
||||
// FIXME: G4Pow doesn't check whether the argument gets too large, which is unsafe! Max is 512.
|
||||
if(m==l) return (l%2 ? -1. : 1.) *
|
||||
G4Exp(g4pow->logfactorial(2*l) - g4pow->logfactorial(l)) *
|
||||
G4Exp(G4Log((1.-x*x)*0.25)*0.5*G4double(l));
|
||||
if(m==l-1) return x*(2.*G4double(m)+1.)*EvalAssocLegendrePoly(m,m,x);
|
||||
|
||||
// See if we have this value cached.
|
||||
if(cache != NULL && cache->count(l) > 0 && (*cache)[l].count(m) > 0) {
|
||||
return (*cache)[l][m];
|
||||
}
|
||||
|
||||
// Otherwise calculate recursively
|
||||
G4double value = (x*G4double(2*l-1)*EvalAssocLegendrePoly(l-1,m,x) -
|
||||
(G4double(l+m-1))*EvalAssocLegendrePoly(l-2,m,x))/G4double(l-m);
|
||||
|
||||
// If we are working with a cache, cache this value.
|
||||
if(cache != NULL) {
|
||||
(*cache)[l][m] = value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void G4LegendrePolynomial::BuildUpToOrder(size_t orderMax)
|
||||
{
|
||||
if(orderMax > 30) {
|
||||
G4cout << "G4LegendrePolynomial::GetCoefficient(): "
|
||||
<< "I refuse to make a Legendre Polynomial of order "
|
||||
<< orderMax << G4endl;
|
||||
return;
|
||||
}
|
||||
while(fCoefficients.size() < orderMax+1) { /* Loop checking, 30-Oct-2015, G.Folger */
|
||||
size_t order = fCoefficients.size();
|
||||
fCoefficients.resize(order+1);
|
||||
if(order <= 1) fCoefficients[order].push_back(1.);
|
||||
else {
|
||||
for(size_t iCoeff = 0; iCoeff < order+1; ++iCoeff) {
|
||||
if((order % 2) == (iCoeff % 2)) {
|
||||
G4double coeff = 0;
|
||||
if(iCoeff <= order-2) coeff -= fCoefficients[order-2][iCoeff/2]*G4double(order-1);
|
||||
if(iCoeff > 0) coeff += fCoefficients[order-1][(iCoeff-1)/2]*G4double(2*order-1);
|
||||
coeff /= G4double(order);
|
||||
fCoefficients[order].push_back(coeff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
|
||||
#include "G4NuclearFermiDensity.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
#include "G4Pow.hh"
|
||||
|
||||
G4NuclearFermiDensity::G4NuclearFermiDensity(G4int anA, G4int /*aZ*/)
|
||||
: theA(anA), a(0.545 * fermi)
|
||||
{
|
||||
G4double a13 = G4Pow::GetInstance()->Z13(anA);
|
||||
const G4double r0 = 1.16 * (1. - 1.16/(a13*a13)) * fermi;
|
||||
theR = r0 * a13;
|
||||
Setrho0(3./ (4.*pi *r0*r0*r0 * theA * (1. + sqr(a/theR)*pi2 )));
|
||||
}
|
||||
|
||||
G4NuclearFermiDensity::~G4NuclearFermiDensity() {}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// 23-Jan-2009 V.Ivanchenko make the class to be a singleton
|
||||
// 17-Aug-2012 V.Ivanchenko added hadronic model factories
|
||||
|
||||
#include "G4NuclearPolarizationStore.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
|
||||
G4ThreadLocal G4NuclearPolarizationStore*
|
||||
G4NuclearPolarizationStore::instance = nullptr;
|
||||
|
||||
G4NuclearPolarizationStore* G4NuclearPolarizationStore::GetInstance()
|
||||
{
|
||||
if(nullptr == instance) {
|
||||
static G4ThreadLocalSingleton<G4NuclearPolarizationStore> inst;
|
||||
instance = inst.Instance();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
G4NuclearPolarizationStore::G4NuclearPolarizationStore()
|
||||
{
|
||||
for(G4int i=0; i<maxNumStates; ++i) { nuclist[i] = nullptr; }
|
||||
oldIdx = 0;
|
||||
}
|
||||
|
||||
G4NuclearPolarizationStore::~G4NuclearPolarizationStore()
|
||||
{
|
||||
for(G4int i=0; i<maxNumStates; ++i) {
|
||||
delete nuclist[i];
|
||||
nuclist[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void G4NuclearPolarizationStore::Register(G4NuclearPolarization* ptr)
|
||||
{
|
||||
G4int idx = -1;
|
||||
for(G4int i=0; i<maxNumStates; ++i) {
|
||||
if(ptr == nuclist[i]) { return; }
|
||||
if(nullptr == nuclist[i]) { idx = i; }
|
||||
}
|
||||
if(idx >= 0) {
|
||||
nuclist[idx] = ptr;
|
||||
return;
|
||||
}
|
||||
// delete oldest object
|
||||
delete nuclist[oldIdx];
|
||||
nuclist[oldIdx] = ptr;
|
||||
// redefine oldIdx
|
||||
++oldIdx;
|
||||
if(oldIdx >= maxNumStates) { oldIdx = 0; }
|
||||
}
|
||||
|
||||
G4NuclearPolarization*
|
||||
G4NuclearPolarizationStore::FindOrBuild(G4int Z, G4int A, G4double Eexc)
|
||||
{
|
||||
static const G4double tolerance = 10.*CLHEP::eV;
|
||||
for(G4int i=0; i<maxNumStates; ++i) {
|
||||
auto nucp = nuclist[i];
|
||||
if(nucp && Z == nucp->GetZ() && A == nucp->GetA() &&
|
||||
std::abs(Eexc - nucp->GetExcitationEnergy()) < tolerance) {
|
||||
return nucp;
|
||||
}
|
||||
}
|
||||
G4NuclearPolarization* ptr = new G4NuclearPolarization(Z, A, Eexc);
|
||||
Register(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void G4NuclearPolarizationStore::RemoveMe(G4NuclearPolarization* ptr)
|
||||
{
|
||||
for(G4int i=0; i<maxNumStates; ++i) {
|
||||
if(ptr == nuclist[i]) {
|
||||
delete ptr;
|
||||
nuclist[i] = nullptr;
|
||||
// do we need redefine oldIdx?
|
||||
if(i == oldIdx) {
|
||||
for(G4int j=0; j<maxNumStates; ++j) {
|
||||
if(j != i && nullptr != nuclist[j]) {
|
||||
oldIdx = j;
|
||||
return;
|
||||
}
|
||||
}
|
||||
oldIdx = i;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// Geant4 class G4NuclearRadii
|
||||
//
|
||||
// Author V.Ivanchenko 27.05.2019
|
||||
//
|
||||
//
|
||||
|
||||
#include "G4NuclearRadii.hh"
|
||||
#include "G4Pow.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4ParticleDefinition.hh"
|
||||
#include "G4NucleiProperties.hh"
|
||||
|
||||
G4Pow* G4NuclearRadii::fG4pow = G4Pow::GetInstance();
|
||||
const G4double fAlpha = 0.5*CLHEP::fine_structure_const*CLHEP::hbarc;
|
||||
const G4double fInvep = 1.0/CLHEP::eplus;
|
||||
|
||||
G4double G4NuclearRadii::ExplicitRadius(G4int Z, G4int A)
|
||||
{
|
||||
G4double R = 0.0;
|
||||
// Special rms radii for light nucleii
|
||||
if(Z <= 4) {
|
||||
if(A == 1) { R = 0.895*CLHEP::fermi; }// p
|
||||
else if(A == 2) { R = 2.13*CLHEP::fermi; }// d
|
||||
else if(Z == 1 && A == 3) { R = 1.80*CLHEP::fermi; }// t
|
||||
else if(Z == 2 && A == 3) { R = 1.96*CLHEP::fermi; }// He3
|
||||
else if(Z == 2 && A == 4) { R = 1.68*CLHEP::fermi; }// He4
|
||||
else if(Z == 3) { R = 2.40*CLHEP::fermi; }// Li7
|
||||
else if(Z == 4) { R = 2.51*CLHEP::fermi; }// Be9
|
||||
}
|
||||
return R;
|
||||
}
|
||||
|
||||
G4double G4NuclearRadii::Radius(G4int Z, G4int A)
|
||||
{
|
||||
G4double R = ExplicitRadius(Z, A);
|
||||
if(0.0 == R) {
|
||||
if (A <= 50) {
|
||||
G4double y = 1.1;
|
||||
if( A <= 15) { y = 1.26; }
|
||||
else if( A <= 20) { y = 1.19; }
|
||||
else if( A <= 30) { y = 1.12; }
|
||||
G4double x = fG4pow->Z13(A);
|
||||
R = y*(x - 1./x);
|
||||
} else {
|
||||
R = fG4pow->powZ(A, 0.27);
|
||||
}
|
||||
R *= CLHEP::fermi;
|
||||
}
|
||||
return R;
|
||||
}
|
||||
|
||||
G4double G4NuclearRadii::RadiusRMS(G4int Z, G4int A)
|
||||
{
|
||||
G4double R = ExplicitRadius(Z, A);
|
||||
if(0.0 == R) {
|
||||
R = 1.24*fG4pow->powZ(A, 0.28)*CLHEP::fermi;
|
||||
}
|
||||
return R;
|
||||
}
|
||||
|
||||
G4double G4NuclearRadii::RadiusNNGG(G4int Z, G4int A)
|
||||
{
|
||||
G4double R = ExplicitRadius(Z, A);
|
||||
if(0.0 == R) {
|
||||
if(A > 20) {
|
||||
R = 1.08*fG4pow->Z13(A)*(0.85 + 0.15*G4Exp(-(G4double)(A - 21)/40.));
|
||||
} else {
|
||||
R = 1.08*fG4pow->Z13(A)*(1.0 + 0.3*G4Exp(-(G4double)(A - 21)/10.));
|
||||
}
|
||||
R *= CLHEP::fermi;
|
||||
}
|
||||
return R;
|
||||
}
|
||||
|
||||
G4double G4NuclearRadii::RadiusECS(G4int Z, G4int A)
|
||||
{
|
||||
G4double R=0.;
|
||||
const G4double c[3]={0.77329745, 1.38206072, 30.28295235};
|
||||
const G4double c1=c[0];
|
||||
const G4double c2=c[1];
|
||||
const G4double c3=c[2];
|
||||
|
||||
// Special rms radii for light nuclei
|
||||
if (A <= 30) {
|
||||
G4double vn = 0.5*A + fG4pow->powN(0.028*A,2) - fG4pow->powN(0.011*A,3);
|
||||
G4double dev = vn - (A-Z);
|
||||
R = c1*fG4pow->Z13(A) + c2/fG4pow->Z13(A) + c3*dev*dev/(A*A);
|
||||
} else if (A<=50){
|
||||
G4double y = 1.1;
|
||||
G4double x = fG4pow->Z13(A);
|
||||
R = y*(x - 1./x);
|
||||
}
|
||||
return R*CLHEP::fermi;
|
||||
}
|
||||
|
||||
G4double G4NuclearRadii::RadiusHNGG(G4int A)
|
||||
{
|
||||
G4double R = CLHEP::fermi;
|
||||
if(A > 20) {
|
||||
R *= 1.08*fG4pow->Z13(A)*(0.8 + 0.2*G4Exp(-(G4double)(A - 20)/20.));
|
||||
} else {
|
||||
R *= 1.08*fG4pow->Z13(A)*(1.0 + 0.1*G4Exp(-(G4double)(A - 20)/20.));
|
||||
}
|
||||
return R;
|
||||
}
|
||||
|
||||
G4double G4NuclearRadii::RadiusKNGG(G4int A)
|
||||
{
|
||||
return 1.3*CLHEP::fermi*fG4pow->Z13(A);
|
||||
}
|
||||
|
||||
G4double G4NuclearRadii::RadiusND(G4int A)
|
||||
{
|
||||
G4double R = CLHEP::fermi;
|
||||
if(1 == A) { return R*0.895; }
|
||||
G4double x = R*fG4pow->Z13(A);
|
||||
if(A <= 3.) { x *= 0.8; }
|
||||
else { x *= 1.7; }
|
||||
return R;
|
||||
}
|
||||
|
||||
G4double G4NuclearRadii::RadiusCB(G4int Z, G4int A)
|
||||
{
|
||||
G4double R = ExplicitRadius(Z, A);
|
||||
if(0.0 == R) {
|
||||
G4int z = std::min(Z, 92);
|
||||
R = r0[z]*fG4pow->Z13(A)*CLHEP::fermi;
|
||||
}
|
||||
return R;
|
||||
}
|
||||
|
||||
G4double G4NuclearRadii::ParticleRadius(const G4ParticleDefinition* p)
|
||||
{
|
||||
G4double R = CLHEP::fermi;
|
||||
G4int pdg = std::abs(p->GetPDGEncoding());
|
||||
if(pdg == 2112 || pdg == 2212) { R *= 0.895; }
|
||||
else if(pdg == 211) { R *= 0.663; }
|
||||
else if(pdg == 321) { R *= 0.340; }
|
||||
else { R *= 0.5; }
|
||||
return R;
|
||||
}
|
||||
|
||||
G4double G4NuclearRadii::CoulombFactor(
|
||||
const G4ParticleDefinition* theParticle,
|
||||
const G4ParticleDefinition* nucleon,
|
||||
G4double ekin)
|
||||
{
|
||||
G4double tR = 0.895*CLHEP::fermi;
|
||||
G4double pR = ParticleRadius(theParticle);
|
||||
|
||||
G4double pZ = theParticle->GetPDGCharge()*fInvep;
|
||||
G4double tZ = nucleon->GetPDGCharge()*fInvep;
|
||||
|
||||
G4double pM = theParticle->GetPDGMass();
|
||||
G4double tM = nucleon->GetPDGMass();
|
||||
|
||||
G4double pElab = ekin + pM;
|
||||
G4double totTcm = std::sqrt(pM*pM + tM*tM + 2.*pElab*tM) - pM -tM;
|
||||
|
||||
G4double bC = fAlpha*pZ*tZ/(pR + tR);
|
||||
return (totTcm > bC) ? 1. - bC/totTcm : 0.0;
|
||||
}
|
||||
|
||||
G4double G4NuclearRadii::CoulombFactor(
|
||||
G4int Z, G4int A,
|
||||
const G4ParticleDefinition* theParticle,
|
||||
G4double ekin)
|
||||
{
|
||||
G4double tR = RadiusCB(Z, A);
|
||||
G4double pR = ParticleRadius(theParticle);
|
||||
|
||||
G4double pZ = theParticle->GetPDGCharge()*fInvep;
|
||||
|
||||
G4double pM = theParticle->GetPDGMass();
|
||||
G4double tM = G4NucleiProperties::GetNuclearMass(A, Z);
|
||||
|
||||
G4double pElab = ekin + pM;
|
||||
G4double totTcm = std::sqrt(pM*pM + tM*tM + 2.*pElab*tM) - pM -tM;
|
||||
|
||||
G4double bC = fAlpha*pZ*Z/(pR + tR);
|
||||
return (totTcm > bC) ? 1. - bC/totTcm : 0.0;
|
||||
}
|
||||
|
||||
const G4double G4NuclearRadii::r0[] = {
|
||||
1.2,
|
||||
1.3, 1.3, 1.3, 1.3,1.17,1.54,1.65,1.71, 1.7,1.75, // 1-10
|
||||
1.7,1.57,1.53, 1.4, 1.3,1.30,1.44, 1.4, 1.4, 1.4, //11-20
|
||||
1.4, 1.4,1.46, 1.4, 1.4,1.46,1.55, 1.5,1.38,1.48, //21-30
|
||||
1.4, 1.4, 1.4,1.46, 1.4, 1.4, 1.4, 1.4, 1.4,1.45, //31-40
|
||||
1.4, 1.4, 1.4, 1.4, 1.4, 1.4,1.45,1.48, 1.4,1.52, //41-50
|
||||
1.46, 1.4, 1.4, 1.4, 1.4, 1.4, 1.4, 1.4, 1.4, 1.5, //51-60
|
||||
1.4, 1.4, 1.4, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.4, //61-70
|
||||
1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3,1.33,1.43, //71-80
|
||||
1.3,1.32,1.34, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, 1.3, //81-90
|
||||
1.3, 1.3};
|
||||
@@ -0,0 +1,60 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
|
||||
#include "G4NuclearShellModelDensity.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
#include "G4Exp.hh"
|
||||
#include "G4Log.hh"
|
||||
#include "G4Pow.hh"
|
||||
|
||||
G4NuclearShellModelDensity::G4NuclearShellModelDensity(G4int anA, G4int /*aZ*/)
|
||||
: theA(anA)//, theZ(aZ)
|
||||
{
|
||||
const G4double r0sq=0.8133*fermi*fermi;
|
||||
theRsquare= r0sq * G4Pow::GetInstance()->Z23(theA);
|
||||
G4double x = 1./(pi*theRsquare);
|
||||
Setrho0(x*std::sqrt(x));
|
||||
}
|
||||
|
||||
G4NuclearShellModelDensity::~G4NuclearShellModelDensity() {}
|
||||
|
||||
G4double G4NuclearShellModelDensity::GetRelativeDensity(const G4ThreeVector & aPosition) const
|
||||
{
|
||||
return G4Exp(-1*aPosition.mag2()/theRsquare);
|
||||
}
|
||||
|
||||
G4double G4NuclearShellModelDensity::GetRadius(const G4double maxRelativeDensity) const
|
||||
{
|
||||
|
||||
return (maxRelativeDensity>0 && maxRelativeDensity <= 1 ) ?
|
||||
std::sqrt(theRsquare * G4Log(1/maxRelativeDensity) ) : DBL_MAX;
|
||||
}
|
||||
|
||||
G4double G4NuclearShellModelDensity::GetDeriv(const G4ThreeVector & aPosition) const
|
||||
{
|
||||
return -2* aPosition.mag() / theRsquare * GetDensity(aPosition);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
//
|
||||
#include "G4Nucleon.hh"
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// GEANT 4 class implementation file
|
||||
//
|
||||
// ---------------- G4Nucleon ----------------
|
||||
// by Gunter Folger, May 1998.
|
||||
// class for a nucleon (inside a 3D Nucleus)
|
||||
// ------------------------------------------------------------
|
||||
|
||||
G4Nucleon::G4Nucleon()
|
||||
: theBindingE(0.) , theParticleType(0), theSplitableHadron(0)
|
||||
{}
|
||||
|
||||
G4Nucleon::~G4Nucleon()
|
||||
{
|
||||
}
|
||||
|
||||
void G4Nucleon::Boost(const G4LorentzVector & aMomentum)
|
||||
{
|
||||
// see e.g. CERNLIB short writeup U101 for the algorithm
|
||||
G4double mass=aMomentum.mag();
|
||||
G4double factor=
|
||||
( theMomentum.vect()*aMomentum.vect()/(aMomentum.e()+mass) - theMomentum.e() ) / mass;
|
||||
|
||||
theMomentum.setE(1/mass*theMomentum.dot(aMomentum));
|
||||
theMomentum.setVect(factor*aMomentum.vect() + theMomentum.vect());
|
||||
}
|
||||
|
||||
#include <iostream>
|
||||
std::ostream & operator << (std::ostream &stream, const G4Nucleon& nucleon)
|
||||
{
|
||||
// stream<< nucleon.GetDefinition()->GetParticleName()
|
||||
// << " is " << nucleon.AreYouHit() ? " " : "not"
|
||||
// << " hit. Momentum/position:" << G4endl;
|
||||
stream<< " momentum : " << nucleon.Get4Momentum() << G4endl;
|
||||
stream<< " position : " << nucleon.GetPosition() ;
|
||||
return stream;
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
//
|
||||
// ------------------------------------------------------------
|
||||
// GEANT 4 class implementation file
|
||||
//
|
||||
// ---------------- G4Parton ----------------
|
||||
// by Gunter Folger, June 1998.
|
||||
// class for Parton (inside a string) used by Parton String Models
|
||||
// ------------------------------------------------------------
|
||||
|
||||
#include "G4Parton.hh"
|
||||
#include "G4HadronicException.hh"
|
||||
|
||||
G4Parton::G4Parton(G4int PDGcode)
|
||||
{
|
||||
PDGencoding=PDGcode;
|
||||
theX = 0;
|
||||
theDefinition=G4ParticleTable::GetParticleTable()->FindParticle(PDGencoding);
|
||||
if (theDefinition == NULL)
|
||||
{
|
||||
G4cout << "Encoding = "<<PDGencoding<<G4endl;
|
||||
G4String text = "G4Parton::GetDefinition(): Encoding not in particle table";
|
||||
throw G4HadronicException(__FILE__, __LINE__, text);
|
||||
}
|
||||
//
|
||||
// colour by random in (1,2,3)=(R,G,B) for quarks and
|
||||
// in (-1,-2,-3)=(Rbar,Gbar,Bbar) for anti-quarks:
|
||||
//
|
||||
if (theDefinition->GetParticleType() == "quarks") {
|
||||
theColour = ((G4int)(3.*G4UniformRand())+1)*(std::abs(PDGencoding)/PDGencoding) ;
|
||||
}
|
||||
//
|
||||
// colour by random in (-1,-2,-3)=(Rbar,Gbar,Bbar)=(GB,RB,RG) for di-quarks and
|
||||
// in (1,2,3)=(R,G,B)=(GB,RB,RG) for anti-di-quarks:
|
||||
//
|
||||
else if (theDefinition->GetParticleType() == "diquarks") {
|
||||
theColour = -((G4int)(3.*G4UniformRand())+1)*(std::abs(PDGencoding)/PDGencoding);
|
||||
}
|
||||
//
|
||||
// colour by random in (-11,-12,...,-33)=(RRbar,RGbar,RBbar,...,BBbar) for gluons:
|
||||
//
|
||||
else if (theDefinition->GetParticleType() == "gluons") {
|
||||
theColour = -(((G4int)(3.*G4UniformRand())+1)*10 + ((G4int)(3.*G4UniformRand())+1));
|
||||
}
|
||||
else {
|
||||
G4cout << "Encoding = "<<PDGencoding<<G4endl;
|
||||
G4String text = "G4Parton::GetDefinition(): Particle is not a parton";
|
||||
throw G4HadronicException(__FILE__, __LINE__, text);
|
||||
}
|
||||
//
|
||||
// isospin-z from PDG-encoded isospin-z for
|
||||
// quarks, anti-quarks, di-quarks, and anti-di-quarks:
|
||||
//
|
||||
if ((theDefinition->GetParticleType() == "quarks") || (theDefinition->GetParticleType() == "diquarks")){
|
||||
theIsoSpinZ = theDefinition->GetPDGIsospin3();
|
||||
}
|
||||
//
|
||||
// isospin-z choosen at random from PDG-encoded isospin for gluons (should be zero):
|
||||
//
|
||||
else {
|
||||
G4int thisPDGiIsospin=theDefinition->GetPDGiIsospin();
|
||||
if (thisPDGiIsospin == 0) {
|
||||
theIsoSpinZ = 0;
|
||||
}
|
||||
else {
|
||||
theIsoSpinZ = ((G4int)((thisPDGiIsospin+1)*G4UniformRand()))-thisPDGiIsospin*0.5;
|
||||
}
|
||||
}
|
||||
//
|
||||
// spin-z choosen at random from PDG-encoded spin:
|
||||
//
|
||||
G4int thisPDGiSpin=theDefinition->GetPDGiSpin();
|
||||
if (thisPDGiSpin == 0) {
|
||||
theSpinZ = 0;
|
||||
}
|
||||
else {
|
||||
G4int rand=((G4int)((thisPDGiSpin+1)*G4UniformRand()));
|
||||
theSpinZ = rand-thisPDGiSpin*0.5;;
|
||||
}
|
||||
}
|
||||
|
||||
G4Parton::G4Parton(const G4Parton &right)
|
||||
{
|
||||
PDGencoding = right.PDGencoding;
|
||||
theMomentum = right.theMomentum;
|
||||
thePosition = right.thePosition;
|
||||
theX = right.theX;
|
||||
theDefinition = right.theDefinition;
|
||||
theColour = right.theColour;
|
||||
theIsoSpinZ = right.theIsoSpinZ;
|
||||
theSpinZ = right.theSpinZ;
|
||||
}
|
||||
|
||||
G4Parton & G4Parton::operator=(const G4Parton &right)
|
||||
{
|
||||
if (this != &right)
|
||||
{
|
||||
PDGencoding=right.GetPDGcode();
|
||||
theMomentum=right.Get4Momentum();
|
||||
thePosition=right.GetPosition();
|
||||
theX = right.theX;
|
||||
theDefinition = right.theDefinition;
|
||||
theColour = right.theColour;
|
||||
theIsoSpinZ = right.theIsoSpinZ;
|
||||
theSpinZ = right.theSpinZ;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
G4Parton::~G4Parton()
|
||||
{
|
||||
// cout << "G4Parton::~G4Parton(): this = "<<this <<endl;
|
||||
// cout << "break here"<<this <<endl;
|
||||
}
|
||||
|
||||
void G4Parton::DefineMomentumInZ(G4double aLightConeMomentum, G4bool aDirection)
|
||||
{
|
||||
G4double Mass = GetMass();
|
||||
G4LorentzVector a4Momentum = Get4Momentum();
|
||||
aLightConeMomentum*=theX;
|
||||
G4double TransverseMass2 = sqr(a4Momentum.px()) + sqr(a4Momentum.py()) + sqr(Mass);
|
||||
a4Momentum.setPz(0.5*(aLightConeMomentum - TransverseMass2/aLightConeMomentum)*(aDirection? 1: -1));
|
||||
a4Momentum.setE( 0.5*(aLightConeMomentum + TransverseMass2/aLightConeMomentum));
|
||||
Set4Momentum(a4Momentum);
|
||||
}
|
||||
|
||||
void G4Parton::DefineMomentumInZ(G4double aLightConeMomentum,G4double aLightConeE, G4bool aDirection)
|
||||
{
|
||||
G4double Mass = GetMass();
|
||||
G4LorentzVector a4Momentum = Get4Momentum();
|
||||
aLightConeMomentum*=theX;
|
||||
aLightConeE*=theX;
|
||||
G4double TransverseMass2 = sqr(a4Momentum.px()) + sqr(a4Momentum.py()) + sqr(Mass);
|
||||
a4Momentum.setPz(0.5*(aLightConeMomentum - aLightConeE - TransverseMass2/aLightConeMomentum)*(aDirection? 1: -1));
|
||||
a4Momentum.setE( 0.5*(aLightConeMomentum + aLightConeE + TransverseMass2/aLightConeMomentum));
|
||||
Set4Momentum(a4Momentum);
|
||||
}
|
||||
@@ -0,0 +1,415 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// -------------------------------------------------------------------
|
||||
// GEANT4 Class file
|
||||
//
|
||||
//
|
||||
// File name: G4PolynomialPDF
|
||||
//
|
||||
// Author: Jason Detwiler (jasondet@gmail.com)
|
||||
//
|
||||
// Creation date: Aug 2012
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
#include "G4PolynomialPDF.hh"
|
||||
#include "Randomize.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
G4PolynomialPDF::G4PolynomialPDF(size_t n, const G4double* coeffs,
|
||||
G4double x1, G4double x2) :
|
||||
fX1(x1), fX2(x2), fChanged(true), fTolerance(1.e-8), fVerbose(0)
|
||||
{
|
||||
if(coeffs != nullptr) SetCoefficients(n, coeffs);
|
||||
else if(n > 0) SetNCoefficients(n);
|
||||
}
|
||||
|
||||
G4PolynomialPDF::~G4PolynomialPDF()
|
||||
{}
|
||||
|
||||
void G4PolynomialPDF::SetCoefficient(size_t i, G4double value, bool doSimplify)
|
||||
{
|
||||
while(i >= fCoefficients.size()) fCoefficients.push_back(0);
|
||||
/* Loop checking, 30-Oct-2015, G.Folger */
|
||||
fCoefficients[i] = value;
|
||||
fChanged = true;
|
||||
if(doSimplify) Simplify();
|
||||
}
|
||||
|
||||
void G4PolynomialPDF::SetCoefficients(size_t nCoeffs,
|
||||
const G4double* coefficients)
|
||||
{
|
||||
SetNCoefficients(nCoeffs);
|
||||
for(size_t i=0; i<GetNCoefficients(); ++i) {
|
||||
SetCoefficient(i, coefficients[i], false);
|
||||
}
|
||||
fChanged = true;
|
||||
Simplify();
|
||||
}
|
||||
|
||||
void G4PolynomialPDF::Simplify()
|
||||
{
|
||||
while(fCoefficients.size() && fCoefficients[fCoefficients.size()-1] == 0) {
|
||||
if(fVerbose > 0) {
|
||||
G4cout << "G4PolynomialPDF::Simplify() WARNING: had to pop coefficient "
|
||||
<< fCoefficients.size()-1 << G4endl;
|
||||
}
|
||||
fCoefficients.pop_back();
|
||||
fChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
void G4PolynomialPDF::SetDomain(G4double x1, G4double x2)
|
||||
{
|
||||
if(x2 <= x1) {
|
||||
if(fVerbose > 0) {
|
||||
G4cout << "G4PolynomialPDF::SetDomain() WARNING: Invalid domain! "
|
||||
<< "(x1 = " << x1 << ", x2 = " << x2 << ")." << G4endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
fX1 = x1;
|
||||
fX2 = x2;
|
||||
fChanged = true;
|
||||
}
|
||||
|
||||
void G4PolynomialPDF::Normalize()
|
||||
{
|
||||
/// Normalize PDF to 1 over domain fX1 to fX2.
|
||||
/// Double-check that the highest-order coefficient is non-zero.
|
||||
while(fCoefficients.size()) { /* Loop checking, 30-Oct-2015, G.Folger */
|
||||
if(fCoefficients[fCoefficients.size()-1] == 0.0) fCoefficients.pop_back();
|
||||
else break;
|
||||
}
|
||||
|
||||
G4double x1N = fX1, x2N = fX2;
|
||||
G4double sum = 0;
|
||||
for(size_t i=0; i<GetNCoefficients(); ++i) {
|
||||
sum += GetCoefficient(i)*(x2N - x1N)/G4double(i+1);
|
||||
x1N*=fX1;
|
||||
x2N*=fX2;
|
||||
}
|
||||
if(sum <= 0) {
|
||||
if(fVerbose > 0) {
|
||||
G4cout << "G4PolynomialPDF::Normalize() WARNING: PDF has non-positive area: "
|
||||
<< sum << G4endl;
|
||||
Dump();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for(size_t i=0; i<GetNCoefficients(); ++i) {
|
||||
SetCoefficient(i, GetCoefficient(i)/sum, false);
|
||||
}
|
||||
Simplify();
|
||||
}
|
||||
|
||||
G4double G4PolynomialPDF::Evaluate(G4double x, G4int ddxPower)
|
||||
{
|
||||
/// Evaluate f(x)
|
||||
/// ddxPower = -1: f = CDF
|
||||
/// ddxPower = 0: f = PDF
|
||||
/// ddxPower = 1: f = (d/dx) PDF
|
||||
/// ddxPower = 2: f = (d2/dx2) PDF
|
||||
if(ddxPower < -1 || ddxPower > 2) {
|
||||
if(fVerbose > 0) {
|
||||
G4cout << "G4PolynomialPDF::GetX() WARNING: ddxPower " << ddxPower
|
||||
<< " not implemented" << G4endl;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double f = 0.; // return value
|
||||
double xN = 1.; // x to the power N
|
||||
double x1N = 1.; // endpoint x1 to the power N; only used by CDF
|
||||
for(size_t i=0; i<=GetNCoefficients(); ++i) {
|
||||
if(ddxPower == -1) { // CDF
|
||||
if(i>0) f += GetCoefficient(i-1)*(xN - x1N)/i;
|
||||
x1N *= fX1;
|
||||
}
|
||||
else if(ddxPower == 0 && i<GetNCoefficients()) f += GetCoefficient(i)*xN; // PDF
|
||||
else if(ddxPower == 1) { // (d/dx) PDF
|
||||
if(i<GetNCoefficients()-1) f += GetCoefficient(i+1)*xN*(i+1);
|
||||
}
|
||||
else if(ddxPower == 2) { // (d2/dx2) PDF
|
||||
if(i<GetNCoefficients()-2) f += GetCoefficient(i+2)*xN*((i+2)*(i+1));
|
||||
}
|
||||
xN *= x;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
G4bool G4PolynomialPDF::HasNegativeMinimum(G4double x1, G4double x2)
|
||||
{
|
||||
// ax2 + bx + c = 0
|
||||
// p': 2ax + b = 0 -> = 0 at min: x_extreme = -b/2a
|
||||
|
||||
if(x1 < fX1 || x2 > fX2 || x2 < x1) {
|
||||
if(fVerbose > 0) {
|
||||
G4cout << "G4PolynomialPDF::HasNegativeMinimum() WARNING: Invalid range "
|
||||
<< x1 << " - " << x2 << G4endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// If flat, then check anywhere.
|
||||
if(GetNCoefficients() == 1) return (Evaluate(x1) < -fTolerance);
|
||||
|
||||
// If linear, or if quadratic with negative second derivative,
|
||||
// just check the endpoints
|
||||
if(GetNCoefficients() == 2 ||
|
||||
(GetNCoefficients() == 3 && GetCoefficient(2) <= 0)) {
|
||||
return (Evaluate(x1) < -fTolerance) || (Evaluate(x2) < -fTolerance);
|
||||
}
|
||||
|
||||
// If quadratic and second dervative is positive, check at the mininum
|
||||
if(GetNCoefficients() == 3) {
|
||||
G4double xMin = -GetCoefficient(1)*0.5/GetCoefficient(2);
|
||||
if(xMin < x1) xMin = x1;
|
||||
if(xMin > x2) xMin = x2;
|
||||
return Evaluate(xMin) < -fTolerance;
|
||||
}
|
||||
|
||||
// Higher-order polynomials: consider any extremum between x1 and x2. If none
|
||||
// are found, check the endpoints.
|
||||
G4double extremum = GetX(0, x1, x2, 1);
|
||||
if(Evaluate(extremum) < -fTolerance) return true;
|
||||
else if(extremum <= x1+(x2-x1)*fTolerance ||
|
||||
extremum >= x2-(x2-x1)*fTolerance) return false;
|
||||
else return
|
||||
HasNegativeMinimum(x1, extremum) || HasNegativeMinimum(extremum, x2);
|
||||
}
|
||||
|
||||
G4double G4PolynomialPDF::GetRandomX()
|
||||
{
|
||||
if(fChanged) {
|
||||
Normalize();
|
||||
if(HasNegativeMinimum(fX1, fX2)) {
|
||||
if(fVerbose > 0) {
|
||||
G4cout << "G4PolynomialPDF::GetRandomX() WARNING: PDF has negative values, returning 0..."
|
||||
<< G4endl;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
fChanged = false;
|
||||
}
|
||||
return EvalInverseCDF(G4UniformRand());
|
||||
}
|
||||
|
||||
G4double G4PolynomialPDF::GetX(G4double p, G4double x1, G4double x2,
|
||||
G4int ddxPower, G4double guess, G4bool bisect)
|
||||
{
|
||||
/// Find a value of X between x1 and x2 at which f(x) = p.
|
||||
/// ddxPower = -1: f = CDF
|
||||
/// ddxPower = 0: f = PDF
|
||||
/// ddxPower = 1: f = (d/dx) PDF
|
||||
/// Uses the Newton-Raphson method to find the zero of f(x) - p.
|
||||
/// If not found in range, returns the nearest boundary
|
||||
|
||||
// input range checking
|
||||
if(GetNCoefficients() == 0) {
|
||||
if(fVerbose > 0) {
|
||||
G4cout << "G4PolynomialPDF::GetX() WARNING: no PDF defined!" << G4endl;
|
||||
}
|
||||
return x2;
|
||||
}
|
||||
if(ddxPower < -1 || ddxPower > 1) {
|
||||
if(fVerbose > 0) {
|
||||
G4cout << "G4PolynomialPDF::GetX() WARNING: ddxPower " << ddxPower
|
||||
<< " not implemented" << G4endl;
|
||||
}
|
||||
return x2;
|
||||
}
|
||||
if(ddxPower == -1 && (p<0 || p>1)) {
|
||||
if(fVerbose > 0) {
|
||||
G4cout << "G4PolynomialPDF::GetX() WARNING: p is out of range" << G4endl;
|
||||
}
|
||||
return fX2;
|
||||
}
|
||||
|
||||
// check limits
|
||||
if(x2 <= x1 || x1 < fX1 || x2 > fX2) {
|
||||
if(fVerbose > 0) {
|
||||
G4cout << "G4PolynomialPDF::GetX() WARNING: domain must have fX1 <= x1 < x2 <= fX2. "
|
||||
<< "You sent x1 = " << x1 << ", x2 = " << x2 << "." << G4endl;
|
||||
}
|
||||
return x2;
|
||||
}
|
||||
|
||||
// Return x2 for flat lines
|
||||
if((ddxPower == 0 && GetNCoefficients() == 1) ||
|
||||
(ddxPower == 1 && GetNCoefficients() == 2)) return x2;
|
||||
|
||||
// Solve p = mx + b -> x = (p-b)/m for linear functions
|
||||
if((ddxPower == -1 && GetNCoefficients() == 1) ||
|
||||
(ddxPower == 0 && GetNCoefficients() == 2) ||
|
||||
(ddxPower == 1 && GetNCoefficients() == 3)) {
|
||||
G4double b = (ddxPower > -1) ? GetCoefficient(ddxPower) : -GetCoefficient(0)*fX1;
|
||||
G4double slope = GetCoefficient(ddxPower+1); // the highest-order coefficient
|
||||
if(slope == 0) { // the highest-order coefficient should never be zero if simplified
|
||||
if(fVerbose > 0) {
|
||||
G4cout << "G4PolynomialPDF::GetX() WARNING: Got slope = 0. "
|
||||
<< "Did you forget to Simplify()?" << G4endl;
|
||||
}
|
||||
return x2;
|
||||
}
|
||||
if(ddxPower == 1) slope *= 2.;
|
||||
G4double value = (p-b)/slope;
|
||||
if(value < x1) {
|
||||
return x1;
|
||||
}
|
||||
else if(value > x2) {
|
||||
return x2;
|
||||
}
|
||||
else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// Solve quadratic equation for f-p=0 when f is quadratic
|
||||
if((ddxPower == -1 && GetNCoefficients() == 2) ||
|
||||
(ddxPower == 0 && GetNCoefficients() == 3) ||
|
||||
(ddxPower == 1 && GetNCoefficients() == 4)) {
|
||||
G4double c = -p + ((ddxPower > -1) ? GetCoefficient(ddxPower) : 0);
|
||||
if(ddxPower == -1) c -= (GetCoefficient(0) + GetCoefficient(1)/2.*fX1)*fX1;
|
||||
G4double b = GetCoefficient(ddxPower+1);
|
||||
if(ddxPower == 1) b *= 2.;
|
||||
G4double a = GetCoefficient(ddxPower+2); // the highest-order coefficient
|
||||
if(a == 0) { // the highest-order coefficient should never be 0 if simplified
|
||||
if(fVerbose > 0) {
|
||||
G4cout << "G4PolynomialPDF::GetX() WARNING: Got a = 0. "
|
||||
<< "Did you forget to Simplify()?" << G4endl;
|
||||
}
|
||||
return x2;
|
||||
}
|
||||
if(ddxPower == 1) a *= 3;
|
||||
else if(ddxPower == -1) a *= 0.5;
|
||||
double sqrtFactor = b*b - 4.*a*c;
|
||||
if(sqrtFactor < 0) return x2; // quadratic equation has no solution (p not in range of f)
|
||||
sqrtFactor = sqrt(sqrtFactor)/2./fabs(a);
|
||||
G4double valueMinus = -b/2./a - sqrtFactor;
|
||||
if(valueMinus >= x1 && valueMinus <= x2) return valueMinus;
|
||||
else if(valueMinus > x2) return x2;
|
||||
G4double valuePlus = -b/2./a + sqrtFactor;
|
||||
if(valuePlus >= x1 && valuePlus <= x2) return valuePlus;
|
||||
else if(valuePlus < x1) return x2;
|
||||
return (x1-valueMinus <= valuePlus-x2) ? x1 : x2;
|
||||
}
|
||||
|
||||
// f is non-trivial, so use Newton-Raphson
|
||||
// start in the middle if no good guess is provided
|
||||
if(guess < x1 || guess > x2) guess = (x2+x1)*0.5;
|
||||
G4double lastChange = 1;
|
||||
size_t iterations = 0;
|
||||
while(fabs(lastChange) > fTolerance) { /* Loop checking, 02.11.2015, A.Ribon */
|
||||
// calculate f and f' simultaneously
|
||||
G4double f = -p;
|
||||
G4double dfdx = 0;
|
||||
G4double xN = 1;
|
||||
G4double x1N = 1; // only used by CDF
|
||||
for(size_t i=0; i<=GetNCoefficients(); ++i) {
|
||||
if(ddxPower == -1) { // CDF
|
||||
if(i>0) f += GetCoefficient(i-1)*(xN - x1N)/G4double(i);
|
||||
if(i<GetNCoefficients()) dfdx += GetCoefficient(i)*xN;
|
||||
x1N *= fX1;
|
||||
}
|
||||
else if(ddxPower == 0) { // PDF
|
||||
if(i<GetNCoefficients()) f += GetCoefficient(i)*xN;
|
||||
if(i+1<GetNCoefficients()) dfdx += GetCoefficient(i+1)*xN*G4double(i+1);
|
||||
}
|
||||
else { // ddxPower == 1: (d/dx) PDF
|
||||
if(i+1<GetNCoefficients()) f += GetCoefficient(i+1)*xN*G4double(i+1);
|
||||
if(i+2<GetNCoefficients()) dfdx += GetCoefficient(i+2)*xN*G4double(i+2);
|
||||
}
|
||||
xN *= guess;
|
||||
}
|
||||
if(f == 0) return guess;
|
||||
if(dfdx == 0) {
|
||||
if(fVerbose > 0) {
|
||||
G4cout << "G4PolynomialPDF::GetX() WARNING: got f != 0 but slope = 0 for ddxPower = "
|
||||
<< ddxPower << G4endl;
|
||||
}
|
||||
return x2;
|
||||
}
|
||||
lastChange = - f/dfdx;
|
||||
|
||||
if(guess + lastChange < x1) {
|
||||
lastChange = x1 - guess;
|
||||
} else if(guess + lastChange > x2) {
|
||||
lastChange = x2 - guess;
|
||||
}
|
||||
|
||||
guess += lastChange;
|
||||
lastChange /= (fX2-fX1);
|
||||
|
||||
++iterations;
|
||||
if(iterations > 50) {
|
||||
if(p!=0) {
|
||||
if(fVerbose > 0) {
|
||||
G4cout << "G4PolynomialPDF::GetX() WARNING: got stuck searching for " << p
|
||||
<< " between " << x1 << " and " << x2 << " with ddxPower = "
|
||||
<< ddxPower
|
||||
<< ". Last guess was " << guess << "." << G4endl;
|
||||
}
|
||||
}
|
||||
if(ddxPower==-1 && bisect) {
|
||||
if(fVerbose > 0) {
|
||||
G4cout << "G4PolynomialPDF::GetX() WARNING: Biseting and trying again..."
|
||||
<< G4endl;
|
||||
}
|
||||
return Bisect(p, x1, x2);
|
||||
}
|
||||
else return guess;
|
||||
}
|
||||
}
|
||||
return guess;
|
||||
}
|
||||
|
||||
G4double G4PolynomialPDF::Bisect( G4double p, G4double x1, G4double x2 ) {
|
||||
// Bisect to get 1% precision, then use Newton-Raphson
|
||||
G4double z = (x2 + x1)/2.0; // [x1 z x2]
|
||||
if((x2 - x1)/(fX2 - fX1) < 0.01) return GetX(p, fX1, fX2, -1, z, false);
|
||||
G4double fz = Evaluate(z, -1) - p;
|
||||
if(fz < 0) return Bisect(p, z, x2); // [z x2]
|
||||
return Bisect(p, x1, z); // [x1 z]
|
||||
}
|
||||
|
||||
void G4PolynomialPDF::Dump()
|
||||
{
|
||||
G4cout << "G4PolynomialPDF::Dump() - PDF(x) = ";
|
||||
for(size_t i=0; i<GetNCoefficients(); i++) {
|
||||
if(i>0) G4cout << " + ";
|
||||
G4cout << GetCoefficient(i);
|
||||
if(i>0) G4cout << "*x";
|
||||
if(i>1) G4cout << "^" << i;
|
||||
}
|
||||
G4cout << G4endl;
|
||||
G4cout << "G4PolynomialPDF::Dump() - Interval: " << fX1 << " <= x < "
|
||||
<< fX2 << G4endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
//
|
||||
// ------------------------------------------------------------
|
||||
// GEANT 4 class header file
|
||||
//
|
||||
// ---------------- G4SampleResonance ----------------
|
||||
// by Henning Weber, March 2001.
|
||||
// helper class for sampling resonance masses
|
||||
// ------------------------------------------------------------
|
||||
|
||||
|
||||
#include "globals.hh"
|
||||
#include <iostream>
|
||||
#include "G4SampleResonance.hh"
|
||||
#include "G4DecayTable.hh"
|
||||
#include "Randomize.hh"
|
||||
#include "G4HadronicException.hh"
|
||||
|
||||
G4ThreadLocal G4SampleResonance::minMassMapType *G4SampleResonance::minMassCache_G4MT_TLS_ = 0;
|
||||
|
||||
G4double G4SampleResonance::GetMinimumMass(const G4ParticleDefinition* p) const
|
||||
{ ;;; if (!minMassCache_G4MT_TLS_) minMassCache_G4MT_TLS_ = new G4SampleResonance::minMassMapType ; G4SampleResonance::minMassMapType &minMassCache = *minMassCache_G4MT_TLS_; ;;;
|
||||
|
||||
G4double minResonanceMass = DBL_MAX;
|
||||
|
||||
if ( p->IsShortLived() )
|
||||
{
|
||||
minMassMapIterator iter = minMassCache.find(p);
|
||||
if ( iter!=minMassCache.end() )
|
||||
{
|
||||
minResonanceMass = (*iter).second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// G4cout << "--> request for " << p->GetParticleName() << G4endl;
|
||||
|
||||
const G4DecayTable* theDecays = p->GetDecayTable();
|
||||
const G4int nDecays = theDecays->entries();
|
||||
|
||||
for (G4int i=0; i<nDecays; i++)
|
||||
{
|
||||
const G4VDecayChannel* aDecay = theDecays->GetDecayChannel(i);
|
||||
const G4int nDaughters = aDecay->GetNumberOfDaughters();
|
||||
|
||||
G4double minChannelMass = 0;
|
||||
|
||||
for (G4int j=0; j<nDaughters; j++)
|
||||
{
|
||||
const G4ParticleDefinition* aDaughter = const_cast<G4VDecayChannel*>(aDecay)->GetDaughter(j);
|
||||
G4double minMass = GetMinimumMass(aDaughter);
|
||||
if (!minMass) minMass = DBL_MAX; // exclude gamma channel;
|
||||
minChannelMass+=minMass;
|
||||
}
|
||||
// G4cout << "channel mass for the above is " << minChannelMass/MeV << G4endl;
|
||||
if (minChannelMass < minResonanceMass) minResonanceMass = minChannelMass;
|
||||
|
||||
}
|
||||
// replace this as soon as the compiler supports mutable!!
|
||||
G4SampleResonance* self = const_cast<G4SampleResonance*>(this);
|
||||
//Andrea Dotti (13Jan2013): Change needed for G4MT
|
||||
//(self->minMassCache)[p] = minResonanceMass;
|
||||
self->minMassCache_G4MT_TLS_->operator[](p) = minResonanceMass;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
minResonanceMass = p->GetPDGMass();
|
||||
|
||||
}
|
||||
// G4cout << "minimal mass for " << p->GetParticleName() << " is " << minResonanceMass/MeV << G4endl;
|
||||
|
||||
return minResonanceMass;
|
||||
}
|
||||
|
||||
|
||||
|
||||
G4double G4SampleResonance::SampleMass(const G4ParticleDefinition* p, const G4double maxMass) const
|
||||
{ if (!minMassCache_G4MT_TLS_) minMassCache_G4MT_TLS_ = new G4SampleResonance::minMassMapType ;
|
||||
return SampleMass(p->GetPDGMass(), p->GetPDGWidth(), GetMinimumMass(p), maxMass);
|
||||
}
|
||||
|
||||
|
||||
G4double G4SampleResonance::SampleMass(const G4double poleMass,
|
||||
const G4double gamma,
|
||||
const G4double minMass,
|
||||
const G4double maxMass) const
|
||||
{ if (!minMassCache_G4MT_TLS_) minMassCache_G4MT_TLS_ = new G4SampleResonance::minMassMapType ;
|
||||
// Chooses a mass randomly between minMass and maxMass
|
||||
// according to a Breit-Wigner function with constant
|
||||
// width gamma and pole poleMass
|
||||
|
||||
|
||||
//AR-14Nov2017 : protection for rare cases when a wide parent resonance, with a very small
|
||||
// dynamic mass, decays into another wide (daughter) resonance: it can happen
|
||||
// then that for the daugther resonance minMass > maxMass : in these cases,
|
||||
// do not crash, but simply consider maxMass as the minimal mass for
|
||||
// the sampling of the daughter resonance mass.
|
||||
G4double protectedMinMass = minMass;
|
||||
if ( minMass > maxMass )
|
||||
{
|
||||
//throw G4HadronicException(__FILE__, __LINE__,
|
||||
// "SampleResonanceMass: mass range negative (minMass>maxMass)");
|
||||
protectedMinMass = maxMass;
|
||||
}
|
||||
|
||||
G4double returnMass;
|
||||
|
||||
if ( gamma < DBL_EPSILON )
|
||||
{
|
||||
returnMass = std::max(minMass, std::min(maxMass, poleMass));
|
||||
}
|
||||
else
|
||||
{
|
||||
//double fmin = BrWigInt0(minMass, gamma, poleMass);
|
||||
double fmin = BrWigInt0(protectedMinMass, gamma, poleMass);
|
||||
double fmax = BrWigInt0(maxMass, gamma, poleMass);
|
||||
double f = fmin + (fmax-fmin)*G4UniformRand();
|
||||
returnMass = BrWigInv(f, gamma, poleMass);
|
||||
}
|
||||
|
||||
return returnMass;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
//
|
||||
#include "G4V3DNucleus.hh"
|
||||
#include "G4HadronicException.hh"
|
||||
|
||||
G4V3DNucleus::G4V3DNucleus()
|
||||
{
|
||||
}
|
||||
|
||||
G4V3DNucleus::G4V3DNucleus(const G4V3DNucleus &)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
G4V3DNucleus::~G4V3DNucleus()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
const G4V3DNucleus & G4V3DNucleus::operator=(const G4V3DNucleus &)
|
||||
{
|
||||
G4String text = "G4V3DNucleus::operator= meant to not be accessible";
|
||||
throw G4HadronicException(__FILE__, __LINE__, text);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
G4bool G4V3DNucleus::operator==(const G4V3DNucleus &) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
G4bool G4V3DNucleus::operator!=(const G4V3DNucleus &) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// Abstract base class for multibody "phase space" generators. Subclasses
|
||||
// implement a specific algorithm, such as Kopylov, GENBOD, or Makoto's
|
||||
// NBody. Subclasses are used by G4HadPhaseSpaceGenerator.
|
||||
//
|
||||
// Author: Michael Kelsey (SLAC) <kelsey@slac.stanford.edu>
|
||||
|
||||
#include "G4VHadDecayAlgorithm.hh"
|
||||
#include "G4HadronicException.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
#include "G4ThreeVector.hh"
|
||||
#include "Randomize.hh"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
|
||||
// Initial state (rest mass) and list of final masses
|
||||
|
||||
void G4VHadDecayAlgorithm::Generate(G4double initialMass,
|
||||
const std::vector<G4double>& masses,
|
||||
std::vector<G4LorentzVector>& finalState) {
|
||||
if (verboseLevel) G4cout << GetName() << "::Generate" << G4endl;
|
||||
|
||||
// Initialization and sanity check
|
||||
finalState.clear();
|
||||
if (!IsDecayAllowed(initialMass, masses)) return;
|
||||
|
||||
// Allow different procedures for two-body or N-body distributions
|
||||
if (masses.size() == 2U)
|
||||
GenerateTwoBody(initialMass, masses, finalState);
|
||||
else
|
||||
GenerateMultiBody(initialMass, masses, finalState);
|
||||
}
|
||||
|
||||
|
||||
// Base class does very simple validation of configuration
|
||||
|
||||
G4bool G4VHadDecayAlgorithm::
|
||||
IsDecayAllowed(G4double initialMass,
|
||||
const std::vector<G4double>& masses) const {
|
||||
G4bool okay =
|
||||
(initialMass > 0. && masses.size() >= 2 &&
|
||||
initialMass >= std::accumulate(masses.begin(),masses.end(),0.));
|
||||
|
||||
if (verboseLevel) {
|
||||
G4cout << GetName() << "::IsDecayAllowed? initialMass " << initialMass
|
||||
<< " " << masses.size() << " masses sum "
|
||||
<< std::accumulate(masses.begin(),masses.end(),0.) << G4endl;
|
||||
|
||||
if (verboseLevel>1) PrintVector(masses," ",G4cout);
|
||||
|
||||
G4cout << " Returning " << okay << G4endl;
|
||||
}
|
||||
|
||||
return okay;
|
||||
}
|
||||
|
||||
|
||||
// Momentum function (c.f. PDK() function from CERNLIB W515)
|
||||
|
||||
G4double G4VHadDecayAlgorithm::TwoBodyMomentum(G4double M0, G4double M1,
|
||||
G4double M2) const {
|
||||
G4double PSQ = (M0+M1+M2)*(M0+M1-M2)*(M0-M1+M2)*(M0-M1-M2);
|
||||
if (PSQ < 0.) {
|
||||
G4cout << GetName() << ": problem of decay of M(GeV) " << M0/GeV
|
||||
<< " to M1(GeV) " << M1/GeV << " and M2(GeV) " << M2/GeV
|
||||
<< " PSQ(MeV) " << PSQ/MeV << " < 0" << G4endl;
|
||||
// exception only if the problem is numerically significant
|
||||
if (PSQ < -CLHEP::eV) {
|
||||
throw G4HadronicException(__FILE__, __LINE__,"Error in decay kinematics");
|
||||
}
|
||||
|
||||
PSQ = 0.;
|
||||
}
|
||||
|
||||
return std::sqrt(PSQ)/(2.*M0);
|
||||
}
|
||||
|
||||
// Convenience functions for uniform angular distributions
|
||||
|
||||
G4double G4VHadDecayAlgorithm::UniformTheta() const {
|
||||
return std::acos(2.0*G4UniformRand() - 1.0);
|
||||
}
|
||||
|
||||
G4double G4VHadDecayAlgorithm::UniformPhi() const {
|
||||
return twopi*G4UniformRand();
|
||||
}
|
||||
|
||||
|
||||
// Dump contents of vector to output
|
||||
|
||||
void G4VHadDecayAlgorithm::
|
||||
PrintVector(const std::vector<G4double>& v,
|
||||
const G4String& vname, std::ostream& os) const {
|
||||
os << " " << vname << "(" << v.size() << ") ";
|
||||
std::copy(v.begin(), v.end(), std::ostream_iterator<G4double>(os, " "));
|
||||
os << std::endl;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
// Abstract base class for multibody uniform phase space generators.
|
||||
// Subclasses implement a specific algorithm, such as Kopylov, GENBOD,
|
||||
// or Makoto's NBody. Subclasses are used by G4HadDecayGenerator.
|
||||
//
|
||||
// Author: Michael Kelsey (SLAC) <kelsey@slac.stanford.edu>
|
||||
|
||||
#include "G4VHadPhaseSpaceAlgorithm.hh"
|
||||
#include "G4HadronicException.hh"
|
||||
#include "G4PhysicalConstants.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
#include "G4ThreeVector.hh"
|
||||
#include "Randomize.hh"
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
|
||||
// Two body decay with uniform angular distribution
|
||||
|
||||
void G4VHadPhaseSpaceAlgorithm::
|
||||
GenerateTwoBody(G4double initialMass,
|
||||
const std::vector<G4double>& masses,
|
||||
std::vector<G4LorentzVector>& finalState) {
|
||||
if (GetVerboseLevel()>1)
|
||||
G4cout << " >>> G4HadDecayGenerator::FillTwoBody" << G4endl;
|
||||
|
||||
// Initialization and sanity check
|
||||
finalState.clear();
|
||||
if (masses.size() != 2U) return; // Should not have been called
|
||||
|
||||
// Momentum of final state (energy balance has already been checked)
|
||||
G4double p = TwoBodyMomentum(initialMass,masses[0],masses[1]);
|
||||
if (GetVerboseLevel()>2) G4cout << " finalState momentum = " << p << G4endl;
|
||||
|
||||
finalState.resize(2); // Allows filling by index
|
||||
finalState[0].setVectM(UniformVector(p), masses[0]);
|
||||
finalState[1].setVectM(-finalState[0].vect(), masses[1]);
|
||||
}
|
||||
|
||||
|
||||
// Samples a random vector with given magnitude
|
||||
|
||||
G4ThreeVector G4VHadPhaseSpaceAlgorithm::UniformVector(G4double mag) const {
|
||||
// FIXME: Should this be made a static thread-local buffer?
|
||||
G4ThreeVector v;
|
||||
v.setRThetaPhi(mag, UniformTheta(), UniformPhi());
|
||||
return v;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
//
|
||||
//
|
||||
#include "G4VKineticNucleon.hh"
|
||||
|
||||
G4VKineticNucleon::G4VKineticNucleon()
|
||||
{
|
||||
}
|
||||
|
||||
G4VKineticNucleon::G4VKineticNucleon(const G4VKineticNucleon &)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
G4VKineticNucleon::~G4VKineticNucleon()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//const G4VKineticNucleon & G4VKineticNucleon::operator=(const G4VKineticNucleon &right)
|
||||
//{}
|
||||
|
||||
|
||||
G4bool G4VKineticNucleon::operator==(const G4VKineticNucleon &right) const
|
||||
{
|
||||
return this == &right;
|
||||
}
|
||||
|
||||
G4bool G4VKineticNucleon::operator!=(const G4VKineticNucleon &right) const
|
||||
{
|
||||
return this != &right;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+10
-2
@@ -23,6 +23,14 @@
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
#include "G4IsoResult.hh"
|
||||
//
|
||||
//
|
||||
|
||||
G4IsoResult::~G4IsoResult(){}
|
||||
#include "G4VNuclearDensity.hh"
|
||||
|
||||
G4VNuclearDensity::G4VNuclearDensity() :
|
||||
rho0(0.)
|
||||
{}
|
||||
|
||||
G4VNuclearDensity::~G4VNuclearDensity() {}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
//
|
||||
// ********************************************************************
|
||||
// * License and Disclaimer *
|
||||
// * *
|
||||
// * The Geant4 software is copyright of the Copyright Holders of *
|
||||
// * the Geant4 Collaboration. It is provided under the terms and *
|
||||
// * conditions of the Geant4 Software License, included in the file *
|
||||
// * LICENSE and available at http://cern.ch/geant4/license . These *
|
||||
// * include a list of copyright holders. *
|
||||
// * *
|
||||
// * Neither the authors of this software system, nor their employing *
|
||||
// * institutes,nor the agencies providing financial support for this *
|
||||
// * work make any representation or warranty, express or implied, *
|
||||
// * regarding this software system or assume any liability for its *
|
||||
// * use. Please see the license in the file LICENSE and URL above *
|
||||
// * for the full disclaimer and the limitation of liability. *
|
||||
// * *
|
||||
// * This code implementation is the result of the scientific and *
|
||||
// * technical work of the GEANT4 collaboration. *
|
||||
// * *
|
||||
// * Parts of this code which have been developed by QinetiQ Ltd *
|
||||
// * under contract to the European Space Agency (ESA) are the *
|
||||
// * intellectual property of ESA. Rights to use, copy, modify and *
|
||||
// * redistribute this software for general public use are granted *
|
||||
// * in compliance with any licensing, distribution and development *
|
||||
// * policy adopted by the Geant4 Collaboration. This code has been *
|
||||
// * written by QinetiQ Ltd for the European Space Agency, under ESA *
|
||||
// * contract 17191/03/NL/LvH (Aurora Programme). *
|
||||
// * *
|
||||
// * By using, copying, modifying or distributing the software (or *
|
||||
// * any work based on the software) you agree to acknowledge its *
|
||||
// * use in resulting scientific publications, and indicate your *
|
||||
// * acceptance of all terms of the Geant4 Software license. *
|
||||
// ********************************************************************
|
||||
//
|
||||
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
// MODULE: G4WilsonRadius.cc
|
||||
//
|
||||
// Version: B.1
|
||||
// Date: 15/04/04
|
||||
// Author: P R Truscott
|
||||
// Organisation: QinetiQ Ltd, UK
|
||||
// Customer: ESA/ESTEC, NOORDWIJK
|
||||
// Contract: 17191/03/NL/LvH
|
||||
//
|
||||
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
// CHANGE HISTORY
|
||||
// --------------
|
||||
//
|
||||
// 6 October 2003, P R Truscott, QinetiQ Ltd, UK
|
||||
// Created.
|
||||
//
|
||||
// 15 March 2004, P R Truscott, QinetiQ Ltd, UK
|
||||
// Beta release
|
||||
//
|
||||
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
#include "G4WilsonRadius.hh"
|
||||
#include "G4SystemOfUnits.hh"
|
||||
#include "G4Pow.hh"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
G4WilsonRadius::G4WilsonRadius ()
|
||||
{
|
||||
G4double r0 = 0.84*fermi;
|
||||
r0sq = r0 * r0;
|
||||
factor = std::sqrt(5.0/3.0) * fermi;
|
||||
third = 1.0 / 3.0;
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
G4WilsonRadius::~G4WilsonRadius ()
|
||||
{;}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
G4double G4WilsonRadius::GetWilsonRMSRadius (G4double A)
|
||||
{
|
||||
G4double radius;
|
||||
if (A > 26.0)
|
||||
radius = factor * (0.84*G4Pow::GetInstance()->A13(A) + 0.55);
|
||||
else
|
||||
{
|
||||
// this was changed from just G4double to static const G4double
|
||||
// to make sure that time wasn't being wasted on every call reloading a stack variable
|
||||
// by MHM 20050119
|
||||
static const G4double r[27] = {0.0, 0.85, 2.095, 1.976, 1.671, 1.986,
|
||||
2.57, 2.41, 2.23, 2.519, 2.45,
|
||||
2.42, 2.471, 2.440, 2.58, 2.611,
|
||||
2.730, 2.662, 2.727, 2.9, 3.040,
|
||||
2.867, 2.969, 2.94, 3.075, 3.11,
|
||||
3.06};
|
||||
radius = factor * r[(G4int) (A+0.4)];
|
||||
}
|
||||
return radius;
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
G4double G4WilsonRadius::GetWilsonRadius (G4double A)
|
||||
{
|
||||
G4double r = GetWilsonRMSRadius(A);
|
||||
return 1.29*std::sqrt(r*r-r0sq);
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
Reference in New Issue
Block a user