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 template<class param_t, class func_t=ode_funct<param_t>, 00040 class vec_t=ovector_view, class alloc_vec_t=ovector, 00041 class alloc_t=ovector_alloc, class mat_row_t=omatrix_row> 00042 class ode_iv_solve { 00043 00044 #ifndef DOXYGEN_INTERNAL 00045 00046 protected: 00047 00048 /// Derivative 00049 alloc_vec_t dydx; 00050 00051 /// Memory allocator 00052 alloc_t ao; 00053 00054 /// The adaptive stepper 00055 adapt_step<param_t,func_t,vec_t,alloc_vec_t,alloc_t> *astp; 00056 00057 /// Print out iteration information 00058 virtual int print_iter(double x, size_t nv, vec_t &y) { 00059 std::cout << type() << " x: " << x << " y: "; 00060 for(size_t i=0;i<nv;i++) std::cout << y[i] << " "; 00061 std::cout << std::endl; 00062 if (verbose>1) { 00063 char ch; 00064 std::cin >> ch; 00065 } 00066 return 0; 00067 } 00068 00069 #endif 00070 00071 public: 00072 00073 ode_iv_solve() { 00074 verbose=0; 00075 ntrial=1000; 00076 nsteps_out=10; 00077 astp=&gsl_astp; 00078 exit_on_fail=true; 00079 } 00080 00081 virtual ~ode_iv_solve() {} 00082 00083 /// Set the adaptive stepper to use 00084 int set_adapt_step(adapt_step<param_t,func_t,vec_t, 00085 alloc_vec_t,alloc_t> &as) { 00086 astp=&as; 00087 return 0; 00088 } 00089 00090 /** 00091 \brief Solve the initial-value problem and output a table 00092 00093 Initially, \c xsol should be a vector of size \c nsol, and \c 00094 ysol should be a two-dimensional array (i.e. omatrix_view) of 00095 size \c [nsol][n]. On exit, \c nsol will will be the size of 00096 the solution table, less than or equal to the original value 00097 of \c nsol. 00098 00099 If \ref verbose is greater than zero, The solution 00100 at each internal point will be written to \c std::cout. 00101 If \ref verbose is greater than one, a character 00102 will be required after each point. 00103 00104 If the given value of \c h is small enough, the solution 00105 may generate more points than the space initially allocated 00106 and the full solution will not be generated. 00107 00108 \future Consider modifying so that this can handle tables 00109 which are too small by removing half the rows and doubling 00110 the stepsize. 00111 00112 */ 00113 template<class mat_t> 00114 int solve_table(double x0, double x1, double h, size_t n, 00115 vec_t &ystart, size_t &nsol, vec_t &xsol, 00116 mat_t &ysol, param_t &pa, func_t &derivs) { 00117 00118 int ret=0, nmax=nsol, i, first_ret=0; 00119 size_t j; 00120 00121 xsol[0]=x0; 00122 for(j=0;j<n;j++) ysol[0][j]=ystart[j]; 00123 if (verbose>0) { 00124 print_iter(xsol[0],n,ystart); 00125 if (verbose>1) { 00126 char ch; 00127 std::cin >> ch; 00128 } 00129 } 00130 00131 alloc_vec_t yerrl; 00132 ao.allocate(yerrl,n); 00133 ao.allocate(dydx,n); 00134 derivs(x0,n,ystart,dydx,pa); 00135 00136 for(i=1;i<nmax && xsol[i-1]<x1;i++) { 00137 00138 xsol[i]=xsol[i-1]; 00139 for(j=0;j<n;j++) ysol[i][j]=ysol[i-1][j]; 00140 00141 mat_row_t ar(ysol,i); 00142 00143 ret=astp->astep_derivs(xsol[i],h,x1,n,ar,dydx,yerrl,pa,derivs); 00144 if (ret!=0) { 00145 if (exit_on_fail) { 00146 nsol=i+1; 00147 add_err_ret 00148 ("Adaptive stepper failed in ode_iv_solve::solve_table()", 00149 ret); 00150 } else if (first_ret!=0) { 00151 first_ret=ret; 00152 } 00153 } 00154 00155 if (verbose>0) { 00156 print_iter(xsol[i],n,ar); 00157 if (verbose>1) { 00158 char ch; 00159 std::cin >> ch; 00160 } 00161 } 00162 } 00163 00164 ao.free(dydx); 00165 ao.free(yerrl); 00166 00167 nsol=i; 00168 00169 if (i==nmax && xsol[i-1]<x1) { 00170 set_err("Ran out of space in ode_iv_solve::solve_table().", 00171 gsl_etable); 00172 return gsl_etable; 00173 } 00174 return first_ret; 00175 } 00176 00177 /** \brief Solve the initial-value problem from \c x0 00178 to \c x1 over a grid 00179 00180 Initially, \c xsol should be an array of size \c nsol, and 00181 \c ysol should be a \c matrix of size \c [nsol][n]. This 00182 function never takes a step larger than the grid size. 00183 00184 If \ref verbose is greater than zero, The solution 00185 at each grid point will be written to \c std::cout. 00186 If \ref verbose is greater than one, a character 00187 will be required after each point. 00188 */ 00189 template<class mat_t> 00190 int solve_grid(double x0, double x1, double h, size_t n, 00191 vec_t &ystart, size_t nsol, vec_t &xsol, mat_t &ysol, 00192 param_t &pa, func_t &derivs) { 00193 00194 double x=x0, xnext; 00195 int ret=0, first_ret=0; 00196 size_t j; 00197 00198 xsol[0]=x0; 00199 for(j=0;j<n;j++) ysol[0][j]=ystart[j]; 00200 if (verbose>0) print_iter(xsol[0],n,ystart); 00201 00202 alloc_vec_t yerrl; 00203 ao.allocate(dydx,n); 00204 ao.allocate(yerrl,n); 00205 00206 if (x0<x1) { 00207 00208 derivs(x0,n,ystart,dydx,pa); 00209 00210 for(size_t i=1;i<nsol && ret==0;i++) { 00211 00212 xsol[i]=xsol[i-1]; 00213 for(j=0;j<n;j++) ysol[i][j]=ysol[i-1][j]; 00214 00215 xnext=x0+(x1-x0)*((double)i)/((double)(nsol-1)); 00216 00217 mat_row_t ar(ysol,i); 00218 while(xsol[i]<xnext && ret==0) { 00219 00220 ret=astp->astep_derivs(xsol[i],h,xnext,n,ar,dydx,yerrl,pa,derivs); 00221 if (ret!=0) { 00222 if (exit_on_fail) { 00223 add_err_ret 00224 ("Adaptive stepper failed in ode_iv_solve::solve_grid()", 00225 ret); 00226 } else if (first_ret!=0) { 00227 first_ret=ret; 00228 } 00229 } 00230 } 00231 if (verbose>0) print_iter(xsol[i],n,ar); 00232 00233 } 00234 00235 } else { 00236 00237 derivs(x0,n,ystart,dydx,pa); 00238 00239 for(size_t i=1;i<nsol && ret==0;i++) { 00240 00241 xsol[i]=xsol[i-1]; 00242 for(j=0;j<n;j++) ysol[i][j]=ysol[i-1][j]; 00243 00244 xnext=x0+(x1-x0)*((double)i)/((double)(nsol-1)); 00245 00246 mat_row_t ar(ysol,i); 00247 while(xsol[i]>xnext && ret==0) { 00248 ret=astp->astep_derivs(xsol[i],h,xnext,n,ar,dydx,yerrl,pa,derivs); 00249 if (ret!=0) { 00250 if (exit_on_fail) { 00251 add_err_ret 00252 ("Adaptive stepper failed in ode_iv_solve::solve_grid()", 00253 ret); 00254 } else if (first_ret!=0) { 00255 first_ret=ret; 00256 } 00257 } 00258 } 00259 if (verbose>0) print_iter(xsol[i],n,ar); 00260 00261 } 00262 00263 } 00264 00265 ao.free(dydx); 00266 ao.free(yerrl); 00267 00268 return first_ret; 00269 } 00270 00271 /** \brief Solve the initial-value problem from \c x0 00272 to \c x1 over a grid storing derivatives 00273 00274 Initially, \c xsol should be an array of size \c nsol, and 00275 \c ysol should be a \c omatrix of size \c [nsol][n]. This 00276 function never takes a step larger than the grid size. 00277 00278 If \ref verbose is greater than zero, The solution 00279 at each grid point will be written to \c std::cout. 00280 If \ref verbose is greater than one, a character 00281 will be required after each point. 00282 00283 \todo Add error information 00284 */ 00285 template<class mat_t> 00286 int solve_grid_derivs(double x0, double x1, double h, size_t n, 00287 vec_t &ystart, size_t nsol, vec_t &xsol, 00288 mat_t &ysol, mat_t &dydx_sol, 00289 param_t &pa, func_t &derivs) { 00290 00291 double x=x0, xnext; 00292 int ret=0, first_ret=0; 00293 size_t j; 00294 00295 xsol[0]=x0; 00296 for(j=0;j<n;j++) ysol[0][j]=ystart[j]; 00297 if (verbose>0) print_iter(xsol[0],n,ystart); 00298 00299 alloc_vec_t yerrl; 00300 ao.allocate(yerrl,n); 00301 00302 if (x0<x1) { 00303 00304 mat_row_t mr0(dydx_sol,0); 00305 derivs(x0,n,ystart,mr0,pa); 00306 00307 for(size_t i=1;i<nsol && ret==0;i++) { 00308 00309 xsol[i]=xsol[i-1]; 00310 for(j=0;j<n;j++) { 00311 ysol[i][j]=ysol[i-1][j]; 00312 dydx_sol[i][j]=dydx_sol[i-1][j]; 00313 } 00314 00315 xnext=x0+(x1-x0)*((double)i)/((double)(nsol-1)); 00316 00317 mat_row_t ar(ysol,i); 00318 mat_row_t ar2(dydx_sol,i); 00319 00320 while(xsol[i]<xnext && ret==0) { 00321 00322 ret=astp->astep_derivs(xsol[i],h,xnext,n,ar,ar2,yerrl,pa,derivs); 00323 if (ret!=0) { 00324 if (exit_on_fail) { 00325 ao.free(yerrl); 00326 add_err_ret 00327 ("Adaptive stepper failed in ode_iv_solve::solve_grid()", 00328 ret); 00329 } else if (first_ret!=0) { 00330 first_ret=ret; 00331 } 00332 } 00333 } 00334 if (verbose>0) print_iter(xsol[i],n,ar); 00335 00336 } 00337 00338 } else { 00339 00340 mat_row_t mr0(dydx_sol,0); 00341 derivs(x0,n,ystart,dydx,pa); 00342 00343 for(size_t i=1;i<nsol && ret==0;i++) { 00344 00345 xsol[i]=xsol[i-1]; 00346 for(j=0;j<n;j++) { 00347 ysol[i][j]=ysol[i-1][j]; 00348 dydx_sol[i][j]=dydx_sol[i-1][j]; 00349 } 00350 00351 xnext=x0+(x1-x0)*((double)i)/((double)(nsol-1)); 00352 00353 mat_row_t ar(ysol,i); 00354 mat_row_t ar2(dydx_sol,i); 00355 00356 while(xsol[i]>xnext && ret==0) { 00357 ret=astp->astep_derivs(xsol[i],h,xnext,n,ar,ar2,yerrl,pa,derivs); 00358 if (ret!=0) { 00359 if (exit_on_fail) { 00360 ao.free(yerrl); 00361 add_err_ret 00362 ("Adaptive stepper failed in ode_iv_solve::solve_grid()", 00363 ret); 00364 } else if (first_ret!=0) { 00365 first_ret=ret; 00366 } 00367 } 00368 } 00369 if (verbose>0) print_iter(xsol[i],n,ar); 00370 00371 } 00372 00373 } 00374 00375 ao.free(yerrl); 00376 00377 return first_ret; 00378 } 00379 00380 /** \brief Solve the initial-value problem 00381 to get the final value 00382 00383 If \ref verbose is greater than zero, The solution at less 00384 than or approximately equal to \ref nsteps_out points will be 00385 written to \c std::cout. If \ref verbose is greater than one, 00386 a character will be required after each selected point. 00387 00388 The solution fails if more than \ref ntrial steps are 00389 required. 00390 */ 00391 int solve_final_value(double x0, double x1, double h, size_t n, 00392 vec_t &ystart, vec_t ¥d, 00393 param_t &pa, func_t &derivs) { 00394 00395 ao.allocate(dydx,n); 00396 int ret=solve_final_value_derivs(x0,x1,h,n,ystart,yend,dydx, 00397 dydx,pa,derivs); 00398 ao.free(dydx); 00399 return ret; 00400 } 00401 00402 /** \brief Solve the initial-value problem 00403 to get the final value and derivative 00404 00405 If \ref verbose is greater than zero, The solution at less 00406 than or approximately equal to \ref nsteps_out points will be 00407 written to \c std::cout. If \ref verbose is greater than one, 00408 a character will be required after each selected point. 00409 00410 The solution fails if more than \ref ntrial steps are 00411 required. 00412 00413 \todo Add error information 00414 */ 00415 int solve_final_value_derivs(double x0, double x1, double h, size_t n, 00416 vec_t &ystart, vec_t ¥d, 00417 vec_t &dydx_start, vec_t &dydx_end, 00418 param_t &pa, func_t &derivs) { 00419 00420 if ((x1>x0 && h<=0.0) || (x0>x1 && h>=0.0)) { 00421 set_err_ret("Interval ordering and sign of h don't match.", 00422 gsl_einval); 00423 } 00424 00425 double x=x0, xverb=0.0, dxverb=0.0; 00426 int ret=0, it=0, first_ret=0; 00427 if (verbose>0) { 00428 print_iter(x0,n,ystart); 00429 if (verbose>1) { 00430 char ch; 00431 std::cin >> ch; 00432 } 00433 if (x1>x0) { 00434 dxverb=(x1-x0)/((double)nsteps_out); 00435 xverb=x0+dxverb; 00436 } else { 00437 dxverb=(x0-x1)/((double)nsteps_out); 00438 xverb=x0-dxverb; 00439 } 00440 } 00441 00442 for(size_t i=0;i<n;i++) yend[i]=ystart[i]; 00443 00444 alloc_vec_t yerrl; 00445 ao.allocate(yerrl,n); 00446 00447 if (x1>x0) { 00448 00449 derivs(x,n,yend,dydx_start,pa); 00450 for(size_t i=0;i<n;i++) dydx_end[i]=dydx_start[i]; 00451 00452 while(x<x1 && ret==0) { 00453 ret=astp->astep_derivs(x,h,x1,n,yend,dydx_end,yerrl,pa,derivs); 00454 if (ret!=0) { 00455 if (exit_on_fail) { 00456 ao.free(yerrl); 00457 add_err_ret 00458 ("Adaptive stepper failed in ode_iv_solve::solve_grid()", 00459 ret); 00460 } else if (first_ret!=0) { 00461 first_ret=ret; 00462 } 00463 } 00464 if (verbose>0 && x>xverb) { 00465 print_iter(x,n,yend); 00466 if (verbose>1) { 00467 char ch; 00468 std::cin >> ch; 00469 } 00470 xverb+=dxverb; 00471 } 00472 it++; 00473 if (it>ntrial) { 00474 ao.free(yerrl); 00475 std::string s="Exceeded max number of iterations in "; 00476 s+="ode_iv_solve::solve_final_value()."; 00477 set_err_ret(s.c_str(),gsl_emaxiter); 00478 } 00479 } 00480 00481 } else { 00482 00483 derivs(x,n,yend,dydx_start,pa); 00484 for(size_t i=0;i<n;i++) dydx_end[i]=dydx_start[i]; 00485 00486 while(x>x1 && ret==0) { 00487 ret=astp->astep_derivs(x,h,x1,n,yend,dydx_end,yerrl,pa,derivs); 00488 if (ret!=0) { 00489 if (exit_on_fail) { 00490 ao.free(yerrl); 00491 add_err_ret 00492 ("Adaptive stepper failed in ode_iv_solve::solve_grid()", 00493 ret); 00494 } else if (first_ret!=0) { 00495 first_ret=ret; 00496 } 00497 } 00498 if (verbose>0 && x<xverb) { 00499 print_iter(x,n,yend); 00500 if (verbose>1) { 00501 char ch; 00502 std::cin >> ch; 00503 } 00504 xverb-=dxverb; 00505 } 00506 it++; 00507 if (it>ntrial) { 00508 ao.free(yerrl); 00509 std::string s="Exceeded max number of iterations in "; 00510 s+="ode_iv_solve::solve_final_value()."; 00511 set_err_ret(s.c_str(),gsl_emaxiter); 00512 } 00513 } 00514 } 00515 00516 if (verbose>0) { 00517 print_iter(x,n,yend); 00518 if (verbose>1) { 00519 char ch; 00520 std::cin >> ch; 00521 } 00522 } 00523 00524 ao.free(yerrl); 00525 return first_ret; 00526 } 00527 00528 /// Set output level 00529 int verbose; 00530 00531 /** 00532 \brief Number of output points if \ref verbose is greater 00533 than zero (default 10) 00534 */ 00535 size_t nsteps_out; 00536 00537 /// Maximum number of steps for solve_final_value() (default 1000) 00538 int ntrial; 00539 00540 /** 00541 \brief If true, stop the solution if the adaptive stepper fails 00542 00543 If this is false, then failures in the adaptive stepper are 00544 ignored. 00545 */ 00546 bool exit_on_fail; 00547 00548 /// The default adaptive stepper 00549 gsl_astep<param_t,func_t,vec_t,alloc_vec_t,alloc_t> gsl_astp; 00550 00551 /// Return the type, \c "ode_iv_solve". 00552 virtual const char *type() { return "ode_iv_solve"; } 00553 00554 }; 00555 00556 #ifdef NEVER_DEFINED 00557 00558 /** 00559 \brief Solve an initial-value ODE problems given an 00560 adaptive ODE stepper 00561 */ 00562 template<class param_t,func_t=ode_funct<param_t> > 00563 class ode_iv_solve_x : public ode_iv_solve<param_t,func_t, 00564 ovector_view,ovector,ovector_alloc,omatrix_row> { 00565 00566 public: 00567 00568 int solve_x_derivs(double x0, double x1, double h, size_t n, 00569 ovector_view &ystart, size_t &nsol, 00570 ovector &xsol, std::vector<ovector> &ysol, 00571 std::vector<ovector> &dydx_sol, 00572 param_t &pa, func_t &derivs) { 00573 00574 // Temporary ovectors 00575 ovector y, dy; 00576 00577 // Proceed with solution 00578 double x=x0, xnext; 00579 int ret=0, first_ret=0; 00580 size_t j; 00581 00582 xsol.push_back(x); 00583 for(j=0;j<n;j++) y[j]=ystart[j]; 00584 ysol.push_back(y); 00585 00586 alloc_vec_t yerrl; 00587 ao.allocate(yerrl,n); 00588 00589 if (x0<x1) { 00590 00591 derivs(x,n,y,dy,pa); 00592 dydx_sol.push_back(dy); 00593 00594 while (x<x1 && ret==0) { 00595 00596 ret=astp->astep_derivs(x,h,x1,n,y,dy,yerrl,pa,derivs); 00597 if (ret!=0) { 00598 if (exit_on_fail) { 00599 ao.free(yerrl); 00600 add_err_ret 00601 ("Adaptive stepper failed in ode_iv_solve::solve_grid()", 00602 ret); 00603 } else if (first_ret!=0) { 00604 first_ret=ret; 00605 } 00606 } 00607 if (verbose>0) print_iter(xsol[i],n,ar); 00608 00609 xsol.push_back(x); 00610 ysol.push_back(y); 00611 ysol.push_back(dy); 00612 00613 00614 } 00615 00616 } 00617 00618 ao.free(yerrl); 00619 00620 return first_ret; 00621 } 00622 00623 #endif 00624 00625 00626 #ifndef DOXYGENP 00627 } 00628 #endif 00629 00630 #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