Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4JTPolynomialSolver Class Reference

#include <G4JTPolynomialSolver.hh>

Public Member Functions

 G4JTPolynomialSolver ()=default
 
 ~G4JTPolynomialSolver ()=default
 
G4int FindRoots (G4double *op, G4int degree, G4double *zeror, G4double *zeroi)
 

Detailed Description

Definition at line 66 of file G4JTPolynomialSolver.hh.

Constructor & Destructor Documentation

◆ G4JTPolynomialSolver()

G4JTPolynomialSolver::G4JTPolynomialSolver ( )
default

◆ ~G4JTPolynomialSolver()

G4JTPolynomialSolver::~G4JTPolynomialSolver ( )
default

Member Function Documentation

◆ FindRoots()

G4int G4JTPolynomialSolver::FindRoots ( G4double op,
G4int  degree,
G4double zeror,
G4double zeroi 
)

Definition at line 44 of file G4JTPolynomialSolver.cc.

46{
47 G4double t = 0.0, aa = 0.0, bb = 0.0, cc = 0.0, factor = 1.0;
48 G4double max = 0.0, min = infin, xxx = 0.0, x = 0.0, sc = 0.0, bnd = 0.0;
49 G4double xm = 0.0, ff = 0.0, df = 0.0, dx = 0.0;
50 G4int cnt = 0, nz = 0, i = 0, j = 0, jj = 0, l = 0, nm1 = 0, zerok = 0;
51 G4Pow* power = G4Pow::GetInstance();
52
53 // Initialization of constants for shift rotation.
54 //
55 static const G4double xx = std::sqrt(0.5);
56 static const G4double rot = 94.0 * deg;
57 static const G4double cosr = std::cos(rot), sinr = std::sin(rot);
58 G4double xo = xx, yo = -xx;
59 n = degr;
60
61 // Algorithm fails if the leading coefficient is zero.
62 //
63 if(!(op[0] != 0.0))
64 {
65 return -1;
66 }
67
68 // Remove the zeros at the origin, if any.
69 //
70 while(!(op[n] != 0.0))
71 {
72 j = degr - n;
73 zeror[j] = 0.0;
74 zeroi[j] = 0.0;
75 n--;
76 }
77 if(n < 1)
78 {
79 return -1;
80 }
81
82 // Allocate buffers here
83 //
84 std::vector<G4double> temp(degr + 1);
85 std::vector<G4double> pt(degr + 1);
86
87 p.assign(degr + 1, 0);
88 qp.assign(degr + 1, 0);
89 k.assign(degr + 1, 0);
90 qk.assign(degr + 1, 0);
91 svk.assign(degr + 1, 0);
92
93 // Make a copy of the coefficients.
94 //
95 for(i = 0; i <= n; ++i)
96 {
97 p[i] = op[i];
98 }
99
100 do
101 {
102 if(n == 1) // Start the algorithm for one zero.
103 {
104 zeror[degr - 1] = -p[1] / p[0];
105 zeroi[degr - 1] = 0.0;
106 n -= 1;
107 return degr - n;
108 }
109 if(n == 2) // Calculate the final zero or pair of zeros.
110 {
111 Quadratic(p[0], p[1], p[2], &zeror[degr - 2], &zeroi[degr - 2],
112 &zeror[degr - 1], &zeroi[degr - 1]);
113 n -= 2;
114 return degr - n;
115 }
116
117 // Find largest and smallest moduli of coefficients.
118 //
119 max = 0.0;
120 min = infin;
121 for(i = 0; i <= n; ++i)
122 {
123 x = std::fabs(p[i]);
124 if(x > max)
125 {
126 max = x;
127 }
128 if(x != 0.0 && x < min)
129 {
130 min = x;
131 }
132 }
133
134 // Scale if there are large or very small coefficients.
135 // Computes a scale factor to multiply the coefficients of the
136 // polynomial. The scaling is done to avoid overflow and to
137 // avoid undetected underflow interfering with the convergence
138 // criterion. The factor is a power of the base.
139 //
140 sc = lo / min;
141
142 if(((sc <= 1.0) && (max >= 10.0)) || ((sc > 1.0) && (infin / sc >= max)) ||
143 ((infin / sc >= max) && (max >= 10)))
144 {
145 if(!(sc != 0.0))
146 {
147 sc = smalno;
148 }
149 l = (G4int)(G4Log(sc) / G4Log(base) + 0.5);
150 factor = power->powN(base, l);
151 if(factor != 1.0)
152 {
153 for(i = 0; i <= n; ++i)
154 {
155 p[i] = factor * p[i];
156 } // Scale polynomial.
157 }
158 }
159
160 // Compute lower bound on moduli of roots.
161 //
162 for(i = 0; i <= n; ++i)
163 {
164 pt[i] = (std::fabs(p[i]));
165 }
166 pt[n] = -pt[n];
167
168 // Compute upper estimate of bound.
169 //
170 x = G4Exp((G4Log(-pt[n]) - G4Log(pt[0])) / (G4double) n);
171
172 // If Newton step at the origin is better, use it.
173 //
174 if(pt[n - 1] != 0.0)
175 {
176 xm = -pt[n] / pt[n - 1];
177 if(xm < x)
178 {
179 x = xm;
180 }
181 }
182
183 // Chop the interval (0,x) until ff <= 0
184 //
185 while(true)
186 {
187 xm = x * 0.1;
188 ff = pt[0];
189 for(i = 1; i <= n; ++i)
190 {
191 ff = ff * xm + pt[i];
192 }
193 if(ff <= 0.0)
194 {
195 break;
196 }
197 x = xm;
198 }
199 dx = x;
200
201 // Do Newton interation until x converges to two decimal places.
202 //
203 while(std::fabs(dx / x) > 0.005)
204 {
205 ff = pt[0];
206 df = ff;
207 for(i = 1; i < n; ++i)
208 {
209 ff = ff * x + pt[i];
210 df = df * x + ff;
211 }
212 ff = ff * x + pt[n];
213 dx = ff / df;
214 x -= dx;
215 }
216 bnd = x;
217
218 // Compute the derivative as the initial k polynomial
219 // and do 5 steps with no shift.
220 //
221 nm1 = n - 1;
222 for(i = 1; i < n; ++i)
223 {
224 k[i] = (G4double)(n - i) * p[i] / (G4double) n;
225 }
226 k[0] = p[0];
227 aa = p[n];
228 bb = p[n - 1];
229 zerok = static_cast<G4int>(k[n - 1] == 0);
230 for(jj = 0; jj < 5; ++jj)
231 {
232 cc = k[n - 1];
233 if(zerok == 0) // Use a scaled form of recurrence if k at 0 is nonzero.
234 {
235 // Use a scaled form of recurrence if value of k at 0 is nonzero.
236 //
237 t = -aa / cc;
238 for(i = 0; i < nm1; ++i)
239 {
240 j = n - i - 1;
241 k[j] = t * k[j - 1] + p[j];
242 }
243 k[0] = p[0];
244 zerok =
245 static_cast<G4int>(std::fabs(k[n - 1]) <= std::fabs(bb) * eta * 10.0);
246 }
247 else // Use unscaled form of recurrence.
248 {
249 for(i = 0; i < nm1; ++i)
250 {
251 j = n - i - 1;
252 k[j] = k[j - 1];
253 }
254 k[0] = 0.0;
255 zerok = static_cast<G4int>(!(k[n - 1] != 0.0));
256 }
257 }
258
259 // Save k for restarts with new shifts.
260 //
261 for(i = 0; i < n; ++i)
262 {
263 temp[i] = k[i];
264 }
265
266 // Loop to select the quadratic corresponding to each new shift.
267 //
268 for(cnt = 0; cnt < 20; ++cnt)
269 {
270 // Quadratic corresponds to a double shift to a
271 // non-real point and its complex conjugate. The point
272 // has modulus bnd and amplitude rotated by 94 degrees
273 // from the previous shift.
274 //
275 xxx = cosr * xo - sinr * yo;
276 yo = sinr * xo + cosr * yo;
277 xo = xxx;
278 sr = bnd * xo;
279 si = bnd * yo;
280 u = -2.0 * sr;
281 v = bnd;
282 ComputeFixedShiftPolynomial(20 * (cnt + 1), &nz);
283 if(nz != 0)
284 {
285 // The second stage jumps directly to one of the third
286 // stage iterations and returns here if successful.
287 // Deflate the polynomial, store the zero or zeros and
288 // return to the main algorithm.
289 //
290 j = degr - n;
291 zeror[j] = szr;
292 zeroi[j] = szi;
293 n -= nz;
294 for(i = 0; i <= n; ++i)
295 {
296 p[i] = qp[i];
297 }
298 if(nz != 1)
299 {
300 zeror[j + 1] = lzr;
301 zeroi[j + 1] = lzi;
302 }
303 break;
304 }
305
306 // If the iteration is unsuccessful another quadratic
307 // is chosen after restoring k.
308 //
309 for(i = 0; i < n; ++i)
310 {
311 k[i] = temp[i];
312 }
313
314 }
315 } while(nz != 0); // End of initial DO loop
316
317 // Return with failure if no convergence with 20 shifts.
318 //
319 return degr - n;
320}
G4double G4Exp(G4double initial_x)
Exponential Function double precision.
Definition: G4Exp.hh:180
G4double G4Log(G4double x)
Definition: G4Log.hh:227
double G4double
Definition: G4Types.hh:83
int G4int
Definition: G4Types.hh:85
Definition: G4Pow.hh:49
static G4Pow * GetInstance()
Definition: G4Pow.cc:41
G4double powN(G4double x, G4int n) const
Definition: G4Pow.cc:162
T max(const T t1, const T t2)
brief Return the largest of the two arguments
T min(const T t1, const T t2)
brief Return the smallest of the two arguments

Referenced by G4TwistBoxSide::DistanceToSurface(), G4TwistTrapAlphaSide::DistanceToSurface(), and G4TwistTrapParallelSide::DistanceToSurface().


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