MFEM  v3.3 Finite element discretization library
ex8.cpp
Go to the documentation of this file.
1 // MFEM Example 8
2 //
3 // Compile with: make ex8
4 //
5 // Sample runs: ex8 -m ../data/square-disc.mesh
6 // ex8 -m ../data/star.mesh
7 // ex8 -m ../data/escher.mesh
8 // ex8 -m ../data/fichera.mesh
9 // ex8 -m ../data/square-disc-p2.vtk
10 // ex8 -m ../data/square-disc-p3.mesh
11 // ex8 -m ../data/star-surf.mesh -o 2
12 // ex8 -m ../data/mobius-strip.mesh
13 //
14 // Description: This example code demonstrates the use of the Discontinuous
15 // Petrov-Galerkin (DPG) method in its primal 2x2 block form as a
16 // simple finite element discretization of the Laplace problem
17 // -Delta u = f with homogeneous Dirichlet boundary conditions. We
18 // use high-order continuous trial space, a high-order interfacial
19 // (trace) space, and a high-order discontinuous test space
20 // defining a local dual (H^{-1}) norm.
21 //
22 // We use the primal form of DPG, see "A primal DPG method without
23 // a first-order reformulation", Demkowicz and Gopalakrishnan, CAM
24 // 2013, DOI:10.1016/j.camwa.2013.06.029.
25 //
26 // The example highlights the use of interfacial (trace) finite
27 // elements and spaces, trace face integrators and the definition
28 // of block operators and preconditioners.
29 //
30 // We recommend viewing examples 1-5 before viewing this example.
31
32 #include "mfem.hpp"
33 #include <fstream>
34 #include <iostream>
35
36 using namespace std;
37 using namespace mfem;
38
39 int main(int argc, char *argv[])
40 {
41  // 1. Parse command-line options.
42  const char *mesh_file = "../data/star.mesh";
43  int order = 1;
44  bool visualization = 1;
45
46  OptionsParser args(argc, argv);
48  "Mesh file to use.");
50  "Finite element order (polynomial degree).");
52  "--no-visualization",
53  "Enable or disable GLVis visualization.");
54  args.Parse();
55  if (!args.Good())
56  {
57  args.PrintUsage(cout);
58  return 1;
59  }
60  args.PrintOptions(cout);
61
62  // 2. Read the mesh from the given mesh file. We can handle triangular,
63  // quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
64  // the same code.
65  Mesh *mesh = new Mesh(mesh_file, 1, 1);
66  int dim = mesh->Dimension();
67
68  // 3. Refine the mesh to increase the resolution. In this example we do
69  // 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
70  // largest number that gives a final mesh with no more than 10,000
71  // elements.
72  {
73  int ref_levels =
74  (int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
75  for (int l = 0; l < ref_levels; l++)
76  {
77  mesh->UniformRefinement();
78  }
79  }
80
81  // 4. Define the trial, interfacial (trace) and test DPG spaces:
82  // - The trial space, x0_space, contains the non-interfacial unknowns and
83  // has the essential BC.
84  // - The interfacial space, xhat_space, contains the interfacial unknowns
85  // and does not have essential BC.
86  // - The test space, test_space, is an enriched space where the enrichment
87  // degree may depend on the spatial dimension of the domain, the type of
88  // the mesh and the trial space order.
89  int trial_order = order;
90  int trace_order = order - 1;
91  int test_order = order; // reduced order, full order is (order + dim - 1)
92  if (dim == 2 && (order%2 == 0 || (mesh->MeshGenerator() & 2 && order > 1)))
93  {
94  test_order++;
95  }
96  if (test_order < trial_order)
97  cerr << "Warning, test space not enriched enough to handle primal"
98  << " trial space\n";
99
100  FiniteElementCollection *x0_fec, *xhat_fec, *test_fec;
101
102  x0_fec = new H1_FECollection(trial_order, dim);
103  xhat_fec = new RT_Trace_FECollection(trace_order, dim);
104  test_fec = new L2_FECollection(test_order, dim);
105
106  FiniteElementSpace *x0_space = new FiniteElementSpace(mesh, x0_fec);
107  FiniteElementSpace *xhat_space = new FiniteElementSpace(mesh, xhat_fec);
108  FiniteElementSpace *test_space = new FiniteElementSpace(mesh, test_fec);
109
110  // 5. Define the block structure of the problem, by creating the offset
111  // variables. Also allocate two BlockVector objects to store the solution
112  // and rhs.
113  enum {x0_var, xhat_var, NVAR};
114
115  int s0 = x0_space->GetVSize();
116  int s1 = xhat_space->GetVSize();
117  int s_test = test_space->GetVSize();
118
119  Array<int> offsets(NVAR+1);
120  offsets[0] = 0;
121  offsets[1] = s0;
122  offsets[2] = s0+s1;
123
124  Array<int> offsets_test(2);
125  offsets_test[0] = 0;
126  offsets_test[1] = s_test;
127
128  std::cout << "\nNumber of Unknowns:\n"
129  << " Trial space, X0 : " << s0
130  << " (order " << trial_order << ")\n"
131  << " Interface space, Xhat : " << s1
132  << " (order " << trace_order << ")\n"
133  << " Test space, Y : " << s_test
134  << " (order " << test_order << ")\n\n";
135
136  BlockVector x(offsets), b(offsets);
137  x = 0.;
138
139  // 6. Set up the linear form F(.) which corresponds to the right-hand side of
140  // the FEM linear system, which in this case is (f,phi_i) where f=1.0 and
141  // phi_i are the basis functions in the test finite element fespace.
142  ConstantCoefficient one(1.0);
143  LinearForm F(test_space);
145  F.Assemble();
146
147  // 7. Set up the mixed bilinear form for the primal trial unknowns, B0,
148  // the mixed bilinear form for the interfacial unknowns, Bhat,
149  // the inverse stiffness matrix on the discontinuous test space, Sinv,
150  // and the stiffness matrix on the continuous trial space, S0.
151  Array<int> ess_bdr(mesh->bdr_attributes.Max());
152  ess_bdr = 1;
153
154  MixedBilinearForm *B0 = new MixedBilinearForm(x0_space,test_space);
156  B0->Assemble();
157  B0->EliminateTrialDofs(ess_bdr, x.GetBlock(x0_var), F);
158  B0->Finalize();
159
160  MixedBilinearForm *Bhat = new MixedBilinearForm(xhat_space,test_space);
162  Bhat->Assemble();
163  Bhat->Finalize();
164
165  BilinearForm *Sinv = new BilinearForm(test_space);
166  SumIntegrator *Sum = new SumIntegrator;
170  Sinv->Assemble();
171  Sinv->Finalize();
172
173  BilinearForm *S0 = new BilinearForm(x0_space);
175  S0->Assemble();
176  S0->EliminateEssentialBC(ess_bdr);
177  S0->Finalize();
178
179  SparseMatrix &matB0 = B0->SpMat();
180  SparseMatrix &matBhat = Bhat->SpMat();
181  SparseMatrix &matSinv = Sinv->SpMat();
182  SparseMatrix &matS0 = S0->SpMat();
183
184  // 8. Set up the 1x2 block Least Squares DPG operator, B = [B0 Bhat],
185  // the normal equation operator, A = B^t Sinv B, and
186  // the normal equation right-hand-size, b = B^t Sinv F.
187  BlockOperator B(offsets_test, offsets);
188  B.SetBlock(0,0,&matB0);
189  B.SetBlock(0,1,&matBhat);
190  RAPOperator A(B, matSinv, B);
191  {
192  Vector SinvF(s_test);
193  matSinv.Mult(F,SinvF);
194  B.MultTranspose(SinvF, b);
195  }
196
197  // 9. Set up a block-diagonal preconditioner for the 2x2 normal equation
198  //
199  // [ S0^{-1} 0 ]
200  // [ 0 Shat^{-1} ] Shat = (Bhat^T Sinv Bhat)
201  //
202  // corresponding to the primal (x0) and interfacial (xhat) unknowns.
203  SparseMatrix * Shat = RAP(matBhat, matSinv, matBhat);
204
205 #ifndef MFEM_USE_SUITESPARSE
206  const double prec_rtol = 1e-3;
207  const int prec_maxit = 200;
208  CGSolver *S0inv = new CGSolver;
209  S0inv->SetOperator(matS0);
210  S0inv->SetPrintLevel(-1);
211  S0inv->SetRelTol(prec_rtol);
212  S0inv->SetMaxIter(prec_maxit);
213  CGSolver *Shatinv = new CGSolver;
214  Shatinv->SetOperator(*Shat);
215  Shatinv->SetPrintLevel(-1);
216  Shatinv->SetRelTol(prec_rtol);
217  Shatinv->SetMaxIter(prec_maxit);
218  // Disable 'iterative_mode' when using CGSolver (or any IterativeSolver) as
219  // a preconditioner:
220  S0inv->iterative_mode = false;
221  Shatinv->iterative_mode = false;
222 #else
223  Operator *S0inv = new UMFPackSolver(matS0);
224  Operator *Shatinv = new UMFPackSolver(*Shat);
225 #endif
226
227  BlockDiagonalPreconditioner P(offsets);
228  P.SetDiagonalBlock(0, S0inv);
229  P.SetDiagonalBlock(1, Shatinv);
230
231  // 10. Solve the normal equation system using the PCG iterative solver.
232  // Check the weighted norm of residual for the DPG least square problem.
233  // Wrap the primal variable in a GridFunction for visualization purposes.
234  PCG(A, P, b, x, 1, 200, 1e-12, 0.0);
235
236  {
237  Vector LSres(s_test);
238  B.Mult(x, LSres);
239  LSres -= F;
240  double res = sqrt(matSinv.InnerProduct(LSres, LSres));
241  cout << "\n|| B0*x0 + Bhat*xhat - F ||_{S^-1} = " << res << endl;
242  }
243
244  GridFunction x0;
245  x0.MakeRef(x0_space, x.GetBlock(x0_var), 0);
246
247  // 11. Save the refined mesh and the solution. This output can be viewed
248  // later using GLVis: "glvis -m refined.mesh -g sol.gf".
249  {
250  ofstream mesh_ofs("refined.mesh");
251  mesh_ofs.precision(8);
252  mesh->Print(mesh_ofs);
253  ofstream sol_ofs("sol.gf");
254  sol_ofs.precision(8);
255  x0.Save(sol_ofs);
256  }
257
258  // 12. Send the solution by socket to a GLVis server.
259  if (visualization)
260  {
261  char vishost[] = "localhost";
262  int visport = 19916;
263  socketstream sol_sock(vishost, visport);
264  sol_sock.precision(8);
265  sol_sock << "solution\n" << *mesh << x0 << flush;
266  }
267
268  // 13. Free the used memory.
269  delete S0inv;
270  delete Shatinv;
271  delete Shat;
272  delete Bhat;
273  delete B0;
274  delete S0;
275  delete Sinv;
276  delete test_space;
277  delete test_fec;
278  delete xhat_space;
279  delete xhat_fec;
280  delete x0_space;
281  delete x0_fec;
282  delete mesh;
283
284  return 0;
285 }
Class for domain integration L(v) := (f, v)
Definition: lininteg.hpp:47
int GetVSize() const
Definition: fespace.hpp:163
Definition: solvers.hpp:111
Class for grid function - Vector with associated FE space.
Definition: gridfunc.hpp:27
Integrator defining a sum of multiple Integrators.
Definition: bilininteg.hpp:150
void Assemble(int skip_zeros=1)
Assembles the form i.e. sums over all domain/bdr integrators.
Subclass constant coefficient.
Definition: coefficient.hpp:57
void Assemble()
Assembles the linear form i.e. sums over all domain/bdr integrators.
Definition: linearform.cpp:42
virtual void MultTranspose(const Vector &x, Vector &y) const
Action of the transpose operator.
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:584
Definition: bilininteg.hpp:160
void SetBlock(int iRow, int iCol, Operator *op)
Add a block op in the block-entry (iblock, jblock).
bool iterative_mode
If true, use the second argument of Mult() as an initial guess.
Definition: operator.hpp:261
virtual void Finalize(int skip_zeros=1)
Finalizes the matrix initialization.
int main(int argc, char *argv[])
Direct sparse solver using UMFPACK.
Definition: solvers.hpp:337
Integrator that inverts the matrix assembled by another integrator.
Definition: bilininteg.hpp:132
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
Definition: gridfunc.cpp:2185
int dim
Definition: ex3.cpp:47
void SetPrintLevel(int print_lvl)
Definition: solvers.cpp:71
A class to handle Block diagonal preconditioners in a matrix-free implementation. ...
Data type sparse matrix.
Definition: sparsemat.hpp:38
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition: mesh.cpp:6684
void SetMaxIter(int max_it)
Definition: solvers.hpp:63
HypreParMatrix * RAP(HypreParMatrix *A, HypreParMatrix *P)
Returns the matrix P^t * A * P.
Definition: hypre.cpp:1385
int MeshGenerator()
Get the mesh generator/type.
Definition: mesh.hpp:577
T Max() const
Find the maximal element in the array, using the comparison operator &lt; for class T.
Definition: array.cpp:108
void Assemble(int skip_zeros=1)
The operator x -&gt; R*A*P*x.
Definition: operator.hpp:318
void EliminateTrialDofs(Array< int > &bdr_attr_is_ess, Vector &sol, Vector &rhs)
void MakeRef(FiniteElementSpace *f, double *v)
Make the GridFunction reference external data on a new FiniteElementSpace.
Definition: gridfunc.cpp:179
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:456
int Dimension() const
Definition: mesh.hpp:611
void PrintUsage(std::ostream &out) const
Definition: optparser.cpp:434
virtual void Mult(const Vector &x, Vector &y) const
Operator application.
Definition: linearform.cpp:19
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition: mesh.hpp:142
void SetRelTol(double rtol)
Definition: solvers.hpp:61
virtual void Mult(const Vector &x, Vector &y) const
Matrix vector multiplication.
Definition: sparsemat.cpp:475
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:74
const SparseMatrix & SpMat() const
virtual void Finalize(int skip_zeros=1)
Finalizes the matrix initialization.
void PrintOptions(std::ostream &out) const
Definition: optparser.cpp:304
virtual void SetOperator(const Operator &op)
Also calls SetOperator for the preconditioner if there is one.
Definition: solvers.hpp:125
Vector data type.
Definition: vector.hpp:36
Arbitrary order H1-conforming (continuous) finite elements.
Definition: fe_coll.hpp:146
Class for linear form - Vector with associated FE space and LFIntegrators.
Definition: linearform.hpp:23
const SparseMatrix & SpMat() const
Returns a reference to the sparse matrix.
Abstract operator.
Definition: operator.hpp:21
void EliminateEssentialBC(const Array< int > &bdr_attr_is_ess, Vector &sol, Vector &rhs, int d=0)
A class to handle Block systems in a matrix-free implementation.
double InnerProduct(const Vector &x, const Vector &y) const
Compute y^t A x.
Definition: sparsemat.cpp:679
void SetDiagonalBlock(int iblock, Operator *op)
Add a square block op in the block-entry (iblock, iblock).
Arbitrary order &quot;L2-conforming&quot; discontinuous finite elements.
Definition: fe_coll.hpp:195
virtual void Print(std::ostream &out=std::cout) const
Definition: mesh.hpp:988
bool Good() const
Definition: optparser.hpp:120