ode_bv_solve.h

00001 /*
00002   -------------------------------------------------------------------
00003   
00004   Copyright (C) 2006, 2007, 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_BV_SOLVE_H
00024 #define O2SCL_ODE_BV_SOLVE_H
00025 #include <string>
00026 #include <o2scl/collection.h>
00027 #include <o2scl/ovector_tlate.h>
00028 #include <o2scl/adapt_step.h>
00029 #include <o2scl/gsl_astep.h>
00030 #include <o2scl/ode_iv_solve.h>
00031 #include <o2scl/gsl_mroot_hybrids.h>
00032 
00033 #ifndef DOXYGENP
00034 namespace o2scl {
00035 #endif
00036 
00037   /** 
00038       \brief Solve boundary-value ODE problems
00039 
00040   */
00041   template<class param_t, class func_t, class vec_t=ovector_view, 
00042     class alloc_vec_t=ovector, class alloc_t=ovector_alloc,
00043     class vec_int_t=ovector_int_view> class ode_bv_solve {
00044 
00045     public:
00046 
00047     ode_bv_solve() {
00048       oisp=&def_ois;
00049       mrootp=&def_mroot;
00050       verbose=0;
00051     }
00052 
00053     virtual ~ode_bv_solve() {}
00054     
00055     /** 
00056         \brief Solve the boundary-value problem
00057     */
00058     virtual int solve(double x0, double x1, double h, size_t n,
00059                       vec_t &ystart, vec_t &yend, vec_int_t &index,
00060                       param_t &pa, func_t &derivs) {
00061       set_err_ret("Missing function in ode_bv_solve::solve().",gsl_nobase);
00062     }
00063     
00064     /** \name Values for the index array */
00065     //@{
00066     /// Unknown on both the left and right boundaries
00067     static const int unk=0;
00068     /// Known on the right boundary
00069     static const int right=1;
00070     /// Known on the left boundary
00071     static const int left=2;
00072     /// Known on both the left and right boundaries
00073     static const int both=3;
00074     //@}
00075 
00076     /** 
00077         \brief Set initial value solver
00078     */
00079     int set_iv(ode_iv_solve<param_t,func_t,vec_t,alloc_vec_t,alloc_t> &ois) {
00080       oisp=&ois;
00081       return 0;
00082     }
00083     
00084     /** \brief Set the equation solver */
00085     int set_mroot(mroot<param_t,mm_funct<param_t> > &root) {
00086       mrootp=&root;
00087       return 0;
00088     }
00089 
00090     /// The default initial value solver
00091     ode_iv_solve<param_t,func_t,vec_t,alloc_vec_t,alloc_t> def_ois;
00092 
00093     /// The default equation solver
00094     gsl_mroot_hybrids<param_t,mm_funct<param_t> > def_mroot;
00095 
00096     /// Set output level
00097     int verbose;
00098     
00099 #ifndef DOXYGEN_INTERNAL
00100     
00101     protected:
00102 
00103     //friend class io_tlate<ode_bv_solve>;
00104     
00105     /// The solver for the initial value problem
00106     ode_iv_solve<param_t,func_t,vec_t,alloc_vec_t,alloc_t> *oisp;
00107 
00108     /// The equation solver
00109     mroot<param_t,mm_funct<param_t> > *mrootp;
00110 
00111     /// The index defining the boundary conditions
00112     vec_int_t *l_index;
00113 
00114     /// Storage for the starting vector
00115     vec_t *l_ystart;
00116 
00117     /// Storage for the ending vector
00118     vec_t *l_yend;
00119 
00120     /// Storage for the starting point
00121     double l_x0;
00122 
00123     /// Storage for the ending abcissa
00124     double l_x1;
00125 
00126     /// Storage for the stepsize
00127     double l_h;
00128 
00129     /// The functions to integrate
00130     func_t *l_derivs;
00131 
00132     /// The number of functions
00133     size_t l_n;
00134     
00135 #endif
00136     
00137   };
00138   
00139   /** 
00140       \brief Solve boundary-value ODE problems by shooting
00141   */
00142   
00143   template<class param_t, class func_t, class vec_t=ovector_view, 
00144     class alloc_vec_t=ovector, class alloc_t=ovector_alloc,
00145     class vec_int_t=ovector_int_view>
00146     class ode_bv_shoot : public ode_bv_solve<param_t,func_t,vec_t,
00147     alloc_vec_t,alloc_t,vec_int_t> {
00148 
00149     public:
00150     
00151     ode_bv_shoot() {}
00152     
00153     virtual ~ode_bv_shoot() {}
00154     
00155     /** 
00156         \brief Solve the boundary-value problem
00157     */
00158     virtual int solve(double x0, double x1, double h, size_t n,
00159                       vec_t &ystart, vec_t &yend, vec_int_t &index,
00160                       param_t &pa, func_t &derivs) {
00161       this->l_index=&index;
00162       this->l_ystart=&ystart;
00163       this->l_yend=&yend;
00164       this->l_x0=x0;
00165       this->l_x1=x1;
00166       this->l_h=h;
00167       this->l_derivs=&derivs;
00168       this->l_n=n;
00169   
00170       int nsolve=0, nsolve2=0, j;
00171 
00172       // Count the number of variables we'll need to solve for:
00173       for (size_t i=0;i<n;i++) {
00174         if (index[i]<2) nsolve++;
00175         if (index[i]%2==1) nsolve2++;
00176       }
00177 
00178       // Make sure that the boundary conditions make sense:
00179       if (nsolve!=nsolve2) {
00180         set_err("Incorrect boundary conditions in ode_bv_shoot::solve",
00181                 gsl_einval);
00182         return gsl_einval;
00183       } 
00184 
00185       // Make space for the solution
00186       ovector sx(nsolve), sy(nsolve);
00187 
00188       // Copy initial guesses from ystart
00189       j=0;
00190       for (size_t i=0;i<n;i++) {
00191         if (index[i]<2) {
00192           sx[j]=ystart[i];
00193           j++;
00194         }
00195       }
00196   
00197       // Solve
00198       mm_funct_mfptr<ode_bv_shoot<param_t,func_t,vec_t,alloc_vec_t,
00199       alloc_t,vec_int_t>,param_t > 
00200       mfm(this,&ode_bv_shoot<param_t,func_t,vec_t,
00201           alloc_vec_t,alloc_t,vec_int_t>::solve_fun);
00202       int ret=this->mrootp->msolve(nsolve,sx,pa,mfm);
00203       solve_fun(nsolve,sx,sy,pa);
00204 
00205       // Copy the solution back to ystart and yend
00206       j=0;
00207       for (size_t i=0;i<n;i++) {
00208         if (index[i]<2) {
00209           ystart[i]=sx[j];
00210           j++;
00211         }
00212       }
00213   
00214       if (ret!=0) {
00215         add_err("Solver failed in ode_bv_shoot::solve().",ret);
00216       }
00217       return ret;
00218     }
00219     
00220 #ifndef DOXYGEN_INTERNAL
00221 
00222     protected:
00223     
00224     //friend class io_tlate<ode_bv_shoot>;
00225     
00226     int solve_fun(size_t nv, const vec_t &sx, vec_t &sy, 
00227                   param_t &pa) {
00228       int j;
00229       ovector y(this->l_n), y2(this->l_n);
00230   
00231       // Create leftmost point from combination of 
00232       // starting array and proposed solution
00233       j=0;
00234       for(size_t i=0;i<this->l_n;i++) {
00235         if ((*this->l_index)[i]<2) {
00236           y[i]=sx[j];
00237           j++;
00238         } else {
00239           y[i]=(*this->l_ystart)[i];
00240         }
00241       }
00242   
00243       // Shoot across
00244       this->oisp->solve_final_value(this->l_x0,this->l_x1,this->l_h,
00245                                     this->l_n,y,y2,pa,*this->l_derivs);
00246   
00247       j=0;
00248       for(size_t i=0;i<this->l_n;i++) {
00249         if ((*this->l_index)[i]%2==1) {
00250           // Construct the equations from the rightmost point
00251           if ((*this->l_yend)[i]==0.0) {
00252             sy[j]=y2[i];
00253           } else {
00254             sy[j]=(y2[i]-(*this->l_yend)[i])/(*this->l_yend)[i];
00255           }
00256           j++;
00257         } else {
00258           // Otherwise copy the final values from y2 to *l_yend
00259           (*this->l_yend)[i]=y2[i];
00260         }
00261       }
00262   
00263       return 0;
00264     }
00265 #endif
00266 
00267   };
00268 
00269 #ifdef NEVER_DEFINED
00270 
00271   /** 
00272       \brief Solve boundary-value ODE problems by relaxation
00273 
00274   */
00275 
00276   class ode_bv_relax : public ode_bv_solve {
00277   public:
00278 
00279     ode_bv_relax();
00280 
00281     virtual ~ode_bv_relax();
00282     
00283     /** 
00284         \brief Solve the boundary-value problem
00285 
00286         How to specify the boundary conditions?
00287     
00288     */
00289     virtual int solve(double x0, double x1, double h, size_t n,
00290                       param_t &pa, func_t &derivs); 
00291 
00292 #ifndef DOXYGENP
00293 
00294   protected:
00295     
00296     friend class io_tlate<ode_bv_relax>;
00297     
00298 #endif
00299 
00300   };
00301 
00302 #endif
00303 
00304 #ifndef DOXYGENP
00305 }
00306 #endif
00307 
00308 #endif

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