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
178template <typename T1, typename T2>
180harmonicInterpolation(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
262template <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
283template <typename T, typename T2, typename T3>
284void
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
310template <typename T, FunctorEvaluationKind FEK = FunctorEvaluationKind::Value>
311T
312linearInterpolation(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");
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
350template <typename T1,
351 typename T2,
352 typename T3,
353 template <typename> class Vector1,
354 template <typename> class Vector2>
355void
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
401template <typename T, typename T2, typename T3, typename Vector>
402void
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
418ADReal gradUDotNormal(const FaceInfo & face_info,
419 const MooseVariableFV<Real> & fv_var,
420 const Moose::StateArg & time,
421 bool correct_skewness = false);
422
446template <typename Scalar, typename Vector>
447Scalar
448rF(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,
459 std::numeric_limits<Real>::min() * MetaPhysicL::raw_value(grad_dot));
460 const Scalar safe = denom + denom_sign * eps;
461 return 2.0 * grad_dot / safe - 1.0;
462}
463
475template <typename T>
476std::pair<T, T>
477interpCoeffs(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
508template <typename Scalar,
509 typename Vector,
510 typename Enable = typename std::enable_if<libMesh::ScalarTraits<Scalar>::value>::type>
511Scalar
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
535template <typename Limiter, typename T, typename Tensor>
537interpolate(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
583template <typename T>
584T
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
646template <typename T,
648 typename Enable = typename std::enable_if<ScalarTraits<T>::value>::type>
649std::pair<Real, Real>
650computeMinMaxValue(const FunctorBase<T> & functor, const FaceArg & face, const StateArg & time)
651{
652 // Initialize max_value to 0 and min_value to a large value
653 Real max_value(std::numeric_limits<Real>::min()), min_value(std::numeric_limits<Real>::max());
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
714template <typename T>
715std::pair<Real, Real>
716computeMinMaxValue(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
722 Real max_value(std::numeric_limits<Real>::min()), min_value(std::numeric_limits<Real>::max());
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
786template <typename T,
788 typename Enable = typename std::enable_if<libMesh::ScalarTraits<T>::value>::type>
789std::pair<std::pair<T, T>, std::pair<T, T>>
790interpCoeffsAndAdvected(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,
825 std::numeric_limits<Real>::max(),
826 std::numeric_limits<Real>::min(),
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
839 Real max_value(std::numeric_limits<Real>::min()), min_value(std::numeric_limits<Real>::max());
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
894template <typename T,
896 typename Enable = typename std::enable_if<libMesh::ScalarTraits<T>::value>::type>
897T
898interpolate(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 ||
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 =
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
941 Real max_value(std::numeric_limits<Real>::min()), min_value(std::numeric_limits<Real>::max());
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
981template <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,
1017 std::numeric_limits<Real>::max(),
1018 std::numeric_limits<Real>::min(),
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
1049 Real max_value(std::numeric_limits<Real>::min()), min_value(std::numeric_limits<Real>::max());
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
1090template <typename T>
1091T
1092containerInterpolate(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,
1121 std::numeric_limits<Real>::max(),
1122 std::numeric_limits<Real>::min(),
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,
1140 std::numeric_limits<Real>::max(),
1141 std::numeric_limits<Real>::min(),
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
1151template <typename T>
1152std::vector<T>
1153interpolate(const FunctorBase<std::vector<T>> & functor,
1154 const FaceArg & face,
1155 const StateArg & time)
1156{
1157 return containerInterpolate(functor, face, time);
1158}
1159
1160template <typename T, std::size_t N>
1161std::array<T, N>
1162interpolate(const FunctorBase<std::array<T, N>> & functor,
1163 const FaceArg & face,
1164 const StateArg & time)
1165{
1166 return containerInterpolate(functor, face, time);
1167}
1168
1172template <typename SubdomainRestrictable>
1173bool
1174onBoundary(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
1186bool onBoundary(const std::set<SubdomainID> & subs, const FaceInfo & fi);
1187}
1188}
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.
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...
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
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:165
std::string stringify(const T &t)
conversion to string
Definition Conversion.h:64
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.