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

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

Public Member Functions

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

Private Attributes

const Systemsystem
 
const PatchRecoveryErrorEstimatorerror_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 130 of file patch_recovery_error_estimator.h.

Constructor & Destructor Documentation

◆ EstimateError()

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

Member Function Documentation

◆ operator()()

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

Definition at line 211 of file 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::Real, libMesh::DenseVector< T >::resize(), libMesh::PatchRecoveryErrorEstimator::specpoly(), libMesh::Threads::spin_mtx, std::sqrt(), system, libMesh::PatchRecoveryErrorEstimator::target_patch_size, libMesh::SystemNorm::type(), libMesh::DofMap::variable_type(), libMesh::W1_INF_SEMINORM, libMesh::W2_INF_SEMINORM, libMesh::SystemNorm::weight(), libMesh::SystemNorm::weight_sq(), and libMesh::zero.

212 {
213  // The current mesh
214  const MeshBase & mesh = system.get_mesh();
215 
216  // The dimensionality of the mesh
217  const unsigned int dim = mesh.mesh_dimension();
218 
219  // The number of variables in the system
220  const unsigned int n_vars = system.n_vars();
221 
222  // The DofMap for this system
223  const DofMap & dof_map = system.get_dof_map();
224 
225  //------------------------------------------------------------
226  // Iterate over all the elements in the range.
227  for (const auto & elem : range)
228  {
229  // We'll need an index into the error vector
230  const dof_id_type e_id=elem->id();
231 
232  // We are going to build a patch containing the current element
233  // and its neighbors on the local processor
234  Patch patch(mesh.processor_id());
235 
236  // If we are reusing patches and the current element
237  // already has an estimate associated with it, move on the
238  // next element
239  if (this->error_estimator.patch_reuse && error_per_cell[e_id] != 0)
240  continue;
241 
242  // If we are not reusing patches or haven't built one containing this element, we build one
243 
244  // Use user specified patch size and growth strategy
245  patch.build_around_element (elem, error_estimator.target_patch_size,
247 
248  // Declare a new_error_per_cell vector to hold error estimates
249  // from each element in this patch, or one estimate if we are
250  // not reusing patches since we will only be computing error for
251  // one cell
252  std::vector<Real> new_error_per_cell(1, 0.);
253  if (this->error_estimator.patch_reuse)
254  new_error_per_cell.resize(patch.size(), 0.);
255 
256  //------------------------------------------------------------
257  // Process each variable in the system using the current patch
258  for (unsigned int var=0; var<n_vars; var++)
259  {
260  const auto norm_type = error_estimator.error_norm.type(var);
261 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
262 #ifdef DEBUG
263  bool is_valid_norm_type =
264  norm_type == L2 ||
265  norm_type == H1_SEMINORM ||
266  norm_type == H2_SEMINORM ||
267  norm_type == H1_X_SEMINORM ||
268  norm_type == H1_Y_SEMINORM ||
269  norm_type == H1_Z_SEMINORM ||
270  norm_type == L_INF ||
271  norm_type == W1_INF_SEMINORM ||
272  norm_type == W2_INF_SEMINORM;
273  libmesh_assert (is_valid_norm_type);
274 #endif // DEBUG
275 #else
276  libmesh_assert (norm_type == L2 ||
277  norm_type == L_INF ||
278  norm_type == H1_SEMINORM ||
279  norm_type == H1_X_SEMINORM ||
280  norm_type == H1_Y_SEMINORM ||
281  norm_type == H1_Z_SEMINORM ||
282  norm_type == W1_INF_SEMINORM);
283 #endif
284 
285 
286 #ifdef DEBUG
287  if (var > 0)
288  {
289  // We can't mix L_inf and L_2 norms
290  bool is_valid_norm_combo =
291  ((norm_type == L2 ||
292  norm_type == H1_SEMINORM ||
293  norm_type == H1_X_SEMINORM ||
294  norm_type == H1_Y_SEMINORM ||
295  norm_type == H1_Z_SEMINORM ||
296  norm_type == H2_SEMINORM) &&
297  (error_estimator.error_norm.type(var-1) == L2 ||
303  ((norm_type == L_INF ||
304  norm_type == W1_INF_SEMINORM ||
305  norm_type == W2_INF_SEMINORM) &&
306  (error_estimator.error_norm.type(var-1) == L_INF ||
309  libmesh_assert (is_valid_norm_combo);
310  }
311 #endif // DEBUG
312 
313  // Possibly skip this variable
314  if (error_estimator.error_norm.weight(var) == 0.0) continue;
315 
316  // The type of finite element to use for this variable
317  const FEType & fe_type = dof_map.variable_type (var);
318 
319  const Order element_order = static_cast<Order>
320  (fe_type.order + elem->p_level());
321 
322  // Finite element object for use in this patch
323  std::unique_ptr<FEBase> fe (FEBase::build (dim, fe_type));
324 
325  // Build an appropriate Gaussian quadrature rule
326  std::unique_ptr<QBase> qrule (fe_type.default_quadrature_rule(dim, error_estimator._extra_order));
327 
328  // Tell the finite element about the quadrature rule.
329  fe->attach_quadrature_rule (qrule.get());
330 
331  // Get Jacobian values, etc..
332  const std::vector<Real> & JxW = fe->get_JxW();
333  const std::vector<Point> & q_point = fe->get_xyz();
334 
335  // Get whatever phi/dphi/d2phi values we need. Avoid
336  // getting them unless the requested norm is actually going
337  // to use them.
338 
339  const std::vector<std::vector<Real>> * phi = nullptr;
340  // If we're using phi to assert the correct dof_indices
341  // vector size later, then we'll need to get_phi whether we
342  // plan to use it or not.
343 #ifdef NDEBUG
344  if (norm_type == L2 ||
345  norm_type == L_INF)
346 #endif
347  phi = &(fe->get_phi());
348 
349  const std::vector<std::vector<RealGradient>> * dphi = nullptr;
350  if (norm_type == H1_SEMINORM ||
351  norm_type == H1_X_SEMINORM ||
352  norm_type == H1_Y_SEMINORM ||
353  norm_type == H1_Z_SEMINORM ||
354  norm_type == W1_INF_SEMINORM)
355  dphi = &(fe->get_dphi());
356 
357 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
358  const std::vector<std::vector<RealTensor>> * d2phi = nullptr;
359  if (norm_type == H2_SEMINORM ||
360  norm_type == W2_INF_SEMINORM)
361  d2phi = &(fe->get_d2phi());
362 #endif
363 
364  // global DOF indices
365  std::vector<dof_id_type> dof_indices;
366 
367  // Compute the appropriate size for the patch projection matrices
368  // and vectors;
369  unsigned int matsize = element_order + 1;
370  if (dim > 1)
371  {
372  matsize *= (element_order + 2);
373  matsize /= 2;
374  }
375  if (dim > 2)
376  {
377  matsize *= (element_order + 3);
378  matsize /= 3;
379  }
380 
381  DenseMatrix<Number> Kp(matsize,matsize);
382  DenseVector<Number> F, Fx, Fy, Fz, Fxy, Fxz, Fyz;
383  DenseVector<Number> Pu_h, Pu_x_h, Pu_y_h, Pu_z_h, Pu_xy_h, Pu_xz_h, Pu_yz_h;
384  if (norm_type == L2 ||
385  norm_type == L_INF)
386  {
387  F.resize(matsize); Pu_h.resize(matsize);
388  }
389  else if (norm_type == H1_SEMINORM ||
390  norm_type == W1_INF_SEMINORM ||
391  norm_type == H2_SEMINORM ||
392  norm_type == W2_INF_SEMINORM)
393  {
394  Fx.resize(matsize); Pu_x_h.resize(matsize); // stores xx in W2 cases
395 #if LIBMESH_DIM > 1
396  Fy.resize(matsize); Pu_y_h.resize(matsize); // stores yy in W2 cases
397 #endif
398 #if LIBMESH_DIM > 2
399  Fz.resize(matsize); Pu_z_h.resize(matsize); // stores zz in W2 cases
400 #endif
401  }
402  else if (norm_type == H1_X_SEMINORM)
403  {
404  Fx.resize(matsize); Pu_x_h.resize(matsize); // Only need to compute the x gradient for the x component seminorm
405  }
406  else if (norm_type == H1_Y_SEMINORM)
407  {
408  libmesh_assert_greater (LIBMESH_DIM, 1);
409  Fy.resize(matsize); Pu_y_h.resize(matsize); // Only need to compute the y gradient for the y component seminorm
410  }
411  else if (norm_type == H1_Z_SEMINORM)
412  {
413  libmesh_assert_greater (LIBMESH_DIM, 2);
414  Fz.resize(matsize); Pu_z_h.resize(matsize); // Only need to compute the z gradient for the z component seminorm
415  }
416 
417 #if LIBMESH_DIM > 1
418  if (norm_type == H2_SEMINORM ||
419  norm_type == W2_INF_SEMINORM)
420  {
421  Fxy.resize(matsize); Pu_xy_h.resize(matsize);
422 #if LIBMESH_DIM > 2
423  Fxz.resize(matsize); Pu_xz_h.resize(matsize);
424  Fyz.resize(matsize); Pu_yz_h.resize(matsize);
425 #endif
426  }
427 #endif
428 
429  //------------------------------------------------------
430  // Loop over each element in the patch and compute their
431  // contribution to the patch gradient projection.
432  for (const auto & e_p : patch)
433  {
434  // Reinitialize the finite element data for this element
435  fe->reinit (e_p);
436 
437  // Get the global DOF indices for the current variable
438  // in the current element
439  dof_map.dof_indices (e_p, dof_indices, var);
440  libmesh_assert_equal_to (dof_indices.size(), phi->size());
441 
442  const unsigned int n_dofs =
443  cast_int<unsigned int>(dof_indices.size());
444  const unsigned int n_qp = qrule->n_points();
445 
446  // Compute the projection components from this cell.
447  // \int_{Omega_e} \psi_i \psi_j = \int_{Omega_e} du_h/dx_k \psi_i
448  for (unsigned int qp=0; qp<n_qp; qp++)
449  {
450  // Construct the shape function values for the patch projection
451  std::vector<Real> psi(specpoly(dim, element_order, q_point[qp], matsize));
452 
453  const unsigned int psi_size = cast_int<unsigned int>(psi.size());
454 
455  // Patch matrix contribution
456  const unsigned int m = Kp.m(), n = Kp.n();
457  for (unsigned int i=0; i<m; i++)
458  for (unsigned int j=0; j<n; j++)
459  Kp(i,j) += JxW[qp]*psi[i]*psi[j];
460 
461  if (norm_type == L2 ||
462  norm_type == L_INF)
463  {
464  // Compute the solution on the current patch element
465  // the quadrature point
466  Number u_h = libMesh::zero;
467 
468  for (unsigned int i=0; i<n_dofs; i++)
469  u_h += (*phi)[i][qp]*system.current_solution (dof_indices[i]);
470 
471  // Patch RHS contributions
472  for (unsigned int i=0; i != psi_size; i++)
473  F(i) += JxW[qp]*u_h*psi[i];
474 
475  }
476  else if (norm_type == H1_SEMINORM ||
477  norm_type == W1_INF_SEMINORM)
478  {
479  // Compute the gradient on the current patch element
480  // at the quadrature point
481  Gradient grad_u_h;
482 
483  for (unsigned int i=0; i<n_dofs; i++)
484  grad_u_h.add_scaled ((*dphi)[i][qp],
485  system.current_solution(dof_indices[i]));
486 
487  // Patch RHS contributions
488  for (unsigned int i=0; i != psi_size; i++)
489  {
490  Fx(i) += JxW[qp]*grad_u_h(0)*psi[i];
491 #if LIBMESH_DIM > 1
492  Fy(i) += JxW[qp]*grad_u_h(1)*psi[i];
493 #endif
494 #if LIBMESH_DIM > 2
495  Fz(i) += JxW[qp]*grad_u_h(2)*psi[i];
496 #endif
497  }
498  }
499  else if (norm_type == H1_X_SEMINORM)
500  {
501  // Compute the gradient on the current patch element
502  // at the quadrature point
503  Gradient grad_u_h;
504 
505  for (unsigned int i=0; i<n_dofs; i++)
506  grad_u_h.add_scaled ((*dphi)[i][qp],
507  system.current_solution(dof_indices[i]));
508 
509  // Patch RHS contributions
510  for (unsigned int i=0; i != psi_size; i++)
511  {
512  Fx(i) += JxW[qp]*grad_u_h(0)*psi[i];
513  }
514  }
515 #if LIBMESH_DIM > 1
516  else if (norm_type == H1_Y_SEMINORM)
517  {
518  // Compute the gradient on the current patch element
519  // at the quadrature point
520  Gradient grad_u_h;
521 
522  for (unsigned int i=0; i<n_dofs; i++)
523  grad_u_h.add_scaled ((*dphi)[i][qp],
524  system.current_solution(dof_indices[i]));
525 
526  // Patch RHS contributions
527  for (unsigned int i=0; i != psi_size; i++)
528  {
529  Fy(i) += JxW[qp]*grad_u_h(1)*psi[i];
530  }
531  }
532 #endif // LIBMESH_DIM > 1
533 #if LIBMESH_DIM > 2
534  else if (norm_type == H1_Z_SEMINORM)
535  {
536  // Compute the gradient on the current patch element
537  // at the quadrature point
538  Gradient grad_u_h;
539 
540  for (unsigned int i=0; i<n_dofs; i++)
541  grad_u_h.add_scaled ((*dphi)[i][qp],
542  system.current_solution(dof_indices[i]));
543 
544  // Patch RHS contributions
545  for (unsigned int i=0; i != psi_size; i++)
546  {
547  Fz(i) += JxW[qp]*grad_u_h(2)*psi[i];
548  }
549  }
550 #endif // LIBMESH_DIM > 2
551  else if (norm_type == H2_SEMINORM ||
552  norm_type == W2_INF_SEMINORM)
553  {
554 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
555  // Compute the hessian on the current patch element
556  // at the quadrature point
557  Tensor hess_u_h;
558 
559  for (unsigned int i=0; i<n_dofs; i++)
560  hess_u_h.add_scaled ((*d2phi)[i][qp],
561  system.current_solution(dof_indices[i]));
562 
563  // Patch RHS contributions
564  for (unsigned int i=0; i != psi_size; i++)
565  {
566  Fx(i) += JxW[qp]*hess_u_h(0,0)*psi[i];
567 #if LIBMESH_DIM > 1
568  Fy(i) += JxW[qp]*hess_u_h(1,1)*psi[i];
569  Fxy(i) += JxW[qp]*hess_u_h(0,1)*psi[i];
570 #endif
571 #if LIBMESH_DIM > 2
572  Fz(i) += JxW[qp]*hess_u_h(2,2)*psi[i];
573  Fxz(i) += JxW[qp]*hess_u_h(0,2)*psi[i];
574  Fyz(i) += JxW[qp]*hess_u_h(1,2)*psi[i];
575 #endif
576  }
577 #else
578  libmesh_error_msg("ERROR: --enable-second-derivatives is required \nfor _sobolev_order == 2!");
579 #endif
580  }
581  else
582  libmesh_error_msg("Unsupported error norm type == " << Utility::enum_to_string(norm_type));
583  } // end quadrature loop
584  } // end patch loop
585 
586 
587 
588  //--------------------------------------------------
589  // Now we have fully assembled the projection system
590  // for this patch. Project the gradient components.
591  // MAY NEED TO USE PARTIAL PIVOTING!
592  if (norm_type == L2 ||
593  norm_type == L_INF)
594  {
595  Kp.lu_solve(F, Pu_h);
596  }
597  else if (norm_type == H1_SEMINORM ||
598  norm_type == W1_INF_SEMINORM ||
599  norm_type == H2_SEMINORM ||
600  norm_type == W2_INF_SEMINORM)
601  {
602  Kp.lu_solve (Fx, Pu_x_h);
603 #if LIBMESH_DIM > 1
604  Kp.lu_solve (Fy, Pu_y_h);
605 #endif
606 #if LIBMESH_DIM > 2
607  Kp.lu_solve (Fz, Pu_z_h);
608 #endif
609  }
610  else if (norm_type == H1_X_SEMINORM)
611  {
612  Kp.lu_solve (Fx, Pu_x_h);
613  }
614  else if (norm_type == H1_Y_SEMINORM)
615  {
616  Kp.lu_solve (Fy, Pu_y_h);
617  }
618  else if (norm_type == H1_Z_SEMINORM)
619  {
620  Kp.lu_solve (Fz, Pu_z_h);
621  }
622 
623 #if LIBMESH_DIM > 1
624  if (norm_type == H2_SEMINORM ||
625  norm_type == W2_INF_SEMINORM)
626  {
627  Kp.lu_solve(Fxy, Pu_xy_h);
628 #if LIBMESH_DIM > 2
629  Kp.lu_solve(Fxz, Pu_xz_h);
630  Kp.lu_solve(Fyz, Pu_yz_h);
631 #endif
632  }
633 #endif
634 
635  // If we are reusing patches, reuse the current patch to loop
636  // over all elements in the current patch, otherwise build a new
637  // patch containing just the current element and loop over it
638  // Note that C++ will not allow patch_re_end to be a const here
639  Patch::const_iterator patch_re_it;
640  Patch::const_iterator patch_re_end;
641 
642  // Declare a new patch
643  Patch patch_re(mesh.processor_id());
644 
645  if (this->error_estimator.patch_reuse)
646  {
647  // Just get the iterators from the current patch
648  patch_re_it = patch.begin();
649  patch_re_end = patch.end();
650  }
651  else
652  {
653  // Use a target patch size of just 0, this will contain
654  // just the current element
655  patch_re.build_around_element (elem, 0,
657 
658  // Get the iterators from this newly constructed patch
659  patch_re_it = patch_re.begin();
660  patch_re_end = patch_re.end();
661  }
662 
663  // If we are reusing patches, loop over all the elements
664  // in the current patch and develop an estimate
665  // for all the elements by computing ||P u_h - u_h|| or ||P grad_u_h - grad_u_h||
666  // or ||P hess_u_h - hess_u_h|| according to the requested
667  // seminorm, otherwise just compute it for the current element
668 
669  // Loop over every element in the patch
670  for (unsigned int e = 0 ; patch_re_it != patch_re_end; ++patch_re_it, ++e)
671  {
672  // Build the Finite Element for the current element
673 
674  // The pth element in the patch
675  const Elem * e_p = *patch_re_it;
676 
677  // We'll need an index into the error vector for this element
678  const dof_id_type e_p_id = e_p->id();
679 
680  // We will update the new_error_per_cell vector with element_error if the
681  // error_per_cell[e_p_id] entry is non-zero, otherwise update it
682  // with 0. i.e. leave it unchanged
683 
684  // No need to compute the estimate if we are reusing patches and already have one
685  if (this->error_estimator.patch_reuse && error_per_cell[e_p_id] != 0.)
686  continue;
687 
688  // Reinitialize the finite element data for this element
689  fe->reinit (e_p);
690 
691  // Get the global DOF indices for the current variable
692  // in the current element
693  dof_map.dof_indices (e_p, dof_indices, var);
694  libmesh_assert_equal_to (dof_indices.size(), phi->size());
695 
696  // The number of dofs for this variable on this element
697  const unsigned int n_dofs =
698  cast_int<unsigned int>(dof_indices.size());
699 
700  // Variable to hold the error on the current element
701  Real element_error = 0;
702 
703  const Order qorder =
704  static_cast<Order>(fe_type.order + e_p->p_level());
705 
706  // A quadrature rule for this element
707  QGrid samprule (dim, qorder);
708 
709  if (norm_type == W1_INF_SEMINORM ||
710  norm_type == W2_INF_SEMINORM)
711  fe->attach_quadrature_rule (&samprule);
712 
713  // The number of points we will sample over
714  const unsigned int n_sp =
715  cast_int<unsigned int>(JxW.size());
716 
717  // Loop over every sample point for the current element
718  for (unsigned int sp=0; sp<n_sp; sp++)
719  {
720  // Compute the solution at the current sample point
721 
722  std::vector<Number> temperr(6,0.0); // x,y,z or xx,yy,zz,xy,xz,yz
723 
724  if (norm_type == L2 ||
725  norm_type == L_INF)
726  {
727  // Compute the value at the current sample point
728  Number u_h = libMesh::zero;
729 
730  for (unsigned int i=0; i<n_dofs; i++)
731  u_h += (*phi)[i][sp]*system.current_solution (dof_indices[i]);
732 
733  // Compute the phi values at the current sample point
734  std::vector<Real> psi(specpoly(dim, element_order, q_point[sp], matsize));
735  for (unsigned int i=0; i<matsize; i++)
736  {
737  temperr[0] += psi[i]*Pu_h(i);
738  }
739 
740  temperr[0] -= u_h;
741  }
742  else if (norm_type == H1_SEMINORM ||
743  norm_type == W1_INF_SEMINORM)
744  {
745  // Compute the gradient at the current sample point
746  Gradient grad_u_h;
747 
748  for (unsigned int i=0; i<n_dofs; i++)
749  grad_u_h.add_scaled ((*dphi)[i][sp],
750  system.current_solution(dof_indices[i]));
751 
752  // Compute the phi values at the current sample point
753  std::vector<Real> psi(specpoly(dim, element_order, q_point[sp], matsize));
754 
755  for (unsigned int i=0; i<matsize; i++)
756  {
757  temperr[0] += psi[i]*Pu_x_h(i);
758 #if LIBMESH_DIM > 1
759  temperr[1] += psi[i]*Pu_y_h(i);
760 #endif
761 #if LIBMESH_DIM > 2
762  temperr[2] += psi[i]*Pu_z_h(i);
763 #endif
764  }
765  temperr[0] -= grad_u_h(0);
766 #if LIBMESH_DIM > 1
767  temperr[1] -= grad_u_h(1);
768 #endif
769 #if LIBMESH_DIM > 2
770  temperr[2] -= grad_u_h(2);
771 #endif
772  }
773  else if (norm_type == H1_X_SEMINORM)
774  {
775  // Compute the gradient at the current sample point
776  Gradient grad_u_h;
777 
778  for (unsigned int i=0; i<n_dofs; i++)
779  grad_u_h.add_scaled ((*dphi)[i][sp],
780  system.current_solution(dof_indices[i]));
781 
782  // Compute the phi values at the current sample point
783  std::vector<Real> psi(specpoly(dim, element_order, q_point[sp], matsize));
784  for (unsigned int i=0; i<matsize; i++)
785  {
786  temperr[0] += psi[i]*Pu_x_h(i);
787  }
788 
789  temperr[0] -= grad_u_h(0);
790  }
791 #if LIBMESH_DIM > 1
792  else if (norm_type == H1_Y_SEMINORM)
793  {
794  // Compute the gradient at the current sample point
795  Gradient grad_u_h;
796 
797  for (unsigned int i=0; i<n_dofs; i++)
798  grad_u_h.add_scaled ((*dphi)[i][sp],
799  system.current_solution(dof_indices[i]));
800 
801  // Compute the phi values at the current sample point
802  std::vector<Real> psi(specpoly(dim, element_order, q_point[sp], matsize));
803  for (unsigned int i=0; i<matsize; i++)
804  {
805  temperr[1] += psi[i]*Pu_y_h(i);
806  }
807 
808  temperr[1] -= grad_u_h(1);
809  }
810 #endif // LIBMESH_DIM > 1
811 #if LIBMESH_DIM > 2
812  else if (norm_type == H1_Z_SEMINORM)
813  {
814  // Compute the gradient at the current sample point
815  Gradient grad_u_h;
816 
817  for (unsigned int i=0; i<n_dofs; i++)
818  grad_u_h.add_scaled ((*dphi)[i][sp],
819  system.current_solution(dof_indices[i]));
820 
821  // Compute the phi values at the current sample point
822  std::vector<Real> psi(specpoly(dim, element_order, q_point[sp], matsize));
823  for (unsigned int i=0; i<matsize; i++)
824  {
825  temperr[2] += psi[i]*Pu_z_h(i);
826  }
827 
828  temperr[2] -= grad_u_h(2);
829  }
830 #endif // LIBMESH_DIM > 2
831  else if (norm_type == H2_SEMINORM ||
832  norm_type == W2_INF_SEMINORM)
833  {
834 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
835  // Compute the Hessian at the current sample point
836  Tensor hess_u_h;
837 
838  for (unsigned int i=0; i<n_dofs; i++)
839  hess_u_h.add_scaled ((*d2phi)[i][sp],
840  system.current_solution(dof_indices[i]));
841 
842  // Compute the phi values at the current sample point
843  std::vector<Real> psi(specpoly(dim, element_order, q_point[sp], matsize));
844  for (unsigned int i=0; i<matsize; i++)
845  {
846  temperr[0] += psi[i]*Pu_x_h(i);
847 #if LIBMESH_DIM > 1
848  temperr[1] += psi[i]*Pu_y_h(i);
849  temperr[3] += psi[i]*Pu_xy_h(i);
850 #endif
851 #if LIBMESH_DIM > 2
852  temperr[2] += psi[i]*Pu_z_h(i);
853  temperr[4] += psi[i]*Pu_xz_h(i);
854  temperr[5] += psi[i]*Pu_yz_h(i);
855 #endif
856  }
857 
858  temperr[0] -= hess_u_h(0,0);
859 #if LIBMESH_DIM > 1
860  temperr[1] -= hess_u_h(1,1);
861  temperr[3] -= hess_u_h(0,1);
862 #endif
863 #if LIBMESH_DIM > 2
864  temperr[2] -= hess_u_h(2,2);
865  temperr[4] -= hess_u_h(0,2);
866  temperr[5] -= hess_u_h(1,2);
867 #endif
868 #else
869  libmesh_error_msg("ERROR: --enable-second-derivatives is required \nfor _sobolev_order == 2!");
870 #endif
871  }
872  // Add up relevant terms. We can easily optimize the
873  // LIBMESH_DIM < 3 cases a little bit with the exception
874  // of the W2 cases
875 
876  if (norm_type == L_INF)
877  element_error = std::max(element_error, std::abs(temperr[0]));
878  else if (norm_type == W1_INF_SEMINORM)
879  for (unsigned int i=0; i != LIBMESH_DIM; ++i)
880  element_error = std::max(element_error, std::abs(temperr[i]));
881  else if (norm_type == W2_INF_SEMINORM)
882  for (unsigned int i=0; i != 6; ++i)
883  element_error = std::max(element_error, std::abs(temperr[i]));
884  else if (norm_type == L2)
885  element_error += JxW[sp]*TensorTools::norm_sq(temperr[0]);
886  else if (norm_type == H1_SEMINORM)
887  for (unsigned int i=0; i != LIBMESH_DIM; ++i)
888  element_error += JxW[sp]*TensorTools::norm_sq(temperr[i]);
889  else if (norm_type == H1_X_SEMINORM)
890  element_error += JxW[sp]*TensorTools::norm_sq(temperr[0]);
891  else if (norm_type == H1_Y_SEMINORM)
892  element_error += JxW[sp]*TensorTools::norm_sq(temperr[1]);
893  else if (norm_type == H1_Z_SEMINORM)
894  element_error += JxW[sp]*TensorTools::norm_sq(temperr[2]);
895  else if (norm_type == H2_SEMINORM)
896  {
897  for (unsigned int i=0; i != LIBMESH_DIM; ++i)
898  element_error += JxW[sp]*TensorTools::norm_sq(temperr[i]);
899  // Off diagonal terms enter into the Hessian norm twice
900  for (unsigned int i=3; i != 6; ++i)
901  element_error += JxW[sp]*2*TensorTools::norm_sq(temperr[i]);
902  }
903 
904  } // End loop over sample points
905 
906  if (norm_type == L_INF ||
907  norm_type == W1_INF_SEMINORM ||
908  norm_type == W2_INF_SEMINORM)
909  new_error_per_cell[e] += error_estimator.error_norm.weight(var) * element_error;
910  else if (norm_type == L2 ||
911  norm_type == H1_SEMINORM ||
912  norm_type == H1_X_SEMINORM ||
913  norm_type == H1_Y_SEMINORM ||
914  norm_type == H1_Z_SEMINORM ||
915  norm_type == H2_SEMINORM)
916  new_error_per_cell[e] += error_estimator.error_norm.weight_sq(var) * element_error;
917  else
918  libmesh_error_msg("Unsupported error norm type == " << Utility::enum_to_string(norm_type));
919  } // End (re) loop over patch elements
920 
921  } // end variables loop
922 
923  // Now that we have the contributions from each variable,
924  // we have take square roots of the entries we
925  // added to error_per_cell to get an error norm
926  // If we are reusing patches, once again reuse the current patch to loop
927  // over all elements in the current patch, otherwise build a new
928  // patch containing just the current element and loop over it
929  Patch::const_iterator patch_re_it;
930  Patch::const_iterator patch_re_end;
931 
932  // Build a new patch if necessary
933  Patch current_elem_patch(mesh.processor_id());
934 
935  if (this->error_estimator.patch_reuse)
936  {
937  // Just get the iterators from the current patch
938  patch_re_it = patch.begin();
939  patch_re_end = patch.end();
940  }
941  else
942  {
943  // Use a target patch size of just 0, this will contain
944  // just the current element.
945  current_elem_patch.build_around_element (elem, 0,
947 
948  // Get the iterators from this newly constructed patch
949  patch_re_it = current_elem_patch.begin();
950  patch_re_end = current_elem_patch.end();
951  }
952 
953  // Loop over every element in the patch we just constructed
954  for (unsigned int i = 0 ; patch_re_it != patch_re_end; ++patch_re_it, ++i)
955  {
956  // The pth element in the patch
957  const Elem * e_p = *patch_re_it;
958 
959  // We'll need an index into the error vector
960  const dof_id_type e_p_id = e_p->id();
961 
962  // Update the error_per_cell vector for this element
963  if (error_estimator.error_norm.type(0) == L2 ||
969  {
970  Threads::spin_mutex::scoped_lock acquire(Threads::spin_mtx);
971  if (!error_per_cell[e_p_id])
972  error_per_cell[e_p_id] =
973  static_cast<ErrorVectorReal>(std::sqrt(new_error_per_cell[i]));
974  }
975  else
976  {
980  Threads::spin_mutex::scoped_lock acquire(Threads::spin_mtx);
981  if (!error_per_cell[e_p_id])
982  error_per_cell[e_p_id] =
983  static_cast<ErrorVectorReal>(new_error_per_cell[i]);
984  }
985 
986  } // End loop over every element in patch
987 
988  } // end element loop
989 
990 } // End () operator definition
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
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
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
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 PatchRecoveryErrorEstimator& libMesh::PatchRecoveryErrorEstimator::EstimateError::error_estimator
private

Definition at line 145 of file patch_recovery_error_estimator.h.

Referenced by operator()().

◆ error_per_cell

ErrorVector& libMesh::PatchRecoveryErrorEstimator::EstimateError::error_per_cell
private

Definition at line 146 of file patch_recovery_error_estimator.h.

Referenced by operator()().

◆ system

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

Definition at line 144 of file patch_recovery_error_estimator.h.

Referenced by operator()().


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