Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4SPSEneDistribution.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// G4SPSEneDistribution class implementation
27//
28// Author: Fan Lei, QinetiQ ltd - 05/02/2004
29// Customer: ESA/ESTEC
30// Revisions: Andrew Green, Andrea Dotti
31// --------------------------------------------------------------------
33
34#include "G4Exp.hh"
35#include "G4SystemOfUnits.hh"
36#include "G4UnitsTable.hh"
37#include "Randomize.hh"
38#include "G4AutoLock.hh"
39#include "G4Threading.hh"
40
42{
44
45 // Initialise all variables
46
47 particle_energy = 1.0 * MeV;
48 EnergyDisType = "Mono";
49 weight=1.;
50 MonoEnergy = 1 * MeV;
51 Emin = 0.;
52 Emax = 1.e30;
53 alpha = 0.;
54 biasalpha = 0.;
55 prob_norm = 1.0;
56 Ezero = 0.;
57 SE = 0.;
58 Temp = 0.;
59 grad = 0.;
60 cept = 0.;
61 IntType = "NULL"; // Interpolation type
62
63 ArbEmin = 0.;
64 ArbEmax = 1.e30;
65
66 verbosityLevel = 0;
67
68 threadLocal_t& data = threadLocalData.Get();
69 data.Emax = Emax;
70 data.Emin = Emin;
71 data.alpha =alpha;
72 data.cept = cept;
73 data.Ezero = Ezero;
74 data.grad = grad;
75 data.particle_energy = 0.;
76 data.particle_definition = nullptr;
77 data.weight = weight;
78}
79
81{
83 if(Arb_grad_cept_flag)
84 {
85 delete [] Arb_grad;
86 delete [] Arb_cept;
87 }
88
89 if(Arb_alpha_Const_flag)
90 {
91 delete [] Arb_alpha;
92 delete [] Arb_Const;
93 }
94
95 if(Arb_ezero_flag)
96 {
97 delete [] Arb_ezero;
98 }
99 delete Bbody_x;
100 delete BBHist;
101 delete CP_x;
102 delete CPHist;
103 for (auto & it : SplineInt)
104 {
105 delete it;
106 it = nullptr;
107 }
108 SplineInt.clear();
109}
110
112{
113 G4AutoLock l(&mutex);
114 EnergyDisType = DisType;
115 if (EnergyDisType == "User")
116 {
117 UDefEnergyH = IPDFEnergyH = ZeroPhysVector;
118 IPDFEnergyExist = false;
119 }
120 else if (EnergyDisType == "Arb")
121 {
122 ArbEnergyH = IPDFArbEnergyH = ZeroPhysVector;
123 IPDFArbExist = false;
124 }
125 else if (EnergyDisType == "Epn")
126 {
127 UDefEnergyH = IPDFEnergyH = ZeroPhysVector;
128 IPDFEnergyExist = false;
129 EpnEnergyH = ZeroPhysVector;
130 }
131}
132
134{
135 G4AutoLock l(&mutex);
136 return EnergyDisType;
137}
138
140{
141 G4AutoLock l(&mutex);
142 Emin = emi;
143 threadLocalData.Get().Emin = Emin;
144}
145
147{
148 return threadLocalData.Get().Emin;
149}
150
152{
153 G4AutoLock l(&mutex);
154 return ArbEmin;
155}
156
158{
159 G4AutoLock l(&mutex);
160 return ArbEmax;
161}
162
164{
165 G4AutoLock l(&mutex);
166 Emax = ema;
167 threadLocalData.Get().Emax = Emax;
168}
169
171{
172 return threadLocalData.Get().Emax;
173}
174
176{
177 G4AutoLock l(&mutex);
178 MonoEnergy = menergy;
179}
180
182{
183 G4AutoLock l(&mutex);
184 SE = e;
185}
187{
188 G4AutoLock l(&mutex);
189 alpha = alp;
190 threadLocalData.Get().alpha = alpha;
191}
192
194{
195 G4AutoLock l(&mutex);
196 biasalpha = alp;
197 Biased = true;
198}
199
201{
202 G4AutoLock l(&mutex);
203 Temp = tem;
204}
205
207{
208 G4AutoLock l(&mutex);
209 Ezero = eze;
210 threadLocalData.Get().Ezero = Ezero;
211}
212
214{
215 G4AutoLock l(&mutex);
216 grad = gr;
217 threadLocalData.Get().grad = grad;
218}
219
221{
222 G4AutoLock l(&mutex);
223 cept = c;
224 threadLocalData.Get().cept = cept;
225}
226
228{
229 G4AutoLock l(&mutex);
230 return IntType;
231}
232
234{
235 G4AutoLock l(&mutex);
236 eneRndm = a;
237}
238
240{
241 G4AutoLock l(&mutex);
242 verbosityLevel = a;
243}
244
246{
247 return threadLocalData.Get().weight;
248}
249
251{
252 G4AutoLock l(&mutex);
253 return MonoEnergy;
254}
255
257{
258 G4AutoLock l(&mutex);
259 return SE;
260}
261
263{
264 return threadLocalData.Get().alpha;
265}
266
268{
269 return threadLocalData.Get().Ezero;
270}
271
273{
274 G4AutoLock l(&mutex);
275 return Temp;
276}
277
279{
280 return threadLocalData.Get().grad;
281}
282
284{
285 return threadLocalData.Get().cept;
286}
287
293
299
301{
302 G4AutoLock l(&mutex);
303 G4double ehi = input.x(),
304 val = input.y();
305 if (verbosityLevel > 1)
306 {
307 G4cout << "In UserEnergyHisto" << G4endl;
308 G4cout << " " << ehi << " " << val << G4endl;
309 }
310 UDefEnergyH.InsertValues(ehi, val);
311 Emax = ehi;
312 threadLocalData.Get().Emax = Emax;
313}
314
316{
317 G4AutoLock l(&mutex);
318 G4double ehi = input.x(),
319 val = input.y();
320 if (verbosityLevel > 1)
321 {
322 G4cout << "In ArbEnergyHisto" << G4endl;
323 G4cout << " " << ehi << " " << val << G4endl;
324 }
325 ArbEnergyH.InsertValues(ehi, val);
326}
327
329{
330 G4AutoLock l(&mutex);
331 std::ifstream infile(filename, std::ios::in);
332 if (!infile)
333 {
334 G4Exception("G4SPSEneDistribution::ArbEnergyHistoFile", "Event0301",
335 FatalException, "Unable to open the histo ASCII file");
336 }
337 G4double ehi, val;
338 while (infile >> ehi >> val)
339 {
340 ArbEnergyH.InsertValues(ehi, val);
341 }
342}
343
345{
346 G4AutoLock l(&mutex);
347 G4double ehi = input.x(),
348 val = input.y();
349 if (verbosityLevel > 1)
350 {
351 G4cout << "In EpnEnergyHisto" << G4endl;
352 G4cout << " " << ehi << " " << val << G4endl;
353 }
354 EpnEnergyH.InsertValues(ehi, val);
355 Emax = ehi;
356 threadLocalData.Get().Emax = Emax;
357 Epnflag = true;
358}
359
361{
362 G4AutoLock l(&mutex);
363 if (EnergyDisType == "Cdg")
364 {
365 CalculateCdgSpectrum();
366 }
367 else if (EnergyDisType == "Bbody")
368 {
369 if(!BBhistInit)
370 {
371 BBInitHists();
372 }
373 CalculateBbodySpectrum();
374 }
375 else if (EnergyDisType == "CPow")
376 {
377 if(!CPhistInit)
378 {
379 CPInitHists();
380 }
381 CalculateCPowSpectrum();
382 }
383}
384
385void G4SPSEneDistribution::BBInitHists() // MT: Lock in caller
386{
387 BBHist = new std::vector<G4double>(10001, 0.0);
388 Bbody_x = new std::vector<G4double>(10001, 0.0);
389 BBhistInit = true;
390}
391
392void G4SPSEneDistribution::CPInitHists() // MT: Lock in caller
393{
394 CPHist = new std::vector<G4double>(10001, 0.0);
395 CP_x = new std::vector<G4double>(10001, 0.0);
396 CPhistInit = true;
397}
398
399void G4SPSEneDistribution::CalculateCdgSpectrum() // MT: Lock in caller
400{
401 // This uses the spectrum from the INTEGRAL Mass Model (TIMM)
402 // to generate a Cosmic Diffuse X/gamma ray spectrum.
403
404 G4double pfact[2] = { 8.5, 112 };
405 G4double spind[2] = { 1.4, 2.3 };
406 G4double ene_line[3] = { 1. * keV, 18. * keV, 1E6 * keV };
407 G4int n_par;
408
409 ene_line[0] = threadLocalData.Get().Emin;
410 if (threadLocalData.Get().Emin < 18 * keV)
411 {
412 n_par = 2;
413 ene_line[2] = threadLocalData.Get().Emax;
414 if (threadLocalData.Get().Emax < 18 * keV)
415 {
416 n_par = 1;
417 ene_line[1] = threadLocalData.Get().Emax;
418 }
419 }
420 else
421 {
422 n_par = 1;
423 pfact[0] = 112.;
424 spind[0] = 2.3;
425 ene_line[1] = threadLocalData.Get().Emax;
426 }
427
428 // Create a cumulative histogram
429 //
430 CDGhist[0] = 0.;
431 G4double omalpha;
432 G4int i = 0;
433 while (i < n_par)
434 {
435 omalpha = 1. - spind[i];
436 CDGhist[i + 1] = CDGhist[i] + (pfact[i] / omalpha)
437 * (std::pow(ene_line[i + 1] / keV, omalpha)
438 - std::pow(ene_line[i] / keV,omalpha));
439 ++i;
440 }
441
442 // Normalise histo and divide by 1000 to make MeV
443 //
444 i = 0;
445 while (i < n_par)
446 {
447 CDGhist[i + 1] = CDGhist[i + 1] / CDGhist[n_par];
448 ++i;
449 }
450}
451
452void G4SPSEneDistribution::CalculateBbodySpectrum() // MT: Lock in caller
453{
454 // Create bbody spectrum
455 // Proved very hard to integrate indefinitely, so different method.
456 // User inputs emin, emax and T. These are used to create a 10,000
457 // bin histogram.
458 // Use photon density spectrum = 2 nu**2/c**2 * (std::exp(h nu/kT)-1)
459 // = 2 E**2/h**2c**2 times the exponential
460
461 G4double erange = threadLocalData.Get().Emax - threadLocalData.Get().Emin;
462 G4double steps = erange / 10000.;
463
464 const G4double k = 8.6181e-11; //Boltzmann const in MeV/K
465 const G4double h = 4.1362e-21; // Plancks const in MeV s
466 const G4double c = 3e8; // Speed of light
467 const G4double h2 = h * h;
468 const G4double c2 = c * c;
469 G4int count = 0;
470 G4double sum = 0.;
471 BBHist->at(0) = 0.;
472
473 while (count < 10000)
474 {
475 Bbody_x->at(count) = threadLocalData.Get().Emin + G4double(count * steps);
476 G4double Bbody_y = (2. * std::pow(Bbody_x->at(count), 2.))
477 / (h2*c2*(std::exp(Bbody_x->at(count) / (k*Temp)) - 1.));
478 sum = sum + Bbody_y;
479 BBHist->at(count + 1) = BBHist->at(count) + Bbody_y;
480 ++count;
481 }
482
483 Bbody_x->at(10000) = threadLocalData.Get().Emax;
484
485 // Normalise cumulative histo
486 //
487 count = 0;
488 while (count < 10001)
489 {
490 BBHist->at(count) = BBHist->at(count) / sum;
491 ++count;
492 }
493}
494
495void G4SPSEneDistribution::CalculateCPowSpectrum() // MT: Lock in caller
496{
497 // Create cutoff power-law spectrum, x^a exp(-x/b)
498 // The integral of this function is an incomplete gamma function, which
499 // is only available in the Boost library.
500 //
501 // User inputs are emin, emax and alpha and Ezero. These are used to
502 // create a 10,000 bin histogram.
503
504 G4double erange = threadLocalData.Get().Emax - threadLocalData.Get().Emin;
505 G4double steps = erange / 10000.;
506 alpha = threadLocalData.Get().alpha ;
507 Ezero = threadLocalData.Get().Ezero ;
508
509 G4int count = 0;
510 G4double sum = 0.;
511 CPHist->at(0) = 0.;
512
513 while (count < 10000)
514 {
515 CP_x->at(count) = threadLocalData.Get().Emin + G4double(count * steps);
516 G4double CP_y = std::pow(CP_x->at(count), alpha)
517 * std::exp(-CP_x->at(count) / Ezero);
518 sum = sum + CP_y;
519 CPHist->at(count + 1) = CPHist->at(count) + CP_y;
520 ++count;
521 }
522
523 CP_x->at(10000) = threadLocalData.Get().Emax;
524
525 // Normalise cumulative histo
526 //
527 count = 0;
528 while (count < 10001)
529 {
530 CPHist->at(count) = CPHist->at(count) / sum;
531 ++count;
532 }
533}
534
536{
537 G4AutoLock l(&mutex);
538
539 // Allows user to specify spectrum is momentum
540 //
541 EnergySpec = value; // false if momentum
542 if (verbosityLevel > 1)
543 {
544 G4cout << "EnergySpec has value " << EnergySpec << G4endl;
545 }
546}
547
549{
550 G4AutoLock l(&mutex);
551
552 // Allows user to specify integral or differential spectra
553 //
554 DiffSpec = value; // true = differential, false = integral
555 if (verbosityLevel > 1)
556 {
557 G4cout << "Diffspec has value " << DiffSpec << G4endl;
558 }
559}
560
562{
563 G4AutoLock l(&mutex);
564
565 IntType = IType;
566 ArbEmax = ArbEnergyH.GetMaxEnergy();
567 ArbEmin = ArbEnergyH.Energy(0);
568
569 // Now interpolate points
570
571 if (IntType == "Lin") LinearInterpolation();
572 if (IntType == "Log") LogInterpolation();
573 if (IntType == "Exp") ExpInterpolation();
574 if (IntType == "Spline") SplineInterpolation();
575}
576
577void G4SPSEneDistribution::LinearInterpolation() // MT: Lock in caller
578{
579 // Method to do linear interpolation on the Arb points
580 // Calculate equation of each line segment, max 1024.
581 // Calculate Area under each segment
582 // Create a cumulative array which is then normalised Arb_Cum_Area
583
584 G4double Area_seg[1024]; // Stores area under each segment
585 G4double sum = 0., Arb_x[1024]={0.}, Arb_y[1024]={0.}, Arb_Cum_Area[1024]={0.};
586 std::size_t i, count;
587 std::size_t maxi = ArbEnergyH.GetVectorLength();
588 for (i = 0; i < maxi; ++i)
589 {
590 Arb_x[i] = ArbEnergyH.GetLowEdgeEnergy(i);
591 Arb_y[i] = ArbEnergyH(i);
592 }
593
594 // Points are now in x,y arrays. If the spectrum is integral it has to be
595 // made differential and if momentum it has to be made energy
596
597 if (!DiffSpec)
598 {
599 // Converts integral point-wise spectra to Differential
600 //
601 for (count = 0; count < maxi-1; ++count)
602 {
603 Arb_y[count] = (Arb_y[count] - Arb_y[count + 1])
604 / (Arb_x[count + 1] - Arb_x[count]);
605 }
606 --maxi;
607 }
608
609 if (!EnergySpec)
610 {
611 // change currently stored values (emin etc) which are actually momenta
612 // to energies
613 //
614 G4ParticleDefinition* pdef = threadLocalData.Get().particle_definition;
615 if (pdef == nullptr)
616 {
617 G4Exception("G4SPSEneDistribution::LinearInterpolation",
618 "Event0302", FatalException,
619 "Error: particle not defined");
620 }
621 else
622 {
623 // Apply Energy**2 = p**2c**2 + m0**2c**4
624 // p should be entered as E/c i.e. without the division by c
625 // being done - energy equivalent
626
627 G4double mass = pdef->GetPDGMass();
628
629 // Convert point to energy unit and its value to per energy unit
630 //
631 G4double total_energy;
632 for (count = 0; count < maxi; ++count)
633 {
634 total_energy = std::sqrt((Arb_x[count] * Arb_x[count])
635 + (mass * mass)); // total energy
636 Arb_y[count] = Arb_y[count] * Arb_x[count] / total_energy;
637 Arb_x[count] = total_energy - mass; // kinetic energy
638 }
639 }
640 }
641
642 i = 1;
643
644 Arb_grad = new G4double [1024];
645 Arb_cept = new G4double [1024];
646 Arb_grad_cept_flag = true;
647
648 Arb_grad[0] = 0.;
649 Arb_cept[0] = 0.;
650 Area_seg[0] = 0.;
651 Arb_Cum_Area[0] = 0.;
652 while (i < maxi)
653 {
654 // calculate gradient and intercept for each segment
655 //
656 Arb_grad[i] = (Arb_y[i] - Arb_y[i - 1]) / (Arb_x[i] - Arb_x[i - 1]);
657 if (verbosityLevel == 2)
658 {
659 G4cout << Arb_grad[i] << G4endl;
660 }
661 if (Arb_grad[i] > 0.)
662 {
663 if (verbosityLevel == 2)
664 {
665 G4cout << "Arb_grad is positive" << G4endl;
666 }
667 Arb_cept[i] = Arb_y[i] - (Arb_grad[i] * Arb_x[i]);
668 }
669 else if (Arb_grad[i] < 0.)
670 {
671 if (verbosityLevel == 2)
672 {
673 G4cout << "Arb_grad is negative" << G4endl;
674 }
675 Arb_cept[i] = Arb_y[i] + (-Arb_grad[i] * Arb_x[i]);
676 }
677 else
678 {
679 if (verbosityLevel == 2)
680 {
681 G4cout << "Arb_grad is 0." << G4endl;
682 }
683 Arb_cept[i] = Arb_y[i];
684 }
685
686 Area_seg[i] = ((Arb_grad[i] / 2)
687 * (Arb_x[i] * Arb_x[i] - Arb_x[i - 1] * Arb_x[i - 1])
688 + Arb_cept[i] * (Arb_x[i] - Arb_x[i - 1]));
689 Arb_Cum_Area[i] = Arb_Cum_Area[i - 1] + Area_seg[i];
690 sum = sum + Area_seg[i];
691 if (verbosityLevel == 2)
692 {
693 G4cout << Arb_x[i] << Arb_y[i] << Area_seg[i] << sum
694 << Arb_grad[i] << G4endl;
695 }
696 ++i;
697 }
698
699 i = 0;
700 while (i < maxi)
701 {
702 Arb_Cum_Area[i] = Arb_Cum_Area[i] / sum; // normalisation
703 IPDFArbEnergyH.InsertValues(Arb_x[i], Arb_Cum_Area[i]);
704 ++i;
705 }
706
707 // now scale the ArbEnergyH, needed by Probability()
708 //
709 ArbEnergyH.ScaleVector(1., 1./sum);
710
711 if (verbosityLevel >= 1)
712 {
713 G4cout << "Leaving LinearInterpolation" << G4endl;
714 ArbEnergyH.DumpValues();
715 IPDFArbEnergyH.DumpValues();
716 }
717}
718
719void G4SPSEneDistribution::LogInterpolation() // MT: Lock in caller
720{
721 // Interpolation based on Logarithmic equations
722 // Generate equations of line segments
723 // y = Ax**alpha => log y = alpha*logx + logA
724 // Find area under line segments
725 // Create normalised, cumulative array Arb_Cum_Area
726
727 G4double Area_seg[1024]; // Stores area under each segment
728 G4double sum = 0., Arb_x[1024]={0.}, Arb_y[1024]={0.}, Arb_Cum_Area[1024]={0.};
729 std::size_t i, count;
730 std::size_t maxi = ArbEnergyH.GetVectorLength();
731 for (i = 0; i < maxi; ++i)
732 {
733 Arb_x[i] = ArbEnergyH.GetLowEdgeEnergy(i);
734 Arb_y[i] = ArbEnergyH(i);
735 }
736
737 // Points are now in x,y arrays. If the spectrum is integral it has to be
738 // made differential and if momentum it has to be made energy
739
740 if (!DiffSpec)
741 {
742 // Converts integral point-wise spectra to Differential
743 //
744 for (count = 0; count < maxi-1; ++count)
745 {
746 Arb_y[count] = (Arb_y[count] - Arb_y[count + 1])
747 / (Arb_x[count + 1] - Arb_x[count]);
748 }
749 --maxi;
750 }
751
752 if (!EnergySpec)
753 {
754 // Change currently stored values (emin etc) which are actually momenta
755 // to energies
756
757 G4ParticleDefinition* pdef = threadLocalData.Get().particle_definition;
758 if (pdef == nullptr)
759 {
760 G4Exception("G4SPSEneDistribution::LogInterpolation",
761 "Event0302", FatalException,
762 "Error: particle not defined");
763 }
764 else
765 {
766 // Apply Energy**2 = p**2c**2 + m0**2c**4
767 // p should be entered as E/c i.e. without the division by c
768 // being done - energy equivalent
769
770 G4double mass = pdef->GetPDGMass();
771
772 // Convert point to energy unit and its value to per energy unit
773 //
774 G4double total_energy;
775 for (count = 0; count < maxi; ++count)
776 {
777 total_energy = std::sqrt((Arb_x[count] * Arb_x[count]) + (mass * mass));
778 Arb_y[count] = Arb_y[count] * Arb_x[count] / total_energy;
779 Arb_x[count] = total_energy - mass; // kinetic energy
780 }
781 }
782 }
783
784 i = 1;
785
786 if ( Arb_ezero != nullptr ) { delete [] Arb_ezero; Arb_ezero = nullptr; }
787 if ( Arb_Const != nullptr ) { delete [] Arb_Const; Arb_Const = nullptr; }
788 Arb_alpha = new G4double [1024];
789 Arb_Const = new G4double [1024];
790 Arb_alpha_Const_flag = true;
791
792 Arb_alpha[0] = 0.;
793 Arb_Const[0] = 0.;
794 Area_seg[0] = 0.;
795 Arb_Cum_Area[0] = 0.;
796 if (Arb_x[0] <= 0. || Arb_y[0] <= 0.)
797 {
798 G4cout << "You should not use log interpolation with points <= 0."
799 << G4endl;
800 G4cout << "These will be changed to 1e-20, which may cause problems"
801 << G4endl;
802 if (Arb_x[0] <= 0.)
803 {
804 Arb_x[0] = 1e-20;
805 }
806 if (Arb_y[0] <= 0.)
807 {
808 Arb_y[0] = 1e-20;
809 }
810 }
811
812 G4double alp;
813 while (i < maxi)
814 {
815 // In case points are negative or zero
816 //
817 if (Arb_x[i] <= 0. || Arb_y[i] <= 0.)
818 {
819 G4cout << "You should not use log interpolation with points <= 0."
820 << G4endl;
821 G4cout << "These will be changed to 1e-20, which may cause problems"
822 << G4endl;
823 if (Arb_x[i] <= 0.)
824 {
825 Arb_x[i] = 1e-20;
826 }
827 if (Arb_y[i] <= 0.)
828 {
829 Arb_y[i] = 1e-20;
830 }
831 }
832
833 Arb_alpha[i] = (std::log10(Arb_y[i]) - std::log10(Arb_y[i - 1]))
834 / (std::log10(Arb_x[i]) - std::log10(Arb_x[i - 1]));
835 Arb_Const[i] = Arb_y[i] / (std::pow(Arb_x[i], Arb_alpha[i]));
836 alp = Arb_alpha[i] + 1;
837 if (alp == 0.)
838 {
839 Area_seg[i] = Arb_Const[i]
840 * (std::log(Arb_x[i]) - std::log(Arb_x[i - 1]));
841 }
842 else
843 {
844 Area_seg[i] = (Arb_Const[i] / alp)
845 * (std::pow(Arb_x[i], alp) - std::pow(Arb_x[i - 1], alp));
846 }
847 sum = sum + Area_seg[i];
848 Arb_Cum_Area[i] = Arb_Cum_Area[i - 1] + Area_seg[i];
849 if (verbosityLevel == 2)
850 {
851 G4cout << Arb_alpha[i] << Arb_Const[i] << Area_seg[i] << G4endl;
852 }
853 ++i;
854 }
855
856 i = 0;
857 while (i < maxi)
858 {
859 Arb_Cum_Area[i] = Arb_Cum_Area[i] / sum;
860 IPDFArbEnergyH.InsertValues(Arb_x[i], Arb_Cum_Area[i]);
861 ++i;
862 }
863
864 // Now scale the ArbEnergyH, needed by Probability()
865 //
866 ArbEnergyH.ScaleVector(1., 1./sum);
867
868 if (verbosityLevel >= 1)
869 {
870 G4cout << "Leaving LogInterpolation " << G4endl;
871 }
872}
873
874void G4SPSEneDistribution::ExpInterpolation() // MT: Lock in caller
875{
876 // Interpolation based on Exponential equations
877 // Generate equations of line segments
878 // y = Ae**-(x/e0) => ln y = -x/e0 + lnA
879 // Find area under line segments
880 // Create normalised, cumulative array Arb_Cum_Area
881
882 G4double Area_seg[1024]; // Stores area under each segment
883 G4double sum = 0., Arb_x[1024]={0.}, Arb_y[1024]={0.}, Arb_Cum_Area[1024]={0.};
884 std::size_t i, count;
885 std::size_t maxi = ArbEnergyH.GetVectorLength();
886 for (i = 0; i < maxi; ++i)
887 {
888 Arb_x[i] = ArbEnergyH.GetLowEdgeEnergy(i);
889 Arb_y[i] = ArbEnergyH(i);
890 }
891
892 // Points are now in x,y arrays. If the spectrum is integral it has to be
893 // made differential and if momentum it has to be made energy
894
895 if (!DiffSpec)
896 {
897 // Converts integral point-wise spectra to Differential
898 //
899 for (count = 0; count < maxi - 1; ++count)
900 {
901 Arb_y[count] = (Arb_y[count] - Arb_y[count + 1])
902 / (Arb_x[count + 1] - Arb_x[count]);
903 }
904 --maxi;
905 }
906
907 if (!EnergySpec)
908 {
909 // Change currently stored values (emin etc) which are actually momenta
910 // to energies
911 //
912 G4ParticleDefinition* pdef = threadLocalData.Get().particle_definition;
913 if (pdef == nullptr)
914 {
915 G4Exception("G4SPSEneDistribution::ExpInterpolation",
916 "Event0302", FatalException,
917 "Error: particle not defined");
918 }
919 else
920 {
921 // Apply Energy**2 = p**2c**2 + m0**2c**4
922 // p should be entered as E/c i.e. without the division by c
923 // being done - energy equivalent
924
925 G4double mass = pdef->GetPDGMass();
926
927 // Convert point to energy unit and its value to per energy unit
928 //
929 G4double total_energy;
930 for (count = 0; count < maxi; ++count)
931 {
932 total_energy = std::sqrt((Arb_x[count] * Arb_x[count]) + (mass * mass));
933 Arb_y[count] = Arb_y[count] * Arb_x[count] / total_energy;
934 Arb_x[count] = total_energy - mass; // kinetic energy
935 }
936 }
937 }
938
939 i = 1;
940
941 if ( Arb_ezero != nullptr ) { delete[] Arb_ezero; Arb_ezero = nullptr; }
942 if ( Arb_Const != nullptr ) { delete[] Arb_Const; Arb_Const = nullptr; }
943 Arb_ezero = new G4double [1024];
944 Arb_Const = new G4double [1024];
945 Arb_ezero_flag = true;
946
947 Arb_ezero[0] = 0.;
948 Arb_Const[0] = 0.;
949 Area_seg[0] = 0.;
950 Arb_Cum_Area[0] = 0.;
951 while (i < maxi)
952 {
953 G4double test = std::log(Arb_y[i]) - std::log(Arb_y[i - 1]);
954 if (test > 0. || test < 0.)
955 {
956 Arb_ezero[i] = -(Arb_x[i] - Arb_x[i - 1])
957 / (std::log(Arb_y[i]) - std::log(Arb_y[i - 1]));
958 Arb_Const[i] = Arb_y[i] / (std::exp(-Arb_x[i] / Arb_ezero[i]));
959 Area_seg[i] = -(Arb_Const[i] * Arb_ezero[i])
960 * (std::exp(-Arb_x[i] / Arb_ezero[i])
961 - std::exp(-Arb_x[i - 1] / Arb_ezero[i]));
962 }
963 else
964 {
965 G4Exception("G4SPSEneDistribution::ExpInterpolation",
966 "Event0302", JustWarning,
967 "Flat line segment: problem, setting to zero parameters.");
968 G4cout << "Flat line segment: problem" << G4endl;
969 Arb_ezero[i] = 0.;
970 Arb_Const[i] = 0.;
971 Area_seg[i] = 0.;
972 }
973 sum = sum + Area_seg[i];
974 Arb_Cum_Area[i] = Arb_Cum_Area[i - 1] + Area_seg[i];
975 if (verbosityLevel == 2)
976 {
977 G4cout << Arb_ezero[i] << Arb_Const[i] << Area_seg[i] << G4endl;
978 }
979 ++i;
980 }
981
982 i = 0;
983 while (i < maxi)
984 {
985 Arb_Cum_Area[i] = Arb_Cum_Area[i] / sum;
986 IPDFArbEnergyH.InsertValues(Arb_x[i], Arb_Cum_Area[i]);
987 ++i;
988 }
989
990 // Now scale the ArbEnergyH, needed by Probability()
991 //
992 ArbEnergyH.ScaleVector(1., 1./sum);
993
994 if (verbosityLevel >= 1)
995 {
996 G4cout << "Leaving ExpInterpolation " << G4endl;
997 }
998}
999
1000void G4SPSEneDistribution::SplineInterpolation() // MT: Lock in caller
1001{
1002 // Interpolation using Splines.
1003 // Create Normalised arrays, make x 0->1 and y hold the function (Energy)
1004 //
1005 // Current method based on the above will not work in all cases.
1006 // New method is implemented below.
1007
1008 G4double sum, Arb_x[1024]={0.}, Arb_y[1024]={0.}, Arb_Cum_Area[1024]={0.};
1009 std::size_t i, count;
1010 std::size_t maxi = ArbEnergyH.GetVectorLength();
1011
1012 for (i = 0; i < maxi; ++i)
1013 {
1014 Arb_x[i] = ArbEnergyH.GetLowEdgeEnergy(i);
1015 Arb_y[i] = ArbEnergyH(i);
1016 }
1017
1018 // Points are now in x,y arrays. If the spectrum is integral it has to be
1019 // made differential and if momentum it has to be made energy
1020
1021 if (!DiffSpec)
1022 {
1023 // Converts integral point-wise spectra to Differential
1024 //
1025 for (count = 0; count < maxi - 1; ++count)
1026 {
1027 Arb_y[count] = (Arb_y[count] - Arb_y[count + 1])
1028 / (Arb_x[count + 1] - Arb_x[count]);
1029 }
1030 --maxi;
1031 }
1032
1033 if (!EnergySpec)
1034 {
1035 // Change currently stored values (emin etc) which are actually momenta
1036 // to energies
1037 //
1038 G4ParticleDefinition* pdef = threadLocalData.Get().particle_definition;
1039 if (pdef == nullptr)
1040 {
1041 G4Exception("G4SPSEneDistribution::SplineInterpolation",
1042 "Event0302", FatalException,
1043 "Error: particle not defined");
1044 }
1045 else
1046 {
1047 // Apply Energy**2 = p**2c**2 + m0**2c**4
1048 // p should be entered as E/c i.e. without the division by c
1049 // being done - energy equivalent
1050
1051 G4double mass = pdef->GetPDGMass();
1052
1053 // Convert point to energy unit and its value to per energy unit
1054 //
1055 G4double total_energy;
1056 for (count = 0; count < maxi; ++count)
1057 {
1058 total_energy = std::sqrt((Arb_x[count] * Arb_x[count]) + (mass * mass));
1059 Arb_y[count] = Arb_y[count] * Arb_x[count] / total_energy;
1060 Arb_x[count] = total_energy - mass; // kinetic energy
1061 }
1062 }
1063 }
1064
1065 i = 1;
1066 Arb_Cum_Area[0] = 0.;
1067 sum = 0.;
1068 Splinetemp = new G4DataInterpolation(Arb_x, Arb_y, (G4int)maxi, 0., 0.);
1069 G4double ei[101], prob[101];
1070 for (auto & it : SplineInt)
1071 {
1072 delete it;
1073 it = nullptr;
1074 }
1075 SplineInt.clear();
1076 SplineInt.resize(1024,nullptr);
1077 while (i < maxi)
1078 {
1079 // 100 step per segment for the integration of area
1080
1081 G4double de = (Arb_x[i] - Arb_x[i - 1])/100.;
1082 G4double area = 0.;
1083
1084 for (count = 0; count < 101; ++count)
1085 {
1086 ei[count] = Arb_x[i - 1] + de*count ;
1087 prob[count] = Splinetemp->CubicSplineInterpolation(ei[count]);
1088 if (prob[count] < 0.)
1089 {
1091 ED << "Warning: G4DataInterpolation returns value < 0 " << prob[count]
1092 << " " << ei[count] << G4endl;
1093 G4Exception("G4SPSEneDistribution::SplineInterpolation", "Event0303",
1094 FatalException, ED);
1095 }
1096 area += prob[count]*de;
1097 }
1098 Arb_Cum_Area[i] = Arb_Cum_Area[i - 1] + area;
1099 sum += area;
1100
1101 prob[0] = prob[0]/(area/de);
1102 for (count = 1; count < 100; ++count)
1103 {
1104 prob[count] = prob[count-1] + prob[count]/(area/de);
1105 }
1106
1107 SplineInt[i] = new G4DataInterpolation(prob, ei, 101, 0., 0.);
1108
1109 // NOTE: i starts from 1!
1110 //
1111 ++i;
1112 }
1113
1114 i = 0;
1115 while (i < maxi)
1116 {
1117 Arb_Cum_Area[i] = Arb_Cum_Area[i] / sum; // normalisation
1118 IPDFArbEnergyH.InsertValues(Arb_x[i], Arb_Cum_Area[i]);
1119 ++i;
1120 }
1121
1122 // Now scale the ArbEnergyH, needed by Probability()
1123 //
1124 ArbEnergyH.ScaleVector(1., 1./sum);
1125
1126 if (verbosityLevel > 0)
1127 {
1128 G4cout << "Leaving SplineInterpolation " << G4endl;
1129 }
1130}
1131
1132void G4SPSEneDistribution::GenerateMonoEnergetic()
1133{
1134 // Method to generate MonoEnergetic particles
1135
1136 threadLocalData.Get().particle_energy = MonoEnergy;
1137}
1138
1139void G4SPSEneDistribution::GenerateGaussEnergies()
1140{
1141 // Method to generate Gaussian particles
1142
1143 G4double ene = G4RandGauss::shoot(MonoEnergy,SE);
1144 if (ene < 0) ene = 0.;
1145 threadLocalData.Get().particle_energy = ene;
1146}
1147
1148void G4SPSEneDistribution::GenerateLinearEnergies(G4bool bArb = false)
1149{
1150 G4double rndm;
1151 threadLocal_t& params = threadLocalData.Get();
1152 G4double emaxsq = std::pow(params.Emax, 2.); // Emax squared
1153 G4double eminsq = std::pow(params.Emin, 2.); // Emin squared
1154 G4double intersq = std::pow(params.cept, 2.); // cept squared
1155
1156 if (bArb) rndm = G4UniformRand();
1157 else rndm = eneRndm->GenRandEnergy();
1158
1159 G4double bracket = ((params.grad / 2.)
1160 * (emaxsq - eminsq)
1161 + params.cept * (params.Emax - params.Emin));
1162 bracket = bracket * rndm;
1163 bracket = bracket + (params.grad / 2.) * eminsq + params.cept * params.Emin;
1164
1165 // Now have a quad of form m/2 E**2 + cE - bracket = 0
1166 //
1167 bracket = -bracket;
1168
1169 if (params.grad != 0.)
1170 {
1171 G4double sqbrack = (intersq - 4 * (params.grad / 2.) * (bracket));
1172 sqbrack = std::sqrt(sqbrack);
1173 G4double root1 = -params.cept + sqbrack;
1174 root1 = root1 / (2. * (params.grad / 2.));
1175
1176 G4double root2 = -params.cept - sqbrack;
1177 root2 = root2 / (2. * (params.grad / 2.));
1178
1179 if (root1 > params.Emin && root1 < params.Emax)
1180 {
1181 params.particle_energy = root1;
1182 }
1183 if (root2 > params.Emin && root2 < params.Emax)
1184 {
1185 params.particle_energy = root2;
1186 }
1187 }
1188 else if (params.grad == 0.)
1189 {
1190 // have equation of form cE - bracket =0
1191 //
1192 params.particle_energy = bracket / params.cept;
1193 }
1194
1195 if (params.particle_energy < 0.)
1196 {
1197 params.particle_energy = -params.particle_energy;
1198 }
1199
1200 if (verbosityLevel >= 1)
1201 {
1202 G4cout << "Energy is " << params.particle_energy << G4endl;
1203 }
1204}
1205
1206void G4SPSEneDistribution::GeneratePowEnergies(G4bool bArb = false)
1207{
1208 // Method to generate particle energies distributed as a power-law
1209
1210 G4double rndm;
1211 G4double emina, emaxa;
1212
1213 threadLocal_t& params = threadLocalData.Get();
1214
1215 emina = std::pow(params.Emin, params.alpha + 1);
1216 emaxa = std::pow(params.Emax, params.alpha + 1);
1217
1218 if (bArb) rndm = G4UniformRand();
1219 else rndm = eneRndm->GenRandEnergy();
1220
1221 if (params.alpha != -1.)
1222 {
1223 G4double ene = ((rndm * (emaxa - emina)) + emina);
1224 ene = std::pow(ene, (1. / (params.alpha + 1.)));
1225 params.particle_energy = ene;
1226 }
1227 else
1228 {
1229 G4double ene = (std::log(params.Emin)
1230 + rndm * (std::log(params.Emax) - std::log(params.Emin)));
1231 params.particle_energy = std::exp(ene);
1232 }
1233 if (verbosityLevel >= 1)
1234 {
1235 G4cout << "Energy is " << params.particle_energy << G4endl;
1236 }
1237}
1238
1239void G4SPSEneDistribution::GenerateCPowEnergies()
1240{
1241 // Method to generate particle energies distributed in
1242 // cutoff power-law distribution
1243 //
1244 // CP_x holds Energies, and CPHist holds the cumulative histo.
1245 // binary search to find correct bin then lin interpolation.
1246 // Use the earlier defined histogram + RandGeneral method to generate
1247 // random numbers following the histos distribution
1248
1249 G4double rndm = eneRndm->GenRandEnergy();
1250 G4int nabove = 10001, nbelow = 0, middle;
1251
1252 G4AutoLock l(&mutex);
1253 G4bool done = CPhistCalcd;
1254 l.unlock();
1255
1256 if(!done)
1257 {
1258 Calculate(); //This is has a lock inside, risk is to do it twice
1259 l.lock();
1260 CPhistCalcd = true;
1261 l.unlock();
1262 }
1263
1264 // Binary search to find bin that rndm is in
1265 //
1266 while (nabove - nbelow > 1)
1267 {
1268 middle = (nabove + nbelow) / 2;
1269 if (rndm == CPHist->at(middle))
1270 {
1271 break;
1272 }
1273 if (rndm < CPHist->at(middle))
1274 {
1275 nabove = middle;
1276 }
1277 else
1278 {
1279 nbelow = middle;
1280 }
1281 }
1282
1283 // Now interpolate in that bin to find the correct output value
1284 //
1285 G4double x1, x2, y1, y2, t, q;
1286 x1 = CP_x->at(nbelow);
1287 if(nbelow+1 == static_cast<G4int>(CP_x->size()))
1288 {
1289 x2 = CP_x->back();
1290 }
1291 else
1292 {
1293 x2 = CP_x->at(nbelow + 1);
1294 }
1295 y1 = CPHist->at(nbelow);
1296 if(nbelow+1 == static_cast<G4int>(CPHist->size()))
1297 {
1298 G4cout << CPHist->back() << G4endl;
1299 y2 = CPHist->back();
1300 }
1301 else
1302 {
1303 y2 = CPHist->at(nbelow + 1);
1304 }
1305 t = (y2 - y1) / (x2 - x1);
1306 q = y1 - t * x1;
1307
1308 threadLocalData.Get().particle_energy = (rndm - q) / t;
1309
1310 if (verbosityLevel >= 1)
1311 {
1312 G4cout << "Energy is " << threadLocalData.Get().particle_energy << G4endl;
1313 }
1314}
1315
1316void G4SPSEneDistribution::GenerateBiasPowEnergies()
1317{
1318 // Method to generate particle energies distributed as
1319 // in biased power-law and calculate its weight
1320
1321 threadLocal_t& params = threadLocalData.Get();
1322
1323 G4double rndm;
1324 G4double emina, emaxa, emin, emax;
1325
1326 G4double normal = 1.;
1327
1328 emin = params.Emin;
1329 emax = params.Emax;
1330
1331 rndm = eneRndm->GenRandEnergy();
1332
1333 if (biasalpha != -1.)
1334 {
1335 emina = std::pow(emin, biasalpha + 1);
1336 emaxa = std::pow(emax, biasalpha + 1);
1337 G4double ee = ((rndm * (emaxa - emina)) + emina);
1338 params.particle_energy = std::pow(ee, (1. / (biasalpha + 1.)));
1339 normal = 1./(1+biasalpha) * (emaxa - emina);
1340 }
1341 else
1342 {
1343 G4double ee = (std::log(emin) + rndm * (std::log(emax) - std::log(emin)));
1344 params.particle_energy = std::exp(ee);
1345 normal = std::log(emax) - std::log(emin);
1346 }
1347 params.weight = GetProbability(params.particle_energy)
1348 / (std::pow(params.particle_energy,biasalpha)/normal);
1349
1350 if (verbosityLevel >= 1)
1351 {
1352 G4cout << "Energy is " << params.particle_energy << G4endl;
1353 }
1354}
1355
1356void G4SPSEneDistribution::GenerateExpEnergies(G4bool bArb = false)
1357{
1358 // Method to generate particle energies distributed according
1359 // to an exponential curve
1360
1361 G4double rndm;
1362
1363 if (bArb) rndm = G4UniformRand();
1364 else rndm = eneRndm->GenRandEnergy();
1365
1366 threadLocal_t& params = threadLocalData.Get();
1367 params.particle_energy = -params.Ezero
1368 * (std::log(rndm * (std::exp(-params.Emax
1369 / params.Ezero)
1370 - std::exp(-params.Emin
1371 / params.Ezero))
1372 + std::exp(-params.Emin / params.Ezero)));
1373 if (verbosityLevel >= 1)
1374 {
1375 G4cout << "Energy is " << params.particle_energy << G4endl;
1376 }
1377}
1378
1379void G4SPSEneDistribution::GenerateBremEnergies()
1380{
1381 // Method to generate particle energies distributed according
1382 // to a Bremstrahlung equation of the form
1383 // I = const*((kT)**1/2)*E*(e**(-E/kT))
1384
1385 G4double rndm = eneRndm->GenRandEnergy();
1386 G4double expmax, expmin, k;
1387
1388 k = 8.6181e-11; // Boltzmann's const in MeV/K
1389 G4double ksq = std::pow(k, 2.); // k squared
1390 G4double Tsq = std::pow(Temp, 2.); // Temp squared
1391
1392 threadLocal_t& params = threadLocalData.Get();
1393
1394 expmax = std::exp(-params.Emax / (k * Temp));
1395 expmin = std::exp(-params.Emin / (k * Temp));
1396
1397 // If either expmax or expmin are zero then this will cause problems
1398 // Most probably this will be because T is too low or E is too high
1399
1400 if (expmax == 0.)
1401 {
1402 G4Exception("G4SPSEneDistribution::GenerateBremEnergies",
1403 "Event0302", FatalException,
1404 "*****EXPMAX=0. Choose different E's or Temp");
1405 }
1406 if (expmin == 0.)
1407 {
1408 G4Exception("G4SPSEneDistribution::GenerateBremEnergies",
1409 "Event0302", FatalException,
1410 "*****EXPMIN=0. Choose different E's or Temp");
1411 }
1412
1413 G4double tempvar = rndm * ((-k) * Temp * (params.Emax * expmax
1414 - params.Emin * expmin)
1415 - (ksq * Tsq * (expmax - expmin)));
1416
1417 G4double bigc = (tempvar - k * Temp * params.Emin * expmin
1418 - ksq * Tsq * expmin) / (-k * Temp);
1419
1420 // This gives an equation of form: Ee(-E/kT) + kTe(-E/kT) - C =0
1421 // Solve this iteratively, step from Emin to Emax in 1000 steps
1422 // and take the best solution.
1423
1424 G4double erange = params.Emax - params.Emin;
1425 G4double steps = erange / 1000.;
1426 G4int i;
1427 G4double etest, diff, err = 100000.;
1428
1429 for (i = 1; i < 1000; ++i)
1430 {
1431 etest = params.Emin + (i - 1) * steps;
1432 diff = etest * (std::exp(-etest / (k * Temp)))
1433 + k * Temp * (std::exp(-etest / (k * Temp))) - bigc;
1434
1435 if (diff < 0.)
1436 {
1437 diff = -diff;
1438 }
1439
1440 if (diff < err)
1441 {
1442 err = diff;
1443 params.particle_energy = etest;
1444 }
1445 }
1446 if (verbosityLevel >= 1)
1447 {
1448 G4cout << "Energy is " << params.particle_energy << G4endl;
1449 }
1450}
1451
1452void G4SPSEneDistribution::GenerateBbodyEnergies()
1453{
1454 // BBody_x holds Energies, and BBHist holds the cumulative histo.
1455 // Binary search to find correct bin then lin interpolation.
1456 // Use the earlier defined histogram + RandGeneral method to generate
1457 // random numbers following the histos distribution
1458
1459 G4double rndm = eneRndm->GenRandEnergy();
1460 G4int nabove = 10001, nbelow = 0, middle;
1461
1462 G4AutoLock l(&mutex);
1463 G4bool done = BBhistCalcd;
1464 l.unlock();
1465
1466 if(!done)
1467 {
1468 Calculate(); //This is has a lock inside, risk is to do it twice
1469 l.lock();
1470 BBhistCalcd = true;
1471 l.unlock();
1472 }
1473
1474 // Binary search to find bin that rndm is in
1475 //
1476 while (nabove - nbelow > 1)
1477 {
1478 middle = (nabove + nbelow) / 2;
1479 if (rndm == BBHist->at(middle))
1480 {
1481 break;
1482 }
1483 if (rndm < BBHist->at(middle))
1484 {
1485 nabove = middle;
1486 }
1487 else
1488 {
1489 nbelow = middle;
1490 }
1491 }
1492
1493 // Now interpolate in that bin to find the correct output value
1494 //
1495 G4double x1, x2, y1, y2, t, q;
1496 x1 = Bbody_x->at(nbelow);
1497
1498 if(nbelow+1 == static_cast<G4int>(Bbody_x->size()))
1499 {
1500 x2 = Bbody_x->back();
1501 }
1502 else
1503 {
1504 x2 = Bbody_x->at(nbelow + 1);
1505 }
1506 y1 = BBHist->at(nbelow);
1507 if(nbelow+1 == static_cast<G4int>(BBHist->size()))
1508 {
1509 G4cout << BBHist->back() << G4endl;
1510 y2 = BBHist->back();
1511 }
1512 else
1513 {
1514 y2 = BBHist->at(nbelow + 1);
1515 }
1516 t = (y2 - y1) / (x2 - x1);
1517 q = y1 - t * x1;
1518
1519 threadLocalData.Get().particle_energy = (rndm - q) / t;
1520
1521 if (verbosityLevel >= 1)
1522 {
1523 G4cout << "Energy is " << threadLocalData.Get().particle_energy << G4endl;
1524 }
1525}
1526
1527void G4SPSEneDistribution::GenerateCdgEnergies()
1528{
1529 // Generate random numbers, compare with values in cumhist
1530 // to find appropriate part of spectrum and then
1531 // generate energy in the usual inversion way
1532
1533 G4double rndm, rndm2;
1534 G4double ene_line[3]={0,0,0};
1535 G4double omalpha[2]={0,0};
1536 threadLocal_t& params = threadLocalData.Get();
1537 if (params.Emin < 18 * keV && params.Emax < 18 * keV)
1538 {
1539 omalpha[0] = 1. - 1.4;
1540 ene_line[0] = params.Emin;
1541 ene_line[1] = params.Emax;
1542 }
1543 if (params.Emin < 18 * keV && params.Emax > 18 * keV)
1544 {
1545 omalpha[0] = 1. - 1.4;
1546 omalpha[1] = 1. - 2.3;
1547 ene_line[0] = params.Emin;
1548 ene_line[1] = 18. * keV;
1549 ene_line[2] = params.Emax;
1550 }
1551 if (params.Emin > 18 * keV)
1552 {
1553 omalpha[0] = 1. - 2.3;
1554 ene_line[0] = params.Emin;
1555 ene_line[1] = params.Emax;
1556 }
1557 rndm = eneRndm->GenRandEnergy();
1558 rndm2 = eneRndm->GenRandEnergy();
1559
1560 G4int i = 0;
1561 while (rndm >= CDGhist[i])
1562 {
1563 ++i;
1564 }
1565
1566 // Generate final energy
1567 //
1568 G4double ene = (std::pow(ene_line[i - 1], omalpha[i - 1])
1569 + (std::pow(ene_line[i], omalpha[i - 1])
1570 - std::pow(ene_line[i - 1], omalpha[i- 1])) * rndm2);
1571 params.particle_energy = std::pow(ene, (1. / omalpha[i - 1]));
1572
1573 if (verbosityLevel >= 1)
1574 {
1575 G4cout << "Energy is " << params.particle_energy << G4endl;
1576 }
1577}
1578
1579void G4SPSEneDistribution::GenUserHistEnergies()
1580{
1581 // Histograms are DIFFERENTIAL
1582
1583 G4AutoLock l(&mutex);
1584
1585 if (!IPDFEnergyExist)
1586 {
1587 std::size_t ii;
1588 std::size_t maxbin = UDefEnergyH.GetVectorLength();
1589 G4double bins[1024], vals[1024], sum;
1590 for ( ii = 0 ; ii<1024 ; ++ii ) { bins[ii]=0; vals[ii]=0; }
1591 sum = 0.;
1592
1593 if ( (!EnergySpec)
1594 && (threadLocalData.Get().particle_definition == nullptr))
1595 {
1596 G4Exception("G4SPSEneDistribution::GenUserHistEnergies",
1597 "Event0302", FatalException,
1598 "Error: particle definition is NULL");
1599 }
1600
1601 if (maxbin > 1024)
1602 {
1603 G4Exception("G4SPSEneDistribution::GenUserHistEnergies",
1604 "Event0302", JustWarning,
1605 "Maxbin>1024\n Setting maxbin to 1024, other bins are lost");
1606 maxbin = 1024;
1607 }
1608
1609 if (!DiffSpec)
1610 {
1611 G4cout << "Histograms are Differential!!! " << G4endl;
1612 }
1613 else
1614 {
1615 bins[0] = UDefEnergyH.GetLowEdgeEnergy(0);
1616 vals[0] = UDefEnergyH(0);
1617 sum = vals[0];
1618 for (ii = 1; ii < maxbin; ++ii)
1619 {
1620 bins[ii] = UDefEnergyH.GetLowEdgeEnergy(ii);
1621 vals[ii] = UDefEnergyH(ii) + vals[ii - 1];
1622 sum = sum + UDefEnergyH(ii);
1623 }
1624 }
1625
1626 if (!EnergySpec)
1627 {
1628 G4double mass = threadLocalData.Get().particle_definition->GetPDGMass();
1629
1630 // Multiply the function (vals) up by the bin width
1631 // to make the function counts/s (i.e. get rid of momentum dependence)
1632
1633 for (ii = 1; ii < maxbin; ++ii)
1634 {
1635 vals[ii] = vals[ii] * (bins[ii] - bins[ii - 1]);
1636 }
1637
1638 // Put energy bins into new histo, plus divide by energy bin width
1639 // to make evals counts/s/energy
1640 //
1641 for (ii = 0; ii < maxbin; ++ii)
1642 {
1643 // kinetic energy
1644 //
1645 bins[ii] = std::sqrt((bins[ii]*bins[ii])+(mass*mass))-mass;
1646 }
1647 for (ii = 1; ii < maxbin; ++ii)
1648 {
1649 vals[ii] = vals[ii] / (bins[ii] - bins[ii - 1]);
1650 }
1651 sum = vals[maxbin - 1];
1652 vals[0] = 0.;
1653 }
1654 for (ii = 0; ii < maxbin; ++ii)
1655 {
1656 vals[ii] = vals[ii] / sum;
1657 IPDFEnergyH.InsertValues(bins[ii], vals[ii]);
1658 }
1659
1660 IPDFEnergyExist = true;
1661 if (verbosityLevel > 1)
1662 {
1663 IPDFEnergyH.DumpValues();
1664 }
1665 }
1666 l.unlock();
1667
1668 // IPDF has been create so carry on
1669 //
1670 G4double rndm = eneRndm->GenRandEnergy();
1671 threadLocalData.Get().particle_energy= IPDFEnergyH.GetEnergy(rndm);
1672
1673 if (verbosityLevel >= 1)
1674 {
1675 G4cout << "Energy is " << particle_energy << G4endl;
1676 }
1677}
1678
1680{
1681 auto nbelow = IPDFArbEnergyH.FindBin(ene,(IPDFArbEnergyH.GetVectorLength())/2);
1682 G4double wei = 0.;
1683 if(IntType=="Lin")
1684 {
1685 // note: grad[i] and cept[i] are calculated with x[i-1] and x[i]
1686 auto gr = Arb_grad[nbelow + 1];
1687 auto ce = Arb_cept[nbelow + 1];
1688 wei = ene*gr + ce;
1689 }
1690 else if(IntType=="Log")
1691 {
1692 auto alp = Arb_alpha[nbelow + 1];
1693 auto cns = Arb_Const[nbelow + 1];
1694 wei = cns * std::pow(ene,alp);
1695 }
1696 else if(IntType=="Exp")
1697 {
1698 auto e0 = Arb_ezero[nbelow + 1];
1699 auto cns = Arb_Const[nbelow + 1];
1700 wei = cns * std::exp(-ene/e0);
1701 }
1702 else if(IntType=="Spline")
1703 {
1704 wei = SplineInt[nbelow+1]->CubicSplineInterpolation(ene);
1705 }
1706 return wei;
1707}
1708
1709void G4SPSEneDistribution::GenArbPointEnergies()
1710{
1711 if (verbosityLevel > 0)
1712 {
1713 G4cout << "In GenArbPointEnergies" << G4endl;
1714 }
1715
1716 G4double rndm = eneRndm->GenRandEnergy();
1717
1718 // Find the Bin, have x, y, no of points, and cumulative area distribution
1719 //
1720 std::size_t nabove = IPDFArbEnergyH.GetVectorLength(), nbelow = 0, middle;
1721
1722 // Binary search to find bin that rndm is in
1723 //
1724 while (nabove - nbelow > 1)
1725 {
1726 middle = (nabove + nbelow) / 2;
1727 if (rndm == IPDFArbEnergyH(middle))
1728 {
1729 break;
1730 }
1731 if (rndm < IPDFArbEnergyH(middle))
1732 {
1733 nabove = middle;
1734 }
1735 else
1736 {
1737 nbelow = middle;
1738 }
1739 }
1740 threadLocal_t& params = threadLocalData.Get();
1741 if (IntType == "Lin")
1742 {
1743 // Update thread-local copy of parameters
1744 //
1745 params.Emax = IPDFArbEnergyH.GetLowEdgeEnergy(nbelow + 1);
1746 params.Emin = IPDFArbEnergyH.GetLowEdgeEnergy(nbelow);
1747 params.grad = Arb_grad[nbelow + 1];
1748 params.cept = Arb_cept[nbelow + 1];
1749 GenerateLinearEnergies(true);
1750 }
1751 else if (IntType == "Log")
1752 {
1753 params.Emax = IPDFArbEnergyH.GetLowEdgeEnergy(nbelow + 1);
1754 params.Emin = IPDFArbEnergyH.GetLowEdgeEnergy(nbelow);
1755 params.alpha = Arb_alpha[nbelow + 1];
1756 GeneratePowEnergies(true);
1757 }
1758 else if (IntType == "Exp")
1759 {
1760 params.Emax = IPDFArbEnergyH.GetLowEdgeEnergy(nbelow + 1);
1761 params.Emin = IPDFArbEnergyH.GetLowEdgeEnergy(nbelow);
1762 params.Ezero = Arb_ezero[nbelow + 1];
1763 GenerateExpEnergies(true);
1764 }
1765 else if (IntType == "Spline")
1766 {
1767 params.Emax = IPDFArbEnergyH.GetLowEdgeEnergy(nbelow + 1);
1768 params.Emin = IPDFArbEnergyH.GetLowEdgeEnergy(nbelow);
1769 params.particle_energy = -1e100;
1770 rndm = eneRndm->GenRandEnergy();
1771 while (params.particle_energy < params.Emin
1772 || params.particle_energy > params.Emax)
1773 {
1774 params.particle_energy =
1775 SplineInt[nbelow+1]->CubicSplineInterpolation(rndm);
1776 rndm = eneRndm->GenRandEnergy();
1777 }
1778 if (verbosityLevel >= 1)
1779 {
1780 G4cout << "Energy is " << params.particle_energy << G4endl;
1781 }
1782 }
1783 else
1784 {
1785 G4Exception("G4SPSEneDistribution::GenArbPointEnergies", "Event0302",
1786 FatalException, "Error: IntType unknown type");
1787 }
1788}
1789
1790void G4SPSEneDistribution::GenEpnHistEnergies()
1791{
1792 // Firstly convert to energy if not already done
1793
1794 G4AutoLock l(&mutex);
1795
1796 if (Epnflag) // true means spectrum is epn, false means e
1797 {
1798 // Convert to energy by multiplying by A number
1799 //
1800 ConvertEPNToEnergy();
1801 }
1802 if (!IPDFEnergyExist)
1803 {
1804 // IPDF has not been created, so create it
1805 //
1806 G4double bins[1024], vals[1024], sum;
1807 std::size_t ii;
1808 std::size_t maxbin = UDefEnergyH.GetVectorLength();
1809 bins[0] = UDefEnergyH.GetLowEdgeEnergy(0);
1810 vals[0] = UDefEnergyH(0);
1811 sum = vals[0];
1812 for (ii = 1; ii < maxbin; ++ii)
1813 {
1814 bins[ii] = UDefEnergyH.GetLowEdgeEnergy(ii);
1815 vals[ii] = UDefEnergyH(ii) + vals[ii - 1];
1816 sum = sum + UDefEnergyH(ii);
1817 }
1818
1819 l.lock();
1820 for (ii = 0; ii < maxbin; ++ii)
1821 {
1822 vals[ii] = vals[ii] / sum;
1823 IPDFEnergyH.InsertValues(bins[ii], vals[ii]);
1824 }
1825 IPDFEnergyExist = true;
1826
1827 }
1828 l.unlock();
1829
1830 // IPDF has been create so carry on
1831 //
1832 G4double rndm = eneRndm->GenRandEnergy();
1833 threadLocalData.Get().particle_energy = IPDFEnergyH.GetEnergy(rndm);
1834
1835 if (verbosityLevel >= 1)
1836 {
1837 G4cout << "Energy is " << threadLocalData.Get().particle_energy << G4endl;
1838 }
1839}
1840
1841void G4SPSEneDistribution::ConvertEPNToEnergy() // MT: lock in caller
1842{
1843 // Use this before particle generation to convert the
1844 // currently stored histogram from energy/nucleon to energy.
1845
1846 threadLocal_t& params = threadLocalData.Get();
1847 if (params.particle_definition == nullptr)
1848 {
1849 G4cout << "Error: particle not defined" << G4endl;
1850 }
1851 else
1852 {
1853 // Need to multiply histogram by the number of nucleons.
1854 // Baryon Number looks to hold the no. of nucleons
1855 //
1856 G4int Bary = params.particle_definition->GetBaryonNumber();
1857
1858 // Change values in histogram, Read it out, delete it, re-create it
1859 //
1860 std::size_t count, maxcount;
1861 maxcount = EpnEnergyH.GetVectorLength();
1862 G4double ebins[1024], evals[1024];
1863 if (maxcount > 1024)
1864 {
1865 G4Exception("G4SPSEneDistribution::ConvertEPNToEnergy()",
1866 "gps001", JustWarning,
1867 "Histogram contains more than 1024 bins!\n\
1868 Those above 1024 will be ignored");
1869 maxcount = 1024;
1870 }
1871 if (maxcount < 1)
1872 {
1873 G4Exception("G4SPSEneDistribution::ConvertEPNToEnergy()",
1874 "gps001", FatalException,
1875 "Histogram contains less than 1 bin!\nRedefine the histogram");
1876 return;
1877 }
1878 for (count = 0; count < maxcount; ++count)
1879 {
1880 // Read out
1881 ebins[count] = EpnEnergyH.GetLowEdgeEnergy(count);
1882 evals[count] = EpnEnergyH(count);
1883 }
1884
1885 // Multiply the channels by the nucleon number to give energies
1886 //
1887 for (count = 0; count < maxcount; ++count)
1888 {
1889 ebins[count] = ebins[count] * Bary;
1890 }
1891
1892 // Set Emin and Emax
1893 //
1894 params.Emin = ebins[0];
1895 if (maxcount > 1)
1896 {
1897 params.Emax = ebins[maxcount - 1];
1898 }
1899 else
1900 {
1901 params.Emax = ebins[0];
1902 }
1903
1904 // Put energy bins into new histogram - UDefEnergyH
1905 //
1906 for (count = 0; count < maxcount; ++count)
1907 {
1908 UDefEnergyH.InsertValues(ebins[count], evals[count]);
1909 }
1910 Epnflag = false; // so that you dont repeat this method
1911 }
1912}
1913
1915{
1916 G4AutoLock l(&mutex);
1917 if (atype == "energy")
1918 {
1919 UDefEnergyH = IPDFEnergyH = ZeroPhysVector;
1920 IPDFEnergyExist = false;
1921 Emin = 0.;
1922 Emax = 1e30;
1923 }
1924 else if (atype == "arb")
1925 {
1926 ArbEnergyH = IPDFArbEnergyH = ZeroPhysVector;
1927 IPDFArbExist = false;
1928 }
1929 else if (atype == "epn")
1930 {
1931 UDefEnergyH = IPDFEnergyH = ZeroPhysVector;
1932 IPDFEnergyExist = false;
1933 EpnEnergyH = ZeroPhysVector;
1934 }
1935 else
1936 {
1937 G4cout << "Error, histtype not accepted " << G4endl;
1938 }
1939}
1940
1942{
1943 // Copy global shared status to thread-local one
1944 //
1945 threadLocal_t& params = threadLocalData.Get();
1946 params.particle_definition=a;
1947 params.particle_energy=-1;
1948 if(applyEvergyWeight)
1949 {
1950 params.Emax = ArbEmax;
1951 params.Emin = ArbEmin;
1952 }
1953 else
1954 {
1955 params.Emax = Emax;
1956 params.Emin = Emin;
1957 }
1958 params.alpha = alpha;
1959 params.Ezero = Ezero;
1960 params.grad = grad;
1961 params.cept = cept;
1962 params.weight = weight;
1963 // particle_energy = -1.;
1964
1965 if((EnergyDisType == "Mono") && ((MonoEnergy>Emax)||(MonoEnergy<Emin)))
1966 {
1968 ed << "MonoEnergy " << G4BestUnit(MonoEnergy,"Energy")
1969 << " is outside of [Emin,Emax] = ["
1970 << G4BestUnit(Emin,"Energy") << ", "
1971 << G4BestUnit(Emax,"Energy") << ". MonoEnergy is used anyway.";
1972 G4Exception("G4SPSEneDistribution::GenerateOne()",
1973 "GPS0001", JustWarning, ed);
1974 params.particle_energy=MonoEnergy;
1975 return params.particle_energy;
1976 }
1977 while ( (EnergyDisType == "Arb")
1978 ? (params.particle_energy < ArbEmin
1979 || params.particle_energy > ArbEmax)
1980 : (params.particle_energy < params.Emin
1981 || params.particle_energy > params.Emax) )
1982 {
1983 if (Biased)
1984 {
1985 GenerateBiasPowEnergies();
1986 }
1987 else
1988 {
1989 if (EnergyDisType == "Mono")
1990 {
1991 GenerateMonoEnergetic();
1992 }
1993 else if (EnergyDisType == "Lin")
1994 {
1995 GenerateLinearEnergies(false);
1996 }
1997 else if (EnergyDisType == "Pow")
1998 {
1999 GeneratePowEnergies(false);
2000 }
2001 else if (EnergyDisType == "CPow")
2002 {
2003 GenerateCPowEnergies();
2004 }
2005 else if (EnergyDisType == "Exp")
2006 {
2007 GenerateExpEnergies(false);
2008 }
2009 else if (EnergyDisType == "Gauss")
2010 {
2011 GenerateGaussEnergies();
2012 }
2013 else if (EnergyDisType == "Brem")
2014 {
2015 GenerateBremEnergies();
2016 }
2017 else if (EnergyDisType == "Bbody")
2018 {
2019 GenerateBbodyEnergies();
2020 }
2021 else if (EnergyDisType == "Cdg")
2022 {
2023 GenerateCdgEnergies();
2024 }
2025 else if (EnergyDisType == "User")
2026 {
2027 GenUserHistEnergies();
2028 }
2029 else if (EnergyDisType == "Arb")
2030 {
2031 GenArbPointEnergies();
2032 }
2033 else if (EnergyDisType == "Epn")
2034 {
2035 GenEpnHistEnergies();
2036 }
2037 else
2038 {
2039 G4cout << "Error: EnergyDisType has unusual value" << G4endl;
2040 }
2041 }
2042 }
2043 return params.particle_energy;
2044}
2045
2047{
2048 G4double prob = 1.;
2049
2050 threadLocal_t& params = threadLocalData.Get();
2051 if (EnergyDisType == "Lin")
2052 {
2053 if (prob_norm == 1.)
2054 {
2055 prob_norm = 0.5*params.grad*params.Emax*params.Emax
2056 + params.cept*params.Emax
2057 - 0.5*params.grad*params.Emin*params.Emin
2058 - params.cept*params.Emin;
2059 }
2060 prob = params.cept + params.grad * ene;
2061 prob /= prob_norm;
2062 }
2063 else if (EnergyDisType == "Pow")
2064 {
2065 if (prob_norm == 1.)
2066 {
2067 if (alpha != -1.)
2068 {
2069 G4double emina = std::pow(params.Emin, params.alpha + 1);
2070 G4double emaxa = std::pow(params.Emax, params.alpha + 1);
2071 prob_norm = 1./(1.+alpha) * (emaxa - emina);
2072 }
2073 else
2074 {
2075 prob_norm = std::log(params.Emax) - std::log(params.Emin) ;
2076 }
2077 }
2078 prob = std::pow(ene, params.alpha)/prob_norm;
2079 }
2080 else if (EnergyDisType == "Exp")
2081 {
2082 if (prob_norm == 1.)
2083 {
2084 prob_norm = -params.Ezero*(std::exp(-params.Emax/params.Ezero)
2085 - std::exp(params.Emin/params.Ezero));
2086 }
2087 prob = std::exp(-ene / params.Ezero);
2088 prob /= prob_norm;
2089 }
2090 else if (EnergyDisType == "Arb")
2091 {
2092 prob = ArbEnergyH.Value(ene);
2093
2094 if (prob <= 0.)
2095 {
2096 G4cout << " Warning:G4SPSEneDistribution::GetProbability: prob<= 0. "
2097 << prob << " " << ene << G4endl;
2098 prob = 1e-30;
2099 }
2100 }
2101 else
2102 {
2103 G4cout << "Error: EnergyDisType not supported" << G4endl;
2104 }
2105
2106 return prob;
2107}
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
std::ostringstream G4ExceptionDescription
#define G4BestUnit(a, b)
#define G4MUTEXDESTROY(mutex)
#define G4MUTEXINIT(mutex)
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
#define G4UniformRand()
Definition Randomize.hh:52
double x() const
double y() const
value_type & Get() const
Definition G4Cache.hh:315
G4double CubicSplineInterpolation(G4double pX) const
void InsertValues(const G4double energy, const G4double value)
G4double GetEnergy(const G4double value) const
G4double GetLowEdgeEnergy(const std::size_t index) const
G4double GetMaxEnergy() const
void ScaleVector(const G4double factorE, const G4double factorV)
G4double Energy(const std::size_t index) const
G4double Value(const G4double energy, std::size_t &lastidx) const
std::size_t GetVectorLength() const
void DumpValues(G4double unitE=1.0, G4double unitV=1.0) const
std::size_t FindBin(const G4double energy, std::size_t idx) const
G4double GetProbability(G4double)
G4double GetArbEneWeight(G4double)
G4double GenerateOne(G4ParticleDefinition *)
void ArbInterpolate(const G4String &)
G4PhysicsFreeVector GetUserDefinedEnergyHisto()
const G4String & GetEnergyDisType()
void SetEnergyDisType(const G4String &)
void EpnEnergyHisto(const G4ThreeVector &)
void ArbEnergyHistoFile(const G4String &)
void ReSetHist(const G4String &)
G4PhysicsFreeVector GetArbEnergyHisto()
void SetBiasRndm(G4SPSRandomGenerator *a)
const G4String & GetIntType()
void UserEnergyHisto(const G4ThreeVector &)
void ArbEnergyHisto(const G4ThreeVector &)