MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
hpref.cpp
Go to the documentation of this file.
1// Serial hp-refinement example
2//
3// Compile with: make hpref
4//
5// Sample runs: hpref -dim 2 -n 1000
6// hpref -dim 3 -n 500
7// hpref -m ../../data/star-mixed.mesh -pref -n 100
8// hpref -m ../../data/fichera-mixed.mesh -pref -n 30
9//
10// Description: This example demonstrates h- and p-refinement in a serial
11// finite element discretization of the Poisson problem (cf. ex1)
12// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
13// Refinements are performed iteratively, each iteration having h-
14// or p-refinements. For simplicity, we randomly choose the
15// elements and the type of refinement, for each iteration. In
16// practice, these choices may be made in a problem-dependent way,
17// but this example serves only to illustrate the capabilities of
18// hp-refinement.
19//
20// We recommend viewing Example 1 before viewing this example.
21
22#include "mfem.hpp"
23#include <fstream>
24#include <iostream>
25
26using namespace std;
27using namespace mfem;
28
30
31// Deterministic function for "random" integers.
32int DetRand(int & seed)
33{
34 seed++;
35 return int(std::abs(1.0e5 * sin(seed * 1.1234 * M_PI)));
36}
37
38void f_exact(const Vector &x, Vector &f);
39
40int main(int argc, char *argv[])
41{
42 // 1. Parse command-line options.
43 const char *mesh_file = "";
44 int order = 1;
45 const char *device_config = "cpu";
46 bool visualization = true;
47 int numIter = 0;
48 int dim = 2;
49 bool deterministic = true;
50 bool projectSolution = false;
51 bool onlyPref = false;
52
53 OptionsParser args(argc, argv);
54 args.AddOption(&mesh_file, "-m", "--mesh",
55 "Mesh file to use.");
56 args.AddOption(&order, "-o", "--order",
57 "Finite element order (polynomial degree) or -1 for"
58 " isoparametric space.");
59 args.AddOption(&device_config, "-d", "--device",
60 "Device configuration string, see Device::Configure().");
61 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
62 "--no-visualization",
63 "Enable or disable GLVis visualization.");
64 args.AddOption(&numIter, "-n", "--num-iter", "Number of hp-ref iterations");
65 args.AddOption(&dim, "-dim", "--dim", "Mesh dimension (2 or 3)");
66 args.AddOption(&deterministic, "-det", "--deterministic", "-not-det",
67 "--not-deterministic",
68 "Use deterministic random refinements");
69 args.AddOption(&projectSolution, "-proj", "--project-solution", "-no-proj",
70 "--no-project",
71 "Project a coefficient to solution");
72 args.AddOption(&onlyPref, "-pref", "--only-p-refinement", "-no-pref",
73 "--hp-refinement",
74 "Use only p-refinement");
75 args.Parse();
76 if (!args.Good())
77 {
78 args.PrintUsage(cout);
79 return 1;
80 }
81 args.PrintOptions(cout);
82
83 // 2. Enable hardware devices such as GPUs, and programming models such as
84 // CUDA, OCCA, RAJA and OpenMP based on command line options.
85 Device device(device_config);
86 device.Print();
87
88 // 3. Construct or load a coarse mesh.
89 std::string mesh_filename(mesh_file);
90 Mesh mesh;
91 if (!mesh_filename.empty())
92 {
93 mesh = Mesh::LoadFromFile(mesh_filename, 1, 1);
94 dim = mesh.Dimension();
95 }
96 else if (dim == 3)
97 {
99 }
100 else
101 {
103 }
104
105 mesh.EnsureNCMesh();
106
107 // 4. Define a finite element space on the mesh. Here we use continuous
108 // Lagrange finite elements of the specified order. If order < 1, we
109 // instead use an isoparametric/isogeometric space.
111 bool delete_fec;
112 if (order > 0)
113 {
114 fec = new H1_FECollection(order, dim);
115 delete_fec = true;
116 }
117 else if (mesh.GetNodes())
118 {
119 fec = mesh.GetNodes()->OwnFEC();
120 delete_fec = false;
121 cout << "Using isoparametric FEs: " << fec->Name() << endl;
122 }
123 else
124 {
125 fec = new H1_FECollection(order = 1, dim);
126 delete_fec = true;
127 }
128
129 const int fespaceDim = projectSolution ? dim : 1;
130 FiniteElementSpace fespace(&mesh, fec, fespaceDim);
131
132 // 5. Iteratively perform h- and p-refinements.
133 int numH = 0;
134 int numP = 0;
135 int seed = 0;
136
137 const std::vector<char> hp_char = {'h', 'p'};
138
139 for (int iter=0; iter<numIter; ++iter)
140 {
141 const int r1 = deterministic ? DetRand(seed) : rand();
142 const int r2 = deterministic ? DetRand(seed) : rand();
143 const int elem = r1 % mesh.GetNE();
144 const int hp = onlyPref ? 1 : r2 % 2;
145
146 cout << "hp-refinement iteration " << iter << ": "
147 << hp_char[hp] << "-refinement" << endl;
148
149 if (hp == 1)
150 {
151 // p-ref
153 refs.Append(pRefinement(elem, 1)); // Increase the element order by 1
154 fespace.PRefineAndUpdate(refs);
155 numP++;
156 }
157 else
158 {
159 // h-ref
161 refs.Append(Refinement(elem));
162 mesh.GeneralRefinement(refs);
163 fespace.Update(false);
164 numH++;
165 }
166 }
167
168 const int size = fespace.GetTrueVSize();
169 cout << "Number of finite element unknowns: " << size << endl;
170
171 const int maxP = fespace.GetMaxElementOrder();
172 cout << "Total number of h-refinements: " << numH
173 << "\nTotal number of p-refinements: " << numP
174 << "\nMaximum order " << maxP << "\n";
175
176 GridFunction x(&fespace);
177 Vector X;
178
179 if (projectSolution)
180 {
182 x.ProjectCoefficient(vec_coef);
183
184 X.SetSize(fespace.GetTrueVSize());
185
186 fespace.GetHpRestrictionMatrix()->Mult(x, X);
187 fespace.GetProlongationMatrix()->Mult(X, x);
188
189 // Compute and print the L^2 norm of the error.
190 const real_t error = x.ComputeL2Error(vec_coef);
191 cout << "\n|| E_h - E ||_{L^2} = " << error << '\n' << endl;
192 }
193 else
194 {
195 // 6. Determine the list of essential boundary dofs. In this example, the
196 // boundary conditions are defined by marking all the boundary attributes
197 // from the mesh as essential (Dirichlet) and converting them to a list of
198 // true dofs.
199 Array<int> ess_tdof_list;
200 if (mesh.bdr_attributes.Size())
201 {
202 Array<int> ess_bdr(mesh.bdr_attributes.Max());
203 ess_bdr = 1;
204 fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
205 }
206
207 // 7. Set up the linear form b(.) which corresponds to the right-hand side of
208 // the FEM linear system, which in this case is (1,phi_i) where phi_i are
209 // the basis functions in fespace.
210 LinearForm b(&fespace);
211 ConstantCoefficient one(1.0);
212 b.AddDomainIntegrator(new DomainLFIntegrator(one));
213 b.Assemble();
214
215 // 8. Define the solution vector x as a finite element grid function
216 // corresponding to fespace. Initialize x with initial guess of zero,
217 // which satisfies the boundary conditions.
218 x = 0.0;
219
220 // 9. Set up the bilinear form a(.,.) on the finite element space
221 // corresponding to the Laplacian operator -Delta, by adding the diffusion
222 // domain integrator.
223 BilinearForm a(&fespace);
224 a.AddDomainIntegrator(new DiffusionIntegrator(one));
225
226 // 10. Assemble the bilinear form and the corresponding linear system,
227 // applying any necessary transformations such as: assembly, eliminating
228 // boundary conditions, applying conforming constraints for non-conforming
229 // AMR, static condensation, etc.
230 a.Assemble();
231
232 OperatorPtr A;
233 Vector B;
234 a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
235
236 // 11. Solve the linear system A X = B.
237 {
238#ifndef MFEM_USE_SUITESPARSE
239 // Use a simple symmetric Gauss-Seidel preconditioner with PCG.
240 GSSmoother M((SparseMatrix&)(*A));
241 PCG(*A, M, B, X, 1, 200, 1e-12, 0.0);
242#else
243 // If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
244 UMFPackSolver umf_solver;
245 umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
246 umf_solver.SetOperator(*A);
247 umf_solver.Mult(B, X);
248#endif
249 }
250
251 // 12. Recover the grid function corresponding to X.
252 a.RecoverFEMSolution(X, b, x);
253 }
254
255 if (fespaceDim == 1)
256 {
257 const real_t h1error = CheckH1Continuity(x);
258 cout << "H1 continuity error " << h1error << endl;
259 MFEM_VERIFY(h1error < 1.0e-12, "H1 continuity is not satisfied");
260 }
261
262 L2_FECollection fecL2(0, dim);
263 FiniteElementSpace l2fespace(&mesh, &fecL2);
264 GridFunction xo(&l2fespace);
265 xo = 0.0;
266
267 for (int e=0; e<mesh.GetNE(); ++e)
268 {
269 const int p_elem = fespace.GetElementOrder(e);
270 Array<int> dofs;
271 l2fespace.GetElementDofs(e, dofs);
272 MFEM_VERIFY(dofs.Size() == 1, "");
273 xo[dofs[0]] = p_elem;
274 }
275
276 // 13. Save the refined mesh and the solution. This output can be viewed later
277 // using GLVis: "glvis -m refined.mesh -g sol.gf".
278 std::unique_ptr<GridFunction> vis_x = x.ProlongateToMaxOrder();
279 ofstream mesh_ofs("refined.mesh");
280 mesh_ofs.precision(8);
281 mesh.Print(mesh_ofs);
282 ofstream sol_ofs("sol.gf");
283 sol_ofs.precision(8);
284 vis_x->Save(sol_ofs);
285 ofstream order_ofs("order.gf");
286 order_ofs.precision(8);
287 xo.Save(order_ofs);
288
289 // 14. Send the solution by socket to a GLVis server.
290 if (visualization)
291 {
292 char vishost[] = "localhost";
293 int visport = 19916;
294 socketstream sol_sock(vishost, visport);
295 sol_sock.precision(8);
296 sol_sock << "solution\n" << mesh << *vis_x << flush;
297 }
298
299 // 15. Free the used memory.
300 if (delete_fec)
301 {
302 delete fec;
303 }
304
305 return 0;
306}
307
309{
310 const FiniteElementSpace *fes = x.FESpace();
311 Mesh *mesh = fes->GetMesh();
312
313 const int dim = mesh->Dimension();
314
315 // Following the example of KellyErrorEstimator::ComputeEstimates(),
316 // we loop over interior faces and compute their error contributions.
317 real_t errorMax = 0.0;
318 for (int f = 0; f < mesh->GetNumFaces(); f++)
319 {
320 if (mesh->FaceIsInterior(f))
321 {
322 int Inf1, Inf2, NCFace;
323 mesh->GetFaceInfos(f, &Inf1, &Inf2, &NCFace);
324
325 auto FT = mesh->GetFaceElementTransformations(f);
326
327 const int faceOrder = dim == 3 ? fes->GetFaceOrder(f) :
328 fes->GetEdgeOrder(f);
329 auto &int_rule = IntRules.Get(FT->FaceGeom, 2 * faceOrder);
330 const auto nip = int_rule.GetNPoints();
331
332 // Convention
333 // * Conforming face: Face side with smaller element id handles
334 // the integration
335 // * Non-conforming face: The slave handles the integration.
336 // See FaceInfo documentation for details.
337 bool isNCSlave = FT->Elem2No >= 0 && NCFace >= 0;
338 bool isConforming = FT->Elem2No >= 0 && NCFace == -1;
339 if ((FT->Elem1No < FT->Elem2No && isConforming) || isNCSlave)
340 {
341 for (int i = 0; i < nip; i++)
342 {
343 const auto &fip = int_rule.IntPoint(i);
345
346 FT->Loc1.Transform(fip, ip);
347 const real_t v1 = x.GetValue(FT->Elem1No, ip);
348
349 FT->Loc2.Transform(fip, ip);
350 const real_t v2 = x.GetValue(FT->Elem2No, ip);
351
352 const real_t err_i = std::abs(v1 - v2);
353 errorMax = std::max(errorMax, err_i);
354 }
355 }
356 }
357 }
358
359 return errorMax;
360}
361
362void f_exact(const Vector &x, Vector &f)
363{
364 constexpr real_t freq = 1.0;
365 constexpr real_t kappa = freq * M_PI;
366
367 if (x.Size() == 3)
368 {
369 f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
370 f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
371 f(2) = (1. + kappa * kappa) * sin(kappa * x(0));
372 }
373 else
374 {
375 f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
376 f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
377 if (x.Size() == 3) { f(2) = 0.0; }
378 }
379}
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:69
int Size() const
Return the logical size of the array.
Definition array.hpp:166
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:912
A "square matrix" operator for the associated FE space and BLFIntegrators The sum of all the BLFInteg...
A coefficient that is constant across space and time.
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
Definition device.hpp:124
void Print(std::ostream &os=mfem::out)
Print the configuration of the MFEM virtual device object.
Definition device.cpp:317
Class for domain integration .
Definition lininteg.hpp:108
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition fe_coll.hpp:27
virtual const char * Name() const
Definition fe_coll.hpp:79
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:208
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
Definition fespace.hpp:829
DofTransformation * GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element 'elem'. The returned indices are offsets into an ldo...
Definition fespace.cpp:3502
int GetEdgeOrder(int edge, int variant=0) const
Definition fespace.cpp:3343
int GetFaceOrder(int face, int variant=0) const
Returns the polynomial degree of the i'th face finite element.
Definition fespace.cpp:3359
virtual void GetEssentialTrueDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_tdof_list, int component=-1) const
Get a list of essential true dofs, ess_tdof_list, corresponding to the boundary attributes marked in ...
Definition fespace.cpp:628
virtual const Operator * GetProlongationMatrix() const
Definition fespace.hpp:696
virtual void Update(bool want_transform=true)
Reflect changes in the mesh: update number of DOFs, etc. Also, calculate GridFunction transformation ...
Definition fespace.cpp:4146
int GetElementOrder(int i) const
Returns the order of the i'th finite element.
Definition fespace.cpp:193
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:644
virtual void PRefineAndUpdate(const Array< pRefinement > &refs, bool want_transfer=true)
Definition fespace.cpp:4269
virtual const SparseMatrix * GetHpRestrictionMatrix() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition fespace.hpp:723
virtual int GetMaxElementOrder() const
Return the maximum polynomial order over all elements.
Definition fespace.hpp:674
Data type for Gauss-Seidel smoother of sparse matrix.
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:32
virtual real_t GetValue(int i, const IntegrationPoint &ip, int vdim=1) const
Definition gridfunc.cpp:449
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
virtual real_t ComputeL2Error(Coefficient *exsol[], const IntegrationRule *irs[]=NULL, const Array< int > *elems=NULL) const
Returns ||exsol - u_h||_L2 for scalar or vector H1 or L2 elements.
FiniteElementSpace * FESpace()
virtual void ProjectCoefficient(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
std::unique_ptr< GridFunction > ProlongateToMaxOrder() const
Return a GridFunction with the values of this, prolongated to the maximum order of all elements in th...
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:279
Class for integration point with weight.
Definition intrules.hpp:35
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:256
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:350
Vector with associated FE space and LinearFormIntegrators.
Mesh data type.
Definition mesh.hpp:65
virtual FaceElementTransformations * GetFaceElementTransformations(int FaceNo, int mask=31)
Definition mesh.cpp:1104
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:304
void GetFaceInfos(int Face, int *Inf1, int *Inf2) const
Definition mesh.cpp:1563
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition mesh.cpp:6846
void GeneralRefinement(const Array< Refinement > &refinements, int nonconforming=-1, int nc_limit=0)
Definition mesh.cpp:11225
virtual void Print(std::ostream &os=mfem::out, const std::string &comments="") const
Print the mesh to the given stream using the default MFEM mesh format.
Definition mesh.hpp:2567
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1377
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1306
bool FaceIsInterior(int FaceNo) const
Return true if the given face is interior.
Definition mesh.hpp:1563
static Mesh MakeCartesian3D(int nx, int ny, int nz, Element::Type type, real_t sx=1.0, real_t sy=1.0, real_t sz=1.0, bool sfc_ordering=true)
Creates a mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz], divided into nx*ny*nz hexahedra if type =...
Definition mesh.cpp:4627
void GetNodes(Vector &node_coord) const
Definition mesh.cpp:9627
static Mesh LoadFromFile(const std::string &filename, int generate_edges=0, int refine=1, bool fix_orientation=true)
Definition mesh.cpp:4599
void EnsureNCMesh(bool simplices_nonconforming=false)
Definition mesh.cpp:11293
static Mesh MakeCartesian2D(int nx, int ny, Element::Type type, bool generate_edges=false, real_t sx=1.0, real_t sy=1.0, bool sfc_ordering=true)
Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny quadrilaterals if type = QUADRILATER...
Definition mesh.cpp:4617
Pointer to an Operator of a specified type.
Definition handle.hpp:34
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
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.
Data type sparse matrix.
Definition sparsemat.hpp:51
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication.
Direct sparse solver using UMFPACK.
Definition solvers.hpp:1210
real_t Control[UMFPACK_CONTROL]
Definition solvers.hpp:1220
void SetOperator(const Operator &op) override
Factorize the given Operator op which must be a SparseMatrix.
Definition solvers.cpp:3368
void Mult(const Vector &b, Vector &x) const override
Direct solution of the linear system using UMFPACK.
Definition solvers.cpp:3463
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
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:584
real_t kappa
Definition ex24.cpp:54
int dim
Definition ex24.cpp:53
real_t freq
Definition ex24.cpp:54
int main()
int DetRand(int &seed)
Definition hpref.cpp:32
real_t CheckH1Continuity(GridFunction &x)
Definition hpref.cpp:308
void f_exact(const Vector &x, Vector &f)
Definition hpref.cpp:362
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
void PCG(const Operator &A, Solver &B, const Vector &b, Vector &x, int print_iter, int max_num_iter, real_t RTOLERANCE, real_t ATOLERANCE)
Preconditioned conjugate gradient method. (tolerances are squared)
Definition solvers.cpp:1067
float real_t
Definition config.hpp:46
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition intrules.hpp:492
const char vishost[]