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
G4ParticleHPInelasticCompFS.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// particle_hp -- source file
27// J.P. Wellisch, Nov-1996
28// A prototype of the low energy neutron transport model.
29//
30// 070523 bug fix for G4FPE_DEBUG on by A. Howard ( and T. Koi)
31// 070606 bug fix and migrate to enable to Partial cases by T. Koi
32// 080603 bug fix for Hadron Hyper News #932 by T. Koi
33// 080612 bug fix contribution from Benoit Pirard and Laurent Desorgher (Univ. Bern) #4,6
34// 080717 bug fix of calculation of residual momentum by T. Koi
35// 080801 protect negative available energy by T. Koi
36// introduce theNDLDataA,Z which has A and Z of NDL data by T. Koi
37// 081024 G4NucleiPropertiesTable:: to G4NucleiProperties::
38// 090514 Fix bug in IC electron emission case
39// Contribution from Chao Zhang (Chao.Zhang@usd.edu) and Dongming Mei(Dongming.Mei@usd.edu)
40// 100406 "nothingWasKnownOnHadron=1" then sample mu isotropic in CM
41// add two_body_reaction
42// 100909 add safty
43// 101111 add safty for _nat_ data case in Binary reaction, but break conservation
44// 110430 add Reaction Q value and break up flag (MF3::QI and LR)
45//
46// P. Arce, June-2014 Conversion neutron_hp to particle_hp
47//
50#include "G4Nucleus.hh"
51#include "G4NucleiProperties.hh"
52#include "G4He3.hh"
53#include "G4Alpha.hh"
54#include "G4Electron.hh"
56#include "G4IonTable.hh"
57#include "G4Pow.hh"
58#include "G4SystemOfUnits.hh"
59
60#include "G4NRESP71M03.hh" // nresp71_m03.hh and nresp71_m02.hh are alike. The only difference between m02 and m03 is in the total carbon cross section that is properly included in the latter. These data are not used in nresp71_m0*.hh.
61
62// June-2019 - E. Mendoza - re-build "two_body_reaction", to be used by incident charged particles (now isotropic emission in the CMS). Also restrict nresp use below 20 MeV (for future developments). Add photon emission when no data available.
63
65{
66 std::ostringstream ost;
67 ost <<gammaPath<<"z"<<ZR<<".a"<<AR;
68 G4String aName = ost.str();
69 std::ifstream from(aName, std::ios::in);
70
71 if(!from) return; // no data found for this isotope
72 std::ifstream theGammaData(aName, std::ios::in);
73
74 theGammas.Init(theGammaData);
75}
76
78{
79 gammaPath = "/Inelastic/Gammas/"; //only in neutron data base
80 if(!G4FindDataDir("G4NEUTRONHPDATA"))
81 throw G4HadronicException(__FILE__, __LINE__, "Please setenv G4NEUTRONHPDATA to point to the neutron cross-section files where Inelastic/Gammas data is found.");
82 G4String tBase = G4FindDataDir("G4NEUTRONHPDATA");
83 gammaPath = tBase+gammaPath;
84 G4String tString = dirName;
85 G4bool dbool;
86 G4ParticleHPDataUsed aFile = theNames.GetName(static_cast<G4int>(A), static_cast<G4int>(Z), M, tString, aFSType, dbool);
87 G4String filename = aFile.GetName();
88#ifdef G4PHPDEBUG
89 if( std::getenv("G4ParticleHPDebug") ) G4cout << " G4ParticleHPInelasticCompFS::Init FILE " << filename << G4endl;
90#endif
91
92 SetAZMs( A, Z, M, aFile );
93
94 if ( !dbool || ( Z<2.5 && ( std::abs(theNDLDataZ - Z)>0.0001 || std::abs(theNDLDataA - A)>0.0001)) )
95 {
96#ifdef G4PHPDEBUG
97 if(std::getenv("G4ParticleHPDebug_NamesLogging")) G4cout << "Skipped = "<< filename <<" "<<A<<" "<<Z<<G4endl;
98#endif
99 hasAnyData = false;
100 hasFSData = false;
101 hasXsec = false;
102 return;
103 }
104 std::istringstream theData(std::ios::in);
106 if(!theData) //"!" is a operator of ios
107 {
108 hasAnyData = false;
109 hasFSData = false;
110 hasXsec = false;
111 // theData.close();
112 return;
113 }
114 // here we go
115 G4int infoType, dataType, dummy;
116 G4int sfType, it;
117 hasFSData = false;
118 while (theData >> infoType) // Loop checking, 11.05.2015, T. Koi
119 {
120 hasFSData = true;
121 theData >> dataType;
122 theData >> sfType >> dummy;
123 it = 50;
124 if(sfType>=600||(sfType<100&&sfType>=50)) it = sfType%50;
125 if(dataType==3)
126 {
127 //theData >> dummy >> dummy;
128 //TK110430
129 // QI and LR introudced since G4NDL3.15
130 G4double dqi;
131 G4int ilr;
132 theData >> dqi >> ilr;
133
134 QI[ it ] = dqi*CLHEP::eV;
135 LR[ it ] = ilr;
137 G4int total;
138 theData >> total;
139 theXsection[it]->Init(theData, total, CLHEP::eV);
140 //std::cout << theXsection[it]->GetXsec(1*MeV) << std::endl;
141 }
142 else if(dataType==4)
143 {
145 theAngularDistribution[it]->Init(theData);
146 }
147 else if(dataType==5)
148 {
150 theEnergyDistribution[it]->Init(theData);
151 }
152 else if(dataType==6)
153 {
155 // G4cout << this << " CompFS theEnergyAngData " << it << theEnergyAngData[it] << G4endl; //GDEB
156 theEnergyAngData[it]->Init(theData);
157 }
158 else if(dataType==12)
159 {
161 theFinalStatePhotons[it]->InitMean(theData);
162 }
163 else if(dataType==13)
164 {
167 }
168 else if(dataType==14)
169 {
170 theFinalStatePhotons[it]->InitAngular(theData);
171 }
172 else if(dataType==15)
173 {
175 }
176 else
177 {
178 throw G4HadronicException(__FILE__, __LINE__, "Data-type unknown to G4ParticleHPInelasticCompFS");
179 }
180 }
181 // theData.close();
182}
183
185{
186 G4double running[50];
187 running[0] = 0;
188 G4int i;
189 for(i=0; i<50; ++i)
190 {
191 if(i!=0) running[i]=running[i-1];
192 if(theXsection[i] != 0)
193 {
194 running[i] += std::max(0., theXsection[i]->GetXsec(eKinetic));
195 }
196 }
197 G4double random = G4UniformRand();
198 G4double sum = running[49];
199 G4int it = 50;
200 if(0!=sum)
201 {
202 G4int i0;
203 for(i0=0; i0<50; ++i0)
204 {
205 it = i0;
206 if(random < running[i0]/sum) break;
207 }
208 }
209 return it;
210}
211
212// n,p,d,t,he3,a
214 G4ParticleDefinition* aDefinition)
215{
216
217 // prepare neutron
218 if ( theResult.Get() == nullptr ) theResult.Put( new G4HadFinalState );
219 theResult.Get()->Clear();
220 G4double eKinetic = theTrack.GetKineticEnergy();
221 const G4HadProjectile *hadProjectile = &theTrack;
222 G4ReactionProduct incidReactionProduct( const_cast<G4ParticleDefinition *>(hadProjectile->GetDefinition()) ); // incidReactionProduct
223 incidReactionProduct.SetMomentum( hadProjectile->Get4Momentum().vect() );
224 incidReactionProduct.SetKineticEnergy( eKinetic );
225
226 // prepare target
227 G4int i;
228 for(i=0; i<50; ++i)
229 { if(theXsection[i] != 0) { break; } }
230
231 G4double targetMass=0;
232 G4double eps = 0.0001;
233 targetMass = G4NucleiProperties::GetNuclearMass(static_cast<G4int>(theBaseA+eps), static_cast<G4int>(theBaseZ+eps));
234#ifdef G4PHPDEBUG
235 if( std::getenv("G4ParticleHPDebug"))
236 G4cout <<this <<" G4ParticleHPInelasticCompFS::CompositeApply A "
237 <<theBaseA <<" Z " <<theBaseZ <<" incident "
238 <<hadProjectile->GetDefinition()->GetParticleName() <<G4endl;
239#endif
240 G4ReactionProduct theTarget;
241 G4Nucleus aNucleus;
242 //G4ThreeVector neuVelo = (1./hadProjectile->GetDefinition()->GetPDGMass())*incidReactionProduct.GetMomentum();
243 //theTarget = aNucleus.GetBiasedThermalNucleus( targetMass/hadProjectile->GetDefinition()->GetPDGMass() , neuVelo, theTrack.GetMaterial()->GetTemperature());
244 //G4Nucleus::GetBiasedThermalNucleus requests normalization of mass and velocity in neutron mass
245 G4ThreeVector neuVelo = ( 1./G4Neutron::Neutron()->GetPDGMass() )*incidReactionProduct.GetMomentum();
246 theTarget = aNucleus.GetBiasedThermalNucleus( targetMass/G4Neutron::Neutron()->GetPDGMass()
247 , neuVelo, theTrack.GetMaterial()->GetTemperature() );
248
250
251 // prepare the residual mass
252 G4double residualMass=0;
253 G4double residualZ = theBaseZ + theProjectile->GetPDGCharge() - aDefinition->GetPDGCharge();
254 G4double residualA = theBaseA + theProjectile->GetBaryonNumber() - aDefinition->GetBaryonNumber();
255 residualMass = G4NucleiProperties::GetNuclearMass(static_cast<G4int>(residualA+eps), static_cast<G4int>(residualZ+eps));
256
257 // prepare energy in target rest frame
258 G4ReactionProduct boosted;
259 boosted.Lorentz(incidReactionProduct, theTarget);
260 eKinetic = boosted.GetKineticEnergy();
261
262 // select exit channel for composite FS class.
263 G4int it = SelectExitChannel( eKinetic );
264
265 //E. Mendoza (2018) -- to use JENDL/AN-2005
268 it=50;
269 }
270 }
271
272 // set target and neutron in the relevant exit channel
273 InitDistributionInitialState(incidReactionProduct, theTarget, it);
274
275 //---------------------------------------------------------------------//
276 // Hook for NRESP71MODEL
277 if ( G4ParticleHPManager::GetInstance()->GetUseNRESP71Model() && eKinetic<20*MeV) {
278 if ( (G4int)(theBaseZ+0.1) == 6 ) // If the reaction is with Carbon...
279 {
281 if ( use_nresp71_model( aDefinition , it , theTarget , boosted ) ) return;
282 }
283 }
284 }
285 //---------------------------------------------------------------------//
286
287 G4ReactionProductVector * thePhotons = 0;
288 G4ReactionProductVector * theParticles = 0;
289 G4ReactionProduct aHadron;
290 aHadron.SetDefinition(aDefinition); // what if only cross-sections exist ==> Na 23 11 @@@@
291 G4double availableEnergy = incidReactionProduct.GetKineticEnergy() + incidReactionProduct.GetMass() - aHadron.GetMass() +
292 (targetMass - residualMass);
293
294 if ( availableEnergy < 0 )
295 {
296 availableEnergy = 0;
297 }
298 G4int nothingWasKnownOnHadron = 0;
299 G4int dummy;
300 G4double eGamm = 0;
301 G4int iLevel=it-1;
302
303 // without photon has it = 0
304 if( 50 == it )
305 {
306 // Excitation level is not determined
307 iLevel=-1;
308 aHadron.SetKineticEnergy(availableEnergy*residualMass/
309 (aHadron.GetMass()+residualMass));
310
311 //aHadron.SetMomentum(incidReactionProduct.GetMomentum()*(1./incidReactionProduct.GetTotalMomentum())*
312 // std::sqrt(aHadron.GetTotalEnergy()*aHadron.GetTotalEnergy()-
313 // aHadron.GetMass()*aHadron.GetMass()));
314
315 //TK add safty 100909
316 G4double p2 = ( aHadron.GetTotalEnergy()*aHadron.GetTotalEnergy() - aHadron.GetMass()*aHadron.GetMass() );
317 G4double p = 0.0;
318 if ( p2 > 0.0 )
319 p = std::sqrt( p );
320 aHadron.SetMomentum(incidReactionProduct.GetMomentum()*(1./incidReactionProduct.GetTotalMomentum())*p );
321 }
322 else
323 {
324 while ( iLevel!=-1 && theGammas.GetLevel(iLevel) == 0 ) { iLevel--; } // Loop checking, 11.05.2015, T. Koi
325 }
326
327 if ( theAngularDistribution[it] != 0 ) // MF4
328 {
329 if(theEnergyDistribution[it]!=0) // MF5
330 {
331 //************************************************************
332 /*
333 aHadron.SetKineticEnergy(theEnergyDistribution[it]->Sample(eKinetic, dummy));
334 G4double eSecN = aHadron.GetKineticEnergy();
335 */
336 //************************************************************
337 //EMendoza --> maximum allowable energy should be taken into account.
338 G4double dqi = 0.0;
339 if ( QI[it] < 0 || 849 < QI[it] ) dqi = QI[it]; //For backword compatibility QI introduced since G4NDL3.15
340 G4double MaxEne=eKinetic+dqi;
341 G4double eSecN=0.;
342
343 G4int icounter=0;
344 G4int icounter_max=1024;
345 do {
346 ++icounter;
347 if ( icounter > icounter_max ) {
348 G4cout << "Loop-counter exceeded the threshold value at " << __LINE__ << "th line of " << __FILE__ << "." << G4endl;
349 break;
350 }
351 eSecN=theEnergyDistribution[it]->Sample(eKinetic, dummy);
352 } while(eSecN>MaxEne); // Loop checking, 11.05.2015, T. Koi
353 aHadron.SetKineticEnergy(eSecN);
354 //************************************************************
355 eGamm = eKinetic-eSecN;
356 for(iLevel=theGammas.GetNumberOfLevels()-1; iLevel>=0; --iLevel)
357 {
358 if(theGammas.GetLevelEnergy(iLevel)<eGamm) break;
359 }
360 G4double random = 2*G4UniformRand();
361 iLevel+=G4int(random);
362 if(iLevel>theGammas.GetNumberOfLevels()-1)iLevel = theGammas.GetNumberOfLevels()-1;
363 }
364 else
365 {
366 G4double eExcitation = 0;
367 if(iLevel>=0) eExcitation = theGammas.GetLevel(iLevel)->GetLevelEnergy();
368 while (eKinetic-eExcitation < 0 && iLevel>0) // Loop checking, 11.05.2015, T. Koi
369 {
370 --iLevel;
371 eExcitation = theGammas.GetLevel(iLevel)->GetLevelEnergy();
372 }
373
374 // Use QI value for calculating excitation energy of residual.
375 G4bool useQI=false;
376 G4double dqi = QI[it];
377 if (dqi < 0 || 849 < dqi) useQI = true; // Former libraries do not have values in this range
378
379 if (useQI) {
380 // QI introudced since G4NDL3.15
381 // G4double QM=(incidReactionProduct.GetMass()+targetMass)-(aHadron.GetMass()+residualMass);
382 // eExcitation = QM-QI[it];
383 // eExcitation = QI[0] - QI[it]; // Bug fix #1838
384 // if(eExcitation < 20*CLHEP::keV) eExcitation = 0;
385
386 eExcitation = std::max(0.,QI[0] - QI[it]); // Bug fix 2333
387
388 // Re-evaluate iLevel based on this eExcitation
389 iLevel = 0;
390 G4bool find = false;
391 G4int imaxEx = 0;
392 G4double level_tolerance = 1.0*CLHEP::keV;
393
394 while( theGammas.GetLevel(iLevel+1) != 0 ) { // Loop checking, 11.05.2015, T. Koi
395 G4double maxEx = 0.0;
396 if (maxEx < theGammas.GetLevel(iLevel)->GetLevelEnergy() ) {
397 maxEx = theGammas.GetLevel(iLevel)->GetLevelEnergy();
398 imaxEx = iLevel;
399 }
400
401 // Fix bug 1789 DHW - first if-branch added because gamma data come from ENSDF
402 // and do not necessarily match the excitations used in ENDF-B.VII
403 // Compromise solution: use 1 keV tolerance suggested by T. Koi
404 if (std::abs(eExcitation - theGammas.GetLevel(iLevel)->GetLevelEnergy() ) < level_tolerance) {
405 find = true;
406 break;
407
408 } else if (eExcitation < theGammas.GetLevel(iLevel)->GetLevelEnergy() ) {
409 find = true;
410 --iLevel;
411 // very small eExcitation, iLevel becomes -1, this is protected below
412 if (theTrack.GetDefinition() == aDefinition) { // this line added as part of fix #1838
413 if (iLevel == -1) iLevel = 0;
414 }
415 break;
416 }
417 ++iLevel;
418 }
419
420 // If proper level cannot be found, use the maximum level
421 if (!find) iLevel = imaxEx;
422 }
423
424 if(std::getenv("G4ParticleHPDebug") && eKinetic-eExcitation < 0)
425 {
426 throw G4HadronicException(__FILE__, __LINE__, "SEVERE: InelasticCompFS: Consistency of data not good enough, please file report");
427 }
428 if(eKinetic-eExcitation < 0) eExcitation = 0;
429 if(iLevel!= -1) aHadron.SetKineticEnergy(eKinetic - eExcitation);
430
431 }
433
434 if( theFinalStatePhotons[it] == 0 )
435 {
436 thePhotons = theGammas.GetDecayGammas(iLevel);
437 eGamm -= theGammas.GetLevelEnergy(iLevel);
438 if(eGamm>0) // @ ok for now, but really needs an efficient way of correllated sampling @
439 {
440 G4ReactionProduct * theRestEnergy = new G4ReactionProduct;
441 theRestEnergy->SetDefinition(G4Gamma::Gamma());
442 theRestEnergy->SetKineticEnergy(eGamm);
443 G4double costh = 2.*G4UniformRand()-1.;
444 G4double phi = CLHEP::twopi*G4UniformRand();
445 theRestEnergy->SetMomentum(eGamm*std::sin(std::acos(costh))*std::cos(phi),
446 eGamm*std::sin(std::acos(costh))*std::sin(phi),
447 eGamm*costh);
448 if(thePhotons == 0) { thePhotons = new G4ReactionProductVector; }
449 thePhotons->push_back(theRestEnergy);
450 }
451 }
452 }
453 else if(theEnergyAngData[it] != 0) // MF6
454 {
455
456 theParticles = theEnergyAngData[it]->Sample(eKinetic);
457
458 // Adjust A and Z in the case of miss much between selected data and target nucleus
459 if ( theParticles != NULL ) {
460 G4int sumA = 0;
461 G4int sumZ = 0;
462 G4int maxA = 0;
463 G4int jAtMaxA = 0;
464 for ( G4int j = 0 ; j != (G4int)theParticles->size() ; ++j ) {
465 if ( theParticles->at(j)->GetDefinition()->GetBaryonNumber() > maxA ) {
466 maxA = theParticles->at(j)->GetDefinition()->GetBaryonNumber();
467 jAtMaxA = j;
468 }
469 sumA += theParticles->at(j)->GetDefinition()->GetBaryonNumber();
470 sumZ += G4int( theParticles->at(j)->GetDefinition()->GetPDGCharge() + eps );
471 }
472 G4int dA = (G4int)theBaseA + hadProjectile->GetDefinition()->GetBaryonNumber() - sumA;
473 G4int dZ = (G4int)theBaseZ + G4int( hadProjectile->GetDefinition()->GetPDGCharge() + eps ) - sumZ;
474 if ( dA < 0 || dZ < 0 ) {
475 G4int newA = theParticles->at(jAtMaxA)->GetDefinition()->GetBaryonNumber() + dA ;
476 G4int newZ = G4int( theParticles->at(jAtMaxA)->GetDefinition()->GetPDGCharge() + eps ) + dZ;
477 G4ParticleDefinition* pd = G4IonTable::GetIonTable()->GetIon ( newZ , newA );
478 theParticles->at( jAtMaxA )->SetDefinition( pd );
479 }
480 }
481 }
482 else
483 {
484 // @@@ what to do, if we have photon data, but no info on the hadron itself
485 nothingWasKnownOnHadron = 1;
486 }
487
488 if ( theFinalStatePhotons[it] != 0 )
489 {
490 // the photon distributions are in the Nucleus rest frame.
491 // TK residual rest frame
492 G4ReactionProduct boosted_tmp;
493 boosted_tmp.Lorentz(incidReactionProduct, theTarget);
494 G4double anEnergy = boosted_tmp.GetKineticEnergy();
495 thePhotons = theFinalStatePhotons[it]->GetPhotons(anEnergy);
496 G4double aBaseEnergy = theFinalStatePhotons[it]->GetLevelEnergy();
497 G4double testEnergy = 0;
498 if(thePhotons!=0 && thePhotons->size()!=0)
499 { aBaseEnergy-=thePhotons->operator[](0)->GetTotalEnergy(); }
500 if(theFinalStatePhotons[it]->NeedsCascade())
501 {
502 while(aBaseEnergy>0.01*CLHEP::keV) // Loop checking, 11.05.2015, T. Koi
503 {
504 // cascade down the levels
505 G4bool foundMatchingLevel = false;
506 G4int closest = 2;
507 G4double deltaEold = -1;
508 for(G4int j=1; j<it; ++j)
509 {
510 if(theFinalStatePhotons[j]!=0)
511 {
512 testEnergy = theFinalStatePhotons[j]->GetLevelEnergy();
513 }
514 else
515 {
516 testEnergy = 0;
517 }
518 G4double deltaE = std::abs(testEnergy-aBaseEnergy);
519 if(deltaE<0.1*CLHEP::keV)
520 {
521 G4ReactionProductVector * theNext =
522 theFinalStatePhotons[j]->GetPhotons(anEnergy);
523 if ( thePhotons != nullptr )
524 thePhotons->push_back(theNext->operator[](0));
525 aBaseEnergy = testEnergy-theNext->operator[](0)->GetTotalEnergy();
526 delete theNext;
527 foundMatchingLevel = true;
528 break; // ===>
529 }
530 if(theFinalStatePhotons[j]!=0 && ( deltaE<deltaEold||deltaEold<0.) )
531 {
532 closest = j;
533 deltaEold = deltaE;
534 }
535 } // <=== the break goes here.
536 if(!foundMatchingLevel)
537 {
538 G4ReactionProductVector * theNext =
539 theFinalStatePhotons[closest]->GetPhotons(anEnergy);
540 if ( thePhotons != nullptr )
541 thePhotons->push_back(theNext->operator[](0));
542 aBaseEnergy = aBaseEnergy-theNext->operator[](0)->GetTotalEnergy();
543 delete theNext;
544 }
545 }
546 }
547 }
548 unsigned int i0;
549 if(thePhotons!=0)
550 {
551 for(i0=0; i0<thePhotons->size(); ++i0)
552 {
553 // back to lab
554 thePhotons->operator[](i0)->Lorentz(*(thePhotons->operator[](i0)), -1.*theTarget);
555 }
556 }
557 if (nothingWasKnownOnHadron)
558 {
559 // In this case, hadron should be isotropic in CM
560 // Next 12 lines are Emilio's replacement
561 // G4double QM=(incidReactionProduct.GetMass()+targetMass)-(aHadron.GetMass()+residualMass);
562 // G4double eExcitation = QM-QI[it];
563 // G4double eExcitation = QI[0] - QI[it]; // Fix of bug #1838
564 // if(eExcitation<20*CLHEP::keV){eExcitation=0;}
565
566 G4double eExcitation = std::max(0.,QI[0] - QI[it]); // Fix of bug #2333
567
568 two_body_reaction(&incidReactionProduct,&theTarget,&aHadron,eExcitation);
569 if(thePhotons==0 && eExcitation>0){
570 for(iLevel=theGammas.GetNumberOfLevels()-1; iLevel>=0; --iLevel)
571 {
572 if(theGammas.GetLevelEnergy(iLevel)<eExcitation+5*keV) break; // 5 keV tolerance
573 }
574 thePhotons = theGammas.GetDecayGammas(iLevel);
575 }
576 }
577
578 // fill the result
579 // Beware - the recoil is not necessarily in the particles...
580 // Can be calculated from momentum conservation?
581 // The idea is that the particles ar emitted forst, and the gammas only once the
582 // recoil is on the residual; assumption is that gammas do not contribute to
583 // the recoil.
584 // This needs more design @@@
585
586 G4bool needsSeparateRecoil = false;
587 G4int totalBaryonNumber = 0;
588 G4int totalCharge = 0;
589 G4ThreeVector totalMomentum(0);
590 if(theParticles != 0)
591 {
592 const G4ParticleDefinition * aDef;
593 std::size_t ii0;
594 for(ii0=0; ii0<theParticles->size(); ++ii0)
595 {
596 aDef = theParticles->operator[](ii0)->GetDefinition();
597 totalBaryonNumber+=aDef->GetBaryonNumber();
598 totalCharge+=G4int(aDef->GetPDGCharge()+eps);
599 totalMomentum += theParticles->operator[](ii0)->GetMomentum();
600 }
601 if(totalBaryonNumber!=G4int(theBaseA+eps+hadProjectile->GetDefinition()->GetBaryonNumber()))
602 {
603 needsSeparateRecoil = true;
604 residualA = G4int(theBaseA+eps+hadProjectile->GetDefinition()->GetBaryonNumber()
605 -totalBaryonNumber);
606 residualZ = G4int(theBaseZ+eps+hadProjectile->GetDefinition()->GetPDGCharge()
607 -totalCharge);
608 }
609 }
610
611 std::size_t nPhotons = 0;
612 if(thePhotons!=0) { nPhotons = thePhotons->size(); }
613
614 G4DynamicParticle * theSec;
615
616 if( theParticles==0 )
617 {
618 theSec = new G4DynamicParticle;
619 theSec->SetDefinition(aHadron.GetDefinition());
620 theSec->SetMomentum(aHadron.GetMomentum());
621 theResult.Get()->AddSecondary(theSec, secID);
622#ifdef G4PHPDEBUG
623 if( std::getenv("G4ParticleHPDebug"))
624 G4cout << this << " G4ParticleHPInelasticCompFS::BaseApply add secondary1 "
625 << theSec->GetParticleDefinition()->GetParticleName() << " E= "
626 << theSec->GetKineticEnergy() << " NSECO "
628#endif
629
630 aHadron.Lorentz(aHadron, theTarget);
631 G4ReactionProduct theResidual;
633 ->GetIon(static_cast<G4int>(residualZ), static_cast<G4int>(residualA), 0));
634 theResidual.SetKineticEnergy(aHadron.GetKineticEnergy()*aHadron.GetMass()/theResidual.GetMass());
635
636 //080612TK contribution from Benoit Pirard and Laurent Desorgher (Univ. Bern) #6
637 //theResidual.SetMomentum(-1.*aHadron.GetMomentum());
638 G4ThreeVector incidentNeutronMomentum = incidReactionProduct.GetMomentum();
639 theResidual.SetMomentum(incidentNeutronMomentum - aHadron.GetMomentum());
640
641 theResidual.Lorentz(theResidual, -1.*theTarget);
642 G4ThreeVector totalPhotonMomentum(0,0,0);
643 if(thePhotons!=0)
644 {
645 for(i=0; i<(G4int)nPhotons; ++i)
646 {
647 totalPhotonMomentum += thePhotons->operator[](i)->GetMomentum();
648 }
649 }
650 theSec = new G4DynamicParticle;
651 theSec->SetDefinition(theResidual.GetDefinition());
652 theSec->SetMomentum(theResidual.GetMomentum()-totalPhotonMomentum);
653 theResult.Get()->AddSecondary(theSec, secID);
654#ifdef G4PHPDEBUG
655 if( std::getenv("G4ParticleHPDebug"))
656 G4cout << this
657 << " G4ParticleHPInelasticCompFS::BaseApply add secondary2 "
658 << theSec->GetParticleDefinition()->GetParticleName() << " E= "
659 << theSec->GetKineticEnergy() << " NSECO "
661#endif
662 }
663 else
664 {
665 for(i0=0; i0<theParticles->size(); ++i0)
666 {
667 theSec = new G4DynamicParticle;
668 theSec->SetDefinition(theParticles->operator[](i0)->GetDefinition());
669 theSec->SetMomentum(theParticles->operator[](i0)->GetMomentum());
670 theResult.Get()->AddSecondary(theSec, secID);
671#ifdef G4PHPDEBUG
672 if( std::getenv("G4ParticleHPDebug"))
673 G4cout << this
674 << " G4ParticleHPInelasticCompFS::BaseApply add secondary3 "
675 << theSec->GetParticleDefinition()->GetParticleName() << " E= "
676 << theSec->GetKineticEnergy() << " NSECO "
678#endif
679 delete theParticles->operator[](i0);
680 }
681 delete theParticles;
682 if(needsSeparateRecoil && residualZ!=0)
683 {
684 G4ReactionProduct theResidual;
686 ->GetIon(static_cast<G4int>(residualZ), static_cast<G4int>(residualA), 0));
687 G4double resiualKineticEnergy = theResidual.GetMass()*theResidual.GetMass();
688 resiualKineticEnergy += totalMomentum*totalMomentum;
689 resiualKineticEnergy = std::sqrt(resiualKineticEnergy) - theResidual.GetMass();
690 theResidual.SetKineticEnergy(resiualKineticEnergy);
691
692 //080612TK contribution from Benoit Pirard and Laurent Desorgher (Univ. Bern) #4
693 //theResidual.SetMomentum(-1.*totalMomentum);
694 //G4ThreeVector incidentNeutronMomentum = incidReactionProduct.GetMomentum();
695 //theResidual.SetMomentum(incidentNeutronMomentum - aHadron.GetMomentum());
696 //080717 TK Comment still do NOT include photon's mometum which produce by thePhotons
697 theResidual.SetMomentum( incidReactionProduct.GetMomentum() + theTarget.GetMomentum() - totalMomentum );
698
699 theSec = new G4DynamicParticle;
700 theSec->SetDefinition(theResidual.GetDefinition());
701 theSec->SetMomentum(theResidual.GetMomentum());
702 theResult.Get()->AddSecondary(theSec, secID);
703#ifdef G4PHPDEBUG
704 if( std::getenv("G4ParticleHPDebug"))
705 G4cout << this
706 << " G4ParticleHPInelasticCompFS::BaseApply add secondary4 "
707 << theSec->GetParticleDefinition()->GetParticleName() << " E= "
708 << theSec->GetKineticEnergy() << " NSECO "
710#endif
711 }
712 }
713 if(thePhotons!=0)
714 {
715 for(i=0; i<(G4int)nPhotons; ++i)
716 {
717 theSec = new G4DynamicParticle;
718 //Bug reported Chao Zhang (Chao.Zhang@usd.edu), Dongming Mei(Dongming.Mei@usd.edu) Feb. 25, 2009
719 //theSec->SetDefinition(G4Gamma::Gamma());
720 theSec->SetDefinition( thePhotons->operator[](i)->GetDefinition() );
721 //But never cause real effect at least with G4NDL3.13 TK
722 theSec->SetMomentum(thePhotons->operator[](i)->GetMomentum());
723 theResult.Get()->AddSecondary(theSec, secID);
724#ifdef G4PHPDEBUG
725 if( std::getenv("G4ParticleHPDebug"))
726 G4cout << this
727 << " G4ParticleHPInelasticCompFS::BaseApply add secondary5 "
728 << theSec->GetParticleDefinition()->GetParticleName() << " E= "
729 << theSec->GetKineticEnergy() << " NSECO "
731#endif
732
733 delete thePhotons->operator[](i);
734 }
735 // some garbage collection
736 delete thePhotons;
737 }
738
740 G4LorentzVector targ_4p_lab ( theTarget.GetMomentum() , std::sqrt( targ_pd->GetPDGMass()*targ_pd->GetPDGMass() + theTarget.GetMomentum().mag2() ) );
741 G4LorentzVector proj_4p_lab = theTrack.Get4Momentum();
742 G4LorentzVector init_4p_lab = proj_4p_lab + targ_4p_lab;
743 adjust_final_state ( init_4p_lab );
744
745 // clean up the primary neutron
747}
748
749//Re-implemented by E. Mendoza (2019). Isotropic emission in the CMS:
750// proj: projectile in target-rest-frame (input)
751// targ: target in target-rest-frame (input)
752// product: secondary particle in target-rest-frame (output)
753// resExcitationEnergy: excitation energy of the residual nucleus
754//
755void G4ParticleHPInelasticCompFS::two_body_reaction(G4ReactionProduct* proj,
756 G4ReactionProduct* targ,
757 G4ReactionProduct* product,
758 G4double resExcitationEnergy)
759{
760 //CMS system:
761 G4ReactionProduct theCMS= *proj+ *targ;
762
763 //Residual definition:
764 G4int resZ=(G4int)(proj->GetDefinition()->GetPDGCharge()+targ->GetDefinition()->GetPDGCharge()-product->GetDefinition()->GetPDGCharge()+0.1);
766 G4ReactionProduct theResidual;
767 theResidual.SetDefinition(G4IonTable::GetIonTable()->GetIon(resZ,resA,0.0));
768
769 //CMS system:
770 G4ReactionProduct theCMSproj;
771 G4ReactionProduct theCMStarg;
772 theCMSproj.Lorentz(*proj,theCMS);
773 theCMStarg.Lorentz(*targ,theCMS);
774 //final Momentum in the CMS:
775 G4double totE=std::sqrt(theCMSproj.GetMass()*theCMSproj.GetMass()+theCMSproj.GetTotalMomentum()*theCMSproj.GetTotalMomentum())+std::sqrt(theCMStarg.GetMass()*theCMStarg.GetMass()+theCMStarg.GetTotalMomentum()*theCMStarg.GetTotalMomentum());
776 G4double prodmass=product->GetMass();
777 G4double resmass=theResidual.GetMass()+resExcitationEnergy;
778 G4double fmomsquared=1./4./totE/totE*(totE*totE-(prodmass-resmass)*(prodmass-resmass))*(totE*totE-(prodmass+resmass)*(prodmass+resmass));
779 G4double fmom=0;
780 if(fmomsquared>0){
781 fmom=std::sqrt(fmomsquared);
782 }
783
784 //random (isotropic direction):
785 G4double cosTh = 2.*G4UniformRand()-1.;
786 G4double phi = CLHEP::twopi*G4UniformRand();
787 G4double theta = std::acos(cosTh);
788 G4double sinth = std::sin(theta);
789 product->SetMomentum(fmom*sinth*std::cos(phi),fmom*sinth*std::sin(phi),fmom*cosTh); //CMS
790 product->SetTotalEnergy(std::sqrt(prodmass*prodmass+fmom*fmom)); //CMS
791 //Back to the LAB system:
792 product->Lorentz(*product,-1.*theCMS);
793}
794
795G4bool G4ParticleHPInelasticCompFS::use_nresp71_model( const G4ParticleDefinition* aDefinition , const G4int it , const G4ReactionProduct& theTarget , G4ReactionProduct& boosted )
796{
797 if ( aDefinition == G4Neutron::Definition() ) // If the outgoing particle is a neutron...
798 {
799 // LR: flag LR in ENDF. It indicates whether there is breakup of the residual nucleus or not.
800 // it: exit channel (index of the carbon excited state)
801
802 // Added by A. R. Garcia (CIEMAT) to include the physics of C(N,N'3A) reactions from NRESP71.
803
804 if ( LR[it] > 0 ) // If there is breakup of the residual nucleus LR(flag LR in ENDF)>0 (i.e. Z=6 MT=52-91 (it=MT-50)).
805 {
806 // Defining carbon as the target in the reference frame at rest.
807 G4ReactionProduct theCarbon(theTarget);
808
809 theCarbon.SetMomentum(G4ThreeVector());
810 theCarbon.SetKineticEnergy(0.);
811
812 // Creating four reaction products.
813 G4ReactionProduct theProds[4];
814
815 // Applying C(N,N'3A) reaction mechanisms in the target rest frame.
816 if ( it == 41 )
817 {
818 // QI=QM=-7.275 MeV for C-0(N,N')C-C(3A) in ENDF/B-VII.1.
819 // This is not the value of the QI of the first step according
820 // to the model. So we don't take it. Instead, we set the one
821 // we have calculated: QI=(mn+m12C)-(ma+m9Be+Ex9Be)=-8.130 MeV.
822 nresp71_model.ApplyMechanismI_NBeA2A(boosted, theCarbon, theProds, -8.130/*QI[it]*/);
823 // N+C --> A[0]+9BE* | 9BE* --> N[1]+8BE | 8BE --> 2*A[2,3].
824 }
825 else
826 {
827 nresp71_model.ApplyMechanismII_ACN2A(boosted, theCarbon, theProds, QI[it]);
828 // N+C --> N'[0]+C* | C* --> A[1]+8BE | 8BE --> 2*A[2,3].
829 }
830
831 // Returning to the reference frame where the target was in motion.
832 for ( G4int j=0; j<4; ++j )
833 {
834 theProds[j].Lorentz(theProds[j], -1.*theTarget);
835 theResult.Get()->AddSecondary(new G4DynamicParticle(theProds[j].GetDefinition(), theProds[j].GetMomentum()), secID);
836 }
837
838 // Killing the primary neutron.
840
841 return true;
842 }
843 }
844 else if ( aDefinition == G4Alpha::Definition() ) // If the outgoing particle is an alpha, ...
845 {
846 // Added by A. R. Garcia (CIEMAT) to include the physics of C(N,A)9BE reactions from NRESP71.
847
848 if ( LR[it] == 0 ) // If Z=6, an alpha particle is emitted and there is no breakup of the residual nucleus LR(flag LR in ENDF)==0.
849 {
850 // Defining carbon as the target in the reference frame at rest.
851 G4ReactionProduct theCarbon(theTarget);
852 theCarbon.SetMomentum(G4ThreeVector());
853 theCarbon.SetKineticEnergy(0.);
854
855 // Creating four reaction products.
856 G4ReactionProduct theProds[2];
857
858 // Applying C(N,A)9BE reaction mechanism.
859 nresp71_model.ApplyMechanismABE(boosted, theCarbon, theProds);
860 // N+C --> A[0]+9BE[1].
861
862 for ( G4int j=0; j<2; ++j )
863 {
864 // Returning to the system of reference where the target was in motion.
865 theProds[j].Lorentz(theProds[j], -1.*theTarget);
866 theResult.Get()->AddSecondary(new G4DynamicParticle(theProds[j].GetDefinition(), theProds[j].GetMomentum()), secID);
867 }
868
869 // Killing the primary neutron.
871
872 return true;
873 }
874 else
875 {
876 G4Exception("G4ParticleHPInelasticCompFS::CompositeApply()",
877 "G4ParticleInelasticCompFS.cc", FatalException,
878 "Alpha production with LR!=0.");
879 }
880 }
881 return false;
882}
const char * G4FindDataDir(const char *)
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:59
@ stopAndKill
#define M(row, col)
std::vector< G4ReactionProduct * > G4ReactionProductVector
CLHEP::Hep3Vector G4ThreeVector
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]
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition: Randomize.hh:52
double mag2() const
Hep3Vector vect() const
static G4Alpha * Definition()
Definition: G4Alpha.cc:48
value_type & Get() const
Definition: G4Cache.hh:315
void Put(const value_type &val) const
Definition: G4Cache.hh:321
void SetDefinition(const G4ParticleDefinition *aParticleDefinition)
const G4ParticleDefinition * GetParticleDefinition() const
G4double GetKineticEnergy() const
void SetMomentum(const G4ThreeVector &momentum)
static G4Gamma * Gamma()
Definition: G4Gamma.cc:85
void SetStatusChange(G4HadFinalStateStatus aS)
void AddSecondary(G4DynamicParticle *aP, G4int mod=-1)
std::size_t GetNumberOfSecondaries() const
const G4Material * GetMaterial() const
const G4ParticleDefinition * GetDefinition() const
G4double GetKineticEnergy() const
const G4LorentzVector & Get4Momentum() const
G4ParticleDefinition * GetIon(G4int Z, G4int A, G4int lvl=0)
Definition: G4IonTable.cc:522
static G4IonTable * GetIonTable()
Definition: G4IonTable.cc:170
G4double GetTemperature() const
Definition: G4Material.hh:177
G4int ApplyMechanismABE(G4ReactionProduct &neut, G4ReactionProduct &carb, G4ReactionProduct *theProds)
G4int ApplyMechanismI_NBeA2A(G4ReactionProduct &neut, G4ReactionProduct &carb, G4ReactionProduct *theProds, const G4double QI)
G4int ApplyMechanismII_ACN2A(G4ReactionProduct &neut, G4ReactionProduct &carb, G4ReactionProduct *theProds, const G4double QI)
static G4Neutron * Neutron()
Definition: G4Neutron.cc:103
static G4Neutron * Definition()
Definition: G4Neutron.cc:53
static G4double GetNuclearMass(const G4double A, const G4double Z)
G4ReactionProduct GetBiasedThermalNucleus(G4double aMass, G4ThreeVector aVelocity, G4double temp=-1) const
Definition: G4Nucleus.cc:118
G4double GetPDGCharge() const
const G4String & GetParticleName() const
void Init(std::istream &aDataFile)
void SampleAndUpdate(G4ReactionProduct &anIncidentParticle)
G4ParticleHPLevel * GetLevel(G4int i)
G4ReactionProductVector * GetDecayGammas(G4int aLevel)
G4double GetLevelEnergy(G4int aLevel)
void Init(std::istream &aDataFile)
void Init(std::istream &aDataFile)
G4ReactionProductVector * Sample(G4double anEnergy)
G4double Sample(G4double anEnergy, G4int &it)
void SetAZMs(G4double anA, G4double aZ, G4int aM, G4ParticleHPDataUsed used)
G4ParticleDefinition * theProjectile
G4Cache< G4HadFinalState * > theResult
void adjust_final_state(G4LorentzVector)
void InitDistributionInitialState(G4ReactionProduct &anIncidentPart, G4ReactionProduct &aTarget, G4int it)
G4int SelectExitChannel(G4double eKinetic)
void CompositeApply(const G4HadProjectile &theTrack, G4ParticleDefinition *aHadron)
G4ParticleHPAngular * theAngularDistribution[51]
void InitGammas(G4double AR, G4double ZR)
void Init(G4double A, G4double Z, G4int M, G4String &dirName, G4String &aSFType, G4ParticleDefinition *)
G4ParticleHPEnergyDistribution * theEnergyDistribution[51]
G4ParticleHPEnAngCorrelation * theEnergyAngData[51]
virtual G4ParticleHPVector * GetXsec()
G4ParticleHPPhotonDist * theFinalStatePhotons[51]
static G4ParticleHPManager * GetInstance()
void GetDataStream(G4String, std::istringstream &iss)
G4ParticleHPDataUsed GetName(G4int A, G4int Z, G4String base, G4String rest, G4bool &active)
void InitEnergies(std::istream &aDataFile)
G4ReactionProductVector * GetPhotons(G4double anEnergy)
void InitAngular(std::istream &aDataFile)
void InitPartials(std::istream &aDataFile, G4ParticleHPVector *theXsec=0)
G4bool InitMean(std::istream &aDataFile)
void Init(std::istream &aDataFile, G4int total, G4double ux=1., G4double uy=1.)
void SetMomentum(const G4double x, const G4double y, const G4double z)
void SetTotalEnergy(const G4double en)
G4double GetTotalMomentum() const
G4double GetKineticEnergy() const
const G4ParticleDefinition * GetDefinition() const
G4double GetTotalEnergy() const
G4ThreeVector GetMomentum() const
void Lorentz(const G4ReactionProduct &p1, const G4ReactionProduct &p2)
void SetDefinition(const G4ParticleDefinition *aParticleDefinition)
void SetKineticEnergy(const G4double en)
G4double GetMass() const