18 #include "libmesh/elem.h" 42 typename Enable =
typename std::enable_if<libMesh::ScalarTraits<T>::value>::type>
47 const bool two_term_boundary_expansion,
49 const bool force_green_gauss =
false)
51 mooseAssert(elem_arg.
elem,
"This should be non-null");
53 const auto rz_radial_coord =
mesh.getAxisymmetricRadialCoord();
55 const T elem_value = functor(elem_arg, state_arg);
58 unsigned int num_ebfs = 0;
67 bool volume_set =
false;
86 std::vector<libMesh::VectorValue<Real>> ebf_grad_coeffs;
89 std::vector<const T *> ebf_b;
92 std::vector<libMesh::VectorValue<Real>> grad_ebf_coeffs;
96 auto action_functor = [&volume_set,
107 two_term_boundary_expansion,
109 rz_radial_coord](
const Elem & libmesh_dbg_var(functor_elem),
112 const Point & surface_vector,
114 const bool elem_has_info)
116 mooseAssert(fi,
"We need a FaceInfo for this action_functor");
118 elem_arg.elem == &functor_elem,
119 "Just a sanity check that the element being passed in is the one we passed out.");
121 if (functor.isExtrapolatedBoundaryFace(*fi, elem_arg.elem, state_arg))
123 if (two_term_boundary_expansion)
128 ebf_grad_coeffs.push_back(-1. * (elem_has_info
129 ? (fi->faceCentroid() - fi->elemCentroid())
130 : (fi->faceCentroid() - fi->neighborCentroid())));
131 ebf_b.push_back(&elem_value);
134 grad_ebf_coeffs.push_back(-surface_vector);
141 grad_b += surface_vector * elem_value;
148 elem_arg.correct_skewness,
160 fi->elemCentroid(), coord, coord_type, rz_radial_coord);
161 volume = fi->elemVolume() * coord;
166 fi->neighborCentroid(), coord, coord_type, rz_radial_coord);
167 volume = fi->neighborVolume() * coord;
175 *elem_arg.elem,
mesh, action_functor, coord_type, rz_radial_coord);
177 mooseAssert(volume_set &&
volume > 0,
"We should have set the volume");
183 grad_b(rz_radial_coord) -= elem_value / elem_arg.elem->vertex_average()(rz_radial_coord);
188 "We have not yet implemented the correct translation from gradient to divergence for " 189 "spherical coordinates yet.");
197 const unsigned int sys_dim =
Moose::dim + num_ebfs;
198 DenseVector<T> x(sys_dim), b(sys_dim);
199 DenseMatrix<T> A(sys_dim, sys_dim);
240 catch (std::exception & e)
245 if (!strstr(e.what(),
"singular"))
249 if (!two_term_boundary_expansion)
251 "I believe we should only get singular systems when two-term boundary expansion is " 252 "being used. The error thrown during the computation of the gradient: ",
286 const size_t num_faces = std::distance(ptr_range.begin(), ptr_range.end());
289 std::vector<Point> delta_x_list;
291 delta_x_list.reserve(num_faces);
295 delta_phi_list.reserve(num_faces);
298 std::vector<Point> delta_x_ebf_list;
299 delta_phi_list.reserve(num_faces);
301 std::vector<VectorValue<Real>>
303 delta_phi_list.reserve(num_faces);
305 std::vector<const T *> ebf_b;
306 delta_phi_list.reserve(num_faces);
308 unsigned int num_ebfs = 0;
311 auto action_functor = [&elem_value,
321 two_term_boundary_expansion](
const Elem & libmesh_dbg_var(loc_elem),
322 const Elem * loc_neigh,
326 const bool elem_has_info)
328 mooseAssert(fi,
"We need a FaceInfo for this action_functor");
330 elem_arg.elem == &loc_elem,
331 "Just a sanity check that the element being passed in is the one we passed out.");
333 if (functor.isExtrapolatedBoundaryFace(*fi, elem_arg.elem, state_arg))
336 const Point delta_x = elem_has_info ? (fi->faceCentroid() - fi->elemCentroid())
337 : (fi->faceCentroid() - fi->neighborCentroid());
338 delta_x_list.push_back(delta_x);
342 if (two_term_boundary_expansion)
348 ebf_grad_coeffs.push_back(-delta_x);
350 ebf_b.push_back(&elem_value);
352 delta_phi = -elem_value;
353 delta_x_ebf_list.push_back(delta_x);
360 delta_phi_list.push_back(delta_phi);
367 if (functor.isInternalFace(*fi))
370 delta_x = loc_neigh->vertex_average() - elem_arg.elem->vertex_average();
373 neighbor_value = functor(neighbor_arg, state_arg);
378 delta_x = elem_has_info ? (fi->faceCentroid() - fi->elemCentroid())
379 : (fi->faceCentroid() - fi->neighborCentroid());
383 elem_arg.correct_skewness,
389 delta_x_list.push_back(delta_x);
390 delta_phi_list.push_back(neighbor_value - elem_value);
396 *elem_arg.elem,
mesh, action_functor, coord_type, rz_radial_coord);
399 const unsigned int n = delta_x_list.size();
400 mooseAssert(n >=
dim,
"Not enough neighbors to perform least squares");
402 DenseMatrix<T> ATA(
dim,
dim);
403 DenseVector<T> ATb(
dim);
411 for (
unsigned int i = 0; i < n; ++i)
413 const Point & delta_x = delta_x_list[i];
414 const T & delta_phi = delta_phi_list[i];
416 for (
unsigned int d1 = 0; d1 <
dim; ++d1)
418 const Real dx_d1 = delta_x(d1);
419 const Real dx_norm = delta_x.norm();
420 const Real dx_d1_norm = dx_d1 / dx_norm;
422 for (
unsigned int d2 = 0; d2 <
dim; ++d2)
424 const Real dx_d2_norm = delta_x(d2) / dx_norm;
425 ATA(d1, d2) += dx_d1_norm * dx_d2_norm;
428 ATb(d1) += dx_d1_norm * delta_phi / dx_norm;
434 for (
unsigned int d = 0; d <
dim; ++d)
436 ATA(d, d) += epsilon;
442 DenseVector<T> grad_ls(
dim);
443 ATA.lu_solve(ATb, grad_ls);
446 for (
unsigned int d = 0; d <
dim; ++d)
448 grad(d) = grad_ls(d);
454 const unsigned int sys_dim =
Moose::dim + num_ebfs;
455 DenseVector<T> x(sys_dim), b(sys_dim);
456 DenseMatrix<T> A(sys_dim, sys_dim);
461 for (
unsigned int d1 = 0; d1 <
dim; ++d1)
464 for (
unsigned int d2 = 0; d2 <
dim; ++d2)
465 A(d1, d2) = ATA(d1, d2);
474 const Point & delta_x = delta_x_ebf_list[i];
475 for (
unsigned int d1 = 0; d1 <
dim; ++d1)
477 const Real dx_d1 = delta_x(d1);
478 A(d1,
Moose::dim + i) -= dx_d1 / delta_x.norm() / delta_x.norm();
510 "We have not yet implemented the correct translation from gradient to divergence for " 511 "spherical coordinates yet.");
513 catch (std::exception & e)
518 if (!strstr(e.what(),
"singular"))
523 "Singular matrix encountered in least squares gradient computation. Falling back " 524 "to Green-Gauss gradient.");
527 elem_arg, state_arg, functor,
false,
mesh,
true);
560 template <
typename T,
561 typename Enable =
typename std::enable_if<libMesh::ScalarTraits<T>::value>::type>
566 const bool two_term_boundary_expansion,
569 mooseAssert(face_arg.
fi,
"We should have a face info to compute a face gradient");
570 const auto & fi = *(face_arg.
fi);
571 const auto & elem_arg = face_arg.
makeElem();
573 const bool defined_on_elem = functor.
hasBlocks(fi.elemSubdomainID());
574 const bool defined_on_neighbor = fi.neighborPtr() && functor.
hasBlocks(fi.neighborSubdomainID());
576 if (defined_on_elem && defined_on_neighbor)
578 const auto & value_elem = functor(elem_arg, state_arg);
579 const auto & value_neighbor = functor(neighbor_arg, state_arg);
587 if (
mesh.dimension() > 1)
594 const auto & grad_elem =
596 const auto & grad_neighbor =
600 interpolated_gradient,
606 face_gradient += interpolated_gradient - (interpolated_gradient * fi.eCN()) * fi.eCN();
609 return face_gradient;
611 else if (defined_on_elem)
612 return functor.
gradient(elem_arg, state_arg);
613 else if (defined_on_neighbor)
614 return functor.
gradient(neighbor_arg, state_arg);
616 mooseError(
"The functor must be defined on one of the sides");
619 template <
typename T>
624 const bool two_term_boundary_expansion,
631 const auto row_gradient =
634 ret(i, j) = row_gradient(j);
640 template <
typename T>
645 const bool two_term_boundary_expansion,
652 const auto row_gradient =
655 ret(i, j) = row_gradient(j);
661 template <
typename T>
666 const bool two_term_boundary_expansion,
670 const auto vals = functor(elem_arg, state_arg);
672 GradientType ret(vals.size());
686 template <
typename T>
691 const bool two_term_boundary_expansion,
695 const auto vals = functor(face_arg, state_arg);
697 GradientType ret(vals.size());
711 template <
typename T, std::
size_t N>
716 const bool two_term_boundary_expansion,
734 template <
typename T, std::
size_t N>
739 const bool two_term_boundary_expansion,
void loopOverElemFaceInfo(const Elem &elem, const MooseMesh &mesh, ActionFunctor &act, const Moose::CoordinateSystemType coord_type, const unsigned int rz_radial_coord=libMesh::invalid_uint)
virtual bool hasBlocks(SubdomainID) const
Returns whether the functor is defined on this block.
Base class template for functor objects.
const unsigned int invalid_uint
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
void coordTransformFactor(const P &point, C &factor, const Moose::CoordinateSystemType coord_type, const unsigned int rz_radial_coord=libMesh::invalid_uint)
compute a coordinate transformation factor
libMesh::VectorValue< T > greenGaussGradient(const ElemArg &elem_arg, const StateArg &state_arg, const FunctorBase< T > &functor, const bool two_term_boundary_expansion, const MooseMesh &mesh, const bool force_green_gauss=false)
Compute a cell gradient using the method of Green-Gauss.
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
This is essentially a forwarding functor that forwards the spatial and temporal evaluation arguments ...
This data structure is used to store geometric and variable related metadata about each cell face in ...
A structure defining a "face" evaluation calling argument for Moose functors.
const FaceInfo * fi
a face information object which defines our location in space
const libMesh::Elem * elem
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
A structure that is used to evaluate Moose functors logically at an element/cell center.
ElemArg makeNeighbor() const
Make a ElemArg from our data using the face information neighbor.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
subdomain_id_type subdomain_id() const
GradientType gradient(const ElemArg &elem, const StateArg &state) const
Same as their evaluateGradient overloads with the same arguments but allows for caching implementatio...
IntRange< T > make_range(T beg, T end)
This is essentially a forwarding functor that forwards the spatial and temporal evaluation arguments ...
State argument for evaluating functors.
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
SimpleRange< NeighborPtrIter > neighbor_ptr_range()
void interpolate(InterpMethod m, T &result, const T2 &value1, const T3 &value2, const FaceInfo &fi, const bool one_is_elem)
Provides interpolation of face values for non-advection-specific purposes (although it can/will still...
ElemArg makeElem() const
Make a ElemArg from our data using the face information element.
auto index_range(const T &sizable)