46 class ReducedSystemOperator;
75 ReducedSystemOperator *reduced_oper;
89 double visc,
double mu,
double K);
95 virtual void ImplicitSolve(
const double dt,
const Vector &x,
Vector &k);
102 virtual ~HyperelasticOperator();
109 class ReducedSystemOperator :
public Operator
125 void SetParameters(
double dt_,
const Vector *v_,
const Vector *x_);
133 virtual ~ReducedSystemOperator();
139 class ElasticEnergyCoefficient :
public Coefficient
148 : model(m), x(x_) { }
150 virtual ~ElasticEnergyCoefficient() { }
159 bool init_vis =
false);
162 int main(
int argc,
char *argv[])
166 MPI_Init(&argc, &argv);
167 MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
168 MPI_Comm_rank(MPI_COMM_WORLD, &myid);
171 const char *mesh_file =
"../data/beam-quad.mesh";
172 int ser_ref_levels = 2;
173 int par_ref_levels = 0;
175 int ode_solver_type = 3;
176 double t_final = 300.0;
181 bool adaptive_lin_rtol =
true;
182 bool visualization =
true;
186 args.
AddOption(&mesh_file,
"-m",
"--mesh",
187 "Mesh file to use.");
188 args.
AddOption(&ser_ref_levels,
"-rs",
"--refine-serial",
189 "Number of times to refine the mesh uniformly in serial.");
190 args.
AddOption(&par_ref_levels,
"-rp",
"--refine-parallel",
191 "Number of times to refine the mesh uniformly in parallel.");
193 "Order (degree) of the finite elements.");
194 args.
AddOption(&ode_solver_type,
"-s",
"--ode-solver",
195 "ODE solver: 1 - Backward Euler, 2 - SDIRK2, 3 - SDIRK3,\n\t"
196 " 11 - Forward Euler, 12 - RK2,\n\t"
197 " 13 - RK3 SSP, 14 - RK4."
198 " 22 - Implicit Midpoint Method,\n\t"
199 " 23 - SDIRK23 (A-stable), 24 - SDIRK34");
200 args.
AddOption(&t_final,
"-tf",
"--t-final",
201 "Final time; start time is 0.");
202 args.
AddOption(&dt,
"-dt",
"--time-step",
204 args.
AddOption(&visc,
"-v",
"--viscosity",
205 "Viscosity coefficient.");
206 args.
AddOption(&mu,
"-mu",
"--shear-modulus",
207 "Shear modulus in the Neo-Hookean hyperelastic model.");
208 args.
AddOption(&K,
"-K",
"--bulk-modulus",
209 "Bulk modulus in the Neo-Hookean hyperelastic model.");
210 args.
AddOption(&adaptive_lin_rtol,
"-alrtol",
"--adaptive-lin-rtol",
211 "-no-alrtol",
"--no-adaptive-lin-rtol",
212 "Enable or disable adaptive linear solver rtol.");
213 args.
AddOption(&visualization,
"-vis",
"--visualization",
"-no-vis",
214 "--no-visualization",
215 "Enable or disable GLVis visualization.");
216 args.
AddOption(&vis_steps,
"-vs",
"--visualization-steps",
217 "Visualize every n-th timestep.");
236 Mesh *mesh =
new Mesh(mesh_file, 1, 1);
243 switch (ode_solver_type)
251 case 12: ode_solver =
new RK2Solver(0.5);
break;
253 case 14: ode_solver =
new RK4Solver;
break;
262 cout <<
"Unknown ODE solver type: " << ode_solver_type <<
'\n';
272 for (
int lev = 0; lev < ser_ref_levels; lev++)
282 for (
int lev = 0; lev < par_ref_levels; lev++)
299 cout <<
"Number of velocity/deformation unknowns: " << glob_size << endl;
304 true_offset[1] = true_size;
305 true_offset[2] = 2*true_size;
309 v_gf.
MakeTRef(&fespace, vx, true_offset[0]);
310 x_gf.
MakeTRef(&fespace, vx, true_offset[1]);
336 HyperelasticOperator oper(fespace, ess_bdr, visc, mu, K);
343 vis_v.
open(vishost, visport);
345 visualize(vis_v, pmesh, &x_gf, &v_gf,
"Velocity",
true);
349 vis_w.
open(vishost, visport);
352 oper.GetElasticEnergyDensity(x_gf, w_gf);
354 visualize(vis_w, pmesh, &x_gf, &w_gf,
"Elastic energy density",
true);
358 double ee0 = oper.ElasticEnergy(x_gf);
359 double ke0 = oper.KineticEnergy(v_gf);
362 cout <<
"initial elastic energy (EE) = " << ee0 << endl;
363 cout <<
"initial kinetic energy (KE) = " << ke0 << endl;
364 cout <<
"initial total energy (TE) = " << (ee0 + ke0) << endl;
369 ode_solver->
Init(oper);
373 bool last_step =
false;
374 for (
int ti = 1; !last_step; ti++)
376 double dt_real = min(dt, t_final - t);
378 ode_solver->
Step(vx, t, dt_real);
380 last_step = (t >= t_final - 1e-8*dt);
382 if (last_step || (ti % vis_steps) == 0)
386 double ee = oper.ElasticEnergy(x_gf);
387 double ke = oper.KineticEnergy(v_gf);
391 cout <<
"step " << ti <<
", t = " << t <<
", EE = " << ee
392 <<
", KE = " << ke <<
", ΔTE = " << (ee+ke)-(ee0+ke0) << endl;
400 oper.GetElasticEnergyDensity(x_gf, w_gf);
414 ostringstream mesh_name, velo_name, ee_name;
415 mesh_name <<
"deformed." << setfill(
'0') << setw(6) << myid;
416 velo_name <<
"velocity." << setfill(
'0') << setw(6) << myid;
417 ee_name <<
"elastic_energy." << setfill(
'0') << setw(6) << myid;
419 ofstream mesh_ofs(mesh_name.str().c_str());
420 mesh_ofs.precision(8);
421 pmesh->
Print(mesh_ofs);
423 ofstream velo_ofs(velo_name.str().c_str());
424 velo_ofs.precision(8);
426 ofstream ee_ofs(ee_name.str().c_str());
428 oper.GetElasticEnergyDensity(x_gf, w_gf);
455 out <<
"solution\n" << *mesh << *field;
461 out <<
"window_size 800 800\n";
462 out <<
"window_title '" << field_name <<
"'\n";
469 out <<
"autoscale value\n";
476 ReducedSystemOperator::ReducedSystemOperator(
479 :
Operator(M_->ParFESpace()->TrueVSize()), M(M_), S(S_), H(H_),
480 Jacobian(NULL), dt(0.0), v(NULL), x(NULL), w(height), z(height),
481 ess_tdof_list(ess_tdof_list_)
484 void ReducedSystemOperator::SetParameters(
double dt_,
const Vector *v_,
487 dt = dt_; v = v_; x = x_;
496 M->TrueAddMult(k, y);
497 S->TrueAddMult(w, y);
501 Operator &ReducedSystemOperator::GetGradient(
const Vector &k)
const
507 localJ->
Add(dt*dt, H->GetLocalGradient(z));
508 Jacobian = M->ParallelAssemble(localJ);
515 ReducedSystemOperator::~ReducedSystemOperator()
525 M(&fespace), S(&fespace), H(&fespace),
526 viscosity(visc), M_solver(f.GetComm()), newton_solver(f.GetComm()),
529 const double rel_tol = 1e-8;
530 const int skip_zero_entries = 0;
532 const double ref_density = 1.0;
535 M.Assemble(skip_zero_entries);
536 M.Finalize(skip_zero_entries);
537 Mmat = M.ParallelAssemble();
538 fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
542 M_solver.iterative_mode =
false;
543 M_solver.SetRelTol(rel_tol);
544 M_solver.SetAbsTol(0.0);
545 M_solver.SetMaxIter(30);
546 M_solver.SetPrintLevel(0);
547 M_prec.SetType(HypreSmoother::Jacobi);
548 M_solver.SetPreconditioner(M_prec);
549 M_solver.SetOperator(*Mmat);
553 H.SetEssentialTrueDofs(ess_tdof_list);
557 S.Assemble(skip_zero_entries);
558 S.Finalize(skip_zero_entries);
560 reduced_oper =
new ReducedSystemOperator(&M, &S, &H, ess_tdof_list);
563 J_hypreSmoother->
SetType(HypreSmoother::l1Jacobi);
565 J_prec = J_hypreSmoother;
576 newton_solver.SetSolver(*J_solver);
577 newton_solver.SetOperator(*reduced_oper);
578 newton_solver.SetPrintLevel(1);
579 newton_solver.SetRelTol(rel_tol);
580 newton_solver.SetAbsTol(0.0);
581 newton_solver.SetAdaptiveLinRtol(2, 0.5, 0.9);
582 newton_solver.SetMaxIter(10);
595 if (viscosity != 0.0)
601 M_solver.Mult(z, dv_dt);
606 void HyperelasticOperator::ImplicitSolve(
const double dt,
621 reduced_oper->SetParameters(dt, &v, &x);
623 newton_solver.Mult(zero, dv_dt);
624 MFEM_VERIFY(newton_solver.GetConverged(),
"Newton solver did not converge.");
625 add(v, dt, dv_dt, dx_dt);
628 double HyperelasticOperator::ElasticEnergy(
const ParGridFunction &x)
const
630 return H.GetEnergy(x);
633 double HyperelasticOperator::KineticEnergy(
const ParGridFunction &v)
const
635 double loc_energy = 0.5*M.InnerProduct(v, v);
637 MPI_Allreduce(&loc_energy, &energy, 1, MPI_DOUBLE, MPI_SUM,
642 void HyperelasticOperator::GetElasticEnergyDensity(
645 ElasticEnergyCoefficient w_coeff(*model, x);
649 HyperelasticOperator::~HyperelasticOperator()
662 model.SetTransformation(T);
665 return model.EvalW(J)/J.Det();
679 const double s = 0.1/64.;
682 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)
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 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.
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
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
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...
bool iterative_mode
If true, use the second argument of Mult() as an initial guess.
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 InitialVelocity(const Vector &x, Vector &v)
void SetPositiveDiagonal(bool pos=true)
After computing l1-norms, replace them with their absolute values.
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.
void SetPrintLevel(int print_lvl)
void Parse()
Parse the command-line options. Note that this function expects all the options provided through the ...
Mesh * GetMesh() const
Returns the mesh.
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.
Newton's method for solving F(x)=b for a given operator F.
virtual void Print(std::ostream &out=mfem::out) const
Parallel smoothers in hypre.
void PrintUsage(std::ostream &out) const
Print the usage message.
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)
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 GetVectorGradient(ElementTransformation &tr, DenseMatrix &grad) const
Implicit midpoint method. A-stable, not L-stable.
Class for integration point with weight.
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.
Class for parallel grid function.
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
The classical forward Euler method.
Wrapper for hypre's ParCSR matrix class.
Class for parallel meshes.
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.
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.