ode_iv_solve.h

00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006, 2007, 2008, Andrew W. Steiner
00005   
00006   This file is part of O2scl.
00007   
00008   O2scl is free software; you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation; either version 3 of the License, or
00011   (at your option) any later version.
00012   
00013   O2scl is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017   
00018   You should have received a copy of the GNU General Public License
00019   along with O2scl. If not, see <http://www.gnu.org/licenses/>.
00020 
00021   -------------------------------------------------------------------
00022 */
00023 #ifndef O2SCL_ODE_IV_SOLVE_H
00024 #define O2SCL_ODE_IV_SOLVE_H
00025 
00026 #include <string>
00027 #include <o2scl/collection.h>
00028 #include <o2scl/adapt_step.h>
00029 #include <o2scl/gsl_astep.h>
00030 
00031 #ifndef DOXYGENP
00032 namespace o2scl {
00033 #endif
00034 
00035   /** 
00036       \brief Solve an initial-value ODE problems given an 
00037       adaptive ODE stepper
00038 
00039       \todo (10/8/07) It's not clear to me that \c astepper shouldn't
00040       be a member pointer instead of having the type \c adapt_step be
00041       a template parameter. The present code certainly works, but
00042       prevents the user from changing the adaptive stepper for the ODE
00043       solver at runtime.
00044       
00045       \todo Decide what to do if the adaptive stepper fails. (1/18/07: 
00046       Two approaches: continue no matter what, or just stop. 10/8/07:
00047       should probably let the class user decide?)
00048 
00049       \future Convert to using \c astep_derivs()?
00050 
00051       \future Consider modifying so that this can handle tables
00052       which are two small by removing half the rows and doubling
00053       the stepsize.
00054       
00055   */
00056   template<class param_t, class func_t=ode_funct<void *>, 
00057     class vec_t=ovector_view, 
00058     class alloc_vec_t=ovector, class alloc_t=ovector_alloc, 
00059     class adapt_step=gsl_astep<param_t,func_t,vec_t,alloc_vec_t,alloc_t> > 
00060     class ode_iv_solve 
00061     
00062     {
00063       public:
00064       
00065       ode_iv_solve() {
00066         verbose=0;
00067         ntrial=1000;
00068       }
00069       
00070       virtual ~ode_iv_solve() {}
00071       
00072       /** 
00073           \brief Solve the initial-value problem and output a table 
00074 
00075           Initially, \c xsol should be a vector of size \c nsol, and
00076           \c ysol should be a two-dimensional array
00077           (i.e. omatrix_view) of size \c [nsol][n]. On exit, \c nsol
00078           will will be the size of the solution table, less than or
00079           equal to the original value of \c nsol.
00080       */
00081       template<class mat_t>
00082       int solve_table(double x0, double x1, double h, size_t n,
00083                       vec_t &ystart, size_t &nsol, vec_t &xsol, 
00084                       mat_t &ysol, param_t &pa, func_t &derivs) 
00085       {
00086         int ret=0, nmax=nsol, i;
00087         size_t j;
00088   
00089         xsol[0]=x0;
00090         for(j=0;j<n;j++) ysol[0][j]=ystart[j];
00091         if (verbose>0) print_iter(xsol[0],n,ystart);
00092   
00093         for(i=1;i<nmax && xsol[i-1]<x1 && ret==0;i++) {
00094     
00095           xsol[i]=xsol[i-1];
00096           for(j=0;j<n;j++) ysol[i][j]=ysol[i-1][j];
00097     
00098           omatrix_row ar(ysol,i);
00099           ret=astepper.astep(xsol[i],h,x1,n,ar,pa,derivs);
00100     
00101           if (verbose>0) print_iter(xsol[i],n,ar);
00102         }
00103 
00104         nsol=i;
00105 
00106         if (ret!=0) return ret;
00107 
00108         if (i==nmax && xsol[i-1]<x1) {
00109           set_err("Ran out of space in ode_iv_solve::solve_table().",
00110                   gsl_etable);
00111           return gsl_etable;
00112         }
00113         return 0;
00114       }
00115 
00116       /** \brief Solve the initial-value problem from \c x0 
00117           to \c x1 over a grid 
00118 
00119           Initially, \c xsol should be an array of size \c nsol, and \c
00120           ysol should be a \c omatrix of size \c [nsol][n].
00121 
00122           This function never takes a step larger than the grid
00123           size. This could cause inaccuracy if the grid size is too
00124           fine.
00125       */
00126       template<class mat_t>
00127       int solve_grid(double x0, double x1, double h, size_t n,
00128                      vec_t &ystart, size_t nsol, vec_t &xsol, mat_t &ysol,
00129                      param_t &pa, func_t &derivs) 
00130       {
00131         double x=x0, xnext;
00132         int ret=0;
00133         size_t j;
00134 
00135         xsol[0]=x0;
00136         for(j=0;j<n;j++) ysol[0][j]=ystart[j];
00137         if (verbose>0) print_iter(xsol[0],n,ystart);
00138 
00139         if (x0<x1) {
00140           for(size_t i=1;i<nsol && ret==0;i++) {
00141             
00142             xsol[i]=xsol[i-1];
00143             for(j=0;j<n;j++) ysol[i][j]=ysol[i-1][j];
00144             
00145             xnext=x0+(x1-x0)*((double)i)/((double)(nsol-1));
00146             
00147             while(xsol[i]<xnext && ret==0) {
00148               omatrix_row ar(ysol,i);
00149               ret=astepper.astep(xsol[i],h,xnext,n,ar,pa,derivs);
00150               if (verbose>0) print_iter(xsol[i],n,ar);
00151             }
00152             
00153           }
00154         } else {
00155           for(size_t i=1;i<nsol && ret==0;i++) {
00156             
00157             xsol[i]=xsol[i-1];
00158             for(j=0;j<n;j++) ysol[i][j]=ysol[i-1][j];
00159             
00160             xnext=x0+(x1-x0)*((double)i)/((double)(nsol-1));
00161             
00162             while(xsol[i]>xnext && ret==0) {
00163               omatrix_row ar(ysol,i);
00164               ret=astepper.astep(xsol[i],h,xnext,n,ar,pa,derivs);
00165               if (verbose>0) print_iter(xsol[i],n,ar);
00166             }
00167             
00168           }
00169         }
00170         if (ret!=0) return ret;
00171         return 0;
00172       }
00173 
00174       /** \brief Solve the initial-value problem 
00175           to get the final value 
00176 
00177           For a partiular adaptive stepper, this will likely be the
00178           fastest approach, but it provides no information about 
00179           the solution other than the final value at x=x1.
00180       */
00181       int solve_final_value(double x0, double x1, double h, size_t n,
00182                             vec_t &ystart, vec_t &yend, 
00183                             param_t &pa, func_t &derivs) 
00184       {
00185         if ((x1>x0 && h<=0.0) || (x0>x1 && h>=0.0)) {
00186           set_err_ret("Interval ordering and sign of h don't match.",
00187                       gsl_einval);
00188         }
00189 
00190         double x=x0;
00191         int ret=0, it=0;
00192         if (verbose>0) print_iter(x0,n,ystart);
00193         
00194         for(size_t i=0;i<n;i++) yend[i]=ystart[i];
00195         
00196         if (x1>x0) {
00197           while(x<x1 && ret==0) {
00198             ret=astepper.astep(x,h,x1,n,yend,pa,derivs);
00199             if (verbose>0) print_iter(x,n,yend);
00200             it++;
00201             if (it>ntrial) {
00202               set_err_ret("Exceed maximum iterations.",gsl_emaxiter);
00203             }
00204           }
00205         } else {
00206 
00207           while(x>x1 && ret==0) {
00208             ret=astepper.astep(x,h,x1,n,yend,pa,derivs);
00209             if (verbose>0) print_iter(x,n,yend);
00210             it++;
00211             if (it>ntrial) {
00212               set_err_ret("Exceed maximum iterations.",gsl_emaxiter);
00213             }
00214           }
00215         }
00216 
00217         if (ret!=0) return ret;
00218         return 0;
00219       }
00220       
00221       /// Set output level
00222       int verbose;
00223       
00224       /// Maximum number of steps for solve_final_value() (default 1000)
00225       int ntrial;
00226 
00227       /// The adaptive stepper utilized
00228       adapt_step astepper;
00229 
00230       /// Return the type, \c "ode_iv_solve".
00231       virtual const char *type() { return "ode_iv_solve"; }
00232       
00233 #ifndef DOXYGEN_INTERNAL
00234 
00235       protected:
00236       
00237       /// Print out iteration information
00238       virtual int print_iter(double x, size_t nv, vec_t &y) {
00239         std::cout << type() << " x: " << x << " y: ";
00240         for(size_t i=0;i<nv;i++) std::cout << y[i] << " ";
00241         std::cout << std::endl;
00242         if (verbose>1) {
00243           char ch;
00244           std::cin >> ch;
00245         }
00246         return 0;
00247       }
00248   
00249 #endif
00250 
00251     };
00252 
00253 #ifndef DOXYGENP
00254 }
00255 #endif
00256 
00257 #endif

Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.

Project hosting provided by SourceForge.net Logo, O2scl Sourceforge Project Page