12 namespace smith::mfem_ext {
15 : mfem::SecondOrderTimeDependentOperator(n, 0.0), state_(std::move(state)), solver_(solver), bcs_(bcs), zero_(n)
27 timestepper_ = timestepper;
29 switch (timestepper) {
31 second_order_ode_solver_ = std::make_unique<mfem::NewmarkSolver>();
34 second_order_ode_solver_ = std::make_unique<mfem::HHTAlphaSolver>();
37 second_order_ode_solver_ = std::make_unique<mfem::WBZAlphaSolver>();
49 "Cannot guarantee stability for AverageAcceleration with time-dependent Dirichlet Boundary Conditions");
50 second_order_ode_solver_ = std::make_unique<mfem::AverageAccelerationSolver>();
53 second_order_ode_solver_ = std::make_unique<mfem::LinearAccelerationSolver>();
56 second_order_ode_solver_ = std::make_unique<mfem::CentralDifferenceSolver>();
59 second_order_ode_solver_ = std::make_unique<mfem::FoxGoodwinSolver>();
62 first_order_system_ode_solver_ = std::make_unique<mfem::BackwardEulerSolver>();
65 SLIC_ERROR_ROOT(
"Timestep method was not a supported second-order ODE method");
68 if (second_order_ode_solver_) {
69 second_order_ode_solver_->Init(*
this);
70 }
else if (first_order_system_ode_solver_) {
73 first_order_system_ode_solver_->Init(*
this);
76 SLIC_ERROR(
"Neither second_order_ode_solver_ nor first_order_system_ode_solver_ specified");
82 if (second_order_ode_solver_) {
84 second_order_ode_solver_->Step(x, dxdt, time, dt);
91 bc.setDofs(U_minus_, t -
epsilon);
93 bc.setDofs(U_plus_, t +
epsilon);
97 for (
int i = 0; i < constrained_dofs.Size(); i++) {
99 dxdt[i] = (U_plus_[i] - U_minus_[i]) / (2.0 *
epsilon);
103 }
else if (first_order_system_ode_solver_) {
105 mfem::Array<int> boffsets(3);
107 boffsets[1] = x.Size();
108 boffsets[2] = x.Size() + dxdt.Size();
109 mfem::BlockVector bx(boffsets);
111 bx.GetBlock(1) = dxdt;
113 first_order_system_ode_solver_->Step(bx, time, dt);
117 dxdt = bx.GetBlock(1);
119 SLIC_ERROR_ROOT(
"Neither second_order_ode_solver_ nor first_order_system_ode_solver_ specified");
135 mfem::Array<int> boffsets(3);
137 boffsets[1] = u.Size() / 2;
138 boffsets[2] = u.Size();
140 const mfem::BlockVector bu(u.GetData(), boffsets);
142 mfem::BlockVector bdu_dt(du_dt.GetData(), boffsets);
144 mfem::Vector u_next(bu.GetBlock(0));
145 u_next.Add(dt, bu.GetBlock(1));
147 Solve(t, dt * dt, dt, u_next,
151 bdu_dt.GetBlock(0) = bu.GetBlock(1);
152 bdu_dt.GetBlock(0).Add(dt, bdu_dt.GetBlock(1));
155 void SecondOrderODE::Solve(
const double time,
const double c0,
const double c1,
const mfem::Vector& u,
156 const mfem::Vector& du_dt, mfem::Vector& d2u_dt2)
const
164 state_.
du_dt = du_dt;
174 bc.setDofs(U_minus_, time -
epsilon);
175 bc.setDofs(U_, time);
176 bc.setDofs(U_plus_, time +
epsilon);
179 bool implicit = (c0 != 0.0 || c1 != 0.0);
185 subtract(1.0 / c0, U_, u, d2U_dt2_);
192 subtract(U_plus_, U_minus_, d2U_dt2_);
203 add(1.0, U_minus_, -2.0, U_, d2U_dt2_);
208 subtract(U_plus_, U_minus_, d2U_dt2_);
214 subtract(U_plus_, U_minus_, dU_dt_);
216 dU_dt_.Add(-1.0 * c1, d2U_dt2_);
219 U_.Add(-1.0 * c0, d2U_dt2_);
223 add(1.0, U_minus_, -2.0, U_, d2U_dt2_);
228 subtract(U_plus_, U_minus_, dU_dt_);
233 state_.
u.SetSubVector(constrained_dofs, 0.0);
234 U_.SetSubVectorComplement(constrained_dofs, 0.0);
237 state_.
du_dt.SetSubVector(constrained_dofs, 0.0);
238 dU_dt_.SetSubVectorComplement(constrained_dofs, 0.0);
239 state_.
du_dt += dU_dt_;
243 d2u_dt2.SetSubVector(constrained_dofs, 0.0);
245 d2u_dt2.SetSubVectorComplement(constrained_dofs, 0.0);
247 solver_.
solve(d2u_dt2);
248 SLIC_WARNING_ROOT_IF(!solver_.
nonlinearSolver().GetConverged(),
"Newton Solver did not converge.");
255 : mfem::TimeDependentOperator(n, 0.0), state_(std::move(state)), solver_(solver), bcs_(bcs), zero_(n)
266 timestepper_ = timestepper;
268 switch (timestepper) {
270 ode_solver_ = std::make_unique<mfem::BackwardEulerSolver>();
273 ode_solver_ = std::make_unique<mfem::SDIRK33Solver>();
276 ode_solver_ = std::make_unique<mfem::ForwardEulerSolver>();
279 ode_solver_ = std::make_unique<mfem::RK2Solver>(0.5);
282 ode_solver_ = std::make_unique<mfem::RK3SSPSolver>();
285 ode_solver_ = std::make_unique<mfem::RK4Solver>();
288 ode_solver_ = std::make_unique<mfem::GeneralizedAlphaSolver>(0.5);
291 ode_solver_ = std::make_unique<mfem::ImplicitMidpointSolver>();
294 ode_solver_ = std::make_unique<mfem::SDIRK23Solver>();
297 ode_solver_ = std::make_unique<mfem::SDIRK34Solver>();
300 SLIC_ERROR_ROOT(
"Timestep method was not a supported first-order ODE method");
302 ode_solver_->Init(*
this);
305 void FirstOrderODE::Solve(
const double time,
const double dt,
const mfem::Vector& u, mfem::Vector& du_dt)
const
321 bc.setDofs(U_minus_, time -
epsilon);
322 bc.setDofs(U_, time);
323 bc.setDofs(U_plus_, time +
epsilon);
326 bool implicit = (dt != 0.0);
332 subtract(1.0 / dt, U_, u, dU_dt_);
338 subtract(1.0 / (2.0 *
epsilon), U_plus_, U_minus_, dU_dt_);
344 subtract(1.0 / (2.0 *
epsilon), U_plus_, U_minus_, dU_dt_);
346 U_.Add(-1.0 * dt, dU_dt_);
350 subtract(1.0 / (2.0 *
epsilon), U_plus_, U_minus_, dU_dt_);
354 state_.
u.SetSubVector(constrained_dofs, 0.0);
355 U_.SetSubVectorComplement(constrained_dofs, 0.0);
358 du_dt = state_.
du_dt;
359 du_dt.SetSubVector(constrained_dofs, 0.0);
360 dU_dt_.SetSubVectorComplement(constrained_dofs, 0.0);
363 solver_.
solve(du_dt);
364 SLIC_WARNING_ROOT_IF(!solver_.
nonlinearSolver().GetConverged(),
"Newton Solver did not converge.");
366 state_.
du_dt = du_dt;
A container for the boundary condition information relating to a specific physics module.
const mfem::Array< int > & allEssentialTrueDofs() const
Returns all the true degrees of freedom associated with all the essential BCs.
std::vector< BoundaryCondition > & essentials()
Accessor for the essential BC objects.
This class manages the objects typically required to solve a nonlinear set of equations arising from ...
mfem::NewtonSolver & nonlinearSolver()
void solve(mfem::Vector &x) const
FirstOrderODE(int n, FirstOrderODE::State &&state, const EquationSolver &solver, const BoundaryConditionManager &bcs)
Constructor defining the size and specific system of ordinary differential equations to be solved.
static constexpr double epsilon
a small number used to compute finite difference approximations to time derivatives of boundary condi...
void SetTimestepper(const smith::TimestepMethod timestepper)
Set the time integration method.
void ImplicitSolve(const double c0, const double c1, const mfem::Vector &u, const mfem::Vector &du_dt, mfem::Vector &d2u_dt2) override
Solves the equation d2u_dt2 = f(u + c0 * d2u_dt2, du_dt + c1 * d2u_dt2, t)
SecondOrderODE(int n, State &&state, const EquationSolver &solver, const BoundaryConditionManager &bcs)
Constructor defining the size and specific system of ordinary differential equations to be solved.
void SetTimestepper(const smith::TimestepMethod timestepper)
Set the time integration method.
void Step(mfem::Vector &x, mfem::Vector &dxdt, double &time, double &dt)
Performs a time step.
static constexpr double epsilon
a small number used to compute finite difference approximations to time derivatives of boundary condi...
TimestepMethod
Timestep method of a solver.
Wrapper classes for using MFEM's ODE solver objects.
A set of references to physics-module-owned variables used by the residual operator.
double & previous_dt
Previous value of dt.
mfem::Vector & u
Predicted true DOFs.
double & time
Time value at which the ODE solver wants to compute a residual.
mfem::Vector & du_dt
Previous value of du_dt.
double & dt
Current time step.
A set of references to physics-module-owned variables used by the residual operator.
double & c0
coefficient used to calculate updated displacement: u_{n + 1} := u + c0 * d2u_dt2
mfem::Vector & du_dt
Predicted du_dt.
mfem::Vector & u
Predicted true DOFs.
mfem::Vector & d2u_dt2
Previous value of d^2u_dt^2.
double & c1
coefficient used to calculate updated velocity: du_dt_{n+1} := du_dt + c1 * d2u_dt2
double & time
Time value at which the ODE solver wants to compute a residual.