48 #ifndef MFEM_USE_SUNDIALS 49 #error This example requires that MFEM is built with MFEM_USE_SUNDIALS=YES 55 class ReducedSystemOperator;
82 ReducedSystemOperator *reduced_oper;
101 enum NonlinearSolverType
108 double visc,
double mu,
double K,
109 NonlinearSolverType nls_type);
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();
160 class ReducedSystemOperator :
public Operator 174 void SetParameters(
double dt_,
const Vector *v_,
const Vector *x_);
182 virtual ~ReducedSystemOperator();
188 class ElasticEnergyCoefficient :
public Coefficient 197 : model(m), x(x_) { }
199 virtual ~ElasticEnergyCoefficient() { }
208 bool init_vis =
false);
211 int 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";
561 ReducedSystemOperator::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)
567 void ReducedSystemOperator::SetParameters(
double dt_,
const Vector *v_,
570 dt = dt_; v = v_; x = x_;
583 Operator &ReducedSystemOperator::GetGradient(
const Vector &k)
const 586 Jacobian =
Add(1.0, M->SpMat(), dt, S->SpMat());
590 Jacobian->
Add(dt*dt, *grad_H);
594 ReducedSystemOperator::~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;
686 if (viscosity != 0.0)
691 M_solver.Mult(z, dv_dt);
696 void HyperelasticOperator::ImplicitSolve(
const double dt,
711 reduced_oper->SetParameters(dt, &v, &x);
713 newton_solver->Mult(zero, dv_dt);
714 MFEM_VERIFY(newton_solver->GetConverged(),
715 "Nonlinear solver did not converge.");
717 cout <<
" num nonlin sol iters = " << newton_solver->GetNumIterations()
718 <<
", final norm = " << newton_solver->GetFinalNorm() <<
'\n';
720 add(v, dt, dv_dt, dx_dt);
723 int HyperelasticOperator::SUNImplicitSetup(
const Vector &y,
724 const Vector &fy,
int jok,
int *jcur,
727 int sc = y.
Size() / 2;
731 if (Jacobian) {
delete Jacobian; }
732 Jacobian =
Add(1.0, M.SpMat(), gamma, S.SpMat());
733 grad_H =
dynamic_cast<SparseMatrix *
>(&H.GetGradient(x));
734 Jacobian->
Add(gamma * gamma, *grad_H);
737 J_solver->SetOperator(*Jacobian);
749 int 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);
764 J_solver->iterative_mode =
false;
765 J_solver->Mult(rhs, x_v);
767 add(b_x, saved_gamma, x_v, x_x);
772 double HyperelasticOperator::ElasticEnergy(
const Vector &x)
const 774 return H.GetEnergy(x);
777 double HyperelasticOperator::KineticEnergy(
const Vector &v)
const 779 return 0.5*M.InnerProduct(v, v);
782 void HyperelasticOperator::GetElasticEnergyDensity(
785 ElasticEnergyCoefficient w_coeff(*model, x);
789 HyperelasticOperator::~HyperelasticOperator()
792 delete newton_solver;
803 model.SetTransformation(T);
806 return model.EvalW(J)/J.Det();
820 const double s = 0.1/64.;
823 v(
dim-1) =
s*x(0)*x(0)*(8.0-x(0));
void Init(TimeDependentOperator &f_)
Initialize CVODE: calls CVodeCreate() to create the CVODE memory and set some defaults.
double Eval(ElementTransformation &T, const IntegrationPoint &ip, double t)
Evaluate the coefficient in the element described by T at the point ip at time t. ...
void InitialDeformation(const Vector &x, Vector &y)
Conjugate gradient method.
Class for grid function - Vector with associated FE space.
Data type for scaled Jacobi-type smoother of sparse matrix.
void SetSStolerances(double reltol, double abstol)
Set the scalar relative and scalar absolute tolerances.
A class to handle Vectors in a block fashion.
void SetFromTrueVector()
Shortcut for calling SetFromTrueDofs() with GetTrueVector() as argument.
A coefficient that is constant across space and time.
void PrintOptions(std::ostream &out) const
Print the options.
int Dimension() const
Dimension of the reference space used within the elements.
void GetVectorGradient(ElementTransformation &tr, DenseMatrix &grad) const
Compute the vector gradient with respect to the physical element variable.
void PrintUsage(std::ostream &out) const
Print the usage message.
Base abstract class for first order time dependent operators.
void SwapNodes(GridFunction *&nodes, int &own_nodes_)
Swap the internal node GridFunction pointer and ownership flag members with the given ones...
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
virtual void Step(Vector &x, double &t, double &dt)=0
Perform a time step from time t [in] to time t [out] based on the requested step size dt [in]...
int Size() const
Returns the size of the vector.
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Data type dense matrix using column-major storage.
Abstract class for solving systems of ODEs: dx/dt = f(x,t)
void SetMaxStep(double dt_max)
Set the maximum time step.
bool Good() const
Return true if the command line options were parsed successfully.
Backward Euler ODE solver. L-stable.
void add(const Vector &v1, const Vector &v2, Vector &v)
void SetMaxSetupCalls(int max_calls)
Set maximum number of nonlinear iterations without a Jacobian update.
void InitialVelocity(const Vector &x, Vector &v)
Interface to ARKode's ARKStep module – additive Runge-Kutta methods.
Direct sparse solver using UMFPACK.
void Add(const DenseMatrix &A, const DenseMatrix &B, double alpha, DenseMatrix &C)
C = A + alpha*B.
void SetTrueVector()
Shortcut for calling GetTrueDofs() with GetTrueVector() as argument.
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
void Parse()
Parse the command-line options. Note that this function expects all the options provided through the ...
Interface to the CVODE library – linear multi-step methods.
Interface to the KINSOL library – nonlinear solver methods.
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
void MakeTRef(FiniteElementSpace *f, double *tv)
Associate a new FiniteElementSpace and new true-dof data with the GridFunction.
void SetMaxIter(int max_it)
void SetMaxStep(double dt_max)
Set the maximum time step.
void visualize(ostream &os, Mesh *mesh, GridFunction *deformed_nodes, GridFunction *field, const char *field_name=NULL, bool init_vis=false)
Newton's method for solving F(x)=b for a given operator F.
void PrintInfo() const
Print various ARKStep statistics.
void Add(const int i, const int j, const double val)
double * GetData() const
Return a pointer to the beginning of the Vector data.
void * GetMem() const
Access the SUNDIALS memory structure.
A general vector function coefficient.
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
Mesh * GetMesh() const
Returns the mesh.
The classical explicit forth-order Runge-Kutta method, RK4.
void SetAbsTol(double atol)
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
void SetRelTol(double rtol)
void PrintInfo() const
Print various CVODE statistics.
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
virtual void SetOperator(const Operator &op)
Set the nonlinear Operator of the system and initialize KINSOL.
Base class Coefficients that optionally depend on space and time. These are used by the BilinearFormI...
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...
Third-order, strong stability preserving (SSP) Runge-Kutta method.
int main(int argc, char *argv[])
int SpaceDimension() const
Dimension of the physical space containing the mesh.
const Vector & GetTrueVector() const
Read only access to the (optional) internal true-dof Vector.
Implicit midpoint method. A-stable, not L-stable.
Class for integration point with weight.
virtual void ProjectCoefficient(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
Abstract class for hyperelastic models.
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
virtual void Print(std::ostream &os=mfem::out) const
Arbitrary order H1-conforming (continuous) finite elements.
void GetNodes(Vector &node_coord) const
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
The classical forward Euler method.
void Init(TimeDependentOperator &f_)
Initialize ARKode: calls ARKStepCreate() to create the ARKStep memory and set some defaults...
void SetSStolerances(double reltol, double abstol)
Set the scalar relative and scalar absolute tolerances.
void UseSundialsLinearSolver()
Attach a SUNDIALS GMRES linear solver to ARKode.
virtual void Init(TimeDependentOperator &f_)
Associate a TimeDependentOperator with the ODE solver.
void UseSundialsLinearSolver()
Attach SUNDIALS GMRES linear solver to CVODE.
Vector & GetBlock(int i)
Get the i-th vector in the block.
Arbitrary order "L2-conforming" discontinuous finite elements.
double f(const Vector &p)
void Neg()
(*this) = -(*this)