20 #include "libmesh/libmesh_common.h" 21 #include "libmesh/patch_recovery_error_estimator.h" 22 #include "libmesh/dof_map.h" 23 #include "libmesh/fe_base.h" 24 #include "libmesh/dense_matrix.h" 25 #include "libmesh/dense_vector.h" 26 #include "libmesh/error_vector.h" 27 #include "libmesh/libmesh_logging.h" 28 #include "libmesh/elem.h" 29 #include "libmesh/patch.h" 30 #include "libmesh/quadrature_grid.h" 31 #include "libmesh/system.h" 32 #include "libmesh/mesh_base.h" 33 #include "libmesh/numeric_vector.h" 34 #include "libmesh/tensor_value.h" 35 #include "libmesh/threads.h" 36 #include "libmesh/tensor_tools.h" 37 #include "libmesh/enum_error_estimator_type.h" 38 #include "libmesh/enum_norm_type.h" 39 #include "libmesh/int_range.h" 40 #include "libmesh/enum_to_string.h" 67 target_patch_size(20),
68 patch_growth_strategy(&
Patch::add_local_face_neighbors),
80 const unsigned int matsize)
82 std::vector<Real> psi;
85 std::vector<Real> xpow(npows,1.), ypow, zpow;
89 xpow[i] = xpow[i-1] * x;
94 ypow.resize(npows,1.);
96 ypow[i] = ypow[i-1] * y;
101 zpow.resize(npows,1.);
103 zpow[i] = zpow[i-1] * z;
108 for (
unsigned int poly_deg=0; poly_deg <= static_cast<unsigned int>(order) ; poly_deg++)
116 for (
int xexp=poly_deg; xexp >= 0; xexp--)
117 for (
int yexp=poly_deg-xexp; yexp >= 0; yexp--)
119 int zexp = poly_deg - xexp - yexp;
120 psi.push_back(xpow[xexp]*ypow[yexp]*zpow[zexp]);
128 for (
int xexp=poly_deg; xexp >= 0; xexp--)
130 int yexp = poly_deg - xexp;
131 psi.push_back(xpow[xexp]*ypow[yexp]);
140 psi.push_back(xpow[xexp]);
145 libmesh_error_msg(
"Invalid dimension dim " <<
dim);
159 LOG_SCOPE(
"estimate_error()",
"PatchRecoveryErrorEstimator");
166 error_per_cell.resize (
mesh.max_elem_id());
167 std::fill (error_per_cell.begin(), error_per_cell.end(), 0.);
171 if (solution_vector && solution_vector != system.
solution.get())
176 newsol->
swap(*sys.solution);
184 mesh.active_local_elements_end(),
199 if (solution_vector && solution_vector != system.
solution.get())
204 newsol->
swap(*sys.solution);
217 const unsigned int dim =
mesh.mesh_dimension();
227 for (
const auto & elem : range)
252 std::vector<Real> new_error_per_cell(1, 0.);
254 new_error_per_cell.resize(patch.size(), 0.);
258 for (
unsigned int var=0; var<
n_vars; var++)
261 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 263 bool is_valid_norm_type =
270 norm_type ==
L_INF ||
277 norm_type ==
L_INF ||
290 bool is_valid_norm_combo =
303 ((norm_type ==
L_INF ||
319 const Order element_order = fe_type.
order + elem->p_level();
328 fe->attach_quadrature_rule (qrule.get());
331 const std::vector<Real> & JxW = fe->get_JxW();
332 const std::vector<Point> & q_point = fe->get_xyz();
338 const std::vector<std::vector<Real>> * phi =
nullptr;
343 if (norm_type ==
L2 ||
346 phi = &(fe->get_phi());
348 const std::vector<std::vector<RealGradient>> * dphi =
nullptr;
354 dphi = &(fe->get_dphi());
356 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 357 const std::vector<std::vector<RealTensor>> * d2phi =
nullptr;
360 d2phi = &(fe->get_d2phi());
364 std::vector<dof_id_type> dof_indices;
368 unsigned int matsize = element_order + 1;
371 matsize *= (element_order + 2);
376 matsize *= (element_order + 3);
383 if (norm_type ==
L2 ||
407 libmesh_assert_greater (LIBMESH_DIM, 1);
412 libmesh_assert_greater (LIBMESH_DIM, 2);
431 for (
const auto & e_p : patch)
439 libmesh_assert_equal_to (dof_indices.size(), phi->size());
441 const unsigned int n_dofs =
442 cast_int<unsigned int>(dof_indices.size());
443 const unsigned int n_qp = qrule->n_points();
447 for (
unsigned int qp=0; qp<n_qp; qp++)
450 std::vector<Real> psi(
specpoly(
dim, element_order, q_point[qp], matsize));
452 const unsigned int psi_size = cast_int<unsigned int>(psi.size());
455 const unsigned int m = Kp.
m(), n = Kp.
n();
456 for (
unsigned int i=0; i<m; i++)
457 for (
unsigned int j=0; j<n; j++)
458 Kp(i,j) += JxW[qp]*psi[i]*psi[j];
460 if (norm_type ==
L2 ||
467 for (
unsigned int i=0; i<n_dofs; i++)
471 for (
unsigned int i=0; i != psi_size; i++)
472 F(i) += JxW[qp]*u_h*psi[i];
482 for (
unsigned int i=0; i<n_dofs; i++)
487 for (
unsigned int i=0; i != psi_size; i++)
489 Fx(i) += JxW[qp]*grad_u_h(0)*psi[i];
491 Fy(i) += JxW[qp]*grad_u_h(1)*psi[i];
494 Fz(i) += JxW[qp]*grad_u_h(2)*psi[i];
504 for (
unsigned int i=0; i<n_dofs; i++)
509 for (
unsigned int i=0; i != psi_size; i++)
511 Fx(i) += JxW[qp]*grad_u_h(0)*psi[i];
521 for (
unsigned int i=0; i<n_dofs; i++)
526 for (
unsigned int i=0; i != psi_size; i++)
528 Fy(i) += JxW[qp]*grad_u_h(1)*psi[i];
531 #endif // LIBMESH_DIM > 1 539 for (
unsigned int i=0; i<n_dofs; i++)
544 for (
unsigned int i=0; i != psi_size; i++)
546 Fz(i) += JxW[qp]*grad_u_h(2)*psi[i];
549 #endif // LIBMESH_DIM > 2 553 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 558 for (
unsigned int i=0; i<n_dofs; i++)
563 for (
unsigned int i=0; i != psi_size; i++)
565 Fx(i) += JxW[qp]*hess_u_h(0,0)*psi[i];
567 Fy(i) += JxW[qp]*hess_u_h(1,1)*psi[i];
568 Fxy(i) += JxW[qp]*hess_u_h(0,1)*psi[i];
571 Fz(i) += JxW[qp]*hess_u_h(2,2)*psi[i];
572 Fxz(i) += JxW[qp]*hess_u_h(0,2)*psi[i];
573 Fyz(i) += JxW[qp]*hess_u_h(1,2)*psi[i];
577 libmesh_error_msg(
"ERROR: --enable-second-derivatives is required \nfor _sobolev_order == 2!");
591 if (norm_type ==
L2 ||
638 Patch::const_iterator patch_re_it;
639 Patch::const_iterator patch_re_end;
647 patch_re_it = patch.begin();
648 patch_re_end = patch.end();
658 patch_re_it = patch_re.begin();
659 patch_re_end = patch_re.end();
669 for (
unsigned int e = 0 ; patch_re_it != patch_re_end; ++patch_re_it, ++e)
674 const Elem * e_p = *patch_re_it;
693 libmesh_assert_equal_to (dof_indices.size(), phi->size());
696 const unsigned int n_dofs =
697 cast_int<unsigned int>(dof_indices.size());
700 Real element_error = 0;
709 fe->attach_quadrature_rule (&samprule);
712 const unsigned int n_sp =
713 cast_int<unsigned int>(JxW.size());
716 for (
unsigned int sp=0; sp<n_sp; sp++)
720 std::vector<Number> temperr(6,0.0);
722 if (norm_type ==
L2 ||
728 for (
unsigned int i=0; i<n_dofs; i++)
732 std::vector<Real> psi(
specpoly(
dim, element_order, q_point[sp], matsize));
733 for (
unsigned int i=0; i<matsize; i++)
735 temperr[0] += psi[i]*Pu_h(i);
746 for (
unsigned int i=0; i<n_dofs; i++)
751 std::vector<Real> psi(
specpoly(
dim, element_order, q_point[sp], matsize));
753 for (
unsigned int i=0; i<matsize; i++)
755 temperr[0] += psi[i]*Pu_x_h(i);
757 temperr[1] += psi[i]*Pu_y_h(i);
760 temperr[2] += psi[i]*Pu_z_h(i);
763 temperr[0] -= grad_u_h(0);
765 temperr[1] -= grad_u_h(1);
768 temperr[2] -= grad_u_h(2);
776 for (
unsigned int i=0; i<n_dofs; i++)
781 std::vector<Real> psi(
specpoly(
dim, element_order, q_point[sp], matsize));
782 for (
unsigned int i=0; i<matsize; i++)
784 temperr[0] += psi[i]*Pu_x_h(i);
787 temperr[0] -= grad_u_h(0);
795 for (
unsigned int i=0; i<n_dofs; i++)
800 std::vector<Real> psi(
specpoly(
dim, element_order, q_point[sp], matsize));
801 for (
unsigned int i=0; i<matsize; i++)
803 temperr[1] += psi[i]*Pu_y_h(i);
806 temperr[1] -= grad_u_h(1);
808 #endif // LIBMESH_DIM > 1 815 for (
unsigned int i=0; i<n_dofs; i++)
820 std::vector<Real> psi(
specpoly(
dim, element_order, q_point[sp], matsize));
821 for (
unsigned int i=0; i<matsize; i++)
823 temperr[2] += psi[i]*Pu_z_h(i);
826 temperr[2] -= grad_u_h(2);
828 #endif // LIBMESH_DIM > 2 832 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES 836 for (
unsigned int i=0; i<n_dofs; i++)
841 std::vector<Real> psi(
specpoly(
dim, element_order, q_point[sp], matsize));
842 for (
unsigned int i=0; i<matsize; i++)
844 temperr[0] += psi[i]*Pu_x_h(i);
846 temperr[1] += psi[i]*Pu_y_h(i);
847 temperr[3] += psi[i]*Pu_xy_h(i);
850 temperr[2] += psi[i]*Pu_z_h(i);
851 temperr[4] += psi[i]*Pu_xz_h(i);
852 temperr[5] += psi[i]*Pu_yz_h(i);
856 temperr[0] -= hess_u_h(0,0);
858 temperr[1] -= hess_u_h(1,1);
859 temperr[3] -= hess_u_h(0,1);
862 temperr[2] -= hess_u_h(2,2);
863 temperr[4] -= hess_u_h(0,2);
864 temperr[5] -= hess_u_h(1,2);
867 libmesh_error_msg(
"ERROR: --enable-second-derivatives is required \nfor _sobolev_order == 2!");
874 if (norm_type ==
L_INF)
875 element_error = std::max(element_error, std::abs(temperr[0]));
877 for (
unsigned int i=0; i != LIBMESH_DIM; ++i)
878 element_error = std::max(element_error, std::abs(temperr[i]));
880 for (
unsigned int i=0; i != 6; ++i)
881 element_error = std::max(element_error, std::abs(temperr[i]));
882 else if (norm_type ==
L2)
885 for (
unsigned int i=0; i != LIBMESH_DIM; ++i)
895 for (
unsigned int i=0; i != LIBMESH_DIM; ++i)
898 for (
unsigned int i=3; i != 6; ++i)
904 if (norm_type ==
L_INF ||
908 else if (norm_type ==
L2 ||
927 Patch::const_iterator patch_re_it;
928 Patch::const_iterator patch_re_end;
931 Patch current_elem_patch(
mesh.processor_id());
936 patch_re_it = patch.begin();
937 patch_re_end = patch.end();
947 patch_re_it = current_elem_patch.begin();
948 patch_re_end = current_elem_patch.end();
952 for (
unsigned int i = 0 ; patch_re_it != patch_re_end; ++patch_re_it, ++i)
955 const Elem * e_p = *patch_re_it;
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
void add_scaled(const TypeVector< T2 > &, const T &)
Add a scaled value to this vector without creating a temporary.
Order
defines an enum for polynomial orders.
SystemNorm error_norm
When estimating the error in a single system, the error_norm is used to control the scaling and norm ...
Patch::PMF patch_growth_strategy
The PatchErrorEstimator will use this pointer to a Patch member function when growing patches...
This class implements useful utility functions for a patch of elements.
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
void parallel_for(const Range &range, const Body &body)
Execute the provided function object in parallel on the specified range.
The ErrorVector is a specialization of the StatisticsVector for error data computed on a finite eleme...
ErrorEstimatorType
Defines an enum for the different types of error estimators which are available.
void resize(const unsigned int n)
Resize the vector.
This is the base class from which all geometric element types are derived.
const Parallel::Communicator & comm() const
unsigned int p_level() const
OrderWrapper order
The approximation order of the element.
This class defines a vector in LIBMESH_DIM dimensional Real or Complex space.
The StoredRange class defines a contiguous, divisible set of objects.
The libMesh namespace provides an interface to certain functionality in the library.
const MeshBase & get_mesh() const
DIE A HORRIBLE DEATH HERE typedef float ErrorVectorReal
void build_around_element(const Elem *elem, const unsigned int target_patch_size=10, PMF patchtype=&Patch::add_local_face_neighbors)
Erases any elements in the current patch, then builds a new patch containing element elem by repeated...
This is the MeshBase class.
StoredRange< MeshBase::const_element_iterator, const Elem * > ConstElemRange
Number current_solution(const dof_id_type global_dof_number) const
This class handles the numbering of degrees of freedom on a mesh.
std::unique_ptr< QBase > default_quadrature_rule(const unsigned int dim, const int extraorder=0) const
Manages consistently variables, degrees of freedom, and coefficient vectors.
FEMNormType type(unsigned int var) const
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
This class holds functions that will estimate the error in a finite element solution on a given mesh...
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 Patch Recovery error estimate to estimate the error on each cell...
const FEType & variable_type(const unsigned int i) const
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...
unsigned int target_patch_size
The PatchErrorEstimator will build patches of at least this many elements to perform estimates...
const PatchRecoveryErrorEstimator & error_estimator
static std::vector< Real > specpoly(const unsigned int dim, const Order order, const Point p, const unsigned int matsize)
void add_scaled(const TypeTensor< T2 > &, const T &)
Add a scaled tensor to this tensor without creating a temporary.
This class creates quadrature points on a uniform grid, with order+1 points on an edge...
void operator()(const ConstElemRange &range) const
std::string enum_to_string(const T e)
Real weight_sq(unsigned int var) const
ErrorVector & error_per_cell
Real weight(unsigned int var) const
void lu_solve(const DenseVector< T > &b, DenseVector< T > &x)
Solve the system Ax=b given the input vector b.
void set_patch_reuse(bool)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual void swap(NumericVector< T > &v)
Swaps the contents of this with v.
PatchRecoveryErrorEstimator()
Constructor.
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...
int _extra_order
Extra order to use for quadrature rule.
virtual ErrorEstimatorType type() const override
friend class EstimateError
unsigned int n_vars() const
const DofMap & get_dof_map() const
A Point defines a location in LIBMESH_DIM dimensional Real space.
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.
spin_mutex spin_mtx
A convenient spin mutex object which can be used for obtaining locks.