Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/hadronic/models/particle_hp/src/G4ParticleHPInelasticCompFS.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

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