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 << 27 // 26 // 28 // Author: E.Medernach, 19.12.2000 - First imp << 27 // $Id: G4PolynomialSolver.icc,v 1.8 2006/06/29 18:59:54 gunter Exp $ 29 // ------------------------------------------- << 28 // GEANT4 tag $Name: geant4-09-00 $ >> 29 // >> 30 // class G4PolynomialSolver >> 31 // >> 32 // 19.12.00 E.Medernach, First implementation >> 33 // 30 34 31 #define POLEPSILON 1e-12 << 35 #define POLEPSILON 1e-12 32 #define POLINFINITY 9.0E99 << 36 #define POLINFINITY 9.0E99 33 #define ITERATION 12 // 20 But 8 is really en << 37 #define ITERATION 12 // 20 But 8 is really enough for Newton with a good guess 34 38 35 template <class T, class F> 39 template <class T, class F> 36 G4PolynomialSolver<T, F>::G4PolynomialSolver(T << 40 G4PolynomialSolver<T,F>::G4PolynomialSolver (T* typeF, F func, F deriv, 37 G 41 G4double precision) 38 { 42 { 39 Precision = precision; << 43 Precision = precision ; 40 FunctionClass = typeF; << 44 FunctionClass = typeF ; 41 Function = func; << 45 Function = func ; 42 Derivative = deriv; << 46 Derivative = deriv ; 43 } 47 } 44 48 45 template <class T, class F> 49 template <class T, class F> 46 G4PolynomialSolver<T, F>::~G4PolynomialSolver( << 50 G4PolynomialSolver<T,F>::~G4PolynomialSolver () 47 {} << 51 { >> 52 } 48 53 49 template <class T, class F> 54 template <class T, class F> 50 G4double G4PolynomialSolver<T, F>::solve(G4dou << 55 G4double G4PolynomialSolver<T,F>::solve(G4double IntervalMin, 51 G4dou << 56 G4double IntervalMax) 52 { 57 { 53 return Newton(IntervalMin, IntervalMax); << 58 return Newton(IntervalMin,IntervalMax); 54 } 59 } 55 60 >> 61 56 /* If we want to be general this could work fo 62 /* If we want to be general this could work for any 57 polynomial of order more that 4 if we find 63 polynomial of order more that 4 if we find the (ORDER + 1) 58 control points 64 control points 59 */ 65 */ 60 #define NBBEZIER 5 66 #define NBBEZIER 5 61 67 62 template <class T, class F> 68 template <class T, class F> 63 G4int G4PolynomialSolver<T, F>::BezierClipping << 69 G4int 64 << 70 G4PolynomialSolver<T,F>::BezierClipping(/*T* typeF,F func,F deriv,*/ 65 << 71 G4double *IntervalMin, >> 72 G4double *IntervalMax) 66 { 73 { 67 /** BezierClipping is a clipping interval Ne 74 /** BezierClipping is a clipping interval Newton method **/ 68 /** It works by clipping the area where the 75 /** It works by clipping the area where the polynomial is **/ 69 76 70 G4double P[NBBEZIER][2], D[2]; << 77 G4double P[NBBEZIER][2],D[2]; 71 G4double NewMin, NewMax; << 78 G4double NewMin,NewMax; 72 79 73 G4int IntervalIsVoid = 1; 80 G4int IntervalIsVoid = 1; 74 << 81 75 /*** Calculating Control Points ***/ 82 /*** Calculating Control Points ***/ 76 /* We see the polynomial as a Bezier curve f 83 /* We see the polynomial as a Bezier curve for some control points to find */ 77 84 78 /* 85 /* 79 For 5 control points (polynomial of degree 86 For 5 control points (polynomial of degree 4) this is: 80 << 87 81 0 p0 = F((*IntervalMin)) 88 0 p0 = F((*IntervalMin)) 82 1/4 p1 = F((*IntervalMin)) + ((*Interval 89 1/4 p1 = F((*IntervalMin)) + ((*IntervalMax) - (*IntervalMin))/4 83 * F'((*IntervalMin)) 90 * F'((*IntervalMin)) 84 2/4 p2 = 1/6 * (16*F(((*IntervalMax) + ( 91 2/4 p2 = 1/6 * (16*F(((*IntervalMax) + (*IntervalMin))/2) 85 - (p0 + 4*p1 + 4*p3 + p4 << 92 - (p0 + 4*p1 + 4*p3 + p4)) 86 3/4 p3 = F((*IntervalMax)) - ((*Interval 93 3/4 p3 = F((*IntervalMax)) - ((*IntervalMax) - (*IntervalMin))/4 87 * F'((*IntervalMax)) 94 * F'((*IntervalMax)) 88 1 p4 = F((*IntervalMax)) 95 1 p4 = F((*IntervalMax)) 89 */ << 96 */ 90 97 91 /* x,y,z,dx,dy,dz are constant during search 98 /* x,y,z,dx,dy,dz are constant during searching */ 92 99 93 D[0] = (FunctionClass->*Derivative)(*Interva 100 D[0] = (FunctionClass->*Derivative)(*IntervalMin); 94 << 101 95 P[0][0] = (*IntervalMin); 102 P[0][0] = (*IntervalMin); 96 P[0][1] = (FunctionClass->*Function)(*Interv 103 P[0][1] = (FunctionClass->*Function)(*IntervalMin); >> 104 97 105 98 if(std::fabs(P[0][1]) < Precision) << 106 if (std::fabs(P[0][1]) < Precision) { 99 { << 100 return 1; 107 return 1; 101 } 108 } 102 << 109 103 if(((*IntervalMax) - (*IntervalMin)) < POLEP << 110 if (((*IntervalMax) - (*IntervalMin)) < POLEPSILON) { 104 { << 105 return 1; 111 return 1; 106 } 112 } 107 113 108 P[1][0] = (*IntervalMin) + ((*IntervalMax) - << 114 P[1][0] = (*IntervalMin) + ((*IntervalMax) - (*IntervalMin))/4; 109 P[1][1] = P[0][1] + (((*IntervalMax) - (*Int << 115 P[1][1] = P[0][1] + (((*IntervalMax) - (*IntervalMin))/4.0) * D[0]; 110 116 111 D[1] = (FunctionClass->*Derivative)(*Interva 117 D[1] = (FunctionClass->*Derivative)(*IntervalMax); 112 118 113 P[4][0] = (*IntervalMax); 119 P[4][0] = (*IntervalMax); 114 P[4][1] = (FunctionClass->*Function)(*Interv 120 P[4][1] = (FunctionClass->*Function)(*IntervalMax); >> 121 >> 122 P[3][0] = (*IntervalMax) - ((*IntervalMax) - (*IntervalMin))/4; >> 123 P[3][1] = P[4][1] - ((*IntervalMax) - (*IntervalMin))/4 * D[1]; >> 124 >> 125 P[2][0] = ((*IntervalMax) + (*IntervalMin))/2; >> 126 P[2][1] = (16*(FunctionClass->*Function)(((*IntervalMax)+(*IntervalMin))/2) >> 127 - (P[0][1] + 4*P[1][1] + 4*P[3][1] + P[4][1]))/6 ; >> 128 >> 129 { >> 130 G4double Intersection ; >> 131 G4int i,j; >> 132 >> 133 NewMin = (*IntervalMax) ; >> 134 NewMax = (*IntervalMin) ; >> 135 >> 136 for (i=0;i<5;i++) >> 137 for (j=i+1;j<5;j++) >> 138 { >> 139 /* there is an intersection only if each have different signs */ >> 140 if (((P[j][1] > -Precision) && (P[i][1] < Precision)) || >> 141 ((P[j][1] < Precision) && (P[i][1] > -Precision))) { >> 142 IntervalIsVoid = 0; >> 143 Intersection = P[j][0] - P[j][1]*((P[i][0] - P[j][0])/ >> 144 (P[i][1] - P[j][1])); >> 145 if (Intersection < NewMin) { >> 146 NewMin = Intersection; >> 147 } >> 148 if (Intersection > NewMax) { >> 149 NewMax = Intersection; >> 150 } >> 151 } >> 152 } 115 153 116 P[3][0] = (*IntervalMax) - ((*IntervalMax) - << 154 117 P[3][1] = P[4][1] - ((*IntervalMax) - (*Inte << 155 if (IntervalIsVoid != 1) { 118 << 119 P[2][0] = ((*IntervalMax) + (*IntervalMin)) << 120 P[2][1] = << 121 (16 * (FunctionClass->*Function)(((*Interv << 122 (P[0][1] + 4 * P[1][1] + 4 * P[3][1] + P[ << 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 ea << 136 if(((P[j][1] > -Precision) && (P[i][1] << 137 ((P[j][1] < Precision) && (P[i][1] << 138 { << 139 IntervalIsVoid = 0; << 140 Intersection = << 141 P[j][0] - P[j][1] * ((P[i][0] - P[ << 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 (*IntervalMax) = NewMax; 156 (*IntervalMin) = NewMin; 157 (*IntervalMin) = NewMin; 157 } 158 } 158 } 159 } 159 << 160 160 if(IntervalIsVoid == 1) << 161 if (IntervalIsVoid == 1) { 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 << 179 G4int i = 0; << 180 G4int j = 0; << 181 178 >> 179 G4int i=0; >> 180 G4int j=0; >> 181 >> 182 182 /* Reduce interval before applying Newton Me 183 /* Reduce interval before applying Newton Method */ 183 { 184 { 184 G4int NewtonIsSafe; << 185 G4int NewtonIsSafe ; 185 186 186 while((NewtonIsSafe = BezierClipping(&Inte << 187 while ((NewtonIsSafe = BezierClipping(&IntervalMin,&IntervalMax)) == 0) ; 187 ; << 188 188 189 if(NewtonIsSafe == -1) << 189 if (NewtonIsSafe == -1) { 190 { << 191 return POLINFINITY; 190 return POLINFINITY; 192 } 191 } 193 } 192 } 194 193 195 Lambda = IntervalMin; 194 Lambda = IntervalMin; 196 Value = (FunctionClass->*Function)(Lambda); << 195 Value = (FunctionClass->*Function)(Lambda); >> 196 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 j ++; 209 ++j; << 209 if (j == 2) { 210 if(j == 2) << 210 j = -1; 211 { << 211 } 212 j = -1; << 212 } else { 213 } << 213 i ++; 214 } << 214 215 else << 215 if (i > ITERATION) 216 { << 216 return POLINFINITY; 217 ++i; << 217 } 218 << 219 if(i > ITERATION) << 220 return POLINFINITY; << 221 } << 222 } 218 } 223 return Lambda; << 219 return Lambda ; 224 } 220 } 225 221