18 #include "libmesh/elem.h" 39 typename Enable =
typename std::enable_if<libMesh::ScalarTraits<T>::value>::type>
44 const bool two_term_boundary_expansion,
46 const bool force_green_gauss =
false)
48 mooseAssert(elem_arg.
elem,
"This should be non-null");
50 const auto rz_radial_coord =
mesh.getAxisymmetricRadialCoord();
52 const T elem_value = functor(elem_arg, state_arg);
55 unsigned int num_ebfs = 0;
64 bool volume_set =
false;
83 std::vector<libMesh::VectorValue<Real>> ebf_grad_coeffs;
86 std::vector<const T *> ebf_b;
89 std::vector<libMesh::VectorValue<Real>> grad_ebf_coeffs;
93 auto action_functor = [&volume_set,
104 two_term_boundary_expansion,
106 rz_radial_coord](
const Elem & libmesh_dbg_var(functor_elem),
109 const Point & surface_vector,
111 const bool elem_has_info)
113 mooseAssert(fi,
"We need a FaceInfo for this action_functor");
115 elem_arg.elem == &functor_elem,
116 "Just a sanity check that the element being passed in is the one we passed out.");
118 if (functor.isExtrapolatedBoundaryFace(*fi, elem_arg.elem, state_arg))
120 if (two_term_boundary_expansion)
125 ebf_grad_coeffs.push_back(-1. * (elem_has_info
126 ? (fi->faceCentroid() - fi->elemCentroid())
127 : (fi->faceCentroid() - fi->neighborCentroid())));
128 ebf_b.push_back(&elem_value);
131 grad_ebf_coeffs.push_back(-surface_vector);
138 grad_b += surface_vector * elem_value;
145 elem_arg.correct_skewness,
157 fi->elemCentroid(), coord, coord_type, rz_radial_coord);
158 volume = fi->elemVolume() * coord;
163 fi->neighborCentroid(), coord, coord_type, rz_radial_coord);
164 volume = fi->neighborVolume() * coord;
172 *elem_arg.elem,
mesh, action_functor, coord_type, rz_radial_coord);
174 mooseAssert(volume_set &&
volume > 0,
"We should have set the volume");
180 grad_b(rz_radial_coord) -= elem_value / elem_arg.elem->vertex_average()(rz_radial_coord);
185 "We have not yet implemented the correct translation from gradient to divergence for " 186 "spherical coordinates yet.");
194 const unsigned int sys_dim =
Moose::dim + num_ebfs;
195 DenseVector<T> x(sys_dim), b(sys_dim);
196 DenseMatrix<T> A(sys_dim, sys_dim);
240 if (!two_term_boundary_expansion)
242 "I believe we should only get singular systems when two-term boundary expansion is " 243 "being used. The error thrown during the computation of the gradient: ",
277 const size_t num_faces = std::distance(ptr_range.begin(), ptr_range.end());
280 std::vector<Point> delta_x_list;
282 delta_x_list.reserve(num_faces);
286 delta_phi_list.reserve(num_faces);
289 std::vector<Point> delta_x_ebf_list;
290 delta_phi_list.reserve(num_faces);
292 std::vector<VectorValue<Real>>
294 delta_phi_list.reserve(num_faces);
296 std::vector<const T *> ebf_b;
297 delta_phi_list.reserve(num_faces);
299 unsigned int num_ebfs = 0;
302 auto action_functor = [&elem_value,
312 two_term_boundary_expansion](
const Elem & libmesh_dbg_var(loc_elem),
313 const Elem * loc_neigh,
317 const bool elem_has_info)
319 mooseAssert(fi,
"We need a FaceInfo for this action_functor");
321 elem_arg.elem == &loc_elem,
322 "Just a sanity check that the element being passed in is the one we passed out.");
324 if (functor.isExtrapolatedBoundaryFace(*fi, elem_arg.elem, state_arg))
327 const Point delta_x = elem_has_info ? (fi->faceCentroid() - fi->elemCentroid())
328 : (fi->faceCentroid() - fi->neighborCentroid());
329 delta_x_list.push_back(delta_x);
333 if (two_term_boundary_expansion)
339 ebf_grad_coeffs.push_back(-delta_x);
341 ebf_b.push_back(&elem_value);
343 delta_phi = -elem_value;
344 delta_x_ebf_list.push_back(delta_x);
351 delta_phi_list.push_back(delta_phi);
358 if (functor.isInternalFace(*fi))
361 delta_x = loc_neigh->vertex_average() - elem_arg.elem->vertex_average();
364 neighbor_value = functor(neighbor_arg, state_arg);
369 delta_x = elem_has_info ? (fi->faceCentroid() - fi->elemCentroid())
370 : (fi->faceCentroid() - fi->neighborCentroid());
374 elem_arg.correct_skewness,
380 delta_x_list.push_back(delta_x);
381 delta_phi_list.push_back(neighbor_value - elem_value);
387 *elem_arg.elem,
mesh, action_functor, coord_type, rz_radial_coord);
390 const unsigned int n = delta_x_list.size();
391 mooseAssert(n >=
dim,
"Not enough neighbors to perform least squares");
393 DenseMatrix<T> ATA(
dim,
dim);
394 DenseVector<T> ATb(
dim);
402 for (
unsigned int i = 0; i < n; ++i)
404 const Point & delta_x = delta_x_list[i];
405 const T & delta_phi = delta_phi_list[i];
407 for (
unsigned int d1 = 0; d1 <
dim; ++d1)
409 const Real dx_d1 = delta_x(d1);
410 const Real dx_norm = delta_x.norm();
411 const Real dx_d1_norm = dx_d1 / dx_norm;
413 for (
unsigned int d2 = 0; d2 <
dim; ++d2)
415 const Real dx_d2_norm = delta_x(d2) / dx_norm;
416 ATA(d1, d2) += dx_d1_norm * dx_d2_norm;
419 ATb(d1) += dx_d1_norm * delta_phi / dx_norm;
425 for (
unsigned int d = 0; d <
dim; ++d)
427 ATA(d, d) += epsilon;
433 DenseVector<T> grad_ls(
dim);
434 ATA.lu_solve(ATb, grad_ls);
437 for (
unsigned int d = 0; d <
dim; ++d)
439 grad(d) = grad_ls(d);
445 const unsigned int sys_dim =
Moose::dim + num_ebfs;
446 DenseVector<T> x(sys_dim), b(sys_dim);
447 DenseMatrix<T> A(sys_dim, sys_dim);
452 for (
unsigned int d1 = 0; d1 <
dim; ++d1)
455 for (
unsigned int d2 = 0; d2 <
dim; ++d2)
456 A(d1, d2) = ATA(d1, d2);
465 const Point & delta_x = delta_x_ebf_list[i];
466 for (
unsigned int d1 = 0; d1 <
dim; ++d1)
468 const Real dx_d1 = delta_x(d1);
469 A(d1,
Moose::dim + i) -= dx_d1 / delta_x.norm() / delta_x.norm();
501 "We have not yet implemented the correct translation from gradient to divergence for " 502 "spherical coordinates yet.");
508 "Singular matrix encountered in least squares gradient computation. Falling back " 509 "to Green-Gauss gradient.");
512 elem_arg, state_arg, functor,
false,
mesh,
true);
545 template <
typename T,
546 typename Enable =
typename std::enable_if<libMesh::ScalarTraits<T>::value>::type>
551 const bool two_term_boundary_expansion,
554 mooseAssert(face_arg.
fi,
"We should have a face info to compute a face gradient");
555 const auto & fi = *(face_arg.
fi);
556 const auto & elem_arg = face_arg.
makeElem();
558 const bool defined_on_elem = functor.
hasBlocks(fi.elemSubdomainID());
559 const bool defined_on_neighbor = fi.neighborPtr() && functor.
hasBlocks(fi.neighborSubdomainID());
561 if (defined_on_elem && defined_on_neighbor)
563 const auto & value_elem = functor(elem_arg, state_arg);
564 const auto & value_neighbor = functor(neighbor_arg, state_arg);
572 if (
mesh.dimension() > 1)
579 const auto & grad_elem =
581 const auto & grad_neighbor =
585 interpolated_gradient,
591 face_gradient += interpolated_gradient - (interpolated_gradient * fi.eCN()) * fi.eCN();
594 return face_gradient;
596 else if (defined_on_elem)
597 return functor.
gradient(elem_arg, state_arg);
598 else if (defined_on_neighbor)
599 return functor.
gradient(neighbor_arg, state_arg);
601 mooseError(
"The functor must be defined on one of the sides");
604 template <
typename T>
609 const bool two_term_boundary_expansion,
616 const auto row_gradient =
619 ret(i, j) = row_gradient(j);
625 template <
typename T>
630 const bool two_term_boundary_expansion,
637 const auto row_gradient =
640 ret(i, j) = row_gradient(j);
646 template <
typename T>
651 const bool two_term_boundary_expansion,
655 const auto vals = functor(elem_arg, state_arg);
671 template <
typename T>
676 const bool two_term_boundary_expansion,
680 const auto vals = functor(face_arg, state_arg);
696 template <
typename T, std::
size_t N>
701 const bool two_term_boundary_expansion,
719 template <
typename T, std::
size_t N>
724 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.
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
Function to check whether two variables are equal within an absolute tolerance.
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)