Geant4 10.7.0
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 ()
 
 ~G4JTPolynomialSolver ()
 
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 ( )

Definition at line 44 of file G4JTPolynomialSolver.cc.

44{}

◆ ~G4JTPolynomialSolver()

G4JTPolynomialSolver::~G4JTPolynomialSolver ( )

Definition at line 46 of file G4JTPolynomialSolver.cc.

46{}

Member Function Documentation

◆ FindRoots()

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

Definition at line 48 of file G4JTPolynomialSolver.cc.

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