47 #ifndef MFEM_USE_SUNDIALS
48 #error This example requires that MFEM is built with MFEM_USE_SUNDIALS=YES
54 class ReducedSystemOperator;
55 class SundialsJacSolver;
82 ReducedSystemOperator *reduced_oper;
96 enum NonlinearSolverType
103 double visc,
double mu,
double K,
104 NonlinearSolverType nls_type);
110 virtual void ImplicitSolve(
const double dt,
const Vector &x,
Vector &k);
116 void InitSundialsJacSolver(SundialsJacSolver &sjsolv);
118 double ElasticEnergy(
Vector &x)
const;
119 double KineticEnergy(
Vector &v)
const;
122 virtual ~HyperelasticOperator();
129 class ReducedSystemOperator :
public Operator
143 void SetParameters(
double dt_,
const Vector *v_,
const Vector *x_);
151 virtual ~ReducedSystemOperator();
176 : M(), S(), H(), grad_H(), Jacobian(), J_solver() { }
182 M = &M_; S = &S_; H = &H_; J_solver = &solver;
192 int InitSystem(
void *sundials_mem);
193 int SetupSystem(
void *sundials_mem,
int conv_fail,
194 const Vector &y_pred,
const Vector &f_pred,
int &jac_cur,
196 int SolveSystem(
void *sundials_mem,
Vector &b,
const Vector &weight,
198 int FreeSystem(
void *sundials_mem);
204 class ElasticEnergyCoefficient :
public Coefficient
213 : model(m), x(x_) { }
215 virtual ~ElasticEnergyCoefficient() { }
224 bool init_vis =
false);
227 int main(
int argc,
char *argv[])
230 const char *mesh_file =
"../../data/beam-quad.mesh";
233 int ode_solver_type = 3;
234 double t_final = 300.0;
239 bool visualization =
true;
240 const char *nls =
"newton";
244 const double reltol = 1e-1, abstol = 1e-1;
247 args.
AddOption(&mesh_file,
"-m",
"--mesh",
248 "Mesh file to use.");
249 args.
AddOption(&ref_levels,
"-r",
"--refine",
250 "Number of times to refine the mesh uniformly.");
252 "Order (degree) of the finite elements.");
253 args.
AddOption(&ode_solver_type,
"-s",
"--ode-solver",
254 "ODE solver: 1 - Backward Euler, 2 - SDIRK2, 3 - SDIRK3,\n\t"
255 " 4 - CVODE implicit, approximate Jacobian,\n\t"
256 " 5 - CVODE implicit, specified Jacobian,\n\t"
257 " 6 - ARKODE implicit, approximate Jacobian,\n\t"
258 " 7 - ARKODE implicit, specified Jacobian,\n\t"
259 " 11 - Forward Euler, 12 - RK2,\n\t"
260 " 13 - RK3 SSP, 14 - RK4,\n\t"
261 " 15 - CVODE (adaptive order) explicit,\n\t"
262 " 16 - ARKODE default (4th order) explicit.");
263 args.
AddOption(&nls,
"-nls",
"--nonlinear-solver",
264 "Nonlinear systems solver: "
265 "\"newton\" (plain Newton) or \"kinsol\" (KINSOL).");
266 args.
AddOption(&t_final,
"-tf",
"--t-final",
267 "Final time; start time is 0.");
268 args.
AddOption(&dt,
"-dt",
"--time-step",
270 args.
AddOption(&visc,
"-v",
"--viscosity",
271 "Viscosity coefficient.");
272 args.
AddOption(&mu,
"-mu",
"--shear-modulus",
273 "Shear modulus in the Neo-Hookean hyperelastic model.");
274 args.
AddOption(&K,
"-K",
"--bulk-modulus",
275 "Bulk modulus in the Neo-Hookean hyperelastic model.");
276 args.
AddOption(&visualization,
"-vis",
"--visualization",
"-no-vis",
277 "--no-visualization",
278 "Enable or disable GLVis visualization.");
279 args.
AddOption(&vis_steps,
"-vs",
"--visualization-steps",
280 "Visualize every n-th timestep.");
291 Mesh *mesh =
new Mesh(mesh_file, 1, 1);
300 SundialsJacSolver *sjsolver = NULL;
301 switch (ode_solver_type)
312 if (ode_solver_type == 5)
314 sjsolver =
new SundialsJacSolver;
317 ode_solver = cvode;
break;
323 if (ode_solver_type == 7)
326 sjsolver =
new SundialsJacSolver;
329 ode_solver = arkode;
break;
332 case 12: ode_solver =
new RK2Solver(0.5);
break;
334 case 14: ode_solver =
new RK4Solver;
break;
339 ode_solver = cvode;
break;
344 ode_solver = arkode;
break;
350 cout <<
"Unknown ODE solver type: " << ode_solver_type <<
'\n';
354 map<string,HyperelasticOperator::NonlinearSolverType> nls_map;
355 nls_map[
"newton"] = HyperelasticOperator::NEWTON;
356 nls_map[
"kinsol"] = HyperelasticOperator::KINSOL;
357 if (nls_map.find(nls) == nls_map.end())
359 cout <<
"Unknown type of nonlinear solver: " << nls << endl;
366 for (
int lev = 0; lev < ref_levels; lev++)
381 cout <<
"Number of velocity/deformation unknowns: " << fe_size << endl;
384 fe_offset[1] = fe_size;
385 fe_offset[2] = 2*fe_size;
412 HyperelasticOperator oper(fespace, ess_bdr, visc, mu, K, nls_map[nls]);
417 char vishost[] =
"localhost";
419 vis_v.
open(vishost, visport);
421 visualize(vis_v, mesh, &x, &v,
"Velocity",
true);
422 vis_w.
open(vishost, visport);
425 oper.GetElasticEnergyDensity(x, w);
427 visualize(vis_w, mesh, &x, &w,
"Elastic energy density",
true);
431 double ee0 = oper.ElasticEnergy(x);
432 double ke0 = oper.KineticEnergy(v);
433 cout <<
"initial elastic energy (EE) = " << ee0 << endl;
434 cout <<
"initial kinetic energy (KE) = " << ke0 << endl;
435 cout <<
"initial total energy (TE) = " << (ee0 + ke0) << endl;
439 ode_solver->
Init(oper);
443 bool last_step =
false;
444 for (
int ti = 1; !last_step; ti++)
446 double dt_real = min(dt, t_final - t);
448 ode_solver->
Step(vx, t, dt_real);
450 last_step = (t >= t_final - 1e-8*dt);
452 if (last_step || (ti % vis_steps) == 0)
454 double ee = oper.ElasticEnergy(x);
455 double ke = oper.KineticEnergy(v);
457 cout <<
"step " << ti <<
", t = " << t <<
", EE = " << ee <<
", KE = "
458 << ke <<
", ΔTE = " << (ee+ke)-(ee0+ke0) << endl;
461 else if (arkode) { arkode->
PrintInfo(); }
468 oper.GetElasticEnergyDensity(x, w);
480 ofstream mesh_ofs(
"deformed.mesh");
481 mesh_ofs.precision(8);
482 mesh->
Print(mesh_ofs);
484 ofstream velo_ofs(
"velocity.sol");
485 velo_ofs.precision(8);
487 ofstream ee_ofs(
"elastic_energy.sol");
489 oper.GetElasticEnergyDensity(x, w);
503 GridFunction *field,
const char *field_name,
bool init_vis)
515 out <<
"solution\n" << *mesh << *field;
521 out <<
"window_size 800 800\n";
522 out <<
"window_title '" << field_name <<
"'\n";
529 out <<
"autoscale value\n";
536 ReducedSystemOperator::ReducedSystemOperator(
538 :
Operator(M_->Height()), M(M_), S(S_), H(H_), Jacobian(NULL),
539 dt(0.0), v(NULL), x(NULL), w(height), z(height)
542 void ReducedSystemOperator::SetParameters(
double dt_,
const Vector *v_,
545 dt = dt_; v = v_; x = x_;
558 Operator &ReducedSystemOperator::GetGradient(
const Vector &k)
const
561 Jacobian =
Add(1.0, M->SpMat(), dt, S->SpMat());
565 Jacobian->
Add(dt*dt, *grad_H);
569 ReducedSystemOperator::~ReducedSystemOperator()
575 int SundialsJacSolver::InitSystem(
void *sundials_mem)
578 HyperelasticOperator *he_oper;
581 he_oper =
dynamic_cast<HyperelasticOperator*
>(td_oper);
582 MFEM_VERIFY(he_oper,
"operator is not HyperelasticOperator");
587 he_oper->InitSundialsJacSolver(*
this);
591 int SundialsJacSolver::SetupSystem(
void *sundials_mem,
int conv_fail,
593 int &jac_cur,
Vector &v_temp1,
596 int sc = y_pred.
Size() / 2;
598 double dt = GetTimeStep(sundials_mem);
602 Jacobian =
Add(1.0, M->SpMat(), dt, S->SpMat());
603 grad_H =
dynamic_cast<SparseMatrix *
>(&H->GetGradient(x));
604 Jacobian->
Add(dt * dt, *grad_H);
606 J_solver->SetOperator(*Jacobian);
612 int SundialsJacSolver::SolveSystem(
void *sundials_mem,
Vector &b,
616 int sc = b.
Size() / 2;
621 double dt = GetTimeStep(sundials_mem);
624 grad_H->Mult(b_x, rhs);
626 M->AddMult(b_v, rhs);
628 J_solver->iterative_mode =
false;
629 J_solver->Mult(rhs, b_v);
636 int SundialsJacSolver::FreeSystem(
void *sundials_mem)
646 NonlinearSolverType nls_type)
648 M(&fespace), S(&fespace), H(&fespace),
649 viscosity(visc), z(height/2)
651 const double rel_tol = 1e-8;
652 const int skip_zero_entries = 0;
654 const double ref_density = 1.0;
657 M.Assemble(skip_zero_entries);
658 M.EliminateEssentialBC(ess_bdr);
659 M.Finalize(skip_zero_entries);
661 M_solver.iterative_mode =
false;
662 M_solver.SetRelTol(rel_tol);
663 M_solver.SetAbsTol(0.0);
664 M_solver.SetMaxIter(30);
665 M_solver.SetPrintLevel(0);
666 M_solver.SetPreconditioner(M_prec);
667 M_solver.SetOperator(M.SpMat());
671 H.SetEssentialBC(ess_bdr);
675 S.Assemble(skip_zero_entries);
676 S.EliminateEssentialBC(ess_bdr);
677 S.Finalize(skip_zero_entries);
679 reduced_oper =
new ReducedSystemOperator(&M, &S, &H);
681 #ifndef MFEM_USE_SUITESPARSE
695 if (nls_type == KINSOL)
699 newton_solver = kinsolver;
701 newton_solver->SetRelTol(rel_tol);
702 newton_solver->SetPrintLevel(0);
707 newton_solver->SetMaxIter(10);
708 newton_solver->SetRelTol(rel_tol);
709 newton_solver->SetPrintLevel(-1);
711 newton_solver->SetSolver(*J_solver);
712 newton_solver->iterative_mode =
false;
713 newton_solver->SetOperator(*reduced_oper);
726 if (viscosity != 0.0)
731 M_solver.Mult(z, dv_dt);
736 void HyperelasticOperator::ImplicitSolve(
const double dt,
751 reduced_oper->SetParameters(dt, &v, &x);
753 newton_solver->Mult(zero, dv_dt);
754 MFEM_VERIFY(newton_solver->GetConverged(),
755 "Nonlinear solver did not converge.");
757 cout <<
" num nonlin sol iters = " << newton_solver->GetNumIterations()
758 <<
", final norm = " << newton_solver->GetFinalNorm() <<
'\n';
760 add(v, dt, dv_dt, dx_dt);
763 void HyperelasticOperator::InitSundialsJacSolver(SundialsJacSolver &sjsolv)
765 sjsolv.SetOperators(M, S, H, *J_solver);
768 double HyperelasticOperator::ElasticEnergy(
Vector &x)
const
770 return H.GetEnergy(x);
773 double HyperelasticOperator::KineticEnergy(
Vector &v)
const
775 return 0.5*M.InnerProduct(v, v);
778 void HyperelasticOperator::GetElasticEnergyDensity(
781 ElasticEnergyCoefficient w_coeff(*model, x);
785 HyperelasticOperator::~HyperelasticOperator()
787 delete newton_solver;
798 model.SetTransformation(T);
801 return model.EvalW(J)/J.Det();
815 const double s = 0.1/64.;
818 v(dim-1) = s*x(0)*x(0)*(8.0-x(0));
void visualize(ostream &out, Mesh *mesh, GridFunction *deformed_nodes, GridFunction *field, const char *field_name=NULL, bool init_vis=false)
double Eval(ElementTransformation &T, const IntegrationPoint &ip, double t)
void Add(const int i, const int j, const double a)
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.
void SetMaxSetupCalls(int max_calls)
Set maximum number of nonlinear iterations without a Jacobian update.
Subclass constant coefficient.
virtual void Init(TimeDependentOperator &f)
Associate a TimeDependentOperator with the ODE solver.
Base abstract class for 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]...
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)
void SetLinearSolver(SundialsODELinearSolver &ls_spec)
Hyperelastic integrator for any given HyperelasticModel.
int main(int argc, char *argv[])
Backward Euler ODE solver. L-stable.
void add(const Vector &v1, const Vector &v2, Vector &v)
void SetSStolerances(double reltol, double abstol)
Specify the scalar relative and scalar absolute tolerances.
void InitialVelocity(const Vector &x, Vector &v)
Direct sparse solver using UMFPACK.
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
void Add(const DenseMatrix &A, const DenseMatrix &B, double alpha, DenseMatrix &C)
C = A + alpha*B.
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
void SetPrintLevel(int print_lvl)
Wrapper for SUNDIALS' KINSOL library – Nonlinear solvers.
Mesh * GetMesh() const
Returns the mesh.
Wrapper for SUNDIALS' CVODE library – Multi-step time integration.
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
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 of the linear multistep method.
Newton's method for solving F(x)=b for a given operator F.
void MakeRef(FiniteElementSpace *f, double *v)
Make the GridFunction reference external data on a new FiniteElementSpace.
void PrintUsage(std::ostream &out) const
Wrapper for SUNDIALS' ARKODE library – Runge-Kutta time integration.
void SetLinearSolver(SundialsODELinearSolver &ls_spec)
Set a custom Jacobian system solver for implicit methods.
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)
Base class Coefficient that may optionally depend on time.
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)
Third-order, strong stability preserving (SSP) Runge-Kutta method.
Abstract base class, wrapping the custom linear solvers interface in SUNDIALS' CVODE and ARKODE solve...
Implicit midpoint method. A-stable, not L-stable.
Class for integration point with weight.
void PrintOptions(std::ostream &out) const
void ProjectCoefficient(Coefficient &coeff)
Abstract class for hyperelastic models.
int open(const char hostname[], int port)
void GetNodes(Vector &node_coord) const
Arbitrary order H1-conforming (continuous) finite elements.
void PrintInfo() const
Print CVODE statistics.
The classical forward Euler method.
void SetMaxStep(double dt_max)
Set the maximum time step of the Runge-Kutta method.
void GetVectorGradient(ElementTransformation &tr, DenseMatrix &grad)
Vector & GetBlock(int i)
Get the i-th vector in the block.
void PrintInfo() const
Print ARKODE statistics.
Arbitrary order "L2-conforming" discontinuous finite elements.
void Neg()
(*this) = -(*this)
virtual void Print(std::ostream &out=std::cout) const