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