Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4ParticleHPContAngularPar.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// 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
48
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"
61#include "G4ParticleHPVector.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
72{
73 theProjectile = (nullptr == p) ? G4Neutron::Neutron() : p;
74 toBeCached v;
75 fCache.Put(v);
76 if (G4ParticleHPManager::GetInstance()->GetDoNotAdjustFinalState()) adjustResult = false;
77}
78
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
110
111void 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
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
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 }
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;
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;
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
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
656 G4InterpolationScheme aScheme,
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
940{
941 G4cout << theEnergy << " " << nEnergies << " " << nDiscreteEnergies << " " << nAngularParameters
942 << G4endl;
943
944 for (G4int ii = 0; ii < nEnergies; ++ii)
945 theAngular[ii].Dump();
946}
G4InterpolationScheme
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
const G4double A[17]
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition Randomize.hh:52
static G4Alpha * Alpha()
Definition G4Alpha.cc:83
value_type & Get() const
Definition G4Cache.hh:315
void Put(const value_type &val) const
Definition G4Cache.hh:321
static G4Deuteron * Deuteron()
Definition G4Deuteron.cc:90
static G4Electron * Electron()
Definition G4Electron.cc:91
static G4Gamma * Gamma()
Definition G4Gamma.cc:81
static G4He3 * He3()
Definition G4He3.cc:90
void Init(G4int aScheme, G4int aRange)
G4InterpolationScheme GetScheme(G4int index) const
G4InterpolationScheme GetInverseScheme(G4int index)
static G4IonTable * GetIonTable()
static G4Neutron * Neutron()
Definition G4Neutron.cc:101
static G4double GetNuclearMass(const G4double A, const G4double Z)
G4ReactionProduct * Sample(G4double anEnergy, G4double massCode, G4double mass, G4int angularRep, G4int interpol)
void Init(std::istream &aDataFile, const G4ParticleDefinition *projectile)
std::map< G4double, G4int > GetDiscreteEnergiesOwn() const
G4ParticleHPContAngularPar(const G4ParticleDefinition *p=nullptr)
void BuildByInterpolation(G4double anEnergy, G4InterpolationScheme aScheme, G4ParticleHPContAngularPar &store1, G4ParticleHPContAngularPar &store2)
G4double Interpolate(G4InterpolationScheme aScheme, G4double x, G4double x1, G4double x2, G4double y1, G4double y2) const
G4double GetWeightedBinIntegral(const G4InterpolationScheme &aScheme, const G4double x1, const G4double x2, const G4double y1, const G4double y2)
G4double Interpolate2(G4InterpolationScheme aScheme, G4double x, G4double x1, G4double x2, G4double y1, G4double y2) const
G4double GetBinIntegral(const G4InterpolationScheme &aScheme, const G4double x1, const G4double x2, const G4double y1, const G4double y2)
void SetCoeff(G4int i, G4int l, G4double coeff)
void Init(G4int i, G4double e, G4int n)
G4double SampleMax(G4double energy)
void SetManager(G4InterpolationManager &aManager)
void SetLabel(G4double aLabel)
void SetValue(G4int i, G4double y)
void Init(std::istream &aDataFile, G4int nPar, G4double unit=1.)
G4double GetValue(G4int i)
static G4ParticleHPManager * GetInstance()
void SetY(G4int i, G4double x)
void SetX(G4int i, G4double e)
void SetInterpolationManager(const G4InterpolationManager &aManager)
G4double GetY(G4double x)
G4double GetX(G4int i) const
G4int GetVectorLength() const
static G4Positron * Positron()
Definition G4Positron.cc:90
static G4Proton * Proton()
Definition G4Proton.cc:90
static G4Triton * Triton()
Definition G4Triton.cc:90
#define DBL_MAX
Definition templates.hh:62