Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/processes/hadronic/models/particle_hp/src/G4ParticleHPContAngularPar.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 // neutron_hp -- source file
 27 // J.P. Wellisch, Nov-1996
 28 // A prototype of the low energy neutron transport model.
 29 //
 30 // 09-May-06 fix in Sample by T. Koi
 31 // 080318 Fix Compilation warnings - gcc-4.3.0 by T. Koi
 32 //        (This fix has a real effect to the code.)
 33 // 080409 Fix div0 error with G4FPE by T. Koi
 34 // 080612 Fix contribution from Benoit Pirard and Laurent Desorgher (Univ. Bern) #1
 35 // 080714 Limiting the sum of energy of secondary particles by T. Koi
 36 // 080801 Fix div0 error wiht G4FPE and memory leak by T. Koi
 37 // 081024 G4NucleiPropertiesTable:: to G4NucleiProperties::
 38 //
 39 // P. Arce, June-2014 Conversion neutron_hp to particle_hp
 40 //
 41 // June-2019 - E. Mendoza --> redefinition of the residual mass to consider incident particles
 42 // different than neutrons.
 43 //
 44 // V. Ivanchenko, July-2023 Basic revision of particle HP classes
 45 //
 46 
 47 #include "G4ParticleHPContAngularPar.hh"
 48 
 49 #include "G4ParticleDefinition.hh"
 50 #include "G4Alpha.hh"
 51 #include "G4Deuteron.hh"
 52 #include "G4Electron.hh"
 53 #include "G4Gamma.hh"
 54 #include "G4He3.hh"
 55 #include "G4IonTable.hh"
 56 #include "G4Neutron.hh"
 57 #include "G4NucleiProperties.hh"
 58 #include "G4ParticleHPKallbachMannSyst.hh"
 59 #include "G4ParticleHPLegendreStore.hh"
 60 #include "G4ParticleHPManager.hh"
 61 #include "G4ParticleHPVector.hh"
 62 #include "G4PhysicalConstants.hh"
 63 #include "G4Positron.hh"
 64 #include "G4Proton.hh"
 65 #include "G4SystemOfUnits.hh"
 66 #include "G4Triton.hh"
 67 
 68 #include <set>
 69 #include <vector>
 70 
 71 G4ParticleHPContAngularPar::G4ParticleHPContAngularPar(const G4ParticleDefinition* p)
 72 {
 73   theProjectile = (nullptr == p) ? G4Neutron::Neutron() : p;
 74   toBeCached v;
 75   fCache.Put(v);
 76   if (G4ParticleHPManager::GetInstance()->GetDoNotAdjustFinalState()) adjustResult = false;
 77 }
 78 
 79 G4ParticleHPContAngularPar::G4ParticleHPContAngularPar(G4ParticleHPContAngularPar& val)
 80 {
 81   theEnergy = val.theEnergy;
 82   nEnergies = val.nEnergies;
 83   nDiscreteEnergies = val.nDiscreteEnergies;
 84   nAngularParameters = val.nAngularParameters;
 85   theProjectile = val.theProjectile;
 86   theManager = val.theManager;
 87   theInt = val.theInt;
 88   adjustResult = val.adjustResult;
 89   theMinEner = val.theMinEner;
 90   theMaxEner = val.theMaxEner;
 91   theEnergiesTransformed = val.theEnergiesTransformed;
 92   theDiscreteEnergies = val.theDiscreteEnergies;
 93   theDiscreteEnergiesOwn = val.theDiscreteEnergiesOwn;
 94   toBeCached v;
 95   fCache.Put(v);
 96   const std::size_t esize = nEnergies > 0 ? nEnergies : 1;
 97   theAngular = new G4ParticleHPList[esize];
 98   for (G4int ie = 0; ie < nEnergies; ++ie) {
 99     theAngular[ie].SetLabel(val.theAngular[ie].GetLabel());
100     for (G4int ip = 0; ip < nAngularParameters; ++ip) {
101       theAngular[ie].SetValue(ip, val.theAngular[ie].GetValue(ip));
102     }
103   }
104 }
105 
106 G4ParticleHPContAngularPar::~G4ParticleHPContAngularPar()
107 {
108   delete[] theAngular;
109 }
110 
111 void G4ParticleHPContAngularPar::Init(std::istream& aDataFile, const G4ParticleDefinition* p)
112 {
113   adjustResult = true;
114   if (G4ParticleHPManager::GetInstance()->GetDoNotAdjustFinalState()) adjustResult = false;
115 
116   theProjectile = (nullptr == p) ? G4Neutron::Neutron() : p;
117 
118   aDataFile >> theEnergy >> nEnergies >> nDiscreteEnergies >> nAngularParameters;
119   theEnergy *= eV;
120   const std::size_t esize = nEnergies > 0 ? nEnergies : 1;
121   theAngular = new G4ParticleHPList[esize];
122   G4double sEnergy;
123   for (G4int i = 0; i < nEnergies; ++i) {
124     aDataFile >> sEnergy;
125     sEnergy *= eV;
126     theAngular[i].SetLabel(sEnergy);
127     theAngular[i].Init(aDataFile, nAngularParameters, 1.);
128     theMinEner = std::min(theMinEner, sEnergy);
129     theMaxEner = std::max(theMaxEner, sEnergy);
130   }
131 }
132 
133 G4ReactionProduct* G4ParticleHPContAngularPar::Sample(G4double anEnergy, G4double massCode,
134                                                       G4double /*targetMass*/, G4int angularRep,
135                                                       G4int /*interpolE*/)
136 {
137   // The following line is needed because it may change between runs by UI command
138   adjustResult = true;
139   if (G4ParticleHPManager::GetInstance()->GetDoNotAdjustFinalState()) adjustResult = false;
140 
141   auto result = new G4ReactionProduct;
142   auto Z = static_cast<G4int>(massCode / 1000);
143   auto A = static_cast<G4int>(massCode - 1000 * Z);
144   if (massCode == 0) {
145     result->SetDefinition(G4Gamma::Gamma());
146   }
147   else if (A == 0) {
148     result->SetDefinition(G4Electron::Electron());
149     if (Z == 1) result->SetDefinition(G4Positron::Positron());
150   }
151   else if (A == 1) {
152     result->SetDefinition(G4Neutron::Neutron());
153     if (Z == 1) result->SetDefinition(G4Proton::Proton());
154   }
155   else if (A == 2) {
156     result->SetDefinition(G4Deuteron::Deuteron());
157   }
158   else if (A == 3) {
159     result->SetDefinition(G4Triton::Triton());
160     if (Z == 2) result->SetDefinition(G4He3::He3());
161   }
162   else if (A == 4) {
163     result->SetDefinition(G4Alpha::Alpha());
164     if (Z != 2)
165       throw G4HadronicException(__FILE__, __LINE__,
166                                 "G4ParticleHPContAngularPar: Unknown ion case 1");
167   }
168   else {
169     result->SetDefinition(G4IonTable::GetIonTable()->GetIon(Z, A, 0));
170   }
171 
172   G4int i(0);
173   G4int it(0);
174   G4double fsEnergy(0);
175   G4double cosTh(0);
176   /*
177   G4cout << "G4ParticleHPContAngularPar::Sample E=" << anEnergy <<" Z=" << Z << " A=" << A
178          << " angularRep=" << angularRep << " Nd=" << nDiscreteEnergies 
179          << " Ne=" << nEnergies << G4endl;
180   */
181   if (angularRep == 1) {
182     if (nDiscreteEnergies != 0) {
183       // 1st check remaining_energy
184       // if this is the first set it. (How?)
185       if (fCache.Get().fresh) {
186         // Discrete Lines, larger energies come first
187         // Continues Emssions, low to high                                 LAST
188         fCache.Get().remaining_energy =
189           std::max(theAngular[0].GetLabel(), theAngular[nEnergies - 1].GetLabel());
190         fCache.Get().fresh = false;
191       }
192 
193       // Cheating for small remaining_energy
194       // Temporary solution
195       if (nDiscreteEnergies == nEnergies) {
196         fCache.Get().remaining_energy =
197           std::max(fCache.Get().remaining_energy,
198                    theAngular[nDiscreteEnergies - 1].GetLabel());  // Minimum Line
199       }
200       else {
201         G4double cont_min = 0.0;
202         for (G4int j = nDiscreteEnergies; j < nEnergies; ++j) {
203           cont_min = theAngular[j].GetLabel();
204           if (theAngular[j].GetValue(0) != 0.0) break;
205         }
206         fCache.Get().remaining_energy = std::max(
207           fCache.Get().remaining_energy, std::min(theAngular[nDiscreteEnergies - 1].GetLabel(),
208                                                    cont_min));  // Minimum Line or grid
209       }
210 
211       G4double random = G4UniformRand();
212       auto running = new G4double[nEnergies + 1];
213       running[0] = 0.0;
214 
215       G4double delta;
216       for (G4int j = 0; j < nDiscreteEnergies; ++j) {
217         delta = 0.0;
218         if (theAngular[j].GetLabel() <= fCache.Get().remaining_energy)
219           delta = theAngular[j].GetValue(0);
220         running[j + 1] = running[j] + delta;
221       }
222 
223       G4double tot_prob_DIS = std::max(running[nDiscreteEnergies], 0.0);
224 
225       G4double delta1;
226       for (G4int j = nDiscreteEnergies; j < nEnergies; ++j) {
227         delta1 = 0.0;
228         G4double e_low = 0.0;
229         G4double e_high = 0.0;
230         if (theAngular[j].GetLabel() <= fCache.Get().remaining_energy)
231           delta1 = theAngular[j].GetValue(0);
232 
233         // To calculate Prob. e_low and e_high should be in eV
234         // There are two cases:
235         // 1: theAngular[nDiscreteEnergies].GetLabel() != 0.0
236         //    delta1 should be used between j-1 and j
237         //    At j = nDiscreteEnergies (the first) e_low should be set explicitly
238         if (theAngular[j].GetLabel() != 0) {
239           if (j == nDiscreteEnergies) {
240             e_low = 0.0 / eV;
241           }
242           else {
243             if (j < 1) j = 1;  // Protection against evaluation of arrays at index j-1
244             e_low = theAngular[j - 1].GetLabel() / eV;
245           }
246           e_high = theAngular[j].GetLabel() / eV;
247         }
248 
249         // 2: theAngular[nDiscreteEnergies].GetLabel() == 0.0
250         //    delta1 should be used between j and j+1
251         if (theAngular[j].GetLabel() == 0.0) {
252           e_low = theAngular[j].GetLabel() / eV;
253           if (j != nEnergies - 1) {
254             e_high = theAngular[j + 1].GetLabel() / eV;
255           }
256           else {
257             e_high = theAngular[j].GetLabel() / eV;
258           }
259         }
260 
261         running[j + 1] = running[j] + ((e_high - e_low) * delta1);
262       }
263       G4double tot_prob_CON = std::max(running[nEnergies] - running[nDiscreteEnergies], 0.0);
264 
265       // Give up in the pathological case of null probabilities
266       if (tot_prob_DIS == 0.0 && tot_prob_CON == 0.0) {
267         delete[] running;
268   return result;
269       }
270       // Normalize random
271       random *= (tot_prob_DIS + tot_prob_CON);
272       // 2nd Judge Discrete or not
273 
274       // This should be relatively close to 1  For safty
275       if (random <= (tot_prob_DIS / (tot_prob_DIS + tot_prob_CON))
276           || nDiscreteEnergies == nEnergies)
277       {
278         // Discrete Emission
279         for (G4int j = 0; j < nDiscreteEnergies; ++j) {
280           // Here we should use i+1
281           if (random < running[j + 1]) {
282             it = j;
283             break;
284           }
285         }
286         fsEnergy = theAngular[it].GetLabel();
287 
288         G4ParticleHPLegendreStore theStore(1);
289         theStore.Init(0, fsEnergy, nAngularParameters);
290         for (G4int j = 0; j < nAngularParameters; ++j) {
291           theStore.SetCoeff(0, j, theAngular[it].GetValue(j));
292         }
293         // use it to sample.
294         cosTh = theStore.SampleMax(fsEnergy);
295         // Done
296       }
297       else {
298         // Continuous emission
299         for (G4int j = nDiscreteEnergies; j < nEnergies; ++j) {
300           // Here we should use i
301           if (random < running[j]) {
302             it = j;
303             break;
304           }
305         }
306 
307         if (it < 1) it = 1;  // Protection against evaluation of arrays at index it-1
308 
309         G4double x1 = running[it - 1];
310         G4double x2 = running[it];
311 
312         G4double y1 = 0.0;
313         if (it != nDiscreteEnergies) y1 = theAngular[it - 1].GetLabel();
314         G4double y2 = theAngular[it].GetLabel();
315 
316         fsEnergy = theInt.Interpolate(theManager.GetInverseScheme(it), random, x1, x2, y1, y2);
317 
318         G4ParticleHPLegendreStore theStore(2);
319         theStore.Init(0, y1, nAngularParameters);
320         theStore.Init(1, y2, nAngularParameters);
321         theStore.SetManager(theManager);
322         G4int itt;
323         for (G4int j = 0; j < nAngularParameters; ++j) {
324           itt = it;
325           if (it == nDiscreteEnergies) itt = it + 1;
326           // "This case "it-1" has data for Discrete, so we will use an extrpolated values it and
327           // it+1
328           theStore.SetCoeff(0, j, theAngular[itt - 1].GetValue(j));
329           theStore.SetCoeff(1, j, theAngular[itt].GetValue(j));
330         }
331         // use it to sample.
332         cosTh = theStore.SampleMax(fsEnergy);
333 
334         // Done
335       }
336 
337       // The remaining energy needs to be lowered by the photon energy in *any* case.
338       // Otherwise additional photons with too high energy will be produced - therefore the
339       // adjustResult condition has been removed
340       fCache.Get().remaining_energy -= fsEnergy;
341       delete[] running;
342 
343       // end (nDiscreteEnergies != 0) branch
344     }
345     else {
346       // Only continue, TK will clean up
347       if (fCache.Get().fresh) {
348         fCache.Get().remaining_energy = theAngular[nEnergies - 1].GetLabel();
349         fCache.Get().fresh = false;
350       }
351 
352       G4double random = G4UniformRand();
353       auto running = new G4double[nEnergies];
354       running[0] = 0;
355       G4double weighted = 0;
356       for (i = 1; i < nEnergies; i++) {
357         running[i] = running[i - 1];
358         if (fCache.Get().remaining_energy >= theAngular[i].GetLabel()) {
359           running[i] += theInt.GetBinIntegral(
360             theManager.GetScheme(i - 1), theAngular[i - 1].GetLabel(), theAngular[i].GetLabel(),
361             theAngular[i - 1].GetValue(0), theAngular[i].GetValue(0));
362           weighted += theInt.GetWeightedBinIntegral(
363             theManager.GetScheme(i - 1), theAngular[i - 1].GetLabel(), theAngular[i].GetLabel(),
364             theAngular[i - 1].GetValue(0), theAngular[i].GetValue(0));
365         }
366       }
367 
368       // Cache the mean energy in this distribution
369       if (nEnergies == 1 || running[nEnergies - 1] == 0) {
370         fCache.Get().currentMeanEnergy = 0.0;
371       }
372       else {
373         fCache.Get().currentMeanEnergy = weighted / running[nEnergies - 1];
374       }
375 
376       if (nEnergies == 1) it = 0;
377       if (running[nEnergies - 1] != 0) {
378         for (i = 1; i < nEnergies; i++) {
379           it = i;
380           if (random < running[i] / running[nEnergies - 1]) break;
381         }
382       }
383 
384       if (running[nEnergies - 1] == 0) it = 0;
385       if (it < nDiscreteEnergies || it == 0) {
386         if (it == 0) {
387           fsEnergy = theAngular[it].GetLabel();
388           G4ParticleHPLegendreStore theStore(1);
389           theStore.Init(0, fsEnergy, nAngularParameters);
390           for (i = 0; i < nAngularParameters; i++) {
391             theStore.SetCoeff(0, i, theAngular[it].GetValue(i));
392           }
393           // use it to sample.
394           cosTh = theStore.SampleMax(fsEnergy);
395         }
396         else {
397           G4double e1, e2;
398           e1 = theAngular[it - 1].GetLabel();
399           e2 = theAngular[it].GetLabel();
400           fsEnergy = theInt.Interpolate(theManager.GetInverseScheme(it), random,
401                                         running[it - 1] / running[nEnergies - 1],
402                                         running[it] / running[nEnergies - 1], e1, e2);
403           // fill a Legendrestore
404           G4ParticleHPLegendreStore theStore(2);
405           theStore.Init(0, e1, nAngularParameters);
406           theStore.Init(1, e2, nAngularParameters);
407           for (i = 0; i < nAngularParameters; i++) {
408             theStore.SetCoeff(0, i, theAngular[it - 1].GetValue(i));
409             theStore.SetCoeff(1, i, theAngular[it].GetValue(i));
410           }
411           // use it to sample.
412           theStore.SetManager(theManager);
413           cosTh = theStore.SampleMax(fsEnergy);
414         }
415       }
416       else {  // continuum contribution
417         G4double x1 = running[it - 1] / running[nEnergies - 1];
418         G4double x2 = running[it] / running[nEnergies - 1];
419         G4double y1 = theAngular[it - 1].GetLabel();
420         G4double y2 = theAngular[it].GetLabel();
421         fsEnergy = theInt.Interpolate(theManager.GetInverseScheme(it), random, x1, x2, y1, y2);
422         G4ParticleHPLegendreStore theStore(2);
423         theStore.Init(0, y1, nAngularParameters);
424         theStore.Init(1, y2, nAngularParameters);
425         theStore.SetManager(theManager);
426         for (i = 0; i < nAngularParameters; i++) {
427           theStore.SetCoeff(0, i, theAngular[it - 1].GetValue(i));
428           theStore.SetCoeff(1, i, theAngular[it].GetValue(i));
429         }
430         // use it to sample.
431         cosTh = theStore.SampleMax(fsEnergy);
432       }
433       delete[] running;
434 
435       // The remaining energy needs to be lowered by the photon energy in
436       // *any* case.  Otherwise additional photons with too much energy will be
437       // produced - therefore the  adjustResult condition has been removed
438 
439       fCache.Get().remaining_energy -= fsEnergy;
440       // end if (nDiscreteEnergies != 0)
441     }
442     // end of (angularRep == 1) branch
443   }
444   else if (angularRep == 2) {
445     // first get the energy (already the right for this incoming energy)
446     G4int j;
447     auto running = new G4double[nEnergies];
448     running[0] = 0;
449     G4double weighted = 0;
450     for (j = 1; j < nEnergies; ++j) {
451       if (j != 0) running[j] = running[j - 1];
452       running[j] += theInt.GetBinIntegral(theManager.GetScheme(j - 1), theAngular[j - 1].GetLabel(),
453                                           theAngular[j].GetLabel(), theAngular[j - 1].GetValue(0),
454                                           theAngular[j].GetValue(0));
455       weighted += theInt.GetWeightedBinIntegral(
456         theManager.GetScheme(j - 1), theAngular[j - 1].GetLabel(), theAngular[j].GetLabel(),
457         theAngular[j - 1].GetValue(0), theAngular[j].GetValue(0));
458     }
459 
460     // Cache the mean energy in this distribution
461     if (nEnergies == 1)
462       fCache.Get().currentMeanEnergy = 0.0;
463     else
464       fCache.Get().currentMeanEnergy = weighted / running[nEnergies - 1];
465 
466     G4int itt(0);
467     G4double randkal = G4UniformRand();
468     for (j = 1; j < nEnergies; ++j) {
469       itt = j;
470       if (randkal*running[nEnergies - 1] < running[j]) break;
471     }
472 
473     // Interpolate the secondary energy
474     G4double x, x1, x2, y1, y2;
475     if (itt == 0) itt = 1;
476     x = randkal * running[nEnergies - 1];
477     x1 = running[itt - 1];
478     x2 = running[itt];
479     G4double compoundFraction;
480     // interpolate energy
481     y1 = theAngular[itt - 1].GetLabel();
482     y2 = theAngular[itt].GetLabel();
483     fsEnergy = theInt.Interpolate(theManager.GetInverseScheme(itt - 1), x, x1, x2, y1, y2);
484 
485     // For theta, interpolate the compoundFractions
486     G4double cLow = theAngular[itt - 1].GetValue(1);
487     G4double cHigh = theAngular[itt].GetValue(1);
488     compoundFraction = theInt.Interpolate(theManager.GetScheme(itt), fsEnergy, y1, y2, cLow, cHigh);
489 
490     if (compoundFraction > 1.0)
491       compoundFraction = 1.0;  // Protection against unphysical interpolation
492 
493     delete[] running;
494 
495     // get cosTh
496     G4double incidentEnergy = anEnergy;
497     G4double incidentMass = theProjectile->GetPDGMass();
498     G4double productEnergy = fsEnergy;
499     G4double productMass = result->GetMass();
500     auto targetZ = G4int(fCache.Get().theTargetCode / 1000);
501     auto targetA = G4int(fCache.Get().theTargetCode - 1000 * targetZ);
502 
503     // To correspond to natural composition (-nat-) data files.
504     if (targetA == 0) targetA = G4int(fCache.Get().theTarget->GetMass() / amu_c2 + 0.5);
505     G4double targetMass = fCache.Get().theTarget->GetMass();
506     auto incidentA = G4int(incidentMass / amu_c2 + 0.5);
507     auto incidentZ = G4int(theProjectile->GetPDGCharge() + 0.5);
508     G4int residualA = targetA + incidentA - A;
509     G4int residualZ = targetZ + incidentZ - Z;
510     G4double residualMass = G4NucleiProperties::GetNuclearMass(residualA, residualZ);
511 
512     G4ParticleHPKallbachMannSyst theKallbach(
513       compoundFraction, incidentEnergy, incidentMass, productEnergy, productMass, residualMass,
514       residualA, residualZ, targetMass, targetA, targetZ, incidentA, incidentZ, A, Z);
515     cosTh = theKallbach.Sample(anEnergy);
516     // end (angularRep == 2) branch
517   }
518   else if (angularRep > 10 && angularRep < 16) {
519     G4double random = G4UniformRand();
520     auto running = new G4double[nEnergies];
521     running[0] = 0;
522     G4double weighted = 0;
523     for (i = 1; i < nEnergies; ++i) {
524       if (i != 0) running[i] = running[i - 1];
525       running[i] += theInt.GetBinIntegral(theManager.GetScheme(i - 1), theAngular[i - 1].GetLabel(),
526                                           theAngular[i].GetLabel(), theAngular[i - 1].GetValue(0),
527                                           theAngular[i].GetValue(0));
528       weighted += theInt.GetWeightedBinIntegral(
529         theManager.GetScheme(i - 1), theAngular[i - 1].GetLabel(), theAngular[i].GetLabel(),
530         theAngular[i - 1].GetValue(0), theAngular[i].GetValue(0));
531     }
532 
533     // Cache the mean energy in this distribution
534     if (nEnergies == 1)
535       fCache.Get().currentMeanEnergy = 0.0;
536     else
537       fCache.Get().currentMeanEnergy = weighted / running[nEnergies - 1];
538 
539     if (nEnergies == 1) it = 0;
540     for (i = 1; i < nEnergies; i++) {
541       it = i;
542       if (random < running[i] / running[nEnergies - 1]) break;
543     }
544 
545     if (it < nDiscreteEnergies || it == 0) {
546       if (it == 0) {
547         fsEnergy = theAngular[0].GetLabel();
548         G4ParticleHPVector theStore;
549         G4int aCounter = 0;
550         for (G4int j = 1; j < nAngularParameters; j += 2) {
551           theStore.SetX(aCounter, theAngular[0].GetValue(j));
552           theStore.SetY(aCounter, theAngular[0].GetValue(j + 1));
553           aCounter++;
554         }
555         G4InterpolationManager aMan;
556         aMan.Init(angularRep - 10, nAngularParameters - 1);
557         theStore.SetInterpolationManager(aMan);
558         cosTh = theStore.Sample();
559       }
560       else {
561         fsEnergy = theAngular[it].GetLabel();
562         G4ParticleHPVector theStore;
563         G4InterpolationManager aMan;
564         aMan.Init(angularRep - 10, nAngularParameters - 1);
565         theStore.SetInterpolationManager(aMan);  // Store interpolates f(costh)
566         G4InterpolationScheme currentScheme = theManager.GetInverseScheme(it);
567         G4int aCounter = 0;
568         for (G4int j = 1; j < nAngularParameters; j += 2) {
569           theStore.SetX(aCounter, theAngular[it].GetValue(j));
570           theStore.SetY(aCounter, theInt.Interpolate(currentScheme, random,
571                                                      running[it - 1] / running[nEnergies - 1],
572                                                      running[it] / running[nEnergies - 1],
573                                                      theAngular[it - 1].GetValue(j + 1),
574                                                      theAngular[it].GetValue(j + 1)));
575           ++aCounter;
576         }
577         cosTh = theStore.Sample();
578       }
579     }
580     else {
581       G4double x1 = running[it - 1] / running[nEnergies - 1];
582       G4double x2 = running[it] / running[nEnergies - 1];
583       G4double y1 = theAngular[it - 1].GetLabel();
584       G4double y2 = theAngular[it].GetLabel();
585       fsEnergy = theInt.Interpolate(theManager.GetInverseScheme(it), random, x1, x2, y1, y2);
586       G4ParticleHPVector theBuff1;
587       G4ParticleHPVector theBuff2;
588       G4InterpolationManager aMan;
589       aMan.Init(angularRep - 10, nAngularParameters - 1);
590 
591       G4int j;
592       for (i = 0, j = 1; i < nAngularParameters; i++, j += 2) {
593         theBuff1.SetX(i, theAngular[it - 1].GetValue(j));
594         theBuff1.SetY(i, theAngular[it - 1].GetValue(j + 1));
595         theBuff2.SetX(i, theAngular[it].GetValue(j));
596         theBuff2.SetY(i, theAngular[it].GetValue(j + 1));
597       }
598 
599       G4ParticleHPVector theStore;
600       theStore.SetInterpolationManager(aMan);  // Store interpolates f(costh)
601       x1 = y1;
602       x2 = y2;
603       G4double x, y;
604       for (i = 0; i < theBuff1.GetVectorLength(); i++) {
605         x = theBuff1.GetX(i);  // costh binning identical
606         y1 = theBuff1.GetY(i);
607         y2 = theBuff2.GetY(i);
608         y = theInt.Interpolate(theManager.GetScheme(it), fsEnergy, theAngular[it - 1].GetLabel(),
609                                theAngular[it].GetLabel(), y1, y2);
610         theStore.SetX(i, x);
611         theStore.SetY(i, y);
612       }
613       cosTh = theStore.Sample();
614     }
615     delete[] running;
616   }
617   else {
618     throw G4HadronicException(__FILE__, __LINE__,
619                               "G4ParticleHPContAngularPar::Sample: Unknown angular representation");
620   }
621   //G4cout << "  Efin=" << fsEnergy << G4endl;
622   result->SetKineticEnergy(fsEnergy);
623 
624   G4double phi = twopi * G4UniformRand();
625   if(cosTh > 1.0) { cosTh = 1.0; }
626   else if (cosTh < -1.0) { cosTh = -1.0; }
627   G4double sinth = std::sqrt((1.0 - cosTh)*(1.0 + cosTh));
628   G4double mtot = result->GetTotalMomentum();
629   G4ThreeVector tempVector(mtot * sinth * std::cos(phi), mtot * sinth * std::sin(phi), mtot * cosTh);
630   result->SetMomentum(tempVector);
631   return result;
632 }
633 
634 void G4ParticleHPContAngularPar::PrepareTableInterpolation()
635 {
636   // Discrete energies: store own energies in a map for faster searching
637   //
638   // The data files sometimes have identical discrete energies (likely typos)
639   // which would lead to overwriting the already existing index and hence
640   // creating a hole in the lookup table.
641   // No attempt is made here to correct for the energies - rather an epsilon
642   // is subtracted from the energy in order to uniquely identify the line
643 
644   for (G4int ie = 0; ie < nDiscreteEnergies; ie++) {
645     // check if energy is already present and subtract epsilon if that's the case
646     G4double myE = theAngular[ie].GetLabel();
647     while (theDiscreteEnergiesOwn.find(myE) != theDiscreteEnergiesOwn.end()) {
648       myE -= 1e-6;
649     }
650     theDiscreteEnergiesOwn[myE] = ie;
651   }
652   return;
653 }
654 
655 void G4ParticleHPContAngularPar::BuildByInterpolation(G4double anEnergy,
656                                                       G4InterpolationScheme aScheme,
657                                                       G4ParticleHPContAngularPar& angpar1,
658                                                       G4ParticleHPContAngularPar& angpar2)
659 {
660   G4int ie, ie1, ie2, ie1Prev, ie2Prev;
661   // Only rebuild the interpolation table if there is a new interaction.
662   // For several subsequent samplings of final state particles in the same
663   // interaction the existing table should be used
664   if (!fCache.Get().fresh) return;
665 
666   // Make copies of angpar1 and angpar2. Since these are given by reference
667   // it can not be excluded that one of them is "this". Hence this code uses
668   // potentially the old "this" for creating the new this - which leads to
669   // memory corruption if the old is not stored as separarte object for lookup
670   const G4ParticleHPContAngularPar copyAngpar1(angpar1), copyAngpar2(angpar2);
671 
672   nAngularParameters = copyAngpar1.nAngularParameters;
673   theManager = copyAngpar1.theManager;
674   theEnergy = anEnergy;
675   theMinEner = DBL_MAX;  // min and max will be re-calculated after interpolation
676   theMaxEner = -DBL_MAX;
677 
678   // The two discrete sets must be merged. A vector holds the temporary data to
679   // be copied to the array in the end.  Since the G4ParticleHPList class
680   // contains pointers, can't simply assign elements of this type. Each member
681   // needs to call the explicit Set() method instead.
682 
683   // First, average probabilities for those lines that are in both sets
684   const std::map<G4double, G4int> discEnerOwn1 = copyAngpar1.GetDiscreteEnergiesOwn();
685   const std::map<G4double, G4int> discEnerOwn2 = copyAngpar2.GetDiscreteEnergiesOwn();
686   std::map<G4double, G4int>::const_iterator itedeo1;
687   std::map<G4double, G4int>::const_iterator itedeo2;
688   std::vector<G4ParticleHPList*> vAngular(discEnerOwn1.size());
689   G4double discEner1;
690   for (itedeo1 = discEnerOwn1.cbegin(); itedeo1 != discEnerOwn1.cend(); ++itedeo1) {
691     discEner1 = itedeo1->first;
692     if (discEner1 < theMinEner) {
693       theMinEner = discEner1;
694     }
695     if (discEner1 > theMaxEner) {
696       theMaxEner = discEner1;
697     }
698     ie1 = itedeo1->second;
699     itedeo2 = discEnerOwn2.find(discEner1);
700     if (itedeo2 == discEnerOwn2.cend()) {
701       ie2 = -1;
702     }
703     else {
704       ie2 = itedeo2->second;
705     }
706     vAngular[ie1] = new G4ParticleHPList();
707     vAngular[ie1]->SetLabel(copyAngpar1.theAngular[ie1].GetLabel());
708     G4double val1, val2;
709     for (G4int ip = 0; ip < nAngularParameters; ++ip) {
710       val1 = copyAngpar1.theAngular[ie1].GetValue(ip);
711       if (ie2 != -1) {
712         val2 = copyAngpar2.theAngular[ie2].GetValue(ip);
713       }
714       else {
715         val2 = 0.;
716       }
717       G4double value = theInt.Interpolate(aScheme, anEnergy, copyAngpar1.theEnergy,
718                                           copyAngpar2.theEnergy, val1, val2);
719       vAngular[ie1]->SetValue(ip, value);
720     }
721   }  // itedeo1 loop
722 
723   // Add the ones in set2 but not in set1
724   std::vector<G4ParticleHPList*>::const_iterator itv;
725   G4double discEner2;
726   for (itedeo2 = discEnerOwn2.cbegin(); itedeo2 != discEnerOwn2.cend(); ++itedeo2) {
727     discEner2 = itedeo2->first;
728     ie2 = itedeo2->second;
729     G4bool notFound = true;
730     itedeo1 = discEnerOwn1.find(discEner2);
731     if (itedeo1 != discEnerOwn1.cend()) {
732       notFound = false;
733     }
734     if (notFound) {
735       // not yet in list
736       if (discEner2 < theMinEner) {
737         theMinEner = discEner2;
738       }
739       if (discEner2 > theMaxEner) {
740         theMaxEner = discEner2;
741       }
742       // find position to insert
743       G4bool isInserted = false;
744       ie = 0;
745       for (itv = vAngular.cbegin(); itv != vAngular.cend(); ++itv, ++ie) {
746         if (discEner2 > (*itv)->GetLabel()) {
747           itv = vAngular.insert(itv, new G4ParticleHPList);
748           (*itv)->SetLabel(copyAngpar2.theAngular[ie2].GetLabel());
749           isInserted = true;
750           break;
751         }
752       }
753       if (!isInserted) {
754         ie = (G4int)vAngular.size();
755         vAngular.push_back(new G4ParticleHPList);
756         vAngular[ie]->SetLabel(copyAngpar2.theAngular[ie2].GetLabel());
757         isInserted = true;
758       }
759 
760       G4double val1, val2;
761       for (G4int ip = 0; ip < nAngularParameters; ++ip) {
762         val1 = 0;
763         val2 = copyAngpar2.theAngular[ie2].GetValue(ip);
764         G4double value = theInt.Interpolate(aScheme, anEnergy, copyAngpar1.theEnergy,
765                                             copyAngpar2.theEnergy, val1, val2);
766         vAngular[ie]->SetValue(ip, value);
767       }
768     }  // end if(notFound)
769   }  // end loop on itedeo2
770 
771   // Store new discrete list
772   nDiscreteEnergies = (G4int)vAngular.size();
773   delete[] theAngular;
774   theAngular = nullptr;
775   if (nDiscreteEnergies > 0) {
776     theAngular = new G4ParticleHPList[nDiscreteEnergies];
777   }
778   theDiscreteEnergiesOwn.clear();
779   theDiscreteEnergies.clear();
780   for (ie = 0; ie < nDiscreteEnergies; ++ie) {
781     theAngular[ie].SetLabel(vAngular[ie]->GetLabel());
782     for (G4int ip = 0; ip < nAngularParameters; ++ip) {
783       theAngular[ie].SetValue(ip, vAngular[ie]->GetValue(ip));
784     }
785     theDiscreteEnergiesOwn[theAngular[ie].GetLabel()] = ie;
786     theDiscreteEnergies.insert(theAngular[ie].GetLabel());
787   }
788 
789   // The continuous energies need to be made from scratch like the discrete
790   // ones. Therefore the re-assignemnt of theAngular needs to be done
791   // after the continuous energy set is also finalized. Only then the
792   // total number of nEnergies is known and the array can be allocated.
793 
794   // Get minimum and maximum energy interpolating
795   // Don't use theMinEner or theMaxEner here, since the transformed energies
796   // need the interpolated range from the original Angpar
797   G4double interMinEner = copyAngpar1.GetMinEner()
798                           + (theEnergy - copyAngpar1.GetEnergy())
799                               * (copyAngpar2.GetMinEner() - copyAngpar1.GetMinEner())
800                               / (copyAngpar2.GetEnergy() - copyAngpar1.GetEnergy());
801   G4double interMaxEner = copyAngpar1.GetMaxEner()
802                           + (theEnergy - copyAngpar1.GetEnergy())
803                               * (copyAngpar2.GetMaxEner() - copyAngpar1.GetMaxEner())
804                               / (copyAngpar2.GetEnergy() - copyAngpar1.GetEnergy());
805 
806   // Loop to energies of new set
807   theEnergiesTransformed.clear();
808 
809   G4int nEnergies1 = copyAngpar1.GetNEnergies();
810   G4int nDiscreteEnergies1 = copyAngpar1.GetNDiscreteEnergies();
811   G4double minEner1 = copyAngpar1.GetMinEner();
812   G4double maxEner1 = copyAngpar1.GetMaxEner();
813   G4int nEnergies2 = copyAngpar2.GetNEnergies();
814   G4int nDiscreteEnergies2 = copyAngpar2.GetNDiscreteEnergies();
815   G4double minEner2 = copyAngpar2.GetMinEner();
816   G4double maxEner2 = copyAngpar2.GetMaxEner();
817 
818   // First build the list of transformed energies normalized
819   // to the new min max by assuming that the min-max range of
820   // each set would be scalable to the new, interpolated min
821   // max range
822 
823   G4double e1(0.);
824   G4double eTNorm1(0.);
825   for (ie1 = nDiscreteEnergies1; ie1 < nEnergies1; ++ie1) {
826     e1 = copyAngpar1.theAngular[ie1].GetLabel();
827     eTNorm1 = (e1 - minEner1);
828     if (maxEner1 != minEner1) eTNorm1 /= (maxEner1 - minEner1);
829     if (eTNorm1 >= 0 && eTNorm1 <= 1) theEnergiesTransformed.insert(eTNorm1);
830   }
831 
832   G4double e2(0.);
833   G4double eTNorm2(0.);
834   for (ie2 = nDiscreteEnergies2; ie2 < nEnergies2; ++ie2) {
835     e2 = copyAngpar2.theAngular[ie2].GetLabel();
836     eTNorm2 = (e2 - minEner2);
837     if (maxEner2 != minEner2) eTNorm2 /= (maxEner2 - minEner2);
838     if (eTNorm2 >= 0 && eTNorm2 <= 1) theEnergiesTransformed.insert(eTNorm2);
839   }
840 
841   // Now the list of energies is complete
842   nEnergies = nDiscreteEnergies + (G4int)theEnergiesTransformed.size();
843 
844   // Create final array of angular parameters
845   const std::size_t esize = nEnergies > 0 ? nEnergies : 1;
846   auto theNewAngular = new G4ParticleHPList[esize];
847 
848   // Copy discrete energies and interpolated parameters to new array
849 
850   if (theAngular != nullptr) {
851     for (ie = 0; ie < nDiscreteEnergies; ++ie) {
852       theNewAngular[ie].SetLabel(theAngular[ie].GetLabel());
853       for (G4int ip = 0; ip < nAngularParameters; ++ip) {
854         theNewAngular[ie].SetValue(ip, theAngular[ie].GetValue(ip));
855       }
856     }
857     delete[] theAngular;
858   }
859   theAngular = theNewAngular;
860 
861   // Interpolate the continuous energies for new array
862   auto iteet = theEnergiesTransformed.begin();
863 
864   G4double e1Interp(0.);
865   G4double e2Interp(0.);
866   for (ie = nDiscreteEnergies; ie < nEnergies; ++ie, ++iteet) {
867     G4double eT = (*iteet);
868 
869     //--- Use eT1 = eT: Get energy and parameters of copyAngpar1 for this eT
870     e1Interp = (maxEner1 - minEner1) * eT + minEner1;
871     //----- Get parameter value corresponding to this e1Interp
872     for (ie1 = nDiscreteEnergies1; ie1 < nEnergies1; ++ie1) {
873       if ((copyAngpar1.theAngular[ie1].GetLabel() - e1Interp) > 1.E-10 * e1Interp) break;
874     }
875     ie1Prev = ie1 - 1;
876     if (ie1 == 0) ++ie1Prev;
877     if (ie1 == nEnergies1) {
878       ie1--;
879       ie1Prev = ie1;
880     }
881 
882     //--- Use eT2 = eT: Get energy and parameters of copyAngpar2 for this eT
883     e2Interp = (maxEner2 - minEner2) * eT + minEner2;
884     //----- Get parameter value corresponding to this e2Interp
885     for (ie2 = nDiscreteEnergies2; ie2 < nEnergies2; ++ie2) {
886       if ((copyAngpar2.theAngular[ie2].GetLabel() - e2Interp) > 1.E-10 * e2Interp) break;
887     }
888     ie2Prev = ie2 - 1;
889     if (ie2 == 0) ++ie2Prev;
890     if (ie2 == nEnergies2) {
891       ie2--;
892       ie2Prev = ie2;
893     }
894 
895     //---- Energy corresponding to energy transformed
896     G4double eN = (interMaxEner - interMinEner) * eT + interMinEner;
897 
898     theAngular[ie].SetLabel(eN);
899     if (eN < theMinEner) {
900       theMinEner = eN;
901     }
902     if (eN > theMaxEner) {
903       theMaxEner = eN;
904     }
905 
906     G4double val1(0.);
907     G4double val2(0.);
908     G4double value(0.);
909     for (G4int ip = 0; ip < nAngularParameters; ++ip) {
910       val1 = theInt.Interpolate2(
911                theManager.GetScheme(ie), e1Interp, copyAngpar1.theAngular[ie1Prev].GetLabel(),
912                copyAngpar1.theAngular[ie1].GetLabel(), copyAngpar1.theAngular[ie1Prev].GetValue(ip),
913                copyAngpar1.theAngular[ie1].GetValue(ip))
914              * (maxEner1 - minEner1);
915       val2 = theInt.Interpolate2(
916                theManager.GetScheme(ie), e2Interp, copyAngpar2.theAngular[ie2Prev].GetLabel(),
917                copyAngpar2.theAngular[ie2].GetLabel(), copyAngpar2.theAngular[ie2Prev].GetValue(ip),
918                copyAngpar2.theAngular[ie2].GetValue(ip))
919              * (maxEner2 - minEner2);
920 
921       value = theInt.Interpolate(aScheme, anEnergy, copyAngpar1.theEnergy, copyAngpar2.theEnergy,
922                                  val1, val2);
923       if (interMaxEner != interMinEner) {
924         value /= (interMaxEner - interMinEner);
925       }
926       else if (value != 0) {
927         throw G4HadronicException(__FILE__, __LINE__,
928                                   "G4ParticleHPContAngularPar::PrepareTableInterpolation "
929                                   "interMaxEner == interMinEner and  value != 0.");
930       }
931       theAngular[ie].SetValue(ip, value);
932     }
933   }  // end loop on nDiscreteEnergies
934 
935   for (itv = vAngular.cbegin(); itv != vAngular.cend(); ++itv)
936     delete (*itv);
937 }
938 
939 void G4ParticleHPContAngularPar::Dump() const
940 {
941   G4cout << theEnergy << " " << nEnergies << " " << nDiscreteEnergies << " " << nAngularParameters
942          << G4endl;
943 
944   for (G4int ii = 0; ii < nEnergies; ++ii)
945     theAngular[ii].Dump();
946 }
947