libMesh
Public Member Functions | Private Attributes | List of all members
libMesh::WeightedPatchRecoveryErrorEstimator::EstimateError Class Reference

Class to compute the error contribution for a range of elements. More...

Public Member Functions

 EstimateError (const System &sys, const WeightedPatchRecoveryErrorEstimator &ee, ErrorVector &epc)
 
void operator() (const ConstElemRange &range) const
 

Private Attributes

const Systemsystem
 Function to set the boolean patch_reuse in case the user wants to change the default behaviour of patch_recovery_error_estimator. More...
 
const WeightedPatchRecoveryErrorEstimatorerror_estimator
 
ErrorVectorerror_per_cell
 

Detailed Description

Class to compute the error contribution for a range of elements.

May be executed in parallel on separate threads.

Definition at line 93 of file weighted_patch_recovery_error_estimator.h.

Constructor & Destructor Documentation

◆ EstimateError()

libMesh::WeightedPatchRecoveryErrorEstimator::EstimateError::EstimateError ( const System sys,
const WeightedPatchRecoveryErrorEstimator ee,
ErrorVector epc 
)
inline

Definition at line 96 of file weighted_patch_recovery_error_estimator.h.

98  :
99  system(sys),
100  error_estimator(ee),
101  error_per_cell(epc)
102  {}
const System & system
Function to set the boolean patch_reuse in case the user wants to change the default behaviour of pat...

Member Function Documentation

◆ operator()()

void libMesh::WeightedPatchRecoveryErrorEstimator::EstimateError::operator() ( const ConstElemRange range) const

Definition at line 112 of file weighted_patch_recovery_error_estimator.C.

References libMesh::PatchRecoveryErrorEstimator::_extra_order, std::abs(), libMesh::TypeTensor< T >::add_scaled(), libMesh::TypeVector< T >::add_scaled(), libMesh::FEGenericBase< OutputType >::build(), libMesh::Patch::build_around_element(), libMesh::System::current_solution(), libMesh::FEType::default_quadrature_rule(), dim, libMesh::DofMap::dof_indices(), libMesh::Utility::enum_to_string(), error_estimator, libMesh::ErrorEstimator::error_norm, error_per_cell, libMesh::ErrorVectorReal, libMesh::System::get_dof_map(), libMesh::System::get_mesh(), libMesh::H1_SEMINORM, libMesh::H1_X_SEMINORM, libMesh::H1_Y_SEMINORM, libMesh::H1_Z_SEMINORM, libMesh::H2_SEMINORM, libMesh::DofObject::id(), libMesh::L2, libMesh::L_INF, libMesh::libmesh_assert(), libMesh::DenseMatrix< T >::lu_solve(), libMesh::DenseMatrixBase< T >::m(), mesh, libMesh::DenseMatrixBase< T >::n(), n_vars, libMesh::System::n_vars(), libMesh::TensorTools::norm_sq(), libMesh::FEType::order, libMesh::Elem::p_level(), libMesh::PatchRecoveryErrorEstimator::patch_growth_strategy, libMesh::PatchRecoveryErrorEstimator::patch_reuse, libMesh::FEMContext::pre_fe_reinit(), libMesh::Real, libMesh::DenseVector< T >::resize(), libMesh::PatchRecoveryErrorEstimator::specpoly(), libMesh::Threads::spin_mtx, std::sqrt(), system, libMesh::PatchRecoveryErrorEstimator::target_patch_size, libMesh::System::time, libMesh::SystemNorm::type(), libMesh::DofMap::variable_type(), libMesh::W1_INF_SEMINORM, libMesh::W2_INF_SEMINORM, libMesh::MeshTools::weight(), libMesh::SystemNorm::weight(), libMesh::WeightedPatchRecoveryErrorEstimator::weight_functions, libMesh::SystemNorm::weight_sq(), and libMesh::zero.

113 {
114  // The current mesh
115  const MeshBase & mesh = system.get_mesh();
116 
117  // The dimensionality of the mesh
118  const unsigned int dim = mesh.mesh_dimension();
119 
120  // The number of variables in the system
121  const unsigned int n_vars = system.n_vars();
122 
123  // The DofMap for this system
124  const DofMap & dof_map = system.get_dof_map();
125 
126  //------------------------------------------------------------
127  // Iterate over all the elements in the range.
128  for (const auto & elem : range)
129  {
130  // We'll need an index into the error vector
131  const dof_id_type e_id=elem->id();
132 
133  // We are going to build a patch containing the current element
134  // and its neighbors on the local processor
135  Patch patch(mesh.processor_id());
136 
137  // If we are reusing patches and the current element
138  // already has an estimate associated with it, move on the
139  // next element
140  if (this->error_estimator.patch_reuse && error_per_cell[e_id] != 0)
141  continue;
142 
143  // If we are not reusing patches or haven't built one containing this element, we build one
144 
145  // Use user specified patch size and growth strategy
146  patch.build_around_element (elem, error_estimator.target_patch_size,
148 
149  // Declare a new_error_per_cell vector to hold error estimates
150  // from each element in this patch, or one estimate if we are
151  // not reusing patches since we will only be computing error for
152  // one cell
153  std::vector<Real> new_error_per_cell(1, 0.);
154  if (this->error_estimator.patch_reuse)
155  new_error_per_cell.resize(patch.size(), 0.);
156 
157  //------------------------------------------------------------
158  // Process each variable in the system using the current patch
159  for (unsigned int var=0; var<n_vars; var++)
160  {
161  const auto norm_type = error_estimator.error_norm.type(var);
162 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
163 #ifdef DEBUG
164  bool is_valid_norm_type =
165  norm_type == L2 ||
166  norm_type == H1_SEMINORM ||
167  norm_type == H2_SEMINORM ||
168  norm_type == H1_X_SEMINORM ||
169  norm_type == H1_Y_SEMINORM ||
170  norm_type == H1_Z_SEMINORM ||
171  norm_type == L_INF ||
172  norm_type == W1_INF_SEMINORM ||
173  norm_type == W2_INF_SEMINORM;
174  libmesh_assert (is_valid_norm_type);
175 #endif // DEBUG
176 #else
177  libmesh_assert (norm_type == L2 ||
178  norm_type == L_INF ||
179  norm_type == H1_SEMINORM ||
180  norm_type == H1_X_SEMINORM ||
181  norm_type == H1_Y_SEMINORM ||
182  norm_type == H1_Z_SEMINORM ||
183  norm_type == W1_INF_SEMINORM);
184 #endif
185 
186 #ifdef DEBUG
187  if (var > 0)
188  {
189  // We can't mix L_inf and L_2 norms
190  bool is_valid_norm_combo =
191  ((norm_type == L2 ||
192  norm_type == H1_SEMINORM ||
193  norm_type == H1_X_SEMINORM ||
194  norm_type == H1_Y_SEMINORM ||
195  norm_type == H1_Z_SEMINORM ||
196  norm_type == H2_SEMINORM) &&
197  (error_estimator.error_norm.type(var-1) == L2 ||
203  ((norm_type == L_INF ||
204  norm_type == W1_INF_SEMINORM ||
205  norm_type == W2_INF_SEMINORM) &&
206  (error_estimator.error_norm.type(var-1) == L_INF ||
209  libmesh_assert (is_valid_norm_combo);
210  }
211 #endif // DEBUG
212 
213  // Possibly skip this variable
214  if (error_estimator.error_norm.weight(var) == 0.0) continue;
215 
216  // The type of finite element to use for this variable
217  const FEType & fe_type = dof_map.variable_type (var);
218 
219  const Order element_order = static_cast<Order>
220  (fe_type.order + elem->p_level());
221 
222  // Finite element object for use in this patch
223  std::unique_ptr<FEBase> fe (FEBase::build (dim, fe_type));
224 
225  // Build an appropriate Gaussian quadrature rule
226  std::unique_ptr<QBase> qrule =
227  fe_type.default_quadrature_rule(dim, error_estimator._extra_order);
228 
229  // Tell the finite element about the quadrature rule.
230  fe->attach_quadrature_rule (qrule.get());
231 
232  // Get Jacobian values, etc..
233  const std::vector<Real> & JxW = fe->get_JxW();
234  const std::vector<Point> & q_point = fe->get_xyz();
235 
236  // Get whatever phi/dphi/d2phi values we need. Avoid
237  // getting them unless the requested norm is actually going
238  // to use them.
239 
240  const std::vector<std::vector<Real>> * phi = nullptr;
241  // If we're using phi to assert the correct dof_indices
242  // vector size later, then we'll need to get_phi whether we
243  // plan to use it or not.
244 #ifdef NDEBUG
245  if (norm_type == L2 ||
246  norm_type == L_INF)
247 #endif
248  phi = &(fe->get_phi());
249 
250  const std::vector<std::vector<RealGradient>> * dphi = nullptr;
251  if (norm_type == H1_SEMINORM ||
252  norm_type == H1_X_SEMINORM ||
253  norm_type == H1_Y_SEMINORM ||
254  norm_type == H1_Z_SEMINORM ||
255  norm_type == W1_INF_SEMINORM)
256  dphi = &(fe->get_dphi());
257 
258 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
259  const std::vector<std::vector<RealTensor>> * d2phi = nullptr;
260  if (norm_type == H2_SEMINORM ||
261  norm_type == W2_INF_SEMINORM)
262  d2phi = &(fe->get_d2phi());
263 #endif
264 
265  // global DOF indices
266  std::vector<dof_id_type> dof_indices;
267 
268  // Compute the appropriate size for the patch projection matrices
269  // and vectors;
270  unsigned int matsize = element_order + 1;
271  if (dim > 1)
272  {
273  matsize *= (element_order + 2);
274  matsize /= 2;
275  }
276  if (dim > 2)
277  {
278  matsize *= (element_order + 3);
279  matsize /= 3;
280  }
281 
282  DenseMatrix<Number> Kp(matsize,matsize);
283  DenseVector<Number> F, Fx, Fy, Fz, Fxy, Fxz, Fyz;
284  DenseVector<Number> Pu_h, Pu_x_h, Pu_y_h, Pu_z_h, Pu_xy_h, Pu_xz_h, Pu_yz_h;
285  if (norm_type == L2 ||
286  norm_type == L_INF)
287  {
288  F.resize(matsize); Pu_h.resize(matsize);
289  }
290  else if (norm_type == H1_SEMINORM ||
291  norm_type == W1_INF_SEMINORM ||
292  norm_type == H2_SEMINORM ||
293  norm_type == W2_INF_SEMINORM)
294  {
295  Fx.resize(matsize); Pu_x_h.resize(matsize); // stores xx in W2 cases
296 #if LIBMESH_DIM > 1
297  Fy.resize(matsize); Pu_y_h.resize(matsize); // stores yy in W2 cases
298 #endif
299 #if LIBMESH_DIM > 2
300  Fz.resize(matsize); Pu_z_h.resize(matsize); // stores zz in W2 cases
301 #endif
302  }
303  else if (norm_type == H1_X_SEMINORM)
304  {
305  Fx.resize(matsize); Pu_x_h.resize(matsize); // Only need to compute the x gradient for the x component seminorm
306  }
307  else if (norm_type == H1_Y_SEMINORM)
308  {
309  libmesh_assert(LIBMESH_DIM > 1);
310  Fy.resize(matsize); Pu_y_h.resize(matsize); // Only need to compute the y gradient for the y component seminorm
311  }
312  else if (norm_type == H1_Z_SEMINORM)
313  {
314  libmesh_assert(LIBMESH_DIM > 2);
315  Fz.resize(matsize); Pu_z_h.resize(matsize); // Only need to compute the z gradient for the z component seminorm
316  }
317 
318 #if LIBMESH_DIM > 1
319  if (norm_type == H2_SEMINORM ||
320  norm_type == W2_INF_SEMINORM)
321  {
322  Fxy.resize(matsize); Pu_xy_h.resize(matsize);
323 #if LIBMESH_DIM > 2
324  Fxz.resize(matsize); Pu_xz_h.resize(matsize);
325  Fyz.resize(matsize); Pu_yz_h.resize(matsize);
326 #endif
327  }
328 #endif
329 
330 
331  //------------------------------------------------------
332  // Loop over each element in the patch and compute their
333  // contribution to the patch gradient projection.
334  for (const auto & e_p : patch)
335  {
336  // Reinitialize the finite element data for this element
337  fe->reinit (e_p);
338 
339  // Get the global DOF indices for the current variable
340  // in the current element
341  dof_map.dof_indices (e_p, dof_indices, var);
342  libmesh_assert (dof_indices.size() == phi->size());
343 
344  const unsigned int n_dofs =
345  cast_int<unsigned int>(dof_indices.size());
346  const unsigned int n_qp = qrule->n_points();
347 
348  // Compute the weighted projection components from this cell.
349  // \int_{Omega_e} \psi_i \psi_j = \int_{Omega_e} w * du_h/dx_k \psi_i
350  for (unsigned int qp=0; qp<n_qp; qp++)
351  {
352  // Construct the shape function values for the patch projection
353  std::vector<Real> psi(specpoly(dim, element_order, q_point[qp], matsize));
354 
355  const unsigned int psi_size = cast_int<unsigned int>(psi.size());
356 
357  // Patch matrix contribution
358  const unsigned int m = Kp.m(), n = Kp.n();
359  for (unsigned int i=0; i<m; i++)
360  for (unsigned int j=0; j<n; j++)
361  Kp(i,j) += JxW[qp]*psi[i]*psi[j];
362 
363  if (norm_type == L2 ||
364  norm_type == L_INF)
365  {
366  // Compute the solution on the current patch element
367  // the quadrature point
368  Number u_h = libMesh::zero;
369 
370  for (unsigned int i=0; i<n_dofs; i++)
371  u_h += (*phi)[i][qp]*system.current_solution (dof_indices[i]);
372 
373  // Patch RHS contributions
374  for (unsigned int i=0; i != psi_size; i++)
375  F(i) = JxW[qp]*u_h*psi[i];
376 
377  }
378  else if (norm_type == H1_SEMINORM ||
379  norm_type == W1_INF_SEMINORM)
380  {
381  // Compute the gradient on the current patch element
382  // at the quadrature point
383  Gradient grad_u_h;
384 
385  for (std::size_t i=0; i<n_dofs; i++)
386  grad_u_h.add_scaled ((*dphi)[i][qp],
387  system.current_solution(dof_indices[i]));
388 
389 
390 
391  // Patch RHS contributions
392  for (unsigned int i=0; i != psi_size; i++)
393  {
394  Fx(i) += JxW[qp]*grad_u_h(0)*psi[i];
395 #if LIBMESH_DIM > 1
396  Fy(i) += JxW[qp]*grad_u_h(1)*psi[i];
397 #endif
398 #if LIBMESH_DIM > 2
399  Fz(i) += JxW[qp]*grad_u_h(2)*psi[i];
400 #endif
401  }
402  }
403  else if (norm_type == H1_X_SEMINORM)
404  {
405  // Compute the gradient on the current patch element
406  // at the quadrature point
407  Gradient grad_u_h;
408 
409  for (unsigned int i=0; i<n_dofs; i++)
410  grad_u_h.add_scaled ((*dphi)[i][qp],
411  system.current_solution(dof_indices[i]));
412 
413 
414 
415  // Patch RHS contributions
416  for (unsigned int i=0; i != psi_size; i++)
417  {
418  Fx(i) += JxW[qp]*grad_u_h(0)*psi[i];
419  }
420  }
421 #if LIBMESH_DIM > 1
422  else if (norm_type == H1_Y_SEMINORM)
423  {
424  // Compute the gradient on the current patch element
425  // at the quadrature point
426  Gradient grad_u_h;
427 
428  for (unsigned int i=0; i<n_dofs; i++)
429  grad_u_h.add_scaled ((*dphi)[i][qp],
430  system.current_solution(dof_indices[i]));
431 
432 
433 
434  // Patch RHS contributions
435  for (unsigned int i=0; i != psi_size; i++)
436  {
437  Fy(i) += JxW[qp]*grad_u_h(1)*psi[i];
438  }
439  }
440 #endif // LIBMESH_DIM > 1
441 #if LIBMESH_DIM > 2
442  else if (norm_type == H1_Z_SEMINORM)
443  {
444  // Compute the gradient on the current patch element
445  // at the quadrature point
446  Gradient grad_u_h;
447 
448  for (unsigned int i=0; i<n_dofs; i++)
449  grad_u_h.add_scaled ((*dphi)[i][qp],
450  system.current_solution(dof_indices[i]));
451 
452 
453 
454  // Patch RHS contributions
455  for (unsigned int i=0; i != psi_size; i++)
456  {
457  Fz(i) += JxW[qp]*grad_u_h(2)*psi[i];
458  }
459  }
460 #endif // LIBMESH_DIM > 2
461  else if (norm_type == H2_SEMINORM ||
462  norm_type == W2_INF_SEMINORM)
463  {
464 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
465  // Compute the hessian on the current patch element
466  // at the quadrature point
467  Tensor hess_u_h;
468 
469  for (unsigned int i=0; i<n_dofs; i++)
470  hess_u_h.add_scaled ((*d2phi)[i][qp],
471  system.current_solution(dof_indices[i]));
472 
473 
474 
475  // Patch RHS contributions
476  for (unsigned int i=0; i != psi_size; i++)
477  {
478  Fx(i) += JxW[qp]*hess_u_h(0,0)*psi[i];
479 #if LIBMESH_DIM > 1
480  Fy(i) += JxW[qp]*hess_u_h(1,1)*psi[i];
481  Fxy(i) += JxW[qp]*hess_u_h(0,1)*psi[i];
482 #endif
483 #if LIBMESH_DIM > 2
484  Fz(i) += JxW[qp]*hess_u_h(2,2)*psi[i];
485  Fxz(i) += JxW[qp]*hess_u_h(0,2)*psi[i];
486  Fyz(i) += JxW[qp]*hess_u_h(1,2)*psi[i];
487 #endif
488  }
489 #else
490  libmesh_error_msg("ERROR: --enable-second-derivatives is required \nfor _sobolev_order == 2!");
491 #endif
492  }
493  else
494  libmesh_error_msg("Unsupported error norm type == " << Utility::enum_to_string(norm_type));
495  } // end quadrature loop
496  } // end patch loop
497 
498 
499 
500  //--------------------------------------------------
501  // Now we have fully assembled the projection system
502  // for this patch. Project the gradient components.
503  // MAY NEED TO USE PARTIAL PIVOTING!
504  if (norm_type == L2 ||
505  norm_type == L_INF)
506  {
507  Kp.lu_solve(F, Pu_h);
508  }
509  else if (norm_type == H1_SEMINORM ||
510  norm_type == W1_INF_SEMINORM ||
511  norm_type == H2_SEMINORM ||
512  norm_type == W2_INF_SEMINORM)
513  {
514  Kp.lu_solve (Fx, Pu_x_h);
515 #if LIBMESH_DIM > 1
516  Kp.lu_solve (Fy, Pu_y_h);
517 #endif
518 #if LIBMESH_DIM > 2
519  Kp.lu_solve (Fz, Pu_z_h);
520 #endif
521  }
522  else if (norm_type == H1_X_SEMINORM)
523  {
524  Kp.lu_solve (Fx, Pu_x_h);
525  }
526  else if (norm_type == H1_Y_SEMINORM)
527  {
528  Kp.lu_solve (Fy, Pu_y_h);
529  }
530  else if (norm_type == H1_Z_SEMINORM)
531  {
532  Kp.lu_solve (Fz, Pu_z_h);
533  }
534 
535 #if LIBMESH_DIM > 1
536  if (norm_type == H2_SEMINORM ||
537  norm_type == W2_INF_SEMINORM)
538  {
539  Kp.lu_solve(Fxy, Pu_xy_h);
540 #if LIBMESH_DIM > 2
541  Kp.lu_solve(Fxz, Pu_xz_h);
542  Kp.lu_solve(Fyz, Pu_yz_h);
543 #endif
544  }
545 #endif
546 
547  // If we are reusing patches, reuse the current patch to loop
548  // over all elements in the current patch, otherwise build a new
549  // patch containing just the current element and loop over it
550  // Note that C++ will not allow patch_re_end to be a const here
551  Patch::const_iterator patch_re_it;
552  Patch::const_iterator patch_re_end;
553 
554  // Declare a new patch
555  Patch patch_re(mesh.processor_id());
556 
557  if (this->error_estimator.patch_reuse)
558  {
559  // Just get the iterators from the current patch
560  patch_re_it = patch.begin();
561  patch_re_end = patch.end();
562  }
563  else
564  {
565  // Use a target patch size of just 0, this will contain
566  // just the current element
567  patch_re.build_around_element (elem, 0,
569 
570  // Get the iterators from this newly constructed patch
571  patch_re_it = patch_re.begin();
572  patch_re_end = patch_re.end();
573  }
574 
575  // If we are reusing patches, loop over all the elements
576  // in the current patch and develop an estimate
577  // for all the elements by computing || w * (P u_h - u_h)|| or ||w *(P grad_u_h - grad_u_h)||
578  // or ||w * (P hess_u_h - hess_u_h)|| according to the requested
579  // seminorm, otherwise just compute it for the current element
580 
581  // Get an FEMContext for this system, this will help us in
582  // obtaining the weights from the user code.
583  // We don't use full elem_jacobian or subjacobians here.
584  FEMContext femcontext(system, nullptr,
585  /* allocate_local_matrices = */ false);
586  error_estimator.weight_functions[var]->init_context(femcontext);
587 
588  // Loop over every element in the patch
589  for (unsigned int e = 0 ; patch_re_it != patch_re_end; ++patch_re_it, ++e)
590  {
591  // Build the Finite Element for the current element
592 
593  // The pth element in the patch
594  const Elem * e_p = *patch_re_it;
595 
596  // We'll need an index into the error vector for this element
597  const dof_id_type e_p_id = e_p->id();
598 
599  // Initialize the FEMContext
600  femcontext.pre_fe_reinit(system, e_p);
601 
602  // We will update the new_error_per_cell vector with element_error if the
603  // error_per_cell[e_p_id] entry is non-zero, otherwise update it
604  // with 0. i.e. leave it unchanged
605 
606  // No need to compute the estimate if we are reusing patches and already have one
607  if (this->error_estimator.patch_reuse && error_per_cell[e_p_id] != 0.)
608  continue;
609 
610  // Reinitialize the finite element data for this element
611  fe->reinit (e_p);
612 
613  // Get the global DOF indices for the current variable
614  // in the current element
615  dof_map.dof_indices (e_p, dof_indices, var);
616  libmesh_assert (dof_indices.size() == phi->size());
617 
618  // The number of dofs for this variable on this element
619  const unsigned int n_dofs =
620  cast_int<unsigned int>(dof_indices.size());
621 
622  // Variable to hold the error on the current element
623  Real element_error = 0;
624 
625  const Order qorder =
626  static_cast<Order>(fe_type.order + e_p->p_level());
627 
628  // A quadrature rule for this element
629  QGrid samprule (dim, qorder);
630 
631  if (norm_type == W1_INF_SEMINORM ||
632  norm_type == W2_INF_SEMINORM)
633  fe->attach_quadrature_rule (&samprule);
634 
635  // The number of points we will sample over
636  const unsigned int n_sp =
637  cast_int<unsigned int>(JxW.size());
638 
639  // Loop over every sample point for the current element
640  for (unsigned int sp=0; sp<n_sp; sp++)
641  {
642  // Compute the solution at the current sample point
643 
644  std::vector<Number> temperr(6,0.0); // x,y,z or xx,yy,zz,xy,xz,yz
645 
646  if (norm_type == L2 ||
647  norm_type == L_INF)
648  {
649  // Compute the value at the current sample point
650  Number u_h = libMesh::zero;
651 
652  for (unsigned int i=0; i<n_dofs; i++)
653  u_h += (*phi)[i][sp]*system.current_solution (dof_indices[i]);
654 
655  // Compute the phi values at the current sample point
656  std::vector<Real> psi(specpoly(dim, element_order, q_point[sp], matsize));
657  for (unsigned int i=0; i<matsize; i++)
658  {
659  temperr[0] += psi[i]*Pu_h(i);
660  }
661 
662  temperr[0] -= u_h;
663  }
664  else if (norm_type == H1_SEMINORM ||
665  norm_type == W1_INF_SEMINORM)
666  {
667  // Compute the gradient at the current sample point
668  Gradient grad_u_h;
669 
670  for (unsigned int i=0; i<n_dofs; i++)
671  grad_u_h.add_scaled ((*dphi)[i][sp],
672  system.current_solution(dof_indices[i]));
673 
674  // Compute the phi values at the current sample point
675  std::vector<Real> psi(specpoly(dim, element_order, q_point[sp], matsize));
676 
677  for (unsigned int i=0; i<matsize; i++)
678  {
679  temperr[0] += psi[i]*Pu_x_h(i);
680 #if LIBMESH_DIM > 1
681  temperr[1] += psi[i]*Pu_y_h(i);
682 #endif
683 #if LIBMESH_DIM > 2
684  temperr[2] += psi[i]*Pu_z_h(i);
685 #endif
686  }
687  temperr[0] -= grad_u_h(0);
688 #if LIBMESH_DIM > 1
689  temperr[1] -= grad_u_h(1);
690 #endif
691 #if LIBMESH_DIM > 2
692  temperr[2] -= grad_u_h(2);
693 #endif
694  }
695  else if (norm_type == H1_X_SEMINORM)
696  {
697  // Compute the gradient at the current sample point
698  Gradient grad_u_h;
699 
700  for (unsigned int i=0; i<n_dofs; i++)
701  grad_u_h.add_scaled ((*dphi)[i][sp],
702  system.current_solution(dof_indices[i]));
703 
704  // Compute the phi values at the current sample point
705  std::vector<Real> psi(specpoly(dim, element_order, q_point[sp], matsize));
706  for (unsigned int i=0; i<matsize; i++)
707  {
708  temperr[0] += psi[i]*Pu_x_h(i);
709  }
710 
711  temperr[0] -= grad_u_h(0);
712  }
713 #if LIBMESH_DIM > 1
714  else if (norm_type == H1_Y_SEMINORM)
715  {
716  // Compute the gradient at the current sample point
717  Gradient grad_u_h;
718 
719  for (unsigned int i=0; i<n_dofs; i++)
720  grad_u_h.add_scaled ((*dphi)[i][sp],
721  system.current_solution(dof_indices[i]));
722 
723  // Compute the phi values at the current sample point
724  std::vector<Real> psi(specpoly(dim, element_order, q_point[sp], matsize));
725  for (unsigned int i=0; i<matsize; i++)
726  {
727  temperr[1] += psi[i]*Pu_y_h(i);
728  }
729 
730  temperr[1] -= grad_u_h(1);
731  }
732 #endif // LIBMESH_DIM > 1
733 #if LIBMESH_DIM > 2
734  else if (norm_type == H1_Z_SEMINORM)
735  {
736  // Compute the gradient at the current sample point
737  Gradient grad_u_h;
738 
739  for (unsigned int i=0; i<n_dofs; i++)
740  grad_u_h.add_scaled ((*dphi)[i][sp],
741  system.current_solution(dof_indices[i]));
742 
743  // Compute the phi values at the current sample point
744  std::vector<Real> psi(specpoly(dim, element_order, q_point[sp], matsize));
745  for (unsigned int i=0; i<matsize; i++)
746  {
747  temperr[2] += psi[i]*Pu_z_h(i);
748  }
749 
750  temperr[2] -= grad_u_h(2);
751  }
752 #endif // LIBMESH_DIM > 2
753  else if (norm_type == H2_SEMINORM ||
754  norm_type == W2_INF_SEMINORM)
755  {
756 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
757  // Compute the Hessian at the current sample point
758  Tensor hess_u_h;
759 
760  for (unsigned int i=0; i<n_dofs; i++)
761  hess_u_h.add_scaled ((*d2phi)[i][sp],
762  system.current_solution(dof_indices[i]));
763 
764  // Compute the phi values at the current sample point
765  std::vector<Real> psi(specpoly(dim, element_order, q_point[sp], matsize));
766  for (unsigned int i=0; i<matsize; i++)
767  {
768  temperr[0] += psi[i]*Pu_x_h(i);
769 #if LIBMESH_DIM > 1
770  temperr[1] += psi[i]*Pu_y_h(i);
771  temperr[3] += psi[i]*Pu_xy_h(i);
772 #endif
773 #if LIBMESH_DIM > 2
774  temperr[2] += psi[i]*Pu_z_h(i);
775  temperr[4] += psi[i]*Pu_xz_h(i);
776  temperr[5] += psi[i]*Pu_yz_h(i);
777 #endif
778  }
779 
780  temperr[0] -= hess_u_h(0,0);
781 #if LIBMESH_DIM > 1
782  temperr[1] -= hess_u_h(1,1);
783  temperr[3] -= hess_u_h(0,1);
784 #endif
785 #if LIBMESH_DIM > 2
786  temperr[2] -= hess_u_h(2,2);
787  temperr[4] -= hess_u_h(0,2);
788  temperr[5] -= hess_u_h(1,2);
789 #endif
790 #else
791  libmesh_error_msg("ERROR: --enable-second-derivatives is required \nfor _sobolev_order == 2!");
792 #endif
793  }
794 
795  // Get the weight from the user code
796  Number weight = (*error_estimator.weight_functions[var])(femcontext, q_point[sp], system.time);
797 
798  // Add up relevant terms. We can easily optimize the
799  // LIBMESH_DIM < 3 cases a little bit with the exception
800  // of the W2 cases
801 
802  if (norm_type == L_INF)
803  element_error = std::max(element_error, std::abs(weight*temperr[0]));
804  else if (norm_type == W1_INF_SEMINORM)
805  for (unsigned int i=0; i != LIBMESH_DIM; ++i)
806  element_error = std::max(element_error, std::abs(weight*temperr[i]));
807  else if (norm_type == W2_INF_SEMINORM)
808  for (unsigned int i=0; i != 6; ++i)
809  element_error = std::max(element_error, std::abs(weight*temperr[i]));
810  else if (norm_type == L2)
811  element_error += JxW[sp]*TensorTools::norm_sq(weight*temperr[0]);
812  else if (norm_type == H1_SEMINORM)
813  for (unsigned int i=0; i != LIBMESH_DIM; ++i)
814  element_error += JxW[sp]*TensorTools::norm_sq(weight*temperr[i]);
815  else if (norm_type == H1_X_SEMINORM)
816  element_error += JxW[sp]*TensorTools::norm_sq(weight*temperr[0]);
817  else if (norm_type == H1_Y_SEMINORM)
818  element_error += JxW[sp]*TensorTools::norm_sq(weight*temperr[1]);
819  else if (norm_type == H1_Z_SEMINORM)
820  element_error += JxW[sp]*TensorTools::norm_sq(weight*temperr[2]);
821  else if (norm_type == H2_SEMINORM)
822  {
823  for (unsigned int i=0; i != LIBMESH_DIM; ++i)
824  element_error += JxW[sp]*TensorTools::norm_sq(weight*temperr[i]);
825  // Off diagonal terms enter into the Hessian norm twice
826  for (unsigned int i=3; i != 6; ++i)
827  element_error += JxW[sp]*2*TensorTools::norm_sq(weight*temperr[i]);
828  }
829 
830  } // End loop over sample points
831 
832  if (norm_type == L_INF ||
833  norm_type == W1_INF_SEMINORM ||
834  norm_type == W2_INF_SEMINORM)
835  new_error_per_cell[e] += error_estimator.error_norm.weight(var) * element_error;
836  else if (norm_type == L2 ||
837  norm_type == H1_SEMINORM ||
838  norm_type == H1_X_SEMINORM ||
839  norm_type == H1_Y_SEMINORM ||
840  norm_type == H1_Z_SEMINORM ||
841  norm_type == H2_SEMINORM)
842  new_error_per_cell[e] += error_estimator.error_norm.weight_sq(var) * element_error;
843  else
844  libmesh_error_msg("Unsupported error norm type == " << Utility::enum_to_string(norm_type));
845  } // End (re) loop over patch elements
846 
847  } // end variables loop
848 
849  // Now that we have the contributions from each variable,
850  // we have take square roots of the entries we
851  // added to error_per_cell to get an error norm
852  // If we are reusing patches, once again reuse the current patch to loop
853  // over all elements in the current patch, otherwise build a new
854  // patch containing just the current element and loop over it
855  Patch::const_iterator patch_re_it;
856  Patch::const_iterator patch_re_end;
857 
858  // Build a new patch if necessary
859  Patch current_elem_patch(mesh.processor_id());
860 
861  if (this->error_estimator.patch_reuse)
862  {
863  // Just get the iterators from the current patch
864  patch_re_it = patch.begin();
865  patch_re_end = patch.end();
866  }
867  else
868  {
869  // Use a target patch size of just 0, this will contain
870  // just the current element.
871  current_elem_patch.build_around_element (elem, 0,
873 
874  // Get the iterators from this newly constructed patch
875  patch_re_it = current_elem_patch.begin();
876  patch_re_end = current_elem_patch.end();
877  }
878 
879  // Loop over every element in the patch we just constructed
880  for (unsigned int i = 0 ; patch_re_it != patch_re_end; ++patch_re_it, ++i)
881  {
882  // The pth element in the patch
883  const Elem * e_p = *patch_re_it;
884 
885  // We'll need an index into the error vector
886  const dof_id_type e_p_id = e_p->id();
887 
888  // Update the error_per_cell vector for this element
889  if (error_estimator.error_norm.type(0) == L2 ||
895  {
896  Threads::spin_mutex::scoped_lock acquire(Threads::spin_mtx);
897  if (!error_per_cell[e_p_id])
898  error_per_cell[e_p_id] = static_cast<ErrorVectorReal>
899  (std::sqrt(new_error_per_cell[i]));
900  }
901  else
902  {
906  Threads::spin_mutex::scoped_lock acquire(Threads::spin_mtx);
907  if (!error_per_cell[e_p_id])
908  error_per_cell[e_p_id] = static_cast<ErrorVectorReal>
909  (new_error_per_cell[i]);
910  }
911 
912  } // End loop over every element in patch
913 
914 
915  } // end element loop
916 
917 } // End () operator definition
Real time
For time-dependent problems, this is the time t at the beginning of the current timestep.
Definition: system.h:1595
void add_scaled(const TypeVector< T2 > &, const T &)
Add a scaled value to this vector without creating a temporary.
Definition: type_vector.h:651
Order
defines an enum for polynomial orders.
Definition: enum_order.h:40
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...
unsigned int dim
const System & system
Function to set the boolean patch_reuse in case the user wants to change the default behaviour of pat...
MeshBase & mesh
ADRealEigenVector< T, D, asd > sqrt(const ADRealEigenVector< T, D, asd > &)
Definition: type_vector.h:53
const Number zero
.
Definition: libmesh.h:280
const MeshBase & get_mesh() const
Definition: system.h:2277
DIE A HORRIBLE DEATH HERE typedef float ErrorVectorReal
Number current_solution(const dof_id_type global_dof_number) const
Definition: system.C:157
ADRealEigenVector< T, D, asd > abs(const ADRealEigenVector< T, D, asd > &)
Definition: type_vector.h:57
unsigned int n_vars
dof_id_type weight(const MeshBase &mesh, const processor_id_type pid)
Definition: mesh_tools.C:436
FEMNormType type(unsigned int var) const
Definition: system_norm.C:112
NumberVectorValue Gradient
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
libmesh_assert(ctx)
unsigned int target_patch_size
The PatchErrorEstimator will build patches of at least this many elements to perform estimates...
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.
Definition: type_tensor.h:851
std::string enum_to_string(const T e)
Real weight_sq(unsigned int var) const
Definition: system_norm.C:177
Real weight(unsigned int var) const
Definition: system_norm.C:134
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
NumberTensorValue Tensor
auto norm_sq(const T &a) -> decltype(std::norm(a))
Definition: tensor_tools.h:104
std::vector< FEMFunctionBase< Number > * > weight_functions
Vector of fem function base pointers, the user will fill this in with pointers to the appropriate wei...
int _extra_order
Extra order to use for quadrature rule.
unsigned int n_vars() const
Definition: system.h:2349
const DofMap & get_dof_map() const
Definition: system.h:2293
uint8_t dof_id_type
Definition: id_types.h:67
spin_mutex spin_mtx
A convenient spin mutex object which can be used for obtaining locks.
Definition: threads.C:30

Member Data Documentation

◆ error_estimator

const WeightedPatchRecoveryErrorEstimator& libMesh::WeightedPatchRecoveryErrorEstimator::EstimateError::error_estimator
private

Definition at line 114 of file weighted_patch_recovery_error_estimator.h.

Referenced by operator()().

◆ error_per_cell

ErrorVector& libMesh::WeightedPatchRecoveryErrorEstimator::EstimateError::error_per_cell
private

Definition at line 115 of file weighted_patch_recovery_error_estimator.h.

Referenced by operator()().

◆ system

const System& libMesh::WeightedPatchRecoveryErrorEstimator::EstimateError::system
private

Function to set the boolean patch_reuse in case the user wants to change the default behaviour of patch_recovery_error_estimator.

Definition at line 113 of file weighted_patch_recovery_error_estimator.h.

Referenced by operator()().


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