Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4INCLXXInterface.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// INCL++ intra-nuclear cascade model
27// Alain Boudard, CEA-Saclay, France
28// Joseph Cugnon, University of Liege, Belgium
29// Jean-Christophe David, CEA-Saclay, France
30// Pekka Kaitaniemi, CEA-Saclay, France, and Helsinki Institute of Physics, Finland
31// Sylvie Leray, CEA-Saclay, France
32// Davide Mancusi, CEA-Saclay, France
33//
34#define INCLXX_IN_GEANT4_MODE 1
35
36#include "globals.hh"
37
38#include <cmath>
39
41#include "G4SystemOfUnits.hh"
42#include "G4INCLXXInterface.hh"
43#include "G4GenericIon.hh"
44#include "G4INCLCascade.hh"
46#include "G4ReactionProduct.hh"
47#include "G4HadSecondary.hh"
48#include "G4ParticleTable.hh"
51#include "G4String.hh"
53#include "G4SystemOfUnits.hh"
55#include "G4INCLVersion.hh"
56#include "G4VEvaporation.hh"
61
63#include "G4HyperTriton.hh"
64#include "G4HyperH4.hh"
65#include "G4HyperAlpha.hh"
66#include "G4DoubleHyperH4.hh"
68#include "G4HyperHe5.hh"
69
71 G4VIntraNuclearTransportModel(G4INCLXXInterfaceStore::GetInstance()->getINCLXXVersionName()),
72 theINCLModel(NULL),
73 thePreCompoundModel(aPreCompound),
74 theInterfaceStore(G4INCLXXInterfaceStore::GetInstance()),
75 theTally(NULL),
76 complainedAboutBackupModel(false),
77 complainedAboutPreCompound(false),
78 theIonTable(G4IonTable::GetIonTable()),
79 theINCLXXLevelDensity(NULL),
80 theINCLXXFissionProbability(NULL),
81 secID(-1)
82{
83 if(!thePreCompoundModel) {
86 thePreCompoundModel = static_cast<G4VPreCompoundModel*>(p);
87 if(!thePreCompoundModel) { thePreCompoundModel = new G4PreCompoundModel; }
88 }
89
90 // Use the environment variable G4INCLXX_NO_DE_EXCITATION to disable de-excitation
91 if(std::getenv("G4INCLXX_NO_DE_EXCITATION")) {
92 G4String message = "de-excitation is completely disabled!";
93 theInterfaceStore->EmitWarning(message);
95 } else {
98 theDeExcitation = static_cast<G4VPreCompoundModel*>(p);
100
101 // set the fission parameters for G4ExcitationHandler
102 G4VEvaporationChannel * const theFissionChannel =
104 G4CompetitiveFission * const theFissionChannelCast = dynamic_cast<G4CompetitiveFission *>(theFissionChannel);
105 if(theFissionChannelCast) {
106 theINCLXXLevelDensity = new G4FissionLevelDensityParameterINCLXX;
107 theFissionChannelCast->SetLevelDensityParameter(theINCLXXLevelDensity);
108 theINCLXXFissionProbability = new G4FissionProbability;
109 theINCLXXFissionProbability->SetFissionLevelDensityParameter(theINCLXXLevelDensity);
110 theFissionChannelCast->SetEmissionStrategy(theINCLXXFissionProbability);
111 theInterfaceStore->EmitBigWarning("INCL++/G4ExcitationHandler uses its own level-density parameter for fission");
112 } else {
113 theInterfaceStore->EmitBigWarning("INCL++/G4ExcitationHandler could not use its own level-density parameter for fission");
114 }
115 }
116
117 // use the envvar G4INCLXX_DUMP_REMNANT to dump information about the
118 // remnants on stdout
119 if(std::getenv("G4INCLXX_DUMP_REMNANT"))
120 dumpRemnantInfo = true;
121 else
122 dumpRemnantInfo = false;
123
124 theBackupModel = new G4BinaryLightIonReaction;
125 theBackupModelNucleon = new G4BinaryCascade;
126 secID = G4PhysicsModelCatalog::GetModelID( "model_INCLXXCascade" );
127}
128
130{
131 delete theINCLXXLevelDensity;
132 delete theINCLXXFissionProbability;
133}
134
135G4bool G4INCLXXInterface::AccurateProjectile(const G4HadProjectile &aTrack, const G4Nucleus &theNucleus) const {
136 // Use direct kinematics if the projectile is a nucleon or a pion
137 const G4ParticleDefinition *projectileDef = aTrack.GetDefinition();
138 if(std::abs(projectileDef->GetBaryonNumber()) < 2) // Every non-composite particle. abs()-> in case of anti-nucleus projectile
139 return false;
140
141 // Here all projectiles should be nuclei
142 const G4int pA = projectileDef->GetAtomicMass();
143 if(pA<=0) {
144 std::stringstream ss;
145 ss << "the model does not know how to handle a collision between a "
146 << projectileDef->GetParticleName() << " projectile and a Z="
147 << theNucleus.GetZ_asInt() << ", A=" << theNucleus.GetA_asInt();
148 theInterfaceStore->EmitBigWarning(ss.str());
149 return true;
150 }
151
152 // If either nucleus is a LCP (A<=4), run the collision as light on heavy
153 const G4int tA = theNucleus.GetA_asInt();
154 if(tA<=4 || pA<=4) {
155 if(pA<tA)
156 return false;
157 else
158 return true;
159 }
160
161 // If one of the nuclei is heavier than theMaxProjMassINCL, run the collision
162 // as light on heavy.
163 // Note that here we are sure that either the projectile or the target is
164 // smaller than theMaxProjMass; otherwise theBackupModel would have been
165 // called.
166 const G4int theMaxProjMassINCL = theInterfaceStore->GetMaxProjMassINCL();
167 if(pA > theMaxProjMassINCL)
168 return true;
169 else if(tA > theMaxProjMassINCL)
170 return false;
171 else
172 // In all other cases, use the global setting
173 return theInterfaceStore->GetAccurateProjectile();
174}
175
177{
178 G4ParticleDefinition const * const trackDefinition = aTrack.GetDefinition();
179 const G4bool isIonTrack = trackDefinition->GetParticleType()==G4GenericIon::GenericIon()->GetParticleType();
180 const G4int trackA = trackDefinition->GetAtomicMass();
181 const G4int trackZ = (G4int) trackDefinition->GetPDGCharge();
182 const G4int trackL = trackDefinition->GetNumberOfLambdasInHypernucleus();
183 const G4int nucleusA = theNucleus.GetA_asInt();
184 const G4int nucleusZ = theNucleus.GetZ_asInt();
185
186 // For reactions induced by weird projectiles (e.g. He2), bail out
187 if((isIonTrack && ((trackZ<=0 && trackL==0) || trackA<=trackZ)) ||
188 (nucleusA>1 && (nucleusZ<=0 || nucleusA<=nucleusZ))) {
189 theResult.Clear();
190 theResult.SetStatusChange(isAlive);
191 theResult.SetEnergyChange(aTrack.GetKineticEnergy());
192 theResult.SetMomentumChange(aTrack.Get4Momentum().vect().unit());
193 return &theResult;
194 }
195
196 // For reactions on nucleons, use the backup model (without complaining)
197 if(trackA<=1 && nucleusA<=1) {
198 return theBackupModelNucleon->ApplyYourself(aTrack, theNucleus);
199 }
200
201 // For systems heavier than theMaxProjMassINCL, use another model (typically
202 // BIC)
203 const G4int theMaxProjMassINCL = theInterfaceStore->GetMaxProjMassINCL();
204 if(trackA > theMaxProjMassINCL && nucleusA > theMaxProjMassINCL) {
205 if(!complainedAboutBackupModel) {
206 complainedAboutBackupModel = true;
207 std::stringstream ss;
208 ss << "INCL++ refuses to handle reactions between nuclei with A>"
209 << theMaxProjMassINCL
210 << ". A backup model ("
211 << theBackupModel->GetModelName()
212 << ") will be used instead.";
213 theInterfaceStore->EmitBigWarning(ss.str());
214 }
215 return theBackupModel->ApplyYourself(aTrack, theNucleus);
216 }
217
218 // For energies lower than cascadeMinEnergyPerNucleon, use PreCompound
219 const G4double cascadeMinEnergyPerNucleon = theInterfaceStore->GetCascadeMinEnergyPerNucleon();
220 const G4double trackKinE = aTrack.GetKineticEnergy();
221 if((trackDefinition==G4Neutron::NeutronDefinition() || trackDefinition==G4Proton::ProtonDefinition())
222 && trackKinE < cascadeMinEnergyPerNucleon) {
223 if(!complainedAboutPreCompound) {
224 complainedAboutPreCompound = true;
225 std::stringstream ss;
226 ss << "INCL++ refuses to handle nucleon-induced reactions below "
227 << cascadeMinEnergyPerNucleon / MeV
228 << " MeV. A PreCoumpound model ("
229 << thePreCompoundModel->GetModelName()
230 << ") will be used instead.";
231 theInterfaceStore->EmitBigWarning(ss.str());
232 }
233 return thePreCompoundModel->ApplyYourself(aTrack, theNucleus);
234 }
235
236 // Calculate the total four-momentum in the entrance channel
237 const G4double theNucleusMass = theIonTable->GetIonMass(nucleusZ, nucleusA);
238 const G4double theTrackMass = trackDefinition->GetPDGMass();
239 const G4double theTrackEnergy = trackKinE + theTrackMass;
240 const G4double theTrackMomentumAbs2 = theTrackEnergy*theTrackEnergy - theTrackMass*theTrackMass;
241 const G4double theTrackMomentumAbs = ((theTrackMomentumAbs2>0.0) ? std::sqrt(theTrackMomentumAbs2) : 0.0);
242 const G4ThreeVector theTrackMomentum = aTrack.Get4Momentum().getV().unit() * theTrackMomentumAbs;
243
244 G4LorentzVector goodTrack4Momentum(theTrackMomentum, theTrackEnergy);
245 G4LorentzVector fourMomentumIn;
246 fourMomentumIn.setE(theTrackEnergy + theNucleusMass);
247 fourMomentumIn.setVect(theTrackMomentum);
248
249 // Check if inverse kinematics should be used
250 const G4bool inverseKinematics = AccurateProjectile(aTrack, theNucleus);
251
252 // If we are running in inverse kinematics, redefine aTrack and theNucleus
253 G4LorentzRotation *toInverseKinematics = NULL;
254 G4LorentzRotation *toDirectKinematics = NULL;
255 G4HadProjectile const *aProjectileTrack = &aTrack;
256 G4Nucleus *theTargetNucleus = &theNucleus;
257 if(inverseKinematics) {
258 G4ParticleDefinition *oldTargetDef = theIonTable->GetIon(nucleusZ, nucleusA, 0);
259 const G4ParticleDefinition *oldProjectileDef = trackDefinition;
260
261 if(oldProjectileDef != 0 && oldTargetDef != 0) {
262 const G4int newTargetA = oldProjectileDef->GetAtomicMass();
263 const G4int newTargetZ = oldProjectileDef->GetAtomicNumber();
264 const G4int newTargetL = oldProjectileDef->GetNumberOfLambdasInHypernucleus();
265 if(newTargetA > 0 && newTargetZ > 0) {
266 // This should give us the same energy per nucleon
267 theTargetNucleus = new G4Nucleus(newTargetA, newTargetZ, newTargetL);
268 toInverseKinematics = new G4LorentzRotation(goodTrack4Momentum.boostVector());
269 G4LorentzVector theProjectile4Momentum(0.0, 0.0, 0.0, theNucleusMass);
270 G4DynamicParticle swappedProjectileParticle(oldTargetDef, (*toInverseKinematics) * theProjectile4Momentum);
271 aProjectileTrack = new G4HadProjectile(swappedProjectileParticle);
272 } else {
273 G4String message = "badly defined target after swapping. Falling back to normal (non-swapped) mode.";
274 theInterfaceStore->EmitWarning(message);
275 toInverseKinematics = new G4LorentzRotation;
276 }
277 } else {
278 G4String message = "oldProjectileDef or oldTargetDef was null";
279 theInterfaceStore->EmitWarning(message);
280 toInverseKinematics = new G4LorentzRotation;
281 }
282 }
283
284 // INCL assumes the projectile particle is going in the direction of
285 // the Z-axis. Here we construct proper rotation to convert the
286 // momentum vectors of the outcoming particles to the original
287 // coordinate system.
288 G4LorentzVector projectileMomentum = aProjectileTrack->Get4Momentum();
289
290 // INCL++ assumes that the projectile is going in the direction of
291 // the z-axis. In principle, if the coordinate system used by G4
292 // hadronic framework is defined differently we need a rotation to
293 // transform the INCL++ reaction products to the appropriate
294 // frame. Please note that it isn't necessary to apply this
295 // transform to the projectile because when creating the INCL++
296 // projectile particle; \see{toINCLKineticEnergy} needs to use only the
297 // projectile energy (direction is simply assumed to be along z-axis).
299 toZ.rotateZ(-projectileMomentum.phi());
300 toZ.rotateY(-projectileMomentum.theta());
301 G4RotationMatrix toLabFrame3 = toZ.inverse();
302 G4LorentzRotation toLabFrame(toLabFrame3);
303 // However, it turns out that the projectile given to us by G4
304 // hadronic framework is already going in the direction of the
305 // z-axis so this rotation is actually unnecessary. Both toZ and
306 // toLabFrame turn out to be unit matrices as can be seen by
307 // uncommenting the folowing two lines:
308 // G4cout <<"toZ = " << toZ << G4endl;
309 // G4cout <<"toLabFrame = " << toLabFrame << G4endl;
310
311 theResult.Clear(); // Make sure the output data structure is clean.
312 theResult.SetStatusChange(stopAndKill);
313
314 std::list<G4Fragment> remnants;
315
316 const G4int maxTries = 200;
317 G4int nTries = 0;
318 // INCL can generate transparent events. However, this is meaningful
319 // only in the standalone code. In Geant4 we must "force" INCL to
320 // produce a valid cascade.
321 G4bool eventIsOK = false;
322 do {
323 const G4INCL::ParticleSpecies theSpecies = toINCLParticleSpecies(*aProjectileTrack);
324 const G4double kineticEnergy = toINCLKineticEnergy(*aProjectileTrack);
325
326 // The INCL model will be created at the first use
328
329 const G4INCL::EventInfo eventInfo = theINCLModel->processEvent(theSpecies, kineticEnergy,
330 theTargetNucleus->GetA_asInt(),
331 theTargetNucleus->GetZ_asInt(),
332 -theTargetNucleus->GetL()); // Strangeness has opposite sign
333 // eventIsOK = !eventInfo.transparent && nTries < maxTries; // of the number of Lambdas
334 eventIsOK = !eventInfo.transparent;
335 if(eventIsOK) {
336
337 // If the collision was run in inverse kinematics, prepare to boost back
338 // all the reaction products
339 if(inverseKinematics) {
340 toDirectKinematics = new G4LorentzRotation(toInverseKinematics->inverse());
341 }
342
343 G4LorentzVector fourMomentumOut;
344
345 for(G4int i = 0; i < eventInfo.nParticles; ++i) {
346 G4int A = eventInfo.A[i];
347 G4int Z = eventInfo.Z[i];
348 G4int S = eventInfo.S[i]; // Strangeness
349 G4int PDGCode = eventInfo.PDGCode[i];
350 // G4cout <<"INCL particle A = " << A << " Z = " << Z << " S = " << S << G4endl;
351 G4double kinE = eventInfo.EKin[i];
352 G4double px = eventInfo.px[i];
353 G4double py = eventInfo.py[i];
354 G4double pz = eventInfo.pz[i];
355 G4DynamicParticle *p = toG4Particle(A, Z, S, PDGCode, kinE, px, py, pz);
356 if(p != 0) {
357 G4LorentzVector momentum = p->Get4Momentum();
358
359 // Apply the toLabFrame rotation
360 momentum *= toLabFrame;
361 // Apply the inverse-kinematics boost
362 if(inverseKinematics) {
363 momentum *= *toDirectKinematics;
364 momentum.setVect(-momentum.vect());
365 }
366
367 // Set the four-momentum of the reaction products
368 p->Set4Momentum(momentum);
369 fourMomentumOut += momentum;
370
371 // Propagate the particle's parent resonance information
372 G4HadSecondary secondary(p, 1.0, secID);
373 G4ParticleDefinition* parentResonanceDef = nullptr;
374 if ( eventInfo.parentResonancePDGCode[i] != 0 ) {
375 parentResonanceDef = G4ParticleTable::GetParticleTable()->FindParticle(eventInfo.parentResonancePDGCode[i]);
376 }
377 secondary.SetParentResonanceDef(parentResonanceDef);
378 secondary.SetParentResonanceID(eventInfo.parentResonanceID[i]);
379
380 theResult.AddSecondary(secondary);
381
382 } else {
383 G4String message = "the model produced a particle that couldn't be converted to Geant4 particle.";
384 theInterfaceStore->EmitWarning(message);
385 }
386 }
387
388 for(G4int i = 0; i < eventInfo.nRemnants; ++i) {
389 const G4int A = eventInfo.ARem[i];
390 const G4int Z = eventInfo.ZRem[i];
391 const G4int S = eventInfo.SRem[i];
392 // G4cout <<"INCL particle A = " << A << " Z = " << Z << " S= " << S << G4endl;
393 // Check that the remnant is a physical bound state: if not, resample the collision.
394 if(( Z == 0 && S == 0 && A > 1 ) || // No bound states for nn, nnn, nnnn, ...
395 ( Z == 0 && S != 0 && A < 4 ) || // No bound states for nl, ll, nnl, nll, lll
396 ( Z != 0 && S != 0 && A == Z + std::abs(S) )) { // No bound states for pl, ppl, pll, ...
397 std::stringstream ss;
398 ss << "unphysical residual fragment : Z=" << Z << " S=" << S << " A=" << A
399 << " skipping it and resampling the collision";
400 theInterfaceStore->EmitWarning(ss.str());
401 eventIsOK = false;
402 continue;
403 }
404 const G4double kinE = eventInfo.EKinRem[i];
405 const G4double px = eventInfo.pxRem[i];
406 const G4double py = eventInfo.pyRem[i];
407 const G4double pz = eventInfo.pzRem[i];
408 G4ThreeVector spin(
409 eventInfo.jxRem[i]*hbar_Planck,
410 eventInfo.jyRem[i]*hbar_Planck,
411 eventInfo.jzRem[i]*hbar_Planck
412 );
413 const G4double excitationE = eventInfo.EStarRem[i];
414 G4double nuclearMass = excitationE;
415 if ( S == 0 ) {
416 nuclearMass += G4NucleiProperties::GetNuclearMass(A, Z);
417 } else {
418 // Assumed that the opposite of the strangeness of the remnant gives the number of Lambdas inside it
419 nuclearMass += G4HyperNucleiProperties::GetNuclearMass(A, Z, std::abs(S));
420 }
421 const G4double scaling = remnant4MomentumScaling(nuclearMass, kinE, px, py, pz);
422 G4LorentzVector fourMomentum(scaling * px, scaling * py, scaling * pz,
423 nuclearMass + kinE);
424 if(std::abs(scaling - 1.0) > 0.01) {
425 std::stringstream ss;
426 ss << "momentum scaling = " << scaling
427 << "\n Lorentz vector = " << fourMomentum
428 << ")\n A = " << A << ", Z = " << Z << ", S = " << S
429 << "\n E* = " << excitationE << ", nuclearMass = " << nuclearMass
430 << "\n remnant i=" << i << ", nRemnants=" << eventInfo.nRemnants
431 << "\n Reaction was: " << aTrack.GetKineticEnergy()/MeV
432 << "-MeV " << trackDefinition->GetParticleName() << " + "
433 << theIonTable->GetIonName(theNucleus.GetZ_asInt(), theNucleus.GetA_asInt(), 0)
434 << ", in " << (inverseKinematics ? "inverse" : "direct") << " kinematics.";
435 theInterfaceStore->EmitWarning(ss.str());
436 }
437
438 // Apply the toLabFrame rotation
439 fourMomentum *= toLabFrame;
440 spin *= toLabFrame3;
441 // Apply the inverse-kinematics boost
442 if(inverseKinematics) {
443 fourMomentum *= *toDirectKinematics;
444 fourMomentum.setVect(-fourMomentum.vect());
445 }
446
447 fourMomentumOut += fourMomentum;
448 G4Fragment remnant(A, Z, std::abs(S), fourMomentum); // Assumed that -strangeness gives the number of Lambdas
449 remnant.SetAngularMomentum(spin);
450 remnant.SetCreatorModelID(secID);
451 if(dumpRemnantInfo) {
452 G4cerr << "G4INCLXX_DUMP_REMNANT: " << remnant << " spin: " << spin << G4endl;
453 }
454 remnants.push_back(remnant);
455 }
456
457 // Give up is the event is not ok (e.g. unphysical residual)
458 if(!eventIsOK) {
459 const G4int nSecondaries = (G4int)theResult.GetNumberOfSecondaries();
460 for(G4int j=0; j<nSecondaries; ++j) delete theResult.GetSecondary(j)->GetParticle();
461 theResult.Clear();
462 theResult.SetStatusChange(stopAndKill);
463 remnants.clear();
464 } else {
465 // Check four-momentum conservation
466 const G4LorentzVector violation4Momentum = fourMomentumOut - fourMomentumIn;
467 const G4double energyViolation = std::abs(violation4Momentum.e());
468 const G4double momentumViolation = violation4Momentum.rho();
469 if(energyViolation > G4INCLXXInterfaceStore::GetInstance()->GetConservationTolerance()) {
470 std::stringstream ss;
471 ss << "energy conservation violated by " << energyViolation/MeV << " MeV in "
472 << aTrack.GetKineticEnergy()/MeV << "-MeV " << trackDefinition->GetParticleName()
473 << " + " << theIonTable->GetIonName(theNucleus.GetZ_asInt(), theNucleus.GetA_asInt(), 0)
474 << " inelastic reaction, in " << (inverseKinematics ? "inverse" : "direct") << " kinematics. Will resample.";
475 theInterfaceStore->EmitWarning(ss.str());
476 eventIsOK = false;
477 const G4int nSecondaries = (G4int)theResult.GetNumberOfSecondaries();
478 for(G4int j=0; j<nSecondaries; ++j) delete theResult.GetSecondary(j)->GetParticle();
479 theResult.Clear();
480 theResult.SetStatusChange(stopAndKill);
481 remnants.clear();
482 } else if(momentumViolation > G4INCLXXInterfaceStore::GetInstance()->GetConservationTolerance()) {
483 std::stringstream ss;
484 ss << "momentum conservation violated by " << momentumViolation/MeV << " MeV in "
485 << aTrack.GetKineticEnergy()/MeV << "-MeV " << trackDefinition->GetParticleName()
486 << " + " << theIonTable->GetIonName(theNucleus.GetZ_asInt(), theNucleus.GetA_asInt(), 0)
487 << " inelastic reaction, in " << (inverseKinematics ? "inverse" : "direct") << " kinematics. Will resample.";
488 theInterfaceStore->EmitWarning(ss.str());
489 eventIsOK = false;
490 const G4int nSecondaries = (G4int)theResult.GetNumberOfSecondaries();
491 for(G4int j=0; j<nSecondaries; ++j) delete theResult.GetSecondary(j)->GetParticle();
492 theResult.Clear();
493 theResult.SetStatusChange(stopAndKill);
494 remnants.clear();
495 }
496 }
497 }
498 nTries++;
499 } while(!eventIsOK && nTries < maxTries); /* Loop checking, 10.07.2015, D.Mancusi */
500
501 // Clean up the objects that we created for the inverse kinematics
502 if(inverseKinematics) {
503 delete aProjectileTrack;
504 delete theTargetNucleus;
505 delete toInverseKinematics;
506 delete toDirectKinematics;
507 }
508
509 if(!eventIsOK) {
510 std::stringstream ss;
511 ss << "maximum number of tries exceeded for the proposed "
512 << aTrack.GetKineticEnergy()/MeV << "-MeV " << trackDefinition->GetParticleName()
513 << " + " << theIonTable->GetIonName(nucleusZ, nucleusA, 0)
514 << " inelastic reaction, in " << (inverseKinematics ? "inverse" : "direct") << " kinematics.";
515 theInterfaceStore->EmitWarning(ss.str());
516 theResult.SetStatusChange(isAlive);
517 theResult.SetEnergyChange(aTrack.GetKineticEnergy());
518 theResult.SetMomentumChange(aTrack.Get4Momentum().vect().unit());
519 return &theResult;
520 }
521
522 // De-excitation:
523
524 if(theDeExcitation != 0) {
525 for(std::list<G4Fragment>::iterator i = remnants.begin();
526 i != remnants.end(); ++i) {
527 G4ReactionProductVector *deExcitationResult = theDeExcitation->DeExcite((*i));
528
529 for(G4ReactionProductVector::iterator fragment = deExcitationResult->begin();
530 fragment != deExcitationResult->end(); ++fragment) {
531 const G4ParticleDefinition *def = (*fragment)->GetDefinition();
532 if(def != 0) {
533 G4DynamicParticle *theFragment = new G4DynamicParticle(def, (*fragment)->GetMomentum());
534 theResult.AddSecondary(theFragment, (*fragment)->GetCreatorModelID());
535 }
536 }
537
538 for(G4ReactionProductVector::iterator fragment = deExcitationResult->begin();
539 fragment != deExcitationResult->end(); ++fragment) {
540 delete (*fragment);
541 }
542 deExcitationResult->clear();
543 delete deExcitationResult;
544 }
545 }
546
547 remnants.clear();
548
549 if((theTally = theInterfaceStore->GetTally()))
550 theTally->Tally(aTrack, theNucleus, theResult);
551
552 return &theResult;
553}
554
556 return 0;
557}
558
559G4INCL::ParticleType G4INCLXXInterface::toINCLParticleType(G4ParticleDefinition const * const pdef) const {
560 if( pdef == G4Proton::Proton()) return G4INCL::Proton;
561 else if(pdef == G4Neutron::Neutron()) return G4INCL::Neutron;
562 else if(pdef == G4PionPlus::PionPlus()) return G4INCL::PiPlus;
563 else if(pdef == G4PionMinus::PionMinus()) return G4INCL::PiMinus;
564 else if(pdef == G4PionZero::PionZero()) return G4INCL::PiZero;
565 else if(pdef == G4KaonPlus::KaonPlus()) return G4INCL::KPlus;
566 else if(pdef == G4KaonZero::KaonZero()) return G4INCL::KZero;
567 else if(pdef == G4KaonMinus::KaonMinus()) return G4INCL::KMinus;
568 else if(pdef == G4AntiKaonZero::AntiKaonZero()) return G4INCL::KZeroBar;
569 // For K0L & K0S we do not take into account K0/K0B oscillations
570 else if(pdef == G4KaonZeroLong::KaonZeroLong()) return G4UniformRand() < 0.5 ? G4INCL::KZeroBar : G4INCL::KZero;
571 else if(pdef == G4KaonZeroShort::KaonZeroShort()) return G4UniformRand() < 0.5 ? G4INCL::KZeroBar : G4INCL::KZero;
572 else if(pdef == G4Deuteron::Deuteron()) return G4INCL::Composite;
573 else if(pdef == G4Triton::Triton()) return G4INCL::Composite;
574 else if(pdef == G4He3::He3()) return G4INCL::Composite;
575 else if(pdef == G4Alpha::Alpha()) return G4INCL::Composite;
577 else return G4INCL::UnknownParticle;
578}
579
580G4INCL::ParticleSpecies G4INCLXXInterface::toINCLParticleSpecies(G4HadProjectile const &aTrack) const {
581 const G4ParticleDefinition *pdef = aTrack.GetDefinition();
582 const G4INCL::ParticleType theType = toINCLParticleType(pdef);
583 if(theType!=G4INCL::Composite)
584 return G4INCL::ParticleSpecies(theType);
585 else {
586 G4INCL::ParticleSpecies theSpecies;
587 theSpecies.theType=theType;
588 theSpecies.theA=pdef->GetAtomicMass();
589 theSpecies.theZ=pdef->GetAtomicNumber();
590 return theSpecies;
591 }
592}
593
594G4double G4INCLXXInterface::toINCLKineticEnergy(G4HadProjectile const &aTrack) const {
595 return aTrack.GetKineticEnergy();
596}
597
598G4ParticleDefinition *G4INCLXXInterface::toG4ParticleDefinition(G4int A, G4int Z, G4int S, G4int PDGCode) const {
599 if (PDGCode == 2212) { return G4Proton::Proton();
600 } else if(PDGCode == 2112) { return G4Neutron::Neutron();
601 } else if(PDGCode == 211) { return G4PionPlus::PionPlus();
602 } else if(PDGCode == 111) { return G4PionZero::PionZero();
603 } else if(PDGCode == -211) { return G4PionMinus::PionMinus();
604
605 } else if(PDGCode == 221) { return G4Eta::Eta();
606 } else if(PDGCode == 22) { return G4Gamma::Gamma();
607
608 } else if(PDGCode == 3122) { return G4Lambda::Lambda();
609 } else if(PDGCode == 3222) { return G4SigmaPlus::SigmaPlus();
610 } else if(PDGCode == 3212) { return G4SigmaZero::SigmaZero();
611 } else if(PDGCode == 3112) { return G4SigmaMinus::SigmaMinus();
612 } else if(PDGCode == 321) { return G4KaonPlus::KaonPlus();
613 } else if(PDGCode == -321) { return G4KaonMinus::KaonMinus();
614 } else if(PDGCode == 130) { return G4KaonZeroLong::KaonZeroLong();
615 } else if(PDGCode == 310) { return G4KaonZeroShort::KaonZeroShort();
616
617 } else if(PDGCode == 1002) { return G4Deuteron::Deuteron();
618 } else if(PDGCode == 1003) { return G4Triton::Triton();
619 } else if(PDGCode == 2003) { return G4He3::He3();
620 } else if(PDGCode == 2004) { return G4Alpha::Alpha();
621 } else if(S != 0) { // Assumed that -S gives the number of Lambdas
622 if (A == 3 && Z == 1 && S == -1 ) return G4HyperTriton::Definition();
623 if (A == 4 && Z == 1 && S == -1 ) return G4HyperH4::Definition();
624 if (A == 4 && Z == 2 && S == -1 ) return G4HyperAlpha::Definition();
625 if (A == 4 && Z == 1 && S == -2 ) return G4DoubleHyperH4::Definition();
626 if (A == 4 && Z == 0 && S == -2 ) return G4DoubleHyperDoubleNeutron::Definition();
627 if (A == 5 && Z == 2 && S == -1 ) return G4HyperHe5::Definition();
628 } else if(A > 0 && Z > 0 && A > Z) { // Returns ground state ion definition.
629 return theIonTable->GetIon(Z, A, 0);
630 }
631 return 0; // Error, unrecognized particle
632}
633
634G4DynamicParticle *G4INCLXXInterface::toG4Particle(G4int A, G4int Z, G4int S, G4int PDGCode,
635 G4double kinE, G4double px,
636 G4double py, G4double pz) const {
637 const G4ParticleDefinition *def = toG4ParticleDefinition(A, Z, S, PDGCode);
638 if(def == 0) { // Check if we have a valid particle definition
639 return 0;
640 }
641 const G4double energy = kinE * MeV;
642 const G4ThreeVector momentum(px, py, pz);
643 const G4ThreeVector momentumDirection = momentum.unit();
644 G4DynamicParticle *p = new G4DynamicParticle(def, momentumDirection, energy);
645 return p;
646}
647
648G4double G4INCLXXInterface::remnant4MomentumScaling(G4double mass,
649 G4double kineticE,
650 G4double px, G4double py,
651 G4double pz) const {
652 const G4double p2 = px*px + py*py + pz*pz;
653 if(p2 > 0.0) {
654 const G4double pnew2 = kineticE*kineticE + 2.0*kineticE*mass;
655 return std::sqrt(pnew2)/std::sqrt(p2);
656 } else {
657 return 1.0;
658 }
659}
660
661void G4INCLXXInterface::ModelDescription(std::ostream& outFile) const {
662 outFile
663 << "The Liège Intranuclear Cascade (INCL++) is a model for reactions induced\n"
664 << "by nucleons, pions and light ion on any nucleus. The reaction is\n"
665 << "described as an avalanche of binary nucleon-nucleon collisions, which can\n"
666 << "lead to the emission of energetic particles and to the formation of an\n"
667 << "excited thermalised nucleus (remnant). The de-excitation of the remnant is\n"
668 << "outside the scope of INCL++ and is typically described by another model.\n\n"
669 << "INCL++ has been reasonably well tested for nucleon (~50 MeV to ~15 GeV),\n"
670 << "pion (idem) and light-ion projectiles (up to A=18, ~10A MeV to 1A GeV).\n"
671 << "Most tests involved target nuclei close to the stability valley, with\n"
672 << "numbers between 4 and 250.\n\n"
673 << "Reference: D. Mancusi et al., Phys. Rev. C90 (2014) 054602\n\n";
674}
675
678}
G4double S(G4double temp)
@ isAlive
@ stopAndKill
Header file for the G4INCLXXInterfaceStore class.
CLHEP::HepLorentzRotation G4LorentzRotation
std::vector< G4ReactionProduct * > G4ReactionProductVector
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
const G4int Z[17]
const G4double A[17]
G4GLOB_DLL std::ostream G4cerr
#define G4endl
Definition: G4ios.hh:57
#define G4UniformRand()
Definition: Randomize.hh:52
Hep3Vector unit() const
HepLorentzRotation inverse() const
double theta() const
Hep3Vector boostVector() const
Hep3Vector getV() const
Hep3Vector vect() const
void setVect(const Hep3Vector &)
HepRotation inverse() const
HepRotation & rotateZ(double delta)
Definition: Rotation.cc:87
HepRotation & rotateY(double delta)
Definition: Rotation.cc:74
static G4Alpha * Alpha()
Definition: G4Alpha.cc:88
static G4AntiKaonZero * AntiKaonZero()
void SetEmissionStrategy(G4VEmissionProbability *aFissionProb)
void SetLevelDensityParameter(G4VLevelDensityParameter *aLevelDensity)
static G4Deuteron * Deuteron()
Definition: G4Deuteron.cc:93
static G4DoubleHyperDoubleNeutron * Definition()
static G4DoubleHyperH4 * Definition()
G4LorentzVector Get4Momentum() const
void Set4Momentum(const G4LorentzVector &momentum)
static G4Eta * Eta()
Definition: G4Eta.cc:108
G4VEvaporation * GetEvaporation()
Revised level-density parameter for fission after INCL++.
void SetFissionLevelDensityParameter(G4VLevelDensityParameter *aLevelDensity)
void SetCreatorModelID(G4int value)
Definition: G4Fragment.hh:433
void SetAngularMomentum(const G4ThreeVector &)
Definition: G4Fragment.cc:325
static G4Gamma * Gamma()
Definition: G4Gamma.cc:85
static G4GenericIon * GenericIon()
Definition: G4GenericIon.cc:92
void SetStatusChange(G4HadFinalStateStatus aS)
void AddSecondary(G4DynamicParticle *aP, G4int mod=-1)
std::size_t GetNumberOfSecondaries() const
void SetEnergyChange(G4double anEnergy)
G4HadSecondary * GetSecondary(size_t i)
void SetMomentumChange(const G4ThreeVector &aV)
const G4ParticleDefinition * GetDefinition() const
G4double GetKineticEnergy() const
const G4LorentzVector & Get4Momentum() const
G4DynamicParticle * GetParticle()
void SetParentResonanceDef(const G4ParticleDefinition *parentDef)
void SetParentResonanceID(const G4int parentID)
G4HadronicInteraction * FindModel(const G4String &name)
static G4HadronicInteractionRegistry * Instance()
virtual G4HadFinalState * ApplyYourself(const G4HadProjectile &aTrack, G4Nucleus &targetNucleus)
const G4String & GetModelName() const
static G4He3 * He3()
Definition: G4He3.cc:93
static G4HyperAlpha * Definition()
Definition: G4HyperAlpha.cc:45
static G4HyperH4 * Definition()
Definition: G4HyperH4.cc:45
static G4HyperHe5 * Definition()
Definition: G4HyperHe5.cc:45
static G4double GetNuclearMass(G4int A, G4int Z, G4int L)
static G4HyperTriton * Definition()
Singleton class for configuring the INCL++ Geant4 interface.
void EmitWarning(const G4String &message)
Emit a warning to G4cout.
static G4INCLXXInterfaceStore * GetInstance()
Get the singleton instance.
G4int GetMaxProjMassINCL() const
Getter for theMaxProjMassINCL.
G4INCL::INCL * GetINCLModel()
Get the cached INCL model engine.
G4double GetConservationTolerance() const
Getter for conservationTolerance.
void EmitBigWarning(const G4String &message) const
Emit a BIG warning to G4cout.
G4double GetCascadeMinEnergyPerNucleon() const
Getter for cascadeMinEnergyPerNucleon.
G4INCLXXVInterfaceTally * GetTally() const
Getter for the interface tally.
G4bool GetAccurateProjectile() const
Getter for accurateProjectile.
virtual void ModelDescription(std::ostream &outFile) const
G4ReactionProductVector * Propagate(G4KineticTrackVector *theSecondaries, G4V3DNucleus *theNucleus)
G4INCLXXInterface(G4VPreCompoundModel *const aPreCompound=0)
G4String const & GetDeExcitationModelName() const
G4HadFinalState * ApplyYourself(const G4HadProjectile &aTrack, G4Nucleus &theNucleus)
virtual void Tally(G4HadProjectile const &aTrack, G4Nucleus const &theNucleus, G4HadFinalState const &result)=0
const EventInfo & processEvent()
const G4String & GetIonName(G4int Z, G4int A, G4int lvl=0) const
Definition: G4IonTable.cc:1229
G4ParticleDefinition * GetIon(G4int Z, G4int A, G4int lvl=0)
Definition: G4IonTable.cc:522
G4double GetIonMass(G4int Z, G4int A, G4int nL=0, G4int lvl=0) const
Definition: G4IonTable.cc:1517
static G4KaonMinus * KaonMinus()
Definition: G4KaonMinus.cc:112
static G4KaonPlus * KaonPlus()
Definition: G4KaonPlus.cc:112
static G4KaonZeroLong * KaonZeroLong()
static G4KaonZeroShort * KaonZeroShort()
static G4KaonZero * KaonZero()
Definition: G4KaonZero.cc:103
static G4Lambda * Lambda()
Definition: G4Lambda.cc:107
static G4Neutron * NeutronDefinition()
Definition: G4Neutron.cc:98
static G4Neutron * Neutron()
Definition: G4Neutron.cc:103
static G4double GetNuclearMass(const G4double A, const G4double Z)
G4int GetA_asInt() const
Definition: G4Nucleus.hh:99
G4int GetZ_asInt() const
Definition: G4Nucleus.hh:105
G4int GetL() const
Definition: G4Nucleus.hh:108
G4int GetAtomicNumber() const
const G4String & GetParticleType() const
G4int GetAtomicMass() const
G4double GetPDGCharge() const
G4int GetNumberOfLambdasInHypernucleus() const
const G4String & GetParticleName() const
G4ParticleDefinition * FindParticle(G4int PDGEncoding)
static G4ParticleTable * GetParticleTable()
static G4int GetModelID(const G4int modelIndex)
static G4PionMinus * PionMinus()
Definition: G4PionMinus.cc:97
static G4PionPlus * PionPlus()
Definition: G4PionPlus.cc:97
static G4PionZero * PionZero()
Definition: G4PionZero.cc:107
static G4Proton * ProtonDefinition()
Definition: G4Proton.cc:87
static G4Proton * Proton()
Definition: G4Proton.cc:92
static G4SigmaMinus * SigmaMinus()
static G4SigmaPlus * SigmaPlus()
Definition: G4SigmaPlus.cc:107
static G4SigmaZero * SigmaZero()
Definition: G4SigmaZero.cc:101
static G4Triton * Triton()
Definition: G4Triton.cc:93
G4VEvaporationChannel * GetFissionChannel()
virtual G4ReactionProductVector * DeExcite(G4Fragment &aFragment)=0
G4ExcitationHandler * GetExcitationHandler() const
G4double energy(const ThreeVector &p, const G4double m)
Short_t S[maxSizeParticles]
Particle strangeness number.
Int_t parentResonancePDGCode[maxSizeParticles]
Particle's parent resonance PDG code.
Short_t nRemnants
Number of remnants.
Bool_t transparent
True if the event is transparent.
Short_t A[maxSizeParticles]
Particle mass number.
Float_t EKinRem[maxSizeRemnants]
Remnant kinetic energy [MeV].
Int_t parentResonanceID[maxSizeParticles]
Particle's parent resonance unique ID identifier.
Float_t jzRem[maxSizeRemnants]
Remnant angular momentum, z component [ ].
Float_t EStarRem[maxSizeRemnants]
Remnant excitation energy [MeV].
Short_t Z[maxSizeParticles]
Particle charge number.
Float_t EKin[maxSizeParticles]
Particle kinetic energy [MeV].
Short_t nParticles
Number of particles in the final state.
Float_t jxRem[maxSizeRemnants]
Remnant angular momentum, x component [ ].
Float_t px[maxSizeParticles]
Particle momentum, x component [MeV/c].
Short_t SRem[maxSizeRemnants]
Remnant strangeness number.
Float_t pxRem[maxSizeRemnants]
Remnant momentum, x component [MeV/c].
Float_t pyRem[maxSizeRemnants]
Remnant momentum, y component [MeV/c].
Float_t pzRem[maxSizeRemnants]
Remnant momentum, z component [MeV/c].
Float_t pz[maxSizeParticles]
Particle momentum, z component [MeV/c].
Int_t PDGCode[maxSizeParticles]
PDG numbering of the particles.
Float_t jyRem[maxSizeRemnants]
Remnant angular momentum, y component [ ].
Float_t py[maxSizeParticles]
Particle momentum, y component [MeV/c].
Short_t ARem[maxSizeRemnants]
Remnant mass number.
Short_t ZRem[maxSizeRemnants]
Remnant charge number.