libMesh
Loading...
Searching...
No Matches
jump_error_estimator.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
19// Local Includes
20#include "libmesh/libmesh_common.h"
21#include "libmesh/jump_error_estimator.h"
22#include "libmesh/dof_map.h"
23#include "libmesh/elem.h"
24#include "libmesh/error_vector.h"
25#include "libmesh/fe_base.h"
26#include "libmesh/fe_interface.h"
27#include "libmesh/fem_context.h"
28#include "libmesh/libmesh_logging.h"
29#include "libmesh/mesh_base.h"
30#include "libmesh/quadrature_gauss.h"
31#include "libmesh/system.h"
32#include "libmesh/dense_vector.h"
33#include "libmesh/numeric_vector.h"
34#include "libmesh/int_range.h"
35
36// C++ Includes
37#include <algorithm> // for std::fill
38#include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
39#include <cmath> // for sqrt
40#include <memory>
41
42
43namespace libMesh
44{
45
46//-----------------------------------------------------------------
47// JumpErrorEstimator implementations
49{
50 // Derived classes are *supposed* to rederive this
51 libmesh_deprecated();
52}
53
54
55
57 ErrorVector & error_per_cell,
58 const NumericVector<Number> * solution_vector,
59 bool estimate_parent_error)
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}
550
551
552
553void
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}
589
590
591
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}
612
613} // namespace libMesh
unsigned int n_vars
unsigned int dim
Defines a dense vector for use in Finite Element-type computations.
virtual unsigned int size() const override final
This class handles the numbering of degrees of freedom on a mesh.
Definition dof_map.h:181
dof_id_type id() const
Definition dof_object.h:819
This is the base class from which all geometric element types are derived.
Definition elem.h:96
bool active() const
Definition elem.h:2958
const Elem * parent() const
Definition elem.h:3047
SimpleRange< ChildRefIter > child_ref_range()
Returns a range with all children of a parent element, usable in range-based for loops.
Definition elem.h:2355
unsigned int level() const
Definition elem.h:3091
const Elem * neighbor_ptr(unsigned int i) const
Definition elem.h:2615
IntRange< unsigned short > side_index_range() const
Definition elem.h:2727
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 ...
The ErrorVector is a specialization of the StatisticsVector for error data computed on a finite eleme...
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.
static std::unique_ptr< FEAbstract > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
Definition fe_abstract.C:78
This class forms the foundation from which generic finite elements may be derived.
Definition fe_base.h:86
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
This class provides all data required for a physics package (e.g.
Definition fem_context.h:63
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
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition fe_type.h:197
std::unique_ptr< QBase > unweighted_quadrature_rule(const unsigned int dim, const int extraorder=0) const
Definition fe_type.C:53
FEFamily family
The type of finite element.
Definition fe_type.h:228
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.
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();.
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...
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() ...
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...
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.
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...
This is the MeshBase class.
Definition mesh_base.h:81
Provides a uniform interface to vector storage schemes for different linear algebra libraries.
virtual void swap(NumericVector< T > &v)
Swaps the contents of this with v.
const Parallel::Communicator & comm() const
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
Real weight(unsigned int var) const
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition system.h:100
int extra_quadrature_order
A member int that can be employed to indicate increased or reduced quadrature order.
Definition system.h:1640
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
unsigned int n_vars() const
Definition system.C:2674
const DofMap & get_dof_map() const
Definition system.h:2417
const MeshBase & get_mesh() const
Definition system.h:2401
MeshBase & mesh
The libMesh namespace provides an interface to certain functionality in the library.
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
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