Geant4 11.4.0
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
void setDinucleonDensityScale ()

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

typedef std::pair<std::vector<G4CascadParticle>, std::vector<G4InuclElementaryParticle> > G4NucleiModel::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 234 of file G4NucleiModel.cc.

235 : verboseLevel(0), nuclei_radius(0.), nuclei_volume(0.), number_of_zones(0),
236 A(0), Z(0), theNucleus(0), neutronNumber(0), protonNumber(0),
237 neutronNumberCurrent(0), protonNumberCurrent(0), current_nucl1(0),
238 current_nucl2(0), dinucleonDensityScale(1.0), gammaQDinterp(kebins),
239 crossSectionUnits(G4CascadeParameters::xsecScale()),
241 skinDepth(0.611207*radiusUnits),
242 radiusScale((G4CascadeParameters::useTwoParam()?1.16:1.2)*radiusUnits),
243 radiusScale2((G4CascadeParameters::useTwoParam()?-1.3456:0.)*radiusUnits),
244 radiusForSmall(G4CascadeParameters::radiusSmall()),
245 radScaleAlpha(G4CascadeParameters::radiusAlpha()),
246 fermiMomentum(G4CascadeParameters::fermiScale()),
248 gammaQDscale(G4CascadeParameters::gammaQDScale()),
249 potentialThickness(1.0),
250 neutronEP(neutron), protonEP(proton) {}
const G4double A[17]
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 252 of file G4NucleiModel.cc.

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

◆ G4NucleiModel() [3/3]

G4NucleiModel::G4NucleiModel ( G4InuclNuclei * nuclei)
explicit

Definition at line 272 of file G4NucleiModel.cc.

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

◆ ~G4NucleiModel()

G4NucleiModel::~G4NucleiModel ( )
virtual

Definition at line 292 of file G4NucleiModel.cc.

292 {
293 delete theNucleus;
294 theNucleus = 0;
295}

Member Function Documentation

◆ absorptionCrossSection()

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

Definition at line 1969 of file G4NucleiModel.cc.

1969 {
1970 if (!useQuasiDeuteron(type)) {
1971 G4cerr << "absorptionCrossSection() only valid for incident pions or gammas"
1972 << G4endl;
1973 return 0.;
1974 }
1975
1976 G4double csec = 0.;
1977
1978 // Pion absorption is parametrized for low vs. medium energy
1979 // ... use for muon capture as well
1980 if (type == pionPlus || type == pionMinus || type == pionZero ||
1981 type == muonMinus) {
1982 if (ke < 0.3) csec = (0.1106 / std::sqrt(ke) - 0.8
1983 + 0.08 / ((ke-0.123)*(ke-0.123) + 0.0056) );
1984 else if (ke < 1.0) csec = 3.6735 * (1.0-ke)*(1.0-ke);
1985 }
1986
1987 if (type == photon) {
1988 csec = gammaQDinterp.interpolate(ke, gammaQDxsec) * gammaQDscale;
1989 }
1990
1991 if (csec < 0.0) csec = 0.0;
1992
1993 if (verboseLevel > 2) {
1994 G4cout << " ekin " << ke << " abs. csec " << csec << " mb" << G4endl;
1995 }
1996
1997 return crossSectionUnits * csec;
1998}
double G4double
Definition G4Types.hh:83
G4GLOB_DLL std::ostream G4cerr
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
static G4bool useQuasiDeuteron(G4int ptype, G4int qdtype=0)

Referenced by inverseMeanFreePath().

◆ boundaryTransition()

void G4NucleiModel::boundaryTransition ( G4CascadParticle & cparticle)
protected

Definition at line 1119 of file G4NucleiModel.cc.

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

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

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 }

◆ fillBindingEnergies()

void G4NucleiModel::fillBindingEnergies ( )
protected

Definition at line 394 of file G4NucleiModel.cc.

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

Referenced by generateModel().

◆ fillPotentials()

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

Definition at line 483 of file G4NucleiModel.cc.

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

Referenced by generateModel().

◆ fillZoneRadii()

void G4NucleiModel::fillZoneRadii ( G4double nuclearRadius)
protected

Definition at line 408 of file G4NucleiModel.cc.

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

Referenced by generateModel().

◆ fillZoneVolumes()

G4double G4NucleiModel::fillZoneVolumes ( G4double nuclearRadius)
protected

Definition at line 448 of file G4NucleiModel.cc.

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

1342 {
1343 return (isProjectile(cparticle) &&
1344 (cparticle.getParticle().isPhoton() ||
1345 cparticle.getParticle().isMuon())
1346 );
1347}
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 1937 of file G4NucleiModel.cc.

1938 {
1939 // Delay interactions of newly formed secondaries (minimum int. length)
1940 const G4double young_cut = std::sqrt(10.0) * 0.25;
1941 const G4double huge_num = 50.0; // Argument to exponential
1942
1943 G4double spath = large; // Buffer for return value
1944
1945 if (invmfp < small) return spath; // No interaction, avoid unnecessary work
1946
1947 G4double pw = -path * invmfp; // Ratio of path in zone to MFP
1948 if (pw < -huge_num) pw = -huge_num;
1949 pw = 1.0 - G4Exp(pw);
1950
1951 if (verboseLevel > 2)
1952 G4cout << " mfp " << 1./invmfp << " pw " << pw << G4endl;
1953
1954 // Primary particle(s) should always interact at least once
1955 if (forceFirst(cparticle) || (G4UniformRand() < pw) ) {
1956 spath = -G4Log(1.0 - pw*G4UniformRand() )/invmfp;
1957 if (cparticle.young(young_cut, spath)) spath = large;
1958
1959 if (verboseLevel > 2)
1960 G4cout << " spath " << spath << " path " << path << G4endl;
1961 }
1962
1963 return spath;
1964}
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 698 of file G4NucleiModel.cc.

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

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

313 {
314 generateModel(nuclei->getA(), nuclei->getZ());
315}

Referenced by G4NucleiModel(), G4NucleiModel(), and generateModel().

◆ generateNucleon()

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

Definition at line 661 of file G4NucleiModel.cc.

661 {
662 if (verboseLevel > 1) {
663 G4cout << " >>> G4NucleiModel::generateNucleon" << G4endl;
664 }
665
667 return G4InuclElementaryParticle(mom, type);
668}
G4LorentzVector generateNucleonMomentum(G4int type, G4int zone) const

Referenced by generateInteractionPartners().

◆ generateNucleonMomentum()

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

Definition at line 652 of file G4NucleiModel.cc.

652 {
653 G4double pmod = getFermiMomentum(type, zone) * G4cbrt(G4UniformRand() );
655
656 return generateWithRandomAngles(pmod, mass);
657}
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 868 of file G4NucleiModel.cc.

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

◆ generateQuasiDeuteron()

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

Definition at line 672 of file G4NucleiModel.cc.

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

Referenced by generateInteractionPartners().

◆ getCurrentDensity()

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

Definition at line 1441 of file G4NucleiModel.cc.

1441 {
1442// const G4double pn_spec = 1.0; // Scale factor for pn vs. pp/nn
1443 const G4double combinatoric_factor =
1445 G4double dens = 0.;
1446
1447 if (ip < 100) dens = getDensity(ip,izone);
1448 else { // For dibaryons, remove extra 1/volume term in density product
1449 switch (ip) {
1450 case diproton:
1451 dens = getDensity(proton,izone) * getDensity(proton,izone)
1452 * dinucleonDensityScale * combinatoric_factor;
1453 break;
1454 case unboundPN:
1455 dens = getDensity(proton,izone) * getDensity(neutron,izone)
1456 * dinucleonDensityScale;
1457 break;
1458 case dineutron:
1459 dens = getDensity(neutron,izone) * getDensity(neutron,izone)
1460 * dinucleonDensityScale * combinatoric_factor;
1461 break;
1462 default: dens = 0.;
1463 }
1464 dens *= getVolume(izone);
1465 }
1466
1467 return getRatio(ip) * dens;
1468}
G4bool IsBertiniNucleiModelAs11_2() const
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(), printModel(), and setDinucleonDensityScale().

◆ getFermiKinetic()

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

Definition at line 638 of file G4NucleiModel.cc.

638 {
639 G4double ekin = 0.0;
640
641 if (ip < 3 && izone < number_of_zones) { // ip for proton/neutron only
642 G4double pfermi = fermi_momenta[ip - 1][izone];
644
645 ekin = std::sqrt(pfermi*pfermi + mass*mass) - mass;
646 }
647 return ekin;
648}

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; }

◆ getNumberOfProtons()

G4int G4NucleiModel::getNumberOfProtons ( ) const
inline

Definition at line 148 of file G4NucleiModel.hh.

148{ return protonNumberCurrent; }

◆ 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; }

◆ getRatio()

G4double G4NucleiModel::getRatio ( G4int ip) const
protected

Definition at line 1384 of file G4NucleiModel.cc.

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

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 }

◆ 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(), and setDinucleonDensityScale().

◆ 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().

◆ initializeCascad() [1/2]

G4CascadParticle G4NucleiModel::initializeCascad ( G4InuclElementaryParticle * particle)

Definition at line 1472 of file G4NucleiModel.cc.

1472 {
1473 if (verboseLevel > 1) {
1474 G4cout << " >>> G4NucleiModel::initializeCascad(particle)" << G4endl;
1475 }
1476
1477 // FIXME: Previous version generated random sin(theta), then used -cos(theta)
1478 // Using generateWithRandomAngles changes result!
1479 // G4ThreeVector pos = generateWithRandomAngles(nuclei_radius).vect();
1480 G4double costh = std::sqrt(1.0 - G4UniformRand() );
1481 G4ThreeVector pos = generateWithFixedTheta(-costh, nuclei_radius);
1482
1483 // Start particle outside nucleus, unless capture-at-rest
1484 G4int zone = number_of_zones;
1485 if (particle->getKineticEnergy() < small) zone--;
1486
1487 G4CascadParticle cpart(*particle, pos, zone, large, 0);
1488
1489 // SPECIAL CASE: Inbound photons are emplanted along through-path
1490 if (forceFirst(cpart)) choosePointAlongTraj(cpart);
1491
1492 if (verboseLevel > 2) G4cout << cpart << G4endl;
1493
1494 return cpart;
1495}
G4double getKineticEnergy() const
void choosePointAlongTraj(G4CascadParticle &cparticle)
G4LorentzVector generateWithFixedTheta(G4double ct, G4double p, G4double mass=0.)

◆ initializeCascad() [2/2]

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

Definition at line 1497 of file G4NucleiModel.cc.

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

1900 {
1901 G4int ptype = cparticle.getParticle().type();
1902 G4int ip = target.type();
1903
1904 // Ensure that zone specified is within nucleus, for array lookups
1905 if (zone<0) zone = cparticle.getCurrentZone();
1906 if (zone>=number_of_zones) zone = number_of_zones-1;
1907
1908 // Special cases: neutrinos, and muon-on-neutron, have infinite path
1909 if (cparticle.getParticle().isNeutrino()) return 0.;
1910 if (ptype == muonMinus && ip == neutron) return 0.;
1911
1912 // Configure frame transformation to get kinetic energy for lookups
1913 dummy_convertor.setBullet(cparticle.getParticle());
1914 dummy_convertor.setTarget(&target);
1915 dummy_convertor.toTheCenterOfMass(); // Fill internal kinematics
1916 G4double ekin = dummy_convertor.getKinEnergyInTheTRS();
1917
1918 // Get cross section for interacting with target (dibaryons are absorptive)
1919 G4double csec = (ip < 100) ? totalCrossSection(ekin, ptype*ip)
1920 : absorptionCrossSection(ekin, ptype);
1921
1922 if (verboseLevel > 2) {
1923 G4cout << " ip " << ip << " zone " << zone << " ekin " << ekin
1924 << " dens " << getCurrentDensity(ip, zone)
1925 << " csec " << csec << G4endl;
1926 }
1927
1928 if (csec <= 0.) return 0.; // No interaction, avoid unnecessary work
1929
1930 // Get nuclear density and compute mean free path
1931 return csec * getCurrentDensity(ip, zone);
1932}
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 1349 of file G4NucleiModel.cc.

1349 {
1350 return (cparticle.getGeneration() == 0); // Only initial state particles
1351}

Referenced by forceFirst(), and generateInteractionPartners().

◆ passFermi()

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

Definition at line 1073 of file G4NucleiModel.cc.

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

Referenced by generateParticleFate().

◆ passTrailing()

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

Definition at line 1102 of file G4NucleiModel.cc.

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

Referenced by generateParticleFate().

◆ printModel()

void G4NucleiModel::printModel ( ) const

Definition at line 616 of file G4NucleiModel.cc.

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

Referenced by generateModel().

◆ reset()

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

Definition at line 300 of file G4NucleiModel.cc.

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

Referenced by generateModel().

◆ setDinucleonDensityScale()

void G4NucleiModel::setDinucleonDensityScale ( )
protected

Definition at line 1401 of file G4NucleiModel.cc.

1401 {
1402 if (A < 5) {
1403 dinucleonDensityScale = 1.0;
1404 // No scaling for light nuclei
1405 return;
1406 }
1407
1408 // At what A should LDA start to be applied?
1409 // Not satisfactory for medium nuclei according to Benhar et al., and a
1410 // sizable experimental uncertainty
1411
1412 // Levinger factor
1413 const G4double Levinger_LDA {10.83 - 9.73/G4Pow::GetInstance()->A13(A)};
1414
1415 // Effective number of quasi-deuterons in a nucleus according to
1416 // local density approximation
1417 const G4double num_LDA_QDs {(Levinger_LDA*Z*(A-Z))/A};
1418
1419 // Number of quasi-deuterons expected from proton and neutron nuclear
1420 // shell densities alone
1421 G4double num_Naive_QDs{0.};
1422 for (G4int zone = 0; zone < number_of_zones; ++zone) {
1423 num_Naive_QDs += getVolume(zone)*getDensity(proton, zone)*
1424 getVolume(zone)*getDensity(neutron, zone);
1425 }
1426
1427 // Density scaling factor determined for quasi-deuterons to be used
1428 // for pp, nn, pn
1429 dinucleonDensityScale = num_LDA_QDs/num_Naive_QDs;
1430
1431 if (verboseLevel > 4) {
1432 G4cout << " >>> G4NucleiModel::setDinucleonDensityScale()" << G4endl;
1433 G4cout << " >>> Naive number of quasi-deuterons in nucleus ("
1434 << Z << ", " << A << ") = " << num_Naive_QDs << G4endl;
1435 G4cout << " >>> Number of quasi-deuterons expected from Levinger LDA is "
1436 << num_LDA_QDs << G4endl;
1437 G4cout << "Rescaling dinucleon densities by " << dinucleonDensityScale << G4endl;
1438 }
1439}
static G4Pow * GetInstance()
Definition G4Pow.cc:41
G4double A13(G4double A) const
Definition G4Pow.cc:116

Referenced by generateModel().

◆ setVerboseLevel()

void G4NucleiModel::setVerboseLevel ( G4int verbose)
inline

Definition at line 99 of file G4NucleiModel.hh.

99{ verboseLevel = verbose; }

◆ sortPartners()

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 }

◆ totalCrossSection()

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

Definition at line 2001 of file G4NucleiModel.cc.

2002{
2003 // All scattering cross-sections are available from tables
2004 const G4CascadeChannel* xsecTable = G4CascadeChannelTables::GetTable(rtype);
2005 if (!xsecTable) {
2006 G4cerr << " unknown collison type = " << rtype << G4endl;
2007 return 0.;
2008 }
2009
2010 return (crossSectionUnits * xsecTable->getCrossSection(ke));
2011}
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 1061 of file G4NucleiModel.cc.

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

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

◆ worthToPropagate()

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

Definition at line 1353 of file G4NucleiModel.cc.

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

◆ zoneIntegralGaussian()

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

Definition at line 568 of file G4NucleiModel.cc.

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

Referenced by fillZoneVolumes().

◆ zoneIntegralWoodsSaxon()

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

Definition at line 515 of file G4NucleiModel.cc.

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

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: