MFEM v4.7.0
Finite element discretization library
Loading...
Searching...
No Matches
ex10p.cpp
Go to the documentation of this file.
1// MFEM Example 10 - Parallel Version
2//
3// Compile with: make ex10p
4//
5// Sample runs:
6// mpirun -np 4 ex10p -m ../data/beam-quad.mesh -s 3 -rs 2 -dt 3
7// mpirun -np 4 ex10p -m ../data/beam-tri.mesh -s 3 -rs 2 -dt 3
8// mpirun -np 4 ex10p -m ../data/beam-hex.mesh -s 2 -rs 1 -dt 3
9// mpirun -np 4 ex10p -m ../data/beam-tet.mesh -s 2 -rs 1 -dt 3
10// mpirun -np 4 ex10p -m ../data/beam-wedge.mesh -s 2 -rs 1 -dt 3
11// mpirun -np 4 ex10p -m ../data/beam-quad.mesh -s 14 -rs 2 -dt 0.03 -vs 20
12// mpirun -np 4 ex10p -m ../data/beam-hex.mesh -s 14 -rs 1 -dt 0.05 -vs 20
13// mpirun -np 4 ex10p -m ../data/beam-quad-amr.mesh -s 3 -rs 2 -dt 3
14//
15// Description: This examples solves a time dependent nonlinear elasticity
16// problem of the form dv/dt = H(x) + S v, dx/dt = v, where H is a
17// hyperelastic model and S is a viscosity operator of Laplacian
18// type. The geometry of the domain is assumed to be as follows:
19//
20// +---------------------+
21// boundary --->| |
22// attribute 1 | |
23// (fixed) +---------------------+
24//
25// The example demonstrates the use of nonlinear operators (the
26// class HyperelasticOperator defining H(x)), as well as their
27// implicit time integration using a Newton method for solving an
28// associated reduced backward-Euler type nonlinear equation
29// (class ReducedSystemOperator). Each Newton step requires the
30// inversion of a Jacobian matrix, which is done through a
31// (preconditioned) inner solver. Note that implementing the
32// method HyperelasticOperator::ImplicitSolve is the only
33// requirement for high-order implicit (SDIRK) time integration.
34//
35// We recommend viewing examples 2 and 9 before viewing this
36// example.
37
38#include "mfem.hpp"
39#include <memory>
40#include <iostream>
41#include <fstream>
42
43using namespace std;
44using namespace mfem;
45
46class ReducedSystemOperator;
47
48/** After spatial discretization, the hyperelastic model can be written as a
49 * system of ODEs:
50 * dv/dt = -M^{-1}*(H(x) + S*v)
51 * dx/dt = v,
52 * where x is the vector representing the deformation, v is the velocity field,
53 * M is the mass matrix, S is the viscosity matrix, and H(x) is the nonlinear
54 * hyperelastic operator.
55 *
56 * Class HyperelasticOperator represents the right-hand side of the above
57 * system of ODEs. */
58class HyperelasticOperator : public TimeDependentOperator
59{
60protected:
61 ParFiniteElementSpace &fespace;
62 Array<int> ess_tdof_list;
63
64 ParBilinearForm M, S;
66 real_t viscosity;
67 HyperelasticModel *model;
68
69 HypreParMatrix *Mmat; // Mass matrix from ParallelAssemble()
70 CGSolver M_solver; // Krylov solver for inverting the mass matrix M
71 HypreSmoother M_prec; // Preconditioner for the mass matrix M
72
73 /** Nonlinear operator defining the reduced backward Euler equation for the
74 velocity. Used in the implementation of method ImplicitSolve. */
75 ReducedSystemOperator *reduced_oper;
76
77 /// Newton solver for the reduced backward Euler equation
78 NewtonSolver newton_solver;
79
80 /// Solver for the Jacobian solve in the Newton method
81 Solver *J_solver;
82 /// Preconditioner for the Jacobian solve in the Newton method
83 Solver *J_prec;
84
85 mutable Vector z; // auxiliary vector
86
87public:
88 HyperelasticOperator(ParFiniteElementSpace &f, Array<int> &ess_bdr,
89 real_t visc, real_t mu, real_t K);
90
91 /// Compute the right-hand side of the ODE system.
92 virtual void Mult(const Vector &vx, Vector &dvx_dt) const;
93 /** Solve the Backward-Euler equation: k = f(x + dt*k, t), for the unknown k.
94 This is the only requirement for high-order SDIRK implicit integration.*/
95 virtual void ImplicitSolve(const real_t dt, const Vector &x, Vector &k);
96
97 real_t ElasticEnergy(const ParGridFunction &x) const;
98 real_t KineticEnergy(const ParGridFunction &v) const;
99 void GetElasticEnergyDensity(const ParGridFunction &x,
100 ParGridFunction &w) const;
101
102 virtual ~HyperelasticOperator();
103};
104
105/** Nonlinear operator of the form:
106 k --> (M + dt*S)*k + H(x + dt*v + dt^2*k) + S*v,
107 where M and S are given BilinearForms, H is a given NonlinearForm, v and x
108 are given vectors, and dt is a scalar. */
109class ReducedSystemOperator : public Operator
110{
111private:
112 ParBilinearForm *M, *S;
114 mutable HypreParMatrix *Jacobian;
115 real_t dt;
116 const Vector *v, *x;
117 mutable Vector w, z;
118 const Array<int> &ess_tdof_list;
119
120public:
121 ReducedSystemOperator(ParBilinearForm *M_, ParBilinearForm *S_,
122 ParNonlinearForm *H_, const Array<int> &ess_tdof_list);
123
124 /// Set current dt, v, x values - needed to compute action and Jacobian.
125 void SetParameters(real_t dt_, const Vector *v_, const Vector *x_);
126
127 /// Compute y = H(x + dt (v + dt k)) + M k + S (v + dt k).
128 virtual void Mult(const Vector &k, Vector &y) const;
129
130 /// Compute J = M + dt S + dt^2 grad_H(x + dt (v + dt k)).
131 virtual Operator &GetGradient(const Vector &k) const;
132
133 virtual ~ReducedSystemOperator();
134};
135
136
137/** Function representing the elastic energy density for the given hyperelastic
138 model+deformation. Used in HyperelasticOperator::GetElasticEnergyDensity. */
139class ElasticEnergyCoefficient : public Coefficient
140{
141private:
142 HyperelasticModel &model;
143 const ParGridFunction &x;
144 DenseMatrix J;
145
146public:
147 ElasticEnergyCoefficient(HyperelasticModel &m, const ParGridFunction &x_)
148 : model(m), x(x_) { }
149 virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip);
150 virtual ~ElasticEnergyCoefficient() { }
151};
152
153void InitialDeformation(const Vector &x, Vector &y);
154
155void InitialVelocity(const Vector &x, Vector &v);
156
157void visualize(ostream &os, ParMesh *mesh,
158 ParGridFunction *deformed_nodes,
159 ParGridFunction *field, const char *field_name = NULL,
160 bool init_vis = false);
161
162
163int main(int argc, char *argv[])
164{
165 // 1. Initialize MPI and HYPRE.
166 Mpi::Init(argc, argv);
167 int myid = Mpi::WorldRank();
168 Hypre::Init();
169
170 // 2. Parse command-line options.
171 const char *mesh_file = "../data/beam-quad.mesh";
172 int ser_ref_levels = 2;
173 int par_ref_levels = 0;
174 int order = 2;
175 int ode_solver_type = 3;
176 real_t t_final = 300.0;
177 real_t dt = 3.0;
178 real_t visc = 1e-2;
179 real_t mu = 0.25;
180 real_t K = 5.0;
181 bool adaptive_lin_rtol = true;
182 bool visualization = true;
183 int vis_steps = 1;
184
185 OptionsParser args(argc, argv);
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.");
192 args.AddOption(&order, "-o", "--order",
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",
203 "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.");
218 args.Parse();
219 if (!args.Good())
220 {
221 if (myid == 0)
222 {
223 args.PrintUsage(cout);
224 }
225 return 1;
226 }
227 if (myid == 0)
228 {
229 args.PrintOptions(cout);
230 }
231
232 // 3. Read the serial mesh from the given mesh file on all processors. We can
233 // handle triangular, quadrilateral, tetrahedral and hexahedral meshes
234 // with the same code.
235 Mesh *mesh = new Mesh(mesh_file, 1, 1);
236 int dim = mesh->Dimension();
237
238 // 4. Define the ODE solver used for time integration. Several implicit
239 // singly diagonal implicit Runge-Kutta (SDIRK) methods, as well as
240 // explicit Runge-Kutta methods are available.
241 ODESolver *ode_solver;
242 switch (ode_solver_type)
243 {
244 // Implicit L-stable methods
245 case 1: ode_solver = new BackwardEulerSolver; break;
246 case 2: ode_solver = new SDIRK23Solver(2); break;
247 case 3: ode_solver = new SDIRK33Solver; break;
248 // Explicit methods
249 case 11: ode_solver = new ForwardEulerSolver; break;
250 case 12: ode_solver = new RK2Solver(0.5); break; // midpoint method
251 case 13: ode_solver = new RK3SSPSolver; break;
252 case 14: ode_solver = new RK4Solver; break;
253 case 15: ode_solver = new GeneralizedAlphaSolver(0.5); break;
254 // Implicit A-stable methods (not L-stable)
255 case 22: ode_solver = new ImplicitMidpointSolver; break;
256 case 23: ode_solver = new SDIRK23Solver; break;
257 case 24: ode_solver = new SDIRK34Solver; break;
258 default:
259 if (myid == 0)
260 {
261 cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
262 }
263 delete mesh;
264 return 3;
265 }
266
267 // 5. Refine the mesh in serial to increase the resolution. In this example
268 // we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
269 // a command-line parameter.
270 for (int lev = 0; lev < ser_ref_levels; lev++)
271 {
272 mesh->UniformRefinement();
273 }
274
275 // 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
276 // this mesh further in parallel to increase the resolution. Once the
277 // parallel mesh is defined, the serial mesh can be deleted.
278 ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
279 delete mesh;
280 for (int lev = 0; lev < par_ref_levels; lev++)
281 {
282 pmesh->UniformRefinement();
283 }
284
285 // 7. Define the parallel vector finite element spaces representing the mesh
286 // deformation x_gf, the velocity v_gf, and the initial configuration,
287 // x_ref. Define also the elastic energy density, w_gf, which is in a
288 // discontinuous higher-order space. Since x and v are integrated in time
289 // as a system, we group them together in block vector vx, on the unique
290 // parallel degrees of freedom, with offsets given by array true_offset.
291 H1_FECollection fe_coll(order, dim);
292 ParFiniteElementSpace fespace(pmesh, &fe_coll, dim);
293
294 HYPRE_BigInt glob_size = fespace.GlobalTrueVSize();
295 if (myid == 0)
296 {
297 cout << "Number of velocity/deformation unknowns: " << glob_size << endl;
298 }
299 int true_size = fespace.TrueVSize();
300 Array<int> true_offset(3);
301 true_offset[0] = 0;
302 true_offset[1] = true_size;
303 true_offset[2] = 2*true_size;
304
305 BlockVector vx(true_offset);
306 ParGridFunction v_gf, x_gf;
307 v_gf.MakeTRef(&fespace, vx, true_offset[0]);
308 x_gf.MakeTRef(&fespace, vx, true_offset[1]);
309
310 ParGridFunction x_ref(&fespace);
311 pmesh->GetNodes(x_ref);
312
313 L2_FECollection w_fec(order + 1, dim);
314 ParFiniteElementSpace w_fespace(pmesh, &w_fec);
315 ParGridFunction w_gf(&w_fespace);
316
317 // 8. Set the initial conditions for v_gf, x_gf and vx, and define the
318 // boundary conditions on a beam-like mesh (see description above).
320 v_gf.ProjectCoefficient(velo);
321 v_gf.SetTrueVector();
323 x_gf.ProjectCoefficient(deform);
324 x_gf.SetTrueVector();
325
327
328 Array<int> ess_bdr(fespace.GetMesh()->bdr_attributes.Max());
329 ess_bdr = 0;
330 ess_bdr[0] = 1; // boundary attribute 1 (index 0) is fixed
331
332 // 9. Initialize the hyperelastic operator, the GLVis visualization and print
333 // the initial energies.
334 HyperelasticOperator oper(fespace, ess_bdr, visc, mu, K);
335
336 socketstream vis_v, vis_w;
337 if (visualization)
338 {
339 char vishost[] = "localhost";
340 int visport = 19916;
341 vis_v.open(vishost, visport);
342 vis_v.precision(8);
343 visualize(vis_v, pmesh, &x_gf, &v_gf, "Velocity", true);
344 // Make sure all ranks have sent their 'v' solution before initiating
345 // another set of GLVis connections (one from each rank):
346 MPI_Barrier(pmesh->GetComm());
347 vis_w.open(vishost, visport);
348 if (vis_w)
349 {
350 oper.GetElasticEnergyDensity(x_gf, w_gf);
351 vis_w.precision(8);
352 visualize(vis_w, pmesh, &x_gf, &w_gf, "Elastic energy density", true);
353 }
354 if (myid == 0)
355 {
356 cout << "GLVis visualization paused."
357 << " Press space (in the GLVis window) to resume it.\n";
358 }
359 }
360
361 real_t ee0 = oper.ElasticEnergy(x_gf);
362 real_t ke0 = oper.KineticEnergy(v_gf);
363 if (myid == 0)
364 {
365 cout << "initial elastic energy (EE) = " << ee0 << endl;
366 cout << "initial kinetic energy (KE) = " << ke0 << endl;
367 cout << "initial total energy (TE) = " << (ee0 + ke0) << endl;
368 }
369
370 real_t t = 0.0;
371 oper.SetTime(t);
372 ode_solver->Init(oper);
373
374 // 10. Perform time-integration
375 // (looping over the time iterations, ti, with a time-step dt).
376 bool last_step = false;
377 for (int ti = 1; !last_step; ti++)
378 {
379 real_t dt_real = min(dt, t_final - t);
380
381 ode_solver->Step(vx, t, dt_real);
382
383 last_step = (t >= t_final - 1e-8*dt);
384
385 if (last_step || (ti % vis_steps) == 0)
386 {
388
389 real_t ee = oper.ElasticEnergy(x_gf);
390 real_t ke = oper.KineticEnergy(v_gf);
391
392 if (myid == 0)
393 {
394 cout << "step " << ti << ", t = " << t << ", EE = " << ee
395 << ", KE = " << ke << ", ΔTE = " << (ee+ke)-(ee0+ke0) << endl;
396 }
397
398 if (visualization)
399 {
400 visualize(vis_v, pmesh, &x_gf, &v_gf);
401 if (vis_w)
402 {
403 oper.GetElasticEnergyDensity(x_gf, w_gf);
404 visualize(vis_w, pmesh, &x_gf, &w_gf);
405 }
406 }
407 }
408 }
409
410 // 11. Save the displaced mesh, the velocity and elastic energy.
411 {
413 GridFunction *nodes = &x_gf;
414 int owns_nodes = 0;
415 pmesh->SwapNodes(nodes, owns_nodes);
416
417 ostringstream mesh_name, velo_name, ee_name;
418 mesh_name << "deformed." << setfill('0') << setw(6) << myid;
419 velo_name << "velocity." << setfill('0') << setw(6) << myid;
420 ee_name << "elastic_energy." << setfill('0') << setw(6) << myid;
421
422 ofstream mesh_ofs(mesh_name.str().c_str());
423 mesh_ofs.precision(8);
424 pmesh->Print(mesh_ofs);
425 pmesh->SwapNodes(nodes, owns_nodes);
426 ofstream velo_ofs(velo_name.str().c_str());
427 velo_ofs.precision(8);
428 v_gf.Save(velo_ofs);
429 ofstream ee_ofs(ee_name.str().c_str());
430 ee_ofs.precision(8);
431 oper.GetElasticEnergyDensity(x_gf, w_gf);
432 w_gf.Save(ee_ofs);
433 }
434
435 // 12. Free the used memory.
436 delete ode_solver;
437 delete pmesh;
438
439 return 0;
440}
441
442void visualize(ostream &os, ParMesh *mesh,
443 ParGridFunction *deformed_nodes,
444 ParGridFunction *field, const char *field_name, bool init_vis)
445{
446 if (!os)
447 {
448 return;
449 }
450
451 GridFunction *nodes = deformed_nodes;
452 int owns_nodes = 0;
453
454 mesh->SwapNodes(nodes, owns_nodes);
455
456 os << "parallel " << mesh->GetNRanks()
457 << " " << mesh->GetMyRank() << "\n";
458 os << "solution\n" << *mesh << *field;
459
460 mesh->SwapNodes(nodes, owns_nodes);
461
462 if (init_vis)
463 {
464 os << "window_size 800 800\n";
465 os << "window_title '" << field_name << "'\n";
466 if (mesh->SpaceDimension() == 2)
467 {
468 os << "view 0 0\n"; // view from top
469 os << "keys jl\n"; // turn off perspective and light
470 }
471 os << "keys cm\n"; // show colorbar and mesh
472 // update value-range; keep mesh-extents fixed
473 os << "autoscale value\n";
474 os << "pause\n";
475 }
476 os << flush;
477}
478
479
480ReducedSystemOperator::ReducedSystemOperator(
482 const Array<int> &ess_tdof_list_)
483 : Operator(M_->ParFESpace()->TrueVSize()), M(M_), S(S_), H(H_),
484 Jacobian(NULL), dt(0.0), v(NULL), x(NULL), w(height), z(height),
485 ess_tdof_list(ess_tdof_list_)
486{ }
487
488void ReducedSystemOperator::SetParameters(real_t dt_, const Vector *v_,
489 const Vector *x_)
490{
491 dt = dt_; v = v_; x = x_;
492}
493
494void ReducedSystemOperator::Mult(const Vector &k, Vector &y) const
495{
496 // compute: y = H(x + dt*(v + dt*k)) + M*k + S*(v + dt*k)
497 add(*v, dt, k, w);
498 add(*x, dt, w, z);
499 H->Mult(z, y);
500 M->TrueAddMult(k, y);
501 S->TrueAddMult(w, y);
502 y.SetSubVector(ess_tdof_list, 0.0);
503}
504
505Operator &ReducedSystemOperator::GetGradient(const Vector &k) const
506{
507 delete Jacobian;
508 SparseMatrix *localJ = Add(1.0, M->SpMat(), dt, S->SpMat());
509 add(*v, dt, k, w);
510 add(*x, dt, w, z);
511 localJ->Add(dt*dt, H->GetLocalGradient(z));
512 Jacobian = M->ParallelAssemble(localJ);
513 delete localJ;
514 HypreParMatrix *Je = Jacobian->EliminateRowsCols(ess_tdof_list);
515 delete Je;
516 return *Jacobian;
517}
518
519ReducedSystemOperator::~ReducedSystemOperator()
520{
521 delete Jacobian;
522}
523
524
525HyperelasticOperator::HyperelasticOperator(ParFiniteElementSpace &f,
526 Array<int> &ess_bdr, real_t visc,
527 real_t mu, real_t K)
528 : TimeDependentOperator(2*f.TrueVSize(), (real_t) 0.0), fespace(f),
529 M(&fespace), S(&fespace), H(&fespace),
530 viscosity(visc), M_solver(f.GetComm()), newton_solver(f.GetComm()),
531 z(height/2)
532{
533#if defined(MFEM_USE_DOUBLE)
534 const real_t rel_tol = 1e-8;
535 const real_t newton_abs_tol = 0.0;
536#elif defined(MFEM_USE_SINGLE)
537 const real_t rel_tol = 1e-3;
538 const real_t newton_abs_tol = 1e-4;
539#else
540#error "Only single and double precision are supported!"
541 const real_t rel_tol = real_t(1);
542 const real_t newton_abs_tol = real_t(0);
543#endif
544 const int skip_zero_entries = 0;
545
546 const real_t ref_density = 1.0; // density in the reference configuration
547 ConstantCoefficient rho0(ref_density);
548 M.AddDomainIntegrator(new VectorMassIntegrator(rho0));
549 M.Assemble(skip_zero_entries);
550 M.Finalize(skip_zero_entries);
551 Mmat = M.ParallelAssemble();
552 fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
553 HypreParMatrix *Me = Mmat->EliminateRowsCols(ess_tdof_list);
554 delete Me;
555
556 M_solver.iterative_mode = false;
557 M_solver.SetRelTol(rel_tol);
558 M_solver.SetAbsTol(0.0);
559 M_solver.SetMaxIter(30);
560 M_solver.SetPrintLevel(0);
561 M_prec.SetType(HypreSmoother::Jacobi);
562 M_solver.SetPreconditioner(M_prec);
563 M_solver.SetOperator(*Mmat);
564
565 model = new NeoHookeanModel(mu, K);
566 H.AddDomainIntegrator(new HyperelasticNLFIntegrator(model));
567 H.SetEssentialTrueDofs(ess_tdof_list);
568
569 ConstantCoefficient visc_coeff(viscosity);
570 S.AddDomainIntegrator(new VectorDiffusionIntegrator(visc_coeff));
571 S.Assemble(skip_zero_entries);
572 S.Finalize(skip_zero_entries);
573
574 reduced_oper = new ReducedSystemOperator(&M, &S, &H, ess_tdof_list);
575
576 HypreSmoother *J_hypreSmoother = new HypreSmoother;
577 J_hypreSmoother->SetType(HypreSmoother::l1Jacobi);
578 J_hypreSmoother->SetPositiveDiagonal(true);
579 J_prec = J_hypreSmoother;
580
581 MINRESSolver *J_minres = new MINRESSolver(f.GetComm());
582 J_minres->SetRelTol(rel_tol);
583 J_minres->SetAbsTol(0.0);
584 J_minres->SetMaxIter(300);
585 J_minres->SetPrintLevel(-1);
586 J_minres->SetPreconditioner(*J_prec);
587 J_solver = J_minres;
588
589 newton_solver.iterative_mode = false;
590 newton_solver.SetSolver(*J_solver);
591 newton_solver.SetOperator(*reduced_oper);
592 newton_solver.SetPrintLevel(1); // print Newton iterations
593 newton_solver.SetRelTol(rel_tol);
594 newton_solver.SetAbsTol(newton_abs_tol);
595 newton_solver.SetAdaptiveLinRtol(2, 0.5, 0.9);
596 newton_solver.SetMaxIter(10);
597}
598
599void HyperelasticOperator::Mult(const Vector &vx, Vector &dvx_dt) const
600{
601 // Create views to the sub-vectors v, x of vx, and dv_dt, dx_dt of dvx_dt
602 int sc = height/2;
603 Vector v(vx.GetData() + 0, sc);
604 Vector x(vx.GetData() + sc, sc);
605 Vector dv_dt(dvx_dt.GetData() + 0, sc);
606 Vector dx_dt(dvx_dt.GetData() + sc, sc);
607
608 H.Mult(x, z);
609 if (viscosity != 0.0)
610 {
611 S.TrueAddMult(v, z);
612 z.SetSubVector(ess_tdof_list, 0.0);
613 }
614 z.Neg(); // z = -z
615 M_solver.Mult(z, dv_dt);
616
617 dx_dt = v;
618}
619
620void HyperelasticOperator::ImplicitSolve(const real_t dt,
621 const Vector &vx, Vector &dvx_dt)
622{
623 int sc = height/2;
624 Vector v(vx.GetData() + 0, sc);
625 Vector x(vx.GetData() + sc, sc);
626 Vector dv_dt(dvx_dt.GetData() + 0, sc);
627 Vector dx_dt(dvx_dt.GetData() + sc, sc);
628
629 // By eliminating kx from the coupled system:
630 // kv = -M^{-1}*[H(x + dt*kx) + S*(v + dt*kv)]
631 // kx = v + dt*kv
632 // we reduce it to a nonlinear equation for kv, represented by the
633 // reduced_oper. This equation is solved with the newton_solver
634 // object (using J_solver and J_prec internally).
635 reduced_oper->SetParameters(dt, &v, &x);
636 Vector zero; // empty vector is interpreted as zero r.h.s. by NewtonSolver
637 newton_solver.Mult(zero, dv_dt);
638 MFEM_VERIFY(newton_solver.GetConverged(), "Newton solver did not converge.");
639 add(v, dt, dv_dt, dx_dt);
640}
641
642real_t HyperelasticOperator::ElasticEnergy(const ParGridFunction &x) const
643{
644 return H.GetEnergy(x);
645}
646
647real_t HyperelasticOperator::KineticEnergy(const ParGridFunction &v) const
648{
649 real_t energy = 0.5*M.ParInnerProduct(v, v);
650 return energy;
651}
652
653void HyperelasticOperator::GetElasticEnergyDensity(
654 const ParGridFunction &x, ParGridFunction &w) const
655{
656 ElasticEnergyCoefficient w_coeff(*model, x);
657 w.ProjectCoefficient(w_coeff);
658}
659
660HyperelasticOperator::~HyperelasticOperator()
661{
662 delete J_solver;
663 delete J_prec;
664 delete reduced_oper;
665 delete model;
666 delete Mmat;
667}
668
669
670real_t ElasticEnergyCoefficient::Eval(ElementTransformation &T,
671 const IntegrationPoint &ip)
672{
673 model.SetTransformation(T);
674 x.GetVectorGradient(T, J);
675 // return model.EvalW(J); // in reference configuration
676 return model.EvalW(J)/J.Det(); // in deformed configuration
677}
678
679
681{
682 // set the initial configuration to be the same as the reference, stress
683 // free, configuration
684 y = x;
685}
686
687void InitialVelocity(const Vector &x, Vector &v)
688{
689 const int dim = x.Size();
690 const real_t s = 0.1/64.;
691
692 v = 0.0;
693 v(dim-1) = s*x(0)*x(0)*(8.0-x(0));
694 v(0) = -s*x(0)*x(0);
695}
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:68
Backward Euler ODE solver. L-stable.
Definition ode.hpp:412
const SparseMatrix & SpMat() const
Returns a const reference to the sparse matrix: .
A class to handle Vectors in a block fashion.
Conjugate gradient method.
Definition solvers.hpp:513
virtual void Mult(const Vector &b, Vector &x) const
Iterative solution of the linear system using the Conjugate Gradient method.
Definition solvers.cpp:718
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.
Definition densemat.hpp:24
real_t Det() const
Definition densemat.cpp:535
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:559
The classical forward Euler method.
Definition ode.hpp:118
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:31
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.
Definition gridfunc.hpp:144
void MakeTRef(FiniteElementSpace *f, real_t *tv)
Associate a new FiniteElementSpace and new true-dof data with the GridFunction.
Definition gridfunc.cpp:221
void SetFromTrueVector()
Shortcut for calling SetFromTrueDofs() with GetTrueVector() as argument.
Definition gridfunc.hpp:150
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:260
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.
Definition hypre.hpp:388
void EliminateRowsCols(const Array< int > &rows_cols, const HypreParVector &X, HypreParVector &B)
Definition hypre.cpp:2356
Parallel smoothers in hypre.
Definition hypre.hpp:1020
void SetPositiveDiagonal(bool pos=true)
After computing l1-norms, replace them with their absolute values.
Definition hypre.hpp:1136
void SetType(HypreSmoother::Type type, int relax_times=1)
Set the relaxation type and number of sweeps.
Definition hypre.cpp:3550
@ l1Jacobi
l1-scaled Jacobi
Definition hypre.hpp:1080
static void Init()
Initialize hypre by calling HYPRE_Init() and set default options. After calling Hypre::Init(),...
Definition hypre.hpp:74
Implicit midpoint method. A-stable, not L-stable.
Definition ode.hpp:425
Class for integration point with weight.
Definition intrules.hpp:35
void SetRelTol(real_t rtol)
Definition solvers.hpp:209
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
Definition solvers.cpp:71
void SetMaxIter(int max_it)
Definition solvers.hpp:211
bool GetConverged() const
Returns true if the last call to Mult() converged successfully.
Definition solvers.hpp:262
void SetAbsTol(real_t atol)
Definition solvers.hpp:210
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:330
MINRES method.
Definition solvers.hpp:628
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
Definition solvers.hpp:640
Mesh data type.
Definition mesh.hpp:56
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:282
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1160
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1163
void GetNodes(Vector &node_coord) const
Definition mesh.cpp:8973
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:10970
void SwapNodes(GridFunction *&nodes, int &own_nodes_)
Swap the internal node GridFunction pointer and ownership flag members with the given ones.
Definition mesh.cpp:9022
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.
Definition solvers.hpp:667
virtual void Mult(const Vector &b, Vector &x) const
Solve the nonlinear system with right-hand side b.
Definition solvers.cpp:1821
virtual void Mult(const Vector &x, Vector &y) const
Evaluate the action of the NonlinearForm.
virtual real_t GetEnergy(const Vector &x) const
Compute the energy corresponding to the state x.
Abstract class for solving systems of ODEs: dx/dt = f(x,t)
Definition ode.hpp:24
virtual void Init(TimeDependentOperator &f_)
Associate a TimeDependentOperator with the ODE solver.
Definition ode.cpp:18
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].
Abstract operator.
Definition operator.hpp:25
int height
Dimension of the output / number of rows in the matrix.
Definition operator.hpp:27
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...
Definition optparser.hpp:82
bool Good() const
Return true if the command line options were parsed successfully.
Class for parallel bilinear form.
Abstract parallel finite element space.
Definition pfespace.hpp:29
HYPRE_BigInt GlobalTrueVSize() const
Definition pfespace.hpp:285
int TrueVSize() const
Obsolete, kept for backward compatibility.
Definition pfespace.hpp:436
Class for parallel grid function.
Definition pgridfunc.hpp:33
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.
Definition pmesh.hpp:34
MPI_Comm GetComm() const
Definition pmesh.hpp:402
int GetMyRank() const
Definition pmesh.hpp:404
int GetNRanks() const
Definition pmesh.hpp:403
void Print(std::ostream &out=mfem::out, const std::string &comments="") const override
Definition pmesh.cpp:4801
Parallel non-linear operator on the true dofs.
Third-order, strong stability preserving (SSP) Runge-Kutta method.
Definition ode.hpp:151
The classical explicit forth-order Runge-Kutta method, RK4.
Definition ode.hpp:164
Base class for solvers.
Definition operator.hpp:683
bool iterative_mode
If true, use the second argument of Mult() as an initial guess.
Definition operator.hpp:686
Data type sparse matrix.
Definition sparsemat.hpp:51
void Add(const int i, const int j, const real_t val)
Base abstract class for first order time dependent operators.
Definition operator.hpp:317
virtual void SetTime(const real_t t_)
Set the current time.
Definition operator.hpp:360
A general vector function coefficient.
Vector data type.
Definition vector.hpp:80
void Neg()
(*this) = -(*this)
Definition vector.cpp:300
void SetSubVector(const Array< int > &dofs, const real_t value)
Set the entries listed in dofs to the given value.
Definition vector.cpp:604
int Size() const
Returns the size of the vector.
Definition vector.hpp:218
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:227
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
void visualize(ostream &os, ParMesh *mesh, ParGridFunction *deformed_nodes, ParGridFunction *field, const char *field_name=NULL, bool init_vis=false)
Definition ex10p.cpp:442
void InitialDeformation(const Vector &x, Vector &y)
Definition ex10p.cpp:680
void InitialVelocity(const Vector &x, Vector &v)
Definition ex10p.cpp:687
int dim
Definition ex24.cpp:53
real_t mu
Definition ex25.cpp:140
int main()
HYPRE_Int HYPRE_BigInt
const int visport
void add(const Vector &v1, const Vector &v2, Vector &v)
Definition vector.cpp:316
float real_t
Definition config.hpp:43
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
void Add(const DenseMatrix &A, const DenseMatrix &B, real_t alpha, DenseMatrix &C)
C = A + alpha*B.
const char vishost[]
RefCoord t[3]
RefCoord s[3]