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