Geant4  10.03.p01
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
G4PolynomialPDF Class Reference

#include <G4PolynomialPDF.hh>

Public Member Functions

 G4PolynomialPDF (size_t n=0, const double *coeffs=nullptr, G4double x1=0, G4double x2=1)
 
 ~G4PolynomialPDF ()
 
void SetNCoefficients (size_t n)
 
size_t GetNCoefficients () const
 
void SetCoefficients (const std::vector< G4double > &v)
 
G4double GetCoefficient (size_t i) const
 
void SetCoefficient (size_t i, G4double value)
 
void SetCoefficients (size_t n, const G4double *coeffs)
 
void SetDomain (G4double x1, G4double x2)
 
void Normalize ()
 
G4double Evaluate (G4double x, G4int ddxPower=0)
 
G4double GetRandomX ()
 
void SetTolerance (G4double tolerance)
 
G4double GetX (G4double p, G4double x1, G4double x2, G4int ddxPower=0, G4double guess=1.e99, G4bool bisect=true)
 
G4double EvalInverseCDF (G4double p)
 
G4double Bisect (G4double p, G4double x1, G4double x2)
 
void Dump ()
 

Protected Member Functions

G4bool HasNegativeMinimum (G4double x1, G4double x2)
 

Protected Attributes

G4double fX1
 
G4double fX2
 
std::vector< G4doublefCoefficients
 
G4bool fChanged
 
G4double fTolerance
 
G4int fVerbose
 

Detailed Description

Definition at line 49 of file G4PolynomialPDF.hh.

Constructor & Destructor Documentation

G4PolynomialPDF::G4PolynomialPDF ( size_t  n = 0,
const double *  coeffs = nullptr,
G4double  x1 = 0,
G4double  x2 = 1 
)

Definition at line 43 of file G4PolynomialPDF.cc.

44  :
45  fX1(x1), fX2(x2), fChanged(true), fTolerance(1.e-8), fVerbose(0)
46 {
47  if(coeffs != nullptr) SetCoefficients(n, coeffs);
48  else if(n > 0) SetNCoefficients(n);
49 }
void SetCoefficients(const std::vector< G4double > &v)
void SetNCoefficients(size_t n)

Here is the call graph for this function:

G4PolynomialPDF::~G4PolynomialPDF ( )

Definition at line 51 of file G4PolynomialPDF.cc.

52 {}

Member Function Documentation

G4double G4PolynomialPDF::Bisect ( G4double  p,
G4double  x1,
G4double  x2 
)

Definition at line 363 of file G4PolynomialPDF.cc.

363  {
364  // Bisect to get 1% precision, then use Newton-Raphson
365  G4double z = (x2 + x1)/2.0; // [x1 z x2]
366  if((x2 - x1)/(fX2 - fX1) < 0.01) return GetX(p, fX1, fX2, -1, z, false);
367  G4double fz = Evaluate(z, -1) - p;
368  if(fz < 0) return Bisect(p, z, x2); // [z x2]
369  return Bisect(p, x1, z); // [x1 z]
370 }
const char * p
Definition: xmltok.h:285
G4double GetX(G4double p, G4double x1, G4double x2, G4int ddxPower=0, G4double guess=1.e99, G4bool bisect=true)
G4double Bisect(G4double p, G4double x1, G4double x2)
G4double Evaluate(G4double x, G4int ddxPower=0)
double G4double
Definition: G4Types.hh:76

Here is the call graph for this function:

Here is the caller graph for this function:

void G4PolynomialPDF::Dump ( )

Definition at line 372 of file G4PolynomialPDF.cc.

373 {
374  G4cout << "G4PolynomialPDF::Dump() - PDF(x) = ";
375  for(size_t i=0; i<GetNCoefficients(); i++) {
376  if(i>0) G4cout << " + ";
377  G4cout << GetCoefficient(i);
378  if(i>0) G4cout << "*x";
379  if(i>1) G4cout << "^" << i;
380  }
381  G4cout << G4endl;
382  G4cout << "G4PolynomialPDF::Dump() - Interval: " << fX1 << " <= x < "
383  << fX2 << G4endl;
384 }
G4GLOB_DLL std::ostream G4cout
G4double GetCoefficient(size_t i) const
size_t GetNCoefficients() const
#define G4endl
Definition: G4ios.hh:61

Here is the call graph for this function:

Here is the caller graph for this function:

G4double G4PolynomialPDF::EvalInverseCDF ( G4double  p)
inline

Definition at line 99 of file G4PolynomialPDF.hh.

99 { return GetX(p, fX1, fX2, -1, fX1 + p*(fX2-fX1)); }
const char * p
Definition: xmltok.h:285
G4double GetX(G4double p, G4double x1, G4double x2, G4int ddxPower=0, G4double guess=1.e99, G4bool bisect=true)

Here is the call graph for this function:

Here is the caller graph for this function:

G4double G4PolynomialPDF::Evaluate ( G4double  x,
G4int  ddxPower = 0 
)

Evaluate f(x) ddxPower = -1: f = CDF ddxPower = 0: f = PDF ddxPower = 1: f = (d/dx) PDF ddxPower = 2: f = (d2/dx2) PDF

Definition at line 116 of file G4PolynomialPDF.cc.

117 {
123  if(ddxPower < -1 || ddxPower > 2) {
124  if(fVerbose > 0) {
125  G4cout << "G4PolynomialPDF::GetX() WARNING: ddxPower " << ddxPower
126  << " not implemented" << G4endl;
127  }
128  return 0.0;
129  }
130 
131  double f = 0.; // return value
132  double xN = 1.; // x to the power N
133  double x1N = 1.; // endpoint x1 to the power N; only used by CDF
134  for(size_t i=0; i<=GetNCoefficients(); ++i) {
135  if(ddxPower == -1) { // CDF
136  if(i>0) f += GetCoefficient(i-1)*(xN - x1N)/i;
137  x1N *= fX1;
138  }
139  else if(ddxPower == 0 && i<GetNCoefficients()) f += GetCoefficient(i)*xN; // PDF
140  else if(ddxPower == 1) { // (d/dx) PDF
141  if(i<GetNCoefficients()-1) f += GetCoefficient(i+1)*xN*(i+1);
142  }
143  else if(ddxPower == 2) { // (d2/dx2) PDF
144  if(i<GetNCoefficients()-2) f += GetCoefficient(i+2)*xN*((i+2)*(i+1));
145  }
146  xN *= x;
147  }
148  return f;
149 }
G4GLOB_DLL std::ostream G4cout
G4double GetCoefficient(size_t i) const
size_t GetNCoefficients() const
#define G4endl
Definition: G4ios.hh:61

Here is the call graph for this function:

Here is the caller graph for this function:

G4double G4PolynomialPDF::GetCoefficient ( size_t  i) const
inline

Definition at line 60 of file G4PolynomialPDF.hh.

60 { return fCoefficients[i]; }
std::vector< G4double > fCoefficients

Here is the caller graph for this function:

size_t G4PolynomialPDF::GetNCoefficients ( ) const
inline

Definition at line 58 of file G4PolynomialPDF.hh.

58 { return fCoefficients.size(); }
std::vector< G4double > fCoefficients

Here is the caller graph for this function:

G4double G4PolynomialPDF::GetRandomX ( )

Definition at line 192 of file G4PolynomialPDF.cc.

193 {
194  if(fChanged) {
195  Normalize();
196  if(HasNegativeMinimum(fX1, fX2)) {
197  if(fVerbose > 0) {
198  G4cout << "G4PolynomialPDF::GetRandomX() WARNING: PDF has negative values, returning 0..."
199  << G4endl;
200  }
201  return 0.0;
202  }
203  fChanged = false;
204  }
205  return EvalInverseCDF(G4UniformRand());
206 }
#define G4UniformRand()
Definition: Randomize.hh:97
G4GLOB_DLL std::ostream G4cout
G4bool HasNegativeMinimum(G4double x1, G4double x2)
#define G4endl
Definition: G4ios.hh:61
G4double EvalInverseCDF(G4double p)

Here is the call graph for this function:

Here is the caller graph for this function:

G4double G4PolynomialPDF::GetX ( G4double  p,
G4double  x1,
G4double  x2,
G4int  ddxPower = 0,
G4double  guess = 1.e99,
G4bool  bisect = true 
)

Find a value of X between x1 and x2 at which f(x) = p. ddxPower = -1: f = CDF ddxPower = 0: f = PDF ddxPower = 1: f = (d/dx) PDF Uses the Newton-Raphson method to find the zero of f(x) - p. If not found in range, returns the nearest boundary

Definition at line 208 of file G4PolynomialPDF.cc.

210 {
217 
218  // input range checking
219  if(GetNCoefficients() == 0) {
220  if(fVerbose > 0) {
221  G4cout << "G4PolynomialPDF::GetX() WARNING: no PDF defined!" << G4endl;
222  }
223  return x2;
224  }
225  if(ddxPower < -1 || ddxPower > 1) {
226  if(fVerbose > 0) {
227  G4cout << "G4PolynomialPDF::GetX() WARNING: ddxPower " << ddxPower
228  << " not implemented" << G4endl;
229  }
230  return x2;
231  }
232  if(ddxPower == -1 && (p<0 || p>1)) {
233  if(fVerbose > 0) {
234  G4cout << "G4PolynomialPDF::GetX() WARNING: p is out of range" << G4endl;
235  }
236  return fX2;
237  }
238 
239  // check limits
240  if(x2 <= x1 || x1 < fX1 || x2 > fX2) {
241  if(fVerbose > 0) {
242  G4cout << "G4PolynomialPDF::GetX() WARNING: domain must have fX1 <= x1 < x2 <= fX2. "
243  << "You sent x1 = " << x1 << ", x2 = " << x2 << "." << G4endl;
244  }
245  return x2;
246  }
247 
248  // Return x2 for flat lines
249  if((ddxPower == 0 && GetNCoefficients() == 1) ||
250  (ddxPower == 1 && GetNCoefficients() == 2)) return x2;
251 
252  // Solve p = mx + b -> x = (p-b)/m for linear functions
253  if((ddxPower == -1 && GetNCoefficients() == 1) ||
254  (ddxPower == 0 && GetNCoefficients() == 2) ||
255  (ddxPower == 1 && GetNCoefficients() == 3)) {
256  G4double b = (ddxPower > -1) ? GetCoefficient(ddxPower) : -GetCoefficient(0)*fX1;
257  G4double slope = GetCoefficient(ddxPower+1);
258  if(ddxPower == 1) slope *= 2.;
259  G4double value = (p-b)/slope;
260  if(value < x1) {
261  return x1;
262  }
263  else if(value > x2) {
264  return x2;
265  }
266  else {
267  return value;
268  }
269  }
270 
271  // Solve quadratic equation for f-p=0 when f is quadratic
272  if((ddxPower == -1 && GetNCoefficients() == 2) ||
273  (ddxPower == 0 && GetNCoefficients() == 3) ||
274  (ddxPower == 1 && GetNCoefficients() == 4)) {
275  G4double c = -p + ((ddxPower > -1) ? GetCoefficient(ddxPower) : 0);
276  if(ddxPower == -1) c -= (GetCoefficient(0) + GetCoefficient(1)/2.*fX1)*fX1;
277  G4double b = GetCoefficient(ddxPower+1);
278  if(ddxPower == 1) b *= 2.;
279  G4double a = GetCoefficient(ddxPower+2);
280  if(ddxPower == 1) a *= 3;
281  else if(ddxPower == -1) a *= 0.5;
282  double sqrtFactor = b*b - 4.*a*c;
283  if(sqrtFactor < 0) return x2; // quadratic equation has no solution (p not in range of f)
284  sqrtFactor = sqrt(sqrtFactor)/2./fabs(a);
285  G4double valueMinus = -b/2./a - sqrtFactor;
286  if(valueMinus >= x1 && valueMinus <= x2) return valueMinus;
287  else if(valueMinus > x2) return x2;
288  G4double valuePlus = -b/2./a + sqrtFactor;
289  if(valuePlus >= x1 && valuePlus <= x2) return valuePlus;
290  else if(valuePlus < x1) return x2;
291  return (x1-valueMinus <= valuePlus-x2) ? x1 : x2;
292  }
293 
294  // f is non-trivial, so use Newton-Raphson
295  // start in the middle if no good guess is provided
296  if(guess < x1 || guess > x2) guess = (x2+x1)*0.5;
297  G4double lastChange = 1;
298  size_t iterations = 0;
299  while(fabs(lastChange) > fTolerance) { /* Loop checking, 02.11.2015, A.Ribon */
300  // calculate f and f' simultaneously
301  G4double f = -p;
302  G4double dfdx = 0;
303  G4double xN = 1;
304  G4double x1N = 1; // only used by CDF
305  for(size_t i=0; i<=GetNCoefficients(); ++i) {
306  if(ddxPower == -1) { // CDF
307  if(i>0) f += GetCoefficient(i-1)*(xN - x1N)/G4double(i);
308  if(i<GetNCoefficients()) dfdx += GetCoefficient(i)*xN;
309  x1N *= fX1;
310  }
311  else if(ddxPower == 0) { // PDF
312  if(i<GetNCoefficients()) f += GetCoefficient(i)*xN;
313  if(i+1<GetNCoefficients()) dfdx += GetCoefficient(i+1)*xN*G4double(i+1);
314  }
315  else { // ddxPower == 1: (d/dx) PDF
316  if(i+1<GetNCoefficients()) f += GetCoefficient(i+1)*xN*G4double(i+1);
317  if(i+2<GetNCoefficients()) dfdx += GetCoefficient(i+2)*xN*G4double(i+2);
318  }
319  xN *= guess;
320  }
321  if(f == 0) return guess;
322  if(dfdx == 0) {
323  if(fVerbose > 0) {
324  G4cout << "G4PolynomialPDF::GetX() WARNING: got f != 0 but slope = 0 for ddxPower = "
325  << ddxPower << G4endl;
326  }
327  return x2;
328  }
329  lastChange = - f/dfdx;
330 
331  if(guess + lastChange < x1) {
332  lastChange = x1 - guess;
333  } else if(guess + lastChange > x2) {
334  lastChange = x2 - guess;
335  }
336 
337  guess += lastChange;
338  lastChange /= (fX2-fX1);
339 
340  ++iterations;
341  if(iterations > 50) {
342  if(p!=0) {
343  if(fVerbose > 0) {
344  G4cout << "G4PolynomialPDF::GetX() WARNING: got stuck searching for " << p
345  << " between " << x1 << " and " << x2 << " with ddxPower = "
346  << ddxPower
347  << ". Last guess was " << guess << "." << G4endl;
348  }
349  }
350  if(ddxPower==-1 && bisect) {
351  if(fVerbose > 0) {
352  G4cout << "G4PolynomialPDF::GetX() WARNING: Bisceting and trying again..."
353  << G4endl;
354  }
355  return Bisect(p, x1, x2);
356  }
357  else return guess;
358  }
359  }
360  return guess;
361 }
const char * p
Definition: xmltok.h:285
G4double Bisect(G4double p, G4double x1, G4double x2)
G4GLOB_DLL std::ostream G4cout
G4double GetCoefficient(size_t i) const
const XML_Char int const XML_Char * value
Definition: expat.h:331
size_t GetNCoefficients() const
#define G4endl
Definition: G4ios.hh:61
double G4double
Definition: G4Types.hh:76

Here is the call graph for this function:

Here is the caller graph for this function:

G4bool G4PolynomialPDF::HasNegativeMinimum ( G4double  x1,
G4double  x2 
)
protected

Definition at line 151 of file G4PolynomialPDF.cc.

152 {
153  // ax2 + bx + c = 0
154  // p': 2ax + b = 0 -> = 0 at min: x_extreme = -b/2a
155 
156  if(x1 < fX1 || x2 > fX2 || x2 < x1) {
157  if(fVerbose > 0) {
158  G4cout << "G4PolynomialPDF::HasNegativeMinimum() WARNING: Invalid range "
159  << x1 << " - " << x2 << G4endl;
160  }
161  return false;
162  }
163 
164  // If flat, then check anywhere.
165  if(GetNCoefficients() == 1) return (Evaluate(x1) < -fTolerance);
166 
167  // If linear, or if quadratic with negative second derivative,
168  // just check the endpoints
169  if(GetNCoefficients() == 2 ||
170  (GetNCoefficients() == 3 && GetCoefficient(2) < 0)) {
171  return (Evaluate(x1) < -fTolerance) || (Evaluate(x2) < -fTolerance);
172  }
173 
174  // If quadratic and second dervative is positive, check at the mininum
175  if(GetNCoefficients() == 3) {
176  G4double xMin = -GetCoefficient(1)*0.5/GetCoefficient(2);
177  if(xMin < x1) xMin = x1;
178  if(xMin > x2) xMin = x2;
179  return Evaluate(xMin) < -fTolerance;
180  }
181 
182  // Higher-order polynomials: consider any extremum between x1 and x2. If none
183  // are found, check the endpoints.
184  G4double extremum = GetX(0, x1, x2, 1);
185  if(Evaluate(extremum) < -fTolerance) return true;
186  else if(extremum <= x1+(x2-x1)*fTolerance ||
187  extremum >= x2-(x2-x1)*fTolerance) return false;
188  else return
189  HasNegativeMinimum(x1, extremum) || HasNegativeMinimum(extremum, x2);
190 }
G4double GetX(G4double p, G4double x1, G4double x2, G4int ddxPower=0, G4double guess=1.e99, G4bool bisect=true)
G4GLOB_DLL std::ostream G4cout
G4double GetCoefficient(size_t i) const
G4bool HasNegativeMinimum(G4double x1, G4double x2)
size_t GetNCoefficients() const
#define G4endl
Definition: G4ios.hh:61
G4double Evaluate(G4double x, G4int ddxPower=0)
double G4double
Definition: G4Types.hh:76

Here is the call graph for this function:

Here is the caller graph for this function:

void G4PolynomialPDF::Normalize ( )

Normalize PDF to 1 over domain fX1 to fX2. Double-check that the highest-order coefficient is non-zero.

Definition at line 86 of file G4PolynomialPDF.cc.

87 {
90  while(fCoefficients.size()) { /* Loop checking, 30-Oct-2015, G.Folger */
91  if(fCoefficients[fCoefficients.size()-1] == 0.0) fCoefficients.pop_back();
92  else break;
93  }
94 
95  G4double x1N = fX1, x2N = fX2;
96  G4double sum = 0;
97  for(size_t i=0; i<GetNCoefficients(); ++i) {
98  sum += GetCoefficient(i)*(x2N - x1N)/G4double(i+1);
99  x1N*=fX1;
100  x2N*=fX2;
101  }
102  if(sum <= 0) {
103  if(fVerbose > 0) {
104  G4cout << "G4PolynomialPDF::Normalize() WARNING: PDF has non-positive area: "
105  << sum << G4endl;
106  Dump();
107  }
108  return;
109  }
110 
111  for(size_t i=0; i<GetNCoefficients(); ++i) {
112  SetCoefficient(i, GetCoefficient(i)/sum);
113  }
114 }
std::vector< G4double > fCoefficients
G4GLOB_DLL std::ostream G4cout
G4double GetCoefficient(size_t i) const
void SetCoefficient(size_t i, G4double value)
size_t GetNCoefficients() const
#define G4endl
Definition: G4ios.hh:61
double G4double
Definition: G4Types.hh:76

Here is the call graph for this function:

Here is the caller graph for this function:

void G4PolynomialPDF::SetCoefficient ( size_t  i,
G4double  value 
)

Definition at line 54 of file G4PolynomialPDF.cc.

55 {
56  while(i >= fCoefficients.size()) fCoefficients.push_back(0);
57  /* Loop checking, 30-Oct-2015, G.Folger */
58  fCoefficients[i] = value;
59  fChanged = true;
60 }
std::vector< G4double > fCoefficients
const XML_Char int const XML_Char * value
Definition: expat.h:331

Here is the caller graph for this function:

void G4PolynomialPDF::SetCoefficients ( const std::vector< G4double > &  v)
inline

Definition at line 59 of file G4PolynomialPDF.hh.

59 { fCoefficients = v; }
std::vector< G4double > fCoefficients

Here is the caller graph for this function:

void G4PolynomialPDF::SetCoefficients ( size_t  n,
const G4double coeffs 
)

Definition at line 62 of file G4PolynomialPDF.cc.

64 {
65  SetNCoefficients(nCoeffs);
66  for(size_t i=0; i<GetNCoefficients(); ++i) {
67  SetCoefficient(i, coefficients[i]);
68  }
69  fChanged = true;
70 }
void SetNCoefficients(size_t n)
void SetCoefficient(size_t i, G4double value)
size_t GetNCoefficients() const

Here is the call graph for this function:

void G4PolynomialPDF::SetDomain ( G4double  x1,
G4double  x2 
)

Definition at line 72 of file G4PolynomialPDF.cc.

73 {
74  if(x2 <= x1) {
75  if(fVerbose > 0) {
76  G4cout << "G4PolynomialPDF::SetDomain() WARNING: Invalide domain! "
77  << "(x1 = " << x1 << ", x2 = " << x2 << ")." << G4endl;
78  }
79  return;
80  }
81  fX1 = x1;
82  fX2 = x2;
83  fChanged = true;
84 }
G4GLOB_DLL std::ostream G4cout
#define G4endl
Definition: G4ios.hh:61
void G4PolynomialPDF::SetNCoefficients ( size_t  n)
inline

Definition at line 57 of file G4PolynomialPDF.hh.

57 { fCoefficients.resize(n); fChanged = true; }
std::vector< G4double > fCoefficients

Here is the caller graph for this function:

void G4PolynomialPDF::SetTolerance ( G4double  tolerance)
inline

Definition at line 84 of file G4PolynomialPDF.hh.

84 { fTolerance = tolerance; }

Member Data Documentation

G4bool G4PolynomialPDF::fChanged
protected

Definition at line 111 of file G4PolynomialPDF.hh.

std::vector<G4double> G4PolynomialPDF::fCoefficients
protected

Definition at line 110 of file G4PolynomialPDF.hh.

G4double G4PolynomialPDF::fTolerance
protected

Definition at line 112 of file G4PolynomialPDF.hh.

G4int G4PolynomialPDF::fVerbose
protected

Definition at line 113 of file G4PolynomialPDF.hh.

G4double G4PolynomialPDF::fX1
protected

Definition at line 108 of file G4PolynomialPDF.hh.

G4double G4PolynomialPDF::fX2
protected

Definition at line 109 of file G4PolynomialPDF.hh.


The documentation for this class was generated from the following files: