libMesh
exact_solution.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 // Local includes
19 #include "libmesh/dof_map.h"
20 #include "libmesh/elem.h"
21 #include "libmesh/exact_solution.h"
22 #include "libmesh/equation_systems.h"
23 #include "libmesh/fe_base.h"
24 #include "libmesh/function_base.h"
25 #include "libmesh/mesh_base.h"
26 #include "libmesh/mesh_function.h"
27 #include "libmesh/mesh_serializer.h"
28 #include "libmesh/numeric_vector.h"
29 #include "libmesh/parallel.h"
30 #include "libmesh/quadrature.h"
31 #include "libmesh/wrapped_function.h"
32 #include "libmesh/wrapped_functor.h"
33 #include "libmesh/fe_interface.h"
34 #include "libmesh/raw_accessor.h"
35 #include "libmesh/tensor_tools.h"
36 #include "libmesh/enum_norm_type.h"
37 #include "libmesh/utility.h"
38 
39 // C++ Includes
40 #include <memory>
41 
42 
43 namespace libMesh
44 {
45 
47  _equation_systems(es),
48  _equation_systems_fine(nullptr),
49  _extra_order(1)
50 {
51  // Initialize the _errors data structure which holds all
52  // the eventual values of the error.
53  for (auto sys : make_range(_equation_systems.n_systems()))
54  {
55  // Reference to the system
56  const System & system = _equation_systems.get_system(sys);
57 
58  // The name of the system
59  const std::string & sys_name = system.name();
60 
61  // The SystemErrorMap to be inserted
63 
64  for (auto var : make_range(system.n_vars()))
65  {
66  // The name of this variable
67  const std::string & var_name = system.variable_name(var);
68  sem[var_name] = std::vector<Real>(5, 0.);
69  }
70 
71  _errors[sys_name] = sem;
72  }
73 }
74 
75 
78 
79 
80 void ExactSolution::
81 set_excluded_subdomains(const std::set<subdomain_id_type> & excluded)
82 {
83  _excluded_subdomains = excluded;
84 }
85 
87 {
88  libmesh_assert(es_fine);
89  _equation_systems_fine = es_fine;
90 
91  // If we're using a fine grid solution, we're not using exact values
92  _exact_values.clear();
93  _exact_derivs.clear();
94  _exact_hessians.clear();
95 }
96 
97 
98 void ExactSolution::attach_exact_value (ValueFunctionPointer fptr)
99 {
101 
102  // Clear out any previous _exact_values entries, then add a new
103  // entry for each system.
104  _exact_values.clear();
105 
106  for (auto sys : make_range(_equation_systems.n_systems()))
107  {
108  const System & system = _equation_systems.get_system(sys);
109  _exact_values.emplace_back(std::make_unique<WrappedFunctor<Number>>(system, fptr, &_equation_systems.parameters));
110  }
111 
112  // If we're using exact values, we're not using a fine grid solution
113  _equation_systems_fine = nullptr;
114 }
115 
116 
118 {
119  // Automatically delete any previous _exact_values entries, then add a new
120  // entry for each system.
121  _exact_values.clear();
122 
123  for (auto ptr : f)
124  _exact_values.emplace_back(ptr ? std::make_unique<WrappedFunctor<Number>>(*ptr) : nullptr);
125 }
126 
127 
129 {
130  // Automatically delete any previous _exact_values entries, then add a new
131  // entry for each system.
132  _exact_values.clear();
133 
134  for (auto ptr : f)
135  _exact_values.emplace_back(ptr ? ptr->clone() : nullptr);
136 }
137 
138 
139 void ExactSolution::attach_exact_value (unsigned int sys_num,
141 {
142  if (_exact_values.size() <= sys_num)
143  _exact_values.resize(sys_num+1);
144 
145  if (f)
146  _exact_values[sys_num] = std::make_unique<WrappedFunctor<Number>>(*f);
147 }
148 
149 
150 void ExactSolution::attach_exact_value (unsigned int sys_num,
152 {
153  if (_exact_values.size() <= sys_num)
154  _exact_values.resize(sys_num+1);
155 
156  if (f)
157  _exact_values[sys_num] = f->clone();
158 }
159 
160 
161 void ExactSolution::attach_exact_deriv (GradientFunctionPointer gptr)
162 {
164 
165  // Clear out any previous _exact_derivs entries, then add a new
166  // entry for each system.
167  _exact_derivs.clear();
168 
169  for (auto sys : make_range(_equation_systems.n_systems()))
170  {
171  const System & system = _equation_systems.get_system(sys);
172  _exact_derivs.emplace_back(std::make_unique<WrappedFunctor<Gradient>>(system, gptr, &_equation_systems.parameters));
173  }
174 
175  // If we're using exact values, we're not using a fine grid solution
176  _equation_systems_fine = nullptr;
177 }
178 
179 
181 {
182  // Automatically delete any previous _exact_derivs entries, then add a new
183  // entry for each system.
184  _exact_derivs.clear();
185 
186  for (auto ptr : g)
187  _exact_derivs.emplace_back(ptr ? std::make_unique<WrappedFunctor<Gradient>>(*ptr) : nullptr);
188 }
189 
190 
192 {
193  // Automatically delete any previous _exact_derivs entries, then add a new
194  // entry for each system.
195  _exact_derivs.clear();
196 
197  for (auto ptr : g)
198  _exact_derivs.emplace_back(ptr ? ptr->clone() : nullptr);
199 }
200 
201 
202 void ExactSolution::attach_exact_deriv (unsigned int sys_num,
204 {
205  if (_exact_derivs.size() <= sys_num)
206  _exact_derivs.resize(sys_num+1);
207 
208  if (g)
209  _exact_derivs[sys_num] = std::make_unique<WrappedFunctor<Gradient>>(*g);
210 }
211 
212 
213 void ExactSolution::attach_exact_deriv (unsigned int sys_num,
215 {
216  if (_exact_derivs.size() <= sys_num)
217  _exact_derivs.resize(sys_num+1);
218 
219  if (g)
220  _exact_derivs[sys_num] = g->clone();
221 }
222 
223 
224 void ExactSolution::attach_exact_hessian (HessianFunctionPointer hptr)
225 {
226  libmesh_assert(hptr);
227 
228  // Clear out any previous _exact_hessians entries, then add a new
229  // entry for each system.
230  _exact_hessians.clear();
231 
232  for (auto sys : make_range(_equation_systems.n_systems()))
233  {
234  const System & system = _equation_systems.get_system(sys);
235  _exact_hessians.emplace_back(std::make_unique<WrappedFunctor<Tensor>>(system, hptr, &_equation_systems.parameters));
236  }
237 
238  // If we're using exact values, we're not using a fine grid solution
239  _equation_systems_fine = nullptr;
240 }
241 
242 
244 {
245  // Automatically delete any previous _exact_hessians entries, then add a new
246  // entry for each system.
247  _exact_hessians.clear();
248 
249  for (auto ptr : h)
250  _exact_hessians.emplace_back(ptr ? std::make_unique<WrappedFunctor<Tensor>>(*ptr) : nullptr);
251 }
252 
253 
255 {
256  // Automatically delete any previous _exact_hessians entries, then add a new
257  // entry for each system.
258  _exact_hessians.clear();
259 
260  for (auto ptr : h)
261  _exact_hessians.emplace_back(ptr ? ptr->clone() : nullptr);
262 }
263 
264 
265 void ExactSolution::attach_exact_hessian (unsigned int sys_num,
267 {
268  if (_exact_hessians.size() <= sys_num)
269  _exact_hessians.resize(sys_num+1);
270 
271  if (h)
272  _exact_hessians[sys_num] = std::make_unique<WrappedFunctor<Tensor>>(*h);
273 }
274 
275 
276 void ExactSolution::attach_exact_hessian (unsigned int sys_num,
278 {
279  if (_exact_hessians.size() <= sys_num)
280  _exact_hessians.resize(sys_num+1);
281 
282  if (h)
283  _exact_hessians[sys_num] = h->clone();
284 }
285 
286 
287 std::vector<Real> & ExactSolution::_check_inputs(std::string_view sys_name,
288  std::string_view unknown_name)
289 {
290  // Return a reference to the proper error entry, or throw an error
291  // if it doesn't exist.
292  auto & system_error_map = libmesh_map_find(_errors, sys_name);
293  return libmesh_map_find(system_error_map, unknown_name);
294 }
295 
296 
297 
298 void ExactSolution::compute_error(std::string_view sys_name,
299  std::string_view unknown_name)
300 {
301  // Check the inputs for validity, and get a reference
302  // to the proper location to store the error
303  std::vector<Real> & error_vals = this->_check_inputs(sys_name,
304  unknown_name);
305 
307  const System & sys = _equation_systems.get_system<System>( sys_name );
308 
309  libmesh_assert( sys.has_variable( unknown_name ) );
310  switch( FEInterface::field_type(sys.variable_type( unknown_name )) )
311  {
312  case TYPE_SCALAR:
313  {
314  this->_compute_error<Real>(sys_name,
315  unknown_name,
316  error_vals);
317  break;
318  }
319  case TYPE_VECTOR:
320  {
321  this->_compute_error<RealGradient>(sys_name,
322  unknown_name,
323  error_vals);
324  break;
325  }
326  default:
327  libmesh_error_msg("Invalid variable type!");
328  }
329 }
330 
331 
332 
333 
334 
335 Real ExactSolution::error_norm(std::string_view sys_name,
336  std::string_view unknown_name,
337  const FEMNormType & norm)
338 {
339  // Check the inputs for validity, and get a reference
340  // to the proper location to store the error
341  std::vector<Real> & error_vals = this->_check_inputs(sys_name,
342  unknown_name);
343 
345  libmesh_assert(_equation_systems.get_system(sys_name).has_variable( unknown_name ));
346  const FEType & fe_type = _equation_systems.get_system(sys_name).variable_type(unknown_name);
347 
348  switch (norm)
349  {
350  case L2:
351  return std::sqrt(error_vals[0]);
352  case H1:
353  return std::sqrt(error_vals[0] + error_vals[1]);
354  case H2:
355  return std::sqrt(error_vals[0] + error_vals[1] + error_vals[2]);
356  case HCURL:
357  {
358  libmesh_error_msg_if(FEInterface::field_type(fe_type) == TYPE_SCALAR,
359  "Cannot compute HCurl error norm of scalar-valued variables!");
360 
361  return std::sqrt(error_vals[0] + error_vals[5]);
362  }
363  case HDIV:
364  {
365  libmesh_error_msg_if(FEInterface::field_type(fe_type) == TYPE_SCALAR,
366  "Cannot compute HDiv error norm of scalar-valued variables!");
367 
368  return std::sqrt(error_vals[0] + error_vals[6]);
369  }
370  case H1_SEMINORM:
371  return std::sqrt(error_vals[1]);
372  case H2_SEMINORM:
373  return std::sqrt(error_vals[2]);
374  case HCURL_SEMINORM:
375  {
376  libmesh_error_msg_if(FEInterface::field_type(fe_type) == TYPE_SCALAR,
377  "Cannot compute HCurl error seminorm of scalar-valued variables!");
378 
379  return std::sqrt(error_vals[5]);
380  }
381  case HDIV_SEMINORM:
382  {
383  libmesh_error_msg_if(FEInterface::field_type(fe_type) == TYPE_SCALAR,
384  "Cannot compute HDiv error seminorm of scalar-valued variables!");
385 
386  return std::sqrt(error_vals[6]);
387  }
388  case L1:
389  return error_vals[3];
390  case L_INF:
391  return error_vals[4];
392 
393  default:
394  libmesh_error_msg("Currently only Sobolev norms/seminorms are supported!");
395  }
396 }
397 
398 
399 
400 
401 
402 
403 
404 Real ExactSolution::l2_error(std::string_view sys_name,
405  std::string_view unknown_name)
406 {
407 
408  // Check the inputs for validity, and get a reference
409  // to the proper location to store the error
410  std::vector<Real> & error_vals = this->_check_inputs(sys_name,
411  unknown_name);
412 
413  // Return the square root of the first component of the
414  // computed error.
415  return std::sqrt(error_vals[0]);
416 }
417 
418 
419 
420 
421 
422 
423 
424 Real ExactSolution::l1_error(std::string_view sys_name,
425  std::string_view unknown_name)
426 {
427 
428  // Check the inputs for validity, and get a reference
429  // to the proper location to store the error
430  std::vector<Real> & error_vals = this->_check_inputs(sys_name,
431  unknown_name);
432 
433  // Return the square root of the first component of the
434  // computed error.
435  return error_vals[3];
436 }
437 
438 
439 
440 
441 
442 
443 
444 Real ExactSolution::l_inf_error(std::string_view sys_name,
445  std::string_view unknown_name)
446 {
447 
448  // Check the inputs for validity, and get a reference
449  // to the proper location to store the error
450  std::vector<Real> & error_vals = this->_check_inputs(sys_name,
451  unknown_name);
452 
453  // Return the square root of the first component of the
454  // computed error.
455  return error_vals[4];
456 }
457 
458 
459 
460 
461 
462 
463 
464 Real ExactSolution::h1_error(std::string_view sys_name,
465  std::string_view unknown_name)
466 {
467  // If the user has supplied no exact derivative function, we
468  // just integrate the H1 norm of the solution; i.e. its
469  // difference from an "exact solution" of zero.
470 
471  // Check the inputs for validity, and get a reference
472  // to the proper location to store the error
473  std::vector<Real> & error_vals = this->_check_inputs(sys_name,
474  unknown_name);
475 
476  // Return the square root of the sum of the computed errors.
477  return std::sqrt(error_vals[0] + error_vals[1]);
478 }
479 
480 
481 Real ExactSolution::hcurl_error(std::string_view sys_name,
482  std::string_view unknown_name)
483 {
484  return this->error_norm(sys_name,unknown_name,HCURL);
485 }
486 
487 
488 Real ExactSolution::hdiv_error(std::string_view sys_name,
489  std::string_view unknown_name)
490 {
491  return this->error_norm(sys_name,unknown_name,HDIV);
492 }
493 
494 
495 
496 Real ExactSolution::h2_error(std::string_view sys_name,
497  std::string_view unknown_name)
498 {
499  // If the user has supplied no exact derivative functions, we
500  // just integrate the H2 norm of the solution; i.e. its
501  // difference from an "exact solution" of zero.
502 
503  // Check the inputs for validity, and get a reference
504  // to the proper location to store the error
505  std::vector<Real> & error_vals = this->_check_inputs(sys_name,
506  unknown_name);
507 
508  // Return the square root of the sum of the computed errors.
509  return std::sqrt(error_vals[0] + error_vals[1] + error_vals[2]);
510 }
511 
512 
513 
514 
515 
516 
517 
518 template<typename OutputShape>
519 void ExactSolution::_compute_error(std::string_view sys_name,
520  std::string_view unknown_name,
521  std::vector<Real> & error_vals)
522 {
523  // Make sure we aren't "overconfigured"
525 
526  // We need a communicator.
528 
529  // This function must be run on all processors at once
530  libmesh_parallel_only(communicator);
531 
532  // Get a reference to the system whose error is being computed.
533  // If we have a fine grid, however, we'll integrate on that instead
534  // for more accuracy.
535  const System & computed_system = _equation_systems_fine ?
537  _equation_systems.get_system (sys_name);
538 
539  FEMContext context(computed_system);
540 
541  const MeshBase & mesh = computed_system.get_mesh();
542 
543  const Real time = _equation_systems.get_system(sys_name).time;
544 
545  const unsigned int sys_num = computed_system.number();
546  const unsigned int var = computed_system.variable_number(unknown_name);
547  unsigned int var_component = 0;
548  for (const auto var_num : make_range(var))
549  {
550  const auto & var_fe_type = computed_system.variable_type(var_num);
551  const auto var_vec_dim = FEInterface::n_vec_dim(mesh, var_fe_type);
552  var_component += var_vec_dim;
553  }
554 
555  // Prepare a global solution, a serialized mesh, and a MeshFunction
556  // of the coarse system, if we need them for fine-system integration
557  std::unique_ptr<MeshFunction> coarse_values;
558  std::unique_ptr<NumericVector<Number>> comparison_soln =
561  serial(const_cast<MeshBase&>(_equation_systems.get_mesh()),
564  {
565  const System & comparison_system
566  = _equation_systems.get_system(sys_name);
567 
568  std::vector<Number> global_soln;
569  comparison_system.update_global_solution(global_soln);
570  comparison_soln->init(comparison_system.solution->size(), true, SERIAL);
571  (*comparison_soln) = global_soln;
572 
573  coarse_values = std::make_unique<MeshFunction>
575  *comparison_soln,
576  comparison_system.get_dof_map(),
577  comparison_system.variable_number(unknown_name));
578  coarse_values->init();
579  }
580 
581  // Grab which element dimensions are present in the mesh
582  const std::set<unsigned char> & elem_dims = mesh.elem_dimensions();
583 
584  // Initialize any functors we're going to use
585  for (auto & ev : _exact_values)
586  if (ev)
587  {
588  ev->init();
589  ev->init_context(context);
590  }
591 
592  for (auto & ed : _exact_derivs)
593  if (ed)
594  {
595  ed->init();
596  ed->init_context(context);
597  }
598 
599  for (auto & eh : _exact_hessians)
600  if (eh)
601  {
602  eh->init();
603  eh->init_context(context);
604  }
605 
606  // If we have *no* functors we intend to use (because we're using a
607  // fine system, or because our exact solution is zero and we're just
608  // computing norms in an outdated way) then let our FE objects know
609  // we don't actually need anything from them, so they don't think
610  // we've just invoked them in a deprecated "compute everything"
611  // fashion.
612  if (_exact_values.empty() && _exact_derivs.empty() &&
613  _exact_hessians.empty())
614  for (auto dim : elem_dims)
615  for (auto v : make_range(computed_system.n_vars()))
616  {
617  FEAbstract * fe;
618  context.get_element_fe(v, fe, dim);
619  fe->get_nothing();
620  }
621 
622  // Get a reference to the dofmap and mesh for that system
623  const DofMap & computed_dof_map = computed_system.get_dof_map();
624 
625  // Zero the error before summation
626  // 0 - sum of square of function error (L2)
627  // 1 - sum of square of gradient error (H1 semi)
628  // 2 - sum of square of Hessian error (H2 semi)
629  // 3 - sum of sqrt(square of function error) (L1)
630  // 4 - max of sqrt(square of function error) (Linfty)
631  // 5 - sum of square of curl error (HCurl semi)
632  // 6 - sum of square of div error (HDiv semi)
633  error_vals = std::vector<Real>(7, 0.);
634 
635  // Construct Quadrature rule based on default quadrature order
636  const FEType & fe_type = computed_dof_map.variable_type(var);
637  const auto field_type = FEInterface::field_type(fe_type);
638 
639  unsigned int n_vec_dim = FEInterface::n_vec_dim( mesh, fe_type );
640 
641  // FIXME: MeshFunction needs to be updated to support vector-valued
642  // elements before we can use a reference solution.
643  if ((n_vec_dim > 1) && _equation_systems_fine)
644  {
645  libMesh::err << "Error calculation using reference solution not yet\n"
646  << "supported for vector-valued elements."
647  << std::endl;
648  libmesh_not_implemented();
649  }
650 
651 
652  // Allow space for dims 0-3, even if we don't use them all
653  std::vector<std::unique_ptr<FEGenericBase<OutputShape>>> fe_ptrs(4);
654  std::vector<std::unique_ptr<QBase>> q_rules(4);
655 
656  // Prepare finite elements for each dimension present in the mesh
657  for (const auto dim : elem_dims)
658  {
659  // Build a quadrature rule.
660  q_rules[dim] = fe_type.default_quadrature_rule (dim, _extra_order);
661 
662  // Disallow rules with negative weights. That will use more
663  // quadrature points, but we're going to be taking square roots
664  // of element integral results here!
665  q_rules[dim]->allow_rules_with_negative_weights = false;
666 
667  // Construct finite element object
668  fe_ptrs[dim] = FEGenericBase<OutputShape>::build(dim, fe_type);
669 
670  // Attach quadrature rule to FE object
671  fe_ptrs[dim]->attach_quadrature_rule (q_rules[dim].get());
672  }
673 
674  // The global degree of freedom indices associated
675  // with the local degrees of freedom.
676  std::vector<dof_id_type> dof_indices;
677 
678 
679  //
680  // Begin the loop over the elements
681  //
682  // TODO: this ought to be threaded (and using subordinate
683  // MeshFunction objects in each thread rather than a single
684  // master)
685  for (const auto & elem : mesh.active_local_element_ptr_range())
686  {
687  // Skip this element if it is in a subdomain excluded by the user.
688  const subdomain_id_type elem_subid = elem->subdomain_id();
689  if (_excluded_subdomains.count(elem_subid))
690  continue;
691 
692  // The spatial dimension of the current Elem. FEs and other data
693  // are indexed on dim.
694  const unsigned int dim = elem->dim();
695 
696  // If the variable is not active on this subdomain, don't bother
697  if (!computed_system.variable(var).active_on_subdomain(elem_subid))
698  continue;
699 
700  /* If the variable is active, then we're going to restrict the
701  MeshFunction evaluations to the current element subdomain.
702  This is for cases such as mixed dimension meshes where we want
703  to restrict the calculation to one particular domain. */
704  std::set<subdomain_id_type> subdomain_id;
705  subdomain_id.insert(elem_subid);
706 
707  FEGenericBase<OutputShape> * fe = fe_ptrs[dim].get();
708  QBase * qrule = q_rules[dim].get();
709  libmesh_assert(fe);
710  libmesh_assert(qrule);
711 
712  // The Jacobian*weight at the quadrature points.
713  const std::vector<Real> & JxW = fe->get_JxW();
714 
715  // The value of the shape functions at the quadrature points
716  // i.e. phi(i) = phi_values[i][qp]
717  const std::vector<std::vector<OutputShape>> & phi_values = fe->get_phi();
718 
719  // The value of the shape function gradients at the quadrature points
720  const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputGradient>> &
721  dphi_values = fe->get_dphi();
722 
723  // The value of the shape function curls at the quadrature points
724  // Only computed for vector-valued elements
725  const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputShape>> * curl_values = nullptr;
726 
727  // The value of the shape function divergences at the quadrature points
728  // Only computed for vector-valued elements
729  const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputDivergence>> * div_values = nullptr;
730 
731  if (field_type == TYPE_VECTOR)
732  {
733  curl_values = &fe->get_curl_phi();
734  div_values = &fe->get_div_phi();
735  }
736 
737 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
738  // The value of the shape function second derivatives at the quadrature points
739  // Not computed for vector-valued elements
740  const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputTensor>> *
741  d2phi_values = nullptr;
742 
743  if (field_type != TYPE_VECTOR)
744  d2phi_values = &fe->get_d2phi();
745 #endif
746 
747  // The XYZ locations (in physical space) of the quadrature points
748  const std::vector<Point> & q_point = fe->get_xyz();
749 
750  // reinitialize the element-specific data
751  // for the current element
752  fe->reinit (elem);
753 
754  context.pre_fe_reinit(computed_system, elem);
755  context.elem_fe_reinit();
756 
757  // Get the local to global degree of freedom maps
758  computed_dof_map.dof_indices (elem, dof_indices, var);
759 
760  // The number of quadrature points
761  const unsigned int n_qp = qrule->n_points();
762 
763  // The number of shape functions
764  const unsigned int n_sf =
765  cast_int<unsigned int>(dof_indices.size());
766 
767  //
768  // Begin the loop over the Quadrature points.
769  //
770  for (unsigned int qp=0; qp<n_qp; qp++)
771  {
772  // Real u_h = 0.;
773  // RealGradient grad_u_h;
774 
776 
778 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
780 #endif
781  typename FEGenericBase<OutputShape>::OutputNumber curl_u_h(0.0);
783 
784  // Compute solution values at the current
785  // quadrature point. This requires a sum
786  // over all the shape functions evaluated
787  // at the quadrature point.
788  for (unsigned int i=0; i<n_sf; i++)
789  {
790  // Values from current solution.
791  u_h += phi_values[i][qp]*computed_system.current_solution (dof_indices[i]);
792  grad_u_h += dphi_values[i][qp]*computed_system.current_solution (dof_indices[i]);
793  if (field_type == TYPE_VECTOR)
794  {
795  curl_u_h += (*curl_values)[i][qp]*computed_system.current_solution (dof_indices[i]);
796  div_u_h += (*div_values)[i][qp]*computed_system.current_solution (dof_indices[i]);
797  }
798  else
799  {
800 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
801  grad2_u_h += (*d2phi_values)[i][qp]*computed_system.current_solution (dof_indices[i]);
802 #endif
803  }
804  }
805 
806  // Compute the value of the error at this quadrature point
807  typename FEGenericBase<OutputShape>::OutputNumber exact_val(0);
808  RawAccessor<typename FEGenericBase<OutputShape>::OutputNumber> exact_val_accessor( exact_val, n_vec_dim );
809  if (_exact_values.size() > sys_num && _exact_values[sys_num])
810  {
811  for (unsigned int c = 0; c < n_vec_dim; c++)
812  exact_val_accessor(c) =
813  _exact_values[sys_num]->
814  component(context, var_component+c, q_point[qp], time);
815  }
816  else if (_equation_systems_fine)
817  {
818  // FIXME: Needs to be updated for vector-valued elements
819  DenseVector<Number> output(1);
820  (*coarse_values)(q_point[qp],time,output,&subdomain_id);
821  exact_val = output(0);
822  }
823  const typename FEGenericBase<OutputShape>::OutputNumber val_error = u_h - exact_val;
824 
825  // Add the squares of the error to each contribution
826  Real error_sq = TensorTools::norm_sq(val_error);
827  error_vals[0] += JxW[qp]*error_sq;
828 
829  Real norm = sqrt(error_sq);
830  error_vals[3] += JxW[qp]*norm;
831 
832  if (error_vals[4]<norm) { error_vals[4] = norm; }
833 
834  // Compute the value of the error in the gradient at this
835  // quadrature point
838  if (_exact_derivs.size() > sys_num && _exact_derivs[sys_num])
839  {
840  for (unsigned int c = 0; c < n_vec_dim; c++)
841  for (unsigned int d = 0; d < LIBMESH_DIM; d++)
842  exact_grad_accessor(d + c*LIBMESH_DIM) =
843  _exact_derivs[sys_num]->
844  component(context, var_component+c, q_point[qp], time)(d);
845  }
846  else if (_equation_systems_fine)
847  {
848  // FIXME: Needs to be updated for vector-valued elements
849  std::vector<Gradient> output(1);
850  coarse_values->gradient(q_point[qp],time,output,&subdomain_id);
851  exact_grad = output[0];
852  }
853 
854  const typename FEGenericBase<OutputShape>::OutputNumberGradient grad_error = grad_u_h - exact_grad;
855 
856  error_vals[1] += JxW[qp]*grad_error.norm_sq();
857 
858 
859  if (field_type == TYPE_VECTOR)
860  {
861  // Compute the value of the error in the curl at this
862  // quadrature point
863  typename FEGenericBase<OutputShape>::OutputNumber exact_curl(0.0);
864  if (_exact_derivs.size() > sys_num && _exact_derivs[sys_num])
865  {
866  exact_curl = TensorTools::curl_from_grad( exact_grad );
867  }
868  else if (_equation_systems_fine)
869  {
870  // FIXME: Need to implement curl for MeshFunction and support reference
871  // solution for vector-valued elements
872  }
873 
874  const typename FEGenericBase<OutputShape>::OutputNumber curl_error = curl_u_h - exact_curl;
875 
876  error_vals[5] += JxW[qp]*TensorTools::norm_sq(curl_error);
877 
878  // Compute the value of the error in the divergence at this
879  // quadrature point
881  if (_exact_derivs.size() > sys_num && _exact_derivs[sys_num])
882  {
883  exact_div = TensorTools::div_from_grad( exact_grad );
884  }
885  else if (_equation_systems_fine)
886  {
887  // FIXME: Need to implement div for MeshFunction and support reference
888  // solution for vector-valued elements
889  }
890 
891  const typename FEGenericBase<OutputShape>::OutputNumberDivergence div_error = div_u_h - exact_div;
892 
893  error_vals[6] += JxW[qp]*TensorTools::norm_sq(div_error);
894  }
895 
896 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
897  // Compute the value of the error in the hessian at this
898  // quadrature point
901  if (_exact_hessians.size() > sys_num && _exact_hessians[sys_num])
902  {
903  //FIXME: This needs to be implemented to support rank 3 tensors
904  // which can't happen until type_n_tensor is fully implemented
905  // and a RawAccessor<TypeNTensor> is fully implemented
906  if (field_type == TYPE_VECTOR)
907  libmesh_not_implemented();
908 
909  for (unsigned int c = 0; c < n_vec_dim; c++)
910  for (unsigned int d = 0; d < dim; d++)
911  for (unsigned int e =0; e < dim; e++)
912  exact_hess_accessor(d + e*dim + c*dim*dim) =
913  _exact_hessians[sys_num]->
914  component(context, var_component+c, q_point[qp], time)(d,e);
915 
916  // FIXME: operator- is not currently implemented for TypeNTensor
917  const typename FEGenericBase<OutputShape>::OutputNumberTensor grad2_error = grad2_u_h - exact_hess;
918  error_vals[2] += JxW[qp]*grad2_error.norm_sq();
919  }
920  else if (_equation_systems_fine)
921  {
922  // FIXME: Needs to be updated for vector-valued elements
923  std::vector<Tensor> output(1);
924  coarse_values->hessian(q_point[qp],time,output,&subdomain_id);
925  exact_hess = output[0];
926 
927  // FIXME: operator- is not currently implemented for TypeNTensor
928  const typename FEGenericBase<OutputShape>::OutputNumberTensor grad2_error = grad2_u_h - exact_hess;
929  error_vals[2] += JxW[qp]*grad2_error.norm_sq();
930  }
931 #endif
932 
933  } // end qp loop
934  } // end element loop
935 
936  // Add up the error values on all processors, except for the L-infty
937  // norm, for which the maximum is computed.
938  Real l_infty_norm = error_vals[4];
939  communicator.max(l_infty_norm);
940  communicator.sum(error_vals);
941  error_vals[4] = l_infty_norm;
942 }
943 
944 // Explicit instantiations of templated member functions
945 template LIBMESH_EXPORT void ExactSolution::_compute_error<Real>(std::string_view, std::string_view, std::vector<Real> &);
946 template LIBMESH_EXPORT void ExactSolution::_compute_error<RealGradient>(std::string_view, std::string_view, std::vector<Real> &);
947 
948 } // namespace libMesh
std::map< std::string, std::vector< Real >, std::less<> > SystemErrorMap
Data structure which stores the errors: ||e|| = ||u - u_h|| ||grad(e)|| = ||grad(u) - grad(u_h)|| for...
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:196
OStreamProxy err
This class handles the computation of the L2 and/or H1 error for the Systems in the EquationSystems o...
Real l_inf_error(std::string_view sys_name, std::string_view unknown_name)
This is the EquationSystems class.
virtual_for_inffe const std::vector< std::vector< OutputDivergence > > & get_div_phi() const
Definition: fe_base.h:261
void update_global_solution(std::vector< Number > &global_soln) const
Fill the input vector global_soln so that it contains the global solution on all processors.
Definition: system.C:745
unsigned int n_systems() const
Real h2_error(std::string_view sys_name, std::string_view unknown_name)
const Variable & variable(unsigned int var) const
Return a constant reference to Variable var.
Definition: system.h:2458
TensorTools::DecrementRank< OutputNumber >::type OutputNumberDivergence
Definition: fe_base.h:126
Number div_from_grad(const VectorValue< Number > &grad)
Dummy. Divergence of a scalar not defined, but is needed for ExactSolution to compile.
Definition: tensor_tools.C:54
Real l1_error(std::string_view sys_name, std::string_view unknown_name)
virtual void pre_fe_reinit(const System &, const Elem *e)
Reinitializes local data vectors/matrices on the current geometric element.
Definition: fem_context.C:1683
Real hdiv_error(std::string_view sys_name, std::string_view unknown_name)
const EquationSystems & _equation_systems
Constant reference to the EquationSystems object used for the simulation.
bool has_system(std::string_view name) const
std::map< std::string, SystemErrorMap, std::less<> > _errors
A map of SystemErrorMaps, which contains entries for each system in the EquationSystems object...
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition: dof_map.C:2164
ExactSolution(const EquationSystems &es)
Constructor.
unsigned int dim
void attach_exact_values(const std::vector< FunctionBase< Number > *> &f)
Clone and attach arbitrary functors which compute the exact values of the EquationSystems&#39; solutions ...
int _extra_order
Extra order to use for quadrature rule.
const FEType & variable_type(const unsigned int c) const
Definition: dof_map.h:2220
MeshBase & mesh
static FEFieldType field_type(const FEType &fe_type)
FEMNormType
defines an enum for norms defined on vectors of finite element coefficients
Real hcurl_error(std::string_view sys_name, std::string_view unknown_name)
const Parallel::Communicator & comm() const
std::vector< Real > & _check_inputs(std::string_view sys_name, std::string_view unknown_name)
This function is responsible for checking the validity of the sys_name and unknown_name inputs...
This class defines a vector in LIBMESH_DIM dimensional Real or Complex space.
std::vector< std::unique_ptr< FEMFunctionBase< Number > > > _exact_values
User-provided functors which compute the exact value of the solution for each system.
The libMesh namespace provides an interface to certain functionality in the library.
void attach_exact_derivs(const std::vector< FunctionBase< Gradient > *> &g)
Clone and attach arbitrary functors which compute the exact gradients of the EquationSystems&#39; solutio...
const T_sys & get_system(std::string_view name) const
const MeshBase & get_mesh() const
Definition: system.h:2358
const EquationSystems * _equation_systems_fine
Constant pointer to the EquationSystems object containing the fine grid solution. ...
std::vector< std::unique_ptr< FEMFunctionBase< Gradient > > > _exact_derivs
User-provided functors which compute the exact derivative of the solution for each system...
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
virtual void elem_fe_reinit(const std::vector< Point > *const pts=nullptr)
Reinitializes interior FE objects on the current geometric element.
Definition: fem_context.C:1477
Number current_solution(const dof_id_type global_dof_number) const
Definition: system.C:165
Number fptr(const Point &p, const Parameters &, const std::string &libmesh_dbg_var(sys_name), const std::string &unknown_name)
Definition: projection.C:80
unsigned int variable_number(std::string_view var) const
Definition: system.C:1609
This class provides a wrapper with which to evaluate a (libMesh-style) function pointer in a Function...
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:179
std::unique_ptr< QBase > default_quadrature_rule(const unsigned int dim, const int extraorder=0) const
Definition: fe_type.C:34
const std::vector< std::vector< OutputGradient > > & get_dphi() const
Definition: fe_base.h:230
std::set< subdomain_id_type > _excluded_subdomains
Elements in a subdomain from this set are skipped during the error computation.
unsigned int number() const
Definition: system.h:2350
auto norm_sq() const -> decltype(std::norm(T()))
Definition: type_vector.h:926
void attach_exact_hessians(std::vector< FunctionBase< Tensor > *> h)
Clone and attach arbitrary functors which compute the exact second derivatives of the EquationSystems...
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition: system.h:96
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(...
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition: system.h:1593
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
libmesh_assert(ctx)
virtual_for_inffe const std::vector< Real > & get_JxW() const
Definition: fe_abstract.h:303
This class provides all data required for a physics package (e.g.
Definition: fem_context.h:62
virtual void reinit(const Elem *elem, const std::vector< Point > *const pts=nullptr, const std::vector< Real > *const weights=nullptr)=0
This is at the core of this class.
const std::string & variable_name(const unsigned int i) const
Definition: system.h:2478
unsigned int n_points() const
Definition: quadrature.h:131
virtual_for_inffe const std::vector< Point > & get_xyz() const
Definition: fe_abstract.h:280
const std::vector< std::vector< OutputTensor > > & get_d2phi() const
Definition: fe_base.h:319
bool active_on_subdomain(subdomain_id_type sid) const
Definition: variable.h:167
Real l2_error(std::string_view sys_name, std::string_view unknown_name)
auto norm(const T &a) -> decltype(std::abs(a))
Definition: tensor_tools.h:74
TensorTools::MakeNumber< OutputShape >::type OutputNumber
Definition: fe_base.h:123
void get_nothing() const
Definition: fe_abstract.h:269
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...
static unsigned int n_vec_dim(const MeshBase &mesh, const FEType &fe_type)
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 _compute_error(std::string_view sys_name, std::string_view unknown_name, std::vector< Real > &error_vals)
This function computes the error (in the solution and its first derivative) for a single unknown in a...
const FEType & variable_type(const unsigned int i) const
Definition: system.h:2508
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
DIE A HORRIBLE DEATH HERE typedef MPI_Comm communicator
Temporarily serialize a DistributedMesh for non-distributed-mesh capable code paths.
auto norm_sq(const T &a) -> decltype(std::norm(a))
Definition: tensor_tools.h:104
void set_excluded_subdomains(const std::set< subdomain_id_type > &excluded)
The user can indicate that elements in certain subdomains should be excluded from the error calculati...
const MeshBase & get_mesh() const
Gradient gptr(const Point &p, const Parameters &, const std::string &libmesh_dbg_var(sys_name), const std::string &unknown_name)
Definition: projection.C:95
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition: int_range.h:140
static std::unique_ptr< NumericVector< T > > build(const Parallel::Communicator &comm, SolverPackage solver_package=libMesh::default_solver_package(), ParallelType parallel_type=AUTOMATIC)
Builds a NumericVector on the processors in communicator comm using the linear solver package specifi...
Parameters parameters
Data structure holding arbitrary parameters.
void get_element_fe(unsigned int var, FEGenericBase< OutputShape > *&fe) const
Accessor for interior finite element object for variable var for the largest dimension in the mesh...
Definition: fem_context.h:277
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...
const std::string & name() const
Definition: system.h:2342
void attach_reference_solution(const EquationSystems *es_fine)
Attach function similar to system.h which allows the user to attach a second EquationSystems object w...
unsigned int n_vars() const
Definition: system.h:2430
This class forms the foundation from which generic finite elements may be derived.
Definition: fe_abstract.h:99
Real h1_error(std::string_view sys_name, std::string_view unknown_name)
virtual std::unique_ptr< FEMFunctionBase< Output > > clone() const =0
const DofMap & get_dof_map() const
Definition: system.h:2374
std::vector< std::unique_ptr< FEMFunctionBase< Tensor > > > _exact_hessians
User-provided functors which compute the exact hessians of the solution for each system.
The QBase class provides the basic functionality from which various quadrature rules can be derived...
Definition: quadrature.h:61
This class forms the foundation from which generic finite elements may be derived.
This class provides single index access to FieldType (i.e.
Definition: raw_accessor.h:93
Number curl_from_grad(const VectorValue< Number > &)
Definition: tensor_tools.C:28
virtual_for_inffe const std::vector< std::vector< OutputShape > > & get_curl_phi() const
Definition: fe_base.h:252
const std::vector< std::vector< OutputShape > > & get_phi() const
Definition: fe_base.h:207
Real error_norm(std::string_view sys_name, std::string_view unknown_name, const FEMNormType &norm)