libMesh
Loading...
Searching...
No Matches
exact_solution.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 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
43namespace 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
81set_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
93 _exact_derivs.clear();
94 _exact_hessians.clear();
95}
96
97
98void 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.
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
139void 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
150void 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
161void 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.
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
202void 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
213void 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
224void 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.
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
265void 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
276void 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
287std::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
298void 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
335Real 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
404Real 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
424Real 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
444Real 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
464Real 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
481Real 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
488Real 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
496Real 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
518template<typename OutputShape>
519void 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.
527 const Parallel::Communicator & communicator(_equation_systems.comm());
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 {
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 {
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
945template LIBMESH_EXPORT void ExactSolution::_compute_error<Real>(std::string_view, std::string_view, std::vector<Real> &);
946template LIBMESH_EXPORT void ExactSolution::_compute_error<RealGradient>(std::string_view, std::string_view, std::vector<Real> &);
947
948} // namespace libMesh
unsigned int dim
Defines a dense vector for use in Finite Element-type computations.
This class handles the numbering of degrees of freedom on a mesh.
Definition dof_map.h:181
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition dof_map.C:2201
const FEType & variable_type(const unsigned int i) const
Definition dof_map.h:2388
This is the EquationSystems class.
unsigned int n_systems() const
const MeshBase & get_mesh() const
Parameters parameters
Data structure holding arbitrary parameters.
bool has_system(std::string_view name) const
virtual void clear()
Restores the data structure to a pristine state.
const T_sys & get_system(std::string_view name) const
This class handles the computation of the L2 and/or H1 error for the Systems in the EquationSystems o...
std::set< subdomain_id_type > _excluded_subdomains
Elements in a subdomain from this set are skipped during the error computation.
Real l2_error(std::string_view sys_name, std::string_view unknown_name)
Real h1_error(std::string_view sys_name, std::string_view unknown_name)
Real hcurl_error(std::string_view sys_name, std::string_view unknown_name)
Real h2_error(std::string_view sys_name, std::string_view unknown_name)
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...
Real error_norm(std::string_view sys_name, std::string_view unknown_name, const FEMNormType &norm)
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 attach_exact_values(const std::vector< FunctionBase< Number > * > &f)
Clone and attach arbitrary functors which compute the exact values of the EquationSystems' solutions ...
void attach_exact_hessians(std::vector< FunctionBase< Tensor > * > h)
Clone and attach arbitrary functors which compute the exact second derivatives of the EquationSystems...
std::map< std::string, SystemErrorMap, std::less<> > _errors
A map of SystemErrorMaps, which contains entries for each system in the EquationSystems object.
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...
std::vector< std::unique_ptr< FEMFunctionBase< Number > > > _exact_values
User-provided functors which compute the exact value of the solution for each system.
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...
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...
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...
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...
const EquationSystems & _equation_systems
Constant reference to the EquationSystems object used for the simulation.
std::vector< std::unique_ptr< FEMFunctionBase< Gradient > > > _exact_derivs
User-provided functors which compute the exact derivative of the solution for each system.
Real hdiv_error(std::string_view sys_name, std::string_view unknown_name)
Real l1_error(std::string_view sys_name, std::string_view unknown_name)
std::vector< std::unique_ptr< FEMFunctionBase< Tensor > > > _exact_hessians
User-provided functors which compute the exact hessians of the solution for each system.
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(...
Real l_inf_error(std::string_view sys_name, std::string_view unknown_name)
ExactSolution(const EquationSystems &es)
Constructor.
void attach_exact_derivs(const std::vector< FunctionBase< Gradient > * > &g)
Clone and attach arbitrary functors which compute the exact gradients of the EquationSystems' solutio...
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.
int _extra_order
Extra order to use for quadrature rule.
const EquationSystems * _equation_systems_fine
Constant pointer to the EquationSystems object containing the fine grid solution.
This class forms the foundation from which generic finite elements may be derived.
void get_nothing() const
virtual_for_inffe const std::vector< Real > & get_JxW() const
virtual_for_inffe const std::vector< Point > & get_xyz() const
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.
This class forms the foundation from which generic finite elements may be derived.
Definition fe_base.h:86
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
virtual_for_inffe const std::vector< std::vector< OutputDivergence > > & get_div_phi() const
Definition fe_base.h:261
const std::vector< std::vector< OutputShape > > & get_phi() const
Definition fe_base.h:207
const std::vector< std::vector< OutputGradient > > & get_dphi() const
Definition fe_base.h:230
TensorTools::MakeNumber< OutputShape >::type OutputNumber
Definition fe_base.h:123
const std::vector< std::vector< OutputTensor > > & get_d2phi() const
Definition fe_base.h:319
virtual_for_inffe const std::vector< std::vector< OutputShape > > & get_curl_phi() const
Definition fe_base.h:252
TensorTools::DecrementRank< OutputNumber >::type OutputNumberDivergence
Definition fe_base.h:126
static unsigned int n_vec_dim(const MeshBase &mesh, const FEType &fe_type)
static FEFieldType field_type(const FEType &fe_type)
This class provides all data required for a physics package (e.g.
Definition fem_context.h:63
virtual void pre_fe_reinit(const System &, const Elem *e)
Reinitializes local data vectors/matrices on the current geometric element.
virtual void elem_fe_reinit(const std::vector< Point > *const pts=nullptr)
Reinitializes interior FE objects on the current geometric element.
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.
FEMFunctionBase is a base class from which users can derive in order to define "function-like" object...
virtual std::unique_ptr< FEMFunctionBase< Output > > clone() const =0
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition fe_type.h:197
std::unique_ptr< QBase > default_quadrature_rule(const unsigned int dim, const int extraorder=0) const
Definition fe_type.C:34
Base class for functors that can be evaluated at a point and (optionally) time.
This is the MeshBase class.
Definition mesh_base.h:81
Temporarily serialize a DistributedMesh for non-distributed-mesh capable code paths.
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...
const Parallel::Communicator & comm() const
The QBase class provides the basic functionality from which various quadrature rules can be derived.
Definition quadrature.h:62
unsigned int n_points() const
Definition quadrature.h:131
This class provides single index access to FieldType (i.e.
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition system.h:100
const std::string & name() const
Definition system.h:2385
Number current_solution(const dof_id_type global_dof_number) const
Definition system.C:162
const Variable & variable(unsigned int var) const
Return a constant reference to Variable var.
Definition system.C:2704
const FEType & variable_type(const unsigned int i) const
Definition system.C:2721
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition system.h:1655
const std::string & variable_name(const unsigned int i) const
Definition system.C:2679
unsigned int variable_number(std::string_view var) const
Definition system.C:1398
bool has_variable(std::string_view var) const
Definition system.C:1393
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:733
unsigned int n_vars() const
Definition system.C:2674
const DofMap & get_dof_map() const
Definition system.h:2417
unsigned int number() const
Definition system.h:2393
const MeshBase & get_mesh() const
Definition system.h:2401
auto norm_sq() const
bool active_on_subdomain(subdomain_id_type sid) const
Definition variable.h:167
This class defines a vector in LIBMESH_DIM dimensional Real or Complex space.
This class provides a wrapper with which to evaluate a (libMesh-style) function pointer in a Function...
MeshBase & mesh
Gradient exact_grad(const Point &, const Parameters &, const std::string &, const std::string &)
Definition mysystems.h:25
Number curl_from_grad(const VectorValue< Number > &)
auto norm_sq(const T &a)
Number div_from_grad(const VectorValue< Number > &grad)
Dummy. Divergence of a scalar not defined, but is needed for ExactSolution to compile.
The libMesh namespace provides an interface to certain functionality in the library.
OStreamProxy err
libmesh_assert(ctx)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
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:176
Gradient gptr(const Point &p, const Parameters &, const std::string &libmesh_dbg_var(sys_name), const std::string &unknown_name)
Definition projection.C:96
Number fptr(const Point &p, const Parameters &, const std::string &libmesh_dbg_var(sys_name), const std::string &unknown_name)
Definition projection.C:81