Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/hadronic/models/particle_hp/src/G4ParticleHPThermalScattering.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 // Thermal Neutron Scattering
 27 // Koi, Tatsumi (SLAC/SCCS)
 28 //
 29 // Class Description:
 30 //
 31 // Final State Generators for a high precision (based on evaluated data
 32 // libraries) description of themal neutron scattering below 4 eV;
 33 // Based on Thermal neutron scattering files
 34 // from the evaluated nuclear data files ENDF/B-VI, Release2
 35 // To be used in your physics list in case you need this physics.
 36 // In this case you want to register an object of this class with
 37 // the corresponding process.
 38 
 39 // 070625 Fix memory leaking at destructor by T. Koi
 40 // 081201 Fix memory leaking at destructor by T. Koi
 41 // 100729 Add model name in constructor Problem #1116
 42 // P. Arce, June-2014 Conversion neutron_hp to particle_hp
 43 //
 44 #include "G4ParticleHPThermalScattering.hh"
 45 
 46 #include "G4ElementTable.hh"
 47 #include "G4MaterialTable.hh"
 48 #include "G4Neutron.hh"
 49 #include "G4ParticleHPElastic.hh"
 50 #include "G4ParticleHPManager.hh"
 51 #include "G4ParticleHPThermalScatteringData.hh"
 52 #include "G4ParticleHPThermalScatteringNames.hh"
 53 #include "G4SystemOfUnits.hh"
 54 #include "G4Threading.hh"
 55 
 56 G4ParticleHPThermalScattering::G4ParticleHPThermalScattering()
 57   : G4HadronicInteraction("NeutronHPThermalScattering")
 58 {
 59   theHPElastic = new G4ParticleHPElastic();
 60 
 61   SetMinEnergy(0. * eV);
 62   SetMaxEnergy(4 * eV);
 63   theXSection = new G4ParticleHPThermalScatteringData();
 64 
 65   nMaterial = 0;
 66   nElement = 0;
 67 }
 68 
 69 G4ParticleHPThermalScattering::~G4ParticleHPThermalScattering()
 70 {
 71   delete theHPElastic;
 72 }
 73 
 74 void G4ParticleHPThermalScattering::clearCurrentFSData()
 75 {
 76   if (incoherentFSs != nullptr) {
 77     for (auto it = incoherentFSs->cbegin(); it != incoherentFSs->cend(); ++it) {
 78       for (auto itt = it->second->cbegin(); itt != it->second->cend(); ++itt) {
 79         for (auto ittt = itt->second->cbegin(); ittt != itt->second->cend(); ++ittt) {
 80           delete *ittt;
 81         }
 82         delete itt->second;
 83       }
 84       delete it->second;
 85     }
 86   }
 87 
 88   if (coherentFSs != nullptr) {
 89     for (auto it = coherentFSs->cbegin(); it != coherentFSs->cend(); ++it) {
 90       for (auto itt = it->second->cbegin(); itt != it->second->cend(); ++itt) {
 91         for (auto ittt = itt->second->cbegin(); ittt != itt->second->cend(); ++ittt) {
 92           delete *ittt;
 93         }
 94         delete itt->second;
 95       }
 96       delete it->second;
 97     }
 98   }
 99 
100   if (inelasticFSs != nullptr) {
101     for (auto it = inelasticFSs->cbegin(); it != inelasticFSs->cend(); ++it) {
102       for (auto itt = it->second->cbegin(); itt != it->second->cend(); ++itt) {
103         for (auto ittt = itt->second->cbegin(); ittt != itt->second->cend(); ++ittt) {
104           for (auto it4 = (*ittt)->vE_isoAngle.cbegin(); it4 != (*ittt)->vE_isoAngle.cend(); ++it4)
105           {
106             delete *it4;
107           }
108           delete *ittt;
109         }
110         delete itt->second;
111       }
112       delete it->second;
113     }
114   }
115 
116   incoherentFSs = nullptr;
117   coherentFSs = nullptr;
118   inelasticFSs = nullptr;
119 }
120 
121 void G4ParticleHPThermalScattering::BuildPhysicsTable(const G4ParticleDefinition& particle)
122 {
123   buildPhysicsTable();
124   theHPElastic->BuildPhysicsTable(particle);
125 }
126 
127 std::map<G4double, std::vector<std::pair<G4double, G4double>*>*>*
128 G4ParticleHPThermalScattering::readACoherentFSDATA(const G4String& name)
129 {
130   auto aCoherentFSDATA = new std::map<G4double, std::vector<std::pair<G4double, G4double>*>*>;
131 
132   std::istringstream theChannel(std::ios::in);
133   G4ParticleHPManager::GetInstance()->GetDataStream(name, theChannel);
134 
135   std::vector<G4double> vBraggE;
136 
137   G4int dummy;
138   while (theChannel >> dummy)  // MF // Loop checking, 11.05.2015, T. Koi
139   {
140     theChannel >> dummy;  // MT
141     G4double temp;
142     theChannel >> temp;
143     auto anBragE_P = new std::vector<std::pair<G4double, G4double>*>;
144 
145     G4int n;
146     theChannel >> n;
147     for (G4int i = 0; i < n; ++i) {
148       G4double Ei;
149       G4double Pi;
150       if (aCoherentFSDATA->empty()) {
151         theChannel >> Ei;
152         vBraggE.push_back(Ei);
153       }
154       else {
155         Ei = vBraggE[i];
156       }
157       theChannel >> Pi;
158       anBragE_P->push_back(new std::pair<G4double, G4double>(Ei, Pi));
159     }
160     aCoherentFSDATA->insert(
161       std::pair<G4double, std::vector<std::pair<G4double, G4double>*>*>(temp, anBragE_P));
162   }
163   return aCoherentFSDATA;
164 }
165 
166 std::map<G4double, std::vector<E_P_E_isoAng*>*>*
167 G4ParticleHPThermalScattering::readAnInelasticFSDATA(const G4String& name)
168 {
169   auto anT_E_P_E_isoAng = new std::map<G4double, std::vector<E_P_E_isoAng*>*>;
170 
171   std::istringstream theChannel(std::ios::in);
172   G4ParticleHPManager::GetInstance()->GetDataStream(name, theChannel);
173 
174   G4int dummy;
175   while (theChannel >> dummy)  // MF // Loop checking, 11.05.2015, T. Koi
176   {
177     theChannel >> dummy;  // MT
178     G4double temp;
179     theChannel >> temp;
180     auto vE_P_E_isoAng = new std::vector<E_P_E_isoAng*>;
181     G4int n;
182     theChannel >> n;
183     for (G4int i = 0; i < n; ++i) {
184       vE_P_E_isoAng->push_back(readAnE_P_E_isoAng(&theChannel));
185     }
186     anT_E_P_E_isoAng->insert(std::pair<G4double, std::vector<E_P_E_isoAng*>*>(temp, vE_P_E_isoAng));
187   }
188 
189   return anT_E_P_E_isoAng;
190 }
191 
192 E_P_E_isoAng*
193 G4ParticleHPThermalScattering::readAnE_P_E_isoAng(std::istream* file)  // for inelastic
194 {
195   auto aData = new E_P_E_isoAng;
196 
197   G4double dummy;
198   G4double energy;
199   G4int nep, nl;
200   *file >> dummy;
201   *file >> energy;
202   aData->energy = energy * eV;
203   *file >> dummy;
204   *file >> dummy;
205   *file >> nep;
206   *file >> nl;
207   aData->n = nep / nl;
208   for (G4int i = 0; i < aData->n; ++i) {
209     G4double prob;
210     auto anE_isoAng = new E_isoAng;
211     aData->vE_isoAngle.push_back(anE_isoAng);
212     *file >> energy;
213     anE_isoAng->energy = energy * eV;
214     anE_isoAng->n = nl - 2;
215     anE_isoAng->isoAngle.resize(anE_isoAng->n);
216     *file >> prob;
217     aData->prob.push_back(prob);
218     // G4cout << "G4ParticleHPThermalScattering inelastic " << energy/eV << " " <<  i << " " << prob
219     // << " " << aData->prob[ i ] << G4endl;
220     for (G4int j = 0; j < anE_isoAng->n; ++j) {
221       G4double x;
222       *file >> x;
223       anE_isoAng->isoAngle[j] = x;
224     }
225   }
226 
227   // Calcuate sum_of_provXdEs
228   G4double total = 0;
229   aData->secondary_energy_cdf.push_back(0.);
230   for (G4int i = 0; i < aData->n - 1; ++i) {
231     G4double E_L = aData->vE_isoAngle[i]->energy / eV;
232     G4double E_H = aData->vE_isoAngle[i + 1]->energy / eV;
233     G4double dE = E_H - E_L;
234     G4double pdf = (aData->prob[i] + aData->prob[i + 1]) / 2. * dE;
235     total += (pdf);
236     aData->secondary_energy_cdf.push_back(total);
237     aData->secondary_energy_pdf.push_back(pdf);
238     aData->secondary_energy_value.push_back(E_L);
239   }
240 
241   aData->sum_of_probXdEs = total;
242 
243   // Normalize CDF
244   aData->secondary_energy_cdf_size = (G4int)aData->secondary_energy_cdf.size();
245   for (G4int i = 0; i < aData->secondary_energy_cdf_size; ++i) {
246     aData->secondary_energy_cdf[i] /= total;
247   }
248 
249   return aData;
250 }
251 
252 std::map<G4double, std::vector<E_isoAng*>*>*
253 G4ParticleHPThermalScattering::readAnIncoherentFSDATA(const G4String& name)
254 {
255   auto T_E = new std::map<G4double, std::vector<E_isoAng*>*>;
256 
257   // std::ifstream theChannel( name.c_str() );
258   std::istringstream theChannel(std::ios::in);
259   G4ParticleHPManager::GetInstance()->GetDataStream(name, theChannel);
260 
261   G4int dummy;
262   while (theChannel >> dummy)  // MF // Loop checking, 11.05.2015, T. Koi
263   {
264     theChannel >> dummy;  // MT
265     G4double temp;
266     theChannel >> temp;
267     auto vE_isoAng = new std::vector<E_isoAng*>;
268     G4int n;
269     theChannel >> n;
270     for (G4int i = 0; i < n; i++)
271       vE_isoAng->push_back(readAnE_isoAng(&theChannel));
272     T_E->insert(std::pair<G4double, std::vector<E_isoAng*>*>(temp, vE_isoAng));
273   }
274   // theChannel.close();
275 
276   return T_E;
277 }
278 
279 E_isoAng* G4ParticleHPThermalScattering::readAnE_isoAng(std::istream* file)
280 {
281   auto aData = new E_isoAng;
282 
283   G4double dummy;
284   G4double energy;
285   G4int n;
286   *file >> dummy;
287   *file >> energy;
288   *file >> dummy;
289   *file >> dummy;
290   *file >> n;
291   *file >> dummy;
292   aData->energy = energy * eV;
293   aData->n = n - 2;
294   aData->isoAngle.resize(n);
295 
296   *file >> dummy;
297   *file >> dummy;
298   for (G4int i = 0; i < aData->n; i++)
299     *file >> aData->isoAngle[i];
300 
301   return aData;
302 }
303 
304 G4HadFinalState* G4ParticleHPThermalScattering::ApplyYourself(const G4HadProjectile& aTrack,
305                                                               G4Nucleus& aNucleus)
306 {
307   // Select Element > Reaction >
308 
309   const G4Material* theMaterial = aTrack.GetMaterial();
310   G4double aTemp = theMaterial->GetTemperature();
311   auto n = (G4int)theMaterial->GetNumberOfElements();
312 
313   G4bool findThermalElement = false;
314   G4int ielement;
315   const G4Element* theElement = nullptr;
316   for (G4int i = 0; i < n; ++i) {
317     theElement = theMaterial->GetElement(i);
318     // Select target element
319     if (aNucleus.GetZ_asInt() == (G4int)(theElement->GetZ() + 0.5)) {
320       // Check Applicability of Thermal Scattering
321       if (getTS_ID(nullptr, theElement) != -1) {
322         ielement = getTS_ID(nullptr, theElement);
323         findThermalElement = true;
324         break;
325       }
326       if (getTS_ID(theMaterial, theElement) != -1) {
327         ielement = getTS_ID(theMaterial, theElement);
328         findThermalElement = true;
329         break;
330       }
331     }
332   }
333 
334   if (findThermalElement) {
335     // Select Reaction  (Inelastic, coherent, incoherent)
336     const G4ParticleDefinition* pd = aTrack.GetDefinition();
337     auto dp = new G4DynamicParticle(pd, aTrack.Get4Momentum());
338     G4double total = theXSection->GetCrossSection(dp, theElement, theMaterial);
339     G4double inelastic = theXSection->GetInelasticCrossSection(dp, theElement, theMaterial);
340 
341     G4double random = G4UniformRand();
342     if (random <= inelastic / total) {
343       // Inelastic
344 
345       std::vector<G4double> v_temp;
346       v_temp.clear();
347       for (auto it = inelasticFSs->find(ielement)->second->cbegin();
348            it != inelasticFSs->find(ielement)->second->cend(); ++it)
349       {
350         v_temp.push_back(it->first);
351       }
352 
353       std::pair<G4double, G4double> tempLH = find_LH(aTemp, &v_temp);
354       //
355       // For T_L aNEP_EPM_TL  and T_H aNEP_EPM_TH
356       //
357       std::vector<E_P_E_isoAng*>* vNEP_EPM_TL = nullptr;
358       std::vector<E_P_E_isoAng*>* vNEP_EPM_TH = nullptr;
359 
360       if (tempLH.first != 0.0 && tempLH.second != 0.0) {
361         vNEP_EPM_TL = inelasticFSs->find(ielement)->second->find(tempLH.first / kelvin)->second;
362         vNEP_EPM_TH = inelasticFSs->find(ielement)->second->find(tempLH.second / kelvin)->second;
363       }
364       else if (tempLH.first == 0.0) {
365         auto itm = inelasticFSs->find(ielement)->second->cbegin();
366         vNEP_EPM_TL = itm->second;
367         ++itm;
368         vNEP_EPM_TH = itm->second;
369         tempLH.first = tempLH.second;
370         tempLH.second = itm->first;
371       }
372       else if (tempLH.second == 0.0) {
373         auto itm = inelasticFSs->find(ielement)->second->cend();
374         --itm;
375         vNEP_EPM_TH = itm->second;
376         --itm;
377         vNEP_EPM_TL = itm->second;
378         tempLH.second = tempLH.first;
379         tempLH.first = itm->first;
380       }
381 
382       G4double sE = 0., mu = 1.0;
383 
384       // New Geant4 method - Stochastic temperature interpolation of the final state
385       // (continuous temperature interpolation was used previously)
386       std::pair<G4double, G4double> secondaryParam;
387       G4double rand_temp = G4UniformRand();
388       if (rand_temp < (aTemp - tempLH.first) / (tempLH.second - tempLH.first))
389         secondaryParam = sample_inelastic_E_mu(aTrack.GetKineticEnergy(), vNEP_EPM_TH);
390       else
391         secondaryParam = sample_inelastic_E_mu(aTrack.GetKineticEnergy(), vNEP_EPM_TL);
392 
393       sE = secondaryParam.first;
394       mu = secondaryParam.second;
395 
396       // set
397       theParticleChange.SetEnergyChange(sE);
398       G4double phi = CLHEP::twopi * G4UniformRand();
399       G4double sint = std::sqrt(1 - mu * mu);
400       theParticleChange.SetMomentumChange(sint * std::cos(phi), sint * std::sin(phi), mu);
401     }
402     else if (random
403              <= (inelastic + theXSection->GetCoherentCrossSection(dp, theElement, theMaterial))
404                   / total)
405     {
406       // Coherent Elastic
407 
408       G4double E = aTrack.GetKineticEnergy();
409 
410       // T_L and T_H
411       std::vector<G4double> v_temp;
412       v_temp.clear();
413       for (auto it = coherentFSs->find(ielement)->second->cbegin();
414            it != coherentFSs->find(ielement)->second->cend(); ++it)
415       {
416         v_temp.push_back(it->first);
417       }
418 
419       //          T_L        T_H
420       std::pair<G4double, G4double> tempLH = find_LH(aTemp, &v_temp);
421       //
422       //
423       // For T_L anEPM_TL  and T_H anEPM_TH
424       //
425       std::vector<std::pair<G4double, G4double>*>* pvE_p_TL = nullptr;
426       std::vector<std::pair<G4double, G4double>*>* pvE_p_TH = nullptr;
427 
428       if (tempLH.first != 0.0 && tempLH.second != 0.0) {
429         pvE_p_TL = coherentFSs->find(ielement)->second->find(tempLH.first / kelvin)->second;
430         pvE_p_TH = coherentFSs->find(ielement)->second->find(tempLH.first / kelvin)->second;
431       }
432       else if (tempLH.first == 0.0) {
433         pvE_p_TL = coherentFSs->find(ielement)->second->find(v_temp[0])->second;
434         pvE_p_TH = coherentFSs->find(ielement)->second->find(v_temp[1])->second;
435         tempLH.first = tempLH.second;
436         tempLH.second = v_temp[1];
437       }
438       else if (tempLH.second == 0.0) {
439         pvE_p_TH = coherentFSs->find(ielement)->second->find(v_temp.back())->second;
440         auto itv = v_temp.cend();
441         --itv;
442         --itv;
443         pvE_p_TL = coherentFSs->find(ielement)->second->find(*itv)->second;
444         tempLH.second = tempLH.first;
445         tempLH.first = *itv;
446       }
447       else {
448         // tempLH.first == 0.0 && tempLH.second
449         throw G4HadronicException(
450           __FILE__, __LINE__,
451           "A problem is found in Thermal Scattering Data! Unexpected temperature values in data");
452       }
453 
454       std::vector<G4double> vE_T;
455       std::vector<G4double> vp_T;
456 
457       auto n1 = (G4int)pvE_p_TL->size();
458 
459       // New Geant4 method - Stochastic interpolation of the final state
460       std::vector<std::pair<G4double, G4double>*>* pvE_p_T_sampled;
461       G4double rand_temp = G4UniformRand();
462       if (rand_temp < (aTemp - tempLH.first) / (tempLH.second - tempLH.first))
463         pvE_p_T_sampled = pvE_p_TH;
464       else
465         pvE_p_T_sampled = pvE_p_TL;
466 
467       // 171005 fix bug, contribution from H.N. TRAN@CEA
468       for (G4int i = 0; i < n1; ++i) {
469         vE_T.push_back((*pvE_p_T_sampled)[i]->first);
470         vp_T.push_back((*pvE_p_T_sampled)[i]->second);
471       }
472 
473       G4int j = 0;
474       for (G4int i = 1; i < n1; ++i) {
475         if (E / eV < vE_T[i]) {
476           j = i - 1;
477           break;
478         }
479       }
480 
481       G4double rand_for_mu = G4UniformRand();
482 
483       G4int k = 0;
484       for (G4int i = 0; i <= j; ++i) {
485         G4double Pi = vp_T[i] / vp_T[j];
486         if (rand_for_mu < Pi) {
487           k = i;
488           break;
489         }
490       }
491 
492       G4double Ei = vE_T[k];
493 
494       G4double mu = 1 - 2 * Ei / (E / eV);
495 
496       if (mu < -1.0) mu = -1.0;
497 
498       theParticleChange.SetEnergyChange(E);
499       G4double phi = CLHEP::twopi * G4UniformRand();
500       G4double sint = std::sqrt(1 - mu * mu);
501       theParticleChange.SetMomentumChange(sint * std::cos(phi), sint * std::sin(phi), mu);
502     }
503     else {
504       // InCoherent Elastic
505 
506       // T_L and T_H
507       std::vector<G4double> v_temp;
508       v_temp.clear();
509       for (auto it = incoherentFSs->find(ielement)->second->cbegin();
510            it != incoherentFSs->find(ielement)->second->cend(); ++it)
511       {
512         v_temp.push_back(it->first);
513       }
514 
515       //          T_L        T_H
516       std::pair<G4double, G4double> tempLH = find_LH(aTemp, &v_temp);
517 
518       //
519       // For T_L anEPM_TL  and T_H anEPM_TH
520       //
521 
522       E_isoAng anEPM_TL_E;
523       E_isoAng anEPM_TH_E;
524 
525       if (tempLH.first != 0.0 && tempLH.second != 0.0) {
526         // Interpolate TL and TH
527         anEPM_TL_E = create_E_isoAng_from_energy(
528           aTrack.GetKineticEnergy(),
529           incoherentFSs->find(ielement)->second->find(tempLH.first / kelvin)->second);
530         anEPM_TH_E = create_E_isoAng_from_energy(
531           aTrack.GetKineticEnergy(),
532           incoherentFSs->find(ielement)->second->find(tempLH.second / kelvin)->second);
533       }
534       else if (tempLH.first == 0.0) {
535         // Extrapolate T0 and T1
536         anEPM_TL_E = create_E_isoAng_from_energy(
537           aTrack.GetKineticEnergy(),
538           incoherentFSs->find(ielement)->second->find(v_temp[0])->second);
539         anEPM_TH_E = create_E_isoAng_from_energy(
540           aTrack.GetKineticEnergy(),
541           incoherentFSs->find(ielement)->second->find(v_temp[1])->second);
542         tempLH.first = tempLH.second;
543         tempLH.second = v_temp[1];
544       }
545       else if (tempLH.second == 0.0) {
546         // Extrapolate Tmax-1 and Tmax
547         anEPM_TH_E = create_E_isoAng_from_energy(
548           aTrack.GetKineticEnergy(),
549           incoherentFSs->find(ielement)->second->find(v_temp.back())->second);
550         auto itv = v_temp.cend();
551         --itv;
552         --itv;
553         anEPM_TL_E = create_E_isoAng_from_energy(
554           aTrack.GetKineticEnergy(), incoherentFSs->find(ielement)->second->find(*itv)->second);
555         tempLH.second = tempLH.first;
556         tempLH.first = *itv;
557       }
558 
559       // E_isoAng for aTemp and aTrack.GetKineticEnergy()
560       G4double mu = 1.0;
561 
562       // New Geant4 method - Stochastic interpolation of the final state
563       E_isoAng anEPM_T_E_sampled;
564       G4double rand_temp = G4UniformRand();
565       if (rand_temp < (aTemp - tempLH.first) / (tempLH.second - tempLH.first))
566         anEPM_T_E_sampled = std::move(anEPM_TH_E);
567       else
568         anEPM_T_E_sampled = std::move(anEPM_TL_E);
569 
570       mu = getMu(&anEPM_T_E_sampled);
571 
572       // Set Final State
573       theParticleChange.SetEnergyChange(aTrack.GetKineticEnergy());  // No energy change in Elastic
574       G4double phi = CLHEP::twopi * G4UniformRand();
575       G4double sint = std::sqrt(1 - mu * mu);
576       theParticleChange.SetMomentumChange(sint * std::cos(phi), sint * std::sin(phi), mu);
577     }
578     delete dp;
579 
580     return &theParticleChange;
581   }
582   // Not thermal element
583   // Neutron HP will handle
584   return theHPElastic->ApplyYourself(aTrack, aNucleus,
585                                      true);  // L. Thulliez 2021/05/04 (CEA-Saclay)
586 }
587 
588 //**********************************************************
589 // Geant4 new algorithm
590 //**********************************************************
591 
592 //--------------------------------------------------
593 // New method added by L. Thulliez 2021 (CEA-Saclay)
594 //--------------------------------------------------
595 std::pair<G4double, G4int>
596 G4ParticleHPThermalScattering::sample_inelastic_E(G4double rndm1, G4double rndm2,
597                                                   E_P_E_isoAng* anE_P_E_isoAng)
598 {
599   G4int i = 0;
600   G4double sE_value = 0;
601 
602   for (; i < anE_P_E_isoAng->secondary_energy_cdf_size - 1; ++i) {
603     if (rndm1 >= anE_P_E_isoAng->secondary_energy_cdf[i]
604         && rndm1 < anE_P_E_isoAng->secondary_energy_cdf[i + 1])
605     {
606       G4double sE_value_i = anE_P_E_isoAng->secondary_energy_value[i];
607       G4double sE_pdf_i = anE_P_E_isoAng->secondary_energy_pdf[i];
608       G4double sE_value_i1 = anE_P_E_isoAng->secondary_energy_value[i + 1];
609       G4double sE_pdf_i1 = anE_P_E_isoAng->secondary_energy_pdf[i + 1];
610 
611       G4double lambda = 0;
612       G4double alpha = (sE_pdf_i1 - sE_pdf_i) / (sE_pdf_i1 + sE_pdf_i);
613       G4double rndm = rndm1;
614 
615       if (std::fabs(alpha) < 1E-8) {
616         lambda = rndm2;
617       }
618       else {
619         G4double beta = 2 * sE_pdf_i / (sE_pdf_i1 + sE_pdf_i);
620         rndm = rndm2;
621         G4double gamma = -rndm;
622         G4double delta = beta * beta - 4 * alpha * gamma;
623 
624         if (delta < 0 && std::fabs(delta) < 1.E-8) delta = 0;
625 
626         lambda = -beta + std::sqrt(delta);
627         lambda = lambda / (2 * alpha);
628 
629         if (lambda > 1)
630           lambda = 1;
631         else if (lambda < 0)
632           lambda = 0;
633       }
634 
635       sE_value = sE_value_i + lambda * (sE_value_i1 - sE_value_i);
636 
637       break;
638     }
639   }
640 
641   return std::pair<G4double, G4int>(sE_value, i);
642 }
643 
644 //--------------------------------------------------
645 // New method added by L. Thulliez 2021 (CEA-Saclay)
646 //--------------------------------------------------
647 std::pair<G4double, G4double>
648 G4ParticleHPThermalScattering::sample_inelastic_E_mu(G4double pE,
649                                                      std::vector<E_P_E_isoAng*>* vNEP_EPM)
650 {
651   // Sample primary energy bin
652   std::map<G4double, G4int> map_energy;
653   map_energy.clear();
654   std::vector<G4double> v_energy;
655   v_energy.clear();
656   G4int i = 0;
657   for (auto itv = vNEP_EPM->cbegin(); itv != vNEP_EPM->cend(); ++itv) {
658     v_energy.push_back((*itv)->energy);
659     map_energy.insert(std::pair<G4double, G4int>((*itv)->energy, i));
660     i++;
661   }
662 
663   std::pair<G4double, G4double> energyLH = find_LH(pE, &v_energy);
664 
665   std::vector<E_P_E_isoAng*> pE_P_E_isoAng_limit(2, nullptr);
666 
667   if (energyLH.first != 0.0 && energyLH.second != 0.0) {
668     pE_P_E_isoAng_limit[0] = (*vNEP_EPM)[map_energy.find(energyLH.first)->second];
669     pE_P_E_isoAng_limit[1] = (*vNEP_EPM)[map_energy.find(energyLH.second)->second];
670   }
671   else if (energyLH.first == 0.0) {
672     pE_P_E_isoAng_limit[0] = (*vNEP_EPM)[0];
673     pE_P_E_isoAng_limit[1] = (*vNEP_EPM)[1];
674   }
675   if (energyLH.second == 0.0) {
676     pE_P_E_isoAng_limit[1] = (*vNEP_EPM).back();
677     auto itv = vNEP_EPM->cend();
678     --itv;
679     --itv;
680     pE_P_E_isoAng_limit[0] = *itv;
681   }
682 
683   // Compute interpolation factor of the incident neutron energy
684   G4double factor = (energyLH.second - pE) / (energyLH.second - energyLH.first);
685 
686   if ((energyLH.second - pE) <= 0. && std::fabs(pE / energyLH.second - 1) < 1E-11) factor = 0.;
687   if ((energyLH.first - pE) >= 0. && std::fabs(energyLH.first / pE - 1) < 1E-11) factor = 1.;
688 
689   G4double rndm1 = G4UniformRand();
690   G4double rndm2 = G4UniformRand();
691 
692   // Sample secondary neutron energy
693   std::pair<G4double, G4int> sE_lower = sample_inelastic_E(rndm1, rndm2, pE_P_E_isoAng_limit[0]);
694   std::pair<G4double, G4int> sE_upper = sample_inelastic_E(rndm1, rndm2, pE_P_E_isoAng_limit[1]);
695   G4double sE = factor * sE_lower.first + (1 - factor) * sE_upper.first;
696   sE = sE * eV;
697 
698   // Sample cosine knowing the secondary neutron energy
699   rndm1 = G4UniformRand();
700   rndm2 = G4UniformRand();
701   G4double mu_lower = getMu(rndm1, rndm2, pE_P_E_isoAng_limit[0]->vE_isoAngle[sE_lower.second]);
702   G4double mu_upper = getMu(rndm1, rndm2, pE_P_E_isoAng_limit[1]->vE_isoAngle[sE_upper.second]);
703   G4double mu = factor * mu_lower + (1 - factor) * mu_upper;
704 
705   return std::pair<G4double, G4double>(sE, mu);
706 }
707 
708 //--------------------------------------------------
709 // New method added by L. Thulliez 2021 (CEA-Saclay)
710 //--------------------------------------------------
711 G4double G4ParticleHPThermalScattering::getMu(G4double rndm1, G4double rndm2, E_isoAng* anEPM)
712 {
713   G4double result = 0.0;
714 
715   auto in = G4int(rndm1 * ((*anEPM).n));
716 
717   if (in != 0) {
718     G4double mu_l = (*anEPM).isoAngle[in - 1];
719     G4double mu_h = (*anEPM).isoAngle[in];
720     result = (mu_h - mu_l) * (rndm1 * ((*anEPM).n) - in) + mu_l;
721   }
722   else {
723     G4double x = rndm1 * (*anEPM).n;
724     G4double ratio = 0.5;
725     if (x <= ratio) {
726       G4double mu_l = -1;
727       G4double mu_h = (*anEPM).isoAngle[0];
728       result = (mu_h - mu_l) * rndm2 + mu_l;
729     }
730     else {
731       G4double mu_l = (*anEPM).isoAngle[(*anEPM).n - 1];
732       G4double mu_h = 1;
733       result = (mu_h - mu_l) * rndm2 + mu_l;
734     }
735   }
736 
737   return result;
738 }
739 
740 //**********************************************************
741 // Geant4 previous algorithm
742 //**********************************************************
743 
744 G4double G4ParticleHPThermalScattering::getMu(E_isoAng* anEPM)
745 {
746   G4double random = G4UniformRand();
747   G4double result = 0.0;
748 
749   auto in = G4int(random * ((*anEPM).n));
750 
751   if (in != 0) {
752     G4double mu_l = (*anEPM).isoAngle[in - 1];
753     G4double mu_h = (*anEPM).isoAngle[in];
754     result = (mu_h - mu_l) * (random * ((*anEPM).n) - in) + mu_l;
755   }
756   else {
757     G4double x = random * (*anEPM).n;
758     // Bugzilla 1971
759     G4double ratio = 0.5;
760     G4double xx = G4UniformRand();
761     if (x <= ratio) {
762       G4double mu_l = -1;
763       G4double mu_h = (*anEPM).isoAngle[0];
764       result = (mu_h - mu_l) * xx + mu_l;
765     }
766     else {
767       G4double mu_l = (*anEPM).isoAngle[(*anEPM).n - 1];
768       G4double mu_h = 1;
769       result = (mu_h - mu_l) * xx + mu_l;
770     }
771   }
772   return result;
773 }
774 
775 std::pair<G4double, G4double> G4ParticleHPThermalScattering::find_LH(G4double x,
776                                                                      std::vector<G4double>* aVector)
777 {
778   G4double LL = 0.0;
779   G4double H = 0.0;
780 
781   // v->size() == 1 --> LL=H=v(0)
782   if (aVector->size() == 1) {
783     LL = aVector->front();
784     H = aVector->front();
785   }
786   else {
787     // 1) temp < v(0) -> LL=0.0 H=v(0)
788     // 2) v(i-1) < temp <= v(i) -> LL=v(i-1) H=v(i)
789     // 3) v(imax) < temp -> LL=v(imax) H=0.0
790     for (auto it = aVector->cbegin(); it != aVector->cend(); ++it) {
791       if (x <= *it) {
792         H = *it;
793         if (it != aVector->cbegin()) {
794           // 2)
795           it--;
796           LL = *it;
797         }
798         else {
799           // 1)
800           LL = 0.0;
801         }
802         break;
803       }
804     }
805     // 3)
806     if (H == 0.0) LL = aVector->back();
807   }
808 
809   return std::pair<G4double, G4double>(LL, H);
810 }
811 
812 G4double G4ParticleHPThermalScattering::get_linear_interpolated(G4double x,
813                                                                 std::pair<G4double, G4double> Low,
814                                                                 std::pair<G4double, G4double> High)
815 {
816   G4double y = 0.0;
817   if (High.first - Low.first != 0) {
818     y = (High.second - Low.second) / (High.first - Low.first) * (x - Low.first) + Low.second;
819   }
820   else {
821     if (High.second == Low.second) {
822       y = High.second;
823     }
824     else {
825       G4cout << "G4ParticleHPThermalScattering liner interpolation err!!" << G4endl;
826     }
827   }
828 
829   return y;
830 }
831 
832 E_isoAng G4ParticleHPThermalScattering::create_E_isoAng_from_energy(G4double energy,
833                                                                     std::vector<E_isoAng*>* vEPM)
834 {
835   E_isoAng anEPM_T_E;
836 
837   std::vector<G4double> v_e;
838   v_e.clear();
839   for (auto iv = vEPM->cbegin(); iv != vEPM->cend(); ++iv)
840     v_e.push_back((*iv)->energy);
841 
842   std::pair<G4double, G4double> energyLH = find_LH(energy, &v_e);
843   // G4cout << " " << energy/eV << " " << energyLH.first/eV  << " " << energyLH.second/eV << G4endl;
844 
845   E_isoAng* panEPM_T_EL = nullptr;
846   E_isoAng* panEPM_T_EH = nullptr;
847 
848   if (energyLH.first != 0.0 && energyLH.second != 0.0) {
849     for (auto iv = vEPM->cbegin(); iv != vEPM->cend(); ++iv) {
850       if (energyLH.first == (*iv)->energy) {
851         panEPM_T_EL = *iv;
852         ++iv;
853         panEPM_T_EH = *iv;
854         break;
855       }
856     }
857   }
858   else if (energyLH.first == 0.0) {
859     panEPM_T_EL = (*vEPM)[0];
860     panEPM_T_EH = (*vEPM)[1];
861   }
862   else if (energyLH.second == 0.0) {
863     panEPM_T_EH = (*vEPM).back();
864     auto iv = vEPM->cend();
865     --iv;
866     --iv;
867     panEPM_T_EL = *iv;
868   }
869 
870   if (panEPM_T_EL != nullptr && panEPM_T_EH != nullptr) {
871     // checking isoAng has proper values or not
872     //  Inelastic/FS, the first and last entries of *vEPM has all zero values.
873     if (!(check_E_isoAng(panEPM_T_EL))) panEPM_T_EL = panEPM_T_EH;
874     if (!(check_E_isoAng(panEPM_T_EH))) panEPM_T_EH = panEPM_T_EL;
875 
876     if (panEPM_T_EL->n == panEPM_T_EH->n) {
877       anEPM_T_E.energy = energy;
878       anEPM_T_E.n = panEPM_T_EL->n;
879 
880       for (G4int i = 0; i < panEPM_T_EL->n; ++i) {
881         G4double angle;
882         angle = get_linear_interpolated(
883           energy, std::pair<G4double, G4double>(energyLH.first, panEPM_T_EL->isoAngle[i]),
884           std::pair<G4double, G4double>(energyLH.second, panEPM_T_EH->isoAngle[i]));
885         anEPM_T_E.isoAngle.push_back(angle);
886       }
887     }
888     else {
889       G4Exception("G4ParticleHPThermalScattering::create_E_isoAng_from_energy", "NotSupported",
890                   JustWarning,
891                   "G4ParticleHPThermalScattering does not support yet EL->n != EH->n.");
892     }
893   }
894   else {
895     G4Exception("G4ParticleHPThermalScattering::create_E_isoAng_from_energy", "HAD_THERM_000",
896                 FatalException, "Pointer panEPM_T_EL or panEPM_T_EH is zero");
897   }
898 
899   return anEPM_T_E;
900 }
901 
902 G4double
903 G4ParticleHPThermalScattering::get_secondary_energy_from_E_P_E_isoAng(G4double random,
904                                                                       E_P_E_isoAng* anE_P_E_isoAng)
905 {
906   G4double secondary_energy = 0.0;
907 
908   G4int n = anE_P_E_isoAng->n;
909   G4double sum_p = 0.0;  // sum_p_H
910   G4double sum_p_L = 0.0;
911 
912   G4double total = 0.0;
913 
914   /*
915      delete for speed up
916      for ( G4int i = 0 ; i < n-1 ; ++i )
917      {
918         G4double E_L = anE_P_E_isoAng->vE_isoAngle[i]->energy/eV;
919         G4double E_H = anE_P_E_isoAng->vE_isoAngle[i+1]->energy/eV;
920         G4double dE = E_H - E_L;
921         total += ( ( anE_P_E_isoAng->prob[i] ) * dE );
922      }
923 
924      if ( std::abs( total - anE_P_E_isoAng->sum_of_probXdEs ) > 1.0e-14 ) G4cout << total -
925      anE_P_E_isoAng->sum_of_probXdEs << G4endl;
926   */
927   total = anE_P_E_isoAng->sum_of_probXdEs;
928 
929   for (G4int i = 0; i < n - 1; ++i) {
930     G4double E_L = anE_P_E_isoAng->vE_isoAngle[i]->energy / eV;
931     G4double E_H = anE_P_E_isoAng->vE_isoAngle[i + 1]->energy / eV;
932     G4double dE = E_H - E_L;
933     sum_p += ((anE_P_E_isoAng->prob[i]) * dE);
934 
935     if (random <= sum_p / total) {
936       secondary_energy =
937         get_linear_interpolated(random, std::pair<G4double, G4double>(sum_p_L / total, E_L),
938                                 std::pair<G4double, G4double>(sum_p / total, E_H));
939       secondary_energy = secondary_energy * eV;  // need eV
940       break;
941     }
942     sum_p_L = sum_p;
943   }
944 
945   return secondary_energy;
946 }
947 
948 std::pair<G4double, E_isoAng>
949 G4ParticleHPThermalScattering::create_sE_and_EPM_from_pE_and_vE_P_E_isoAng(
950   G4double rand_for_sE, G4double pE, std::vector<E_P_E_isoAng*>* vNEP_EPM)
951 {
952   std::map<G4double, G4int> map_energy;
953   map_energy.clear();
954   std::vector<G4double> v_energy;
955   v_energy.clear();
956   G4int i = 0;
957   for (auto itv = vNEP_EPM->cbegin(); itv != vNEP_EPM->cend(); ++itv) {
958     v_energy.push_back((*itv)->energy);
959     map_energy.insert(std::pair<G4double, G4int>((*itv)->energy, i));
960     i++;
961   }
962 
963   std::pair<G4double, G4double> energyLH = find_LH(pE, &v_energy);
964 
965   E_P_E_isoAng* pE_P_E_isoAng_EL = nullptr;
966   E_P_E_isoAng* pE_P_E_isoAng_EH = nullptr;
967 
968   if (energyLH.first != 0.0 && energyLH.second != 0.0) {
969     pE_P_E_isoAng_EL = (*vNEP_EPM)[map_energy.find(energyLH.first)->second];
970     pE_P_E_isoAng_EH = (*vNEP_EPM)[map_energy.find(energyLH.second)->second];
971   }
972   else if (energyLH.first == 0.0) {
973     pE_P_E_isoAng_EL = (*vNEP_EPM)[0];
974     pE_P_E_isoAng_EH = (*vNEP_EPM)[1];
975   }
976   if (energyLH.second == 0.0) {
977     pE_P_E_isoAng_EH = (*vNEP_EPM).back();
978     auto itv = vNEP_EPM->cend();
979     --itv;
980     --itv;
981     pE_P_E_isoAng_EL = *itv;
982   }
983 
984   G4double sE;
985   G4double sE_L;
986   G4double sE_H;
987 
988   sE_L = get_secondary_energy_from_E_P_E_isoAng(rand_for_sE, pE_P_E_isoAng_EL);
989   sE_H = get_secondary_energy_from_E_P_E_isoAng(rand_for_sE, pE_P_E_isoAng_EH);
990 
991   sE = get_linear_interpolated(pE, std::pair<G4double, G4double>(energyLH.first, sE_L),
992                                std::pair<G4double, G4double>(energyLH.second, sE_H));
993 
994   E_isoAng E_isoAng_L = create_E_isoAng_from_energy(sE, &(pE_P_E_isoAng_EL->vE_isoAngle));
995   E_isoAng E_isoAng_H = create_E_isoAng_from_energy(sE, &(pE_P_E_isoAng_EH->vE_isoAngle));
996 
997   E_isoAng anE_isoAng;
998   // For defeating warning message from compiler
999   anE_isoAng.n = 1;
1000   anE_isoAng.energy = sE;  // never used
1001   if (E_isoAng_L.n == E_isoAng_H.n) {
1002     anE_isoAng.n = E_isoAng_L.n;
1003     for (G4int j = 0; j < anE_isoAng.n; ++j) {
1004       G4double angle;
1005       angle =
1006         get_linear_interpolated(sE, std::pair<G4double, G4double>(sE_L, E_isoAng_L.isoAngle[j]),
1007                                 std::pair<G4double, G4double>(sE_H, E_isoAng_H.isoAngle[j]));
1008       anE_isoAng.isoAngle.push_back(angle);
1009     }
1010   }
1011   else {
1012     throw G4HadronicException(__FILE__, __LINE__, "Unexpected values!");
1013   }
1014 
1015   return std::pair<G4double, E_isoAng>(sE, anE_isoAng);
1016 }
1017 
1018 void G4ParticleHPThermalScattering::buildPhysicsTable()
1019 {
1020   // Is rebuild of physics table a necessity
1021   if (nMaterial == G4Material::GetMaterialTable()->size()
1022       && nElement == G4Element::GetElementTable()->size())
1023   {
1024     return;
1025   }
1026   nMaterial = G4Material::GetMaterialTable()->size();
1027   nElement = G4Element::GetElementTable()->size();
1028 
1029   dic.clear();
1030   std::map<G4String, G4int> co_dic;
1031 
1032   // Searching Nist Materials
1033   static G4ThreadLocal G4MaterialTable* theMaterialTable = nullptr;
1034   if (theMaterialTable == nullptr) theMaterialTable = G4Material::GetMaterialTable();
1035   std::size_t numberOfMaterials = G4Material::GetNumberOfMaterials();
1036   for (std::size_t i = 0; i < numberOfMaterials; ++i) {
1037     G4Material* material = (*theMaterialTable)[i];
1038     auto numberOfElements = (G4int)material->GetNumberOfElements();
1039     for (G4int j = 0; j < numberOfElements; ++j) {
1040       const G4Element* element = material->GetElement(j);
1041       if (names.IsThisThermalElement(material->GetName(), element->GetName())) {
1042         G4int ts_ID_of_this_geometry;
1043         G4String ts_ndl_name = names.GetTS_NDL_Name(material->GetName(), element->GetName());
1044         if (co_dic.find(ts_ndl_name) != co_dic.cend()) {
1045           ts_ID_of_this_geometry = co_dic.find(ts_ndl_name)->second;
1046         }
1047         else {
1048           ts_ID_of_this_geometry = (G4int)co_dic.size();
1049           co_dic.insert(std::pair<G4String, G4int>(ts_ndl_name, ts_ID_of_this_geometry));
1050         }
1051 
1052         // G4cout << "Neutron HP Thermal Scattering: Registering a material-element pair of "
1053         //        << material->GetName() << " " << element->GetName()
1054         //        << " as internal thermal scattering id of  " <<  ts_ID_of_this_geometry << "." <<
1055         //        G4endl;
1056 
1057         dic.insert(std::pair<std::pair<G4Material*, const G4Element*>, G4int>(
1058           std::pair<G4Material*, const G4Element*>(material, element), ts_ID_of_this_geometry));
1059       }
1060     }
1061   }
1062 
1063   // Searching TS Elements
1064   auto theElementTable = G4Element::GetElementTable();
1065   std::size_t numberOfElements = G4Element::GetNumberOfElements();
1066   for (std::size_t i = 0; i < numberOfElements; ++i) {
1067     const G4Element* element = (*theElementTable)[i];
1068     if (names.IsThisThermalElement(element->GetName())) {
1069       if (names.IsThisThermalElement(element->GetName())) {
1070         G4int ts_ID_of_this_geometry;
1071         G4String ts_ndl_name = names.GetTS_NDL_Name(element->GetName());
1072         if (co_dic.find(ts_ndl_name) != co_dic.cend()) {
1073           ts_ID_of_this_geometry = co_dic.find(ts_ndl_name)->second;
1074         }
1075         else {
1076           ts_ID_of_this_geometry = (G4int)co_dic.size();
1077           co_dic.insert(std::pair<G4String, G4int>(ts_ndl_name, ts_ID_of_this_geometry));
1078         }
1079         dic.insert(std::pair<std::pair<const G4Material*, const G4Element*>, G4int>(
1080           std::pair<const G4Material*, const G4Element*>((G4Material*)nullptr, element),
1081           ts_ID_of_this_geometry));
1082       }
1083     }
1084   }
1085 
1086   G4cout << G4endl;
1087   G4cout
1088     << "Neutron HP Thermal Scattering: Following material-element pairs or elements are registered."
1089     << G4endl;
1090   for (const auto& it : dic) {
1091     if (it.first.first != nullptr) {
1092       G4cout << "Material " << it.first.first->GetName() << " - Element "
1093              << it.first.second->GetName() << ",  internal thermal scattering id " << it.second
1094              << G4endl;
1095     }
1096     else {
1097       G4cout << "Element " << it.first.second->GetName() << ",  internal thermal scattering id "
1098              << it.second << G4endl;
1099     }
1100   }
1101   G4cout << G4endl;
1102 
1103   // Read Cross Section Data files
1104 
1105   G4ParticleHPManager* hpmanager = G4ParticleHPManager::GetInstance();
1106   coherentFSs = hpmanager->GetThermalScatteringCoherentFinalStates();
1107   incoherentFSs = hpmanager->GetThermalScatteringIncoherentFinalStates();
1108   inelasticFSs = hpmanager->GetThermalScatteringInelasticFinalStates();
1109 
1110   if (G4Threading::IsMasterThread()) {
1111     clearCurrentFSData();
1112 
1113     if (coherentFSs == nullptr)
1114       coherentFSs =
1115         new std::map<G4int, std::map<G4double, std::vector<std::pair<G4double, G4double>*>*>*>;
1116     if (incoherentFSs == nullptr)
1117       incoherentFSs = new std::map<G4int, std::map<G4double, std::vector<E_isoAng*>*>*>;
1118     if (inelasticFSs == nullptr)
1119       inelasticFSs = new std::map<G4int, std::map<G4double, std::vector<E_P_E_isoAng*>*>*>;
1120 
1121     G4String dirName;
1122     if (G4FindDataDir("G4NEUTRONHPDATA") == nullptr)
1123       throw G4HadronicException(
1124         __FILE__, __LINE__,
1125         "Please setenv G4NEUTRONHPDATA to point to the neutron cross-section files.");
1126     dirName = G4FindDataDir("G4NEUTRONHPDATA");
1127 
1128     for (const auto& it : co_dic) {
1129       G4String tsndlName = it.first;
1130       G4int ts_ID = it.second;
1131 
1132       // Coherent
1133       G4String fsName = "/ThermalScattering/Coherent/FS/";
1134       G4String fileName = dirName + fsName + tsndlName;
1135       coherentFSs->insert(
1136         std::pair<G4int, std::map<G4double, std::vector<std::pair<G4double, G4double>*>*>*>(
1137           ts_ID, readACoherentFSDATA(fileName)));
1138 
1139       // incoherent elastic
1140       fsName = "/ThermalScattering/Incoherent/FS/";
1141       fileName = dirName + fsName + tsndlName;
1142       incoherentFSs->insert(std::pair<G4int, std::map<G4double, std::vector<E_isoAng*>*>*>(
1143         ts_ID, readAnIncoherentFSDATA(fileName)));
1144 
1145       // inelastic
1146       fsName = "/ThermalScattering/Inelastic/FS/";
1147       fileName = dirName + fsName + tsndlName;
1148       inelasticFSs->insert(std::pair<G4int, std::map<G4double, std::vector<E_P_E_isoAng*>*>*>(
1149         ts_ID, readAnInelasticFSDATA(fileName)));
1150     }
1151 
1152     hpmanager->RegisterThermalScatteringCoherentFinalStates(coherentFSs);
1153     hpmanager->RegisterThermalScatteringIncoherentFinalStates(incoherentFSs);
1154     hpmanager->RegisterThermalScatteringInelasticFinalStates(inelasticFSs);
1155   }
1156 
1157   theXSection->BuildPhysicsTable(*(G4Neutron::Neutron()));
1158 }
1159 
1160 G4int G4ParticleHPThermalScattering::getTS_ID(const G4Material* material, const G4Element* element)
1161 {
1162   G4int result = -1;
1163   if (dic.find(std::pair<const G4Material*, const G4Element*>(material, element)) != dic.end())
1164     result = dic.find(std::pair<const G4Material*, const G4Element*>(material, element))->second;
1165   return result;
1166 }
1167 
1168 const std::pair<G4double, G4double> G4ParticleHPThermalScattering::GetFatalEnergyCheckLevels() const
1169 {
1170   // max energy non-conservation is mass of heavy nucleus
1171   return std::pair<G4double, G4double>(10.0 * perCent, 350.0 * CLHEP::GeV);
1172 }
1173 
1174 void G4ParticleHPThermalScattering::AddUserThermalScatteringFile(const G4String& nameG4Element,
1175                                                                  const G4String& filename)
1176 {
1177   names.AddThermalElement(nameG4Element, filename);
1178   theXSection->AddUserThermalScatteringFile(nameG4Element, filename);
1179   buildPhysicsTable();
1180 }
1181 
1182 G4bool G4ParticleHPThermalScattering::check_E_isoAng(E_isoAng* anE_IsoAng)
1183 {
1184   G4bool result = false;
1185 
1186   G4int n = anE_IsoAng->n;
1187   G4double sum = 0.0;
1188   for (G4int i = 0; i < n; ++i) {
1189     sum += anE_IsoAng->isoAngle[i];
1190   }
1191   if (sum != 0.0) result = true;
1192 
1193   return result;
1194 }
1195 
1196 void G4ParticleHPThermalScattering::ModelDescription(std::ostream& outFile) const
1197 {
1198   outFile << "High Precision model based on thermal scattering data in\n"
1199           << "evaluated nuclear data libraries for neutrons below 5eV\n"
1200           << "on specific materials\n";
1201 }
1202