48 #ifndef MFEM_USE_SUNDIALS
49 #error This example requires that MFEM is built with MFEM_USE_SUNDIALS=YES
55 class ReducedSystemOperator;
84 ReducedSystemOperator *reduced_oper;
103 enum NonlinearSolverType
110 double visc,
double mu,
double K,
111 NonlinearSolverType nls_type);
118 virtual void ImplicitSolve(
const double dt,
const Vector &x,
Vector &k);
144 virtual int SUNImplicitSetup(
const Vector &y,
const Vector &fy,
145 int jok,
int *jcur,
double gamma);
149 virtual int SUNImplicitSolve(
const Vector &
b,
Vector &x,
double tol);
156 virtual ~HyperelasticOperator();
163 class ReducedSystemOperator :
public Operator
179 void SetParameters(
double dt_,
const Vector *v_,
const Vector *x_);
187 virtual ~ReducedSystemOperator();
193 class ElasticEnergyCoefficient :
public Coefficient
202 : model(m), x(x_) { }
204 virtual ~ElasticEnergyCoefficient() { }
213 bool init_vis =
false);
216 int main(
int argc,
char *argv[])
219 Mpi::Init(argc, argv);
220 int myid = Mpi::WorldRank();
224 const char *mesh_file =
"../../data/beam-quad.mesh";
225 int ser_ref_levels = 2;
226 int par_ref_levels = 0;
228 int ode_solver_type = 3;
229 double t_final = 300.0;
234 bool visualization =
true;
235 const char *nls =
"newton";
239 const double reltol = 1e-1, abstol = 1e-1;
243 const double cvode_eps_lin = 1e-4;
245 const double arkode_eps_nonlin = 1e-6;
248 args.
AddOption(&mesh_file,
"-m",
"--mesh",
249 "Mesh file to use.");
250 args.
AddOption(&ser_ref_levels,
"-rs",
"--refine-serial",
251 "Number of times to refine the mesh uniformly in serial.");
252 args.
AddOption(&par_ref_levels,
"-rp",
"--refine-parallel",
253 "Number of times to refine the mesh uniformly in parallel.");
255 "Order (degree) of the finite elements.");
256 args.
AddOption(&ode_solver_type,
"-s",
"--ode-solver",
258 "1 - Backward Euler,\n\t"
259 "2 - SDIRK2, L-stable\n\t"
260 "3 - SDIRK3, L-stable\n\t"
261 "4 - Implicit Midpoint,\n\t"
262 "5 - SDIRK2, A-stable,\n\t"
263 "6 - SDIRK3, A-stable,\n\t"
264 "7 - Forward Euler,\n\t"
268 "11 - CVODE implicit BDF, approximate Jacobian,\n\t"
269 "12 - CVODE implicit BDF, specified Jacobian,\n\t"
270 "13 - CVODE implicit ADAMS, approximate Jacobian,\n\t"
271 "14 - CVODE implicit ADAMS, specified Jacobian,\n\t"
272 "15 - ARKODE implicit, approximate Jacobian,\n\t"
273 "16 - ARKODE implicit, specified Jacobian,\n\t"
274 "17 - ARKODE explicit, 4th order.");
275 args.
AddOption(&nls,
"-nls",
"--nonlinear-solver",
276 "Nonlinear systems solver: "
277 "\"newton\" (plain Newton) or \"kinsol\" (KINSOL).");
278 args.
AddOption(&t_final,
"-tf",
"--t-final",
279 "Final time; start time is 0.");
280 args.
AddOption(&dt,
"-dt",
"--time-step",
282 args.
AddOption(&visc,
"-v",
"--viscosity",
283 "Viscosity coefficient.");
284 args.
AddOption(&mu,
"-mu",
"--shear-modulus",
285 "Shear modulus in the Neo-Hookean hyperelastic model.");
286 args.
AddOption(&K,
"-K",
"--bulk-modulus",
287 "Bulk modulus in the Neo-Hookean hyperelastic model.");
288 args.
AddOption(&visualization,
"-vis",
"--visualization",
"-no-vis",
289 "--no-visualization",
290 "Enable or disable GLVis visualization.");
291 args.
AddOption(&vis_steps,
"-vs",
"--visualization-steps",
292 "Visualize every n-th timestep.");
308 if (ode_solver_type < 1 || ode_solver_type > 17)
312 cout <<
"Unknown ODE solver type: " << ode_solver_type <<
'\n';
320 Mesh *mesh =
new Mesh(mesh_file, 1, 1);
324 map<string,HyperelasticOperator::NonlinearSolverType> nls_map;
325 nls_map[
"newton"] = HyperelasticOperator::NEWTON;
326 nls_map[
"kinsol"] = HyperelasticOperator::KINSOL;
327 if (nls_map.find(nls) == nls_map.end())
331 cout <<
"Unknown type of nonlinear solver: " << nls << endl;
340 for (
int lev = 0; lev < ser_ref_levels; lev++)
350 for (
int lev = 0; lev < par_ref_levels; lev++)
367 cout <<
"Number of velocity/deformation unknowns: " << glob_size << endl;
372 true_offset[1] = true_size;
373 true_offset[2] = 2*true_size;
377 v_gf.
MakeTRef(&fespace, vx, true_offset[0]);
378 x_gf.
MakeTRef(&fespace, vx, true_offset[1]);
404 HyperelasticOperator oper(fespace, ess_bdr, visc, mu, K, nls_map[nls]);
411 vis_v.
open(vishost, visport);
413 visualize(vis_v, pmesh, &x_gf, &v_gf,
"Velocity",
true);
417 vis_w.
open(vishost, visport);
420 oper.GetElasticEnergyDensity(x_gf, w_gf);
422 visualize(vis_w, pmesh, &x_gf, &w_gf,
"Elastic energy density",
true);
426 double ee0 = oper.ElasticEnergy(x_gf);
427 double ke0 = oper.KineticEnergy(v_gf);
430 cout <<
"initial elastic energy (EE) = " << ee0 << endl;
431 cout <<
"initial kinetic energy (KE) = " << ke0 << endl;
432 cout <<
"initial total energy (TE) = " << (ee0 + ke0) << endl;
444 switch (ode_solver_type)
456 case 8: ode_solver =
new RK2Solver(0.5);
break;
458 case 10: ode_solver =
new RK4Solver;
break;
465 CVodeSetEpsLin(cvode->
GetMem(), cvode_eps_lin);
467 if (ode_solver_type == 11)
471 ode_solver = cvode;
break;
478 CVodeSetEpsLin(cvode->
GetMem(), cvode_eps_lin);
480 if (ode_solver_type == 13)
484 ode_solver = cvode;
break;
488 arkode =
new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::IMPLICIT);
491 ARKStepSetNonlinConvCoef(arkode->
GetMem(), arkode_eps_nonlin);
493 if (ode_solver_type == 15)
497 ode_solver = arkode;
break;
500 arkode =
new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::EXPLICIT);
504 ode_solver = arkode;
break;
508 if (ode_solver_type < 11) { ode_solver->
Init(oper); }
512 bool last_step =
false;
513 for (
int ti = 1; !last_step; ti++)
515 double dt_real = min(dt, t_final - t);
517 ode_solver->
Step(vx, t, dt_real);
519 last_step = (t >= t_final - 1e-8*dt);
521 if (last_step || (ti % vis_steps) == 0)
525 double ee = oper.ElasticEnergy(x_gf);
526 double ke = oper.KineticEnergy(v_gf);
530 cout <<
"step " << ti <<
", t = " << t <<
", EE = " << ee
531 <<
", KE = " << ke <<
", ΔTE = " << (ee+ke)-(ee0+ke0) << endl;
534 else if (arkode) { arkode->
PrintInfo(); }
542 oper.GetElasticEnergyDensity(x_gf, w_gf);
556 ostringstream mesh_name, velo_name, ee_name;
557 mesh_name <<
"deformed." << setfill(
'0') << setw(6) << myid;
558 velo_name <<
"velocity." << setfill(
'0') << setw(6) << myid;
559 ee_name <<
"elastic_energy." << setfill(
'0') << setw(6) << myid;
561 ofstream mesh_ofs(mesh_name.str().c_str());
562 mesh_ofs.precision(8);
563 pmesh->
Print(mesh_ofs);
565 ofstream velo_ofs(velo_name.str().c_str());
566 velo_ofs.precision(8);
568 ofstream ee_ofs(ee_name.str().c_str());
570 oper.GetElasticEnergyDensity(x_gf, w_gf);
595 os <<
"solution\n" << *mesh << *field;
601 os <<
"window_size 800 800\n";
602 os <<
"window_title '" << field_name <<
"'\n";
609 os <<
"autoscale value\n";
616 ReducedSystemOperator::ReducedSystemOperator(
619 :
Operator(M_->ParFESpace()->TrueVSize()), M(M_), S(S_), H(H_),
620 Jacobian(NULL), dt(0.0), v(NULL), x(NULL), w(height), z(height),
621 ess_tdof_list(ess_tdof_list_)
624 void ReducedSystemOperator::SetParameters(
double dt_,
const Vector *v_,
627 dt = dt_; v = v_; x = x_;
636 M->TrueAddMult(k, y);
637 S->TrueAddMult(w, y);
641 Operator &ReducedSystemOperator::GetGradient(
const Vector &k)
const
647 localJ->
Add(dt*dt, H->GetLocalGradient(z));
648 Jacobian = M->ParallelAssemble(localJ);
655 ReducedSystemOperator::~ReducedSystemOperator()
664 NonlinearSolverType nls_type)
666 M(&fespace), S(&fespace), H(&fespace),
667 viscosity(visc), M_solver(f.GetComm()), z(height/2),
668 local_grad_H(NULL), Jacobian(NULL)
670 const double rel_tol = 1e-8;
671 const int skip_zero_entries = 0;
673 const double ref_density = 1.0;
676 M.Assemble(skip_zero_entries);
677 M.Finalize(skip_zero_entries);
678 Mmat = M.ParallelAssemble();
679 fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
683 M_solver.iterative_mode =
false;
684 M_solver.SetRelTol(rel_tol);
685 M_solver.SetAbsTol(0.0);
686 M_solver.SetMaxIter(30);
687 M_solver.SetPrintLevel(0);
688 M_prec.SetType(HypreSmoother::Jacobi);
689 M_solver.SetPreconditioner(M_prec);
690 M_solver.SetOperator(*Mmat);
694 H.SetEssentialTrueDofs(ess_tdof_list);
698 S.Assemble(skip_zero_entries);
699 S.Finalize(skip_zero_entries);
701 reduced_oper =
new ReducedSystemOperator(&M, &S, &H, ess_tdof_list);
704 J_hypreSmoother->
SetType(HypreSmoother::l1Jacobi);
706 J_prec = J_hypreSmoother;
716 if (nls_type == KINSOL)
721 newton_solver = kinsolver;
723 newton_solver->SetMaxIter(200);
724 newton_solver->SetRelTol(rel_tol);
725 newton_solver->SetPrintLevel(1);
732 newton_solver->SetMaxIter(10);
733 newton_solver->SetRelTol(rel_tol);
734 newton_solver->SetPrintLevel(-1);
736 newton_solver->SetSolver(*J_solver);
737 newton_solver->iterative_mode =
false;
750 if (viscosity != 0.0)
756 M_solver.Mult(z, dv_dt);
761 void HyperelasticOperator::ImplicitSolve(
const double dt,
776 reduced_oper->SetParameters(dt, &v, &x);
778 newton_solver->Mult(zero, dv_dt);
779 MFEM_VERIFY(newton_solver->GetConverged(),
780 "Nonlinear solver did not converge.");
782 if (fespace.GetMyRank() == 0)
784 cout <<
" num nonlin sol iters = " << newton_solver->GetNumIterations()
785 <<
", final norm = " << newton_solver->GetFinalNorm() <<
'\n';
788 add(v, dt, dv_dt, dx_dt);
791 int HyperelasticOperator::SUNImplicitSetup(
const Vector &y,
792 const Vector &fy,
int jok,
int *jcur,
795 int sc = y.
Size() / 2;
799 if (Jacobian) {
delete Jacobian; }
801 local_grad_H = &H.GetLocalGradient(x);
802 localJ->
Add(gamma*gamma, *local_grad_H);
803 Jacobian = M.ParallelAssemble(localJ);
809 J_solver->SetOperator(*Jacobian);
821 int HyperelasticOperator::SUNImplicitSolve(
const Vector &
b,
Vector &x,
824 int sc = b.
Size() / 2;
836 lb_x.Distribute(b_x);
837 local_grad_H->Mult(lb_x, lrhs);
838 lrhs.ParallelAssemble(rhs);
840 M.TrueAddMult(b_v, rhs);
841 rhs.SetSubVector(ess_tdof_list, 0.0);
843 J_solver->iterative_mode =
false;
844 J_solver->Mult(rhs, x_v);
846 add(b_x, saved_gamma, x_v, x_x);
851 double HyperelasticOperator::ElasticEnergy(
const ParGridFunction &x)
const
853 return H.GetEnergy(x);
856 double HyperelasticOperator::KineticEnergy(
const ParGridFunction &v)
const
858 double loc_energy = 0.5*M.InnerProduct(v, v);
860 MPI_Allreduce(&loc_energy, &energy, 1, MPI_DOUBLE, MPI_SUM,
865 void HyperelasticOperator::GetElasticEnergyDensity(
868 ElasticEnergyCoefficient w_coeff(*model, x);
872 HyperelasticOperator::~HyperelasticOperator()
875 delete newton_solver;
887 model.SetTransformation(T);
890 return model.EvalW(J)/J.Det();
904 const double s = 0.1/64.;
907 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.
void EliminateRowsCols(const Array< int > &rows_cols, const HypreParVector &X, HypreParVector &B)
void SetSubVector(const Array< int > &dofs, const double value)
Set the entries listed in dofs to the given value.
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.
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.
int TrueVSize() const
Obsolete, kept for backward compatibility.
Base abstract class for first order time dependent operators.
void SwapNodes(GridFunction *&nodes, int &own_nodes_)
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]...
HYPRE_BigInt GlobalTrueVSize() const
void * GetMem() const
Access the SUNDIALS memory structure.
Data type dense matrix using column-major storage.
int Size() const
Returns the size of the vector.
Abstract class for solving systems of ODEs: dx/dt = f(x,t)
virtual void Save(std::ostream &out) const
void SetMaxStep(double dt_max)
Set the maximum time step.
Abstract parallel finite element space.
virtual void ProjectCoefficient(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
Backward Euler ODE solver. L-stable.
double * GetData() const
Return a pointer to the beginning of the Vector data.
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)
void SetPositiveDiagonal(bool pos=true)
After computing l1-norms, replace them with their absolute values.
Interface to ARKode's ARKStep module – additive Runge-Kutta methods.
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 ...
Mesh * GetMesh() const
Returns the mesh.
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)
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
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 SetJFNK(bool use_jfnk)
Set the Jacobian Free Newton Krylov flag. The default is false.
Parallel smoothers in hypre.
void PrintUsage(std::ostream &out) const
Print the usage message.
void Add(const int i, const int j, const double val)
A general vector function coefficient.
int SpaceDimension() const
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)
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.
void SetLSMaxIter(int m)
Set the maximum number of linear solver iterations.
void GetVectorGradient(ElementTransformation &tr, DenseMatrix &grad) const
Implicit midpoint method. A-stable, not L-stable.
Class for integration point with weight.
void PrintInfo() const
Print various ARKStep statistics.
void PrintOptions(std::ostream &out) const
Print the options.
Abstract class for hyperelastic models.
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
void GetNodes(Vector &node_coord) const
Arbitrary order H1-conforming (continuous) finite elements.
void PrintInfo() const
Print various CVODE statistics.
void Print(std::ostream &out=mfem::out) const override
Class for parallel grid function.
The classical forward Euler method.
Wrapper for hypre's ParCSR matrix class.
void Init(TimeDependentOperator &f_)
Initialize ARKode: calls ARKStepCreate() to create the ARKStep memory and set some defaults...
Class for parallel meshes.
void SetSStolerances(double reltol, double abstol)
Set the scalar relative and scalar absolute tolerances.
void UseSundialsLinearSolver()
Attach a SUNDIALS GMRES linear solver to ARKode.
void SetType(HypreSmoother::Type type, int relax_times=1)
Set the relaxation type and number of sweeps.
virtual void Init(TimeDependentOperator &f_)
Associate a TimeDependentOperator with the ODE solver.
void UseSundialsLinearSolver()
Attach SUNDIALS GMRES linear solver to CVODE.
virtual void SetOperator(const Operator &op)
Also calls SetOperator for the preconditioner if there is one.
Arbitrary order "L2-conforming" discontinuous finite elements.
double f(const Vector &p)
bool Good() const
Return true if the command line options were parsed successfully.