MFEM v4.7.0
Finite element discretization library
Loading...
Searching...
No Matches
ex6.cpp
Go to the documentation of this file.
1// MFEM Example 6
2//
3// Compile with: make ex6
4//
5// Sample runs: ex6 -m ../data/square-disc.mesh -o 1
6// ex6 -m ../data/square-disc.mesh -o 2
7// ex6 -m ../data/square-disc-nurbs.mesh -o 2
8// ex6 -m ../data/star.mesh -o 3
9// ex6 -m ../data/escher.mesh -o 2
10// ex6 -m ../data/fichera.mesh -o 2
11// ex6 -m ../data/disc-nurbs.mesh -o 2
12// ex6 -m ../data/ball-nurbs.mesh
13// ex6 -m ../data/pipe-nurbs.mesh
14// ex6 -m ../data/star-surf.mesh -o 2
15// ex6 -m ../data/square-disc-surf.mesh -o 2
16// ex6 -m ../data/amr-quad.mesh
17// ex6 -m ../data/inline-segment.mesh -o 1 -md 100
18//
19// Device sample runs:
20// ex6 -pa -d cuda
21// ex6 -pa -d occa-cuda
22// ex6 -pa -d raja-omp
23// ex6 -pa -d ceed-cpu
24// * ex6 -pa -d ceed-cuda
25// ex6 -pa -d ceed-cuda:/gpu/cuda/shared
26//
27// Description: This is a version of Example 1 with a simple adaptive mesh
28// refinement loop. The problem being solved is again the Laplace
29// equation -Delta u = 1 with homogeneous Dirichlet boundary
30// conditions. The problem is solved on a sequence of meshes which
31// are locally refined in a conforming (triangles, tetrahedrons)
32// or non-conforming (quadrilaterals, hexahedra) manner according
33// to a simple ZZ error estimator.
34//
35// The example demonstrates MFEM's capability to work with both
36// conforming and nonconforming refinements, in 2D and 3D, on
37// linear, curved and surface meshes. Interpolation of functions
38// from coarse to fine meshes, as well as persistent GLVis
39// visualization are also illustrated.
40//
41// We recommend viewing Example 1 before viewing this example.
42
43#include "mfem.hpp"
44#include <fstream>
45#include <iostream>
46
47using namespace std;
48using namespace mfem;
49
50int main(int argc, char *argv[])
51{
52 // 1. Parse command-line options.
53 const char *mesh_file = "../data/star.mesh";
54 int order = 1;
55 bool pa = false;
56 const char *device_config = "cpu";
57 int max_dofs = 50000;
58 bool LSZZ = false;
59 bool visualization = true;
60
61 OptionsParser args(argc, argv);
62 args.AddOption(&mesh_file, "-m", "--mesh",
63 "Mesh file to use.");
64 args.AddOption(&order, "-o", "--order",
65 "Finite element order (polynomial degree).");
66 args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
67 "--no-partial-assembly", "Enable Partial Assembly.");
68 args.AddOption(&device_config, "-d", "--device",
69 "Device configuration string, see Device::Configure().");
70 args.AddOption(&max_dofs, "-md", "--max-dofs",
71 "Stop after reaching this many degrees of freedom.");
72 args.AddOption(&LSZZ, "-ls", "--ls-zz", "-no-ls",
73 "--no-ls-zz",
74 "Switch to least-squares ZZ estimator.");
75 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
76 "--no-visualization",
77 "Enable or disable GLVis visualization.");
78 args.Parse();
79 if (!args.Good())
80 {
81 args.PrintUsage(cout);
82 return 1;
83 }
84 args.PrintOptions(cout);
85
86 // 2. Enable hardware devices such as GPUs, and programming models such as
87 // CUDA, OCCA, RAJA and OpenMP based on command line options.
88 Device device(device_config);
89 device.Print();
90
91 // 3. Read the mesh from the given mesh file. We can handle triangular,
92 // quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
93 // the same code.
94 Mesh mesh(mesh_file, 1, 1);
95 int dim = mesh.Dimension();
96 int sdim = mesh.SpaceDimension();
97
98 // 4. Since a NURBS mesh can currently only be refined uniformly, we need to
99 // convert it to a piecewise-polynomial curved mesh. First we refine the
100 // NURBS mesh a bit more and then project the curvature to quadratic Nodes.
101 if (mesh.NURBSext)
102 {
103 for (int i = 0; i < 2; i++)
104 {
105 mesh.UniformRefinement();
106 }
107 mesh.SetCurvature(2);
108 }
109
110 // 5. Define a finite element space on the mesh. The polynomial order is
111 // one (linear) by default, but this can be changed on the command line.
112 H1_FECollection fec(order, dim);
113 FiniteElementSpace fespace(&mesh, &fec);
114
115 // 6. As in Example 1, we set up bilinear and linear forms corresponding to
116 // the Laplace problem -\Delta u = 1. We don't assemble the discrete
117 // problem yet, this will be done in the main loop.
118 BilinearForm a(&fespace);
119 if (pa)
120 {
121 a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
122 a.SetDiagonalPolicy(Operator::DIAG_ONE);
123 }
124 LinearForm b(&fespace);
125
126 ConstantCoefficient one(1.0);
127 ConstantCoefficient zero(0.0);
128
130 a.AddDomainIntegrator(integ);
131 b.AddDomainIntegrator(new DomainLFIntegrator(one));
132
133 // 7. The solution vector x and the associated finite element grid function
134 // will be maintained over the AMR iterations. We initialize it to zero.
135 GridFunction x(&fespace);
136 x = 0.0;
137
138 // 8. All boundary attributes will be used for essential (Dirichlet) BC.
139 MFEM_VERIFY(mesh.bdr_attributes.Size() > 0,
140 "Boundary attributes required in the mesh.");
141 Array<int> ess_bdr(mesh.bdr_attributes.Max());
142 ess_bdr = 1;
143
144 // 9. Connect to GLVis.
145 char vishost[] = "localhost";
146 int visport = 19916;
147 socketstream sol_sock;
148 if (visualization)
149 {
150 sol_sock.open(vishost, visport);
151 }
152
153 // 10. Set up an error estimator. Here we use the Zienkiewicz-Zhu estimator
154 // that uses the ComputeElementFlux method of the DiffusionIntegrator to
155 // recover a smoothed flux (gradient) that is subtracted from the element
156 // flux to get an error indicator. We need to supply the space for the
157 // smoothed flux: an (H1)^sdim (i.e., vector-valued) space is used here.
158 ErrorEstimator *estimator{nullptr};
159
160 if (LSZZ)
161 {
162 estimator = new LSZienkiewiczZhuEstimator(*integ, x);
163 if (dim == 3 && mesh.GetElementType(0) != Element::HEXAHEDRON)
164 {
165 dynamic_cast<LSZienkiewiczZhuEstimator *>
166 (estimator)->SetTichonovRegularization();
167 }
168 }
169 else
170 {
171 auto flux_fes = new FiniteElementSpace(&mesh, &fec, sdim);
172 estimator = new ZienkiewiczZhuEstimator(*integ, x, flux_fes);
173 dynamic_cast<ZienkiewiczZhuEstimator *>(estimator)->SetAnisotropic();
174 }
175
176 // 11. A refiner selects and refines elements based on a refinement strategy.
177 // The strategy here is to refine elements with errors larger than a
178 // fraction of the maximum element error. Other strategies are possible.
179 // The refiner will call the given error estimator.
180 ThresholdRefiner refiner(*estimator);
181 refiner.SetTotalErrorFraction(0.7);
182
183 // 12. The main AMR loop. In each iteration we solve the problem on the
184 // current mesh, visualize the solution, and refine the mesh.
185 for (int it = 0; ; it++)
186 {
187 int cdofs = fespace.GetTrueVSize();
188 cout << "\nAMR iteration " << it << endl;
189 cout << "Number of unknowns: " << cdofs << endl;
190
191 // 13. Assemble the right-hand side.
192 b.Assemble();
193
194 // 14. Set Dirichlet boundary values in the GridFunction x.
195 // Determine the list of Dirichlet true DOFs in the linear system.
196 Array<int> ess_tdof_list;
197 x.ProjectBdrCoefficient(zero, ess_bdr);
198 fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
199
200 // 15. Assemble the stiffness matrix.
201 a.Assemble();
202
203 // 16. Create the linear system: eliminate boundary conditions, constrain
204 // hanging nodes and possibly apply other transformations. The system
205 // will be solved for true (unconstrained) DOFs only.
206 OperatorPtr A;
207 Vector B, X;
208
209 const int copy_interior = 1;
210 a.FormLinearSystem(ess_tdof_list, x, b, A, X, B, copy_interior);
211
212 // 17. Solve the linear system A X = B.
213 if (!pa)
214 {
215#ifndef MFEM_USE_SUITESPARSE
216 // Use a simple symmetric Gauss-Seidel preconditioner with PCG.
217 GSSmoother M((SparseMatrix&)(*A));
218 PCG(*A, M, B, X, 3, 200, 1e-12, 0.0);
219#else
220 // If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
221 UMFPackSolver umf_solver;
222 umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
223 umf_solver.SetOperator(*A);
224 umf_solver.Mult(B, X);
225#endif
226 }
227 else // Diagonal preconditioning in partial assembly mode.
228 {
229 OperatorJacobiSmoother M(a, ess_tdof_list);
230 PCG(*A, M, B, X, 3, 2000, 1e-12, 0.0);
231 }
232
233 // 18. After solving the linear system, reconstruct the solution as a
234 // finite element GridFunction. Constrained nodes are interpolated
235 // from true DOFs (it may therefore happen that x.Size() >= X.Size()).
236 a.RecoverFEMSolution(X, b, x);
237
238 // 19. Send solution by socket to the GLVis server.
239 if (visualization && sol_sock.good())
240 {
241 sol_sock.precision(8);
242 sol_sock << "solution\n" << mesh << x << flush;
243 }
244
245 if (cdofs > max_dofs)
246 {
247 cout << "Reached the maximum number of dofs. Stop." << endl;
248 break;
249 }
250
251 // 20. Call the refiner to modify the mesh. The refiner calls the error
252 // estimator to obtain element errors, then it selects elements to be
253 // refined and finally it modifies the mesh. The Stop() method can be
254 // used to determine if a stopping criterion was met.
255 refiner.Apply(mesh);
256 if (refiner.Stop())
257 {
258 cout << "Stopping criterion satisfied. Stop." << endl;
259 break;
260 }
261
262 // 21. Update the space to reflect the new state of the mesh. Also,
263 // interpolate the solution x so that it lies in the new space but
264 // represents the same function. This saves solver iterations later
265 // since we'll have a good initial guess of x in the next step.
266 // Internally, FiniteElementSpace::Update() calculates an
267 // interpolation matrix which is then used by GridFunction::Update().
268 fespace.Update();
269 x.Update();
270
271 // 22. Inform also the bilinear and linear forms that the space has
272 // changed.
273 a.Update();
274 b.Update();
275 }
276
277 delete estimator;
278 return 0;
279}
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:68
int Size() const
Return the logical size of the array.
Definition array.hpp:144
Abstract base class BilinearFormIntegrator.
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:123
void Print(std::ostream &out=mfem::out)
Print the configuration of the MFEM virtual device object.
Definition device.cpp:286
Class for domain integration .
Definition lininteg.hpp:109
Base class for all element based error estimators.
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:220
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
Definition fespace.hpp:716
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:588
virtual void Update(bool want_transform=true)
Reflect changes in the mesh: update number of DOFs, etc. Also, calculate GridFunction transformation ...
Definition fespace.cpp:3439
Data type for Gauss-Seidel smoother of sparse matrix.
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:31
virtual void Update()
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition gridfunc.cpp:164
void ProjectBdrCoefficient(Coefficient &coeff, const Array< int > &attr)
Project a Coefficient on the GridFunction, modifying only DOFs on the boundary associated with the bo...
Definition gridfunc.hpp:469
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:260
The LSZienkiewiczZhuEstimator class implements the Zienkiewicz-Zhu error estimation procedure [1,...
Vector with associated FE space and LinearFormIntegrators.
bool Apply(Mesh &mesh)
Perform the mesh operation.
bool Stop() const
Check if STOP action is requested, e.g. stopping criterion is satisfied.
Mesh data type.
Definition mesh.hpp:56
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:282
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition mesh.hpp:290
Element::Type GetElementType(int i) const
Returns the type of element i.
Definition mesh.cpp:7316
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
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:6211
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:10970
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:313
@ DIAG_ONE
Set the diagonal value to one.
Definition operator.hpp:50
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
Mesh refinement operator using an error threshold.
void SetTotalErrorFraction(real_t fraction)
Set the total fraction used in the computation of the threshold. The default value is 1/2.
Direct sparse solver using UMFPACK.
Definition solvers.hpp:1096
virtual void SetOperator(const Operator &op)
Factorize the given Operator op which must be a SparseMatrix.
Definition solvers.cpp:3102
real_t Control[UMFPACK_CONTROL]
Definition solvers.hpp:1106
virtual void Mult(const Vector &b, Vector &x) const
Direct solution of the linear system using UMFPACK.
Definition solvers.cpp:3197
Vector data type.
Definition vector.hpp:80
The ZienkiewiczZhuEstimator class implements the Zienkiewicz-Zhu error estimation procedure.
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
int dim
Definition ex24.cpp:53
int main()
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
const int visport
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:913
const char vishost[]