MFEM  v4.1.0
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
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 //
18 // Device sample runs:
19 // ex6 -pa -d cuda
20 // ex6 -pa -d occa-cuda
21 // ex6 -pa -d raja-omp
22 // ex6 -pa -d ceed-cpu
23 // ex6 -pa -d ceed-cuda
24 //
25 // Description: This is a version of Example 1 with a simple adaptive mesh
26 // refinement loop. The problem being solved is again the Laplace
27 // equation -Delta u = 1 with homogeneous Dirichlet boundary
28 // conditions. The problem is solved on a sequence of meshes which
29 // are locally refined in a conforming (triangles, tetrahedrons)
30 // or non-conforming (quadrilaterals, hexahedra) manner according
31 // to a simple ZZ error estimator.
32 //
33 // The example demonstrates MFEM's capability to work with both
34 // conforming and nonconforming refinements, in 2D and 3D, on
35 // linear, curved and surface meshes. Interpolation of functions
36 // from coarse to fine meshes, as well as persistent GLVis
37 // visualization are also illustrated.
38 //
39 // We recommend viewing Example 1 before viewing this example.
40 
41 #include "mfem.hpp"
42 #include <fstream>
43 #include <iostream>
44 
45 using namespace std;
46 using namespace mfem;
47 
48 int main(int argc, char *argv[])
49 {
50  // 1. Parse command-line options.
51  const char *mesh_file = "../data/star.mesh";
52  int order = 1;
53  bool pa = false;
54  const char *device_config = "cpu";
55  bool visualization = true;
56 
57  OptionsParser args(argc, argv);
58  args.AddOption(&mesh_file, "-m", "--mesh",
59  "Mesh file to use.");
60  args.AddOption(&order, "-o", "--order",
61  "Finite element order (polynomial degree).");
62  args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
63  "--no-partial-assembly", "Enable Partial Assembly.");
64  args.AddOption(&device_config, "-d", "--device",
65  "Device configuration string, see Device::Configure().");
66  args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
67  "--no-visualization",
68  "Enable or disable GLVis visualization.");
69  args.Parse();
70  if (!args.Good())
71  {
72  args.PrintUsage(cout);
73  return 1;
74  }
75  args.PrintOptions(cout);
76 
77  // 2. Enable hardware devices such as GPUs, and programming models such as
78  // CUDA, OCCA, RAJA and OpenMP based on command line options.
79  Device device(device_config);
80  device.Print();
81 
82  // 3. Read the mesh from the given mesh file. We can handle triangular,
83  // quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
84  // the same code.
85  Mesh mesh(mesh_file, 1, 1);
86  int dim = mesh.Dimension();
87  int sdim = mesh.SpaceDimension();
88 
89  // 4. Since a NURBS mesh can currently only be refined uniformly, we need to
90  // convert it to a piecewise-polynomial curved mesh. First we refine the
91  // NURBS mesh a bit more and then project the curvature to quadratic Nodes.
92  if (mesh.NURBSext)
93  {
94  for (int i = 0; i < 2; i++)
95  {
96  mesh.UniformRefinement();
97  }
98  mesh.SetCurvature(2);
99  }
100 
101  // 5. Define a finite element space on the mesh. The polynomial order is
102  // one (linear) by default, but this can be changed on the command line.
103  H1_FECollection fec(order, dim);
104  FiniteElementSpace fespace(&mesh, &fec);
105 
106  // 6. As in Example 1, we set up bilinear and linear forms corresponding to
107  // the Laplace problem -\Delta u = 1. We don't assemble the discrete
108  // problem yet, this will be done in the main loop.
109  BilinearForm a(&fespace);
110  if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
111  LinearForm b(&fespace);
112 
113  ConstantCoefficient one(1.0);
114  ConstantCoefficient zero(0.0);
115 
117  a.AddDomainIntegrator(integ);
119 
120  // 7. The solution vector x and the associated finite element grid function
121  // will be maintained over the AMR iterations. We initialize it to zero.
122  GridFunction x(&fespace);
123  x = 0.0;
124 
125  // 8. All boundary attributes will be used for essential (Dirichlet) BC.
126  MFEM_VERIFY(mesh.bdr_attributes.Size() > 0,
127  "Boundary attributes required in the mesh.");
128  Array<int> ess_bdr(mesh.bdr_attributes.Max());
129  ess_bdr = 1;
130 
131  // 9. Connect to GLVis.
132  char vishost[] = "localhost";
133  int visport = 19916;
134  socketstream sol_sock;
135  if (visualization)
136  {
137  sol_sock.open(vishost, visport);
138  }
139 
140  // 10. Set up an error estimator. Here we use the Zienkiewicz-Zhu estimator
141  // that uses the ComputeElementFlux method of the DiffusionIntegrator to
142  // recover a smoothed flux (gradient) that is subtracted from the element
143  // flux to get an error indicator. We need to supply the space for the
144  // smoothed flux: an (H1)^sdim (i.e., vector-valued) space is used here.
145  FiniteElementSpace flux_fespace(&mesh, &fec, sdim);
146  ZienkiewiczZhuEstimator estimator(*integ, x, flux_fespace);
147  estimator.SetAnisotropic();
148 
149  // 11. A refiner selects and refines elements based on a refinement strategy.
150  // The strategy here is to refine elements with errors larger than a
151  // fraction of the maximum element error. Other strategies are possible.
152  // The refiner will call the given error estimator.
153  ThresholdRefiner refiner(estimator);
154  refiner.SetTotalErrorFraction(0.7);
155 
156  // 12. The main AMR loop. In each iteration we solve the problem on the
157  // current mesh, visualize the solution, and refine the mesh.
158  const int max_dofs = 50000;
159  for (int it = 0; ; it++)
160  {
161  int cdofs = fespace.GetTrueVSize();
162  cout << "\nAMR iteration " << it << endl;
163  cout << "Number of unknowns: " << cdofs << endl;
164 
165  // 13. Assemble the right-hand side.
166  b.Assemble();
167 
168  // 14. Set Dirichlet boundary values in the GridFunction x.
169  // Determine the list of Dirichlet true DOFs in the linear system.
170  Array<int> ess_tdof_list;
171  x.ProjectBdrCoefficient(zero, ess_bdr);
172  fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
173 
174  // 15. Assemble the stiffness matrix.
175  a.Assemble();
176 
177  // 16. Create the linear system: eliminate boundary conditions, constrain
178  // hanging nodes and possibly apply other transformations. The system
179  // will be solved for true (unconstrained) DOFs only.
180  OperatorPtr A;
181  Vector B, X;
182 
183  const int copy_interior = 1;
184  a.FormLinearSystem(ess_tdof_list, x, b, A, X, B, copy_interior);
185 
186  // 17. Solve the linear system A X = B.
187  if (!pa)
188  {
189 #ifndef MFEM_USE_SUITESPARSE
190  // Use a simple symmetric Gauss-Seidel preconditioner with PCG.
191  GSSmoother M((SparseMatrix&)(*A));
192  PCG(*A, M, B, X, 3, 200, 1e-12, 0.0);
193 #else
194  // If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
195  UMFPackSolver umf_solver;
196  umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
197  umf_solver.SetOperator(*A);
198  umf_solver.Mult(B, X);
199 #endif
200  }
201  else // No preconditioning for now in partial assembly mode.
202  {
203  CG(*A, B, X, 3, 2000, 1e-12, 0.0);
204  }
205 
206  // 18. After solving the linear system, reconstruct the solution as a
207  // finite element GridFunction. Constrained nodes are interpolated
208  // from true DOFs (it may therefore happen that x.Size() >= X.Size()).
209  a.RecoverFEMSolution(X, b, x);
210 
211  // 19. Send solution by socket to the GLVis server.
212  if (visualization && sol_sock.good())
213  {
214  sol_sock.precision(8);
215  sol_sock << "solution\n" << mesh << x << flush;
216  }
217 
218  if (cdofs > max_dofs)
219  {
220  cout << "Reached the maximum number of dofs. Stop." << endl;
221  break;
222  }
223 
224  // 20. Call the refiner to modify the mesh. The refiner calls the error
225  // estimator to obtain element errors, then it selects elements to be
226  // refined and finally it modifies the mesh. The Stop() method can be
227  // used to determine if a stopping criterion was met.
228  refiner.Apply(mesh);
229  if (refiner.Stop())
230  {
231  cout << "Stopping criterion satisfied. Stop." << endl;
232  break;
233  }
234 
235  // 21. Update the space to reflect the new state of the mesh. Also,
236  // interpolate the solution x so that it lies in the new space but
237  // represents the same function. This saves solver iterations later
238  // since we'll have a good initial guess of x in the next step.
239  // Internally, FiniteElementSpace::Update() calculates an
240  // interpolation matrix which is then used by GridFunction::Update().
241  fespace.Update();
242  x.Update();
243 
244  // 22. Inform also the bilinear and linear forms that the space has
245  // changed.
246  a.Update();
247  b.Update();
248  }
249 
250  return 0;
251 }
int Size() const
Logical size of the array.
Definition: array.hpp:124
Class for domain integration L(v) := (f, v)
Definition: lininteg.hpp:93
void SetAnisotropic(bool aniso=true)
Enable/disable anisotropic estimates. To enable this option, the BilinearFormIntegrator must support ...
Definition: estimators.hpp:149
Class for grid function - Vector with associated FE space.
Definition: gridfunc.hpp:27
virtual void Update(bool want_transform=true)
Definition: fespace.cpp:2057
void Assemble(int skip_zeros=1)
Assembles the form i.e. sums over all domain/bdr integrators.
Subclass constant coefficient.
Definition: coefficient.hpp:67
void Assemble()
Assembles the linear form i.e. sums over all domain/bdr integrators.
Definition: linearform.cpp:79
Pointer to an Operator of a specified type.
Definition: handle.hpp:33
virtual void FormLinearSystem(const Array< int > &ess_tdof_list, Vector &x, Vector &b, OperatorHandle &A, Vector &X, Vector &B, int copy_interior=0)
Form the linear system A X = B, corresponding to this bilinear form and the linear form b(...
virtual void RecoverFEMSolution(const Vector &X, const Vector &b, Vector &x)
Recover the solution of a linear system formed with FormLinearSystem().
virtual void GetEssentialTrueDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_tdof_list, int component=-1)
Definition: fespace.cpp:366
bool Stop() const
Check if STOP action is requested, e.g. stopping criterion is satisfied.
void Print(std::ostream &out=mfem::out)
Print the configuration of the MFEM virtual device object.
Definition: device.cpp:236
void SetAssemblyLevel(AssemblyLevel assembly_level)
Set the desired assembly level. The default is AssemblyLevel::FULL.
int main(int argc, char *argv[])
Definition: ex1.cpp:62
Data type for Gauss-Seidel smoother of sparse matrix.
Direct sparse solver using UMFPACK.
Definition: solvers.hpp:580
bool Apply(Mesh &mesh)
Perform the mesh operation.
Data type sparse matrix.
Definition: sparsemat.hpp:40
double b
Definition: lissajous.cpp:42
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition: mesh.cpp:7982
Mesh refinement operator using an error threshold.
virtual void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1)
Definition: mesh.cpp:3924
T Max() const
Find the maximal element in the array, using the comparison operator &lt; for class T.
Definition: array.cpp:68
void CG(const Operator &A, const Vector &b, Vector &x, int print_iter, int max_num_iter, double RTOLERANCE, double ATOLERANCE)
Conjugate gradient method. (tolerances are squared)
Definition: solvers.cpp:516
virtual void Update(FiniteElementSpace *nfes=NULL)
void PCG(const Operator &A, Solver &B, const Vector &b, Vector &x, int print_iter, int max_num_iter, double RTOLERANCE, double ATOLERANCE)
Preconditioned conjugate gradient method. (tolerances are squared)
Definition: solvers.cpp:529
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
Definition: fespace.hpp:384
int Dimension() const
Definition: mesh.hpp:744
void PrintUsage(std::ostream &out) const
Definition: optparser.cpp:434
int SpaceDimension() const
Definition: mesh.hpp:745
void AddDomainIntegrator(LinearFormIntegrator *lfi)
Adds new Domain Integrator. Assumes ownership of lfi.
Definition: linearform.cpp:39
Abstract base class BilinearFormIntegrator.
Definition: bilininteg.hpp:24
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition: mesh.hpp:189
double Control[UMFPACK_CONTROL]
Definition: solvers.hpp:591
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition: fespace.hpp:87
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)
Definition: optparser.hpp:76
virtual void Update()
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition: gridfunc.cpp:152
void Update()
Update the object according to the associated FE space fes.
Definition: linearform.hpp:166
double a
Definition: lissajous.cpp:41
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition: mesh.hpp:191
int dim
Definition: ex24.cpp:43
void AddDomainIntegrator(BilinearFormIntegrator *bfi)
Adds new Domain Integrator. Assumes ownership of bfi.
void PrintOptions(std::ostream &out) const
Definition: optparser.cpp:304
int open(const char hostname[], int port)
The ZienkiewiczZhuEstimator class implements the Zienkiewicz-Zhu error estimation procedure...
Definition: estimators.hpp:72
Vector data type.
Definition: vector.hpp:48
Arbitrary order H1-conforming (continuous) finite elements.
Definition: fe_coll.hpp:83
Class for linear form - Vector with associated FE space and LFIntegrators.
Definition: linearform.hpp:23
void SetTotalErrorFraction(double fraction)
Set the total fraction used in the computation of the threshold. The default value is 1/2...
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
Definition: device.hpp:114
virtual void Mult(const Vector &b, Vector &x) const
Operator application: y=A(x).
Definition: solvers.cpp:2382
void ProjectBdrCoefficient(Coefficient &coeff, Array< int > &attr)
Project a Coefficient on the GridFunction, modifying only DOFs on the boundary associated with the bo...
Definition: gridfunc.hpp:287
virtual void SetOperator(const Operator &op)
Factorize the given Operator op which must be a SparseMatrix.
Definition: solvers.cpp:2285
bool Good() const
Definition: optparser.hpp:125