source: trunk/source/global/HEPNumerics/include/G4PolynomialSolver.icc @ 1261

Last change on this file since 1261 was 1058, checked in by garnier, 15 years ago

file release beta

File size: 6.3 KB
Line 
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//
27// $Id: G4PolynomialSolver.icc,v 1.8 2006/06/29 18:59:54 gunter Exp $
28// GEANT4 tag $Name: geant4-09-02-ref-02 $
29//
30// class G4PolynomialSolver
31//
32// 19.12.00 E.Medernach, First implementation
33//
34
35#define POLEPSILON   1e-12
36#define POLINFINITY  9.0E99
37#define ITERATION  12 // 20 But 8 is really enough for Newton with a good guess
38
39template <class T, class F>
40G4PolynomialSolver<T,F>::G4PolynomialSolver (T* typeF, F func, F deriv,
41                                             G4double precision)
42{
43  Precision = precision ;
44  FunctionClass = typeF ;
45  Function = func ;
46  Derivative = deriv ; 
47}
48
49template <class T, class F>
50G4PolynomialSolver<T,F>::~G4PolynomialSolver ()
51{
52}
53
54template <class T, class F>
55G4double G4PolynomialSolver<T,F>::solve(G4double IntervalMin,
56                                        G4double IntervalMax)
57{
58  return Newton(IntervalMin,IntervalMax); 
59}
60
61
62/* If we want to be general this could work for any
63   polynomial of order more that 4 if we find the (ORDER + 1)
64   control points
65*/
66#define NBBEZIER 5
67
68template <class T, class F>
69G4int
70G4PolynomialSolver<T,F>::BezierClipping(/*T* typeF,F func,F deriv,*/
71                                        G4double *IntervalMin,
72                                        G4double *IntervalMax)
73{
74  /** BezierClipping is a clipping interval Newton method **/
75  /** It works by clipping the area where the polynomial is **/
76
77  G4double P[NBBEZIER][2],D[2];
78  G4double NewMin,NewMax;
79
80  G4int IntervalIsVoid = 1;
81 
82  /*** Calculating Control Points  ***/
83  /* We see the polynomial as a Bezier curve for some control points to find */
84
85  /*
86    For 5 control points (polynomial of degree 4) this is:
87   
88    0     p0 = F((*IntervalMin))
89    1/4   p1 = F((*IntervalMin)) + ((*IntervalMax) - (*IntervalMin))/4
90                 * F'((*IntervalMin))
91    2/4   p2 = 1/6 * (16*F(((*IntervalMax) + (*IntervalMin))/2)
92                      - (p0 + 4*p1 + 4*p3 + p4)) 
93    3/4   p3 = F((*IntervalMax)) - ((*IntervalMax) - (*IntervalMin))/4
94                 * F'((*IntervalMax))
95    1     p4 = F((*IntervalMax))
96  */ 
97
98  /* x,y,z,dx,dy,dz are constant during searching */
99
100  D[0] = (FunctionClass->*Derivative)(*IntervalMin);
101 
102  P[0][0] = (*IntervalMin);
103  P[0][1] = (FunctionClass->*Function)(*IntervalMin);
104 
105
106  if (std::fabs(P[0][1]) < Precision) {
107    return 1;
108  }
109 
110  if (((*IntervalMax) - (*IntervalMin)) < POLEPSILON) {
111    return 1;
112  }
113
114  P[1][0] = (*IntervalMin) + ((*IntervalMax) - (*IntervalMin))/4;
115  P[1][1] = P[0][1] + (((*IntervalMax) - (*IntervalMin))/4.0) * D[0];
116
117  D[1] = (FunctionClass->*Derivative)(*IntervalMax);
118
119  P[4][0] = (*IntervalMax);
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        }
153
154   
155    if (IntervalIsVoid != 1) {
156      (*IntervalMax) = NewMax;
157      (*IntervalMin) = NewMin;
158    }
159  }
160 
161  if (IntervalIsVoid == 1) {
162    return -1;
163  }
164 
165  return 0;
166}
167
168template <class T, class F>
169G4double 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 
183  /* Reduce interval before applying Newton Method */
184  {
185    G4int NewtonIsSafe ;
186
187    while ((NewtonIsSafe = BezierClipping(&IntervalMin,&IntervalMax)) == 0) ;
188
189    if (NewtonIsSafe == -1) {
190      return POLINFINITY;
191    }
192  }
193
194  Lambda = IntervalMin;
195  Value = (FunctionClass->*Function)(Lambda);
196
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      j ++;
209      if (j == 2) {
210        j = -1;
211      }     
212    } else {
213      i ++;
214     
215      if (i > ITERATION)
216        return POLINFINITY;
217    }   
218  }
219  return Lambda ;
220}
Note: See TracBrowser for help on using the repository browser.