TimeDiscretizedODESystem<ODESystemTag::FirstOrderImplicitQuasilinear, NonlinearSolverTag::Picard>:: TimeDiscretizedODESystem(ODE& ode, TimeDisc& time_discretization) : _ode(ode), _time_disc(time_discretization), _mat_trans(createMatrixTranslator<ODETag>(time_discretization)) { _M = &NumLib::GlobalMatrixProvider::provider.getMatrix( ode.getMatrixSpecifications(), _M_id); _K = &NumLib::GlobalMatrixProvider::provider.getMatrix( ode.getMatrixSpecifications(), _K_id); _b = &NumLib::GlobalVectorProvider::provider.getVector( ode.getMatrixSpecifications(), _b_id); }
Solution run_test(ODE& ode, TimeDisc& timeDisc, const unsigned num_timesteps) { using ODE_ = ODE; using ODET = ODETraits<ODE>; Solution sol; const int process_id = 0; NumLib::TimeDiscretizedODESystem<ODE_::ODETag, NLTag> ode_sys(process_id, ode, timeDisc); auto linear_solver = createLinearSolver(); auto conv_crit = std::make_unique<NumLib::ConvergenceCriterionDeltaX>( _tol, boost::none, MathLib::VecNormType::NORM2); auto nonlinear_solver = std::make_unique<NLSolver>(*linear_solver, _maxiter); NumLib::TimeLoopSingleODE<NLTag> loop(ode_sys, std::move(linear_solver), std::move(nonlinear_solver), std::move(conv_crit)); const double t0 = ODET::t0; const double t_end = ODET::t_end; const double delta_t = (num_timesteps == 0) ? -1.0 : ((t_end-t0) / num_timesteps); DBUG("Running test with %u timesteps of size %g s.", num_timesteps, delta_t); // initial condition GlobalVector x0(ode.getMatrixSpecifications(process_id).nrows); ODET::setIC(x0); sol.ts.push_back(t0); sol.solutions.push_back(x0); auto cb = [&sol](const double t, GlobalVector const& x) { sol.ts.push_back(t); sol.solutions.push_back(x); }; if (num_timesteps > 0) { EXPECT_TRUE(loop.loop(t0, x0, t_end, delta_t, cb)); } for (auto& x : sol.solutions) MathLib::LinAlg::setLocalAccessibleVector(x); return sol; }
Foam::RK::RK(ODE& ode) : ODESolver(ode), yTemp_(ode.nEqns()), ak2_(ode.nEqns()), ak3_(ode.nEqns()), ak4_(ode.nEqns()), ak5_(ode.nEqns()), ak6_(ode.nEqns()), yErr_(ode.nEqns()), yTemp2_(ode.nEqns()) {}
void run_test(ODE& ode, TimeDisc& timeDisc, const unsigned num_timesteps) { using ODE_ = ODE; using ODET = ODETraits<ODE>; NumLib::TimeDiscretizedODESystem<ODE_::ODETag, NLTag> ode_sys(ode, timeDisc); auto linear_solver = std::unique_ptr<GlobalLinearSolver>{ new GlobalLinearSolver{"", nullptr}}; auto conv_crit = std::unique_ptr<NumLib::ConvergenceCriterion>( new NumLib::ConvergenceCriterionDeltaX( _tol, boost::none, MathLib::VecNormType::NORM2)); std::unique_ptr<NLSolver> nonlinear_solver( new NLSolver(*linear_solver, _maxiter)); NumLib::TimeLoopSingleODE<NLTag> loop(ode_sys, std::move(linear_solver), std::move(nonlinear_solver), std::move(conv_crit)); const double t0 = ODET::t0; const double t_end = ODET::t_end; const double delta_t = (num_timesteps == 0) ? -1.0 : ((t_end-t0) / num_timesteps); INFO("Running test %s with %u timesteps of size %g s.", _file_name_part.c_str(), num_timesteps, delta_t); init_file(delta_t); // initial condition Vector x0(ode.getMatrixSpecifications().nrows); ODET::setIC(x0); write(t0, x0, x0); auto cb = [this](const double t, Vector const& x) { loopCallback<ODE>(t, x); }; if (num_timesteps > 0) EXPECT_TRUE(loop.loop(t0, x0, t_end, delta_t, cb)); }
void Foam::ODESolver::solve ( const ODE& ode, const scalar xStart, const scalar xEnd, scalarField& y, const scalar eps, scalar& hEst ) const { const label MAXSTP = 10000; scalar x = xStart; scalar h = hEst; scalar hNext = 0; scalar hPrev = 0; for (label nStep=0; nStep<MAXSTP; nStep++) { ode.derivatives(x, y, dydx_); for (label i=0; i<n_; i++) { yScale_[i] = mag(y[i]) + mag(dydx_[i]*h) + SMALL; } if ((x + h - xEnd)*(x + h - xStart) > 0.0) { h = xEnd - x; hPrev = hNext; } hNext = 0; scalar hDid; solve(ode, x, y, dydx_, eps, yScale_, h, hDid, hNext); if ((x - xEnd)*(xEnd - xStart) >= 0.0) { if (hPrev != 0) { hEst = hPrev; } else { hEst = hNext; } return; } h = hNext; } FatalErrorIn ( "ODESolver::solve" "(const ODE& ode, const scalar xStart, const scalar xEnd," "scalarField& yStart, const scalar eps, scalar& hEst) const" ) << "Too many integration steps" << exit(FatalError); }
Foam::ODESolver::ODESolver(const ODE& ode) : n_(ode.nEqns()), yScale_(n_), dydx_(n_) {}
void Foam::SIBS::SIMPR ( const ODE& ode, const scalar xStart, const scalarField& y, const scalarField& dydx, const scalarField& dfdx, const scalarSquareMatrix& dfdy, const scalar deltaX, const label nSteps, scalarField& yEnd ) const { scalar h = deltaX/nSteps; scalarSquareMatrix a(n_); for (register label i=0; i<n_; i++) { for (register label j=0; j<n_; j++) { a[i][j] = -h*dfdy[i][j]; } ++a[i][i]; } labelList pivotIndices(n_); LUDecompose(a, pivotIndices); for (register label i=0; i<n_; i++) { yEnd[i] = h*(dydx[i] + h*dfdx[i]); } LUBacksubstitute(a, pivotIndices, yEnd); scalarField del(yEnd); scalarField ytemp(n_); for (register label i=0; i<n_; i++) { ytemp[i] = y[i] + del[i]; } scalar x = xStart + h; ode.derivatives(x, ytemp, yEnd); for (register label nn=2; nn<=nSteps; nn++) { for (register label i=0; i<n_; i++) { yEnd[i] = h*yEnd[i] - del[i]; } LUBacksubstitute(a, pivotIndices, yEnd); for (register label i=0; i<n_; i++) { ytemp[i] += (del[i] += 2.0*yEnd[i]); } x += h; ode.derivatives(x, ytemp, yEnd); } for (register label i=0; i<n_; i++) { yEnd[i] = h*yEnd[i] - del[i]; } LUBacksubstitute(a, pivotIndices, yEnd); for (register label i=0; i<n_; i++) { yEnd[i] += ytemp[i]; } }
void Foam::SIBS::solve ( const ODE& ode, scalar& x, scalarField& y, scalarField& dydx, const scalar eps, const scalarField& yScale, const scalar hTry, scalar& hDid, scalar& hNext ) const { bool exitflag = false; if (eps != epsOld_) { hNext = xNew_ = -GREAT; scalar eps1 = safe1*eps; a_[0] = nSeq_[0] + 1; for (register label k=0; k<kMaxX_; k++) { a_[k + 1] = a_[k] + nSeq_[k + 1]; } for (register label iq = 1; iq<kMaxX_; iq++) { for (register label k=0; k<iq; k++) { alpha_[k][iq] = pow(eps1, (a_[k + 1] - a_[iq + 1]) /((a_[iq + 1] - a_[0] + 1.0)*(2*k + 3))); } } epsOld_ = eps; a_[0] += n_; for (register label k=0; k<kMaxX_; k++) { a_[k + 1] = a_[k] + nSeq_[k + 1]; } for (kOpt_ = 1; kOpt_<kMaxX_ - 1; kOpt_++) { if (a_[kOpt_ + 1] > a_[kOpt_]*alpha_[kOpt_ - 1][kOpt_]) { break; } } kMax_ = kOpt_; } label k=0; scalar h = hTry; yTemp_ = y; ode.jacobian(x, y, dfdx_, dfdy_); if (x != xNew_ || h != hNext) { first_ = 1; kOpt_ = kMax_; } label km=0; label reduct=0; scalar maxErr = SMALL; for (;;) { scalar red = 1.0; for (k=0; k <= kMax_; k++) { xNew_ = x + h; if (xNew_ == x) { FatalErrorIn("ODES::SIBS") << "step size underflow" << exit(FatalError); } SIMPR(ode, x, yTemp_, dydx, dfdx_, dfdy_, h, nSeq_[k], ySeq_); scalar xest = sqr(h/nSeq_[k]); polyExtrapolate(k, xest, ySeq_, y, yErr_, x_p_, d_p_); if (k != 0) { maxErr = SMALL; for (register label i=0; i<n_; i++) { maxErr = max(maxErr, mag(yErr_[i]/yScale[i])); } maxErr /= eps; km = k - 1; err_[km] = pow(maxErr/safe1, 1.0/(2*km + 3)); } if (k != 0 && (k >= kOpt_ - 1 || first_)) { if (maxErr < 1.0) { exitflag = true; break; } if (k == kMax_ || k == kOpt_ + 1) { red = safe2/err_[km]; break; } else if (k == kOpt_ && alpha_[kOpt_ - 1][kOpt_] < err_[km]) { red = 1.0/err_[km]; break; } else if (kOpt_ == kMax_ && alpha_[km][kMax_ - 1] < err_[km]) { red = alpha_[km][kMax_ - 1]*safe2/err_[km]; break; } else if (alpha_[km][kOpt_] < err_[km]) { red = alpha_[km][kOpt_ - 1]/err_[km]; break; } } } if (exitflag) { break; } red = min(red, redMin); red = max(red, redMax); h *= red; reduct = 1; } x = xNew_; hDid = h; first_=0; scalar wrkmin = GREAT; scalar scale = 1.0; for (register label kk=0; kk<=km; kk++) { scalar fact = max(err_[kk], scaleMX); scalar work = fact*a_[kk + 1]; if (work < wrkmin) { scale = fact; wrkmin = work; kOpt_ = kk + 1; } } hNext = h/scale; if (kOpt_ >= k && kOpt_ != kMax_ && !reduct) { scalar fact = max(scale/alpha_[kOpt_ - 1][kOpt_], scaleMX); if (a_[kOpt_ + 1]*fact <= wrkmin) { hNext = h/fact; kOpt_++; } } }
void Foam::KRR4::solve ( const ODE& ode, scalar& x, scalarField& y, scalarField& dydx, const scalar eps, const scalarField& yScale, const scalar hTry, scalar& hDid, scalar& hNext ) const { scalar xTemp = x; yTemp_ = y; dydxTemp_ = dydx; ode.jacobian(xTemp, yTemp_, dfdx_, dfdy_); scalar h = hTry; for (register label jtry=0; jtry<maxtry; jtry++) { for (register label i=0; i<n_; i++) { for (register label j=0; j<n_; j++) { a_[i][j] = -dfdy_[i][j]; } a_[i][i] += 1.0/(gamma*h); } LUDecompose(a_, pivotIndices_); for (register label i=0; i<n_; i++) { g1_[i] = dydxTemp_[i] + h*c1X*dfdx_[i]; } LUBacksubstitute(a_, pivotIndices_, g1_); for (register label i=0; i<n_; i++) { y[i] = yTemp_[i] + a21*g1_[i]; } x = xTemp + a2X*h; ode.derivatives(x, y, dydx_); for (register label i=0; i<n_; i++) { g2_[i] = dydx_[i] + h*c2X*dfdx_[i] + c21*g1_[i]/h; } LUBacksubstitute(a_, pivotIndices_, g2_); for (register label i=0; i<n_; i++) { y[i] = yTemp_[i] + a31*g1_[i] + a32*g2_[i]; } x = xTemp + a3X*h; ode.derivatives(x, y, dydx_); for (register label i=0; i<n_; i++) { g3_[i] = dydx[i] + h*c3X*dfdx_[i] + (c31*g1_[i] + c32*g2_[i])/h; } LUBacksubstitute(a_, pivotIndices_, g3_); for (register label i=0; i<n_; i++) { g4_[i] = dydx_[i] + h*c4X*dfdx_[i] + (c41*g1_[i] + c42*g2_[i] + c43*g3_[i])/h; } LUBacksubstitute(a_, pivotIndices_, g4_); for (register label i=0; i<n_; i++) { y[i] = yTemp_[i] + b1*g1_[i] + b2*g2_[i] + b3*g3_[i] + b4*g4_[i]; yErr_[i] = e1*g1_[i] + e2*g2_[i] + e3*g3_[i] + e4*g4_[i]; } x = xTemp + h; if (x == xTemp) { FatalErrorIn("ODES::KRR4") << "stepsize not significant" << exit(FatalError); } scalar maxErr = 0.0; for (register label i=0; i<n_; i++) { maxErr = max(maxErr, mag(yErr_[i]/yScale[i])); } maxErr /= eps; if (maxErr <= 1.0) { hDid = h; hNext = (maxErr > errcon ? safety*h*pow(maxErr, pgrow) : grow*h); return; } else { hNext = safety*h*pow(maxErr, pshrink); h = (h >= 0.0 ? max(hNext, shrink*h) : min(hNext, shrink*h)); } } FatalErrorIn("ODES::KRR4") << "exceeded maxtry" << exit(FatalError); }
Foam::ODESolver::ODESolver(ODE& ode) : ode_(ode), yScale_(ode.nEqns()), dydx_(ode.nEqns()) {}