https://mooseframework.inl.gov
MathFVUtils.h
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #pragma once
11 
12 #include "MooseError.h"
13 #include "FaceInfo.h"
14 #include "Limiter.h"
15 #include "MathUtils.h"
16 #include "MooseFunctor.h"
17 #include "metaphysicl/raw_type.h"
18 #include "libmesh/compare_types.h"
19 #include "libmesh/elem.h"
20 #include <cmath>
21 #include <limits>
22 #include <tuple>
23 
24 template <typename>
25 class MooseVariableFV;
26 class FaceArgInterface;
27 
28 namespace Moose
29 {
30 namespace FV
31 {
38 enum class InterpMethod
39 {
41  Average,
47  Upwind,
48  // Rhie-Chow
49  RhieChow,
50  VanLeer,
51  MinMod,
52  SOU,
53  QUICK,
55 };
56 
58 {
59  RHS,
60  Matrix,
62 };
63 
70 
76 
77 /*
78  * Converts from the interpolation method to the interpolation enum.
79  * This routine is here in lieu of using a MooseEnum for InterpMethod
80  * @param interp_method the name of the interpolation method
81  * @return the interpolation method
82  */
83 InterpMethod selectInterpolationMethod(const std::string & interp_method);
84 
93 bool setInterpolationMethod(const MooseObject & obj,
94  Moose::FV::InterpMethod & interp_method,
95  const std::string & param_name);
96 
115 template <typename T = Real>
116 std::pair<Real, Real>
118  const FaceInfo & fi,
119  const bool one_is_elem,
120  const T & face_flux = 0.0)
121 {
122  switch (m)
123  {
126  {
127  if (one_is_elem)
128  return std::make_pair(fi.gC(), 1. - fi.gC());
129  else
130  return std::make_pair(1. - fi.gC(), fi.gC());
131  }
132 
134  {
135  if ((face_flux > 0) == one_is_elem)
136  return std::make_pair(1., 0.);
137  else
138  return std::make_pair(0., 1.);
139  }
140 
141  default:
142  mooseError("Unrecognized interpolation method");
143  }
144 }
145 
151 template <typename T, typename T2>
153 linearInterpolation(const T & value1,
154  const T2 & value2,
155  const FaceInfo & fi,
156  const bool one_is_elem,
157  const InterpMethod interp_method = InterpMethod::Average)
158 {
159  mooseAssert(interp_method == InterpMethod::Average ||
160  interp_method == InterpMethod::SkewCorrectedAverage,
161  "The selected interpolation function only works with average or skewness-corrected "
162  "average options!");
163  const auto coeffs = interpCoeffs(interp_method, fi, one_is_elem);
164  return coeffs.first * value1 + coeffs.second * value2;
165 }
166 
178 template <typename T1, typename T2>
180 harmonicInterpolation(const T1 & value1,
181  const T2 & value2,
182  const FaceInfo & fi,
183  const bool one_is_elem)
184 {
185  // We check if the base values of the given template types match, if not we throw a compile-time
186  // error
187  static_assert(std::is_same<typename MetaPhysicL::RawType<T1>::value_type,
188  typename MetaPhysicL::RawType<T2>::value_type>::value,
189  "The input values for harmonic interpolation need to have the same raw-value!");
190 
191  // Fetch the interpolation coefficients, we use the exact same coefficients as for a simple
192  // weighted average
193  const auto coeffs = interpCoeffs(InterpMethod::Average, fi, one_is_elem);
194 
195  // We check if the types are fit to compute the harmonic mean of. This is done compile-time
196  // using constexpr. We start with Real/ADReal which is straightforward if the input values are
197  // positive.
199  {
200  // The harmonic mean of mixed positive and negative numbers (and 0 as well) is not well-defined
201  // so we assert that the input values shall be positive.
202 #ifndef NDEBUG
203  if (value1 * value2 <= 0)
204  mooseWarning("Input values (" + Moose::stringify(MetaPhysicL::raw_value(value1)) + " & " +
206  ") must be of the same sign for harmonic interpolation");
207 #endif
208  return 1.0 / (coeffs.first / value1 + coeffs.second / value2);
209  }
210  // For vectors (ADRealVectorValue, VectorValue), we take the component-wise harmonic mean
211  else if constexpr (libMesh::TensorTools::TensorTraits<T1>::rank == 1)
212  {
214  for (const auto i : make_range(Moose::dim))
215  {
216 #ifndef NDEBUG
217  if (value1(i) * value2(i) <= 0)
218  mooseWarning("Component " + std::to_string(i) + " of input values (" +
219  Moose::stringify(MetaPhysicL::raw_value(value1(i))) + " & " +
221  ") must be of the same sign for harmonic interpolation");
222 #endif
223  result(i) = 1.0 / (coeffs.first / value1(i) + coeffs.second / value2(i));
224  }
225  return result;
226  }
227  // For tensors (ADRealTensorValue, TensorValue), similarly to the vectors,
228  // we take the component-wise harmonic mean instead of the matrix-inverse approach
229  else if constexpr (libMesh::TensorTools::TensorTraits<T1>::rank == 2)
230  {
232  for (const auto i : make_range(Moose::dim))
233  for (const auto j : make_range(Moose::dim))
234  {
235 #ifndef NDEBUG
236  if (value1(i, j) * value2(i, j) <= 0)
237  mooseWarning("Component (" + std::to_string(i) + "," + std::to_string(j) +
238  ") of input values (" +
239  Moose::stringify(MetaPhysicL::raw_value(value1(i, j))) + " & " +
241  ") must be of the same sign for harmonic interpolation");
242 #endif
243  result(i, j) = 1.0 / (coeffs.first / value1(i, j) + coeffs.second / value2(i, j));
244  }
245  return result;
246  }
247  // We ran out of options, harmonic mean is not supported for other types at the moment
248  else
249  // This line is supposed to throw an error when the user tries to compile this function with
250  // types that are not supported. This is the reason we needed the always_false function. Hope as
251  // C++ gets nicer, we can do this in a nicer way.
252  static_assert(Moose::always_false<T1>,
253  "Harmonic interpolation is not implemented for the used type!");
254 }
255 
262 template <typename T, typename T2, typename T3>
265  const T2 & value2,
266  const T3 & face_gradient,
267  const FaceInfo & fi,
268  const bool one_is_elem)
269 {
270  const auto coeffs = interpCoeffs(InterpMethod::SkewCorrectedAverage, fi, one_is_elem);
271 
272  auto value = (coeffs.first * value1 + coeffs.second * value2) +
273  face_gradient * fi.skewnessCorrectionVector();
274  return value;
275 }
276 
283 template <typename T, typename T2, typename T3>
284 void
286  T & result,
287  const T2 & value1,
288  const T3 & value2,
289  const FaceInfo & fi,
290  const bool one_is_elem)
291 {
292  switch (m)
293  {
296  result = linearInterpolation(value1, value2, fi, one_is_elem);
297  break;
299  result = harmonicInterpolation(value1, value2, fi, one_is_elem);
300  break;
301  default:
302  mooseError("unsupported interpolation method for interpolate() function");
303  }
304 }
305 
310 template <typename T, FunctorEvaluationKind FEK = FunctorEvaluationKind::Value>
311 T
312 linearInterpolation(const FunctorBase<T> & functor, const FaceArg & face, const StateArg & time)
313 {
314  static_assert((FEK == FunctorEvaluationKind::Value) || (FEK == FunctorEvaluationKind::Dot),
315  "Only Value and Dot evaluations currently supported");
316  mooseAssert(face.limiter_type == LimiterType::CentralDifference,
317  "this interpolation method is meant for linear interpolations");
318 
319  mooseAssert(face.fi,
320  "We must have a non-null face_info in order to prepare our ElemFromFace tuples");
321 
323 
324  const auto elem_arg = face.makeElem();
325  const auto neighbor_arg = face.makeNeighbor();
326 
327  const auto elem_eval = functor.template genericEvaluate<FEK>(elem_arg, time);
328  const auto neighbor_eval = functor.template genericEvaluate<FEK>(neighbor_arg, time);
329 
330  if (face.correct_skewness)
331  {
332  // This condition ensures that the recursive algorithm (face_center->
333  // face_gradient -> cell_gradient -> face_center -> ...) terminates after
334  // one loop. It is hardcoded to one loop at this point since it yields
335  // 2nd order accuracy on skewed meshes with the minimum additional effort.
336  FaceArg new_face(face);
337  new_face.correct_skewness = false;
338  const auto surface_gradient = functor.template genericEvaluate<GFEK>(new_face, time);
339 
341  elem_eval, neighbor_eval, surface_gradient, *face.fi, true);
342  }
343  else
344  return linearInterpolation(elem_eval, neighbor_eval, *face.fi, true);
345 }
346 
350 template <typename T1,
351  typename T2,
352  typename T3,
353  template <typename> class Vector1,
354  template <typename> class Vector2>
355 void
357  Vector1<T1> & result,
358  const T2 & fi_elem_advected,
359  const T2 & fi_neighbor_advected,
360  const Vector2<T3> & fi_elem_advector,
361  const Vector2<T3> & fi_neighbor_advector,
362  const FaceInfo & fi)
363 {
364  switch (m)
365  {
367  result = linearInterpolation(fi_elem_advected * fi_elem_advector,
368  fi_neighbor_advected * fi_neighbor_advector,
369  fi,
370  true);
371  break;
373  {
374  const auto face_advector = linearInterpolation(MetaPhysicL::raw_value(fi_elem_advector),
375  MetaPhysicL::raw_value(fi_neighbor_advector),
376  fi,
377  true);
378  Real elem_coeff, neighbor_coeff;
379  if (face_advector * fi.normal() > 0)
380  elem_coeff = 1, neighbor_coeff = 0;
381  else
382  elem_coeff = 0, neighbor_coeff = 1;
383 
384  result = elem_coeff * fi_elem_advected * fi_elem_advector +
385  neighbor_coeff * fi_neighbor_advected * fi_neighbor_advector;
386  break;
387  }
388  default:
389  mooseError("unsupported interpolation method for FVFaceInterface::interpolate");
390  }
391 }
392 
401 template <typename T, typename T2, typename T3, typename Vector>
402 void
404  T & result,
405  const T2 & value1,
406  const T3 & value2,
407  const Vector & advector,
408  const FaceInfo & fi,
409  const bool one_is_elem)
410 {
411  const auto coeffs = interpCoeffs(m, fi, one_is_elem, advector * fi.normal());
412  result = coeffs.first * value1 + coeffs.second * value2;
413 }
414 
418 ADReal gradUDotNormal(const FaceInfo & face_info,
419  const MooseVariableFV<Real> & fv_var,
420  const Moose::StateArg & time,
421  bool correct_skewness = false);
422 
446 template <typename Scalar, typename Vector>
447 Scalar
448 rF(const Scalar & phiC, const Scalar & phiD, const Vector & gradC, const RealVectorValue & dCD)
449 {
450  const Scalar denom = phiD - phiC;
451  const Scalar grad_dot = gradC * dCD;
452 
453  // This is an arbitrary number here, when we start seeing convergence issues we
454  // can tune this but so far this has shown okay results.
455  constexpr Real eps = 1e-10;
456  const Real denom_sign =
457  std::copysign(1.0,
458  MetaPhysicL::raw_value(denom) +
460  const Scalar safe = denom + denom_sign * eps;
461  return 2.0 * grad_dot / safe - 1.0;
462 }
463 
475 template <typename T>
476 std::pair<T, T>
477 interpCoeffs(const Limiter<T> & limiter,
478  const T & phi_upwind,
479  const T & phi_downwind,
480  const libMesh::VectorValue<T> * const grad_phi_upwind,
481  const libMesh::VectorValue<T> * const grad_phi_face,
482  const Real & max_value,
483  const Real & min_value,
484  const FaceInfo & fi,
485  const bool fi_elem_is_upwind)
486 {
487  // Using beta, w_f, g nomenclature from Greenshields
488  const auto beta = limiter(phi_upwind,
489  phi_downwind,
490  grad_phi_upwind,
491  grad_phi_face,
492  fi_elem_is_upwind ? fi.dCN() : Point(-fi.dCN()),
493  max_value,
494  min_value,
495  &fi,
496  fi_elem_is_upwind);
497 
498  const auto w_f = fi_elem_is_upwind ? fi.gC() : (1. - fi.gC());
499 
500  const auto g = beta * (1. - w_f);
501 
502  return std::make_pair(1. - g, g);
503 }
504 
508 template <typename Scalar,
509  typename Vector,
510  typename Enable = typename std::enable_if<libMesh::ScalarTraits<Scalar>::value>::type>
511 Scalar
512 interpolate(const Limiter<Scalar> & limiter,
513  const Scalar & phi_upwind,
514  const Scalar & phi_downwind,
515  const Vector * const grad_phi_upwind,
516  const FaceInfo & fi,
517  const bool fi_elem_is_upwind)
518 {
519  auto pr =
520  interpCoeffs(limiter,
521  phi_upwind,
522  phi_downwind,
523  grad_phi_upwind,
524  /*grad_phi_face*/ static_cast<const libMesh::VectorValue<Scalar> *>(nullptr),
525  /* max_value */ std::numeric_limits<Real>::max(),
526  /* min_value */ std::numeric_limits<Real>::min(),
527  fi,
528  fi_elem_is_upwind);
529  return pr.first * phi_upwind + pr.second * phi_downwind;
530 }
531 
535 template <typename Limiter, typename T, typename Tensor>
537 interpolate(const Limiter & limiter,
538  const TypeVector<T> & phi_upwind,
539  const TypeVector<T> & phi_downwind,
540  const Tensor * const grad_phi_upwind,
541  const FaceInfo & fi,
542  const bool fi_elem_is_upwind)
543 {
544  mooseAssert(limiter.constant() || grad_phi_upwind,
545  "Non-null gradient only supported for constant limiters.");
546 
547  const libMesh::VectorValue<T> * const gradient_example = nullptr;
549  for (const auto i : make_range(unsigned(LIBMESH_DIM)))
550  {
551  if (grad_phi_upwind)
552  {
553  const libMesh::VectorValue<T> gradient = grad_phi_upwind->row(i);
554  ret(i) =
555  interpolate(limiter, phi_upwind(i), phi_downwind(i), &gradient, fi, fi_elem_is_upwind);
556  }
557  else
558  ret(i) = interpolate(
559  limiter, phi_upwind(i), phi_downwind(i), gradient_example, fi, fi_elem_is_upwind);
560  }
561 
562  return ret;
563 }
564 
583 template <typename T>
584 T
586  const T & phi_upwind,
587  const T & phi_downwind,
588  const VectorValue<T> * const grad_phi_upwind,
589  const VectorValue<T> * const grad_phi_face,
590  const Real & max_value,
591  const Real & min_value,
592  const FaceArg & face)
593 {
594  // Compute the direction vector based on whether the current element is upwind
595  const auto dCD = face.elem_is_upwind ? face.fi->dCN() : Point(-face.fi->dCN());
596 
597  // Compute the flux limiting ratio using the specified limiter
598  const auto beta = limiter(phi_upwind,
599  phi_downwind,
600  grad_phi_upwind,
601  grad_phi_face,
602  dCD,
603  max_value,
604  min_value,
605  face.fi,
606  face.elem_is_upwind);
607 
608  // Determine the face centroid and the appropriate cell centroid
609  const auto & face_centroid = face.fi->faceCentroid();
610  const auto & cell_centroid =
611  face.elem_is_upwind ? face.fi->elemCentroid() : face.fi->neighborCentroid();
612 
613  // Compute the delta value at the face
614  T delta_face;
616  delta_face = (*grad_phi_upwind) * (face_centroid - cell_centroid);
617  else
618  delta_face = (*grad_phi_face) * (face_centroid - cell_centroid);
619 
620  // Return the interpolated value
621  return phi_upwind + beta * delta_face;
622 }
623 
646 template <typename T,
648  typename Enable = typename std::enable_if<ScalarTraits<T>::value>::type>
649 std::pair<Real, Real>
650 computeMinMaxValue(const FunctorBase<T> & functor, const FaceArg & face, const StateArg & time)
651 {
652  // Initialize max_value to 0 and min_value to a large value
654 
655  // Iterate over the direct neighbors of the element associated with the face
656  for (const auto neighbor : (*face.fi).elem().neighbor_ptr_range())
657  {
658  // If not a valid neighbor, skip to the next one
659  if (neighbor == nullptr)
660  continue;
661 
662  // Evaluate the functor at the neighbor and update max_value and min_value
663  const ElemArg local_cell_arg = {neighbor, false};
664  const auto value =
665  MetaPhysicL::raw_value(functor.template genericEvaluate<FEK>(local_cell_arg, time));
666  max_value = std::max(max_value, value);
667  min_value = std::min(min_value, value);
668  }
669 
670  // Iterate over the neighbors of the neighbor
671  for (const auto neighbor : (*face.fi).neighbor().neighbor_ptr_range())
672  {
673  // If not a valid neighbor, skip to the next one
674  if (neighbor == nullptr)
675  continue;
676 
677  // Evaluate the functor at the neighbor and update max_value and min_value
678  const ElemArg local_cell_arg = {neighbor, false};
679  const auto value =
680  MetaPhysicL::raw_value(functor.template genericEvaluate<FEK>(local_cell_arg, time));
681  max_value = std::max(max_value, value);
682  min_value = std::min(min_value, value);
683  }
684 
685  // Return a pair containing the computed maximum and minimum values
686  return std::make_pair(max_value, min_value);
687 }
688 
714 template <typename T>
715 std::pair<Real, Real>
716 computeMinMaxValue(const FunctorBase<VectorValue<T>> & functor,
717  const FaceArg & face,
718  const StateArg & time,
719  const unsigned int & component)
720 {
721  // Initialize max_value to 0 and min_value to a large value
723 
724  // Iterate over the direct neighbors of the element associated with the face
725  for (const auto neighbor : (*face.fi).elem().neighbor_ptr_range())
726  {
727  // If not a valid neighbor, skip to the next one
728  if (neighbor == nullptr)
729  continue;
730 
731  // Evaluate the functor at the neighbor for the specified component and update max_value and
732  // min_value
733  const ElemArg local_cell_arg = {neighbor, false};
734  const auto value = MetaPhysicL::raw_value(functor(local_cell_arg, time)(component));
735  max_value = std::max(max_value, value);
736  min_value = std::min(min_value, value);
737  }
738 
739  // Iterate over the neighbors of the neighbor associated with the face
740  for (const auto neighbor : (*face.fi).neighbor().neighbor_ptr_range())
741  {
742  // If not a valid neighbor, skip to the next one
743  if (neighbor == nullptr)
744  continue;
745 
746  // Evaluate the functor at the neighbor for the specified component and update max_value and
747  // min_value
748  const ElemArg local_cell_arg = {neighbor, false};
749  const auto value = MetaPhysicL::raw_value(functor(local_cell_arg, time)(component));
750  max_value = std::max(max_value, value);
751  min_value = std::min(min_value, value);
752  }
753 
754  // Return a pair containing the computed maximum and minimum values
755  return std::make_pair(max_value, min_value);
756 }
757 
786 template <typename T,
788  typename Enable = typename std::enable_if<libMesh::ScalarTraits<T>::value>::type>
789 std::pair<std::pair<T, T>, std::pair<T, T>>
790 interpCoeffsAndAdvected(const FunctorBase<T> & functor, const FaceArg & face, const StateArg & time)
791 {
792  // Ensure only supported FunctorEvaluationKinds are used
793  static_assert((FEK == FunctorEvaluationKind::Value) || (FEK == FunctorEvaluationKind::Dot),
794  "Only Value and Dot evaluations currently supported");
795 
796  // Determine the gradient evaluation kind
798  typedef typename FunctorBase<T>::GradientType GradientType;
799  static const GradientType zero(0);
800 
801  mooseAssert(face.fi, "this must be non-null");
802 
803  // Construct the limiter based on the face limiter type
804  const auto limiter = Limiter<typename LimiterValueType<T>::value_type>::build(face.limiter_type);
805 
806  // Determine upwind and downwind arguments based on the face element
807  const auto upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor();
808  const auto downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem();
809 
810  // Evaluate the functor at the upwind and downwind locations
811  auto phi_upwind = functor.template genericEvaluate<FEK>(upwind_arg, time);
812  auto phi_downwind = functor.template genericEvaluate<FEK>(downwind_arg, time);
813 
814  // Initialize the interpolation coefficients
815  std::pair<T, T> interp_coeffs;
816 
817  // Compute interpolation coefficients for Upwind or CentralDifference limiters
818  if (face.limiter_type == LimiterType::Upwind ||
820  interp_coeffs = interpCoeffs(*limiter,
821  phi_upwind,
822  phi_downwind,
823  &zero,
824  &zero,
827  *face.fi,
828  face.elem_is_upwind);
829  else
830  {
831  // Determine the time argument for the limiter
832  auto * time_arg = face.state_limiter;
833  if (!time_arg)
834  {
836  time_arg = &temp_state;
837  }
838 
840 
841  // Compute min-max values for min-max limiters
843  std::tie(max_value, min_value) = computeMinMaxValue(functor, face, *time_arg);
844 
845  // Evaluate the gradient of the functor at the upwind and downwind locations
846  const auto grad_phi_upwind = functor.template genericEvaluate<GFEK>(upwind_arg, *time_arg);
847  const auto grad_phi_face = functor.template genericEvaluate<GFEK>(face, *time_arg);
848 
849  // Compute the interpolation coefficients using the specified limiter
850  interp_coeffs = interpCoeffs(*limiter,
851  phi_upwind,
852  phi_downwind,
853  &grad_phi_upwind,
854  &grad_phi_face,
855  max_value,
856  min_value,
857  *face.fi,
858  face.elem_is_upwind);
859  }
860 
861  // Return the interpolation coefficients and advected values
862  if (face.elem_is_upwind)
863  return std::make_pair(std::move(interp_coeffs),
864  std::make_pair(std::move(phi_upwind), std::move(phi_downwind)));
865  else
866  return std::make_pair(
867  std::make_pair(std::move(interp_coeffs.second), std::move(interp_coeffs.first)),
868  std::make_pair(std::move(phi_downwind), std::move(phi_upwind)));
869 }
870 
894 template <typename T,
896  typename Enable = typename std::enable_if<libMesh::ScalarTraits<T>::value>::type>
897 T
898 interpolate(const FunctorBase<T> & functor, const FaceArg & face, const StateArg & time)
899 {
900  // Ensure only supported FunctorEvaluationKinds are used
901  static_assert((FEK == FunctorEvaluationKind::Value) || (FEK == FunctorEvaluationKind::Dot),
902  "Only Value and Dot evaluations currently supported");
903 
904  // Special handling for central differencing as it is the only interpolation method which
905  // currently supports skew correction
907  return linearInterpolation<T, FEK>(functor, face, time);
908 
909  if (face.limiter_type == LimiterType::Upwind ||
910  face.limiter_type == LimiterType::CentralDifference)
911  {
912  // Compute interpolation coefficients and advected values
913  const auto [interp_coeffs, advected] = interpCoeffsAndAdvected<T, FEK>(functor, face, time);
914  // Return the interpolated value
915  return interp_coeffs.first * advected.first + interp_coeffs.second * advected.second;
916  }
917  else
918  {
919  // Determine the gradient evaluation kind
921  typedef typename FunctorBase<T>::GradientType GradientType;
922  static const GradientType zero(0);
923  const auto & limiter =
924  Limiter<typename LimiterValueType<T>::value_type>::build(face.limiter_type);
925 
926  // Determine upwind and downwind arguments based on the face element
927  const auto & upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor();
928  const auto & downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem();
929  const auto & phi_upwind = functor.template genericEvaluate<FEK>(upwind_arg, time);
930  const auto & phi_downwind = functor.template genericEvaluate<FEK>(downwind_arg, time);
931 
932  // Determine the time argument for the limiter
933  auto * time_arg = face.state_limiter;
934  if (!time_arg)
935  {
937  time_arg = &temp_state;
938  }
939 
940  // Initialize min-max values
942  if (face.limiter_type == LimiterType::Venkatakrishnan || face.limiter_type == LimiterType::SOU)
943  std::tie(max_value, min_value) = computeMinMaxValue(functor, face, *time_arg);
944 
945  // Evaluate the gradient of the functor at the upwind and downwind locations
946  const auto & grad_phi_upwind = functor.template genericEvaluate<GFEK>(upwind_arg, *time_arg);
947  const auto & grad_phi_face = functor.template genericEvaluate<GFEK>(face, *time_arg);
948 
949  // Perform full limited interpolation and return the interpolated value
950  return fullLimitedInterpolation(*limiter,
951  phi_upwind,
952  phi_downwind,
953  &grad_phi_upwind,
954  &grad_phi_face,
955  max_value,
956  min_value,
957  face);
958  }
959 }
960 
981 template <typename T>
984  const FaceArg & face,
985  const StateArg & time)
986 {
987  // Define a zero gradient vector for initialization
988  static const libMesh::VectorValue<T> grad_zero(0);
989 
990  mooseAssert(face.fi, "this must be non-null");
991 
992  // Construct the limiter based on the face limiter type
993  const auto limiter = Limiter<typename LimiterValueType<T>::value_type>::build(face.limiter_type);
994 
995  // Determine upwind and downwind arguments based on the face element
996  const auto upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor();
997  const auto downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem();
998  auto phi_upwind = functor(upwind_arg, time);
999  auto phi_downwind = functor(downwind_arg, time);
1000 
1001  // Initialize the return vector value
1003  T coeff_upwind, coeff_downwind;
1004 
1005  // Compute interpolation coefficients and advected values for Upwind or CentralDifference limiters
1006  if (face.limiter_type == LimiterType::Upwind ||
1008  {
1009  for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
1010  {
1011  const auto &component_upwind = phi_upwind(i), component_downwind = phi_downwind(i);
1012  std::tie(coeff_upwind, coeff_downwind) = interpCoeffs(*limiter,
1013  component_upwind,
1014  component_downwind,
1015  &grad_zero,
1016  &grad_zero,
1019  *face.fi,
1020  face.elem_is_upwind);
1021  ret(i) = coeff_upwind * component_upwind + coeff_downwind * component_downwind;
1022  }
1023  }
1024  else
1025  {
1026  // Determine the time argument for the limiter
1027  auto * time_arg = face.state_limiter;
1028  if (!time_arg)
1029  {
1031  time_arg = &temp_state;
1032  }
1033 
1034  // Evaluate the gradient of the functor at the upwind and downwind locations
1035  const auto & grad_phi_upwind = functor.gradient(upwind_arg, *time_arg);
1036  const auto & grad_phi_downwind = functor.gradient(downwind_arg, *time_arg);
1037 
1038  const auto coeffs = interpCoeffs(InterpMethod::Average, *face.fi, face.elem_is_upwind);
1039 
1040  // Compute interpolation coefficients and advected values for each component
1041  for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
1042  {
1043  const auto &component_upwind = phi_upwind(i), component_downwind = phi_downwind(i);
1044  const libMesh::VectorValue<T> &grad_upwind = grad_phi_upwind.row(i),
1045  grad_face = coeffs.first * grad_phi_upwind.row(i) +
1046  coeffs.second * grad_phi_downwind.row(i);
1047 
1048  // Initialize min-max values
1052  std::tie(max_value, min_value) = computeMinMaxValue(functor, face, *time_arg, i);
1053 
1054  // Perform full limited interpolation for the component
1055  ret(i) = fullLimitedInterpolation(*limiter,
1056  component_upwind,
1057  component_downwind,
1058  &grad_upwind,
1059  &grad_face,
1060  max_value,
1061  min_value,
1062  face);
1063  }
1064  }
1065 
1066  // Return the interpolated vector value
1067  return ret;
1068 }
1069 
1090 template <typename T>
1091 T
1092 containerInterpolate(const FunctorBase<T> & functor, const FaceArg & face, const StateArg & time)
1093 {
1094  typedef typename FunctorBase<T>::GradientType ContainerGradientType;
1095  typedef typename ContainerGradientType::value_type GradientType;
1096  const GradientType * const example_gradient = nullptr;
1097 
1098  mooseAssert(face.fi, "this must be non-null");
1099  const auto limiter = Limiter<typename T::value_type>::build(face.limiter_type);
1100 
1101  const auto upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor();
1102  const auto downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem();
1103  const auto phi_upwind = functor(upwind_arg, time);
1104  const auto phi_downwind = functor(downwind_arg, time);
1105 
1106  // initialize in order to get proper size
1107  T ret = phi_upwind;
1108  typename T::value_type coeff_upwind, coeff_downwind;
1109 
1110  if (face.limiter_type == LimiterType::Upwind ||
1112  {
1113  for (const auto i : index_range(ret))
1114  {
1115  const auto &component_upwind = phi_upwind[i], component_downwind = phi_downwind[i];
1116  std::tie(coeff_upwind, coeff_downwind) = interpCoeffs(*limiter,
1117  component_upwind,
1118  component_downwind,
1119  example_gradient,
1120  example_gradient,
1123  *face.fi,
1124  face.elem_is_upwind);
1125  ret[i] = coeff_upwind * component_upwind + coeff_downwind * component_downwind;
1126  }
1127  }
1128  else
1129  {
1130  const auto grad_phi_upwind = functor.gradient(upwind_arg, time);
1131  for (const auto i : index_range(ret))
1132  {
1133  const auto &component_upwind = phi_upwind[i], component_downwind = phi_downwind[i];
1134  const auto & grad = grad_phi_upwind[i];
1135  std::tie(coeff_upwind, coeff_downwind) = interpCoeffs(*limiter,
1136  component_upwind,
1137  component_downwind,
1138  &grad,
1139  example_gradient,
1142  *face.fi,
1143  face.elem_is_upwind);
1144  ret[i] = coeff_upwind * component_upwind + coeff_downwind * component_downwind;
1145  }
1146  }
1147 
1148  return ret;
1149 }
1150 
1151 template <typename T>
1152 std::vector<T>
1153 interpolate(const FunctorBase<std::vector<T>> & functor,
1154  const FaceArg & face,
1155  const StateArg & time)
1156 {
1157  return containerInterpolate(functor, face, time);
1158 }
1159 
1160 template <typename T, std::size_t N>
1161 std::array<T, N>
1162 interpolate(const FunctorBase<std::array<T, N>> & functor,
1163  const FaceArg & face,
1164  const StateArg & time)
1165 {
1166  return containerInterpolate(functor, face, time);
1167 }
1168 
1172 template <typename SubdomainRestrictable>
1173 bool
1174 onBoundary(const SubdomainRestrictable & obj, const FaceInfo & fi)
1175 {
1176  const bool internal = fi.neighborPtr() && obj.hasBlocks(fi.elemSubdomainID()) &&
1177  obj.hasBlocks(fi.neighborSubdomainID());
1178  return !internal;
1179 }
1180 
1186 bool onBoundary(const std::set<SubdomainID> & subs, const FaceInfo & fi);
1187 }
1188 }
gc*elem+(1-gc)*neighbor
int eps(unsigned int i, unsigned int j)
2D version
Base class template for functor objects.
Definition: MooseFunctor.h:137
libMesh::CompareTypes< T1, T2 >::supertype harmonicInterpolation(const T1 &value1, const T2 &value2, const FaceInfo &fi, const bool one_is_elem)
Computes the harmonic mean (1/(gc/value1+(1-gc)/value2)) of Reals, RealVectorValues and RealTensorVal...
Definition: MathFVUtils.h:180
Point skewnessCorrectionVector() const
Returns the skewness-correction vector (vector between the approximate and real face centroids)...
Definition: FaceInfo.C:74
Base class for defining slope limiters for finite volume or potentially reconstructed Discontinuous-G...
Definition: Limiter.h:62
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311
std::pair< Real, Real > interpCoeffs(const InterpMethod m, const FaceInfo &fi, const bool one_is_elem, const T &face_flux=0.0)
Produce the interpolation coefficients in the equation:
Definition: MathFVUtils.h:117
LinearFVComputationMode
Definition: MathFVUtils.h:57
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition: MooseError.h:345
1/(gc/elem+(1-gc)/neighbor)
const Point & faceCentroid() const
Returns the coordinates of the face centroid.
Definition: FaceInfo.h:75
bool correct_skewness
Whether to perform skew correction.
Scalar rF(const Scalar &phiC, const Scalar &phiD, const Vector &gradC, const RealVectorValue &dCD)
From Moukalled 12.30.
Definition: MathFVUtils.h:448
auto raw_value(const Eigen::Map< T > &in)
Definition: EigenADReal.h:100
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
Definition: Moose.h:163
const Point & neighborCentroid() const
Definition: FaceInfo.h:247
const Number zero
libMesh::CompareTypes< T, T2 >::supertype linearInterpolation(const T &value1, const T2 &value2, const FaceInfo &fi, const bool one_is_elem, const InterpMethod interp_method=InterpMethod::Average)
A simple linear interpolation of values between cell centers to a cell face.
Definition: MathFVUtils.h:153
DualNumber< Real, DNDerivativeType, true > ADReal
Definition: ADRealForward.h:42
MooseEnum interpolationMethods()
Returns an enum with all the currently supported interpolation methods and the current default for FV...
Definition: MathFVUtils.C:61
const Moose::StateArg * state_limiter
A member that can be used to define the instance in which the limiters are executed.
T containerInterpolate(const FunctorBase< T > &functor, const FaceArg &face, const StateArg &time)
This function interpolates container values at faces in a computational grid using a specified functo...
Definition: MathFVUtils.h:1092
typename FunctorReturnType< T, FunctorEvaluationKind::Gradient >::type GradientType
This rigmarole makes it so that a user can create functors that return containers (std::vector...
Definition: MooseFunctor.h:149
auto max(const L &left, const R &right)
SubdomainID elemSubdomainID() const
Definition: FaceInfo.h:106
FunctorEvaluationKind
An enumeration of possible functor evaluation kinds.
Definition: MooseFunctor.h:36
libMesh::CompareTypes< T, T2 >::supertype skewCorrectedLinearInterpolation(const T &value1, const T2 &value2, const T3 &face_gradient, const FaceInfo &fi, const bool one_is_elem)
Linear interpolation with skewness correction using the face gradient.
Definition: MathFVUtils.h:264
This data structure is used to store geometric and variable related metadata about each cell face in ...
Definition: FaceInfo.h:37
virtual bool constant() const =0
const Elem * neighborPtr() const
Definition: FaceInfo.h:88
const Point & elemCentroid() const
Returns the element centroids of the elements on the elem and neighbor sides of the face...
Definition: FaceInfo.h:99
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
InputParameters advectedInterpolationParameter()
Definition: MathFVUtils.C:68
A structure defining a "face" evaluation calling argument for Moose functors.
Every object that can be built by the factory should be derived from this class.
Definition: MooseObject.h:28
const FaceInfo * fi
a face information object which defines our location in space
Real gC() const
Return the geometric weighting factor.
Definition: FaceInfo.h:136
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition: MooseEnum.h:54
Moose::FV::LimiterType limiter_type
a limiter which defines how the functor evaluated on either side of the face should be interpolated t...
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.
const Point & normal() const
Returns the unit normal vector for the face oriented outward from the face&#39;s elem element...
Definition: FaceInfo.h:72
std::pair< Real, Real > computeMinMaxValue(const FunctorBase< T > &functor, const FaceArg &face, const StateArg &time)
This function calculates the minimum and maximum values within a two-cell stencil.
Definition: MathFVUtils.h:650
std::string stringify(const T &t)
conversion to string
Definition: Conversion.h:64
This structure takes an evaluation kind as a template argument and defines a constant expression indi...
Definition: MooseFunctor.h:98
bool onBoundary(const SubdomainRestrictable &obj, const FaceInfo &fi)
Return whether the supplied face is on a boundary of the object&#39;s execution.
Definition: MathFVUtils.h:1174
(gc*elem+(1-gc)*neighbor)+gradient*(rf-rf&#39;)
T fullLimitedInterpolation(const Limiter< T > &limiter, const T &phi_upwind, const T &phi_downwind, const VectorValue< T > *const grad_phi_upwind, const VectorValue< T > *const grad_phi_face, const Real &max_value, const Real &min_value, const FaceArg &face)
This function performs a full limited interpolation of a variable, taking into account the values and...
Definition: MathFVUtils.h:585
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
NumberTensorValue Tensor
ADReal gradUDotNormal(const FaceInfo &face_info, const MooseVariableFV< Real > &fv_var, const Moose::StateArg &time, bool correct_skewness=false)
Calculates and returns "grad_u dot normal" on the face to be used for diffusive terms.
Definition: MathFVUtils.C:18
GradientType gradient(const ElemArg &elem, const StateArg &state) const
Same as their evaluateGradient overloads with the same arguments but allows for caching implementatio...
Definition: MooseFunctor.h:853
IntRange< T > make_range(T beg, T end)
SubdomainID neighborSubdomainID() const
Definition: FaceInfo.h:256
State argument for evaluating functors.
InterpMethod selectInterpolationMethod(const std::string &interp_method)
Definition: MathFVUtils.C:81
Venkatakrishnan limiter (smooth, multidimensional).
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
bool elem_is_upwind
a boolean which states whether the face information element is upwind of the face ...
This class provides variable solution values for other classes/objects to bind to when looping over f...
std::pair< std::pair< T, T >, std::pair< T, T > > interpCoeffsAndAdvected(const FunctorBase< T > &functor, const FaceArg &face, const StateArg &time)
This function interpolates values using a specified limiter and face argument.
Definition: MathFVUtils.h:790
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...
Definition: MathFVUtils.h:285
InterpMethod
This codifies a set of available ways to interpolate with elem+neighbor solution information to calcu...
Definition: MathFVUtils.h:38
auto min(const L &left, const R &right)
A base class interface for both producers and consumers of functor face arguments, e.g.
ElemArg makeElem() const
Make a ElemArg from our data using the face information element.
static std::unique_ptr< Limiter > build(LimiterType limiter)
Definition: Limiter.C:32
auto index_range(const T &sizable)
bool setInterpolationMethod(const MooseObject &obj, Moose::FV::InterpMethod &interp_method, const std::string &param_name)
Sets one interpolation method.
Definition: MathFVUtils.C:110
const Point & dCN() const
Definition: FaceInfo.h:142