Geant4  10.00.p02
G4FPYSamplingOps.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 /*
27  * File: G4FPYSamplingOps.cc
28  * Author: B. Wendt (wendbryc@isu.edu)
29  *
30  * Created on June 30, 2011, 11:10 AM
31  */
32 
33 #include <iostream>
34 
35 #include <CLHEP/Random/Stat.h>
36 #include "Randomize.hh"
37 #include "globals.hh"
38 
39 #include "G4FFGDebuggingMacros.hh"
40 #include "G4FFGDefaultValues.hh"
41 #include "G4FFGEnumerations.hh"
42 #include "G4FPYSamplingOps.hh"
43 #include "G4ShiftedGaussian.hh"
45 
48 {
49  // Set the default verbosity
51 
52  // Initialize the class
53  Initialize();
54 }
55 
58 {
59  // Set the default verbosity
61 
62  // Initialize the class
63  Initialize();
64 }
65 
67 Initialize( void )
68 {
70 
71  // Get the pointer to the random number generator
72  RandomEngine_ = CLHEP::HepRandom::getTheEngine();
73 
74  // Initialize the data members
76  Mean_ = 0;
77  StdDev_ = 0;
79  GaussianOne_ = 0;
80  GaussianTwo_ = 0;
81  Tolerance_ = 0.000001;
84 
86 }
87 
90  G4double StdDev )
91 {
93 
94  // Determine if the parameters have changed
95  G4bool ParametersChanged = (Mean_ != Mean || StdDev_ != StdDev);
96  if(ParametersChanged == TRUE)
97  {
98  // Set the new values if the parameters have changed
100 
101  Mean_ = Mean;
102  StdDev_ = StdDev;
103  }
104 
105  G4double Sample = SampleGaussian();
106 
108  return Sample;
109 }
110 
113  G4double StdDev,
115 {
117 
118  if(Range == G4FFGEnumerations::ALL)
119  {
120  // Call the overloaded function
121  G4double Sample = G4SampleGaussian(Mean, StdDev);
122 
124  return Sample;
125  }
126 
127  // Determine if the parameters have changed
128  G4bool ParametersChanged = (Mean_ != Mean ||
129  StdDev_ != StdDev);
130  if(ParametersChanged == TRUE)
131  {
132  if(Mean <= 0)
133  {
134  std::ostringstream Temp;
135  Temp << "Mean value of " << Mean << " out of range";
136  G4Exception("G4FPYGaussianOps::G4SampleIntegerGaussian()",
137  Temp.str().c_str(),
138  JustWarning,
139  "A value of '0' will be used instead.");
140 
142  return 0;
143  }
144 
145  // Set the new values if the parameters have changed and then perform
146  // the shift
147  Mean_ = Mean;
148  StdDev_ = StdDev;
149 
151  }
152 
153  // Sample the Gaussian distribution
154  G4double Rand;
155  do
156  {
157  Rand = SampleGaussian();
158  } while(Rand < 0);
159 
161  return Rand;
162 }
163 
166  G4double StdDev )
167 {
169 
170  // Determine if the parameters have changed
171  G4bool ParametersChanged = (Mean_ != Mean || StdDev_ != StdDev);
172  if(ParametersChanged == TRUE)
173  {
174  // Set the new values if the parameters have changed
176 
177  Mean_ = Mean;
178  StdDev_ = StdDev;
179  }
180 
181  // Return the sample integer value
182  G4int Sample = (G4int)(std::floor(SampleGaussian()));
183 
185  return Sample;
186 }
187 
190  G4double StdDev,
192 {
194 
195  if(Range == G4FFGEnumerations::ALL)
196  {
197  // Call the overloaded function
198  G4int Sample = G4SampleIntegerGaussian(Mean, StdDev);
199 
201  return Sample;
202  } else
203  {
204  // ParameterShift() locks up if the mean is less than 1.
205  std::ostringstream Temp;
206  if(Mean < 1)
207  {
208  // Temp << "Mean value of " << Mean << " out of range";
209  // G4Exception("G4FPYGaussianOps::G4SampleIntegerGaussian()",
210  // Temp.str().c_str(),
211  // JustWarning,
212  // "A value of '0' will be used instead.");
213 
214  // return 0;
215  }
216 
217  if(Mean / StdDev < 2)
218  {
219  //Temp << "Non-ideal conditions:\tMean:" << Mean << "\tStdDev: "
220  // << StdDev;
221  //G4Exception("G4FPYGaussianOps::G4SampleIntegerGaussian()",
222  // Temp.str().c_str(),
223  // JustWarning,
224  // "Results not guaranteed: Consider tightening the standard deviation");
225  }
226 
227  // Determine if the parameters have changed
228  G4bool ParametersChanged = (Mean_ != Mean ||
229  StdDev_ != StdDev);
230  if(ParametersChanged == TRUE)
231  {
232  // Set the new values if the parameters have changed and then perform
233  // the shift
234  Mean_ = Mean;
235  StdDev_ = StdDev;
236 
238  }
239 
240  G4int RandInt;
241  // Sample the Gaussian distribution - only non-negative values are
242  // accepted
243  do
244  {
245  RandInt = (G4int)floor(SampleGaussian());
246  } while (RandInt < 0);
247 
249  return RandInt;
250  }
251 }
252 
255 {
257 
258  G4double Sample = RandomEngine_->flat();
259 
261  return Sample;
262 }
263 
266  G4double Upper )
267 {
269 
270  // Calculate the difference
271  G4double Difference = Upper - Lower;
272 
273  // Scale appropriately and return the value
274  G4double Sample = G4SampleUniform() * Difference + Lower;
275 
277  return Sample;
278 }
279 
281 G4SampleWatt( G4int WhatIsotope,
283  G4double WhatEnergy )
284 {
286 
287  // Determine if the parameters are different
288  //TK modified 131108
289  //if(WattConstants_->Product != WhatIsotope
290  if(WattConstants_->Product != WhatIsotope/10
291  || WattConstants_->Cause != WhatCause
292  || WattConstants_->Energy!= WhatEnergy )
293  {
294  // If the parameters are different or have not yet been defined then we
295  // need to re-evaluate the constants
296  //TK modified 131108
297  //WattConstants_->Product = WhatIsotope;
298  WattConstants_->Product = WhatIsotope/10;
299  WattConstants_->Cause = WhatCause;
300  WattConstants_->Energy = WhatEnergy;
301 
303  }
304 
305  G4double X = -std::log(G4SampleUniform());
306  G4double Y = -std::log(G4SampleUniform());
307  while(std::pow(Y - WattConstants_->M*(X + 1), 2)
308  > WattConstants_->B * WattConstants_->L * X)
309  {
310  X = -std::log(G4SampleUniform());
311  Y = -std::log(G4SampleUniform());
312  }
313 
315  return WattConstants_->L * X;
316 }
317 
320 {
322 
324 
326 
328 }
329 
332 {
334 
336  if(ShiftedMean == 0)
337  {
339  return FALSE;
340  }
341 
342  Mean_ = ShiftedMean;
343 
345  return TRUE;
346 }
347 
350 {
352 
353  G4double A, K;
354  A = K = 0;
355  // Use the default values if IsotopeIndex is not reset
356  G4int IsotopeIndex = 0;
357 
359  {
360  // Determine if the isotope requested exists in the lookup tables
361  for(G4int i = 0; SpontaneousWattIsotopesIndex[i] != -1; i++)
362  {
365  {
366  IsotopeIndex = i;
367 
368  break;
369  }
370  }
371 
372  // Get A and B
373  A = SpontaneousWattConstants[IsotopeIndex][0];
374  WattConstants_->B = SpontaneousWattConstants[IsotopeIndex][1];
376  {
377  // Determine if the isotope requested exists in the lookup tables
378  for(G4int i = 0; NeutronInducedWattIsotopesIndex[i] != -1; i++)
379  {
381  {
382  IsotopeIndex = i;
383  break;
384  }
385  }
386 
387  // Determine the Watt fission spectrum constants based on the energy of
388  // the incident neutron
390  {
391  A = NeutronInducedWattConstants[IsotopeIndex][0][0];
392  WattConstants_->B = NeutronInducedWattConstants[IsotopeIndex][0][1];
393  } else if (WattConstants_->Energy > 14.0 * MeV)
394  {
395  G4Exception("G4FPYSamplingOps::G4SampleWatt()",
396  "Incident neutron energy above 14 MeV requested.",
397  JustWarning,
398  "Using Watt fission constants for 14 Mev.");
399 
400  A = NeutronInducedWattConstants[IsotopeIndex][2][0];
401  WattConstants_->B = NeutronInducedWattConstants[IsotopeIndex][2][1];
402  } else
403  {
404  G4int EnergyIndex = 0;
405  G4double EnergyDifference = 0;
406  G4double RangeDifference, ConstantDifference;
407 
408  for(G4int i = 1; IncidentEnergyBins[i] != -1; i++)
409  {
411  {
412  EnergyIndex = i;
413  EnergyDifference = IncidentEnergyBins[EnergyIndex] - WattConstants_->Energy;
414  if(EnergyDifference != 0)
415  {
416  std::ostringstream Temp;
417  Temp << "Incident neutron energy of ";
418  Temp << WattConstants_->Energy << " MeV is not ";
419  Temp << "explicitly listed in the data tables";
420 // G4Exception("G4FPYSamplingOps::G4SampleWatt()",
421 // Temp.str().c_str(),
422 // JustWarning,
423 // "Using linear interpolation.");
424  }
425  break;
426  }
427  }
428 
429  RangeDifference = IncidentEnergyBins[EnergyIndex] - IncidentEnergyBins[EnergyIndex - 1];
430 
431  // Interpolate the value for 'a'
432  ConstantDifference =
433  NeutronInducedWattConstants[IsotopeIndex][EnergyIndex][0] -
434  NeutronInducedWattConstants[IsotopeIndex]
435  [EnergyIndex - 1][0];
436  A = (EnergyDifference / RangeDifference) * ConstantDifference +
437  NeutronInducedWattConstants[IsotopeIndex]
438  [EnergyIndex - 1][0];
439 
440  // Interpolate the value for 'b'
441  ConstantDifference =
442  NeutronInducedWattConstants[IsotopeIndex][EnergyIndex][1] -
443  NeutronInducedWattConstants[IsotopeIndex]
444  [EnergyIndex - 1][1];
445  WattConstants_->B =
446  (EnergyDifference / RangeDifference) * ConstantDifference +
447  NeutronInducedWattConstants[IsotopeIndex]
448  [EnergyIndex - 1][1];
449  }
450  } else
451  {
452  // Produce an error since an unsupported fission type was requested and
453  // abort the current run
454  G4String Temp = "Watt fission spectra data not available for ";
456  {
457  Temp += "proton induced fission.";
459  {
460  Temp += "gamma induced fission.";
461  } else
462  {
463  Temp += "!Warning! unknown cause.";
464  }
465  G4Exception("G4FPYSamplingOps::G4SampleWatt()",
466  Temp,
468  "Fission events will not be sampled in this run.");
469  }
470 
471  // Calculate the constants
472  K = 1 + (WattConstants_->B / (8.0 * A));
473  WattConstants_->L = (K + std::pow((K * K - 1), 0.5)) / A;
474  WattConstants_->M = A * WattConstants_->L - 1;
475 
477 }
478 
481 {
483 
485  {
487 
489  return GaussianTwo_;
490  }
491 
492  // Define the variables to be used
493  G4double Radius;
494  G4double MappingFactor;
495 
496  // Sample from the unit circle (21.4% rejection probability)
497  do
498  {
499  GaussianOne_ = 2.0 * G4SampleUniform() - 1.0;
500  GaussianTwo_ = 2.0 * G4SampleUniform() - 1.0;
502  } while (Radius > 1.0);
503 
504  // Translate the values to Gaussian space
505  MappingFactor = std::sqrt(-2.0*std::log(Radius)/Radius) * StdDev_;
506  GaussianOne_ = Mean_ + GaussianOne_*MappingFactor;
507  GaussianTwo_ = Mean_ + GaussianTwo_*MappingFactor;
508 
509  // Set the flag that a value is now stored in memory
511 
513  return GaussianOne_;
514 }
515 
518 {
520 
521  // Set the flag that any second value stored is no longer valid
523 
524  // Check if the requested parameters have already been calculated
525  if(CheckAndSetParameters() == TRUE)
526  {
528  return;
529  }
530 
531  // If the requested type is INT, then perform an iterative refinement of the
532  // mean that is going to be sampled
533  if(Type == G4FFGEnumerations::INT)
534  {
535  // Return if the mean is greater than 7 standard deviations away from 0
536  // since there is essentially 0 probability that a sampled number will
537  // be less than 0
538  if(Mean_ > 7 * StdDev_)
539  {
541  return;
542  }
543  // Variables that contain the area and weighted area information for
544  // calculating the statistical mean of the Gaussian distribution when
545  // converted to a step function
546  G4double ErfContainer, AdjustedErfContainer, Container;
547 
548  // Variables that store lower and upper bounds information
549  G4double LowErf, HighErf;
550 
551  // Values for determining the convergence of the solution
552  G4double AdjMean = Mean_;
553  G4double Delta = 1.0;
554  G4bool HalfDelta = false;
555  G4bool ToleranceCheck = false;
556 
557 
558  // Normalization constant for use with erf()
559  const G4double Normalization = StdDev_ * std::sqrt(2.0);
560 
561  // Determine the upper limit of the estimates
562  const G4int UpperLimit = (G4int) std::ceil(Mean_ + 9 * StdDev_);
563 
564  // Calculate the integral of the Gaussian distribution
565 
566  do
567  {
568  // Set the variables
569  ErfContainer = 0;
570  AdjustedErfContainer = 0;
571 
572  // Calculate the area and weighted area
573  for(G4int i = 0; i <= UpperLimit; i++)
574  {
575  // Determine the lower and upper bounds
576  LowErf = ((AdjMean - i) / Normalization);
577  HighErf = ((AdjMean - (i + 1.0)) / Normalization);
578 
579  // Correct the bounds for how they lie on the x-axis with
580  // respect to the mean
581  if(LowErf <= 0)
582  {
583  LowErf *= -1;
584  HighErf *= -1;
585  //Container = (erf(HighErf) - erf(LowErf))/2.0;
586  #if defined WIN32-VC
587  Container = (CLHEP::HepStat::erf(HighErf) - CLHEP::HepStat::erf(LowErf))/2.0;
588  #else
589  Container = (erf(HighErf) - erf(LowErf))/2.0;
590  #endif
591  } else if (HighErf < 0)
592  {
593  HighErf *= -1;
594 
595  //Container = (erf(HighErf) + erf(LowErf))/2.0;
596  #if defined WIN32-VC
597  Container = (CLHEP::HepStat::erf(HighErf) + CLHEP::HepStat::erf(LowErf))/2.0;
598  #else
599  Container = (erf(HighErf) + erf(LowErf))/2.0;
600  #endif
601  } else
602  {
603  //Container = (erf(LowErf) - erf(HighErf))/2.0;
604  #if defined WIN32-VC
605  Container = (CLHEP::HepStat::erf(LowErf) - CLHEP::HepStat::erf(HighErf))/2.0;
606  #else
607  Container = (erf(LowErf) - erf(HighErf))/2.0;
608  #endif
609  }
610 
611  // Add up the weighted area
612  ErfContainer += Container;
613  AdjustedErfContainer += Container * i;
614  }
615 
616  // Calculate the statistical mean
617  Container = AdjustedErfContainer / ErfContainer;
618 
619  // Is it close enough to what we want?
620  ToleranceCheck = (std::fabs(Mean_ - Container) < Tolerance_);
621  if(ToleranceCheck == TRUE)
622  {
623  break;
624  }
625 
626  // Determine the step size
627  if(HalfDelta == TRUE)
628  {
629  Delta /= 2;
630  }
631 
632  // Step in the appropriate direction
633  if(Container > Mean_)
634  {
635  AdjMean -= Delta;
636  } else
637  {
638  HalfDelta = TRUE;
639  AdjMean += Delta;
640  }
641  } while(TRUE);
642 
644  Mean_ = AdjMean;
645  } else if(Mean_ / 7 < StdDev_)
646  {
647  // If the requested type is double, then just re-define the standard
648  // deviation appropriately - chances are approximately 2.56E-12 that
649  // the value will be negative using this sampling scheme
650  StdDev_ = Mean_ / 7;
651  }
652 
654 }
655 
657 {
659 
660  delete ShiftedGaussianValues_;
661  delete WattConstants_;
662 
664 }
G4double G4SampleGaussian(G4double Mean, G4double StdDev)
Returns a double value taken from a Gaussian distribution about Mean and with a standard deviation of...
static const double MeV
Definition: G4SIunits.hh:193
static const G4double NeutronInducedWattConstants[][3][2]
Watt fission spectrum constants for neutron induced fission.
G4double SampleGaussian(void)
Samples a Gaussian distribution defined by the internal class variables NewMean_ and NewStdDev_...
~G4FPYSamplingOps(void)
Default deconstructor.
void EvaluateWattConstants(void)
Evaluates the constants that are required for the Watt fission spectrum sampling. ...
G4double G4SampleWatt(G4int WhatIsotope, G4FFGEnumerations::FissionCause WhatCause, G4double WhatEnergy)
Samples the Watt fission spectrum for the selected isotope, using an algorithm adopted from Ref...
WattSpectrumConstants contains constants and other variables for use in sampling the Watt fission spe...
#define G4FFG_SAMPLING_FUNCTIONENTER__
G4double G4SampleUniform(void)
Returns a double value evenly distributed in the range (0, 1].
G4double Energy
Energy, if any, of the incident particle that cause the fission.
static const G4double SpontaneousWattConstants[][2]
Watt fission spectrum constants for spontaneous fission.
G4double G4FindShiftedMean(G4double RequestedMean, G4double RequestedStdDev)
Returns the shifted mean that correlates to a RequestedMean and RequestedStdDev pair.
G4FFGEnumerations::FissionCause Cause
Fission cause for which the Watt fission spectrum is being sampled.
G4double StdDev_
Standard deviation for sampling a GaussianDistribution.
G4ShiftedGaussian * ShiftedGaussianValues_
Structure chain that contains the all the previous values used for sampling a Gaussian distribution...
int G4int
Definition: G4Types.hh:78
FissionCause
Causes of fission.
Verbosity
These are the verbosity levels.
G4double M
Sampling constant.
WattSpectrumConstants * WattConstants_
Structure that contains the values for sampling the Watt fission spectrum.
GaussianReturnType
Sample a discretized Gaussian distribution (INT) or continuous (DOUBLE)
void G4SetVerbosity(G4int WhatVerbosity)
Sets the verbosity levels.
G4int Product
Isotope code in ZZZAAA format for which the Watt fission spectrum is being sampled.
static const G4int SpontaneousWattIsotopesIndex[]
This table provides the indexing for SpontaneousWattConstants_.
G4double GaussianOne_
Contains the first of the two paired random numbers from the Gaussian distribution sampling...
bool G4bool
Definition: G4Types.hh:79
void G4InsertShiftedMean(G4double ShiftedMean, G4double RequestedMean, G4double RequestedStdDev)
Inserts a ShiftedMean indexed by the RequestedMean and RequestedStdDev.
void ShiftParameters(G4FFGEnumerations::GaussianReturnType Type)
Sets the mean and standard deviation of the Gaussian distribution sampled by this class when POSITIVE...
#define FALSE
Definition: globals.hh:52
G4double B
Sampling constant taken from the data tables.
G4int Verbosity_
Verbosity level.
#define TRUE
Definition: globals.hh:55
G4double GaussianTwo_
Contains the second of the two paired random numbers from the Gaussian distribution sampling...
static const G4double A[nN]
void Initialize(void)
Initialize is a common function called by all constructors.
GaussianRange
Truncate the Gaussian distribution at 0 (POSITIVE) or sample all values (ALL)
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *comments)
Definition: G4Exception.cc:41
static const G4int NeutronInducedWattIsotopesIndex[]
This table provides the indexing for NeutronInducedWattConstants_.
CLHEP::HepRandomEngine * RandomEngine_
Pointer to the CLHEP random number generator.
G4double Tolerance_
Defines the tolerance that ShiftParameters() must match.
#define G4FFG_FUNCTIONLEAVE__
G4double Mean_
Mean for sampling a Gaussian distribution.
G4double L
Sampling constant.
G4ShiftedGaussian is a class for storing the shifted values used for sampling a Gaussian distribution...
#define G4FFG_SAMPLING_FUNCTIONLEAVE__
double G4double
Definition: G4Types.hh:76
void G4SetVerbosity(G4int WhatVerbosity)
Sets the verbosity levels.
G4FPYSamplingOps(void)
Default constructor.
static const G4double IncidentEnergyBins[]
These are the energy values in MeV for the neutron induced Watt fission spectrum constants.
static const G4double ThermalNeutronEnergy
The energy of thermal neutrons.
G4bool CheckAndSetParameters(void)
Check to see if the user requested parameters have already been calculated.
#define G4FFG_FUNCTIONENTER__
static const G4FFGEnumerations::Verbosity Verbosity
Verbosity for the entire package.
G4bool NextGaussianIsStoredInMemory_
Declares whether the second paired random number has been already returned.
G4int G4SampleIntegerGaussian(G4double Mean, G4double StdDev)
Returns an integer value taken from a Gaussian distribution.