Geant4-11
Public Member Functions | Protected Member Functions | Protected Attributes
G4PolynomialPDF Class Reference

#include <G4PolynomialPDF.hh>

Public Member Functions

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

Protected Member Functions

G4bool HasNegativeMinimum (G4double x1, G4double x2)
 

Protected Attributes

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

Detailed Description

Definition at line 49 of file G4PolynomialPDF.hh.

Constructor & Destructor Documentation

◆ G4PolynomialPDF()

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 SetNCoefficients(size_t n)
void SetCoefficients(const std::vector< G4double > &v)

References CLHEP::detail::n, SetCoefficients(), and SetNCoefficients().

◆ ~G4PolynomialPDF()

G4PolynomialPDF::~G4PolynomialPDF ( )

Definition at line 51 of file G4PolynomialPDF.cc.

52{}

Member Function Documentation

◆ Bisect()

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

Definition at line 392 of file G4PolynomialPDF.cc.

392 {
393 // Bisect to get 1% precision, then use Newton-Raphson
394 G4double z = (x2 + x1)/2.0; // [x1 z x2]
395 if((x2 - x1)/(fX2 - fX1) < 0.01) return GetX(p, fX1, fX2, -1, z, false);
396 G4double fz = Evaluate(z, -1) - p;
397 if(fz < 0) return Bisect(p, z, x2); // [z x2]
398 return Bisect(p, x1, z); // [x1 z]
399}
double G4double
Definition: G4Types.hh:83
G4double Evaluate(G4double x, G4int ddxPower=0)
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)

References Bisect(), Evaluate(), fX1, fX2, and GetX().

Referenced by Bisect(), and GetX().

◆ Dump()

void G4PolynomialPDF::Dump ( )

Definition at line 401 of file G4PolynomialPDF.cc.

402{
403 G4cout << "G4PolynomialPDF::Dump() - PDF(x) = ";
404 for(size_t i=0; i<GetNCoefficients(); i++) {
405 if(i>0) G4cout << " + ";
407 if(i>0) G4cout << "*x";
408 if(i>1) G4cout << "^" << i;
409 }
410 G4cout << G4endl;
411 G4cout << "G4PolynomialPDF::Dump() - Interval: " << fX1 << " <= x < "
412 << fX2 << G4endl;
413}
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
size_t GetNCoefficients() const
G4double GetCoefficient(size_t i) const

References fX1, fX2, G4cout, G4endl, GetCoefficient(), and GetNCoefficients().

Referenced by Normalize().

◆ EvalInverseCDF()

G4double G4PolynomialPDF::EvalInverseCDF ( G4double  p)
inline

Definition at line 102 of file G4PolynomialPDF.hh.

102{ return GetX(p, fX1, fX2, -1, fX1 + p*(fX2-fX1)); }

References fX1, fX2, and GetX().

Referenced by GetRandomX().

◆ Evaluate()

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 131 of file G4PolynomialPDF.cc.

132{
138 if(ddxPower < -1 || ddxPower > 2) {
139 if(fVerbose > 0) {
140 G4cout << "G4PolynomialPDF::GetX() WARNING: ddxPower " << ddxPower
141 << " not implemented" << G4endl;
142 }
143 return 0.0;
144 }
145
146 double f = 0.; // return value
147 double xN = 1.; // x to the power N
148 double x1N = 1.; // endpoint x1 to the power N; only used by CDF
149 for(size_t i=0; i<=GetNCoefficients(); ++i) {
150 if(ddxPower == -1) { // CDF
151 if(i>0) f += GetCoefficient(i-1)*(xN - x1N)/i;
152 x1N *= fX1;
153 }
154 else if(ddxPower == 0 && i<GetNCoefficients()) f += GetCoefficient(i)*xN; // PDF
155 else if(ddxPower == 1) { // (d/dx) PDF
156 if(i<GetNCoefficients()-1) f += GetCoefficient(i+1)*xN*(i+1);
157 }
158 else if(ddxPower == 2) { // (d2/dx2) PDF
159 if(i<GetNCoefficients()-2) f += GetCoefficient(i+2)*xN*((i+2)*(i+1));
160 }
161 xN *= x;
162 }
163 return f;
164}

References fVerbose, fX1, G4cout, G4endl, GetCoefficient(), and GetNCoefficients().

Referenced by Bisect(), and HasNegativeMinimum().

◆ GetCoefficient()

G4double G4PolynomialPDF::GetCoefficient ( size_t  i) const
inline

Definition at line 62 of file G4PolynomialPDF.hh.

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

References fCoefficients.

Referenced by Dump(), Evaluate(), GetX(), HasNegativeMinimum(), and Normalize().

◆ GetNCoefficients()

size_t G4PolynomialPDF::GetNCoefficients ( ) const
inline

Definition at line 58 of file G4PolynomialPDF.hh.

58{ return fCoefficients.size(); }

References fCoefficients.

Referenced by Dump(), Evaluate(), GetX(), HasNegativeMinimum(), Normalize(), and SetCoefficients().

◆ GetRandomX()

G4double G4PolynomialPDF::GetRandomX ( )

Definition at line 207 of file G4PolynomialPDF.cc.

208{
209 if(fChanged) {
210 Normalize();
212 if(fVerbose > 0) {
213 G4cout << "G4PolynomialPDF::GetRandomX() WARNING: PDF has negative values, returning 0..."
214 << G4endl;
215 }
216 return 0.0;
217 }
218 fChanged = false;
219 }
221}
#define G4UniformRand()
Definition: Randomize.hh:52
G4bool HasNegativeMinimum(G4double x1, G4double x2)
G4double EvalInverseCDF(G4double p)

References EvalInverseCDF(), fChanged, fVerbose, fX1, fX2, G4cout, G4endl, G4UniformRand, HasNegativeMinimum(), and Normalize().

Referenced by G4PolarizationTransition::GenerateGammaCosTheta().

◆ GetX()

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 223 of file G4PolynomialPDF.cc.

225{
232
233 // input range checking
234 if(GetNCoefficients() == 0) {
235 if(fVerbose > 0) {
236 G4cout << "G4PolynomialPDF::GetX() WARNING: no PDF defined!" << G4endl;
237 }
238 return x2;
239 }
240 if(ddxPower < -1 || ddxPower > 1) {
241 if(fVerbose > 0) {
242 G4cout << "G4PolynomialPDF::GetX() WARNING: ddxPower " << ddxPower
243 << " not implemented" << G4endl;
244 }
245 return x2;
246 }
247 if(ddxPower == -1 && (p<0 || p>1)) {
248 if(fVerbose > 0) {
249 G4cout << "G4PolynomialPDF::GetX() WARNING: p is out of range" << G4endl;
250 }
251 return fX2;
252 }
253
254 // check limits
255 if(x2 <= x1 || x1 < fX1 || x2 > fX2) {
256 if(fVerbose > 0) {
257 G4cout << "G4PolynomialPDF::GetX() WARNING: domain must have fX1 <= x1 < x2 <= fX2. "
258 << "You sent x1 = " << x1 << ", x2 = " << x2 << "." << G4endl;
259 }
260 return x2;
261 }
262
263 // Return x2 for flat lines
264 if((ddxPower == 0 && GetNCoefficients() == 1) ||
265 (ddxPower == 1 && GetNCoefficients() == 2)) return x2;
266
267 // Solve p = mx + b -> x = (p-b)/m for linear functions
268 if((ddxPower == -1 && GetNCoefficients() == 1) ||
269 (ddxPower == 0 && GetNCoefficients() == 2) ||
270 (ddxPower == 1 && GetNCoefficients() == 3)) {
271 G4double b = (ddxPower > -1) ? GetCoefficient(ddxPower) : -GetCoefficient(0)*fX1;
272 G4double slope = GetCoefficient(ddxPower+1); // the highest-order coefficient
273 if(slope == 0) { // the highest-order coefficient should never be zero if simplified
274 if(fVerbose > 0) {
275 G4cout << "G4PolynomialPDF::GetX() WARNING: Got slope = 0. "
276 << "Did you forget to Simplify()?" << G4endl;
277 }
278 return x2;
279 }
280 if(ddxPower == 1) slope *= 2.;
281 G4double value = (p-b)/slope;
282 if(value < x1) {
283 return x1;
284 }
285 else if(value > x2) {
286 return x2;
287 }
288 else {
289 return value;
290 }
291 }
292
293 // Solve quadratic equation for f-p=0 when f is quadratic
294 if((ddxPower == -1 && GetNCoefficients() == 2) ||
295 (ddxPower == 0 && GetNCoefficients() == 3) ||
296 (ddxPower == 1 && GetNCoefficients() == 4)) {
297 G4double c = -p + ((ddxPower > -1) ? GetCoefficient(ddxPower) : 0);
298 if(ddxPower == -1) c -= (GetCoefficient(0) + GetCoefficient(1)/2.*fX1)*fX1;
299 G4double b = GetCoefficient(ddxPower+1);
300 if(ddxPower == 1) b *= 2.;
301 G4double a = GetCoefficient(ddxPower+2); // the highest-order coefficient
302 if(a == 0) { // the highest-order coefficient should never be 0 if simplified
303 if(fVerbose > 0) {
304 G4cout << "G4PolynomialPDF::GetX() WARNING: Got a = 0. "
305 << "Did you forget to Simplify()?" << G4endl;
306 }
307 return x2;
308 }
309 if(ddxPower == 1) a *= 3;
310 else if(ddxPower == -1) a *= 0.5;
311 double sqrtFactor = b*b - 4.*a*c;
312 if(sqrtFactor < 0) return x2; // quadratic equation has no solution (p not in range of f)
313 sqrtFactor = sqrt(sqrtFactor)/2./fabs(a);
314 G4double valueMinus = -b/2./a - sqrtFactor;
315 if(valueMinus >= x1 && valueMinus <= x2) return valueMinus;
316 else if(valueMinus > x2) return x2;
317 G4double valuePlus = -b/2./a + sqrtFactor;
318 if(valuePlus >= x1 && valuePlus <= x2) return valuePlus;
319 else if(valuePlus < x1) return x2;
320 return (x1-valueMinus <= valuePlus-x2) ? x1 : x2;
321 }
322
323 // f is non-trivial, so use Newton-Raphson
324 // start in the middle if no good guess is provided
325 if(guess < x1 || guess > x2) guess = (x2+x1)*0.5;
326 G4double lastChange = 1;
327 size_t iterations = 0;
328 while(fabs(lastChange) > fTolerance) { /* Loop checking, 02.11.2015, A.Ribon */
329 // calculate f and f' simultaneously
330 G4double f = -p;
331 G4double dfdx = 0;
332 G4double xN = 1;
333 G4double x1N = 1; // only used by CDF
334 for(size_t i=0; i<=GetNCoefficients(); ++i) {
335 if(ddxPower == -1) { // CDF
336 if(i>0) f += GetCoefficient(i-1)*(xN - x1N)/G4double(i);
337 if(i<GetNCoefficients()) dfdx += GetCoefficient(i)*xN;
338 x1N *= fX1;
339 }
340 else if(ddxPower == 0) { // PDF
341 if(i<GetNCoefficients()) f += GetCoefficient(i)*xN;
342 if(i+1<GetNCoefficients()) dfdx += GetCoefficient(i+1)*xN*G4double(i+1);
343 }
344 else { // ddxPower == 1: (d/dx) PDF
345 if(i+1<GetNCoefficients()) f += GetCoefficient(i+1)*xN*G4double(i+1);
346 if(i+2<GetNCoefficients()) dfdx += GetCoefficient(i+2)*xN*G4double(i+2);
347 }
348 xN *= guess;
349 }
350 if(f == 0) return guess;
351 if(dfdx == 0) {
352 if(fVerbose > 0) {
353 G4cout << "G4PolynomialPDF::GetX() WARNING: got f != 0 but slope = 0 for ddxPower = "
354 << ddxPower << G4endl;
355 }
356 return x2;
357 }
358 lastChange = - f/dfdx;
359
360 if(guess + lastChange < x1) {
361 lastChange = x1 - guess;
362 } else if(guess + lastChange > x2) {
363 lastChange = x2 - guess;
364 }
365
366 guess += lastChange;
367 lastChange /= (fX2-fX1);
368
369 ++iterations;
370 if(iterations > 50) {
371 if(p!=0) {
372 if(fVerbose > 0) {
373 G4cout << "G4PolynomialPDF::GetX() WARNING: got stuck searching for " << p
374 << " between " << x1 << " and " << x2 << " with ddxPower = "
375 << ddxPower
376 << ". Last guess was " << guess << "." << G4endl;
377 }
378 }
379 if(ddxPower==-1 && bisect) {
380 if(fVerbose > 0) {
381 G4cout << "G4PolynomialPDF::GetX() WARNING: Biseting and trying again..."
382 << G4endl;
383 }
384 return Bisect(p, x1, x2);
385 }
386 else return guess;
387 }
388 }
389 return guess;
390}

References Bisect(), fTolerance, fVerbose, fX1, fX2, G4cout, G4endl, GetCoefficient(), and GetNCoefficients().

Referenced by Bisect(), EvalInverseCDF(), and HasNegativeMinimum().

◆ HasNegativeMinimum()

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

Definition at line 166 of file G4PolynomialPDF.cc.

167{
168 // ax2 + bx + c = 0
169 // p': 2ax + b = 0 -> = 0 at min: x_extreme = -b/2a
170
171 if(x1 < fX1 || x2 > fX2 || x2 < x1) {
172 if(fVerbose > 0) {
173 G4cout << "G4PolynomialPDF::HasNegativeMinimum() WARNING: Invalid range "
174 << x1 << " - " << x2 << G4endl;
175 }
176 return false;
177 }
178
179 // If flat, then check anywhere.
180 if(GetNCoefficients() == 1) return (Evaluate(x1) < -fTolerance);
181
182 // If linear, or if quadratic with negative second derivative,
183 // just check the endpoints
184 if(GetNCoefficients() == 2 ||
185 (GetNCoefficients() == 3 && GetCoefficient(2) <= 0)) {
186 return (Evaluate(x1) < -fTolerance) || (Evaluate(x2) < -fTolerance);
187 }
188
189 // If quadratic and second dervative is positive, check at the mininum
190 if(GetNCoefficients() == 3) {
191 G4double xMin = -GetCoefficient(1)*0.5/GetCoefficient(2);
192 if(xMin < x1) xMin = x1;
193 if(xMin > x2) xMin = x2;
194 return Evaluate(xMin) < -fTolerance;
195 }
196
197 // Higher-order polynomials: consider any extremum between x1 and x2. If none
198 // are found, check the endpoints.
199 G4double extremum = GetX(0, x1, x2, 1);
200 if(Evaluate(extremum) < -fTolerance) return true;
201 else if(extremum <= x1+(x2-x1)*fTolerance ||
202 extremum >= x2-(x2-x1)*fTolerance) return false;
203 else return
204 HasNegativeMinimum(x1, extremum) || HasNegativeMinimum(extremum, x2);
205}

References Evaluate(), fTolerance, fVerbose, fX2, G4cout, G4endl, GetCoefficient(), GetNCoefficients(), GetX(), and HasNegativeMinimum().

Referenced by GetRandomX(), and HasNegativeMinimum().

◆ Normalize()

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 100 of file G4PolynomialPDF.cc.

101{
104 while(fCoefficients.size()) { /* Loop checking, 30-Oct-2015, G.Folger */
105 if(fCoefficients[fCoefficients.size()-1] == 0.0) fCoefficients.pop_back();
106 else break;
107 }
108
109 G4double x1N = fX1, x2N = fX2;
110 G4double sum = 0;
111 for(size_t i=0; i<GetNCoefficients(); ++i) {
112 sum += GetCoefficient(i)*(x2N - x1N)/G4double(i+1);
113 x1N*=fX1;
114 x2N*=fX2;
115 }
116 if(sum <= 0) {
117 if(fVerbose > 0) {
118 G4cout << "G4PolynomialPDF::Normalize() WARNING: PDF has non-positive area: "
119 << sum << G4endl;
120 Dump();
121 }
122 return;
123 }
124
125 for(size_t i=0; i<GetNCoefficients(); ++i) {
126 SetCoefficient(i, GetCoefficient(i)/sum, false);
127 }
128 Simplify();
129}
void SetCoefficient(size_t i, G4double value, bool doSimplify)

References Dump(), fCoefficients, fVerbose, fX1, fX2, G4cout, G4endl, GetCoefficient(), GetNCoefficients(), SetCoefficient(), and Simplify().

Referenced by GetRandomX().

◆ SetCoefficient()

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

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 if(doSimplify) Simplify();
61}

References fChanged, fCoefficients, and Simplify().

Referenced by Normalize(), and SetCoefficients().

◆ SetCoefficients() [1/2]

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

Definition at line 59 of file G4PolynomialPDF.hh.

59 {
60 fCoefficients = v; fChanged = true; Simplify();
61 }

References fChanged, fCoefficients, and Simplify().

Referenced by G4PolynomialPDF(), and G4PolarizationTransition::GenerateGammaCosTheta().

◆ SetCoefficients() [2/2]

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

Definition at line 63 of file G4PolynomialPDF.cc.

65{
66 SetNCoefficients(nCoeffs);
67 for(size_t i=0; i<GetNCoefficients(); ++i) {
68 SetCoefficient(i, coefficients[i], false);
69 }
70 fChanged = true;
71 Simplify();
72}

References fChanged, GetNCoefficients(), SetCoefficient(), SetNCoefficients(), and Simplify().

◆ SetDomain()

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

Definition at line 86 of file G4PolynomialPDF.cc.

87{
88 if(x2 <= x1) {
89 if(fVerbose > 0) {
90 G4cout << "G4PolynomialPDF::SetDomain() WARNING: Invalid domain! "
91 << "(x1 = " << x1 << ", x2 = " << x2 << ")." << G4endl;
92 }
93 return;
94 }
95 fX1 = x1;
96 fX2 = x2;
97 fChanged = true;
98}

References fChanged, fVerbose, fX1, fX2, G4cout, and G4endl.

◆ SetNCoefficients()

void G4PolynomialPDF::SetNCoefficients ( size_t  n)
inline

Definition at line 57 of file G4PolynomialPDF.hh.

57{ fCoefficients.resize(n); fChanged = true; }

References fChanged, fCoefficients, and CLHEP::detail::n.

Referenced by G4PolynomialPDF(), and SetCoefficients().

◆ SetTolerance()

void G4PolynomialPDF::SetTolerance ( G4double  tolerance)
inline

Definition at line 87 of file G4PolynomialPDF.hh.

87{ fTolerance = tolerance; }

References fTolerance.

◆ Simplify()

void G4PolynomialPDF::Simplify ( )

Definition at line 74 of file G4PolynomialPDF.cc.

75{
76 while(fCoefficients.size() && fCoefficients[fCoefficients.size()-1] == 0) {
77 if(fVerbose > 0) {
78 G4cout << "G4PolynomialPDF::Simplify() WARNING: had to pop coefficient "
79 << fCoefficients.size()-1 << G4endl;
80 }
81 fCoefficients.pop_back();
82 fChanged = true;
83 }
84}

References fChanged, fCoefficients, fVerbose, G4cout, and G4endl.

Referenced by Normalize(), SetCoefficient(), and SetCoefficients().

Field Documentation

◆ fChanged

G4bool G4PolynomialPDF::fChanged
protected

◆ fCoefficients

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

◆ fTolerance

G4double G4PolynomialPDF::fTolerance
protected

Definition at line 115 of file G4PolynomialPDF.hh.

Referenced by GetX(), HasNegativeMinimum(), and SetTolerance().

◆ fVerbose

G4int G4PolynomialPDF::fVerbose
protected

◆ fX1

G4double G4PolynomialPDF::fX1
protected

◆ fX2

G4double G4PolynomialPDF::fX2
protected

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