48#ifndef MFEM_USE_SUNDIALS
49#error This example requires that MFEM is built with MFEM_USE_SUNDIALS=YES
55class ReducedSystemOperator;
82 ReducedSystemOperator *reduced_oper;
101 enum NonlinearSolverType
108 double visc,
double mu,
double K,
109 NonlinearSolverType nls_type);
112 virtual void Mult(
const Vector &vx,
Vector &dvx_dt)
const;
116 virtual void ImplicitSolve(
const double dt,
const Vector &x,
Vector &k);
142 virtual int SUNImplicitSetup(
const Vector &y,
const Vector &fy,
143 int jok,
int *jcur,
double gamma);
147 virtual int SUNImplicitSolve(
const Vector &
b,
Vector &x,
double tol);
149 double ElasticEnergy(
const Vector &x)
const;
150 double KineticEnergy(
const Vector &v)
const;
153 virtual ~HyperelasticOperator();
160class ReducedSystemOperator :
public Operator
174 void SetParameters(
double dt_,
const Vector *v_,
const Vector *x_);
182 virtual ~ReducedSystemOperator();
197 : model(m), x(x_) { }
199 virtual ~ElasticEnergyCoefficient() { }
208 bool init_vis =
false);
211int main(
int argc,
char *argv[])
217 const char *mesh_file =
"../../data/beam-quad.mesh";
220 int ode_solver_type = 3;
221 double t_final = 300.0;
226 bool visualization =
true;
227 const char *nls =
"newton";
231 const double reltol = 1e-1, abstol = 1e-1;
235 const double cvode_eps_lin = 1e-4;
237 const double arkode_eps_nonlin = 1e-6;
240 args.
AddOption(&mesh_file,
"-m",
"--mesh",
241 "Mesh file to use.");
242 args.
AddOption(&ref_levels,
"-r",
"--refine",
243 "Number of times to refine the mesh uniformly.");
245 "Order (degree) of the finite elements.");
246 args.
AddOption(&ode_solver_type,
"-s",
"--ode-solver",
248 "1 - Backward Euler,\n\t"
249 "2 - SDIRK2, L-stable\n\t"
250 "3 - SDIRK3, L-stable\n\t"
251 "4 - Implicit Midpoint,\n\t"
252 "5 - SDIRK2, A-stable,\n\t"
253 "6 - SDIRK3, A-stable,\n\t"
254 "7 - Forward Euler,\n\t"
258 "11 - CVODE implicit BDF, approximate Jacobian,\n\t"
259 "12 - CVODE implicit BDF, specified Jacobian,\n\t"
260 "13 - CVODE implicit ADAMS, approximate Jacobian,\n\t"
261 "14 - CVODE implicit ADAMS, specified Jacobian,\n\t"
262 "15 - ARKODE implicit, approximate Jacobian,\n\t"
263 "16 - ARKODE implicit, specified Jacobian,\n\t"
264 "17 - ARKODE explicit, 4th order.");
265 args.
AddOption(&nls,
"-nls",
"--nonlinear-solver",
266 "Nonlinear systems solver: "
267 "\"newton\" (plain Newton) or \"kinsol\" (KINSOL).");
268 args.
AddOption(&t_final,
"-tf",
"--t-final",
269 "Final time; start time is 0.");
270 args.
AddOption(&dt,
"-dt",
"--time-step",
272 args.
AddOption(&visc,
"-v",
"--viscosity",
273 "Viscosity coefficient.");
275 "Shear modulus in the Neo-Hookean hyperelastic model.");
276 args.
AddOption(&K,
"-K",
"--bulk-modulus",
277 "Bulk modulus in the Neo-Hookean hyperelastic model.");
278 args.
AddOption(&visualization,
"-vis",
"--visualization",
"-no-vis",
279 "--no-visualization",
280 "Enable or disable GLVis visualization.");
281 args.
AddOption(&vis_steps,
"-vs",
"--visualization-steps",
282 "Visualize every n-th timestep.");
292 if (ode_solver_type < 1 || ode_solver_type > 17)
294 cout <<
"Unknown ODE solver type: " << ode_solver_type <<
'\n';
300 Mesh *mesh =
new Mesh(mesh_file, 1, 1);
304 map<string,HyperelasticOperator::NonlinearSolverType> nls_map;
305 nls_map[
"newton"] = HyperelasticOperator::NEWTON;
306 nls_map[
"kinsol"] = HyperelasticOperator::KINSOL;
307 if (nls_map.find(nls) == nls_map.end())
309 cout <<
"Unknown type of nonlinear solver: " << nls << endl;
316 for (
int lev = 0; lev < ref_levels; lev++)
331 cout <<
"Number of velocity/deformation unknowns: " << fe_size << endl;
334 fe_offset[1] = fe_size;
335 fe_offset[2] = 2*fe_size;
364 HyperelasticOperator oper(fespace, ess_bdr, visc,
mu, K, nls_map[nls]);
374 visualize(vis_v, mesh, &x, &v,
"Velocity",
true);
378 oper.GetElasticEnergyDensity(x, w);
380 visualize(vis_w, mesh, &x, &w,
"Elastic energy density",
true);
386 cout <<
"initial elastic energy (EE) = " << ee0 << endl;
387 cout <<
"initial kinetic energy (KE) = " << ke0 << endl;
388 cout <<
"initial total energy (TE) = " << (ee0 + ke0) << endl;
399 switch (ode_solver_type)
411 case 8: ode_solver =
new RK2Solver(0.5);
break;
413 case 10: ode_solver =
new RK4Solver;
break;
420 CVodeSetEpsLin(cvode->
GetMem(), cvode_eps_lin);
422 if (ode_solver_type == 11)
426 ode_solver = cvode;
break;
433 CVodeSetEpsLin(cvode->
GetMem(), cvode_eps_lin);
435 if (ode_solver_type == 13)
439 ode_solver = cvode;
break;
446 ARKStepSetNonlinConvCoef(arkode->
GetMem(), arkode_eps_nonlin);
448 if (ode_solver_type == 15)
452 ode_solver = arkode;
break;
459 ode_solver = arkode;
break;
463 if (ode_solver_type < 11) { ode_solver->
Init(oper); }
467 bool last_step =
false;
468 for (
int ti = 1; !last_step; ti++)
470 double dt_real = min(dt, t_final -
t);
472 ode_solver->
Step(vx,
t, dt_real);
474 last_step = (
t >= t_final - 1e-8*dt);
476 if (last_step || (ti % vis_steps) == 0)
481 cout <<
"step " << ti <<
", t = " <<
t <<
", EE = " << ee <<
", KE = "
482 << ke <<
", ΔTE = " << (ee+ke)-(ee0+ke0) << endl;
485 else if (arkode) { arkode->
PrintInfo(); }
493 oper.GetElasticEnergyDensity(x, w);
506 ofstream mesh_ofs(
"deformed.mesh");
507 mesh_ofs.precision(8);
508 mesh->
Print(mesh_ofs);
510 ofstream velo_ofs(
"velocity.sol");
511 velo_ofs.precision(8);
513 ofstream ee_ofs(
"elastic_energy.sol");
515 oper.GetElasticEnergyDensity(x, w);
528 GridFunction *field,
const char *field_name,
bool init_vis)
540 os <<
"solution\n" << *mesh << *field;
546 os <<
"window_size 800 800\n";
547 os <<
"window_title '" << field_name <<
"'\n";
554 os <<
"autoscale value\n";
561ReducedSystemOperator::ReducedSystemOperator(
563 :
Operator(M_->Height()), M(M_), S(S_), H(H_), Jacobian(NULL),
564 dt(0.0), v(NULL), x(NULL), w(height), z(height)
567void ReducedSystemOperator::SetParameters(
double dt_,
const Vector *v_,
570 dt = dt_; v = v_; x = x_;
573void ReducedSystemOperator::Mult(
const Vector &k,
Vector &y)
const
583Operator &ReducedSystemOperator::GetGradient(
const Vector &k)
const
590 Jacobian->
Add(dt*dt, *grad_H);
594ReducedSystemOperator::~ReducedSystemOperator()
603 NonlinearSolverType nls_type)
605 M(&fespace), S(&fespace), H(&fespace),
606 viscosity(visc), z(height/2),
607 grad_H(NULL), Jacobian(NULL)
609 const double rel_tol = 1e-8;
610 const int skip_zero_entries = 0;
612 const double ref_density = 1.0;
615 M.Assemble(skip_zero_entries);
617 fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
619 M.FormSystemMatrix(ess_tdof_list, tmp);
621 M_solver.iterative_mode =
false;
622 M_solver.SetRelTol(rel_tol);
623 M_solver.SetAbsTol(0.0);
624 M_solver.SetMaxIter(30);
625 M_solver.SetPrintLevel(0);
626 M_solver.SetPreconditioner(M_prec);
627 M_solver.SetOperator(M.SpMat());
631 H.SetEssentialTrueDofs(ess_tdof_list);
635 S.Assemble(skip_zero_entries);
636 S.FormSystemMatrix(ess_tdof_list, tmp);
638 reduced_oper =
new ReducedSystemOperator(&M, &S, &H);
640#ifndef MFEM_USE_SUITESPARSE
654 if (nls_type == KINSOL)
657 newton_solver = kinsolver;
659 newton_solver->SetMaxIter(200);
660 newton_solver->SetRelTol(rel_tol);
661 newton_solver->SetPrintLevel(0);
667 newton_solver->SetOperator(*reduced_oper);
668 newton_solver->SetMaxIter(10);
669 newton_solver->SetRelTol(rel_tol);
670 newton_solver->SetPrintLevel(-1);
672 newton_solver->SetSolver(*J_solver);
673 newton_solver->iterative_mode =
false;
676void HyperelasticOperator::Mult(
const Vector &vx,
Vector &dvx_dt)
const
686 if (viscosity != 0.0)
691 M_solver.
Mult(z, dv_dt);
696void HyperelasticOperator::ImplicitSolve(
const double dt,
711 reduced_oper->SetParameters(dt, &v, &x);
713 newton_solver->
Mult(zero, dv_dt);
715 "Nonlinear solver did not converge.");
718 <<
", final norm = " << newton_solver->
GetFinalNorm() <<
'\n';
720 add(v, dt, dv_dt, dx_dt);
723int HyperelasticOperator::SUNImplicitSetup(
const Vector &y,
724 const Vector &fy,
int jok,
int *jcur,
727 int sc = y.
Size() / 2;
731 if (Jacobian) {
delete Jacobian; }
734 Jacobian->
Add(gamma * gamma, *grad_H);
749int HyperelasticOperator::SUNImplicitSolve(
const Vector &
b,
Vector &x,
752 int sc =
b.Size() / 2;
753 Vector b_v(
b.GetData() + 0, sc);
754 Vector b_x(
b.GetData() + sc, sc);
760 grad_H->
Mult(b_x, rhs);
765 J_solver->
Mult(rhs, x_v);
767 add(b_x, saved_gamma, x_v, x_x);
772double HyperelasticOperator::ElasticEnergy(
const Vector &x)
const
777double HyperelasticOperator::KineticEnergy(
const Vector &v)
const
782void HyperelasticOperator::GetElasticEnergyDensity(
785 ElasticEnergyCoefficient w_coeff(*model, x);
789HyperelasticOperator::~HyperelasticOperator()
792 delete newton_solver;
820 const double s = 0.1/64.;
823 v(
dim-1) =
s*x(0)*x(0)*(8.0-x(0));
Interface to ARKode's ARKStep module – additive Runge-Kutta methods.
void SetMaxStep(double dt_max)
Set the maximum time step.
void PrintInfo() const
Print various ARKStep statistics.
void Init(TimeDependentOperator &f_)
Initialize ARKode: calls ARKStepCreate() to create the ARKStep memory and set some defaults.
@ IMPLICIT
Implicit RK method.
@ EXPLICIT
Explicit RK method.
void UseSundialsLinearSolver()
Attach a SUNDIALS GMRES linear solver to ARKode.
void SetSStolerances(double reltol, double abstol)
Set the scalar relative and scalar absolute tolerances.
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Backward Euler ODE solver. L-stable.
A class to handle Vectors in a block fashion.
Vector & GetBlock(int i)
Get the i-th vector in the block.
Conjugate gradient method.
virtual void Mult(const Vector &b, Vector &x) const
Iterative solution of the linear system using the Conjugate Gradient method.
Interface to the CVODE library – linear multi-step methods.
void SetSStolerances(double reltol, double abstol)
Set the scalar relative and scalar absolute tolerances.
void SetMaxStep(double dt_max)
Set the maximum time step.
void Init(TimeDependentOperator &f_)
Initialize CVODE: calls CVodeCreate() to create the CVODE memory and set some defaults.
void PrintInfo() const
Print various CVODE statistics.
void UseSundialsLinearSolver()
Attach SUNDIALS GMRES linear solver to CVODE.
Base class Coefficients that optionally depend on space and time. These are used by the BilinearFormI...
A coefficient that is constant across space and time.
Data type for scaled Jacobi-type smoother of sparse matrix.
Data type dense matrix using column-major storage.
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
Mesh * GetMesh() const
Returns the mesh.
The classical forward Euler method.
Class for grid function - Vector with associated FE space.
void GetVectorGradient(ElementTransformation &tr, DenseMatrix &grad) const
Compute the vector gradient with respect to the physical element variable.
void SetTrueVector()
Shortcut for calling GetTrueDofs() with GetTrueVector() as argument.
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
void MakeTRef(FiniteElementSpace *f, real_t *tv)
Associate a new FiniteElementSpace and new true-dof data with the GridFunction.
void SetFromTrueVector()
Shortcut for calling SetFromTrueDofs() with GetTrueVector() as argument.
const Vector & GetTrueVector() const
Read only access to the (optional) internal true-dof Vector.
virtual void ProjectCoefficient(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
Arbitrary order H1-conforming (continuous) finite elements.
Abstract class for hyperelastic models.
virtual real_t EvalW(const DenseMatrix &Jpt) const =0
Evaluate the strain energy density function, W = W(Jpt).
void SetTransformation(ElementTransformation &Ttr_)
Implicit midpoint method. A-stable, not L-stable.
Class for integration point with weight.
real_t GetFinalNorm() const
Returns the final residual norm after termination of the solver during the last call to Mult().
void SetRelTol(real_t rtol)
int GetNumIterations() const
Returns the number of iterations taken during the last call to Mult()
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
void SetMaxIter(int max_it)
bool GetConverged() const
Returns true if the last call to Mult() converged successfully.
void SetAbsTol(real_t atol)
Interface to the KINSOL library – nonlinear solver methods.
virtual void SetOperator(const Operator &op)
Set the nonlinear Operator of the system and initialize KINSOL.
void SetMaxSetupCalls(int max_calls)
Set maximum number of nonlinear iterations without a Jacobian update.
Arbitrary order "L2-conforming" discontinuous finite elements.
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
virtual void Print(std::ostream &os=mfem::out, const std::string &comments="") const
int Dimension() const
Dimension of the reference space used within the elements.
int SpaceDimension() const
Dimension of the physical space containing the mesh.
void GetNodes(Vector &node_coord) const
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
void SwapNodes(GridFunction *&nodes, int &own_nodes_)
Swap the internal node GridFunction pointer and ownership flag members with the given ones.
Newton's method for solving F(x)=b for a given operator F.
virtual void Mult(const Vector &b, Vector &x) const
Solve the nonlinear system with right-hand side b.
Abstract class for solving systems of ODEs: dx/dt = f(x,t)
virtual void Init(TimeDependentOperator &f_)
Associate a TimeDependentOperator with the ODE solver.
virtual void Step(Vector &x, real_t &t, real_t &dt)=0
Perform a time step from time t [in] to time t [out] based on the requested step size dt [in].
int height
Dimension of the output / number of rows in the matrix.
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
void Parse()
Parse the command-line options. Note that this function expects all the options provided through the ...
void PrintUsage(std::ostream &out) const
Print the usage message.
void PrintOptions(std::ostream &out) const
Print the options.
void AddOption(bool *var, const char *enable_short_name, const char *enable_long_name, const char *disable_short_name, const char *disable_long_name, const char *description, bool required=false)
Add a boolean option and set 'var' to receive the value. Enable/disable tags are used to set the bool...
bool Good() const
Return true if the command line options were parsed successfully.
Third-order, strong stability preserving (SSP) Runge-Kutta method.
The classical explicit forth-order Runge-Kutta method, RK4.
bool iterative_mode
If true, use the second argument of Mult() as an initial guess.
virtual void SetOperator(const Operator &op)=0
Set/update the solver for the given operator.
void Add(const int i, const int j, const real_t val)
virtual void Mult(const Vector &x, Vector &y) const
Matrix vector multiplication.
void * GetMem() const
Access the SUNDIALS memory structure.
Base abstract class for first order time dependent operators.
virtual void SetTime(const real_t t_)
Set the current time.
Direct sparse solver using UMFPACK.
A general vector function coefficient.
void Neg()
(*this) = -(*this)
int Size() const
Returns the size of the vector.
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
void add(const Vector &v1, const Vector &v2, Vector &v)
std::function< real_t(const Vector &)> f(real_t mass_coeff)
void Add(const DenseMatrix &A, const DenseMatrix &B, real_t alpha, DenseMatrix &C)
C = A + alpha*B.
void visualize(ostream &os, Mesh *mesh, GridFunction *deformed_nodes, GridFunction *field, const char *field_name=NULL, bool init_vis=false)
void InitialDeformation(const Vector &x, Vector &y)
void InitialVelocity(const Vector &x, Vector &v)