libMesh
Loading...
Searching...
No Matches
Public Types | Public Member Functions | Public Attributes | Protected Member Functions | Protected Attributes | List of all members
libMesh::JumpErrorEstimator Class Referenceabstract

This abstract base class implements utility functions for error estimators which are based on integrated jumps between elements. More...

#include <jump_error_estimator.h>

Inheritance diagram for libMesh::JumpErrorEstimator:
[legend]

Public Types

typedef std::map< std::pair< const System *, unsigned int >, std::unique_ptr< ErrorVector > > ErrorMap
 When calculating many error vectors at once, we need a data structure to hold them all.
 

Public Member Functions

 JumpErrorEstimator ()
 Constructor.
 
 JumpErrorEstimator (const JumpErrorEstimator &)=delete
 This class cannot be (default) copy constructed/assigned because it has unique_ptr members.
 
JumpErrorEstimatoroperator= (const JumpErrorEstimator &)=delete
 
 JumpErrorEstimator (JumpErrorEstimator &&)=default
 Defaulted move ctor, move assignment operator, and destructor.
 
JumpErrorEstimatoroperator= (JumpErrorEstimator &&)=default
 
virtual ~JumpErrorEstimator ()=default
 
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.
 
virtual void estimate_errors (const EquationSystems &equation_systems, ErrorVector &error_per_cell, const std::map< const System *, SystemNorm > &error_norms, const std::map< const System *, const NumericVector< Number > * > *solution_vectors=nullptr, bool estimate_parent_error=false)
 This virtual function can be redefined in derived classes, but by default computes the sum of the error_per_cell for each system in the equation_systems.
 
virtual void estimate_errors (const EquationSystems &equation_systems, ErrorMap &errors_per_cell, const std::map< const System *, const NumericVector< Number > * > *solution_vectors=nullptr, bool estimate_parent_error=false)
 This virtual function can be redefined in derived classes, but by default it calls estimate_error repeatedly to calculate the requested error vectors.
 
virtual ErrorEstimatorType type () const =0
 

Public Attributes

bool scale_by_n_flux_faces
 This boolean flag allows you to scale the error indicator result for each element by the number of "flux faces" the element actually has.
 
bool use_unweighted_quadrature_rules
 This boolean flag allows you to use "unweighted" quadrature rules (sized to exactly integrate unweighted shape functions in master element space) rather than "default" quadrature rules (sized to exactly integrate polynomials of one higher degree than mass matrix terms).
 
bool integrate_slits
 A boolean flag, by default false, to be set to true if integrations should be performed on "slits" where two elements' faces overlap even if those elements are not connected by neighbor links.
 
SystemNorm error_norm
 When estimating the error in a single system, the error_norm is used to control the scaling and norm choice for each variable.
 

Protected Member Functions

void reinit_sides ()
 A utility function to reinit the finite element data on elements sharing a side.
 
float coarse_n_flux_faces_increment ()
 A utility function to correctly increase n_flux_faces for the coarse element.
 
virtual void init_context (FEMContext &c)
 An initialization function, to give derived classes a chance to request specific data from the FE objects.
 
virtual void internal_side_integration ()=0
 The function, to be implemented by derived classes, which calculates an error term on an internal side.
 
virtual bool boundary_side_integration ()
 The function, to be implemented by derived classes, which calculates an error term on a boundary side.
 
void reduce_error (std::vector< ErrorVectorReal > &error_per_cell, const Parallel::Communicator &comm) const
 This method takes the local error contributions in error_per_cell from each processor and combines them to get the global error vector.
 

Protected Attributes

bool integrate_boundary_sides
 A boolean flag, by default false, to be set to true if integrations with boundary_side_integration() should be performed.
 
std::unique_ptr< FEMContextfine_context
 Context objects for integrating on the fine and coarse elements sharing a face.
 
std::unique_ptr< FEMContextcoarse_context
 
Real fine_error
 The fine and coarse error values to be set by each side_integration();.
 
Real coarse_error
 
unsigned int var
 The variable number currently being evaluated.
 

Detailed Description

This abstract base class implements utility functions for error estimators which are based on integrated jumps between elements.

Author
Roy H. Stogner
Date
2006

Definition at line 48 of file jump_error_estimator.h.

Member Typedef Documentation

◆ ErrorMap

typedef std::map<std::pair<const System *, unsigned int>, std::unique_ptr<ErrorVector> > libMesh::ErrorEstimator::ErrorMap
inherited

When calculating many error vectors at once, we need a data structure to hold them all.

Definition at line 121 of file error_estimator.h.

Constructor & Destructor Documentation

◆ JumpErrorEstimator() [1/3]

libMesh::JumpErrorEstimator::JumpErrorEstimator ( )
inline

Constructor.

Definition at line 55 of file jump_error_estimator.h.

59 integrate_slits(false),
63 fine_error(0),
64 coarse_error(0) {}
ErrorEstimator()=default
Constructor.
bool integrate_slits
A boolean flag, by default false, to be set to true if integrations should be performed on "slits" wh...
bool use_unweighted_quadrature_rules
This boolean flag allows you to use "unweighted" quadrature rules (sized to exactly integrate unweigh...
Real fine_error
The fine and coarse error values to be set by each side_integration();.
bool scale_by_n_flux_faces
This boolean flag allows you to scale the error indicator result for each element by the number of "f...
bool integrate_boundary_sides
A boolean flag, by default false, to be set to true if integrations with boundary_side_integration() ...
std::unique_ptr< FEMContext > coarse_context
std::unique_ptr< FEMContext > fine_context
Context objects for integrating on the fine and coarse elements sharing a face.

◆ JumpErrorEstimator() [2/3]

libMesh::JumpErrorEstimator::JumpErrorEstimator ( const JumpErrorEstimator )
delete

This class cannot be (default) copy constructed/assigned because it has unique_ptr members.

Explicitly deleting these functions is the best way to document this fact.

◆ JumpErrorEstimator() [3/3]

libMesh::JumpErrorEstimator::JumpErrorEstimator ( JumpErrorEstimator &&  )
default

Defaulted move ctor, move assignment operator, and destructor.

◆ ~JumpErrorEstimator()

virtual libMesh::JumpErrorEstimator::~JumpErrorEstimator ( )
virtualdefault

Member Function Documentation

◆ boundary_side_integration()

virtual bool libMesh::JumpErrorEstimator::boundary_side_integration ( )
inlineprotectedvirtual

The function, to be implemented by derived classes, which calculates an error term on a boundary side.

Returns
true if the flux bc function is in fact defined on the current side.

Reimplemented in libMesh::DiscontinuityMeasure, and libMesh::KellyErrorEstimator.

Definition at line 163 of file jump_error_estimator.h.

163{ return false; }

Referenced by estimate_error().

◆ coarse_n_flux_faces_increment()

float libMesh::JumpErrorEstimator::coarse_n_flux_faces_increment ( )
protected

A utility function to correctly increase n_flux_faces for the coarse element.

Definition at line 592 of file jump_error_estimator.C.

593{
594 // Keep track of the number of internal flux sides found on each
595 // element
596 unsigned short dim = coarse_context->get_elem().dim();
597
598 const unsigned int divisor =
599 1 << (dim-1)*(fine_context->get_elem().level() -
600 coarse_context->get_elem().level());
601
602 // With a difference of n levels between fine and coarse elements,
603 // we compute a fractional flux face for the coarse element by adding:
604 // 1/2^n in 2D
605 // 1/4^n in 3D
606 // each time. This code will get hit 2^n times in 2D and 4^n
607 // times in 3D so that the final flux face count for the coarse
608 // element will be an integer value.
609
610 return 1.0f / static_cast<float>(divisor);
611}
unsigned int dim

References coarse_context, dim, and fine_context.

Referenced by estimate_error().

◆ estimate_error()

void libMesh::JumpErrorEstimator::estimate_error ( const System system,
ErrorVector error_per_cell,
const NumericVector< Number > *  solution_vector = nullptr,
bool  estimate_parent_error = false 
)
overridevirtual

This function uses the derived class's jump error estimate formula to estimate the error on each cell.

The estimated error is output in the vector error_per_cell

Conventions for assigning the direction of the normal:

  • e & f are global element ids

Case (1.) Elements are at the same level, e<f Compute the flux jump on the face and add it as a contribution to error_per_cell[e] and error_per_cell[f]


| | |

f
e —> n

Case (2.) The neighbor is at a higher level. Compute the flux jump on e's face and add it as a contribution to error_per_cell[e] and error_per_cell[f]


| | | | | | e |—> n | | | | | |--------—| f |


Implements libMesh::ErrorEstimator.

Definition at line 56 of file jump_error_estimator.C.

60{
61 LOG_SCOPE("estimate_error()", "JumpErrorEstimator");
62
99 // This parameter is not used when !LIBMESH_ENABLE_AMR.
100 libmesh_ignore(estimate_parent_error);
101
102 // The current mesh
103 const MeshBase & mesh = system.get_mesh();
104
105 // The number of variables in the system
106 const unsigned int n_vars = system.n_vars();
107
108 // The DofMap for this system
109#ifdef LIBMESH_ENABLE_AMR
110 const DofMap & dof_map = system.get_dof_map();
111#endif
112
113 // Resize the error_per_cell vector according to the
114 // maximum element ID because we will be indexing it with IDs.
115 // Initialize to 0.
116 error_per_cell.resize (mesh.max_elem_id());
117 std::fill (error_per_cell.begin(), error_per_cell.end(), 0.);
118
119 // Declare a vector of floats which is as long as
120 // error_per_cell above, and fill with zeros. This vector will be
121 // used to keep track of the number of edges (faces) on each active
122 // element which are either:
123 // 1) an internal edge
124 // 2) an edge on a Neumann boundary for which a boundary condition
125 // function has been specified.
126 // The error estimator can be scaled by the number of flux edges (faces)
127 // which the element actually has to obtain a more uniform measure
128 // of the error. Use floats instead of ints since in case 2 (above)
129 // f gets 1/2 of a flux face contribution from each of his
130 // neighbors
131 std::vector<float> n_flux_faces;
133 n_flux_faces.resize(error_per_cell.size(), 0);
134
135 // Prepare current_local_solution to localize a non-standard
136 // solution vector if necessary
137 if (solution_vector && solution_vector != system.solution.get())
138 {
139 NumericVector<Number> * newsol =
140 const_cast<NumericVector<Number> *>(solution_vector);
141 System & sys = const_cast<System &>(system);
142 newsol->swap(*sys.solution);
143 sys.update();
144 }
145
146 // We don't use full elem_jacobian or subjacobians here.
147 fine_context = std::make_unique<FEMContext>
148 (system, nullptr, /* allocate_local_matrices = */ false);
149 coarse_context = std::make_unique<FEMContext>
150 (system, nullptr, /* allocate_local_matrices = */ false);
151
152 // Don't overintegrate - we're evaluating differences of FE values,
153 // not products of them.
155 fine_context->use_unweighted_quadrature_rules(system.extra_quadrature_order);
156
157 // Loop over all the variables we've been requested to find jumps in, to
158 // pre-request
159 for (var=0; var<n_vars; var++)
160 {
161 // Skip variables which aren't part of our norm,
162 // as well as SCALAR variables, which have no jumps
163 if (error_norm.weight(var) == 0.0 ||
164 system.variable_type(var).family == SCALAR)
165 continue;
166
167 // FIXME: Need to generalize this to vector-valued elements. [PB]
168 FEBase * side_fe = nullptr;
169
170 const std::set<unsigned char> & elem_dims =
171 fine_context->elem_dimensions();
172
173 for (const auto & dim : elem_dims)
174 {
175 fine_context->get_side_fe( var, side_fe, dim );
176
177 side_fe->get_xyz();
178 }
179 }
180
183
184 // If we're integrating jumps across mesh slits, then we'll need a
185 // point locator to find slits, and we'll need to integrate point by
186 // point on sides.
187 std::unique_ptr<PointLocatorBase> point_locator;
188 std::unique_ptr<const Elem> side_ptr;
189
190 if (integrate_slits)
191 point_locator = mesh.sub_point_locator();
192
193 // Iterate over all the active elements in the mesh
194 // that live on this processor.
195 for (const auto & e : mesh.active_local_element_ptr_range())
196 {
197 const dof_id_type e_id = e->id();
198
199#ifdef LIBMESH_ENABLE_AMR
200
201 if (e->infinite())
202 {
203 libmesh_warning("Warning: Jumps on the border of infinite elements are ignored."
204 << std::endl);
205 continue;
206 }
207
208 // See if the parent of element e has been examined yet;
209 // if not, we may want to compute the estimator on it
210 const Elem * parent = e->parent();
211
212 // We only can compute and only need to compute on
213 // parents with all active children
214 bool compute_on_parent = true;
215 if (!parent || !estimate_parent_error)
216 compute_on_parent = false;
217 else
218 for (auto & child : parent->child_ref_range())
219 if (!child.active())
220 compute_on_parent = false;
221
222 if (compute_on_parent &&
223 !error_per_cell[parent->id()])
224 {
225 // Compute a projection onto the parent
226 DenseVector<Number> Uparent;
228 (*(system.solution), dof_map, parent, Uparent, false);
229
230 // Loop over the neighbors of the parent
231 for (auto n_p : parent->side_index_range())
232 {
233 if (parent->neighbor_ptr(n_p) != nullptr) // parent has a neighbor here
234 {
235 // Find the active neighbors in this direction
236 std::vector<const Elem *> active_neighbors;
237 parent->neighbor_ptr(n_p)->
238 active_family_tree_by_neighbor(active_neighbors,
239 parent);
240 // Compute the flux to each active neighbor
241 for (std::size_t a=0,
242 n_active_neighbors = active_neighbors.size();
243 a != n_active_neighbors; ++a)
244 {
245 const Elem * f = active_neighbors[a];
246
247 if (f ->infinite()) // don't take infinite elements into account
248 continue;
249
250 // FIXME - what about when f->level <
251 // parent->level()??
252 if (f->level() >= parent->level())
253 {
254 fine_context->pre_fe_reinit(system, f);
255 coarse_context->pre_fe_reinit(system, parent);
256 libmesh_assert_equal_to
257 (coarse_context->get_elem_solution().size(),
258 Uparent.size());
259 coarse_context->get_elem_solution() = Uparent;
260
261 this->reinit_sides();
262
263 // Loop over all significant variables in the system
264 for (var=0; var<n_vars; var++)
265 if (error_norm.weight(var) != 0.0 &&
266 system.variable_type(var).family != SCALAR)
267 {
269
270 error_per_cell[fine_context->get_elem().id()] +=
271 static_cast<ErrorVectorReal>(fine_error);
272 error_per_cell[coarse_context->get_elem().id()] +=
273 static_cast<ErrorVectorReal>(coarse_error);
274 }
275
276 // Keep track of the number of internal flux
277 // sides found on each element
279 {
280 n_flux_faces[fine_context->get_elem().id()]++;
281 n_flux_faces[coarse_context->get_elem().id()] +=
283 }
284 }
285 }
286 }
288 {
289 fine_context->pre_fe_reinit(system, parent);
290 libmesh_assert_equal_to
291 (fine_context->get_elem_solution().size(),
292 Uparent.size());
293 fine_context->get_elem_solution() = Uparent;
294 fine_context->side = cast_int<unsigned char>(n_p);
295 fine_context->side_fe_reinit();
296
297 // If we find a boundary flux for any variable,
298 // let's just count it as a flux face for all
299 // variables. Otherwise we'd need to keep track of
300 // a separate n_flux_faces and error_per_cell for
301 // every single var.
302 bool found_boundary_flux = false;
303
304 for (var=0; var<n_vars; var++)
305 if (error_norm.weight(var) != 0.0 &&
306 system.variable_type(var).family != SCALAR)
307 {
308 if (this->boundary_side_integration())
309 {
310 error_per_cell[fine_context->get_elem().id()] +=
311 static_cast<ErrorVectorReal>(fine_error);
312 found_boundary_flux = true;
313 }
314 }
315
316 if (scale_by_n_flux_faces && found_boundary_flux)
317 n_flux_faces[fine_context->get_elem().id()]++;
318 }
319 }
320 }
321#endif // #ifdef LIBMESH_ENABLE_AMR
322
323 // If we do any more flux integration, e will be the fine element
324 fine_context->pre_fe_reinit(system, e);
325
326 // Loop over the neighbors of element e
327 for (auto n_e : e->side_index_range())
328 {
329 if ((e->neighbor_ptr(n_e) != nullptr) ||
331 {
332 fine_context->side = cast_int<unsigned char>(n_e);
333 fine_context->side_fe_reinit();
334 }
335
336 // e is not on the boundary (infinite elements are treated as boundary)
337 if (e->neighbor_ptr(n_e) != nullptr
338 && !e->neighbor_ptr(n_e) ->infinite())
339 {
340
341 const Elem * f = e->neighbor_ptr(n_e);
342 const dof_id_type f_id = f->id();
343
344 // Compute flux jumps if we are in case 1 or case 2.
345 if ((f->active() && (f->level() == e->level()) && (e_id < f_id))
346 || (f->level() < e->level()))
347 {
348 // f is now the coarse element
349 coarse_context->pre_fe_reinit(system, f);
350
351 this->reinit_sides();
352
353 // Loop over all significant variables in the system
354 for (var=0; var<n_vars; var++)
355 if (error_norm.weight(var) != 0.0 &&
356 system.variable_type(var).family != SCALAR)
357 {
359
360 error_per_cell[fine_context->get_elem().id()] +=
361 static_cast<ErrorVectorReal>(fine_error);
362 error_per_cell[coarse_context->get_elem().id()] +=
363 static_cast<ErrorVectorReal>(coarse_error);
364 }
365
366 // Keep track of the number of internal flux
367 // sides found on each element
369 {
370 n_flux_faces[fine_context->get_elem().id()]++;
371 n_flux_faces[coarse_context->get_elem().id()] +=
373 }
374 } // end if (case1 || case2)
375 } // if (e->neighbor(n_e) != nullptr)
376
377 // e might not have a neighbor_ptr, but might still have
378 // another element sharing its side. This can happen in a
379 // mesh where solution continuity is maintained via nodal
380 // constraint rows.
381 else if (integrate_slits)
382 {
383 side_ptr = e->build_side_ptr(n_e);
384 std::set<const Elem *> candidate_elements;
385 (*point_locator)(side_ptr->vertex_average(), candidate_elements);
386
387 // We should have at least found ourselves...
388 libmesh_assert(candidate_elements.count(e));
389
390 // If we only found ourselves, this probably isn't a
391 // slit; we don't yet support meshes so non-conforming
392 // as to have overlap of part of an element side without
393 // overlap of its center.
394 if (candidate_elements.size() < 2)
395 continue;
396
397 FEType hardest_fe_type = fine_context->find_hardest_fe_type();
398
399 auto dim = e->dim();
400
401 auto side_qrule =
402 hardest_fe_type.unweighted_quadrature_rule
403 (dim-1, system.extra_quadrature_order);
404 auto side_fe = FEAbstract::build(dim, hardest_fe_type);
405 side_fe->attach_quadrature_rule(side_qrule.get());
406 const std::vector<Point> & qface_point = side_fe->get_xyz();
407 side_fe->reinit(e, n_e);
408
409 for (auto qp : make_range(side_qrule->n_points()))
410 {
411 const Point p = qface_point[qp];
412 const std::vector<Point> qp_pointvec(1, p);
413 std::set<const Elem *> side_elements;
414 (*point_locator)(side_ptr->vertex_average(), side_elements);
415
416 // If we have multiple neighbors meeting here we'll just
417 // take weighted jumps from all of them.
418 //
419 // We'll also do integrations from both sides of slits,
420 // rather than try to figure out a disambiguation rule
421 // that makes sense for non-conforming slits in general.
422 // This means we want an extra factor of 0.5 on the
423 // integrals to compensate for doubling them.
424 const std::size_t n_neighbors = side_elements.size() - 1;
425 const Real neighbor_frac = Real(1)/n_neighbors;
426
427 const std::vector<Real>
428 qp_weightvec(1, neighbor_frac * side_qrule->w(qp));
429
430 for (const Elem * f : side_elements)
431 {
432 if (f == e)
433 continue;
434
435 coarse_context->pre_fe_reinit(system, f);
436 fine_context->pre_fe_reinit(system, e);
437 std::vector<Point> qp_coarse, qp_fine;
438 for (unsigned int v=0; v<n_vars; v++)
439 if (error_norm.weight(v) != 0.0 &&
440 fine_context->get_system().variable_type(v).family != SCALAR)
441 {
442 FEBase * coarse_fe = coarse_context->get_side_fe(v, dim);
443 if (qp_coarse.empty())
444 FEMap::inverse_map (dim, f, qp_pointvec, qp_coarse);
445 coarse_fe->reinit(f, &qp_coarse, &qp_weightvec);
446 FEBase * fine_fe = fine_context->get_side_fe(v, dim);
447 if (qp_fine.empty())
448 FEMap::inverse_map (dim, e, qp_pointvec, qp_fine);
449 fine_fe->reinit(e, &qp_fine, &qp_weightvec);
450 }
451
452 // Loop over all significant variables in the system
453 for (var=0; var<n_vars; var++)
454 if (error_norm.weight(var) != 0.0 &&
455 system.variable_type(var).family != SCALAR)
456 {
458
459 error_per_cell[fine_context->get_elem().id()] +=
460 static_cast<ErrorVectorReal>(fine_error);
461 error_per_cell[coarse_context->get_elem().id()] +=
462 static_cast<ErrorVectorReal>(coarse_error);
463 }
464 }
465 }
466 }
467
468 // Otherwise, e is on the boundary. If it happens to
469 // be on a Dirichlet boundary, we need not do anything.
470 // On the other hand, if e is on a Neumann (flux) boundary
471 // with grad(u).n = g, we need to compute the additional residual
472 // (h * \int |g - grad(u_h).n|^2 dS)^(1/2).
473 // We can only do this with some knowledge of the boundary
474 // conditions, i.e. the user must have attached an appropriate
475 // BC function.
477 {
478 if (integrate_slits)
479 libmesh_not_implemented();
480
481 bool found_boundary_flux = false;
482
483 for (var=0; var<n_vars; var++)
484 if (error_norm.weight(var) != 0.0 &&
485 system.variable_type(var).family != SCALAR)
486 if (this->boundary_side_integration())
487 {
488 error_per_cell[fine_context->get_elem().id()] +=
489 static_cast<ErrorVectorReal>(fine_error);
490 found_boundary_flux = true;
491 }
492
493 if (scale_by_n_flux_faces && found_boundary_flux)
494 n_flux_faces[fine_context->get_elem().id()]++;
495 } // end if (e->neighbor_ptr(n_e) == nullptr)
496 } // end loop over neighbors
497 } // End loop over active local elements
498
499
500 // Each processor has now computed the error contributions
501 // for its local elements. We need to sum the vector
502 // and then take the square-root of each component. Note
503 // that we only need to sum if we are running on multiple
504 // processors, and we only need to take the square-root
505 // if the value is nonzero. There will in general be many
506 // zeros for the inactive elements.
507
508 // First sum the vector of estimated error values
509 this->reduce_error(error_per_cell, system.comm());
510
511 // Compute the square-root of each component.
512 for (auto i : index_range(error_per_cell))
513 if (error_per_cell[i] != 0.)
514 error_per_cell[i] = std::sqrt(error_per_cell[i]);
515
516
517 if (this->scale_by_n_flux_faces)
518 {
519 // Sum the vector of flux face counts
520 this->reduce_error(n_flux_faces, system.comm());
521
522 // Sanity check: Make sure the number of flux faces is
523 // always an integer value
524#ifdef DEBUG
525 for (const auto & val : n_flux_faces)
526 libmesh_assert_equal_to (val, static_cast<float>(static_cast<unsigned int>(val)));
527#endif
528
529 // Scale the error by the number of flux faces for each element
530 for (auto i : index_range(n_flux_faces))
531 {
532 if (n_flux_faces[i] == 0.0) // inactive or non-local element
533 continue;
534
535 error_per_cell[i] /= static_cast<ErrorVectorReal>(n_flux_faces[i]);
536 }
537 }
538
539 // If we used a non-standard solution before, now is the time to fix
540 // the current_local_solution
541 if (solution_vector && solution_vector != system.solution.get())
542 {
543 NumericVector<Number> * newsol =
544 const_cast<NumericVector<Number> *>(solution_vector);
545 System & sys = const_cast<System &>(system);
546 newsol->swap(*sys.solution);
547 sys.update();
548 }
549}
unsigned int n_vars
void ErrorVector unsigned int
void reduce_error(std::vector< ErrorVectorReal > &error_per_cell, const Parallel::Communicator &comm) const
This method takes the local error contributions in error_per_cell from each processor and combines th...
SystemNorm error_norm
When estimating the error in a single system, the error_norm is used to control the scaling and norm ...
static std::unique_ptr< FEAbstract > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
Definition fe_abstract.C:78
static void coarsened_dof_values(const NumericVector< Number > &global_vector, const DofMap &dof_map, const Elem *coarse_elem, DenseVector< Number > &coarse_dofs, const unsigned int var, const bool use_old_dof_indices=false)
Creates a local projection on coarse_elem, based on the DoF values in global_vector for it's children...
Definition fe_base.C:976
static Point inverse_map(const unsigned int dim, const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true, const bool extra_checks=true)
Definition fe_map.C:1512
float coarse_n_flux_faces_increment()
A utility function to correctly increase n_flux_faces for the coarse element.
unsigned int var
The variable number currently being evaluated.
virtual bool boundary_side_integration()
The function, to be implemented by derived classes, which calculates an error term on a boundary side...
virtual void internal_side_integration()=0
The function, to be implemented by derived classes, which calculates an error term on an internal sid...
void reinit_sides()
A utility function to reinit the finite element data on elements sharing a side.
virtual void init_context(FEMContext &c)
An initialization function, to give derived classes a chance to request specific data from the FE obj...
Real weight(unsigned int var) const
MeshBase & mesh
void active_family_tree_by_neighbor(T elem, std::vector< T > &family, T neighbor_in, bool reset=true)
DIE A HORRIBLE DEATH HERE typedef float ErrorVectorReal
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition int_range.h:153
void libmesh_ignore(const Args &...)
libmesh_assert(ctx)
uint8_t dof_id_type
Definition id_types.h:67
FEGenericBase< Real > FEBase
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
template class LIBMESH_EXPORT NumericVector< Number >
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

References libMesh::Elem::active(), boundary_side_integration(), libMesh::FEAbstract::build(), libMesh::Elem::child_ref_range(), coarse_context, coarse_error, coarse_n_flux_faces_increment(), libMesh::FEGenericBase< OutputType >::coarsened_dof_values(), libMesh::ParallelObject::comm(), dim, libMesh::ErrorEstimator::error_norm, libMesh::ErrorVectorReal, libMesh::System::extra_quadrature_order, libMesh::FEType::family, fine_context, fine_error, libMesh::System::get_dof_map(), libMesh::System::get_mesh(), libMesh::FEAbstract::get_xyz(), libMesh::DofObject::id(), libMesh::index_range(), init_context(), integrate_boundary_sides, integrate_slits, internal_side_integration(), libMesh::FEMap::inverse_map(), libMesh::Elem::level(), libMesh::libmesh_assert(), libMesh::libmesh_ignore(), libMesh::make_range(), mesh, n_vars, libMesh::System::n_vars(), libMesh::Elem::neighbor_ptr(), libMesh::Elem::parent(), libMesh::Real, libMesh::ErrorEstimator::reduce_error(), libMesh::FEAbstract::reinit(), reinit_sides(), libMesh::SCALAR, scale_by_n_flux_faces, libMesh::Elem::side_index_range(), libMesh::DenseVector< T >::size(), libMesh::System::solution, libMesh::NumericVector< T >::swap(), libMesh::FEType::unweighted_quadrature_rule(), use_unweighted_quadrature_rules, var, libMesh::System::variable_type(), and libMesh::SystemNorm::weight().

Referenced by assemble_and_solve(), main(), and SlitMeshRefinedSystemTest::testSystem().

◆ estimate_errors() [1/2]

void libMesh::ErrorEstimator::estimate_errors ( const EquationSystems equation_systems,
ErrorMap errors_per_cell,
const std::map< const System *, const NumericVector< Number > * > *  solution_vectors = nullptr,
bool  estimate_parent_error = false 
)
virtualinherited

This virtual function can be redefined in derived classes, but by default it calls estimate_error repeatedly to calculate the requested error vectors.

FIXME: This is a default implementation - derived classes should reimplement it for efficiency.

Currently this function ignores the error_norm.weight() values because it calculates each variable's error individually, unscaled.

The user selects which errors get computed by filling a map with error vectors: If errors_per_cell[&system][v] exists, it will be filled with the error values in variable v of system

Reimplemented in libMesh::UniformRefinementEstimator.

Definition at line 94 of file error_estimator.C.

98{
99 SystemNorm old_error_norm = this->error_norm;
100
101 // Find the requested error values from each system
102 for (auto s : make_range(equation_systems.n_systems()))
103 {
104 const System & sys = equation_systems.get_system(s);
105
106 unsigned int n_vars = sys.n_vars();
107
108 for (unsigned int v = 0; v != n_vars; ++v)
109 {
110 // Only fill in ErrorVectors the user asks for
111 if (!errors_per_cell.count(std::make_pair(&sys, v)))
112 continue;
113
114 // Calculate error in only one variable
115 std::vector<Real> weights(n_vars, 0.0);
116 weights[v] = 1.0;
117 this->error_norm =
118 SystemNorm(std::vector<FEMNormType>(n_vars, old_error_norm.type(v)),
119 weights);
120
121 const NumericVector<Number> * solution_vector = nullptr;
122 if (solution_vectors &&
123 solution_vectors->find(&sys) != solution_vectors->end())
124 solution_vector = solution_vectors->find(&sys)->second;
125
126 this->estimate_error
127 (sys, *errors_per_cell[std::make_pair(&sys, v)],
128 solution_vector, estimate_parent_error);
129 }
130 }
131
132 // Restore our old state before returning
133 this->error_norm = old_error_norm;
134}
virtual void estimate_error(const System &system, ErrorVector &error_per_cell, const NumericVector< Number > *solution_vector=nullptr, bool estimate_parent_error=false)=0
This pure virtual function must be redefined in derived classes to compute the error for each active ...

References libMesh::ErrorEstimator::error_norm, libMesh::ErrorEstimator::estimate_error(), libMesh::EquationSystems::get_system(), libMesh::make_range(), libMesh::EquationSystems::n_systems(), n_vars, libMesh::System::n_vars(), and libMesh::SystemNorm::type().

◆ estimate_errors() [2/2]

void libMesh::ErrorEstimator::estimate_errors ( const EquationSystems equation_systems,
ErrorVector error_per_cell,
const std::map< const System *, SystemNorm > &  error_norms,
const std::map< const System *, const NumericVector< Number > * > *  solution_vectors = nullptr,
bool  estimate_parent_error = false 
)
virtualinherited

This virtual function can be redefined in derived classes, but by default computes the sum of the error_per_cell for each system in the equation_systems.

Currently this function ignores the error_norm member variable, and uses the function argument error_norms instead.

This function is named estimate_errors instead of estimate_error because otherwise C++ can get confused.

Reimplemented in libMesh::UniformRefinementEstimator.

Definition at line 47 of file error_estimator.C.

52{
53 SystemNorm old_error_norm = this->error_norm;
54
55 // Sum the error values from each system
56 for (auto s : make_range(equation_systems.n_systems()))
57 {
58 ErrorVector system_error_per_cell;
59 const System & sys = equation_systems.get_system(s);
60 if (const auto it = error_norms.find(&sys);
61 it == error_norms.end())
62 this->error_norm = old_error_norm;
63 else
64 this->error_norm = it->second;
65
66 const NumericVector<Number> * solution_vector = nullptr;
67 if (solution_vectors &&
68 solution_vectors->find(&sys) != solution_vectors->end())
69 solution_vector = solution_vectors->find(&sys)->second;
70
71 this->estimate_error(sys, system_error_per_cell,
72 solution_vector, estimate_parent_error);
73
74 if (s)
75 {
76 libmesh_assert_equal_to (error_per_cell.size(), system_error_per_cell.size());
77 for (auto i : index_range(error_per_cell))
78 error_per_cell[i] += system_error_per_cell[i];
79 }
80 else
81 error_per_cell = system_error_per_cell;
82 }
83
84 // Restore our old state before returning
85 this->error_norm = old_error_norm;
86}

References libMesh::ErrorEstimator::error_norm, libMesh::ErrorEstimator::estimate_error(), libMesh::EquationSystems::get_system(), libMesh::index_range(), libMesh::make_range(), and libMesh::EquationSystems::n_systems().

◆ init_context()

void libMesh::JumpErrorEstimator::init_context ( FEMContext c)
protectedvirtual

An initialization function, to give derived classes a chance to request specific data from the FE objects.

Reimplemented in libMesh::DiscontinuityMeasure, libMesh::LaplacianErrorEstimator, and libMesh::KellyErrorEstimator.

Definition at line 48 of file jump_error_estimator.C.

49{
50 // Derived classes are *supposed* to rederive this
51 libmesh_deprecated();
52}

Referenced by estimate_error().

◆ internal_side_integration()

virtual void libMesh::JumpErrorEstimator::internal_side_integration ( )
protectedpure virtual

The function, to be implemented by derived classes, which calculates an error term on an internal side.

Implemented in libMesh::DiscontinuityMeasure, libMesh::LaplacianErrorEstimator, and libMesh::KellyErrorEstimator.

Referenced by estimate_error().

◆ operator=() [1/2]

JumpErrorEstimator & libMesh::JumpErrorEstimator::operator= ( const JumpErrorEstimator )
delete

◆ operator=() [2/2]

JumpErrorEstimator & libMesh::JumpErrorEstimator::operator= ( JumpErrorEstimator &&  )
default

◆ reduce_error()

void libMesh::ErrorEstimator::reduce_error ( std::vector< ErrorVectorReal > &  error_per_cell,
const Parallel::Communicator comm 
) const
protectedinherited

This method takes the local error contributions in error_per_cell from each processor and combines them to get the global error vector.

Definition at line 32 of file error_estimator.C.

34{
35 // This function must be run on all processors at once
36 // parallel_object_only();
37
38 // Each processor has now computed the error contributions
39 // for its local elements. We may need to sum the vector to
40 // recover the error for each element.
41
42 comm.sum(error_per_cell);
43}

References libMesh::Parallel::Communicator::sum().

Referenced by libMesh::UniformRefinementEstimator::_estimate_error(), libMesh::AdjointRefinementEstimator::estimate_error(), libMesh::ExactErrorEstimator::estimate_error(), estimate_error(), libMesh::PatchRecoveryErrorEstimator::estimate_error(), and libMesh::WeightedPatchRecoveryErrorEstimator::estimate_error().

◆ reinit_sides()

void libMesh::JumpErrorEstimator::reinit_sides ( )
protected

A utility function to reinit the finite element data on elements sharing a side.

Definition at line 554 of file jump_error_estimator.C.

555{
556 fine_context->side_fe_reinit();
557
558 unsigned short dim = fine_context->get_elem().dim();
559 libmesh_assert_equal_to(dim, coarse_context->get_elem().dim());
560
561 FEBase * fe_fine = nullptr;
562 fine_context->get_side_fe( 0, fe_fine, dim );
563
564 // Get the physical locations of the fine element quadrature points
565 std::vector<Point> qface_point = fe_fine->get_xyz();
566
567 // Find the master quadrature point locations on the coarse element
568 FEBase * fe_coarse = nullptr;
569 coarse_context->get_side_fe( 0, fe_coarse, dim );
570
571 std::vector<Point> qp_coarse;
572
573 FEMap::inverse_map (coarse_context->get_elem().dim(),
574 &coarse_context->get_elem(), qface_point,
575 qp_coarse);
576
577 // The number of variables in the system
578 const unsigned int n_vars = fine_context->n_vars();
579
580 // Calculate all coarse element shape functions at those locations
581 for (unsigned int v=0; v<n_vars; v++)
582 if (error_norm.weight(v) != 0.0 &&
583 fine_context->get_system().variable_type(v).family != SCALAR)
584 {
585 coarse_context->get_side_fe( v, fe_coarse, dim );
586 fe_coarse->reinit (&coarse_context->get_elem(), &qp_coarse);
587 }
588}

References coarse_context, dim, libMesh::ErrorEstimator::error_norm, fine_context, libMesh::FEAbstract::get_xyz(), libMesh::FEMap::inverse_map(), n_vars, libMesh::FEAbstract::reinit(), libMesh::SCALAR, and libMesh::SystemNorm::weight().

Referenced by estimate_error().

◆ type()

virtual ErrorEstimatorType libMesh::ErrorEstimator::type ( ) const
pure virtualinherited

Member Data Documentation

◆ coarse_context

std::unique_ptr<FEMContext> libMesh::JumpErrorEstimator::coarse_context
protected

◆ coarse_error

Real libMesh::JumpErrorEstimator::coarse_error
protected

◆ error_norm

SystemNorm libMesh::ErrorEstimator::error_norm
inherited

When estimating the error in a single system, the error_norm is used to control the scaling and norm choice for each variable.

Not all estimators will support all norm choices. The default scaling is for all variables to be weighted equally. The default norm choice depends on the error estimator.

Part of this functionality was supported via component_scale and sobolev_order in older libMesh versions, and a small part was supported via component_mask in even older versions. Hopefully the encapsulation here will allow us to avoid changing this API again.

Definition at line 158 of file error_estimator.h.

Referenced by libMesh::UniformRefinementEstimator::_estimate_error(), libMesh::AdjointRefinementEstimator::AdjointRefinementEstimator(), libMesh::DiscontinuityMeasure::boundary_side_integration(), libMesh::KellyErrorEstimator::boundary_side_integration(), libMesh::DiscontinuityMeasure::DiscontinuityMeasure(), libMesh::AdjointResidualErrorEstimator::estimate_error(), libMesh::ExactErrorEstimator::estimate_error(), estimate_error(), libMesh::ErrorEstimator::estimate_errors(), libMesh::ErrorEstimator::estimate_errors(), libMesh::ExactErrorEstimator::ExactErrorEstimator(), libMesh::ExactErrorEstimator::find_squared_element_error(), libMesh::DiscontinuityMeasure::init_context(), libMesh::LaplacianErrorEstimator::init_context(), libMesh::KellyErrorEstimator::init_context(), libMesh::DiscontinuityMeasure::internal_side_integration(), libMesh::LaplacianErrorEstimator::internal_side_integration(), libMesh::KellyErrorEstimator::internal_side_integration(), libMesh::KellyErrorEstimator::KellyErrorEstimator(), libMesh::LaplacianErrorEstimator::LaplacianErrorEstimator(), libMesh::PatchRecoveryErrorEstimator::EstimateError::operator()(), libMesh::WeightedPatchRecoveryErrorEstimator::EstimateError::operator()(), libMesh::PatchRecoveryErrorEstimator::PatchRecoveryErrorEstimator(), reinit_sides(), and libMesh::UniformRefinementEstimator::UniformRefinementEstimator().

◆ fine_context

std::unique_ptr<FEMContext> libMesh::JumpErrorEstimator::fine_context
protected

◆ fine_error

Real libMesh::JumpErrorEstimator::fine_error
protected

◆ integrate_boundary_sides

bool libMesh::JumpErrorEstimator::integrate_boundary_sides
protected

A boolean flag, by default false, to be set to true if integrations with boundary_side_integration() should be performed.

Definition at line 169 of file jump_error_estimator.h.

Referenced by libMesh::DiscontinuityMeasure::attach_essential_bc_function(), libMesh::KellyErrorEstimator::attach_flux_bc_function(), and estimate_error().

◆ integrate_slits

bool libMesh::JumpErrorEstimator::integrate_slits

A boolean flag, by default false, to be set to true if integrations should be performed on "slits" where two elements' faces overlap even if those elements are not connected by neighbor links.

This may only be useful for flex-IGA meshes, where highly-nonconforming meshes are given pseudo-conforming solutions via nodal constraints.

Note that, to safely use this option in parallel, it is also necessary to expand the default algebraic ghosting requirements to include elements on the opposite sides of slits from local elements.

Definition at line 130 of file jump_error_estimator.h.

Referenced by estimate_error(), and SlitMeshRefinedSystemTest::testSystem().

◆ scale_by_n_flux_faces

bool libMesh::JumpErrorEstimator::scale_by_n_flux_faces

This boolean flag allows you to scale the error indicator result for each element by the number of "flux faces" the element actually has.

This tends to weight more evenly cells which are on the boundaries and thus have fewer contributions to their flux. The value is initialized to false, simply set it to true if you want to use the feature.

Definition at line 100 of file jump_error_estimator.h.

Referenced by estimate_error().

◆ use_unweighted_quadrature_rules

bool libMesh::JumpErrorEstimator::use_unweighted_quadrature_rules

This boolean flag allows you to use "unweighted" quadrature rules (sized to exactly integrate unweighted shape functions in master element space) rather than "default" quadrature rules (sized to exactly integrate polynomials of one higher degree than mass matrix terms).

The results with the former, lower-order rules will be somewhat less accurate in many cases but will be much cheaper to compute.

The value is initialized to false, simply set it to true if you want to use the feature.

Definition at line 114 of file jump_error_estimator.h.

Referenced by estimate_error(), and main().

◆ var

unsigned int libMesh::JumpErrorEstimator::var
protected

The documentation for this class was generated from the following files: