Loading [MathJax]/extensions/tex2jax.js
libMesh
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
adaptivity_ex3.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>Adaptivity Example 3 - Laplace Equation in the L-Shaped Domain</h1>
21 // \author Benjamin S. Kirk
22 // \date 2003
23 //
24 // This example solves the Laplace equation on the classic "L-shaped"
25 // domain with adaptive mesh refinement. In this case, the exact
26 // solution is u(r,\theta) = r^{2/3} * \sin ( (2/3) * \theta), but
27 // the standard Kelly error indicator is used to estimate the error.
28 // The initial mesh contains three QUAD9 elements which represent the
29 // standard quadrants I, II, and III of the domain [-1,1]x[-1,1],
30 // i.e.
31 // Element 0: [-1,0]x[ 0,1]
32 // Element 1: [ 0,1]x[ 0,1]
33 // Element 2: [-1,0]x[-1,0]
34 // The mesh is provided in the standard libMesh ASCII format file
35 // named "lshaped.xda". In addition, an input file named "adaptivity_ex3.in"
36 // is provided which allows the user to set several parameters for
37 // the solution so that the problem can be re-run without a
38 // re-compile. The solution technique employed is to have a
39 // refinement loop with a linear solve inside followed by a
40 // refinement of the grid and projection of the solution to the new grid
41 // In the final loop iteration, there is no additional
42 // refinement after the solve. In the input file "adaptivity_ex3.in",
43 // the variable "max_r_steps" controls the number of refinement steps,
44 // "max_r_level" controls the maximum element refinement level, and
45 // "refine_percentage" / "coarsen_percentage" determine the number of
46 // elements which will be refined / coarsened at each step.
47 
48 // LibMesh include files.
49 #include "libmesh/mesh.h"
50 #include "libmesh/equation_systems.h"
51 #include "libmesh/linear_implicit_system.h"
52 #include "libmesh/exodusII_io.h"
53 #include "libmesh/tecplot_io.h"
54 #include "libmesh/fe.h"
55 #include "libmesh/quadrature_gauss.h"
56 #include "libmesh/dense_matrix.h"
57 #include "libmesh/dense_vector.h"
58 #include "libmesh/sparse_matrix.h"
59 #include "libmesh/mesh_refinement.h"
60 #include "libmesh/error_vector.h"
61 #include "libmesh/discontinuity_measure.h"
62 #include "libmesh/exact_error_estimator.h"
63 #include "libmesh/kelly_error_estimator.h"
64 #include "libmesh/patch_recovery_error_estimator.h"
65 #include "libmesh/uniform_refinement_estimator.h"
66 #include "libmesh/hp_coarsentest.h"
67 #include "libmesh/hp_singular.h"
68 #include "libmesh/sibling_coupling.h"
69 #include "libmesh/mesh_generation.h"
70 #include "libmesh/mesh_modification.h"
71 #include "libmesh/perf_log.h"
72 #include "libmesh/getpot.h"
73 #include "libmesh/exact_solution.h"
74 #include "libmesh/dof_map.h"
75 #include "libmesh/numeric_vector.h"
76 #include "libmesh/elem.h"
77 #include "libmesh/string_to_enum.h"
78 #include "libmesh/enum_solver_package.h"
79 #include "libmesh/dirichlet_boundaries.h"
80 #include "libmesh/wrapped_function.h"
81 
82 // Bring in everything from the libMesh namespace
83 using namespace libMesh;
84 
85 // Function prototype. This is the function that will assemble
86 // the linear system for our Laplace problem. Note that the
87 // function will take the EquationSystems object and the
88 // name of the system we are assembling as input. From the
89 // EquationSystems object we have access to the Mesh and
90 // other objects we might need.
92  const std::string & system_name);
93 
94 
95 // Prototype for calculation of the exact solution. Useful
96 // for setting boundary conditions.
97 Number exact_solution(const Point & p,
98  const Parameters &, // EquationSystem parameters, not needed
99  const std::string &, // sys_name, not needed
100  const std::string &); // unk_name, not needed);
101 
102 // Prototype for calculation of the gradient of the exact solution.
104  const Parameters &, // EquationSystems parameters, not needed
105  const std::string &, // sys_name, not needed
106  const std::string &); // unk_name, not needed);
107 
108 
109 // These are non-const because the input file may change it,
110 // It is global because our exact_* functions use it.
111 
112 // Set the dimensionality of the mesh
113 unsigned int dim = 2;
114 
115 // Set the number of variables to solve for
116 unsigned int n_vars = 1;
117 
118 // Choose whether or not to use the singular solution
119 bool singularity = true;
120 
121 
122 int main(int argc, char ** argv)
123 {
124  // Initialize libMesh.
125  LibMeshInit init (argc, argv);
126 
127  // This example requires a linear solver package.
128  libmesh_example_requires(libMesh::default_solver_package() != INVALID_SOLVER_PACKAGE,
129  "--enable-petsc, --enable-trilinos, or --enable-eigen");
130 
131  // Single precision is inadequate for p refinement
132  libmesh_example_requires(sizeof(Real) > 4, "--disable-singleprecision");
133 
134  // Skip adaptive examples on a non-adaptive libMesh build
135 #ifndef LIBMESH_ENABLE_AMR
136  libmesh_example_requires(false, "--enable-amr");
137 #else
138 
139  // Parse the input file
140  GetPot input_file("adaptivity_ex3.in");
141 
142  // But allow the command line to override it.
143  input_file.parse_command_line(argc, argv);
144 
145  // Read in parameters from the input file
146  const unsigned int max_r_steps = input_file("max_r_steps", 3);
147  const unsigned int max_r_level = input_file("max_r_level", 3);
148  const Real refine_percentage = input_file("refine_percentage", 0.5);
149  const Real coarsen_percentage = input_file("coarsen_percentage", 0.5);
150  const unsigned int uniform_refine = input_file("uniform_refine",0);
151  const std::string refine_type = input_file("refinement_type", "h");
152  const std::string approx_type = input_file("approx_type", "LAGRANGE");
153  const unsigned int approx_order = input_file("approx_order", 1);
154  n_vars = input_file("n_vars", n_vars);
155  const std::string element_type = input_file("element_type", "tensor");
156  const int extra_error_quadrature = input_file("extra_error_quadrature", 0);
157  const int max_linear_iterations = input_file("max_linear_iterations", 5000);
158 
159 #ifdef LIBMESH_HAVE_EXODUS_API
160  const bool output_intermediate = input_file("output_intermediate", false);
161 #endif
162 
163  // If libmesh is configured without second derivative support, we
164  // can't run this example with Hermite elements and will therefore
165  // fail gracefully.
166 #if !defined(LIBMESH_ENABLE_SECOND_DERIVATIVES)
167  libmesh_example_requires(approx_type != "HERMITE", "--enable-second");
168 #endif
169 
170  dim = input_file("dimension", 2);
171  const std::string indicator_type = input_file("indicator_type", "kelly");
172  singularity = input_file("singularity", true);
173  const bool extrusion = input_file("extrusion",false);
174  const bool complete = input_file("complete",false);
175  libmesh_error_msg_if(extrusion && dim < 3, "Extrusion option is only for 3D meshes");
176 
177  // Skip higher-dimensional examples on a lower-dimensional libMesh build
178  libmesh_example_requires(dim <= LIBMESH_DIM, "2D/3D support");
179 
180  // Output file for plotting the error as a function of
181  // the number of degrees of freedom.
182  std::string approx_name = "";
183  if (element_type == "tensor")
184  approx_name += "bi";
185  if (approx_order == 1)
186  approx_name += "linear";
187  else if (approx_order == 2)
188  approx_name += "quadratic";
189  else if (approx_order == 3)
190  approx_name += "cubic";
191  else if (approx_order == 4)
192  approx_name += "quartic";
193 
194  std::string output_file = approx_name;
195  output_file += "_";
196  output_file += refine_type;
197  if (uniform_refine == 0)
198  output_file += "_adaptive.m";
199  else
200  output_file += "_uniform.m";
201 
202  std::ofstream out (output_file.c_str());
203  out << "% dofs L2-error H1-error" << std::endl;
204  out << "e = [" << std::endl;
205 
206  // Create a mesh, with dimension to be overridden later, on the
207  // default MPI communicator.
208  Mesh mesh(init.comm());
209 
210  // Create an equation systems object.
211  EquationSystems equation_systems (mesh);
212 
213  // Declare the system we will solve, named Laplace
214  LinearImplicitSystem & system =
215  equation_systems.add_system<LinearImplicitSystem> ("Laplace");
216 
217  // If we're doing HP refinement, then we'll need to be able to
218  // evaluate data on elements' siblings in HPCoarsenTest, which means
219  // we should instruct our system's DofMap to distribute that data.
220  // Create and add (and keep around! the DofMap will only be holding
221  // a pointer to it!) a SiblingCoupling functor to provide that
222  // instruction.
223  SiblingCoupling sibling_coupling;
224  if (refine_type == "hp")
225  system.get_dof_map().add_algebraic_ghosting_functor(sibling_coupling);
226 
227  // Read in the mesh
228  if (dim == 1)
230  else if (dim == 2 || extrusion == true)
231  mesh.read("lshaped.xda");
232  else
233  mesh.read("lshaped3D.xda");
234 
235  // Use triangles if the config file says so
236  if (element_type == "simplex")
238 
239  if (extrusion)
240  {
241  Mesh flat_mesh = mesh;
242  mesh.clear();
243  MeshTools::Generation::build_extrusion(mesh, flat_mesh, 1, {0,0,1});
244  }
245 
246  // Use highest-order elements if the config file says so.
247  if (complete)
249  // Otherwise, we used first order elements to describe the geometry,
250  // but we may need second order elements to hold the degrees
251  // of freedom
252  else if (approx_order > 1 || refine_type != "h")
254 
255  // Mesh Refinement object
256  MeshRefinement mesh_refinement(mesh);
257  mesh_refinement.refine_fraction() = refine_percentage;
258  mesh_refinement.coarsen_fraction() = coarsen_percentage;
259  mesh_refinement.max_h_level() = max_r_level;
260 
261  // Adds the variable "u" to "Laplace", using
262  // the finite element type and order specified
263  // in the config file
264  unsigned int u_var =
265  system.add_variable("u", static_cast<Order>(approx_order),
266  Utility::string_to_enum<FEFamily>(approx_type));
267 
268  std::vector<unsigned int> all_vars(1, u_var);
269 
270  // For benchmarking purposes, add more variables if requested.
271  for (unsigned int var_num=1; var_num < n_vars; ++var_num)
272  {
273  std::ostringstream var_name;
274  var_name << "u" << var_num;
275  unsigned int next_var =
276  system.add_variable(var_name.str(),
277  static_cast<Order>(approx_order),
278  Utility::string_to_enum<FEFamily>(approx_type));
279  all_vars.push_back(next_var);
280  }
281 
282  // Give the system a pointer to the matrix assembly
283  // function.
285 
286  // Add Dirichlet boundary conditions
287  WrappedFunction<Number> exact_val(system, exact_solution);
289  DirichletBoundary exact_bc({0} , all_vars, exact_val, exact_grad);
290  system.get_dof_map().add_dirichlet_boundary(exact_bc);
291 
292  // Initialize the data structures for the equation system.
293  equation_systems.init();
294 
295  // Set linear solver max iterations
296  equation_systems.parameters.set<unsigned int>("linear solver maximum iterations")
297  = max_linear_iterations;
298 
299  // Linear solver tolerance.
300  equation_systems.parameters.set<Real>("linear solver tolerance") =
301  std::pow(TOLERANCE, 2.5);
302 
303  // Prints information about the system to the screen.
304  equation_systems.print_info();
305 
306  // Construct ExactSolution object and attach solution functions
307  ExactSolution exact_sol(equation_systems);
310 
311  // Use higher quadrature order for more accurate error results
312  exact_sol.extra_quadrature_order(extra_error_quadrature);
313 
314  // Compute the initial error
315  exact_sol.compute_error("Laplace", "u");
316 
317  // Print out the error values
318  libMesh::out << "Initial L2-Error is: "
319  << exact_sol.l2_error("Laplace", "u")
320  << std::endl;
321  libMesh::out << "Initial H1-Error is: "
322  << exact_sol.h1_error("Laplace", "u")
323  << std::endl;
324 
325  // A refinement loop.
326  for (unsigned int r_step=0; r_step<max_r_steps; r_step++)
327  {
328  libMesh::out << "Beginning Solve " << r_step << std::endl;
329 
330  // Solve the system "Laplace", just like example 2.
331  system.solve();
332 
333  libMesh::out << "System has: "
334  << equation_systems.n_active_dofs()
335  << " degrees of freedom."
336  << std::endl;
337 
338  libMesh::out << "Linear solver converged at step: "
339  << system.n_linear_iterations()
340  << ", final residual: "
341  << system.final_linear_residual()
342  << std::endl;
343 
344 #ifdef LIBMESH_HAVE_EXODUS_API
345  // After solving the system write the solution
346  // to a ExodusII-formatted plot file.
347  if (output_intermediate)
348  {
349  std::ostringstream outfile;
350  outfile << "lshaped_" << r_step << ".e";
351  ExodusII_IO (mesh).write_equation_systems (outfile.str(),
352  equation_systems);
353  }
354 #endif // #ifdef LIBMESH_HAVE_EXODUS_API
355 
356  // Compute the error.
357  exact_sol.compute_error("Laplace", "u");
358 
359  // The error should at least be sane, but it isn't if the solver
360  // failed badly enough
361  if (libmesh_isnan(exact_sol.l2_error("Laplace", "u")))
362  libmesh_error_msg("NaN solve result");
363 
364  // Print out the error values
365  libMesh::out << "L2-Error is: "
366  << exact_sol.l2_error("Laplace", "u")
367  << std::endl;
368  libMesh::out << "H1-Error is: "
369  << exact_sol.h1_error("Laplace", "u")
370  << std::endl;
371 
372  // Compute any discontinuity. There should be none.
373  {
375 
376  // This is a subclass of JumpErrorEstimator, based on
377  // measuring discontinuities across sides between
378  // elements, and we can tell it to use a cheaper
379  // "unweighted" quadrature rule when numerically
380  // integrating those discontinuities.
382 
383  ErrorVector disc_error;
384  disc.estimate_error(system, disc_error);
385 
386  Real mean_disc_error = disc_error.mean();
387 
388  libMesh::out << "Mean discontinuity error = " << mean_disc_error << std::endl;
389 
390  // FIXME - this test fails when solving with Eigen?
391 #ifdef LIBMESH_ENABLE_PETSC
392  libmesh_assert_less (mean_disc_error, 1e-14);
393 #endif
394  }
395 
396  // Print to output file
397  out << equation_systems.n_active_dofs() << " "
398  << exact_sol.l2_error("Laplace", "u") << " "
399  << exact_sol.h1_error("Laplace", "u") << std::endl;
400 
401  // Possibly refine the mesh
402  if (r_step+1 != max_r_steps)
403  {
404  libMesh::out << " Refining the mesh..." << std::endl;
405 
406  if (uniform_refine == 0)
407  {
408 
409  // The ErrorVector is a particular StatisticsVector
410  // for computing error information on a finite element mesh.
411  ErrorVector error;
412 
413  if (indicator_type == "exact")
414  {
415  // The ErrorEstimator class interrogates a
416  // finite element solution and assigns to each
417  // element a positive error value.
418  // This value is used for deciding which elements to
419  // refine and which to coarsen.
420  // For these simple test problems, we can use
421  // numerical quadrature of the exact error between
422  // the approximate and analytic solutions.
423  // However, for real problems, we would need an error
424  // indicator which only relies on the approximate
425  // solution.
426  ExactErrorEstimator error_estimator;
427 
428  error_estimator.attach_exact_value(exact_solution);
429  error_estimator.attach_exact_deriv(exact_derivative);
430 
431  // We optimize in H1 norm, the default
432  // error_estimator.error_norm = H1;
433 
434  // Compute the error for each active element using
435  // the provided indicator. Note in general you
436  // will need to provide an error estimator
437  // specifically designed for your application.
438  error_estimator.estimate_error (system, error);
439  }
440  else if (indicator_type == "patch")
441  {
442  // The patch recovery estimator should give a
443  // good estimate of the solution interpolation
444  // error.
445  PatchRecoveryErrorEstimator error_estimator;
446 
447  error_estimator.estimate_error (system, error);
448  }
449  else if (indicator_type == "uniform")
450  {
451  // Error indication based on uniform refinement
452  // is reliable, but very expensive.
453  UniformRefinementEstimator error_estimator;
454 
455  error_estimator.estimate_error (system, error);
456  }
457  else
458  {
459  libmesh_assert_equal_to (indicator_type, "kelly");
460 
461  // The Kelly error estimator is based on
462  // an error bound for the Poisson problem
463  // on linear elements, but is useful for
464  // driving adaptive refinement in many problems
465  KellyErrorEstimator error_estimator;
466 
467  // This is a subclass of JumpErrorEstimator, based on
468  // measuring gradient discontinuities across sides
469  // between elements, and we can tell it to use a
470  // cheaper "unweighted" quadrature rule when
471  // numerically integrating those discontinuities.
472  error_estimator.use_unweighted_quadrature_rules = true;
473 
474  error_estimator.estimate_error (system, error);
475  }
476 
477  // Write out the error distribution
478  std::ostringstream ss;
479  ss << r_step;
480 #ifdef LIBMESH_HAVE_EXODUS_API
481 # ifdef LIBMESH_HAVE_NEMESIS_API
482  std::string error_output = "error_" + ss.str() + ".n";
483 # else
484  std::string error_output = "error_" + ss.str() + ".e";
485 # endif
486 #else
487  std::string error_output = "error_" + ss.str() + ".gmv";
488 #endif
489  error.plot_error(error_output, mesh);
490 
491  // This takes the error in error and decides which elements
492  // will be coarsened or refined. Any element within 20% of the
493  // maximum error on any element will be refined, and any
494  // element within 10% of the minimum error on any element might
495  // be coarsened. Note that the elements flagged for refinement
496  // will be refined, but those flagged for coarsening _might_ be
497  // coarsened.
498  mesh_refinement.flag_elements_by_error_fraction (error);
499 
500  // If we are doing adaptive p refinement, we want
501  // elements flagged for that instead.
502  if (refine_type == "p")
503  mesh_refinement.switch_h_to_p_refinement();
504  // If we are doing "matched hp" refinement, we
505  // flag elements for both h and p
506  else if (refine_type == "matchedhp")
507  mesh_refinement.add_p_to_h_refinement();
508  // If we are doing hp refinement, we
509  // try switching some elements from h to p
510  else if (refine_type == "hp")
511  {
512  HPCoarsenTest hpselector;
513  hpselector.select_refinement(system);
514  }
515  // If we are doing "singular hp" refinement, we
516  // try switching most elements from h to p
517  else if (refine_type == "singularhp")
518  {
519  // This only differs from p refinement for
520  // the singular problem
522  HPSingularity hpselector;
523  // Our only singular point is at the origin
524  hpselector.singular_points.push_back(Point());
525  hpselector.select_refinement(system);
526  }
527  else
528  libmesh_error_msg_if(refine_type != "h",
529  "Unknown refinement_type = " << refine_type);
530 
531  // This call actually refines and coarsens the flagged
532  // elements.
533  mesh_refinement.refine_and_coarsen_elements();
534  }
535 
536  else if (uniform_refine == 1)
537  {
538  if (refine_type == "h" || refine_type == "hp" ||
539  refine_type == "matchedhp")
540  mesh_refinement.uniformly_refine(1);
541  if (refine_type == "p" || refine_type == "hp" ||
542  refine_type == "matchedhp")
543  mesh_refinement.uniformly_p_refine(1);
544  }
545 
546  // This call reinitializes the EquationSystems object for
547  // the newly refined mesh. One of the steps in the
548  // reinitialization is projecting the solution,
549  // old_solution, etc... vectors from the old mesh to
550  // the current one.
551  equation_systems.reinit ();
552  }
553  }
554 
555 #ifdef LIBMESH_HAVE_EXODUS_API
556  // Write out the solution
557  // After solving the system write the solution
558  // to a ExodusII-formatted plot file.
559  ExodusII_IO (mesh).write_equation_systems ("lshaped.e",
560  equation_systems);
561 #endif // #ifdef LIBMESH_HAVE_EXODUS_API
562 
563  // Close up the output file.
564  out << "];" << std::endl;
565  out << "hold on" << std::endl;
566  out << "plot(e(:,1), e(:,2), 'bo-');" << std::endl;
567  out << "plot(e(:,1), e(:,3), 'ro-');" << std::endl;
568  // out << "set(gca,'XScale', 'Log');" << std::endl;
569  // out << "set(gca,'YScale', 'Log');" << std::endl;
570  out << "xlabel('dofs');" << std::endl;
571  out << "title('" << approx_name << " elements');" << std::endl;
572  out << "legend('L2-error', 'H1-error');" << std::endl;
573  // out << "disp('L2-error linear fit');" << std::endl;
574  // out << "polyfit(log10(e(:,1)), log10(e(:,2)), 1)" << std::endl;
575  // out << "disp('H1-error linear fit');" << std::endl;
576  // out << "polyfit(log10(e(:,1)), log10(e(:,3)), 1)" << std::endl;
577 #endif // #ifndef LIBMESH_ENABLE_AMR
578 
579  // All done.
580  return 0;
581 }
582 
583 
584 
585 
586 // We now define the exact solution, being careful
587 // to obtain an angle from atan2 in the correct
588 // quadrant.
590  const Parameters &, // parameters, not needed
591  const std::string &, // sys_name, not needed
592  const std::string &) // unk_name, not needed
593 {
594  const Real x = p(0);
595  const Real y = (dim > 1) ? p(1) : 0.;
596 
597  if (singularity)
598  {
599  // The exact solution to the singular problem,
600  // u_exact = r^(2/3)*sin(2*theta/3).
601  Real theta = atan2(y, x);
602 
603  // Make sure 0 <= theta <= 2*pi
604  if (theta < 0)
605  theta += 2. * libMesh::pi;
606 
607  // Make the 3D solution similar
608  const Real z = (dim > 2) ? p(2) : 0;
609 
610  return pow(x*x + y*y, 1./3.)*sin(2./3.*theta) + z;
611  }
612  else
613  {
614  // The exact solution to a nonsingular problem,
615  // good for testing ideal convergence rates
616  const Real z = (dim > 2) ? p(2) : 0;
617 
618  return cos(x) * exp(y) * (1. - z);
619  }
620 }
621 
622 
623 
624 
625 
626 // We now define the gradient of the exact solution, again being careful
627 // to obtain an angle from atan2 in the correct
628 // quadrant.
630  const Parameters &, // parameters, not needed
631  const std::string &, // sys_name, not needed
632  const std::string &) // unk_name, not needed
633 {
634  // Gradient value to be returned.
635  Gradient gradu;
636 
637  // x and y coordinates in space
638  const Real x = p(0);
639  const Real y = dim > 1 ? p(1) : 0.;
640 
641  if (singularity)
642  {
643  // We can't compute the gradient at x=0, it is not defined.
644  libmesh_assert_not_equal_to (x, 0.);
645 
646  // For convenience...
647  const Real tt = 2./3.;
648  const Real ot = 1./3.;
649 
650  // The value of the radius, squared
651  const Real r2 = x*x + y*y;
652 
653  // The boundary value, given by the exact solution,
654  // u_exact = r^(2/3)*sin(2*theta/3).
655  Real theta = atan2(y, x);
656 
657  // Make sure 0 <= theta <= 2*pi
658  if (theta < 0)
659  theta += 2. * libMesh::pi;
660 
661  // du/dx
662  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;
663 
664  // du/dy
665  if (dim > 1)
666  gradu(1) = tt*y*pow(r2,-tt)*sin(tt*theta) + pow(r2,ot)*cos(tt*theta)*tt/(1.+y*y/x/x)*1./x;
667 
668  if (dim > 2)
669  gradu(2) = 1.;
670  }
671  else
672  {
673  const Real z = (dim > 2) ? p(2) : 0;
674 
675  gradu(0) = -sin(x) * exp(y) * (1. - z);
676  if (dim > 1)
677  gradu(1) = cos(x) * exp(y) * (1. - z);
678  if (dim > 2)
679  gradu(2) = -cos(x) * exp(y);
680  }
681 
682  return gradu;
683 }
684 
685 
686 
687 
688 
689 
690 // We now define the matrix assembly function for the
691 // Laplace system. We need to first compute element
692 // matrices and right-hand sides, and then take into
693 // account the boundary conditions, which will be handled
694 // via a penalty method.
696  const std::string & system_name)
697 {
698  // Ignore unused parameter warnings when !LIBMESH_ENABLE_AMR.
699  libmesh_ignore(es, system_name);
700 
701 #ifdef LIBMESH_ENABLE_AMR
702  // It is a good idea to make sure we are assembling
703  // the proper system.
704  libmesh_assert_equal_to (system_name, "Laplace");
705 
706  // Declare a performance log. Give it a descriptive
707  // string to identify what part of the code we are
708  // logging, since there may be many PerfLogs in an
709  // application.
710  PerfLog perf_log ("Matrix Assembly", false);
711 
712  // Get a constant reference to the mesh object.
713  const MeshBase & mesh = es.get_mesh();
714 
715  // The dimension that we are running
716  const unsigned int mesh_dim = mesh.mesh_dimension();
717 
718  // Get a reference to the LinearImplicitSystem we are solving
719  LinearImplicitSystem & system = es.get_system<LinearImplicitSystem>("Laplace");
720 
721  // A reference to the DofMap object for this system. The DofMap
722  // object handles the index translation from node and element numbers
723  // to degree of freedom numbers. We will talk more about the DofMap
724  // in future examples.
725  const DofMap & dof_map = system.get_dof_map();
726 
727  // Get a constant reference to the Finite Element type
728  // for the first (and only) variable type in the system.
729  FEType fe_type = dof_map.variable_type(0);
730 
731  // Build a Finite Element object of the specified type. Since the
732  // FEBase::build() member dynamically creates memory we will
733  // store the object as a std::unique_ptr<FEBase>. This can be thought
734  // of as a pointer that will clean up after itself.
735  std::unique_ptr<FEBase> fe (FEBase::build(mesh_dim, fe_type));
736  std::unique_ptr<FEBase> fe_face (FEBase::build(mesh_dim, fe_type));
737 
738  // Quadrature rules for numerical integration.
739  std::unique_ptr<QBase> qrule(fe_type.default_quadrature_rule(mesh_dim));
740  std::unique_ptr<QBase> qface(fe_type.default_quadrature_rule(mesh_dim-1));
741 
742  // Tell the finite element object to use our quadrature rule.
743  fe->attach_quadrature_rule (qrule.get());
744  fe_face->attach_quadrature_rule (qface.get());
745 
746  // Here we define some references to cell-specific data that
747  // will be used to assemble the linear system.
748  // We begin with the element Jacobian * quadrature weight at each
749  // integration point.
750  const std::vector<Real> & JxW = fe->get_JxW();
751 
752  // The physical XY locations of the quadrature points on the element.
753  // These might be useful for evaluating spatially varying material
754  // properties or forcing functions at the quadrature points.
755  const std::vector<Point> & q_point = fe->get_xyz();
756 
757  // The element shape functions evaluated at the quadrature points.
758  const std::vector<std::vector<Real>> & phi = fe->get_phi();
759 
760  // The element shape function gradients evaluated at the quadrature
761  // points.
762  const std::vector<std::vector<RealGradient>> & dphi = fe->get_dphi();
763 
764  // Define data structures to contain the element matrix
765  // and right-hand-side vector contribution. Following
766  // basic finite element terminology we will denote these
767  // "Ke" and "Fe". More detail is in example 3.
770 
771  // This vector will hold the degree of freedom indices for
772  // the element. These define where in the global system
773  // the element degrees of freedom get mapped.
774  std::vector<dof_id_type> dof_indices;
775 
776  // The global system matrix
777  SparseMatrix<Number> & matrix = system.get_system_matrix();
778 
779  // Now we will loop over all the elements in the mesh. We will
780  // compute the element matrix and right-hand-side contribution. See
781  // example 3 for a discussion of the element iterators. Here we use
782  // the const_active_local_elem_iterator to indicate we only want
783  // to loop over elements that are assigned to the local processor
784  // which are "active" in the sense of AMR. This allows each
785  // processor to compute its components of the global matrix for
786  // active elements while ignoring parent elements which have been
787  // refined.
788  for (const auto & elem : mesh.active_local_element_ptr_range())
789  {
790  // Start logging the shape function initialization.
791  // This is done through a simple function call with
792  // the name of the event to log.
793  perf_log.push("elem init");
794 
795  // Get the degree of freedom indices for the
796  // current element. These define where in the global
797  // matrix and right-hand-side this element will
798  // contribute to.
799  dof_map.dof_indices (elem, dof_indices);
800 
801  // Compute the element-specific data for the current
802  // element. This involves computing the location of the
803  // quadrature points (q_point) and the shape functions
804  // (phi, dphi) for the current element.
805  fe->reinit (elem);
806 
807  const unsigned int n_dofs =
808  cast_int<unsigned int>(dof_indices.size());
809 
810  // Zero the element matrix and right-hand side before
811  // summing them. We use the resize member here because
812  // the number of degrees of freedom might have changed from
813  // the last element. Note that this will be the case if the
814  // element type is different (i.e. the last element was a
815  // triangle, now we are on a quadrilateral).
816  Ke.resize (n_dofs, n_dofs);
817 
818  Fe.resize (n_dofs);
819 
820  // Stop logging the shape function initialization.
821  // If you forget to stop logging an event the PerfLog
822  // object will probably catch the error and abort.
823  perf_log.pop("elem init");
824 
825  // Now we will build the element matrix. This involves
826  // a quadruple loop to integrate the test functions (i) against
827  // the trial functions (j) for each variable (v) at each
828  // quadrature point (qp).
829  //
830  // Now start logging the element matrix computation
831  perf_log.push ("Ke");
832 
833  std::vector<dof_id_type> dof_indices_u;
834  dof_map.dof_indices (elem, dof_indices_u, 0);
835  const unsigned int n_u_dofs = dof_indices_u.size();
836  libmesh_assert_equal_to (n_u_dofs, phi.size());
837  libmesh_assert_equal_to (n_u_dofs, dphi.size());
838 
839  for (unsigned int v=0; v != n_vars; ++v)
840  {
841  DenseSubMatrix<Number> Kuu(Ke);
842  Kuu.reposition (v*n_u_dofs, v*n_u_dofs, n_u_dofs, n_u_dofs);
843 
844  for (unsigned int qp=0; qp<qrule->n_points(); qp++)
845  for (unsigned int i=0; i != n_u_dofs; i++)
846  for (unsigned int j=0; j != n_u_dofs; j++)
847  Kuu(i,j) += JxW[qp]*(dphi[i][qp]*dphi[j][qp]);
848 
849  // We need a forcing function to make the 1D case interesting
850  if (mesh_dim == 1)
851  {
852  DenseSubVector<Number> Fu(Fe);
853  Fu.reposition (v*n_u_dofs, n_u_dofs);
854 
855  for (unsigned int qp=0; qp<qrule->n_points(); qp++)
856  {
857  Real x = q_point[qp](0);
858  Real f = singularity ? sqrt(3.)/9.*pow(-x, -4./3.) :
859  cos(x);
860  for (unsigned int i=0; i != n_u_dofs; ++i)
861  Fu(i) += JxW[qp]*phi[i][qp]*f;
862  }
863  }
864  }
865 
866  // Stop logging the matrix computation
867  perf_log.pop ("Ke");
868 
869  // The element matrix and right-hand-side are now built
870  // for this element. Add them to the global matrix and
871  // right-hand-side vector. The SparseMatrix::add_matrix()
872  // and NumericVector::add_vector() members do this for us.
873  // Start logging the insertion of the local (element)
874  // matrix and vector into the global matrix and vector
875  LOG_SCOPE_WITH("matrix insertion", "", perf_log);
876 
877  // Use heterogenously here to handle Dirichlet as well as AMR
878  // constraints.
879  dof_map.heterogenously_constrain_element_matrix_and_vector(Ke, Fe, dof_indices);
880  matrix.add_matrix (Ke, dof_indices);
881  system.rhs->add_vector (Fe, dof_indices);
882  }
883 
884  // That's it. We don't need to do anything else to the
885  // PerfLog. When it goes out of scope (at this function return)
886  // it will print its log to the screen. Pretty easy, huh?
887 #endif // #ifdef LIBMESH_ENABLE_AMR
888 }
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...
Wrap a libMesh-style function pointer into a FunctionBase object.
void uniformly_p_refine(unsigned int n=1)
Uniformly p refines the mesh n times.
void build_extrusion(UnstructuredMesh &mesh, const MeshBase &cross_section, const unsigned int nz, RealVectorValue extrusion_vector, QueryElemSubdomainIDBase *elem_subdomain=nullptr)
Meshes the tensor product of a 1D and a 1D-or-2D domain.
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.
void assemble_laplace(EquationSystems &es, const std::string &system_name)
void pop(const char *label, const char *header="")
Pop the event label off the stack, resuming any lower event.
Definition: perf_log.C:168
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
virtual void select_refinement(System &system) override
This pure virtual function must be redefined in derived classes to take a mesh flagged for h refineme...
static constexpr Real TOLERANCE
unsigned int dim
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]...
Real & coarsen_fraction()
The coarsen_fraction sets either a desired target or a desired maximum number of elements to flag for...
MeshBase & mesh
void extra_quadrature_order(const int extraorder)
Increases or decreases the order of the quadrature rule used for numerical integration.
NumericVector< Number > * rhs
The system matrix.
This class allows one to associate Dirichlet boundary values with a given set of mesh boundary ids an...
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.
virtual void solve() override
Assembles & solves the linear system A*x=b.
const T_sys & get_system(std::string_view name) const
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...
bool libmesh_isnan(T x)
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
Gradient exact_grad(const Point &, const Parameters &, const std::string &, const std::string &)
Definition: mysystems.h:25
Defines a dense subvector for use in finite element computations.
std::list< Point > singular_points
This list, to be filled by the user, should include all singular points in the solution.
Definition: hp_singular.h:83
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 exact solution function to estimate the error on each cell.
SolverPackage default_solver_package()
Definition: libmesh.C:1111
The PerfLog class allows monitoring of specific events.
Definition: perf_log.h:145
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:178
void switch_h_to_p_refinement()
Takes a mesh whose elements are flagged for h refinement and coarsening, and switches those flags to ...
std::unique_ptr< QBase > default_quadrature_rule(const unsigned int dim, const int extraorder=0) const
Definition: fe_type.C:34
void reposition(const unsigned int ioff, const unsigned int n)
Changes the location of the subvector in the parent vector.
void all_tri(MeshBase &mesh)
Subdivides any non-simplex elements in a Mesh to produce simplex (triangular in 2D, tetrahedral in 3D) elements.
void libmesh_ignore(const Args &...)
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
Implements (adaptive) mesh refinement algorithms for a MeshBase.
int main(int argc, char **argv)
unsigned int n_vars
unsigned int n_linear_iterations() const
virtual void write_equation_systems(const std::string &fname, const EquationSystems &es, const std::set< std::string > *system_names=nullptr) override
Writes out the solution for no specific time or timestep.
Definition: exodusII_io.C:2013
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(...
Defines a dense submatrix for use in Finite Element-type computations.
This class implements a `‘brute force’&#39; error estimator which integrates differences between the cu...
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.
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 Patch Recovery error estimate to estimate the error on each cell...
libmesh_assert(ctx)
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:1335
void push(const char *label, const char *header="")
Push the event label onto the stack, pausing any active event.
Definition: perf_log.C:138
Number exact_solution(const Point &p, const Parameters &, const std::string &, const std::string &)
void attach_assemble_function(void fptr(EquationSystems &es, const std::string &name))
Register a user function to use in assembling the system matrix and RHS.
Definition: system.C:2139
Real l2_error(std::string_view sys_name, std::string_view unknown_name)
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 does uniform refinements and a solve to get an improved solution on each cell...
void plot_error(const std::string &filename, const MeshBase &mesh) const
Plots a data file, of a type determined by looking at the file extension in filename, of the error values on the active elements of mesh.
Definition: error_vector.C:210
virtual void clear()
Deletes all the element and node data that is currently stored.
Definition: mesh_base.C:902
virtual void select_refinement(System &system)
This pure virtual function must be redefined in derived classes to take a mesh flagged for h refineme...
Definition: hp_singular.C:36
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...
Gradient exact_derivative(const Point &p, const Parameters &, const std::string &, const std::string &)
This class implements the Kelly error indicator which is based on the flux jumps between elements...
This class uses the error estimate given by different types of derefinement (h coarsening or p reduct...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
This class adds coupling (for use in send_list construction) between active elements and all descenda...
This class implements an "error estimator" based on the difference between the approximate and exact ...
virtual void all_complete_order()
Calls the range-based version of this function with a range consisting of all elements in the mesh...
Definition: mesh_base.C:1595
This class implements the Patch Recovery error indicator.
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
bool use_unweighted_quadrature_rules
This boolean flag allows you to use "unweighted" quadrature rules (sized to exactly integrate unweigh...
void all_second_order(const bool full_ordered=true)
Calls the range-based version of this function with a range consisting of all elements in the mesh...
Definition: mesh_base.C:1590
unsigned int mesh_dimension() const
Definition: mesh_base.C:354
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 add_dirichlet_boundary(const DirichletBoundary &dirichlet_boundary)
Adds a copy of the specified Dirichlet boundary to the system.
void reposition(const unsigned int ioff, const unsigned int joff, const unsigned int new_m, const unsigned int new_n)
Changes the location of the submatrix in the parent matrix.
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...
This class uses a user-provided list of singularity locations to choose between h refining and p elev...
Definition: hp_singular.h:49
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...
void add_algebraic_ghosting_functor(GhostingFunctor &evaluable_functor, bool to_mesh=true)
Adds a functor which can specify algebraic ghosting requirements for use with distributed vectors...
Definition: dof_map.C:2078
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50
Real h1_error(std::string_view sys_name, std::string_view unknown_name)
const DofMap & get_dof_map() const
Definition: system.h:2370
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
const SparseMatrix< Number > & get_system_matrix() const
virtual Real mean() const override
Definition: error_vector.C:69
const Real pi
.
Definition: libmesh.h:281
void uniformly_refine(unsigned int n=1)
Uniformly refines the mesh n times.