libMesh
miscellaneous_ex5.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 
20 // <h1>Miscellaneous Example 5 - Interior Penalty Discontinuous Galerkin</h1>
21 // \author Lorenzo Botti
22 // \date 2010
23 //
24 // This example is based on Adaptivity Example 3, but uses an
25 // Interior Penalty Discontinuous Galerkin formulation.
26 
27 #include <iostream>
28 
29 // LibMesh include files.
30 #include "libmesh/libmesh.h"
31 #include "libmesh/mesh.h"
32 #include "libmesh/equation_systems.h"
33 #include "libmesh/mesh_generation.h"
34 #include "libmesh/mesh_modification.h"
35 #include "libmesh/elem.h"
36 #include "libmesh/transient_system.h"
37 #include "libmesh/fe.h"
38 #include "libmesh/quadrature_gauss.h"
39 #include "libmesh/dof_map.h"
40 #include "libmesh/sparse_matrix.h"
41 #include "libmesh/dense_matrix.h"
42 #include "libmesh/dense_vector.h"
43 #include "libmesh/dense_submatrix.h"
44 #include "libmesh/dense_subvector.h"
45 #include "libmesh/numeric_vector.h"
46 #include "libmesh/linear_implicit_system.h"
47 #include "libmesh/exodusII_io.h"
48 #include "libmesh/fe_interface.h"
49 #include "libmesh/getpot.h"
50 #include "libmesh/mesh_refinement.h"
51 #include "libmesh/error_vector.h"
52 #include "libmesh/kelly_error_estimator.h"
53 #include "libmesh/discontinuity_measure.h"
54 #include "libmesh/string_to_enum.h"
55 #include "libmesh/exact_solution.h"
56 #include "libmesh/enum_solver_package.h"
57 #include "libmesh/elem_side_builder.h"
58 //#define QORDER TWENTYSIXTH
59 
60 // Bring in everything from the libMesh namespace
61 using namespace libMesh;
62 
64  const Parameters & parameters,
65  const std::string &,
66  const std::string &)
67 {
68  const Real x = p(0);
69  const Real y = p(1);
70  const Real z = p(2);
71 
72  if (parameters.get<bool>("singularity"))
73  {
74  Real theta = atan2(y, x);
75 
76  if (theta < 0)
77  theta += 2. * libMesh::pi;
78 
79  return pow(x*x + y*y, 1./3.)*sin(2./3.*theta) + z;
80  }
81  else
82  {
83  return cos(x) * exp(y) * (1. - z);
84  }
85 }
86 
87 // We now define the gradient of the exact solution, again being careful
88 // to obtain an angle from atan2 in the correct
89 // quadrant.
91  const Parameters & parameters, // es parameters
92  const std::string &, // sys_name, not needed
93  const std::string &) // unk_name, not needed
94 {
95  // Gradient value to be returned.
96  Gradient gradu;
97 
98  // x and y coordinates in space
99  const Real x = p(0);
100  const Real y = p(1);
101  const Real z = p(2);
102 
103  if (parameters.get<bool>("singularity"))
104  {
105  libmesh_assert_not_equal_to (x, 0.);
106 
107  // For convenience...
108  const Real tt = 2./3.;
109  const Real ot = 1./3.;
110 
111  // The value of the radius, squared
112  const Real r2 = x*x + y*y;
113 
114  // The boundary value, given by the exact solution,
115  // u_exact = r^(2/3)*sin(2*theta/3).
116  Real theta = atan2(y, x);
117 
118  // Make sure 0 <= theta <= 2*pi
119  if (theta < 0)
120  theta += 2. * libMesh::pi;
121 
122  // du/dx
123  gradu(0) = tt*x*pow(r2,-tt)*sin(tt*theta) - pow(r2,ot)*cos(tt*theta)*tt/(1.+y*y/x/x)*y/x/x;
124  gradu(1) = tt*y*pow(r2,-tt)*sin(tt*theta) + pow(r2,ot)*cos(tt*theta)*tt/(1.+y*y/x/x)*1./x;
125  gradu(2) = 1.;
126  }
127  else
128  {
129  gradu(0) = -sin(x) * exp(y) * (1. - z);
130  gradu(1) = cos(x) * exp(y) * (1. - z);
131  gradu(2) = -cos(x) * exp(y);
132  }
133  return gradu;
134 }
135 
136 // We now define the matrix assembly function for the
137 // Laplace system. We need to first compute element volume
138 // matrices, and then take into account the boundary
139 // conditions and the flux integrals, which will be handled
140 // via an interior penalty method.
142  const std::string & libmesh_dbg_var(system_name))
143 {
144  libMesh::out << " assembling elliptic dg system... ";
146 
147  // It is a good idea to make sure we are assembling
148  // the proper system.
149  libmesh_assert_equal_to (system_name, "EllipticDG");
150 
151  // Get a constant reference to the mesh object.
152  const MeshBase & mesh = es.get_mesh();
153  // The dimension that we are running
154  const unsigned int dim = mesh.mesh_dimension();
155 
156  // Get a reference to the LinearImplicitSystem we are solving
157  LinearImplicitSystem & ellipticdg_system = es.get_system<LinearImplicitSystem> ("EllipticDG");
158  // Get some parameters that we need during assembly
159  const Real penalty = es.parameters.get<Real> ("penalty");
160  std::string refinement_type = es.parameters.get<std::string> ("refinement");
161 
162  // A reference to the DofMap object for this system. The DofMap
163  // object handles the index translation from node and element numbers
164  // to degree of freedom numbers. We will talk more about the DofMap
165  const DofMap & dof_map = ellipticdg_system.get_dof_map();
166 
167  // Get a constant reference to the Finite Element type
168  // for the first (and only) variable in the system.
169  FEType fe_type = ellipticdg_system.variable_type(0);
170 
171  // Build a Finite Element object of the specified type. Since the
172  // FEBase::build() member dynamically creates memory we will
173  // store the object as a std::unique_ptr<FEBase>. This can be thought
174  // of as a pointer that will clean up after itself.
175  std::unique_ptr<FEBase> fe (FEBase::build(dim, fe_type));
176  std::unique_ptr<FEBase> fe_elem_face(FEBase::build(dim, fe_type));
177  std::unique_ptr<FEBase> fe_neighbor_face(FEBase::build(dim, fe_type));
178 
179  // Quadrature rules for numerical integration.
180 #ifdef QORDER
181  QGauss qrule (dim, QORDER);
182 #else
183  QGauss qrule (dim, fe_type.default_quadrature_order());
184 #endif
185  fe->attach_quadrature_rule (&qrule);
186 
187 #ifdef QORDER
188  QGauss qface(dim-1, QORDER);
189 #else
190  QGauss qface(dim-1, fe_type.default_quadrature_order());
191 #endif
192 
193  // Tell the finite element object to use our quadrature rule.
194  fe_elem_face->attach_quadrature_rule(&qface);
195  fe_neighbor_face->attach_quadrature_rule(&qface);
196 
197  // Here we define some references to cell-specific data that
198  // will be used to assemble the linear system.
199  // Data for interior volume integrals
200  const std::vector<Real> & JxW = fe->get_JxW();
201  const std::vector<std::vector<RealGradient>> & dphi = fe->get_dphi();
202 
203  // Data for surface integrals on the element boundary
204  const std::vector<std::vector<Real>> & phi_face = fe_elem_face->get_phi();
205  const std::vector<std::vector<RealGradient>> & dphi_face = fe_elem_face->get_dphi();
206  const std::vector<Real> & JxW_face = fe_elem_face->get_JxW();
207  const std::vector<Point> & qface_normals = fe_elem_face->get_normals();
208  const std::vector<Point> & qface_points = fe_elem_face->get_xyz();
209 
210  // Data for surface integrals on the neighbor boundary
211  const std::vector<std::vector<Real>> & phi_neighbor_face = fe_neighbor_face->get_phi();
212  const std::vector<std::vector<RealGradient>> & dphi_neighbor_face = fe_neighbor_face->get_dphi();
213 
214  // Define data structures to contain the element interior matrix
215  // and right-hand-side vector contribution. Following
216  // basic finite element terminology we will denote these
217  // "Ke" and "Fe".
220 
221  // Data structures to contain the element and neighbor boundary matrix
222  // contribution. This matrices will do the coupling between the dofs of
223  // the element and those of his neighbors.
224  // Ken: matrix coupling elem and neighbor dofs
229 
230  // This vector will hold the degree of freedom indices for
231  // the element. These define where in the global system
232  // the element degrees of freedom get mapped.
233  std::vector<dof_id_type> dof_indices;
234 
235  // The global system matrix
236  SparseMatrix<Number> & matrix = ellipticdg_system.get_system_matrix();
237 
238  // We need to compute element side volumes, which requires obtaining
239  // a side element. Instead of constructing a new side every time,
240  // we leverage the ElemSideBuilder which can produce element sides
241  // and only allocates memory for each unique element side type.
242  ElemSideBuilder side_builder;
243 
244  // Now we will loop over all the elements in the mesh. We will
245  // compute first the element interior matrix and right-hand-side contribution
246  // and then the element and neighbors boundary matrix contributions.
247  for (const auto & elem : mesh.active_local_element_ptr_range())
248  {
249  // Get the degree of freedom indices for the
250  // current element. These define where in the global
251  // matrix and right-hand-side this element will
252  // contribute to.
253  dof_map.dof_indices (elem, dof_indices);
254  const unsigned int n_dofs =
255  cast_int<unsigned int>(dof_indices.size());
256 
257  // Compute the element-specific data for the current
258  // element. This involves computing the location of the
259  // quadrature points (q_point) and the shape functions
260  // (phi, dphi) for the current element.
261  fe->reinit (elem);
262 
263  // Zero the element matrix and right-hand side before
264  // summing them. We use the resize member here because
265  // the number of degrees of freedom might have changed from
266  // the last element.
267  Ke.resize (n_dofs, n_dofs);
268  Fe.resize (n_dofs);
269 
270  // Now we will build the element interior matrix. This involves
271  // a double loop to integrate the test functions (i) against
272  // the trial functions (j).
273  for (unsigned int qp=0; qp<qrule.n_points(); qp++)
274  for (unsigned int i=0; i<n_dofs; i++)
275  for (unsigned int j=0; j<n_dofs; j++)
276  Ke(i,j) += JxW[qp]*(dphi[i][qp]*dphi[j][qp]);
277 
278  // Now we address boundary conditions.
279  // We consider Dirichlet bc imposed via the interior penalty method
280  // The following loops over the sides of the element.
281  // If the element has no neighbor on a side then that
282  // side MUST live on a boundary of the domain.
283  for (auto side : elem->side_index_range())
284  {
285  if (elem->neighbor_ptr(side) == nullptr)
286  {
287  // Reinit the side
288  fe_elem_face->reinit(elem, side);
289 
290  // h element dimension to compute the interior penalty penalty parameter
291  const auto side_volume = side_builder(*elem, side).volume();
292  const unsigned int elem_b_order = static_cast<unsigned int> (fe_elem_face->get_order());
293  const Real h_elem = elem->volume()/side_volume * 1./pow(elem_b_order, 2.);
294 
295  for (unsigned int qp=0; qp<qface.n_points(); qp++)
296  {
297  Number bc_value = exact_solution(qface_points[qp], es.parameters, "null", "void");
298  for (unsigned int i=0; i<n_dofs; i++)
299  {
300  // Matrix contribution
301  for (unsigned int j=0; j<n_dofs; j++)
302  {
303  // stability
304  Ke(i,j) += JxW_face[qp] * penalty/h_elem * phi_face[i][qp] * phi_face[j][qp];
305 
306  // consistency
307  Ke(i,j) -=
308  JxW_face[qp] *
309  (phi_face[i][qp] * (dphi_face[j][qp]*qface_normals[qp]) +
310  phi_face[j][qp] * (dphi_face[i][qp]*qface_normals[qp]));
311  }
312 
313  // RHS contributions
314 
315  // stability
316  Fe(i) += JxW_face[qp] * bc_value * penalty/h_elem * phi_face[i][qp];
317 
318  // consistency
319  Fe(i) -= JxW_face[qp] * dphi_face[i][qp] * (bc_value*qface_normals[qp]);
320  }
321  }
322  }
323 
324  // If the element is not on a boundary of the domain
325  // we loop over his neighbors to compute the element
326  // and neighbor boundary matrix contributions
327  else
328  {
329  // Store a pointer to the neighbor we are currently
330  // working on.
331  const Elem * neighbor = elem->neighbor_ptr(side);
332 
333  // Get the global id of the element and the neighbor
334  const unsigned int elem_id = elem->id();
335  const unsigned int neighbor_id = neighbor->id();
336 
337  // If the neighbor has the same h level and is active
338  // perform integration only if our global id is bigger than our neighbor id.
339  // We don't want to compute twice the same contributions.
340  // If the neighbor has a different h level perform integration
341  // only if the neighbor is at a lower level.
342  if ((neighbor->active() &&
343  (neighbor->level() == elem->level()) &&
344  (elem_id < neighbor_id)) ||
345  (neighbor->level() < elem->level()))
346  {
347  const Elem & elem_side = side_builder(*elem, side);
348 
349  // h dimension to compute the interior penalty penalty parameter
350  const unsigned int elem_b_order = static_cast<unsigned int>(fe_elem_face->get_order());
351  const unsigned int neighbor_b_order = static_cast<unsigned int>(fe_neighbor_face->get_order());
352  const double side_order = (elem_b_order + neighbor_b_order)/2.;
353  const Real h_elem = (elem->volume()/elem_side.volume()) * 1./pow(side_order,2.);
354 
355  // The quadrature point locations on the neighbor side
356  std::vector<Point> qface_neighbor_point;
357 
358  // The quadrature point locations on the element side
359  std::vector<Point > qface_point;
360 
361  // Reinitialize shape functions on the element side
362  fe_elem_face->reinit(elem, side);
363 
364  // Get the physical locations of the element quadrature points
365  qface_point = fe_elem_face->get_xyz();
366 
367  // Find their locations on the neighbor
368  unsigned int side_neighbor = neighbor->which_neighbor_am_i(elem);
369  if (refinement_type == "p")
370  fe_neighbor_face->side_map (neighbor,
371  &elem_side,
372  side_neighbor,
373  qface.get_points(),
374  qface_neighbor_point);
375  else
376  FEMap::inverse_map (elem->dim(), neighbor,
377  qface_point,
378  qface_neighbor_point);
379 
380  // Calculate the neighbor element shape functions at those locations
381  fe_neighbor_face->reinit(neighbor, &qface_neighbor_point);
382 
383  // Get the degree of freedom indices for the
384  // neighbor. These define where in the global
385  // matrix this neighbor will contribute to.
386  std::vector<dof_id_type> neighbor_dof_indices;
387  dof_map.dof_indices (neighbor, neighbor_dof_indices);
388  const unsigned int n_neighbor_dofs =
389  cast_int<unsigned int>(neighbor_dof_indices.size());
390 
391  // Zero the element and neighbor side matrix before
392  // summing them. We use the resize member here because
393  // the number of degrees of freedom might have changed from
394  // the last element or neighbor.
395  // Note that Kne and Ken are not square matrices if neighbor
396  // and element have a different p level
397  Kne.resize (n_neighbor_dofs, n_dofs);
398  Ken.resize (n_dofs, n_neighbor_dofs);
399  Kee.resize (n_dofs, n_dofs);
400  Knn.resize (n_neighbor_dofs, n_neighbor_dofs);
401 
402  // Now we will build the element and neighbor
403  // boundary matrices. This involves
404  // a double loop to integrate the test functions
405  // (i) against the trial functions (j).
406  for (unsigned int qp=0; qp<qface.n_points(); qp++)
407  {
408  // Kee Matrix. Integrate the element test function i
409  // against the element test function j
410  for (unsigned int i=0; i<n_dofs; i++)
411  {
412  for (unsigned int j=0; j<n_dofs; j++)
413  {
414  // consistency
415  Kee(i,j) -=
416  0.5 * JxW_face[qp] *
417  (phi_face[j][qp]*(qface_normals[qp]*dphi_face[i][qp]) +
418  phi_face[i][qp]*(qface_normals[qp]*dphi_face[j][qp]));
419 
420  // stability
421  Kee(i,j) += JxW_face[qp] * penalty/h_elem * phi_face[j][qp]*phi_face[i][qp];
422  }
423  }
424 
425  // Knn Matrix. Integrate the neighbor test function i
426  // against the neighbor test function j
427  for (unsigned int i=0; i<n_neighbor_dofs; i++)
428  {
429  for (unsigned int j=0; j<n_neighbor_dofs; j++)
430  {
431  // consistency
432  Knn(i,j) +=
433  0.5 * JxW_face[qp] *
434  (phi_neighbor_face[j][qp]*(qface_normals[qp]*dphi_neighbor_face[i][qp]) +
435  phi_neighbor_face[i][qp]*(qface_normals[qp]*dphi_neighbor_face[j][qp]));
436 
437  // stability
438  Knn(i,j) +=
439  JxW_face[qp] * penalty/h_elem * phi_neighbor_face[j][qp]*phi_neighbor_face[i][qp];
440  }
441  }
442 
443  // Kne Matrix. Integrate the neighbor test function i
444  // against the element test function j
445  for (unsigned int i=0; i<n_neighbor_dofs; i++)
446  {
447  for (unsigned int j=0; j<n_dofs; j++)
448  {
449  // consistency
450  Kne(i,j) +=
451  0.5 * JxW_face[qp] *
452  (phi_neighbor_face[i][qp]*(qface_normals[qp]*dphi_face[j][qp]) -
453  phi_face[j][qp]*(qface_normals[qp]*dphi_neighbor_face[i][qp]));
454 
455  // stability
456  Kne(i,j) -= JxW_face[qp] * penalty/h_elem * phi_face[j][qp]*phi_neighbor_face[i][qp];
457  }
458  }
459 
460  // Ken Matrix. Integrate the element test function i
461  // against the neighbor test function j
462  for (unsigned int i=0; i<n_dofs; i++)
463  {
464  for (unsigned int j=0; j<n_neighbor_dofs; j++)
465  {
466  // consistency
467  Ken(i,j) +=
468  0.5 * JxW_face[qp] *
469  (phi_neighbor_face[j][qp]*(qface_normals[qp]*dphi_face[i][qp]) -
470  phi_face[i][qp]*(qface_normals[qp]*dphi_neighbor_face[j][qp]));
471 
472  // stability
473  Ken(i,j) -= JxW_face[qp] * penalty/h_elem * phi_face[i][qp]*phi_neighbor_face[j][qp];
474  }
475  }
476  }
477 
478  // The element and neighbor boundary matrix are now built
479  // for this side. Add them to the global matrix
480  // The SparseMatrix::add_matrix() members do this for us.
481  matrix.add_matrix(Kne, neighbor_dof_indices, dof_indices);
482  matrix.add_matrix(Ken, dof_indices, neighbor_dof_indices);
483  matrix.add_matrix(Kee, dof_indices);
484  matrix.add_matrix(Knn, neighbor_dof_indices);
485  }
486  }
487  }
488  // The element interior matrix and right-hand-side are now built
489  // for this element. Add them to the global matrix and
490  // right-hand-side vector. The SparseMatrix::add_matrix()
491  // and NumericVector::add_vector() members do this for us.
492  matrix.add_matrix(Ke, dof_indices);
493  ellipticdg_system.rhs->add_vector(Fe, dof_indices);
494  }
495 
496  libMesh::out << "done" << std::endl;
497 }
498 
499 
500 
501 int main (int argc, char** argv)
502 {
503  LibMeshInit init(argc, argv);
504 
505  // This example requires a linear solver package.
506  libmesh_example_requires(libMesh::default_solver_package() != INVALID_SOLVER_PACKAGE,
507  "--enable-petsc, --enable-trilinos, or --enable-eigen");
508 
509  // Skip adaptive examples on a non-adaptive libMesh build
510 #ifndef LIBMESH_ENABLE_AMR
511  libmesh_example_requires(false, "--enable-amr");
512 #else
513 
514  //Parse the input file
515  GetPot input_file("miscellaneous_ex5.in");
516 
517  // But allow the command line to override it.
518  input_file.parse_command_line(argc, argv);
519 
520  //Read in parameters from the input file
521  const unsigned int adaptive_refinement_steps = input_file("max_adaptive_r_steps", 3);
522  const unsigned int uniform_refinement_steps = input_file("uniform_h_r_steps", 3);
523  const Real refine_fraction = input_file("refine_fraction", 0.5);
524  const Real coarsen_fraction = input_file("coarsen_fraction", 0.);
525  const unsigned int max_h_level = input_file("max_h_level", 10);
526  const std::string refinement_type = input_file("refinement_type","p");
527  Order p_order = static_cast<Order>(input_file("p_order", 1));
528  const std::string element_type = input_file("element_type", "tensor");
529  const Real penalty = input_file("ip_penalty", 10.);
530  const bool singularity = input_file("singularity", true);
531  const unsigned int dim = input_file("dimension", 3);
532  const std::string fe_family = input_file("fe_family", "MONOMIAL");
533 
534  // Skip higher-dimensional examples on a lower-dimensional libMesh build
535  libmesh_example_requires(dim <= LIBMESH_DIM, "2D/3D support");
536 
537 
538  // Create a mesh, with dimension to be overridden later, distributed
539  // across the default MPI communicator.
540  Mesh mesh(init.comm());
541 
542  if (dim == 1)
544  else if (dim == 2)
545  mesh.read("lshaped.xda");
546  else
547  mesh.read ("lshaped3D.xda");
548 
549  // Use triangles if the config file says so
550  if (element_type == "simplex")
552 
553  // Mesh Refinement object
554  MeshRefinement mesh_refinement(mesh);
555  mesh_refinement.refine_fraction() = refine_fraction;
556  mesh_refinement.coarsen_fraction() = coarsen_fraction;
557  mesh_refinement.max_h_level() = max_h_level;
558 
559  // Do uniform refinement
560  for (unsigned int rstep=0; rstep<uniform_refinement_steps; rstep++)
561  mesh_refinement.uniformly_refine(1);
562 
563  // Create an equation system object
564  EquationSystems equation_system (mesh);
565 
566  // Set parameters for the equation system and the solver
567  equation_system.parameters.set<Real>("linear solver tolerance") = TOLERANCE * TOLERANCE;
568  equation_system.parameters.set<unsigned int>("linear solver maximum iterations") = 1000;
569  equation_system.parameters.set<Real>("penalty") = penalty;
570  equation_system.parameters.set<bool>("singularity") = singularity;
571  equation_system.parameters.set<std::string>("refinement") = refinement_type;
572 
573  // Create a system named ellipticdg
574  LinearImplicitSystem & ellipticdg_system = equation_system.add_system<LinearImplicitSystem> ("EllipticDG");
575 
576  // Add a variable "u" to "ellipticdg" using the p_order specified in the config file
577  ellipticdg_system.add_variable ("u", p_order, Utility::string_to_enum<FEFamily>(fe_family));
578 
579  // Give the system a pointer to the matrix assembly function
580  ellipticdg_system.attach_assemble_function (assemble_ellipticdg);
581 
582  // Initialize the data structures for the equation system
583  equation_system.init();
584 
585  // Construct ExactSolution object and attach solution functions
586  ExactSolution exact_sol(equation_system);
589 
590  // A refinement loop.
591  for (unsigned int rstep=0; rstep<adaptive_refinement_steps; ++rstep)
592  {
593  libMesh::out << " Beginning Solve " << rstep << std::endl;
594  libMesh::out << "Number of elements: " << mesh.n_elem() << std::endl;
595 
596  // Solve the system
597  ellipticdg_system.solve();
598 
599  libMesh::out << "System has: "
600  << equation_system.n_active_dofs()
601  << " degrees of freedom."
602  << std::endl;
603 
604  libMesh::out << "Linear solver converged at step: "
605  << ellipticdg_system.n_linear_iterations()
606  << ", final residual: "
607  << ellipticdg_system.final_linear_residual()
608  << std::endl;
609 
610  // Compute the error
611  exact_sol.compute_error("EllipticDG", "u");
612 
613  // Print out the error values
614  libMesh::out << "L2-Error is: "
615  << exact_sol.l2_error("EllipticDG", "u")
616  << std::endl;
617 
618  // Possibly refine the mesh
619  if (rstep+1 < adaptive_refinement_steps)
620  {
621  // The ErrorVector is a particular StatisticsVector
622  // for computing error information on a finite element mesh.
623  ErrorVector error;
624 
625  // The discontinuity error estimator
626  // evaluate the jump of the solution
627  // on elements faces
628  DiscontinuityMeasure error_estimator;
629  error_estimator.estimate_error(ellipticdg_system,error);
630 
631  // Take the error in error and decide which elements will be coarsened or refined
632  mesh_refinement.flag_elements_by_error_fraction(error);
633  if (refinement_type == "p")
634  mesh_refinement.switch_h_to_p_refinement();
635  if (refinement_type == "hp")
636  mesh_refinement.add_p_to_h_refinement();
637 
638  // Refine and coarsen the flagged elements
639  mesh_refinement.refine_and_coarsen_elements();
640  equation_system.reinit();
641  }
642  }
643 
644  // Write out the solution
645  // After solving the system write the solution
646  // to a ExodusII-formatted plot file.
647 #ifdef LIBMESH_HAVE_EXODUS_API
648  ExodusII_IO (mesh).write_discontinuous_exodusII("lshaped_dg.e", equation_system);
649 #endif
650 
651 #endif // #ifndef LIBMESH_ENABLE_AMR
652 
653  // All done.
654  return 0;
655 }
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:196
This class handles the computation of the L2 and/or H1 error for the Systems in the EquationSystems o...
This is the EquationSystems class.
virtual void read(const std::string &name, void *mesh_data=nullptr, bool skip_renumber_nodes_and_elements=false, bool skip_find_neighbors=false)=0
Interfaces for reading/writing a mesh to/from a file.
Order
defines an enum for polynomial orders.
Definition: enum_order.h:40
This class provides the ability to map between arbitrary, user-defined strings and several data types...
Definition: parameters.h:67
static constexpr Real TOLERANCE
unsigned int dim
static Point inverse_map(const unsigned int dim, const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true, const bool extra_checks=true)
Definition: fe_map.C:1628
The ErrorVector is a specialization of the StatisticsVector for error data computed on a finite eleme...
Definition: error_vector.h:50
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
Definition: exodusII_io.h:52
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and linear solvers ...
void resize(const unsigned int n)
Resize the vector.
Definition: dense_vector.h:396
virtual void add_vector(const T *v, const std::vector< numeric_index_type > &dof_indices)
Computes , where v is a pointer and each dof_indices[i] specifies where to add value v[i]...
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
Real & coarsen_fraction()
The coarsen_fraction sets either a desired target or a desired maximum number of elements to flag for...
MeshBase & mesh
int main(int argc, char **argv)
NumericVector< Number > * rhs
The system matrix.
Order default_quadrature_order() const
Definition: fe_type.h:371
Real & refine_fraction()
The refine_fraction sets either a desired target or a desired maximum number of elements to flag for ...
This class defines a vector in LIBMESH_DIM dimensional Real or Complex space.
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition: libmesh.h:90
The libMesh namespace provides an interface to certain functionality in the library.
const T_sys & get_system(std::string_view name) const
bool singularity
unsigned int & max_h_level()
The max_h_level is the greatest refinement level an element should reach.
This class measures discontinuities between elements for debugging purposes.
This is the MeshBase class.
Definition: mesh_base.h:75
SolverPackage default_solver_package()
Definition: libmesh.C:1117
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:179
void switch_h_to_p_refinement()
Takes a mesh whose elements are flagged for h refinement and coarsening, and switches those flags to ...
void all_tri(MeshBase &mesh)
Subdivides any non-simplex elements in a Mesh to produce simplex (triangular in 2D, tetrahedral in 3D) elements.
Gradient exact_derivative(const Point &p, const Parameters &parameters, const std::string &, const std::string &)
virtual void add_matrix(const DenseMatrix< T > &dm, const std::vector< numeric_index_type > &rows, const std::vector< numeric_index_type > &cols)=0
Add the full matrix dm to the SparseMatrix.
T pow(const T &x)
Definition: utility.h:328
const T & get(std::string_view) const
Definition: parameters.h:426
Implements (adaptive) mesh refinement algorithms for a MeshBase.
dof_id_type id() const
Definition: dof_object.h:828
unsigned int which_neighbor_am_i(const Elem *e) const
This function tells you which neighbor e is.
Definition: elem.h:2919
void compute_error(std::string_view sys_name, std::string_view unknown_name)
Computes and stores the error in the solution value e = u-u_h, the gradient grad(e) = grad(u) - grad(...
virtual void reinit()
Handle any mesh changes and reinitialize all the systems on the updated mesh.
Number exact_solution(const Point &p, const Parameters &parameters, const std::string &, const std::string &)
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
unsigned int add_variable(std::string_view var, const FEType &type, const std::set< subdomain_id_type > *const active_subdomains=nullptr)
Adds the variable var to the list of variables for this system.
Definition: system.C:1357
unsigned int n_points() const
Definition: quadrature.h:131
Helper for building element sides that minimizes the construction of new elements.
Real l2_error(std::string_view sys_name, std::string_view unknown_name)
void attach_exact_deriv(unsigned int sys_num, FunctionBase< Gradient > *g)
Clone and attach an arbitrary functor which computes the exact gradient of the system sys_num solutio...
const Elem * neighbor_ptr(unsigned int i) const
Definition: elem.h:2598
BasicOStreamProxy & flush()
Flush the associated stream buffer.
unsigned int level() const
Definition: elem.h:3074
void write_discontinuous_exodusII(const std::string &name, const EquationSystems &es, const std::set< std::string > *system_names=nullptr)
Writes a exodusII file with discontinuous data.
Definition: exodusII_io.C:193
const FEType & variable_type(const unsigned int i) const
Definition: system.h:2508
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const std::vector< Point > & get_points() const
Definition: quadrature.h:156
T & set(const std::string &)
Definition: parameters.h:469
OStreamProxy out
bool refine_and_coarsen_elements()
Refines and coarsens user-requested elements.
const MeshBase & get_mesh() const
void resize(const unsigned int new_m, const unsigned int new_n)
Resizes the matrix to the specified size and calls zero().
Definition: dense_matrix.h:895
virtual Real volume() const
Definition: elem.C:3429
std::size_t n_active_dofs() const
This class implements specific orders of Gauss quadrature.
unsigned int mesh_dimension() const
Definition: mesh_base.C:372
Parameters parameters
Data structure holding arbitrary parameters.
void flag_elements_by_error_fraction(const ErrorVector &error_per_cell, const Real refine_fraction=0.3, const Real coarsen_fraction=0.0, const unsigned int max_level=libMesh::invalid_uint)
Flags elements for coarsening and refinement based on the computed error passed in error_per_cell...
void build_line(UnstructuredMesh &mesh, const unsigned int nx, const Real xmin=0., const Real xmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 1D meshes.
void assemble_ellipticdg(EquationSystems &es, const std::string &libmesh_dbg_var(system_name))
void attach_exact_value(unsigned int sys_num, FunctionBase< Number > *f)
Clone and attach an arbitrary functor which computes the exact value of the system sys_num solution a...
void add_p_to_h_refinement()
Takes a mesh whose elements are flagged for h refinement and coarsening, and adds flags to request p ...
virtual void estimate_error(const System &system, ErrorVector &error_per_cell, const NumericVector< Number > *solution_vector=nullptr, bool estimate_parent_error=false) override
This function uses the derived class&#39;s jump error estimate formula to estimate the error on each cell...
virtual void init()
Initialize all the systems.
virtual dof_id_type n_elem() const =0
virtual System & add_system(std::string_view system_type, std::string_view name)
Add the system of type system_type named name to the systems array.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50
bool active() const
Definition: elem.h:2941
const DofMap & get_dof_map() const
Definition: system.h:2374
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
const SparseMatrix< Number > & get_system_matrix() const
const Real pi
.
Definition: libmesh.h:299
void uniformly_refine(unsigned int n=1)
Uniformly refines the mesh n times.