libMesh
adaptivity_ex4.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 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 // <h1>Adaptivity Example 4 - Biharmonic Equation</h1>
19 // \author Benjamin S. Kirk
20 // \date 2004
21 //
22 // This example solves the Biharmonic equation on a square or cube,
23 // using a Galerkin formulation with C1 elements approximating the
24 // H^2_0 function space.
25 // The initial mesh contains two TRI6, one QUAD9 or one HEX27
26 // An input file named "ex15.in"
27 // is provided which allows the user to set several parameters for
28 // the solution so that the problem can be re-run without a
29 // re-compile. The solution technique employed is to have a
30 // refinement loop with a linear solve inside followed by a
31 // refinement of the grid and projection of the solution to the new grid
32 // In the final loop iteration, there is no additional
33 // refinement after the solve. In the input file "ex15.in", the variable
34 // "max_r_steps" controls the number of refinement steps, and
35 // "max_r_level" controls the maximum element refinement level.
36 
37 // LibMesh include files.
38 #include "libmesh/mesh.h"
39 #include "libmesh/equation_systems.h"
40 #include "libmesh/linear_implicit_system.h"
41 #include "libmesh/exodusII_io.h"
42 #include "libmesh/fe.h"
43 #include "libmesh/quadrature.h"
44 #include "libmesh/dense_matrix.h"
45 #include "libmesh/dense_vector.h"
46 #include "libmesh/sparse_matrix.h"
47 #include "libmesh/mesh_generation.h"
48 #include "libmesh/mesh_modification.h"
49 #include "libmesh/mesh_refinement.h"
50 #include "libmesh/error_vector.h"
51 #include "libmesh/fourth_error_estimators.h"
52 #include "libmesh/getpot.h"
53 #include "libmesh/exact_solution.h"
54 #include "libmesh/dof_map.h"
55 #include "libmesh/numeric_vector.h"
56 #include "libmesh/elem.h"
57 #include "libmesh/tensor_value.h"
58 #include "libmesh/perf_log.h"
59 #include "libmesh/string_to_enum.h"
60 #include "libmesh/enum_solver_package.h"
61 
62 // Bring in everything from the libMesh namespace
63 using namespace libMesh;
64 
65 // Function prototype. This is the function that will assemble
66 // the linear system for our Biharmonic problem. Note that the
67 // function will take the EquationSystems object and the
68 // name of the system we are assembling as input. From the
69 // EquationSystems object we have access to the Mesh and
70 // other objects we might need.
72  const std::string & system_name);
73 
74 
75 // Prototypes for calculation of the exact solution. Necessary
76 // for setting boundary conditions.
78  const Parameters &,
79  const std::string &,
80  const std::string &);
81 
83  const Parameters &, // parameters, not needed
84  const std::string &, // sys_name, not needed
85  const std::string &); // unk_name, not needed);
86 
88  const Parameters &,
89  const std::string &,
90  const std::string &);
91 
92 // Prototypes for calculation of the gradient of the exact solution.
93 // Necessary for setting boundary conditions in H^2_0 and testing
94 // H^1 convergence of the solution
96  const Parameters &,
97  const std::string &,
98  const std::string &);
99 
101  const Parameters &,
102  const std::string &,
103  const std::string &);
104 
106  const Parameters &,
107  const std::string &,
108  const std::string &);
109 
110 Tensor exact_1D_hessian(const Point & p,
111  const Parameters &,
112  const std::string &,
113  const std::string &);
114 
115 Tensor exact_2D_hessian(const Point & p,
116  const Parameters &,
117  const std::string &,
118  const std::string &);
119 
120 Tensor exact_3D_hessian(const Point & p,
121  const Parameters &,
122  const std::string &,
123  const std::string &);
124 
125 Number forcing_function_1D(const Point & p);
126 
127 Number forcing_function_2D(const Point & p);
128 
129 Number forcing_function_3D(const Point & p);
130 
131 // Pointers to dimension-independent functions
133  const Parameters &,
134  const std::string &,
135  const std::string &);
136 
138  const Parameters &,
139  const std::string &,
140  const std::string &);
141 
143  const Parameters &,
144  const std::string &,
145  const std::string &);
146 
148 
149 
150 
151 int main(int argc, char ** argv)
152 {
153  // Initialize libMesh.
154  LibMeshInit init (argc, argv);
155 
156  // This example requires a linear solver package.
157  libmesh_example_requires(libMesh::default_solver_package() != INVALID_SOLVER_PACKAGE,
158  "--enable-petsc, --enable-trilinos, or --enable-eigen");
159 
160  // Adaptive constraint calculations for fine Hermite elements seems
161  // to require half-decent precision
162 #ifdef LIBMESH_DEFAULT_SINGLE_PRECISION
163  libmesh_example_requires(false, "double precision");
164 #endif
165 
166  // This example requires Adaptive Mesh Refinement support
167 #ifndef LIBMESH_ENABLE_AMR
168  libmesh_example_requires(false, "--enable-amr");
169 #else
170 
171  // This example requires second derivative calculation support
172 #ifndef LIBMESH_ENABLE_SECOND_DERIVATIVES
173  libmesh_example_requires(false, "--enable-second");
174 #else
175 
176  // Parse the input file
177  GetPot input_file("adaptivity_ex4.in");
178 
179  // But allow the command line to override it.
180  input_file.parse_command_line(argc, argv);
181 
182  // Read in parameters from the input file
183  const unsigned int max_r_level = input_file("max_r_level", 10);
184  const unsigned int max_r_steps = input_file("max_r_steps", 4);
185  const std::string approx_type = input_file("approx_type", "HERMITE");
186  const std::string approx_order_string = input_file("approx_order", "THIRD");
187  const unsigned int uniform_refine = input_file("uniform_refine", 0);
188  const Real refine_percentage = input_file("refine_percentage", 0.5);
189  const Real coarsen_percentage = input_file("coarsen_percentage", 0.5);
190  const unsigned int dim = input_file("dimension", 2);
191  const unsigned int max_linear_iterations = input_file("max_linear_iterations", 10000);
192 
193  // Skip higher-dimensional examples on a lower-dimensional libMesh build
194  libmesh_example_requires(dim <= LIBMESH_DIM, "2D/3D support");
195 
196  // Currently only the Hermite cubics give a 1D or 3D C^1 basis
197  libmesh_assert (dim == 2 || approx_type == "HERMITE");
198 
199  // Create a mesh, with dimension to be overridden later, on the
200  // default MPI communicator.
201  Mesh mesh(init.comm());
202 
203  // Output file for plotting the error
204  std::string output_file = "";
205 
206  if (dim == 1)
207  output_file += "1D_";
208  else if (dim == 2)
209  output_file += "2D_";
210  else if (dim == 3)
211  output_file += "3D_";
212 
213  if (approx_type == "HERMITE")
214  output_file += "hermite_";
215  else if (approx_type == "SECOND")
216  output_file += "reducedclough_";
217  else
218  output_file += "clough_";
219 
220  if (uniform_refine == 0)
221  output_file += "adaptive";
222  else
223  output_file += "uniform";
224 
225 #ifdef LIBMESH_HAVE_EXODUS_API
226  // If we have Exodus, use the same base output filename
227  std::string exd_file = output_file;
228  exd_file += ".e";
229 #endif // #ifdef LIBMESH_HAVE_EXODUS_API
230 
231  output_file += ".m";
232 
233  std::ofstream out (output_file.c_str());
234  out << "% dofs L2-error H1-error H2-error\n"
235  << "e = [\n";
236 
237  // Set up the dimension-dependent coarse mesh and solution
238  if (dim == 1)
239  {
245  }
246 
247  if (dim == 2)
248  {
254  }
255  else if (dim == 3)
256  {
262  }
263 
264  // Convert the mesh to second order: necessary for computing with
265  // Clough-Tocher elements, useful for getting slightly less
266  // broken visualization output with Hermite elements
268 
269  // Convert it to triangles if necessary
270  if (approx_type != "HERMITE")
272 
273  // Mesh Refinement object
274  MeshRefinement mesh_refinement(mesh);
275  mesh_refinement.refine_fraction() = refine_percentage;
276  mesh_refinement.coarsen_fraction() = coarsen_percentage;
277  mesh_refinement.max_h_level() = max_r_level;
278 
279  // Create an equation systems object.
280  EquationSystems equation_systems (mesh);
281 
282  // Declare the system and its variables.
283  // Create a system named "Biharmonic"
284  LinearImplicitSystem & system =
285  equation_systems.add_system<LinearImplicitSystem> ("Biharmonic");
286 
287  Order approx_order = approx_type == "SECOND" ? SECOND :
288  Utility::string_to_enum<Order>(approx_order_string);
289 
290  // Adds the variable "u" to "Biharmonic". "u" will be approximated
291  // using Hermite tensor product squares or Clough-Tocher triangles
292 
293  if (approx_type == "HERMITE")
294  system.add_variable("u", approx_order, HERMITE);
295  else if (approx_type == "SECOND")
296  system.add_variable("u", SECOND, CLOUGH);
297  else if (approx_type == "CLOUGH")
298  system.add_variable("u", approx_order, CLOUGH);
299  else
300  libmesh_error_msg("Invalid approx_type = " << approx_type);
301 
302  // Give the system a pointer to the matrix assembly
303  // function.
305 
306  // Initialize the data structures for the equation system.
307  equation_systems.init();
308 
309  // Set linear solver max iterations
310  equation_systems.parameters.set<unsigned int>
311  ("linear solver maximum iterations") = max_linear_iterations;
312 
313  // Linear solver tolerance.
314  equation_systems.parameters.set<Real>
315  ("linear solver tolerance") = TOLERANCE * TOLERANCE;
316 
317  // Prints information about the system to the screen.
318  equation_systems.print_info();
319 
320  // Construct ExactSolution object and attach function to compute exact solution
321  ExactSolution exact_sol(equation_systems);
325 
326  // Construct zero solution object, useful for computing solution norms
327  // Attaching "zero_solution" functions is unnecessary
328  ExactSolution zero_sol(equation_systems);
329 
330  // A refinement loop.
331  for (unsigned int r_step=0; r_step<max_r_steps; r_step++)
332  {
333  mesh.print_info();
334  equation_systems.print_info();
335 
336  libMesh::out << "Beginning Solve " << r_step << std::endl;
337 
338  // Solve the system "Biharmonic", just like example 2.
339  system.solve();
340 
341  libMesh::out << "Linear solver converged at step: "
342  << system.n_linear_iterations()
343  << ", final residual: "
344  << system.final_linear_residual()
345  << std::endl;
346 
347  // Compute the error.
348  exact_sol.compute_error("Biharmonic", "u");
349  // Compute the norm.
350  zero_sol.compute_error("Biharmonic", "u");
351 
352  // Print out the error values
353  libMesh::out << "L2-Norm is: "
354  << zero_sol.l2_error("Biharmonic", "u")
355  << std::endl;
356  libMesh::out << "H1-Norm is: "
357  << zero_sol.h1_error("Biharmonic", "u")
358  << std::endl;
359  libMesh::out << "H2-Norm is: "
360  << zero_sol.h2_error("Biharmonic", "u")
361  << std::endl
362  << std::endl;
363  libMesh::out << "L2-Error is: "
364  << exact_sol.l2_error("Biharmonic", "u")
365  << std::endl;
366  libMesh::out << "H1-Error is: "
367  << exact_sol.h1_error("Biharmonic", "u")
368  << std::endl;
369  libMesh::out << "H2-Error is: "
370  << exact_sol.h2_error("Biharmonic", "u")
371  << std::endl
372  << std::endl;
373 
374  // Print to output file
375  out << equation_systems.n_active_dofs() << " "
376  << exact_sol.l2_error("Biharmonic", "u") << " "
377  << exact_sol.h1_error("Biharmonic", "u") << " "
378  << exact_sol.h2_error("Biharmonic", "u") << std::endl;
379 
380  // Possibly refine the mesh
381  if (r_step+1 != max_r_steps)
382  {
383  libMesh::out << " Refining the mesh..." << std::endl;
384 
385  if (uniform_refine == 0)
386  {
387  ErrorVector error;
388  LaplacianErrorEstimator error_estimator;
389 
390  // This is another subclass of JumpErrorEstimator, based
391  // on measuring discontinuities across sides between
392  // elements, and we can tell it to use a cheaper
393  // "unweighted" quadrature rule when numerically
394  // integrating those discontinuities.
395  error_estimator.use_unweighted_quadrature_rules = true;
396 
397  error_estimator.estimate_error(system, error);
398  mesh_refinement.flag_elements_by_elem_fraction (error);
399 
400  libMesh::out << "Mean Error: " << error.mean() << std::endl;
401  libMesh::out << "Error Variance: " << error.variance() << std::endl;
402 
403  mesh_refinement.refine_and_coarsen_elements();
404  }
405  else
406  {
407  mesh_refinement.uniformly_refine(1);
408  }
409 
410  // This call reinitializes the EquationSystems object for
411  // the newly refined mesh. One of the steps in the
412  // reinitialization is projecting the solution,
413  // old_solution, etc... vectors from the old mesh to
414  // the current one.
415  equation_systems.reinit ();
416  }
417  }
418 
419 #ifdef LIBMESH_HAVE_EXODUS_API
420  // After solving the system write the solution
421  // to a ExodusII-formatted plot file.
423  equation_systems);
424 #endif // #ifdef LIBMESH_HAVE_EXODUS_API
425 
426  // Close up the output file.
427  out << "];\n"
428  << "hold on\n"
429  << "loglog(e(:,1), e(:,2), 'bo-');\n"
430  << "loglog(e(:,1), e(:,3), 'ro-');\n"
431  << "loglog(e(:,1), e(:,4), 'go-');\n"
432  << "xlabel('log(dofs)');\n"
433  << "ylabel('log(error)');\n"
434  << "title('C1 " << approx_type << " elements');\n"
435  << "legend('L2-error', 'H1-error', 'H2-error');\n";
436 
437  // All done.
438  return 0;
439 #endif // #ifndef LIBMESH_ENABLE_SECOND_DERIVATIVES
440 #endif // #ifndef LIBMESH_ENABLE_AMR
441 }
442 
443 
444 
446  const Parameters &, // parameters, not needed
447  const std::string &, // sys_name, not needed
448  const std::string &) // unk_name, not needed
449 {
450  // x coordinate in space
451  const Real x = p(0);
452 
453  // analytic solution value
454  return 256.*(x-x*x)*(x-x*x);
455 }
456 
457 
458 // We now define the gradient of the exact solution
460  const Parameters &, // parameters, not needed
461  const std::string &, // sys_name, not needed
462  const std::string &) // unk_name, not needed
463 {
464  // x coordinate in space
465  const Real x = p(0);
466 
467  // First derivatives to be returned.
468  Gradient gradu;
469 
470  gradu(0) = 256.*2.*(x-x*x)*(1-2*x);
471 
472  return gradu;
473 }
474 
475 
476 // We now define the hessian of the exact solution
478  const Parameters &, // parameters, not needed
479  const std::string &, // sys_name, not needed
480  const std::string &) // unk_name, not needed
481 {
482  // Second derivatives to be returned.
483  Tensor hessu;
484 
485  // x coordinate in space
486  const Real x = p(0);
487 
488  hessu(0,0) = 256.*2.*(1-6.*x+6.*x*x);
489 
490  return hessu;
491 }
492 
493 
494 
496 {
497  // Equals laplacian(laplacian(u)), u'''' in 1D
498  return 256. * 2. * 12.;
499 }
500 
501 
503  const Parameters &, // parameters, not needed
504  const std::string &, // sys_name, not needed
505  const std::string &) // unk_name, not needed
506 {
507  // x and y coordinates in space
508  const Real x = p(0);
509  const Real y = p(1);
510 
511  // analytic solution value
512  return 256.*(x-x*x)*(x-x*x)*(y-y*y)*(y-y*y);
513 }
514 
515 
516 // We now define the gradient of the exact solution
518  const Parameters &, // parameters, not needed
519  const std::string &, // sys_name, not needed
520  const std::string &) // unk_name, not needed
521 {
522  // x and y coordinates in space
523  const Real x = p(0);
524  const Real y = p(1);
525 
526  // First derivatives to be returned.
527  Gradient gradu;
528 
529  gradu(0) = 256.*2.*(x-x*x)*(1-2*x)*(y-y*y)*(y-y*y);
530  gradu(1) = 256.*2.*(x-x*x)*(x-x*x)*(y-y*y)*(1-2*y);
531 
532  return gradu;
533 }
534 
535 
536 // We now define the hessian of the exact solution
538  const Parameters &, // parameters, not needed
539  const std::string &, // sys_name, not needed
540  const std::string &) // unk_name, not needed
541 {
542  // Second derivatives to be returned.
543  Tensor hessu;
544 
545  // x and y coordinates in space
546  const Real x = p(0);
547  const Real y = p(1);
548 
549  hessu(0,0) = 256.*2.*(1-6.*x+6.*x*x)*(y-y*y)*(y-y*y);
550  hessu(0,1) = 256.*4.*(x-x*x)*(1.-2.*x)*(y-y*y)*(1.-2.*y);
551  hessu(1,1) = 256.*2.*(x-x*x)*(x-x*x)*(1.-6.*y+6.*y*y);
552 
553  // Hessians are always symmetric
554  hessu(1,0) = hessu(0,1);
555  return hessu;
556 }
557 
558 
559 
561 {
562  // x and y coordinates in space
563  const Real x = p(0);
564  const Real y = p(1);
565 
566  // Equals laplacian(laplacian(u))
567  return 256. * 8. * (3.*((y-y*y)*(y-y*y)+(x-x*x)*(x-x*x))
568  + (1.-6.*x+6.*x*x)*(1.-6.*y+6.*y*y));
569 }
570 
571 
572 
574  const Parameters &, // parameters, not needed
575  const std::string &, // sys_name, not needed
576  const std::string &) // unk_name, not needed
577 {
578  // xyz coordinates in space
579  const Real x = p(0);
580  const Real y = p(1);
581  const Real z = p(2);
582 
583  // analytic solution value
584  return 4096.*(x-x*x)*(x-x*x)*(y-y*y)*(y-y*y)*(z-z*z)*(z-z*z);
585 }
586 
587 
589  const Parameters &, // parameters, not needed
590  const std::string &, // sys_name, not needed
591  const std::string &) // unk_name, not needed
592 {
593  // First derivatives to be returned.
594  Gradient gradu;
595 
596  // xyz coordinates in space
597  const Real x = p(0);
598  const Real y = p(1);
599  const Real z = p(2);
600 
601  gradu(0) = 4096.*2.*(x-x*x)*(1.-2.*x)*(y-y*y)*(y-y*y)*(z-z*z)*(z-z*z);
602  gradu(1) = 4096.*2.*(x-x*x)*(x-x*x)*(y-y*y)*(1.-2.*y)*(z-z*z)*(z-z*z);
603  gradu(2) = 4096.*2.*(x-x*x)*(x-x*x)*(y-y*y)*(y-y*y)*(z-z*z)*(1.-2.*z);
604 
605  return gradu;
606 }
607 
608 
609 // We now define the hessian of the exact solution
611  const Parameters &, // parameters, not needed
612  const std::string &, // sys_name, not needed
613  const std::string &) // unk_name, not needed
614 {
615  // Second derivatives to be returned.
616  Tensor hessu;
617 
618  // xyz coordinates in space
619  const Real x = p(0);
620  const Real y = p(1);
621  const Real z = p(2);
622 
623  hessu(0,0) = 4096.*(2.-12.*x+12.*x*x)*(y-y*y)*(y-y*y)*(z-z*z)*(z-z*z);
624  hessu(0,1) = 4096.*4.*(x-x*x)*(1.-2.*x)*(y-y*y)*(1.-2.*y)*(z-z*z)*(z-z*z);
625  hessu(0,2) = 4096.*4.*(x-x*x)*(1.-2.*x)*(y-y*y)*(y-y*y)*(z-z*z)*(1.-2.*z);
626  hessu(1,1) = 4096.*(x-x*x)*(x-x*x)*(2.-12.*y+12.*y*y)*(z-z*z)*(z-z*z);
627  hessu(1,2) = 4096.*4.*(x-x*x)*(x-x*x)*(y-y*y)*(1.-2.*y)*(z-z*z)*(1.-2.*z);
628  hessu(2,2) = 4096.*(x-x*x)*(x-x*x)*(y-y*y)*(y-y*y)*(2.-12.*z+12.*z*z);
629 
630  // Hessians are always symmetric
631  hessu(1,0) = hessu(0,1);
632  hessu(2,0) = hessu(0,2);
633  hessu(2,1) = hessu(1,2);
634 
635  return hessu;
636 }
637 
638 
639 
641 {
642  // xyz coordinates in space
643  const Real x = p(0);
644  const Real y = p(1);
645  const Real z = p(2);
646 
647  // Equals laplacian(laplacian(u))
648  return 4096. * 8. * (3.*((y-y*y)*(y-y*y)*(x-x*x)*(x-x*x) +
649  (z-z*z)*(z-z*z)*(x-x*x)*(x-x*x) +
650  (z-z*z)*(z-z*z)*(y-y*y)*(y-y*y)) +
651  (1.-6.*x+6.*x*x)*(1.-6.*y+6.*y*y)*(z-z*z)*(z-z*z) +
652  (1.-6.*x+6.*x*x)*(1.-6.*z+6.*z*z)*(y-y*y)*(y-y*y) +
653  (1.-6.*y+6.*y*y)*(1.-6.*z+6.*z*z)*(x-x*x)*(x-x*x));
654 }
655 
656 
657 
658 // We now define the matrix assembly function for the
659 // Biharmonic system. We need to first compute element
660 // matrices and right-hand sides, and then take into
661 // account the boundary conditions, which will be handled
662 // via a penalty method.
664  const std::string & system_name)
665 {
666  // Ignore unused parameter warnings when libmesh is configured without certain options.
667  libmesh_ignore(es, system_name);
668 
669 #ifdef LIBMESH_ENABLE_AMR
670 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
671 
672  // It is a good idea to make sure we are assembling
673  // the proper system.
674  libmesh_assert_equal_to (system_name, "Biharmonic");
675 
676  // Declare a performance log. Give it a descriptive
677  // string to identify what part of the code we are
678  // logging, since there may be many PerfLogs in an
679  // application.
680  PerfLog perf_log ("Matrix Assembly", false);
681 
682  // Get a constant reference to the mesh object.
683  const MeshBase & mesh = es.get_mesh();
684 
685  // The dimension that we are running
686  const unsigned int dim = mesh.mesh_dimension();
687 
688  // Get a reference to the LinearImplicitSystem we are solving
689  LinearImplicitSystem & system = es.get_system<LinearImplicitSystem>("Biharmonic");
690 
691  // A reference to the DofMap object for this system. The DofMap
692  // object handles the index translation from node and element numbers
693  // to degree of freedom numbers. We will talk more about the DofMap
694  // in future examples.
695  const DofMap & dof_map = system.get_dof_map();
696 
697  // Get a constant reference to the Finite Element type
698  // for the first (and only) variable in the system.
699  FEType fe_type = dof_map.variable_type(0);
700 
701  // Build a Finite Element object of the specified type. Since the
702  // FEBase::build() member dynamically creates memory we will
703  // store the object as a std::unique_ptr<FEBase>. This can be thought
704  // of as a pointer that will clean up after itself.
705  std::unique_ptr<FEBase> fe (FEBase::build(dim, fe_type));
706 
707  // Quadrature rule for numerical integration.
708  // With 2D triangles, the Clough quadrature rule puts a Gaussian
709  // quadrature rule on each of the 3 subelements
710  std::unique_ptr<QBase> qrule(fe_type.default_quadrature_rule(dim));
711 
712  // Tell the finite element object to use our quadrature rule.
713  fe->attach_quadrature_rule (qrule.get());
714 
715  // Declare a special finite element object for
716  // boundary integration.
717  std::unique_ptr<FEBase> fe_face (FEBase::build(dim, fe_type));
718 
719  // Boundary integration requires another quadrature rule,
720  // with dimensionality one less than the dimensionality
721  // of the element.
722  // In 1D, the Clough and Gauss quadrature rules are identical.
723  std::unique_ptr<QBase> qface(fe_type.default_quadrature_rule(dim-1));
724 
725  // Tell the finite element object to use our
726  // quadrature rule.
727  fe_face->attach_quadrature_rule (qface.get());
728 
729  // Here we define some references to cell-specific data that
730  // will be used to assemble the linear system.
731  // We begin with the element Jacobian * quadrature weight at each
732  // integration point.
733  const std::vector<Real> & JxW = fe->get_JxW();
734 
735  // The physical XY locations of the quadrature points on the element.
736  // These might be useful for evaluating spatially varying material
737  // properties at the quadrature points.
738  const std::vector<Point> & q_point = fe->get_xyz();
739 
740  // The element shape functions evaluated at the quadrature points.
741  const std::vector<std::vector<Real>> & phi = fe->get_phi();
742 
743  // The element shape function second derivatives evaluated at the
744  // quadrature points. Note that for the simple biharmonic, shape
745  // function first derivatives are unnecessary.
746  const std::vector<std::vector<RealTensor>> & d2phi = fe->get_d2phi();
747 
748  // For efficiency we will compute shape function laplacians n times,
749  // not n^2
750  std::vector<Real> shape_laplacian;
751 
752  // Define data structures to contain the element matrix
753  // and right-hand-side vector contribution. Following
754  // basic finite element terminology we will denote these
755  // "Ke" and "Fe". More detail is in example 3.
758 
759  // This vector will hold the degree of freedom indices for
760  // the element. These define where in the global system
761  // the element degrees of freedom get mapped.
762  std::vector<dof_id_type> dof_indices;
763 
764  // Now we will loop over all the elements in the mesh. We will
765  // compute the element matrix and right-hand-side contribution. See
766  // example 3 for a discussion of the element iterators.
767  for (const auto & elem : mesh.active_local_element_ptr_range())
768  {
769  // Start logging the shape function initialization.
770  // This is done through a simple function call with
771  // the name of the event to log.
772  perf_log.push("elem init");
773 
774  // Get the degree of freedom indices for the
775  // current element. These define where in the global
776  // matrix and right-hand-side this element will
777  // contribute to.
778  dof_map.dof_indices (elem, dof_indices);
779 
780  // Compute the element-specific data for the current
781  // element. This involves computing the location of the
782  // quadrature points (q_point) and the shape functions
783  // (phi, dphi) for the current element.
784  fe->reinit (elem);
785 
786  const unsigned int n_dofs =
787  cast_int<unsigned int>(dof_indices.size());
788  libmesh_assert_equal_to (n_dofs, phi.size());
789 
790  // Zero the element matrix and right-hand side before
791  // summing them.
792  Ke.resize (n_dofs, n_dofs);
793 
794  Fe.resize (n_dofs);
795 
796  // Make sure there is enough room in this cache
797  shape_laplacian.resize(n_dofs);
798 
799  // Stop logging the shape function initialization.
800  // If you forget to stop logging an event the PerfLog
801  // object will probably catch the error and abort.
802  perf_log.pop("elem init");
803 
804  // Now we will build the element matrix. This involves
805  // a double loop to integrate laplacians of the test functions
806  // (i) against laplacians of the trial functions (j).
807  //
808  // This step is why we need the Clough-Tocher elements -
809  // these C1 differentiable elements have square-integrable
810  // second derivatives.
811  //
812  // Now start logging the element matrix computation
813  perf_log.push ("Ke");
814 
815  for (unsigned int qp=0; qp<qrule->n_points(); qp++)
816  {
817  for (unsigned int i=0; i != n_dofs; i++)
818  {
819  shape_laplacian[i] = d2phi[i][qp](0,0);
820  if (dim > 1)
821  shape_laplacian[i] += d2phi[i][qp](1,1);
822  if (dim == 3)
823  shape_laplacian[i] += d2phi[i][qp](2,2);
824  }
825  for (unsigned int i=0; i != n_dofs; i++)
826  for (unsigned int j=0; j != n_dofs; j++)
827  Ke(i,j) += JxW[qp]*
828  shape_laplacian[i]*shape_laplacian[j];
829  }
830 
831  // Stop logging the matrix computation
832  perf_log.pop ("Ke");
833 
834 
835  // At this point the interior element integration has
836  // been completed. However, we have not yet addressed
837  // boundary conditions. For this example we will only
838  // consider simple Dirichlet boundary conditions imposed
839  // via the penalty method. Note that this is a fourth-order
840  // problem: Dirichlet boundary conditions include *both*
841  // boundary values and boundary normal fluxes.
842  {
843  // Start logging the boundary condition computation. We use a
844  // macro to log everything in this scope.
845  LOG_SCOPE_WITH("BCs", "", perf_log);
846 
847  // The penalty values, for solution boundary trace and flux.
848  const Real penalty = 1e10;
849  const Real penalty2 = 1e10;
850 
851  // The following loops over the sides of the element.
852  // If the element has no neighbor on a side then that
853  // side MUST live on a boundary of the domain.
854  for (auto s : elem->side_index_range())
855  if (elem->neighbor_ptr(s) == nullptr)
856  {
857  // The value of the shape functions at the quadrature
858  // points.
859  const std::vector<std::vector<Real>> & phi_face =
860  fe_face->get_phi();
861 
862  // The value of the shape function derivatives at the
863  // quadrature points.
864  const std::vector<std::vector<RealGradient>> & dphi_face =
865  fe_face->get_dphi();
866 
867  // The Jacobian * Quadrature Weight at the quadrature
868  // points on the face.
869  const std::vector<Real> & JxW_face = fe_face->get_JxW();
870 
871  // The XYZ locations (in physical space) of the
872  // quadrature points on the face. This is where
873  // we will interpolate the boundary value function.
874  const std::vector<Point> & qface_point = fe_face->get_xyz();
875  const std::vector<Point> & face_normals = fe_face->get_normals();
876 
877  // Compute the shape function values on the element
878  // face.
879  fe_face->reinit(elem, s);
880 
881  libmesh_assert_equal_to (n_dofs, phi_face.size());
882 
883  // Loop over the face quadrature points for integration.
884  for (unsigned int qp=0; qp<qface->n_points(); qp++)
885  {
886  // The boundary value.
887  Number value = exact_solution(qface_point[qp],
888  es.parameters, "null",
889  "void");
890  Gradient flux = exact_2D_derivative(qface_point[qp],
891  es.parameters,
892  "null", "void");
893 
894  // Matrix contribution of the L2 projection.
895  // Note that the basis function values are
896  // integrated against test function values while
897  // basis fluxes are integrated against test function
898  // fluxes.
899  for (unsigned int i=0; i != n_dofs; i++)
900  for (unsigned int j=0; j != n_dofs; j++)
901  Ke(i,j) += JxW_face[qp] *
902  (penalty * phi_face[i][qp] *
903  phi_face[j][qp] + penalty2
904  * (dphi_face[i][qp] *
905  face_normals[qp]) *
906  (dphi_face[j][qp] *
907  face_normals[qp]));
908 
909  // Right-hand-side contribution of the L2
910  // projection.
911  for (unsigned int i=0; i != n_dofs; i++)
912  Fe(i) += JxW_face[qp] *
913  (penalty * value * phi_face[i][qp]
914  + penalty2 *
915  (flux * face_normals[qp])
916  * (dphi_face[i][qp]
917  * face_normals[qp]));
918 
919  }
920  }
921  }
922 
923  for (unsigned int qp=0; qp<qrule->n_points(); qp++)
924  for (unsigned int i=0; i != n_dofs; i++)
925  Fe(i) += JxW[qp]*phi[i][qp]*forcing_function(q_point[qp]);
926 
927  // The element matrix and right-hand-side are now built
928  // for this element. Add them to the global matrix and
929  // right-hand-side vector. The SparseMatrix::add_matrix()
930  // and NumericVector::add_vector() members do this for us.
931  // Start logging the insertion of the local (element)
932  // matrix and vector into the global matrix and vector
933  LOG_SCOPE_WITH("matrix insertion", "", perf_log);
934 
935  dof_map.constrain_element_matrix_and_vector(Ke, Fe, dof_indices);
936  system.matrix->add_matrix (Ke, dof_indices);
937  system.rhs->add_vector (Fe, dof_indices);
938  }
939 
940  // That's it. We don't need to do anything else to the
941  // PerfLog. When it goes out of scope (at this function return)
942  // it will print its log to the screen. Pretty easy, huh?
943 
944 #else
945 
946 #endif // #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
947 #endif // #ifdef LIBMESH_ENABLE_AMR
948 }
libMesh::ExactSolution
This class handles the computation of the L2 and/or H1 error for the Systems in the EquationSystems o...
Definition: exact_solution.h:73
libMesh::Number
Real Number
Definition: libmesh_common.h:195
forcing_function_1D
Number forcing_function_1D(const Point &p)
Definition: adaptivity_ex4.C:495
libMesh::MeshRefinement::refine_and_coarsen_elements
bool refine_and_coarsen_elements()
Refines and coarsens user-requested elements.
Definition: mesh_refinement.C:476
libMesh::Mesh
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50
exact_1D_hessian
Tensor exact_1D_hessian(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition: adaptivity_ex4.C:477
exact_3D_derivative
Gradient exact_3D_derivative(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition: adaptivity_ex4.C:588
exact_2D_solution
Number exact_2D_solution(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition: adaptivity_ex4.C:502
libMesh::EquationSystems::add_system
virtual System & add_system(const std::string &system_type, const std::string &name)
Add the system of type system_type named name to the systems array.
Definition: equation_systems.C:345
libMesh::EquationSystems::get_mesh
const MeshBase & get_mesh() const
Definition: equation_systems.h:637
exact_solution
Number(* exact_solution)(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition: adaptivity_ex4.C:132
exact_2D_hessian
Tensor exact_2D_hessian(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition: adaptivity_ex4.C:537
libMesh::CLOUGH
Definition: enum_fe_family.h:53
libMesh::ExplicitSystem::rhs
NumericVector< Number > * rhs
The system matrix.
Definition: explicit_system.h:114
libMesh::MeshBase::all_second_order
virtual void all_second_order(const bool full_ordered=true)=0
Converts a (conforming, non-refined) mesh with linear elements into a mesh with second-order elements...
libMesh::JumpErrorEstimator::estimate_error
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's jump error estimate formula to estimate the error on each cell...
Definition: jump_error_estimator.C:53
libMesh::LaplacianErrorEstimator
This class is an error indicator based on laplacian jumps between elements.
Definition: fourth_error_estimators.h:41
libMesh::MeshBase::active_local_element_ptr_range
virtual SimpleRange< element_iterator > active_local_element_ptr_range()=0
libMesh::HERMITE
Definition: enum_fe_family.h:54
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::EquationSystems::get_system
const T_sys & get_system(const std::string &name) const
Definition: equation_systems.h:757
libMesh::ExactSolution::h1_error
Real h1_error(const std::string &sys_name, const std::string &unknown_name)
Definition: exact_solution.C:393
libMesh::Order
Order
Definition: enum_order.h:40
libMesh::MeshTools::Generation::build_cube
void build_cube(UnstructuredMesh &mesh, const unsigned int nx=0, const unsigned int ny=0, const unsigned int nz=0, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const Real zmin=0., const Real zmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
Builds a (elements) cube.
Definition: mesh_generation.C:298
libMesh::TOLERANCE
static const Real TOLERANCE
Definition: libmesh_common.h:128
libMesh::DenseMatrix< Number >
libMesh::LinearImplicitSystem::solve
virtual void solve() override
Assembles & solves the linear system A*x=b.
Definition: linear_implicit_system.C:108
libMesh::default_solver_package
SolverPackage default_solver_package()
Definition: libmesh.C:993
forcing_function_3D
Number forcing_function_3D(const Point &p)
Definition: adaptivity_ex4.C:640
mesh
MeshBase & mesh
Definition: mesh_communication.C:1257
libMesh::MeshBase::mesh_dimension
unsigned int mesh_dimension() const
Definition: mesh_base.C:135
libMesh::ExactSolution::h2_error
Real h2_error(const std::string &sys_name, const std::string &unknown_name)
Definition: exact_solution.C:425
libMesh::ExodusII_IO
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
Definition: exodusII_io.h:51
libMesh::SECOND
Definition: enum_order.h:43
dim
unsigned int dim
Definition: adaptivity_ex3.C:113
libMesh::DenseMatrix::resize
void resize(const unsigned int new_m, const unsigned int new_n)
Resize the matrix.
Definition: dense_matrix.h:822
libMesh::VectorValue< Number >
libMesh::TriangleWrapper::init
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
libMesh::MeshRefinement
Implements (adaptive) mesh refinement algorithms for a MeshBase.
Definition: mesh_refinement.h:61
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::MeshTools::Generation::build_square
void build_square(UnstructuredMesh &mesh, const unsigned int nx, const unsigned int ny, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 2D meshes.
Definition: mesh_generation.C:1501
libMesh::ExactSolution::attach_exact_value
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...
Definition: exact_solution.C:123
libMesh::System::attach_assemble_function
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:1755
libMesh::NumericVector::add_vector
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].
Definition: numeric_vector.C:363
libMesh::MeshBase
This is the MeshBase class.
Definition: mesh_base.h:78
main
int main(int argc, char **argv)
Definition: adaptivity_ex4.C:151
exact_hessian
Tensor(* exact_hessian)(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition: adaptivity_ex4.C:142
exact_3D_solution
Number exact_3D_solution(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition: adaptivity_ex4.C:573
libMesh::EquationSystems::n_active_dofs
std::size_t n_active_dofs() const
Definition: equation_systems.C:1362
exact_1D_derivative
Gradient exact_1D_derivative(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition: adaptivity_ex4.C:459
libMesh::PerfLog::pop
void pop(const char *label, const char *header="")
Pop the event label off the stack, resuming any lower event.
Definition: perf_log.C:163
libMesh::ExactSolution::attach_exact_hessian
void attach_exact_hessian(unsigned int sys_num, FunctionBase< Tensor > *h)
Clone and attach an arbitrary functor which computes the exact second derivatives of the system sys_n...
Definition: exact_solution.C:205
libMesh::MeshRefinement::flag_elements_by_elem_fraction
void flag_elements_by_elem_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.
Definition: mesh_refinement_flagging.C:446
libMesh::INVALID_SOLVER_PACKAGE
Definition: enum_solver_package.h:43
libMesh::libmesh_ignore
void libmesh_ignore(const Args &...)
Definition: libmesh_common.h:526
libMesh::FEGenericBase::build
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
libMesh::System::add_variable
unsigned int add_variable(const std::string &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:1069
libMesh::MeshTools::Generation::build_line
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.
Definition: mesh_generation.C:1480
libMesh::TensorValue
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.
Definition: exact_solution.h:53
libMesh::PerfLog
The PerfLog class allows monitoring of specific events.
Definition: perf_log.h:125
libMesh::EquationSystems::init
virtual void init()
Initialize all the systems.
Definition: equation_systems.C:96
libMesh::Point
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:38
libMesh::ImplicitSystem::matrix
SparseMatrix< Number > * matrix
The system matrix.
Definition: implicit_system.h:393
libMesh::ErrorVector
The ErrorVector is a specialization of the StatisticsVector for error data computed on a finite eleme...
Definition: error_vector.h:50
libMesh::FEType::default_quadrature_rule
std::unique_ptr< QBase > default_quadrature_rule(const unsigned int dim, const int extraorder=0) const
Definition: fe_type.C:31
libMesh::LibMeshInit
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition: libmesh.h:83
libMesh::ExactSolution::l2_error
Real l2_error(const std::string &sys_name, const std::string &unknown_name)
Definition: exact_solution.C:333
forcing_function
Number(* forcing_function)(const Point &p)
Definition: adaptivity_ex4.C:147
exact_1D_solution
Number exact_1D_solution(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition: adaptivity_ex4.C:445
libMesh::MeshRefinement::max_h_level
unsigned int & max_h_level()
The max_h_level is the greatest refinement level an element should reach.
Definition: mesh_refinement.h:891
libMesh::ExactSolution::compute_error
void compute_error(const std::string &sys_name, const std::string &unknown_name)
Computes and stores the error in the solution value e = u-u_h, the gradient grad(e) = grad(u) - grad(...
Definition: exact_solution.C:227
libMesh::EquationSystems::print_info
void print_info(std::ostream &os=libMesh::out) const
Prints information about the equation systems, by default to libMesh::out.
Definition: equation_systems.C:1314
libMesh::EquationSystems
This is the EquationSystems class.
Definition: equation_systems.h:74
libMesh::Parameters::set
T & set(const std::string &)
Definition: parameters.h:460
libMesh::LinearImplicitSystem::n_linear_iterations
unsigned int n_linear_iterations() const
Definition: linear_implicit_system.h:164
libMesh::MeshOutput::write_equation_systems
virtual void write_equation_systems(const std::string &, const EquationSystems &, const std::set< std::string > *system_names=nullptr)
This method implements writing a mesh with data to a specified file where the data is taken from the ...
Definition: mesh_output.C:31
libMesh::DenseVector::resize
void resize(const unsigned int n)
Resize the vector.
Definition: dense_vector.h:355
exact_2D_derivative
Gradient exact_2D_derivative(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition: adaptivity_ex4.C:517
libMesh::EquationSystems::reinit
virtual void reinit()
Handle any mesh changes and reinitialize all the systems on the updated mesh.
Definition: equation_systems.C:121
libMesh::MeshTools::Modification::all_tri
void all_tri(MeshBase &mesh)
Converts the 2D quadrilateral elements of a Mesh into triangular elements.
Definition: mesh_modification.C:280
libMesh::MeshRefinement::coarsen_fraction
Real & coarsen_fraction()
The coarsen_fraction sets either a desired target or a desired maximum number of elements to flag for...
Definition: mesh_refinement.h:885
libMesh::Gradient
NumberVectorValue Gradient
Definition: exact_solution.h:58
libMesh::SparseMatrix::add_matrix
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.
libMesh::MeshRefinement::refine_fraction
Real & refine_fraction()
The refine_fraction sets either a desired target or a desired maximum number of elements to flag for ...
Definition: mesh_refinement.h:879
libMesh::FEType
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:178
value
static const bool value
Definition: xdr_io.C:56
libMesh::DofMap
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:176
libMesh::MeshBase::print_info
void print_info(std::ostream &os=libMesh::out) const
Prints relevant information about the mesh.
Definition: mesh_base.C:585
libMesh::ErrorVector::mean
virtual Real mean() const override
Definition: error_vector.C:69
libMesh::JumpErrorEstimator::use_unweighted_quadrature_rules
bool use_unweighted_quadrature_rules
This boolean flag allows you to use "unweighted" quadrature rules (sized to exactly integrate unweigh...
Definition: jump_error_estimator.h:113
libMesh::PerfLog::push
void push(const char *label, const char *header="")
Push the event label onto the stack, pausing any active event.
Definition: perf_log.C:133
libMesh::LinearImplicitSystem::final_linear_residual
Real final_linear_residual() const
Definition: linear_implicit_system.h:169
forcing_function_2D
Number forcing_function_2D(const Point &p)
Definition: adaptivity_ex4.C:560
libMesh::System::get_dof_map
const DofMap & get_dof_map() const
Definition: system.h:2099
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121
libMesh::LinearImplicitSystem
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and linear solvers ...
Definition: linear_implicit_system.h:55
libMesh::Tensor
NumberTensorValue Tensor
Definition: exact_solution.h:56
libMesh::out
OStreamProxy out
libMesh::ExactSolution::attach_exact_deriv
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...
Definition: exact_solution.C:164
libMesh::MeshRefinement::uniformly_refine
void uniformly_refine(unsigned int n=1)
Uniformly refines the mesh n times.
Definition: mesh_refinement.C:1678
exact_derivative
Gradient(* exact_derivative)(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition: adaptivity_ex4.C:137
exact_3D_hessian
Tensor exact_3D_hessian(const Point &p, const Parameters &, const std::string &, const std::string &)
Definition: adaptivity_ex4.C:610
libMesh::ErrorVector::variance
virtual Real variance() const override
Definition: error_vector.h:115
assemble_biharmonic
void assemble_biharmonic(EquationSystems &es, const std::string &system_name)
Definition: adaptivity_ex4.C:663
libMesh::Parameters
This class provides the ability to map between arbitrary, user-defined strings and several data types...
Definition: parameters.h:59
libMesh::DenseVector< Number >
libMesh::EquationSystems::parameters
Parameters parameters
Data structure holding arbitrary parameters.
Definition: equation_systems.h:557