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