protected void rkck(List <double> y, List <double> dydx, ref double x, double h, ref List <double> yout, ref List <double> yerr, OdeFct derivs) { int n = y.Count; List <double> ak2 = new List <double>(n), ak3 = new List <double>(n), ak4 = new List <double>(n), ak5 = new List <double>(n), ak6 = new List <double>(n), ytemp = new List <double>(n); // first step for (int i = 0; i < n; i++) { ytemp[i] = y[i] + b21 * h * dydx[i]; } // second step ak2 = derivs(x + a2 * h, ytemp); for (int i = 0; i < n; i++) { ytemp[i] = y[i] + h * (b31 * dydx[i] + b32 * ak2[i]); } // third step ak3 = derivs(x + a3 * h, ytemp); for (int i = 0; i < n; i++) { ytemp[i] = y[i] + h * (b41 * dydx[i] + b42 * ak2[i] + b43 * ak3[i]); } // fourth step ak4 = derivs(x + a4 * h, ytemp); for (int i = 0; i < n; i++) { ytemp[i] = y[i] + h * (b51 * dydx[i] + b52 * ak2[i] + b53 * ak3[i] + b54 * ak4[i]); } // fifth step ak5 = derivs(x + a5 * h, ytemp); for (int i = 0; i < n; i++) { ytemp[i] = y[i] + h * (b61 * dydx[i] + b62 * ak2[i] + b63 * ak3[i] + b64 * ak4[i] + b65 * ak5[i]); } // sixth step ak6 = derivs(x + a6 * h, ytemp); for (int i = 0; i < n; i++) { yout[i] = y[i] + h * (c1 * dydx[i] + c3 * ak3[i] + c4 * ak4[i] + c6 * ak6[i]); yerr[i] = h * (dc1 * dydx[i] + dc3 * ak3[i] + dc4 * ak4[i] + dc5 * ak5[i] + dc6 * ak6[i]); } }
/*! Integrate the ode from \f$ x1 \f$ to \f$ x2 \f$ with * initial value condition \f$ f(x1)=y1 \f$. * * The ode is given by a function \f$ F: R \times K^n * \rightarrow K^n \f$ as \f$ f'(x) = F(x,f(x)) \f$, $K=R, * C$ */ public List <double> value(OdeFct ode, List <double> y1, double x1, double x2) { int n = y1.Count; List <double> y = new List <double>(y1); List <double> yScale = new List <double>(n); double x = x1; double h = h1_ * (x1 <= x2 ? 1 : -1); double hnext = 0, hdid = 0; for (int nstp = 1; nstp <= ADAPTIVERK_MAXSTP; nstp++) { List <double> dydx = ode(x, y); for (int i = 0; i < n; i++) { yScale[i] = Math.Abs(y[i]) + Math.Abs(dydx[i] * h) + ADAPTIVERK_TINY; } if ((x + h - x2) * (x + h - x1) > 0.0) { h = x2 - x; } rkqs(y, dydx, ref x, h, eps_, yScale, ref hdid, ref hnext, ode); if ((x - x2) * (x2 - x1) >= 0.0) { return(y); } if (Math.Abs(hnext) <= hmin_) { Utils.QL_FAIL("Step size (" + hnext + ") too small (" + hmin_ + " min) in AdaptiveRungeKutta"); } h = hnext; } Utils.QL_FAIL("Too many steps (" + ADAPTIVERK_MAXSTP + ") in AdaptiveRungeKutta"); return(null); }
protected void rkqs(List <double> y, List <double> dydx, ref double x, double htry, double eps, List <double> yScale, ref double hdid, ref double hnext, OdeFct derivs) { int n = y.Count; double errmax, xnew; List <double> yerr = new List <double>(n), ytemp = new List <double>(n); double h = htry; for (;;) { rkck(y, dydx, ref x, h, ref ytemp, ref yerr, derivs); errmax = 0.0; for (int i = 0; i < n; i++) { errmax = Math.Max(errmax, Math.Abs(yerr[i] / yScale[i])); } errmax /= eps; if (errmax > 1.0) { double htemp1 = ADAPTIVERK_SAFETY * h * Math.Pow(errmax, ADAPTIVERK_PSHRINK); double htemp2 = h / 10; // These would be std::min and std::max, of course, // but VC++14 had problems inlining them and caused // the wrong results to be calculated. The problem // seems to be fixed in update 3, but let's keep this // implementation for compatibility. double max_positive = htemp1 > htemp2 ? htemp1 : htemp2; double max_negative = htemp1 < htemp2 ? htemp1 : htemp2; h = ((h >= 0.0) ? max_positive : max_negative); xnew = x + h; if (xnew.IsEqual(x)) { Utils.QL_FAIL("Stepsize underflow (" + h + " at x = " + x + ") in AdaptiveRungeKutta::rkqs"); } continue; } else { if (errmax > ADAPTIVERK_ERRCON) { hnext = ADAPTIVERK_SAFETY * h * Math.Pow(errmax, ADAPTIVERK_PGROW); } else { hnext = 5.0 * h; } x += (hdid = h); for (int i = 0; i < n; i++) { y[i] = ytemp[i]; } break; } } }