/home/coin/SVN-release/CoinAll-1.1.0/cppad/cppad/ode_gear.hpp

Go to the documentation of this file.
00001 # ifndef CPPAD_ODE_GEAR_INCLUDED
00002 # define CPPAD_ODE_GEAR_INCLUDED
00003 
00004 /* --------------------------------------------------------------------------
00005 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-07 Bradley M. Bell
00006 
00007 CppAD is distributed under multiple licenses. This distribution is under
00008 the terms of the 
00009                     Common Public License Version 1.0.
00010 
00011 A copy of this license is included in the COPYING file of this distribution.
00012 Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
00013 -------------------------------------------------------------------------- */
00014 
00015 /*
00016 $begin OdeGear$$
00017 $spell
00018         cppad.hpp
00019         Jan
00020         bool
00021         const
00022         CppAD
00023         dep
00024 $$
00025 
00026 $index OdeGear$$
00027 $index Ode, Gear$$
00028 $index Gear, Ode$$
00029 $index stiff, Ode$$
00030 $index differential, equation$$
00031 $index equation, differential$$
00032  
00033 $section An Arbitrary Order Gear Method$$
00034 
00035 $head Syntax$$
00036 $syntax%# include <cppad/ode_gear.hpp>
00037 %$$
00038 $syntax%OdeGear(%F%, %m%, %n%, %T%, %X%, %e%)%$$
00039 
00040 
00041 $head Purpose$$
00042 This routine applies
00043 $xref/OdeGear/Gear's Method/Gear's Method/$$
00044 to solve an explicit set of ordinary differential equations.
00045 We are given 
00046 $latex f : \R \times \R^n \rightarrow \R^n$$ be a smooth function.
00047 This routine solves the following initial value problem
00048 $latex \[
00049 \begin{array}{rcl}
00050         x( t_{m-1} )  & = & x^0    \\
00051         x^\prime (t)  & = & f[t , x(t)] 
00052 \end{array}
00053 \] $$
00054 for the value of $latex x( t_m )$$.
00055 If your set of  ordinary differential equations are not stiff
00056 an explicit method may be better (perhaps $xref/Runge45/$$.)
00057 
00058 $head Include$$
00059 The file $code cppad/ode_gear.hpp$$ is included by $code cppad/cppad.hpp$$
00060 but it can also be included separately with out the rest of 
00061 the $code CppAD$$ routines.
00062 
00063 $head Fun$$
00064 The class $italic Fun$$ 
00065 and the object $italic F$$ satisfy the prototype
00066 $syntax%
00067         %Fun% &%F%
00068 %$$
00069 This must support the following set of calls
00070 $syntax%
00071         %F%.Ode(%t%, %x%, %f%)
00072         %F%.Ode_dep(%t%, %x%, %f_x%)
00073 %$$
00074 
00075 $subhead t$$
00076 The argument $italic t$$ has prototype
00077 $syntax%
00078         const %Scalar% &%t%
00079 %$$
00080 (see description of $xref/OdeGear/Scalar/Scalar/$$ below). 
00081 
00082 $subhead x$$
00083 The argument $italic x$$ has prototype
00084 $syntax%
00085         const %Vector% &%x%
00086 %$$
00087 and has size $italic n$$
00088 (see description of $xref/OdeGear/Vector/Vector/$$ below). 
00089 
00090 $subhead f$$
00091 The argument $italic f$$ to $syntax%%F%.Ode%$$ has prototype
00092 $syntax%
00093         %Vector% &%f%
00094 %$$
00095 On input and output, $italic f$$ is a vector of size $italic n$$
00096 and the input values of the elements of $italic f$$ do not matter.
00097 On output,
00098 $italic f$$ is set equal to $latex f(t, x)$$
00099 (see $italic f(t, x)$$ in $xref/OdeGear/Purpose/Purpose/$$). 
00100 
00101 $subhead f_x$$
00102 The argument $italic f_x$$ has prototype
00103 $syntax%
00104         %Vector% &%f_x%
00105 %$$
00106 On input and output, $italic f_x$$ is a vector of size $latex n * n$$
00107 and the input values of the elements of $italic f_x$$ do not matter.
00108 On output, 
00109 $latex \[
00110         f\_x [i * n + j] = \partial_{x(j)} f_i ( t , x )
00111 \] $$ 
00112 
00113 $subhead Warning$$
00114 The arguments $italic f$$, and $italic f_x$$
00115 must have a call by reference in their prototypes; i.e.,
00116 do not forget the $code &$$ in the prototype for 
00117 $italic f$$ and $italic f_x$$.
00118 
00119 $head m$$
00120 The argument $italic m$$ has prototype
00121 $syntax%
00122         size_t %m%
00123 %$$
00124 It specifies the order (highest power of $latex t$$) 
00125 used to represent the function $latex x(t)$$ in the multi-step method. 
00126 Upon return from $code OdeGear$$,
00127 the $th i$$ component of the polynomial is defined by
00128 $latex \[
00129         p_i ( t_j ) = X[ j * n + i ]
00130 \] $$
00131 for $latex j = 0 , \ldots , m$$ (where $latex 0 \leq i < n$$).
00132 The value of $latex m$$ must be greater than or equal one.
00133 
00134 $head n$$
00135 The argument $italic n$$ has prototype
00136 $syntax%
00137         size_t %n%
00138 %$$
00139 It specifies the range space dimension of the 
00140 vector valued function $latex x(t)$$.
00141 
00142 $head T$$
00143 The argument $italic T$$ has prototype
00144 $syntax%
00145         const %Vector% &%T%
00146 %$$
00147 and size greater than or equal to $latex m+1$$.
00148 For $latex j = 0 , \ldots m$$, $latex T[j]$$ is the time 
00149 corresponding to time corresponding 
00150 to a previous point in the multi-step method.
00151 The value $latex T[m]$$ is the time 
00152 of the next point in the multi-step method.
00153 The array $latex T$$ must be monotone increasing; i.e.,
00154 $latex T[j] < T[j+1]$$.
00155 Above and below we often use the shorthand $latex t_j$$ for $latex T[j]$$.
00156 
00157 
00158 $head X$$
00159 The argument $italic X$$ has the prototype
00160 $syntax%
00161         %Vector% &%X%
00162 %$$
00163 and size greater than or equal to $latex (m+1) * n$$.
00164 On input to $code OdeGear$$,
00165 for $latex j = 0 , \ldots , m-1$$, and
00166 $latex i = 0 , \ldots , n-1$$ 
00167 $latex \[
00168         X[ j * n + i ] = x_i ( t_j )
00169 \] $$
00170 Upon return from $code OdeGear$$,
00171 for $latex i = 0 , \ldots , n-1$$ 
00172 $latex \[
00173         X[ m * n + i ] \approx x_i ( t_m ) 
00174 \] $$
00175 
00176 $head e$$
00177 The vector $italic e$$ is an approximate error bound for the result; i.e.,
00178 $latex \[
00179         e[i] \geq | X[ m * n + i ] - x_i ( t_m ) |
00180 \] $$
00181 The order of this approximation is one less than the order of
00182 the solution; i.e., 
00183 $latex \[
00184         e = O ( h^m )
00185 \] $$
00186 where $latex h$$ is the maximum of $latex t_{j+1} - t_j$$.
00187 
00188 $head Scalar$$
00189 The type $italic Scalar$$ must satisfy the conditions
00190 for a $xref/NumericType/$$ type.
00191 The routine $xref/CheckNumericType/$$ will generate an error message
00192 if this is not the case.
00193 In addition, the following operations must be defined for 
00194 $italic Scalar$$ objects $italic a$$ and $italic b$$:
00195 
00196 $table
00197 $bold Operation$$ $cnext $bold Description$$  $rnext
00198 $syntax%%a% < %b%$$ $cnext
00199         less than operator (returns a $code bool$$ object)
00200 $tend
00201 
00202 $head Vector$$
00203 The type $italic Vector$$ must be a $xref/SimpleVector/$$ class with
00204 $xref/SimpleVector/Elements of Specified Type/elements of type Scalar/$$.
00205 The routine $xref/CheckSimpleVector/$$ will generate an error message
00206 if this is not the case.
00207 
00208 $head Example$$
00209 $children%
00210         example/ode_gear.cpp
00211 %$$
00212 The file
00213 $xref/OdeGear.cpp/$$
00214 contains an example and test a test of using this routine.
00215 It returns true if it succeeds and false otherwise.
00216 
00217 $head Source Code$$
00218 The source code for this routine is in the file
00219 $code cppad/ode_gear.hpp$$.
00220 
00221 $head Theory$$
00222 For this discussion we use the shorthand $latex x_j$$ 
00223 for the value $latex x ( t_j ) \in \R^n$$ which is not to be confused
00224 with $latex x_i (t) \in \R$$ in the notation above.
00225 The interpolating polynomial $latex p(t)$$ is given by
00226 $latex \[
00227 p(t) = 
00228 \sum_{j=0}^m 
00229 x_j
00230 \frac{ 
00231         \prod_{i \neq j} ( t - t_i )
00232 }{
00233         \prod_{i \neq j} ( t_j - t_i ) 
00234 }
00235 \] $$
00236 The derivative $latex p^\prime (t)$$ is given by
00237 $latex \[
00238 p^\prime (t) = 
00239 \sum_{j=0}^m 
00240 x_j
00241 \frac{ 
00242         \sum_{i \neq j} \prod_{k \neq i,j} ( t - t_k )
00243 }{ 
00244         \prod_{k \neq j} ( t_j - t_k ) 
00245 }
00246 \] $$
00247 Evaluating the derivative at the point $latex t_\ell$$ we have
00248 $latex \[
00249 \begin{array}{rcl}
00250 p^\prime ( t_\ell ) & = & 
00251 x_\ell
00252 \frac{ 
00253         \sum_{i \neq \ell} \prod_{k \neq i,\ell} ( t_\ell - t_k )
00254 }{ 
00255         \prod_{k \neq \ell} ( t_\ell - t_k ) 
00256 }
00257 +
00258 \sum_{j \neq \ell}
00259 x_j
00260 \frac{ 
00261         \sum_{i \neq j} \prod_{k \neq i,j} ( t_\ell - t_k )
00262 }{ 
00263         \prod_{k \neq j} ( t_j - t_k ) 
00264 }
00265 \\
00266 & = &
00267 x_\ell
00268 \sum_{i \neq \ell} 
00269 \frac{ 1 }{ t_\ell - t_i }
00270 +
00271 \sum_{j \neq \ell}
00272 x_j
00273 \frac{ 
00274         \prod_{k \neq \ell,j} ( t_\ell - t_k )
00275 }{ 
00276         \prod_{k \neq j} ( t_j - t_k ) 
00277 }
00278 \\
00279 & = &
00280 x_\ell
00281 \sum_{k \neq \ell} ( t_\ell - t_k )^{-1}
00282 +
00283 \sum_{j \neq \ell}
00284 x_j
00285 ( t_j - t_\ell )^{-1}
00286 \prod_{k \neq \ell ,j} ( t_\ell - t_k ) / ( t_j - t_k )
00287 \end{array}
00288 \] $$
00289 We define the vector $latex \alpha \in \R^{m+1}$$ by
00290 $latex \[
00291 \alpha_j = \left\{ \begin{array}{ll}
00292 \sum_{k \neq m} ( t_m - t_k )^{-1}
00293         & {\rm if} \; j = m
00294 \\
00295 ( t_j - t_m )^{-1}
00296 \prod_{k \neq m,j} ( t_m - t_k ) / ( t_j - t_k )
00297         & {\rm otherwise}
00298 \end{array} \right.
00299 \] $$
00300 It follows that
00301 $latex \[
00302         p^\prime ( t_m ) = \alpha_0 x_0 + \cdots + \alpha_m x_m
00303 \] $$
00304 Gear's method determines $latex x_m$$ by solving the following 
00305 nonlinear equation
00306 $latex \[
00307         f( t_m , x_m ) = \alpha_0 x_0 + \cdots + \alpha_m x_m
00308 \] $$
00309 Newton's method for solving this equation determines iterates, 
00310 which we denote by $latex x_m^k$$, by solving the following affine 
00311 approximation of the equation above
00312 $latex \[
00313 \begin{array}{rcl}
00314 f( t_m , x_m^{k-1} ) + \partial_x f( t_m , x_m^{k-1} ) ( x_m^k - x_m^{k-1} )
00315 & = &
00316 \alpha_0 x_0^k + \alpha_1 x_1 + \cdots + \alpha_m x_m
00317 \\
00318 \left[ \alpha_m I - \partial_x f( t_m , x_m^{k-1} ) \right]  x_m
00319 & = &
00320 \left[ 
00321 f( t_m , x_m^{k-1} ) - \partial_x f( t_m , x_m^{k-1} ) x_m^{k-1} 
00322 - \alpha_0 x_0 - \cdots - \alpha_{m-1} x_{m-1}
00323 \right]
00324 \end{array}
00325 \] $$
00326 In order to initialize Newton's method; i.e. choose $latex x_m^0$$
00327 we define the vector $latex \beta \in \R^{m+1}$$ by
00328 $latex \[
00329 \beta_j = \left\{ \begin{array}{ll}
00330 \sum_{k \neq m-1} ( t_{m-1} - t_k )^{-1}
00331         & {\rm if} \; j = m-1
00332 \\
00333 ( t_j - t_{m-1} )^{-1}
00334 \prod_{k \neq m-1,j} ( t_{m-1} - t_k ) / ( t_j - t_k )
00335         & {\rm otherwise}
00336 \end{array} \right.
00337 \] $$
00338 It follows that
00339 $latex \[
00340         p^\prime ( t_{m-1} ) = \beta_0 x_0 + \cdots + \beta_m x_m
00341 \] $$
00342 We solve the following approximation of the equation above to determine
00343 $latex x_m^0$$:
00344 $latex \[
00345         f( t_{m-1} , x_{m-1} ) = 
00346         \beta_0 x_0 + \cdots + \beta_{m-1} x_{m-1} + \beta_m x_m^0
00347 \] $$
00348 
00349 
00350 $head Gear's Method$$
00351 C. W. Gear, 
00352 ``Simultaneous Numerical Solution of Differential-Algebraic Equations,'' 
00353 IEEE Transactions on Circuit Theory, 
00354 vol. 18, no. 1, pp. 89-95, Jan. 1971.
00355 
00356 
00357 $end
00358 --------------------------------------------------------------------------
00359 */
00360 
00361 # include <cstddef>
00362 # include <cppad/local/cppad_assert.hpp>
00363 # include <cppad/check_simple_vector.hpp>
00364 # include <cppad/check_numeric_type.hpp>
00365 # include <cppad/vector.hpp>
00366 # include <cppad/lu_factor.hpp>
00367 # include <cppad/lu_invert.hpp>
00368 
00369 namespace CppAD { // BEGIN CppAD namespace
00370 
00371 template <typename Vector, typename Fun>
00372 void OdeGear(
00373         Fun          &F  , 
00374         size_t        m  ,
00375         size_t        n  ,
00376         const Vector &T  , 
00377         Vector       &X  ,
00378         Vector       &e  ) 
00379 {
00380         // temporary indices
00381         size_t i, j, k;
00382 
00383         typedef typename Vector::value_type Scalar;
00384 
00385         // check numeric type specifications
00386         CheckNumericType<Scalar>();
00387 
00388         // check simple vector class specifications
00389         CheckSimpleVector<Scalar, Vector>();
00390 
00391         CPPAD_ASSERT_KNOWN(
00392                 m >= 1,
00393                 "OdeGear: m is less than one"
00394         );
00395         CPPAD_ASSERT_KNOWN(
00396                 n > 0,
00397                 "OdeGear: n is equal to zero"
00398         );
00399         CPPAD_ASSERT_KNOWN(
00400                 T.size() >= (m+1),
00401                 "OdeGear: size of T is not greater than or equal (m+1)"
00402         );
00403         CPPAD_ASSERT_KNOWN(
00404                 X.size() >= (m+1) * n,
00405                 "OdeGear: size of X is not greater than or equal (m+1) * n"
00406         );
00407         for(j = 0; j < m; j++) CPPAD_ASSERT_KNOWN(
00408                 T[j] < T[j+1],
00409                 "OdeGear: the array T is not monotone increasing"
00410         );
00411 
00412         // some constants
00413         Scalar zero(0);
00414         Scalar one(1);
00415 
00416         // vectors required by method
00417         Vector alpha(m + 1);
00418         Vector beta(m + 1);
00419         Vector f(n);
00420         Vector f_x(n * n);
00421         Vector x_m0(n);
00422         Vector x_m(n);
00423         Vector b(n);
00424         Vector A(n * n);
00425 
00426         // compute alpha[m] 
00427         alpha[m] = zero;
00428         for(k = 0; k < m; k++)
00429                 alpha[m] += one / (T[m] - T[k]);
00430 
00431         // compute beta[m-1]
00432         beta[m-1] = one / (T[m-1] - T[m]);
00433         for(k = 0; k < m-1; k++)
00434                 beta[m-1] += one / (T[m-1] - T[k]);
00435 
00436 
00437         // compute other components of alpha 
00438         for(j = 0; j < m; j++)
00439         {       // compute alpha[j]
00440                 alpha[j] = one / (T[j] - T[m]);
00441                 for(k = 0; k < m; k++)
00442                 {       if( k != j )
00443                         {       alpha[j] *= (T[m] - T[k]);
00444                                 alpha[j] /= (T[j] - T[k]);
00445                         }
00446                 }
00447         }
00448 
00449         // compute other components of beta 
00450         for(j = 0; j <= m; j++)
00451         {       if( j != m-1 )
00452                 {       // compute beta[j]
00453                         beta[j] = one / (T[j] - T[m-1]);
00454                         for(k = 0; k <= m; k++)
00455                         {       if( k != j && k != m-1 )
00456                                 {       beta[j] *= (T[m-1] - T[k]);
00457                                         beta[j] /= (T[j] - T[k]);
00458                                 }
00459                         }
00460                 }
00461         }
00462 
00463         // evaluate f(T[m-1], x_{m-1} )
00464         for(i = 0; i < n; i++)
00465                 x_m[i] = X[(m-1) * n + i];
00466         F.Ode(T[m-1], x_m, f);
00467 
00468         // solve for x_m^0
00469         for(i = 0; i < n; i++)
00470         {       x_m[i] =  f[i];
00471                 for(j = 0; j < m; j++)
00472                         x_m[i] -= beta[j] * X[j * n + i];
00473                 x_m[i] /= beta[m];
00474         }
00475         x_m0 = x_m;
00476 
00477         // evaluate partial w.r.t x of f(T[m], x_m^0)
00478         F.Ode_dep(T[m], x_m, f_x);
00479 
00480         // compute the matrix A = ( alpha[m] * I - f_x )
00481         for(i = 0; i < n; i++)
00482         {       for(j = 0; j < n; j++)
00483                         A[i * n + j]  = - f_x[i * n + j];
00484                 A[i * n + i] += alpha[m];
00485         }
00486 
00487         // LU factor (and overwrite) the matrix A
00488         int sign;
00489         CppAD::vector<size_t> ip(n) , jp(n);
00490         sign = LuFactor(ip, jp, A);
00491         CPPAD_ASSERT_KNOWN(
00492                 sign != 0,
00493                 "OdeGear: step size is to large"
00494         );
00495 
00496         // Iterations of Newton's method
00497         for(k = 0; k < 3; k++)
00498         {
00499                 // only evaluate f( T[m] , x_m ) keep f_x during iteration
00500                 F.Ode(T[m], x_m, f);
00501 
00502                 // b = f + f_x x_m - alpha[0] x_0 - ... - alpha[m-1] x_{m-1}
00503                 for(i = 0; i < n; i++)
00504                 {       b[i]         = f[i];
00505                         for(j = 0; j < n; j++)
00506                                 b[i]         -= f_x[i * n + j] * x_m[j];
00507                         for(j = 0; j < m; j++)
00508                                 b[i] -= alpha[j] * X[ j * n + i ];
00509                 }
00510                 LuInvert(ip, jp, A, b);
00511                 x_m = b;
00512         }
00513 
00514         // return estimate for x( t[k] ) and the estimated error bound
00515         for(i = 0; i < n; i++)
00516         {       X[m * n + i] = x_m[i];
00517                 e[i]         = x_m[i] - x_m0[i];
00518                 if( e[i] < zero )
00519                         e[i] = - e[i];
00520         }
00521 }
00522 
00523 } // End CppAD namespace 
00524 
00525 # endif

Generated on Sun Nov 14 14:06:33 2010 for Coin-All by  doxygen 1.4.7