MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
ex9p.cpp
Go to the documentation of this file.
1// MFEM Example 9 - Parallel Version
2//
3// Compile with: make ex9p
4//
5// Sample runs:
6// mpirun -np 4 ex9p -m ../data/periodic-segment.mesh -p 0 -dt 0.005
7// mpirun -np 4 ex9p -m ../data/periodic-square.mesh -p 0 -dt 0.01
8// mpirun -np 4 ex9p -m ../data/periodic-hexagon.mesh -p 0 -dt 0.01
9// mpirun -np 4 ex9p -m ../data/periodic-square.mesh -p 1 -dt 0.005 -tf 9
10// mpirun -np 4 ex9p -m ../data/periodic-hexagon.mesh -p 1 -dt 0.005 -tf 9
11// mpirun -np 4 ex9p -m ../data/amr-quad.mesh -p 1 -rp 1 -dt 0.002 -tf 9
12// mpirun -np 4 ex9p -m ../data/amr-quad.mesh -p 1 -rp 1 -dt 0.02 -s 23 -tf 9
13// mpirun -np 4 ex9p -m ../data/star-q3.mesh -p 1 -rp 1 -dt 0.004 -tf 9
14// mpirun -np 4 ex9p -m ../data/star-mixed.mesh -p 1 -rp 1 -dt 0.004 -tf 9
15// mpirun -np 4 ex9p -m ../data/disc-nurbs.mesh -p 1 -rp 1 -dt 0.005 -tf 9
16// mpirun -np 4 ex9p -m ../data/disc-nurbs.mesh -p 2 -rp 1 -dt 0.005 -tf 9
17// mpirun -np 4 ex9p -m ../data/periodic-square.mesh -p 3 -rp 2 -dt 0.0025 -tf 9 -vs 20
18// mpirun -np 4 ex9p -m ../data/periodic-cube.mesh -p 0 -o 2 -rp 1 -dt 0.01 -tf 8
19// mpirun -np 4 ex9p -m ../data/periodic-square.msh -p 0 -rs 2 -dt 0.005 -tf 2
20// mpirun -np 4 ex9p -m ../data/periodic-cube.msh -p 0 -rs 1 -o 2 -tf 2
21// mpirun -np 3 ex9p -m ../data/amr-hex.mesh -p 1 -rs 1 -rp 0 -dt 0.005 -tf 0.5
22// mpirun -np 3 ex9p -m ../data/amr-hex.mesh -p 1 -rs 1 -rp 0 -dt 0.005 -tf 0.5 -s 21 -imp-state
23//
24// Device sample runs:
25// mpirun -np 4 ex9p -pa
26// mpirun -np 4 ex9p -ea
27// mpirun -np 4 ex9p -fa
28// mpirun -np 4 ex9p -pa -m ../data/periodic-cube.mesh
29// mpirun -np 4 ex9p -pa -m ../data/periodic-cube.mesh -d cuda
30// mpirun -np 4 ex9p -ea -m ../data/periodic-cube.mesh -d cuda
31// mpirun -np 4 ex9p -fa -m ../data/periodic-cube.mesh -d cuda
32// mpirun -np 4 ex9p -pa -m ../data/amr-quad.mesh -p 1 -rp 1 -dt 0.002 -tf 9 -d cuda
33//
34// Description: This example code solves the time-dependent advection equation
35// du/dt + v.grad(u) = 0, where v is a given fluid velocity, and
36// u0(x)=u(0,x) is a given initial condition.
37//
38// The example demonstrates the use of Discontinuous Galerkin (DG)
39// bilinear forms in MFEM (face integrators), the use of implicit
40// and explicit ODE time integrators, the definition of periodic
41// boundary conditions through periodic meshes, as well as the use
42// of GLVis for persistent visualization of a time-evolving
43// solution. Saving of time-dependent data files for visualization
44// with VisIt (visit.llnl.gov) and ParaView (paraview.org), as
45// well as the optional saving with ADIOS2 (adios2.readthedocs.io)
46// are also illustrated.
47
48#include "mfem.hpp"
49#include <fstream>
50#include <iostream>
51
52using namespace std;
53using namespace mfem;
54
55// Choice for the problem setup. The fluid velocity, initial condition and
56// inflow boundary condition are chosen based on this parameter.
58
59// Velocity coefficient
60void velocity_function(const Vector &x, Vector &v);
61
62// Initial condition
63real_t u0_function(const Vector &x);
64
65// Inflow boundary condition
67
68// Mesh bounding box
70
71// Type of preconditioner for implicit time integrator
72enum class PrecType : int
73{
74 ILU = 0,
75 AIR = 1
76};
77
78#if MFEM_HYPRE_VERSION >= 21800
79// Algebraic multigrid preconditioner for advective problems based on
80// approximate ideal restriction (AIR). Most effective when matrix is
81// first scaled by DG block inverse, and AIR applied to scaled matrix.
82// See https://doi.org/10.1137/17M1144350.
83class AIR_prec : public Solver
84{
85private:
86 const HypreParMatrix *A;
87 // Copy of A scaled by block-diagonal inverse
89
90 HypreBoomerAMG *AIR_solver;
91 int blocksize;
92
93public:
94 AIR_prec(int blocksize_) : AIR_solver(NULL), blocksize(blocksize_) { }
95
96 void SetOperator(const Operator &op) override
97 {
98 width = op.Width();
99 height = op.Height();
100
101 A = dynamic_cast<const HypreParMatrix *>(&op);
102 MFEM_VERIFY(A != NULL, "AIR_prec requires a HypreParMatrix.")
103
104 // Scale A by block-diagonal inverse
105 BlockInverseScale(A, &A_s, NULL, NULL, blocksize,
107 delete AIR_solver;
108 AIR_solver = new HypreBoomerAMG(A_s);
109 AIR_solver->SetAdvectiveOptions(1, "", "FA");
110 AIR_solver->SetPrintLevel(0);
111 AIR_solver->SetMaxLevels(50);
112 }
113
114 void Mult(const Vector &x, Vector &y) const override
115 {
116 // Scale the rhs by block inverse and solve system
117 HypreParVector z_s;
118 BlockInverseScale(A, NULL, &x, &z_s, blocksize,
119 BlockInverseScaleJob::RHS_ONLY);
120 AIR_solver->Mult(z_s, y);
121 }
122
123 ~AIR_prec() override
124 {
125 delete AIR_solver;
126 }
127};
128#endif
129
130
131class DG_Solver : public Solver
132{
133private:
134 HypreParMatrix &M, &K;
135 SparseMatrix M_diag;
137 GMRESSolver linear_solver;
138 Solver *prec;
139 real_t dt;
140public:
141 DG_Solver(HypreParMatrix &M_, HypreParMatrix &K_, const FiniteElementSpace &fes,
142 PrecType prec_type)
143 : M(M_),
144 K(K_),
145 A(NULL),
146 linear_solver(M.GetComm()),
147 dt(-1.0)
148 {
149 int block_size = fes.GetTypicalFE()->GetDof();
150 if (prec_type == PrecType::ILU)
151 {
152 prec = new BlockILU(block_size,
153 BlockILU::Reordering::MINIMUM_DISCARDED_FILL);
154 }
155 else if (prec_type == PrecType::AIR)
156 {
157#if MFEM_HYPRE_VERSION >= 21800
158 prec = new AIR_prec(block_size);
159#else
160 MFEM_ABORT("Must have MFEM_HYPRE_VERSION >= 21800 to use AIR.\n");
161#endif
162 }
163 linear_solver.iterative_mode = false;
164 linear_solver.SetRelTol(1e-9);
165 linear_solver.SetAbsTol(0.0);
166 linear_solver.SetMaxIter(100);
167 linear_solver.SetPrintLevel(0);
168 linear_solver.SetPreconditioner(*prec);
169
170 M.GetDiag(M_diag);
171 }
172
173 void SetTimeStep(real_t dt_)
174 {
175 if (dt_ != dt)
176 {
177 dt = dt_;
178 // Form operator A = M - dt*K
179 delete A;
180 A = Add(-dt, K, 0.0, K);
181 SparseMatrix A_diag;
182 A->GetDiag(A_diag);
183 A_diag.Add(1.0, M_diag);
184 // this will also call SetOperator on the preconditioner
185 linear_solver.SetOperator(*A);
186 }
187 }
188
189 void SetOperator(const Operator &op) override
190 {
191 linear_solver.SetOperator(op);
192 }
193
194 void Mult(const Vector &x, Vector &y) const override
195 {
196 linear_solver.Mult(x, y);
197 }
198
199 ~DG_Solver() override
200 {
201 delete prec;
202 delete A;
203 }
204};
205
206
207/** A time-dependent operator for the right-hand side of the ODE. The DG weak
208 form of du/dt = -v.grad(u) is M du/dt = K u + b, where M and K are the mass
209 and advection matrices, and b describes the flow on the boundary. This can
210 be written as a general ODE, du/dt = M^{-1} (K u + b), and this class is
211 used to evaluate the right-hand side. */
212class FE_Evolution : public TimeDependentOperator
213{
214private:
215 OperatorHandle M, K;
216 const Vector &b;
217 Solver *M_prec;
218 CGSolver M_solver;
219 DG_Solver *dg_solver;
220
221 mutable Vector z;
222
223public:
224 FE_Evolution(ParBilinearForm &M_, ParBilinearForm &K_, const Vector &b_,
225 PrecType prec_type);
226
227 void Mult(const Vector &x, Vector &y) const override;
228 void ImplicitSolve(const real_t dt, const Vector &x, Vector &k) override;
229
230 ~FE_Evolution() override;
231};
232
233
234int main(int argc, char *argv[])
235{
236 // 1. Initialize MPI and HYPRE.
237 Mpi::Init();
238 int num_procs = Mpi::WorldSize();
239 int myid = Mpi::WorldRank();
240 Hypre::Init();
241
242 // 2. Parse command-line options.
243 problem = 0;
244 const char *mesh_file = "../data/periodic-hexagon.mesh";
245 int ser_ref_levels = 2;
246 int par_ref_levels = 0;
247 int order = 3;
248 bool pa = false;
249 bool ea = false;
250 bool fa = false;
251 const char *device_config = "cpu";
252 int ode_solver_type = 4;
253 real_t t_final = 10.0;
254 real_t dt = 0.01;
255 bool visualization = true;
256 bool visit = false;
257 bool paraview = false;
258 bool adios2 = false;
259 bool binary = false;
260 int vis_steps = 5;
261 bool solve_implicit_state = false;
262#if MFEM_HYPRE_VERSION >= 21800
263 PrecType prec_type = PrecType::AIR;
264#else
265 PrecType prec_type = PrecType::ILU;
266#endif
267 int precision = 8;
268 cout.precision(precision);
269
270 OptionsParser args(argc, argv);
271 args.AddOption(&mesh_file, "-m", "--mesh",
272 "Mesh file to use.");
273 args.AddOption(&problem, "-p", "--problem",
274 "Problem setup to use. See options in velocity_function().");
275 args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
276 "Number of times to refine the mesh uniformly in serial.");
277 args.AddOption(&par_ref_levels, "-rp", "--refine-parallel",
278 "Number of times to refine the mesh uniformly in parallel.");
279 args.AddOption(&order, "-o", "--order",
280 "Order (degree) of the finite elements.");
281 args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
282 "--no-partial-assembly", "Enable Partial Assembly.");
283 args.AddOption(&ea, "-ea", "--element-assembly", "-no-ea",
284 "--no-element-assembly", "Enable Element Assembly.");
285 args.AddOption(&fa, "-fa", "--full-assembly", "-no-fa",
286 "--no-full-assembly", "Enable Full Assembly.");
287 args.AddOption(&device_config, "-d", "--device",
288 "Device configuration string, see Device::Configure().");
289 args.AddOption(&ode_solver_type, "-s", "--ode-solver",
290 ODESolver::Types.c_str());
291 args.AddOption(&t_final, "-tf", "--t-final",
292 "Final time; start time is 0.");
293 args.AddOption(&dt, "-dt", "--time-step",
294 "Time step.");
295 args.AddOption(&solve_implicit_state, "-imp-state", "--implicit-state",
296 "-imp-slope", "--implicit-slope",
297 "Implicitly solve for stage state or slope.");
298 args.AddOption((int *)&prec_type, "-pt", "--prec-type", "Preconditioner for "
299 "implicit solves. 0 for ILU, 1 for pAIR-AMG.");
300 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
301 "--no-visualization",
302 "Enable or disable GLVis visualization.");
303 args.AddOption(&visit, "-visit", "--visit-datafiles", "-no-visit",
304 "--no-visit-datafiles",
305 "Save data files for VisIt (visit.llnl.gov) visualization.");
306 args.AddOption(&paraview, "-paraview", "--paraview-datafiles", "-no-paraview",
307 "--no-paraview-datafiles",
308 "Save data files for ParaView (paraview.org) visualization.");
309 args.AddOption(&adios2, "-adios2", "--adios2-streams", "-no-adios2",
310 "--no-adios2-streams",
311 "Save data using adios2 streams.");
312 args.AddOption(&binary, "-binary", "--binary-datafiles", "-ascii",
313 "--ascii-datafiles",
314 "Use binary (Sidre) or ascii format for VisIt data files.");
315 args.AddOption(&vis_steps, "-vs", "--visualization-steps",
316 "Visualize every n-th timestep.");
317 args.Parse();
318 if (!args.Good())
319 {
320 if (Mpi::Root())
321 {
322 args.PrintUsage(cout);
323 }
324 return 1;
325 }
326 if (Mpi::Root())
327 {
328 args.PrintOptions(cout);
329 }
330
331 Device device(device_config);
332 if (Mpi::Root()) { device.Print(); }
333
334 // 3. Read the serial mesh from the given mesh file on all processors. We can
335 // handle geometrically periodic meshes in this code.
336 Mesh *mesh = new Mesh(mesh_file, 1, 1);
337 int dim = mesh->Dimension();
338
339 // 4. Define the ODE solver used for time integration. Several explicit
340 // Runge-Kutta methods are available.
341 unique_ptr<ODESolver> ode_solver = ODESolver::Select(ode_solver_type);
342
343 // 5. Refine the mesh in serial to increase the resolution. In this example
344 // we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
345 // a command-line parameter. If the mesh is of NURBS type, we convert it
346 // to a (piecewise-polynomial) high-order mesh.
347 for (int lev = 0; lev < ser_ref_levels; lev++)
348 {
349 mesh->UniformRefinement();
350 }
351 if (mesh->NURBSext)
352 {
353 mesh->SetCurvature(max(order, 1));
354 }
355 mesh->GetBoundingBox(bb_min, bb_max, max(order, 1));
356
357 // 6. Define the parallel mesh by a partitioning of the serial mesh. Refine
358 // this mesh further in parallel to increase the resolution. Once the
359 // parallel mesh is defined, the serial mesh can be deleted.
360 ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
361 delete mesh;
362 for (int lev = 0; lev < par_ref_levels; lev++)
363 {
364 pmesh->UniformRefinement();
365 }
366
367 // 7. Define the parallel discontinuous DG finite element space on the
368 // parallel refined mesh of the given polynomial order.
370 ParFiniteElementSpace *fes = new ParFiniteElementSpace(pmesh, &fec);
371
372 HYPRE_BigInt global_vSize = fes->GlobalTrueVSize();
373 if (Mpi::Root())
374 {
375 cout << "Number of unknowns: " << global_vSize << endl;
376 }
377
378 // 8. Set up and assemble the parallel bilinear and linear forms (and the
379 // parallel hypre matrices) corresponding to the DG discretization. The
380 // DGTraceIntegrator involves integrals over mesh interior faces.
384
385 ParBilinearForm *m = new ParBilinearForm(fes);
386 ParBilinearForm *k = new ParBilinearForm(fes);
387 if (pa)
388 {
389 m->SetAssemblyLevel(AssemblyLevel::PARTIAL);
390 k->SetAssemblyLevel(AssemblyLevel::PARTIAL);
391 }
392 else if (ea)
393 {
394 m->SetAssemblyLevel(AssemblyLevel::ELEMENT);
395 k->SetAssemblyLevel(AssemblyLevel::ELEMENT);
396 }
397 else if (fa)
398 {
399 m->SetAssemblyLevel(AssemblyLevel::FULL);
400 k->SetAssemblyLevel(AssemblyLevel::FULL);
401 }
402
404 constexpr real_t alpha = -1.0;
410
411 ParLinearForm *b = new ParLinearForm(fes);
412 b->AddBdrFaceIntegrator(
413 new BoundaryFlowIntegrator(inflow, velocity, alpha));
414
415 int skip_zeros = 0;
416 m->Assemble();
417 k->Assemble(skip_zeros);
418 b->Assemble();
419 m->Finalize();
420 k->Finalize(skip_zeros);
421
422
423 HypreParVector *B = b->ParallelAssemble();
424
425 // 9. Define the initial conditions, save the corresponding grid function to
426 // a file and (optionally) save data in the VisIt format and initialize
427 // GLVis visualization.
429 u->ProjectCoefficient(u0);
430 HypreParVector *U = u->GetTrueDofs();
431
432 {
433 ostringstream mesh_name, sol_name;
434 mesh_name << "ex9-mesh." << setfill('0') << setw(6) << myid;
435 sol_name << "ex9-init." << setfill('0') << setw(6) << myid;
436 ofstream omesh(mesh_name.str().c_str());
437 omesh.precision(precision);
438 pmesh->Print(omesh);
439 ofstream osol(sol_name.str().c_str());
440 osol.precision(precision);
441 u->Save(osol);
442 }
443
444 // Create data collection for solution output: either VisItDataCollection for
445 // ascii data files, or SidreDataCollection for binary data files.
446 DataCollection *dc = NULL;
447 if (visit)
448 {
449 if (binary)
450 {
451#ifdef MFEM_USE_SIDRE
452 dc = new SidreDataCollection("Example9-Parallel", pmesh);
453#else
454 MFEM_ABORT("Must build with MFEM_USE_SIDRE=YES for binary output.");
455#endif
456 }
457 else
458 {
459 dc = new VisItDataCollection("Example9-Parallel", pmesh);
460 dc->SetPrecision(precision);
461 // To save the mesh using MFEM's parallel mesh format:
462 // dc->SetFormat(DataCollection::PARALLEL_FORMAT);
463 }
464 dc->RegisterField("solution", u);
465 dc->SetCycle(0);
466 dc->SetTime(0.0);
467 dc->Save();
468 }
469
470 ParaViewDataCollection *pd = NULL;
471 if (paraview)
472 {
473 pd = new ParaViewDataCollection("Example9P", pmesh);
474 pd->SetPrefixPath("ParaView");
475 pd->RegisterField("solution", u);
476 pd->SetLevelsOfDetail(order);
477 pd->SetDataFormat(VTKFormat::BINARY);
478 pd->SetHighOrderOutput(true);
479 pd->SetCycle(0);
480 pd->SetTime(0.0);
481 pd->Save();
482 }
483
484 // Optionally output a BP (binary pack) file using ADIOS2. This can be
485 // visualized with the ParaView VTX reader.
486#ifdef MFEM_USE_ADIOS2
487 ADIOS2DataCollection *adios2_dc = NULL;
488 if (adios2)
489 {
490 std::string postfix(mesh_file);
491 postfix.erase(0, std::string("../data/").size() );
492 postfix += "_o" + std::to_string(order);
493 const std::string collection_name = "ex9-p-" + postfix + ".bp";
494
495 adios2_dc = new ADIOS2DataCollection(MPI_COMM_WORLD, collection_name, pmesh);
496 // output data substreams are half the number of mpi processes
497 adios2_dc->SetParameter("SubStreams", std::to_string(num_procs/2) );
498 // adios2_dc->SetLevelsOfDetail(2);
499 adios2_dc->RegisterField("solution", u);
500 adios2_dc->SetCycle(0);
501 adios2_dc->SetTime(0.0);
502 adios2_dc->Save();
503 }
504#endif
505
506 socketstream sout;
507 if (visualization)
508 {
509 char vishost[] = "localhost";
510 int visport = 19916;
511 sout.open(vishost, visport);
512 if (!sout)
513 {
514 if (Mpi::Root())
515 {
516 cout << "Unable to connect to GLVis server at "
517 << vishost << ':' << visport << endl;
518 }
519 visualization = false;
520 if (Mpi::Root())
521 {
522 cout << "GLVis visualization disabled.\n";
523 }
524 }
525 else
526 {
527 sout << "parallel " << num_procs << " " << myid << "\n";
528 sout.precision(precision);
529 sout << "solution\n" << *pmesh << *u;
530 sout << "pause\n";
531 sout << flush;
532 if (Mpi::Root())
533 {
534 cout << "GLVis visualization paused."
535 << " Press space (in the GLVis window) to resume it.\n";
536 }
537 }
538 }
539
540 // 10. Define the time-dependent evolution operator describing the ODE
541 // right-hand side, and perform time-integration (looping over the time
542 // iterations, ti, with a time-step dt).
543 FE_Evolution adv(*m, *k, *B, prec_type);
544 using ImplicitVariableType = FE_Evolution::ImplicitVariableType;
545 ImplicitVariableType imp_var = solve_implicit_state ?
546 ImplicitVariableType::STATE
547 : ImplicitVariableType::SLOPE;
548
549 real_t t = 0.0;
550 adv.SetTime(t);
551 ode_solver->Init(adv);
552 ode_solver->SetImplicitVariableType(imp_var);
553
554 bool done = false;
555 for (int ti = 0; !done; )
556 {
557 real_t dt_real = min(dt, t_final - t);
558 ode_solver->Step(*U, t, dt_real);
559 ti++;
560
561 done = (t >= t_final - 1e-8*dt);
562
563 if (done || ti % vis_steps == 0)
564 {
565 if (Mpi::Root())
566 {
567 cout << "time step: " << ti << ", time: " << t << endl;
568 }
569
570 // 11. Extract the parallel grid function corresponding to the finite
571 // element approximation U (the local solution on each processor).
572 *u = *U;
573
574 if (visualization)
575 {
576 sout << "parallel " << num_procs << " " << myid << "\n";
577 sout << "solution\n" << *pmesh << *u << flush;
578 }
579
580 if (visit)
581 {
582 dc->SetCycle(ti);
583 dc->SetTime(t);
584 dc->Save();
585 }
586
587 if (paraview)
588 {
589 pd->SetCycle(ti);
590 pd->SetTime(t);
591 pd->Save();
592 }
593
594#ifdef MFEM_USE_ADIOS2
595 // transient solutions can be visualized with ParaView
596 if (adios2)
597 {
598 adios2_dc->SetCycle(ti);
599 adios2_dc->SetTime(t);
600 adios2_dc->Save();
601 }
602#endif
603 }
604 }
605
606 // 12. Save the final solution in parallel. This output can be viewed later
607 // using GLVis: "glvis -np <np> -m ex9-mesh -g ex9-final".
608 {
609 *u = *U;
610 ostringstream sol_name;
611 sol_name << "ex9-final." << setfill('0') << setw(6) << myid;
612 ofstream osol(sol_name.str().c_str());
613 osol.precision(precision);
614 u->Save(osol);
615 }
616
617 // 13. Free the used memory.
618 delete U;
619 delete u;
620 delete B;
621 delete b;
622 delete k;
623 delete m;
624 delete fes;
625 delete pmesh;
626 delete pd;
627#ifdef MFEM_USE_ADIOS2
628 if (adios2)
629 {
630 delete adios2_dc;
631 }
632#endif
633 delete dc;
634
635 return 0;
636}
637
638
639// Implementation of class FE_Evolution
640FE_Evolution::FE_Evolution(ParBilinearForm &M_, ParBilinearForm &K_,
641 const Vector &b_, PrecType prec_type)
642 : TimeDependentOperator(M_.ParFESpace()->GetTrueVSize()), b(b_),
643 M_solver(M_.ParFESpace()->GetComm()),
644 z(height)
645{
646 if (M_.GetAssemblyLevel()==AssemblyLevel::LEGACY)
647 {
648 M.Reset(M_.ParallelAssemble(), true);
649 K.Reset(K_.ParallelAssemble(), true);
650 }
651 else
652 {
653 M.Reset(&M_, false);
654 K.Reset(&K_, false);
655 }
656
657 M_solver.SetOperator(*M);
658
660 if (M_.GetAssemblyLevel()==AssemblyLevel::LEGACY)
661 {
662 HypreParMatrix &M_mat = *M.As<HypreParMatrix>();
663 HypreParMatrix &K_mat = *K.As<HypreParMatrix>();
664 HypreSmoother *hypre_prec = new HypreSmoother(M_mat, HypreSmoother::Jacobi);
665 M_prec = hypre_prec;
666
667 dg_solver = new DG_Solver(M_mat, K_mat, *M_.FESpace(), prec_type);
668 }
669 else
670 {
671 M_prec = new OperatorJacobiSmoother(M_, ess_tdof_list);
672 dg_solver = NULL;
673 }
674
675 M_solver.SetPreconditioner(*M_prec);
676 M_solver.iterative_mode = false;
677 M_solver.SetRelTol(1e-9);
678 M_solver.SetAbsTol(0.0);
679 M_solver.SetMaxIter(100);
680 M_solver.SetPrintLevel(0);
681}
682
683// Solve the equation:
684// u_t = M^{-1}(Ku + b),
685// by solving associated linear system
686// (M - dt*K) d = K*u + b
687void FE_Evolution::ImplicitSolve(const real_t dt, const Vector &x, Vector &k)
688{
689 // Construct current right-hand side for stage state vs. slope solve
690 real_t c = 1.0;
692 {
693 // k, on return, is the stage value u
694 M->Mult(x, z);
695 c = dt;
696 }
697 else
698 {
699 // k, on return, is the stage slope du/dt
700 K->Mult(x, z);
701 }
702 z.Add(c, b);
703 dg_solver->SetTimeStep(dt);
704 dg_solver->Mult(z, k);
705}
706
707void FE_Evolution::Mult(const Vector &x, Vector &y) const
708{
709 // y = M^{-1} (K x + b)
710 K->Mult(x, z);
711 z += b;
712 M_solver.Mult(z, y);
713}
714
715FE_Evolution::~FE_Evolution()
716{
717 delete M_prec;
718 delete dg_solver;
719}
720
721
722// Velocity coefficient
724{
725 int dim = x.Size();
726
727 // map to the reference [-1,1] domain
728 Vector X(dim);
729 for (int i = 0; i < dim; i++)
730 {
731 real_t center = (bb_min[i] + bb_max[i]) * 0.5;
732 X(i) = 2 * (x(i) - center) / (bb_max[i] - bb_min[i]);
733 }
734
735 switch (problem)
736 {
737 case 0:
738 {
739 // Translations in 1D, 2D, and 3D
740 switch (dim)
741 {
742 case 1: v(0) = 1.0; break;
743 case 2: v(0) = sqrt(2./3.); v(1) = sqrt(1./3.); break;
744 case 3: v(0) = sqrt(3./6.); v(1) = sqrt(2./6.); v(2) = sqrt(1./6.);
745 break;
746 }
747 break;
748 }
749 case 1:
750 case 2:
751 {
752 // Clockwise rotation in 2D around the origin
753 const real_t w = M_PI/2;
754 switch (dim)
755 {
756 case 1: v(0) = 1.0; break;
757 case 2: v(0) = w*X(1); v(1) = -w*X(0); break;
758 case 3: v(0) = w*X(1); v(1) = -w*X(0); v(2) = 0.0; break;
759 }
760 break;
761 }
762 case 3:
763 {
764 // Clockwise twisting rotation in 2D around the origin
765 const real_t w = M_PI/2;
766 real_t d = max((X(0)+1.)*(1.-X(0)),0.) * max((X(1)+1.)*(1.-X(1)),0.);
767 d = d*d;
768 switch (dim)
769 {
770 case 1: v(0) = 1.0; break;
771 case 2: v(0) = d*w*X(1); v(1) = -d*w*X(0); break;
772 case 3: v(0) = d*w*X(1); v(1) = -d*w*X(0); v(2) = 0.0; break;
773 }
774 break;
775 }
776 }
777}
778
779// Initial condition
781{
782 int dim = x.Size();
783
784 // map to the reference [-1,1] domain
785 Vector X(dim);
786 for (int i = 0; i < dim; i++)
787 {
788 real_t center = (bb_min[i] + bb_max[i]) * 0.5;
789 X(i) = 2 * (x(i) - center) / (bb_max[i] - bb_min[i]);
790 }
791
792 switch (problem)
793 {
794 case 0:
795 case 1:
796 {
797 switch (dim)
798 {
799 case 1:
800 return exp(-40.*pow(X(0)-0.5,2));
801 case 2:
802 case 3:
803 {
804 real_t rx = 0.45, ry = 0.25, cx = 0., cy = -0.2, w = 10.;
805 if (dim == 3)
806 {
807 const real_t s = (1. + 0.25*cos(2*M_PI*X(2)));
808 rx *= s;
809 ry *= s;
810 }
811 return ( std::erfc(w*(X(0)-cx-rx))*std::erfc(-w*(X(0)-cx+rx)) *
812 std::erfc(w*(X(1)-cy-ry))*std::erfc(-w*(X(1)-cy+ry)) )/16;
813 }
814 }
815 }
816 case 2:
817 {
818 real_t x_ = X(0), y_ = X(1), rho, phi;
819 rho = std::hypot(x_, y_);
820 phi = atan2(y_, x_);
821 return pow(sin(M_PI*rho),2)*sin(3*phi);
822 }
823 case 3:
824 {
825 const real_t f = M_PI;
826 return sin(f*X(0))*sin(f*X(1));
827 }
828 }
829 return 0.0;
830}
831
832// Inflow boundary condition (zero for the problems considered in this example)
834{
835 switch (problem)
836 {
837 case 0:
838 case 1:
839 case 2:
840 case 3: return 0.0;
841 }
842 return 0.0;
843}
void SetParameter(const std::string key, const std::string value) noexcept
@ GaussLobatto
Closed type.
Definition fe_base.hpp:36
void SetAssemblyLevel(AssemblyLevel assembly_level)
Set the desired assembly level.
void AddDomainIntegrator(BilinearFormIntegrator *bfi)
Adds new Domain Integrator. Assumes ownership of bfi.
void Finalize(int skip_zeros=1) override
Finalizes the matrix initialization if the AssemblyLevel is AssemblyLevel::LEGACY....
FiniteElementSpace * FESpace()
Return the FE space associated with the BilinearForm.
AssemblyLevel GetAssemblyLevel() const
Returns the assembly level.
void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi)
Adds new boundary Face Integrator. Assumes ownership of bfi.
void AddInteriorFaceIntegrator(BilinearFormIntegrator *bfi)
Adds new interior Face Integrator. Assumes ownership of bfi.
Conjugate gradient method.
Definition solvers.hpp:627
void Mult(const Vector &b, Vector &x) const override
Iterative solution of the linear system using the Conjugate Gradient method.
Definition solvers.cpp:869
void SetPrecision(int prec)
Set the precision (number of digits) used for the text output of doubles.
virtual void RegisterField(const std::string &field_name, GridFunction *gf)
Add a grid function to the collection.
void SetCycle(int c)
Set time cycle (for time-dependent simulations)
void SetTime(real_t t)
Set physical time (for time-dependent simulations)
void SetPrefixPath(const std::string &prefix)
Set the path where the DataCollection will be saved.
virtual void Save()
Save the collection to disk.
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
Definition device.hpp:129
void Print(std::ostream &os=mfem::out)
Print the configuration of the MFEM virtual device object.
Definition device.cpp:319
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:210
const FiniteElement * GetTypicalFE() const
Return GetFE(0) if the local mesh is not empty; otherwise return a typical FE based on the Geometry t...
Definition fespace.cpp:3896
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition fe_base.hpp:410
A general function coefficient.
GMRES method.
Definition solvers.hpp:661
void Mult(const Vector &b, Vector &x) const override
Iterative solution of the linear system using the GMRES method.
Definition solvers.cpp:1134
The BoomerAMG solver in hypre.
Definition hypre.hpp:1829
Wrapper for hypre's ParCSR matrix class.
Definition hypre.hpp:419
void GetDiag(Vector &diag) const
Get the local diagonal of the matrix.
Definition hypre.cpp:1610
HYPRE_Int Mult(HypreParVector &x, HypreParVector &y, real_t alpha=1.0, real_t beta=0.0) const
Computes y = alpha * A * x + beta * y.
Definition hypre.cpp:1873
Wrapper for hypre's parallel vector class.
Definition hypre.hpp:230
Parallel smoothers in hypre.
Definition hypre.hpp:1077
static void Init()
Initialize hypre by calling HYPRE_Init() and set default options. After calling Hypre::Init(),...
Definition hypre.cpp:33
void SetOperator(const Operator &op) override
Also calls SetOperator for the preconditioner if there is one.
Definition solvers.cpp:184
void SetRelTol(real_t rtol)
Definition solvers.hpp:238
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
Definition solvers.cpp:178
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
Definition solvers.cpp:76
void SetMaxIter(int max_it)
Definition solvers.hpp:240
void SetAbsTol(real_t atol)
Definition solvers.hpp:239
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:369
Mesh data type.
Definition mesh.hpp:67
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition mesh.hpp:317
void GetBoundingBox(Vector &min, Vector &max, int ref=2)
Returns the minimum and maximum corners of the mesh bounding box.
Definition mesh.cpp:142
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1314
virtual void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1, int pyr_type=1)
Set the curvature of the mesh nodes using the given polynomial degree.
Definition mesh.cpp:7211
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:12125
static bool Root()
Return true if the rank in MPI_COMM_WORLD is zero.
static int WorldRank()
Return the MPI rank in MPI_COMM_WORLD.
static int WorldSize()
Return the size of 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).
static MFEM_EXPORT std::string Types
Definition ode.hpp:235
static MFEM_EXPORT std::unique_ptr< ODESolver > Select(const int ode_solver_type)
Definition ode.cpp:41
Pointer to an Operator of a specified type.
Definition handle.hpp:34
Jacobi smoothing for a given bilinear form (no matrix necessary).
Definition solvers.hpp:422
Abstract operator.
Definition operator.hpp:27
int width
Dimension of the input / number of columns in the matrix.
Definition operator.hpp:30
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:68
int height
Dimension of the output / number of rows in the matrix.
Definition operator.hpp:29
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:74
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.
HypreParMatrix * ParallelAssemble()
Returns the matrix assembled on the true dofs, i.e. P^t A P.
void Assemble(int skip_zeros=1)
Assemble the local matrix.
Abstract parallel finite element space.
Definition pfespace.hpp:31
HYPRE_BigInt GlobalTrueVSize() const
Definition pfespace.hpp:361
Class for parallel grid function.
Definition pgridfunc.hpp:50
Class for parallel linear form.
Class for parallel meshes.
Definition pmesh.hpp:35
void Print(std::ostream &out=mfem::out, const std::string &comments="") const override
Definition pmesh.cpp:4856
void SetLevelsOfDetail(int levels_of_detail_)
Set the refinement level.
void SetHighOrderOutput(bool high_order_output_)
Sets whether or not to output the data as high-order elements (false by default).
void SetDataFormat(VTKFormat fmt)
Set the data format for the ParaView output files.
Writer for ParaView visualization (PVD and VTU format)
Data collection with Sidre routines following the Conduit mesh blueprint specification.
Base class for solvers.
Definition operator.hpp:855
bool iterative_mode
If true, use the second argument of Mult() as an initial guess.
Definition operator.hpp:858
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:367
virtual bool ImplicitVarTypeIsState() const
Returns true if implicit variable is STATE and false otherwise. Used by ODESolver to identify the sta...
Definition operator.hpp:484
virtual void SetTime(const real_t t_)
Set the current time.
Definition operator.hpp:442
A general vector function coefficient.
Vector data type.
Definition vector.hpp:82
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
Vector & Add(const real_t a, const Vector &Va)
(*this) += a * Va
Definition vector.cpp:326
Data collection with VisIt I/O routines.
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
const int * ess_tdof_list
const real_t alpha
Definition ex15.cpp:369
int dim
Definition ex24.cpp:53
void velocity_function(const Vector &x, Vector &v)
Definition ex9p.cpp:723
real_t inflow_function(const Vector &x)
Definition ex9p.cpp:833
int problem
Definition ex9p.cpp:57
PrecType
Definition ex9p.cpp:73
real_t u0_function(const Vector &x)
Definition ex9p.cpp:780
Vector bb_min
Definition ex9p.cpp:69
Vector bb_max
Definition ex9p.cpp:69
int main()
HYPRE_Int HYPRE_BigInt
real_t b
Definition lissajous.cpp:42
int GetTrueVSize(const FieldDescriptor &f)
Get the true dof size of a field descriptor.
Definition util.hpp:786
real_t u(const Vector &xvec)
Definition lor_mms.hpp:22
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition table.cpp:505
BlockInverseScaleJob
Definition hypre.hpp:1017
float real_t
Definition config.hpp:46
void BlockInverseScale(const HypreParMatrix *A, HypreParMatrix *C, const Vector *b, HypreParVector *d, int blocksize, BlockInverseScaleJob job)
Definition hypre.cpp:2970
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[]
STL namespace.
MFEM_HOST_DEVICE Complex exp(const Complex &q)
void velocity_function(const Vector &x, Vector &v)
Definition ex9p.cpp:754
double u0_function(const Vector &x)
Definition ex9p.cpp:811
int problem
Definition ex9p.cpp:54
double inflow_function(const Vector &x)
Definition ex9p.cpp:864
Vector bb_min
Definition ex9p.cpp:66
Vector bb_max
Definition ex9p.cpp:66