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_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 ¥d, 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
,
O2scl Sourceforge Project Page