MFEM v4.7.0
Finite element discretization library
Loading...
Searching...
No Matches
plor_solvers.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11//
12// ------------------------------------------
13// Parallel Low-Order Refined Solvers Miniapp
14// ------------------------------------------
15//
16// This miniapp illustrates the use of low-order refined preconditioners for
17// finite element problems defined using H1, H(curl), H(div), or L2 finite
18// element spaces. The following problems are solved, depending on the chosen
19// finite element space:
20//
21// H1 and L2: definite Helmholtz problem, u - Delta u = f
22// (in L2 discretized using the symmetric interior penalty DG method)
23//
24// H(curl): definite Maxwell problem, u + curl curl u = f
25//
26// H(div): grad-div problem, u - grad(div u) = f
27//
28// In each case, the high-order finite element problem is preconditioned using a
29// low-order finite element discretization defined on a Gauss-Lobatto refined
30// mesh. The low-order problem is solved using hypre's AMG preconditioners:
31// BoomerAMG is used for H1 and L2 problems, AMS is used for H(curl) and 2D
32// H(div) problems, and ADS is used for 3D H(div) problems.
33//
34// For vector finite element spaces, the special "Integrated" basis type is used
35// to obtain spectral equivalence between the high-order and low-order refined
36// discretizations. This basis is defined in reference [1] and spectral
37// equivalence is shown in [2]:
38//
39// [1]. M. Gerritsma. Edge functions for spectral element methods. Spectral and
40// High Order Methods for Partial Differential Equations. (2010)
41// [2]. C. Dohrmann. Spectral equivalence properties of higher-order tensor
42// product finite elements and applications to preconditioning. (2021)
43//
44// The action of the high-order operator is computed using MFEM's partial
45// assembly/matrix-free algorithms (except in the case of L2, which remains
46// future work).
47//
48// Compile with: make plor_solvers
49//
50// Sample runs:
51//
52// mpirun -np 4 plor_solvers -m ../../data/fichera.mesh -fe h
53// mpirun -np 4 plor_solvers -m ../../data/fichera.mesh -fe n
54// mpirun -np 4 plor_solvers -m ../../data/fichera.mesh -fe r
55// mpirun -np 4 plor_solvers -m ../../data/fichera.mesh -fe l
56// mpirun -np 4 plor_solvers -m ../../data/amr-hex.mesh -fe h -rs 0 -o 2
57// mpirun -np 4 plor_solvers -m ../../data/amr-hex.mesh -fe l -rs 0 -o 2
58// mpirun -np 4 plor_solvers -m ../../data/star-surf.mesh -fe h
59// mpirun -np 4 plor_solvers -m ../../data/star-surf.mesh -fe n
60// mpirun -np 4 plor_solvers -m ../../data/star-surf.mesh -fe r
61//
62// Device sample runs:
63// mpirun -np 4 plor_solvers -m ../../data/fichera.mesh -fe h -d cuda
64// mpirun -np 4 plor_solvers -m ../../data/fichera.mesh -fe n -d cuda
65// mpirun -np 4 plor_solvers -m ../../data/fichera.mesh -fe r -d cuda
66// mpirun -np 4 plor_solvers -m ../../data/fichera.mesh -fe l -d cuda
67
68#include "mfem.hpp"
69#include <fstream>
70#include <iostream>
71#include <memory>
72
73#include "lor_mms.hpp"
74
75using namespace std;
76using namespace mfem;
77
78int main(int argc, char *argv[])
79{
80 Mpi::Init();
82
83 const char *mesh_file = "../../data/star.mesh";
84 int ser_ref_levels = 1, par_ref_levels = 1;
85 int order = 3;
86 const char *fe = "h";
87 const char *device_config = "cpu";
88 bool visualization = true;
89
90 OptionsParser args(argc, argv);
91 args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use.");
92 args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
93 "Number of times to refine the mesh uniformly in serial.");
94 args.AddOption(&par_ref_levels, "-rp", "--refine-parallel",
95 "Number of times to refine the mesh uniformly in parallel.");
96 args.AddOption(&order, "-o", "--order", "Polynomial degree.");
97 args.AddOption(&fe, "-fe", "--fe-type",
98 "FE type. h for H1, n for Hcurl, r for Hdiv, l for L2");
99 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
100 "--no-visualization",
101 "Enable or disable GLVis visualization.");
102 args.AddOption(&device_config, "-d", "--device",
103 "Device configuration string, see Device::Configure().");
104 args.ParseCheck();
105
106 Device device(device_config);
107 if (Mpi::Root()) { device.Print(); }
108
109 bool H1 = false, ND = false, RT = false, L2 = false;
110 if (string(fe) == "h") { H1 = true; }
111 else if (string(fe) == "n") { ND = true; }
112 else if (string(fe) == "r") { RT = true; }
113 else if (string(fe) == "l") { L2 = true; }
114 else { MFEM_ABORT("Bad FE type. Must be 'h', 'n', 'r', or 'l'."); }
115
116 real_t kappa = (order+1)*(order+1); // Penalty used for DG discretizations
117
118 Mesh serial_mesh(mesh_file, 1, 1);
119 const int dim = serial_mesh.Dimension();
120 const int sdim = serial_mesh.SpaceDimension();
121 MFEM_VERIFY(dim == 2 || dim == 3, "Mesh dimension must be 2 or 3.");
122 MFEM_VERIFY(!L2 || dim == sdim, "DG surface meshes not supported.");
123 for (int l = 0; l < ser_ref_levels; l++) { serial_mesh.UniformRefinement(); }
124 ParMesh mesh(MPI_COMM_WORLD, serial_mesh);
125 for (int l = 0; l < par_ref_levels; l++) { mesh.UniformRefinement(); }
126 serial_mesh.Clear();
127
128 if (mesh.ncmesh && (RT || ND))
129 { MFEM_ABORT("LOR AMS and ADS solvers are not supported with AMR meshes."); }
130
131 FunctionCoefficient f_coeff(f(1.0)), u_coeff(u);
132 VectorFunctionCoefficient f_vec_coeff(sdim, f_vec(RT)),
133 u_vec_coeff(sdim, u_vec);
134
136 unique_ptr<FiniteElementCollection> fec;
137 if (H1) { fec.reset(new H1_FECollection(order, dim, b1)); }
138 else if (ND) { fec.reset(new ND_FECollection(order, dim, b1, b2)); }
139 else if (RT) { fec.reset(new RT_FECollection(order-1, dim, b1, b2)); }
140 else { fec.reset(new L2_FECollection(order, dim, b1)); }
141
142 ParFiniteElementSpace fes(&mesh, fec.get());
143 HYPRE_Int ndofs = fes.GlobalTrueVSize();
144 if (Mpi::Root()) { cout << "Number of DOFs: " << ndofs << endl; }
145
146 Array<int> ess_dofs;
147 // In DG, boundary conditions are enforced weakly, so no essential DOFs.
148 if (!L2) { fes.GetBoundaryTrueDofs(ess_dofs); }
149
150 ParBilinearForm a(&fes);
151 if (H1 || L2)
152 {
153 a.AddDomainIntegrator(new MassIntegrator);
154 a.AddDomainIntegrator(new DiffusionIntegrator);
155 }
156 else
157 {
158 a.AddDomainIntegrator(new VectorFEMassIntegrator);
159 }
160
161 if (ND) { a.AddDomainIntegrator(new CurlCurlIntegrator); }
162 else if (RT) { a.AddDomainIntegrator(new DivDivIntegrator); }
163 else if (L2)
164 {
165 a.AddInteriorFaceIntegrator(new DGDiffusionIntegrator(-1.0, kappa));
166 a.AddBdrFaceIntegrator(new DGDiffusionIntegrator(-1.0, kappa));
167 }
168 // Partial assembly not currently supported for DG or for surface meshes with
169 // vector finite elements (ND or RT).
170 if (!L2 && (H1 || sdim == dim)) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
171 a.Assemble();
172
173 ParLinearForm b(&fes);
174 if (H1 || L2) { b.AddDomainIntegrator(new DomainLFIntegrator(f_coeff)); }
175 else { b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(f_vec_coeff)); }
176 if (L2)
177 {
178 // DG boundary conditions are enforced weakly with this integrator.
179 b.AddBdrFaceIntegrator(new DGDirichletLFIntegrator(u_coeff, -1.0, kappa));
180 }
181 b.Assemble();
182
183 ParGridFunction x(&fes);
184 if (H1 || L2) { x.ProjectCoefficient(u_coeff);}
185 else { x.ProjectCoefficient(u_vec_coeff); }
186
187 Vector X, B;
189 a.FormLinearSystem(ess_dofs, x, b, A, X, B);
190
191 unique_ptr<Solver> solv_lor;
192 if (H1 || L2)
193 {
194 solv_lor.reset(new LORSolver<HypreBoomerAMG>(a, ess_dofs));
195 }
196 else if (RT && dim == 3)
197 {
198 solv_lor.reset(new LORSolver<HypreADS>(a, ess_dofs));
199 }
200 else
201 {
202 solv_lor.reset(new LORSolver<HypreAMS>(a, ess_dofs));
203 }
204
205 CGSolver cg(MPI_COMM_WORLD);
206 cg.SetAbsTol(0.0);
207 cg.SetRelTol(1e-12);
208 cg.SetMaxIter(500);
209 cg.SetPrintLevel(1);
210 cg.SetOperator(*A);
211 cg.SetPreconditioner(*solv_lor);
212 cg.Mult(B, X);
213
214 a.RecoverFEMSolution(X, b, x);
215
216 if (sdim == dim)
217 {
218 real_t er =
219 (H1 || L2) ? x.ComputeL2Error(u_coeff) : x.ComputeL2Error(u_vec_coeff);
220 if (Mpi::Root()) { cout << "L2 error: " << er << endl; }
221 }
222
223 if (visualization)
224 {
225 // Save the solution and mesh to disk. The output can be viewed using
226 // GLVis as follows: "glvis -np <np> -m mesh -g sol"
227 x.Save("sol");
228 mesh.Save("mesh");
229
230 // Also save the solution for visualization using ParaView
231 ParaViewDataCollection dc("PLOR", &mesh);
232 dc.SetPrefixPath("ParaView");
233 dc.SetHighOrderOutput(true);
234 dc.SetLevelsOfDetail(order);
235 dc.RegisterField("u", &x);
236 dc.SetCycle(0);
237 dc.SetTime(0.0);
238 dc.Save();
239 }
240
241 return 0;
242}
@ GaussLobatto
Closed type.
Definition fe_base.hpp:32
@ IntegratedGLL
Integrated GLL indicator functions.
Definition fe_base.hpp:39
Conjugate gradient method.
Definition solvers.hpp:513
virtual void SetOperator(const Operator &op)
Also calls SetOperator for the preconditioner if there is one.
Definition solvers.hpp:526
virtual void Mult(const Vector &b, Vector &x) const
Iterative solution of the linear system using the Conjugate Gradient method.
Definition solvers.cpp:718
Integrator for for Nedelec elements.
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.
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:286
for Raviart-Thomas elements
Class for domain integration .
Definition lininteg.hpp:109
void GetBoundaryTrueDofs(Array< int > &boundary_dofs, int component=-1)
Get a list of all boundary true dofs, boundary_dofs. For spaces with 'vdim' > 1, the 'component' para...
Definition fespace.cpp:632
A general function coefficient.
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:260
static void Init()
Initialize hypre by calling HYPRE_Init() and set default options. After calling Hypre::Init(),...
Definition hypre.hpp:74
void SetRelTol(real_t rtol)
Definition solvers.hpp:209
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
Definition solvers.cpp:173
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
void SetAbsTol(real_t atol)
Definition solvers.hpp:210
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:330
Represents a solver of type SolverType created using the low-order refined version of the given Bilin...
Definition lor.hpp:204
Mesh data type.
Definition mesh.hpp:56
void Clear()
Clear the contents of the Mesh.
Definition mesh.hpp:730
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
NCMesh * ncmesh
Optional nonconforming mesh extension.
Definition mesh.hpp:291
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:10970
static bool Root()
Return true if the rank in MPI_COMM_WORLD is zero.
static void Init(int &argc, char **&argv, int required=default_thread_required, int *provided=nullptr)
Singleton creation with Mpi::Init(argc, argv).
Arbitrary order H(curl)-conforming Nedelec finite elements.
Definition fe_coll.hpp:465
Pointer to an Operator of a specified type.
Definition handle.hpp:34
void ParseCheck(std::ostream &out=mfem::out)
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
Class for parallel bilinear form.
Abstract parallel finite element space.
Definition pfespace.hpp:29
HYPRE_BigInt GlobalTrueVSize() const
Definition pfespace.hpp:285
Class for parallel grid function.
Definition pgridfunc.hpp:33
void Save(std::ostream &out) const override
real_t ComputeL2Error(Coefficient *exsol[], const IntegrationRule *irs[]=NULL, const Array< int > *elems=NULL) 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 linear form.
Class for parallel meshes.
Definition pmesh.hpp:34
void Save(const std::string &fname, int precision=16) const override
Definition pmesh.cpp:4940
Helper class for ParaView visualization data.
void SetHighOrderOutput(bool high_order_output_)
void SetLevelsOfDetail(int levels_of_detail_)
virtual void Save() override
Arbitrary order H(div)-conforming Raviart-Thomas finite elements.
Definition fe_coll.hpp:386
for VectorFiniteElements (Nedelec, Raviart-Thomas)
Definition lininteg.hpp:347
A general vector function coefficient.
Vector data type.
Definition vector.hpp:80
real_t kappa
Definition ex24.cpp:54
int dim
Definition ex24.cpp:53
int main()
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
real_t u(const Vector &xvec)
Definition lor_mms.hpp:22
void u_vec(const Vector &xvec, Vector &u)
Definition lor_mms.hpp:50
std::function< void(const Vector &, Vector &)> f_vec(bool grad_div_problem)
Definition lor_mms.hpp:68
float real_t
Definition config.hpp:43
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30