1 // ------------------------------------------------------------------------ //
2 // This source file is part of the 'ESA Advanced Concepts Team's //
3 // Space Mechanics Toolbox' software. //
5 // The source files are for research use only, //
6 // and are distributed WITHOUT ANY WARRANTY. Use them on your own risk. //
8 // Copyright (c) 2004-2007 European Space Agency //
9 // ------------------------------------------------------------------------ //
14 #define NUMERATOR(dab,dcb,fa,fb,fc) fb*(dab*fc*(fc-fb)-fa*dcb*(fa-fb))
15 #define DENOMINATOR(fa,fb,fc) (fc-fb)*(fa-fb)*(fa-fc)
21 /// Class for one dimensional functions
22 // with some parameters
23 /** The ()-operator with one double argument
24 * has to be overloaded for a derived class
25 * The return value is the ordinate computed for
26 * the abscissa-argument.
31 Function1D(const double &a
, const double &b
):p1(a
),p2(b
) {}
36 class Function1D_7param
39 Function1D_7param(const double &a
, const double &b
, const double &c
,
40 const double &d
, const double &e
, const double &f
,
41 const double &g
):p1(a
),p2(b
),p3(c
),p4(d
),p5(e
),p6(f
),p7(g
) {}
43 const double p1
,p2
,p3
,p4
,p5
,p6
,p7
;
50 double a
, c
; // lower and upper bounds
53 FZero(const double &a_
, const double &c_
):a(a_
),c(c_
) {} // constructor
55 template <class Functor
>
56 double FindZero(const Functor
&f
);
59 //-------------------------------------------------------------------------------------//
60 // This part is an adaption of the 'Amsterdam method', which is an inversre quadratic //
61 // interpolation - bisection method //
62 // See http://mymathlib.webtrellis.net/roots/amsterdam.html //
64 //-------------------------------------------------------------------------------------//
65 template <class Functor
>
66 double FZero::FindZero(const Functor
&f
)
68 static const int max_iterations
= 500;
69 static const double tolerance
= 1e-15;
71 double fa
= f(a
), b
= 0.5 * ( a
+ c
), fc
= f(c
), fb
= fa
* fc
;
72 double delta
, dab
, dcb
;
75 // If the initial estimates do not bracket a root, set the err flag and //
76 // return. If an initial estimate is a root, then return the root. //
80 if ( fb
> 0.0 ) { err
= -1; return 0.0; }
81 else return ( fa
== 0.0 ) ? a
: c
;
83 // Insure that the initial estimate a < c. //
86 delta
= a
; a
= c
; c
= delta
; delta
= fa
; fa
= fc
; fc
= delta
;
89 // If the function at the left endpoint is positive, and the function //
90 // at the right endpoint is negative. Iterate reducing the length //
91 // of the interval by either bisection or quadratic inverse //
92 // interpolation. Note that the function at the left endpoint //
93 // remains nonnegative and the function at the right endpoint remains //
97 for ( i
= 0; i
< max_iterations
; i
++) {
99 // Are the two endpoints within the user specified tolerance ?
101 if ( ( c
- a
) < tolerance
) return 0.5 * ( a
+ c
);
103 // No, Continue iteration.
107 // Check that we are converging or that we have converged near //
108 // the left endpoint of the inverval. If it appears that the //
109 // interval is not decreasing fast enough, use bisection. //
110 if ( ( c
- a
) < tolerance
) return 0.5 * ( a
+ c
);
111 if ( ( b
- a
) < tolerance
)
113 a
= b
; fa
= fb
; b
= 0.5 * ( a
+ c
); continue;
117 // Check that we are converging or that we have converged near //
118 // the right endpoint of the inverval. If it appears that the //
119 // interval is not decreasing fast enough, use bisection. //
121 if ( ( c
- b
) < tolerance
)
123 c
= b
; fc
= fb
; b
= 0.5 * ( a
+ c
); continue;
127 // If quadratic inverse interpolation is feasible, try it. //
129 if ( ( fa
> fb
) && ( fb
> fc
) ) {
130 delta
= DENOMINATOR(fa
,fb
,fc
);
131 if ( delta
!= 0.0 ) {
134 delta
= NUMERATOR(dab
,dcb
,fa
,fb
,fc
) / delta
;
136 // Will the new estimate of the root be within the //
137 // interval? If yes, use it and update interval. //
138 // If no, use the bisection method. //
140 if ( delta
> dab
&& delta
< dcb
) {
141 if ( fb
> 0.0 ) { a
= b
; fa
= fb
; }
142 else if ( fb
< 0.0 ) { c
= b
; fc
= fb
; }
150 // If not, use the bisection method. //
152 fb
> 0 ? ( a
= b
, fa
= fb
) : ( c
= b
, fc
= fb
);
157 // If the function at the left endpoint is negative, and the function //
158 // at the right endpoint is positive. Iterate reducing the length //
159 // of the interval by either bisection or quadratic inverse //
160 // interpolation. Note that the function at the left endpoint //
161 // remains nonpositive and the function at the right endpoint remains //
164 for ( i
= 0; i
< max_iterations
; i
++) {
165 if ( ( c
- a
) < tolerance
) return 0.5 * ( a
+ c
);
168 if ( ( b
- a
) < tolerance
)
170 a
= b
; fa
= fb
; b
= 0.5 * ( a
+ c
); continue;
174 if ( ( c
- b
) < tolerance
)
176 c
= b
; fc
= fb
; b
= 0.5 * ( a
+ c
); continue;
180 if ( ( fa
< fb
) && ( fb
< fc
) ) {
181 delta
= DENOMINATOR(fa
,fb
,fc
);
182 if ( delta
!= 0.0 ) {
185 delta
= NUMERATOR(dab
,dcb
,fa
,fb
,fc
) / delta
;
186 if ( delta
> dab
&& delta
< dcb
) {
187 if ( fb
< 0.0 ) { a
= b
; fa
= fb
; }
188 else if ( fb
> 0.0 ) { c
= b
; fc
= fb
; }
195 fb
< 0 ? ( a
= b
, fa
= fb
) : ( c
= b
, fc
= fb
);