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