Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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
289{
290 G4AutoLock l(&mutex);
291 return UDefEnergyH;
292}
293
295{
296 G4AutoLock l(&mutex);
297 return ArbEnergyH;
298}
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 = 0;
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)
Definition: G4Exception.cc:59
std::ostringstream G4ExceptionDescription
Definition: G4Exception.hh:40
#define G4BestUnit(a, b)
#define G4MUTEXDESTROY(mutex)
Definition: G4Threading.hh:90
#define G4MUTEXINIT(mutex)
Definition: G4Threading.hh:87
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
#define G4endl
Definition: G4ios.hh:57
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 &)
void InputDifferentialSpectra(G4bool)
G4PhysicsFreeVector GetArbEnergyHisto()
void SetBiasRndm(G4SPSRandomGenerator *a)
const G4String & GetIntType()
void UserEnergyHisto(const G4ThreeVector &)
void ArbEnergyHisto(const G4ThreeVector &)