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 "libmesh/compare_types.h"
18 #include "libmesh/elem.h"
19 #include <tuple>
20 
21 template <typename>
22 class MooseVariableFV;
23 class FaceArgInterface;
24 
25 namespace Moose
26 {
27 namespace FV
28 {
35 enum class InterpMethod
36 {
38  Average,
44  Upwind,
45  // Rhie-Chow
46  RhieChow,
47  VanLeer,
48  MinMod,
49  SOU,
50  QUICK,
52 };
53 
55 {
56  RHS,
57  Matrix,
59 };
60 
67 
73 
74 /*
75  * Converts from the interpolation method to the interpolation enum.
76  * This routine is here in lieu of using a MooseEnum for InterpMethod
77  * @param interp_method the name of the interpolation method
78  * @return the interpolation method
79  */
80 InterpMethod selectInterpolationMethod(const std::string & interp_method);
81 
90 bool setInterpolationMethod(const MooseObject & obj,
91  Moose::FV::InterpMethod & interp_method,
92  const std::string & param_name);
93 
112 template <typename T = Real>
113 std::pair<Real, Real>
115  const FaceInfo & fi,
116  const bool one_is_elem,
117  const T & face_flux = 0.0)
118 {
119  switch (m)
120  {
123  {
124  if (one_is_elem)
125  return std::make_pair(fi.gC(), 1. - fi.gC());
126  else
127  return std::make_pair(1. - fi.gC(), fi.gC());
128  }
129 
131  {
132  if ((face_flux > 0) == one_is_elem)
133  return std::make_pair(1., 0.);
134  else
135  return std::make_pair(0., 1.);
136  }
137 
138  default:
139  mooseError("Unrecognized interpolation method");
140  }
141 }
142 
148 template <typename T, typename T2>
150 linearInterpolation(const T & value1,
151  const T2 & value2,
152  const FaceInfo & fi,
153  const bool one_is_elem,
154  const InterpMethod interp_method = InterpMethod::Average)
155 {
156  mooseAssert(interp_method == InterpMethod::Average ||
157  interp_method == InterpMethod::SkewCorrectedAverage,
158  "The selected interpolation function only works with average or skewness-corrected "
159  "average options!");
160  const auto coeffs = interpCoeffs(interp_method, fi, one_is_elem);
161  return coeffs.first * value1 + coeffs.second * value2;
162 }
163 
175 template <typename T1, typename T2>
177 harmonicInterpolation(const T1 & value1,
178  const T2 & value2,
179  const FaceInfo & fi,
180  const bool one_is_elem)
181 {
182  // We check if the base values of the given template types match, if not we throw a compile-time
183  // error
184  static_assert(std::is_same<typename MetaPhysicL::RawType<T1>::value_type,
185  typename MetaPhysicL::RawType<T2>::value_type>::value,
186  "The input values for harmonic interpolation need to have the same raw-value!");
187 
188  // Fetch the interpolation coefficients, we use the exact same coefficients as for a simple
189  // weighted average
190  const auto coeffs = interpCoeffs(InterpMethod::Average, fi, one_is_elem);
191 
192  // We check if the types are fit to compute the harmonic mean of. This is done compile-time
193  // using constexpr. We start with Real/ADReal which is straightforward if the input values are
194  // positive.
196  {
197  // The harmonic mean of mixed positive and negative numbers (and 0 as well) is not well-defined
198  // so we assert that the input values shall be positive.
199 #ifndef NDEBUG
200  if (value1 * value2 <= 0)
201  mooseWarning("Input values (" + Moose::stringify(MetaPhysicL::raw_value(value1)) + " & " +
203  ") must be of the same sign for harmonic interpolation");
204 #endif
205  return 1.0 / (coeffs.first / value1 + coeffs.second / value2);
206  }
207  // For vectors (ADRealVectorValue, VectorValue), we take the component-wise harmonic mean
208  else if constexpr (libMesh::TensorTools::TensorTraits<T1>::rank == 1)
209  {
211  for (const auto i : make_range(Moose::dim))
212  {
213 #ifndef NDEBUG
214  if (value1(i) * value2(i) <= 0)
215  mooseWarning("Component " + std::to_string(i) + " of input values (" +
216  Moose::stringify(MetaPhysicL::raw_value(value1(i))) + " & " +
218  ") must be of the same sign for harmonic interpolation");
219 #endif
220  result(i) = 1.0 / (coeffs.first / value1(i) + coeffs.second / value2(i));
221  }
222  return result;
223  }
224  // For tensors (ADRealTensorValue, TensorValue), similarly to the vectors,
225  // we take the component-wise harmonic mean instead of the matrix-inverse approach
226  else if constexpr (libMesh::TensorTools::TensorTraits<T1>::rank == 2)
227  {
229  for (const auto i : make_range(Moose::dim))
230  for (const auto j : make_range(Moose::dim))
231  {
232 #ifndef NDEBUG
233  if (value1(i, j) * value2(i, j) <= 0)
234  mooseWarning("Component (" + std::to_string(i) + "," + std::to_string(j) +
235  ") of input values (" +
236  Moose::stringify(MetaPhysicL::raw_value(value1(i, j))) + " & " +
238  ") must be of the same sign for harmonic interpolation");
239 #endif
240  result(i, j) = 1.0 / (coeffs.first / value1(i, j) + coeffs.second / value2(i, j));
241  }
242  return result;
243  }
244  // We ran out of options, harmonic mean is not supported for other types at the moment
245  else
246  // This line is supposed to throw an error when the user tries to compile this function with
247  // types that are not supported. This is the reason we needed the always_false function. Hope as
248  // C++ gets nicer, we can do this in a nicer way.
249  static_assert(Moose::always_false<T1>,
250  "Harmonic interpolation is not implemented for the used type!");
251 }
252 
259 template <typename T, typename T2, typename T3>
262  const T2 & value2,
263  const T3 & face_gradient,
264  const FaceInfo & fi,
265  const bool one_is_elem)
266 {
267  const auto coeffs = interpCoeffs(InterpMethod::SkewCorrectedAverage, fi, one_is_elem);
268 
269  auto value = (coeffs.first * value1 + coeffs.second * value2) +
270  face_gradient * fi.skewnessCorrectionVector();
271  return value;
272 }
273 
280 template <typename T, typename T2, typename T3>
281 void
283  T & result,
284  const T2 & value1,
285  const T3 & value2,
286  const FaceInfo & fi,
287  const bool one_is_elem)
288 {
289  switch (m)
290  {
293  result = linearInterpolation(value1, value2, fi, one_is_elem);
294  break;
296  result = harmonicInterpolation(value1, value2, fi, one_is_elem);
297  break;
298  default:
299  mooseError("unsupported interpolation method for interpolate() function");
300  }
301 }
302 
307 template <typename T, FunctorEvaluationKind FEK = FunctorEvaluationKind::Value>
308 T
309 linearInterpolation(const FunctorBase<T> & functor, const FaceArg & face, const StateArg & time)
310 {
311  static_assert((FEK == FunctorEvaluationKind::Value) || (FEK == FunctorEvaluationKind::Dot),
312  "Only Value and Dot evaluations currently supported");
313  mooseAssert(face.limiter_type == LimiterType::CentralDifference,
314  "this interpolation method is meant for linear interpolations");
315 
316  mooseAssert(face.fi,
317  "We must have a non-null face_info in order to prepare our ElemFromFace tuples");
318 
320 
321  const auto elem_arg = face.makeElem();
322  const auto neighbor_arg = face.makeNeighbor();
323 
324  const auto elem_eval = functor.template genericEvaluate<FEK>(elem_arg, time);
325  const auto neighbor_eval = functor.template genericEvaluate<FEK>(neighbor_arg, time);
326 
327  if (face.correct_skewness)
328  {
329  // This condition ensures that the recursive algorithm (face_center->
330  // face_gradient -> cell_gradient -> face_center -> ...) terminates after
331  // one loop. It is hardcoded to one loop at this point since it yields
332  // 2nd order accuracy on skewed meshes with the minimum additional effort.
333  FaceArg new_face(face);
334  new_face.correct_skewness = false;
335  const auto surface_gradient = functor.template genericEvaluate<GFEK>(new_face, time);
336 
338  elem_eval, neighbor_eval, surface_gradient, *face.fi, true);
339  }
340  else
341  return linearInterpolation(elem_eval, neighbor_eval, *face.fi, true);
342 }
343 
347 template <typename T1,
348  typename T2,
349  typename T3,
350  template <typename>
351  class Vector1,
352  template <typename>
353  class Vector2>
354 void
356  Vector1<T1> & result,
357  const T2 & fi_elem_advected,
358  const T2 & fi_neighbor_advected,
359  const Vector2<T3> & fi_elem_advector,
360  const Vector2<T3> & fi_neighbor_advector,
361  const FaceInfo & fi)
362 {
363  switch (m)
364  {
366  result = linearInterpolation(fi_elem_advected * fi_elem_advector,
367  fi_neighbor_advected * fi_neighbor_advector,
368  fi,
369  true);
370  break;
372  {
373  const auto face_advector = linearInterpolation(MetaPhysicL::raw_value(fi_elem_advector),
374  MetaPhysicL::raw_value(fi_neighbor_advector),
375  fi,
376  true);
377  Real elem_coeff, neighbor_coeff;
378  if (face_advector * fi.normal() > 0)
379  elem_coeff = 1, neighbor_coeff = 0;
380  else
381  elem_coeff = 0, neighbor_coeff = 1;
382 
383  result = elem_coeff * fi_elem_advected * fi_elem_advector +
384  neighbor_coeff * fi_neighbor_advected * fi_neighbor_advector;
385  break;
386  }
387  default:
388  mooseError("unsupported interpolation method for FVFaceInterface::interpolate");
389  }
390 }
391 
400 template <typename T, typename T2, typename T3, typename Vector>
401 void
403  T & result,
404  const T2 & value1,
405  const T3 & value2,
406  const Vector & advector,
407  const FaceInfo & fi,
408  const bool one_is_elem)
409 {
410  const auto coeffs = interpCoeffs(m, fi, one_is_elem, advector * fi.normal());
411  result = coeffs.first * value1 + coeffs.second * value2;
412 }
413 
417 ADReal gradUDotNormal(const FaceInfo & face_info,
418  const MooseVariableFV<Real> & fv_var,
419  const Moose::StateArg & time,
420  bool correct_skewness = false);
421 
443 template <typename Scalar, typename Vector>
444 Scalar
445 rF(const Scalar & phiC, const Scalar & phiD, const Vector & gradC, const RealVectorValue & dCD)
446 {
447  static const auto zero_vec = RealVectorValue(0);
448  if ((phiD - phiC) == 0)
449  // Handle zero denominator case. Note that MathUtils::sign returns 1 for sign(0) so we can omit
450  // that operation here (e.g. sign(phiD - phiC) = sign(0) = 1). The second term preserves the
451  // same sparsity pattern as the else branch; we want to add this so that we don't risk PETSc
452  // shrinking the matrix now and then potentially reallocating nonzeros later (which is very
453  // slow)
454  return 1e6 * MathUtils::sign(gradC * dCD) + zero_vec * gradC;
455 
456  return 2. * gradC * dCD / (phiD - phiC) - 1.;
457 }
458 
470 template <typename T>
471 std::pair<T, T>
472 interpCoeffs(const Limiter<T> & limiter,
473  const T & phi_upwind,
474  const T & phi_downwind,
475  const libMesh::VectorValue<T> * const grad_phi_upwind,
476  const libMesh::VectorValue<T> * const grad_phi_face,
477  const Real & max_value,
478  const Real & min_value,
479  const FaceInfo & fi,
480  const bool fi_elem_is_upwind)
481 {
482  // Using beta, w_f, g nomenclature from Greenshields
483  const auto beta = limiter(phi_upwind,
484  phi_downwind,
485  grad_phi_upwind,
486  grad_phi_face,
487  fi_elem_is_upwind ? fi.dCN() : Point(-fi.dCN()),
488  max_value,
489  min_value,
490  &fi,
491  fi_elem_is_upwind);
492 
493  const auto w_f = fi_elem_is_upwind ? fi.gC() : (1. - fi.gC());
494 
495  const auto g = beta * (1. - w_f);
496 
497  return std::make_pair(1. - g, g);
498 }
499 
503 template <typename Scalar,
504  typename Vector,
505  typename Enable = typename std::enable_if<libMesh::ScalarTraits<Scalar>::value>::type>
506 Scalar
507 interpolate(const Limiter<Scalar> & limiter,
508  const Scalar & phi_upwind,
509  const Scalar & phi_downwind,
510  const Vector * const grad_phi_upwind,
511  const FaceInfo & fi,
512  const bool fi_elem_is_upwind)
513 {
514  auto pr =
515  interpCoeffs(limiter,
516  phi_upwind,
517  phi_downwind,
518  grad_phi_upwind,
519  /*grad_phi_face*/ static_cast<const libMesh::VectorValue<Scalar> *>(nullptr),
520  /* max_value */ std::numeric_limits<Real>::max(),
521  /* min_value */ std::numeric_limits<Real>::min(),
522  fi,
523  fi_elem_is_upwind);
524  return pr.first * phi_upwind + pr.second * phi_downwind;
525 }
526 
530 template <typename Limiter, typename T, typename Tensor>
532 interpolate(const Limiter & limiter,
533  const TypeVector<T> & phi_upwind,
534  const TypeVector<T> & phi_downwind,
535  const Tensor * const grad_phi_upwind,
536  const FaceInfo & fi,
537  const bool fi_elem_is_upwind)
538 {
539  mooseAssert(limiter.constant() || grad_phi_upwind,
540  "Non-null gradient only supported for constant limiters.");
541 
542  const libMesh::VectorValue<T> * const gradient_example = nullptr;
544  for (const auto i : make_range(unsigned(LIBMESH_DIM)))
545  {
546  if (grad_phi_upwind)
547  {
548  const libMesh::VectorValue<T> gradient = grad_phi_upwind->row(i);
549  ret(i) =
550  interpolate(limiter, phi_upwind(i), phi_downwind(i), &gradient, fi, fi_elem_is_upwind);
551  }
552  else
553  ret(i) = interpolate(
554  limiter, phi_upwind(i), phi_downwind(i), gradient_example, fi, fi_elem_is_upwind);
555  }
556 
557  return ret;
558 }
559 
578 template <typename T>
579 T
581  const T & phi_upwind,
582  const T & phi_downwind,
583  const VectorValue<T> * const grad_phi_upwind,
584  const VectorValue<T> * const grad_phi_face,
585  const Real & max_value,
586  const Real & min_value,
587  const FaceArg & face)
588 {
589  // Compute the direction vector based on whether the current element is upwind
590  const auto dCD = face.elem_is_upwind ? face.fi->dCN() : Point(-face.fi->dCN());
591 
592  // Compute the flux limiting ratio using the specified limiter
593  const auto beta = limiter(phi_upwind,
594  phi_downwind,
595  grad_phi_upwind,
596  grad_phi_face,
597  dCD,
598  max_value,
599  min_value,
600  face.fi,
601  face.elem_is_upwind);
602 
603  // Determine the face centroid and the appropriate cell centroid
604  const auto & face_centroid = face.fi->faceCentroid();
605  const auto & cell_centroid =
606  face.elem_is_upwind ? face.fi->elemCentroid() : face.fi->neighborCentroid();
607 
608  // Compute the delta value at the face
609  T delta_face;
611  delta_face = (*grad_phi_upwind) * (face_centroid - cell_centroid);
612  else
613  delta_face = (*grad_phi_face) * (face_centroid - cell_centroid);
614 
615  // Return the interpolated value
616  return phi_upwind + beta * delta_face;
617 }
618 
641 template <typename T,
643  typename Enable = typename std::enable_if<ScalarTraits<T>::value>::type>
644 std::pair<Real, Real>
645 computeMinMaxValue(const FunctorBase<T> & functor, const FaceArg & face, const StateArg & time)
646 {
647  // Initialize max_value to 0 and min_value to a large value
649 
650  // Iterate over the direct neighbors of the element associated with the face
651  for (const auto neighbor : (*face.fi).elem().neighbor_ptr_range())
652  {
653  // If not a valid neighbor, skip to the next one
654  if (neighbor == nullptr)
655  continue;
656 
657  // Evaluate the functor at the neighbor and update max_value and min_value
658  const ElemArg local_cell_arg = {neighbor, false};
659  const auto value =
660  MetaPhysicL::raw_value(functor.template genericEvaluate<FEK>(local_cell_arg, time));
661  max_value = std::max(max_value, value);
662  min_value = std::min(min_value, value);
663  }
664 
665  // Iterate over the neighbors of the neighbor
666  for (const auto neighbor : (*face.fi).neighbor().neighbor_ptr_range())
667  {
668  // If not a valid neighbor, skip to the next one
669  if (neighbor == nullptr)
670  continue;
671 
672  // Evaluate the functor at the neighbor and update max_value and min_value
673  const ElemArg local_cell_arg = {neighbor, false};
674  const auto value =
675  MetaPhysicL::raw_value(functor.template genericEvaluate<FEK>(local_cell_arg, time));
676  max_value = std::max(max_value, value);
677  min_value = std::min(min_value, value);
678  }
679 
680  // Return a pair containing the computed maximum and minimum values
681  return std::make_pair(max_value, min_value);
682 }
683 
709 template <typename T>
710 std::pair<Real, Real>
711 computeMinMaxValue(const FunctorBase<VectorValue<T>> & functor,
712  const FaceArg & face,
713  const StateArg & time,
714  const unsigned int & component)
715 {
716  // Initialize max_value to 0 and min_value to a large value
718 
719  // Iterate over the direct neighbors of the element associated with the face
720  for (const auto neighbor : (*face.fi).elem().neighbor_ptr_range())
721  {
722  // If not a valid neighbor, skip to the next one
723  if (neighbor == nullptr)
724  continue;
725 
726  // Evaluate the functor at the neighbor for the specified component and update max_value and
727  // min_value
728  const ElemArg local_cell_arg = {neighbor, false};
729  const auto value = MetaPhysicL::raw_value(functor(local_cell_arg, time)(component));
730  max_value = std::max(max_value, value);
731  min_value = std::min(min_value, value);
732  }
733 
734  // Iterate over the neighbors of the neighbor associated with the face
735  for (const auto neighbor : (*face.fi).neighbor().neighbor_ptr_range())
736  {
737  // If not a valid neighbor, skip to the next one
738  if (neighbor == nullptr)
739  continue;
740 
741  // Evaluate the functor at the neighbor for the specified component and update max_value and
742  // min_value
743  const ElemArg local_cell_arg = {neighbor, false};
744  const auto value = MetaPhysicL::raw_value(functor(local_cell_arg, time)(component));
745  max_value = std::max(max_value, value);
746  min_value = std::min(min_value, value);
747  }
748 
749  // Return a pair containing the computed maximum and minimum values
750  return std::make_pair(max_value, min_value);
751 }
752 
781 template <typename T,
783  typename Enable = typename std::enable_if<libMesh::ScalarTraits<T>::value>::type>
784 std::pair<std::pair<T, T>, std::pair<T, T>>
785 interpCoeffsAndAdvected(const FunctorBase<T> & functor, const FaceArg & face, const StateArg & time)
786 {
787  // Ensure only supported FunctorEvaluationKinds are used
788  static_assert((FEK == FunctorEvaluationKind::Value) || (FEK == FunctorEvaluationKind::Dot),
789  "Only Value and Dot evaluations currently supported");
790 
791  // Determine the gradient evaluation kind
794  static const GradientType zero(0);
795 
796  mooseAssert(face.fi, "this must be non-null");
797 
798  // Construct the limiter based on the face limiter type
799  const auto limiter = Limiter<typename LimiterValueType<T>::value_type>::build(face.limiter_type);
800 
801  // Determine upwind and downwind arguments based on the face element
802  const auto upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor();
803  const auto downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem();
804 
805  // Evaluate the functor at the upwind and downwind locations
806  auto phi_upwind = functor.template genericEvaluate<FEK>(upwind_arg, time);
807  auto phi_downwind = functor.template genericEvaluate<FEK>(downwind_arg, time);
808 
809  // Initialize the interpolation coefficients
810  std::pair<T, T> interp_coeffs;
811 
812  // Compute interpolation coefficients for Upwind or CentralDifference limiters
813  if (face.limiter_type == LimiterType::Upwind ||
815  interp_coeffs = interpCoeffs(*limiter,
816  phi_upwind,
817  phi_downwind,
818  &zero,
819  &zero,
822  *face.fi,
823  face.elem_is_upwind);
824  else
825  {
826  // Determine the time argument for the limiter
827  auto * time_arg = face.state_limiter;
828  if (!time_arg)
829  {
831  time_arg = &temp_state;
832  }
833 
835 
836  // Compute min-max values for min-max limiters
838  std::tie(max_value, min_value) = computeMinMaxValue(functor, face, *time_arg);
839 
840  // Evaluate the gradient of the functor at the upwind and downwind locations
841  const auto grad_phi_upwind = functor.template genericEvaluate<GFEK>(upwind_arg, *time_arg);
842  const auto grad_phi_face = functor.template genericEvaluate<GFEK>(face, *time_arg);
843 
844  // Compute the interpolation coefficients using the specified limiter
845  interp_coeffs = interpCoeffs(*limiter,
846  phi_upwind,
847  phi_downwind,
848  &grad_phi_upwind,
849  &grad_phi_face,
850  max_value,
851  min_value,
852  *face.fi,
853  face.elem_is_upwind);
854  }
855 
856  // Return the interpolation coefficients and advected values
857  if (face.elem_is_upwind)
858  return std::make_pair(std::move(interp_coeffs),
859  std::make_pair(std::move(phi_upwind), std::move(phi_downwind)));
860  else
861  return std::make_pair(
862  std::make_pair(std::move(interp_coeffs.second), std::move(interp_coeffs.first)),
863  std::make_pair(std::move(phi_downwind), std::move(phi_upwind)));
864 }
865 
889 template <typename T,
891  typename Enable = typename std::enable_if<libMesh::ScalarTraits<T>::value>::type>
892 T
893 interpolate(const FunctorBase<T> & functor, const FaceArg & face, const StateArg & time)
894 {
895  // Ensure only supported FunctorEvaluationKinds are used
896  static_assert((FEK == FunctorEvaluationKind::Value) || (FEK == FunctorEvaluationKind::Dot),
897  "Only Value and Dot evaluations currently supported");
898 
899  // Special handling for central differencing as it is the only interpolation method which
900  // currently supports skew correction
902  return linearInterpolation<T, FEK>(functor, face, time);
903 
904  if (face.limiter_type == LimiterType::Upwind ||
905  face.limiter_type == LimiterType::CentralDifference)
906  {
907  // Compute interpolation coefficients and advected values
908  const auto [interp_coeffs, advected] = interpCoeffsAndAdvected<T, FEK>(functor, face, time);
909  // Return the interpolated value
910  return interp_coeffs.first * advected.first + interp_coeffs.second * advected.second;
911  }
912  else
913  {
914  // Determine the gradient evaluation kind
917  static const GradientType zero(0);
918  const auto & limiter =
919  Limiter<typename LimiterValueType<T>::value_type>::build(face.limiter_type);
920 
921  // Determine upwind and downwind arguments based on the face element
922  const auto & upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor();
923  const auto & downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem();
924  const auto & phi_upwind = functor.template genericEvaluate<FEK>(upwind_arg, time);
925  const auto & phi_downwind = functor.template genericEvaluate<FEK>(downwind_arg, time);
926 
927  // Determine the time argument for the limiter
928  auto * time_arg = face.state_limiter;
929  if (!time_arg)
930  {
932  time_arg = &temp_state;
933  }
934 
935  // Initialize min-max values
937  if (face.limiter_type == LimiterType::Venkatakrishnan || face.limiter_type == LimiterType::SOU)
938  std::tie(max_value, min_value) = computeMinMaxValue(functor, face, *time_arg);
939 
940  // Evaluate the gradient of the functor at the upwind and downwind locations
941  const auto & grad_phi_upwind = functor.template genericEvaluate<GFEK>(upwind_arg, *time_arg);
942  const auto & grad_phi_face = functor.template genericEvaluate<GFEK>(face, *time_arg);
943 
944  // Perform full limited interpolation and return the interpolated value
945  return fullLimitedInterpolation(*limiter,
946  phi_upwind,
947  phi_downwind,
948  &grad_phi_upwind,
949  &grad_phi_face,
950  max_value,
951  min_value,
952  face);
953  }
954 }
955 
976 template <typename T>
979  const FaceArg & face,
980  const StateArg & time)
981 {
982  // Define a zero gradient vector for initialization
983  static const libMesh::VectorValue<T> grad_zero(0);
984 
985  mooseAssert(face.fi, "this must be non-null");
986 
987  // Construct the limiter based on the face limiter type
988  const auto limiter = Limiter<typename LimiterValueType<T>::value_type>::build(face.limiter_type);
989 
990  // Determine upwind and downwind arguments based on the face element
991  const auto upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor();
992  const auto downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem();
993  auto phi_upwind = functor(upwind_arg, time);
994  auto phi_downwind = functor(downwind_arg, time);
995 
996  // Initialize the return vector value
998  T coeff_upwind, coeff_downwind;
999 
1000  // Compute interpolation coefficients and advected values for Upwind or CentralDifference limiters
1001  if (face.limiter_type == LimiterType::Upwind ||
1003  {
1004  for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
1005  {
1006  const auto &component_upwind = phi_upwind(i), component_downwind = phi_downwind(i);
1007  std::tie(coeff_upwind, coeff_downwind) = interpCoeffs(*limiter,
1008  component_upwind,
1009  component_downwind,
1010  &grad_zero,
1011  &grad_zero,
1014  *face.fi,
1015  face.elem_is_upwind);
1016  ret(i) = coeff_upwind * component_upwind + coeff_downwind * component_downwind;
1017  }
1018  }
1019  else
1020  {
1021  // Determine the time argument for the limiter
1022  auto * time_arg = face.state_limiter;
1023  if (!time_arg)
1024  {
1026  time_arg = &temp_state;
1027  }
1028 
1029  // Evaluate the gradient of the functor at the upwind and downwind locations
1030  const auto & grad_phi_upwind = functor.gradient(upwind_arg, *time_arg);
1031  const auto & grad_phi_downwind = functor.gradient(downwind_arg, *time_arg);
1032 
1033  const auto coeffs = interpCoeffs(InterpMethod::Average, *face.fi, face.elem_is_upwind);
1034 
1035  // Compute interpolation coefficients and advected values for each component
1036  for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
1037  {
1038  const auto &component_upwind = phi_upwind(i), component_downwind = phi_downwind(i);
1039  const libMesh::VectorValue<T> &grad_upwind = grad_phi_upwind.row(i),
1040  grad_face = coeffs.first * grad_phi_upwind.row(i) +
1041  coeffs.second * grad_phi_downwind.row(i);
1042 
1043  // Initialize min-max values
1047  std::tie(max_value, min_value) = computeMinMaxValue(functor, face, *time_arg, i);
1048 
1049  // Perform full limited interpolation for the component
1050  ret(i) = fullLimitedInterpolation(*limiter,
1051  component_upwind,
1052  component_downwind,
1053  &grad_upwind,
1054  &grad_face,
1055  max_value,
1056  min_value,
1057  face);
1058  }
1059  }
1060 
1061  // Return the interpolated vector value
1062  return ret;
1063 }
1064 
1085 template <typename T>
1086 T
1087 containerInterpolate(const FunctorBase<T> & functor, const FaceArg & face, const StateArg & time)
1088 {
1089  typedef typename FunctorBase<T>::GradientType ContainerGradientType;
1090  typedef typename ContainerGradientType::value_type GradientType;
1091  const GradientType * const example_gradient = nullptr;
1092 
1093  mooseAssert(face.fi, "this must be non-null");
1094  const auto limiter = Limiter<typename T::value_type>::build(face.limiter_type);
1095 
1096  const auto upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor();
1097  const auto downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem();
1098  const auto phi_upwind = functor(upwind_arg, time);
1099  const auto phi_downwind = functor(downwind_arg, time);
1100 
1101  // initialize in order to get proper size
1102  T ret = phi_upwind;
1103  typename T::value_type coeff_upwind, coeff_downwind;
1104 
1105  if (face.limiter_type == LimiterType::Upwind ||
1107  {
1108  for (const auto i : index_range(ret))
1109  {
1110  const auto &component_upwind = phi_upwind[i], component_downwind = phi_downwind[i];
1111  std::tie(coeff_upwind, coeff_downwind) = interpCoeffs(*limiter,
1112  component_upwind,
1113  component_downwind,
1114  example_gradient,
1115  example_gradient,
1118  *face.fi,
1119  face.elem_is_upwind);
1120  ret[i] = coeff_upwind * component_upwind + coeff_downwind * component_downwind;
1121  }
1122  }
1123  else
1124  {
1125  const auto grad_phi_upwind = functor.gradient(upwind_arg, time);
1126  for (const auto i : index_range(ret))
1127  {
1128  const auto &component_upwind = phi_upwind[i], component_downwind = phi_downwind[i];
1129  const auto & grad = grad_phi_upwind[i];
1130  std::tie(coeff_upwind, coeff_downwind) = interpCoeffs(*limiter,
1131  component_upwind,
1132  component_downwind,
1133  &grad,
1134  example_gradient,
1137  *face.fi,
1138  face.elem_is_upwind);
1139  ret[i] = coeff_upwind * component_upwind + coeff_downwind * component_downwind;
1140  }
1141  }
1142 
1143  return ret;
1144 }
1145 
1146 template <typename T>
1147 std::vector<T>
1148 interpolate(const FunctorBase<std::vector<T>> & functor,
1149  const FaceArg & face,
1150  const StateArg & time)
1151 {
1152  return containerInterpolate(functor, face, time);
1153 }
1154 
1155 template <typename T, std::size_t N>
1156 std::array<T, N>
1157 interpolate(const FunctorBase<std::array<T, N>> & functor,
1158  const FaceArg & face,
1159  const StateArg & time)
1160 {
1161  return containerInterpolate(functor, face, time);
1162 }
1163 
1167 template <typename SubdomainRestrictable>
1168 bool
1169 onBoundary(const SubdomainRestrictable & obj, const FaceInfo & fi)
1170 {
1171  const bool internal = fi.neighborPtr() && obj.hasBlocks(fi.elemSubdomainID()) &&
1172  obj.hasBlocks(fi.neighborSubdomainID());
1173  return !internal;
1174 }
1175 
1181 bool onBoundary(const std::set<SubdomainID> & subs, const FaceInfo & fi);
1182 }
1183 }
gc*elem+(1-gc)*neighbor
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:177
Point skewnessCorrectionVector() const
Returns the skewness-correction vector (vector between the approximate and real face centroids)...
Definition: FaceInfo.C:80
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:302
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:114
LinearFVComputationMode
Definition: MathFVUtils.h:54
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition: MooseError.h:336
1/(gc/elem+(1-gc)/neighbor)
const Point & faceCentroid() const
Returns the coordinates of the face centroid.
Definition: FaceInfo.h:71
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:445
auto raw_value(const Eigen::Map< T > &in)
Definition: EigenADReal.h:73
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:153
const Point & neighborCentroid() const
Definition: FaceInfo.h:243
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:150
DualNumber< Real, DNDerivativeType, true > ADReal
Definition: ADRealForward.h:47
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:1087
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:102
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:261
This data structure is used to store geometric and variable related metadata about each cell face in ...
Definition: FaceInfo.h:36
virtual bool constant() const =0
const Elem * neighborPtr() const
Definition: FaceInfo.h:84
const Point & elemCentroid() const
Returns the element centroids of the elements on the elem and neighbor sides of the face...
Definition: FaceInfo.h:95
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:132
T sign(T x)
Definition: MathUtils.h:84
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition: MooseEnum.h:33
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:68
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:645
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:1169
(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:580
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:847
IntRange< T > make_range(T beg, T end)
SubdomainID neighborSubdomainID() const
Definition: FaceInfo.h:252
State argument for evaluating functors.
InterpMethod selectInterpolationMethod(const std::string &interp_method)
Definition: MathFVUtils.C:81
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:785
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:282
InterpMethod
This codifies a set of available ways to interpolate with elem+neighbor solution information to calcu...
Definition: MathFVUtils.h:35
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:138