Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4NucleiModel Class Reference

#include <G4NucleiModel.hh>

Public Types

typedef std::pair< std::vector< G4CascadParticle >, std::vector< G4InuclElementaryParticle > > modelLists
 

Public Member Functions

 G4NucleiModel ()
 
 G4NucleiModel (G4int a, G4int z)
 
 G4NucleiModel (G4InuclNuclei *nuclei)
 
virtual ~G4NucleiModel ()
 
void setVerboseLevel (G4int verbose)
 
void generateModel (G4InuclNuclei *nuclei)
 
void generateModel (G4int a, G4int z)
 
void reset (G4int nHitNeutrons=0, G4int nHitProtons=0, const std::vector< G4ThreeVector > *hitPoints=0)
 
void printModel () const
 
G4double getDensity (G4int ip, G4int izone) const
 
G4double getFermiMomentum (G4int ip, G4int izone) const
 
G4double getFermiKinetic (G4int ip, G4int izone) const
 
G4double getPotential (G4int ip, G4int izone) const
 
G4double getRadiusUnits () const
 
G4double getRadius () const
 
G4double getRadius (G4int izone) const
 
G4double getVolume (G4int izone) const
 
G4int getNumberOfZones () const
 
G4int getZone (G4double r) const
 
G4int getNumberOfNeutrons () const
 
G4int getNumberOfProtons () const
 
G4bool empty () const
 
G4bool stillInside (const G4CascadParticle &cparticle)
 
G4CascadParticle initializeCascad (G4InuclElementaryParticle *particle)
 
void initializeCascad (G4InuclNuclei *bullet, G4InuclNuclei *target, modelLists &output)
 
std::pair< G4int, G4intgetTypesOfNucleonsInvolved () const
 
void generateParticleFate (G4CascadParticle &cparticle, G4ElementaryParticleCollider *theEPCollider, std::vector< G4CascadParticle > &cascade)
 
G4bool forceFirst (const G4CascadParticle &cparticle) const
 
G4bool isProjectile (const G4CascadParticle &cparticle) const
 
G4bool worthToPropagate (const G4CascadParticle &cparticle) const
 
G4InuclElementaryParticle generateNucleon (G4int type, G4int zone) const
 
G4LorentzVector generateNucleonMomentum (G4int type, G4int zone) const
 
G4double absorptionCrossSection (G4double e, G4int type) const
 
G4double totalCrossSection (G4double ke, G4int rtype) const
 

Static Public Member Functions

static G4bool useQuasiDeuteron (G4int ptype, G4int qdtype=0)
 

Protected Types

typedef std::pair< G4InuclElementaryParticle, G4doublepartner
 

Protected Member Functions

G4bool passFermi (const std::vector< G4InuclElementaryParticle > &particles, G4int zone)
 
G4bool passTrailing (const G4ThreeVector &hit_position)
 
void boundaryTransition (G4CascadParticle &cparticle)
 
void choosePointAlongTraj (G4CascadParticle &cparticle)
 
G4InuclElementaryParticle generateQuasiDeuteron (G4int type1, G4int type2, G4int zone) const
 
void generateInteractionPartners (G4CascadParticle &cparticle)
 
void fillBindingEnergies ()
 
void fillZoneRadii (G4double nuclearRadius)
 
G4double fillZoneVolumes (G4double nuclearRadius)
 
void fillPotentials (G4int type, G4double tot_vol)
 
G4double zoneIntegralWoodsSaxon (G4double ur1, G4double ur2, G4double nuclearRadius) const
 
G4double zoneIntegralGaussian (G4double ur1, G4double ur2, G4double nuclearRadius) const
 
G4double getRatio (G4int ip) const
 
G4double getCurrentDensity (G4int ip, G4int izone) const
 
G4double inverseMeanFreePath (const G4CascadParticle &cparticle, const G4InuclElementaryParticle &target, G4int zone=-1)
 
G4double generateInteractionLength (const G4CascadParticle &cparticle, G4double path, G4double invmfp) const
 

Static Protected Member Functions

static G4bool sortPartners (const partner &p1, const partner &p2)
 

Protected Attributes

std::vector< partnerthePartners
 

Detailed Description

Definition at line 91 of file G4NucleiModel.hh.

Member Typedef Documentation

◆ modelLists

Definition at line 161 of file G4NucleiModel.hh.

◆ partner

Definition at line 203 of file G4NucleiModel.hh.

Constructor & Destructor Documentation

◆ G4NucleiModel() [1/3]

G4NucleiModel::G4NucleiModel ( )

Definition at line 232 of file G4NucleiModel.cc.

233 : verboseLevel(0), nuclei_radius(0.), nuclei_volume(0.), number_of_zones(0),
234 A(0), Z(0), theNucleus(0), neutronNumber(0), protonNumber(0),
235 neutronNumberCurrent(0), protonNumberCurrent(0), current_nucl1(0),
236 current_nucl2(0), gammaQDinterp(kebins),
237 crossSectionUnits(G4CascadeParameters::xsecScale()),
239 skinDepth(0.611207*radiusUnits),
240 radiusScale((G4CascadeParameters::useTwoParam()?1.16:1.2)*radiusUnits),
241 radiusScale2((G4CascadeParameters::useTwoParam()?-1.3456:0.)*radiusUnits),
242 radiusForSmall(G4CascadeParameters::radiusSmall()),
243 radScaleAlpha(G4CascadeParameters::radiusAlpha()),
244 fermiMomentum(G4CascadeParameters::fermiScale()),
246 gammaQDscale(G4CascadeParameters::gammaQDScale()),
247 potentialThickness(1.0),
248 neutronEP(neutron), protonEP(proton) {}
static G4double xsecScale()
static G4double radiusScale()
static G4bool useTwoParam()
static G4double gammaQDScale()
static G4double radiusAlpha()
static G4double radiusSmall()
static G4double fermiScale()
static G4double radiusTrailing()

◆ G4NucleiModel() [2/3]

G4NucleiModel::G4NucleiModel ( G4int a,
G4int z )

Definition at line 250 of file G4NucleiModel.cc.

251 : verboseLevel(0), nuclei_radius(0.), nuclei_volume(0.), number_of_zones(0),
252 A(0), Z(0), theNucleus(0), neutronNumber(0), protonNumber(0),
253 neutronNumberCurrent(0), protonNumberCurrent(0), current_nucl1(0),
254 current_nucl2(0), gammaQDinterp(kebins),
255 crossSectionUnits(G4CascadeParameters::xsecScale()),
257 skinDepth(0.611207*radiusUnits),
258 radiusScale((G4CascadeParameters::useTwoParam()?1.16:1.2)*radiusUnits),
259 radiusScale2((G4CascadeParameters::useTwoParam()?-1.3456:0.)*radiusUnits),
260 radiusForSmall(G4CascadeParameters::radiusSmall()),
261 radScaleAlpha(G4CascadeParameters::radiusAlpha()),
262 fermiMomentum(G4CascadeParameters::fermiScale()),
264 gammaQDscale(G4CascadeParameters::gammaQDScale()),
265 potentialThickness(1.0),
266 neutronEP(neutron), protonEP(proton) {
267 generateModel(a,z);
268}
void generateModel(G4InuclNuclei *nuclei)

◆ G4NucleiModel() [3/3]

G4NucleiModel::G4NucleiModel ( G4InuclNuclei * nuclei)
explicit

Definition at line 270 of file G4NucleiModel.cc.

271 : verboseLevel(0), nuclei_radius(0.), nuclei_volume(0.), number_of_zones(0),
272 A(0), Z(0), theNucleus(0), neutronNumber(0), protonNumber(0),
273 neutronNumberCurrent(0), protonNumberCurrent(0), current_nucl1(0),
274 current_nucl2(0), gammaQDinterp(kebins),
275 crossSectionUnits(G4CascadeParameters::xsecScale()),
277 skinDepth(0.611207*radiusUnits),
278 radiusScale((G4CascadeParameters::useTwoParam()?1.16:1.2)*radiusUnits),
279 radiusScale2((G4CascadeParameters::useTwoParam()?-1.3456:0.)*radiusUnits),
280 radiusForSmall(G4CascadeParameters::radiusSmall()),
281 radScaleAlpha(G4CascadeParameters::radiusAlpha()),
282 fermiMomentum(G4CascadeParameters::fermiScale()),
284 gammaQDscale(G4CascadeParameters::gammaQDScale()),
285 potentialThickness(1.0),
286 neutronEP(neutron), protonEP(proton) {
288}

◆ ~G4NucleiModel()

G4NucleiModel::~G4NucleiModel ( )
virtual

Definition at line 290 of file G4NucleiModel.cc.

290 {
291 delete theNucleus;
292 theNucleus = 0;
293}

Member Function Documentation

◆ absorptionCrossSection()

G4double G4NucleiModel::absorptionCrossSection ( G4double e,
G4int type ) const

Definition at line 1922 of file G4NucleiModel.cc.

1922 {
1923 if (!useQuasiDeuteron(type)) {
1924 G4cerr << "absorptionCrossSection() only valid for incident pions or gammas"
1925 << G4endl;
1926 return 0.;
1927 }
1928
1929 G4double csec = 0.;
1930
1931 // Pion absorption is parametrized for low vs. medium energy
1932 // ... use for muon capture as well
1933 if (type == pionPlus || type == pionMinus || type == pionZero ||
1934 type == muonMinus) {
1935 if (ke < 0.3) csec = (0.1106 / std::sqrt(ke) - 0.8
1936 + 0.08 / ((ke-0.123)*(ke-0.123) + 0.0056) );
1937 else if (ke < 1.0) csec = 3.6735 * (1.0-ke)*(1.0-ke);
1938 }
1939
1940 if (type == photon) {
1941 csec = gammaQDinterp.interpolate(ke, gammaQDxsec) * gammaQDscale;
1942 }
1943
1944 if (csec < 0.0) csec = 0.0;
1945
1946 if (verboseLevel > 2) {
1947 G4cout << " ekin " << ke << " abs. csec " << csec << " mb" << G4endl;
1948 }
1949
1950 return crossSectionUnits * csec;
1951}
double G4double
Definition G4Types.hh:83
G4GLOB_DLL std::ostream G4cerr
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
G4double interpolate(const G4double x, const G4double(&yb)[nBins]) const
static G4bool useQuasiDeuteron(G4int ptype, G4int qdtype=0)

Referenced by inverseMeanFreePath().

◆ boundaryTransition()

void G4NucleiModel::boundaryTransition ( G4CascadParticle & cparticle)
protected

Definition at line 1115 of file G4NucleiModel.cc.

1115 {
1116 if (verboseLevel > 1) {
1117 G4cout << " >>> G4NucleiModel::boundaryTransition" << G4endl;
1118 }
1119
1120 G4int zone = cparticle.getCurrentZone();
1121
1122 if (cparticle.movingInsideNuclei() && zone == 0) {
1123 if (verboseLevel) G4cerr << " boundaryTransition-> in zone 0 " << G4endl;
1124 return;
1125 }
1126
1127 G4LorentzVector mom = cparticle.getMomentum();
1128 G4ThreeVector pos = cparticle.getPosition();
1129
1130 G4int type = cparticle.getParticle().type();
1131
1132 G4double r = pos.mag();
1133 G4double p = mom.vect().mag(); // NAT
1134 G4double pr = pos.dot(mom.vect()) / r;
1135 G4double pperp2 = p*p - pr*pr; // NAT
1136
1137 G4int next_zone = cparticle.movingInsideNuclei() ? zone - 1 : zone + 1;
1138
1139 // NOTE: dv is the height of the wall seen by the particle
1140 G4double dv = getPotential(type,next_zone) - getPotential(type,zone);
1141 if (verboseLevel > 3) {
1142 G4cout << "Potentials for type " << type << " = "
1143 << getPotential(type,zone) << " , "
1144 << getPotential(type,next_zone) << G4endl;
1145 }
1146
1147 G4double qv = dv*dv + 2.0*dv*mom.e() + pr*pr;
1148 // G4double qv = dv*dv + 2.0*dv*mom.m() + pr*pr; // more correct? NAT
1149 G4double p1r = 0.;
1150
1151 // Perpendicular contribution to pr^2 after penetrating // NAT
1152 // potential, to leading order in thickness // NAT
1153 G4double qperp = 2.0*pperp2*potentialThickness/r; // NAT
1154
1155 if (verboseLevel > 3) {
1156 G4cout << " type " << type << " zone " << zone << " next " << next_zone
1157 << " qv " << qv << " dv " << dv << G4endl;
1158 }
1159
1160 G4bool adjustpperp = false; // NAT
1161 G4double smallish = 0.001; // NAT
1162
1163// if (qv <= 0.0) { // reflection
1164 if (qv <= 0.0 && qv+qperp <=0 ) { // reflection // NAT
1165 if (verboseLevel > 3) G4cout << " reflects off boundary" << G4endl;
1166 p1r = -pr;
1167 cparticle.incrementReflectionCounter();
1168// } else { // transition
1169
1170 } else if (qv > 0.0) { // standard transition // NAT
1171 if (verboseLevel > 3) G4cout << " passes thru boundary" << G4endl;
1172 p1r = std::sqrt(qv);
1173 if (pr < 0.0) p1r = -p1r;
1174 cparticle.updateZone(next_zone);
1175 cparticle.resetReflection();
1176
1177 } else { // transition via transverse kinetic energy (allowed for thick walls) // NAT
1178 if (verboseLevel > 3) G4cout << " passes thru boundary due to angular momentum" << G4endl;
1179 p1r = smallish * pr; // don't want exactly tangent momentum
1180 adjustpperp = true;
1181
1182 cparticle.updateZone(next_zone);
1183 cparticle.resetReflection();
1184 }
1185
1186 G4double prr = (p1r - pr)/r; // change to radial momentum, divided by r
1187
1188 if (verboseLevel > 3) {
1189 G4cout << " prr " << prr << " delta px " << prr*pos.x() << " py "
1190 << prr*pos.y() << " pz " << prr*pos.z() << " mag "
1191 << std::fabs(prr*r) << G4endl;
1192 }
1193
1194 if (adjustpperp) { // NAT
1195 G4ThreeVector old_pperp = mom.vect() - pos*(pr/r);
1196 G4double new_pperp_mag = std::sqrt(std::max(0.0, pperp2 + qv - p1r*p1r) );
1197 // new total momentum found by rescaling p_perp
1198 mom.setVect(old_pperp * new_pperp_mag/std::sqrt(pperp2));
1199 // add a small radial component to make sure that we propagate into new zone
1200 mom.setVect(mom.vect() + pos*p1r/r);
1201 } else {
1202 mom.setVect(mom.vect() + pos*prr);
1203 }
1204
1205 cparticle.updateParticleMomentum(mom);
1206}
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
double mag() const
Hep3Vector vect() const
void setVect(const Hep3Vector &)
void updateZone(G4int izone)
const G4InuclElementaryParticle & getParticle() const
void updateParticleMomentum(const G4LorentzVector &mom)
G4bool movingInsideNuclei() const
G4LorentzVector getMomentum() const
void incrementReflectionCounter()
G4int getCurrentZone() const
const G4ThreeVector & getPosition() const
G4double getPotential(G4int ip, G4int izone) const

Referenced by generateParticleFate().

◆ choosePointAlongTraj()

void G4NucleiModel::choosePointAlongTraj ( G4CascadParticle & cparticle)
protected

Definition at line 1212 of file G4NucleiModel.cc.

1212 {
1213 if (verboseLevel > 1)
1214 G4cout << " >>> G4NucleiModel::choosePointAlongTraj" << G4endl;
1215
1216 // Get trajectory through nucleus by computing exit point of line,
1217 // assuming that current position is on surface
1218
1219 // FIXME: These need to be reusable (static) buffers
1220 G4ThreeVector pos = cparticle.getPosition();
1221 G4ThreeVector rhat = pos.unit();
1222
1223 G4ThreeVector phat = cparticle.getMomentum().vect().unit();
1224 if (cparticle.getMomentum().vect().mag() < small) phat.set(0.,0.,1.);
1225
1226 if (verboseLevel > 3)
1227 G4cout << " pos " << pos << " phat " << phat << " rhat " << rhat << G4endl;
1228
1229 G4ThreeVector posout = pos;
1230 G4double prang = rhat.angle(-phat);
1231
1232 if (prang < 1e-6) posout = -pos; // Check for radial incidence
1233 else {
1234 G4double posrot = 2.*prang - pi;
1235 posout.rotate(posrot, phat.cross(rhat));
1236 if (verboseLevel > 3) G4cout << " posrot " << posrot/deg << " deg";
1237 }
1238
1239 if (verboseLevel > 3) G4cout << " posout " << posout << G4endl;
1240
1241 // Get list of zone crossings along trajectory
1242 G4ThreeVector posmid = (pos+posout)/2.; // Midpoint of trajectory
1243 G4double r2mid = posmid.mag2();
1244 G4double lenmid = (posout-pos).mag()/2.; // Half-length of trajectory
1245
1246 G4int zoneout = number_of_zones-1;
1247 G4int zonemid = getZone(posmid.mag()); // Middle zone traversed
1248
1249 // Every zone is entered then exited, so preallocate vector
1250 G4int ncross = (number_of_zones-zonemid)*2;
1251
1252 if (verboseLevel > 3) {
1253 G4cout << " posmid " << posmid << " lenmid " << lenmid
1254 << " zoneout " << zoneout << " zonemid " << zonemid
1255 << " ncross " << ncross << G4endl;
1256 }
1257
1258 // FIXME: These need to be reusable (static) buffers
1259 std::vector<G4double> wtlen(ncross,0.); // CDF from entry point
1260 std::vector<G4double> len(ncross,0.); // Distance from entry point
1261
1262 // Work from outside in, to accumulate CDF steps properly
1263 G4int i; // Loop variable, used multiple times
1264 for (i=0; i<ncross/2; i++) {
1265 G4int iz = zoneout-i;
1266 G4double ds = std::sqrt(zone_radii[iz]*zone_radii[iz]-r2mid);
1267
1268 len[i] = lenmid - ds; // Distance from entry to crossing
1269 len[ncross-1-i] = lenmid + ds; // Distance to outbound crossing
1270
1271 if (verboseLevel > 3) {
1272 G4cout << " i " << i << " iz " << iz << " ds " << ds
1273 << " len " << len[i] << G4endl;
1274 }
1275 }
1276
1277 // Compute weights for each zone along trajectory and integrate
1278 for (i=1; i<ncross; i++) {
1279 G4int iz = (i<ncross/2) ? zoneout-i+1 : zoneout-ncross+i+1;
1280
1281 G4double dlen = len[i]-len[i-1]; // Distance from previous crossing
1282
1283 // Uniform probability across entire zone
1284 //*** G4double wt = dlen*(getDensity(1,iz)+getDensity(2,iz));
1285
1286 // Probability based on interaction length through zone
1287 G4double invmfp = (inverseMeanFreePath(cparticle, neutronEP, iz)
1288 + inverseMeanFreePath(cparticle, protonEP, iz));
1289
1290 // Integral of exp(-len/mfp) from start of zone to end
1291 G4double wt = (G4Exp(-len[i-1]*invmfp)-G4Exp(-len[i]*invmfp)) / invmfp;
1292
1293 wtlen[i] = wtlen[i-1] + wt;
1294
1295 if (verboseLevel > 3) {
1296 G4cout << " i " << i << " iz " << iz << " avg.mfp " << 1./invmfp
1297 << " dlen " << dlen << " wt " << wt << " wtlen " << wtlen[i]
1298 << G4endl;
1299 }
1300 }
1301
1302 // Normalize CDF to unit integral
1303 std::transform(wtlen.begin(), wtlen.end(), wtlen.begin(),
1304 std::bind(std::divides<G4double>(), std::placeholders::_1, wtlen.back()));
1305
1306 if (verboseLevel > 3) {
1307 G4cout << " weights";
1308 for (i=0; i<ncross; i++) G4cout << " " << wtlen[i];
1309 G4cout << G4endl;
1310 }
1311
1312 // Choose random point along trajectory, weighted by density
1313 G4double rand = G4UniformRand();
1314 G4long ir = std::upper_bound(wtlen.begin(),wtlen.end(),rand) - wtlen.begin();
1315
1316 G4double frac = (rand-wtlen[ir-1]) / (wtlen[ir]-wtlen[ir-1]);
1317 G4double drand = (1.-frac)*len[ir-1] + frac*len[ir];
1318
1319 if (verboseLevel > 3) {
1320 G4cout << " rand " << rand << " ir " << ir << " frac " << frac
1321 << " drand " << drand << G4endl;
1322 }
1323
1324 pos += drand * phat; // Distance from entry point along trajectory
1325
1326 // Update input particle with new location
1327 cparticle.updatePosition(pos);
1328 cparticle.updateZone(getZone(pos.mag()));
1329
1330 if (verboseLevel > 2) {
1331 G4cout << " moved particle to zone " << cparticle.getCurrentZone()
1332 << " @ " << pos << G4endl;
1333 }
1334}
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition G4Exp.hh:180
long G4long
Definition G4Types.hh:87
#define G4UniformRand()
Definition Randomize.hh:52
Hep3Vector unit() const
double mag2() const
Hep3Vector cross(const Hep3Vector &) const
double angle(const Hep3Vector &) const
void set(double x, double y, double z)
Hep3Vector & rotate(double, const Hep3Vector &)
void updatePosition(const G4ThreeVector &pos)
G4int getZone(G4double r) const
G4double inverseMeanFreePath(const G4CascadParticle &cparticle, const G4InuclElementaryParticle &target, G4int zone=-1)

Referenced by initializeCascad().

◆ empty()

G4bool G4NucleiModel::empty ( ) const
inline

Definition at line 150 of file G4NucleiModel.hh.

150 {
151 return neutronNumberCurrent < 1 && protonNumberCurrent < 1;
152 }

Referenced by G4IntraNucleiCascader::generateCascade().

◆ fillBindingEnergies()

void G4NucleiModel::fillBindingEnergies ( )
protected

Definition at line 390 of file G4NucleiModel.cc.

390 {
391 if (verboseLevel > 1)
392 G4cout << " >>> G4NucleiModel::fillBindingEnergies" << G4endl;
393
394 G4double dm = bindingEnergy(A,Z);
395
396 // Binding energy differences for proton and neutron loss, respectively
397 // FIXME: Why is fabs() used here instead of the signed difference?
398 binding_energies.push_back(std::fabs(bindingEnergy(A-1,Z-1)-dm)/GeV);
399 binding_energies.push_back(std::fabs(bindingEnergy(A-1,Z)-dm)/GeV);
400}
G4double bindingEnergy(G4int A, G4int Z)

Referenced by generateModel().

◆ fillPotentials()

void G4NucleiModel::fillPotentials ( G4int type,
G4double tot_vol )
protected

Definition at line 479 of file G4NucleiModel.cc.

479 {
480 if (verboseLevel > 1)
481 G4cout << " >>> G4NucleiModel::fillZoneVolumes(" << type << ")" << G4endl;
482
483 if (type != proton && type != neutron) return;
484
486
487 // FIXME: This is the fabs() binding energy difference, not signed
488 const G4double dm = binding_energies[type-1];
489
490 rod.clear(); rod.reserve(number_of_zones);
491 pf.clear(); pf.reserve(number_of_zones);
492 vz.clear(); vz.reserve(number_of_zones);
493
494 G4int nNucleons = (type==proton) ? protonNumber : neutronNumber;
495 G4double dd0 = nNucleons / tot_vol / piTimes4thirds;
496
497 for (G4int i = 0; i < number_of_zones; i++) {
498 G4double rd = dd0 * v[i] / v1[i];
499 rod.push_back(rd);
500 G4double pff = fermiMomentum * G4cbrt(rd);
501 pf.push_back(pff);
502 vz.push_back(0.5 * pff * pff / mass + dm);
503 }
504
505 nucleon_densities.push_back(rod);
506 fermi_momenta.push_back(pf);
507 zone_potentials.push_back(vz);
508}
static G4double getParticleMass(G4int type)

Referenced by generateModel().

◆ fillZoneRadii()

void G4NucleiModel::fillZoneRadii ( G4double nuclearRadius)
protected

Definition at line 404 of file G4NucleiModel.cc.

404 {
405 if (verboseLevel > 1)
406 G4cout << " >>> G4NucleiModel::fillZoneRadii" << G4endl;
407
408 G4double skinRatio = nuclearRadius/skinDepth;
409 G4double skinDecay = G4Exp(-skinRatio);
410
411 if (A < 5) { // Light ions treated as simple balls
412 zone_radii.push_back(nuclearRadius);
413 ur[0] = 0.;
414 ur[1] = 1.;
415 } else if (A < 12) { // Small nuclei have Gaussian potential
416 G4double rSq = nuclearRadius * nuclearRadius;
417 G4double gaussRadius = std::sqrt(rSq * (1.0 - 1.0/A) + 6.4);
418
419 ur[0] = 0.0;
420 for (G4int i = 0; i < number_of_zones; i++) {
421 G4double y = std::sqrt(-G4Log(alfa3[i]));
422 zone_radii.push_back(gaussRadius * y);
423 ur[i+1] = y;
424 }
425 } else if (A < 100) { // Intermediate nuclei have three-zone W-S
426 ur[0] = -skinRatio;
427 for (G4int i = 0; i < number_of_zones; i++) {
428 G4double y = G4Log((1.0 + skinDecay)/alfa3[i] - 1.0);
429 zone_radii.push_back(nuclearRadius + skinDepth * y);
430 ur[i+1] = y;
431 }
432 } else { // Heavy nuclei have six-zone W-S
433 ur[0] = -skinRatio;
434 for (G4int i = 0; i < number_of_zones; i++) {
435 G4double y = G4Log((1.0 + skinDecay)/alfa6[i] - 1.0);
436 zone_radii.push_back(nuclearRadius + skinDepth * y);
437 ur[i+1] = y;
438 }
439 }
440}
G4double G4Log(G4double x)
Definition G4Log.hh:227

Referenced by generateModel().

◆ fillZoneVolumes()

G4double G4NucleiModel::fillZoneVolumes ( G4double nuclearRadius)
protected

Definition at line 444 of file G4NucleiModel.cc.

444 {
445 if (verboseLevel > 1)
446 G4cout << " >>> G4NucleiModel::fillZoneVolumes" << G4endl;
447
448 G4double tot_vol = 0.; // Return value omitting 4pi/3 for sphere!
449
450 if (A < 5) { // Light ions are treated as simple balls
451 v[0] = v1[0] = 1.;
452 tot_vol = zone_radii[0]*zone_radii[0]*zone_radii[0];
453 zone_volumes.push_back(tot_vol*piTimes4thirds); // True volume of sphere
454
455 return tot_vol;
456 }
457
458 PotentialType usePotential = (A < 12) ? Gaussian : WoodsSaxon;
459
460 for (G4int i = 0; i < number_of_zones; i++) {
461 if (usePotential == WoodsSaxon) {
462 v[i] = zoneIntegralWoodsSaxon(ur[i], ur[i+1], nuclearRadius);
463 } else {
464 v[i] = zoneIntegralGaussian(ur[i], ur[i+1], nuclearRadius);
465 }
466
467 tot_vol += v[i];
468
469 v1[i] = zone_radii[i]*zone_radii[i]*zone_radii[i];
470 if (i > 0) v1[i] -= zone_radii[i-1]*zone_radii[i-1]*zone_radii[i-1];
471
472 zone_volumes.push_back(v1[i]*piTimes4thirds); // True volume of shell
473 }
474
475 return tot_vol; // Sum of zone integrals, not geometric volume
476}
G4double zoneIntegralGaussian(G4double ur1, G4double ur2, G4double nuclearRadius) const
G4double zoneIntegralWoodsSaxon(G4double ur1, G4double ur2, G4double nuclearRadius) const

Referenced by generateModel().

◆ forceFirst()

G4bool G4NucleiModel::forceFirst ( const G4CascadParticle & cparticle) const

Definition at line 1338 of file G4NucleiModel.cc.

1338 {
1339 return (isProjectile(cparticle) &&
1340 (cparticle.getParticle().isPhoton() ||
1341 cparticle.getParticle().isMuon())
1342 );
1343}
G4bool isProjectile(const G4CascadParticle &cparticle) const

Referenced by generateInteractionLength(), and initializeCascad().

◆ generateInteractionLength()

G4double G4NucleiModel::generateInteractionLength ( const G4CascadParticle & cparticle,
G4double path,
G4double invmfp ) const
protected

Definition at line 1890 of file G4NucleiModel.cc.

1891 {
1892 // Delay interactions of newly formed secondaries (minimum int. length)
1893 const G4double young_cut = std::sqrt(10.0) * 0.25;
1894 const G4double huge_num = 50.0; // Argument to exponential
1895
1896 G4double spath = large; // Buffer for return value
1897
1898 if (invmfp < small) return spath; // No interaction, avoid unnecessary work
1899
1900 G4double pw = -path * invmfp; // Ratio of path in zone to MFP
1901 if (pw < -huge_num) pw = -huge_num;
1902 pw = 1.0 - G4Exp(pw);
1903
1904 if (verboseLevel > 2)
1905 G4cout << " mfp " << 1./invmfp << " pw " << pw << G4endl;
1906
1907 // Primary particle(s) should always interact at least once
1908 if (forceFirst(cparticle) || (inuclRndm() < pw)) {
1909 spath = -G4Log(1.0 - pw * inuclRndm()) / invmfp;
1910 if (cparticle.young(young_cut, spath)) spath = large;
1911
1912 if (verboseLevel > 2)
1913 G4cout << " spath " << spath << " path " << path << G4endl;
1914 }
1915
1916 return spath;
1917}
G4bool young(G4double young_path_cut, G4double cpath) const
G4bool forceFirst(const G4CascadParticle &cparticle) const

Referenced by generateInteractionPartners().

◆ generateInteractionPartners()

void G4NucleiModel::generateInteractionPartners ( G4CascadParticle & cparticle)
protected

Definition at line 694 of file G4NucleiModel.cc.

694 {
695 if (verboseLevel > 1) {
696 G4cout << " >>> G4NucleiModel::generateInteractionPartners" << G4endl;
697 }
698
699 thePartners.clear(); // Reset buffer for next cycle
700
701 G4int ptype = cparticle.getParticle().type();
702 G4int zone = cparticle.getCurrentZone();
703
704 G4double r_in; // Destination radius if inbound
705 G4double r_out; // Destination radius if outbound
706
707 if (zone == number_of_zones) {
708 r_in = nuclei_radius;
709 r_out = 0.0;
710 } else if (zone == 0) { // particle is outside core
711 r_in = 0.0;
712 r_out = zone_radii[0];
713 } else {
714 r_in = zone_radii[zone - 1];
715 r_out = zone_radii[zone];
716 }
717
718 G4double path = cparticle.getPathToTheNextZone(r_in, r_out);
719
720 if (verboseLevel > 2) {
721 if (isProjectile(cparticle)) G4cout << " incident particle: ";
722 G4cout << " r_in " << r_in << " r_out " << r_out << " path " << path
723 << G4endl;
724 }
725
726 if (path < -small) { // something wrong
727 if (verboseLevel)
728 G4cerr << " generateInteractionPartners-> negative path length" << G4endl;
729 return;
730 }
731
732 if (std::fabs(path) < small) { // Not moving, or just at boundary
733 if (cparticle.getMomentum().vect().mag() > small) {
734 if (verboseLevel > 3)
735 G4cout << " generateInteractionPartners-> zero path" << G4endl;
736
737 thePartners.push_back(partner()); // Dummy list terminator with zero path
738 return;
739 }
740
741 if (zone >= number_of_zones) // Place captured-at-rest in nucleus
742 zone = number_of_zones-1;
743 }
744
745 G4double invmfp = 0.; // Buffers for interaction probability
746 G4double spath = 0.;
747 for (G4int ip = 1; ip < 3; ip++) {
748 // Only process nucleons which remain active in target
749 if (ip==proton && protonNumberCurrent < 1) continue;
750 if (ip==neutron && neutronNumberCurrent < 1) continue;
751 if (ip==neutron && ptype==muonMinus) continue; // mu-/n forbidden
752
753 // All nucleons are assumed to be at rest when colliding
754 G4InuclElementaryParticle particle = generateNucleon(ip, zone);
755 invmfp = inverseMeanFreePath(cparticle, particle);
756 spath = generateInteractionLength(cparticle, path, invmfp);
757
758 if (path<small || spath < path) {
759 if (verboseLevel > 3) {
760 G4cout << " adding partner[" << thePartners.size() << "]: "
761 << particle << G4endl;
762 }
763 thePartners.push_back(partner(particle, spath));
764 }
765 } // for (G4int ip...
766
767 if (verboseLevel > 2) {
768 G4cout << " after nucleons " << thePartners.size() << " path " << path << G4endl;
769 }
770
771 // Absorption possible for pions or photons interacting with dibaryons
772 if (useQuasiDeuteron(cparticle.getParticle().type())) {
773 if (verboseLevel > 2) {
774 G4cout << " trying quasi-deuterons with bullet: "
775 << cparticle.getParticle() << G4endl;
776 }
777
778 // Initialize buffers for quasi-deuteron results
779 qdeutrons.clear();
780 acsecs.clear();
781
782 G4double tot_invmfp = 0.0; // Total inv. mean-free-path for all QDs
783
784 // Proton-proton state interacts with pi-, mu- or neutrals
785 if (protonNumberCurrent >= 2 && ptype != pip) {
787 if (verboseLevel > 2)
788 G4cout << " ptype=" << ptype << " using pp target\n" << ppd << G4endl;
789
790 invmfp = inverseMeanFreePath(cparticle, ppd);
791 tot_invmfp += invmfp;
792 acsecs.push_back(invmfp);
793 qdeutrons.push_back(ppd);
794 }
795
796 // Proton-neutron state interacts with any pion type or photon
797 if (protonNumberCurrent >= 1 && neutronNumberCurrent >= 1) {
799 if (verboseLevel > 2)
800 G4cout << " ptype=" << ptype << " using np target\n" << npd << G4endl;
801
802 invmfp = inverseMeanFreePath(cparticle, npd);
803 tot_invmfp += invmfp;
804 acsecs.push_back(invmfp);
805 qdeutrons.push_back(npd);
806 }
807
808 // Neutron-neutron state interacts with pi+ or neutrals
809 if (neutronNumberCurrent >= 2 && ptype != pim && ptype != mum) {
811 if (verboseLevel > 2)
812 G4cout << " ptype=" << ptype << " using nn target\n" << nnd << G4endl;
813
814 invmfp = inverseMeanFreePath(cparticle, nnd);
815 tot_invmfp += invmfp;
816 acsecs.push_back(invmfp);
817 qdeutrons.push_back(nnd);
818 }
819
820 // Select quasideuteron interaction from non-zero cross-section choices
821 if (verboseLevel > 2) {
822 for (std::size_t i=0; i<qdeutrons.size(); i++) {
823 G4cout << " acsecs[" << qdeutrons[i].getDefinition()->GetParticleName()
824 << "] " << acsecs[i];
825 }
826 G4cout << G4endl;
827 }
828
829 if (tot_invmfp > small) { // Must have absorption cross-section
830 G4double apath = generateInteractionLength(cparticle, path, tot_invmfp);
831
832 if (path<small || apath < path) { // choose the qdeutron
833 G4double sl = inuclRndm() * tot_invmfp;
834 G4double as = 0.0;
835
836 for (std::size_t i = 0; i < qdeutrons.size(); i++) {
837 as += acsecs[i];
838 if (sl < as) {
839 if (verboseLevel > 2)
840 G4cout << " deut type " << qdeutrons[i] << G4endl;
841
842 thePartners.push_back(partner(qdeutrons[i], apath));
843 break;
844 }
845 } // for (qdeutrons...
846 } // if (apath < path)
847 } // if (tot_invmfp > small)
848 } // if (useQuasiDeuteron) [pion, muon or photon]
849
850 if (verboseLevel > 2) {
851 G4cout << " after deuterons " << thePartners.size() << " partners"
852 << G4endl;
853 }
854
855 if (thePartners.size() > 1) { // Sort list by path length
856 std::sort(thePartners.begin(), thePartners.end(), sortPartners);
857 }
858
859 G4InuclElementaryParticle particle; // Total path at end of list
860 thePartners.push_back(partner(particle, path));
861}
G4double getPathToTheNextZone(G4double rz_in, G4double rz_out)
G4double generateInteractionLength(const G4CascadParticle &cparticle, G4double path, G4double invmfp) const
G4InuclElementaryParticle generateNucleon(G4int type, G4int zone) const
std::pair< G4InuclElementaryParticle, G4double > partner
G4InuclElementaryParticle generateQuasiDeuteron(G4int type1, G4int type2, G4int zone) const
std::vector< partner > thePartners
static G4bool sortPartners(const partner &p1, const partner &p2)

Referenced by generateParticleFate().

◆ generateModel() [1/2]

void G4NucleiModel::generateModel ( G4int a,
G4int z )

Definition at line 315 of file G4NucleiModel.cc.

315 {
316 if (verboseLevel) {
317 G4cout << " >>> G4NucleiModel::generateModel A " << a << " Z " << z
318 << G4endl;
319 }
320
321 // If model already built, just return; otherwise initialize everything
322 if (a == A && z == Z) {
323 if (verboseLevel > 1) G4cout << " model already generated" << z << G4endl;
324 reset();
325 return;
326 }
327
328 A = a;
329 Z = z;
330 delete theNucleus;
331 theNucleus = new G4InuclNuclei(A,Z); // For conservation checking
332
333 neutronNumber = A - Z;
334 protonNumber = Z;
335 reset();
336
337 if (verboseLevel > 3) {
338 G4cout << " crossSectionUnits = " << crossSectionUnits << G4endl
339 << " radiusUnits = " << radiusUnits << G4endl
340 << " skinDepth = " << skinDepth << G4endl
341 << " radiusScale = " << radiusScale << G4endl
342 << " radiusScale2 = " << radiusScale2 << G4endl
343 << " radiusForSmall = " << radiusForSmall << G4endl
344 << " radScaleAlpha = " << radScaleAlpha << G4endl
345 << " fermiMomentum = " << fermiMomentum << G4endl
346 << " piTimes4thirds = " << piTimes4thirds << G4endl;
347 }
348
349 G4double nuclearRadius; // Nuclear radius computed from A
350 if (A>4) nuclearRadius = radiusScale*G4cbrt(A) + radiusScale2/G4cbrt(A);
351 else nuclearRadius = radiusForSmall * (A==4 ? radScaleAlpha : 1.);
352
353 // This will be used to pre-allocate lots of arrays below
354 number_of_zones = (A < 5) ? 1 : (A < 100) ? 3 : 6;
355
356 // Clear all parameters arrays for reloading
357 binding_energies.clear();
358 nucleon_densities.clear();
359 zone_potentials.clear();
360 fermi_momenta.clear();
361 zone_radii.clear();
362 zone_volumes.clear();
363
365 fillZoneRadii(nuclearRadius);
366
367 G4double tot_vol = fillZoneVolumes(nuclearRadius); // Woods-Saxon integral
368
369 fillPotentials(proton, tot_vol); // Protons
370 fillPotentials(neutron, tot_vol); // Neutrons
371
372 // Additional flat zone potentials for other hadrons
373 const std::vector<G4double> vp(number_of_zones, (A>4)?pion_vp:pion_vp_small);
374 const std::vector<G4double> kp(number_of_zones, kaon_vp);
375 const std::vector<G4double> hp(number_of_zones, hyperon_vp);
376
377 zone_potentials.push_back(vp);
378 zone_potentials.push_back(kp);
379 zone_potentials.push_back(hp);
380
381 nuclei_radius = zone_radii.back();
382 nuclei_volume = std::accumulate(zone_volumes.begin(),zone_volumes.end(),0.);
383
384 if (verboseLevel > 3) printModel();
385}
const G4double A[17]
void printModel() const
void fillBindingEnergies()
G4double fillZoneVolumes(G4double nuclearRadius)
void reset(G4int nHitNeutrons=0, G4int nHitProtons=0, const std::vector< G4ThreeVector > *hitPoints=0)
void fillZoneRadii(G4double nuclearRadius)
void fillPotentials(G4int type, G4double tot_vol)

◆ generateModel() [2/2]

void G4NucleiModel::generateModel ( G4InuclNuclei * nuclei)

Definition at line 311 of file G4NucleiModel.cc.

311 {
312 generateModel(nuclei->getA(), nuclei->getZ());
313}

Referenced by G4NucleiModel(), G4NucleiModel(), generateModel(), and G4IntraNucleiCascader::initialize().

◆ generateNucleon()

G4InuclElementaryParticle G4NucleiModel::generateNucleon ( G4int type,
G4int zone ) const

Definition at line 657 of file G4NucleiModel.cc.

657 {
658 if (verboseLevel > 1) {
659 G4cout << " >>> G4NucleiModel::generateNucleon" << G4endl;
660 }
661
663 return G4InuclElementaryParticle(mom, type);
664}
G4LorentzVector generateNucleonMomentum(G4int type, G4int zone) const

Referenced by generateInteractionPartners().

◆ generateNucleonMomentum()

G4LorentzVector G4NucleiModel::generateNucleonMomentum ( G4int type,
G4int zone ) const

Definition at line 648 of file G4NucleiModel.cc.

648 {
649 G4double pmod = getFermiMomentum(type, zone) * G4cbrt(inuclRndm());
651
652 return generateWithRandomAngles(pmod, mass);
653}
G4double getFermiMomentum(G4int ip, G4int izone) const
G4LorentzVector generateWithRandomAngles(G4double p, G4double mass=0.)

Referenced by generateNucleon(), and generateQuasiDeuteron().

◆ generateParticleFate()

void G4NucleiModel::generateParticleFate ( G4CascadParticle & cparticle,
G4ElementaryParticleCollider * theEPCollider,
std::vector< G4CascadParticle > & cascade )

Definition at line 864 of file G4NucleiModel.cc.

867 {
868 if (verboseLevel > 1)
869 G4cout << " >>> G4NucleiModel::generateParticleFate" << G4endl;
870
871 if (verboseLevel > 2) G4cout << " cparticle: " << cparticle << G4endl;
872
873 // Create four-vector checking
874#ifdef G4CASCADE_CHECK_ECONS
875 G4CascadeCheckBalance balance(0.005, 0.01, "G4NucleiModel"); // Second arg is in GeV
876 balance.setVerboseLevel(verboseLevel);
877#endif
878
879 outgoing_cparticles.clear(); // Clear return buffer for this event
880 generateInteractionPartners(cparticle); // Fills "thePartners" data
881
882 if (thePartners.empty()) { // smth. is wrong -> needs special treatment
883 if (verboseLevel)
884 G4cerr << " generateParticleFate-> got empty interaction-partners list "
885 << G4endl;
886 return;
887 }
888
889 std::size_t npart = thePartners.size(); // Last item is a total-path placeholder
890
891 if (npart == 1) { // cparticle is on the next zone entry
892 if (verboseLevel > 1)
893 G4cout << " no interactions; moving to next zone" << G4endl;
894
895 cparticle.propagateAlongThePath(thePartners[0].second);
896 cparticle.incrementCurrentPath(thePartners[0].second);
897 boundaryTransition(cparticle);
898 outgoing_cparticles.push_back(cparticle);
899
900 if (verboseLevel > 2) G4cout << " next zone \n" << cparticle << G4endl;
901
902 //A.R. 19-Jun-2013: Fixed rare cases of non-reproducibility.
903 current_nucl1 = 0;
904 current_nucl2 = 0;
905
906 return;
907 } // if (npart == 1)
908
909 if (verboseLevel > 1)
910 G4cout << " processing " << npart-1 << " possible interactions" << G4endl;
911
912 G4ThreeVector old_position = cparticle.getPosition();
913 G4InuclElementaryParticle& bullet = cparticle.getParticle();
914 G4bool no_interaction = true;
915 G4int zone = cparticle.getCurrentZone();
916
917 for (std::size_t i=0; i<npart-1; ++i) { // Last item is a total-path placeholder
918 if (i > 0) cparticle.updatePosition(old_position);
919
920 G4InuclElementaryParticle& target = thePartners[i].first;
921
922 if (verboseLevel > 3) {
923 if (target.quasi_deutron()) G4cout << " try absorption: ";
924 G4cout << " target " << target.type() << " bullet " << bullet.type()
925 << G4endl;
926 }
927
928 EPCoutput.reset();
929 // Pass current (A,Z) configuration for possible recoils
930 G4int massNumberCurrent = protonNumberCurrent+neutronNumberCurrent;
931 theEPCollider->setNucleusState(massNumberCurrent, protonNumberCurrent);
932 theEPCollider->collide(&bullet, &target, EPCoutput);
933
934 // If collision failed, exit loop over partners
935 if (EPCoutput.numberOfOutgoingParticles() == 0) break;
936
937 if (verboseLevel > 2) {
938 EPCoutput.printCollisionOutput();
939#ifdef G4CASCADE_CHECK_ECONS
940 balance.collide(&bullet, &target, EPCoutput);
941 balance.okay(); // Do checks, but ignore result
942#endif
943 }
944
945 // Get list of outgoing particles for evaluation
946 std::vector<G4InuclElementaryParticle>& outgoing_particles =
947 EPCoutput.getOutgoingParticles();
948
949 if (!passFermi(outgoing_particles, zone)) continue; // Interaction fails
950
951 // Trailing effect: reject interaction at previously hit nucleon
952 cparticle.propagateAlongThePath(thePartners[i].second);
953 const G4ThreeVector& new_position = cparticle.getPosition();
954
955 if (!passTrailing(new_position)) continue;
956 collisionPts.push_back(new_position);
957
958 // Sort particles according to beta (fastest first)
959 std::sort(outgoing_particles.begin(), outgoing_particles.end(),
961
962 if (verboseLevel > 2)
963 G4cout << " adding " << outgoing_particles.size()
964 << " output particles" << G4endl;
965
966 // NOTE: Embedded temporary is optimized away (no copying gets done)
967 G4int nextGen = cparticle.getGeneration()+1;
968 for (std::size_t ip = 0; ip < outgoing_particles.size(); ++ip) {
969 outgoing_cparticles.push_back(G4CascadParticle(outgoing_particles[ip],
970 new_position, zone,
971 0.0, nextGen));
972 }
973
974 no_interaction = false;
975 current_nucl1 = 0;
976 current_nucl2 = 0;
977
978#ifdef G4CASCADE_DEBUG_CHARGE
979 {
980 G4double out_charge = 0.0;
981
982 for (G4int ip = 0; ip < G4int(outgoing_particles.size()); ip++)
983 out_charge += outgoing_particles[ip].getCharge();
984
985 G4cout << " multiplicity " << outgoing_particles.size()
986 << " bul type " << bullet.type()
987 << " targ type " << target.type()
988 << "\n initial charge "
989 << bullet.getCharge() + target.getCharge()
990 << " out charge " << out_charge << G4endl;
991 }
992#endif
993
994 if (verboseLevel > 2)
995 G4cout << " partner type " << target.type() << G4endl;
996
997 if (target.nucleon()) {
998 current_nucl1 = target.type();
999 } else {
1000 if (verboseLevel > 2) G4cout << " good absorption " << G4endl;
1001 current_nucl1 = (target.type() - 100) / 10;
1002 current_nucl2 = target.type() - 100 - 10 * current_nucl1;
1003 }
1004
1005 if (current_nucl1 == 1) {
1006 if (verboseLevel > 3) G4cout << " decrement proton count" << G4endl;
1007 protonNumberCurrent--;
1008 } else {
1009 if (verboseLevel > 3) G4cout << " decrement neutron count" << G4endl;
1010 neutronNumberCurrent--;
1011 }
1012
1013 if (current_nucl2 == 1) {
1014 if (verboseLevel > 3) G4cout << " decrement proton count" << G4endl;
1015 protonNumberCurrent--;
1016 } else if (current_nucl2 == 2) {
1017 if (verboseLevel > 3) G4cout << " decrement neutron count" << G4endl;
1018 neutronNumberCurrent--;
1019 }
1020
1021 break;
1022 } // loop over partners
1023
1024 if (no_interaction) { // still no interactions
1025 if (verboseLevel > 1) G4cout << " no interaction " << G4endl;
1026
1027 // For conservation checking (below), get particle before updating
1028 static G4ThreadLocal G4InuclElementaryParticle *prescatCP_G4MT_TLS_ = 0;
1029 if (!prescatCP_G4MT_TLS_) {
1030 prescatCP_G4MT_TLS_ = new G4InuclElementaryParticle;
1031 G4AutoDelete::Register(prescatCP_G4MT_TLS_);
1032 }
1033 G4InuclElementaryParticle &prescatCP = *prescatCP_G4MT_TLS_; // Avoid memory churn
1034 prescatCP = cparticle.getParticle();
1035
1036 // Last "partner" is just a total-path placeholder
1037 cparticle.updatePosition(old_position);
1038 cparticle.propagateAlongThePath(thePartners[npart-1].second);
1039 cparticle.incrementCurrentPath(thePartners[npart-1].second);
1040 boundaryTransition(cparticle);
1041 outgoing_cparticles.push_back(cparticle);
1042
1043 // Check conservation for simple scattering (ignore target nucleus!)
1044#ifdef G4CASCADE_CHECK_ECONS
1045 if (verboseLevel > 2) {
1046 balance.collide(&prescatCP, 0, outgoing_cparticles);
1047 balance.okay(); // Report violations, but don't act on them
1048 }
1049#endif
1050 } // if (no_interaction)
1051
1052 return;
1053}
G4int getGeneration() const
void incrementCurrentPath(G4double npath)
void propagateAlongThePath(G4double path)
G4int numberOfOutgoingParticles() const
void printCollisionOutput(std::ostream &os=G4cout) const
const std::vector< G4InuclElementaryParticle > & getOutgoingParticles() const
void collide(G4InuclParticle *bullet, G4InuclParticle *target, G4CollisionOutput &output)
G4double getCharge() const
void boundaryTransition(G4CascadParticle &cparticle)
G4bool passTrailing(const G4ThreeVector &hit_position)
G4bool passFermi(const std::vector< G4InuclElementaryParticle > &particles, G4int zone)
void generateInteractionPartners(G4CascadParticle &cparticle)
void Register(T *inst)
#define G4ThreadLocal
Definition tls.hh:77

Referenced by G4IntraNucleiCascader::generateCascade().

◆ generateQuasiDeuteron()

G4InuclElementaryParticle G4NucleiModel::generateQuasiDeuteron ( G4int type1,
G4int type2,
G4int zone ) const
protected

Definition at line 668 of file G4NucleiModel.cc.

669 {
670 if (verboseLevel > 1) {
671 G4cout << " >>> G4NucleiModel::generateQuasiDeuteron" << G4endl;
672 }
673
674 // Quasideuteron consists of an unbound but associated nucleon pair
675
676 // FIXME: Why generate two separate nucleon momenta (randomly!) and
677 // add them, instead of just throwing a net momentum for the
678 // dinulceon state? And why do I have to capture the two
679 // return values into local variables?
680 G4LorentzVector mom1 = generateNucleonMomentum(type1, zone);
681 G4LorentzVector mom2 = generateNucleonMomentum(type2, zone);
682 G4LorentzVector dmom = mom1+mom2;
683
684 G4int dtype = 0;
685 if (type1*type2 == pro*pro) dtype = 111;
686 else if (type1*type2 == pro*neu) dtype = 112;
687 else if (type1*type2 == neu*neu) dtype = 122;
688
689 return G4InuclElementaryParticle(dmom, dtype);
690}

Referenced by generateInteractionPartners().

◆ getCurrentDensity()

G4double G4NucleiModel::getCurrentDensity ( G4int ip,
G4int izone ) const
protected

Definition at line 1397 of file G4NucleiModel.cc.

1397 {
1398 const G4double pn_spec = 1.0; // Scale factor for pn vs. pp/nn
1399 //const G4double pn_spec = 0.5;
1400
1401 G4double dens = 0.;
1402
1403 if (ip < 100) dens = getDensity(ip,izone);
1404 else { // For dibaryons, remove extra 1/volume term in density product
1405 switch (ip) {
1406 case diproton:
1407 dens = getDensity(proton,izone) * getDensity(proton,izone);
1408 break;
1409 case unboundPN:
1410 dens = getDensity(proton,izone) * getDensity(neutron,izone) * pn_spec;
1411 break;
1412 case dineutron:
1413 dens = getDensity(neutron,izone) * getDensity(neutron,izone);
1414 break;
1415 default: dens = 0.;
1416 }
1417 dens *= getVolume(izone);
1418 }
1419
1420 return getRatio(ip) * dens;
1421}
G4double getRatio(G4int ip) const
G4double getDensity(G4int ip, G4int izone) const
G4double getVolume(G4int izone) const

Referenced by inverseMeanFreePath().

◆ getDensity()

G4double G4NucleiModel::getDensity ( G4int ip,
G4int izone ) const
inline

Definition at line 110 of file G4NucleiModel.hh.

110 {
111 return nucleon_densities[ip - 1][izone];
112 }

Referenced by getCurrentDensity(), and printModel().

◆ getFermiKinetic()

G4double G4NucleiModel::getFermiKinetic ( G4int ip,
G4int izone ) const

Definition at line 634 of file G4NucleiModel.cc.

634 {
635 G4double ekin = 0.0;
636
637 if (ip < 3 && izone < number_of_zones) { // ip for proton/neutron only
638 G4double pfermi = fermi_momenta[ip - 1][izone];
640
641 ekin = std::sqrt(pfermi*pfermi + mass*mass) - mass;
642 }
643 return ekin;
644}

Referenced by worthToPropagate().

◆ getFermiMomentum()

G4double G4NucleiModel::getFermiMomentum ( G4int ip,
G4int izone ) const
inline

Definition at line 114 of file G4NucleiModel.hh.

114 {
115 return fermi_momenta[ip - 1][izone];
116 }

Referenced by generateNucleonMomentum(), and printModel().

◆ getNumberOfNeutrons()

G4int G4NucleiModel::getNumberOfNeutrons ( ) const
inline

Definition at line 147 of file G4NucleiModel.hh.

147{ return neutronNumberCurrent; }

Referenced by G4IntraNucleiCascader::generateCascade().

◆ getNumberOfProtons()

G4int G4NucleiModel::getNumberOfProtons ( ) const
inline

Definition at line 148 of file G4NucleiModel.hh.

148{ return protonNumberCurrent; }

Referenced by G4IntraNucleiCascader::generateCascade().

◆ getNumberOfZones()

G4int G4NucleiModel::getNumberOfZones ( ) const
inline

Definition at line 141 of file G4NucleiModel.hh.

141{ return number_of_zones; }

◆ getPotential()

G4double G4NucleiModel::getPotential ( G4int ip,
G4int izone ) const
inline

Definition at line 120 of file G4NucleiModel.hh.

120 {
121 if (ip == 9 || ip < 0) return 0.0; // Photons and leptons
122 G4int ip0 = ip < 3 ? ip - 1 : 2;
123 if (ip > 10 && ip < 18) ip0 = 3;
124 if (ip > 20) ip0 = 4;
125 return izone < number_of_zones ? zone_potentials[ip0][izone] : 0.0;
126 }

Referenced by boundaryTransition(), and printModel().

◆ getRadius() [1/2]

G4double G4NucleiModel::getRadius ( ) const
inline

Definition at line 131 of file G4NucleiModel.hh.

131{ return nuclei_radius; }

◆ getRadius() [2/2]

G4double G4NucleiModel::getRadius ( G4int izone) const
inline

Definition at line 132 of file G4NucleiModel.hh.

132 {
133 return ( (izone<0) ? 0.
134 : (izone<number_of_zones) ? zone_radii[izone] : nuclei_radius);
135 }

◆ getRadiusUnits()

G4double G4NucleiModel::getRadiusUnits ( ) const
inline

Definition at line 129 of file G4NucleiModel.hh.

129{ return radiusUnits*CLHEP::fermi; }

Referenced by G4IntraNucleiCascader::processSecondary().

◆ getRatio()

G4double G4NucleiModel::getRatio ( G4int ip) const
protected

Definition at line 1380 of file G4NucleiModel.cc.

1380 {
1381 if (verboseLevel > 4) {
1382 G4cout << " >>> G4NucleiModel::getRatio " << ip << G4endl;
1383 }
1384
1385 switch (ip) {
1386 case proton: return G4double(protonNumberCurrent)/G4double(protonNumber);
1387 case neutron: return G4double(neutronNumberCurrent)/G4double(neutronNumber);
1388 case diproton: return getRatio(proton)*getRatio(proton);
1389 case unboundPN: return getRatio(proton)*getRatio(neutron);
1390 case dineutron: return getRatio(neutron)*getRatio(neutron);
1391 default: return 0.;
1392 }
1393
1394 return 0.;
1395}

Referenced by getCurrentDensity(), and getRatio().

◆ getTypesOfNucleonsInvolved()

std::pair< G4int, G4int > G4NucleiModel::getTypesOfNucleonsInvolved ( ) const
inline

Definition at line 167 of file G4NucleiModel.hh.

167 {
168 return std::pair<G4int, G4int>(current_nucl1, current_nucl2);
169 }

Referenced by G4IntraNucleiCascader::generateCascade().

◆ getVolume()

G4double G4NucleiModel::getVolume ( G4int izone) const
inline

Definition at line 136 of file G4NucleiModel.hh.

136 {
137 return ( (izone<0) ? 0.
138 : (izone<number_of_zones) ? zone_volumes[izone] : nuclei_volume);
139 }

Referenced by getCurrentDensity().

◆ getZone()

G4int G4NucleiModel::getZone ( G4double r) const
inline

Definition at line 142 of file G4NucleiModel.hh.

142 {
143 for (G4int iz=0; iz<number_of_zones; iz++) if (r<zone_radii[iz]) return iz;
144 return number_of_zones;
145 }

Referenced by choosePointAlongTraj(), and G4IntraNucleiCascader::processSecondary().

◆ initializeCascad() [1/2]

G4CascadParticle G4NucleiModel::initializeCascad ( G4InuclElementaryParticle * particle)

Definition at line 1425 of file G4NucleiModel.cc.

1425 {
1426 if (verboseLevel > 1) {
1427 G4cout << " >>> G4NucleiModel::initializeCascad(particle)" << G4endl;
1428 }
1429
1430 // FIXME: Previous version generated random sin(theta), then used -cos(theta)
1431 // Using generateWithRandomAngles changes result!
1432 // G4ThreeVector pos = generateWithRandomAngles(nuclei_radius).vect();
1433 G4double costh = std::sqrt(1.0 - inuclRndm());
1434 G4ThreeVector pos = generateWithFixedTheta(-costh, nuclei_radius);
1435
1436 // Start particle outside nucleus, unless capture-at-rest
1437 G4int zone = number_of_zones;
1438 if (particle->getKineticEnergy() < small) zone--;
1439
1440 G4CascadParticle cpart(*particle, pos, zone, large, 0);
1441
1442 // SPECIAL CASE: Inbound photons are emplanted along through-path
1443 if (forceFirst(cpart)) choosePointAlongTraj(cpart);
1444
1445 if (verboseLevel > 2) G4cout << cpart << G4endl;
1446
1447 return cpart;
1448}
G4double getKineticEnergy() const
void choosePointAlongTraj(G4CascadParticle &cparticle)
G4LorentzVector generateWithFixedTheta(G4double ct, G4double p, G4double mass=0.)

Referenced by G4IntraNucleiCascader::setupCascade().

◆ initializeCascad() [2/2]

void G4NucleiModel::initializeCascad ( G4InuclNuclei * bullet,
G4InuclNuclei * target,
modelLists & output )

Definition at line 1450 of file G4NucleiModel.cc.

1452 {
1453 if (verboseLevel) {
1454 G4cout << " >>> G4NucleiModel::initializeCascad(bullet,target,output)"
1455 << G4endl;
1456 }
1457
1458 const G4double max_a_for_cascad = 5.0;
1459 const G4double ekin_cut = 2.0;
1460 const G4double small_ekin = 1.0e-6;
1461 const G4double r_large2for3 = 62.0;
1462 const G4double r0forAeq3 = 3.92;
1463 const G4double s3max = 6.5;
1464 const G4double r_large2for4 = 69.14;
1465 const G4double r0forAeq4 = 4.16;
1466 const G4double s4max = 7.0;
1467 const G4int itry_max = 100;
1468
1469 // Convenient references to input buffer contents
1470 std::vector<G4CascadParticle>& casparticles = output.first;
1471 std::vector<G4InuclElementaryParticle>& particles = output.second;
1472
1473 casparticles.clear(); // Reset input buffer to fill this event
1474 particles.clear();
1475
1476 // first decide whether it will be cascad or compound final nuclei
1477 G4int ab = bullet->getA();
1478 G4int zb = bullet->getZ();
1479 G4int at = target->getA();
1480 G4int zt = target->getZ();
1481
1482 G4double massb = bullet->getMass(); // For creating LorentzVectors below
1483
1484 if (ab < max_a_for_cascad) {
1485
1486 G4double benb = bindingEnergy(ab,zb)/GeV / G4double(ab);
1487 G4double bent = bindingEnergy(at,zt)/GeV / G4double(at);
1488 G4double ben = benb < bent ? bent : benb;
1489
1490 if (bullet->getKineticEnergy()/ab > ekin_cut*ben) {
1491 G4int itryg = 0;
1492
1493 /* Loop checking 08.06.2015 MHK */
1494 while (casparticles.size() == 0 && itryg < itry_max) {
1495 itryg++;
1496 particles.clear();
1497
1498 // nucleons coordinates and momenta in nuclei rest frame
1499 coordinates.clear();
1500 momentums.clear();
1501
1502 if (ab < 3) { // deuteron, simplest case
1503 G4double r = 2.214 - 3.4208 * G4Log(1.0 - 0.981 * inuclRndm());
1505 coordinates.push_back(coord1);
1506 coordinates.push_back(-coord1);
1507
1508 G4double p = 0.0;
1509 G4bool bad = true;
1510 G4int itry = 0;
1511
1512 while (bad && itry < itry_max) { /* Loop checking 08.06.2015 MHK */
1513 itry++;
1514 p = 456.0 * inuclRndm();
1515
1516 if (p * p / (p * p + 2079.36) / (p * p + 2079.36) > 1.2023e-4 * inuclRndm() &&
1517 p * r > 312.0) bad = false;
1518 }
1519
1520 if (itry == itry_max)
1521 if (verboseLevel > 2){
1522 G4cout << " deutron bullet generation-> itry = " << itry_max << G4endl;
1523 }
1524
1525 p = 0.0005 * p;
1526
1527 if (verboseLevel > 2){
1528 G4cout << " p nuc " << p << G4endl;
1529 }
1530
1532
1533 momentums.push_back(mom);
1534 mom.setVect(-mom.vect());
1535 momentums.push_back(-mom);
1536 } else {
1537 G4ThreeVector coord1;
1538
1539 G4bool badco = true;
1540
1541 G4int itry = 0;
1542
1543 if (ab == 3) {
1544 while (badco && itry < itry_max) {/* Loop checking 08.06.2015 MHK */
1545 if (itry > 0) coordinates.clear();
1546 itry++;
1547 G4int i(0);
1548
1549 for (i = 0; i < 2; i++) {
1550 G4int itry1 = 0;
1551 G4double ss, u, rho;
1552 G4double fmax = G4Exp(-0.5) / std::sqrt(0.5);
1553
1554 while (itry1 < itry_max) { /* Loop checking 08.06.2015 MHK */
1555 itry1++;
1556 ss = -G4Log(inuclRndm());
1557 u = fmax * inuclRndm();
1558 rho = std::sqrt(ss) * G4Exp(-ss);
1559
1560 if (rho > u && ss < s3max) {
1561 ss = r0forAeq3 * std::sqrt(ss);
1562 coord1 = generateWithRandomAngles(ss).vect();
1563 coordinates.push_back(coord1);
1564
1565 if (verboseLevel > 2){
1566 G4cout << " i " << i << " r " << coord1.mag() << G4endl;
1567 }
1568 break;
1569 }
1570 }
1571
1572 if (itry1 == itry_max) { // bad case
1573 coord1.set(10000.,10000.,10000.);
1574 coordinates.push_back(coord1);
1575 break;
1576 }
1577 }
1578
1579 coord1 = -coordinates[0] - coordinates[1];
1580 if (verboseLevel > 2) {
1581 G4cout << " 3 r " << coord1.mag() << G4endl;
1582 }
1583
1584 coordinates.push_back(coord1);
1585
1586 G4bool large_dist = false;
1587
1588 for (i = 0; i < 2; i++) {
1589 for (G4int j = i+1; j < 3; j++) {
1590 G4double r2 = (coordinates[i]-coordinates[j]).mag2();
1591
1592 if (verboseLevel > 2) {
1593 G4cout << " i " << i << " j " << j << " r2 " << r2 << G4endl;
1594 }
1595
1596 if (r2 > r_large2for3) {
1597 large_dist = true;
1598
1599 break;
1600 }
1601 }
1602
1603 if (large_dist) break;
1604 }
1605
1606 if(!large_dist) badco = false;
1607
1608 }
1609
1610 } else { // a >= 4
1611 G4double b = 3./(ab - 2.0);
1612 G4double b1 = 1.0 - b / 2.0;
1613 G4double u = b1 + std::sqrt(b1 * b1 + b);
1614 G4double fmax = (1.0 + u/b) * u * G4Exp(-u);
1615
1616 while (badco && itry < itry_max) {/* Loop checking 08.06.2015 MHK */
1617
1618 if (itry > 0) coordinates.clear();
1619 itry++;
1620 G4int i(0);
1621
1622 for (i = 0; i < ab-1; i++) {
1623 G4int itry1 = 0;
1624 G4double ss;
1625
1626 while (itry1 < itry_max) { /* Loop checking 08.06.2015 MHK */
1627 itry1++;
1628 ss = -G4Log(inuclRndm());
1629 u = fmax * inuclRndm();
1630
1631 if (std::sqrt(ss) * G4Exp(-ss) * (1.0 + ss/b) > u
1632 && ss < s4max) {
1633 ss = r0forAeq4 * std::sqrt(ss);
1634 coord1 = generateWithRandomAngles(ss).vect();
1635 coordinates.push_back(coord1);
1636
1637 if (verboseLevel > 2) {
1638 G4cout << " i " << i << " r " << coord1.mag() << G4endl;
1639 }
1640
1641 break;
1642 }
1643 }
1644
1645 if (itry1 == itry_max) { // bad case
1646 coord1.set(10000.,10000.,10000.);
1647 coordinates.push_back(coord1);
1648 break;
1649 }
1650 }
1651
1652 coord1 *= 0.0; // Cheap way to reset
1653 for(G4int j = 0; j < ab -1; j++) coord1 -= coordinates[j];
1654
1655 coordinates.push_back(coord1);
1656
1657 if (verboseLevel > 2){
1658 G4cout << " last r " << coord1.mag() << G4endl;
1659 }
1660
1661 G4bool large_dist = false;
1662
1663 for (i = 0; i < ab-1; i++) {
1664 for (G4int j = i+1; j < ab; j++) {
1665
1666 G4double r2 = (coordinates[i]-coordinates[j]).mag2();
1667
1668 if (verboseLevel > 2){
1669 G4cout << " i " << i << " j " << j << " r2 " << r2 << G4endl;
1670 }
1671
1672 if (r2 > r_large2for4) {
1673 large_dist = true;
1674
1675 break;
1676 }
1677 }
1678
1679 if (large_dist) break;
1680 }
1681
1682 if (!large_dist) badco = false;
1683 }
1684 }
1685
1686 if(badco) {
1687 G4cout << " can not generate the nucleons coordinates for a "
1688 << ab << G4endl;
1689
1690 casparticles.clear(); // Return empty buffer on error
1691 particles.clear();
1692 return;
1693
1694 } else { // momentums
1695 G4double p, u, x;
1696 G4LorentzVector mom;
1697 //G4bool badp = True;
1698
1699 for (G4int i = 0; i < ab - 1; i++) {
1700 G4int itry2 = 0;
1701
1702 while(itry2 < itry_max) { /* Loop checking 08.06.2015 MHK */
1703 itry2++;
1704 u = -G4Log(0.879853 - 0.8798502 * inuclRndm());
1705 x = u * G4Exp(-u);
1706
1707 if(x > inuclRndm()) {
1708 p = std::sqrt(0.01953 * u);
1709 mom = generateWithRandomAngles(p, massb);
1710 momentums.push_back(mom);
1711
1712 break;
1713 }
1714 } // while (itry2 < itry_max)
1715
1716 if(itry2 == itry_max) {
1717 G4cout << " can not generate proper momentum for a "
1718 << ab << G4endl;
1719
1720 casparticles.clear(); // Return empty buffer on error
1721 particles.clear();
1722 return;
1723 }
1724 } // for (i=0 ...
1725 // last momentum
1726
1727 mom *= 0.; // Cheap way to reset
1728 mom.setE(bullet->getEnergy()+target->getEnergy());
1729
1730 for(G4int j=0; j< ab-1; j++) mom -= momentums[j];
1731
1732 momentums.push_back(mom);
1733 }
1734 }
1735
1736 // Coordinates and momenta at rest are generated, now back to the lab
1737 G4double rb = 0.0;
1738 G4int i(0);
1739
1740 for(i = 0; i < G4int(coordinates.size()); i++) {
1741 G4double rp = coordinates[i].mag2();
1742
1743 if(rp > rb) rb = rp;
1744 }
1745
1746 // nuclei i.p. as a whole
1747 G4double s1 = std::sqrt(inuclRndm());
1748 G4double phi = randomPHI();
1749 G4double rz = (nuclei_radius + rb) * s1;
1750 G4ThreeVector global_pos(rz*std::cos(phi), rz*std::sin(phi),
1751 -(nuclei_radius+rb)*std::sqrt(1.0-s1*s1));
1752
1753 for (i = 0; i < G4int(coordinates.size()); i++) {
1754 coordinates[i] += global_pos;
1755 }
1756
1757 // all nucleons at rest
1758 raw_particles.clear();
1759
1760 for (G4int ipa = 0; ipa < ab; ipa++) {
1761 G4int knd = ipa < zb ? 1 : 2;
1762 raw_particles.push_back(G4InuclElementaryParticle(momentums[ipa], knd));
1763 }
1764
1765 G4InuclElementaryParticle dummy(small_ekin, 1);
1766 G4LorentzConvertor toTheBulletRestFrame(&dummy, bullet);
1767 toTheBulletRestFrame.toTheTargetRestFrame();
1768
1769 particleIterator ipart;
1770
1771 for (ipart = raw_particles.begin(); ipart != raw_particles.end(); ipart++) {
1772 ipart->setMomentum(toTheBulletRestFrame.backToTheLab(ipart->getMomentum()));
1773 }
1774
1775 // fill cascad particles and outgoing particles
1776
1777 for(G4int ip = 0; ip < G4int(raw_particles.size()); ip++) {
1778 G4LorentzVector mom = raw_particles[ip].getMomentum();
1779 G4double pmod = mom.rho();
1780 G4double t0 = -mom.vect().dot(coordinates[ip]) / pmod;
1781 G4double det = t0 * t0 + nuclei_radius * nuclei_radius
1782 - coordinates[ip].mag2();
1783 G4double tr = -1.0;
1784
1785 if(det > 0.0) {
1786 G4double t1 = t0 + std::sqrt(det);
1787 G4double t2 = t0 - std::sqrt(det);
1788
1789 if(std::fabs(t1) <= std::fabs(t2)) {
1790 if(t1 > 0.0) {
1791 if(coordinates[ip].z() + mom.z() * t1 / pmod <= 0.0) tr = t1;
1792 }
1793
1794 if(tr < 0.0 && t2 > 0.0) {
1795
1796 if(coordinates[ip].z() + mom.z() * t2 / pmod <= 0.0) tr = t2;
1797 }
1798
1799 } else {
1800 if(t2 > 0.0) {
1801
1802 if(coordinates[ip].z() + mom.z() * t2 / pmod <= 0.0) tr = t2;
1803 }
1804
1805 if(tr < 0.0 && t1 > 0.0) {
1806 if(coordinates[ip].z() + mom.z() * t1 / pmod <= 0.0) tr = t1;
1807 }
1808 }
1809
1810 }
1811
1812 if(tr >= 0.0) { // cascad particle
1813 coordinates[ip] += mom.vect()*tr / pmod;
1814 casparticles.push_back(G4CascadParticle(raw_particles[ip],
1815 coordinates[ip],
1816 number_of_zones, large, 0));
1817
1818 } else {
1819 particles.push_back(raw_particles[ip]);
1820 }
1821 }
1822 }
1823
1824 if(casparticles.size() == 0) {
1825 particles.clear();
1826
1827 G4cout << " can not generate proper distribution for " << itry_max
1828 << " steps " << G4endl;
1829 }
1830 }
1831 }
1832
1833 if(verboseLevel > 2){
1834 G4int ip(0);
1835
1836 G4cout << " cascad particles: " << casparticles.size() << G4endl;
1837 for(ip = 0; ip < G4int(casparticles.size()); ip++)
1838 G4cout << casparticles[ip] << G4endl;
1839
1840 G4cout << " outgoing particles: " << particles.size() << G4endl;
1841 for(ip = 0; ip < G4int(particles.size()); ip++)
1842 G4cout << particles[ip] << G4endl;
1843 }
1844
1845 return; // Buffer has been filled
1846}
std::vector< G4InuclElementaryParticle >::iterator particleIterator
double dot(const Hep3Vector &) const
G4int getZ() const
G4int getA() const
G4double getMass() const
G4double getEnergy() const

◆ inverseMeanFreePath()

G4double G4NucleiModel::inverseMeanFreePath ( const G4CascadParticle & cparticle,
const G4InuclElementaryParticle & target,
G4int zone = -1 )
protected

Definition at line 1851 of file G4NucleiModel.cc.

1853 {
1854 G4int ptype = cparticle.getParticle().type();
1855 G4int ip = target.type();
1856
1857 // Ensure that zone specified is within nucleus, for array lookups
1858 if (zone<0) zone = cparticle.getCurrentZone();
1859 if (zone>=number_of_zones) zone = number_of_zones-1;
1860
1861 // Special cases: neutrinos, and muon-on-neutron, have infinite path
1862 if (cparticle.getParticle().isNeutrino()) return 0.;
1863 if (ptype == muonMinus && ip == neutron) return 0.;
1864
1865 // Configure frame transformation to get kinetic energy for lookups
1866 dummy_convertor.setBullet(cparticle.getParticle());
1867 dummy_convertor.setTarget(&target);
1868 dummy_convertor.toTheCenterOfMass(); // Fill internal kinematics
1869 G4double ekin = dummy_convertor.getKinEnergyInTheTRS();
1870
1871 // Get cross section for interacting with target (dibaryons are absorptive)
1872 G4double csec = (ip < 100) ? totalCrossSection(ekin, ptype*ip)
1873 : absorptionCrossSection(ekin, ptype);
1874
1875 if (verboseLevel > 2) {
1876 G4cout << " ip " << ip << " zone " << zone << " ekin " << ekin
1877 << " dens " << getCurrentDensity(ip, zone)
1878 << " csec " << csec << G4endl;
1879 }
1880
1881 if (csec <= 0.) return 0.; // No interaction, avoid unnecessary work
1882
1883 // Get nuclear density and compute mean free path
1884 return csec * getCurrentDensity(ip, zone);
1885}
void setBullet(const G4InuclParticle *bullet)
G4double getKinEnergyInTheTRS() const
void setTarget(const G4InuclParticle *target)
G4double getCurrentDensity(G4int ip, G4int izone) const
G4double totalCrossSection(G4double ke, G4int rtype) const
G4double absorptionCrossSection(G4double e, G4int type) const

Referenced by choosePointAlongTraj(), and generateInteractionPartners().

◆ isProjectile()

G4bool G4NucleiModel::isProjectile ( const G4CascadParticle & cparticle) const

Definition at line 1345 of file G4NucleiModel.cc.

1345 {
1346 return (cparticle.getGeneration() == 0); // Only initial state particles
1347}

Referenced by forceFirst(), and generateInteractionPartners().

◆ passFermi()

G4bool G4NucleiModel::passFermi ( const std::vector< G4InuclElementaryParticle > & particles,
G4int zone )
protected

Definition at line 1069 of file G4NucleiModel.cc.

1070 {
1071 if (verboseLevel > 1) {
1072 G4cout << " >>> G4NucleiModel::passFermi" << G4endl;
1073 }
1074
1075 // Only check Fermi momenta for nucleons
1076 for (G4int i = 0; i < G4int(particles.size()); i++) {
1077 if (!particles[i].nucleon()) continue;
1078
1079 G4int type = particles[i].type();
1080 G4double mom = particles[i].getMomModule();
1081 G4double pfermi = fermi_momenta[type-1][zone];
1082
1083 if (verboseLevel > 2)
1084 G4cout << " type " << type << " p " << mom << " pf " << pfermi << G4endl;
1085
1086 if (mom < pfermi) {
1087 if (verboseLevel > 2) G4cout << " rejected by Fermi" << G4endl;
1088 return false;
1089 }
1090 }
1091 return true;
1092}
G4bool nucleon(G4int ityp)

Referenced by generateParticleFate().

◆ passTrailing()

G4bool G4NucleiModel::passTrailing ( const G4ThreeVector & hit_position)
protected

Definition at line 1098 of file G4NucleiModel.cc.

1098 {
1099 if (verboseLevel > 1)
1100 G4cout << " >>> G4NucleiModel::passTrailing " << hit_position << G4endl;
1101
1102 G4double dist;
1103 for (G4int i = 0; i < G4int(collisionPts.size() ); i++) {
1104 dist = (collisionPts[i] - hit_position).mag();
1105 if (verboseLevel > 2) G4cout << " dist " << dist << G4endl;
1106 if (dist < R_nucleon) {
1107 if (verboseLevel > 2) G4cout << " rejected by Trailing" << G4endl;
1108 return false;
1109 }
1110 }
1111 return true; // New point far enough away to be used
1112}

Referenced by generateParticleFate().

◆ printModel()

void G4NucleiModel::printModel ( ) const

Definition at line 612 of file G4NucleiModel.cc.

612 {
613 if (verboseLevel > 1) {
614 G4cout << " >>> G4NucleiModel::printModel" << G4endl;
615 }
616
617 G4cout << " nuclei model for A " << A << " Z " << Z << G4endl
618 << " proton binding energy " << binding_energies[0]
619 << " neutron binding energy " << binding_energies[1] << G4endl
620 << " Nuclei radius " << nuclei_radius << " volume " << nuclei_volume
621 << " number of zones " << number_of_zones << G4endl;
622
623 for (G4int i = 0; i < number_of_zones; i++)
624 G4cout << " zone " << i+1 << " radius " << zone_radii[i]
625 << " volume " << zone_volumes[i] << G4endl
626 << " protons: density " << getDensity(1,i) << " PF " <<
627 getFermiMomentum(1,i) << " VP " << getPotential(1,i) << G4endl
628 << " neutrons: density " << getDensity(2,i) << " PF " <<
629 getFermiMomentum(2,i) << " VP " << getPotential(2,i) << G4endl
630 << " pions: VP " << getPotential(3,i) << G4endl;
631}

Referenced by generateModel().

◆ reset()

void G4NucleiModel::reset ( G4int nHitNeutrons = 0,
G4int nHitProtons = 0,
const std::vector< G4ThreeVector > * hitPoints = 0 )

Definition at line 298 of file G4NucleiModel.cc.

299 {
300 neutronNumberCurrent = neutronNumber - nHitNeutrons;
301 protonNumberCurrent = protonNumber - nHitProtons;
302
303 // zero or copy collision point array for trailing effect
304 if (!hitPoints || !hitPoints->empty()) collisionPts.clear();
305 else collisionPts = *hitPoints;
306}

Referenced by G4IntraNucleiCascader::copyWoundedNucleus(), generateModel(), and G4IntraNucleiCascader::newCascade().

◆ setVerboseLevel()

void G4NucleiModel::setVerboseLevel ( G4int verbose)
inline

Definition at line 99 of file G4NucleiModel.hh.

99{ verboseLevel = verbose; }

Referenced by G4IntraNucleiCascader::setVerboseLevel().

◆ sortPartners()

static G4bool G4NucleiModel::sortPartners ( const partner & p1,
const partner & p2 )
inlinestaticprotected

Definition at line 209 of file G4NucleiModel.hh.

209 {
210 return (p2.second > p1.second);
211 }

Referenced by generateInteractionPartners().

◆ stillInside()

G4bool G4NucleiModel::stillInside ( const G4CascadParticle & cparticle)
inline

Definition at line 154 of file G4NucleiModel.hh.

154 {
155 return cparticle.getCurrentZone() < number_of_zones;
156 }

Referenced by G4IntraNucleiCascader::generateCascade().

◆ totalCrossSection()

G4double G4NucleiModel::totalCrossSection ( G4double ke,
G4int rtype ) const

Definition at line 1954 of file G4NucleiModel.cc.

1955{
1956 // All scattering cross-sections are available from tables
1957 const G4CascadeChannel* xsecTable = G4CascadeChannelTables::GetTable(rtype);
1958 if (!xsecTable) {
1959 G4cerr << " unknown collison type = " << rtype << G4endl;
1960 return 0.;
1961 }
1962
1963 return (crossSectionUnits * xsecTable->getCrossSection(ke));
1964}
static const G4CascadeChannel * GetTable(G4int initialState)
virtual G4double getCrossSection(double ke) const =0

Referenced by inverseMeanFreePath().

◆ useQuasiDeuteron()

G4bool G4NucleiModel::useQuasiDeuteron ( G4int ptype,
G4int qdtype = 0 )
static

Definition at line 1057 of file G4NucleiModel.cc.

1057 {
1058 if (qdtype==pn || qdtype==0) // All absorptive particles
1059 return (ptype==pi0 || ptype==pip || ptype==pim || ptype==gam || ptype==mum);
1060 else if (qdtype==pp) // Negative or neutral only
1061 return (ptype==pi0 || ptype==pim || ptype==gam || ptype==mum);
1062 else if (qdtype==nn) // Positive or neutral only
1063 return (ptype==pi0 || ptype==pip || ptype==gam);
1064
1065 return false; // Not a quasideuteron target
1066}

Referenced by absorptionCrossSection(), G4ElementaryParticleCollider::collide(), and generateInteractionPartners().

◆ worthToPropagate()

G4bool G4NucleiModel::worthToPropagate ( const G4CascadParticle & cparticle) const

Definition at line 1349 of file G4NucleiModel.cc.

1349 {
1350 if (verboseLevel > 1) {
1351 G4cout << " >>> G4NucleiModel::worthToPropagate" << G4endl;
1352 }
1353
1354 const G4double ekin_scale = 2.0;
1355
1356 G4bool worth = true;
1357
1358 if (cparticle.reflectedNow()) { // Just reflected -- keep going?
1359 G4int zone = cparticle.getCurrentZone();
1360 G4int ip = cparticle.getParticle().type();
1361
1362 // NOTE: Temporarily backing out use of potential for non-nucleons
1363 G4double ekin_cut = (cparticle.getParticle().nucleon()) ?
1364 getFermiKinetic(ip, zone) : 0.; //*** getPotential(ip, zone);
1365
1366 worth = cparticle.getParticle().getKineticEnergy()/ekin_scale > ekin_cut;
1367
1368 if (verboseLevel > 3) {
1369 G4cout << " type=" << ip
1370 << " ekin=" << cparticle.getParticle().getKineticEnergy()
1371 << " potential=" << ekin_cut
1372 << " : worth? " << worth << G4endl;
1373 }
1374 }
1375
1376 return worth;
1377}
G4bool reflectedNow() const
G4double getFermiKinetic(G4int ip, G4int izone) const

Referenced by G4IntraNucleiCascader::generateCascade().

◆ zoneIntegralGaussian()

G4double G4NucleiModel::zoneIntegralGaussian ( G4double ur1,
G4double ur2,
G4double nuclearRadius ) const
protected

Definition at line 564 of file G4NucleiModel.cc.

565 {
566 if (verboseLevel > 1) {
567 G4cout << " >>> G4NucleiModel::zoneIntegralGaussian" << G4endl;
568 }
569
570 G4double gaussRadius = std::sqrt(nucRad*nucRad * (1.0 - 1.0/A) + 6.4);
571
572 const G4double epsilon = 1.0e-3;
573 const G4int itry_max = 1000;
574
575 G4double dr = r2 - r1;
576 G4double fr1 = r1 * r1 * G4Exp(-r1 * r1);
577 G4double fr2 = r2 * r2 * G4Exp(-r2 * r2);
578 G4double fi = (fr1 + fr2) / 2.;
579 G4double fun1 = fi * dr;
580 G4double fun;
581 G4int jc = 1;
582 G4double dr1 = dr;
583 G4int itry = 0;
584
585 while (itry < itry_max) { /* Loop checking 08.06.2015 MHK */
586 dr /= 2.;
587 itry++;
588 G4double r = r1 - dr;
589 fi = 0.0;
590
591 for (G4int i = 0; i < jc; i++) {
592 r += dr1;
593 fi += r * r * G4Exp(-r * r);
594 }
595
596 fun = 0.5 * fun1 + fi * dr;
597
598 if (std::fabs((fun - fun1) / fun) <= epsilon) break;
599
600 jc *= 2;
601 dr1 = dr;
602 fun1 = fun;
603 } // while (itry < itry_max)
604
605 if (verboseLevel > 2 && itry == itry_max)
606 G4cerr << " zoneIntegralGaussian-> n iter " << itry_max << G4endl;
607
608 return gaussRadius*gaussRadius*gaussRadius * fun;
609}
G4double epsilon(G4double density, G4double temperature)

Referenced by fillZoneVolumes().

◆ zoneIntegralWoodsSaxon()

G4double G4NucleiModel::zoneIntegralWoodsSaxon ( G4double ur1,
G4double ur2,
G4double nuclearRadius ) const
protected

Definition at line 511 of file G4NucleiModel.cc.

512 {
513 if (verboseLevel > 1) {
514 G4cout << " >>> G4NucleiModel::zoneIntegralWoodsSaxon" << G4endl;
515 }
516
517 const G4double epsilon = 1.0e-3;
518 const G4int itry_max = 1000;
519
520 G4double skinRatio = nuclearRadius / skinDepth;
521
522 G4double d2 = 2.0 * skinRatio;
523 G4double dr = r2 - r1;
524 G4double fr1 = r1 * (r1 + d2) / (1.0 + G4Exp(r1));
525 G4double fr2 = r2 * (r2 + d2) / (1.0 + G4Exp(r2));
526 G4double fi = (fr1 + fr2) / 2.;
527 G4double fun1 = fi * dr;
528 G4double fun;
529 G4int jc = 1;
530 G4double dr1 = dr;
531 G4int itry = 0;
532
533 while (itry < itry_max) { /* Loop checking 08.06.2015 MHK */
534 dr /= 2.;
535 itry++;
536
537 G4double r = r1 - dr;
538 fi = 0.0;
539
540 for (G4int i = 0; i < jc; i++) {
541 r += dr1;
542 fi += r * (r + d2) / (1.0 + G4Exp(r));
543 }
544
545 fun = 0.5 * fun1 + fi * dr;
546
547 if (std::fabs((fun - fun1) / fun) <= epsilon) break;
548
549 jc *= 2;
550 dr1 = dr;
551 fun1 = fun;
552 } // while (itry < itry_max)
553
554 if (verboseLevel > 2 && itry == itry_max)
555 G4cout << " zoneIntegralWoodsSaxon-> n iter " << itry_max << G4endl;
556
557 G4double skinDepth3 = skinDepth*skinDepth*skinDepth;
558
559 return skinDepth3 * (fun + skinRatio*skinRatio*G4Log((1.0 + G4Exp(-r1)) / (1.0 + G4Exp(-r2))));
560}

Referenced by fillZoneVolumes().

Member Data Documentation

◆ thePartners

std::vector<partner> G4NucleiModel::thePartners
protected

Definition at line 205 of file G4NucleiModel.hh.

Referenced by generateInteractionPartners(), and generateParticleFate().


The documentation for this class was generated from the following files: