https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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
24template <typename>
25class MooseVariableFV;
27
28namespace Moose
29{
30namespace FV
31{
38enum class InterpMethod
39{
41 Average,
47 Upwind,
48 // Rhie-Chow
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 */
83InterpMethod selectInterpolationMethod(const std::string & interp_method);
84
93bool setInterpolationMethod(const MooseObject & obj,
94 Moose::FV::InterpMethod & interp_method,
95 const std::string & param_name);
96
115template <typename T = Real>
116std::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
151template <typename T, typename T2>
153linearInterpolation(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
177template <typename T1, typename T2>
179harmonicInterpolation(const T1 & value1, const T2 & value2, const Real weight1, const Real weight2)
180{
181 // We check if the base values of the given template types match, if not we throw a compile-time
182 // error
183 static_assert(std::is_same<typename MetaPhysicL::RawType<T1>::value_type,
184 typename MetaPhysicL::RawType<T2>::value_type>::value,
185 "The input values for harmonic interpolation need to have the same raw-value!");
186
187 // We check if the types are fit to compute the harmonic mean of. This is done compile-time
188 // using constexpr. We start with Real/ADReal which is straightforward if the input values are
189 // positive.
191 {
192 // The harmonic mean of mixed positive and negative numbers (and 0 as well) is not well-defined
193 // so we assert that the input values shall be positive.
194#ifndef NDEBUG
195 if (value1 * value2 <= 0)
196 mooseWarning("Input values (" + Moose::stringify(MetaPhysicL::raw_value(value1)) + " & " +
198 ") must be of the same sign for harmonic interpolation");
199#endif
200 return 1.0 / (weight1 / value1 + weight2 / value2);
201 }
202 // For vectors (ADRealVectorValue, VectorValue), we take the component-wise harmonic mean
203 else if constexpr (libMesh::TensorTools::TensorTraits<T1>::rank == 1)
204 {
206 for (const auto i : make_range(Moose::dim))
207 {
208#ifndef NDEBUG
209 if (value1(i) * value2(i) <= 0)
210 mooseWarning("Component " + std::to_string(i) + " of input values (" +
211 Moose::stringify(MetaPhysicL::raw_value(value1(i))) + " & " +
213 ") must be of the same sign for harmonic interpolation");
214#endif
215 result(i) = 1.0 / (weight1 / value1(i) + weight2 / value2(i));
216 }
217 return result;
218 }
219 // For tensors (ADRealTensorValue, TensorValue), similarly to the vectors,
220 // we take the component-wise harmonic mean instead of the matrix-inverse approach
221 else if constexpr (libMesh::TensorTools::TensorTraits<T1>::rank == 2)
222 {
224 for (const auto i : make_range(Moose::dim))
225 for (const auto j : make_range(Moose::dim))
226 {
227#ifndef NDEBUG
228 if (value1(i, j) * value2(i, j) <= 0)
229 mooseWarning("Component (" + std::to_string(i) + "," + std::to_string(j) +
230 ") of input values (" +
231 Moose::stringify(MetaPhysicL::raw_value(value1(i, j))) + " & " +
233 ") must be of the same sign for harmonic interpolation");
234#endif
235 result(i, j) = 1.0 / (weight1 / value1(i, j) + weight2 / value2(i, j));
236 }
237 return result;
238 }
239 // We ran out of options, harmonic mean is not supported for other types at the moment
240 else
241 // This line is supposed to throw an error when the user tries to compile this function with
242 // types that are not supported. This is the reason we needed the always_false function. Hope as
243 // C++ gets nicer, we can do this in a nicer way.
244 static_assert(Moose::always_false<T1>,
245 "Harmonic interpolation is not implemented for the used type!");
246}
247
258template <typename T1, typename T2>
260harmonicInterpolation(const T1 & value1,
261 const T2 & value2,
262 const FaceInfo & fi,
263 const bool one_is_elem)
264{
265 const auto coeffs = interpCoeffs(InterpMethod::Average, fi, one_is_elem);
266 return harmonicInterpolation(value1, value2, coeffs.first, coeffs.second);
267}
268
275template <typename T, typename T2, typename T3>
278 const T2 & value2,
279 const T3 & face_gradient,
280 const FaceInfo & fi,
281 const bool one_is_elem)
282{
283 const auto coeffs = interpCoeffs(InterpMethod::SkewCorrectedAverage, fi, one_is_elem);
284
285 auto value = (coeffs.first * value1 + coeffs.second * value2) +
286 face_gradient * fi.skewnessCorrectionVector();
287 return value;
288}
289
296template <typename T, typename T2, typename T3>
297void
299 T & result,
300 const T2 & value1,
301 const T3 & value2,
302 const FaceInfo & fi,
303 const bool one_is_elem)
304{
305 switch (m)
306 {
309 result = linearInterpolation(value1, value2, fi, one_is_elem);
310 break;
312 result = harmonicInterpolation(value1, value2, fi, one_is_elem);
313 break;
314 default:
315 mooseError("unsupported interpolation method for interpolate() function");
316 }
317}
318
323template <typename T, FunctorEvaluationKind FEK = FunctorEvaluationKind::Value>
324T
325linearInterpolation(const FunctorBase<T> & functor, const FaceArg & face, const StateArg & time)
326{
327 static_assert((FEK == FunctorEvaluationKind::Value) || (FEK == FunctorEvaluationKind::Dot),
328 "Only Value and Dot evaluations currently supported");
330 "this interpolation method is meant for linear interpolations");
331
332 mooseAssert(face.fi,
333 "We must have a non-null face_info in order to prepare our ElemFromFace tuples");
334
336
337 const auto elem_arg = face.makeElem();
338 const auto neighbor_arg = face.makeNeighbor();
339
340 const auto elem_eval = functor.template genericEvaluate<FEK>(elem_arg, time);
341 const auto neighbor_eval = functor.template genericEvaluate<FEK>(neighbor_arg, time);
342
343 if (face.correct_skewness)
344 {
345 // This condition ensures that the recursive algorithm (face_center->
346 // face_gradient -> cell_gradient -> face_center -> ...) terminates after
347 // one loop. It is hardcoded to one loop at this point since it yields
348 // 2nd order accuracy on skewed meshes with the minimum additional effort.
349 FaceArg new_face(face);
350 new_face.correct_skewness = false;
351 const auto surface_gradient = functor.template genericEvaluate<GFEK>(new_face, time);
352
354 elem_eval, neighbor_eval, surface_gradient, *face.fi, true);
355 }
356 else
357 return linearInterpolation(elem_eval, neighbor_eval, *face.fi, true);
358}
359
363template <typename T1,
364 typename T2,
365 typename T3,
366 template <typename> class Vector1,
367 template <typename> class Vector2>
368void
370 Vector1<T1> & result,
371 const T2 & fi_elem_advected,
372 const T2 & fi_neighbor_advected,
373 const Vector2<T3> & fi_elem_advector,
374 const Vector2<T3> & fi_neighbor_advector,
375 const FaceInfo & fi)
376{
377 switch (m)
378 {
380 result = linearInterpolation(fi_elem_advected * fi_elem_advector,
381 fi_neighbor_advected * fi_neighbor_advector,
382 fi,
383 true);
384 break;
386 {
387 const auto face_advector = linearInterpolation(MetaPhysicL::raw_value(fi_elem_advector),
388 MetaPhysicL::raw_value(fi_neighbor_advector),
389 fi,
390 true);
391 Real elem_coeff, neighbor_coeff;
392 if (face_advector * fi.normal() > 0)
393 elem_coeff = 1, neighbor_coeff = 0;
394 else
395 elem_coeff = 0, neighbor_coeff = 1;
396
397 result = elem_coeff * fi_elem_advected * fi_elem_advector +
398 neighbor_coeff * fi_neighbor_advected * fi_neighbor_advector;
399 break;
400 }
401 default:
402 mooseError("unsupported interpolation method for FVFaceInterface::interpolate");
403 }
404}
405
414template <typename T, typename T2, typename T3, typename Vector>
415void
417 T & result,
418 const T2 & value1,
419 const T3 & value2,
420 const Vector & advector,
421 const FaceInfo & fi,
422 const bool one_is_elem)
423{
424 const auto coeffs = interpCoeffs(m, fi, one_is_elem, advector * fi.normal());
425 result = coeffs.first * value1 + coeffs.second * value2;
426}
427
431ADReal gradUDotNormal(const FaceInfo & face_info,
432 const MooseVariableFV<Real> & fv_var,
433 const Moose::StateArg & time,
434 bool correct_skewness = false);
435
459template <typename Scalar, typename Vector>
460Scalar
461rF(const Scalar & phiC, const Scalar & phiD, const Vector & gradC, const RealVectorValue & dCD)
462{
463 const Scalar denom = phiD - phiC;
464 const Scalar grad_dot = gradC * dCD;
465
466 // This is an arbitrary number here, when we start seeing convergence issues we
467 // can tune this but so far this has shown okay results.
468 constexpr Real eps = 1e-10;
469 const Real denom_sign =
470 std::copysign(1.0,
472 std::numeric_limits<Real>::min() * MetaPhysicL::raw_value(grad_dot));
473 const Scalar safe = denom + denom_sign * eps;
474 return 2.0 * grad_dot / safe - 1.0;
475}
476
488template <typename T>
489std::pair<T, T>
490interpCoeffs(const Limiter<T> & limiter,
491 const T & phi_upwind,
492 const T & phi_downwind,
493 const libMesh::VectorValue<T> * const grad_phi_upwind,
494 const libMesh::VectorValue<T> * const grad_phi_face,
495 const Real & max_value,
496 const Real & min_value,
497 const FaceInfo & fi,
498 const bool fi_elem_is_upwind)
499{
500 // Using beta, w_f, g nomenclature from Greenshields
501 const auto beta = limiter(phi_upwind,
502 phi_downwind,
503 grad_phi_upwind,
504 grad_phi_face,
505 fi_elem_is_upwind ? fi.dCN() : Point(-fi.dCN()),
506 max_value,
507 min_value,
508 &fi,
509 fi_elem_is_upwind);
510
511 const auto w_f = fi_elem_is_upwind ? fi.gC() : (1. - fi.gC());
512
513 const auto g = beta * (1. - w_f);
514
515 return std::make_pair(1. - g, g);
516}
517
521template <typename Scalar,
522 typename Vector,
523 typename Enable = typename std::enable_if<libMesh::ScalarTraits<Scalar>::value>::type>
524Scalar
526 const Scalar & phi_upwind,
527 const Scalar & phi_downwind,
528 const Vector * const grad_phi_upwind,
529 const FaceInfo & fi,
530 const bool fi_elem_is_upwind)
531{
532 auto pr =
533 interpCoeffs(limiter,
534 phi_upwind,
535 phi_downwind,
536 grad_phi_upwind,
537 /*grad_phi_face*/ static_cast<const libMesh::VectorValue<Scalar> *>(nullptr),
538 /* max_value */ std::numeric_limits<Real>::max(),
539 /* min_value */ std::numeric_limits<Real>::min(),
540 fi,
541 fi_elem_is_upwind);
542 return pr.first * phi_upwind + pr.second * phi_downwind;
543}
544
548template <typename Limiter, typename T, typename Tensor>
550interpolate(const Limiter & limiter,
551 const TypeVector<T> & phi_upwind,
552 const TypeVector<T> & phi_downwind,
553 const Tensor * const grad_phi_upwind,
554 const FaceInfo & fi,
555 const bool fi_elem_is_upwind)
556{
557 mooseAssert(limiter.constant() || grad_phi_upwind,
558 "Non-null gradient only supported for constant limiters.");
559
560 const libMesh::VectorValue<T> * const gradient_example = nullptr;
562 for (const auto i : make_range(unsigned(LIBMESH_DIM)))
563 {
564 if (grad_phi_upwind)
565 {
566 const libMesh::VectorValue<T> gradient = grad_phi_upwind->row(i);
567 ret(i) =
568 interpolate(limiter, phi_upwind(i), phi_downwind(i), &gradient, fi, fi_elem_is_upwind);
569 }
570 else
571 ret(i) = interpolate(
572 limiter, phi_upwind(i), phi_downwind(i), gradient_example, fi, fi_elem_is_upwind);
573 }
574
575 return ret;
576}
577
596template <typename T>
597T
599 const T & phi_upwind,
600 const T & phi_downwind,
601 const VectorValue<T> * const grad_phi_upwind,
602 const VectorValue<T> * const grad_phi_face,
603 const Real & max_value,
604 const Real & min_value,
605 const FaceArg & face)
606{
607 // Compute the direction vector based on whether the current element is upwind
608 const auto dCD = face.elem_is_upwind ? face.fi->dCN() : Point(-face.fi->dCN());
609
610 // Compute the flux limiting ratio using the specified limiter
611 const auto beta = limiter(phi_upwind,
612 phi_downwind,
613 grad_phi_upwind,
614 grad_phi_face,
615 dCD,
616 max_value,
617 min_value,
618 face.fi,
619 face.elem_is_upwind);
620
621 // Determine the face centroid and the appropriate cell centroid
622 const auto & face_centroid = face.fi->faceCentroid();
623 const auto & cell_centroid =
624 face.elem_is_upwind ? face.fi->elemCentroid() : face.fi->neighborCentroid();
625
626 // Compute the delta value at the face
627 T delta_face;
629 delta_face = (*grad_phi_upwind) * (face_centroid - cell_centroid);
630 else
631 delta_face = (*grad_phi_face) * (face_centroid - cell_centroid);
632
633 // Return the interpolated value
634 return phi_upwind + beta * delta_face;
635}
636
659template <typename T,
661 typename Enable = typename std::enable_if<ScalarTraits<T>::value>::type>
662std::pair<Real, Real>
663computeMinMaxValue(const FunctorBase<T> & functor, const FaceArg & face, const StateArg & time)
664{
665 // Initialize max_value to 0 and min_value to a large value
666 Real max_value(std::numeric_limits<Real>::min()), min_value(std::numeric_limits<Real>::max());
667
668 // Iterate over the direct neighbors of the element associated with the face
669 for (const auto neighbor : (*face.fi).elem().neighbor_ptr_range())
670 {
671 // If not a valid neighbor, skip to the next one
672 if (neighbor == nullptr)
673 continue;
674
675 // Evaluate the functor at the neighbor and update max_value and min_value
676 const ElemArg local_cell_arg = {neighbor, false};
677 const auto value =
678 MetaPhysicL::raw_value(functor.template genericEvaluate<FEK>(local_cell_arg, time));
679 max_value = std::max(max_value, value);
680 min_value = std::min(min_value, value);
681 }
682
683 // Iterate over the neighbors of the neighbor
684 for (const auto neighbor : (*face.fi).neighbor().neighbor_ptr_range())
685 {
686 // If not a valid neighbor, skip to the next one
687 if (neighbor == nullptr)
688 continue;
689
690 // Evaluate the functor at the neighbor and update max_value and min_value
691 const ElemArg local_cell_arg = {neighbor, false};
692 const auto value =
693 MetaPhysicL::raw_value(functor.template genericEvaluate<FEK>(local_cell_arg, time));
694 max_value = std::max(max_value, value);
695 min_value = std::min(min_value, value);
696 }
697
698 // Return a pair containing the computed maximum and minimum values
699 return std::make_pair(max_value, min_value);
700}
701
727template <typename T>
728std::pair<Real, Real>
729computeMinMaxValue(const FunctorBase<VectorValue<T>> & functor,
730 const FaceArg & face,
731 const StateArg & time,
732 const unsigned int & component)
733{
734 // Initialize max_value to 0 and min_value to a large value
735 Real max_value(std::numeric_limits<Real>::min()), min_value(std::numeric_limits<Real>::max());
736
737 // Iterate over the direct neighbors of the element associated with the face
738 for (const auto neighbor : (*face.fi).elem().neighbor_ptr_range())
739 {
740 // If not a valid neighbor, skip to the next one
741 if (neighbor == nullptr)
742 continue;
743
744 // Evaluate the functor at the neighbor for the specified component and update max_value and
745 // min_value
746 const ElemArg local_cell_arg = {neighbor, false};
747 const auto value = MetaPhysicL::raw_value(functor(local_cell_arg, time)(component));
748 max_value = std::max(max_value, value);
749 min_value = std::min(min_value, value);
750 }
751
752 // Iterate over the neighbors of the neighbor associated with the face
753 for (const auto neighbor : (*face.fi).neighbor().neighbor_ptr_range())
754 {
755 // If not a valid neighbor, skip to the next one
756 if (neighbor == nullptr)
757 continue;
758
759 // Evaluate the functor at the neighbor for the specified component and update max_value and
760 // min_value
761 const ElemArg local_cell_arg = {neighbor, false};
762 const auto value = MetaPhysicL::raw_value(functor(local_cell_arg, time)(component));
763 max_value = std::max(max_value, value);
764 min_value = std::min(min_value, value);
765 }
766
767 // Return a pair containing the computed maximum and minimum values
768 return std::make_pair(max_value, min_value);
769}
770
799template <typename T,
801 typename Enable = typename std::enable_if<libMesh::ScalarTraits<T>::value>::type>
802std::pair<std::pair<T, T>, std::pair<T, T>>
803interpCoeffsAndAdvected(const FunctorBase<T> & functor, const FaceArg & face, const StateArg & time)
804{
805 // Ensure only supported FunctorEvaluationKinds are used
806 static_assert((FEK == FunctorEvaluationKind::Value) || (FEK == FunctorEvaluationKind::Dot),
807 "Only Value and Dot evaluations currently supported");
808
809 // Determine the gradient evaluation kind
811 typedef typename FunctorBase<T>::GradientType GradientType;
812 static const GradientType zero(0);
813
814 mooseAssert(face.fi, "this must be non-null");
815
816 // Construct the limiter based on the face limiter type
817 const auto limiter = Limiter<typename LimiterValueType<T>::value_type>::build(face.limiter_type);
818
819 // Determine upwind and downwind arguments based on the face element
820 const auto upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor();
821 const auto downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem();
822
823 // Evaluate the functor at the upwind and downwind locations
824 auto phi_upwind = functor.template genericEvaluate<FEK>(upwind_arg, time);
825 auto phi_downwind = functor.template genericEvaluate<FEK>(downwind_arg, time);
826
827 // Initialize the interpolation coefficients
828 std::pair<T, T> interp_coeffs;
829
830 // Compute interpolation coefficients for Upwind or CentralDifference limiters
831 if (face.limiter_type == LimiterType::Upwind ||
833 interp_coeffs = interpCoeffs(*limiter,
834 phi_upwind,
835 phi_downwind,
836 &zero,
837 &zero,
838 std::numeric_limits<Real>::max(),
839 std::numeric_limits<Real>::min(),
840 *face.fi,
841 face.elem_is_upwind);
842 else
843 {
844 // Determine the time argument for the limiter
845 auto * time_arg = face.state_limiter;
846 if (!time_arg)
847 {
849 time_arg = &temp_state;
850 }
851
852 Real max_value(std::numeric_limits<Real>::min()), min_value(std::numeric_limits<Real>::max());
853
854 // Compute min-max values for min-max limiters
856 std::tie(max_value, min_value) = computeMinMaxValue(functor, face, *time_arg);
857
858 // Evaluate the gradient of the functor at the upwind and downwind locations
859 const auto grad_phi_upwind = functor.template genericEvaluate<GFEK>(upwind_arg, *time_arg);
860 const auto grad_phi_face = functor.template genericEvaluate<GFEK>(face, *time_arg);
861
862 // Compute the interpolation coefficients using the specified limiter
863 interp_coeffs = interpCoeffs(*limiter,
864 phi_upwind,
865 phi_downwind,
866 &grad_phi_upwind,
867 &grad_phi_face,
868 max_value,
869 min_value,
870 *face.fi,
871 face.elem_is_upwind);
872 }
873
874 // Return the interpolation coefficients and advected values
875 if (face.elem_is_upwind)
876 return std::make_pair(std::move(interp_coeffs),
877 std::make_pair(std::move(phi_upwind), std::move(phi_downwind)));
878 else
879 return std::make_pair(
880 std::make_pair(std::move(interp_coeffs.second), std::move(interp_coeffs.first)),
881 std::make_pair(std::move(phi_downwind), std::move(phi_upwind)));
882}
883
907template <typename T,
909 typename Enable = typename std::enable_if<libMesh::ScalarTraits<T>::value>::type>
910T
911interpolate(const FunctorBase<T> & functor, const FaceArg & face, const StateArg & time)
912{
913 // Ensure only supported FunctorEvaluationKinds are used
914 static_assert((FEK == FunctorEvaluationKind::Value) || (FEK == FunctorEvaluationKind::Dot),
915 "Only Value and Dot evaluations currently supported");
916
917 // Special handling for central differencing as it is the only interpolation method which
918 // currently supports skew correction
920 return linearInterpolation<T, FEK>(functor, face, time);
921
922 if (face.limiter_type == LimiterType::Upwind ||
924 {
925 // Compute interpolation coefficients and advected values
926 const auto [interp_coeffs, advected] = interpCoeffsAndAdvected<T, FEK>(functor, face, time);
927 // Return the interpolated value
928 return interp_coeffs.first * advected.first + interp_coeffs.second * advected.second;
929 }
930 else
931 {
932 // Determine the gradient evaluation kind
934 typedef typename FunctorBase<T>::GradientType GradientType;
935 static const GradientType zero(0);
936 const auto & limiter =
938
939 // Determine upwind and downwind arguments based on the face element
940 const auto & upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor();
941 const auto & downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem();
942 const auto & phi_upwind = functor.template genericEvaluate<FEK>(upwind_arg, time);
943 const auto & phi_downwind = functor.template genericEvaluate<FEK>(downwind_arg, time);
944
945 // Determine the time argument for the limiter
946 auto * time_arg = face.state_limiter;
947 if (!time_arg)
948 {
950 time_arg = &temp_state;
951 }
952
953 // Initialize min-max values
954 Real max_value(std::numeric_limits<Real>::min()), min_value(std::numeric_limits<Real>::max());
956 std::tie(max_value, min_value) = computeMinMaxValue(functor, face, *time_arg);
957
958 // Evaluate the gradient of the functor at the upwind and downwind locations
959 const auto & grad_phi_upwind = functor.template genericEvaluate<GFEK>(upwind_arg, *time_arg);
960 const auto & grad_phi_face = functor.template genericEvaluate<GFEK>(face, *time_arg);
961
962 // Perform full limited interpolation and return the interpolated value
963 return fullLimitedInterpolation(*limiter,
964 phi_upwind,
965 phi_downwind,
966 &grad_phi_upwind,
967 &grad_phi_face,
968 max_value,
969 min_value,
970 face);
971 }
972}
973
994template <typename T>
997 const FaceArg & face,
998 const StateArg & time)
999{
1000 // Define a zero gradient vector for initialization
1001 static const libMesh::VectorValue<T> grad_zero(0);
1002
1003 mooseAssert(face.fi, "this must be non-null");
1004
1005 // Construct the limiter based on the face limiter type
1006 const auto limiter = Limiter<typename LimiterValueType<T>::value_type>::build(face.limiter_type);
1007
1008 // Determine upwind and downwind arguments based on the face element
1009 const auto upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor();
1010 const auto downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem();
1011 auto phi_upwind = functor(upwind_arg, time);
1012 auto phi_downwind = functor(downwind_arg, time);
1013
1014 // Initialize the return vector value
1016 T coeff_upwind, coeff_downwind;
1017
1018 // Compute interpolation coefficients and advected values for Upwind or CentralDifference limiters
1019 if (face.limiter_type == LimiterType::Upwind ||
1021 {
1022 for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
1023 {
1024 const auto &component_upwind = phi_upwind(i), component_downwind = phi_downwind(i);
1025 std::tie(coeff_upwind, coeff_downwind) = interpCoeffs(*limiter,
1026 component_upwind,
1027 component_downwind,
1028 &grad_zero,
1029 &grad_zero,
1030 std::numeric_limits<Real>::max(),
1031 std::numeric_limits<Real>::min(),
1032 *face.fi,
1033 face.elem_is_upwind);
1034 ret(i) = coeff_upwind * component_upwind + coeff_downwind * component_downwind;
1035 }
1036 }
1037 else
1038 {
1039 // Determine the time argument for the limiter
1040 auto * time_arg = face.state_limiter;
1041 if (!time_arg)
1042 {
1044 time_arg = &temp_state;
1045 }
1046
1047 // Evaluate the gradient of the functor at the upwind and downwind locations
1048 const auto & grad_phi_upwind = functor.gradient(upwind_arg, *time_arg);
1049 const auto & grad_phi_downwind = functor.gradient(downwind_arg, *time_arg);
1050
1051 const auto coeffs = interpCoeffs(InterpMethod::Average, *face.fi, face.elem_is_upwind);
1052
1053 // Compute interpolation coefficients and advected values for each component
1054 for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
1055 {
1056 const auto &component_upwind = phi_upwind(i), component_downwind = phi_downwind(i);
1057 const libMesh::VectorValue<T> &grad_upwind = grad_phi_upwind.row(i),
1058 grad_face = coeffs.first * grad_phi_upwind.row(i) +
1059 coeffs.second * grad_phi_downwind.row(i);
1060
1061 // Initialize min-max values
1062 Real max_value(std::numeric_limits<Real>::min()), min_value(std::numeric_limits<Real>::max());
1065 std::tie(max_value, min_value) = computeMinMaxValue(functor, face, *time_arg, i);
1066
1067 // Perform full limited interpolation for the component
1068 ret(i) = fullLimitedInterpolation(*limiter,
1069 component_upwind,
1070 component_downwind,
1071 &grad_upwind,
1072 &grad_face,
1073 max_value,
1074 min_value,
1075 face);
1076 }
1077 }
1078
1079 // Return the interpolated vector value
1080 return ret;
1081}
1082
1103template <typename T>
1104T
1105containerInterpolate(const FunctorBase<T> & functor, const FaceArg & face, const StateArg & time)
1106{
1107 typedef typename FunctorBase<T>::GradientType ContainerGradientType;
1108 typedef typename ContainerGradientType::value_type GradientType;
1109 const GradientType * const example_gradient = nullptr;
1110
1111 mooseAssert(face.fi, "this must be non-null");
1112 const auto limiter = Limiter<typename T::value_type>::build(face.limiter_type);
1113
1114 const auto upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor();
1115 const auto downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem();
1116 const auto phi_upwind = functor(upwind_arg, time);
1117 const auto phi_downwind = functor(downwind_arg, time);
1118
1119 // initialize in order to get proper size
1120 T ret = phi_upwind;
1121 typename T::value_type coeff_upwind, coeff_downwind;
1122
1123 if (face.limiter_type == LimiterType::Upwind ||
1125 {
1126 for (const auto i : index_range(ret))
1127 {
1128 const auto &component_upwind = phi_upwind[i], component_downwind = phi_downwind[i];
1129 std::tie(coeff_upwind, coeff_downwind) = interpCoeffs(*limiter,
1130 component_upwind,
1131 component_downwind,
1132 example_gradient,
1133 example_gradient,
1134 std::numeric_limits<Real>::max(),
1135 std::numeric_limits<Real>::min(),
1136 *face.fi,
1137 face.elem_is_upwind);
1138 ret[i] = coeff_upwind * component_upwind + coeff_downwind * component_downwind;
1139 }
1140 }
1141 else
1142 {
1143 const auto grad_phi_upwind = functor.gradient(upwind_arg, time);
1144 for (const auto i : index_range(ret))
1145 {
1146 const auto &component_upwind = phi_upwind[i], component_downwind = phi_downwind[i];
1147 const auto & grad = grad_phi_upwind[i];
1148 std::tie(coeff_upwind, coeff_downwind) = interpCoeffs(*limiter,
1149 component_upwind,
1150 component_downwind,
1151 &grad,
1152 example_gradient,
1153 std::numeric_limits<Real>::max(),
1154 std::numeric_limits<Real>::min(),
1155 *face.fi,
1156 face.elem_is_upwind);
1157 ret[i] = coeff_upwind * component_upwind + coeff_downwind * component_downwind;
1158 }
1159 }
1160
1161 return ret;
1162}
1163
1164template <typename T>
1165std::vector<T>
1166interpolate(const FunctorBase<std::vector<T>> & functor,
1167 const FaceArg & face,
1168 const StateArg & time)
1169{
1170 return containerInterpolate(functor, face, time);
1171}
1172
1173template <typename T, std::size_t N>
1174std::array<T, N>
1175interpolate(const FunctorBase<std::array<T, N>> & functor,
1176 const FaceArg & face,
1177 const StateArg & time)
1178{
1179 return containerInterpolate(functor, face, time);
1180}
1181
1185template <typename SubdomainRestrictable>
1186bool
1187onBoundary(const SubdomainRestrictable & obj, const FaceInfo & fi)
1188{
1189 const bool internal = fi.neighborPtr() && obj.hasBlocks(fi.elemSubdomainID()) &&
1190 obj.hasBlocks(fi.neighborSubdomainID());
1191 return !internal;
1192}
1193
1199bool onBoundary(const std::set<SubdomainID> & subs, const FaceInfo & fi);
1200}
1201}
DualNumber< Real, DNDerivativeType, true > ADReal
void mooseWarning(Args &&... args)
Emit a warning message with the given stringified, concatenated args.
Definition MooseError.h:345
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
A base class interface for both producers and consumers of functor face arguments,...
This data structure is used to store geometric and variable related metadata about each cell face in ...
Definition FaceInfo.h:38
SubdomainID neighborSubdomainID() const
Definition FaceInfo.h:256
Point skewnessCorrectionVector() const
Returns the skewness-correction vector (vector between the approximate and real face centroids).
Definition FaceInfo.C:74
const Point & normal() const
Returns the unit normal vector for the face oriented outward from the face's elem element.
Definition FaceInfo.h:72
const Elem * neighborPtr() const
Definition FaceInfo.h:88
SubdomainID elemSubdomainID() const
Definition FaceInfo.h:106
const Point & neighborCentroid() const
Definition FaceInfo.h:247
const Point & dCN() const
Definition FaceInfo.h:142
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 gC() const
Return the geometric weighting factor.
Definition FaceInfo.h:136
const Point & faceCentroid() const
Returns the coordinates of the face centroid.
Definition FaceInfo.h:75
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
Every object that can be built by the factory should be derived from this class.
Definition MooseObject.h:31
This class provides variable solution values for other classes/objects to bind to when looping over f...
Base class for defining slope limiters for finite volume or potentially reconstructed Discontinuous-G...
Definition Limiter.h:63
static std::unique_ptr< Limiter > build(LimiterType limiter)
Definition Limiter.C:32
virtual bool constant() const =0
Base class template for functor objects.
typename FunctorReturnType< T, FunctorEvaluationKind::Gradient >::type GradientType
This rigmarole makes it so that a user can create functors that return containers (std::vector,...
GradientType gradient(const ElemArg &elem, const StateArg &state) const
Same as their evaluateGradient overloads with the same arguments but allows for caching implementatio...
auto raw_value(const Eigen::Map< T > &in)
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...
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.
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...
Scalar rF(const Scalar &phiC, const Scalar &phiD, const Vector &gradC, const RealVectorValue &dCD)
From Moukalled 12.30.
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.
bool setInterpolationMethod(const MooseObject &obj, Moose::FV::InterpMethod &interp_method, const std::string &param_name)
Sets one interpolation method.
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
@ Venkatakrishnan
Venkatakrishnan limiter (smooth, multidimensional).
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.
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...
InterpMethod
This codifies a set of available ways to interpolate with elem+neighbor solution information to calcu...
Definition MathFVUtils.h:39
@ SkewCorrectedAverage
(gc*elem+(1-gc)*neighbor)+gradient*(rf-rf')
@ HarmonicAverage
1/(gc/elem+(1-gc)/neighbor)
@ Average
gc*elem+(1-gc)*neighbor
libMesh::CompareTypes< T1, T2 >::supertype harmonicInterpolation(const T1 &value1, const T2 &value2, const Real weight1, const Real weight2)
Computes a weighted harmonic mean of Reals, RealVectorValues, and RealTensorValues while accounting 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.
MooseEnum interpolationMethods()
Returns an enum with all the currently supported interpolation methods and the current default for FV...
Definition MathFVUtils.C:61
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:
bool onBoundary(const SubdomainRestrictable &obj, const FaceInfo &fi)
Return whether the supplied face is on a boundary of the object's execution.
InputParameters advectedInterpolationParameter()
Definition MathFVUtils.C:68
LinearFVComputationMode
Definition MathFVUtils.h:58
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...
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
Definition Moose.h:175
std::string stringify(const T &t)
conversion to string
Definition Conversion.h:65
FunctorEvaluationKind
An enumeration of possible functor evaluation kinds.
A structure that is used to evaluate Moose functors logically at an element/cell center.
A structure defining a "face" evaluation calling argument for Moose functors.
ElemArg makeNeighbor() const
Make a ElemArg from our data using the face information neighbor.
bool elem_is_upwind
a boolean which states whether the face information element is upwind of the face
ElemArg makeElem() const
Make a ElemArg from our data using the face information element.
bool correct_skewness
Whether to perform skew correction.
Moose::FV::LimiterType limiter_type
a limiter which defines how the functor evaluated on either side of the face should be interpolated t...
const FaceInfo * fi
a face information object which defines our location in space
const Moose::StateArg * state_limiter
A member that can be used to define the instance in which the limiters are executed.
This structure takes an evaluation kind as a template argument and defines a constant expression indi...
State argument for evaluating functors.