Geant4 Cross Reference |
1 // 2 // ******************************************************************** 3 // * License and Disclaimer * 4 // * * 5 // * The Geant4 software is copyright of the Copyright Holders of * 6 // * the Geant4 Collaboration. It is provided under the terms and * 7 // * conditions of the Geant4 Software License, included in the file * 8 // * LICENSE and available at http://cern.ch/geant4/license . These * 9 // * include a list of copyright holders. * 10 // * * 11 // * Neither the authors of this software system, nor their employing * 12 // * institutes,nor the agencies providing financial support for this * 13 // * work make any representation or warranty, express or implied, * 14 // * regarding this software system or assume any liability for its * 15 // * use. Please see the license in the file LICENSE and URL above * 16 // * for the full disclaimer and the limitation of liability. * 17 // * * 18 // * This code implementation is the result of the scientific and * 19 // * technical work of the GEANT4 collaboration. * 20 // * By using, copying, modifying or distributing the software (or * 21 // * any work based on the software) you agree to acknowledge its * 22 // * use in resulting scientific publications, and indicate your * 23 // * acceptance of all terms of the Geant4 Software license. * 24 // ******************************************************************** 25 // 26 // G4PolynomialSolver inline methods implementation 27 // 28 // Author: E.Medernach, 19.12.2000 - First implementation 29 // -------------------------------------------------------------------- 30 31 #define POLEPSILON 1e-12 32 #define POLINFINITY 9.0E99 33 #define ITERATION 12 // 20 But 8 is really enough for Newton with a good guess 34 35 template <class T, class F> 36 G4PolynomialSolver<T, F>::G4PolynomialSolver(T* typeF, F func, F deriv, 37 G4double precision) 38 { 39 Precision = precision; 40 FunctionClass = typeF; 41 Function = func; 42 Derivative = deriv; 43 } 44 45 template <class T, class F> 46 G4PolynomialSolver<T, F>::~G4PolynomialSolver() 47 {} 48 49 template <class T, class F> 50 G4double G4PolynomialSolver<T, F>::solve(G4double IntervalMin, 51 G4double IntervalMax) 52 { 53 return Newton(IntervalMin, IntervalMax); 54 } 55 56 /* If we want to be general this could work for any 57 polynomial of order more that 4 if we find the (ORDER + 1) 58 control points 59 */ 60 #define NBBEZIER 5 61 62 template <class T, class F> 63 G4int G4PolynomialSolver<T, F>::BezierClipping(/*T* typeF,F func,F deriv,*/ 64 G4double* IntervalMin, 65 G4double* IntervalMax) 66 { 67 /** BezierClipping is a clipping interval Newton method **/ 68 /** It works by clipping the area where the polynomial is **/ 69 70 G4double P[NBBEZIER][2], D[2]; 71 G4double NewMin, NewMax; 72 73 G4int IntervalIsVoid = 1; 74 75 /*** Calculating Control Points ***/ 76 /* We see the polynomial as a Bezier curve for some control points to find */ 77 78 /* 79 For 5 control points (polynomial of degree 4) this is: 80 81 0 p0 = F((*IntervalMin)) 82 1/4 p1 = F((*IntervalMin)) + ((*IntervalMax) - (*IntervalMin))/4 83 * F'((*IntervalMin)) 84 2/4 p2 = 1/6 * (16*F(((*IntervalMax) + (*IntervalMin))/2) 85 - (p0 + 4*p1 + 4*p3 + p4)) 86 3/4 p3 = F((*IntervalMax)) - ((*IntervalMax) - (*IntervalMin))/4 87 * F'((*IntervalMax)) 88 1 p4 = F((*IntervalMax)) 89 */ 90 91 /* x,y,z,dx,dy,dz are constant during searching */ 92 93 D[0] = (FunctionClass->*Derivative)(*IntervalMin); 94 95 P[0][0] = (*IntervalMin); 96 P[0][1] = (FunctionClass->*Function)(*IntervalMin); 97 98 if(std::fabs(P[0][1]) < Precision) 99 { 100 return 1; 101 } 102 103 if(((*IntervalMax) - (*IntervalMin)) < POLEPSILON) 104 { 105 return 1; 106 } 107 108 P[1][0] = (*IntervalMin) + ((*IntervalMax) - (*IntervalMin)) / 4; 109 P[1][1] = P[0][1] + (((*IntervalMax) - (*IntervalMin)) / 4.0) * D[0]; 110 111 D[1] = (FunctionClass->*Derivative)(*IntervalMax); 112 113 P[4][0] = (*IntervalMax); 114 P[4][1] = (FunctionClass->*Function)(*IntervalMax); 115 116 P[3][0] = (*IntervalMax) - ((*IntervalMax) - (*IntervalMin)) / 4; 117 P[3][1] = P[4][1] - ((*IntervalMax) - (*IntervalMin)) / 4 * D[1]; 118 119 P[2][0] = ((*IntervalMax) + (*IntervalMin)) / 2; 120 P[2][1] = 121 (16 * (FunctionClass->*Function)(((*IntervalMax) + (*IntervalMin)) / 2) - 122 (P[0][1] + 4 * P[1][1] + 4 * P[3][1] + P[4][1])) / 123 6; 124 125 { 126 G4double Intersection; 127 G4int i, j; 128 129 NewMin = (*IntervalMax); 130 NewMax = (*IntervalMin); 131 132 for(i = 0; i < 5; ++i) 133 for(j = i + 1; j < 5; ++j) 134 { 135 /* there is an intersection only if each have different signs */ 136 if(((P[j][1] > -Precision) && (P[i][1] < Precision)) || 137 ((P[j][1] < Precision) && (P[i][1] > -Precision))) 138 { 139 IntervalIsVoid = 0; 140 Intersection = 141 P[j][0] - P[j][1] * ((P[i][0] - P[j][0]) / (P[i][1] - P[j][1])); 142 if(Intersection < NewMin) 143 { 144 NewMin = Intersection; 145 } 146 if(Intersection > NewMax) 147 { 148 NewMax = Intersection; 149 } 150 } 151 } 152 153 if(IntervalIsVoid != 1) 154 { 155 (*IntervalMax) = NewMax; 156 (*IntervalMin) = NewMin; 157 } 158 } 159 160 if(IntervalIsVoid == 1) 161 { 162 return -1; 163 } 164 165 return 0; 166 } 167 168 template <class T, class F> 169 G4double G4PolynomialSolver<T, F>::Newton(G4double IntervalMin, 170 G4double IntervalMax) 171 { 172 /* So now we have a good guess and an interval where 173 if there are an intersection the root must be */ 174 175 G4double Value = 0; 176 G4double Gradient = 0; 177 G4double Lambda; 178 179 G4int i = 0; 180 G4int j = 0; 181 182 /* Reduce interval before applying Newton Method */ 183 { 184 G4int NewtonIsSafe; 185 186 while((NewtonIsSafe = BezierClipping(&IntervalMin, &IntervalMax)) == 0) 187 ; 188 189 if(NewtonIsSafe == -1) 190 { 191 return POLINFINITY; 192 } 193 } 194 195 Lambda = IntervalMin; 196 Value = (FunctionClass->*Function)(Lambda); 197 198 // while ((std::fabs(Value) > Precision)) { 199 while(j != -1) 200 { 201 Value = (FunctionClass->*Function)(Lambda); 202 203 Gradient = (FunctionClass->*Derivative)(Lambda); 204 205 Lambda = Lambda - Value / Gradient; 206 207 if(std::fabs(Value) <= Precision) 208 { 209 ++j; 210 if(j == 2) 211 { 212 j = -1; 213 } 214 } 215 else 216 { 217 ++i; 218 219 if(i > ITERATION) 220 return POLINFINITY; 221 } 222 } 223 return Lambda; 224 } 225