Geant4 10.7.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
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, bool doSimplify)
 
void SetCoefficients (size_t n, const G4double *coeffs)
 
void Simplify ()
 
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::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)

◆ ~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)

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

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)); }

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{
133 /// Evaluate f(x)
134 /// ddxPower = -1: f = CDF
135 /// ddxPower = 0: f = PDF
136 /// ddxPower = 1: f = (d/dx) PDF
137 /// ddxPower = 2: f = (d2/dx2) PDF
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}

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

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(); }

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)

◆ 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{
226 /// Find a value of X between x1 and x2 at which f(x) = p.
227 /// ddxPower = -1: f = CDF
228 /// ddxPower = 0: f = PDF
229 /// ddxPower = 1: f = (d/dx) PDF
230 /// Uses the Newton-Raphson method to find the zero of f(x) - p.
231 /// If not found in range, returns the nearest boundary
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}

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}

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{
102 /// Normalize PDF to 1 over domain fX1 to fX2.
103 /// Double-check that the highest-order coefficient is non-zero.
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)

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}

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 }

Referenced by G4PolynomialPDF().

◆ 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}

◆ 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}

◆ SetNCoefficients()

void G4PolynomialPDF::SetNCoefficients ( size_t  n)
inline

Definition at line 57 of file G4PolynomialPDF.hh.

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

Referenced by G4PolynomialPDF(), and SetCoefficients().

◆ SetTolerance()

void G4PolynomialPDF::SetTolerance ( G4double  tolerance)
inline

Definition at line 87 of file G4PolynomialPDF.hh.

87{ fTolerance = tolerance; }

◆ 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}

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

Member Data 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: