45#error This example requires that MFEM is built with MFEM_USE_PETSC=YES
51class ReducedSystemOperator;
80 ReducedSystemOperator *reduced_oper;
100 bool use_petsc,
bool petsc_use_jfnk);
103 virtual void Mult(
const Vector &vx,
Vector &dvx_dt)
const;
113 virtual ~HyperelasticOperator();
120class ReducedSystemOperator :
public Operator
144 virtual ~ReducedSystemOperator();
155 PreconditionerFactory(
const ReducedSystemOperator& op_,
const string& name_)
158 virtual ~PreconditionerFactory() {}
172 : model(m), x(x_) { }
174 virtual ~ElasticEnergyCoefficient() { }
183 bool init_vis =
false);
186int main(
int argc,
char *argv[])
194 const char *mesh_file =
"../../data/beam-quad.mesh";
195 int ser_ref_levels = 2;
196 int par_ref_levels = 0;
198 int ode_solver_type = 3;
204 bool visualization =
true;
206 bool use_petsc =
true;
207 const char *petscrc_file =
"";
208 bool petsc_use_jfnk =
false;
211 args.
AddOption(&mesh_file,
"-m",
"--mesh",
212 "Mesh file to use.");
213 args.
AddOption(&ser_ref_levels,
"-rs",
"--refine-serial",
214 "Number of times to refine the mesh uniformly in serial.");
215 args.
AddOption(&par_ref_levels,
"-rp",
"--refine-parallel",
216 "Number of times to refine the mesh uniformly in parallel.");
218 "Order (degree) of the finite elements.");
219 args.
AddOption(&ode_solver_type,
"-s",
"--ode-solver",
220 "ODE solver: 1 - Backward Euler, 2 - SDIRK2, 3 - SDIRK3,\n\t"
221 " 11 - Forward Euler, 12 - RK2,\n\t"
222 " 13 - RK3 SSP, 14 - RK4.");
223 args.
AddOption(&t_final,
"-tf",
"--t-final",
224 "Final time; start time is 0.");
225 args.
AddOption(&dt,
"-dt",
"--time-step",
227 args.
AddOption(&visc,
"-v",
"--viscosity",
228 "Viscosity coefficient.");
230 "Shear modulus in the Neo-Hookean hyperelastic model.");
231 args.
AddOption(&K,
"-K",
"--bulk-modulus",
232 "Bulk modulus in the Neo-Hookean hyperelastic model.");
233 args.
AddOption(&visualization,
"-vis",
"--visualization",
"-no-vis",
234 "--no-visualization",
235 "Enable or disable GLVis visualization.");
236 args.
AddOption(&vis_steps,
"-vs",
"--visualization-steps",
237 "Visualize every n-th timestep.");
238 args.
AddOption(&use_petsc,
"-usepetsc",
"--usepetsc",
"-no-petsc",
240 "Use or not PETSc to solve the nonlinear system.");
241 args.
AddOption(&petscrc_file,
"-petscopts",
"--petscopts",
242 "PetscOptions file to use.");
243 args.
AddOption(&petsc_use_jfnk,
"-jfnk",
"--jfnk",
"-no-jfnk",
245 "Use JFNK with user-defined preconditioner factory.");
269 Mesh *mesh =
new Mesh(mesh_file, 1, 1);
276 switch (ode_solver_type)
284 case 12: ode_solver =
new RK2Solver(0.5);
break;
286 case 14: ode_solver =
new RK4Solver;
break;
294 cout <<
"Unknown ODE solver type: " << ode_solver_type <<
'\n';
302 for (
int lev = 0; lev < ser_ref_levels; lev++)
312 for (
int lev = 0; lev < par_ref_levels; lev++)
329 cout <<
"Number of velocity/deformation unknowns: " << glob_size << endl;
334 true_offset[1] = true_size;
335 true_offset[2] = 2*true_size;
339 v_gf.
MakeTRef(&fespace, vx, true_offset[0]);
340 x_gf.
MakeTRef(&fespace, vx, true_offset[1]);
366 HyperelasticOperator *oper =
new HyperelasticOperator(fespace, ess_bdr, visc,
377 visualize(vis_v, pmesh, &x_gf, &v_gf,
"Velocity",
true);
384 oper->GetElasticEnergyDensity(x_gf, w_gf);
386 visualize(vis_w, pmesh, &x_gf, &w_gf,
"Elastic energy density",
true);
390 real_t ee0 = oper->ElasticEnergy(x_gf);
391 real_t ke0 = oper->KineticEnergy(v_gf);
394 cout <<
"initial elastic energy (EE) = " << ee0 << endl;
395 cout <<
"initial kinetic energy (KE) = " << ke0 << endl;
396 cout <<
"initial total energy (TE) = " << (ee0 + ke0) << endl;
401 ode_solver->
Init(*oper);
405 bool last_step =
false;
406 for (
int ti = 1; !last_step; ti++)
408 real_t dt_real = min(dt, t_final -
t);
410 ode_solver->
Step(vx,
t, dt_real);
412 last_step = (
t >= t_final - 1e-8*dt);
414 if (last_step || (ti % vis_steps) == 0)
418 real_t ee = oper->ElasticEnergy(x_gf);
419 real_t ke = oper->KineticEnergy(v_gf);
423 cout <<
"step " << ti <<
", t = " <<
t <<
", EE = " << ee
424 <<
", KE = " << ke <<
", ΔTE = " << (ee+ke)-(ee0+ke0) << endl;
432 oper->GetElasticEnergyDensity(x_gf, w_gf);
446 ostringstream mesh_name, velo_name, ee_name;
447 mesh_name <<
"deformed." << setfill(
'0') << setw(6) << myid;
448 velo_name <<
"velocity." << setfill(
'0') << setw(6) << myid;
449 ee_name <<
"elastic_energy." << setfill(
'0') << setw(6) << myid;
451 ofstream mesh_ofs(mesh_name.str().c_str());
452 mesh_ofs.precision(8);
453 pmesh->
Print(mesh_ofs);
455 ofstream velo_ofs(velo_name.str().c_str());
456 velo_ofs.precision(8);
458 ofstream ee_ofs(ee_name.str().c_str());
460 oper->GetElasticEnergyDensity(x_gf, w_gf);
489 os <<
"solution\n" << *mesh << *field;
495 os <<
"window_size 800 800\n";
496 os <<
"window_title '" << field_name <<
"'\n";
503 os <<
"autoscale value\n";
510ReducedSystemOperator::ReducedSystemOperator(
513 :
Operator(M_->ParFESpace()->TrueVSize()), M(M_), S(S_), H(H_),
514 Jacobian(NULL), dt(0.0), v(NULL), x(NULL), w(height), z(height),
515 ess_tdof_list(ess_tdof_list_)
518void ReducedSystemOperator::SetParameters(
real_t dt_,
const Vector *v_,
521 dt = dt_; v = v_; x = x_;
524void ReducedSystemOperator::Mult(
const Vector &k,
Vector &y)
const
530 M->TrueAddMult(k, y);
531 S->TrueAddMult(w, y);
535Operator &ReducedSystemOperator::GetGradient(
const Vector &k)
const
541 localJ->
Add(dt*dt, H->GetLocalGradient(z));
544 Jacobian = M->ParallelAssemble(localJ);
551ReducedSystemOperator::~ReducedSystemOperator()
560 bool use_petsc_factory)
562 M(&fespace), S(&fespace), H(&fespace),
563 viscosity(visc), M_solver(
f.GetComm()),
564 newton_solver(
f.GetComm()), pnewton_solver(NULL), z(height/2)
566#if defined(MFEM_USE_DOUBLE)
567 const real_t rel_tol = 1e-8;
568 const real_t newton_abs_tol = 0.0;
569#elif defined(MFEM_USE_SINGLE)
570 const real_t rel_tol = 1e-3;
571 const real_t newton_abs_tol = 1e-4;
573 const int skip_zero_entries = 0;
575 const real_t ref_density = 1.0;
578 M.Assemble(skip_zero_entries);
579 M.Finalize(skip_zero_entries);
580 Mmat = M.ParallelAssemble();
581 fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
585 M_solver.iterative_mode =
false;
586 M_solver.SetRelTol(rel_tol);
587 M_solver.SetAbsTol(0.0);
588 M_solver.SetMaxIter(30);
589 M_solver.SetPrintLevel(0);
591 M_solver.SetPreconditioner(M_prec);
592 M_solver.SetOperator(*Mmat);
596 H.SetEssentialTrueDofs(ess_tdof_list);
600 S.Assemble(skip_zero_entries);
601 S.Finalize(skip_zero_entries);
603 reduced_oper =
new ReducedSystemOperator(&M, &S, &H, ess_tdof_list);
609 J_prec = J_hypreSmoother;
622 newton_solver.SetSolver(*J_solver);
623 newton_solver.SetOperator(*reduced_oper);
624 newton_solver.SetPrintLevel(1);
625 newton_solver.SetRelTol(rel_tol);
626 newton_solver.SetAbsTol(newton_abs_tol);
627 newton_solver.SetMaxIter(10);
640 if (use_petsc_factory)
642 J_factory =
new PreconditionerFactory(*reduced_oper,
"JFNK preconditioner");
643 pnewton_solver->SetPreconditionerFactory(J_factory);
645 pnewton_solver->SetPrintLevel(1);
646 pnewton_solver->SetRelTol(rel_tol);
647 pnewton_solver->SetAbsTol(newton_abs_tol);
648 pnewton_solver->SetMaxIter(10);
652void HyperelasticOperator::Mult(
const Vector &vx,
Vector &dvx_dt)
const
662 if (viscosity != 0.0)
668 M_solver.
Mult(z, dv_dt);
673void HyperelasticOperator::ImplicitSolve(
const real_t dt,
688 reduced_oper->SetParameters(dt, &v, &x);
692 newton_solver.
Mult(zero, dv_dt);
694 "Newton solver did not converge.");
698 pnewton_solver->
Mult(zero, dv_dt);
700 "Newton solver did not converge.");
702 add(v, dt, dv_dt, dx_dt);
712 real_t energy = 0.5*M.ParInnerProduct(v, v);
716void HyperelasticOperator::GetElasticEnergyDensity(
719 ElasticEnergyCoefficient w_coeff(*model, x);
723HyperelasticOperator::~HyperelasticOperator()
731 delete pnewton_solver;
771 v(
dim-1) =
s*x(0)*x(0)*(8.0-x(0));
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.
Conjugate gradient method.
virtual void Mult(const Vector &b, Vector &x) const
Iterative solution of the linear system using the Conjugate Gradient method.
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 dense matrix using column-major storage.
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.
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.
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_)
Wrapper for hypre's ParCSR matrix class.
void EliminateRowsCols(const Array< int > &rows_cols, const HypreParVector &X, HypreParVector &B)
Parallel smoothers in hypre.
void SetPositiveDiagonal(bool pos=true)
After computing l1-norms, replace them with their absolute values.
void SetType(HypreSmoother::Type type, int relax_times=1)
Set the relaxation type and number of sweeps.
@ l1Jacobi
l1-scaled Jacobi
static void Init()
Initialize hypre by calling HYPRE_Init() and set default options. After calling Hypre::Init(),...
Implicit midpoint method. A-stable, not L-stable.
Class for integration point with weight.
void SetRelTol(real_t rtol)
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)
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.
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.
static int WorldRank()
Return the MPI rank in MPI_COMM_WORLD.
static void Init(int &argc, char **&argv, int required=default_thread_required, int *provided=nullptr)
Singleton creation with Mpi::Init(argc, argv).
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].
Pointer to an Operator of a specified type.
void Get(OpType *&A) const
Return the Operator pointer statically cast to a given OpType.
int height
Dimension of the output / number of rows in the matrix.
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.
Abstract parallel finite element space.
HYPRE_BigInt GlobalTrueVSize() const
int TrueVSize() const
Obsolete, kept for backward compatibility.
Class for parallel grid function.
void Save(std::ostream &out) const override
void ProjectCoefficient(Coefficient &coeff) override
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
Class for parallel meshes.
void Print(std::ostream &out=mfem::out, const std::string &comments="") const override
Abstract class for PETSc's nonlinear solvers.
virtual void Mult(const Vector &b, Vector &x) const
Application of the solver.
Wrapper for PETSc's matrix class.
Abstract class for PETSc's preconditioners.
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.
void Add(const int i, const int j, const real_t val)
Base abstract class for first order time dependent operators.
virtual void SetTime(const real_t t_)
Set the current time.
A general vector function coefficient.
void Neg()
(*this) = -(*this)
void SetSubVector(const Array< int > &dofs, const real_t value)
Set the entries listed in dofs to the given value.
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)
void MFEMInitializePetsc()
Convenience functions to initialize/finalize PETSc.
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, ParMesh *mesh, ParGridFunction *deformed_nodes, ParGridFunction *field, const char *field_name=NULL, bool init_vis=false)
void InitialDeformation(const Vector &x, Vector &y)
void InitialVelocity(const Vector &x, Vector &v)