|
Fluid Dynamics Library
|
00001 00023 #ifndef __FDL_ODESTEPPER_HPP 00024 #define __FDL_ODESTEPPER_HPP 00025 00026 #include <string> 00027 #include <sstream> 00028 #include "macbase.hpp" 00029 00030 namespace fdl { 00031 00034 template <typename scalar_t> 00035 class ODEStepper 00036 { 00037 protected: 00038 stepper_T rule_; 00039 scalar_t tol_; 00040 scalar_t err_; 00041 unsigned npts_; 00042 std::vector<scalar_t> xtmp, k1, k2, k3, k4; 00043 00044 public: 00045 ODEStepper(unsigned npts =1); 00046 ~ODEStepper() {} 00047 00048 void setRule(stepper_T rule) {rule_ = rule;} 00049 std::string getRule(); 00050 void setTolerance(scalar_t tol) {tol_ = tol;} 00051 scalar_t getTolerance() const {return tol_;} 00053 scalar_t getError() const {return err_;} 00054 00056 void resize(unsigned npts); 00057 00059 void step(MACBase<scalar_t>* macGrid, 00060 unsigned npts, scalar_t& dt, 00061 const scalar_t x0[], scalar_t x1[]); 00062 }; 00063 00064 template <typename scalar_t> 00065 ODEStepper<scalar_t>::ODEStepper(unsigned npts) 00066 : rule_(RK2), tol_(1), xtmp(), k1(), k2(), k3(), k4() 00067 { 00068 resize(npts); 00069 } 00070 00071 template <typename scalar_t> 00072 void ODEStepper<scalar_t>::resize(unsigned npts) 00073 { 00074 xtmp.resize(npts * 3); 00075 k1.resize(npts * 3); 00076 k2.resize(npts * 3); 00077 k3.resize(npts * 3); 00078 k4.resize(npts * 3); 00079 npts_ = npts; 00080 } 00081 00082 template <typename scalar_t> 00083 std::string ODEStepper<scalar_t>::getRule() 00084 { 00085 std::ostringstream oss; 00086 switch (rule_) { 00087 case ARK23: 00088 oss << "Adaptive Runge-Kutta (2, 3)"; 00089 break; 00090 case RK2: 00091 default: 00092 oss << "Runge-Kutta order 2"; 00093 break; 00094 } 00095 return oss.str(); 00096 } 00097 00101 template <typename scalar_t> 00102 void ODEStepper<scalar_t>::step(MACBase<scalar_t>* macGrid, 00103 unsigned npts, scalar_t& dt, 00104 const scalar_t x0[], scalar_t x1[]) 00105 { 00106 if (npts > npts_) { 00107 DEV() << "Resizing ODEStepper scratch space"; 00108 resize(npts); 00109 } 00110 00111 /* We use the standard notation for Butcher tableaux; see 00112 <http://www.scholarpedia.org/article/Runge-Kutta_methods>. 00113 The c_j coefficients are not needed because the RHS is "stationary". 00114 The coefficients e_j are for the error term. 00115 */ 00116 scalar_t a21, a31, a32, a41, a42, a43; 00117 scalar_t b1, b2, b3, b4, e1, e2, e3, e4; 00118 scalar_t delta; 00119 00120 size_t j, dim = npts * 3; 00121 00122 switch (rule_) 00123 { 00124 case ARK23: // Bogacki-Shampine method 00125 a21 = scalar_t(1)/2; 00126 a31 = scalar_t(0); a32 = scalar_t(3)/4; 00127 a41 = scalar_t(2)/9, a42 = scalar_t(1)/3, a43 = scalar_t(4)/9; 00128 b1 = a41, b2 = a42, b3 = a43, b4 = scalar_t(0); 00129 e1 = b1 - scalar_t(7)/24, 00130 e2 = b2 - scalar_t(1)/4, 00131 e3 = b3 - scalar_t(1)/3, 00132 e4 = b4 - scalar_t(1)/8; 00133 00134 do { 00135 macGrid->interpField(npts, &x0[0], &k1[0]); 00136 00137 for (j = 0; j < dim; ++j) 00138 xtmp[j] = x0[j] + dt * a21 * k1[j]; 00139 // xtmp[j] = x0[j] - dt * a21 * k1[j]; 00140 macGrid->interpField(npts, &xtmp[0], &k2[0]); 00141 00142 for (j = 0; j < dim; ++j) 00143 xtmp[j] = x0[j] + dt * (a31 * k1[j] + a32 * k2[j]); 00144 // xtmp[j] = x0[j] - dt * (a31 * k1[j] + a32 * k2[j]); 00145 macGrid->interpField(npts, &xtmp[0], &k3[0]); 00146 00147 for (j = 0; j < dim; ++j) 00148 xtmp[j] = x0[j] + dt * (a41 * k1[j] + a42 * k2[j] + a43 * k3[j]); 00149 // xtmp[j] = x0[j] - dt * (a41 * k1[j] + a42 * k2[j] + a43 * k3[j]); 00150 macGrid->interpField(npts, &xtmp[0], &k4[0]); 00151 00152 err_ = scalar_t(0); 00153 for (j = 0; j < dim; ++j) { 00154 x1[j] = xtmp[j]; 00155 // compute sup-norm |err| on the fly... 00156 delta = dt * fabs(e1 * k1[j] + e2 * k2[j] + e3 * k3[j] + e4 * k4[j]); 00157 if (delta > err_) 00158 err_ = delta; 00159 } 00160 if (err_ >= tol_) { 00161 dt /= 2; 00162 DEV() << "Time step adaptively adjusted: dt = " << dt; 00163 } 00164 } while (err_ >= tol_); 00165 break; 00166 00167 case RK2: 00168 default: // non-adaptive Runge-Kutta 2. 00169 a21 = scalar_t(1)/2; 00170 macGrid->interpField(npts, &x0[0], &k1[0]); 00171 00172 for (j = 0; j < dim; ++j) 00173 xtmp[j] = x0[j] + dt * a21 * k1[j]; 00174 // xtmp[j] = x0[j] - dt * a21 * k1[j]; 00175 macGrid->interpField(npts, &xtmp[0], &k2[0]); 00176 00177 for (j = 0; j < dim; ++j) 00178 x1[j] = x0[j] + dt * k2[j]; 00179 // x1[j] = x0[j] - dt * k2[j]; 00180 break; 00181 } 00182 } 00183 00184 } // namespace fdl 00185 00186 #endif // __FDL_ODESTEPPER_HPP
1.7.4