Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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.