diff --git a/NumLib/ODESolver/MatrixTranslator.cpp b/NumLib/ODESolver/MatrixTranslator.cpp index e6cf7ee6dda85c3b10ded49bcc98fcba1dbffe65..ff7d31b25cb944d3ecc1e939ff86d2f4d6486676 100644 --- a/NumLib/ODESolver/MatrixTranslator.cpp +++ b/NumLib/ODESolver/MatrixTranslator.cpp @@ -29,12 +29,13 @@ void MatrixTranslatorGeneral<ODESystemTag::FirstOrderImplicitQuasilinear>:: void MatrixTranslatorGeneral<ODESystemTag::FirstOrderImplicitQuasilinear>:: computeRhs(const GlobalMatrix& M, const GlobalMatrix& /*K*/, - const GlobalVector& b, GlobalVector& rhs) const + const GlobalVector& b, const GlobalVector& x_prev, + GlobalVector& rhs) const { namespace LinAlg = MathLib::LinAlg; auto& tmp = NumLib::GlobalVectorProvider::provider.getVector(_tmp_id); - _time_disc.getWeightedOldX(tmp); + _time_disc.getWeightedOldX(tmp, x_prev); // rhs = M * weighted_old_x + b LinAlg::matMultAdd(M, tmp, b, rhs); diff --git a/NumLib/ODESolver/MatrixTranslator.h b/NumLib/ODESolver/MatrixTranslator.h index 2008c173bd5a76978dfe872b1c8455764e89f0a7..33a4ba00098e75762c14ff59aa170848fa4f5e4b 100644 --- a/NumLib/ODESolver/MatrixTranslator.h +++ b/NumLib/ODESolver/MatrixTranslator.h @@ -44,9 +44,10 @@ public: virtual void computeA(GlobalMatrix const& M, GlobalMatrix const& K, GlobalMatrix& A) const = 0; - //! Computes \c rhs from \c M, \c K and \c b. + //! Computes \c rhs from \c M, \c K, \c b and \c x_prev. virtual void computeRhs(const GlobalMatrix& M, const GlobalMatrix& K, - const GlobalVector& b, GlobalVector& rhs) const = 0; + const GlobalVector& b, const GlobalVector& x_prev, + GlobalVector& rhs) const = 0; /*! Computes \c res from \c M, \c K, \c b, \f$ \hat x \f$ and \f$ x_N \f$. * You might also want read the remarks on @@ -101,7 +102,8 @@ public: //! Computes \f$ \mathtt{rhs} = M \cdot x_O + b \f$. void computeRhs(const GlobalMatrix& M, const GlobalMatrix& /*K*/, - const GlobalVector& b, GlobalVector& rhs) const override; + const GlobalVector& b, const GlobalVector& x_prev, + GlobalVector& rhs) const override; //! Computes \f$ r = M \cdot \hat x + K \cdot x_C - b \f$. void computeResidual(GlobalMatrix const& M, GlobalMatrix const& K, diff --git a/NumLib/ODESolver/NonlinearSolver.cpp b/NumLib/ODESolver/NonlinearSolver.cpp index 8d7127a480fb7a9847afb542544833fa72c79273..cd0195360dec1ca65a6dc8e481796e400ccc02fb 100644 --- a/NumLib/ODESolver/NonlinearSolver.cpp +++ b/NumLib/ODESolver/NonlinearSolver.cpp @@ -23,8 +23,9 @@ namespace NumLib { void NonlinearSolver<NonlinearSolverTag::Picard>:: - calculateNonEquilibriumInitialResiduum(std::vector<GlobalVector*> const& x, - int const process_id) + calculateNonEquilibriumInitialResiduum( + std::vector<GlobalVector*> const& x, + std::vector<GlobalVector*> const& x_prev, int const process_id) { if (!_compensate_non_equilibrium_initial_residuum) { @@ -33,9 +34,9 @@ void NonlinearSolver<NonlinearSolverTag::Picard>:: auto& A = NumLib::GlobalMatrixProvider::provider.getMatrix(_A_id); auto& rhs = NumLib::GlobalVectorProvider::provider.getVector(_rhs_id); - _equation_system->assemble(x, process_id); + _equation_system->assemble(x, x_prev, process_id); _equation_system->getA(A); - _equation_system->getRhs(rhs); + _equation_system->getRhs(*x_prev[process_id], rhs); // r_neq = A * x - rhs _r_neq = &NumLib::GlobalVectorProvider::provider.getVector(); @@ -45,6 +46,7 @@ void NonlinearSolver<NonlinearSolverTag::Picard>:: NonlinearSolverStatus NonlinearSolver<NonlinearSolverTag::Picard>::solve( std::vector<GlobalVector*>& x, + std::vector<GlobalVector*> const& x_prev, std::function<void(int, std::vector<GlobalVector*> const&)> const& postIterationCallback, int const process_id) @@ -85,9 +87,9 @@ NonlinearSolverStatus NonlinearSolver<NonlinearSolverTag::Picard>::solve( BaseLib::RunTime time_assembly; time_assembly.start(); - sys.assemble(x_new, process_id); + sys.assemble(x_new, x_prev, process_id); sys.getA(A); - sys.getRhs(rhs); + sys.getRhs(*x_prev[process_id], rhs); INFO("[time] Assembly took {:g} s.", time_assembly.elapsed()); // Subract non-equilibrium initial residuum if set @@ -206,21 +208,23 @@ NonlinearSolverStatus NonlinearSolver<NonlinearSolverTag::Picard>::solve( } void NonlinearSolver<NonlinearSolverTag::Newton>:: - calculateNonEquilibriumInitialResiduum(std::vector<GlobalVector*> const& x, - int const process_id) + calculateNonEquilibriumInitialResiduum( + std::vector<GlobalVector*> const& x, + std::vector<GlobalVector*> const& x_prev, int const process_id) { if (!_compensate_non_equilibrium_initial_residuum) { return; } - _equation_system->assemble(x, process_id); + _equation_system->assemble(x, x_prev, process_id); _r_neq = &NumLib::GlobalVectorProvider::provider.getVector(); - _equation_system->getResidual(*x[process_id], *_r_neq); + _equation_system->getResidual(*x[process_id], *x_prev[process_id], *_r_neq); } NonlinearSolverStatus NonlinearSolver<NonlinearSolverTag::Newton>::solve( std::vector<GlobalVector*>& x, + std::vector<GlobalVector*> const& x_prev, std::function<void(int, std::vector<GlobalVector*> const&)> const& postIterationCallback, int const process_id) @@ -265,7 +269,7 @@ NonlinearSolverStatus NonlinearSolver<NonlinearSolverTag::Newton>::solve( time_assembly.start(); try { - sys.assemble(x, process_id); + sys.assemble(x, x_prev, process_id); } catch (AssemblyException const& e) { @@ -275,7 +279,7 @@ NonlinearSolverStatus NonlinearSolver<NonlinearSolverTag::Newton>::solve( iteration = _maxiter; break; } - sys.getResidual(*x[process_id], res); + sys.getResidual(*x[process_id], *x_prev[process_id], res); sys.getJacobian(J); INFO("[time] Assembly took {:g} s.", time_assembly.elapsed()); diff --git a/NumLib/ODESolver/NonlinearSolver.h b/NumLib/ODESolver/NonlinearSolver.h index 6b2509668574ab998f5045f8dd0c7e25b761d986..26f2c94d228fa91dda5ad1f7b0add34a5a8e7079 100644 --- a/NumLib/ODESolver/NonlinearSolver.h +++ b/NumLib/ODESolver/NonlinearSolver.h @@ -36,11 +36,13 @@ class NonlinearSolverBase { public: virtual void calculateNonEquilibriumInitialResiduum( - std::vector<GlobalVector*> const& x, int const process_id) = 0; + std::vector<GlobalVector*> const& x, + std::vector<GlobalVector*> const& x_prev, int const process_id) = 0; /*! Assemble and solve the equation system. * * \param x in: the initial guess, out: the solution. + * \param x_prev previous time step solution. * \param postIterationCallback called after each iteration if set. * \param process_id usually used in staggered schemes. * @@ -49,6 +51,7 @@ public: */ virtual NonlinearSolverStatus solve( std::vector<GlobalVector*>& x, + std::vector<GlobalVector*> const& x_prev, std::function<void(int, std::vector<GlobalVector*> const&)> const& postIterationCallback, int const process_id) = 0; @@ -100,10 +103,13 @@ public: } void calculateNonEquilibriumInitialResiduum( - std::vector<GlobalVector*> const& x, int const process_id) override; + std::vector<GlobalVector*> const& x, + std::vector<GlobalVector*> const& x_prev, + int const process_id) override; NonlinearSolverStatus solve( std::vector<GlobalVector*>& x, + std::vector<GlobalVector*> const& x_prev, std::function<void(int, std::vector<GlobalVector*> const&)> const& postIterationCallback, int const process_id) override; @@ -175,10 +181,13 @@ public: } void calculateNonEquilibriumInitialResiduum( - std::vector<GlobalVector*> const& x, int const process_id) override; + std::vector<GlobalVector*> const& x, + std::vector<GlobalVector*> const& x_prev, + int const process_id) override; NonlinearSolverStatus solve( std::vector<GlobalVector*>& x, + std::vector<GlobalVector*> const& x_prev, std::function<void(int, std::vector<GlobalVector*> const&)> const& postIterationCallback, int const process_id) override; diff --git a/NumLib/ODESolver/NonlinearSystem.h b/NumLib/ODESolver/NonlinearSystem.h index 85c3787af2f60725b6681b62ea8ff05bbef629e8..6094520a50ca11f5d51b162b0f21abd1c0e6c0bb 100644 --- a/NumLib/ODESolver/NonlinearSystem.h +++ b/NumLib/ODESolver/NonlinearSystem.h @@ -38,6 +38,7 @@ public: //! The linearized system is \f$A(x) \cdot x = b(x)\f$. Here the matrix //! \f$A(x)\f$ and the vector \f$b(x)\f$ are assembled. virtual void assemble(std::vector<GlobalVector*> const& x, + std::vector<GlobalVector*> const& x_prev, int const process_id) = 0; /*! Writes the residual at point \c x to \c res. @@ -47,6 +48,7 @@ public: * \todo Remove argument \c x. */ virtual void getResidual(GlobalVector const& x, + GlobalVector const& x_prev, GlobalVector& res) const = 0; /*! Writes the Jacobian of the residual to \c Jac. @@ -85,6 +87,7 @@ public: //! The linearized system is \f$J(x) \cdot \Delta x = (x)\f$. Here the //! residual vector \f$r(x)\f$ and its Jacobian \f$J(x)\f$ are assembled. virtual void assemble(std::vector<GlobalVector*> const& x, + std::vector<GlobalVector*> const& x_prev, int const process_id) = 0; //! Writes the linearized equation system matrix to \c A. @@ -93,7 +96,8 @@ public: //! Writes the linearized equation system right-hand side to \c rhs. //! \pre assemble() must have been called before. - virtual void getRhs(GlobalVector& rhs) const = 0; + virtual void getRhs(GlobalVector const& x_prev, + GlobalVector& rhs) const = 0; //! Pre-compute known solutions and possibly store them internally. virtual void computeKnownSolutions(GlobalVector const& x, diff --git a/NumLib/ODESolver/TimeDiscretization.cpp b/NumLib/ODESolver/TimeDiscretization.cpp index 08f9c684a6d16b8ae610e958d6ec893fb150adf5..551384e4b4f435449bff5ac92f587511b92a3a1b 100644 --- a/NumLib/ODESolver/TimeDiscretization.cpp +++ b/NumLib/ODESolver/TimeDiscretization.cpp @@ -54,9 +54,11 @@ double TimeDiscretization::computeRelativeChangeFromPreviousTimestep( } double BackwardEuler::getRelativeChangeFromPreviousTimestep( - GlobalVector const& x, MathLib::VecNormType norm_type) + GlobalVector const& x, + GlobalVector const& x_old, + MathLib::VecNormType norm_type) { - return computeRelativeChangeFromPreviousTimestep(x, _x_old, norm_type); + return computeRelativeChangeFromPreviousTimestep(x, x_old, norm_type); } } // end of namespace NumLib diff --git a/NumLib/ODESolver/TimeDiscretization.h b/NumLib/ODESolver/TimeDiscretization.h index f53765d4f6c2604b6eab80b82dd5d640b6fd6ee2..f5dcbab099f2a5cfabe56719e4056eb70695f6e9 100644 --- a/NumLib/ODESolver/TimeDiscretization.h +++ b/NumLib/ODESolver/TimeDiscretization.h @@ -90,7 +90,7 @@ public: TimeDiscretization() = default; //! Sets the initial condition. - virtual void setInitialState(const double t0, GlobalVector const& x0) = 0; + virtual void setInitialState(const double t0) = 0; /*! Get the relative change of solutions between two successive time steps * by \f$ e_n = \|u^{n+1}-u^{n}\|/\|u^{n+1}\| \f$. @@ -99,30 +99,9 @@ public: * \param norm_type The type of global vector norm. */ virtual double getRelativeChangeFromPreviousTimestep( - GlobalVector const& x, MathLib::VecNormType norm_type) = 0; - - /*! Indicate that the current timestep is done and that you will proceed to - * the next one. - * - * \warning Do not use this method for setting the initial condition, - * rather use setInitialState()! - * - * \param t The current timestep. - * \param x The solution at the current timestep. - */ - virtual void pushState(const double t, GlobalVector const& x) = 0; - - /*! - * Restores the given vector x to its old value. - * Used only for repeating of the time step with new time step size when - * the current time step is rejected. The restored x is only used as - * an initial guess for linear solver in the first Picard nonlinear - * iteration. - * - * \param x The solution at the current time step, which is going to be - * reset to its previous value. - */ - virtual void popState(GlobalVector& x) = 0; + GlobalVector const& x, + GlobalVector const& x_old, + MathLib::VecNormType norm_type) = 0; /*! Indicate that the computation of a new timestep is being started now. * @@ -142,14 +121,16 @@ public: //! Returns \f$ \hat x \f$, i.e. the discretized approximation of \f$ \dot x //! \f$. - void getXdot(GlobalVector const& x_at_new_timestep, GlobalVector& xdot) const + void getXdot(GlobalVector const& x_at_new_timestep, + GlobalVector const& x_old, + GlobalVector& xdot) const { namespace LinAlg = MathLib::LinAlg; auto const dxdot_dx = getNewXWeight(); // xdot = dxdot_dx * x_at_new_timestep - x_old - getWeightedOldX(xdot); + getWeightedOldX(xdot, x_old); LinAlg::axpby(xdot, dxdot_dx, -1.0, x_at_new_timestep); } @@ -157,7 +138,8 @@ public: virtual double getNewXWeight() const = 0; //! Returns \f$ x_O \f$. - virtual void getWeightedOldX(GlobalVector& y) const = 0; // = x_old + virtual void getWeightedOldX( + GlobalVector& y, GlobalVector const& x_old) const = 0; // = x_old virtual ~TimeDiscretization() = default; @@ -186,34 +168,12 @@ protected: class BackwardEuler final : public TimeDiscretization { public: - BackwardEuler() - : _x_old(NumLib::GlobalVectorProvider::provider.getVector()) - { - } - - ~BackwardEuler() override - { - NumLib::GlobalVectorProvider::provider.releaseVector(_x_old); - } - - void setInitialState(const double t0, GlobalVector const& x0) override - { - _t = t0; - MathLib::LinAlg::copy(x0, _x_old); - } + void setInitialState(const double t0) override { _t = t0; } double getRelativeChangeFromPreviousTimestep( - GlobalVector const& x, MathLib::VecNormType norm_type) override; - - void pushState(const double /*t*/, GlobalVector const& x) override - { - MathLib::LinAlg::copy(x, _x_old); - } - - void popState(GlobalVector& x) override - { - MathLib::LinAlg::copy(_x_old, x); - } + GlobalVector const& x, + GlobalVector const& x_old, + MathLib::VecNormType norm_type) override; void nextTimestep(const double t, const double delta_t) override { @@ -224,12 +184,13 @@ public: double getCurrentTime() const override { return _t; } double getCurrentTimeIncrement() const override { return _delta_t; } double getNewXWeight() const override { return 1.0 / _delta_t; } - void getWeightedOldX(GlobalVector& y) const override + void getWeightedOldX(GlobalVector& y, + GlobalVector const& x_old) const override { namespace LinAlg = MathLib::LinAlg; // y = x_old / delta_t - LinAlg::copy(_x_old, y); + LinAlg::copy(x_old, y); LinAlg::scale(y, 1.0 / _delta_t); } @@ -237,7 +198,6 @@ private: double _t = std::numeric_limits<double>::quiet_NaN(); //!< \f$ t_C \f$ double _delta_t = std::numeric_limits<double>::quiet_NaN(); //!< the timestep size - GlobalVector& _x_old; //!< the solution from the preceding timestep }; //! @} diff --git a/NumLib/ODESolver/TimeDiscretizedODESystem.cpp b/NumLib/ODESolver/TimeDiscretizedODESystem.cpp index 85bd3bd4e080491b0f6377752c58d219dad53a69..21e603274906820cfc0842e54b68c743b7d1a8d2 100644 --- a/NumLib/ODESolver/TimeDiscretizedODESystem.cpp +++ b/NumLib/ODESolver/TimeDiscretizedODESystem.cpp @@ -73,6 +73,7 @@ TimeDiscretizedODESystem< void TimeDiscretizedODESystem<ODESystemTag::FirstOrderImplicitQuasilinear, NonlinearSolverTag::Newton>:: assemble(std::vector<GlobalVector*> const& x_new_timestep, + std::vector<GlobalVector*> const& x_prev, int const process_id) { namespace LinAlg = MathLib::LinAlg; @@ -86,7 +87,8 @@ void TimeDiscretizedODESystem<ODESystemTag::FirstOrderImplicitQuasilinear, for (auto& v : xdot) { v = &NumLib::GlobalVectorProvider::provider.getVector(); - _time_disc.getXdot(*x_new_timestep[process_id], *v); + _time_disc.getXdot(*x_new_timestep[process_id], *x_prev[process_id], + *v); } _M->setZero(); @@ -124,13 +126,14 @@ void TimeDiscretizedODESystem<ODESystemTag::FirstOrderImplicitQuasilinear, void TimeDiscretizedODESystem< ODESystemTag::FirstOrderImplicitQuasilinear, NonlinearSolverTag::Newton>::getResidual(GlobalVector const& x_new_timestep, + GlobalVector const& x_prev, GlobalVector& res) const { // TODO Maybe the duplicate calculation of xdot here and in assembleJacobian // can be optimuized. However, that would make the interface a bit more // fragile. auto& xdot = NumLib::GlobalVectorProvider::provider.getVector(_xdot_id); - _time_disc.getXdot(x_new_timestep, xdot); + _time_disc.getXdot(x_new_timestep, x_prev, xdot); _mat_trans->computeResidual(*_M, *_K, *_b, x_new_timestep, xdot, res); @@ -210,6 +213,7 @@ TimeDiscretizedODESystem< void TimeDiscretizedODESystem<ODESystemTag::FirstOrderImplicitQuasilinear, NonlinearSolverTag::Picard>:: assemble(std::vector<GlobalVector*> const& x_new_timestep, + std::vector<GlobalVector*> const& x_prev, int const process_id) { namespace LinAlg = MathLib::LinAlg; @@ -221,7 +225,8 @@ void TimeDiscretizedODESystem<ODESystemTag::FirstOrderImplicitQuasilinear, for (auto& v : xdot) { v = &NumLib::GlobalVectorProvider::provider.getVector(); - _time_disc.getXdot(*x_new_timestep[process_id], *v); + _time_disc.getXdot(*x_new_timestep[process_id], *x_prev[process_id], + *v); } _M->setZero(); diff --git a/NumLib/ODESolver/TimeDiscretizedODESystem.h b/NumLib/ODESolver/TimeDiscretizedODESystem.h index e28470e0f3293a196f157cf412356c4d76b2942f..fbbe1a84a4692d8237dde58a09132cf8248de4ff 100644 --- a/NumLib/ODESolver/TimeDiscretizedODESystem.h +++ b/NumLib/ODESolver/TimeDiscretizedODESystem.h @@ -83,9 +83,11 @@ public: ~TimeDiscretizedODESystem() override; void assemble(std::vector<GlobalVector*> const& x_new_timestep, + std::vector<GlobalVector*> const& x_prev, int const process_id) override; void getResidual(GlobalVector const& x_new_timestep, + GlobalVector const& x_prev, GlobalVector& res) const override; void getJacobian(GlobalMatrix& Jac) const override; @@ -173,6 +175,7 @@ public: ~TimeDiscretizedODESystem() override; void assemble(std::vector<GlobalVector*> const& x_new_timestep, + std::vector<GlobalVector*> const& x_prev, int const process_id) override; void getA(GlobalMatrix& A) const override @@ -180,9 +183,9 @@ public: _mat_trans->computeA(*_M, *_K, A); } - void getRhs(GlobalVector& rhs) const override + void getRhs(GlobalVector const& x_prev, GlobalVector& rhs) const override { - _mat_trans->computeRhs(*_M, *_K, *_b, rhs); + _mat_trans->computeRhs(*_M, *_K, *_b, x_prev, rhs); } void computeKnownSolutions(GlobalVector const& x, diff --git a/ProcessLib/TimeLoop.cpp b/ProcessLib/TimeLoop.cpp index e7f43b569ed97d0b532430f941d596b7e16dbe8e..53d3da26793d0c817418f1ee3cc17cd9064626b4 100644 --- a/ProcessLib/TimeLoop.cpp +++ b/ProcessLib/TimeLoop.cpp @@ -121,11 +121,13 @@ void setTimeDiscretizedODESystem(ProcessData& process_data) setTimeDiscretizedODESystem(process_data, process_data.process); } -std::vector<GlobalVector*> setInitialConditions( +std::pair<std::vector<GlobalVector*>, std::vector<GlobalVector*>> +setInitialConditions( double const t0, std::vector<std::unique_ptr<ProcessData>> const& per_process_data) { std::vector<GlobalVector*> process_solutions; + std::vector<GlobalVector*> process_solutions_prev; for (auto& process_data : per_process_data) { @@ -139,21 +141,27 @@ std::vector<GlobalVector*> setInitialConditions( process_solutions.emplace_back( &NumLib::GlobalVectorProvider::provider.getVector( ode_sys.getMatrixSpecifications(process_id))); + process_solutions_prev.emplace_back( + &NumLib::GlobalVectorProvider::provider.getVector( + ode_sys.getMatrixSpecifications(process_id))); - auto& x0 = *process_solutions[process_id]; - pcs.setInitialConditions(process_id, t0, x0); - MathLib::LinAlg::finalizeAssembly(x0); + auto& x = *process_solutions[process_id]; + auto& x_prev = *process_solutions_prev[process_id]; + pcs.setInitialConditions(process_id, t0, x); + MathLib::LinAlg::finalizeAssembly(x); - time_disc.setInitialState(t0, x0); // push IC + time_disc.setInitialState(t0); // push IC + MathLib::LinAlg::copy(x, x_prev); // pushState } - return process_solutions; + return {process_solutions, process_solutions_prev}; } void calculateNonEquilibriumInitialResiduum( std::vector<std::unique_ptr<ProcessData>> const& per_process_data, std::vector<GlobalVector*> - process_solutions) + process_solutions, + std::vector<GlobalVector*> const& process_solutions_prev) { INFO("Calculate non-equilibrium initial residuum."); for (auto& process_data : per_process_data) @@ -172,14 +180,15 @@ void calculateNonEquilibriumInitialResiduum( double const dt = 1; time_disc.nextTimestep(t, dt); nonlinear_solver.calculateNonEquilibriumInitialResiduum( - process_solutions, process_data->process_id); + process_solutions, process_solutions_prev, + process_data->process_id); } } NumLib::NonlinearSolverStatus solveOneTimeStepOneProcess( - std::vector<GlobalVector*>& x, std::size_t const timestep, double const t, - double const delta_t, ProcessData const& process_data, - Output& output_control) + std::vector<GlobalVector*>& x, std::vector<GlobalVector*> const& x_prev, + std::size_t const timestep, double const t, double const delta_t, + ProcessData const& process_data, Output& output_control) { auto& process = process_data.process; int const process_id = process_data.process_id; @@ -205,7 +214,7 @@ NumLib::NonlinearSolverStatus solveOneTimeStepOneProcess( }; auto const nonlinear_solver_status = - nonlinear_solver.solve(x, post_iteration_callback, process_id); + nonlinear_solver.solve(x, x_prev, post_iteration_callback, process_id); if (nonlinear_solver_status.error_norms_met) { @@ -262,6 +271,7 @@ double TimeLoop::computeTimeStepping(const double prev_dt, double& t, auto& time_disc = ppd.time_disc; auto const& x = *_process_solutions[i]; + auto const& x_prev = *_process_solutions_prev[i]; auto const& conv_crit = ppd.conv_crit; const MathLib::VecNormType norm_type = @@ -273,7 +283,7 @@ double TimeLoop::computeTimeStepping(const double prev_dt, double& t, ? ((t == timestepper->begin()) ? 0. // Always accepts the zeroth step : time_disc->getRelativeChangeFromPreviousTimestep( - x, norm_type)) + x, x_prev, norm_type)) : 0.; if (!ppd.nonlinear_solver_status.error_norms_met) @@ -324,7 +334,7 @@ double TimeLoop::computeTimeStepping(const double prev_dt, double& t, bool is_initial_step = false; // Reset the time step with the minimum step size, dt - // Update the solution of the previous time step in time_disc. + // Update the solution of the previous time step. for (std::size_t i = 0; i < _per_process_data.size(); i++) { const auto& ppd = *_per_process_data[i]; @@ -337,11 +347,11 @@ double TimeLoop::computeTimeStepping(const double prev_dt, double& t, continue; } - auto& time_disc = ppd.time_disc; auto& x = *_process_solutions[i]; + auto& x_prev = *_process_solutions_prev[i]; if (all_process_steps_accepted) { - time_disc->pushState(t, x); + MathLib::LinAlg::copy(x, x_prev); // pushState } else { @@ -352,7 +362,7 @@ double TimeLoop::computeTimeStepping(const double prev_dt, double& t, "Time step {:d} was rejected {:d} times " "and it will be repeated with a reduced step size.", accepted_steps + 1, _repeating_times_of_rejected_step); - time_disc->popState(x); + MathLib::LinAlg::copy(x_prev, x); // popState } } } @@ -431,7 +441,8 @@ void TimeLoop::initialize() } // init solution storage - _process_solutions = setInitialConditions(_start_time, _per_process_data); + std::tie(_process_solutions, _process_solutions_prev) = + setInitialConditions(_start_time, _per_process_data); if (_chemical_system != nullptr) { @@ -504,8 +515,8 @@ bool TimeLoop::loop() if (!non_equilibrium_initial_residuum_computed) { - calculateNonEquilibriumInitialResiduum(_per_process_data, - _process_solutions); + calculateNonEquilibriumInitialResiduum( + _per_process_data, _process_solutions, _process_solutions_prev); non_equilibrium_initial_residuum_computed = true; } @@ -581,13 +592,13 @@ void preTimestepForAllProcesses( static NumLib::NonlinearSolverStatus solveMonolithicProcess( const double t, const double dt, const std::size_t timestep_id, ProcessData const& process_data, std::vector<GlobalVector*>& x, - Output& output) + std::vector<GlobalVector*> const& x_prev, Output& output) { BaseLib::RunTime time_timestep_process; time_timestep_process.start(); - auto const nonlinear_solver_status = - solveOneTimeStepOneProcess(x, timestep_id, t, dt, process_data, output); + auto const nonlinear_solver_status = solveOneTimeStepOneProcess( + x, x_prev, timestep_id, t, dt, process_data, output); INFO("[time] Solving process #{:d} took {:g} s in time step #{:d} ", process_data.process_id, time_timestep_process.elapsed(), timestep_id); @@ -634,7 +645,8 @@ NumLib::NonlinearSolverStatus TimeLoop::solveUncoupledEquationSystems( { auto const process_id = process_data->process_id; nonlinear_solver_status = solveMonolithicProcess( - t, dt, timestep_id, *process_data, _process_solutions, *_output); + t, dt, timestep_id, *process_data, _process_solutions, + _process_solutions_prev, *_output); process_data->nonlinear_solver_status = nonlinear_solver_status; if (!nonlinear_solver_status.error_norms_met) @@ -704,9 +716,9 @@ TimeLoop::solveCoupledEquationSystemsByStaggeredScheme( process_data->process.setCoupledSolutionsForStaggeredScheme( &coupled_solutions); - nonlinear_solver_status = - solveOneTimeStepOneProcess(_process_solutions, timestep_id, t, - dt, *process_data, *_output); + nonlinear_solver_status = solveOneTimeStepOneProcess( + _process_solutions, _process_solutions_prev, timestep_id, t, dt, + *process_data, *_output); process_data->nonlinear_solver_status = nonlinear_solver_status; INFO( diff --git a/ProcessLib/TimeLoop.h b/ProcessLib/TimeLoop.h index c97f2297552fc162960943a2d922c508a1e0cd53..a555112d361b1fc7309620c529cbd4be6fab1db5 100644 --- a/ProcessLib/TimeLoop.h +++ b/ProcessLib/TimeLoop.h @@ -110,6 +110,7 @@ private: private: std::vector<GlobalVector*> _process_solutions; + std::vector<GlobalVector*> _process_solutions_prev; std::unique_ptr<Output> _output; std::vector<std::unique_ptr<ProcessData>> _per_process_data; diff --git a/Tests/NumLib/TimeLoopSingleODE.h b/Tests/NumLib/TimeLoopSingleODE.h index f0e7b0f46b3ad3cecd19c2a474d558ceeaa8c831..b8986f99962c40dd02f4d8279f47c98e60d954c7 100644 --- a/Tests/NumLib/TimeLoopSingleODE.h +++ b/Tests/NumLib/TimeLoopSingleODE.h @@ -90,9 +90,14 @@ NumLib::NonlinearSolverStatus TimeLoopSingleODE<NLTag>::loop( xs.push_back(&NumLib::GlobalVectorProvider::provider.getVector(x0)); GlobalVector& x = *xs.back(); + std::vector<GlobalVector*> xs_prev; + xs_prev.push_back(&NumLib::GlobalVectorProvider::provider.getVector(x0)); + GlobalVector& x_prev = *xs_prev.back(); + auto& time_disc = _ode_sys.getTimeDiscretization(); - time_disc.setInitialState(t0, x0); // push IC + time_disc.setInitialState(t0); // push IC + MathLib::LinAlg::copy(x, x_prev); // pushState _nonlinear_solver->setEquationSystem(_ode_sys, *_convergence_criterion); @@ -109,13 +114,13 @@ NumLib::NonlinearSolverStatus TimeLoopSingleODE<NLTag>::loop( int const process_id = 0; nonlinear_solver_status = - _nonlinear_solver->solve(xs, nullptr, process_id); + _nonlinear_solver->solve(xs, xs_prev, nullptr, process_id); if (!nonlinear_solver_status.error_norms_met) { break; } - time_disc.pushState(t, x); + MathLib::LinAlg::copy(x, x_prev); // pushState auto const t_cb = t; // make sure the callback cannot overwrite anything.