From fce91c818346f5a7c7172d40a1900b56b722803a Mon Sep 17 00:00:00 2001 From: Tano Retamales Date: Fri, 18 Oct 2024 18:48:59 -0600 Subject: [PATCH 01/20] changing second order upwind and limitng formulation to work with incompressible flow Refs #28891 --- framework/contrib/wasp | 2 +- .../include/base/MooseFunctorArguments.h | 179 ++++++------ .../include/interfaces/FaceArgInterface.h | 3 +- .../limiters/CentralDifferenceLimiter.h | 11 +- framework/include/limiters/Limiter.h | 269 ++++++++++++++++- framework/include/limiters/MinModLimiter.h | 14 +- framework/include/limiters/QUICKLimiter.h | 42 ++- framework/include/limiters/SOULimiter.h | 29 +- framework/include/limiters/UpwindLimiter.h | 11 +- framework/include/limiters/VanLeerLimiter.h | 82 +++++- .../include/limiters/VenkatakrishnanLimiter.h | 53 ++++ framework/include/utils/GreenGaussGradient.h | 6 +- framework/include/utils/MathFVUtils.h | 274 +++++++++++++++++- .../src/functormaterials/FunctorSmoother.C | 2 +- framework/src/fvbcs/FVFunctorDirichletBC.C | 4 +- framework/src/fviks/FVInterfaceKernel.C | 2 +- framework/src/interfaces/FaceArgInterface.C | 5 +- framework/src/limiters/Limiter.C | 11 +- .../SideAdvectiveFluxIntegral.C | 18 +- framework/src/utils/MathFVUtils.C | 17 +- .../src/fvbcs/FVFunctorConvectiveHeatFluxBC.C | 2 +- .../include/utils/Reconstructions.h | 3 +- .../src/fvkernels/INSFVMomentumAdvection.C | 2 +- .../src/fvkernels/INSFVScalarFieldAdvection.C | 2 +- .../src/fvkernels/INSFVTKEDSourceSink.C | 2 +- .../src/fvkernels/INSFVTKESourceSink.C | 2 +- .../fvkernels/WCNSFV2PMomentumAdvectionSlip.C | 4 +- .../IntegralDirectedSurfaceForce.C | 2 +- .../postprocessors/MassFluxWeightedFlowRate.C | 3 +- .../src/postprocessors/PressureDrop.C | 8 +- .../src/postprocessors/VolumetricFlowRate.C | 3 +- .../userobjects/INSFVRhieChowInterpolator.C | 12 +- .../INSFVRhieChowInterpolatorSegregated.C | 10 +- .../src/userobjects/RhieChowMassFlux.C | 4 +- modules/navier_stokes/src/utils/NSFVUtils.C | 4 +- .../src/variables/BernoulliPressureVariable.C | 6 +- .../src/variables/INSFVVelocityVariable.C | 1 + .../ins/limiters/bottom_left_advection.i | 109 +++++++ 38 files changed, 1028 insertions(+), 185 deletions(-) create mode 100644 framework/include/limiters/VenkatakrishnanLimiter.h create mode 100644 modules/navier_stokes/test/tests/finite_volume/ins/limiters/bottom_left_advection.i diff --git a/framework/contrib/wasp b/framework/contrib/wasp index c8c9ce425911..42b77e3afaae 160000 --- a/framework/contrib/wasp +++ b/framework/contrib/wasp @@ -1 +1 @@ -Subproject commit c8c9ce4259115973f147e345608450d87dc390c4 +Subproject commit 42b77e3afaae89af4dbac976a80ad6a7d77270ce diff --git a/framework/include/base/MooseFunctorArguments.h b/framework/include/base/MooseFunctorArguments.h index c87371ed3c62..74174e8bfdaa 100644 --- a/framework/include/base/MooseFunctorArguments.h +++ b/framework/include/base/MooseFunctorArguments.h @@ -75,6 +75,94 @@ struct ElemPointArg ElemArg makeElem() const { return {elem, correct_skewness}; } }; +/** + * Argument for requesting functor evaluation at quadrature point locations on an element side. + * Data in the argument: + * - The element + * - The element side on which the quadrature points are located + * - The quadrature point index, e.g. if there are \p n quadrature points, we are requesting the\n + * evaluation of the i-th point + * - The quadrature rule that can be used to initialize the functor on the given element and side + */ +struct ElemSideQpArg +{ + /// The element + const libMesh::Elem * elem; + + /// The local side index + unsigned int side; + + /// The quadrature point index + unsigned int qp; + + /// The qudrature rule + const QBase * qrule; + + /// The physical location of the quadrature point + Point point; + + /** + * @returns The conceptual physical location of this data structure + */ + Point getPoint() const { return point; } +}; + +/** + * State argument for evaluating functors. The iteration type indicates whether you want to evaluate + * a functor based on some iterate state of a transient calculation, nonlinear solve, etc. The state + * indicates which iterate of the iterate type we want to evaluate on. A state of 0 indicates + * "current", e.g. the current time or the current nonlinear iteration (which should actually be + * equivalent); a state of 1 indicates the most-recent "old" time or the most recent previous + * nonlinear iteration, etc. + */ + +struct StateArg +{ + /** + * Prevent implicit conversions from boolean to avoid users accidentally constructing a time + * argument when they meant to construct a skewness argument, etc. + */ + StateArg(bool) = delete; + + StateArg(unsigned int state_in) : state(state_in), iteration_type(SolutionIterationType::Time) {} + + StateArg(unsigned int state_in, SolutionIterationType iteration_type_in) + : state(state_in), iteration_type(iteration_type_in) + { + } + + /// The state. Zero represents the most recent state, so for any kind of iteration type, a zero + /// state represents the current state, e.g. current solution + /// One may represent the 'old' value (one before, in the iteration_type specified), and two an 'older' or two steps away state + unsigned int state; + + /// The solution iteration type, e.g. time or nonlinear + SolutionIterationType iteration_type; + +private: + StateArg() : state(0), iteration_type(SolutionIterationType::Time) {} + + friend StateArg currentState(); +}; + +inline StateArg +currentState() +{ + return {}; +} + +inline StateArg +oldState() +{ + return {(unsigned int)1}; +} + +inline StateArg +previousNonlinearState() +{ + return {(unsigned int)1, SolutionIterationType::Nonlinear}; +} + /** * A structure defining a "face" evaluation calling argument for Moose functors */ @@ -104,6 +192,9 @@ struct FaceArg /// on one side of the face. const Elem * face_side; + /// A member that can be used to define the instance in which the limiters are executed + const Moose::StateArg * state_limiter; + /** * @returns The conceptual physical location of this data structure */ @@ -169,92 +260,4 @@ struct ElemQpArg */ Point getPoint() const { return point; } }; - -/** - * Argument for requesting functor evaluation at quadrature point locations on an element side. - * Data in the argument: - * - The element - * - The element side on which the quadrature points are located - * - The quadrature point index, e.g. if there are \p n quadrature points, we are requesting the\n - * evaluation of the i-th point - * - The quadrature rule that can be used to initialize the functor on the given element and side - */ -struct ElemSideQpArg -{ - /// The element - const libMesh::Elem * elem; - - /// The local side index - unsigned int side; - - /// The quadrature point index - unsigned int qp; - - /// The qudrature rule - const QBase * qrule; - - /// The physical location of the quadrature point - Point point; - - /** - * @returns The conceptual physical location of this data structure - */ - Point getPoint() const { return point; } -}; - -/** - * State argument for evaluating functors. The iteration type indicates whether you want to evaluate - * a functor based on some iterate state of a transient calculation, nonlinear solve, etc. The state - * indicates which iterate of the iterate type we want to evaluate on. A state of 0 indicates - * "current", e.g. the current time or the current nonlinear iteration (which should actually be - * equivalent); a state of 1 indicates the most-recent "old" time or the most recent previous - * nonlinear iteration, etc. - */ - -struct StateArg -{ - /** - * Prevent implicit conversions from boolean to avoid users accidentally constructing a time - * argument when they meant to construct a skewness argument, etc. - */ - StateArg(bool) = delete; - - StateArg(unsigned int state_in) : state(state_in), iteration_type(SolutionIterationType::Time) {} - - StateArg(unsigned int state_in, SolutionIterationType iteration_type_in) - : state(state_in), iteration_type(iteration_type_in) - { - } - - /// The state. Zero represents the most recent state, so for any kind of iteration type, a zero - /// state represents the current state, e.g. current solution - /// One may represent the 'old' value (one before, in the iteration_type specified), and two an 'older' or two steps away state - unsigned int state; - - /// The solution iteration type, e.g. time or nonlinear - SolutionIterationType iteration_type; - -private: - StateArg() : state(0), iteration_type(SolutionIterationType::Time) {} - - friend StateArg currentState(); -}; - -inline StateArg -currentState() -{ - return {}; -} - -inline StateArg -oldState() -{ - return {(unsigned int)1}; -} - -inline StateArg -previousNonlinearState() -{ - return {(unsigned int)1, SolutionIterationType::Nonlinear}; -} } diff --git a/framework/include/interfaces/FaceArgInterface.h b/framework/include/interfaces/FaceArgInterface.h index 82f9b9b51c4b..f994ad862286 100644 --- a/framework/include/interfaces/FaceArgInterface.h +++ b/framework/include/interfaces/FaceArgInterface.h @@ -44,7 +44,8 @@ class FaceArgProducerInterface : public FaceArgInterface Moose::FaceArg makeFace(const FaceInfo & fi, const Moose::FV::LimiterType limiter_type, const bool elem_is_upwind, - const bool correct_skewness = false) const; + const bool correct_skewness = false, + const Moose::StateArg * state_limiter = nullptr) const; /** * Make a functor face argument with a central differencing limiter, e.g. compose a face diff --git a/framework/include/limiters/CentralDifferenceLimiter.h b/framework/include/limiters/CentralDifferenceLimiter.h index 9b1c878bd58e..027d1d43a2c8 100644 --- a/framework/include/limiters/CentralDifferenceLimiter.h +++ b/framework/include/limiters/CentralDifferenceLimiter.h @@ -25,8 +25,15 @@ template class CentralDifferenceLimiter : public Limiter { public: - T - limit(const T &, const T &, const VectorValue *, const RealVectorValue &) const override final + T limit(const T &, + const T &, + const VectorValue *, + const VectorValue *, + const RealVectorValue &, + const T &, + const T &, + const FaceInfo *, + const bool &) const override final { return 1; } diff --git a/framework/include/limiters/Limiter.h b/framework/include/limiters/Limiter.h index 5b2f35ae8cf0..2166aa9604fe 100644 --- a/framework/include/limiters/Limiter.h +++ b/framework/include/limiters/Limiter.h @@ -12,6 +12,7 @@ #include "ADReal.h" #include "MooseTypes.h" #include "HasMembers.h" +#include "FaceInfo.h" #include class MooseEnum; @@ -29,7 +30,8 @@ enum class LimiterType : int CentralDifference, MinMod, SOU, - QUICK + QUICK, + Venkatakrishnan }; extern const MooseEnum moose_limiter_type; @@ -61,23 +63,280 @@ class Limiter { public: /** - * Defines the slope limiter function $\beta(r_f)$ where $r_f$ represents the ratio of upstream to - * downstream gradients + * @brief Pure virtual method for computing the flux limiting ratio. + * + * This method computes the flux limiting ratio based on the provided scalar values, + * gradient vectors, direction vector, maximum and minimum allowable values, and + * geometric information from the face and cell centroids. It must be overridden + * by any derived class implementing a specific limiting strategy. + * + * @tparam T The data type of the scalar values and the return type. + * @param phi_upwind The scalar value at the upwind location. + * @param phi_downwind The scalar value at the downwind location. + * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. + * @param grad_phi_downwind Pointer to the gradient vector at the downwind location. + * @param dCD A constant direction vector representing the direction of the cell face. + * @param max_value The maximum allowable value. + * @param min_value The minimum allowable value. + * @param fi FaceInfo object containing geometric details such as face centroid and cell + * centroids. + * @param fi_elem_is_upwind Boolean indicating if the face info element is upwind. + * @return The computed flux limiting ratio. + * + * This pure virtual function is intended to be defined in derived classes, which will implement + * the specific limiting algorithm. Derived classes will provide the actual logic for computing + * the flux limiting ratio, ensuring that the result adheres to the constraints and properties + * required by the specific limiting method. + * + * Here is an example of how a derived class might implement this method: + * + * @example + * @code + * class MyLimiter : public Limiter + * { + * public: + * Real limit(const Real & phi_upwind, + * const Real & phi_downwind, + * const VectorValue * grad_phi_upwind, + * const VectorValue * grad_phi_downwind, + * const RealVectorValue & dCD, + * const Real & max_value, + * const Real & min_value, + * const FaceInfo * fi, + * const bool & fi_elem_is_upwind) const override + * { + * // Implementation of the specific limiting algorithm. + * Real ratio = ... // Compute the ratio. + * return ratio; // Return the computed ratio. + * } + * }; + * @endcode */ virtual T limit(const T & phi_upwind, const T & phi_downwind, const VectorValue * grad_phi_upwind, - const RealVectorValue & dCD) const = 0; + const VectorValue * grad_phi_downwind, + const RealVectorValue & dCD, + const T & max_value, + const T & min_value, + const FaceInfo * fi, + const bool & fi_elem_is_upwind) const = 0; virtual bool constant() const = 0; virtual InterpMethod interpMethod() const = 0; + + /** + * @brief Functor for applying tsimplified slope limiting. + * + * This function applies the limiter by invoking the `limit` method with the provided parameters. + * It acts as a functor, enabling objects of the `VanLeerLimiter` class to be used as if they were + * functions. + * + * @tparam T The data type of the scalar values and the return type. + * @param phi_upwind The scalar value at the upwind location. + * @param phi_downwind The scalar value at the downwind location. + * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. + * @param dCD A constant direction vector representing the direction of the cell face. + * @return The computed limited value, ensuring it is within the range [0, 2]. + * + * This method performs the following steps: + * 1. Calls the `limit` method with the provided scalar values, the upwind gradient vector, and + * the direction vector. + * 2. Ensures the result is within the range [0, 2] by using `std::max` and `std::min`. + * 3. Returns the computed limited value. + * + * @example + * @code + * Limiter * myLimiter = ... // Assume this is properly initialized + * Real phi_upwind = 2.0; + * Real phi_downwind = 1.5; + * VectorValue grad_upwind(0.1, 0.2, 0.3); + * RealVectorValue dCD(1.0, 0.0, 0.0); + * FaceInfo * fi = ... // Assume this is properly initialized + * Real result = (*myLimiter)(phi_upwind, phi_downwind, &grad_upwind, dCD); + * @endcode + */ T operator()(const T & phi_upwind, const T & phi_downwind, const VectorValue * grad_phi_upwind, const RealVectorValue & dCD) const { - return std::max(T(0), std::min(T(2), limit(phi_upwind, phi_downwind, grad_phi_upwind, dCD))); + return std::max(T(0), + std::min(T(2), + limit(phi_upwind, + phi_downwind, + grad_phi_upwind, + nullptr, + dCD, + 0.0, + 0.0, + nullptr, + false))); + } + + /** + * @brief Functor for applying general slope limiter. + * + * This function applies the slope limiter by invoking the `limit` method with the provided + * parameters. It acts as a functor, enabling objects of the `Limiter` class to be used as if they + * were functions. + * + * @tparam T The data type of the scalar values and the return type. + * @param phi_upwind The scalar value at the upwind location. + * @param phi_downwind The scalar value at the downwind location. + * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. + * @param grad_phi_downwind Pointer to the gradient vector at the downwind location. + * @param dCD A constant direction vector representing the direction of the cell face. + * @param max_value The maximum allowable value. + * @param min_value The minimum allowable value. + * @param fi FaceInfo object containing geometric details such as face centroid and cell + * centroids. + * @param fi_elem_is_upwind Boolean indicating if the face info element is upwind. + * @return The result of the `limit` function applied to the provided parameters. + * + * This function performs the following steps: + * 1. Calls the `limit` method with the provided scalar values, gradient vectors, direction + * vector, maximum and minimum values, face information, and upwind status. + * 2. Returns the result of the `limit` method. + * + * This functor allows for more intuitive and flexible usage of the `Limiter` class, enabling + * instances of the class to be called with arguments directly. + * + * @example + * @code + * Limiter * myLimiter = ... // Assume this is properly initialized + * Real phi_upwind = 2.0; + * Real phi_downwind = 1.5; + * VectorValue grad_upwind(0.1, 0.2, 0.3); + * VectorValue grad_downwind(0.4, 0.5, 0.6); + * RealVectorValue dCD(1.0, 0.0, 0.0); + * Real max_value = 5.0; + * Real min_value = 1.0; + * FaceInfo * fi = ... // Assume this is properly initialized + * bool is_upwind = true; + * Real result = (*myLimiter)(phi_upwind, phi_downwind, &grad_upwind, &grad_downwind, dCD, + * max_value, min_value, fi, is_upwind); + * @endcode + */ + T operator()(const T & phi_upwind, + const T & phi_downwind, + const VectorValue * grad_phi_upwind, + const VectorValue * grad_phi_downwind, + const RealVectorValue & dCD, + const T & max_value, + const T & min_value, + const FaceInfo * fi, + const bool & fi_elem_is_upwind) const + { + return limit(phi_upwind, + phi_downwind, + grad_phi_upwind, + grad_phi_downwind, + dCD, + max_value, + min_value, + fi, + fi_elem_is_upwind); } + /** + * @brief Computes the flux limiting ratio using gradients. + * + * This function calculates the flux limiting ratio based on the provided gradients + * at the upwind and downwind locations, along with a direction vector. + * + * @tparam T The data type of the gradient values and the return type. + * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. + * @param grad_phi_downwind Pointer to the gradient vector at the downwind location. + * @param dCD A constant direction vector representing the direction of the cell face. + * @return The computed flux limiting ratio. + * + * This function performs the following steps: + * 1. Computes the dot product of the upwind gradient vector with the direction vector `dCD`. + * 2. Computes the dot product of the downwind gradient vector with the direction vector `dCD`. + * 3. Calculates the ratio of the upwind gradient dot product to the downwind gradient dot + * product, adding a small epsilon value to the denominator to prevent division by zero. + * 4. Applies a flux limiting formula to this ratio to ensure it remains within a physically + * reasonable range, specifically ensuring non-negative values. + * + * @note The small epsilon value `1e-10` is added to the denominator to avoid division by zero + * and numerical instability. + * + * @example + * @code + * VectorValue grad_upwind(0.1, 0.2, 0.3); + * VectorValue grad_downwind(0.4, 0.5, 0.6); + * RealVectorValue dCD(1.0, 0.0, 0.0); + * Real ratio = rf_grad(&grad_upwind, &grad_downwind, dCD); + * @endcode + */ + T rf_grad(const VectorValue * grad_phi_upwind, + const VectorValue * grad_phi_downwind, + const RealVectorValue & dCD) const + { + const auto grad_elem = (*grad_phi_upwind) * dCD; + const auto grad_face = (*grad_phi_downwind) * dCD; + const auto grad_ratio = grad_elem / (grad_face + 1e-10); + return std::max(2.0 * grad_ratio - 1.0, 0.0); + }; + + /** + * @brief Computes the flux limiting ratio using successive deltas. + * + * This function calculates the flux limiting ratio based on the upwind value, + * its gradient, maximum and minimum allowable values, and geometric information + * from the face and cell centroids. + * + * @tparam T The data type of the scalar values and the return type. + * @param phi_upwind The scalar value at the upwind location. + * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. + * @param max_value The maximum allowable value. + * @param min_value The minimum allowable value. + * @param fi FaceInfo object containing geometric details such as face centroid and cell + * centroids. + * @param fi_elem_is_upwind Boolean indicating if the face info element is upwind. + * @return The computed flux limiting ratio. + * + * This function performs the following steps: + * 1. Retrieves the face centroid from the `FaceInfo` object. + * 2. Determines the cell centroid based on whether the current element is upwind. + * 3. Computes the delta value at the face by taking the dot product of the upwind gradient + * vector with the difference between the face and cell centroids. + * 4. Computes the delta values for the maximum and minimum allowable values, adding a small + * epsilon value to prevent division by zero. + * 5. Calculates the flux limiting ratio based on whether the delta value at the face is + * non-negative or negative, using the appropriate delta (either max or min). + * + * @note The small epsilon value `1e-10` is added to the delta max and delta min values to + * avoid division by zero and numerical instability. + * + * @example + * @code + * Real phi_upwind = 2.0; + * VectorValue grad_upwind(0.1, 0.2, 0.3); + * Real max_value = 5.0; + * Real min_value = 1.0; + * FaceInfo * fi = ... // Assume this is properly initialized + * bool is_upwind = true; + * Real ratio = rf_minmax(phi_upwind, &grad_upwind, max_value, min_value, fi, is_upwind); + * @endcode + */ + T rf_minmax(const T & phi_upwind, + const VectorValue * grad_phi_upwind, + const T & max_value, + const T & min_value, + const FaceInfo * fi, + const bool & fi_elem_is_upwind) const + { + const auto face_centroid = fi->faceCentroid(); + const auto cell_centroid = fi_elem_is_upwind ? fi->elemCentroid() : fi->neighborCentroid(); + + const auto delta_face = (*grad_phi_upwind) * (face_centroid - cell_centroid); + const auto delta_max = max_value - phi_upwind + 1e-10; + const auto delta_min = min_value - phi_upwind + 1e-10; + + return delta_face >= 0 ? delta_face / delta_max : delta_face / delta_min; + }; + Limiter() = default; virtual ~Limiter() = default; diff --git a/framework/include/limiters/MinModLimiter.h b/framework/include/limiters/MinModLimiter.h index dfffa029c2a3..668595e748cb 100644 --- a/framework/include/limiters/MinModLimiter.h +++ b/framework/include/limiters/MinModLimiter.h @@ -27,10 +27,20 @@ class MinModLimiter : public Limiter T limit(const T & phi_upwind, const T & phi_downwind, const VectorValue * grad_phi_upwind, - const RealVectorValue & dCD) const override final + const VectorValue * grad_phi_downwind, + const RealVectorValue & dCD, + const T &, + const T &, + const FaceInfo *, + const bool &) const override final { mooseAssert(grad_phi_upwind, "min-mod limiter requires a gradient"); - const auto r_f = Moose::FV::rF(phi_upwind, phi_downwind, *grad_phi_upwind, dCD); + // Compute gradient ratio coefficient + T r_f; + if (grad_phi_downwind) // compute full slope-reconstruction limiter + r_f = this->rf_grad(grad_phi_upwind, grad_phi_downwind, dCD); + else // compute upwind slope reconstruction limiter + r_f = Moose::FV::rF(phi_upwind, phi_downwind, *grad_phi_upwind, dCD); // Dummy addition to avoid new nonzeros return 0 * r_f + std::max(T(0), std::min(T(1), r_f)); diff --git a/framework/include/limiters/QUICKLimiter.h b/framework/include/limiters/QUICKLimiter.h index 71171929dcd5..ffdc51afae78 100644 --- a/framework/include/limiters/QUICKLimiter.h +++ b/framework/include/limiters/QUICKLimiter.h @@ -27,12 +27,48 @@ class QUICKLimiter : public Limiter T limit(const T & phi_upwind, const T & phi_downwind, const VectorValue * grad_phi_upwind, - const RealVectorValue & dCD) const override final + const VectorValue * grad_phi_downwind, + const RealVectorValue & dCD, + const T &, + const T &, + const FaceInfo * fi, + const bool & fi_elem_is_upwind) const override final { mooseAssert(grad_phi_upwind, "QUICK limiter requires a gradient"); - const auto r_f = Moose::FV::rF(phi_upwind, phi_downwind, *grad_phi_upwind, dCD); - return (3. + r_f) / 4.; + const auto & w_f = fi_elem_is_upwind ? fi->gC() : (1. - fi->gC()); + const auto & phiCD = w_f * phi_upwind + (1.0 - w_f) * phi_downwind; + const auto & face_grad = w_f * (*grad_phi_upwind) + (1.0 - w_f) * (*grad_phi_downwind); + const auto & faceFlux = face_grad * fi->normal(); + + T phiU, phif; + + if (faceFlux > 0) + { + phiU = phi_upwind; + phif = 0.5 * (phiCD + phiU + (1 - w_f) * (dCD * (*grad_phi_upwind))); + } + else + { + phiU = phi_downwind; + phif = 0.5 * (phiCD + phiU - w_f * (dCD * (*grad_phi_downwind))); + } + + const auto & s = phiCD - phiU; + if (s >= 0) + { + return s + 1e-10; + } + else + { + return s - 1e-10; + } + + // Calculate the effective limiter for the QUICK interpolation + const auto quick = (phif - phiU) / s; + + // Limit the limiter between upwind and downwind + return std::max(std::min(quick, T(2)), T(0)); } bool constant() const override final { return false; } InterpMethod interpMethod() const override final { return InterpMethod::QUICK; } diff --git a/framework/include/limiters/SOULimiter.h b/framework/include/limiters/SOULimiter.h index aaaf08131cca..d93b5013622e 100644 --- a/framework/include/limiters/SOULimiter.h +++ b/framework/include/limiters/SOULimiter.h @@ -24,14 +24,33 @@ template class SOULimiter : public Limiter { public: - T limit(const T & phi_upwind, - const T & phi_downwind, + T limit(const T &, + const T &, const VectorValue * grad_phi_upwind, - const RealVectorValue & dCD) const override final + const VectorValue *, + const RealVectorValue &, + const T & max_value, + const T & min_value, + const FaceInfo * fi, + const bool & fi_elem_is_upwind) const override final { mooseAssert(grad_phi_upwind, "SOU limiter requires a gradient"); - const auto r_f = Moose::FV::rF(phi_upwind, phi_downwind, *grad_phi_upwind, dCD); - return r_f; + + // Determine the face centroid and the appropriate cell centroid + const auto & face_centroid = fi->faceCentroid(); + const auto & cell_centroid = fi_elem_is_upwind ? fi->elemCentroid() : fi->neighborCentroid(); + + // Compute the abs delta value at the face + const auto & delta_face = std::abs((*grad_phi_upwind) * (face_centroid - cell_centroid)); + + // Compute the delta between the two elements + const auto & elem_delta = max_value - min_value; + + // return the limited value + if (elem_delta > 1e-10) + return std::min(1.0, elem_delta / delta_face); + else + return 1.0; } bool constant() const override final { return false; } InterpMethod interpMethod() const override final { return InterpMethod::SOU; } diff --git a/framework/include/limiters/UpwindLimiter.h b/framework/include/limiters/UpwindLimiter.h index 62e9148a453f..4926f3e2b35a 100644 --- a/framework/include/limiters/UpwindLimiter.h +++ b/framework/include/limiters/UpwindLimiter.h @@ -24,8 +24,15 @@ template class UpwindLimiter : public Limiter { public: - T - limit(const T &, const T &, const VectorValue *, const RealVectorValue &) const override final + T limit(const T &, + const T &, + const VectorValue *, + const VectorValue *, + const RealVectorValue &, + const T &, + const T &, + const FaceInfo *, + const bool &) const override final { return 0; } diff --git a/framework/include/limiters/VanLeerLimiter.h b/framework/include/limiters/VanLeerLimiter.h index f07e8e5a072e..9e9779c4b456 100644 --- a/framework/include/limiters/VanLeerLimiter.h +++ b/framework/include/limiters/VanLeerLimiter.h @@ -17,25 +17,95 @@ namespace Moose namespace FV { /** - * Implements the Van Leer limiter, defined by - * $\beta(r_f) = \frac{r_f + \text{abs}(r_f)}{1 + \text{abs}(r_f)}$ + * @brief Implements the Van Leer limiter for flux limiting in numerical methods. + * + * The Van Leer limiter is a slope limiter used to reduce numerical oscillations and + * enforce monotonicity in computational fluid dynamics (CFD) and other numerical simulations. + * The limiter function $\beta(r_f)$ is defined as: + * + * \f[ + * \beta(r_f) = \frac{r_f + \text{abs}(r_f)}{1 + \text{abs}(r_f)} + * \f] + * + * where \( r_f \) is the ratio of the upwind to downwind gradients. + * + * @tparam T The data type of the scalar values and the return type. */ template class VanLeerLimiter : public Limiter { public: + /** + * @brief Computes the limited value using the Van Leer limiter. + * + * This method overrides the pure virtual `limit` method in the base `Limiter` class. + * It calculates the flux limiting ratio based on the Van Leer limiter formula. + * + * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. + * @param grad_phi_downwind Pointer to the gradient vector at the downwind location. + * @param dCD A constant direction vector representing the direction of the cell face. + * @return The computed flux limiting ratio. + * + * This method performs the following steps: + * 1. Asserts that the upwind and downwind gradient pointers are not null. + * 2. Computes the gradient ratio coefficient \( r_f \) using the `rf_grad` method. + * 3. Applies the Van Leer limiter formula to \( r_f \) to obtain the limited value. + * 4. Returns the computed limited value. + * + * @example + * @code + * VanLeerLimiter vanLeer; + * VectorValue grad_upwind(0.1, 0.2, 0.3); + * VectorValue grad_downwind(0.4, 0.5, 0.6); + * RealVectorValue dCD(1.0, 0.0, 0.0); + * Real result = vanLeer.limit(0.0, 0.0, &grad_upwind, &grad_downwind, dCD, 0.0, 0.0, nullptr, + * true); + * @endcode + */ T limit(const T & phi_upwind, const T & phi_downwind, const VectorValue * grad_phi_upwind, - const RealVectorValue & dCD) const override final + const VectorValue * grad_phi_downwind, + const RealVectorValue & dCD, + const T & /* max_value */, + const T & /* min_value */, + const FaceInfo * /* fi */, + const bool & /* fi_elem_is_upwind */) const override final { - mooseAssert(grad_phi_upwind, "Van Leer limiter requires a gradient"); - const auto r_f = Moose::FV::rF(phi_upwind, phi_downwind, *grad_phi_upwind, dCD); - return (r_f + std::abs(r_f)) / (1. + std::abs(r_f)); + mooseAssert(grad_phi_upwind, "Van Leer limiter requires the upwind gradient"); + + // Compute gradient ratio coefficient + T r_f; + if (grad_phi_downwind) // compute full slope-reconstruction limiter + r_f = this->rf_grad(grad_phi_upwind, grad_phi_downwind, dCD); + else // compute upwind slope reconstruction limiter + r_f = Moose::FV::rF(phi_upwind, phi_downwind, *grad_phi_upwind, dCD); + + // Return limiter value + return (r_f + std::abs(r_f)) / (1.0 + std::abs(r_f)); } + + /** + * @brief Indicates whether the Van Leer limiter is constant. + * + * This method always returns `false` as the Van Leer limiter is not a constant limiter. + * + * @return `false` indicating the Van Leer limiter is not constant. + */ bool constant() const override final { return false; } + + /** + * @brief Returns the interpolation method used by the Van Leer limiter. + * + * This method returns `InterpMethod::VanLeer`, indicating the interpolation method used. + * + * @return The interpolation method `InterpMethod::VanLeer`. + */ InterpMethod interpMethod() const override final { return InterpMethod::VanLeer; } + /** + * @brief Default constructor for the Van Leer limiter. + */ VanLeerLimiter() = default; }; } diff --git a/framework/include/limiters/VenkatakrishnanLimiter.h b/framework/include/limiters/VenkatakrishnanLimiter.h new file mode 100644 index 000000000000..514cc7ad305f --- /dev/null +++ b/framework/include/limiters/VenkatakrishnanLimiter.h @@ -0,0 +1,53 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#pragma once + +#include "Limiter.h" +#include "MathFVUtils.h" + +namespace Moose +{ +namespace FV +{ +/** + * Implements a limiter which reproduces the second-order-upwind scheme, defined by + * $\beta(r_f) = r_f$ + */ +template +class VenkatakrishnanLimiter : public Limiter +{ +public: + T limit(const T & phi_upwind, + const T &, + const VectorValue * grad_phi_upwind, + const VectorValue *, + const RealVectorValue &, + const T & max_value, + const T & min_value, + const FaceInfo * fi, + const bool & fi_elem_is_upwind) const override final + { + const auto face_centroid = fi->faceCentroid(); + const auto cell_centroid = fi_elem_is_upwind ? fi->elemCentroid() : fi->neighborCentroid(); + + const auto delta_face = (*grad_phi_upwind) * (face_centroid - cell_centroid); + const auto delta_max = max_value - phi_upwind + 1e-10; + const auto delta_min = min_value - phi_upwind + 1e-10; + + return delta_face >= 0 ? delta_face / delta_max : delta_face / delta_min; + + } + bool constant() const override final { return false; } + InterpMethod interpMethod() const override final { return InterpMethod::SOU; } + + VenkatakrishnanLimiter() = default; +}; +} +} diff --git a/framework/include/utils/GreenGaussGradient.h b/framework/include/utils/GreenGaussGradient.h index c8def8cc405c..704fbee3a29f 100644 --- a/framework/include/utils/GreenGaussGradient.h +++ b/framework/include/utils/GreenGaussGradient.h @@ -142,7 +142,8 @@ greenGaussGradient(const ElemArg & elem_arg, Moose::FV::LimiterType::CentralDifference, true, elem_arg.correct_skewness, - elem_arg.elem}, + elem_arg.elem, + nullptr}, state_arg); if (!volume_set) @@ -370,7 +371,8 @@ greenGaussGradient(const ElemArg & elem_arg, Moose::FV::LimiterType::CentralDifference, true, elem_arg.correct_skewness, - elem_arg.elem}, + elem_arg.elem, + nullptr}, state_arg); } diff --git a/framework/include/utils/MathFVUtils.h b/framework/include/utils/MathFVUtils.h index 7ac85fbd5ca0..fb9175235b41 100644 --- a/framework/include/utils/MathFVUtils.h +++ b/framework/include/utils/MathFVUtils.h @@ -47,7 +47,8 @@ enum class InterpMethod VanLeer, MinMod, SOU, - QUICK + QUICK, + Venkatakrishnan }; enum class LinearFVComputationMode @@ -537,6 +538,74 @@ interpolate(const Limiter & limiter, return ret; } +/** + * @brief Computes the full limited interpolation of a variable using a specified limiter. + * + * This function performs a full limited interpolation of a variable, taking into account + * the values and gradients at both upwind and downwind locations, as well as geometric + * information and limits. It applies the specified limiter to ensure the interpolation + * adheres to the constraints imposed by the limiter. + * + * @tparam T The data type of the scalar values and the return type. + * @param limiter The limiter object used to compute the flux limiting ratio. + * @param phi_upwind The scalar value at the upwind location. + * @param phi_downwind The scalar value at the downwind location. + * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. + * @param grad_phi_downwind Pointer to the gradient vector at the downwind location. + * @param fi FaceInfo object containing geometric details such as face centroid and cell centroids. + * @param fi_elem_is_upwind Boolean indicating if the face info element is upwind. + * @param max_value The maximum allowable value. + * @param min_value The minimum allowable value. + * @return The computed limited interpolation value. + * + * This function performs the following steps: + * 1. Computes the direction vector \( dCD \) based on whether the current element is upwind. + * 2. Calls the `limiter` functor with the provided scalar values, gradient vectors, direction + * vector, and geometric information to compute the flux limiting ratio \( \beta \). + * 3. Determines the face centroid and the appropriate cell centroid based on whether the current + * element is upwind. + * 4. Computes the delta value at the face by taking the dot product of the upwind gradient vector + * with the difference between the face and cell centroids. + * 5. Returns the interpolated value by adding the product of the limiter \( \beta \) and the delta + * value to the upwind scalar value. + */ +template +T +fullLimitedInterpolation(const Limiter & limiter, + const T & phi_upwind, + const T & phi_downwind, + const VectorValue * const grad_phi_upwind, + const VectorValue * const grad_phi_downwind, + const FaceInfo & fi, + const bool fi_elem_is_upwind, + const T & max_value, + const T & min_value) +{ + // Compute the direction vector based on whether the current element is upwind + const auto dCD = fi_elem_is_upwind ? fi.dCN() : Point(-fi.dCN()); + + // Compute the flux limiting ratio using the specified limiter + const auto beta = limiter(phi_upwind, + phi_downwind, + grad_phi_upwind, + grad_phi_downwind, + dCD, + max_value, + min_value, + &fi, + fi_elem_is_upwind); + + // Determine the face centroid and the appropriate cell centroid + const auto & face_centroid = fi.faceCentroid(); + const auto & cell_centroid = fi_elem_is_upwind ? fi.elemCentroid() : fi.neighborCentroid(); + + // Compute the delta value at the face + const auto & delta_face = (*grad_phi_upwind) * (face_centroid - cell_centroid); + + // Return the interpolated value + return phi_upwind + beta * delta_face; +} + /** * Interpolates with a limiter and a face argument * @return a pair of pairs. The first pair corresponds to the interpolation coefficients with the @@ -586,6 +655,43 @@ interpCoeffsAndAdvected(const FunctorBase & functor, const FaceArg & face, co std::make_pair(std::move(phi_downwind), std::move(phi_upwind))); } +// Utility function to compute the min-max values in a two-cell stencil +template ::value>::type> +std::pair +computeMinMaxValue(const FunctorBase & functor, const FaceArg & face, const StateArg & time) +{ + T max_value(0), min_value(1e10); + for (auto neighbor : (*face.fi).elem().neighbor_ptr_range()) + { + // If not a valid neighbor + if (neighbor == nullptr) + continue; + else + { + const ElemArg local_cell_arg = {neighbor, false}; + const auto value = functor.template genericEvaluate(local_cell_arg, time); + max_value = std::max(max_value, value); + min_value = std::min(min_value, value); + } + } + for (auto neighbor : (*face.fi).neighbor().neighbor_ptr_range()) + { + // If not a valid neighbor + if (neighbor == nullptr) + continue; + else + { + const ElemArg local_cell_arg = {neighbor, false}; + const auto value = functor.template genericEvaluate(local_cell_arg, time); + max_value = std::max(max_value, value); + min_value = std::min(min_value, value); + } + } + return std::make_pair(max_value, min_value); +} + template ::value>::type> @@ -600,8 +706,83 @@ interpolate(const FunctorBase & functor, const FaceArg & face, const StateArg if (face.limiter_type == LimiterType::CentralDifference) return linearInterpolation(functor, face, time); - const auto [interp_coeffs, advected] = interpCoeffsAndAdvected(functor, face, time); - return interp_coeffs.first * advected.first + interp_coeffs.second * advected.second; + if (face.limiter_type == LimiterType::Upwind || + face.limiter_type == LimiterType::CentralDifference) + { + const auto [interp_coeffs, advected] = interpCoeffsAndAdvected(functor, face, time); + return interp_coeffs.first * advected.first + interp_coeffs.second * advected.second; + } + else + { + + constexpr FunctorEvaluationKind GFEK = FunctorGradientEvaluationKind::value; + typedef typename FunctorBase::GradientType GradientType; + static const GradientType zero(0); + const auto & limiter = + Limiter::value_type>::build(face.limiter_type); + + const auto & upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor(); + const auto & downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem(); + const auto & phi_upwind = functor.template genericEvaluate(upwind_arg, time); + const auto & phi_downwind = functor.template genericEvaluate(downwind_arg, time); + + const auto & time_arg = Moose::StateArg(1, Moose::SolutionIterationType::Time); + + // Min-Max value + T max_value, min_value; + std::tie(max_value, min_value) = computeMinMaxValue(functor, face, time_arg); + + const auto & grad_phi_upwind = functor.template genericEvaluate(upwind_arg, time_arg); + const auto & grad_phi_downwind = functor.template genericEvaluate(face, time_arg); + + return fullLimitedInterpolation(*limiter, + phi_upwind, + phi_downwind, + &grad_phi_upwind, + &grad_phi_downwind, + *face.fi, + face.elem_is_upwind, + max_value, + min_value); + } +} + +// Utility function to compute the min-max values in a two-cell stencil +template +std::pair +computeMinMaxValue(const FunctorBase> & functor, + const FaceArg & face, + const StateArg & time, + const unsigned int & component) +{ + T max_value(0), min_value(1e10); + for (auto neighbor : (*face.fi).elem().neighbor_ptr_range()) + { + // If not a valid neighbor + if (neighbor == nullptr) + continue; + else + { + const ElemArg local_cell_arg = {neighbor, false}; + const auto value = functor(local_cell_arg, time)(component); + max_value = std::max(max_value, value); + min_value = std::min(min_value, value); + } + } + for (auto neighbor : (*face.fi).neighbor().neighbor_ptr_range()) + { + // If not a valid neighbor + if (neighbor == nullptr) + continue; + else + { + const ElemArg local_cell_arg = {neighbor, false}; + const auto value = functor(local_cell_arg, time)(component); + max_value = std::max(max_value, value); + min_value = std::min(min_value, value); + } + } + return std::make_pair(max_value, min_value); } template @@ -640,20 +821,73 @@ interpolate(const FunctorBase> & functor, } else { - const auto grad_phi_upwind = functor.gradient(upwind_arg, time); + const auto & time_arg = Moose::StateArg(1, Moose::SolutionIterationType::Time); + const auto & grad_phi_upwind = functor.gradient(upwind_arg, time_arg); + const auto & grad_phi_downwind = functor.gradient(downwind_arg, time_arg); + for (unsigned int i = 0; i < LIBMESH_DIM; ++i) { const auto &component_upwind = phi_upwind(i), component_downwind = phi_downwind(i); - const VectorValue grad = grad_phi_upwind.row(i); - std::tie(coeff_upwind, coeff_downwind) = interpCoeffs( - *limiter, component_upwind, component_downwind, &grad, *face.fi, face.elem_is_upwind); - ret(i) = coeff_upwind * component_upwind + coeff_downwind * component_downwind; + const VectorValue &grad_upwind = grad_phi_upwind.row(i), + grad_downwind = grad_phi_downwind.row(i); + + // Min-Max value + T max_value, min_value; + std::tie(max_value, min_value) = computeMinMaxValue(functor, face, time_arg, i); + + ret(i) = fullLimitedInterpolation(*limiter, + component_upwind, + component_downwind, + &grad_upwind, + &grad_downwind, + *face.fi, + face.elem_is_upwind, + max_value, + min_value); } } return ret; } +// Utility function to compute the min-max values in a two-cell stencil +template +std::pair +containerComputeMinMaxValue(const FunctorBase & functor, + const FaceArg & face, + const StateArg & time, + const unsigned int & component) +{ + T max_value(0), min_value(1e10); + for (auto neighbor : (*face.fi).elem().neighbor_ptr_range()) + { + // If not a valid neighbor + if (neighbor == nullptr) + continue; + else + { + const ElemArg local_cell_arg = {neighbor, false}; + const auto value = functor(local_cell_arg, time)[component]; + max_value = std::max(max_value, value); + min_value = std::min(min_value, value); + } + } + for (auto neighbor : (*face.fi).neighbor().neighbor_ptr_range()) + { + // If not a valid neighbor + if (neighbor == nullptr) + continue; + else + { + const ElemArg local_cell_arg = {neighbor, false}; + const auto value = functor(local_cell_arg, time)[component]; + max_value = std::max(max_value, value); + min_value = std::min(min_value, value); + } + } + return std::make_pair(max_value, min_value); +} + template T containerInterpolate(const FunctorBase & functor, const FaceArg & face, const StateArg & time) @@ -691,14 +925,28 @@ containerInterpolate(const FunctorBase & functor, const FaceArg & face, const } else { - const auto grad_phi_upwind = functor.gradient(upwind_arg, time); + const auto & time_arg = Moose::StateArg(1, Moose::SolutionIterationType::Time); + const auto & grad_phi_upwind = functor.gradient(upwind_arg, time_arg); + const auto & grad_phi_downwind = functor.gradient(downwind_arg, time_arg); + for (const auto i : index_range(ret)) { const auto &component_upwind = phi_upwind[i], component_downwind = phi_downwind[i]; - const auto & grad = grad_phi_upwind[i]; - std::tie(coeff_upwind, coeff_downwind) = interpCoeffs( - *limiter, component_upwind, component_downwind, &grad, *face.fi, face.elem_is_upwind); - ret[i] = coeff_upwind * component_upwind + coeff_downwind * component_downwind; + const VectorValue &grad_upwind = grad_phi_upwind[i], grad_downwind = grad_phi_downwind[i]; + + // Min-Max value + T max_value, min_value; + std::tie(max_value, min_value) = containerComputeMinMaxValue(functor, face, time_arg, i); + + ret[i] = fullLimitedInterpolation(*limiter, + component_upwind, + component_downwind, + &grad_upwind, + &grad_downwind, + *face.fi, + face.elem_is_upwind, + max_value, + min_value); } } diff --git a/framework/src/functormaterials/FunctorSmoother.C b/framework/src/functormaterials/FunctorSmoother.C index e457aa729a31..63dd7059bc66 100644 --- a/framework/src/functormaterials/FunctorSmoother.C +++ b/framework/src/functormaterials/FunctorSmoother.C @@ -102,7 +102,7 @@ FunctorSmootherTempl::FunctorSmootherTempl(const InputParameters & parameters _mesh.faceInfo(r_elem->neighbor_ptr(side_index), r_elem->neighbor_ptr(side_index)->which_neighbor_am_i(r_elem)); Moose::FaceArg face_arg{ - fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr}; + fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}; if (face_arg.fi) { average += functor_in(face_arg, t); diff --git a/framework/src/fvbcs/FVFunctorDirichletBC.C b/framework/src/fvbcs/FVFunctorDirichletBC.C index 103f8854a051..6bd5c542e0a4 100644 --- a/framework/src/fvbcs/FVFunctorDirichletBC.C +++ b/framework/src/fvbcs/FVFunctorDirichletBC.C @@ -59,10 +59,10 @@ FVFunctorDirichletBCTempl::boundaryValue(const FaceInfo & fi, if (!_use_other_side) return _functor(sfa, state); else if (fi.elemPtr() == sfa.face_side) - return _functor({&fi, Moose::FV::LimiterType::CentralDifference, true, false, fi.neighborPtr()}, + return _functor({&fi, Moose::FV::LimiterType::CentralDifference, true, false, fi.neighborPtr(), nullptr}, state); else - return _functor({&fi, Moose::FV::LimiterType::CentralDifference, true, false, fi.elemPtr()}, + return _functor({&fi, Moose::FV::LimiterType::CentralDifference, true, false, fi.elemPtr(), nullptr}, state); } diff --git a/framework/src/fviks/FVInterfaceKernel.C b/framework/src/fviks/FVInterfaceKernel.C index 11d831fe4b18..8af68ad75ef9 100644 --- a/framework/src/fviks/FVInterfaceKernel.C +++ b/framework/src/fviks/FVInterfaceKernel.C @@ -255,7 +255,7 @@ FVInterfaceKernel::singleSidedFaceArg(const MooseVariableFV & variable, ? nullptr : (defined_on_elem_side ? fi->elemPtr() : fi->neighborPtr()); - return {fi, limiter_type, true, correct_skewness, elem}; + return {fi, limiter_type, true, correct_skewness, elem, nullptr}; } bool diff --git a/framework/src/interfaces/FaceArgInterface.C b/framework/src/interfaces/FaceArgInterface.C index 6e75706117f2..110e371b1875 100644 --- a/framework/src/interfaces/FaceArgInterface.C +++ b/framework/src/interfaces/FaceArgInterface.C @@ -13,7 +13,8 @@ Moose::FaceArg FaceArgProducerInterface::makeFace(const FaceInfo & fi, const Moose::FV::LimiterType limiter_type, const bool elem_is_upwind, - const bool correct_skewness) const + const bool correct_skewness, + const Moose::StateArg * state_limiter) const { const bool defined_on_elem_side = hasFaceSide(fi, true); const bool defined_on_neighbor_side = hasFaceSide(fi, false); @@ -24,5 +25,5 @@ FaceArgProducerInterface::makeFace(const FaceInfo & fi, if (!defined_on_elem_side && !defined_on_neighbor_side) mooseError("No definition on either side"); - return {&fi, limiter_type, elem_is_upwind, correct_skewness, elem}; + return {&fi, limiter_type, elem_is_upwind, correct_skewness, elem, state_limiter}; } diff --git a/framework/src/limiters/Limiter.C b/framework/src/limiters/Limiter.C index a96b192e9cd9..dc5adb679b1a 100644 --- a/framework/src/limiters/Limiter.C +++ b/framework/src/limiters/Limiter.C @@ -14,6 +14,7 @@ #include "MinModLimiter.h" #include "SOULimiter.h" #include "QUICKLimiter.h" +#include "VenkatakrishnanLimiter.h" #include "MooseError.h" #include "MathFVUtils.h" @@ -23,8 +24,8 @@ namespace Moose { namespace FV { -const MooseEnum - moose_limiter_type("vanLeer=0 upwind=1 central_difference=2 min_mod=3 sou=4 quick=5", "upwind"); +const MooseEnum moose_limiter_type( + "vanLeer=0 upwind=1 central_difference=2 min_mod=3 sou=4 quick=5 venkatakrishnan=6", "upwind"); template std::unique_ptr> @@ -50,6 +51,9 @@ Limiter::build(const LimiterType limiter) case LimiterType::QUICK: return std::make_unique>(); + case LimiterType::Venkatakrishnan: + return std::make_unique>(); + default: mooseError("Unrecognized limiter type ", unsigned(limiter)); } @@ -79,6 +83,9 @@ limiterType(const InterpMethod interp_method) case InterpMethod::QUICK: return LimiterType::QUICK; + case InterpMethod::Venkatakrishnan: + return LimiterType::Venkatakrishnan; + default: mooseError("Unrecognized interpolation method type."); } diff --git a/framework/src/postprocessors/SideAdvectiveFluxIntegral.C b/framework/src/postprocessors/SideAdvectiveFluxIntegral.C index 393e999f01a1..3751638a9e39 100644 --- a/framework/src/postprocessors/SideAdvectiveFluxIntegral.C +++ b/framework/src/postprocessors/SideAdvectiveFluxIntegral.C @@ -91,19 +91,21 @@ SideAdvectiveFluxIntegralTempl::computeFaceInfoIntegral(const FaceInfo * // Get face value for velocity const auto vel_x = (_vel_x)(Moose::FaceArg( - {fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr}), + {fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}), state); const auto vel_y = _vel_y - ? ((*_vel_y)(Moose::FaceArg( - {fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr}), - state)) + ? ((*_vel_y)( + Moose::FaceArg( + {fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}), + state)) : 0; const auto vel_z = _vel_z - ? ((*_vel_z)(Moose::FaceArg( - {fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr}), - state)) + ? ((*_vel_z)( + Moose::FaceArg( + {fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}), + state)) : 0; auto fi_normal = _current_elem == fi->elemPtr() ? fi->normal() : Point(-fi->normal()); @@ -111,7 +113,7 @@ SideAdvectiveFluxIntegralTempl::computeFaceInfoIntegral(const FaceInfo * const auto adv_quant_face = (*_adv_quant)( Moose::FaceArg( - {fi, Moose::FV::LimiterType::CentralDifference, elem_is_upwind, false, nullptr}), + {fi, Moose::FV::LimiterType::CentralDifference, elem_is_upwind, false, nullptr, nullptr}), state); return fi_normal * adv_quant_face * RealVectorValue(vel_x, vel_y, vel_z); diff --git a/framework/src/utils/MathFVUtils.C b/framework/src/utils/MathFVUtils.C index ad16b2f7dd89..759cdc11d83e 100644 --- a/framework/src/utils/MathFVUtils.C +++ b/framework/src/utils/MathFVUtils.C @@ -60,19 +60,20 @@ onBoundary(const std::set & subs, const FaceInfo & fi) MooseEnum interpolationMethods() { - return MooseEnum("average upwind sou min_mod vanLeer quick skewness-corrected", "upwind"); + return MooseEnum("average upwind sou min_mod vanLeer quick venkatakrishnan skewness-corrected", + "upwind"); } InputParameters advectedInterpolationParameter() { auto params = emptyInputParameters(); - params.addParam( - "advected_interp_method", - interpolationMethods(), - "The interpolation to use for the advected quantity. Options are " - "'upwind', 'average', 'sou' (for second-order upwind), 'min_mod', 'vanLeer', 'quick', and " - "'skewness-corrected' with the default being 'upwind'."); + params.addParam("advected_interp_method", + interpolationMethods(), + "The interpolation to use for the advected quantity. Options are " + "'upwind', 'average', 'sou' (for second-order upwind), 'min_mod', " + "'vanLeer', 'quick', 'venkatakrishnan', and " + "'skewness-corrected' with the default being 'upwind'."); return params; } @@ -97,6 +98,8 @@ selectInterpolationMethod(const std::string & interp_method) return InterpMethod::SOU; else if (interp_method == "quick") return InterpMethod::QUICK; + else if (interp_method == "venkatakrishnan") + return InterpMethod::Venkatakrishnan; else mooseError("Interpolation method ", interp_method, diff --git a/modules/heat_transfer/src/fvbcs/FVFunctorConvectiveHeatFluxBC.C b/modules/heat_transfer/src/fvbcs/FVFunctorConvectiveHeatFluxBC.C index 59381376eb72..ad0daf3060ec 100644 --- a/modules/heat_transfer/src/fvbcs/FVFunctorConvectiveHeatFluxBC.C +++ b/modules/heat_transfer/src/fvbcs/FVFunctorConvectiveHeatFluxBC.C @@ -43,7 +43,7 @@ FVFunctorConvectiveHeatFluxBC::computeQpResidual() // Allow the functors to pick their side evaluation since either T_bulk or T_solid is likely not // defined on this boundary condition's side const Moose::FaceArg face{ - _face_info, Moose::FV::LimiterType::CentralDifference, true, false, nullptr}; + _face_info, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}; const auto flux = _htc(face, determineState()) * (_T_bulk(face, determineState()) - _T_solid(face, determineState())); if (_is_solid) diff --git a/modules/navier_stokes/include/utils/Reconstructions.h b/modules/navier_stokes/include/utils/Reconstructions.h index 08b49c3c0c99..6a85ef224636 100644 --- a/modules/navier_stokes/include/utils/Reconstructions.h +++ b/modules/navier_stokes/include/utils/Reconstructions.h @@ -61,7 +61,8 @@ interpolateReconstruct(CellCenteredMapFunctor & output_functor, false, input_functor.hasFaceSide(*face, true) ? (input_functor.hasFaceSide(*face, false) ? nullptr : face->elemPtr()) - : face->neighborPtr()}; + : face->neighborPtr(), + nullptr}; auto face_value = input_functor(face_arg, time); std::pair * neighbor_pair = nullptr; if (face->neighborPtr() && face->neighborPtr() != libMesh::remote_elem) diff --git a/modules/navier_stokes/src/fvkernels/INSFVMomentumAdvection.C b/modules/navier_stokes/src/fvkernels/INSFVMomentumAdvection.C index 5fc190c0c5ef..5ee7c4a00fe0 100644 --- a/modules/navier_stokes/src/fvkernels/INSFVMomentumAdvection.C +++ b/modules/navier_stokes/src/fvkernels/INSFVMomentumAdvection.C @@ -124,7 +124,7 @@ INSFVMomentumAdvection::computeResidualsAndAData(const FaceInfo & fi) { const bool elem_is_upwind = MetaPhysicL::raw_value(v_face) * _normal > 0; const Moose::FaceArg advected_face_arg{ - &fi, limiterType(_advected_interp_method), elem_is_upwind, correct_skewness, nullptr}; + &fi, limiterType(_advected_interp_method), elem_is_upwind, correct_skewness, nullptr, nullptr}; if (const auto [is_jump, eps_elem_face, eps_neighbor_face] = NS::isPorosityJumpFace(epsilon(), fi, state); is_jump) diff --git a/modules/navier_stokes/src/fvkernels/INSFVScalarFieldAdvection.C b/modules/navier_stokes/src/fvkernels/INSFVScalarFieldAdvection.C index ae30650de2e7..6b86104da417 100644 --- a/modules/navier_stokes/src/fvkernels/INSFVScalarFieldAdvection.C +++ b/modules/navier_stokes/src/fvkernels/INSFVScalarFieldAdvection.C @@ -55,7 +55,7 @@ INSFVScalarFieldAdvection::computeQpResidual() face_arg = singleSidedFaceArg(); else face_arg = Moose::FaceArg{ - _face_info, Moose::FV::LimiterType::CentralDifference, true, false, nullptr}; + _face_info, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}; ADRealVectorValue velocity_slip_vel_vec; if (_dim >= 1) diff --git a/modules/navier_stokes/src/fvkernels/INSFVTKEDSourceSink.C b/modules/navier_stokes/src/fvkernels/INSFVTKEDSourceSink.C index ea2a076418e5..31a4a14fd6cd 100644 --- a/modules/navier_stokes/src/fvkernels/INSFVTKEDSourceSink.C +++ b/modules/navier_stokes/src/fvkernels/INSFVTKEDSourceSink.C @@ -149,7 +149,7 @@ INSFVTKEDSourceSink::computeQpResidual() const bool defined_on_elem_side = _var.hasFaceSide(*fi, true); const Elem * const loc_elem = defined_on_elem_side ? &fi->elem() : fi->neighborPtr(); const Moose::FaceArg facearg = { - fi, Moose::FV::LimiterType::CentralDifference, false, false, loc_elem}; + fi, Moose::FV::LimiterType::CentralDifference, false, false, loc_elem, nullptr}; destruction += 2.0 * TKE_old * _mu(facearg, state) / rho / Utility::pow<2>(distance_vec[i]) / tot_weight; } diff --git a/modules/navier_stokes/src/fvkernels/INSFVTKESourceSink.C b/modules/navier_stokes/src/fvkernels/INSFVTKESourceSink.C index b5902edcd259..354ba1775921 100644 --- a/modules/navier_stokes/src/fvkernels/INSFVTKESourceSink.C +++ b/modules/navier_stokes/src/fvkernels/INSFVTKESourceSink.C @@ -163,7 +163,7 @@ INSFVTKESourceSink::computeQpResidual() const bool defined_on_elem_side = _var.hasFaceSide(*fi, true); const Elem * const loc_elem = defined_on_elem_side ? &fi->elem() : fi->neighborPtr(); const Moose::FaceArg facearg = { - fi, Moose::FV::LimiterType::CentralDifference, false, false, loc_elem}; + fi, Moose::FV::LimiterType::CentralDifference, false, false, loc_elem, nullptr}; const ADReal wall_mut = _mu_t(facearg, state); const ADReal wall_mu = _mu(facearg, state); diff --git a/modules/navier_stokes/src/fvkernels/WCNSFV2PMomentumAdvectionSlip.C b/modules/navier_stokes/src/fvkernels/WCNSFV2PMomentumAdvectionSlip.C index 21c20a90ca7b..f69e3416f890 100644 --- a/modules/navier_stokes/src/fvkernels/WCNSFV2PMomentumAdvectionSlip.C +++ b/modules/navier_stokes/src/fvkernels/WCNSFV2PMomentumAdvectionSlip.C @@ -73,7 +73,7 @@ WCNSFV2PMomentumAdvectionSlip::computeResidualsAndAData(const FaceInfo & fi) if (on_boundary) face_arg = singleSidedFaceArg(); else - face_arg = Moose::FaceArg{&fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr}; + face_arg = Moose::FaceArg{&fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}; ADRealVectorValue u_slip_vel_vec; if (_dim == 1) @@ -119,7 +119,7 @@ WCNSFV2PMomentumAdvectionSlip::computeResidualsAndAData(const FaceInfo & fi) { const bool elem_is_upwind = MetaPhysicL::raw_value(u_slip_vel_vec) * _normal > 0; const Moose::FaceArg advected_face_arg{ - &fi, limiterType(_advected_interp_method), elem_is_upwind, correct_skewness, nullptr}; + &fi, limiterType(_advected_interp_method), elem_is_upwind, correct_skewness, nullptr, nullptr}; if (const auto [is_jump, eps_elem_face, eps_neighbor_face] = NS::isPorosityJumpFace(epsilon(), fi, state); is_jump) diff --git a/modules/navier_stokes/src/postprocessors/IntegralDirectedSurfaceForce.C b/modules/navier_stokes/src/postprocessors/IntegralDirectedSurfaceForce.C index 9969dea156a6..296dcbcd187e 100644 --- a/modules/navier_stokes/src/postprocessors/IntegralDirectedSurfaceForce.C +++ b/modules/navier_stokes/src/postprocessors/IntegralDirectedSurfaceForce.C @@ -75,7 +75,7 @@ IntegralDirectedSurfaceForce::computeFaceInfoIntegral(const FaceInfo * fi) const auto state = determineState(); const auto face_arg = - Moose::FaceArg({fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr}); + Moose::FaceArg({fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}); const auto elem_arg = Moose::ElemArg({fi->elemPtr(), false}); RealTensorValue pressure_term; diff --git a/modules/navier_stokes/src/postprocessors/MassFluxWeightedFlowRate.C b/modules/navier_stokes/src/postprocessors/MassFluxWeightedFlowRate.C index 3d200dbcc3c4..dc614f188e9f 100644 --- a/modules/navier_stokes/src/postprocessors/MassFluxWeightedFlowRate.C +++ b/modules/navier_stokes/src/postprocessors/MassFluxWeightedFlowRate.C @@ -70,7 +70,8 @@ MassFluxWeightedFlowRate::computeFaceInfoIntegral([[maybe_unused]] const FaceInf Moose::FV::limiterType(_advected_interp_method), MetaPhysicL::raw_value(vel) * fi->normal() > 0, correct_skewness, - _adv_quant->hasFaceSide(*fi, true) ? fi->elemPtr() : fi->neighborPtr()}); + _adv_quant->hasFaceSide(*fi, true) ? fi->elemPtr() : fi->neighborPtr(), + nullptr}); auto dens = _density(face_arg, state); const auto adv_quant_face = MetaPhysicL::raw_value(dens * (*_adv_quant)(face_arg, state)); _mdot += fi->faceArea() * fi->faceCoord() * MetaPhysicL::raw_value(dens) * fi->normal() * vel; diff --git a/modules/navier_stokes/src/postprocessors/PressureDrop.C b/modules/navier_stokes/src/postprocessors/PressureDrop.C index 977c2abb30c1..6b2688ce0c0a 100644 --- a/modules/navier_stokes/src/postprocessors/PressureDrop.C +++ b/modules/navier_stokes/src/postprocessors/PressureDrop.C @@ -238,14 +238,15 @@ PressureDrop::computeFaceInfoWeightedPressureIntegral(const FaceInfo * const fi) Moose::FV::limiterType(_weight_interp_method), MetaPhysicL::raw_value((*_weighting_functor)(elem_arg, state)) * fi->normal() > 0, correct_skewness, - elem}); + elem, + nullptr}); const auto face_weighting = MetaPhysicL::raw_value((*_weighting_functor)(ssf, state)); return fi->normal() * face_weighting * _pressure(ssf, state); } else { const auto ssf = Moose::FaceArg( - {fi, Moose::FV::limiterType(_weight_interp_method), true, correct_skewness, elem}); + {fi, Moose::FV::limiterType(_weight_interp_method), true, correct_skewness, elem, nullptr}); return _pressure(ssf, state); } } @@ -268,7 +269,8 @@ PressureDrop::computeFaceInfoWeightIntegral(const FaceInfo * fi) const Moose::FV::limiterType(_weight_interp_method), MetaPhysicL::raw_value((*_weighting_functor)(elem_arg, state)) * fi->normal() > 0, correct_skewness, - _weighting_functor->hasFaceSide(*fi, true) ? fi->elemPtr() : fi->neighborPtr()}); + _weighting_functor->hasFaceSide(*fi, true) ? fi->elemPtr() : fi->neighborPtr(), + nullptr}); return fi->normal() * MetaPhysicL::raw_value((*_weighting_functor)(ssf, state)); } else diff --git a/modules/navier_stokes/src/postprocessors/VolumetricFlowRate.C b/modules/navier_stokes/src/postprocessors/VolumetricFlowRate.C index 7c9220f8809d..540146720b07 100644 --- a/modules/navier_stokes/src/postprocessors/VolumetricFlowRate.C +++ b/modules/navier_stokes/src/postprocessors/VolumetricFlowRate.C @@ -147,7 +147,8 @@ VolumetricFlowRate::computeFaceInfoIntegral(const FaceInfo * fi) Moose::FV::limiterType(_advected_interp_method), MetaPhysicL::raw_value(vel) * fi->normal() > 0, correct_skewness, - elem}), + elem, + nullptr}), state)); return fi->normal() * adv_quant_face * vel; } diff --git a/modules/navier_stokes/src/userobjects/INSFVRhieChowInterpolator.C b/modules/navier_stokes/src/userobjects/INSFVRhieChowInterpolator.C index 619e6335cd75..808966737087 100644 --- a/modules/navier_stokes/src/userobjects/INSFVRhieChowInterpolator.C +++ b/modules/navier_stokes/src/userobjects/INSFVRhieChowInterpolator.C @@ -545,7 +545,7 @@ INSFVRhieChowInterpolator::getVelocity(const Moose::FV::InterpMethod m, { const Elem * const boundary_elem = hasBlocks(elem->subdomain_id()) ? elem : neighbor; const Moose::FaceArg boundary_face{ - &fi, Moose::FV::LimiterType::CentralDifference, true, correct_skewness, boundary_elem}; + &fi, Moose::FV::LimiterType::CentralDifference, true, correct_skewness, boundary_elem, nullptr}; auto velocity = vel(boundary_face, time); incorporate_mesh_velocity(boundary_face, velocity); @@ -559,7 +559,7 @@ INSFVRhieChowInterpolator::getVelocity(const Moose::FV::InterpMethod m, VectorValue velocity; Moose::FaceArg face{ - &fi, Moose::FV::LimiterType::CentralDifference, true, correct_skewness, nullptr}; + &fi, Moose::FV::LimiterType::CentralDifference, true, correct_skewness, nullptr, nullptr}; // Create the average face velocity (not corrected using RhieChow yet) velocity(0) = (*u)(face, time); if (v) @@ -625,7 +625,7 @@ INSFVRhieChowInterpolator::getVelocity(const Moose::FV::InterpMethod m, // Compute the corrected interpolated face value Moose::FaceArg face{ - &fi, Moose::FV::LimiterType::CentralDifference, true, correct_skewness, nullptr}; + &fi, Moose::FV::LimiterType::CentralDifference, true, correct_skewness, nullptr, nullptr}; interp_vf = 0.0; for (const auto i : make_range(_volumetric_force.size())) @@ -654,7 +654,7 @@ INSFVRhieChowInterpolator::getVelocity(const Moose::FV::InterpMethod m, elem_has_fi ? side : loc_neighbor->which_neighbor_am_i(elem)); Moose::FaceArg loc_face{ - fi_loc, Moose::FV::LimiterType::CentralDifference, true, correct_skewness, elem}; + fi_loc, Moose::FV::LimiterType::CentralDifference, true, correct_skewness, elem, nullptr}; MooseMeshUtils::coordTransformFactor( elem->vertex_average(), coord_multiplier, coord_type, rz_radial_coord); @@ -689,7 +689,7 @@ INSFVRhieChowInterpolator::getVelocity(const Moose::FV::InterpMethod m, elem_has_fi ? side : loc_elem->which_neighbor_am_i(neighbor)); Moose::FaceArg loc_face{ - fi_loc, Moose::FV::LimiterType::CentralDifference, true, correct_skewness, elem}; + fi_loc, Moose::FV::LimiterType::CentralDifference, true, correct_skewness, elem, nullptr}; MooseMeshUtils::coordTransformFactor( neighbor->vertex_average(), coord_multiplier, coord_type, rz_radial_coord); @@ -730,7 +730,7 @@ INSFVRhieChowInterpolator::getVelocity(const Moose::FV::InterpMethod m, { Real value = 0.0; Moose::FaceArg loc_face{ - &fi, Moose::FV::LimiterType::CentralDifference, true, correct_skewness, nullptr}; + &fi, Moose::FV::LimiterType::CentralDifference, true, correct_skewness, nullptr, nullptr}; for (const auto i : make_range(_volumetric_force.size())) value += (*_volumetric_force[i])(loc_face, time) * (face_normal * fi.normal()); diff --git a/modules/navier_stokes/src/userobjects/INSFVRhieChowInterpolatorSegregated.C b/modules/navier_stokes/src/userobjects/INSFVRhieChowInterpolatorSegregated.C index 3b7da0b91cf1..3fe5dc55962f 100644 --- a/modules/navier_stokes/src/userobjects/INSFVRhieChowInterpolatorSegregated.C +++ b/modules/navier_stokes/src/userobjects/INSFVRhieChowInterpolatorSegregated.C @@ -136,7 +136,7 @@ INSFVRhieChowInterpolatorSegregated::initFaceVelocities() if (_u->isInternalFace(*fi)) { const Moose::FaceArg face{ - fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr}; + fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}; _face_velocity[fi->id()] = MetaPhysicL::raw_value((*_vel)(face, Moose::currentState())); } @@ -147,7 +147,7 @@ INSFVRhieChowInterpolatorSegregated::initFaceVelocities() hasBlocks(fi->elemPtr()->subdomain_id()) ? fi->elemPtr() : fi->neighborPtr(); const Moose::FaceArg boundary_face{ - fi, Moose::FV::LimiterType::CentralDifference, true, false, boundary_elem}; + fi, Moose::FV::LimiterType::CentralDifference, true, false, boundary_elem, nullptr}; _face_velocity[fi->id()] = MetaPhysicL::raw_value((*_vel)(boundary_face, Moose::currentState())); @@ -185,7 +185,7 @@ INSFVRhieChowInterpolatorSegregated::computeFaceVelocity() if (_u->isInternalFace(*fi)) { const Moose::FaceArg face{ - fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr}; + fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}; RealVectorValue Ainv; RealVectorValue HbyA = MetaPhysicL::raw_value(_HbyA(face, time_arg)); @@ -207,7 +207,7 @@ INSFVRhieChowInterpolatorSegregated::computeFaceVelocity() const Elem * const boundary_elem = hasBlocks(fi->elemPtr()->subdomain_id()) ? fi->elemPtr() : fi->neighborPtr(); const Moose::FaceArg boundary_face{ - fi, Moose::FV::LimiterType::CentralDifference, true, false, boundary_elem}; + fi, Moose::FV::LimiterType::CentralDifference, true, false, boundary_elem, nullptr}; // If we have a dirichlet boundary conditions, this sill give us the exact value of the // velocity on the face as expected (see populateHbyA()) @@ -310,7 +310,7 @@ INSFVRhieChowInterpolatorSegregated::populateHbyA( hasBlocks(fi->elemPtr()->subdomain_id()) ? fi->elemPtr() : fi->neighborPtr(); const Moose::FaceArg boundary_face{ - fi, Moose::FV::LimiterType::CentralDifference, true, false, boundary_elem}; + fi, Moose::FV::LimiterType::CentralDifference, true, false, boundary_elem, nullptr}; if (_u->isDirichletBoundaryFace(*fi, boundary_elem, Moose::currentState())) _HbyA[fi->id()] = -MetaPhysicL::raw_value((*_vel)(boundary_face, Moose::currentState())); diff --git a/modules/navier_stokes/src/userobjects/RhieChowMassFlux.C b/modules/navier_stokes/src/userobjects/RhieChowMassFlux.C index 288788806778..4e33d9722d40 100644 --- a/modules/navier_stokes/src/userobjects/RhieChowMassFlux.C +++ b/modules/navier_stokes/src/userobjects/RhieChowMassFlux.C @@ -216,7 +216,7 @@ RhieChowMassFlux::initFaceMassFlux() hasBlocks(fi->elemPtr()->subdomain_id()) ? fi->elemPtr() : fi->neighborPtr(); const Moose::FaceArg boundary_face{ - fi, Moose::FV::LimiterType::CentralDifference, true, false, boundary_elem}; + fi, Moose::FV::LimiterType::CentralDifference, true, false, boundary_elem, nullptr}; const Real face_rho = _rho(boundary_face, time_arg); for (const auto dim_i : index_range(_vel)) @@ -405,7 +405,7 @@ RhieChowMassFlux::populateCouplingFunctors( if (_vel[0]->isDirichletBoundaryFace(*fi)) { const Moose::FaceArg boundary_face{ - fi, Moose::FV::LimiterType::CentralDifference, true, false, elem_info.elem()}; + fi, Moose::FV::LimiterType::CentralDifference, true, false, elem_info.elem(), nullptr}; face_rho = _rho(boundary_face, Moose::currentState()); for (const auto dim_i : make_range(_dim)) diff --git a/modules/navier_stokes/src/utils/NSFVUtils.C b/modules/navier_stokes/src/utils/NSFVUtils.C index 747b2e08ad90..2db25a74299e 100644 --- a/modules/navier_stokes/src/utils/NSFVUtils.C +++ b/modules/navier_stokes/src/utils/NSFVUtils.C @@ -68,9 +68,9 @@ isPorosityJumpFace(const Moose::Functor & porosity, "Porosity should have blocks on both elem and neighbor"); const Moose::FaceArg face_elem{ - &fi, Moose::FV::LimiterType::CentralDifference, true, false, fi.elemPtr()}; + &fi, Moose::FV::LimiterType::CentralDifference, true, false, fi.elemPtr(), nullptr}; const Moose::FaceArg face_neighbor{ - &fi, Moose::FV::LimiterType::CentralDifference, true, false, fi.neighborPtr()}; + &fi, Moose::FV::LimiterType::CentralDifference, true, false, fi.neighborPtr(), nullptr}; const auto eps_elem = porosity(face_elem, time), eps_neighbor = porosity(face_neighbor, time); return {!MooseUtils::relativeFuzzyEqual(eps_elem, eps_neighbor), eps_elem, eps_neighbor}; } diff --git a/modules/navier_stokes/src/variables/BernoulliPressureVariable.C b/modules/navier_stokes/src/variables/BernoulliPressureVariable.C index 1a2b2ee75c24..9551f67292e5 100644 --- a/modules/navier_stokes/src/variables/BernoulliPressureVariable.C +++ b/modules/navier_stokes/src/variables/BernoulliPressureVariable.C @@ -68,7 +68,7 @@ BernoulliPressureVariable::elemIsUpwind(const Elem & elem, const FaceInfo & fi, const Moose::StateArg & time) const { - const Moose::FaceArg face{&fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr}; + const Moose::FaceArg face{&fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}; const VectorValue vel_face{(*_u)(face, time), (*_v)(face, time), (*_w)(face, time)}; const bool fi_elem_is_upwind = vel_face * fi.normal() > 0; @@ -131,9 +131,9 @@ BernoulliPressureVariable::getDirichletBoundaryFaceValue(const FaceInfo & fi, #endif const Moose::FaceArg face_elem{ - &fi, Moose::FV::LimiterType::CentralDifference, true, false, &fi.elem()}; + &fi, Moose::FV::LimiterType::CentralDifference, true, false, &fi.elem(), nullptr}; const Moose::FaceArg face_neighbor{ - &fi, Moose::FV::LimiterType::CentralDifference, true, false, fi.neighborPtr()}; + &fi, Moose::FV::LimiterType::CentralDifference, true, false, fi.neighborPtr(), nullptr}; const auto [elem_is_upwind, vel_face] = elemIsUpwind(*elem, fi, time); const auto & vel_elem = vel_face; diff --git a/modules/navier_stokes/src/variables/INSFVVelocityVariable.C b/modules/navier_stokes/src/variables/INSFVVelocityVariable.C index f2f17a353ea6..aa214a7af666 100644 --- a/modules/navier_stokes/src/variables/INSFVVelocityVariable.C +++ b/modules/navier_stokes/src/variables/INSFVVelocityVariable.C @@ -273,6 +273,7 @@ INSFVVelocityVariable::adGradSln(const Elem * const elem, Moose::FV::LimiterType::CentralDifference, true, correct_skewness, + nullptr, nullptr}), time); else diff --git a/modules/navier_stokes/test/tests/finite_volume/ins/limiters/bottom_left_advection.i b/modules/navier_stokes/test/tests/finite_volume/ins/limiters/bottom_left_advection.i new file mode 100644 index 000000000000..38cb2d588462 --- /dev/null +++ b/modules/navier_stokes/test/tests/finite_volume/ins/limiters/bottom_left_advection.i @@ -0,0 +1,109 @@ +diff = 1e-12 +advected_interp_method = 'vanLeer' #average upwind sou min_mod vanLeer quick venkatakrishnan skewness-corrected +velocity_interp_method = 'average' + +[UserObjects] + [rc] + type = INSFVRhieChowInterpolator + u = vel_x + v = vel_y + a_u = vel_x + a_v = vel_y + pressure = pressure + [] +[] + +[Mesh] + [gen] + type = GeneratedMeshGenerator + dim = 2 + xmin = 0 + xmax = 1 + ymin = 0 + ymax = 1 + nx = 50 + ny = 50 + [] +[] + +[AuxVariables] + [vel_x] + type = INSFVVelocityVariable + initial_condition = 1.0 + [] + [vel_y] + type = INSFVVelocityVariable + initial_condition = 1.0 + [] + [pressure] + type = INSFVPressureVariable + initial_condition = 1.0 + [] +[] + +[Variables] + [scalar] + type = INSFVScalarFieldVariable + [] +[] + +[FVKernels] + [scalar_time] + type = FVFunctorTimeKernel + variable = scalar + [] + [scalar_advection] + type = INSFVScalarFieldAdvection + variable = scalar + velocity_interp_method = ${velocity_interp_method} + advected_interp_method = ${advected_interp_method} + rhie_chow_user_object = 'rc' + [] + [scalar_diffusion] + type = FVDiffusion + coeff = ${diff} + variable = scalar + [] +[] + +[FVBCs] + [fv_inflow] + type = NSFVOutflowTemperatureBC + u = vel_x + v = vel_y + backflow_T = 1.0 + rho = 1.0 + cp = 1.0 + variable = scalar + boundary = 'left' + [] + [fv_outflow] + type = NSFVOutflowTemperatureBC + u = vel_x + v = vel_y + backflow_T = 0.0 + rho = 1.0 + cp = 1.0 + variable = scalar + boundary = 'right top bottom' + [] +[] + +[Executioner] + type = Transient + solve_type = 'NEWTON' + petsc_options_iname = '-pc_type -pc_factor_shift_type' + petsc_options_value = 'lu NONZERO' + [TimeStepper] + type = IterationAdaptiveDT + optimal_iterations = 20 + linear_iteration_ratio = 2 + dt = 0.1 + [] + nl_abs_tol = 1e-10 +[] + +[Outputs] + exodus = true + csv = true +[] From 317ba496e141ab82f9010b4ab8de7f2a0d7db461 Mon Sep 17 00:00:00 2001 From: tanome Date: Thu, 24 Oct 2024 10:11:23 -0600 Subject: [PATCH 02/20] correcting limting action to face grdient limiter Refs #28891 --- framework/include/fvbcs/FVBoundaryCondition.h | 3 +- framework/include/fviks/FVInterfaceKernel.h | 3 +- framework/include/fvkernels/FVFluxKernel.h | 3 +- framework/include/limiters/MinModLimiter.h | 72 +- framework/include/limiters/QUICKLimiter.h | 123 ++- framework/include/limiters/SOULimiter.h | 112 ++- .../include/limiters/VenkatakrishnanLimiter.h | 103 ++- framework/include/utils/MathFVUtils.h | 729 +++++++++++++----- framework/include/variables/MooseVariableFV.h | 3 + framework/src/fvbcs/FVBoundaryCondition.C | 5 +- framework/src/fviks/FVInterfaceKernel.C | 5 +- framework/src/fvkernels/FVFluxKernel.C | 5 +- .../src/fvkernels/INSFVAdvectionKernel.C | 9 + .../src/fvkernels/INSFVEnergyAdvection.C | 7 +- .../src/fvkernels/INSFVMomentumAdvection.C | 11 +- .../src/fvkernels/INSFVScalarFieldAdvection.C | 16 +- 16 files changed, 955 insertions(+), 254 deletions(-) diff --git a/framework/include/fvbcs/FVBoundaryCondition.h b/framework/include/fvbcs/FVBoundaryCondition.h index 8875eba4e1fe..276d06ecefe6 100644 --- a/framework/include/fvbcs/FVBoundaryCondition.h +++ b/framework/include/fvbcs/FVBoundaryCondition.h @@ -91,7 +91,8 @@ class FVBoundaryCondition : public MooseObject, Moose::FaceArg singleSidedFaceArg( const FaceInfo * fi = nullptr, Moose::FV::LimiterType limiter_type = Moose::FV::LimiterType::CentralDifference, - bool correct_skewness = false) const; + bool correct_skewness = false, + const Moose::StateArg * state_limiter = nullptr) const; MooseVariableFV & _var; diff --git a/framework/include/fviks/FVInterfaceKernel.h b/framework/include/fviks/FVInterfaceKernel.h index ff6ad444a88b..670d9f26cf47 100644 --- a/framework/include/fviks/FVInterfaceKernel.h +++ b/framework/include/fviks/FVInterfaceKernel.h @@ -160,7 +160,8 @@ class FVInterfaceKernel : public MooseObject, const MooseVariableFV & variable, const FaceInfo * fi = nullptr, Moose::FV::LimiterType limiter_type = Moose::FV::LimiterType::CentralDifference, - bool correct_skewness = false) const; + bool correct_skewness = false, + const Moose::StateArg * state_limiter = nullptr) const; /// To be consistent with FE interfaces we introduce this quadrature point member. However, for FV /// calculations there should every only be one qudrature point and it should be located at the diff --git a/framework/include/fvkernels/FVFluxKernel.h b/framework/include/fvkernels/FVFluxKernel.h index 1812455b13f8..9fa815b1add0 100644 --- a/framework/include/fvkernels/FVFluxKernel.h +++ b/framework/include/fvkernels/FVFluxKernel.h @@ -118,7 +118,8 @@ class FVFluxKernel : public FVKernel, Moose::FaceArg singleSidedFaceArg( const FaceInfo * fi = nullptr, Moose::FV::LimiterType limiter_type = Moose::FV::LimiterType::CentralDifference, - bool correct_skewness = false) const; + bool correct_skewness = false, + const Moose::StateArg * state_limiter = nullptr) const; /** * Returns whether to avoid execution on a boundary diff --git a/framework/include/limiters/MinModLimiter.h b/framework/include/limiters/MinModLimiter.h index 668595e748cb..af2837f7cb7a 100644 --- a/framework/include/limiters/MinModLimiter.h +++ b/framework/include/limiters/MinModLimiter.h @@ -17,24 +17,63 @@ namespace Moose namespace FV { /** - * Implements the Min-Mod limiter, defined by - * $\beta(r_f) = \text{max}(0, \text{min}(1, r_f))$ + * @brief Implements the Min-Mod limiter for flux limiting in numerical methods. + * + * The Min-Mod limiter is used to reduce numerical oscillations and + * enforce monotonicity in computational fluid dynamics (CFD) and other numerical simulations. + * The limiter function $\beta(r_f)$ is defined as: + * + * \f[ + * \beta(r_f) = \text{max}(0, \text{min}(1, r_f)) + * \f] + * + * where \( r_f \) is the ratio of the upwind to downwind gradients. + * + * @tparam T The data type of the scalar values and the return type. */ template class MinModLimiter : public Limiter { public: + /** + * @brief Computes the limited value using the Min-Mod limiter. + * + * This method overrides the pure virtual `limit` method in the base `Limiter` class. + * It calculates the flux limiting ratio based on the Min-Mod limiter formula. + * + * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. + * @param grad_phi_downwind Pointer to the gradient vector at the downwind location. + * @param dCD A constant direction vector representing the direction of the cell face. + * @return The computed flux limiting ratio. + * + * This method performs the following steps: + * 1. Asserts that the upwind gradient pointer is not null. + * 2. Computes the gradient ratio coefficient \( r_f \) using the `rf_grad` method. + * 3. Applies the Min-Mod limiter formula to \( r_f \) to obtain the limited value. + * 4. Returns the computed limited value. + * + * @example + * @code + * MinModLimiter minMod; + * VectorValue grad_upwind(0.1, 0.2, 0.3); + * VectorValue grad_downwind(0.4, 0.5, 0.6); + * RealVectorValue dCD(1.0, 0.0, 0.0); + * Real result = minMod.limit(0.0, 0.0, &grad_upwind, &grad_downwind, dCD, 0.0, 0.0, nullptr, + * true); + * @endcode + */ T limit(const T & phi_upwind, const T & phi_downwind, const VectorValue * grad_phi_upwind, const VectorValue * grad_phi_downwind, const RealVectorValue & dCD, - const T &, - const T &, - const FaceInfo *, - const bool &) const override final + const T & /* max_value */, + const T & /* min_value */, + const FaceInfo * /* fi */, + const bool & /* fi_elem_is_upwind */) const override final { mooseAssert(grad_phi_upwind, "min-mod limiter requires a gradient"); + // Compute gradient ratio coefficient T r_f; if (grad_phi_downwind) // compute full slope-reconstruction limiter @@ -42,12 +81,31 @@ class MinModLimiter : public Limiter else // compute upwind slope reconstruction limiter r_f = Moose::FV::rF(phi_upwind, phi_downwind, *grad_phi_upwind, dCD); - // Dummy addition to avoid new nonzeros + // Return limiter value return 0 * r_f + std::max(T(0), std::min(T(1), r_f)); } + + /** + * @brief Indicates whether the Min-Mod limiter is constant. + * + * This method always returns `false` as the Min-Mod limiter is not a constant limiter. + * + * @return `false` indicating the Min-Mod limiter is not constant. + */ bool constant() const override final { return false; } + + /** + * @brief Returns the interpolation method used by the Min-Mod limiter. + * + * This method returns `InterpMethod::MinMod`, indicating the interpolation method used. + * + * @return The interpolation method `InterpMethod::MinMod`. + */ InterpMethod interpMethod() const override final { return InterpMethod::MinMod; } + /** + * @brief Default constructor for the Min-Mod limiter. + */ MinModLimiter() = default; }; } diff --git a/framework/include/limiters/QUICKLimiter.h b/framework/include/limiters/QUICKLimiter.h index ffdc51afae78..592f607286b6 100644 --- a/framework/include/limiters/QUICKLimiter.h +++ b/framework/include/limiters/QUICKLimiter.h @@ -17,62 +17,117 @@ namespace Moose namespace FV { /** - * Implements a limiter which reproduces the QUICK scheme, defined by - * $\beta(r_f) = \frac{3+r_f}{4}$ + * @brief Implements the QUICK limiter for flux limiting in numerical methods. + * + * The QUICK (Quadratic Upstream Interpolation for Convective Kinematics) limiter is used to reduce + * numerical oscillations and enforce monotonicity in computational fluid dynamics (CFD) and other + * numerical simulations. This limiter ensures Total Variation Diminishing (TVD) compliance. + * + * The limiter function is derived from the following equations: + * + * 1. Calculation of the gradient ratio coefficient \( r_f \): + * \f[ + * r_f = \begin{cases} + * \text{if grad\_phi\_downwind is not null, use } \text{rf\_grad}(\nabla \phi_{\text{upwind}}, + * \nabla \phi_{\text{downwind}}, \mathbf{dCD}) \\ \text{otherwise, use } + * \text{rF}(\phi_{\text{upwind}}, \phi_{\text{downwind}}, \nabla \phi_{\text{upwind}}, + * \mathbf{dCD}) \end{cases} \f] + * + * 2. QUICK limiter formula ensuring TVD compliance: + * \f[ + * \beta(r_f) = \min\left(\beta, \max\left(\min\left(\min\left(\frac{1 + 3.0 r_f}{4.0}, 2.0 + * r_f\right), 2.0\right), 0.0\right)\right) \f] where \(\beta = 1.0\). + * + * @tparam T The data type of the scalar values and the return type. */ template class QUICKLimiter : public Limiter { public: + /** + * @brief Computes the limited value using the QUICK limiter. + * + * This method overrides the pure virtual `limit` method in the base `Limiter` class. + * It calculates the flux limiting ratio based on the QUICK limiter formula. + * + * @param phi_upwind Scalar value at the upwind location. + * @param phi_downwind Scalar value at the downwind location. + * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. + * @param grad_phi_downwind Pointer to the gradient vector at the downwind location. + * @param dCD A constant direction vector representing the direction of the cell face. + * @return The computed flux limiting ratio. + * + * This method performs the following steps: + * 1. Asserts that the upwind gradient pointer is not null. + * 2. Computes the gradient ratio coefficient \( r_f \) using the `rf_grad` method or `rF` method. + * 3. Applies the QUICK limiter formula to \( r_f \) to obtain the limited value, ensuring TVD + * compliance. + * 4. Returns the computed limited value. + * + * @example + * @code + * QUICKLimiter quick; + * VectorValue grad_upwind(0.1, 0.2, 0.3); + * VectorValue grad_downwind(0.4, 0.5, 0.6); + * RealVectorValue dCD(1.0, 0.0, 0.0); + * Real result = quick.limit(0.0, 0.0, &grad_upwind, &grad_downwind, dCD, 0.0, 0.0, nullptr, + * true); + * @endcode + */ T limit(const T & phi_upwind, const T & phi_downwind, const VectorValue * grad_phi_upwind, const VectorValue * grad_phi_downwind, const RealVectorValue & dCD, - const T &, - const T &, - const FaceInfo * fi, - const bool & fi_elem_is_upwind) const override final + const T & /* max_value */, + const T & /* min_value */, + const FaceInfo * /* fi */, + const bool & /* fi_elem_is_upwind */) const override final { mooseAssert(grad_phi_upwind, "QUICK limiter requires a gradient"); - const auto & w_f = fi_elem_is_upwind ? fi->gC() : (1. - fi->gC()); - const auto & phiCD = w_f * phi_upwind + (1.0 - w_f) * phi_downwind; - const auto & face_grad = w_f * (*grad_phi_upwind) + (1.0 - w_f) * (*grad_phi_downwind); - const auto & faceFlux = face_grad * fi->normal(); - - T phiU, phif; - - if (faceFlux > 0) - { - phiU = phi_upwind; - phif = 0.5 * (phiCD + phiU + (1 - w_f) * (dCD * (*grad_phi_upwind))); - } - else - { - phiU = phi_downwind; - phif = 0.5 * (phiCD + phiU - w_f * (dCD * (*grad_phi_downwind))); - } - - const auto & s = phiCD - phiU; - if (s >= 0) + // Compute gradient ratio coefficient + T limiter; + if (grad_phi_downwind) // compute full slope-reconstruction limiter for weakly-compressible flow { - return s + 1e-10; + const auto & r_f = this->rf_grad(grad_phi_upwind, grad_phi_downwind, dCD); + const auto & beta = T(1.0); // Ensures TVD compliance + limiter = + 0 * r_f + + std::min(beta, + std::max(std::min(std::min((1 + 3.0 * r_f) / 4.0, 2.0 * r_f), T(2.0)), T(0.0))); } - else + else // compute upwind slope reconstruction limiter for compressible flow { - return s - 1e-10; + const auto & r_f = Moose::FV::rF(phi_upwind, phi_downwind, *grad_phi_upwind, dCD); + limiter = (3.0 * r_f) / 4.0; } - // Calculate the effective limiter for the QUICK interpolation - const auto quick = (phif - phiU) / s; - - // Limit the limiter between upwind and downwind - return std::max(std::min(quick, T(2)), T(0)); + // Return limiter value + return limiter; } + + /** + * @brief Indicates whether the QUICK limiter is constant. + * + * This method always returns `false` as the QUICK limiter is not a constant limiter. + * + * @return `false` indicating the QUICK limiter is not constant. + */ bool constant() const override final { return false; } + + /** + * @brief Returns the interpolation method used by the QUICK limiter. + * + * This method returns `InterpMethod::QUICK`, indicating the interpolation method used. + * + * @return The interpolation method `InterpMethod::QUICK`. + */ InterpMethod interpMethod() const override final { return InterpMethod::QUICK; } + /** + * @brief Default constructor for the QUICK limiter. + */ QUICKLimiter() = default; }; } diff --git a/framework/include/limiters/SOULimiter.h b/framework/include/limiters/SOULimiter.h index d93b5013622e..db94adbc9a56 100644 --- a/framework/include/limiters/SOULimiter.h +++ b/framework/include/limiters/SOULimiter.h @@ -17,18 +17,66 @@ namespace Moose namespace FV { /** - * Implements a limiter which reproduces the second-order-upwind scheme, defined by - * $\beta(r_f) = r_f$ + * @brief Implements the Second-Order Upwind (SOU) limiter for flux limiting in numerical methods. + * + * The SOU limiter is used for reproducing the second-order-upwind scheme. The limiter function + * $\beta(delta_max)$ is defined as: + * + * \f[ + * \beta(delta_max) = min(1, delta_face/delta_max) + * \f] + * + * where: + * \( delta_max \) is the maximum variation admited for the computatioanl stencil + * \( delta_max \) is the variation at the face computed with SOU + * + * @tparam T The data type of the scalar values and the return type. */ template class SOULimiter : public Limiter { public: - T limit(const T &, - const T &, + /** + * @brief Computes the limited value using the SOU limiter. + * + * This method overrides the pure virtual `limit` method in the base `Limiter` class. + * It calculates the flux limiting ratio based on the SOU limiter formula. + * + * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. + * @param grad_phi_downwind Pointer to the gradient vector at the downwind location. + * @param dCD A constant direction vector representing the direction of the cell face. + * @param max_value The maximum value in the current element. + * @param min_value The minimum value in the current element. + * @param fi Pointer to the face information structure. + * @param fi_elem_is_upwind Boolean flag indicating if the current element is upwind. + * @return The computed flux limiting ratio. + * + * This method performs the following steps: + * 1. Asserts that the upwind gradient pointer is not null. + * 2. Handles initialization conflict by determining the face centroid and the appropriate cell + * centroid. + * 3. Computes the absolute delta value at the face. + * 4. Computes the delta between the two elements. + * 5. Returns the limited value based on the computed deltas. + * + * @example + * @code + * SOULimiter sou; + * VectorValue grad_upwind(0.1, 0.2, 0.3); + * RealVectorValue dCD(1.0, 0.0, 0.0); + * Real max_value = 1.0; + * Real min_value = 0.0; + * FaceInfo fi; + * bool fi_elem_is_upwind = true; + * Real result = sou.limit(0.0, 0.0, &grad_upwind, nullptr, dCD, max_value, min_value, &fi, + * fi_elem_is_upwind); + * @endcode + */ + T limit(const T & phi_upwind, + const T & phi_downwind, const VectorValue * grad_phi_upwind, - const VectorValue *, - const RealVectorValue &, + const VectorValue * grad_phi_downwind, + const RealVectorValue & dCD, const T & max_value, const T & min_value, const FaceInfo * fi, @@ -36,25 +84,55 @@ class SOULimiter : public Limiter { mooseAssert(grad_phi_upwind, "SOU limiter requires a gradient"); - // Determine the face centroid and the appropriate cell centroid - const auto & face_centroid = fi->faceCentroid(); - const auto & cell_centroid = fi_elem_is_upwind ? fi->elemCentroid() : fi->neighborCentroid(); + T limiter; + if (!grad_phi_downwind) + { + // Determine the face centroid and the appropriate cell centroid + const auto & face_centroid = fi->faceCentroid(); + const auto & cell_centroid = fi_elem_is_upwind ? fi->elemCentroid() : fi->neighborCentroid(); - // Compute the abs delta value at the face - const auto & delta_face = std::abs((*grad_phi_upwind) * (face_centroid - cell_centroid)); + // Compute the abs delta value at the face + const auto & delta_face = + std::abs((*grad_phi_upwind) * (face_centroid - cell_centroid)) + 1e-10; - // Compute the delta between the two elements - const auto & elem_delta = max_value - min_value; + // Compute the delta between the two elements + const auto & elem_delta = max_value - min_value; - // return the limited value - if (elem_delta > 1e-10) - return std::min(1.0, elem_delta / delta_face); + // Return the limited value + if (elem_delta > 1e-10) + limiter = std::min(1.0, elem_delta / delta_face); + else + limiter = T(1.0); + } else - return 1.0; + { + const auto & r_f = Moose::FV::rF(phi_upwind, phi_downwind, *grad_phi_upwind, dCD); + limiter = r_f; + } + return limiter; } + + /** + * @brief Indicates whether the SOU limiter is constant. + * + * This method always returns `false` as the SOU limiter is not a constant limiter. + * + * @return `false` indicating the SOU limiter is not constant. + */ bool constant() const override final { return false; } + + /** + * @brief Returns the interpolation method used by the SOU limiter. + * + * This method returns `InterpMethod::SOU`, indicating the interpolation method used. + * + * @return The interpolation method `InterpMethod::SOU`. + */ InterpMethod interpMethod() const override final { return InterpMethod::SOU; } + /** + * @brief Default constructor for the SOU limiter. + */ SOULimiter() = default; }; } diff --git a/framework/include/limiters/VenkatakrishnanLimiter.h b/framework/include/limiters/VenkatakrishnanLimiter.h index 514cc7ad305f..f08b94cd71f7 100644 --- a/framework/include/limiters/VenkatakrishnanLimiter.h +++ b/framework/include/limiters/VenkatakrishnanLimiter.h @@ -17,18 +17,84 @@ namespace Moose namespace FV { /** - * Implements a limiter which reproduces the second-order-upwind scheme, defined by - * $\beta(r_f) = r_f$ + * @brief Implements the Venkatakrishnan limiter for flux limiting. + * + * The Venkatakrishnan limiter is used to reduce numerical oscillations and enforce monotonicity + * in computational fluid dynamics (CFD) and other numerical simulations. This limiter adjusts + * the flux limiting ratio based on face centroids and cell centroids, handling different gradient + * conditions. + * + * The limiter function is derived from the following equations: + * + * 1. Calculation of the face delta: + * \f[ + * \Delta_{\text{face}} = \nabla \phi_{\text{upwind}} \cdot (\mathbf{x}_{\text{face}} - + * \mathbf{x}_{\text{cell}}) \f] + * + * 2. Calculation of the deltas for maximum and minimum values relative to the upwind value with a + * small perturbation to avoid division by zero: \f[ \Delta_{\text{max}} = \phi_{\text{max}} - + * \phi_{\text{upwind}} + 1e-10 \f] \f[ \Delta_{\text{min}} = \phi_{\text{min}} - + * \phi_{\text{upwind}} + 1e-10 \f] + * + * 3. Calculation of the gradient ratio coefficient \( r_f \): + * \f[ + * r_f = \begin{cases} + * \frac{\Delta_{\text{face}}}{\Delta_{\text{max}}} & \text{if } \Delta_{\text{face}} \geq 0 \\ + * \frac{\Delta_{\text{face}}}{\Delta_{\text{min}}} & \text{otherwise} + * \end{cases} + * \f] + * + * 4. Venkatakrishnan limiter formula: + * \f[ + * \beta(r_f) = \frac{2 r_f + 1.0}{r_f (2 r_f + 1.0) + 1.0} + * \f] + * + * @tparam T The data type of the scalar values and the return type. */ template class VenkatakrishnanLimiter : public Limiter { public: + /** + * @brief Computes the limited value using the Venkatakrishnan limiter. + * + * This method overrides the pure virtual `limit` method in the base `Limiter` class. + * It calculates the flux limiting ratio based on the Venkatakrishnan limiter formula. + * + * @param phi_upwind Scalar value at the upwind location. + * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. + * @param max_value The maximum value in the current element. + * @param min_value The minimum value in the current element. + * @param fi Pointer to the face information structure. + * @param fi_elem_is_upwind Boolean flag indicating if the current element is upwind. + * @return The computed flux limiting ratio. + * + * This method performs the following steps: + * 1. Determines the face centroid and the appropriate cell centroid. + * 2. Computes the delta value at the face. + * 3. Computes deltas for the maximum and minimum values relative to the upwind value. + * 4. Computes the ratio \( r_f \) based on the sign of the delta face value. + * 5. Applies the Venkatakrishnan limiter formula to \( r_f \) to obtain the limited value. + * 6. Returns the computed limited value. + * + * @example + * @code + * VenkatakrishnanLimiter venkatakrishnan; + * VectorValue grad_upwind(0.1, 0.2, 0.3); + * RealVectorValue dCD(1.0, 0.0, 0.0); + * Real max_value = 1.0; + * Real min_value = 0.0; + * FaceInfo fi; + * bool fi_elem_is_upwind = true; + * Real result = venkatakrishnan.limit(0.0, 0.0, &grad_upwind, nullptr, dCD, max_value, min_value, + * &fi, fi_elem_is_upwind); + * @endcode + */ T limit(const T & phi_upwind, - const T &, + const T & /* phi_downwind */, const VectorValue * grad_phi_upwind, - const VectorValue *, - const RealVectorValue &, + const VectorValue * /* grad_phi_downwind */, + const RealVectorValue & /* dCD */, const T & max_value, const T & min_value, const FaceInfo * fi, @@ -38,15 +104,36 @@ class VenkatakrishnanLimiter : public Limiter const auto cell_centroid = fi_elem_is_upwind ? fi->elemCentroid() : fi->neighborCentroid(); const auto delta_face = (*grad_phi_upwind) * (face_centroid - cell_centroid); - const auto delta_max = max_value - phi_upwind + 1e-10; - const auto delta_min = min_value - phi_upwind + 1e-10; + const auto delta_max = std::abs(max_value - phi_upwind) + 1e-10; + const auto delta_min = std::abs(min_value - phi_upwind) + 1e-10; - return delta_face >= 0 ? delta_face / delta_max : delta_face / delta_min; + const auto rf = + delta_face >= 0 ? std::abs(delta_face) / delta_max : std::abs(delta_face) / delta_min; + return (2 * rf + 1.0) / (rf * (2 * rf + 1.0) + 1.0); } + + /** + * @brief Indicates whether the Venkatakrishnan limiter is constant. + * + * This method always returns `false` as the Venkatakrishnan limiter is not a constant limiter. + * + * @return `false` indicating the Venkatakrishnan limiter is not constant. + */ bool constant() const override final { return false; } + + /** + * @brief Returns the interpolation method used by the Venkatakrishnan limiter. + * + * This method returns `InterpMethod::SOU`, indicating the interpolation method used. + * + * @return The interpolation method `InterpMethod::SOU`. + */ InterpMethod interpMethod() const override final { return InterpMethod::SOU; } + /** + * @brief Default constructor for the Venkatakrishnan limiter. + */ VenkatakrishnanLimiter() = default; }; } diff --git a/framework/include/utils/MathFVUtils.h b/framework/include/utils/MathFVUtils.h index fb9175235b41..95234d19b54e 100644 --- a/framework/include/utils/MathFVUtils.h +++ b/framework/include/utils/MathFVUtils.h @@ -473,12 +473,22 @@ interpCoeffs(const Limiter & limiter, const T & phi_upwind, const T & phi_downwind, const VectorValue * const grad_phi_upwind, + const VectorValue * const grad_phi_face, + const T & max_value, + const T & min_value, const FaceInfo & fi, const bool fi_elem_is_upwind) { // Using beta, w_f, g nomenclature from Greenshields - const auto beta = limiter( - phi_upwind, phi_downwind, grad_phi_upwind, fi_elem_is_upwind ? fi.dCN() : Point(-fi.dCN())); + const auto beta = limiter(phi_upwind, + phi_downwind, + grad_phi_upwind, + grad_phi_face, + fi_elem_is_upwind ? fi.dCN() : Point(-fi.dCN()), + max_value, + min_value, + &fi, + fi_elem_is_upwind); const auto w_f = fi_elem_is_upwind ? fi.gC() : (1. - fi.gC()); @@ -501,7 +511,15 @@ interpolate(const Limiter & limiter, const FaceInfo & fi, const bool fi_elem_is_upwind) { - auto pr = interpCoeffs(limiter, phi_upwind, phi_downwind, grad_phi_upwind, fi, fi_elem_is_upwind); + auto pr = interpCoeffs(limiter, + phi_upwind, + phi_downwind, + grad_phi_upwind, + /*grad_phi_face*/ static_cast*>(nullptr), + /* max_value */ Scalar(0.0), + /* min_value */ Scalar(0.0), + fi, + fi_elem_is_upwind); return pr.first * phi_upwind + pr.second * phi_downwind; } @@ -551,7 +569,7 @@ interpolate(const Limiter & limiter, * @param phi_upwind The scalar value at the upwind location. * @param phi_downwind The scalar value at the downwind location. * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. - * @param grad_phi_downwind Pointer to the gradient vector at the downwind location. + * @param grad_phi_face Pointer to the gradient vector at the face location. * @param fi FaceInfo object containing geometric details such as face centroid and cell centroids. * @param fi_elem_is_upwind Boolean indicating if the face info element is upwind. * @param max_value The maximum allowable value. @@ -575,43 +593,324 @@ fullLimitedInterpolation(const Limiter & limiter, const T & phi_upwind, const T & phi_downwind, const VectorValue * const grad_phi_upwind, - const VectorValue * const grad_phi_downwind, - const FaceInfo & fi, - const bool fi_elem_is_upwind, + const VectorValue * const grad_phi_face, const T & max_value, - const T & min_value) + const T & min_value, + const FaceArg & face) { // Compute the direction vector based on whether the current element is upwind - const auto dCD = fi_elem_is_upwind ? fi.dCN() : Point(-fi.dCN()); + const auto dCD = face.elem_is_upwind ? face.fi->dCN() : Point(-face.fi->dCN()); // Compute the flux limiting ratio using the specified limiter const auto beta = limiter(phi_upwind, phi_downwind, grad_phi_upwind, - grad_phi_downwind, + grad_phi_face, dCD, max_value, min_value, - &fi, - fi_elem_is_upwind); + face.fi, + face.elem_is_upwind); // Determine the face centroid and the appropriate cell centroid - const auto & face_centroid = fi.faceCentroid(); - const auto & cell_centroid = fi_elem_is_upwind ? fi.elemCentroid() : fi.neighborCentroid(); + const auto & face_centroid = face.fi->faceCentroid(); + const auto & cell_centroid = + face.elem_is_upwind ? face.fi->elemCentroid() : face.fi->neighborCentroid(); // Compute the delta value at the face - const auto & delta_face = (*grad_phi_upwind) * (face_centroid - cell_centroid); + T delta_face; + if (face.limiter_type == LimiterType::Venkatakrishnan || face.limiter_type == LimiterType::SOU) + delta_face = (*grad_phi_upwind) * (face_centroid - cell_centroid); + else + delta_face = (*grad_phi_face) * (face_centroid - cell_centroid); // Return the interpolated value return phi_upwind + beta * delta_face; } /** - * Interpolates with a limiter and a face argument - * @return a pair of pairs. The first pair corresponds to the interpolation coefficients with the - * first corresponding to the face information element and the second corresponding to the face - * information neighbor. This pair should sum to unity. The second pair corresponds to the face - * information functor element value and neighbor + * @brief Computes the minimum and maximum scalar values in a two-cell stencil around a given face + * in a computational grid. + * + * This function calculates the minimum and maximum values within a two-cell stencil. The stencil + * includes the immediate neighboring elements of the face's associated element and the neighboring + * elements of those neighbors. It evaluates the values using a provided functor and accounts for + * the valid (non-null) neighbors. + * + * @tparam T The data type for the values being computed. This is typically a scalar type. + * @tparam FEK Enumeration type FunctorEvaluationKind with a default value of + * FunctorEvaluationKind::Value. This determines the kind of evaluation the functor will perform. + * @tparam Enable A type trait used for SFINAE (Substitution Failure Is Not An Error) to ensure that + * T is a valid scalar type as determined by ScalarTraits. + * + * @param functor An object of a functor class derived from FunctorBase. This object provides the + * genericEvaluate method to compute the value at a given element and time. + * @param face An argument representing the face in the computational domain. The face provides + * access to neighboring elements via neighbor_ptr_range(). + * @param time An argument representing the state or time at which the evaluation is performed. + * + * @return std::pair A pair containing the minimum and maximum values computed across the + * two-cell stencil. The first element is the maximum value, and the second element is the minimum + * value. + * + * This function performs the following steps: + * 1. Initializes max_value to 0 and min_value to a large value (1e10). + * 2. Iterates over the direct neighbors of the element associated with the face. + * - If a neighbor is valid (not null), it evaluates the functor at that neighbor and updates + * max_value and min_value. + * 3. Iterates over the neighbors of the neighbors. + * - Similar to the first loop, it evaluates the functor at valid neighbors and updates max_value + * and min_value. + * 4. Returns a pair containing the computed max_value and min_value. + * + * Usage: + * This function is typically used in the finite volume methods for min-max computations over + * stencils (neighborhoods). It helps compute the limiting for limited second order upwind at the + * faces. + */ +template ::value>::type> +std::pair +computeMinMaxValue(const FunctorBase & functor, const FaceArg & face, const StateArg & time) +{ + // Initialize max_value to 0 and min_value to a large value (1e10) + T max_value(0), min_value(1e10); + + // Iterate over the direct neighbors of the element associated with the face + for (auto neighbor : (*face.fi).elem().neighbor_ptr_range()) + { + // If not a valid neighbor, skip to the next one + if (neighbor == nullptr) + continue; + + // Evaluate the functor at the neighbor and update max_value and min_value + const ElemArg local_cell_arg = {neighbor, false}; + const auto value = functor.template genericEvaluate(local_cell_arg, time); + max_value = std::max(max_value, value); + min_value = std::min(min_value, value); + } + + // Iterate over the neighbors of the neighbor + for (auto neighbor : (*face.fi).neighbor().neighbor_ptr_range()) + { + // If not a valid neighbor, skip to the next one + if (neighbor == nullptr) + continue; + + // Evaluate the functor at the neighbor and update max_value and min_value + const ElemArg local_cell_arg = {neighbor, false}; + const auto value = functor.template genericEvaluate(local_cell_arg, time); + max_value = std::max(max_value, value); + min_value = std::min(min_value, value); + } + + // Return a pair containing the computed maximum and minimum values + return std::make_pair(max_value, min_value); +} + +/** + * @brief Computes the minimum and maximum scalar values of a specific component in a two-cell + * stencil around a given face in a computational grid. + * + * This function calculates the minimum and maximum values of a specified component within a + * two-cell stencil. The stencil includes the immediate neighboring elements of the face's + * associated element and the neighboring elements of those neighbors. It evaluates the values using + * a provided functor and accounts for the valid (non-null) neighbors. + * + * @tparam T The data type for the values being computed. This is typically a scalar type. + * + * @param functor An object of a functor class derived from FunctorBase>. This object + * provides the operator() method to compute the value at a given element and time. + * @param face An argument representing the face in the computational domain. The face provides + * access to neighboring elements via neighbor_ptr_range(). + * @param time An argument representing the state or time at which the evaluation is performed. + * @param component An unsigned integer representing the specific component of the vector to be + * evaluated. + * + * @return std::pair A pair containing the minimum and maximum values of the specified + * component computed across the two-cell stencil. The first element is the maximum value, and the + * second element is the minimum value. + * + * This function performs the following steps: + * 1. Initializes max_value to 0 and min_value to a large value (1e10). + * 2. Iterates over the direct neighbors of the element associated with the face. + * - If a neighbor is valid (not null), it evaluates the functor at that neighbor for the + * specified component and updates max_value and min_value. + * 3. Iterates over the neighbors of the neighbors. + * - Similar to the first loop, it evaluates the functor at valid neighbors for the specified + * component and updates max_value and min_value. + * 4. Returns a pair containing the computed max_value and min_value. + * + * Usage: + * This function is typically used in the finite volume methods for min-max computations over + * stencils (neighborhoods). It helps compute the limiting for limited second order upwind at the + * faces. + */ +template +std::pair +computeMinMaxValue(const FunctorBase> & functor, + const FaceArg & face, + const StateArg & time, + const unsigned int & component) +{ + // Initialize max_value to 0 and min_value to a large value (1e10) + T max_value(0), min_value(1e10); + + // Iterate over the direct neighbors of the element associated with the face + for (auto neighbor : (*face.fi).elem().neighbor_ptr_range()) + { + // If not a valid neighbor, skip to the next one + if (neighbor == nullptr) + continue; + + // Evaluate the functor at the neighbor for the specified component and update max_value and + // min_value + const ElemArg local_cell_arg = {neighbor, false}; + const auto value = functor(local_cell_arg, time)(component); + max_value = std::max(max_value, value); + min_value = std::min(min_value, value); + } + + // Iterate over the neighbors of the neighbor associated with the face + for (auto neighbor : (*face.fi).neighbor().neighbor_ptr_range()) + { + // If not a valid neighbor, skip to the next one + if (neighbor == nullptr) + continue; + + // Evaluate the functor at the neighbor for the specified component and update max_value and + // min_value + const ElemArg local_cell_arg = {neighbor, false}; + const auto value = functor(local_cell_arg, time)(component); + max_value = std::max(max_value, value); + min_value = std::min(min_value, value); + } + + // Return a pair containing the computed maximum and minimum values + return std::make_pair(max_value, min_value); +} + +/** + * @brief Computes the minimum and maximum scalar values of a specific component in a two-cell + * stencil around a given face in a computational grid. + * + * This function calculates the minimum and maximum values of a specified component within a + * two-cell stencil. The stencil includes the immediate neighboring elements of the face's + * associated element and the neighboring elements of those neighbors. It evaluates the values using + * a provided functor and accounts for the valid (non-null) neighbors. + * + * @tparam T The data type for the values being computed. This is typically a scalar type. + * + * @param functor An object of a functor class derived from FunctorBase. This object provides the + * operator() method to compute the value at a given element and time. + * @param face An argument representing the face in the computational domain. The face provides + * access to neighboring elements via neighbor_ptr_range(). + * @param time An argument representing the state or time at which the evaluation is performed. + * @param component An unsigned integer representing the specific component of the container to be + * evaluated. + * + * @return std::pair A pair containing the minimum and maximum values of the specified + * component computed across the two-cell stencil. The first element is the maximum value, and the + * second element is the minimum value. + * + * This function performs the following steps: + * 1. Initializes max_value to 0 and min_value to a large value (1e10). + * 2. Iterates over the direct neighbors of the element associated with the face. + * - If a neighbor is valid (not null), it evaluates the functor at that neighbor for the + * specified component and updates max_value and min_value. + * 3. Iterates over the neighbors of the neighbors. + * - Similar to the first loop, it evaluates the functor at valid neighbors for the specified + * component and updates max_value and min_value. + * 4. Returns a pair containing the computed max_value and min_value. + * + * Usage: + * This function is typically used in the finite volume methods for min-max computations over + * stencils (neighborhoods). It helps compute the limiting for limited second order upwind at the + * faces. + */ +template +std::pair +containerComputeMinMaxValue(const FunctorBase & functor, + const FaceArg & face, + const StateArg & time, + const unsigned int & component) +{ + // Initialize max_value to 0 and min_value to a large value (1e10) + T max_value(0), min_value(1e10); + + // Iterate over the direct neighbors of the element associated with the face + for (auto neighbor : (*face.fi).elem().neighbor_ptr_range()) + { + // If not a valid neighbor, skip to the next one + if (neighbor == nullptr) + continue; + + // Evaluate the functor at the neighbor for the specified component and update max_value and + // min_value + const ElemArg local_cell_arg = {neighbor, false}; + const auto value = functor(local_cell_arg, time)[component]; + max_value = std::max(max_value, value); + min_value = std::min(min_value, value); + } + + // Iterate over the neighbors of the neighbor associated with the face + for (auto neighbor : (*face.fi).neighbor().neighbor_ptr_range()) + { + // If not a valid neighbor, skip to the next one + if (neighbor == nullptr) + continue; + + // Evaluate the functor at the neighbor for the specified component and update max_value and + // min_value + const ElemArg local_cell_arg = {neighbor, false}; + const auto value = functor(local_cell_arg, time)[component]; + max_value = std::max(max_value, value); + min_value = std::min(min_value, value); + } + + // Return a pair containing the computed maximum and minimum values + return std::make_pair(max_value, min_value); +} + +/** + * @brief Interpolates with a limiter and a face argument. + * + * This function interpolates values using a specified limiter and face argument. It evaluates the + * values at upwind and downwind locations and computes interpolation coefficients and advected + * values. + * + * @tparam T The data type for the values being interpolated. This is typically a scalar type. + * @tparam FEK Enumeration type FunctorEvaluationKind with a default value of + * FunctorEvaluationKind::Value. This determines the kind of evaluation the functor will perform. + * @tparam Enable A type trait used for SFINAE (Substitution Failure Is Not An Error) to ensure that + * T is a valid scalar type as determined by ScalarTraits. + * + * @param functor An object of a functor class derived from FunctorBase. This object provides the + * genericEvaluate method to compute the value at a given element and time. + * @param face An argument representing the face in the computational domain. The face provides + * access to neighboring elements and limiter type. + * @param time An argument representing the state or time at which the evaluation is performed. + * + * @return std::pair, std::pair> A pair of pairs. + * - The first pair corresponds to the interpolation coefficients, with the + * first value corresponding to the face information element and the second to the face information + * neighbor. This pair should sum to unity. + * - The second pair corresponds to the face information functor element + * value and neighbor value. + * + * This function performs the following steps: + * 1. Asserts that the face information is non-null. + * 2. Constructs a limiter based on the face limiter type. + * 3. Determines the upwind and downwind arguments based on the face element. + * 4. Evaluates the functor at the upwind and downwind locations. + * 5. Computes the interpolation coefficients using the specified limiter. + * 6. If necessary, computes the gradient and min-max values for certain limiter types. + * 7. Returns the interpolation coefficients and advected values. + * + * Usage: + * This function is used for interpolating values at faces in a finite volume method, ensuring that + * the interpolation adheres to the constraints imposed by the limiter. */ template , std::pair> interpCoeffsAndAdvected(const FunctorBase & functor, const FaceArg & face, const StateArg & time) { + // Ensure only supported FunctorEvaluationKinds are used static_assert((FEK == FunctorEvaluationKind::Value) || (FEK == FunctorEvaluationKind::Dot), "Only Value and Dot evaluations currently supported"); + // Determine the gradient evaluation kind constexpr FunctorEvaluationKind GFEK = FunctorGradientEvaluationKind::value; typedef typename FunctorBase::GradientType GradientType; static const GradientType zero(0); + // Assert that the face information is non-null mooseAssert(face.fi, "this must be non-null"); + + // Construct the limiter based on the face limiter type const auto limiter = Limiter::value_type>::build(face.limiter_type); + // Determine upwind and downwind arguments based on the face element const auto upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor(); const auto downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem(); + + // Evaluate the functor at the upwind and downwind locations auto phi_upwind = functor.template genericEvaluate(upwind_arg, time); auto phi_downwind = functor.template genericEvaluate(downwind_arg, time); + // Initialize the interpolation coefficients std::pair interp_coeffs; + + // Compute interpolation coefficients for Upwind or CentralDifference limiters if (face.limiter_type == LimiterType::Upwind || face.limiter_type == LimiterType::CentralDifference) - interp_coeffs = - interpCoeffs(*limiter, phi_upwind, phi_downwind, &zero, *face.fi, face.elem_is_upwind); + { + interp_coeffs = interpCoeffs(*limiter, + phi_upwind, + phi_downwind, + &zero, + &zero, + T(0.0), + T(0.0), + *face.fi, + face.elem_is_upwind); + } else { - const auto grad_phi_upwind = functor.template genericEvaluate(upwind_arg, time); - interp_coeffs = interpCoeffs( - *limiter, phi_upwind, phi_downwind, &grad_phi_upwind, *face.fi, face.elem_is_upwind); + // Determine the time argument for the limiter + auto * time_arg = face.state_limiter; + if (!time_arg) + { + static Moose::StateArg temp_state(0, Moose::SolutionIterationType::Time); + time_arg = &temp_state; + } + + T max_value(0.0), min_value(1e10); + + // Compute min-max values for min-max limiters + if (face.limiter_type == LimiterType::Venkatakrishnan || face.limiter_type == LimiterType::SOU) + { + std::tie(max_value, min_value) = computeMinMaxValue(functor, face, *time_arg); + } + + // Evaluate the gradient of the functor at the upwind and downwind locations + const auto grad_phi_upwind = functor.template genericEvaluate(upwind_arg, *time_arg); + const auto grad_phi_face = functor.template genericEvaluate(face, *time_arg); + + // Compute the interpolation coefficients using the specified limiter + interp_coeffs = interpCoeffs(*limiter, + phi_upwind, + phi_downwind, + &grad_phi_upwind, + &grad_phi_face, + max_value, + min_value, + *face.fi, + face.elem_is_upwind); } + // Return the interpolation coefficients and advected values if (face.elem_is_upwind) return std::make_pair(std::move(interp_coeffs), std::make_pair(std::move(phi_upwind), std::move(phi_downwind))); @@ -655,49 +1002,46 @@ interpCoeffsAndAdvected(const FunctorBase & functor, const FaceArg & face, co std::make_pair(std::move(phi_downwind), std::move(phi_upwind))); } -// Utility function to compute the min-max values in a two-cell stencil -template ::value>::type> -std::pair -computeMinMaxValue(const FunctorBase & functor, const FaceArg & face, const StateArg & time) -{ - T max_value(0), min_value(1e10); - for (auto neighbor : (*face.fi).elem().neighbor_ptr_range()) - { - // If not a valid neighbor - if (neighbor == nullptr) - continue; - else - { - const ElemArg local_cell_arg = {neighbor, false}; - const auto value = functor.template genericEvaluate(local_cell_arg, time); - max_value = std::max(max_value, value); - min_value = std::min(min_value, value); - } - } - for (auto neighbor : (*face.fi).neighbor().neighbor_ptr_range()) - { - // If not a valid neighbor - if (neighbor == nullptr) - continue; - else - { - const ElemArg local_cell_arg = {neighbor, false}; - const auto value = functor.template genericEvaluate(local_cell_arg, time); - max_value = std::max(max_value, value); - min_value = std::min(min_value, value); - } - } - return std::make_pair(max_value, min_value); -} - +/** + * @brief Interpolates values using a specified functor and face argument. + * + * This function interpolates values at faces in a computational grid using a specified functor, + * face argument, and evaluation kind. It handles different limiter types and performs + * interpolation accordingly. + * + * @tparam T The data type for the values being interpolated. This is typically a scalar type. + * @tparam FEK Enumeration type FunctorEvaluationKind with a default value of + * FunctorEvaluationKind::Value. This determines the kind of evaluation the functor will perform. + * @tparam Enable A type trait used for SFINAE (Substitution Failure Is Not An Error) to ensure that + * T is a valid scalar type as determined by ScalarTraits. + * + * @param functor An object of a functor class derived from FunctorBase. This object provides the + * genericEvaluate method to compute the value at a given element and time. + * @param face An argument representing the face in the computational domain. The face provides + * access to neighboring elements and limiter type. + * @param time An argument representing the state or time at which the evaluation is performed. + * + * @return T The interpolated value at the face. + * + * This function performs the following steps: + * 1. Checks that only supported FunctorEvaluationKinds are used. + * 2. Handles central differencing separately as it supports skew correction. + * 3. For Upwind or CentralDifference limiters, computes interpolation coefficients and advected + * values. + * 4. For other limiter types, computes the gradient and min-max values if necessary, and performs + * full limited interpolation. + * + * Usage: + * This function is used for interpolating values at faces in a finite volume method, ensuring that + * the interpolation adheres to the constraints imposed by the limiter. + */ template ::value>::type> T interpolate(const FunctorBase & functor, const FaceArg & face, const StateArg & time) { + // Ensure only supported FunctorEvaluationKinds are used static_assert((FEK == FunctorEvaluationKind::Value) || (FEK == FunctorEvaluationKind::Dot), "Only Value and Dot evaluations currently supported"); @@ -709,101 +1053,112 @@ interpolate(const FunctorBase & functor, const FaceArg & face, const StateArg if (face.limiter_type == LimiterType::Upwind || face.limiter_type == LimiterType::CentralDifference) { + // Compute interpolation coefficients and advected values const auto [interp_coeffs, advected] = interpCoeffsAndAdvected(functor, face, time); + // Return the interpolated value return interp_coeffs.first * advected.first + interp_coeffs.second * advected.second; } else { - + // Determine the gradient evaluation kind constexpr FunctorEvaluationKind GFEK = FunctorGradientEvaluationKind::value; typedef typename FunctorBase::GradientType GradientType; static const GradientType zero(0); const auto & limiter = Limiter::value_type>::build(face.limiter_type); + // Determine upwind and downwind arguments based on the face element const auto & upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor(); const auto & downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem(); const auto & phi_upwind = functor.template genericEvaluate(upwind_arg, time); const auto & phi_downwind = functor.template genericEvaluate(downwind_arg, time); - const auto & time_arg = Moose::StateArg(1, Moose::SolutionIterationType::Time); + // Determine the time argument for the limiter + auto * time_arg = face.state_limiter; + if (!time_arg) + { + static Moose::StateArg temp_state(0, Moose::SolutionIterationType::Time); + time_arg = &temp_state; + } - // Min-Max value - T max_value, min_value; - std::tie(max_value, min_value) = computeMinMaxValue(functor, face, time_arg); + // Initialize min-max values + T max_value(0.0), min_value(1e10); + if (face.limiter_type == LimiterType::Venkatakrishnan || face.limiter_type == LimiterType::SOU) + std::tie(max_value, min_value) = computeMinMaxValue(functor, face, *time_arg); - const auto & grad_phi_upwind = functor.template genericEvaluate(upwind_arg, time_arg); - const auto & grad_phi_downwind = functor.template genericEvaluate(face, time_arg); + // Evaluate the gradient of the functor at the upwind and downwind locations + const auto & grad_phi_upwind = functor.template genericEvaluate(upwind_arg, *time_arg); + const auto & grad_phi_face = functor.template genericEvaluate(face, *time_arg); + // Perform full limited interpolation and return the interpolated value return fullLimitedInterpolation(*limiter, phi_upwind, phi_downwind, &grad_phi_upwind, - &grad_phi_downwind, - *face.fi, - face.elem_is_upwind, + &grad_phi_face, max_value, - min_value); - } -} - -// Utility function to compute the min-max values in a two-cell stencil -template -std::pair -computeMinMaxValue(const FunctorBase> & functor, - const FaceArg & face, - const StateArg & time, - const unsigned int & component) -{ - T max_value(0), min_value(1e10); - for (auto neighbor : (*face.fi).elem().neighbor_ptr_range()) - { - // If not a valid neighbor - if (neighbor == nullptr) - continue; - else - { - const ElemArg local_cell_arg = {neighbor, false}; - const auto value = functor(local_cell_arg, time)(component); - max_value = std::max(max_value, value); - min_value = std::min(min_value, value); - } - } - for (auto neighbor : (*face.fi).neighbor().neighbor_ptr_range()) - { - // If not a valid neighbor - if (neighbor == nullptr) - continue; - else - { - const ElemArg local_cell_arg = {neighbor, false}; - const auto value = functor(local_cell_arg, time)(component); - max_value = std::max(max_value, value); - min_value = std::min(min_value, value); - } + min_value, + face); } - return std::make_pair(max_value, min_value); } +/** + * @brief Interpolates vector values using a specified functor and face argument. + * + * This function interpolates vector values at faces in a computational grid using a specified + * functor, face argument, and limiter type. It handles different limiter types and performs + * interpolation accordingly. + * + * @tparam T The data type for the vector values being interpolated. This is typically a scalar + * type. + * + * @param functor An object of a functor class derived from FunctorBase>. This object + * provides the operator() method to compute the value at a given element and time. + * @param face An argument representing the face in the computational domain. The face provides + * access to neighboring elements and limiter type. + * @param time An argument representing the state or time at which the evaluation is performed. + * + * @return VectorValue The interpolated vector value at the face. + * + * This function performs the following steps: + * 1. Asserts that the face information is non-null. + * 2. Constructs a limiter based on the face limiter type. + * 3. Determines the upwind and downwind arguments based on the face element. + * 4. Evaluates the functor at the upwind and downwind locations. + * 5. Initializes the return vector value. + * 6. Computes the interpolation coefficients and advected values for each component. + * 7. If necessary, computes the gradient and min-max values for certain limiter types. + * + * Usage: + * This function is used for interpolating vector values at faces in a finite volume method, + * ensuring that the interpolation adheres to the constraints imposed by the limiter. + */ template VectorValue interpolate(const FunctorBase> & functor, const FaceArg & face, const StateArg & time) { + // Define a zero gradient vector for initialization static const VectorValue grad_zero(0); + // Assert that the face information is non-null mooseAssert(face.fi, "this must be non-null"); + + // Construct the limiter based on the face limiter type const auto limiter = Limiter::value_type>::build(face.limiter_type); + // Determine upwind and downwind arguments based on the face element const auto upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor(); const auto downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem(); auto phi_upwind = functor(upwind_arg, time); auto phi_downwind = functor(downwind_arg, time); + // Initialize the return vector value VectorValue ret; T coeff_upwind, coeff_downwind; + // Compute interpolation coefficients and advected values for Upwind or CentralDifference limiters if (face.limiter_type == LimiterType::Upwind || face.limiter_type == LimiterType::CentralDifference) { @@ -814,6 +1169,9 @@ interpolate(const FunctorBase> & functor, component_upwind, component_downwind, &grad_zero, + &grad_zero, + T(0.0), + T(0.0), *face.fi, face.elem_is_upwind); ret(i) = coeff_upwind * component_upwind + coeff_downwind * component_downwind; @@ -821,93 +1179,103 @@ interpolate(const FunctorBase> & functor, } else { - const auto & time_arg = Moose::StateArg(1, Moose::SolutionIterationType::Time); - const auto & grad_phi_upwind = functor.gradient(upwind_arg, time_arg); - const auto & grad_phi_downwind = functor.gradient(downwind_arg, time_arg); + // Determine the time argument for the limiter + auto * time_arg = face.state_limiter; + if (!time_arg) + { + static Moose::StateArg temp_state(0, Moose::SolutionIterationType::Time); + time_arg = &temp_state; + } + + // Evaluate the gradient of the functor at the upwind and downwind locations + const auto & grad_phi_upwind = functor.gradient(upwind_arg, *time_arg); + const auto & grad_phi_face = functor.gradient(face, *time_arg); + // Compute interpolation coefficients and advected values for each component for (unsigned int i = 0; i < LIBMESH_DIM; ++i) { const auto &component_upwind = phi_upwind(i), component_downwind = phi_downwind(i); - const VectorValue &grad_upwind = grad_phi_upwind.row(i), - grad_downwind = grad_phi_downwind.row(i); + const VectorValue &grad_upwind = grad_phi_upwind.row(i), grad_face = grad_phi_face.row(i); - // Min-Max value - T max_value, min_value; - std::tie(max_value, min_value) = computeMinMaxValue(functor, face, time_arg, i); + // Initialize min-max values + T max_value(0.0), min_value(1e10); + if (face.limiter_type == LimiterType::Venkatakrishnan || + face.limiter_type == LimiterType::SOU) + std::tie(max_value, min_value) = computeMinMaxValue(functor, face, *time_arg, i); + // Perform full limited interpolation for the component ret(i) = fullLimitedInterpolation(*limiter, component_upwind, component_downwind, &grad_upwind, - &grad_downwind, - *face.fi, - face.elem_is_upwind, + &grad_face, max_value, - min_value); + min_value, + face); } } + // Return the interpolated vector value return ret; } -// Utility function to compute the min-max values in a two-cell stencil -template -std::pair -containerComputeMinMaxValue(const FunctorBase & functor, - const FaceArg & face, - const StateArg & time, - const unsigned int & component) -{ - T max_value(0), min_value(1e10); - for (auto neighbor : (*face.fi).elem().neighbor_ptr_range()) - { - // If not a valid neighbor - if (neighbor == nullptr) - continue; - else - { - const ElemArg local_cell_arg = {neighbor, false}; - const auto value = functor(local_cell_arg, time)[component]; - max_value = std::max(max_value, value); - min_value = std::min(min_value, value); - } - } - for (auto neighbor : (*face.fi).neighbor().neighbor_ptr_range()) - { - // If not a valid neighbor - if (neighbor == nullptr) - continue; - else - { - const ElemArg local_cell_arg = {neighbor, false}; - const auto value = functor(local_cell_arg, time)[component]; - max_value = std::max(max_value, value); - min_value = std::min(min_value, value); - } - } - return std::make_pair(max_value, min_value); -} - +/** + * @brief Interpolates container values using a specified functor and face argument. + * + * This function interpolates container values at faces in a computational grid using a specified + * functor, face argument, and limiter type. It handles different limiter types and performs + * interpolation accordingly. + * + * @tparam T The data type for the container values being interpolated. This is typically a + * container type such as a vector or array. + * + * @param functor An object of a functor class derived from FunctorBase. This object provides the + * operator() method to compute the value at a given element and time. + * @param face An argument representing the face in the computational domain. The face provides + * access to neighboring elements and limiter type. + * @param time An argument representing the state or time at which the evaluation is performed. + * + * @return T The interpolated container value at the face. + * + * This function performs the following steps: + * 1. Asserts that the face information is non-null. + * 2. Constructs a limiter based on the face limiter type. + * 3. Determines the upwind and downwind arguments based on the face element. + * 4. Evaluates the functor at the upwind and downwind locations. + * 5. Initializes the return container value. + * 6. Computes the interpolation coefficients and advected values for each component. + * 7. If necessary, computes the gradient and min-max values for certain limiter types. + * + * Usage: + * This function is used for interpolating container values at faces in a finite volume method, + * ensuring that the interpolation adheres to the constraints imposed by the limiter. + */ template T containerInterpolate(const FunctorBase & functor, const FaceArg & face, const StateArg & time) { + // Define types for container gradient and gradient value typedef typename FunctorBase::GradientType ContainerGradientType; typedef typename ContainerGradientType::value_type GradientType; const GradientType * const example_gradient = nullptr; + // Assert that the face information is non-null mooseAssert(face.fi, "this must be non-null"); + + // Construct the limiter based on the face limiter type const auto limiter = Limiter::build(face.limiter_type); + // Determine upwind and downwind arguments based on the face element const auto upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor(); const auto downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem(); const auto phi_upwind = functor(upwind_arg, time); const auto phi_downwind = functor(downwind_arg, time); - // initialize in order to get proper size + // Initialize the return container value T ret = phi_upwind; typename T::value_type coeff_upwind, coeff_downwind; + // Compute interpolation coefficients and advected values for Upwind or CentralDifference limiters if (face.limiter_type == LimiterType::Upwind || face.limiter_type == LimiterType::CentralDifference) { @@ -918,6 +1286,9 @@ containerInterpolate(const FunctorBase & functor, const FaceArg & face, const component_upwind, component_downwind, example_gradient, + example_gradient, + T(0.0), + T(0.0), *face.fi, face.elem_is_upwind); ret[i] = coeff_upwind * component_upwind + coeff_downwind * component_downwind; @@ -925,31 +1296,43 @@ containerInterpolate(const FunctorBase & functor, const FaceArg & face, const } else { - const auto & time_arg = Moose::StateArg(1, Moose::SolutionIterationType::Time); - const auto & grad_phi_upwind = functor.gradient(upwind_arg, time_arg); - const auto & grad_phi_downwind = functor.gradient(downwind_arg, time_arg); + // Determine the time argument for the limiter + auto * time_arg = face.state_limiter; + if (!time_arg) + { + static Moose::StateArg temp_state(0, Moose::SolutionIterationType::Time); + time_arg = &temp_state; + } + + // Evaluate the gradient of the functor at the upwind and downwind locations + const auto & grad_phi_upwind = functor.gradient(upwind_arg, *time_arg); + const auto & grad_phi_face = functor.gradient(face, *time_arg); + // Compute interpolation coefficients and advected values for each component for (const auto i : index_range(ret)) { const auto &component_upwind = phi_upwind[i], component_downwind = phi_downwind[i]; - const VectorValue &grad_upwind = grad_phi_upwind[i], grad_downwind = grad_phi_downwind[i]; + const VectorValue &grad_upwind = grad_phi_upwind[i], grad_face = grad_phi_face[i]; - // Min-Max value - T max_value, min_value; - std::tie(max_value, min_value) = containerComputeMinMaxValue(functor, face, time_arg, i); + // Initialize min-max values + T max_value(0.0), min_value(1e10); + if (face.limiter_type == LimiterType::Venkatakrishnan || + face.limiter_type == LimiterType::SOU) + std::tie(max_value, min_value) = containerComputeMinMaxValue(functor, face, *time_arg, i); + // Perform full limited interpolation for the component ret[i] = fullLimitedInterpolation(*limiter, component_upwind, component_downwind, &grad_upwind, - &grad_downwind, - *face.fi, - face.elem_is_upwind, + &grad_face, max_value, - min_value); + min_value, + face); } } + // Return the interpolated container value return ret; } diff --git a/framework/include/variables/MooseVariableFV.h b/framework/include/variables/MooseVariableFV.h index 6084c33d6482..84541b179b7c 100644 --- a/framework/include/variables/MooseVariableFV.h +++ b/framework/include/variables/MooseVariableFV.h @@ -651,6 +651,9 @@ class MooseVariableFV : public MooseVariableField const Elem * elem_side_to_extrapolate_from, const StateArg & state) const; + /// Function to get the two term boudnary exansion for the variable + const bool & getTwoTermBoundaryExpansion() const { return _two_term_boundary_expansion; } + protected: /** * clear finite volume caches diff --git a/framework/src/fvbcs/FVBoundaryCondition.C b/framework/src/fvbcs/FVBoundaryCondition.C index 2a54c9823604..5d992c748a52 100644 --- a/framework/src/fvbcs/FVBoundaryCondition.C +++ b/framework/src/fvbcs/FVBoundaryCondition.C @@ -85,12 +85,13 @@ FVBoundaryCondition::FVBoundaryCondition(const InputParameters & parameters) Moose::FaceArg FVBoundaryCondition::singleSidedFaceArg(const FaceInfo * fi, const Moose::FV::LimiterType limiter_type, - const bool correct_skewness) const + const bool correct_skewness, + const Moose::StateArg * state_limiter) const { if (!fi) fi = _face_info; - return makeFace(*fi, limiter_type, true, correct_skewness); + return makeFace(*fi, limiter_type, true, correct_skewness, state_limiter); } bool diff --git a/framework/src/fviks/FVInterfaceKernel.C b/framework/src/fviks/FVInterfaceKernel.C index 8af68ad75ef9..72212f45388b 100644 --- a/framework/src/fviks/FVInterfaceKernel.C +++ b/framework/src/fviks/FVInterfaceKernel.C @@ -241,7 +241,8 @@ Moose::FaceArg FVInterfaceKernel::singleSidedFaceArg(const MooseVariableFV & variable, const FaceInfo * fi, const Moose::FV::LimiterType limiter_type, - const bool correct_skewness) const + const bool correct_skewness, + const Moose::StateArg * state_limiter) const { if (!fi) fi = _face_info; @@ -255,7 +256,7 @@ FVInterfaceKernel::singleSidedFaceArg(const MooseVariableFV & variable, ? nullptr : (defined_on_elem_side ? fi->elemPtr() : fi->neighborPtr()); - return {fi, limiter_type, true, correct_skewness, elem, nullptr}; + return {fi, limiter_type, true, correct_skewness, elem, state_limiter}; } bool diff --git a/framework/src/fvkernels/FVFluxKernel.C b/framework/src/fvkernels/FVFluxKernel.C index ac426dd2cfad..0d3dabe8b345 100644 --- a/framework/src/fvkernels/FVFluxKernel.C +++ b/framework/src/fvkernels/FVFluxKernel.C @@ -249,12 +249,13 @@ FVFluxKernel::neighborArg(const bool correct_skewness) const Moose::FaceArg FVFluxKernel::singleSidedFaceArg(const FaceInfo * fi, const Moose::FV::LimiterType limiter_type, - const bool correct_skewness) const + const bool correct_skewness, + const Moose::StateArg * state_limiter) const { if (!fi) fi = _face_info; - return makeFace(*fi, limiter_type, true, correct_skewness); + return makeFace(*fi, limiter_type, true, correct_skewness, state_limiter); } bool diff --git a/modules/navier_stokes/src/fvkernels/INSFVAdvectionKernel.C b/modules/navier_stokes/src/fvkernels/INSFVAdvectionKernel.C index 3d3fc9e45ae4..4db0bfcbb4c2 100644 --- a/modules/navier_stokes/src/fvkernels/INSFVAdvectionKernel.C +++ b/modules/navier_stokes/src/fvkernels/INSFVAdvectionKernel.C @@ -13,6 +13,7 @@ #include "RelationshipManager.h" #include "NSFVUtils.h" #include "FVBoundaryScalarLagrangeMultiplierConstraint.h" +#include "Limiter.h" InputParameters INSFVAdvectionKernel::validParams() @@ -55,6 +56,14 @@ INSFVAdvectionKernel::INSFVAdvectionKernel(const InputParameters & params) }; param_check("force_boundary_execution"); + + if (_var.getTwoTermBoundaryExpansion() && + !(_advected_interp_method == Moose::FV::InterpMethod::Upwind || + _advected_interp_method == Moose::FV::InterpMethod::Average)) + mooseWarning("Second order upwind limiting is not supported when `two_term_boundary_expansion " + "= true` for the limited variable. Use at your own risk or please consider " + "changing `two_term_boundary_expansion = false` or changing your " + "advected_interp_method to first order methods (`upwind`, `average`)"); } void diff --git a/modules/navier_stokes/src/fvkernels/INSFVEnergyAdvection.C b/modules/navier_stokes/src/fvkernels/INSFVEnergyAdvection.C index 97ead95634a9..d311363004e0 100644 --- a/modules/navier_stokes/src/fvkernels/INSFVEnergyAdvection.C +++ b/modules/navier_stokes/src/fvkernels/INSFVEnergyAdvection.C @@ -36,9 +36,14 @@ ADReal INSFVEnergyAdvection::computeQpResidual() { const auto v = velocity(); + const auto & limiter_time = _subproblem.isTransient() + ? Moose::StateArg(1, Moose::SolutionIterationType::Time) + : Moose::StateArg(1, Moose::SolutionIterationType::Nonlinear); const auto adv_quant_face = _adv_quant(makeFace(*_face_info, limiterType(_advected_interp_method), - MetaPhysicL::raw_value(v) * _normal > 0), + MetaPhysicL::raw_value(v) * _normal > 0, + false, + &limiter_time), determineState()); return _normal * v * adv_quant_face; } diff --git a/modules/navier_stokes/src/fvkernels/INSFVMomentumAdvection.C b/modules/navier_stokes/src/fvkernels/INSFVMomentumAdvection.C index 5ee7c4a00fe0..5f1628c67f09 100644 --- a/modules/navier_stokes/src/fvkernels/INSFVMomentumAdvection.C +++ b/modules/navier_stokes/src/fvkernels/INSFVMomentumAdvection.C @@ -123,8 +123,15 @@ INSFVMomentumAdvection::computeResidualsAndAData(const FaceInfo & fi) else // we are an internal fluid flow face { const bool elem_is_upwind = MetaPhysicL::raw_value(v_face) * _normal > 0; - const Moose::FaceArg advected_face_arg{ - &fi, limiterType(_advected_interp_method), elem_is_upwind, correct_skewness, nullptr, nullptr}; + const auto & limiter_time = _subproblem.isTransient() + ? Moose::StateArg(1, Moose::SolutionIterationType::Time) + : Moose::StateArg(1, Moose::SolutionIterationType::Nonlinear); + const Moose::FaceArg advected_face_arg{&fi, + limiterType(_advected_interp_method), + elem_is_upwind, + correct_skewness, + nullptr, + &limiter_time}; if (const auto [is_jump, eps_elem_face, eps_neighbor_face] = NS::isPorosityJumpFace(epsilon(), fi, state); is_jump) diff --git a/modules/navier_stokes/src/fvkernels/INSFVScalarFieldAdvection.C b/modules/navier_stokes/src/fvkernels/INSFVScalarFieldAdvection.C index 6b86104da417..4072387362b2 100644 --- a/modules/navier_stokes/src/fvkernels/INSFVScalarFieldAdvection.C +++ b/modules/navier_stokes/src/fvkernels/INSFVScalarFieldAdvection.C @@ -46,16 +46,24 @@ ADReal INSFVScalarFieldAdvection::computeQpResidual() { const auto state = determineState(); + const auto & limiter_time = _subproblem.isTransient() + ? Moose::StateArg(1, Moose::SolutionIterationType::Time) + : Moose::StateArg(1, Moose::SolutionIterationType::Nonlinear); ADRealVectorValue advection_velocity; if (_add_slip_model) { + Moose::FaceArg face_arg; if (onBoundary(*_face_info)) face_arg = singleSidedFaceArg(); else - face_arg = Moose::FaceArg{ - _face_info, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}; + face_arg = Moose::FaceArg{_face_info, + Moose::FV::LimiterType::CentralDifference, + true, + false, + nullptr, + &limiter_time}; ADRealVectorValue velocity_slip_vel_vec; if (_dim >= 1) @@ -71,7 +79,9 @@ INSFVScalarFieldAdvection::computeQpResidual() advection_velocity += v; const auto var_face = _var(makeFace(*_face_info, limiterType(_advected_interp_method), - MetaPhysicL::raw_value(v) * _normal > 0), + MetaPhysicL::raw_value(v) * _normal > 0, + false, + &limiter_time), state); return _normal * advection_velocity * var_face; From ab87a8b8ff6a677ac58ea909d86b24859d9ea79d Mon Sep 17 00:00:00 2001 From: tanome Date: Thu, 24 Oct 2024 10:12:33 -0600 Subject: [PATCH 03/20] amending limiter documentation Refs #28891 --- framework/doc/content/bib/moose.bib | 18 +++ .../doc/content/syntax/Limiters/index.md | 104 ++++++++++++++++-- 2 files changed, 111 insertions(+), 11 deletions(-) diff --git a/framework/doc/content/bib/moose.bib b/framework/doc/content/bib/moose.bib index 40183a629b63..623d99ddf788 100644 --- a/framework/doc/content/bib/moose.bib +++ b/framework/doc/content/bib/moose.bib @@ -620,4 +620,22 @@ @article{rao2018stopping doi = {https://doi.org/10.1016/j.jcp.2017.09.033}, url = {https://www.sciencedirect.com/science/article/pii/S0021999117306939}, author = {Kaustubh Rao and Paul Malan and J. Blair Perot} + +@inproceedings{venkatakrishnan1993, + title={On the accuracy of limiters and convergence to steady state solutions}, + author={Venkatakrishnan, Venkat}, + booktitle={31st Aerospace Sciences Meeting}, + pages={880}, + year={1993} +} + +@article{harten1997, + title={High resolution schemes for hyperbolic conservation laws}, + author={Harten, Ami}, + journal={Journal of computational physics}, + volume={135}, + number={2}, + pages={260--278}, + year={1997}, + publisher={Elsevier} } diff --git a/framework/doc/content/syntax/Limiters/index.md b/framework/doc/content/syntax/Limiters/index.md index a08a469d9bce..6875812a85de 100644 --- a/framework/doc/content/syntax/Limiters/index.md +++ b/framework/doc/content/syntax/Limiters/index.md @@ -20,7 +20,10 @@ and $u_j^n = u(x_j,t^n)$. A numerical method is TVD if TV(u^{n+1}) \leq TV(u^n) \end{equation} -## Limiting Process +Different formulations are used for compressible and incompressible/weakly-compressible +flow. + +## Limiting Process for Compressible Flow Borrowing notation from [!citep](greenshields2010implementation), we will now discuss computation of limited quantities, represented by $\bm{\Psi}_{f\pm}$ where @@ -66,7 +69,7 @@ non-skewed mesh the definition in [eq:weighting] and [!citep](greenshields2010implementation) are the same. The flux limiter function $\beta(r_{\pm})$ takes different forms as shown in -[limiter_summary]. $r_{\pm}$ is computed as follows +[limiter_summary_compressible]. $r_{\pm}$ is computed as follows \begin{equation} r_{\pm} = 2 \frac{\bm{d}_{\pm}\cdot\left(\nabla @@ -81,14 +84,93 @@ The following limiters are available in MOOSE. We have noted the convergence orders of each (when considering that the solution is smooth), whether they are TVD, and what the functional form of the flux limiting function $\beta(r)$ is. -!table id=limiter_summary caption=Limiter Overview -|Limiter class name | Convergence Order | TVD | $\beta(r)$ | -|------------------ | ----------------- | --- | --- | -| `VanLeer` | 2 | Yes | $\frac{r +\text{abs}(r)}{1 + \text{abs}(r)}$ | -| `Upwind` | 1 | Yes | 0 | -| `CentralDifference` | 2 | No | 1 | -| `MinMod` | 2 | Yes | $\text{max}(0, \text{min}(1, r))$ | -| `SOU` | 2 | No | $r$ | -| `QUICK` | 2 | No | $\frac{3+r}{4}$ | +!table id=limiter_summary_compressible caption=Compressible Limiter Overview +| Limiter class name | Convergence Order | TVD | $\beta(r)$ | +| ------------------- | ----------------- | --- | -------------------------------------------- | +| `VanLeer` | 2 | Yes | $\frac{r +\text{abs}(r)}{1 + \text{abs}(r)}$ | +| `Upwind` | 1 | Yes | 0 | +| `CentralDifference` | 2 | No | 1 | +| `MinMod` | 2 | Yes | $\text{max}(0, \text{min}(1, r))$ | +| `SOU` | 2 | No | $r$ | +| `QUICK` | 2 | No | $\frac{3+r}{4}$ | + +## Limiting Process for Incompressible and Weakly-Compressible flow Flow + +A full second-order upwind reconstruction is used for incompressible and weakly-compressible solvers. In this reconstruction, the limited quantity at the face is expressed as follows: + +\begin{equation} +\bm{\Psi}_f = \bm{\Psi}_C + \beta(r) ((\nabla \bm{\Psi})_C \cdot \bm{d}_{fC}) +\end{equation} + +where: + +- $\bm{\Psi}_f$ is the value of the variable at the face +- $\bm{\Psi}_C$ is the value of the variable at the cell +- $(\nabla \bm{\Psi})_C$ is the value of the gradient at the cell, which is computed with second-order methods (Green-Gauss without skewness correction and Least-Squares for skewness corrected) +- $\bm{d}_{fC}$ is the distance vector from the face to the cell used in the interpolation +- $\beta(r)$ is the limiting function + +Two kinds of limiters are supported: slope-limited and face-value limited. These limiters are defined below. + +For slope-limiting, the limiting function $r$ is defined as follows: + +\begin{equation} +r = 2 \frac{\bm{d}_{NC} \cdot (\nabla \bm{\Psi})_C}{\bm{d}_{NC} \cdot (\nabla \bm{\Psi})_f} - 1 +\end{equation} + +where: + +- $\bm{d}_{NC}$ is the vector between the neighbor and current cell adjacent to the face +- $(\nabla \bm{\Psi})_f$ is the gradient of the variable at the face, which is computed by linear interpolation of second-order gradients at the adjacent cells to the face + +For face-value limiting, the limiting function is defined as follows: + +\begin{equation} +r = +\begin{cases} + \frac{|\Delta_f|}{\Delta_{\text{max}}} & \text{if } \Delta_f > 0 \\ + \frac{|\Delta_f|}{\Delta_{\text{min}}} & \text{if } \Delta_f \leq 0 +\end{cases} +\end{equation} + +where: + +- $\Delta_f = (\nabla \bm{\Psi})_C \cdot \bm{d}_{fC}$ is the increment at the face +- $\Delta_{\text{max}} = \bm{\Psi}_{\text{max}} - \bm{\Psi}_C$ is the maximum increment +- $\Delta_{\text{min}} = \bm{\Psi}_{\text{min}} - \bm{\Psi}_C$ is the minimum increment + +The maximum and minimum variable values, $\Delta_{\text{max}}$ and $\Delta_{\text{min}}$, respectively, are computed with a two-cell stencil. In this method, the maximum value is determined as the maximum cell value of the two faces adjacent to the face and their neighbors, respectively. Similarly, the minimum value is computed as the minimum cell value for these cells. + +Each of the limiters implemented along with the implementation reference, limiting type, whether they are TVD, and the functional form of the flux limiting function $\beta(r)$ is shown in [limiter_summary_incompressible]. + +!table id=limiter_summary_incompressible caption=Incompressible/Weakly-Compressible Limiter Overview +| Limiter class name | Limiting Type | TVD | $\beta(r)$ | +| ----------------------------------------------- | ------------- | --- | ----------------------------------------------------------------- | +| `VanLeer` [!citep](harten1997) | Slope | Yes | $\frac{r +\text{abs}(r)}{1 + \text{abs}(r)}$ | +| `MinMod` [!citep](harten1997) | Slope | Yes | $\text{max}(0, \text{min}(1, r))$ | +| `QUICK` [!citep](harten1997) | Slope | Yes | $\text{min}(1,\text{max}(\text{min}(\frac{1 + 3r}{4}, 2r, 2),0))$ | +| `SOU` [!citep](harten1997) | Face-Value | No | $\text{min}(1,1/r)$ | +| `Venkatakrishnan` [!citep](venkatakrishnan1993) | Face-Value | No | $\frac{2r+1}{r(2r+1)+1}$ | + + +To illustrate the performance of the limiters, a dispersion analysis is developed. +The problem is illustrated in [dispersion]. +This consists of the advection of a passive scalar in a Cartesian mesh at 45 degrees. +The exact solution, without numerical diffusion, is a straight line at 45 degrees +dividing the regions with a scalar concentration of 1 and 0. + +!media framework/finite_volume/dispersion.png + style=display: block;margin-left:auto;margin-right:auto;width:40%; + id=dispersion + caption=Dispersion problem, advection in a Cartesian mesh at 45 degrees. + +The results and performance of each of the limiters are shown in [dispersion_line]. +This image provides an idea of the limiting action and results that +can be expected for each of the limiters. + +!media framework/finite_volume/dispersion_line.png + style=display: block;margin-left:auto;margin-right:auto;width:40%; + id=dispersion_line + caption=Performance of each of the limiters in a line perpendicular to the advection front. !bibtex bibliography From d3c562121854adcc218286efd98f6922f15f890c Mon Sep 17 00:00:00 2001 From: tanome Date: Thu, 24 Oct 2024 16:41:33 -0600 Subject: [PATCH 04/20] adding limiter tests Refs #28891 --- .../ins/advection-schemes/gold/min_mod.e | Bin 66564 -> 0 bytes .../ins/advection-schemes/gold/quick.e | Bin 66560 -> 0 bytes .../ins/advection-schemes/gold/sou.e | Bin 66560 -> 0 bytes .../ins/advection-schemes/gold/vanLeer.e | Bin 66564 -> 0 bytes .../dispersion-test}/bottom_left_advection.i | 36 ++-- .../bottom_left_tri_mesh_advection.i | 114 ++++++++++++ .../limiters/dispersion-test/tests | 104 +++++++++++ .../dispersion-test/top_right_advection.i | 99 ++++++++++ .../lid-driven-segregated.i | 169 ++++++++++++++++++ .../limiters/lid-driven-segregated/tests | 83 +++++++++ .../lid-driven}/test.i | 13 +- .../lid-driven}/tests | 11 +- 12 files changed, 601 insertions(+), 28 deletions(-) delete mode 100644 modules/navier_stokes/test/tests/finite_volume/ins/advection-schemes/gold/min_mod.e delete mode 100644 modules/navier_stokes/test/tests/finite_volume/ins/advection-schemes/gold/quick.e delete mode 100644 modules/navier_stokes/test/tests/finite_volume/ins/advection-schemes/gold/sou.e delete mode 100644 modules/navier_stokes/test/tests/finite_volume/ins/advection-schemes/gold/vanLeer.e rename modules/navier_stokes/test/tests/finite_volume/{ins/limiters => limiters/dispersion-test}/bottom_left_advection.i (68%) create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/bottom_left_tri_mesh_advection.i create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/top_right_advection.i create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/lid-driven-segregated.i create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests rename modules/navier_stokes/test/tests/finite_volume/{ins/advection-schemes => limiters/lid-driven}/test.i (87%) rename modules/navier_stokes/test/tests/finite_volume/{ins/advection-schemes => limiters/lid-driven}/tests (78%) diff --git a/modules/navier_stokes/test/tests/finite_volume/ins/advection-schemes/gold/min_mod.e b/modules/navier_stokes/test/tests/finite_volume/ins/advection-schemes/gold/min_mod.e deleted file mode 100644 index 49f615ca20a815c1c9587c0a3f4ca11aa2985e92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66564 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 diff --git a/modules/navier_stokes/test/tests/finite_volume/ins/advection-schemes/gold/quick.e b/modules/navier_stokes/test/tests/finite_volume/ins/advection-schemes/gold/quick.e deleted file mode 100644 index dfecc7a513ad585bd0fce3b2679b7a17291c9c4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66560 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 diff --git a/modules/navier_stokes/test/tests/finite_volume/ins/advection-schemes/gold/sou.e b/modules/navier_stokes/test/tests/finite_volume/ins/advection-schemes/gold/sou.e deleted file mode 100644 index 9009f9b5e75d3f242402530fa7cd17474a1a09c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66560 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 diff --git a/modules/navier_stokes/test/tests/finite_volume/ins/limiters/bottom_left_advection.i b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/bottom_left_advection.i similarity index 68% rename from modules/navier_stokes/test/tests/finite_volume/ins/limiters/bottom_left_advection.i rename to modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/bottom_left_advection.i index 38cb2d588462..55f731b30c1f 100644 --- a/modules/navier_stokes/test/tests/finite_volume/ins/limiters/bottom_left_advection.i +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/bottom_left_advection.i @@ -1,6 +1,7 @@ -diff = 1e-12 -advected_interp_method = 'vanLeer' #average upwind sou min_mod vanLeer quick venkatakrishnan skewness-corrected -velocity_interp_method = 'average' +[GlobalParams] + advected_interp_method = 'min_mod' #average upwind sou min_mod vanLeer quick venkatakrishnan skewness-corrected + velocity_interp_method = 'average' +[] [UserObjects] [rc] @@ -10,6 +11,7 @@ velocity_interp_method = 'average' a_u = vel_x a_v = vel_y pressure = pressure + velocity_interp_method = 'rc' [] [] @@ -21,8 +23,8 @@ velocity_interp_method = 'average' xmax = 1 ymin = 0 ymax = 1 - nx = 50 - ny = 50 + nx = 10 + ny = 10 [] [] @@ -44,26 +46,16 @@ velocity_interp_method = 'average' [Variables] [scalar] type = INSFVScalarFieldVariable + two_term_boundary_expansion = false [] [] [FVKernels] - [scalar_time] - type = FVFunctorTimeKernel - variable = scalar - [] [scalar_advection] type = INSFVScalarFieldAdvection variable = scalar - velocity_interp_method = ${velocity_interp_method} - advected_interp_method = ${advected_interp_method} rhie_chow_user_object = 'rc' [] - [scalar_diffusion] - type = FVDiffusion - coeff = ${diff} - variable = scalar - [] [] [FVBCs] @@ -94,13 +86,11 @@ velocity_interp_method = 'average' solve_type = 'NEWTON' petsc_options_iname = '-pc_type -pc_factor_shift_type' petsc_options_value = 'lu NONZERO' - [TimeStepper] - type = IterationAdaptiveDT - optimal_iterations = 20 - linear_iteration_ratio = 2 - dt = 0.1 - [] - nl_abs_tol = 1e-10 + dt = 0.1 + end_time = 5.0 + steady_state_detection = false + steady_state_tolerance = 1e-12 + nl_abs_tol = 1e-12 [] [Outputs] diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/bottom_left_tri_mesh_advection.i b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/bottom_left_tri_mesh_advection.i new file mode 100644 index 000000000000..5266b809c0a2 --- /dev/null +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/bottom_left_tri_mesh_advection.i @@ -0,0 +1,114 @@ +[GlobalParams] + advected_interp_method = 'min_mod' #average upwind sou min_mod vanLeer quick venkatakrishnan skewness-corrected + velocity_interp_method = 'average' +[] + +[UserObjects] + [rc] + type = INSFVRhieChowInterpolator + u = vel_x + v = vel_y + a_u = vel_x + a_v = vel_y + pressure = pressure + velocity_interp_method = 'rc' + [] +[] + +[Mesh] + [outer_bdy] + type = PolyLineMeshGenerator + points = '0.0 0.0 0.0 + 0.0 1.0 0.0 + 1.0 1.0 0.0 + 1.0 0.0 0.0' + loop = true + [] + [triang] + type = XYDelaunayGenerator + boundary = 'outer_bdy' + add_nodes_per_boundary_segment = 3 + refine_boundary = true + desired_area = 0.02 + [] + [sidesets] + type = SideSetsFromNormalsGenerator + input = triang + normals = '-1 0 0 + 1 0 0 + 0 -1 0 + 0 1 0' + fixed_normal = true + new_boundary = 'left right bottom top' + [] +[] + +[AuxVariables] + [vel_x] + type = INSFVVelocityVariable + initial_condition = 1.0 + [] + [vel_y] + type = INSFVVelocityVariable + initial_condition = 1.0 + [] + [pressure] + type = INSFVPressureVariable + initial_condition = 1.0 + [] +[] + +[Variables] + [scalar] + type = INSFVScalarFieldVariable + two_term_boundary_expansion = false + [] +[] + +[FVKernels] + [scalar_advection] + type = INSFVScalarFieldAdvection + variable = scalar + rhie_chow_user_object = 'rc' + [] +[] + +[FVBCs] + [fv_inflow] + type = NSFVOutflowTemperatureBC + u = vel_x + v = vel_y + backflow_T = 1.0 + rho = 1.0 + cp = 1.0 + variable = scalar + boundary = 'left' + [] + [fv_outflow] + type = NSFVOutflowTemperatureBC + u = vel_x + v = vel_y + backflow_T = 0.0 + rho = 1.0 + cp = 1.0 + variable = scalar + boundary = 'right top bottom' + [] +[] + +[Executioner] + type = Transient + solve_type = 'NEWTON' + petsc_options_iname = '-pc_type -pc_factor_shift_type' + petsc_options_value = 'lu NONZERO' + dt = 0.1 + end_time = 5.0 + steady_state_detection = false + steady_state_tolerance = 1e-12 + nl_abs_tol = 1e-12 +[] + +[Outputs] + exodus = true + csv = true +[] diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests new file mode 100644 index 000000000000..1ceea5e1dfe0 --- /dev/null +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests @@ -0,0 +1,104 @@ +[Tests] + design = 'INSFVScalarFieldAdvection.md' + issues = '#28891' + [bottom_left_limited_scalar_advection] + requirement = 'The system shall be able to perform a variety of limiting schemes when solving scalar transport equations in cartesian meshes with bottom-left advection. These schemes include' + [sou] + type = Exodiff + input = 'bottom_left_advection.i' + exodiff = bottom_left_sou.e + cli_args = 'GlobalParams/advected_interp_method=sou Outputs/file_base=bottom_left_sou' + detail = 'second-order upwind' + [] + [vanLeer] + type = Exodiff + input = 'bottom_left_advection.i' + exodiff = bottom_left_vanLeer.e + cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=bottom_left_vanLeer' + detail = 'van Leer' + [] + [min_mod] + type = Exodiff + input = 'bottom_left_advection.i' + exodiff = bottom_left_min_mod.e + cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=bottom_left_min_mod' + detail = 'min-mod' + [] + [quick] + type = Exodiff + input = 'bottom_left_advection.i' + exodiff = bottom_left_quick.e + cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=bottom_left_quick' + detail = 'QUICK' + [] + [venkatakrishnan] + type = Exodiff + input = 'bottom_left_advection.i' + exodiff = bottom_left_venkatakrishnan.e + cli_args = 'GlobalParams/advected_interp_method=venkatakrishnan Outputs/file_base=bottom_left_venkatakrishnan' + detail = 'venkatakrishnan' + [] + [] + [top_right_limited_scalar_advection] + requirement = 'The system shall be able to perform a variety of limiting schemes when solving scalar transport equations in cartesian meshes with top-right advection. These schemes include' + [sou] + type = Exodiff + input = 'top_right_advection.i' + exodiff = top_right_sou.e + cli_args = 'GlobalParams/advected_interp_method=sou Outputs/file_base=top_right_sou' + detail = 'second-order upwind' + [] + [vanLeer] + type = Exodiff + input = 'top_right_advection.i' + exodiff = top_right_vanLeer.e + cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=top_right_vanLeer' + detail = 'van Leer' + [] + [min_mod] + type = Exodiff + input = 'top_right_advection.i' + exodiff = top_right_min_mod.e + cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=top_right_min_mod' + detail = 'min-mod' + [] + [quick] + type = Exodiff + input = 'top_right_advection.i' + exodiff = top_right_quick.e + cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=top_right_quick' + detail = 'QUICK' + [] + [venkatakrishnan] + type = Exodiff + input = 'top_right_advection.i' + exodiff = top_right_venkatakrishnan.e + cli_args = 'GlobalParams/advected_interp_method=venkatakrishnan Outputs/file_base=top_right_venkatakrishnan' + detail = 'venkatakrishnan' + [] + [] + [bottom_left_tri_mesh_limited_scalar_advection] + requirement = 'The system shall be able to perform a variety of limiting schemes when solving scalar transport equations in triangular meshes with bottom-left advection. These schemes include' + [vanLeer] + type = Exodiff + input = 'bottom_left_tri_mesh_advection.i' + exodiff = bottom_left_tri_mesh_vanLeer.e + cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=bottom_left_tri_mesh_vanLeer' + detail = 'van Leer' + [] + [min_mod] + type = Exodiff + input = 'bottom_left_tri_mesh_advection.i' + exodiff = bottom_left_tri_mesh_min_mod.e + cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=bottom_left_tri_mesh_min_mod' + detail = 'min-mod' + [] + [quick] + type = Exodiff + input = 'bottom_left_tri_mesh_advection.i' + exodiff = bottom_left_tri_mesh_quick.e + cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=bottom_left_tri_mesh_quick' + detail = 'QUICK' + [] + [] +[] diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/top_right_advection.i b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/top_right_advection.i new file mode 100644 index 000000000000..c45521297532 --- /dev/null +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/top_right_advection.i @@ -0,0 +1,99 @@ +[GlobalParams] + advected_interp_method = 'min_mod' #average upwind sou min_mod vanLeer quick venkatakrishnan skewness-corrected + velocity_interp_method = 'average' +[] + +[UserObjects] + [rc] + type = INSFVRhieChowInterpolator + u = vel_x + v = vel_y + a_u = vel_x + a_v = vel_y + pressure = pressure + velocity_interp_method = 'rc' + [] +[] + +[Mesh] + [gen] + type = GeneratedMeshGenerator + dim = 2 + xmin = 0 + xmax = 1 + ymin = 0 + ymax = 1 + nx = 10 + ny = 10 + [] +[] + +[AuxVariables] + [vel_x] + type = INSFVVelocityVariable + initial_condition = -1.0 + [] + [vel_y] + type = INSFVVelocityVariable + initial_condition = -1.0 + [] + [pressure] + type = INSFVPressureVariable + initial_condition = 1.0 + [] +[] + +[Variables] + [scalar] + type = INSFVScalarFieldVariable + two_term_boundary_expansion = false + [] +[] + +[FVKernels] + [scalar_advection] + type = INSFVScalarFieldAdvection + variable = scalar + rhie_chow_user_object = 'rc' + [] +[] + +[FVBCs] + [fv_inflow] + type = NSFVOutflowTemperatureBC + u = vel_x + v = vel_y + backflow_T = 1.0 + rho = 1.0 + cp = 1.0 + variable = scalar + boundary = 'right' + [] + [fv_outflow] + type = NSFVOutflowTemperatureBC + u = vel_x + v = vel_y + backflow_T = 0.0 + rho = 1.0 + cp = 1.0 + variable = scalar + boundary = 'left top bottom' + [] +[] + +[Executioner] + type = Transient + solve_type = 'NEWTON' + petsc_options_iname = '-pc_type -pc_factor_shift_type' + petsc_options_value = 'lu NONZERO' + dt = 0.1 + end_time = 5.0 + steady_state_detection = false + steady_state_tolerance = 1e-12 + nl_abs_tol = 1e-12 +[] + +[Outputs] + exodus = true + csv = true +[] diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/lid-driven-segregated.i b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/lid-driven-segregated.i new file mode 100644 index 000000000000..fa95501f020d --- /dev/null +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/lid-driven-segregated.i @@ -0,0 +1,169 @@ +mu = .001 +rho = 1 + +pressure_tag = "pressure_grad" + +[GlobalParams] + rhie_chow_user_object = 'rc' + advected_interp_method = 'min_mod' #average upwind sou min_mod vanLeer quick venkatakrishnan skewness-corrected + velocity_interp_method = 'rc' +[] + +[Mesh] + [gen] + type = GeneratedMeshGenerator + dim = 2 + xmin = 0 + xmax = 1 + ymin = 0 + ymax = 1 + nx = 25 + ny = 25 + [] +[] + +[Problem] + nl_sys_names = 'u_system v_system pressure_system' + previous_nl_solution_required = true +[] + +[UserObjects] + [rc] + type = INSFVRhieChowInterpolatorSegregated + u = vel_x + v = vel_y + pressure = pressure + [] +[] + +[Variables] + [vel_x] + type = INSFVVelocityVariable + initial_condition = 0.0 + solver_sys = u_system + two_term_boundary_expansion = false + [] + [vel_y] + type = INSFVVelocityVariable + initial_condition = 0.0 + solver_sys = v_system + two_term_boundary_expansion = false + [] + [pressure] + type = INSFVPressureVariable + solver_sys = pressure_system + initial_condition = 0.2 + two_term_boundary_expansion = false + [] +[] + +[FVKernels] + [u_advection] + type = INSFVMomentumAdvection + variable = vel_x + rho = ${rho} + momentum_component = 'x' + [] + [u_viscosity] + type = INSFVMomentumDiffusion + variable = vel_x + mu = ${mu} + momentum_component = 'x' + [] + [u_pressure] + type = INSFVMomentumPressure + variable = vel_x + momentum_component = 'x' + pressure = pressure + extra_vector_tags = ${pressure_tag} + [] + [v_advection] + type = INSFVMomentumAdvection + variable = vel_y + rho = ${rho} + momentum_component = 'y' + [] + [v_viscosity] + type = INSFVMomentumDiffusion + variable = vel_y + mu = ${mu} + momentum_component = 'y' + [] + [v_pressure] + type = INSFVMomentumPressure + variable = vel_y + momentum_component = 'y' + pressure = pressure + extra_vector_tags = ${pressure_tag} + [] + [p_diffusion] + type = FVAnisotropicDiffusion + variable = pressure + coeff = "Ainv" + coeff_interp_method = 'average' + [] + [p_source] + type = FVDivergence + variable = pressure + vector_field = "HbyA" + force_boundary_execution = true + [] +[] + +[FVBCs] + [top_x] + type = INSFVNoSlipWallBC + variable = vel_x + boundary = 'top' + function = 1 + [] + [no_slip_x] + type = INSFVNoSlipWallBC + variable = vel_x + boundary = 'left right bottom' + function = 0 + [] + [no_slip_y] + type = INSFVNoSlipWallBC + variable = vel_y + boundary = 'left right top bottom' + function = 0 + [] +[] + +[Executioner] + type = SIMPLENonlinearAssembly + rhie_chow_user_object = 'rc' + momentum_systems = 'u_system v_system' + pressure_system = 'pressure_system' + pressure_gradient_tag = ${pressure_tag} + momentum_equation_relaxation = 0.5 + pressure_variable_relaxation = 0.2 + num_iterations = 1000 + pressure_absolute_tolerance = 1e-13 + momentum_absolute_tolerance = 1e-13 + momentum_petsc_options_iname = '-pc_type -pc_hypre_type' + momentum_petsc_options_value = 'hypre boomeramg' + pressure_petsc_options_iname = '-pc_type -pc_hypre_type' + pressure_petsc_options_value = 'hypre boomeramg' + + momentum_l_abs_tol = 1e-14 + pressure_l_abs_tol = 1e-14 + momentum_l_max_its = 30 + pressure_l_max_its = 30 + momentum_l_tol = 0.0 + pressure_l_tol = 0.0 + print_fields = false + + pin_pressure = true + pressure_pin_value = 0.0 + pressure_pin_point = '0.01 0.099 0.0' +[] + +[Outputs] + exodus = true + csv = false + perf_graph = false + print_nonlinear_residuals = false + print_linear_residuals = true +[] diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests new file mode 100644 index 000000000000..5bf35ccbfade --- /dev/null +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests @@ -0,0 +1,83 @@ +[Tests] + design = 'INSFVMomentumAdvection.md' + issues = '#28891' + [segregated_advection_limiting_schemes] + requirement = 'The system shall be able to perform a variety of limiting schemes when solving fluid flow equations in the segreagated solver. These schemes include' + [upwind] + type = 'Exodiff' + input = 'lid-driven-segregated.i' + exodiff = 'upwind.e' + detail = 'and pass debugging checks.' + abs_zero = 1e-6 + cli_args = 'GlobalParams/advected_interp_method=upwind Outputs/file_base=upwind' + heavy = true + detail = 'first-order upwind test' + [] + [upwind_run] + type = 'Exodiff' + input = 'lid-driven-segregated.i' + exodiff = 'upwind_run.e' + detail = 'and reach converged results with segregated solvers.' + abs_zero = 1e-6 + cli_args = 'GlobalParams/advected_interp_method=upwind Executioner/num_iterations=10 Outputs/file_base=upwind_run' + detail = 'first-order upwind run test' + [] + [vanLeer] + type = 'Exodiff' + input = 'lid-driven-segregated.i' + exodiff = 'vanLeer.e' + detail = 'and pass debugging checks.' + abs_zero = 1e-6 + cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=vanLeer' + heavy = true + detail = 'van Leer test' + [] + [vanLeer_run] + type = 'Exodiff' + input = 'lid-driven-segregated.i' + exodiff = 'vanLeer_run.e' + detail = 'and reach converged results with segregated solvers.' + abs_zero = 1e-6 + cli_args = 'GlobalParams/advected_interp_method=vanLeer Executioner/num_iterations=10 Outputs/file_base=vanLeer_run' + detail = 'van Leer run test' + [] + [min_mod] + type = 'Exodiff' + input = 'lid-driven-segregated.i' + exodiff = 'min_mod.e' + detail = 'and pass debugging checks.' + abs_zero = 1e-6 + cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=min_mod' + heavy = true + detail = 'min-mod test' + [] + [min_mod_run] + type = 'Exodiff' + input = 'lid-driven-segregated.i' + exodiff = 'min_mod_run.e' + detail = 'and reach converged results with segregated solvers.' + abs_zero = 1e-6 + cli_args = 'GlobalParams/advected_interp_method=min_mod Executioner/num_iterations=10 Outputs/file_base=min_mod_run' + detail = 'min-mod run test' + [] + [quick] + type = 'Exodiff' + input = 'lid-driven-segregated.i' + exodiff = 'quick.e' + detail = 'and pass debugging checks.' + abs_zero = 1e-6 + cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=quick' + heavy = true + detail = 'QUICK test' + [] + [quick_run] + type = 'Exodiff' + input = 'lid-driven-segregated.i' + exodiff = 'quick_run.e' + detail = 'and reach converged results with segregated solvers.' + abs_zero = 1e-6 + cli_args = 'GlobalParams/advected_interp_method=quick Executioner/num_iterations=10 Outputs/file_base=quick_run' + detail = 'QUICK run test' + [] + [] +[] diff --git a/modules/navier_stokes/test/tests/finite_volume/ins/advection-schemes/test.i b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/test.i similarity index 87% rename from modules/navier_stokes/test/tests/finite_volume/ins/advection-schemes/test.i rename to modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/test.i index dcac9d28c458..37a23fb2d436 100644 --- a/modules/navier_stokes/test/tests/finite_volume/ins/advection-schemes/test.i +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/test.i @@ -19,12 +19,15 @@ rho=1 [Variables] [u] type = INSFVVelocityVariable + two_term_boundary_expansion = false [] [v] type = INSFVVelocityVariable + two_term_boundary_expansion = false [] [pressure] type = INSFVPressureVariable + two_term_boundary_expansion = false [] [lambda] family = SCALAR @@ -128,11 +131,15 @@ rho=1 [] [Executioner] - type = Steady + type = Transient solve_type = 'NEWTON' petsc_options_iname = '-pc_type -pc_factor_shift_type' - petsc_options_value = 'lu NONZERO' - nl_rel_tol = 1e-12 + petsc_options_value = 'lu NONZERO' + dt = 0.1 + end_time = 5.0 + steady_state_detection = false + steady_state_tolerance = 1e-12 + nl_abs_tol = 1e-12 [] [Outputs] diff --git a/modules/navier_stokes/test/tests/finite_volume/ins/advection-schemes/tests b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/tests similarity index 78% rename from modules/navier_stokes/test/tests/finite_volume/ins/advection-schemes/tests rename to modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/tests index 00b1b96cc8e5..25d55f2a368d 100644 --- a/modules/navier_stokes/test/tests/finite_volume/ins/advection-schemes/tests +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/tests @@ -1,8 +1,15 @@ [Tests] design = 'INSFVMomentumAdvection.md' - issues = '#20493' - [limiting_schemes] + issues = '#20493 #28891' + [advection_limiting_schemes] requirement = 'The system shall be able to perform a variety of limiting schemes when solving fluid flow equations. These schemes include' + [upwind] + type = Exodiff + input = 'test.i' + exodiff = upwind.e + cli_args = 'GlobalParams/advected_interp_method=upwind Outputs/file_base=upwind' + detail = 'first-order upwind' + [] [sou] type = Exodiff input = 'test.i' From 7c4a199c4e4fa15bfcdd32b5ec793a7a69f147b0 Mon Sep 17 00:00:00 2001 From: tanome Date: Thu, 24 Oct 2024 16:51:52 -0600 Subject: [PATCH 05/20] style changes required by code pre-check and removing wasp Refs #28891 --- framework/contrib/wasp | 2 +- framework/include/limiters/Limiter.h | 2 +- framework/include/utils/MathFVUtils.h | 19 ++++++++++--------- .../fvkernels/WCNSFV2PMomentumAdvectionSlip.C | 11 ++++++++--- .../IntegralDirectedSurfaceForce.C | 4 ++-- .../userobjects/INSFVRhieChowInterpolator.C | 8 ++++++-- .../src/variables/BernoulliPressureVariable.C | 3 ++- 7 files changed, 30 insertions(+), 19 deletions(-) diff --git a/framework/contrib/wasp b/framework/contrib/wasp index 42b77e3afaae..c8c9ce425911 160000 --- a/framework/contrib/wasp +++ b/framework/contrib/wasp @@ -1 +1 @@ -Subproject commit 42b77e3afaae89af4dbac976a80ad6a7d77270ce +Subproject commit c8c9ce4259115973f147e345608450d87dc390c4 diff --git a/framework/include/limiters/Limiter.h b/framework/include/limiters/Limiter.h index 2166aa9604fe..410ff6e7c138 100644 --- a/framework/include/limiters/Limiter.h +++ b/framework/include/limiters/Limiter.h @@ -125,7 +125,7 @@ class Limiter virtual InterpMethod interpMethod() const = 0; /** - * @brief Functor for applying tsimplified slope limiting. + * @brief Functor for applying simplified slope limiting. * * This function applies the limiter by invoking the `limit` method with the provided parameters. * It acts as a functor, enabling objects of the `VanLeerLimiter` class to be used as if they were diff --git a/framework/include/utils/MathFVUtils.h b/framework/include/utils/MathFVUtils.h index 95234d19b54e..a8fb0be2614d 100644 --- a/framework/include/utils/MathFVUtils.h +++ b/framework/include/utils/MathFVUtils.h @@ -511,15 +511,16 @@ interpolate(const Limiter & limiter, const FaceInfo & fi, const bool fi_elem_is_upwind) { - auto pr = interpCoeffs(limiter, - phi_upwind, - phi_downwind, - grad_phi_upwind, - /*grad_phi_face*/ static_cast*>(nullptr), - /* max_value */ Scalar(0.0), - /* min_value */ Scalar(0.0), - fi, - fi_elem_is_upwind); + auto pr = + interpCoeffs(limiter, + phi_upwind, + phi_downwind, + grad_phi_upwind, + /*grad_phi_face*/ static_cast *>(nullptr), + /* max_value */ Scalar(0.0), + /* min_value */ Scalar(0.0), + fi, + fi_elem_is_upwind); return pr.first * phi_upwind + pr.second * phi_downwind; } diff --git a/modules/navier_stokes/src/fvkernels/WCNSFV2PMomentumAdvectionSlip.C b/modules/navier_stokes/src/fvkernels/WCNSFV2PMomentumAdvectionSlip.C index f69e3416f890..7dab106d0fe3 100644 --- a/modules/navier_stokes/src/fvkernels/WCNSFV2PMomentumAdvectionSlip.C +++ b/modules/navier_stokes/src/fvkernels/WCNSFV2PMomentumAdvectionSlip.C @@ -73,7 +73,8 @@ WCNSFV2PMomentumAdvectionSlip::computeResidualsAndAData(const FaceInfo & fi) if (on_boundary) face_arg = singleSidedFaceArg(); else - face_arg = Moose::FaceArg{&fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}; + face_arg = Moose::FaceArg{ + &fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}; ADRealVectorValue u_slip_vel_vec; if (_dim == 1) @@ -118,8 +119,12 @@ WCNSFV2PMomentumAdvectionSlip::computeResidualsAndAData(const FaceInfo & fi) else // we are an internal fluid flow face { const bool elem_is_upwind = MetaPhysicL::raw_value(u_slip_vel_vec) * _normal > 0; - const Moose::FaceArg advected_face_arg{ - &fi, limiterType(_advected_interp_method), elem_is_upwind, correct_skewness, nullptr, nullptr}; + const Moose::FaceArg advected_face_arg{&fi, + limiterType(_advected_interp_method), + elem_is_upwind, + correct_skewness, + nullptr, + nullptr}; if (const auto [is_jump, eps_elem_face, eps_neighbor_face] = NS::isPorosityJumpFace(epsilon(), fi, state); is_jump) diff --git a/modules/navier_stokes/src/postprocessors/IntegralDirectedSurfaceForce.C b/modules/navier_stokes/src/postprocessors/IntegralDirectedSurfaceForce.C index 296dcbcd187e..604f7ad61442 100644 --- a/modules/navier_stokes/src/postprocessors/IntegralDirectedSurfaceForce.C +++ b/modules/navier_stokes/src/postprocessors/IntegralDirectedSurfaceForce.C @@ -74,8 +74,8 @@ IntegralDirectedSurfaceForce::computeFaceInfoIntegral(const FaceInfo * fi) mooseAssert(fi, "We should have a face info in " + name()); const auto state = determineState(); - const auto face_arg = - Moose::FaceArg({fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}); + const auto face_arg = Moose::FaceArg( + {fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}); const auto elem_arg = Moose::ElemArg({fi->elemPtr(), false}); RealTensorValue pressure_term; diff --git a/modules/navier_stokes/src/userobjects/INSFVRhieChowInterpolator.C b/modules/navier_stokes/src/userobjects/INSFVRhieChowInterpolator.C index 808966737087..fa5b49240454 100644 --- a/modules/navier_stokes/src/userobjects/INSFVRhieChowInterpolator.C +++ b/modules/navier_stokes/src/userobjects/INSFVRhieChowInterpolator.C @@ -544,8 +544,12 @@ INSFVRhieChowInterpolator::getVelocity(const Moose::FV::InterpMethod m, if (Moose::FV::onBoundary(*this, fi)) { const Elem * const boundary_elem = hasBlocks(elem->subdomain_id()) ? elem : neighbor; - const Moose::FaceArg boundary_face{ - &fi, Moose::FV::LimiterType::CentralDifference, true, correct_skewness, boundary_elem, nullptr}; + const Moose::FaceArg boundary_face{&fi, + Moose::FV::LimiterType::CentralDifference, + true, + correct_skewness, + boundary_elem, + nullptr}; auto velocity = vel(boundary_face, time); incorporate_mesh_velocity(boundary_face, velocity); diff --git a/modules/navier_stokes/src/variables/BernoulliPressureVariable.C b/modules/navier_stokes/src/variables/BernoulliPressureVariable.C index 9551f67292e5..c605dda566da 100644 --- a/modules/navier_stokes/src/variables/BernoulliPressureVariable.C +++ b/modules/navier_stokes/src/variables/BernoulliPressureVariable.C @@ -68,7 +68,8 @@ BernoulliPressureVariable::elemIsUpwind(const Elem & elem, const FaceInfo & fi, const Moose::StateArg & time) const { - const Moose::FaceArg face{&fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}; + const Moose::FaceArg face{ + &fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}; const VectorValue vel_face{(*_u)(face, time), (*_v)(face, time), (*_w)(face, time)}; const bool fi_elem_is_upwind = vel_face * fi.normal() > 0; From 1f98ca3d4748619c1adc53691e996bd140f5fa56 Mon Sep 17 00:00:00 2001 From: tanome Date: Mon, 28 Oct 2024 21:39:50 -0600 Subject: [PATCH 06/20] chaging interpolation method for vectors in MathFVUtils and regolding vanLeer vector limiter (ref difs ~1e-5) Refs #28891 --- framework/include/utils/MathFVUtils.h | 16 ++++++++++++---- .../vector-interpolation/gold/vanLeer.e | Bin 53448 -> 74468 bytes 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/framework/include/utils/MathFVUtils.h b/framework/include/utils/MathFVUtils.h index a8fb0be2614d..ca9a31fe84b1 100644 --- a/framework/include/utils/MathFVUtils.h +++ b/framework/include/utils/MathFVUtils.h @@ -1190,13 +1190,17 @@ interpolate(const FunctorBase> & functor, // Evaluate the gradient of the functor at the upwind and downwind locations const auto & grad_phi_upwind = functor.gradient(upwind_arg, *time_arg); - const auto & grad_phi_face = functor.gradient(face, *time_arg); + const auto & grad_phi_downwind = functor.gradient(downwind_arg, *time_arg); + + const auto coeffs = interpCoeffs(InterpMethod::Average, *face.fi, face.elem_is_upwind); // Compute interpolation coefficients and advected values for each component for (unsigned int i = 0; i < LIBMESH_DIM; ++i) { const auto &component_upwind = phi_upwind(i), component_downwind = phi_downwind(i); - const VectorValue &grad_upwind = grad_phi_upwind.row(i), grad_face = grad_phi_face.row(i); + const VectorValue &grad_upwind = grad_phi_upwind.row(i), + grad_face = coeffs.first * grad_phi_upwind.row(i) + + coeffs.second * grad_phi_downwind.row(i); // Initialize min-max values T max_value(0.0), min_value(1e10); @@ -1307,13 +1311,17 @@ containerInterpolate(const FunctorBase & functor, const FaceArg & face, const // Evaluate the gradient of the functor at the upwind and downwind locations const auto & grad_phi_upwind = functor.gradient(upwind_arg, *time_arg); - const auto & grad_phi_face = functor.gradient(face, *time_arg); + const auto & grad_phi_downwind = functor.gradient(downwind_arg, *time_arg); + + const auto coeffs = interpCoeffs(InterpMethod::Average, *face.fi, face.elem_is_upwind); // Compute interpolation coefficients and advected values for each component for (const auto i : index_range(ret)) { const auto &component_upwind = phi_upwind[i], component_downwind = phi_downwind[i]; - const VectorValue &grad_upwind = grad_phi_upwind[i], grad_face = grad_phi_face[i]; + const VectorValue &grad_upwind = grad_phi_upwind[i], + grad_face = coeffs.first * grad_phi_upwind[i] + + coeffs.second * grad_phi_downwind[i]; // Initialize min-max values T max_value(0.0), min_value(1e10); diff --git a/test/tests/fvkernels/vector-interpolation/gold/vanLeer.e b/test/tests/fvkernels/vector-interpolation/gold/vanLeer.e index ec501e9ade36c54f98a787fc78ac2cb1e94b1adb..adf6790caef86006ddf10920b25c3cc1fc6f4e9b 100644 GIT binary patch literal 74468 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 LH`erx$G`srFtD`# delta 3727 zcmcIl4RBLc7S2u6CTUW({IsEeulO}9agDOd(_CTvQ%dW-0lMQA)yS8Rj6A>%C5L8Om`HuE(NhvT5#Oionh}ynoe3) zT|n>5z4zR6&Uena=bm@o=lzO-u9&Kt+7)t{Oh#rro^#3WVL7|#72More3HpB@l+9> z$IY>rw&AI0!5n<+Q=2Rq?KL`zoO0U`*Ux|6j7FH15JcmhHES`w) z;YG9(l=2D~M%hp!PY0zU5qNoAn(X8^SVzq|a14ysClVCK;HiQRxh|=KP*~b5@Xf|4 z$uW6uN)eo){w-SAP{b+qsCkmM^tU*@dAObi6hFDz&dF7cVT|`wT z)2N^|R%eX9J<%k2#zW)5i^|D!9P9Lw*Cnx|RoEAcrp2-X@tXdCdZ zVm)k=T@)jgk$`I^Iazy=wo&PT4ME9V88S5L;2`Q&mu<(%DF%5U-Izyp!s~BOwnjS~u6o+XdE% zYdlh1b1jrs#XpInoJnbW=-x-N$<_siXb~F6S9+Y;0|3zz@tZ% z(59Og$RLDKHy33EI7}|c%F3c@_@*X?b5Uz>v!SYm&Auj<^NJJ}1@6?Nq6DgN3*W>R z;$GxpT+lXuVYa|GQu%Jm%ZlCtH?`8kI~b3Z5tt?sYc&-V6wq!j^v|~x_&A@)x~Tko zRuFh0pT})UaJ#UAjKxfj&)@8FJ+7d!zT{c-rJ#vs|L5;=@4v=I$yDC;s>=;qvBH{-#Nia!P) zCLC-dFR-}1u_EiWJDeh1G2}qQA_csiGY&g%rPFSJE$C5(8s?z0_OXf^GsM zjro@&IJYboa#!E1FX+C{083l<1gKc_3LLe4J;QI(-S}=lx8Zn|KyO$*xhvHi@3rHM z;_~ULC=dKL4XL4X!(HS$>J=O7Sb<|bB6N-CcCHJ-k@GTMFD;CckyJJ@#92o6)(dO$xeh$Mb3Tt$CizxlKC5&2VoE<@$dn(Ykwq zH2AAO<7%7A-W#}379r?sj)m)wOn>;BG}N~{S+#C?^?E?> zo@fU?N=E;mx*nH~KOERd_j>6cf4oN?>ORf`nRqwB;RDUkaKtEWI`}Mt-0Vzvpr;MQ zLpBJ$ehoTy=|jpd1+T(qN37E0z2_19=~%c^?S5m!^pr^(-^9g6+7r{W1UEAU9HbRe z##_%LP#hnJ7f!q^ZSTh~`PY-LK-!QMguz!O Ng@sLja@Mse3Ut9q@G5xn*8&Kz! z(vzpp%Ax1)b+GP360iY&_u+&zd}bL6;`Xx(1^=Q$gE4BxxrMbi;$KtXlX#Q_9=|D& zI2Xlf2+NND{61C$V@nn3I<`>9*~kcP#^J&2uJI+o(KPfd3O<;Cp8KHyJ+v%}iCTM^5>NoUQVa%1TnqK+X`e>$Ok tGQD6M{mE}eKI(72Mt}U!$>H>gf74_AKW>2j?~U-s4Y1+%Q~2Eh{ukh0 Date: Tue, 29 Oct 2024 08:34:58 -0600 Subject: [PATCH 07/20] changing fvkernels/mms/advection-outflow test logic to ensure that convergence is at leaste the required order of convergence Refs #28891 --- .../fvkernels/mms/advective-outflow/test.py | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/test/tests/fvkernels/mms/advective-outflow/test.py b/test/tests/fvkernels/mms/advective-outflow/test.py index 33eb5133f465..535d77e90140 100644 --- a/test/tests/fvkernels/mms/advective-outflow/test.py +++ b/test/tests/fvkernels/mms/advective-outflow/test.py @@ -1,6 +1,8 @@ import mms import unittest -from mooseutils import fuzzyAbsoluteEqual + +def bottom_bound(value, order, tolerance): + return value > (order - tolerance) class TestOutflow(unittest.TestCase): def test(self): @@ -15,9 +17,9 @@ def test(self): fig.save('outflow.png') for label,value in fig.label_to_slope.items(): if label == 'L2u': - self.assertTrue(fuzzyAbsoluteEqual(value, 1., .05)) + self.assertTrue(bottom_bound(value, 1., .05)) else: - self.assertTrue(fuzzyAbsoluteEqual(value, 2., .05)) + self.assertTrue(bottom_bound(value, 2., .05)) class TestOutflowMinMod(unittest.TestCase): def test(self): @@ -39,9 +41,9 @@ def test(self): fig.save('outflow-min-mod.png') for label,value in fig.label_to_slope.items(): if label == 'L2u': - self.assertTrue(fuzzyAbsoluteEqual(value, 1.5, .05)) + self.assertTrue(bottom_bound(value, 1.5, .05)) else: - self.assertTrue(fuzzyAbsoluteEqual(value, 2., .05)) + self.assertTrue(bottom_bound(value, 2., .05)) class TestExtrapolation(unittest.TestCase): def test(self): @@ -56,9 +58,9 @@ def test(self): fig.save('extrapolation.png') for label,value in fig.label_to_slope.items(): if label == 'L2u': - self.assertTrue(fuzzyAbsoluteEqual(value, 1., .05)) + self.assertTrue(bottom_bound(value, 1., .05)) else: - self.assertTrue(fuzzyAbsoluteEqual(value, 2., .05)) + self.assertTrue(bottom_bound(value, 2., .05)) class UpwindLimiter(unittest.TestCase): def test(self): @@ -72,7 +74,7 @@ def test(self): slope_precision=1) fig.save('upwind-limiter.png') for label,value in fig.label_to_slope.items(): - self.assertTrue(fuzzyAbsoluteEqual(value, 1., .05)) + self.assertTrue(bottom_bound(value, 1., .05)) class CentralDifferenceLimiter(unittest.TestCase): def test(self): @@ -86,7 +88,7 @@ def test(self): slope_precision=1) fig.save('cd-limiter.png') for label,value in fig.label_to_slope.items(): - self.assertTrue(fuzzyAbsoluteEqual(value, 2., .05)) + self.assertTrue(bottom_bound(value, 2., .05)) class VanLeerLimiter(unittest.TestCase): def test(self): @@ -100,7 +102,7 @@ def test(self): slope_precision=1) fig.save('vanLeer-limiter.png') for label,value in fig.label_to_slope.items(): - self.assertTrue(fuzzyAbsoluteEqual(value, 2., .05)) + self.assertTrue(bottom_bound(value, 2., .05)) class MinModLimiter(unittest.TestCase): def test(self): @@ -114,7 +116,7 @@ def test(self): slope_precision=1) fig.save('min-mod-limiter.png') for label,value in fig.label_to_slope.items(): - self.assertTrue(fuzzyAbsoluteEqual(value, 2., .05)) + self.assertTrue(bottom_bound(value, 2., .05)) class SOULimiter(unittest.TestCase): def test(self): @@ -128,7 +130,7 @@ def test(self): slope_precision=1) fig.save('sou-limiter.png') for label,value in fig.label_to_slope.items(): - self.assertTrue(fuzzyAbsoluteEqual(value, 2., .05)) + self.assertTrue(bottom_bound(value, 2., .05)) class QUICKLimiter(unittest.TestCase): def test(self): @@ -142,7 +144,7 @@ def test(self): slope_precision=1) fig.save('quick-limiter.png') for label,value in fig.label_to_slope.items(): - self.assertTrue(fuzzyAbsoluteEqual(value, 2., .05)) + self.assertTrue(bottom_bound(value, 2., .05)) class KTLimitedCD(unittest.TestCase): def test(self): @@ -156,7 +158,7 @@ def test(self): slope_precision=1) fig.save('kt-cd-limiter.png') for key,value in fig.label_to_slope.items(): - self.assertTrue(fuzzyAbsoluteEqual(value, 2., .05)) + self.assertTrue(bottom_bound(value, 2., .05)) print("%s slope, %f" % (key, value)) class KTLimitedUpwind(unittest.TestCase): @@ -171,7 +173,7 @@ def test(self): slope_precision=1) fig.save('kt-upwind-limiter.png') for key,value in fig.label_to_slope.items(): - self.assertTrue(fuzzyAbsoluteEqual(value, 1., .05)) + self.assertTrue(bottom_bound(value, 1., .05)) print("%s slope, %f" % (key, value)) class KTLimitedVanLeer(unittest.TestCase): @@ -186,5 +188,5 @@ def test(self): slope_precision=1) fig.save('kt-van-leer-limiter.png') for key,value in fig.label_to_slope.items(): - self.assertTrue(fuzzyAbsoluteEqual(value, 2.5, .05)) + self.assertTrue(bottom_bound(value, 2.5, .05)) print("%s slope, %f" % (key, value)) From 4a285fda9afc3e50d7b57a1c51ea027b9d1c4129 Mon Sep 17 00:00:00 2001 From: tanome Date: Tue, 29 Oct 2024 14:11:31 -0600 Subject: [PATCH 08/20] extending supported two-term-boundary expansion methods in INSFAdvectionKernel Refs #28891 --- .../src/fvkernels/INSFVAdvectionKernel.C | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/navier_stokes/src/fvkernels/INSFVAdvectionKernel.C b/modules/navier_stokes/src/fvkernels/INSFVAdvectionKernel.C index 4db0bfcbb4c2..816bb62e7dd0 100644 --- a/modules/navier_stokes/src/fvkernels/INSFVAdvectionKernel.C +++ b/modules/navier_stokes/src/fvkernels/INSFVAdvectionKernel.C @@ -59,11 +59,15 @@ INSFVAdvectionKernel::INSFVAdvectionKernel(const InputParameters & params) if (_var.getTwoTermBoundaryExpansion() && !(_advected_interp_method == Moose::FV::InterpMethod::Upwind || - _advected_interp_method == Moose::FV::InterpMethod::Average)) - mooseWarning("Second order upwind limiting is not supported when `two_term_boundary_expansion " - "= true` for the limited variable. Use at your own risk or please consider " - "changing `two_term_boundary_expansion = false` or changing your " - "advected_interp_method to first order methods (`upwind`, `average`)"); + _advected_interp_method == Moose::FV::InterpMethod::Average || + _advected_interp_method == Moose::FV::InterpMethod::HarmonicAverage || + _advected_interp_method == Moose::FV::InterpMethod::SkewCorrectedAverage)) + mooseWarning( + "Second order upwind limiting is not supported when `two_term_boundary_expansion " + "= true` for the limited variable. Use at your own risk or please consider " + "setting `two_term_boundary_expansion = false` in the advected variable parameters or " + "changing your " + "'advected_interp_method' of the kernel to first order methods (`upwind`, `average`)"); } void From 3a8de792e1931a9291ff86edb4bf3982e074e77c Mon Sep 17 00:00:00 2001 From: tanome Date: Wed, 30 Oct 2024 22:25:55 -0600 Subject: [PATCH 09/20] completing argument definition for passing compile checks Refs #28891 --- framework/include/utils/MathFVUtils.h | 5 ++--- unit/src/ContainerFunctors.C | 2 +- unit/src/MooseFunctorTest.C | 5 +++-- unit/src/ParsedFunctionTest.C | 3 ++- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/framework/include/utils/MathFVUtils.h b/framework/include/utils/MathFVUtils.h index ca9a31fe84b1..f5fb11e7d987 100644 --- a/framework/include/utils/MathFVUtils.h +++ b/framework/include/utils/MathFVUtils.h @@ -1259,7 +1259,6 @@ template T containerInterpolate(const FunctorBase & functor, const FaceArg & face, const StateArg & time) { - // Define types for container gradient and gradient value typedef typename FunctorBase::GradientType ContainerGradientType; typedef typename ContainerGradientType::value_type GradientType; const GradientType * const example_gradient = nullptr; @@ -1290,8 +1289,8 @@ containerInterpolate(const FunctorBase & functor, const FaceArg & face, const std::tie(coeff_upwind, coeff_downwind) = interpCoeffs(*limiter, component_upwind, component_downwind, - example_gradient, - example_gradient, + /*grad_phi_upwind*/ example_gradient, + /*grad_phi_face*/ example_gradient, T(0.0), T(0.0), *face.fi, diff --git a/unit/src/ContainerFunctors.C b/unit/src/ContainerFunctors.C index 743cdbcd524d..a24ce11b647e 100644 --- a/unit/src/ContainerFunctors.C +++ b/unit/src/ContainerFunctors.C @@ -92,7 +92,7 @@ TEST(ContainerFunctors, Test) for (const auto * const face : faces) { const auto elem = vector_functor.isInternalFace(*face) ? nullptr : face->elemPtr(); - const auto face_arg = Moose::FaceArg({face, limiter_type, true, false, elem}); + const auto face_arg = Moose::FaceArg({face, limiter_type, true, false, elem, nullptr}); const auto current_time = Moose::currentState(); EXPECT_TRUE(vector_functor(face_arg, current_time)[0] == 1.); EXPECT_TRUE(array_functor(face_arg, current_time)[0] == 1.); diff --git a/unit/src/MooseFunctorTest.C b/unit/src/MooseFunctorTest.C index 3d74948d36e7..4e6e6fdff87a 100644 --- a/unit/src/MooseFunctorTest.C +++ b/unit/src/MooseFunctorTest.C @@ -132,7 +132,7 @@ TEST(MooseFunctorTest, testArgs) QGauss qrule(1, CONSTANT); auto elem_arg = ElemArg{elem.get(), false}; - auto face = FaceArg({&fi, LimiterType::CentralDifference, true, false, nullptr}); + auto face = FaceArg({&fi, LimiterType::CentralDifference, true, false, nullptr, nullptr}); auto elem_qp = ElemQpArg({elem.get(), 0, &qrule, Point(0)}); auto elem_side_qp = ElemSideQpArg({elem.get(), 0, 0, &qrule, Point(0)}); auto elem_point = ElemPointArg({elem.get(), Point(0), false}); @@ -355,7 +355,8 @@ TEST(MooseFunctorTest, testArgs) if (!mesh_fi.neighborPtr()) continue; - auto vec_face_arg = FaceArg({&mesh_fi, LimiterType::CentralDifference, true, false, nullptr}); + auto vec_face_arg = + FaceArg({&mesh_fi, LimiterType::CentralDifference, true, false, nullptr, nullptr}); const auto vec_elem_arg = vec_face_arg.makeElem(); const auto vec_neighbor_arg = vec_face_arg.makeNeighbor(); zero_gradient_and_grad_dot_test(vec_comp, vec_elem_arg); diff --git a/unit/src/ParsedFunctionTest.C b/unit/src/ParsedFunctionTest.C index 9fd1f5e31e68..928152efe075 100644 --- a/unit/src/ParsedFunctionTest.C +++ b/unit/src/ParsedFunctionTest.C @@ -100,7 +100,8 @@ TEST_F(ParsedFunctionTest, basicConstructor) // Test face overloads _mesh->buildFiniteVolumeInfo(); const FaceInfo * const fi = _mesh->faceInfo(elem, side); - auto face = Moose::FaceArg({fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr}); + auto face = Moose::FaceArg( + {fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}); f_traditional = f.value(0, fi->faceCentroid()); f_functor = f_wrapped(face, Moose::currentState()); gradient_traditional = f.gradient(0, fi->faceCentroid()); From 4c2691274aa20f98278ffe5bad8adc1f976941ed Mon Sep 17 00:00:00 2001 From: tanome Date: Wed, 30 Oct 2024 22:25:55 -0600 Subject: [PATCH 10/20] completing argument definition for passing compile checks and modifying test tolerance Refs #28891 --- .../limiters/CentralDifferenceLimiter.h | 4 +- framework/include/limiters/Limiter.h | 16 +- framework/include/limiters/MinModLimiter.h | 4 +- framework/include/limiters/QUICKLimiter.h | 4 +- framework/include/limiters/SOULimiter.h | 4 +- framework/include/limiters/UpwindLimiter.h | 4 +- framework/include/limiters/VanLeerLimiter.h | 4 +- .../include/limiters/VenkatakrishnanLimiter.h | 4 +- framework/include/utils/MathFVUtils.h | 196 ++++-------------- .../limiters/dispersion-test/tests | 13 ++ .../limiters/lid-driven-segregated/tests | 33 +-- .../finite_volume/limiters/lid-driven/tests | 5 + .../unit/src/TestFaceCenteredMapFunctor.C | 15 +- .../unit/src/TestReconstruction.C | 4 +- 14 files changed, 113 insertions(+), 197 deletions(-) diff --git a/framework/include/limiters/CentralDifferenceLimiter.h b/framework/include/limiters/CentralDifferenceLimiter.h index 027d1d43a2c8..abfa9a66e34b 100644 --- a/framework/include/limiters/CentralDifferenceLimiter.h +++ b/framework/include/limiters/CentralDifferenceLimiter.h @@ -30,8 +30,8 @@ class CentralDifferenceLimiter : public Limiter const VectorValue *, const VectorValue *, const RealVectorValue &, - const T &, - const T &, + const Real &, + const Real &, const FaceInfo *, const bool &) const override final { diff --git a/framework/include/limiters/Limiter.h b/framework/include/limiters/Limiter.h index 410ff6e7c138..1ab0ce4b8938 100644 --- a/framework/include/limiters/Limiter.h +++ b/framework/include/limiters/Limiter.h @@ -117,8 +117,8 @@ class Limiter const VectorValue * grad_phi_upwind, const VectorValue * grad_phi_downwind, const RealVectorValue & dCD, - const T & max_value, - const T & min_value, + const Real & max_value, + const Real & min_value, const FaceInfo * fi, const bool & fi_elem_is_upwind) const = 0; virtual bool constant() const = 0; @@ -167,8 +167,8 @@ class Limiter grad_phi_upwind, nullptr, dCD, - 0.0, - 0.0, + T(0), + T(0), nullptr, false))); } @@ -222,8 +222,8 @@ class Limiter const VectorValue * grad_phi_upwind, const VectorValue * grad_phi_downwind, const RealVectorValue & dCD, - const T & max_value, - const T & min_value, + const Real & max_value, + const Real & min_value, const FaceInfo * fi, const bool & fi_elem_is_upwind) const { @@ -322,8 +322,8 @@ class Limiter */ T rf_minmax(const T & phi_upwind, const VectorValue * grad_phi_upwind, - const T & max_value, - const T & min_value, + const Real & max_value, + const Real & min_value, const FaceInfo * fi, const bool & fi_elem_is_upwind) const { diff --git a/framework/include/limiters/MinModLimiter.h b/framework/include/limiters/MinModLimiter.h index af2837f7cb7a..85c1dadb881c 100644 --- a/framework/include/limiters/MinModLimiter.h +++ b/framework/include/limiters/MinModLimiter.h @@ -67,8 +67,8 @@ class MinModLimiter : public Limiter const VectorValue * grad_phi_upwind, const VectorValue * grad_phi_downwind, const RealVectorValue & dCD, - const T & /* max_value */, - const T & /* min_value */, + const Real & /* max_value */, + const Real & /* min_value */, const FaceInfo * /* fi */, const bool & /* fi_elem_is_upwind */) const override final { diff --git a/framework/include/limiters/QUICKLimiter.h b/framework/include/limiters/QUICKLimiter.h index 592f607286b6..bdbda88027a8 100644 --- a/framework/include/limiters/QUICKLimiter.h +++ b/framework/include/limiters/QUICKLimiter.h @@ -79,8 +79,8 @@ class QUICKLimiter : public Limiter const VectorValue * grad_phi_upwind, const VectorValue * grad_phi_downwind, const RealVectorValue & dCD, - const T & /* max_value */, - const T & /* min_value */, + const Real & /* max_value */, + const Real & /* min_value */, const FaceInfo * /* fi */, const bool & /* fi_elem_is_upwind */) const override final { diff --git a/framework/include/limiters/SOULimiter.h b/framework/include/limiters/SOULimiter.h index db94adbc9a56..500084dddfd2 100644 --- a/framework/include/limiters/SOULimiter.h +++ b/framework/include/limiters/SOULimiter.h @@ -77,8 +77,8 @@ class SOULimiter : public Limiter const VectorValue * grad_phi_upwind, const VectorValue * grad_phi_downwind, const RealVectorValue & dCD, - const T & max_value, - const T & min_value, + const Real & max_value, + const Real & min_value, const FaceInfo * fi, const bool & fi_elem_is_upwind) const override final { diff --git a/framework/include/limiters/UpwindLimiter.h b/framework/include/limiters/UpwindLimiter.h index 4926f3e2b35a..43734b7d6928 100644 --- a/framework/include/limiters/UpwindLimiter.h +++ b/framework/include/limiters/UpwindLimiter.h @@ -29,8 +29,8 @@ class UpwindLimiter : public Limiter const VectorValue *, const VectorValue *, const RealVectorValue &, - const T &, - const T &, + const Real &, + const Real &, const FaceInfo *, const bool &) const override final { diff --git a/framework/include/limiters/VanLeerLimiter.h b/framework/include/limiters/VanLeerLimiter.h index 9e9779c4b456..035c797fdd8f 100644 --- a/framework/include/limiters/VanLeerLimiter.h +++ b/framework/include/limiters/VanLeerLimiter.h @@ -67,8 +67,8 @@ class VanLeerLimiter : public Limiter const VectorValue * grad_phi_upwind, const VectorValue * grad_phi_downwind, const RealVectorValue & dCD, - const T & /* max_value */, - const T & /* min_value */, + const Real & /* max_value */, + const Real & /* min_value */, const FaceInfo * /* fi */, const bool & /* fi_elem_is_upwind */) const override final { diff --git a/framework/include/limiters/VenkatakrishnanLimiter.h b/framework/include/limiters/VenkatakrishnanLimiter.h index f08b94cd71f7..3402a02930c6 100644 --- a/framework/include/limiters/VenkatakrishnanLimiter.h +++ b/framework/include/limiters/VenkatakrishnanLimiter.h @@ -95,8 +95,8 @@ class VenkatakrishnanLimiter : public Limiter const VectorValue * grad_phi_upwind, const VectorValue * /* grad_phi_downwind */, const RealVectorValue & /* dCD */, - const T & max_value, - const T & min_value, + const Real & max_value, + const Real & min_value, const FaceInfo * fi, const bool & fi_elem_is_upwind) const override final { diff --git a/framework/include/utils/MathFVUtils.h b/framework/include/utils/MathFVUtils.h index f5fb11e7d987..e9f3feddff34 100644 --- a/framework/include/utils/MathFVUtils.h +++ b/framework/include/utils/MathFVUtils.h @@ -474,8 +474,8 @@ interpCoeffs(const Limiter & limiter, const T & phi_downwind, const VectorValue * const grad_phi_upwind, const VectorValue * const grad_phi_face, - const T & max_value, - const T & min_value, + const Real & max_value, + const Real & min_value, const FaceInfo & fi, const bool fi_elem_is_upwind) { @@ -517,8 +517,8 @@ interpolate(const Limiter & limiter, phi_downwind, grad_phi_upwind, /*grad_phi_face*/ static_cast *>(nullptr), - /* max_value */ Scalar(0.0), - /* min_value */ Scalar(0.0), + /* max_value */ std::numeric_limits::max(), + /* min_value */ std::numeric_limits::min(), fi, fi_elem_is_upwind); return pr.first * phi_upwind + pr.second * phi_downwind; @@ -595,8 +595,8 @@ fullLimitedInterpolation(const Limiter & limiter, const T & phi_downwind, const VectorValue * const grad_phi_upwind, const VectorValue * const grad_phi_face, - const T & max_value, - const T & min_value, + const Real & max_value, + const Real & min_value, const FaceArg & face) { // Compute the direction vector based on whether the current element is upwind @@ -655,7 +655,7 @@ fullLimitedInterpolation(const Limiter & limiter, * value. * * This function performs the following steps: - * 1. Initializes max_value to 0 and min_value to a large value (1e10). + * 1. Initializes max_value to 0 and min_value to a large value. * 2. Iterates over the direct neighbors of the element associated with the face. * - If a neighbor is valid (not null), it evaluates the functor at that neighbor and updates * max_value and min_value. @@ -672,11 +672,11 @@ fullLimitedInterpolation(const Limiter & limiter, template ::value>::type> -std::pair +std::pair computeMinMaxValue(const FunctorBase & functor, const FaceArg & face, const StateArg & time) { - // Initialize max_value to 0 and min_value to a large value (1e10) - T max_value(0), min_value(1e10); + // Initialize max_value to 0 and min_value to a large value + Real max_value(std::numeric_limits::min()), min_value(std::numeric_limits::max()); // Iterate over the direct neighbors of the element associated with the face for (auto neighbor : (*face.fi).elem().neighbor_ptr_range()) @@ -687,7 +687,8 @@ computeMinMaxValue(const FunctorBase & functor, const FaceArg & face, const S // Evaluate the functor at the neighbor and update max_value and min_value const ElemArg local_cell_arg = {neighbor, false}; - const auto value = functor.template genericEvaluate(local_cell_arg, time); + const auto value = + MetaPhysicL::raw_value(functor.template genericEvaluate(local_cell_arg, time)); max_value = std::max(max_value, value); min_value = std::min(min_value, value); } @@ -701,7 +702,8 @@ computeMinMaxValue(const FunctorBase & functor, const FaceArg & face, const S // Evaluate the functor at the neighbor and update max_value and min_value const ElemArg local_cell_arg = {neighbor, false}; - const auto value = functor.template genericEvaluate(local_cell_arg, time); + const auto value = + MetaPhysicL::raw_value(functor.template genericEvaluate(local_cell_arg, time)); max_value = std::max(max_value, value); min_value = std::min(min_value, value); } @@ -734,7 +736,7 @@ computeMinMaxValue(const FunctorBase & functor, const FaceArg & face, const S * second element is the minimum value. * * This function performs the following steps: - * 1. Initializes max_value to 0 and min_value to a large value (1e10). + * 1. Initializes max_value to 0 and min_value to a large value. * 2. Iterates over the direct neighbors of the element associated with the face. * - If a neighbor is valid (not null), it evaluates the functor at that neighbor for the * specified component and updates max_value and min_value. @@ -749,14 +751,14 @@ computeMinMaxValue(const FunctorBase & functor, const FaceArg & face, const S * faces. */ template -std::pair +std::pair computeMinMaxValue(const FunctorBase> & functor, const FaceArg & face, const StateArg & time, const unsigned int & component) { - // Initialize max_value to 0 and min_value to a large value (1e10) - T max_value(0), min_value(1e10); + // Initialize max_value to 0 and min_value to a large value + Real max_value(std::numeric_limits::min()), min_value(std::numeric_limits::max()); // Iterate over the direct neighbors of the element associated with the face for (auto neighbor : (*face.fi).elem().neighbor_ptr_range()) @@ -768,7 +770,7 @@ computeMinMaxValue(const FunctorBase> & functor, // Evaluate the functor at the neighbor for the specified component and update max_value and // min_value const ElemArg local_cell_arg = {neighbor, false}; - const auto value = functor(local_cell_arg, time)(component); + const auto value = MetaPhysicL::raw_value(functor(local_cell_arg, time)(component)); max_value = std::max(max_value, value); min_value = std::min(min_value, value); } @@ -783,89 +785,7 @@ computeMinMaxValue(const FunctorBase> & functor, // Evaluate the functor at the neighbor for the specified component and update max_value and // min_value const ElemArg local_cell_arg = {neighbor, false}; - const auto value = functor(local_cell_arg, time)(component); - max_value = std::max(max_value, value); - min_value = std::min(min_value, value); - } - - // Return a pair containing the computed maximum and minimum values - return std::make_pair(max_value, min_value); -} - -/** - * @brief Computes the minimum and maximum scalar values of a specific component in a two-cell - * stencil around a given face in a computational grid. - * - * This function calculates the minimum and maximum values of a specified component within a - * two-cell stencil. The stencil includes the immediate neighboring elements of the face's - * associated element and the neighboring elements of those neighbors. It evaluates the values using - * a provided functor and accounts for the valid (non-null) neighbors. - * - * @tparam T The data type for the values being computed. This is typically a scalar type. - * - * @param functor An object of a functor class derived from FunctorBase. This object provides the - * operator() method to compute the value at a given element and time. - * @param face An argument representing the face in the computational domain. The face provides - * access to neighboring elements via neighbor_ptr_range(). - * @param time An argument representing the state or time at which the evaluation is performed. - * @param component An unsigned integer representing the specific component of the container to be - * evaluated. - * - * @return std::pair A pair containing the minimum and maximum values of the specified - * component computed across the two-cell stencil. The first element is the maximum value, and the - * second element is the minimum value. - * - * This function performs the following steps: - * 1. Initializes max_value to 0 and min_value to a large value (1e10). - * 2. Iterates over the direct neighbors of the element associated with the face. - * - If a neighbor is valid (not null), it evaluates the functor at that neighbor for the - * specified component and updates max_value and min_value. - * 3. Iterates over the neighbors of the neighbors. - * - Similar to the first loop, it evaluates the functor at valid neighbors for the specified - * component and updates max_value and min_value. - * 4. Returns a pair containing the computed max_value and min_value. - * - * Usage: - * This function is typically used in the finite volume methods for min-max computations over - * stencils (neighborhoods). It helps compute the limiting for limited second order upwind at the - * faces. - */ -template -std::pair -containerComputeMinMaxValue(const FunctorBase & functor, - const FaceArg & face, - const StateArg & time, - const unsigned int & component) -{ - // Initialize max_value to 0 and min_value to a large value (1e10) - T max_value(0), min_value(1e10); - - // Iterate over the direct neighbors of the element associated with the face - for (auto neighbor : (*face.fi).elem().neighbor_ptr_range()) - { - // If not a valid neighbor, skip to the next one - if (neighbor == nullptr) - continue; - - // Evaluate the functor at the neighbor for the specified component and update max_value and - // min_value - const ElemArg local_cell_arg = {neighbor, false}; - const auto value = functor(local_cell_arg, time)[component]; - max_value = std::max(max_value, value); - min_value = std::min(min_value, value); - } - - // Iterate over the neighbors of the neighbor associated with the face - for (auto neighbor : (*face.fi).neighbor().neighbor_ptr_range()) - { - // If not a valid neighbor, skip to the next one - if (neighbor == nullptr) - continue; - - // Evaluate the functor at the neighbor for the specified component and update max_value and - // min_value - const ElemArg local_cell_arg = {neighbor, false}; - const auto value = functor(local_cell_arg, time)[component]; + const auto value = MetaPhysicL::raw_value(functor(local_cell_arg, time)(component)); max_value = std::max(max_value, value); min_value = std::min(min_value, value); } @@ -954,8 +874,8 @@ interpCoeffsAndAdvected(const FunctorBase & functor, const FaceArg & face, co phi_downwind, &zero, &zero, - T(0.0), - T(0.0), + std::numeric_limits::max(), + std::numeric_limits::min(), *face.fi, face.elem_is_upwind); } @@ -969,7 +889,7 @@ interpCoeffsAndAdvected(const FunctorBase & functor, const FaceArg & face, co time_arg = &temp_state; } - T max_value(0.0), min_value(1e10); + Real max_value(std::numeric_limits::min()), min_value(std::numeric_limits::max()); // Compute min-max values for min-max limiters if (face.limiter_type == LimiterType::Venkatakrishnan || face.limiter_type == LimiterType::SOU) @@ -1083,7 +1003,7 @@ interpolate(const FunctorBase & functor, const FaceArg & face, const StateArg } // Initialize min-max values - T max_value(0.0), min_value(1e10); + Real max_value(std::numeric_limits::min()), min_value(std::numeric_limits::max()); if (face.limiter_type == LimiterType::Venkatakrishnan || face.limiter_type == LimiterType::SOU) std::tie(max_value, min_value) = computeMinMaxValue(functor, face, *time_arg); @@ -1171,8 +1091,8 @@ interpolate(const FunctorBase> & functor, component_downwind, &grad_zero, &grad_zero, - T(0.0), - T(0.0), + std::numeric_limits::max(), + std::numeric_limits::min(), *face.fi, face.elem_is_upwind); ret(i) = coeff_upwind * component_upwind + coeff_downwind * component_downwind; @@ -1203,7 +1123,7 @@ interpolate(const FunctorBase> & functor, coeffs.second * grad_phi_downwind.row(i); // Initialize min-max values - T max_value(0.0), min_value(1e10); + Real max_value(std::numeric_limits::min()), min_value(std::numeric_limits::max()); if (face.limiter_type == LimiterType::Venkatakrishnan || face.limiter_type == LimiterType::SOU) std::tie(max_value, min_value) = computeMinMaxValue(functor, face, *time_arg, i); @@ -1263,23 +1183,18 @@ containerInterpolate(const FunctorBase & functor, const FaceArg & face, const typedef typename ContainerGradientType::value_type GradientType; const GradientType * const example_gradient = nullptr; - // Assert that the face information is non-null mooseAssert(face.fi, "this must be non-null"); - - // Construct the limiter based on the face limiter type const auto limiter = Limiter::build(face.limiter_type); - // Determine upwind and downwind arguments based on the face element const auto upwind_arg = face.elem_is_upwind ? face.makeElem() : face.makeNeighbor(); const auto downwind_arg = face.elem_is_upwind ? face.makeNeighbor() : face.makeElem(); const auto phi_upwind = functor(upwind_arg, time); const auto phi_downwind = functor(downwind_arg, time); - // Initialize the return container value + // initialize in order to get proper size T ret = phi_upwind; typename T::value_type coeff_upwind, coeff_downwind; - // Compute interpolation coefficients and advected values for Upwind or CentralDifference limiters if (face.limiter_type == LimiterType::Upwind || face.limiter_type == LimiterType::CentralDifference) { @@ -1289,10 +1204,10 @@ containerInterpolate(const FunctorBase & functor, const FaceArg & face, const std::tie(coeff_upwind, coeff_downwind) = interpCoeffs(*limiter, component_upwind, component_downwind, - /*grad_phi_upwind*/ example_gradient, - /*grad_phi_face*/ example_gradient, - T(0.0), - T(0.0), + example_gradient, + example_gradient, + std::numeric_limits::max(), + std::numeric_limits::min(), *face.fi, face.elem_is_upwind); ret[i] = coeff_upwind * component_upwind + coeff_downwind * component_downwind; @@ -1300,47 +1215,24 @@ containerInterpolate(const FunctorBase & functor, const FaceArg & face, const } else { - // Determine the time argument for the limiter - auto * time_arg = face.state_limiter; - if (!time_arg) - { - static Moose::StateArg temp_state(0, Moose::SolutionIterationType::Time); - time_arg = &temp_state; - } - - // Evaluate the gradient of the functor at the upwind and downwind locations - const auto & grad_phi_upwind = functor.gradient(upwind_arg, *time_arg); - const auto & grad_phi_downwind = functor.gradient(downwind_arg, *time_arg); - - const auto coeffs = interpCoeffs(InterpMethod::Average, *face.fi, face.elem_is_upwind); - - // Compute interpolation coefficients and advected values for each component + const auto grad_phi_upwind = functor.gradient(upwind_arg, time); for (const auto i : index_range(ret)) { const auto &component_upwind = phi_upwind[i], component_downwind = phi_downwind[i]; - const VectorValue &grad_upwind = grad_phi_upwind[i], - grad_face = coeffs.first * grad_phi_upwind[i] + - coeffs.second * grad_phi_downwind[i]; - - // Initialize min-max values - T max_value(0.0), min_value(1e10); - if (face.limiter_type == LimiterType::Venkatakrishnan || - face.limiter_type == LimiterType::SOU) - std::tie(max_value, min_value) = containerComputeMinMaxValue(functor, face, *time_arg, i); - - // Perform full limited interpolation for the component - ret[i] = fullLimitedInterpolation(*limiter, - component_upwind, - component_downwind, - &grad_upwind, - &grad_face, - max_value, - min_value, - face); + const auto & grad = grad_phi_upwind[i]; + std::tie(coeff_upwind, coeff_downwind) = interpCoeffs(*limiter, + component_upwind, + component_downwind, + &grad, + example_gradient, + std::numeric_limits::max(), + std::numeric_limits::min(), + *face.fi, + face.elem_is_upwind); + ret[i] = coeff_upwind * component_upwind + coeff_downwind * component_downwind; } } - // Return the interpolated container value return ret; } diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests index 1ceea5e1dfe0..ede120a78804 100644 --- a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests @@ -8,6 +8,7 @@ input = 'bottom_left_advection.i' exodiff = bottom_left_sou.e cli_args = 'GlobalParams/advected_interp_method=sou Outputs/file_base=bottom_left_sou' + abs_zero = 1e-4 detail = 'second-order upwind' [] [vanLeer] @@ -15,6 +16,7 @@ input = 'bottom_left_advection.i' exodiff = bottom_left_vanLeer.e cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=bottom_left_vanLeer' + abs_zero = 1e-4 detail = 'van Leer' [] [min_mod] @@ -22,6 +24,7 @@ input = 'bottom_left_advection.i' exodiff = bottom_left_min_mod.e cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=bottom_left_min_mod' + abs_zero = 1e-4 detail = 'min-mod' [] [quick] @@ -29,6 +32,7 @@ input = 'bottom_left_advection.i' exodiff = bottom_left_quick.e cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=bottom_left_quick' + abs_zero = 1e-4 detail = 'QUICK' [] [venkatakrishnan] @@ -36,6 +40,7 @@ input = 'bottom_left_advection.i' exodiff = bottom_left_venkatakrishnan.e cli_args = 'GlobalParams/advected_interp_method=venkatakrishnan Outputs/file_base=bottom_left_venkatakrishnan' + abs_zero = 1e-4 detail = 'venkatakrishnan' [] [] @@ -46,6 +51,7 @@ input = 'top_right_advection.i' exodiff = top_right_sou.e cli_args = 'GlobalParams/advected_interp_method=sou Outputs/file_base=top_right_sou' + abs_zero = 1e-4 detail = 'second-order upwind' [] [vanLeer] @@ -53,6 +59,7 @@ input = 'top_right_advection.i' exodiff = top_right_vanLeer.e cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=top_right_vanLeer' + abs_zero = 1e-4 detail = 'van Leer' [] [min_mod] @@ -60,6 +67,7 @@ input = 'top_right_advection.i' exodiff = top_right_min_mod.e cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=top_right_min_mod' + abs_zero = 1e-4 detail = 'min-mod' [] [quick] @@ -67,6 +75,7 @@ input = 'top_right_advection.i' exodiff = top_right_quick.e cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=top_right_quick' + abs_zero = 1e-4 detail = 'QUICK' [] [venkatakrishnan] @@ -74,6 +83,7 @@ input = 'top_right_advection.i' exodiff = top_right_venkatakrishnan.e cli_args = 'GlobalParams/advected_interp_method=venkatakrishnan Outputs/file_base=top_right_venkatakrishnan' + abs_zero = 1e-4 detail = 'venkatakrishnan' [] [] @@ -84,6 +94,7 @@ input = 'bottom_left_tri_mesh_advection.i' exodiff = bottom_left_tri_mesh_vanLeer.e cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=bottom_left_tri_mesh_vanLeer' + abs_zero = 1e-4 detail = 'van Leer' [] [min_mod] @@ -91,6 +102,7 @@ input = 'bottom_left_tri_mesh_advection.i' exodiff = bottom_left_tri_mesh_min_mod.e cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=bottom_left_tri_mesh_min_mod' + abs_zero = 1e-4 detail = 'min-mod' [] [quick] @@ -98,6 +110,7 @@ input = 'bottom_left_tri_mesh_advection.i' exodiff = bottom_left_tri_mesh_quick.e cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=bottom_left_tri_mesh_quick' + abs_zero = 1e-4 detail = 'QUICK' [] [] diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests index 5bf35ccbfade..e8247172bc4d 100644 --- a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests @@ -7,8 +7,13 @@ type = 'Exodiff' input = 'lid-driven-segregated.i' exodiff = 'upwind.e' +<<<<<<< HEAD detail = 'and pass debugging checks.' abs_zero = 1e-6 +======= + detail = 'and reach converged results with upwind advection scheme.' + abs_zero = 1e-4 +>>>>>>> a8e5e18f83 (completing argument definition for passing compile checks Refs #28891) cli_args = 'GlobalParams/advected_interp_method=upwind Outputs/file_base=upwind' heavy = true detail = 'first-order upwind test' @@ -17,8 +22,8 @@ type = 'Exodiff' input = 'lid-driven-segregated.i' exodiff = 'upwind_run.e' - detail = 'and reach converged results with segregated solvers.' - abs_zero = 1e-6 + detail = 'and pass debugging checks with segregated solvers with upwind advection scheme.' + abs_zero = 1e-4 cli_args = 'GlobalParams/advected_interp_method=upwind Executioner/num_iterations=10 Outputs/file_base=upwind_run' detail = 'first-order upwind run test' [] @@ -26,8 +31,8 @@ type = 'Exodiff' input = 'lid-driven-segregated.i' exodiff = 'vanLeer.e' - detail = 'and pass debugging checks.' - abs_zero = 1e-6 + detail = 'and reach converged results with van Leer limiter.' + abs_zero = 1e-4 cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=vanLeer' heavy = true detail = 'van Leer test' @@ -36,8 +41,8 @@ type = 'Exodiff' input = 'lid-driven-segregated.i' exodiff = 'vanLeer_run.e' - detail = 'and reach converged results with segregated solvers.' - abs_zero = 1e-6 + detail = 'and pass debugging checks with segregated solvers with van Leer limiter.' + abs_zero = 1e-4 cli_args = 'GlobalParams/advected_interp_method=vanLeer Executioner/num_iterations=10 Outputs/file_base=vanLeer_run' detail = 'van Leer run test' [] @@ -45,8 +50,8 @@ type = 'Exodiff' input = 'lid-driven-segregated.i' exodiff = 'min_mod.e' - detail = 'and pass debugging checks.' - abs_zero = 1e-6 + detail = 'and reach converged results with min-mod limiter.' + abs_zero = 1e-4 cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=min_mod' heavy = true detail = 'min-mod test' @@ -55,8 +60,8 @@ type = 'Exodiff' input = 'lid-driven-segregated.i' exodiff = 'min_mod_run.e' - detail = 'and reach converged results with segregated solvers.' - abs_zero = 1e-6 + detail = 'and pass debugging checks with segregated solvers with min-mod limiter.' + abs_zero = 1e-4 cli_args = 'GlobalParams/advected_interp_method=min_mod Executioner/num_iterations=10 Outputs/file_base=min_mod_run' detail = 'min-mod run test' [] @@ -64,8 +69,8 @@ type = 'Exodiff' input = 'lid-driven-segregated.i' exodiff = 'quick.e' - detail = 'and pass debugging checks.' - abs_zero = 1e-6 + detail = 'and reach converged results with QUICK limiter.' + abs_zero = 1e-4 cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=quick' heavy = true detail = 'QUICK test' @@ -74,8 +79,8 @@ type = 'Exodiff' input = 'lid-driven-segregated.i' exodiff = 'quick_run.e' - detail = 'and reach converged results with segregated solvers.' - abs_zero = 1e-6 + detail = 'and pass debugging checks with segregated solvers with QUICK limiter.' + abs_zero = 1e-4 cli_args = 'GlobalParams/advected_interp_method=quick Executioner/num_iterations=10 Outputs/file_base=quick_run' detail = 'QUICK run test' [] diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/tests b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/tests index 25d55f2a368d..946303391953 100644 --- a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/tests +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/tests @@ -8,6 +8,7 @@ input = 'test.i' exodiff = upwind.e cli_args = 'GlobalParams/advected_interp_method=upwind Outputs/file_base=upwind' + abs_zero = 1e-4 detail = 'first-order upwind' [] [sou] @@ -15,6 +16,7 @@ input = 'test.i' exodiff = sou.e cli_args = 'GlobalParams/advected_interp_method=sou Outputs/file_base=sou' + abs_zero = 1e-4 detail = 'second-order upwind' [] [vanLeer] @@ -22,6 +24,7 @@ input = 'test.i' exodiff = vanLeer.e cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=vanLeer' + abs_zero = 1e-4 detail = 'van Leer' [] [min_mod] @@ -29,6 +32,7 @@ input = 'test.i' exodiff = min_mod.e cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=min_mod' + abs_zero = 1e-4 detail = 'min-mod' [] [quick] @@ -36,6 +40,7 @@ input = 'test.i' exodiff = quick.e cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=quick' + abs_zero = 1e-4 detail = 'QUICK' [] [] diff --git a/modules/navier_stokes/unit/src/TestFaceCenteredMapFunctor.C b/modules/navier_stokes/unit/src/TestFaceCenteredMapFunctor.C index d74a47274750..7c7def4f9744 100644 --- a/modules/navier_stokes/unit/src/TestFaceCenteredMapFunctor.C +++ b/modules/navier_stokes/unit/src/TestFaceCenteredMapFunctor.C @@ -85,8 +85,8 @@ TEST(FaceCenteredMapFunctorTest, testArgs) for (auto & fi : all_fi) { const auto & face_center = fi.faceCentroid(); - const auto face_arg = - Moose::FaceArg{&fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr}; + const auto face_arg = Moose::FaceArg{ + &fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}; const auto result = u(face_arg, Moose::currentState()); @@ -128,8 +128,8 @@ TEST(FaceCenteredMapFunctorTest, testArgs) // Arguments for the simple error checks, we use the first face and the corresponding // owner element QGauss qrule(1, CONSTANT); - const auto face_arg = - Moose::FaceArg{&all_fi[0], Moose::FV::LimiterType::CentralDifference, true, false, nullptr}; + const auto face_arg = Moose::FaceArg{ + &all_fi[0], Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}; const auto elem_arg = ElemArg{all_fi[0].elemPtr(), false}; const auto elem_qp_arg = ElemQpArg({all_fi[0].elemPtr(), 0, &qrule, Point(0)}); const auto elem_side_qp_arg = ElemSideQpArg({all_fi[0].elemPtr(), 0, 0, &qrule, Point(0)}); @@ -148,7 +148,7 @@ TEST(FaceCenteredMapFunctorTest, testArgs) try { unrestricted_error_test( - FaceArg{&all_fi[2], LimiterType::CentralDifference, true, false, nullptr}, + FaceArg{&all_fi[2], LimiterType::CentralDifference, true, false, nullptr, nullptr}, Moose::currentState()); EXPECT_TRUE(false); } @@ -162,8 +162,9 @@ TEST(FaceCenteredMapFunctorTest, testArgs) restricted_error_test(*mesh, {1}, "is_restricted"); try { - restricted_error_test(FaceArg{&all_fi[2], LimiterType::CentralDifference, true, false, nullptr}, - Moose::currentState()); + restricted_error_test( + FaceArg{&all_fi[2], LimiterType::CentralDifference, true, false, nullptr, nullptr}, + Moose::currentState()); EXPECT_TRUE(false); } catch (std::runtime_error & e) diff --git a/modules/navier_stokes/unit/src/TestReconstruction.C b/modules/navier_stokes/unit/src/TestReconstruction.C index 9c9d385980d9..65c381f07d80 100644 --- a/modules/navier_stokes/unit/src/TestReconstruction.C +++ b/modules/navier_stokes/unit/src/TestReconstruction.C @@ -115,8 +115,8 @@ testReconstruction(const Moose::CoordinateSystemType coord_type) { auto moukalled_reconstruct = [&fi](auto & functor, auto & container) { - auto face = - Moose::FaceArg({&fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr}); + auto face = Moose::FaceArg( + {&fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr}); const RealVectorValue uf(functor(face, Moose::currentState())); const Point surface_vector = fi.normal() * fi.faceArea(); auto product = (uf * fi.dCN()) * surface_vector; From 678cf6dd00a300bc170089ff27a3572622244162 Mon Sep 17 00:00:00 2001 From: Mauricio Tano Date: Tue, 29 Oct 2024 09:23:37 -0600 Subject: [PATCH 11/20] Apply suggestions from giudgiud code review 1 Refs #28891 Co-authored-by: Guillaume Giudicelli regolding tests to latest mods in limiters and avoid testing unnecessary recovers Refs #28891 --- framework/doc/content/bib/moose.bib | 1 + framework/include/limiters/Limiter.h | 3 +- framework/include/variables/MooseVariableFV.h | 2 +- ...left_advection.i => cartesian_advection.i} | 9 +- .../limiters/dispersion-test/tests | 62 +++++------ .../dispersion-test/top_right_advection.i | 99 ------------------ ..._mesh_advection.i => tri_mesh_advection.i} | 9 +- .../limiters/lid-driven-segregated/tests | 25 ++--- .../limiters/lid-driven/gold/min_mod.e | Bin 0 -> 88408 bytes .../limiters/lid-driven/gold/quick.e | Bin 0 -> 88404 bytes .../limiters/lid-driven/gold/sou.e | Bin 0 -> 88404 bytes .../limiters/lid-driven/gold/upwind.e | Bin 0 -> 88408 bytes .../limiters/lid-driven/gold/vanLeer.e | Bin 0 -> 88408 bytes .../finite_volume/limiters/lid-driven/test.i | 8 +- .../finite_volume/limiters/lid-driven/tests | 10 +- 15 files changed, 67 insertions(+), 161 deletions(-) rename modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/{bottom_left_advection.i => cartesian_advection.i} (92%) delete mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/top_right_advection.i rename modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/{bottom_left_tri_mesh_advection.i => tri_mesh_advection.i} (94%) create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/gold/min_mod.e create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/gold/quick.e create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/gold/sou.e create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/gold/upwind.e create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/gold/vanLeer.e diff --git a/framework/doc/content/bib/moose.bib b/framework/doc/content/bib/moose.bib index 623d99ddf788..6d947f08e73d 100644 --- a/framework/doc/content/bib/moose.bib +++ b/framework/doc/content/bib/moose.bib @@ -620,6 +620,7 @@ @article{rao2018stopping doi = {https://doi.org/10.1016/j.jcp.2017.09.033}, url = {https://www.sciencedirect.com/science/article/pii/S0021999117306939}, author = {Kaustubh Rao and Paul Malan and J. Blair Perot} +} @inproceedings{venkatakrishnan1993, title={On the accuracy of limiters and convergence to steady state solutions}, diff --git a/framework/include/limiters/Limiter.h b/framework/include/limiters/Limiter.h index 1ab0ce4b8938..915dc0cb29dd 100644 --- a/framework/include/limiters/Limiter.h +++ b/framework/include/limiters/Limiter.h @@ -240,6 +240,7 @@ class Limiter /** * @brief Computes the flux limiting ratio using gradients. + * This method works well for incompressible and compressible flow. * * This function calculates the flux limiting ratio based on the provided gradients * at the upwind and downwind locations, along with a direction vector. @@ -255,8 +256,6 @@ class Limiter * 2. Computes the dot product of the downwind gradient vector with the direction vector `dCD`. * 3. Calculates the ratio of the upwind gradient dot product to the downwind gradient dot * product, adding a small epsilon value to the denominator to prevent division by zero. - * 4. Applies a flux limiting formula to this ratio to ensure it remains within a physically - * reasonable range, specifically ensuring non-negative values. * * @note The small epsilon value `1e-10` is added to the denominator to avoid division by zero * and numerical instability. diff --git a/framework/include/variables/MooseVariableFV.h b/framework/include/variables/MooseVariableFV.h index 84541b179b7c..b4b3096e6ca8 100644 --- a/framework/include/variables/MooseVariableFV.h +++ b/framework/include/variables/MooseVariableFV.h @@ -651,7 +651,7 @@ class MooseVariableFV : public MooseVariableField const Elem * elem_side_to_extrapolate_from, const StateArg & state) const; - /// Function to get the two term boudnary exansion for the variable + /// Function to get the two term boundary expansion for the variable const bool & getTwoTermBoundaryExpansion() const { return _two_term_boundary_expansion; } protected: diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/bottom_left_advection.i b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/cartesian_advection.i similarity index 92% rename from modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/bottom_left_advection.i rename to modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/cartesian_advection.i index 55f731b30c1f..7a684b457220 100644 --- a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/bottom_left_advection.i +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/cartesian_advection.i @@ -88,12 +88,15 @@ petsc_options_value = 'lu NONZERO' dt = 0.1 end_time = 5.0 - steady_state_detection = false + steady_state_detection = true steady_state_tolerance = 1e-12 nl_abs_tol = 1e-12 [] [Outputs] - exodus = true - csv = true + [out] + type = Exodus + execute_on = 'final' + hide = 'vel_x vel_y pressure' + [] [] diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests index ede120a78804..6c2b7f5dcb5e 100644 --- a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests @@ -5,42 +5,42 @@ requirement = 'The system shall be able to perform a variety of limiting schemes when solving scalar transport equations in cartesian meshes with bottom-left advection. These schemes include' [sou] type = Exodiff - input = 'bottom_left_advection.i' + input = 'cartesian_advection.i' exodiff = bottom_left_sou.e cli_args = 'GlobalParams/advected_interp_method=sou Outputs/file_base=bottom_left_sou' - abs_zero = 1e-4 + abs_zero = 1e-5 detail = 'second-order upwind' [] [vanLeer] type = Exodiff - input = 'bottom_left_advection.i' + input = 'cartesian_advection.i' exodiff = bottom_left_vanLeer.e cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=bottom_left_vanLeer' - abs_zero = 1e-4 + abs_zero = 1e-5 detail = 'van Leer' [] [min_mod] type = Exodiff - input = 'bottom_left_advection.i' + input = 'cartesian_advection.i' exodiff = bottom_left_min_mod.e cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=bottom_left_min_mod' - abs_zero = 1e-4 + abs_zero = 1e-5 detail = 'min-mod' [] [quick] type = Exodiff - input = 'bottom_left_advection.i' + input = 'cartesian_advection.i' exodiff = bottom_left_quick.e cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=bottom_left_quick' - abs_zero = 1e-4 + abs_zero = 1e-5 detail = 'QUICK' [] [venkatakrishnan] type = Exodiff - input = 'bottom_left_advection.i' + input = 'cartesian_advection.i' exodiff = bottom_left_venkatakrishnan.e cli_args = 'GlobalParams/advected_interp_method=venkatakrishnan Outputs/file_base=bottom_left_venkatakrishnan' - abs_zero = 1e-4 + abs_zero = 1e-5 detail = 'venkatakrishnan' [] [] @@ -48,42 +48,42 @@ requirement = 'The system shall be able to perform a variety of limiting schemes when solving scalar transport equations in cartesian meshes with top-right advection. These schemes include' [sou] type = Exodiff - input = 'top_right_advection.i' + input = 'cartesian_advection.i' exodiff = top_right_sou.e - cli_args = 'GlobalParams/advected_interp_method=sou Outputs/file_base=top_right_sou' - abs_zero = 1e-4 + cli_args = "GlobalParams/advected_interp_method=sou Outputs/file_base=top_right_sou AuxVariables/vel_x/initial_condition=-1.0 AuxVariables/vel_y/initial_condition=-1.0 FVBCs/fv_inflow/boundary='right' FVBCs/fv_outflow/boundary='left top bottom'" + abs_zero = 1e-5 detail = 'second-order upwind' [] [vanLeer] type = Exodiff - input = 'top_right_advection.i' + input = 'cartesian_advection.i' exodiff = top_right_vanLeer.e - cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=top_right_vanLeer' - abs_zero = 1e-4 + cli_args = "GlobalParams/advected_interp_method=vanLeer Outputs/file_base=top_right_vanLeer AuxVariables/vel_x/initial_condition=-1.0 AuxVariables/vel_y/initial_condition=-1.0 FVBCs/fv_inflow/boundary='right' FVBCs/fv_outflow/boundary='left top bottom'" + abs_zero = 1e-5 detail = 'van Leer' [] [min_mod] type = Exodiff - input = 'top_right_advection.i' + input = 'cartesian_advection.i' exodiff = top_right_min_mod.e - cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=top_right_min_mod' - abs_zero = 1e-4 + cli_args = "GlobalParams/advected_interp_method=min_mod Outputs/file_base=top_right_min_mod AuxVariables/vel_x/initial_condition=-1.0 AuxVariables/vel_y/initial_condition=-1.0 FVBCs/fv_inflow/boundary='right' FVBCs/fv_outflow/boundary='left top bottom'" + abs_zero = 1e-5 detail = 'min-mod' [] [quick] type = Exodiff - input = 'top_right_advection.i' + input = 'cartesian_advection.i' exodiff = top_right_quick.e - cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=top_right_quick' - abs_zero = 1e-4 + cli_args = "GlobalParams/advected_interp_method=quick Outputs/file_base=top_right_quick AuxVariables/vel_x/initial_condition=-1.0 AuxVariables/vel_y/initial_condition=-1.0 FVBCs/fv_inflow/boundary='right' FVBCs/fv_outflow/boundary='left top bottom'" + abs_zero = 1e-5 detail = 'QUICK' [] [venkatakrishnan] type = Exodiff - input = 'top_right_advection.i' + input = 'cartesian_advection.i' exodiff = top_right_venkatakrishnan.e - cli_args = 'GlobalParams/advected_interp_method=venkatakrishnan Outputs/file_base=top_right_venkatakrishnan' - abs_zero = 1e-4 + cli_args = "GlobalParams/advected_interp_method=venkatakrishnan Outputs/file_base=top_right_venkatakrishnan AuxVariables/vel_x/initial_condition=-1.0 AuxVariables/vel_y/initial_condition=-1.0 FVBCs/fv_inflow/boundary='right' FVBCs/fv_outflow/boundary='left top bottom'" + abs_zero = 1e-5 detail = 'venkatakrishnan' [] [] @@ -91,26 +91,26 @@ requirement = 'The system shall be able to perform a variety of limiting schemes when solving scalar transport equations in triangular meshes with bottom-left advection. These schemes include' [vanLeer] type = Exodiff - input = 'bottom_left_tri_mesh_advection.i' + input = 'tri_mesh_advection.i' exodiff = bottom_left_tri_mesh_vanLeer.e cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=bottom_left_tri_mesh_vanLeer' - abs_zero = 1e-4 + abs_zero = 1e-5 detail = 'van Leer' [] [min_mod] type = Exodiff - input = 'bottom_left_tri_mesh_advection.i' + input = 'tri_mesh_advection.i' exodiff = bottom_left_tri_mesh_min_mod.e cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=bottom_left_tri_mesh_min_mod' - abs_zero = 1e-4 + abs_zero = 1e-5 detail = 'min-mod' [] [quick] type = Exodiff - input = 'bottom_left_tri_mesh_advection.i' + input = 'tri_mesh_advection.i' exodiff = bottom_left_tri_mesh_quick.e cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=bottom_left_tri_mesh_quick' - abs_zero = 1e-4 + abs_zero = 1e-5 detail = 'QUICK' [] [] diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/top_right_advection.i b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/top_right_advection.i deleted file mode 100644 index c45521297532..000000000000 --- a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/top_right_advection.i +++ /dev/null @@ -1,99 +0,0 @@ -[GlobalParams] - advected_interp_method = 'min_mod' #average upwind sou min_mod vanLeer quick venkatakrishnan skewness-corrected - velocity_interp_method = 'average' -[] - -[UserObjects] - [rc] - type = INSFVRhieChowInterpolator - u = vel_x - v = vel_y - a_u = vel_x - a_v = vel_y - pressure = pressure - velocity_interp_method = 'rc' - [] -[] - -[Mesh] - [gen] - type = GeneratedMeshGenerator - dim = 2 - xmin = 0 - xmax = 1 - ymin = 0 - ymax = 1 - nx = 10 - ny = 10 - [] -[] - -[AuxVariables] - [vel_x] - type = INSFVVelocityVariable - initial_condition = -1.0 - [] - [vel_y] - type = INSFVVelocityVariable - initial_condition = -1.0 - [] - [pressure] - type = INSFVPressureVariable - initial_condition = 1.0 - [] -[] - -[Variables] - [scalar] - type = INSFVScalarFieldVariable - two_term_boundary_expansion = false - [] -[] - -[FVKernels] - [scalar_advection] - type = INSFVScalarFieldAdvection - variable = scalar - rhie_chow_user_object = 'rc' - [] -[] - -[FVBCs] - [fv_inflow] - type = NSFVOutflowTemperatureBC - u = vel_x - v = vel_y - backflow_T = 1.0 - rho = 1.0 - cp = 1.0 - variable = scalar - boundary = 'right' - [] - [fv_outflow] - type = NSFVOutflowTemperatureBC - u = vel_x - v = vel_y - backflow_T = 0.0 - rho = 1.0 - cp = 1.0 - variable = scalar - boundary = 'left top bottom' - [] -[] - -[Executioner] - type = Transient - solve_type = 'NEWTON' - petsc_options_iname = '-pc_type -pc_factor_shift_type' - petsc_options_value = 'lu NONZERO' - dt = 0.1 - end_time = 5.0 - steady_state_detection = false - steady_state_tolerance = 1e-12 - nl_abs_tol = 1e-12 -[] - -[Outputs] - exodus = true - csv = true -[] diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/bottom_left_tri_mesh_advection.i b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tri_mesh_advection.i similarity index 94% rename from modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/bottom_left_tri_mesh_advection.i rename to modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tri_mesh_advection.i index 5266b809c0a2..7f0e533a9faa 100644 --- a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/bottom_left_tri_mesh_advection.i +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tri_mesh_advection.i @@ -103,12 +103,15 @@ petsc_options_value = 'lu NONZERO' dt = 0.1 end_time = 5.0 - steady_state_detection = false + steady_state_detection = true steady_state_tolerance = 1e-12 nl_abs_tol = 1e-12 [] [Outputs] - exodus = true - csv = true + [out] + type = Exodus + execute_on = 'final' + hide = 'vel_x vel_y pressure' + [] [] diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests index e8247172bc4d..103b1c91d405 100644 --- a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests @@ -7,16 +7,11 @@ type = 'Exodiff' input = 'lid-driven-segregated.i' exodiff = 'upwind.e' -<<<<<<< HEAD - detail = 'and pass debugging checks.' - abs_zero = 1e-6 -======= detail = 'and reach converged results with upwind advection scheme.' abs_zero = 1e-4 ->>>>>>> a8e5e18f83 (completing argument definition for passing compile checks Refs #28891) cli_args = 'GlobalParams/advected_interp_method=upwind Outputs/file_base=upwind' + prereq = segregated_advection_limiting_schemes/upwind_run heavy = true - detail = 'first-order upwind test' [] [upwind_run] type = 'Exodiff' @@ -24,8 +19,8 @@ exodiff = 'upwind_run.e' detail = 'and pass debugging checks with segregated solvers with upwind advection scheme.' abs_zero = 1e-4 + rel_err = 1e-4 cli_args = 'GlobalParams/advected_interp_method=upwind Executioner/num_iterations=10 Outputs/file_base=upwind_run' - detail = 'first-order upwind run test' [] [vanLeer] type = 'Exodiff' @@ -33,9 +28,9 @@ exodiff = 'vanLeer.e' detail = 'and reach converged results with van Leer limiter.' abs_zero = 1e-4 - cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=vanLeer' + cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=vanLeer Outputs/file_base=vanLeer Mesh/gen/nx=10 Mesh/gen/ny=10' + prereq = segregated_advection_limiting_schemes/vanLeer_run heavy = true - detail = 'van Leer test' [] [vanLeer_run] type = 'Exodiff' @@ -43,8 +38,8 @@ exodiff = 'vanLeer_run.e' detail = 'and pass debugging checks with segregated solvers with van Leer limiter.' abs_zero = 1e-4 - cli_args = 'GlobalParams/advected_interp_method=vanLeer Executioner/num_iterations=10 Outputs/file_base=vanLeer_run' - detail = 'van Leer run test' + rel_err = 1e-4 + cli_args = 'GlobalParams/advected_interp_method=vanLeer Executioner/num_iterations=10 Outputs/file_base=vanLeer_run Mesh/gen/nx=10 Mesh/gen/ny=10' [] [min_mod] type = 'Exodiff' @@ -53,8 +48,8 @@ detail = 'and reach converged results with min-mod limiter.' abs_zero = 1e-4 cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=min_mod' + prereq = segregated_advection_limiting_schemes/min_mod_run heavy = true - detail = 'min-mod test' [] [min_mod_run] type = 'Exodiff' @@ -62,8 +57,8 @@ exodiff = 'min_mod_run.e' detail = 'and pass debugging checks with segregated solvers with min-mod limiter.' abs_zero = 1e-4 + rel_err = 1e-4 cli_args = 'GlobalParams/advected_interp_method=min_mod Executioner/num_iterations=10 Outputs/file_base=min_mod_run' - detail = 'min-mod run test' [] [quick] type = 'Exodiff' @@ -72,8 +67,8 @@ detail = 'and reach converged results with QUICK limiter.' abs_zero = 1e-4 cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=quick' + prereq = segregated_advection_limiting_schemes/quick_run heavy = true - detail = 'QUICK test' [] [quick_run] type = 'Exodiff' @@ -81,8 +76,8 @@ exodiff = 'quick_run.e' detail = 'and pass debugging checks with segregated solvers with QUICK limiter.' abs_zero = 1e-4 + rel_err = 1e-4 cli_args = 'GlobalParams/advected_interp_method=quick Executioner/num_iterations=10 Outputs/file_base=quick_run' - detail = 'QUICK run test' [] [] [] diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/gold/min_mod.e b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/gold/min_mod.e new file mode 100644 index 0000000000000000000000000000000000000000..530874a05e8e98b965e7064e07152cf9fbf09fc1 GIT binary patch literal 88408 zcmeG_349Y(^Wi?Er5tjJvVw9`prxFqo6=G!6ezUZN17(vHjrdPjvgqAD3qf>@sB8e z%Bcd1A{0?Md;x)iqMV9=pNJ@;pn#~KqT+vMk6hiP-EH`P@TdD@*xBjsWZt}a@6DTc z#U~_IRjE`}0O|tV3sBp{ShNN*Iu4_m(b^r175*q(wJc7v)?hT_BYs~8pDnC` zvGXq!!L2sZ7!!jpgG{I@0FoY(T39!0F9s$zMvFt6%i0W}pXtaO^@Vv-8=y|6(FD5Z|KRmE{Cgv_ zF3)Jj{01A*f^b=mY#_V8rvR@9%zO3#qtQ8>n5`mjKvgvyMu!Q15H7Txx@O2tGi!(x zXqZQ>kTT;_fRJB!gnM1hdN)ty*9k>{d@RsS-&TK ze;MAbV=w)CXb0lu{d<1_u{ON#{d@RsIe)J%zE@Mvf_3C^>`^CZo8kqsSD(p0)NKiO z{#`7Iy#4~b8~!5v9rcdtMZ3WK7xPGzt*$oFXfln~nVh^q;5+#HcmXb=jqrC-r{26o z{g;!Mke#Z=952w9H!o4QGI=#aUUgA-Zf<-!F&%i7lb`r{OXOD%>sBpRG-e%E!~XdJ z38|_9I$RHMY02d}jhtY|T*w!B z@ofWAz_y|KI>2F7hT+Zk+oI|6z5ej8ohZ%3id_;Lhoz1E@2fM=8y>pxKsfO7dK z*k2^36WY>DR%>JQP#cSNW+R|C#+QYws;bHZSU%v2#5<-RFT8t$NWM4*dzd<#glct0upUA+Gr|2nBDE#A)w?~C_uxX&li;{7|} zd-485g`t9~ys(uvf$xz+JdhAx+Px{s0p?((Y-CK1R+m%~& z7u$(jbr%?jj?EqF-HJkOc-OEV!RT^mzw}I1!xA)9H0fjeE=;1?gw}PpcMcG@E|~I zfHnXR0Xz)Q7N8wKdw>oA9RWH4bOz`G5DCx~pc?>&gfZ@o@obD!#{l#M=mpRlpbtP_ zfPMgv0H^_C0cZdXKpa4SfOvoefB^uB00RLA0VDwo1{ea63@{V`1I)t#QUFE(j08vp zNCOxJFdASCz*vBB0OJ8B089j!1TYyu3y=<=1IPf-0~i1pfJ}fafNTIGz!ZR~044zR z)-3=m06K5e0Bitu0Q6;?0674;0C@m7VmBS&QGmw)W&k`6@C3k2fF}WF0XzlpG{9_t zIRFI!a{=Z7%m-KiPzbOPU=hG#fFgh@096610aO?88gQ>E&=9W$P+OoOUI(DAKtuc< zfO-NA@i2gJfrfZ}fCzzxxM*`oLtL~y(GEo$Yz%)xT(m{BOOz3173~snlojn0X^5k& zXsbv=9A!njMH=ELE7~y95Jy?jo{@$)%0&Sn4RMs~K>$j?QLfeiNJAXuY6E~Y#If8w z1b{RwJ1Ez~0Br>vLkz*rvN$wAPsSps|x_q z5J$Np0g#3`%GDJBX^5k&-2jk=GNP>A0ipyPWySJ|G{jNX9so!~9A%9GKpNsGYfk{A zA&zokc}5!IC>NG(q#=%S^#MQ{;wTrEd88qZa`gj18saGHBLGN48Bs1ZK&*hHT(m$# z9OcpgAPsSpD-J*-;3!vr0Hh&~a>WB64RMq!0RU-;qg(?3kcK$Ql?Z?|#8Iw+07yd| zWgP^7G?Wo#O#&D!;3(G+frhvSAQ=E@h@)IX0g#3`$~6oCX^5j-!vT`5NL>_tTO?ShB(Ul zB*07oM_Fe9APsSp^(g?PA&#;>4S+P15oMhXFh{^q)&hZsILbO#pdpU3&J$>eqpb4< z8saF|0)dA3On^cFq#=%SEd)Rs;waZ50Hh&~axDfx8saEx5dhMv08|C222dTK20%@K zS^%{H>HyRQxCfvfKo~$cKz)D+fCc~!0U7}`2DlfX2|!bTW&q6rS^(S!&=TN&fCm6t z0Z;%B0<;Eb1Mm>Q!vJjo+5xl&=m5|Wpc6o6fGz-$09^sP0dxn50*D6a0T2Vw6QCDB zZ-71keF6FbJOZEwhy|blGyrh`{Q=?u5&#AOBmxWs7zB_6Fc@G6Kr+BkfMEc`0a5@) z0E`4k1xN!J1uz<548T}`aRB21CICzXm;^8xKnsu#paaMN&;u9%7=TQGEP!kPBfu1Z zsQ@MbGk^tv1+W5$_AS~m+OBA$XqRYh*eCF%&% zj%h+!Q3m||@`9YSVVcSdn67#NXq&A8(3a3f;sG#EF|RNW@b^(qLv`JJ^+>xEFV}l@V60~0XzhNHjH+OwubhT4uJWLdG|Cx5x{JKIRFI!a{=Z7%m-Ki zPzbOPU=hG#0DK?iLD{j~VOhfRfi{nJjJBBpfcY{VV2;(s*zHam+TC4wVS%}uFRU!? z@(arg2W=!SRYdWy=EZ9xTn#6#ccnZ8!Fz$=p2lJ%E+gN4j-O6fNG;U`{{?@Pg?GZXmFUoyWk3K&xHtl6xy7^q~JQclI$vYckd;;>WjC)MDiu7)pvUbRNz zlP;?5s;6UfSG%Z1uTNO_*=kqwlrKJQko%hJp4KNLFV<;A(wj9^hn;FnbI^x+kTGasLOElzYR!xzn>DC~DdW^|r^D)m-{YpMXXxyV`!8L(Fg6=7 zY{A+n4rgs$SeO-WgGB{EFc~u(tWBTY#lYkk^$exAI#D;H`RVjj5=^<{G~$Z;`jJ1{ z7OZjg`)KR=I#p9#QKJ$;Fa{>hPvzdSnPEOXYw4@Hl=0r4SB7Y!;yxJiQjhkUetVX@ zRd{H2trowdrxBx@*LYmXA#sZgUOUUUI$h&@ry~FV=4{Ss(8{1 zs!Ve-)G#)O>K;XPkLeo|)3Q#{jjFoOpO~4!;H^`hv2f0S?>P^-+k6|Ah^e%b#KdF7UH2RI~Y4FXH zXGOMN#Bw=GnpS& zjypk$8s*(%=&^uoQlB|9|E;<{c{-gChPRd!O$THF#J(Qu1X6we?7Qa^R;+&#SuF zNXb{%mv+!}A$woUzP@fHUHAKM)kskb>cYa}_sFti-=Af_aFODi zswpqigt(S2YT0)3ePr+DFGoFf?@UrsHR_A#36oSM|5{K#XD~%dYDE8a--oBk-k&=@ zRx>h>xL#OdJ&^DvDSl!s`^-~I$g;DKhKGOEjI3Cby>N13G}+d+=a6eBmXP-kJTj!y zcV~$!J?gd9EhtLsv>2y38Ldu_#h9D2?)LGp_*I&sj24tFhml~0BsJCE!fFjn zrp{?{bWoB1e6y9*X6R)}qc@%g5+%hdS%TZ}@>e_xHEw_H>M+Pd7Ye%&q@#`uGON z&F59yVsGx0VhA&wJ>q(j++R=9W9ChnccwQnHQD{-oDs{2<@(TT>B(D(VP5U4&b3$G zzxj~K!_eUHaPh)C4A;hfaxjceifKS*UCd=qKe>(+&HA8mT=h%jnVo5|hUA{4Fn%Ct z&cx4y6t4yl;!lYKFCv?b^V5Dw2eWZP^Js=uZLEH(n~g_QKMAe$_UQ57wLkMXz4796pLP3d zH(kB1y2e{u3E6nAPScAw+PWFSq;Y7|Jd8xlqr<}oo98>}{m#M8qkRhL-8(;DS5&Z* zE{<7oBXVzTy5TcD!w(;PoKO@lWq>MH%W)Lhc=4APzj~(>>jECPEcUVIo zYvr6$T&SjxY>9k)t1*o(`8s>M`Rr->-6<5sEhGudRbbemB>w8_WWTZC=lLfN(TDHd zyK~;N*XR?gPlXNJ@*{m@<%@kr9c>iEos1q^*`JQLlo)?f6o;)uvE{@O_&IGp(`RA2PYl~rPok5khdej4!f=F>Z9 zYSP0EdVjQ?Z1`lw<|&JQB|D#KRnTr+S90LvC2t=4xE?vSZNl=O*S99ev`tzrn|7Ao zbD;f7*Y5*pS0h86Le)p~misS_ty8UlUXxmHTJeU7^rD6F?|%Nz({$}2_k6m1XgXOm z_Db^JHj~Mk`0+WLRv#o=?wz&%)#76VjdtOb@cdSwn4Jvo<*8oPXK<<{6` zas`I=;Th;y^P2HWERV`ha+!vmX46^hMkwxON{25%rev@-s2VI~LPvmWj-lx*H&=g#R-;}AOJ5c7;*ufQA@oml z7U(~ezC0Cd`I5~u#NLEnYuD>w!LPSf1AqAp_1TPms#fRBD=i&TWT;O_GIU13J%ok9 zynK+~K1r8vhv+PUcf&1jhNa#*=#go;rWJDAq%&t2bXxGj?I0>fwaUEsvh2^$q?UDjpTwH`JeeL|9%E-~dcLzTN-w(`!Fhm(LQme9t4&*@I6hc72#Hw=81@1iJ! z5h_=Q)@p^ddawxB!-~h`n~lL}$BvXwDTX+t(clCx)WX`#TFz3-Ymg`*&rm4E72w6` z1Q<#?nqtx+$&qqe6=Vq2miT$;J7!9!XgOvB42_o3j6@2T%iYUWNQ5La7OrzEGVs3x z!}8gS@D})o7K0W$68@ZoXEhZgm!ZuDi>RSZkxsjO3B6kpi2}{(P*z#?VQ9)?ZAM47 z*^_=X#T#gO(@jy{3^O4<1#7;cc(~nn`9;s0AvUB&Pag&4te6fl3Kvp_5_K4tDYB|B zV;1O)!F9$)v~ar?6bX%>gB4pt2;+@NKn*bB6;xCmIJ`B6TRbH!6p@dR3 zzndek!}1qDUUf1BBeYnIW#GdPMc<(Whsxs6ORNH!#f1g!(IBhfhuATFWgSyhu^7sR_tvVJ)ak zSn+KIkIu@vy*kJg8F|bzgeauV;j}^|ow2$r1u^OJD+dd2*#={dr2U}Tbdpsc3Jg&^ zDUOOI3}oG$VasauK*B)D<;@0?++9x51BP5hjeUtyS)#_RNs*DoykVPQHv$u9gdxjiiJD)uYfLiJMOG8wDRj`mfI*)u#;2nquL0nS9<;*H zC7TYFB5QJTkz#`}Gn02-GxEVhK`F~!KS1RGTe)PxSd>&2bD2_pX85Z-L&<7^SEKy; zkcH$KjJhn=g4=9BOV7n!#5NR?TmDkQOUUwLb?$8SL*!=)*JNm601;w95_+s4Lr5}= z^LY!YrrLF}>iISTkxb}lf@=Yz0+|ku+RoPiD85k>B`n>W0){3hHEj5>@dHK<_xsqF z75@Yb`LIPGe}pS3GK#aCp@gr=rCfe43lau$aO9K{-fY}`JZUFKe&qmFjV_N1APG6> zoySUCVvZpMEZiQaKSQ4Z8mWx+p-~j{XBh|9DbknxOyN4n+8n!fiq0Ke0yhi>vbkSS z$Pjz)Fp&V6vKdC51sa1a7@lWr3MvPX5PchdI0^^yeUt7t{NbZ7sRz`d)6V#Wi9s&U zr6kFv8FDSP;ND^T3Sp{pd7B_Ij8+Iiv@9D7E?p_(kzak;A&TN#V|mgGn3^)0ttO-1 z=;*@0v<#b+-n?lb;Z&nl%j97o7RN^UAdQEod>z^?jNP0G-UF&qDwpN9dVI7wpx3UZ zh7A~#HXLXBmFt2egN7WqL82#_-k5wlgiYo6Fs!r>E5G^zhQUHX3NnQ&cmX3fN*FRa zLq4}RA_D`{4hSZK`MA|6zX<@p#>0@WC%nb2poEYyFreV=Aaa=^t6PEM;NGJ~)}Vzr zn7=n7zbtz*o~a?*OWej1gRhv3=I8@tw$X?75E|=x@0-!gR0doVrc=(`lC4?dM+x(i4IJ$qlJ%nPG zXGk3f{_uDC0b@>rz-lVT2)JCsmN#c9uxPjHFBCN)vMWrRvYWue$qPZ|pb-b1O2$nj z^UD&C1f|o741-Q3lV4+(F)=}Y^;O2i1o;hp88dD$$*GB>hq0-UZDU}ZxIeDt2z;Rq zp{tA$8ypXSu}s)6o9nX+lk=45kefuNv*jc6QWy5Un+d7EiH&6-Iu}20lm}xcX z^xWjCQcbfG34@O8DajNj4_ZFx>o{!2yi)TT6-mf3^vw&mE|oCEXsM5r>E;HA+%^Tj z6}w8_eB8Ja9R|=I&r?m=^TC%g2R3Ejzu;Hc)QhHLfO+vS-`jI3NwVnCc({0BYRc&= zLK#o^X@LCYxvD7$(xSst1|#v$SYtZYVk z5dxA%nCT1)<8(Q!(QA#XlAx|HLvCu2M^GgU@50VwRyJ#gWlg$#sl~VDT+QURBh>!w z-+9Ed2DLB&2$tt*?aoYCdEl`c1!JQyg(us{z~l*7XAQAVSO~%`ffRYFDO>rci-RWd zJ6kp@eqQ>nB&cg=V6T@zmy!@c$b-7bkl#9mg*^;lARHzWxM#~Nm5^VDX~8A$uZ!4ZW8nVugVWD;s*$g69&WBCy}0#o;uU85zMZL*CF=Mn!OO zzIUd`ogoQ^oec|cU~fyC(a!DpV)gD!DhUKtI!m4mLG1r$n8hpe zP2o<`<-hRDkoz{3ahr-y#=GO=HvjeMf_G=!#)(TFD;Td4s}HOkD&o$Gl8F3N$gt9# zLoIkNKX)!g$UV2t{1N;zeH)L-Aa+{> zfsdRDoc-4$ zOKwTT0*z(4(iK51crHIzBmp)!a@vE;xxp`Qe^QLlk-~R5L*~ukN z`ahVAC#zvbE@r3Xqz?WE)D%Q$&9J|GIVT$7R~9DMA?||CbMg9Li5=dJ4yTvON});u z<9Fk%s#1#cA}G;e8Pl|6l{^*767p$Uxn3zOh00Iz9pPi=+%}`PUXqASHD*GkkL_!U zem-{P=&fiho;xb+4shBlM{j+iy7DVnin{%M?Eh<*SYp!#Pr)dKVM)3D{lm&x_jlf` z`~UjF{JV4XHs`h(z4b`qu63}ssdVR13!cl*ovR$Zbz6%YL1k5r-g-<1vAc5gR*7#@ zIeP1DI7;G&cVp~JIQhw2b#7cu{nve)J0!B?9y9$fkKX2J-I9on3g%{|E8@0k4)JqE zDo1ZcWAWTkPri|*5NvKxIeHs{ZIQU64l74*#S*Qgp}+k@Rh6T+x8a@`p`R`&8nM(} zNtF0*^kAiQC(@MYu#C~$|GG;|QMdQ#?VYd*8*YKl+J?gRE^zSeZMYX3zX_YO!o3N% zKZgaP9P3kj^&;%W=1a79<)#iH!^&<2YQb~CxfKZm84K8yKG9cc?tJh;@XL@dClNhE zk62!qlKK#G88$+)IN)?~FHQmqr-lt5HozxUK_Bol1EV+T;GCRN8(-lcmF$@Y2Q1?m z%mxV(|Yk&~q8hypkF_=%ROID0jQUpu5h=XLtwL;ZRsMA3E<4 zE7+jkA?h&R#(=+^Ae_KtNU^aQCdSNLB#Pr}K)1kbf^Mpg5+)5B9haPx;44VLCul@1 zu&0PI$7^pAq4MW%@>{*2-EWjo?xy8Ni{9ikFk0AD5e^WBgT=XNVD2MV<;T8+X5N>L zC)M&9a{jBX@6Ftgyk;O87s=Ll#B`(noO|ow2iSi%^48;@IMb+eygW5S+jLo8w=Yn`z+KGGF`re8H^(c zKLxoQG-{)$)pHt61}z-ZDKr6WE@SgLsZf4N(Zgm}HrU=?>#lL2&N3KrrxDbtd>wik zDR-;HH&X643z(L_)<*vjDr;>(O)8NP83wGx)YRB<;{(-I5_AYu>A-9ZHt-O^@xr*C z4uZy>nn%8b2BX>Yd1*|J{`l%EXrK!1u>2XqGlW1IIGPfP<)xLM>K#&E_yR{o7 zVoD-Ixvd`52~gEArT~RSO(hISj2o4lCQ&M+ND!M7og+!-3+xa=v^qFzUFvHI8Zwm1 zT(3;&AuG)yL*Wp4-0T~+|MohU7y^D>psdin=;Q*7nH{sd^G8=JMkISlws7_wce+?AW^)ONXRkt zsQbAsfSWn>uC|5CCA zE`$fn0UA+dB_*gsrzBJO^XO4d=n!y20$HA8mXzo)OXsxPAt0HdbHEW=SvH^0pORb- z>fI<}7^v8x34jh|`Na5*B~Y$ zDygyUcs3Qp3?)yMQY2yEn255XXLmD{OtRcS5JlxdM?fMwc#@K`oChc91z{+^g3S-L zg!!SCaC)dEoE};U@4gXm^ngO&LV&j1VNZIAG-3ZRzr3 z4lp4(69Nr7YqlqyUYL9xdKki7o6^(2jG_)b4E<6qj~zAve5P=DZDOGiIy*+gVBe!k>YA< zyMwWE(N~*Kbq>Z#FrOsot63kIUC#o-5@+3#tmPXv%$?(ASi%exDR*1G=YRr=%Xwiktg3K1Ph|3-MW+U2) z(E`DY(qdMSVd*t{3UnwW8D`G;Cl}>aE}<3XLcyvtJ+%3(&F&UeNpF;2pa}DvSsP4m z_VD5qs+^%67A}Cx>6673N;1#TPd?P4{0=yuWP3i87c=KSdm4Hz~$Y2@%>LkA2i z&tx)+G8r?tE`XFjtjKHx=U?>IwFU>w5Q0szgpeKNayL1BGnA0)L%A9H)sONk2Y-fK z)8eUe?<|UNmZjrsIsDKejKW%bz2snmfRqf|6fe!sX3H~TfN(i_>MZVbxktHq; zf-``*#r|S_jb;WULPP0Vig*uem zNO25tp^ub&N{SxGP-0+N;137snqW9Y!i1$sLXu(ftKR5$+@YvLxvd^2VF1?)c!CbW z`zn8}4a+=XRi?N&-?Pz#TcPspknf-PHhNm0T2U5HJRrfA!3G)`Rg%k|*q4_h>`pQ2 zP*(LNo%a=>a?@kLy$RV&ElgX`psDU?JXRK zD`HqG@a#1=BQy-fzB9yL6zNcqP%@HTVTSJTu%Jy$vb=z#CnU*7vc2?&JS(C@$0CgbA~}z`cr8NGW3sRdxu~#Ph>{gOEdIo5|rrBUqYWQxe|s!L*q)?Wq0Th zLO}eaD(@i+nM%Y=kznXiqmm>`F!WNROpYiaU&^2d2}=}9b#diy9pGl@xAali-A75L z2og$9X_P<3$St9CBwMBmRbD#e?HdW+R|S#`1ESm(*}faYR)C?~db|aM%0X_()U89` zW?AH_q)m}_{{@bUB!vD%uFV*#l?xCW4;E`zQ_<2@a{wwP43x*sxDnOnb5~-AzPaHW zvr&}G{O%CAcv)gRQ%R->PLf173KFk~Av4X%lp4bnG^s>~K_^`*scrb+y<|yN=G$;v zJ_YLID$-%F(EupRvVv)-`k=vkMVW#VzC5GyLiSc9mxBfG73t6&y!RE3ds1XJZiW)0 z0ZMep1)gz0MQY$oNsS#ek_`-H#<9zYWGl%O42{DCE!-)$w1cBWhanA(qiF<21&OOP$u~Vc?G`slIgD zAZrShF$}UmMG?acZjA~9Q&vq*_#ZaRWNqSrk|KuO_NWF}`e@XH4<<})he2%!`$0np z{x>Y(D{tF^c@S{RO#Gt~3H7WE_XXAF;J7;Dfa7a$SVfqXS6<1)ssx3=!Qdd9U&$S? z78nMY=AbCaoP>dP;ZdT)pcDC(_%?jlnKKjI(;5~)vQGD`ekGa0heM!4Z!_kJ_Kcau zU5b*Nhapqn0wVHLlqsCiX|W55(?I+#B}o<-!Yaqo{K{SAybar|gT1fJEOtj>4K6>? z+bt*TA!(B1-Qb4-vV-TTrubhFB`E8TU%^BXyWMG%4n4!<6XDNgvEu*EGi0r>A*=)U zJTG-(lag+Q)d{O|aAgjLg1B=Hyyo60$>ktT6xN5%@}*UH3zLjaJ5~@TogP-9a`Tdq z%wLKm1cux^5w5)jo?zkbsE`tdK^jp^@@;TNVbCL4iEo%-1{l|3VeKd! zZv)d$u*vEIULS0g>wp3pEZZ?F{aZVqv%{3shd~?>CGGOv*YO!G97cbec6)I0$%M$R z{J27~*mM}6kEr`~9|AZf596R8=dnHK@y5Lw% z4P{{hrD%KoVVfCWk^G)eLNQagqind*YmCr(=6^i`BThKK#TUm?r=m$tBceXRkW--F1&!|kPONlEI@{UhtFy}^zg#75O#PAWS zK#AFKOAWvq&X?k;q!++BoUnh2RGuiX!w`E80n4P)KXA>c*b@mwLyCG+-i(TpcqIoJ z{$Dqv$#DZm#tj=-&ck$3!pde8wcxq#gl3eB!KMhkaIrb{vOHfD(^lDxdU6;sB{jBQ z2V0bA^$bKEU?VXDE{^lm-AbBKJ$v`H%Mc9_q8MVQ+mkVB3N{S4>9T@*g&yO^FUx4? z<@+|be?#xcWwj7UGm9rP=EG=!RVU1PQ{vm)jh=%u6fT2cifD(*JqL-9DFC= zE2*(7JK$(Zo(pvdqqn0O2$>rl`IVl7r!5gNR95Ia;FX?(#|Qya;w)uWdJcX%ls`~d z={bnST-lwAIpo|no`b{)9hyj`=TPZ6$lk@M%+u>CJ%=*t3@mz;o&##Zb1CVKhJGxd z(sS_S2w+ME7w$68VL}Moc)r@8zvAz%`fp8$TsC!*>)wvN-fZt^?P?lPy;j_p*IkV! zeziAt@n%B}QDHCw%O{!pi6O{1Jyy_?=xqiNc);LnIY12p$0 z%$qp~miAOiPB8rDKFJ2qrYB+JlOV?JLUE%t_Ur0UwgR4r! z{Ry8(^rH*DH!euO&_h#2v%17Gy{{&G+3VG)npRE2+=%ac<@MG?d|bF`(od^2HS+Tk zI$U{<{C)P*55J$Z+!fK_Ov`IA`L2e&e*NrF+()jklFu&XO$c+T7A=iUj2lhQuCZ`o zuahrmRPP-=sp`C26ZYHD;%k|MGz~}0uKm!*Gc*yM*rg3`Y^HCN&%zhr)8 zRBuhg(O0UyugcOit(EantHXmejSmm5{pRJ>nySSe-bfyN)Yb6i&#Tr*e9}d=UG;Qq z?rImc==BNfK3nZ-p7O<~4RT*|-P8JHabIdHTO^x<9na4qiH@SK7P09 zLk+d8XVclAchXSZT5HxfeMZx;cC_a2U2wAGMV+oAx)!*hnM$wDniqGXusXx6u+$LK>gCU>zY2A zj^F%qws6bKnl@Jl94Xm8%GINKx2ZFio^|!?pBVPp(mt-JKR54QwRokgwlN`>=m$ zden^m`1lsJtN%~Wx3s?XlPm7)NB(GAu*TKzqpj!bR84V3jk5Cf zHl-X~^w;6Vng=gsytn6-A)2VT4~D$dqrIlzo+Ymp?AoM>`+Aad=*R?3|7&S&dK{_l z8Zo2gV-tqkTtl{(TyH#dj4M9*a^r}fmbiM?+E-BH?-*Cxn`57U;fL8|YuuH~M_L@$ zwB2f3KKi}qG`)V*?21bGL=!*o(fzOL_i2Xg8W{7y={1@WPsUGvtp2aA^d;?|E!gy` zEA80^qaV6&n`_|pU8|fl& zHE{QZ|8!W>+0`qm%I|eH6u8=KIrz_veVxgh^_!hMQ`k$>W=2BB^~9x`UTyZKzqsKi z&A^fc&1yENrI~QwM^hpib=H`33i6gxok;}!<4b=$JCLxi?fZUClPYAs$yrqJp^xZjv_~-#+=;zBkF1EwwuR zvh*vmwN;a@ZIfc*`O!h2+#uwQoO_0=+jOw>|_vu*pe(;gswyTKY+vV54tTu!= zR!wdFbi*rT`Gj7Jk4F}ejhFksS%0ybY#Tk`&!pc|$c~cvZNt;|lU;Am4sTpnPj(#0 zF|E29OSX-fJ?~gtA=&s--RDnCSVfjkOo^?YxPdrU_L(uf)tBUnK^H&Y@$Ou*rrJ#N zmHrn<@%jzJU;g5Lvg^_BZ>INopX{k#_rd^OBl1DJUruS9MPyHnYAa5KZzsDRfByyB z+Qp>!^|}|&cil$T)Hqo8WXn0^iNQMxqdMIna~>V!8ojGGS>HT{eQeOXDPlf$M z*0*{jxC*EDyVyv{SJ#(z&~zbtU(CL~c+E}nel@FpcuFqWlyqJ9`)}1qQ48wA z!s7SHvSZ($WxsHd;+(1}FVlp$mM&`9cJh5>@8vH?J$3I)Qc^YQi|D*`Qu40_^>YSO zq@+glU-x}@n(Y0#<6|`=^N8z(CDsE8Uy|Y{#&6c47&6|G*JRxYDCuTiqgzkl&tK+;PkaLiD|~N#C|2-4Z5fwJT>3v# z&&SRu?;o#wq5q0s$hK~Y6MOFkew&Yy{u_>yl{a3zFe+j_+44uzE@M~KBX2CA_Fo-2 zi#)^pe$F*^5?%P_{(AROI{JmN%}Bom|Imdc`kIekaFJ)m{M~%zuiMER^CvvgE&LI( z* z?rKpOef-rh_WthS^y#n%Up*6%M4!9y`~%H9nCNeZB{|M~QX#q_L8$*o@Qwl?;YgJE=1Oan6OVlI37$#tY?)(4H_s$U|{ z>`aR_B=;nR@dKF?qn;z?@sl@feq%Ac;5<`x@s&FCnw^*bq@oS{q7o%*~Ay>@?5 zzpfMhpqH87>7CMlMC`dN>+++z?PS@M=OS}PoFZ%YKRdVYd!LeZwf9#&nfMi1v+I{j z^^Sf^7Mz>>0~r-fujuew&dqJL=*|0IFGqh_%(I*;aac^!V@EpLv|#c=5TBSpu$@ZuZ2H9?85m$pB4zpQWva`5fjbX`A6XOkwb?*te<^$ zA35~8=IF^^HWSjEEMN4ogWjL<@LS^!Yv^OGoKuPm)%1}qk&kaRrqLx|XKy#3Jx#wm zWlzcF%PZ)I-Y_;QX|kETJI?$!!~6yH(V`#6-#d~VDPGjOP3x!0v4=X8#9w`#>^Bzt zJpaTY`tZGbcg}nE8hv8*sjy*Nex#4Ae9>@Y{ziJ=@r;ZI*-P}>3C&U(RhdJ#)%1;C zHE9QVyW8lee)(h<+4u2B?PGLya%9!EtEoS|Lr$!#*>^|l56NNb_{@a`41H`o6Wy=Y zU-Yr!h{!Mg+DRWcocZkX|CvGWTv;Xd_&7Da;imylZ$7<)rY1eyp!Y}H$%ao>Y@V{{ zSF-b&Rt4?GbtMNrUh?L#kL!_R+a@gkd3|egOxvX8vT0}OJqOyabp1Ynb~Q58DNOx{ z-g5t?v305y&}&lbO)K6okzTYg{@u_2d77?0{ZVvvrMsqHy?XD} zt9K*DjkRXj;BgT?V}6)fE98e}C;MeT(7#KoEN446{w|Vy&4vyN$KFbU8MM3G_1!d858CPpSb_&tT1w<;H9kc>}76bg?co{vcdvJJqJRS>xo6 z90l{IB|r_%=5n%Z!i)I32;x;05R?8eKcop9EIoT>FCjo{3R{Z`HJXg0mOZ*BMy4RYrc|>&=kggIKTXu#&Op?eH9! zACQnrTA;)AD3=za&1z+gF0^fAg!x$=K>Y3MTz%u3YUfqVy;F7Qh=e4rR^n{^fhF)h zT+}G|??LW;|KAsthc5vh@g*V}O*^#JYTWxyu7X5av0V`_{O+&(!{bNbUQJRrhkEx0 zzANy>N*3S6xWJxtb~MALb1+7zjm0{%0ni)b8^Tpd6Y(gf3$Bh>PB8s=;av(M4SyGvDgB%D z8}aY>zJ}i3_aCnD5BC%A91-co0$sf0TR@`4`zONR#rqfd*YOY2;{Af~zIgwV`+Pht z-oF;U7w`Y>xTx^T&S+Y^e<$!0@BiT?qs9An{`(U02Fe#GPvGwd{$2%tPVsbLz69n& zh5pgf`jxQP3i~OO{fOmOyo>dZcn_rCZOdtIe?M0M_j~!jpYy&V?VJWMCMd=NF;jGT;(rB*0_X@34bTYyL&6yM#&|Zysk;Jn1LzJA z2hancCqOTNCjjCBdIQh^T7U$AJ^+aTNdSET`T_I@7yytAFc9ELfI$E$0I2|j0fqn! z1sDb}93Tx~1VB2#NPtlQqXEVMj0G46Fdkq6fDT|HfF8gAU<5D$FaQ|OasYAxaKvsJz;u8a05bue0+tJirS8ivgAZL;zF*s0>g=z$4*aRiGjM06;Z?hIn;= z8UhXRng9<9G{kEG)D~!n*8!+2&=41G4rz#swkO)5XoC&mZ-|Swh<1rGqO77_B95}6 zeIgBUlof3iX^5k&Xtzj19A!ltMjGNME7~*C5J$Nv0Hh&~a+4W zILg`$0BMM$Tv(owhB(TFWgBUTqg*`zkcK$Qg=HRTh@)J+0FZ__%K8KV(ojZ}D;}V? zfTLWrKtmkm(gGk2ag-|oKr7%VS04bRA&zn-0w4`>lq(4UX^5j-eF2b$ILg%z0BMM$ zT>Sx%hB(SP003zyBg&c#Fi^lzt|tW=;#z<~07yd|lxr9O(hx_vh65lCag;R;0BI;A$~podUBFSUkpc~IlxvhgLmcHA zEzl50xyA@I#8IxX0u6DLYn(ts9OW7>&=5ztCI~ddQ7)Z8LmXwD2!J${5oOf_7z7+; zH3~GuQC5>cLmXvg1RCNfYlc8W9A(WEXo#b%Spp4ll$8}|h@-5N1RCNf*JOc)_(T9R z0MbxKl+^-Y6>yZ*CeRQ^S?vN1ag=q6Ktmj5bqF-XQC6owLmXvw2{gn}R<}Sy9A(WG zXo#a+IRXuFlr>kNp^PZ&RDfv$jO z10W4?lywfkYyn4E=K>%Nag=o)0MZagS)T?#8p?>WJ_9gcz){u(0u6DL^;v<2ILi8* zKtmj5T`15HN4XXWG{k2EXbI2?pfx}nfVKeb03HK)9H2cw2Y|l0{GAQqqt zKv#fn0NnxN0D1uQ1n33u1VB7MZvYxV3y=WN2Otq337{`PKY;!K0|1f%1_C?@FbE(8 zAQfORzz~3;0K))=1Ec|r07wTI2`~y^G{6{uu>j)$#sf?M&;d*Y&;u9%i~uG81|S0< z6CewK1(*ad8Ndu+0k8tt0PFyweT#OCwkz5w+9ldz1VAN#$^fP1F}_3R?VZL=i++7jAGA^_$o<`w1v{yyrdtblwm zZCG}&++dkO-P8i81At`&%LkSX{B4BB0IdPghS4t3*3f=g(6=^je42!*b z=#sY9&w0yP839{q_8xv>!#q!=h1bVTX&&Kexc$~wAH4jG=b>v471vog)Kfp{Sj{)m zZ+fakytp8H%qBYbmGf&ie0x}1kf_k?Zv(xs_iNZ{rxu{>V-8ar~mn+=aC`XJ6B!P!Bey4Zy$cWr57=*Sw7&9 zbq*DsWwS8RF1;0RFx_|(%sO>OTWmHb1OJ=cX2uz9)n~IXC*SF^O%8mDve{i!6ic}n zr>i4egr)kMZ3ex0h~A;MIHUEZY+%TkbTFBmaoBYh#+79=#dFiesljfS-3`CSO;k7N zos2+_ieelNn}do1hD~@p$_BIH9k7^yii$F`2A9oY%!)EG*{qSFjCMEbC7qu}PbI^2 zJ5C!ZtrNfWBwT!?(&rbud3qgQetl?aO;1dEKM;(8N%NDrHysw3OK-FG)Lf;PWX?IK zjY-%PJNJ46ZLfXvFIRnbmNwzy==90C4sD-nsU5d6<2*xWeCwHi_^jv2op0w|E12X- z9P}UFQiPxHN%^i!)bck9+UhUwP18)dUnF`Z(%M0M^A|1?AAJh8gcnCCnb zmqz~Dbk|@{+KL*Z2C;?|#+fCi$j7p4m$=w&UAh>$but>e#>VNp7`k>b#deO#h>44f z?P@Uf=+e1U_ii!WHM6u6^O<(fyfn;Xu}pun`jEb9!;K}`QB-Wln9d!$YM24!oj$EA zr}SE=Z8dXf^=fOJ+U~6*pILk1pW6P#uWhR2epWlS>F$Le=3muXvR!T3oE<)>?~vdO zJ8S+!R-dcgvam`tdG*l1eJi%*kk#iKHySju23cut8>wqzCJWvATZ1yz6Wg0--fdQJ zD$(t5fEiP1uujF7UQlJ4o1s!|*;MBks&m(#UAy+|+?i9Krg@#)i`%D>&6}TU^U=UX zWMg)tm`~%aq;Q0`?K4;3A$@ZhqZ=k^ni-BKtYWa(ImZ4BV|(WNJ)UeEnHLw|>;~DOX)t%Z;}j_vmwcty_&DNPqaCv-r4N}kVBIG- z3a636%2|<0bI*=W| zXy1z&IE?J8cXm+kZIwvTD-92hzBr8>_(%6QempXh6s`UO3qi6KN)!bX@ENWM&}4n{ zuB|inEF<%0Px>PAdxk7&knwQsGjZhI_`Ppjn7xzizM0vy@+YZe|BKP5M^qn4iqAS+ z{U^Lk4u1b@oaSf?QhcFu%$)O=$^Msfic(XTl0B8@Zan&KC-QFc*Tu62HY7`$JUT2c zVkOBxaW;R`rN(57`}Y|G3tAG-@`Ai+6AfhlxBp!+;=5L)xYF=mZO4w+6uO~)< zkmAUsf5-oDhV1__Zt=d$MZ~kJ;LERO+$39Ojj1%G(JYdGF3bMZ`*q3c!U?T66<;FT z+73y0|M)?&=ir7L+dhaPo{5gOQI{x6=eDv_+>B0d#A3`%+4mJdii)QaOr~LsnJeVZ zEY_Z)x9T$)hi1*qGw+_?I-6|%^(iXuc?;Q?*R#o~2CFD2uvVADW`+sAnNBGu0gtDW zQ_~X$!J3lP6|*#B$>!giMfAx&PF~f_9J%OVH#)D^OY0wcwlbYx|AFDh;{Kp1inXF_ z*^CS`B*jyYS#3HKlc9H;U5{(XFBhM&tgm*KEkbX?tuD{XLb7xxqK)S!g4zQfZr%$Og?)0b0b)PMaMJAL8z%Ne)+ zewsd0|LBF}$b9!Iq*gA+q>i#!VG7hxV|J8O(GM!j#>EPvK(T5=#w7ryfm0t ze@b6mFtIH$Jy*3-(#V)Sx7$?qF*Lb+TqKx};q~7C*tl@mnU`;pxmWtF?RMoSvSjX2 zwwA?1mhBq-z&F=VlDx$JGbqYz%Yg>SU~@yeCvyepaLxJ|y)PZE_xqHdV3(7Ow|kG6 zM%ErEtbBCcZSqF7BbrYsN^b_1IxCY2hLO$arsOai&n`aOI;Z>lUt~BL^;j{)d?{WW)K-IyN;u=w%3##-UyFF%mJK4)@*u ztg=WndoNjFGOPXA+;g-{eOWq>MH$8i+d`0h|r zMx+hakoq03M~|vWA6d66)@5HvA31cZ-^@lybkXreKi6(Jo8De~!CTpT+S89xR1iiY zOM&4ddulBk)}B6KsM8`gZ9RRWdG3JUK0ihu-`wNYypImh#TRFFID9#U-Z6=yxP>Ia zxe5$pw=Ug(mKYp%T_;Ae+2M>``Z`3@QRZu{VQ75-=o4J)fF=krg)a}*j6I&8mef;kv`rxq{ zU7`A-cdg#98~jBq{pNQUmsV+4nWlQgXuDN6kT*Zxa{OmjXz*LQLFmVg~JLKjmgQ6u$rJEvsqy& zqa<^%=qb4r)YxTXtF*>0l`AlG4mO};&1*)ISRPfL4!m$D zh>B6IQZK$N2QoCfY@#u$&>`P0>kUqwkBv{CkYpyRYnjbZ<87DiytC!wBw(r~bTHs^ zdK2p7%SqS?1D|EPD9Xe_@tAV6F|khUNcojwh(od_H+Z2|o5P~x zEVZl#i4yV*g;HD&UYt&Vp}eChCLNO8QAw+U458W*KQDR5Oz9A-#B6{eYc0u0q;R?1 zxlDybNHSyPI=3Q&z&kK3o4p8cfq!T<>98Xa$VqsPr@AU-h(R1|Q{>aGTtaCpB2%C_ z9V#lzehkf-HV5m;|}Ccq4<_)BDk zAHz;?mDOrAD4|@<@8!tru7X^Pu!f{?qE8RGF&mzW-1dUWd^)1yr328J0KP=5vO@WoR(_A-kH zFH)41%Vn$0ipqo)-*)im>^84g2brQEk9md=g><;wc8H`ic5kI1CS7^uVC5~_#AeId z51LH}MfIV;5XF<@s9M5c*3B8VqE-(i43=EpY#_;K zwi;#lVU4Y@au68GipP}{1zF4+wi$LKFmpy2wp^B}`9-_NBr{QpngCy+gAN7^{A4nI z9TjB_09W*&6^1U^G^iA9W;YipHnABQyz^?93LXkdS?2lyDhJrgB@@P@ze@=W2H3>^$0 zLJUYokL6?tNrrJgsgUthyC}PnZzB-NfQ}}(7BDK1;o_+6{0)HO8#PhFlD#QlXm(Sn zgHy-!9X2@NV}Dls6ENh%7Qy@xuB0d^&R&Kxz9yG)<+&_K7|g*@Qc8HU@%HiLogC$r z15`EoTrPklJQcq-SS)51g_|S#k}1WM+aYW!$A@9%eOTqy7cdMJ3R00N zT)_((xlzNA(VM1ndm}P1Fzte1BAAa?jmnz<@N0Yw`FcVsZaF1{jDZ0Kse{O6ilS}> zii7)(vNn?r;$VT^i1M;5Wyq!2pJlli`m^HmMIA%2qZgn*WT`@jIOL=g%Zt}sL_~Qm zyO1GxHWqH^$mxRFX-1g+Y7>UTm6v5H!xHs1CRu4i&&MwKIEEg4NMRa=&cI}1uvdAK zv0k;nJP=k7(fg7PggS;W)~XwxG8n3DK4dTE2$#!BdjZfJGr-(H2@gM1se~}3ewSZk z`=$3ubcRvPvJ9!?z#slDKVZyB5L``V7y(ym*vjTC1sCm3{e_~&c8rE;Q%*B@IJsfS z95mvPQ^~lAWC2;?lb~cekzvTGWXfyoQYI!Suf9r|n4r9&FJ;CJCV6mZ8X zKqXYi9vQ%3rroSJa+9k{G|g%x3^}r=CR3PPX!)S8<8rXMCFV7%l8|HQpBG+Ts$q!H zQa>lt%MB2vZ3=!Xc9o=jyto=22GJhRGoErz1z*Y{Z^k95_!TzwqUo4mUOdeA_FZa{ zEP6CPE)p!Ba+ee%1O-10lD|CHcnX5F=KPNQdE@s zHU*dA1zgCmqD?_9_%5t%?xi*bHf1ZNUBR@86$8Jt$Cp|TQ&YiKv?=~dR8zrLv?+l) zRJIxszrG*a6e#jx>7!t4fI3v(rf?DjG$z6$GOTD*Pz%26UT9O4ZSIL_t7udF7j&s< zMoa0ZC>{Q&=%@G!9gqG0>!;ik5zZ$Whm|phGs-F7+Nh**T{DZ`88!jY*vit3@_G@Y zu!5GNQIdd^Aj67g6t&>Hgl04aw3WbZ0|29l0c!Jm#4p1h?vvkuKoByX;x;1ilOogu ze#Wiv6uvKUQ`4ph0ZA5SI>W*^eYTC2tZ`Kn)b(e`O%3u1s)pfx*m=y%vN>T{lYXk) z;@dK=X7XARYX9!>m1L#z`Pf^bV9 zMV|4LqwLegL6i8MBg-a!Uh=LcsOw~4ua{t#nh-(QgSyC&-#Wzxdlb&R(6?6K!V3i)OPczIULuKDVIaebh90%xyTqsn?6+ujxhUSr%xBWKjSuTT=H1Xc#T+nVC7IA zcTSW<=;b25_yYd$3*Vh~?V z2fV_!@tF)_cSRs5>~Whr;M?$(p}+EkC)jkTw9@8R`tY;6-&v}NEZyTXs?h{{!(9L})FrzkC@d8sS$~CdVc2g3fc1{IA9i z??;DIqOuaGn!xz|IIF6J;v@t$IxJ7u8i>!BW)S?_>X8yTme^Huwrg2@Ffh z-R~b(%(}n#X5Ihk3-j;K(cA31X7tu4iMQ6l+NQ#tLoN8O0C%op^ww)FUIdj@F?#DW z8N}|((OWgXO~vS~)Ns_q5AVm=mvHivRCQiFp8C^$n|ma(zqOthys3-r(QW!Qjs2IHs!?sA=QHK?yw_=G_)6n1jp{k0}+q-a2 zjPOqv6pdK!t|m%+KYFlox)W(?bXdyh?Vs)vQ`Fr(dV4Qy!iHO*+Z-vdy$c+Cdl&A- z#&5#rE_ZLj>(60`f4vBMvH267(cIJ_WLVLyKrQ$#IJY9HKVt=(GWPRVnl~T( z5d1Ri%SlAf&?lAzQ&S&8F2hDhRu`NuF5x7gaBA4#)V_YH3i*JanHZy459j2R*!T+n zsAkVJIA9siU^dy{OgvuilHpc0@xwb1gT*89nZ)o6B`7#(b?2nPtm!Q$LBFz=D8 z%41(bGw;vFmulqCOm>3%kDe~lLes#@CER_`a?vygq*$jF$81GfL&7g zg*3`Dg>??*wy5Q+4?pR636+)1+;@-`Uk7XC?Z>8bdhH*~GwNGe{$x=LtuE zyI2m_XW+KI4zANt=8O>-dbxPZa5*Hz^Ow0(z(pQ@cjdVp^lWIJFKnC1nwgSSeXtr9 z&Rw&zc&4nVD?jnzL3yTN1Y=(WO9gNj&F+l7i@H}wkt)AX&&(iB0HrRgIZ=s%$ z>B=QEFs=~%ROE8VsEw*t&&`@mIyk0NXaa0Gj6-r#q4JVqgw3uTu)V#`TjM~TWnyus z5!9)29r_w6Z>z*NQrgMS1dV+)k8%l3ti|_vNlc0U`06WUpbG7<>>0u{gg_cNnlg#yrB$BfOufYt zqU@<)h^GZWB?E@-GG;+>ndaxeD`#kCteLJX?EXl1hx6u+a)uUtuFlNpGfK!N>QHGQ z$O`A(I$4>RlE_eLs|R%gR5gq_NMVVmlKS>b7%?bKrc}t0AT}pDN3zZr*dc^y^>Eg@ z+}AQRWGI)pl1%BMD9s{6;ShP;>>IZKmYhor0Z9gqTbGeVo&*OZOoLqovBJ^k%4JPF zHCq15AXEuMu1YMC+sf_GE1|dA_hVWPhBi2}nYH?HgRD``&^Z~76z3gjT}~F%vi|;^ z^6JZNm$Y$SYw;pVB@B{R>dD-=9@MU33*BJSLPl=5v((XN=LV**0rN#{qCt|tv>-!h z>cMw_+ClF>T?zlDB9}`Ev?%YV0K-t-N9ATy>RIZ7@)(n!CIfXRKBJlptlp`Up6Y@` z@lqop$52vZiM+VGYKGJN*!Uh)G4usmbheBP=u-Lkf!Qdkur>IpU!Vn-`$*>mDJ{#$ zFr@#bW(!;h4_JaUqUuUYNQX{Mrts&{qnywo;D!V;ea9@R(P5_E?Q}vw(x7+25n7oJ zztEqWTn_2osA3qb*r5r44i)*t_>DDKu~W@3Sg{iriWNzj?)VKK)QqxaB8?EoEB~gr-fI-`)>psJ)p3;uVt#>6uxu^eC&!`R+tBO{`HDnF29b) z4tBfjZdX_)vT)Lr(ig>cInic;ZQ}SJ=6j-o5VFaE*(`QD1LJxSiuDWgiS4TLR!_oE zhl5jkX)i^M=U}v%rBPu~GV!jwp~pzO%`BT-WU7i`@cuk9RC*wb5FiK)0Qr)vw6AA$ zW{V%o-IeFE$(CW!+vRw1H02EWT{45r;6xp^OHNHrOHLR>r6s5I9iG;Ah^}vHQaf3z z1|qEU&$XG{!8C{rmFh4924{5!y)%g6C_jHW(-P)P$+WudW}AO`lVp+dBxk|Mt%N}! zs@$-{J|k$7Q*PF@S5W0i2KSYVO$>0*oJBHdIx3+jCEwfd>)w6#~G-KBug2>(EzN; z4GU?!*`k&q40L6|Io5hBN+%5$sK{kbLaWUhEY-?n6m{rh7?5gZ?63*oGlk1*vn|uB zI}uTnWLqX4(;#vPxGQIfQJVlJ(nsYLEI2mYUemfPnB-=21P0brNI2DMe>0<0$^wr^4U4t@}n@zTBvNRI{apgM9HR%JHNT1a(luVP5vf^A+lj9Zz|^DcK4&kXXuyl$u-)I*&!vVItp62oxpA zGmPqGF~-T2o&X+l7rKgIO~>Wt=zC-?i@G65@w*tx!cM;2NY0T&I^-i9Txve zLV1#f&Lh;ZE|~F9LXXNBh8*uvV>Z}X#>%FIY&=1^4v`^da`+f>=MBIK4*ZxDWVV<^ zT<$108_`x+D+Du2idjyECD-h!(4mlIm^l}iT$ES6gm#z<1*^`C(B|75POqqHdZYXT zMVRMobHMawA1_X!>KQs=;R3jvepy_uB=Zad_?AQ?jhyoAE`@BW!x96==X$z&8|W(`~yK+YdlWj2EIFZ${_lM7}D!6sQk$PRM3lajs}O33x0ybJ^C zN9C16AVaQc@m0CX8RGmyhb_myt@C9LBw11K5l;SqiRVs;I`Hc~_$HrQT*&*f%3D1+ z`2!`?xggBx&|9UaL!+D^ArsX(Ca^#ReTETwZ!gcAFVc)wp35=}r5UX}Q)C!QGg>)A z2(y@3n9~i};$mSXNWjcXD9N2V#!)drBai{wv0CS7|#rhh}M(G&6mmwBuUkMR0)e?F$TjV6%RWl5%`bEB~GsS6iFpSJ( z0_6xZF?${9M1EKK)eGgv-0;>!-TN#>^Sa8(U-flAH^QXygR_JmJz=Z@Wbbnn)K z=@8o~F2F`)9$|T%%?wkPg7^(;DhIxL4%(MeUfW3P`@kH5XB7-F_603pU=&SYt|C*s z!89R0;xDEe3BA6xKP&zT8mSD3zc4vA$7BlqK1%P-^)=>#0}M61(2Bu4T^#m+5m&cG zrt(4^Ds7}VhPcp2PChk7k7Fn^uq^P0gLKU>93o@F@+2Y2F!|NU1{`-N>QHH`$4MB( z^#Y!tL-4-JUTecLPgs>HF3$IDG~rdKay#VvC;p9|&aYNf#1jula2RaCMn=`-vM=@} zafH1oMja}uzU1@198_+447fL8o2i9q3mG(39x^Ruwg|U!VK6sC#c!fWG$cz-Gbo`j zF`;7R0xAP8=zw$64CM4BN5gMIMq!mV0i{ggQB;sYWKKfgoS>3Zc*-H64XO#J9uJts zUlA`g5<+c=rpQ{|wvux^)G+h~OQ9O%!ib`Ha9739s)y}cBuu2J@@5pztq2i#R+A~x z{G$dPk&X_(6)NxLM<5 zStFJsB9D->=i(`|-eNH65^?VCkc< zyN{Yo5hRqK(x`ljkyk?bNVY;1Y9u=3?HdWws~ky&0a0#?Z2yg6%fZlVJyHRoa!?vF z_3F^SSr)mfX;b9ge}SVa386oc<6y(Jasfi)p@Qs&p7?Gyux7qF@@TK4kD-Ri@yCFW;!VkiF%}ZBQ zm!ZsPfEpcgfoB|0ksCNuQ)7pWWCKHmaqLne*=jNcL*p<(3wO#b>ENi*VOT@sXc{3S z*=mX&*W&52Oc`Be?NDh$fB&t$9pPjg{O+jXTbUWu3sCb1Zg9b24BOa(1`Vb3U5tEs z;l~4f&(7$89mA1f#aIAp!FOS8GrV8=uq>8Igk>GcR`BfYHki|8li&6Xztrp8J_do9 zn(9lh3$dn99m5a{R8%oEaBEZ;n6hei!~d{hrp+M^D5+w|ZI5b#rH`x;d@x~ZI}B<= z*bf>)@V{XJUs>B0%!8m?X5t^!NNBVbeHjb+^E;zmhhgF1Gd1aMMtVmD@91ISz z`IXWEYk^^qX%4EA%t;t*7alb_3^|csjc>z;ojEhXJ*{B@q|NP})vqQ~_;3hx=pAgX zXwR5g+@&hXxfn9_FCZd6RhhyWoesN@I1MD=Qj=tXA*^yN$*;^sPHNZ|J?wpDv0--< z*5L9Jy}fe69+GAy-VJ^jBs+MX@f80Hq6DSg@hg}p;&i$l@}Xy#d?Nh0G*N+FhnDYNxlotC=7Wdi}Dj*UO=EWP6+>V@z2h)+&I5Kq=Z@AJ}HbU!;I1lu*nR?kF2>^cv%J!i4I0YEVKN?2{AlUC>8)hS|Pl z8)}lQcR2LHdKIet!#mJ5v)FA``Oy!MQ0Z)En9ah%rq8HMxl4^J684TyMkwb-jfDK@ zt<3Ndsz8m|a7zuq8=fl1Q%x^`b2wrD6uCT6VTWP%9DH?uBNQi@^>Ndf{SoDzQ9&6w_AGjQVmI zF*P-|Q4d>`=!^_R9bh9d6E2SP)!k~EQKRktYnLG!B1AF7PPZ>(;wjiL+@a45?G^fr z8^0{2p;zwP-2Dx`E61jTK$=B7nQOp(qr!6t z(4q2y!V1qpEavL&T+AW+uJIgXM(EH)Dm;e@&q47nMx~x!SK&F7QfFY%tMD993%*ND zZ#4X40TrHuFGm1VGq`Y{c@AU4*v9kK27R8td+NNG5x4her>9Z-xGH;?N}h-7YCb&j z_6ME@<1QUu`RN%?TVe|b4{&RJoU#FUXQd7_tZ9NqBpyb zdm`$lrCr`~gI-{FPam-)LmQ#(^yG`%uWD=O>!QCt&`n!E`{J6O4`ylW9v!o%aM2!Z z_ zr*nTh!NwJ7H6IL%y?W@9w${&i%h@$swe^RlElzCKR9m-0kMFWO#L~Cp_a1&?!#q!= zh1bVTX&&Kexc$~wAH4jG=b>v471vog)Kfp{Sj{)mZ+fakytp8H%qBYbmGf&ie0x}1 zK;y`>j1tXV$bkado>X7l|KpKSVz z_K}hG`%G{1oR-ROxNp=O30f-pkBQeZUeVUy^2F)qVjFu}UHxF?{@-tU+Mj*;<6rU{ zcph(l;`^M0L{H1K8NX@I#d;e2_0#p|(h|th*01Y+Sz24$pw6{7Bd5NtZJ81^q3YUA z+Q+H0w~ibr)VBZf)2rvY{Y~5IKka)ZzkS@(rAnn23?HBMbnDaPsm-q)^2GeMj6{Q7 zv>*SI;fH0fc$)m{;k=A6%y8#{AOt-3gW4 z+HQ%K)Bh?;&~~ZXnsKZu^z`{YGo^Lnm!5=+k5u~nVmD8(!^^J^O|9vPNspj&nyvM; zY(06%wQt*zcNba4ZaVc(ZHue)lFT{hv@r>rV&`6OpzXD9{^hFA&eA4a9GyNn*P-om zEw$rTW}Ii}jBh>j51;isx%2J3YXy@$iG%*Lsc7A5Puv5a_kB91ny2mU`FTIFlgZXm zbk4#m?`hj^ozOSx?JRBg?-J{e?ESblvA?_E)Ut!xCwKRxfB))V+M#ovSY2t%bDoJy zBY$nWYp^G6MU7F{TEF4x|5MTX*$+i~dJVbp{^*}`Jdgc$a<%F62(q=ysHnGZJG75& zetlexiT~2}iqoC=M~_9?{?}GEot@lLo3<)?<*4sxX(#40?VfpQn8#w7{$}<17d>O^ z)%|jA(o3HHdp{le`|K8;?wz;Ron51|r`6^q(@!!3$UA*nS5E1*P}^$e(CXFJIJMnd zM?SOm!aueBi(lJR$^EQ$Y}4HfKg_?XwPd^6v^hJT)TJ97puTvX*xp)|(7E5EWT7i! zW8-75l9iKAH(WmNKVPs{qzZpqPS9Hzlw0?s;fAryTQ9qm^g=y0+>^A3;jjjV9&WLD5 zHgCFh=(9s3$kyg{ZZB@1MmBGLs?A3O7m+^HAunOMmOsHG=XgRwpE?C1`QzF(qk^{iJwM3ES{VE-jKay_xrP5 zJM;6&hX-fOdw+U7*)}pSF230fvf=v%bH_VQk%Do_S9*<)Bd#^tF^f|AkXZxPeR894 z8Y!%t6*;N)3bJK=zUFIc0NFkL^uK%l<|g~9)L3w1V-xcCcGn~6D-+1R$Z97qj_pNu zKUJLG?spT}@^-zE+TOiLVdVZcTl)_svj!Grz1F57nLnKxrRkqY)<4oXD!o|;vf~%+ zdocrtk$v^f4(h$F5-ED6;la@tr;!8y=>Eo!M`n_u)nByTHaU^(Yq;UbZzgObJ8mt_ z+-0H3`sQ6*XY5%<=Fgt=MdbGkS<)cm;o4{7$h+}--?%V)C)s^7vuWi|Qpx@oqfd{h zK9Urlb-4OZc$pmh{@1vcM_Z8M3zcK$oWD%=znoK)n!1$isXTY%(RVwMcay&^o;9!` zS<>XuVQ~>FN&bnm`I{~^CR^OU&lp(Hl6aOEdj`%SFVqs^H77X51uOW{s&dq|q#re=f`Z)cbYG>cR=F zHx*wZ+u9CEc>nl8vghE28{0mJA)bkjwo#Wd3HkY7Rfha{kq~1>ahuDt3Ax#8L&E56 z;xSeFZTy;V$)1x9n{BGspKR;Y_nV!I%w+YZe>^t&+4snrn`hoVzjZd*{OeOx-18Q) zF|TKnQw>&;WtoGXUOtee^EPg6!JfWEuNwK|l4!OwomX6NDvIt#mW@2EE6}_{HZDwE zF-tR+Z2rAjM4#;Ay<(qXUE zF%;1!YNs!q+Rl4*G9CeWLCkSv6mXp^vP3$+a%(ZJPXY@rm1p^>lvnGW(79 z=F@pI|MvOqyyo=D*L$2?;T%YxsWtr5O!_!|;pWb~Q|1Et@{{9-*EcSwzxvF5bJ^0# z^w)!?EkB{t(O;dJ#*F!KJbgK3M*Y{HvC|iRznpRF@2BZA^^aaij?AY|zL`7wodaL= zzP+oc`lfFh)20RajPr$5+WMb8BiA`4|~&?ml{(v@EQxF<5}^fh|ZffZ|pKKe4f^`nTtzk2K^dK0_u)S|C? z(rah$KlP5dU)O^S9ax*O$Y0kwjOzp ztbTlShm1oe`YrvBpX|>`p?AHz+tuUIg|w&c%f@XlN7FlF^$SvU|3h!M^3jxa3)j(+ z1D8Ml!^{}6;rwSEo0=XZJ7YdO-gRCA@zlF!jOu!Z?Ak(qYN;`myk%s*$TM`Jx1MfN zG;iQ9bWzoPxBvL#B7ML;;Gv_Yti`|D|XTi(v#Ewm}MbbIwn`` z`Pe_n-d$CDp1J%JIgpdFe8(y)DXL){wL0<;+4|YTD<%r%!B2X!Y^GljwuTW^^5TYBs%V^?u#pFJkF8zq`1!O1sK5)gwmR zt-67{`SF(Hf4lq+*|jWXqWPQgaCPrFNm1Qn5@&w@x-uwX$%QQ@64Wm{&G%w%~#JTl*RGG|U^&YpYjx%ZxXZj0~P zJ2)sPs2o5QfVu#cjf`1s)|eQc9289Lq&RF1|!d1!aFsbzh6F%biA^2=&^^A>w zVF}zSBaJaK_|kZQD*UrrYaGkHguhu`{7!9S?83JdM7qtOhu`(0*ARFZ%*ZB+MK&vYLj+tW@R1N8F8nW}HAv<3hvg2r+ ze5fOJrp5}i@&KIP4CXWz9_QmT=7-T>hWrQ`41m8`381RRVo+x?R-1t}!(&iIfO2u= z@)pCrk{^1#G$X6A8_ely3u`dj)mf}n5Biyayis46CzSz0(hNq>J^v4n|Ka~@n>6DL zCd_ZJ5j6;xZqER+>w60DYQVf>3>b~Z?!asnc>@|$(QdFC@dx2T+j+vqIwFK;%%3Iz zRXCf=%3y^T@plo#>j^+mPM{|K27f~st^3E23V`|$FZ_K3xI#|BpUUvQ#mZXHCd7A9 zuZUORZJ(2^eBYix;lCBX{{)^x%(gk~Q_EMpwU9(96tDPACZg=zdlm3naJ-^EhM z>(9@-HQs>#qux=yXcL(CVjhXIRZ;gg7>%hKqk}gHdN zvNNa-#|!l3$xGC&OkVYnR~6KqiyNO#Ob1>iGXy~V?GUcMv5&V1We(qYV(`$oo?NZO*?OfVK!b~V0sd6u z-uM1}QF-_h;N`9&5){-NZM8D@zKyFOQC4hM#0$S`!#}h<0r$!tb#qbg{(5rWnYRa*ert$K;f{RU@z1SM&*HnH9%}OcRrK-d*7Ft|)IU zKkps{dUY&VoFgDKazI0y3lqLUeRFwVblDfHmDWGN`?WGPMw^Rg6r)9BhYR^4FSL2_ zf_kC+aqgj9;@@!h{x-U#-wr-n=-c)s{dOqoj4wyf&a3SjEj**FSpSK70F=u=)CXJ< zm`-R%(^$2Y(Lrr2)|s_|UI*V0uHc|@jWAtsMPNC>^y7thPY`MNyQoah|9O5R{vY2D zqWAVXZGY*h-r}7jBE3MMi+6krNVItWO!&WeKac-?=_y*gUlQII?^n6cU!ukPx5D@0 z{kw?yIoJ0`(&GI`fuDH)nU{I)<5Fim;SIl7pfn{dNNRVu^xL+_s@Ll??69`_3neZi|xvTx{K|^ zgSw0L>w~(B?b?I7i|xUKx{LMb1GVz0vUWSmh4&s$4Ok878TQ9B>0GMqtmQFI zeNd2*Nqd~LKd7wymzDp=xdM3H%m3q?_ho74G=MQdF&2oiVvJSd7z>V#V0;zF6fm}r zad?bbVtgB8(HLV61;Cgv#x})xC5|mW3GfsEj#JbJXaLX<;Awzo02%=_2A}|*1!w}$ z6rdTva{%E0%>h~fv;=4cfI;y#0Br#x03rd}0bocNJU~x?UI4uT5&-%D^abb#&>vs`Kq5dAz(9aO0D}RB03-vX z01O341sDeK0>E&97Xd~9j0AWIU=)BFU^IXRKntJ)&;u|4X#nW}82|==F#ux$i~#7Z zn*mq=blzSDumacs(3f!lWCCOXj03?3Bf&t0{R1olraDPIeAzlffvOq&T1fYsQL%b?L zHGzhBb$}WI4e^=)p#lwY(dLkbxM+K#9f~$s2mXh+Xp3lv|*$njU0u6DL)h^HwM_C;L4RMq;Q=lP^a%BlL z#8K990u5zES;qrR5O9=rqCi6&Wt}9@5Jy=j3pB)0)+quFag=qcKtmj5od$q3#8KAi z0Mi59k1AvAAPXjyy&f{9sxZgRbxo;wE2FV9dP+NLAUnaUO&YdJpanDbJRR%oqex2*n1?y`Q$H~fB!kUt23-ubc?my$~!9rZ{OD= z|0CKqxqpkSs9aTr29PN&1D$PCuRMA|iG zyuoziF)-`Y7HMKx8v}p!4kKfWG;1;qFel$;XUFn7+I~x zI7nmFm~4?6eI_tu^lF$)&R8vK6JyU{^|3HroEqq`TO9CP+%$Eq#>Q~ewrv@!m9~RJ=GVc+Hsn2_W1GOm-U)& zaK>Fae(&4G%_6ETim^43@d)sP)x%8~LYtZ)@r+ZyYRYk|0tJK2L zTGcJ@jqWL?O{%!drkv37S5!TIX?H#`>fg@6llp&_Jg14X|Ni7L<^DC?89(4--cke+ zx>D{d-C(D5kXvxmM(H|5w}Zc(Db`Fyw~LNx8x_?yIyz|Z^sct~N$JkfOC~2oE}ZC0 zS@!YT0S0X%W6Kazjsf?W3a8qC0nP-$ASI5);*~ zQ^)8|LDN*Dvy+3St*GcUnfgpzHKYifSJb9UT!Bqo;rzd(}ZhcBxF6^*+1ZGkHL-K}9jVOjdurZ%~-M zB3b)>$LOui|0Js~w!OA(^$TRVkx8o2_!~0MQ4s04Z71x;LC&1pRpK31E0{5r0_#-V z=>=6Lg1VB}Oe(qq72UpTbX3=2yV0BE<}U91%zc_{$sCd8JhOo044wGS z;P*F@UgH>@114!28IC8cVlY`a#@-C0x^#_+;Tfjg)whl(hj!2XyT|qMPs0tLld1iF-E?mH4KjPe;5YYOnnO0!JGAf5>Xpd8JFPzIFe8fO)w*_X z?c%%S*s6BA-`Djd`KPrZid+{+tH3ck+I_^d+$IsQ{(wV-d; zkb+A+hhz-9MUKAtZpfCcuam>&SKe8XJeX|jyIb>~CYmg1Q18<(v=Jox%-Y0>TdI+r znGLCoM#04SdWGwCe@Y-nf6RGm`ESceLGVx0>W_FSsNl_7jjuivM+zz~{yRUl7diTC zdM7&kDdJq2yZi0y^U2PsZB89%P?=<32))}Wr6F0JbM#(P!--^1^Sa-EcO-)x{$Q~7 z^G{wTPED&r>8B`4?Jyf&b}(v<4vR52W#3%@DJqtV)9Z&YMy`)_TiuU{s`dVW4%ZK-B=u7{6_jT)8KhR%>9jJQYNG^T$ z-Fdg-ZdLAnZ-*2^nBnXe*PY~^b;;8g(UaAJJ&_=LYm2r=I}5}p28CehFB*J=N{ zBZu!rb#OD(+ud9|FgL@a-9Ml8)FNYtT4ctz#^f0d?~^4n@){(wIb`Xxka{ADwD9rY0?stz| zKiRpBj=VK##POFdUL`vWiw1080cPWX=FtQz+F0FK7aO;zJ`%o7?{7aRI{(lrdh?Bu zE0_OIHeLD9#8qEfZj;RyTWx=0|56u2m^2P;o12k{xplaA+q9dr>3m1}sOU9s&_@o{ zJka23J9=lw*3Rg>g>>C&+V4hgXhGX*YdQF*hu|9q5)XA?mm8(PVt#L6tGGYYXn4%SMAcKA;^U$Z^t z$CL~7nZ}3y4*P5`eJVHe#P$!a(*>80*_*Vc>3w4;id#tHpR2&I_r0A>e!<9?P zLG;IUkJYxdT0no2GwIl@>Oaw^*4B)ha??g1JDW*SxIjh}N8%n!CBzL)P7bQrD4cw< zK6T2Av$m6uskcvtMCj->C}kAGaNCRAVa!Bynf4fSTy@BZ*= z-!vTAp^+uCreg)Su3My6$Vslk(}D!F?(Wo3)-^G_PXks2dDjsqZpVLbI-9 z(XiX$&V{Q;PP{hnv!PFu+`5+&qT&!WIST$yw0g8LE(%}n`DO%PFRfAb=V~tQBrfCdDPcdUD zjC_>*0){#rW8pZ$Qd4N9#z7x|U$1I_jsVvjL(^AcuD%Q{2Au|$y(;3xB}1@7=$~lJ z(2pp5xhvR`C7Wl6y$PM#rqjS;Ur(zB{_+{>G8o-hwZ<{7uyja~p*|tW&=~>u5EcdV z@*Cm#-!D2)Zm5NKvaxs6?^ez*_WZw&WgsU zK!<$0tkK%kZZ>XxLXw%b9ZGD5L9TY$!aG}TP6DP_LMsD4rz@duzMO>ZFz{Kji=y-f zs9f!8iv`x|!6IBYD;|??HhO~%J5pYy7~+ryy#u^ZGix=eIZG|6L862_L!lIxf)}R~ zU?}Zqib;ngLoc`F7czuuOZ>d>9W$kMdpTwU3=QVOj6@2T%TXmNBtnuIGuOEl8Tj6T zVad}AZ-Rel)~m52;mb*Qj-@)tWr%?sY*VDuE?+{=Rz#veb2^k&mc1An(^;#*o?&vQ zKbGPRw4~{#C{KoI5T}AQ-%vbU?z{Y==gANoQiHpXf^wElhhUL`WhhaHahW2k`ZA=0 z&KO*0Y(NXQsX>v@2-;b(Rh3u8Lg!H}VJx1xEVl_T!YckkS>eU79b6@~njn-=s^)ib zNHY~KqE-oHOEG5JnN+_cjL$yVt8w)WM4}M^W7TDuOS3-7J+n@%=rNO2t z4vQW_?w-sLkELRwyTo+q*eSY8iP8-W)6$^+^4sByrLrs~77t#eC^MJKX4Z_#gcaWw z@aQb8%d3M-k&(wdLx@6J?G6h>(iw}ZQV^3azj841maR8rO4<*aO>0^8p}-Kulj5jY zLVwoH8Mdre4UBMewBOVs?LU1O4&wz8T4ccFt01`PhBGhQ7Pc?|$p^q>`nF4+XA z6j`H#ixle(X=%LksvQp=3QAex`T;5j*vcgx#-yaOn9G!sGs9oy8A?_Qyc*@#hb$yd zZ_uQ(X53~2T6!+-BDSHB+>)0PUP6{1uXAOq4CKY{5{@-k)XX>x#NyZ}AEa^fl&?dZnX#GDzB|zY<-LWYCZuH%D|Q(-V_#hp?#}ABL6oVdYm}z_6%Lkb+F%3ZCD{jS_~8Mn9h0 z8ijfopNve{vF znhs{avchn<{IcxHuuy%CNtWBt^RWv)j-de`QkaIJ)-vfB?3JHntXEAi55%B>=zU=a zLK#CCYgH#F4uoo(57~=3!sW8uUI6sQv@kc&gNGL?S3($4f5@*9y;FO{+X5(NNru#M z;17S7A28-5@UNy4jDX8EYi7A#Y{|)UwsubF+qMqU(AdfOmcGX)Fd_;vTYcQ6ZgQi9R4rVA#{~7 zVuRxWFqR2>WpjOYVRD`l9deV%G}iIRywHU`de}9F;ewR#7|gU7H9Br` zRiUO?iG)Rt>?z3|3pK&WZh3^a9l(Z>AK+*s+ zonc{|CX+RItZ`Km)b(b_O$~Ajs)XTV*m+FPU~RChNi$w*@ofoLGr5c#wg2#U9`UR} zHB114<#}qGBMnv_xUELP*eFcl$uKZ5c>>m1L#z`Pf^bV9MV_&gwdB*qL6i8MHG>sD zFML-L)U`3N*NeYPNr)ieL0x3XZ=J%z9tJQF4wDI7v*nda$gjgRhex8Jcc}Ru zF7&OHx9~y%$C9SJq4$tPtT2#aSwoLna9?6n1om4r+a0E2BO~}_z#ICqs0c33_skTz zGbF*VGhhJ@>}_c^*tk7kES{Z7C4rzaXUUx*i2eTzvzUZ}ug1-IV4p77^wNFBQn-_J z$uIme;J!^++@|!C@gDiOjhwJJADt_U+myWAO1;Sqayf9xV=3b`B6F-9O5@Inl8F3* zkYSlShgxu7KJMHgA@^K5^F{E>fV*=6kK5>2*p3=!OSppvJ%koHJAyj^n9|<2j^Pw5N^^intsxcGF zd~9!1^zpIFMsG!9ao z%^^OnNZIJEXe{nK>d8B@6oAbQ%0_Pkuq_gI)M44^tyrR!H1rRDsH$xA_95I8Bkc9l;)f3)28(kn8A%mFlH&#piyNL?q~bjOiE0Y?MkV}-qcEnz z!qHrI*dPyoMZA<`N|8sHawi&;^f&`ZItmi-(OZro9$e~`Rw2zwW=L`jxwBIwID#F@ zI{yjf2)x4?*e%Wi9G!avJck4$tJN3>;c=h=*&wx;RvGI<&!6O5WKW7my}+Tc%z)ef z6SlA8_p*cIPV5=1d+R;e_1BVRFzbCk^!Hp$Gq0q^E^^U3GL*YrVUfGe$!GWo*kK|p zn-83Kh!t#+-XZER-pYW#+*3G#Nk7QSYK@GEw@4Jn+khT`*%Y~{I!f3#DK&0D-=5xr z_!SHx0~n*fZS{7m5)`kp85Vyb{4>oDu#5HdeP%Fkud!&XZRDW4(d zVOt%z2Hb#|4V&Dk)2ysXZDxf>&|}G+2Vt@xv;gh^zDs|I$d{0_7cYijjA^h-D!-6M zex?{~1Gz0~`Rc<o7WHb@s`om(TI4K8e^_G(2RiE+SZoGqg!4S%2ynZB z!!>ERZLgKL7M8KJ3=7GqfT7U{`%YUKv%{o?*oW_V;PP8NjnR^!QCnHqe%WiGo{;JC zCDbzZBKRrDbYO{c8$!l%&523PF`_-fp36Y`SN-UOoVfc&w>M9931gbP(HhL>~ zh~Ri(Tu%c*V|UFXUqZdX)cCP#mK^;Kk`3hl7u8NxG!KpHrj5{c!dm7nBvjmcC* z*;Bv}PYZxb1`OM-%YfoC!OMS_&(O%2)9o49{qfu#&Xqgz8JaZX)J8^=R!BBchjIf! zW;pNGW{`*}i45hodQc}oRl^wl6qZ=3XRqFILkFZtlnN;l#O6fjNYeQNJA@Fe2F_ZS z`dWg945c#HBU55zrCDSs93qdKeZ%(O9_JE6K$3yu)+J<-Ccyy-6JS?CtZ+2rq_QTK z8ZP~%AF2mKu1YMF+w$$uC84X@_hMQKhAf=fY%qIqgRGIy&^8v16z3gjbyfz{vflok z{OZeL@o3{**5X3sO6VuAl#{t}J*Zs+7P`Tt6&bnV&QeF8og0|K2Fx9?i3CY}(}E14 zsR!QyY6p$?bS3mHE3*V&r@BH zC|*h=J@0gu4B+KpV z>1>(e$5MCsxvXc?Od5+6FODXkA-_wepBbE}!{&XH`lj@a8$hM>P3)DN(rb{qS5nXB zl2#2wSm!^E)jRxY5E;tVVHyn1sd?*5C)M)UVH3b-3YXVL zHr=H=5mAz4HXV;?5IOkVjI5yl~)9MVE=>BIug2+L+VN_f4$QUJv6Rc3lB`gDiN%aaDamEO^H@Y3#`E0- zUs3!#!>C>cqZ`W|M_*WhK#`v*SvXyZvu;V&@(mm2&T%s=VFrqnyDi^yKmo<&yfB&8 zYVximfo|%mzElSlJYkjVH+0Au_~F4je=7ya71Dfgh8C z%oekV%N_Y8^Wqe$oS_XCE`ZDFmBpn>GSARQKGdQ74mh7=+juB1CeGQ!XplJL zRC%TpX2@j>nhh5r@KZzkk}*WUODJsr?w#4CF&jySD5N|s!cihH0o??P6gVR({3n*` zm6Y0d$iSq;UP&dHOh!>ggO=+8NcqEx%tmnjMPFU5x5Eq}*d$8`*+DM1lhZdt3AsL$ zi=j{bD8F*>Wym!x?kZP4L!5tTWwX57I(Ozkl4bQC;p7jPcy5EJ1HaybZ}Pdtg}g5- zztw}2KTtxo9m1SejoI^bXp|EqWZFhW`xXel&oDyo>gBoe#WSPj=duJt&y1FzDH04l zGg>}F2(uUsFsB=`#cqI=AU-oMp(MA9=uAcXjX?Tnlbb`pF%+w6ABPEa=<`X@kK&{R zzYA34n~e}z;^H7U1DIRvFV@#+Hgd=4T@0~EyGw|ODVETc*&-+5u9%^3)i3f@oGCV) zm0=_%6Ub+1L9g9+&4(x-W=c%acH;A2A@-HQXrvc%Dad8N0Ty0L`I#azl2 zOQ()qnAYvvb@s6liAPvo#~NYEk{`c8N#(#-&wl$-@@pH<`rbE3;8_7fjD11N=Nm;6 zm@CK>S1?V8k9dozL_(Ku?ahjRf<`J0;x9}VYaL6W-$!X26O3@i)$;UHZj42MXVurx_XGE9Ee8GMdA6m=-K z)#D`e<9Y#4&>?tVC9kz%nJ28u6c^{aH=1xMRK6YZ{S)s-PwiDJ%HoL!Bv`eqzmZWT zx$KU8c{swZ6r&DhRbSG1UkWNWJqFyHfX&pxv=tdNl^-%KX0`~oa$z7hL&a;NNF*dn zN;4>-FfpNQj}Iv`Y#c!5jZWgP5*@lmq$T)4 zifyc%b7hf7k+bJwDWk@u)oUb+g#-~9`bM%nL$H`9G9&GU8G1DdN_6Nep;wn&3Bw{o z<4W3PSLhHzK>VaC&mjw$O2kZ&VCYt(k|awo^iZQrjwm5t%Af}cOB4%rapi9v;9}^r z^ikN|M@gm#5=u{Llt0DDC82aATc!$wJaow0HxfLrQY0A$M7b@py*Gv}1w)thcnS!W zgWQm*ONZXgvdC3QnppHt07P;7a%lVRIELgYA;bQ`zK+-KzZDZ8&Pdu zcO`b{og3aU8%4Ry?+$^BmnFtCm1K(GBuR9mAn}SAGA}!rLSvYMCY9*0$Vrzmx~JCE7GAWc<(J7 z_oT>dTnr^f1C;2H3q0e1iqycFk{Y|nNH#E(8OJUrlC30DFfq#ep_=pVnew?l1=mERpTa4R$Yy8#OR!woK2bpab&2tq?C zeitLRUik3<_p>e1XUA}4ST+`bT5w-j+a&i+9g<;S;$c}wUo&|278d4ovC`X~;g=e< z!_B}KQ&N3t)J3c*RK~D~1uBXdYPmHk3`|)yI^ZvCn8{kj0VPEYx$RN)u=LTO10PJ7 z+75%-5cY$H5d3dgz*o|?1@pk~mYMiZB@*gbEA9)b&ctzb#tz5V;IN7?E3c%IiS-By zfrG(CYT6&>RmuYeu^@MGdeYPA#oar&!r^E0z+8kSeRdli=3xnn>4WZ zm5IgfD6GNdCwjZ&ggqpUa=aV-&`);oJRzvd#mhwrio4@iFj2&2b6BNA&oKE!_;+!v z`2X_^Sqp3kYsWp$3!T`cq+4Nez^WWvnS-Gq?pyq9wVaejOmop!7s zj2a!RLgnTq@fm`D6-fvTxp^X7dkZ|l!d+1zB@BybL{Y+r;Eci|k7SX5!V65{;Tk8t zVS*W8T#JRZqj0%KB8XuZjbn66D0Anb7UCsj!&A#Wbil16l$B~__zUa zL%hT&;sGTra+?h$ZHnMVB5>osX@lsNj1HQqmzk^9QA#qy5kmQsiwC4RU{0QUN ze&^jQNpg`3j$^4r7A8=Nw$}r;nei6M=LsbgGle_Kh8w-cc%3kzI+hv`mje6b_k?#B8{w2H*{km*T0U7r;53uz!kFo+z-x0DBI8%cRnOaLuUL6A45^ zih5JtjEa(YBnKJ(UpJ!z;u40$B_)*bFkO_etQkcuxUWZ{8RcTIgM?nV*qnM;o;QkV zD{DsGIgFT+8e6AI9v52FDVjWFv?iEr~bdJc|2xD0|Rq8%#t z93(=E$gs?F@Sc3Hq{c4mfTJb3FVrE7-lj4TGB?=Amw68EwnW5GS%L3>mw66uBLqx| zvy@imIr!*M{y<@w=O7kyWp^&-konMf4iY1DXd-2vLz(9wdl#c(Pp>QU9Ezzku;`U} z4yXn9rKC3+__2U8&%vD|fGHVVc+5P95dm!D`D%kc+a9kNXU!cm|D4~gsdBcyJEp6G_OL@|Z0f42{#(K?!+zVP3L7+L`i+a7RiUlA%_&Fv)AzdE z+IxHb6ld`KE5puF^PF||z20E&kqqaPzij^f=jg7^uwKzE)^02BtPs3?UyuBcXxrre zEwZ9=RTUak`mO%%w^d<7$G=!mzrE_IClbEt_l8wf=VYB%b6+#6f_H@c*)_F+Gi=?# zaO0#8oK*OU4I6(R?xYqS3oZ94>#RTMT%Uq^_ncLmemc2;-b;+HH9FtvbeO8@(>>h%Tf^wnQeQIT1hjS8ly!gBR{^gmv5HvK+)TJWx?ovpq$c0ah| zinC?ox6MLz^18Ej+y1tsP4~#s`eRa#H{PwPU1QI)PyaPm)ntHmWYV6m zR4u7aU)+v+M%C(S%j8op! zXRA>)x|?hEbT&92p11OXlf1S1ym9yTUsMg2kN7Ghtd6Qx?~9Fk?LDW8zSD9|^<0Ol zV|*La=PR;RF%`f2aN_XQ&K^G={IXv24bHer$M1dHKgHSY!^L;z2eHoR)J_eCgj{eo zX?8uhZR{?x?Z|fg@6llp&_Jg14X|Ni7L<^DC?89(6T*>&Hj=`5=uV$&jcfDh}KPFh!>BmvOJg;l4iciSUEbVDh^*_}4=D_DdRD-8?wargTcaB~% zIU#c4L}$vfkJpZV?>lG0ttoFGZ}*S0+o04hZZtUNZ1GoO;*i-($jrIy*UN+KP%!lc~?dRX>F~M}%I` zC%!S;nQ-LaA8nj)#M!Cc>9bR>?Q=HWaqr0cnpen{`+aVFy7IEB>6GN>`XtO$b!xWz zUHz_nRYJju9cRPmszx-lR~V=MzZjuiP^ooohABfKlFe0 z?K;H1=9O#vTK6Fp zJUMWD#dMRk2H7+0aNG0Ron-UPu^(R@IE$vSXUwWt)k>OvmLtJtvMP}(JOXv)2r z{r<~Jc5do<;PR1bB&Xu>Ps0tLld1iF-E?mH4KjPe;5YYOnnO0!JGAf5>Xpd8JFPzI zFe8fO)w*_X?c%%S*s6BA-`Djd`KPrZKO^me zg=}cta&P{)ZDjVe$$#6P-%OT-{SyDy&acR}*tz$ct)s}HyDK`49QzwN`i5!3y}Z$+ z;OqR1&pITK<3A-V5i!HiBfIS(`XxkW{fRwE!JD-j zUwtNy6jWUNcYbOwa`e~qPIUNF#JMte_uJR!lbuuBoI22;GReLWdbd+bL$W&O=)I(d z6Umv@pS(<*npTI>PsI{)=Yp^#w%MKUt_>u6+Ksrkdh=PbddF*(4kUd~*4#^eW?1-mlKWStsabXdvSo3F z^(XFbB})z0I{x?Es`P>_<;Z~Zo9UG=u#-v^lTV&sNM~0M$v)pXm?l?~ZdRDphd%MIo7cBI zSBpMVV}0!THIwMGeOrC-NB4ixXKKaVe}B+L`ozjF7bVqcO_M(=M{n5Fo6hcg<;0lT z9q9#=|E!tUJe5AX{)y0I7s}IL)@bP1^TRy)(qA$A58UccU+e$I)vNzCmHy_7)t2B3 zo9S-{*>9g<7yA^k< za`$^X*4?@B({HqXPEukYy^S{iynOas!!OXrCv*Q8xNHqQx=W?-Dl;~8-~YzC85?`n zC8J}et2*k#iSfzf6aFG0#C+>WboytRL_fD*r~T`W9KILTVM@c;_O$7xBTHWRIg?%x zH^dnl{2aY>|F0j88|0*y%ve84^K%S6{+p~134PNR z{~pOX-0Vv2@3YDLOIy!}Ro_XkZgKO({i*Hf9r>f8BmVA3?|T3D4fVTTqjwm#tZozA zgnny!qqEczg!?0+;_7%;^t`GCy$sXI4>^Rkb+|0kQS zd}!jTFDe8f^k`L{sc=Ci}|?vqn%Z{DfcD4cw>C}kAGaN=3(bL`rs<^>xOzW>34s4wQtQ33*G3;4flVw z?;!7fOpiMGY5_U8^nE(0VO4VcWYy+OlV;@19_#PsrZ18+>MA=fQ~T+>f+H(dcP&pl zYuDMYnbDuleY);z%aiiyoWXr644bu{UNo;_=cpSDU8(OfQ$n+@WYMtO;m(DtNKU*q h@3Wy#lia$O8ZF6Y!7gfS?X&S!l6U;htx+AG|6guris1kN literal 0 HcmV?d00001 diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/gold/upwind.e b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/gold/upwind.e new file mode 100644 index 0000000000000000000000000000000000000000..c3f5fac22fe7882848dea19482c8e7ef920eefbb GIT binary patch literal 88408 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 literal 0 HcmV?d00001 diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/test.i b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/test.i index 37a23fb2d436..b71871c695d0 100644 --- a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/test.i +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/test.i @@ -137,11 +137,15 @@ rho=1 petsc_options_value = 'lu NONZERO' dt = 0.1 end_time = 5.0 - steady_state_detection = false + steady_state_detection = true steady_state_tolerance = 1e-12 nl_abs_tol = 1e-12 [] [Outputs] - exodus = true + [out] + type = Exodus + execute_on = 'final' + hide = 'lambda' + [] [] diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/tests b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/tests index 946303391953..32978ecc3959 100644 --- a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/tests +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/tests @@ -8,7 +8,7 @@ input = 'test.i' exodiff = upwind.e cli_args = 'GlobalParams/advected_interp_method=upwind Outputs/file_base=upwind' - abs_zero = 1e-4 + rel_err = 1e-4 detail = 'first-order upwind' [] [sou] @@ -16,7 +16,7 @@ input = 'test.i' exodiff = sou.e cli_args = 'GlobalParams/advected_interp_method=sou Outputs/file_base=sou' - abs_zero = 1e-4 + rel_err = 1e-4 detail = 'second-order upwind' [] [vanLeer] @@ -24,7 +24,7 @@ input = 'test.i' exodiff = vanLeer.e cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=vanLeer' - abs_zero = 1e-4 + rel_err = 1e-4 detail = 'van Leer' [] [min_mod] @@ -32,7 +32,7 @@ input = 'test.i' exodiff = min_mod.e cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=min_mod' - abs_zero = 1e-4 + rel_err = 1e-4 detail = 'min-mod' [] [quick] @@ -40,7 +40,7 @@ input = 'test.i' exodiff = quick.e cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=quick' - abs_zero = 1e-4 + rel_err = 1e-4 detail = 'QUICK' [] [] From 3a28d09ef68e948c6d5b2aceb94681852ea081a9 Mon Sep 17 00:00:00 2001 From: tanome Date: Thu, 7 Nov 2024 12:45:18 -0700 Subject: [PATCH 12/20] addressing guiallaume's code-reviewer comments Refs #28891 --- framework/include/limiters/Limiter.h | 15 ++------------- framework/include/limiters/MinModLimiter.h | 14 -------------- framework/include/limiters/QUICKLimiter.h | 14 -------------- framework/include/limiters/SOULimiter.h | 14 -------------- framework/include/limiters/VanLeerLimiter.h | 14 -------------- .../include/limiters/VenkatakrishnanLimiter.h | 16 +--------------- framework/include/utils/MathFVUtils.h | 8 ++++---- framework/include/variables/MooseVariableFV.h | 2 +- 8 files changed, 8 insertions(+), 89 deletions(-) diff --git a/framework/include/limiters/Limiter.h b/framework/include/limiters/Limiter.h index 915dc0cb29dd..a0e1aed8922e 100644 --- a/framework/include/limiters/Limiter.h +++ b/framework/include/limiters/Limiter.h @@ -128,8 +128,8 @@ class Limiter * @brief Functor for applying simplified slope limiting. * * This function applies the limiter by invoking the `limit` method with the provided parameters. - * It acts as a functor, enabling objects of the `VanLeerLimiter` class to be used as if they were - * functions. + * It acts as a functor, enabling objects of the derived `Limiter` class to be used as if they + * were functions. * * @tparam T The data type of the scalar values and the return type. * @param phi_upwind The scalar value at the upwind location. @@ -307,17 +307,6 @@ class Limiter * * @note The small epsilon value `1e-10` is added to the delta max and delta min values to * avoid division by zero and numerical instability. - * - * @example - * @code - * Real phi_upwind = 2.0; - * VectorValue grad_upwind(0.1, 0.2, 0.3); - * Real max_value = 5.0; - * Real min_value = 1.0; - * FaceInfo * fi = ... // Assume this is properly initialized - * bool is_upwind = true; - * Real ratio = rf_minmax(phi_upwind, &grad_upwind, max_value, min_value, fi, is_upwind); - * @endcode */ T rf_minmax(const T & phi_upwind, const VectorValue * grad_phi_upwind, diff --git a/framework/include/limiters/MinModLimiter.h b/framework/include/limiters/MinModLimiter.h index 85c1dadb881c..5ff074710add 100644 --- a/framework/include/limiters/MinModLimiter.h +++ b/framework/include/limiters/MinModLimiter.h @@ -85,22 +85,8 @@ class MinModLimiter : public Limiter return 0 * r_f + std::max(T(0), std::min(T(1), r_f)); } - /** - * @brief Indicates whether the Min-Mod limiter is constant. - * - * This method always returns `false` as the Min-Mod limiter is not a constant limiter. - * - * @return `false` indicating the Min-Mod limiter is not constant. - */ bool constant() const override final { return false; } - /** - * @brief Returns the interpolation method used by the Min-Mod limiter. - * - * This method returns `InterpMethod::MinMod`, indicating the interpolation method used. - * - * @return The interpolation method `InterpMethod::MinMod`. - */ InterpMethod interpMethod() const override final { return InterpMethod::MinMod; } /** diff --git a/framework/include/limiters/QUICKLimiter.h b/framework/include/limiters/QUICKLimiter.h index bdbda88027a8..b9faeaa940b2 100644 --- a/framework/include/limiters/QUICKLimiter.h +++ b/framework/include/limiters/QUICKLimiter.h @@ -107,22 +107,8 @@ class QUICKLimiter : public Limiter return limiter; } - /** - * @brief Indicates whether the QUICK limiter is constant. - * - * This method always returns `false` as the QUICK limiter is not a constant limiter. - * - * @return `false` indicating the QUICK limiter is not constant. - */ bool constant() const override final { return false; } - /** - * @brief Returns the interpolation method used by the QUICK limiter. - * - * This method returns `InterpMethod::QUICK`, indicating the interpolation method used. - * - * @return The interpolation method `InterpMethod::QUICK`. - */ InterpMethod interpMethod() const override final { return InterpMethod::QUICK; } /** diff --git a/framework/include/limiters/SOULimiter.h b/framework/include/limiters/SOULimiter.h index 500084dddfd2..cf182d2a6a34 100644 --- a/framework/include/limiters/SOULimiter.h +++ b/framework/include/limiters/SOULimiter.h @@ -112,22 +112,8 @@ class SOULimiter : public Limiter return limiter; } - /** - * @brief Indicates whether the SOU limiter is constant. - * - * This method always returns `false` as the SOU limiter is not a constant limiter. - * - * @return `false` indicating the SOU limiter is not constant. - */ bool constant() const override final { return false; } - /** - * @brief Returns the interpolation method used by the SOU limiter. - * - * This method returns `InterpMethod::SOU`, indicating the interpolation method used. - * - * @return The interpolation method `InterpMethod::SOU`. - */ InterpMethod interpMethod() const override final { return InterpMethod::SOU; } /** diff --git a/framework/include/limiters/VanLeerLimiter.h b/framework/include/limiters/VanLeerLimiter.h index 035c797fdd8f..ec07d948e4a2 100644 --- a/framework/include/limiters/VanLeerLimiter.h +++ b/framework/include/limiters/VanLeerLimiter.h @@ -85,22 +85,8 @@ class VanLeerLimiter : public Limiter return (r_f + std::abs(r_f)) / (1.0 + std::abs(r_f)); } - /** - * @brief Indicates whether the Van Leer limiter is constant. - * - * This method always returns `false` as the Van Leer limiter is not a constant limiter. - * - * @return `false` indicating the Van Leer limiter is not constant. - */ bool constant() const override final { return false; } - /** - * @brief Returns the interpolation method used by the Van Leer limiter. - * - * This method returns `InterpMethod::VanLeer`, indicating the interpolation method used. - * - * @return The interpolation method `InterpMethod::VanLeer`. - */ InterpMethod interpMethod() const override final { return InterpMethod::VanLeer; } /** diff --git a/framework/include/limiters/VenkatakrishnanLimiter.h b/framework/include/limiters/VenkatakrishnanLimiter.h index 3402a02930c6..ab7078d573cb 100644 --- a/framework/include/limiters/VenkatakrishnanLimiter.h +++ b/framework/include/limiters/VenkatakrishnanLimiter.h @@ -44,7 +44,7 @@ namespace FV * \end{cases} * \f] * - * 4. Venkatakrishnan limiter formula: + * 4. Venkatakrishnan limiter formula (Venkatakrishnan, 1993): * \f[ * \beta(r_f) = \frac{2 r_f + 1.0}{r_f (2 r_f + 1.0) + 1.0} * \f] @@ -113,22 +113,8 @@ class VenkatakrishnanLimiter : public Limiter return (2 * rf + 1.0) / (rf * (2 * rf + 1.0) + 1.0); } - /** - * @brief Indicates whether the Venkatakrishnan limiter is constant. - * - * This method always returns `false` as the Venkatakrishnan limiter is not a constant limiter. - * - * @return `false` indicating the Venkatakrishnan limiter is not constant. - */ bool constant() const override final { return false; } - /** - * @brief Returns the interpolation method used by the Venkatakrishnan limiter. - * - * This method returns `InterpMethod::SOU`, indicating the interpolation method used. - * - * @return The interpolation method `InterpMethod::SOU`. - */ InterpMethod interpMethod() const override final { return InterpMethod::SOU; } /** diff --git a/framework/include/utils/MathFVUtils.h b/framework/include/utils/MathFVUtils.h index e9f3feddff34..71dbf709ef13 100644 --- a/framework/include/utils/MathFVUtils.h +++ b/framework/include/utils/MathFVUtils.h @@ -679,7 +679,7 @@ computeMinMaxValue(const FunctorBase & functor, const FaceArg & face, const S Real max_value(std::numeric_limits::min()), min_value(std::numeric_limits::max()); // Iterate over the direct neighbors of the element associated with the face - for (auto neighbor : (*face.fi).elem().neighbor_ptr_range()) + for (const auto neighbor : (*face.fi).elem().neighbor_ptr_range()) { // If not a valid neighbor, skip to the next one if (neighbor == nullptr) @@ -694,7 +694,7 @@ computeMinMaxValue(const FunctorBase & functor, const FaceArg & face, const S } // Iterate over the neighbors of the neighbor - for (auto neighbor : (*face.fi).neighbor().neighbor_ptr_range()) + for (const auto neighbor : (*face.fi).neighbor().neighbor_ptr_range()) { // If not a valid neighbor, skip to the next one if (neighbor == nullptr) @@ -761,7 +761,7 @@ computeMinMaxValue(const FunctorBase> & functor, Real max_value(std::numeric_limits::min()), min_value(std::numeric_limits::max()); // Iterate over the direct neighbors of the element associated with the face - for (auto neighbor : (*face.fi).elem().neighbor_ptr_range()) + for (const auto neighbor : (*face.fi).elem().neighbor_ptr_range()) { // If not a valid neighbor, skip to the next one if (neighbor == nullptr) @@ -776,7 +776,7 @@ computeMinMaxValue(const FunctorBase> & functor, } // Iterate over the neighbors of the neighbor associated with the face - for (auto neighbor : (*face.fi).neighbor().neighbor_ptr_range()) + for (const auto neighbor : (*face.fi).neighbor().neighbor_ptr_range()) { // If not a valid neighbor, skip to the next one if (neighbor == nullptr) diff --git a/framework/include/variables/MooseVariableFV.h b/framework/include/variables/MooseVariableFV.h index b4b3096e6ca8..34badfa92c81 100644 --- a/framework/include/variables/MooseVariableFV.h +++ b/framework/include/variables/MooseVariableFV.h @@ -651,7 +651,7 @@ class MooseVariableFV : public MooseVariableField const Elem * elem_side_to_extrapolate_from, const StateArg & state) const; - /// Function to get the two term boundary expansion for the variable + /// Function to get wether two term boundary expansion is used for the variable const bool & getTwoTermBoundaryExpansion() const { return _two_term_boundary_expansion; } protected: From a05b07f7e56c70ba067cfcd51af77e7c728417ec Mon Sep 17 00:00:00 2001 From: tanome Date: Fri, 8 Nov 2024 10:55:38 -0700 Subject: [PATCH 13/20] changing test tolerances to match serial and parallel runs Refs #28891 --- .../finite_volume/limiters/lid-driven-segregated/tests | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests index 103b1c91d405..9fff4b87af06 100644 --- a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests @@ -8,7 +8,7 @@ input = 'lid-driven-segregated.i' exodiff = 'upwind.e' detail = 'and reach converged results with upwind advection scheme.' - abs_zero = 1e-4 + rel_err = 1e-3 cli_args = 'GlobalParams/advected_interp_method=upwind Outputs/file_base=upwind' prereq = segregated_advection_limiting_schemes/upwind_run heavy = true @@ -46,7 +46,7 @@ input = 'lid-driven-segregated.i' exodiff = 'min_mod.e' detail = 'and reach converged results with min-mod limiter.' - abs_zero = 1e-4 + rel_err = 1e-3 cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=min_mod' prereq = segregated_advection_limiting_schemes/min_mod_run heavy = true @@ -65,7 +65,7 @@ input = 'lid-driven-segregated.i' exodiff = 'quick.e' detail = 'and reach converged results with QUICK limiter.' - abs_zero = 1e-4 + rel_err = 1e-3 cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=quick' prereq = segregated_advection_limiting_schemes/quick_run heavy = true From d199348fc3fc51891af013290b22491512c463a2 Mon Sep 17 00:00:00 2001 From: Mauricio Tano Date: Tue, 12 Nov 2024 13:48:24 -0700 Subject: [PATCH 14/20] Apply suggestions from code review peter Refs #28891 Co-authored-by: Peter German <31662443+grmnptr@users.noreply.github.com> --- .../doc/content/syntax/Limiters/index.md | 12 +- framework/include/limiters/Limiter.h | 159 +++--------------- framework/include/limiters/MinModLimiter.h | 27 +-- framework/include/limiters/QUICKLimiter.h | 31 +--- framework/include/limiters/SOULimiter.h | 28 --- framework/include/limiters/VanLeerLimiter.h | 27 +-- .../include/limiters/VenkatakrishnanLimiter.h | 35 +--- framework/include/utils/MathFVUtils.h | 101 +---------- 8 files changed, 36 insertions(+), 384 deletions(-) diff --git a/framework/doc/content/syntax/Limiters/index.md b/framework/doc/content/syntax/Limiters/index.md index 6875812a85de..1a674bfc111c 100644 --- a/framework/doc/content/syntax/Limiters/index.md +++ b/framework/doc/content/syntax/Limiters/index.md @@ -94,7 +94,7 @@ TVD, and what the functional form of the flux limiting function $\beta(r)$ is. | `SOU` | 2 | No | $r$ | | `QUICK` | 2 | No | $\frac{3+r}{4}$ | -## Limiting Process for Incompressible and Weakly-Compressible flow Flow +## Limiting Process for Incompressible and Weakly-Compressible flow A full second-order upwind reconstruction is used for incompressible and weakly-compressible solvers. In this reconstruction, the limited quantity at the face is expressed as follows: @@ -112,7 +112,7 @@ where: Two kinds of limiters are supported: slope-limited and face-value limited. These limiters are defined below. -For slope-limiting, the limiting function $r$ is defined as follows: +For slope-limiting, the approximate gradient ratio (or flux limiting ratio) $r$ is defined as follows: \begin{equation} r = 2 \frac{\bm{d}_{NC} \cdot (\nabla \bm{\Psi})_C}{\bm{d}_{NC} \cdot (\nabla \bm{\Psi})_f} - 1 @@ -153,8 +153,7 @@ Each of the limiters implemented along with the implementation reference, limiti | `Venkatakrishnan` [!citep](venkatakrishnan1993) | Face-Value | No | $\frac{2r+1}{r(2r+1)+1}$ | -To illustrate the performance of the limiters, a dispersion analysis is developed. -The problem is illustrated in [dispersion]. +To illustrate the performance of the limiters, a dispersion analysis is developedand presented in [dispersion]. This consists of the advection of a passive scalar in a Cartesian mesh at 45 degrees. The exact solution, without numerical diffusion, is a straight line at 45 degrees dividing the regions with a scalar concentration of 1 and 0. @@ -173,4 +172,9 @@ can be expected for each of the limiters. id=dispersion_line caption=Performance of each of the limiters in a line perpendicular to the advection front. +!alert warning +When using limiters with `Executioner` of `type = Steady`, +the solver uses the previous nonlinear iterate for the limiting flux. +This can ultimately lead to bad condition numbers in the Jacobian and poor convergence. + !bibtex bibliography diff --git a/framework/include/limiters/Limiter.h b/framework/include/limiters/Limiter.h index a0e1aed8922e..ae1b3450e796 100644 --- a/framework/include/limiters/Limiter.h +++ b/framework/include/limiters/Limiter.h @@ -63,18 +63,16 @@ class Limiter { public: /** - * @brief Pure virtual method for computing the flux limiting ratio. - * * This method computes the flux limiting ratio based on the provided scalar values, * gradient vectors, direction vector, maximum and minimum allowable values, and * geometric information from the face and cell centroids. It must be overridden * by any derived class implementing a specific limiting strategy. * - * @tparam T The data type of the scalar values and the return type. - * @param phi_upwind The scalar value at the upwind location. - * @param phi_downwind The scalar value at the downwind location. - * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. - * @param grad_phi_downwind Pointer to the gradient vector at the downwind location. + * @tparam T The data type of the field values and the return type. + * @param phi_upwind The field value at the upwind location. + * @param phi_downwind The field value at the downwind location. + * @param grad_phi_upwind Pointer to the gradient of the field at the upwind location. + * @param grad_phi_downwind Pointer to the gradient of the field at the downwind location. * @param dCD A constant direction vector representing the direction of the cell face. * @param max_value The maximum allowable value. * @param min_value The minimum allowable value. @@ -87,30 +85,6 @@ class Limiter * the specific limiting algorithm. Derived classes will provide the actual logic for computing * the flux limiting ratio, ensuring that the result adheres to the constraints and properties * required by the specific limiting method. - * - * Here is an example of how a derived class might implement this method: - * - * @example - * @code - * class MyLimiter : public Limiter - * { - * public: - * Real limit(const Real & phi_upwind, - * const Real & phi_downwind, - * const VectorValue * grad_phi_upwind, - * const VectorValue * grad_phi_downwind, - * const RealVectorValue & dCD, - * const Real & max_value, - * const Real & min_value, - * const FaceInfo * fi, - * const bool & fi_elem_is_upwind) const override - * { - * // Implementation of the specific limiting algorithm. - * Real ratio = ... // Compute the ratio. - * return ratio; // Return the computed ratio. - * } - * }; - * @endcode */ virtual T limit(const T & phi_upwind, const T & phi_downwind, @@ -125,35 +99,12 @@ class Limiter virtual InterpMethod interpMethod() const = 0; /** - * @brief Functor for applying simplified slope limiting. - * - * This function applies the limiter by invoking the `limit` method with the provided parameters. - * It acts as a functor, enabling objects of the derived `Limiter` class to be used as if they - * were functions. - * - * @tparam T The data type of the scalar values and the return type. - * @param phi_upwind The scalar value at the upwind location. - * @param phi_downwind The scalar value at the downwind location. - * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. + * @tparam T The data type of the field values and the return type. + * @param phi_upwind The field value at the upwind location. + * @param phi_downwind The field value at the downwind location. + * @param grad_phi_upwind Pointer to the gradient of the field value at the upwind location. * @param dCD A constant direction vector representing the direction of the cell face. * @return The computed limited value, ensuring it is within the range [0, 2]. - * - * This method performs the following steps: - * 1. Calls the `limit` method with the provided scalar values, the upwind gradient vector, and - * the direction vector. - * 2. Ensures the result is within the range [0, 2] by using `std::max` and `std::min`. - * 3. Returns the computed limited value. - * - * @example - * @code - * Limiter * myLimiter = ... // Assume this is properly initialized - * Real phi_upwind = 2.0; - * Real phi_downwind = 1.5; - * VectorValue grad_upwind(0.1, 0.2, 0.3); - * RealVectorValue dCD(1.0, 0.0, 0.0); - * FaceInfo * fi = ... // Assume this is properly initialized - * Real result = (*myLimiter)(phi_upwind, phi_downwind, &grad_upwind, dCD); - * @endcode */ T operator()(const T & phi_upwind, const T & phi_downwind, @@ -174,17 +125,11 @@ class Limiter } /** - * @brief Functor for applying general slope limiter. - * - * This function applies the slope limiter by invoking the `limit` method with the provided - * parameters. It acts as a functor, enabling objects of the `Limiter` class to be used as if they - * were functions. - * - * @tparam T The data type of the scalar values and the return type. - * @param phi_upwind The scalar value at the upwind location. - * @param phi_downwind The scalar value at the downwind location. - * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. - * @param grad_phi_downwind Pointer to the gradient vector at the downwind location. + * @tparam T The data type of the field values and the return type. + * @param phi_upwind The field value at the upwind location. + * @param phi_downwind The field value at the downwind location. + * @param grad_phi_upwind Pointer to the gradient at the upwind location. + * @param grad_phi_downwind Pointer to the gradient at the downwind location. * @param dCD A constant direction vector representing the direction of the cell face. * @param max_value The maximum allowable value. * @param min_value The minimum allowable value. @@ -192,30 +137,6 @@ class Limiter * centroids. * @param fi_elem_is_upwind Boolean indicating if the face info element is upwind. * @return The result of the `limit` function applied to the provided parameters. - * - * This function performs the following steps: - * 1. Calls the `limit` method with the provided scalar values, gradient vectors, direction - * vector, maximum and minimum values, face information, and upwind status. - * 2. Returns the result of the `limit` method. - * - * This functor allows for more intuitive and flexible usage of the `Limiter` class, enabling - * instances of the class to be called with arguments directly. - * - * @example - * @code - * Limiter * myLimiter = ... // Assume this is properly initialized - * Real phi_upwind = 2.0; - * Real phi_downwind = 1.5; - * VectorValue grad_upwind(0.1, 0.2, 0.3); - * VectorValue grad_downwind(0.4, 0.5, 0.6); - * RealVectorValue dCD(1.0, 0.0, 0.0); - * Real max_value = 5.0; - * Real min_value = 1.0; - * FaceInfo * fi = ... // Assume this is properly initialized - * bool is_upwind = true; - * Real result = (*myLimiter)(phi_upwind, phi_downwind, &grad_upwind, &grad_downwind, dCD, - * max_value, min_value, fi, is_upwind); - * @endcode */ T operator()(const T & phi_upwind, const T & phi_downwind, @@ -239,34 +160,11 @@ class Limiter } /** - * @brief Computes the flux limiting ratio using gradients. - * This method works well for incompressible and compressible flow. - * - * This function calculates the flux limiting ratio based on the provided gradients - * at the upwind and downwind locations, along with a direction vector. - * * @tparam T The data type of the gradient values and the return type. - * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. - * @param grad_phi_downwind Pointer to the gradient vector at the downwind location. + * @param grad_phi_upwind Pointer to the gradient at the upwind location. + * @param grad_phi_downwind Pointer to the gradient at the downwind location. * @param dCD A constant direction vector representing the direction of the cell face. * @return The computed flux limiting ratio. - * - * This function performs the following steps: - * 1. Computes the dot product of the upwind gradient vector with the direction vector `dCD`. - * 2. Computes the dot product of the downwind gradient vector with the direction vector `dCD`. - * 3. Calculates the ratio of the upwind gradient dot product to the downwind gradient dot - * product, adding a small epsilon value to the denominator to prevent division by zero. - * - * @note The small epsilon value `1e-10` is added to the denominator to avoid division by zero - * and numerical instability. - * - * @example - * @code - * VectorValue grad_upwind(0.1, 0.2, 0.3); - * VectorValue grad_downwind(0.4, 0.5, 0.6); - * RealVectorValue dCD(1.0, 0.0, 0.0); - * Real ratio = rf_grad(&grad_upwind, &grad_downwind, dCD); - * @endcode */ T rf_grad(const VectorValue * grad_phi_upwind, const VectorValue * grad_phi_downwind, @@ -279,34 +177,15 @@ class Limiter }; /** - * @brief Computes the flux limiting ratio using successive deltas. - * - * This function calculates the flux limiting ratio based on the upwind value, - * its gradient, maximum and minimum allowable values, and geometric information - * from the face and cell centroids. - * - * @tparam T The data type of the scalar values and the return type. - * @param phi_upwind The scalar value at the upwind location. - * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. + * @tparam T The data type of the field values and the return type. + * @param phi_upwind The field value at the upwind location. + * @param grad_phi_upwind Pointer to the gradient at the upwind location. * @param max_value The maximum allowable value. * @param min_value The minimum allowable value. * @param fi FaceInfo object containing geometric details such as face centroid and cell * centroids. * @param fi_elem_is_upwind Boolean indicating if the face info element is upwind. * @return The computed flux limiting ratio. - * - * This function performs the following steps: - * 1. Retrieves the face centroid from the `FaceInfo` object. - * 2. Determines the cell centroid based on whether the current element is upwind. - * 3. Computes the delta value at the face by taking the dot product of the upwind gradient - * vector with the difference between the face and cell centroids. - * 4. Computes the delta values for the maximum and minimum allowable values, adding a small - * epsilon value to prevent division by zero. - * 5. Calculates the flux limiting ratio based on whether the delta value at the face is - * non-negative or negative, using the appropriate delta (either max or min). - * - * @note The small epsilon value `1e-10` is added to the delta max and delta min values to - * avoid division by zero and numerical instability. */ T rf_minmax(const T & phi_upwind, const VectorValue * grad_phi_upwind, diff --git a/framework/include/limiters/MinModLimiter.h b/framework/include/limiters/MinModLimiter.h index 5ff074710add..a70f3a6814de 100644 --- a/framework/include/limiters/MinModLimiter.h +++ b/framework/include/limiters/MinModLimiter.h @@ -17,11 +17,7 @@ namespace Moose namespace FV { /** - * @brief Implements the Min-Mod limiter for flux limiting in numerical methods. - * - * The Min-Mod limiter is used to reduce numerical oscillations and - * enforce monotonicity in computational fluid dynamics (CFD) and other numerical simulations. - * The limiter function $\beta(r_f)$ is defined as: + * The Min-Mod limiter function $\beta(r_f)$ is defined as: * * \f[ * \beta(r_f) = \text{max}(0, \text{min}(1, r_f)) @@ -36,8 +32,6 @@ class MinModLimiter : public Limiter { public: /** - * @brief Computes the limited value using the Min-Mod limiter. - * * This method overrides the pure virtual `limit` method in the base `Limiter` class. * It calculates the flux limiting ratio based on the Min-Mod limiter formula. * @@ -45,22 +39,6 @@ class MinModLimiter : public Limiter * @param grad_phi_downwind Pointer to the gradient vector at the downwind location. * @param dCD A constant direction vector representing the direction of the cell face. * @return The computed flux limiting ratio. - * - * This method performs the following steps: - * 1. Asserts that the upwind gradient pointer is not null. - * 2. Computes the gradient ratio coefficient \( r_f \) using the `rf_grad` method. - * 3. Applies the Min-Mod limiter formula to \( r_f \) to obtain the limited value. - * 4. Returns the computed limited value. - * - * @example - * @code - * MinModLimiter minMod; - * VectorValue grad_upwind(0.1, 0.2, 0.3); - * VectorValue grad_downwind(0.4, 0.5, 0.6); - * RealVectorValue dCD(1.0, 0.0, 0.0); - * Real result = minMod.limit(0.0, 0.0, &grad_upwind, &grad_downwind, dCD, 0.0, 0.0, nullptr, - * true); - * @endcode */ T limit(const T & phi_upwind, const T & phi_downwind, @@ -89,9 +67,6 @@ class MinModLimiter : public Limiter InterpMethod interpMethod() const override final { return InterpMethod::MinMod; } - /** - * @brief Default constructor for the Min-Mod limiter. - */ MinModLimiter() = default; }; } diff --git a/framework/include/limiters/QUICKLimiter.h b/framework/include/limiters/QUICKLimiter.h index b9faeaa940b2..38355ddda121 100644 --- a/framework/include/limiters/QUICKLimiter.h +++ b/framework/include/limiters/QUICKLimiter.h @@ -17,13 +17,8 @@ namespace Moose namespace FV { /** - * @brief Implements the QUICK limiter for flux limiting in numerical methods. - * - * The QUICK (Quadratic Upstream Interpolation for Convective Kinematics) limiter is used to reduce - * numerical oscillations and enforce monotonicity in computational fluid dynamics (CFD) and other - * numerical simulations. This limiter ensures Total Variation Diminishing (TVD) compliance. - * - * The limiter function is derived from the following equations: + * The QUICK (Quadratic Upstream Interpolation for Convective Kinematics) limiter + * function is derived from the following equations: * * 1. Calculation of the gradient ratio coefficient \( r_f \): * \f[ @@ -45,8 +40,6 @@ class QUICKLimiter : public Limiter { public: /** - * @brief Computes the limited value using the QUICK limiter. - * * This method overrides the pure virtual `limit` method in the base `Limiter` class. * It calculates the flux limiting ratio based on the QUICK limiter formula. * @@ -56,23 +49,6 @@ class QUICKLimiter : public Limiter * @param grad_phi_downwind Pointer to the gradient vector at the downwind location. * @param dCD A constant direction vector representing the direction of the cell face. * @return The computed flux limiting ratio. - * - * This method performs the following steps: - * 1. Asserts that the upwind gradient pointer is not null. - * 2. Computes the gradient ratio coefficient \( r_f \) using the `rf_grad` method or `rF` method. - * 3. Applies the QUICK limiter formula to \( r_f \) to obtain the limited value, ensuring TVD - * compliance. - * 4. Returns the computed limited value. - * - * @example - * @code - * QUICKLimiter quick; - * VectorValue grad_upwind(0.1, 0.2, 0.3); - * VectorValue grad_downwind(0.4, 0.5, 0.6); - * RealVectorValue dCD(1.0, 0.0, 0.0); - * Real result = quick.limit(0.0, 0.0, &grad_upwind, &grad_downwind, dCD, 0.0, 0.0, nullptr, - * true); - * @endcode */ T limit(const T & phi_upwind, const T & phi_downwind, @@ -111,9 +87,6 @@ class QUICKLimiter : public Limiter InterpMethod interpMethod() const override final { return InterpMethod::QUICK; } - /** - * @brief Default constructor for the QUICK limiter. - */ QUICKLimiter() = default; }; } diff --git a/framework/include/limiters/SOULimiter.h b/framework/include/limiters/SOULimiter.h index cf182d2a6a34..020e18c6ae70 100644 --- a/framework/include/limiters/SOULimiter.h +++ b/framework/include/limiters/SOULimiter.h @@ -17,8 +17,6 @@ namespace Moose namespace FV { /** - * @brief Implements the Second-Order Upwind (SOU) limiter for flux limiting in numerical methods. - * * The SOU limiter is used for reproducing the second-order-upwind scheme. The limiter function * $\beta(delta_max)$ is defined as: * @@ -37,8 +35,6 @@ class SOULimiter : public Limiter { public: /** - * @brief Computes the limited value using the SOU limiter. - * * This method overrides the pure virtual `limit` method in the base `Limiter` class. * It calculates the flux limiting ratio based on the SOU limiter formula. * @@ -50,27 +46,6 @@ class SOULimiter : public Limiter * @param fi Pointer to the face information structure. * @param fi_elem_is_upwind Boolean flag indicating if the current element is upwind. * @return The computed flux limiting ratio. - * - * This method performs the following steps: - * 1. Asserts that the upwind gradient pointer is not null. - * 2. Handles initialization conflict by determining the face centroid and the appropriate cell - * centroid. - * 3. Computes the absolute delta value at the face. - * 4. Computes the delta between the two elements. - * 5. Returns the limited value based on the computed deltas. - * - * @example - * @code - * SOULimiter sou; - * VectorValue grad_upwind(0.1, 0.2, 0.3); - * RealVectorValue dCD(1.0, 0.0, 0.0); - * Real max_value = 1.0; - * Real min_value = 0.0; - * FaceInfo fi; - * bool fi_elem_is_upwind = true; - * Real result = sou.limit(0.0, 0.0, &grad_upwind, nullptr, dCD, max_value, min_value, &fi, - * fi_elem_is_upwind); - * @endcode */ T limit(const T & phi_upwind, const T & phi_downwind, @@ -116,9 +91,6 @@ class SOULimiter : public Limiter InterpMethod interpMethod() const override final { return InterpMethod::SOU; } - /** - * @brief Default constructor for the SOU limiter. - */ SOULimiter() = default; }; } diff --git a/framework/include/limiters/VanLeerLimiter.h b/framework/include/limiters/VanLeerLimiter.h index ec07d948e4a2..8ed61b409fb0 100644 --- a/framework/include/limiters/VanLeerLimiter.h +++ b/framework/include/limiters/VanLeerLimiter.h @@ -17,11 +17,7 @@ namespace Moose namespace FV { /** - * @brief Implements the Van Leer limiter for flux limiting in numerical methods. - * - * The Van Leer limiter is a slope limiter used to reduce numerical oscillations and - * enforce monotonicity in computational fluid dynamics (CFD) and other numerical simulations. - * The limiter function $\beta(r_f)$ is defined as: + * The Van Leer limiter limiter function $\beta(r_f)$ is defined as: * * \f[ * \beta(r_f) = \frac{r_f + \text{abs}(r_f)}{1 + \text{abs}(r_f)} @@ -36,8 +32,6 @@ class VanLeerLimiter : public Limiter { public: /** - * @brief Computes the limited value using the Van Leer limiter. - * * This method overrides the pure virtual `limit` method in the base `Limiter` class. * It calculates the flux limiting ratio based on the Van Leer limiter formula. * @@ -45,22 +39,6 @@ class VanLeerLimiter : public Limiter * @param grad_phi_downwind Pointer to the gradient vector at the downwind location. * @param dCD A constant direction vector representing the direction of the cell face. * @return The computed flux limiting ratio. - * - * This method performs the following steps: - * 1. Asserts that the upwind and downwind gradient pointers are not null. - * 2. Computes the gradient ratio coefficient \( r_f \) using the `rf_grad` method. - * 3. Applies the Van Leer limiter formula to \( r_f \) to obtain the limited value. - * 4. Returns the computed limited value. - * - * @example - * @code - * VanLeerLimiter vanLeer; - * VectorValue grad_upwind(0.1, 0.2, 0.3); - * VectorValue grad_downwind(0.4, 0.5, 0.6); - * RealVectorValue dCD(1.0, 0.0, 0.0); - * Real result = vanLeer.limit(0.0, 0.0, &grad_upwind, &grad_downwind, dCD, 0.0, 0.0, nullptr, - * true); - * @endcode */ T limit(const T & phi_upwind, const T & phi_downwind, @@ -89,9 +67,6 @@ class VanLeerLimiter : public Limiter InterpMethod interpMethod() const override final { return InterpMethod::VanLeer; } - /** - * @brief Default constructor for the Van Leer limiter. - */ VanLeerLimiter() = default; }; } diff --git a/framework/include/limiters/VenkatakrishnanLimiter.h b/framework/include/limiters/VenkatakrishnanLimiter.h index ab7078d573cb..ae9da92c3100 100644 --- a/framework/include/limiters/VenkatakrishnanLimiter.h +++ b/framework/include/limiters/VenkatakrishnanLimiter.h @@ -17,14 +17,7 @@ namespace Moose namespace FV { /** - * @brief Implements the Venkatakrishnan limiter for flux limiting. - * - * The Venkatakrishnan limiter is used to reduce numerical oscillations and enforce monotonicity - * in computational fluid dynamics (CFD) and other numerical simulations. This limiter adjusts - * the flux limiting ratio based on face centroids and cell centroids, handling different gradient - * conditions. - * - * The limiter function is derived from the following equations: + * The Venkatakrishnan limiter is derived from the following equations: * * 1. Calculation of the face delta: * \f[ @@ -56,8 +49,6 @@ class VenkatakrishnanLimiter : public Limiter { public: /** - * @brief Computes the limited value using the Venkatakrishnan limiter. - * * This method overrides the pure virtual `limit` method in the base `Limiter` class. * It calculates the flux limiting ratio based on the Venkatakrishnan limiter formula. * @@ -68,27 +59,6 @@ class VenkatakrishnanLimiter : public Limiter * @param fi Pointer to the face information structure. * @param fi_elem_is_upwind Boolean flag indicating if the current element is upwind. * @return The computed flux limiting ratio. - * - * This method performs the following steps: - * 1. Determines the face centroid and the appropriate cell centroid. - * 2. Computes the delta value at the face. - * 3. Computes deltas for the maximum and minimum values relative to the upwind value. - * 4. Computes the ratio \( r_f \) based on the sign of the delta face value. - * 5. Applies the Venkatakrishnan limiter formula to \( r_f \) to obtain the limited value. - * 6. Returns the computed limited value. - * - * @example - * @code - * VenkatakrishnanLimiter venkatakrishnan; - * VectorValue grad_upwind(0.1, 0.2, 0.3); - * RealVectorValue dCD(1.0, 0.0, 0.0); - * Real max_value = 1.0; - * Real min_value = 0.0; - * FaceInfo fi; - * bool fi_elem_is_upwind = true; - * Real result = venkatakrishnan.limit(0.0, 0.0, &grad_upwind, nullptr, dCD, max_value, min_value, - * &fi, fi_elem_is_upwind); - * @endcode */ T limit(const T & phi_upwind, const T & /* phi_downwind */, @@ -117,9 +87,6 @@ class VenkatakrishnanLimiter : public Limiter InterpMethod interpMethod() const override final { return InterpMethod::SOU; } - /** - * @brief Default constructor for the Venkatakrishnan limiter. - */ VenkatakrishnanLimiter() = default; }; } diff --git a/framework/include/utils/MathFVUtils.h b/framework/include/utils/MathFVUtils.h index 71dbf709ef13..3e07407219d9 100644 --- a/framework/include/utils/MathFVUtils.h +++ b/framework/include/utils/MathFVUtils.h @@ -558,8 +558,6 @@ interpolate(const Limiter & limiter, } /** - * @brief Computes the full limited interpolation of a variable using a specified limiter. - * * This function performs a full limited interpolation of a variable, taking into account * the values and gradients at both upwind and downwind locations, as well as geometric * information and limits. It applies the specified limiter to ensure the interpolation @@ -567,26 +565,15 @@ interpolate(const Limiter & limiter, * * @tparam T The data type of the scalar values and the return type. * @param limiter The limiter object used to compute the flux limiting ratio. - * @param phi_upwind The scalar value at the upwind location. - * @param phi_downwind The scalar value at the downwind location. - * @param grad_phi_upwind Pointer to the gradient vector at the upwind location. - * @param grad_phi_face Pointer to the gradient vector at the face location. + * @param phi_upwind The field value at the upwind location. + * @param phi_downwind The field value at the downwind location. + * @param grad_phi_upwind Pointer to the gradient at the upwind location. + * @param grad_phi_face Pointer to the gradient at the face location. * @param fi FaceInfo object containing geometric details such as face centroid and cell centroids. * @param fi_elem_is_upwind Boolean indicating if the face info element is upwind. * @param max_value The maximum allowable value. * @param min_value The minimum allowable value. * @return The computed limited interpolation value. - * - * This function performs the following steps: - * 1. Computes the direction vector \( dCD \) based on whether the current element is upwind. - * 2. Calls the `limiter` functor with the provided scalar values, gradient vectors, direction - * vector, and geometric information to compute the flux limiting ratio \( \beta \). - * 3. Determines the face centroid and the appropriate cell centroid based on whether the current - * element is upwind. - * 4. Computes the delta value at the face by taking the dot product of the upwind gradient vector - * with the difference between the face and cell centroids. - * 5. Returns the interpolated value by adding the product of the limiter \( \beta \) and the delta - * value to the upwind scalar value. */ template T @@ -630,9 +617,6 @@ fullLimitedInterpolation(const Limiter & limiter, } /** - * @brief Computes the minimum and maximum scalar values in a two-cell stencil around a given face - * in a computational grid. - * * This function calculates the minimum and maximum values within a two-cell stencil. The stencil * includes the immediate neighboring elements of the face's associated element and the neighboring * elements of those neighbors. It evaluates the values using a provided functor and accounts for @@ -653,21 +637,6 @@ fullLimitedInterpolation(const Limiter & limiter, * @return std::pair A pair containing the minimum and maximum values computed across the * two-cell stencil. The first element is the maximum value, and the second element is the minimum * value. - * - * This function performs the following steps: - * 1. Initializes max_value to 0 and min_value to a large value. - * 2. Iterates over the direct neighbors of the element associated with the face. - * - If a neighbor is valid (not null), it evaluates the functor at that neighbor and updates - * max_value and min_value. - * 3. Iterates over the neighbors of the neighbors. - * - Similar to the first loop, it evaluates the functor at valid neighbors and updates max_value - * and min_value. - * 4. Returns a pair containing the computed max_value and min_value. - * - * Usage: - * This function is typically used in the finite volume methods for min-max computations over - * stencils (neighborhoods). It helps compute the limiting for limited second order upwind at the - * faces. */ template & functor, const FaceArg & face, const S } /** - * @brief Computes the minimum and maximum scalar values of a specific component in a two-cell - * stencil around a given face in a computational grid. - * * This function calculates the minimum and maximum values of a specified component within a * two-cell stencil. The stencil includes the immediate neighboring elements of the face's * associated element and the neighboring elements of those neighbors. It evaluates the values using @@ -735,16 +701,6 @@ computeMinMaxValue(const FunctorBase & functor, const FaceArg & face, const S * component computed across the two-cell stencil. The first element is the maximum value, and the * second element is the minimum value. * - * This function performs the following steps: - * 1. Initializes max_value to 0 and min_value to a large value. - * 2. Iterates over the direct neighbors of the element associated with the face. - * - If a neighbor is valid (not null), it evaluates the functor at that neighbor for the - * specified component and updates max_value and min_value. - * 3. Iterates over the neighbors of the neighbors. - * - Similar to the first loop, it evaluates the functor at valid neighbors for the specified - * component and updates max_value and min_value. - * 4. Returns a pair containing the computed max_value and min_value. - * * Usage: * This function is typically used in the finite volume methods for min-max computations over * stencils (neighborhoods). It helps compute the limiting for limited second order upwind at the @@ -795,8 +751,6 @@ computeMinMaxValue(const FunctorBase> & functor, } /** - * @brief Interpolates with a limiter and a face argument. - * * This function interpolates values using a specified limiter and face argument. It evaluates the * values at upwind and downwind locations and computes interpolation coefficients and advected * values. @@ -820,15 +774,6 @@ computeMinMaxValue(const FunctorBase> & functor, * - The second pair corresponds to the face information functor element * value and neighbor value. * - * This function performs the following steps: - * 1. Asserts that the face information is non-null. - * 2. Constructs a limiter based on the face limiter type. - * 3. Determines the upwind and downwind arguments based on the face element. - * 4. Evaluates the functor at the upwind and downwind locations. - * 5. Computes the interpolation coefficients using the specified limiter. - * 6. If necessary, computes the gradient and min-max values for certain limiter types. - * 7. Returns the interpolation coefficients and advected values. - * * Usage: * This function is used for interpolating values at faces in a finite volume method, ensuring that * the interpolation adheres to the constraints imposed by the limiter. @@ -848,7 +793,6 @@ interpCoeffsAndAdvected(const FunctorBase & functor, const FaceArg & face, co typedef typename FunctorBase::GradientType GradientType; static const GradientType zero(0); - // Assert that the face information is non-null mooseAssert(face.fi, "this must be non-null"); // Construct the limiter based on the face limiter type @@ -868,7 +812,6 @@ interpCoeffsAndAdvected(const FunctorBase & functor, const FaceArg & face, co // Compute interpolation coefficients for Upwind or CentralDifference limiters if (face.limiter_type == LimiterType::Upwind || face.limiter_type == LimiterType::CentralDifference) - { interp_coeffs = interpCoeffs(*limiter, phi_upwind, phi_downwind, @@ -878,7 +821,6 @@ interpCoeffsAndAdvected(const FunctorBase & functor, const FaceArg & face, co std::numeric_limits::min(), *face.fi, face.elem_is_upwind); - } else { // Determine the time argument for the limiter @@ -893,9 +835,7 @@ interpCoeffsAndAdvected(const FunctorBase & functor, const FaceArg & face, co // Compute min-max values for min-max limiters if (face.limiter_type == LimiterType::Venkatakrishnan || face.limiter_type == LimiterType::SOU) - { std::tie(max_value, min_value) = computeMinMaxValue(functor, face, *time_arg); - } // Evaluate the gradient of the functor at the upwind and downwind locations const auto grad_phi_upwind = functor.template genericEvaluate(upwind_arg, *time_arg); @@ -924,8 +864,6 @@ interpCoeffsAndAdvected(const FunctorBase & functor, const FaceArg & face, co } /** - * @brief Interpolates values using a specified functor and face argument. - * * This function interpolates values at faces in a computational grid using a specified functor, * face argument, and evaluation kind. It handles different limiter types and performs * interpolation accordingly. @@ -944,14 +882,6 @@ interpCoeffsAndAdvected(const FunctorBase & functor, const FaceArg & face, co * * @return T The interpolated value at the face. * - * This function performs the following steps: - * 1. Checks that only supported FunctorEvaluationKinds are used. - * 2. Handles central differencing separately as it supports skew correction. - * 3. For Upwind or CentralDifference limiters, computes interpolation coefficients and advected - * values. - * 4. For other limiter types, computes the gradient and min-max values if necessary, and performs - * full limited interpolation. - * * Usage: * This function is used for interpolating values at faces in a finite volume method, ensuring that * the interpolation adheres to the constraints imposed by the limiter. @@ -1024,8 +954,6 @@ interpolate(const FunctorBase & functor, const FaceArg & face, const StateArg } /** - * @brief Interpolates vector values using a specified functor and face argument. - * * This function interpolates vector values at faces in a computational grid using a specified * functor, face argument, and limiter type. It handles different limiter types and performs * interpolation accordingly. @@ -1041,15 +969,6 @@ interpolate(const FunctorBase & functor, const FaceArg & face, const StateArg * * @return VectorValue The interpolated vector value at the face. * - * This function performs the following steps: - * 1. Asserts that the face information is non-null. - * 2. Constructs a limiter based on the face limiter type. - * 3. Determines the upwind and downwind arguments based on the face element. - * 4. Evaluates the functor at the upwind and downwind locations. - * 5. Initializes the return vector value. - * 6. Computes the interpolation coefficients and advected values for each component. - * 7. If necessary, computes the gradient and min-max values for certain limiter types. - * * Usage: * This function is used for interpolating vector values at faces in a finite volume method, * ensuring that the interpolation adheres to the constraints imposed by the limiter. @@ -1063,7 +982,6 @@ interpolate(const FunctorBase> & functor, // Define a zero gradient vector for initialization static const VectorValue grad_zero(0); - // Assert that the face information is non-null mooseAssert(face.fi, "this must be non-null"); // Construct the limiter based on the face limiter type @@ -1145,8 +1063,6 @@ interpolate(const FunctorBase> & functor, } /** - * @brief Interpolates container values using a specified functor and face argument. - * * This function interpolates container values at faces in a computational grid using a specified * functor, face argument, and limiter type. It handles different limiter types and performs * interpolation accordingly. @@ -1162,15 +1078,6 @@ interpolate(const FunctorBase> & functor, * * @return T The interpolated container value at the face. * - * This function performs the following steps: - * 1. Asserts that the face information is non-null. - * 2. Constructs a limiter based on the face limiter type. - * 3. Determines the upwind and downwind arguments based on the face element. - * 4. Evaluates the functor at the upwind and downwind locations. - * 5. Initializes the return container value. - * 6. Computes the interpolation coefficients and advected values for each component. - * 7. If necessary, computes the gradient and min-max values for certain limiter types. - * * Usage: * This function is used for interpolating container values at faces in a finite volume method, * ensuring that the interpolation adheres to the constraints imposed by the limiter. From 7c47d77eb0da8b91dc3809bc5f753a0ea74cb9ea Mon Sep 17 00:00:00 2001 From: Peter German Date: Sun, 17 Nov 2024 09:34:49 -0700 Subject: [PATCH 15/20] Disable recover due to comparison on final timestep Refs #28891 --- .../limiters/dispersion-test/tests | 21 ++++++---- .../limiters/lid-driven-segregated/tests | 40 +++++++++++-------- .../finite_volume/limiters/lid-driven/tests | 10 ++--- 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests index 6c2b7f5dcb5e..47a669a4ce59 100644 --- a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests @@ -8,32 +8,32 @@ input = 'cartesian_advection.i' exodiff = bottom_left_sou.e cli_args = 'GlobalParams/advected_interp_method=sou Outputs/file_base=bottom_left_sou' - abs_zero = 1e-5 detail = 'second-order upwind' + recover = false # only using final for output in a transient [] [vanLeer] type = Exodiff input = 'cartesian_advection.i' exodiff = bottom_left_vanLeer.e cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=bottom_left_vanLeer' - abs_zero = 1e-5 detail = 'van Leer' + recover = false # only using final for output in a transient [] [min_mod] type = Exodiff input = 'cartesian_advection.i' exodiff = bottom_left_min_mod.e cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=bottom_left_min_mod' - abs_zero = 1e-5 detail = 'min-mod' + recover = false # only using final for output in a transient [] [quick] type = Exodiff input = 'cartesian_advection.i' exodiff = bottom_left_quick.e cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=bottom_left_quick' - abs_zero = 1e-5 detail = 'QUICK' + recover = false # only using final for output in a transient [] [venkatakrishnan] type = Exodiff @@ -42,6 +42,7 @@ cli_args = 'GlobalParams/advected_interp_method=venkatakrishnan Outputs/file_base=bottom_left_venkatakrishnan' abs_zero = 1e-5 detail = 'venkatakrishnan' + recover = false # only using final for output in a transient [] [] [top_right_limited_scalar_advection] @@ -51,32 +52,32 @@ input = 'cartesian_advection.i' exodiff = top_right_sou.e cli_args = "GlobalParams/advected_interp_method=sou Outputs/file_base=top_right_sou AuxVariables/vel_x/initial_condition=-1.0 AuxVariables/vel_y/initial_condition=-1.0 FVBCs/fv_inflow/boundary='right' FVBCs/fv_outflow/boundary='left top bottom'" - abs_zero = 1e-5 detail = 'second-order upwind' + recover = false # only using final for output in a transient [] [vanLeer] type = Exodiff input = 'cartesian_advection.i' exodiff = top_right_vanLeer.e cli_args = "GlobalParams/advected_interp_method=vanLeer Outputs/file_base=top_right_vanLeer AuxVariables/vel_x/initial_condition=-1.0 AuxVariables/vel_y/initial_condition=-1.0 FVBCs/fv_inflow/boundary='right' FVBCs/fv_outflow/boundary='left top bottom'" - abs_zero = 1e-5 detail = 'van Leer' + recover = false # only using final for output in a transient [] [min_mod] type = Exodiff input = 'cartesian_advection.i' exodiff = top_right_min_mod.e cli_args = "GlobalParams/advected_interp_method=min_mod Outputs/file_base=top_right_min_mod AuxVariables/vel_x/initial_condition=-1.0 AuxVariables/vel_y/initial_condition=-1.0 FVBCs/fv_inflow/boundary='right' FVBCs/fv_outflow/boundary='left top bottom'" - abs_zero = 1e-5 detail = 'min-mod' + recover = false # only using final for output in a transient [] [quick] type = Exodiff input = 'cartesian_advection.i' exodiff = top_right_quick.e cli_args = "GlobalParams/advected_interp_method=quick Outputs/file_base=top_right_quick AuxVariables/vel_x/initial_condition=-1.0 AuxVariables/vel_y/initial_condition=-1.0 FVBCs/fv_inflow/boundary='right' FVBCs/fv_outflow/boundary='left top bottom'" - abs_zero = 1e-5 detail = 'QUICK' + recover = false # only using final for output in a transient [] [venkatakrishnan] type = Exodiff @@ -85,6 +86,7 @@ cli_args = "GlobalParams/advected_interp_method=venkatakrishnan Outputs/file_base=top_right_venkatakrishnan AuxVariables/vel_x/initial_condition=-1.0 AuxVariables/vel_y/initial_condition=-1.0 FVBCs/fv_inflow/boundary='right' FVBCs/fv_outflow/boundary='left top bottom'" abs_zero = 1e-5 detail = 'venkatakrishnan' + recover = false # only using final for output in a transient [] [] [bottom_left_tri_mesh_limited_scalar_advection] @@ -96,6 +98,7 @@ cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=bottom_left_tri_mesh_vanLeer' abs_zero = 1e-5 detail = 'van Leer' + recover = false # only using final for output in a transient [] [min_mod] type = Exodiff @@ -104,6 +107,7 @@ cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=bottom_left_tri_mesh_min_mod' abs_zero = 1e-5 detail = 'min-mod' + recover = false # only using final for output in a transient [] [quick] type = Exodiff @@ -112,6 +116,7 @@ cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=bottom_left_tri_mesh_quick' abs_zero = 1e-5 detail = 'QUICK' + recover = false # only using final for output in a transient [] [] [] diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests index 9fff4b87af06..ecc297a13ab9 100644 --- a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/tests @@ -1,83 +1,89 @@ [Tests] design = 'INSFVMomentumAdvection.md' issues = '#28891' - [segregated_advection_limiting_schemes] + [advection_limiting_schemes] requirement = 'The system shall be able to perform a variety of limiting schemes when solving fluid flow equations in the segreagated solver. These schemes include' [upwind] type = 'Exodiff' input = 'lid-driven-segregated.i' exodiff = 'upwind.e' detail = 'and reach converged results with upwind advection scheme.' - rel_err = 1e-3 cli_args = 'GlobalParams/advected_interp_method=upwind Outputs/file_base=upwind' - prereq = segregated_advection_limiting_schemes/upwind_run heavy = true + recover = false # we don't support recovery for SIMPLE yet + max_threads = 1 # see libmesh issue #3808 [] [upwind_run] type = 'Exodiff' input = 'lid-driven-segregated.i' exodiff = 'upwind_run.e' detail = 'and pass debugging checks with segregated solvers with upwind advection scheme.' - abs_zero = 1e-4 - rel_err = 1e-4 cli_args = 'GlobalParams/advected_interp_method=upwind Executioner/num_iterations=10 Outputs/file_base=upwind_run' + recover = false # we don't support recovery for SIMPLE yet + max_threads = 1 # see libmesh issue #3808 [] [vanLeer] type = 'Exodiff' input = 'lid-driven-segregated.i' exodiff = 'vanLeer.e' detail = 'and reach converged results with van Leer limiter.' - abs_zero = 1e-4 cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=vanLeer Outputs/file_base=vanLeer Mesh/gen/nx=10 Mesh/gen/ny=10' - prereq = segregated_advection_limiting_schemes/vanLeer_run heavy = true + recover = false # we don't support recovery for SIMPLE yet + max_threads = 1 # see libmesh issue #3808 [] [vanLeer_run] type = 'Exodiff' input = 'lid-driven-segregated.i' exodiff = 'vanLeer_run.e' detail = 'and pass debugging checks with segregated solvers with van Leer limiter.' - abs_zero = 1e-4 - rel_err = 1e-4 cli_args = 'GlobalParams/advected_interp_method=vanLeer Executioner/num_iterations=10 Outputs/file_base=vanLeer_run Mesh/gen/nx=10 Mesh/gen/ny=10' + recover = false # we don't support recovery for SIMPLE yet + max_threads = 1 # see libmesh issue #3808 [] [min_mod] type = 'Exodiff' input = 'lid-driven-segregated.i' exodiff = 'min_mod.e' detail = 'and reach converged results with min-mod limiter.' - rel_err = 1e-3 cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=min_mod' - prereq = segregated_advection_limiting_schemes/min_mod_run heavy = true + recover = false # we don't support recovery for SIMPLE yet + max_threads = 1 # see libmesh issue #3808 [] [min_mod_run] type = 'Exodiff' input = 'lid-driven-segregated.i' exodiff = 'min_mod_run.e' detail = 'and pass debugging checks with segregated solvers with min-mod limiter.' - abs_zero = 1e-4 - rel_err = 1e-4 + abs_zero = 1e-5 # limiter sensitive to roundoff + rel_err = 1e-4 # limiter sensitive to roundoff cli_args = 'GlobalParams/advected_interp_method=min_mod Executioner/num_iterations=10 Outputs/file_base=min_mod_run' + recover = false # we don't support recovery for SIMPLE yet + max_threads = 1 # see libmesh issue #3808 + max_parallel = 4 # limiter sensitive to roundoff [] [quick] type = 'Exodiff' input = 'lid-driven-segregated.i' exodiff = 'quick.e' detail = 'and reach converged results with QUICK limiter.' - rel_err = 1e-3 cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=quick' - prereq = segregated_advection_limiting_schemes/quick_run heavy = true + recover = false # we don't support recovery for SIMPLE yet + max_threads = 1 # see libmesh issue #3808 [] [quick_run] type = 'Exodiff' input = 'lid-driven-segregated.i' exodiff = 'quick_run.e' detail = 'and pass debugging checks with segregated solvers with QUICK limiter.' - abs_zero = 1e-4 - rel_err = 1e-4 + abs_zero = 1e-5 # limiter sensitive to roundoff + rel_err = 1e-4 # limiter sensitive to roundoff cli_args = 'GlobalParams/advected_interp_method=quick Executioner/num_iterations=10 Outputs/file_base=quick_run' + recover = false # we don't support recovery for SIMPLE yet + max_threads = 1 # see libmesh issue #3808 + max_parallel = 4 # limiter sensitive to roundoff [] [] [] diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/tests b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/tests index 32978ecc3959..f814763a1f6a 100644 --- a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/tests +++ b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven/tests @@ -8,40 +8,40 @@ input = 'test.i' exodiff = upwind.e cli_args = 'GlobalParams/advected_interp_method=upwind Outputs/file_base=upwind' - rel_err = 1e-4 detail = 'first-order upwind' + recover = false # only using final for output in a transient [] [sou] type = Exodiff input = 'test.i' exodiff = sou.e cli_args = 'GlobalParams/advected_interp_method=sou Outputs/file_base=sou' - rel_err = 1e-4 detail = 'second-order upwind' + recover = false # only using final for output in a transient [] [vanLeer] type = Exodiff input = 'test.i' exodiff = vanLeer.e cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=vanLeer' - rel_err = 1e-4 detail = 'van Leer' + recover = false # only using final for output in a transient [] [min_mod] type = Exodiff input = 'test.i' exodiff = min_mod.e cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=min_mod' - rel_err = 1e-4 detail = 'min-mod' + recover = false # only using final for output in a transient [] [quick] type = Exodiff input = 'test.i' exodiff = quick.e cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=quick' - rel_err = 1e-4 detail = 'QUICK' + recover = false # only using final for output in a transient [] [] [] From 8acd64470e2d5ed69c4d0abd16ae7aab8bb2eaad Mon Sep 17 00:00:00 2001 From: Peter German Date: Mon, 18 Nov 2024 17:32:26 -0700 Subject: [PATCH 16/20] Transition towards less limiting of SOU and move tests to framework Refs #28891 --- framework/include/limiters/SOULimiter.h | 28 +---- .../src/fvbcs/FVConstantScalarOutflowBC.C | 5 +- framework/src/fvkernels/FVAdvection.C | 9 +- .../dispersion-test/cartesian_advection.i | 102 --------------- .../dispersion-test/tri_mesh_advection.i | 117 ------------------ .../dispersion-test/cartesian_advection.i | 76 ++++++++++++ .../tests/fvkernels}/dispersion-test/tests | 40 +----- 7 files changed, 93 insertions(+), 284 deletions(-) delete mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/cartesian_advection.i delete mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tri_mesh_advection.i create mode 100644 test/tests/fvkernels/dispersion-test/cartesian_advection.i rename {modules/navier_stokes/test/tests/finite_volume/limiters => test/tests/fvkernels}/dispersion-test/tests (61%) diff --git a/framework/include/limiters/SOULimiter.h b/framework/include/limiters/SOULimiter.h index 020e18c6ae70..1ebf2ef23107 100644 --- a/framework/include/limiters/SOULimiter.h +++ b/framework/include/limiters/SOULimiter.h @@ -58,33 +58,7 @@ class SOULimiter : public Limiter const bool & fi_elem_is_upwind) const override final { mooseAssert(grad_phi_upwind, "SOU limiter requires a gradient"); - - T limiter; - if (!grad_phi_downwind) - { - // Determine the face centroid and the appropriate cell centroid - const auto & face_centroid = fi->faceCentroid(); - const auto & cell_centroid = fi_elem_is_upwind ? fi->elemCentroid() : fi->neighborCentroid(); - - // Compute the abs delta value at the face - const auto & delta_face = - std::abs((*grad_phi_upwind) * (face_centroid - cell_centroid)) + 1e-10; - - // Compute the delta between the two elements - const auto & elem_delta = max_value - min_value; - - // Return the limited value - if (elem_delta > 1e-10) - limiter = std::min(1.0, elem_delta / delta_face); - else - limiter = T(1.0); - } - else - { - const auto & r_f = Moose::FV::rF(phi_upwind, phi_downwind, *grad_phi_upwind, dCD); - limiter = r_f; - } - return limiter; + return T(1.0); } bool constant() const override final { return false; } diff --git a/framework/src/fvbcs/FVConstantScalarOutflowBC.C b/framework/src/fvbcs/FVConstantScalarOutflowBC.C index 07b2c66344cd..da240085b891 100644 --- a/framework/src/fvbcs/FVConstantScalarOutflowBC.C +++ b/framework/src/fvbcs/FVConstantScalarOutflowBC.C @@ -33,7 +33,10 @@ FVConstantScalarOutflowBC::computeQpResidual() "This boundary condition is for outflow but the flow is in the opposite direction of " "the boundary normal"); + const auto boundary_face = singleSidedFaceArg(); + const auto state = determineState(); + // This will either be second or first order accurate depending on whether the user has asked // for a two term expansion in their input file - return _normal * _velocity * _var.getBoundaryFaceValue(*_face_info, determineState()); + return _normal * _velocity * _var(boundary_face, state); } diff --git a/framework/src/fvkernels/FVAdvection.C b/framework/src/fvkernels/FVAdvection.C index a731a791c274..f17206d2e987 100644 --- a/framework/src/fvkernels/FVAdvection.C +++ b/framework/src/fvkernels/FVAdvection.C @@ -42,10 +42,15 @@ FVAdvection::FVAdvection(const InputParameters & params) ADReal FVAdvection::computeQpResidual() { + const auto state = determineState(); + const auto & limiter_time = _subproblem.isTransient() + ? Moose::StateArg(1, Moose::SolutionIterationType::Time) + : Moose::StateArg(1, Moose::SolutionIterationType::Nonlinear); + const bool elem_is_upwind = _velocity * _normal >= 0; const auto face = - makeFace(*_face_info, Moose::FV::limiterType(_advected_interp_method), elem_is_upwind); - ADReal u_interface = _var(face, determineState()); + makeFace(*_face_info, Moose::FV::limiterType(_advected_interp_method), elem_is_upwind, false, &limiter_time); + ADReal u_interface = _var(face, state); return _normal * _velocity * u_interface; } diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/cartesian_advection.i b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/cartesian_advection.i deleted file mode 100644 index 7a684b457220..000000000000 --- a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/cartesian_advection.i +++ /dev/null @@ -1,102 +0,0 @@ -[GlobalParams] - advected_interp_method = 'min_mod' #average upwind sou min_mod vanLeer quick venkatakrishnan skewness-corrected - velocity_interp_method = 'average' -[] - -[UserObjects] - [rc] - type = INSFVRhieChowInterpolator - u = vel_x - v = vel_y - a_u = vel_x - a_v = vel_y - pressure = pressure - velocity_interp_method = 'rc' - [] -[] - -[Mesh] - [gen] - type = GeneratedMeshGenerator - dim = 2 - xmin = 0 - xmax = 1 - ymin = 0 - ymax = 1 - nx = 10 - ny = 10 - [] -[] - -[AuxVariables] - [vel_x] - type = INSFVVelocityVariable - initial_condition = 1.0 - [] - [vel_y] - type = INSFVVelocityVariable - initial_condition = 1.0 - [] - [pressure] - type = INSFVPressureVariable - initial_condition = 1.0 - [] -[] - -[Variables] - [scalar] - type = INSFVScalarFieldVariable - two_term_boundary_expansion = false - [] -[] - -[FVKernels] - [scalar_advection] - type = INSFVScalarFieldAdvection - variable = scalar - rhie_chow_user_object = 'rc' - [] -[] - -[FVBCs] - [fv_inflow] - type = NSFVOutflowTemperatureBC - u = vel_x - v = vel_y - backflow_T = 1.0 - rho = 1.0 - cp = 1.0 - variable = scalar - boundary = 'left' - [] - [fv_outflow] - type = NSFVOutflowTemperatureBC - u = vel_x - v = vel_y - backflow_T = 0.0 - rho = 1.0 - cp = 1.0 - variable = scalar - boundary = 'right top bottom' - [] -[] - -[Executioner] - type = Transient - solve_type = 'NEWTON' - petsc_options_iname = '-pc_type -pc_factor_shift_type' - petsc_options_value = 'lu NONZERO' - dt = 0.1 - end_time = 5.0 - steady_state_detection = true - steady_state_tolerance = 1e-12 - nl_abs_tol = 1e-12 -[] - -[Outputs] - [out] - type = Exodus - execute_on = 'final' - hide = 'vel_x vel_y pressure' - [] -[] diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tri_mesh_advection.i b/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tri_mesh_advection.i deleted file mode 100644 index 7f0e533a9faa..000000000000 --- a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tri_mesh_advection.i +++ /dev/null @@ -1,117 +0,0 @@ -[GlobalParams] - advected_interp_method = 'min_mod' #average upwind sou min_mod vanLeer quick venkatakrishnan skewness-corrected - velocity_interp_method = 'average' -[] - -[UserObjects] - [rc] - type = INSFVRhieChowInterpolator - u = vel_x - v = vel_y - a_u = vel_x - a_v = vel_y - pressure = pressure - velocity_interp_method = 'rc' - [] -[] - -[Mesh] - [outer_bdy] - type = PolyLineMeshGenerator - points = '0.0 0.0 0.0 - 0.0 1.0 0.0 - 1.0 1.0 0.0 - 1.0 0.0 0.0' - loop = true - [] - [triang] - type = XYDelaunayGenerator - boundary = 'outer_bdy' - add_nodes_per_boundary_segment = 3 - refine_boundary = true - desired_area = 0.02 - [] - [sidesets] - type = SideSetsFromNormalsGenerator - input = triang - normals = '-1 0 0 - 1 0 0 - 0 -1 0 - 0 1 0' - fixed_normal = true - new_boundary = 'left right bottom top' - [] -[] - -[AuxVariables] - [vel_x] - type = INSFVVelocityVariable - initial_condition = 1.0 - [] - [vel_y] - type = INSFVVelocityVariable - initial_condition = 1.0 - [] - [pressure] - type = INSFVPressureVariable - initial_condition = 1.0 - [] -[] - -[Variables] - [scalar] - type = INSFVScalarFieldVariable - two_term_boundary_expansion = false - [] -[] - -[FVKernels] - [scalar_advection] - type = INSFVScalarFieldAdvection - variable = scalar - rhie_chow_user_object = 'rc' - [] -[] - -[FVBCs] - [fv_inflow] - type = NSFVOutflowTemperatureBC - u = vel_x - v = vel_y - backflow_T = 1.0 - rho = 1.0 - cp = 1.0 - variable = scalar - boundary = 'left' - [] - [fv_outflow] - type = NSFVOutflowTemperatureBC - u = vel_x - v = vel_y - backflow_T = 0.0 - rho = 1.0 - cp = 1.0 - variable = scalar - boundary = 'right top bottom' - [] -[] - -[Executioner] - type = Transient - solve_type = 'NEWTON' - petsc_options_iname = '-pc_type -pc_factor_shift_type' - petsc_options_value = 'lu NONZERO' - dt = 0.1 - end_time = 5.0 - steady_state_detection = true - steady_state_tolerance = 1e-12 - nl_abs_tol = 1e-12 -[] - -[Outputs] - [out] - type = Exodus - execute_on = 'final' - hide = 'vel_x vel_y pressure' - [] -[] diff --git a/test/tests/fvkernels/dispersion-test/cartesian_advection.i b/test/tests/fvkernels/dispersion-test/cartesian_advection.i new file mode 100644 index 000000000000..24382b94e1bd --- /dev/null +++ b/test/tests/fvkernels/dispersion-test/cartesian_advection.i @@ -0,0 +1,76 @@ +[GlobalParams] + advected_interp_method = 'min_mod' #average upwind sou min_mod vanLeer quick venkatakrishnan skewness-corrected +[] + +[Mesh] + [gen] + type = GeneratedMeshGenerator + dim = 2 + xmin = 0 + xmax = 1 + ymin = 0 + ymax = 1 + nx = 11 + ny = 11 + [] +[] + +[Variables] + [scalar] + type = MooseVariableFVReal + two_term_boundary_expansion = false + [] +[] + +[FVKernels] + [time_derivative] + type = FVTimeKernel + variable = scalar + [] + [scalar_advection] + type = FVAdvection + variable = scalar + velocity = '1 1 0' + [] +[] + +[FVBCs] + [inflow_1] + type = FVDirichletBC + boundary = 'left' + value = '1' + variable = scalar + [] + [inflow_0] + type = FVDirichletBC + boundary = 'bottom' + value = '0' + variable = scalar + [] + [outflow] + type = FVConstantScalarOutflowBC + variable = scalar + velocity = '1 1 0' + boundary = 'right top' + [] +[] + +[Executioner] + type = Transient + solve_type = 'NEWTON' + petsc_options_iname = '-pc_type -pc_factor_shift_type' + petsc_options_value = 'lu NONZERO' + dt = 0.1 + end_time = 10.0 + steady_state_detection = true + steady_state_tolerance = 1e-12 + nl_abs_tol = 1e-12 + line_search = none +[] + +[Outputs] + [out] + type = Exodus + execute_on = 'final' + [] +[] diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests b/test/tests/fvkernels/dispersion-test/tests similarity index 61% rename from modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests rename to test/tests/fvkernels/dispersion-test/tests index 47a669a4ce59..6a94bc822eb2 100644 --- a/modules/navier_stokes/test/tests/finite_volume/limiters/dispersion-test/tests +++ b/test/tests/fvkernels/dispersion-test/tests @@ -51,7 +51,7 @@ type = Exodiff input = 'cartesian_advection.i' exodiff = top_right_sou.e - cli_args = "GlobalParams/advected_interp_method=sou Outputs/file_base=top_right_sou AuxVariables/vel_x/initial_condition=-1.0 AuxVariables/vel_y/initial_condition=-1.0 FVBCs/fv_inflow/boundary='right' FVBCs/fv_outflow/boundary='left top bottom'" + cli_args = "GlobalParams/advected_interp_method=sou Outputs/file_base=top_right_sou FVKernels/scalar_advection/velocity='-1 -1 0' FVBCs/inflow_1/boundary='top' FVBCs/inflow_0/boundary='right' FVBCs/outflow/boundary='left bottom' FVBCs/outflow/velocity='-1 -1 0'" detail = 'second-order upwind' recover = false # only using final for output in a transient [] @@ -59,7 +59,7 @@ type = Exodiff input = 'cartesian_advection.i' exodiff = top_right_vanLeer.e - cli_args = "GlobalParams/advected_interp_method=vanLeer Outputs/file_base=top_right_vanLeer AuxVariables/vel_x/initial_condition=-1.0 AuxVariables/vel_y/initial_condition=-1.0 FVBCs/fv_inflow/boundary='right' FVBCs/fv_outflow/boundary='left top bottom'" + cli_args = "GlobalParams/advected_interp_method=vanLeer Outputs/file_base=top_right_vanLeer FVKernels/scalar_advection/velocity='-1 -1 0' FVBCs/inflow_1/boundary='top' FVBCs/inflow_0/boundary='right' FVBCs/outflow/boundary='left bottom' FVBCs/outflow/velocity='-1 -1 0'" detail = 'van Leer' recover = false # only using final for output in a transient [] @@ -67,7 +67,7 @@ type = Exodiff input = 'cartesian_advection.i' exodiff = top_right_min_mod.e - cli_args = "GlobalParams/advected_interp_method=min_mod Outputs/file_base=top_right_min_mod AuxVariables/vel_x/initial_condition=-1.0 AuxVariables/vel_y/initial_condition=-1.0 FVBCs/fv_inflow/boundary='right' FVBCs/fv_outflow/boundary='left top bottom'" + cli_args = "GlobalParams/advected_interp_method=min_mod Outputs/file_base=top_right_min_mod FVKernels/scalar_advection/velocity='-1 -1 0' FVBCs/inflow_1/boundary='top' FVBCs/inflow_0/boundary='right' FVBCs/outflow/boundary='left bottom' FVBCs/outflow/velocity='-1 -1 0'" detail = 'min-mod' recover = false # only using final for output in a transient [] @@ -75,7 +75,7 @@ type = Exodiff input = 'cartesian_advection.i' exodiff = top_right_quick.e - cli_args = "GlobalParams/advected_interp_method=quick Outputs/file_base=top_right_quick AuxVariables/vel_x/initial_condition=-1.0 AuxVariables/vel_y/initial_condition=-1.0 FVBCs/fv_inflow/boundary='right' FVBCs/fv_outflow/boundary='left top bottom'" + cli_args = "GlobalParams/advected_interp_method=quick Outputs/file_base=top_right_quick FVKernels/scalar_advection/velocity='-1 -1 0' FVBCs/inflow_1/boundary='top' FVBCs/inflow_0/boundary='right' FVBCs/outflow/boundary='left bottom' FVBCs/outflow/velocity='-1 -1 0'" detail = 'QUICK' recover = false # only using final for output in a transient [] @@ -83,40 +83,10 @@ type = Exodiff input = 'cartesian_advection.i' exodiff = top_right_venkatakrishnan.e - cli_args = "GlobalParams/advected_interp_method=venkatakrishnan Outputs/file_base=top_right_venkatakrishnan AuxVariables/vel_x/initial_condition=-1.0 AuxVariables/vel_y/initial_condition=-1.0 FVBCs/fv_inflow/boundary='right' FVBCs/fv_outflow/boundary='left top bottom'" + cli_args = "GlobalParams/advected_interp_method=venkatakrishnan Outputs/file_base=top_right_venkatakrishnan FVKernels/scalar_advection/velocity='-1 -1 0' FVBCs/inflow_1/boundary='top' FVBCs/inflow_0/boundary='right' FVBCs/outflow/boundary='left bottom' FVBCs/outflow/velocity='-1 -1 0'" abs_zero = 1e-5 detail = 'venkatakrishnan' recover = false # only using final for output in a transient [] [] - [bottom_left_tri_mesh_limited_scalar_advection] - requirement = 'The system shall be able to perform a variety of limiting schemes when solving scalar transport equations in triangular meshes with bottom-left advection. These schemes include' - [vanLeer] - type = Exodiff - input = 'tri_mesh_advection.i' - exodiff = bottom_left_tri_mesh_vanLeer.e - cli_args = 'GlobalParams/advected_interp_method=vanLeer Outputs/file_base=bottom_left_tri_mesh_vanLeer' - abs_zero = 1e-5 - detail = 'van Leer' - recover = false # only using final for output in a transient - [] - [min_mod] - type = Exodiff - input = 'tri_mesh_advection.i' - exodiff = bottom_left_tri_mesh_min_mod.e - cli_args = 'GlobalParams/advected_interp_method=min_mod Outputs/file_base=bottom_left_tri_mesh_min_mod' - abs_zero = 1e-5 - detail = 'min-mod' - recover = false # only using final for output in a transient - [] - [quick] - type = Exodiff - input = 'tri_mesh_advection.i' - exodiff = bottom_left_tri_mesh_quick.e - cli_args = 'GlobalParams/advected_interp_method=quick Outputs/file_base=bottom_left_tri_mesh_quick' - abs_zero = 1e-5 - detail = 'QUICK' - recover = false # only using final for output in a transient - [] - [] [] From af9d399f58d8358a2243166d918bff16c199d4f1 Mon Sep 17 00:00:00 2001 From: Peter German Date: Mon, 18 Nov 2024 18:34:51 -0700 Subject: [PATCH 17/20] Add error messages for steady state executioners when using second order limiting schemes Refs #28891 --- .../doc/content/syntax/Limiters/index.md | 10 ++++------ framework/include/limiters/SOULimiter.h | 19 +++++++++++++------ .../include/limiters/VenkatakrishnanLimiter.h | 2 +- framework/src/fvkernels/FVAdvection.C | 18 ++++++++++++++++-- framework/src/utils/MathFVUtils.C | 3 ++- .../src/fvkernels/INSFVAdvectionKernel.C | 10 ++++++++++ 6 files changed, 46 insertions(+), 16 deletions(-) diff --git a/framework/doc/content/syntax/Limiters/index.md b/framework/doc/content/syntax/Limiters/index.md index 1a674bfc111c..3e631e869d04 100644 --- a/framework/doc/content/syntax/Limiters/index.md +++ b/framework/doc/content/syntax/Limiters/index.md @@ -152,12 +152,15 @@ Each of the limiters implemented along with the implementation reference, limiti | `SOU` [!citep](harten1997) | Face-Value | No | $\text{min}(1,1/r)$ | | `Venkatakrishnan` [!citep](venkatakrishnan1993) | Face-Value | No | $\frac{2r+1}{r(2r+1)+1}$ | - To illustrate the performance of the limiters, a dispersion analysis is developedand presented in [dispersion]. This consists of the advection of a passive scalar in a Cartesian mesh at 45 degrees. The exact solution, without numerical diffusion, is a straight line at 45 degrees dividing the regions with a scalar concentration of 1 and 0. +!alert note +In general, we recomment using `VanLeer` and `MinMod` limiters for most of the +applications considering that they provide truly bounded solutions. + !media framework/finite_volume/dispersion.png style=display: block;margin-left:auto;margin-right:auto;width:40%; id=dispersion @@ -172,9 +175,4 @@ can be expected for each of the limiters. id=dispersion_line caption=Performance of each of the limiters in a line perpendicular to the advection front. -!alert warning -When using limiters with `Executioner` of `type = Steady`, -the solver uses the previous nonlinear iterate for the limiting flux. -This can ultimately lead to bad condition numbers in the Jacobian and poor convergence. - !bibtex bibliography diff --git a/framework/include/limiters/SOULimiter.h b/framework/include/limiters/SOULimiter.h index 1ebf2ef23107..9192dd354b08 100644 --- a/framework/include/limiters/SOULimiter.h +++ b/framework/include/limiters/SOULimiter.h @@ -47,18 +47,25 @@ class SOULimiter : public Limiter * @param fi_elem_is_upwind Boolean flag indicating if the current element is upwind. * @return The computed flux limiting ratio. */ - T limit(const T & phi_upwind, - const T & phi_downwind, + T limit(const T & /* phi_upwind */, + const T & /* phi_downwind */, const VectorValue * grad_phi_upwind, - const VectorValue * grad_phi_downwind, + const VectorValue * /* grad_phi_downwind */, const RealVectorValue & dCD, const Real & max_value, const Real & min_value, - const FaceInfo * fi, - const bool & fi_elem_is_upwind) const override final + const FaceInfo * /* fi */, + const bool & /*fi_elem_is_upwind */) const override final { mooseAssert(grad_phi_upwind, "SOU limiter requires a gradient"); - return T(1.0); + + T delta_face = std::abs((*grad_phi_upwind) * dCD); + T delta_max = std::abs(max_value - min_value); + + if (delta_face > 1e-10) + return std::min(1.0, delta_max / delta_face); + else + return T(1.0); } bool constant() const override final { return false; } diff --git a/framework/include/limiters/VenkatakrishnanLimiter.h b/framework/include/limiters/VenkatakrishnanLimiter.h index ae9da92c3100..7688bd8ae85c 100644 --- a/framework/include/limiters/VenkatakrishnanLimiter.h +++ b/framework/include/limiters/VenkatakrishnanLimiter.h @@ -85,7 +85,7 @@ class VenkatakrishnanLimiter : public Limiter bool constant() const override final { return false; } - InterpMethod interpMethod() const override final { return InterpMethod::SOU; } + InterpMethod interpMethod() const override final { return InterpMethod::Venkatakrishnan; } VenkatakrishnanLimiter() = default; }; diff --git a/framework/src/fvkernels/FVAdvection.C b/framework/src/fvkernels/FVAdvection.C index f17206d2e987..a2bfc4653ec9 100644 --- a/framework/src/fvkernels/FVAdvection.C +++ b/framework/src/fvkernels/FVAdvection.C @@ -8,6 +8,7 @@ //* https://www.gnu.org/licenses/lgpl-2.1.html #include "FVAdvection.h" +#include "Steady.h" registerADMooseObject("MooseApp", FVAdvection); @@ -37,6 +38,16 @@ FVAdvection::FVAdvection(const InputParameters & params) getCheckedPointerParam("_fe_problem_base") ->setErrorOnJacobianNonzeroReallocation(false); } + + if (dynamic_cast(_app.getExecutioner())) + { + const MooseEnum not_available_with_steady("sou min_mod vanLeer quick venkatakrishnan"); + const std::string chosen_scheme = + static_cast(getParam("advected_interp_method")); + if (not_available_with_steady.find(chosen_scheme) != not_available_with_steady.items().end()) + paramError("advected_interp_method", + "The given advected interpolation cannot be used with steady-state runs!"); + } } ADReal @@ -48,8 +59,11 @@ FVAdvection::computeQpResidual() : Moose::StateArg(1, Moose::SolutionIterationType::Nonlinear); const bool elem_is_upwind = _velocity * _normal >= 0; - const auto face = - makeFace(*_face_info, Moose::FV::limiterType(_advected_interp_method), elem_is_upwind, false, &limiter_time); + const auto face = makeFace(*_face_info, + Moose::FV::limiterType(_advected_interp_method), + elem_is_upwind, + false, + &limiter_time); ADReal u_interface = _var(face, state); return _normal * _velocity * u_interface; diff --git a/framework/src/utils/MathFVUtils.C b/framework/src/utils/MathFVUtils.C index 759cdc11d83e..ba6becde8585 100644 --- a/framework/src/utils/MathFVUtils.C +++ b/framework/src/utils/MathFVUtils.C @@ -117,7 +117,8 @@ setInterpolationMethod(const MooseObject & obj, interp_method = selectInterpolationMethod(interp_method_in); if (interp_method == InterpMethod::SOU || interp_method == InterpMethod::MinMod || - interp_method == InterpMethod::VanLeer || interp_method == InterpMethod::QUICK) + interp_method == InterpMethod::VanLeer || interp_method == InterpMethod::QUICK || + interp_method == InterpMethod::Venkatakrishnan) need_more_ghosting = true; return need_more_ghosting; diff --git a/modules/navier_stokes/src/fvkernels/INSFVAdvectionKernel.C b/modules/navier_stokes/src/fvkernels/INSFVAdvectionKernel.C index 816bb62e7dd0..eafcf92ed866 100644 --- a/modules/navier_stokes/src/fvkernels/INSFVAdvectionKernel.C +++ b/modules/navier_stokes/src/fvkernels/INSFVAdvectionKernel.C @@ -68,6 +68,16 @@ INSFVAdvectionKernel::INSFVAdvectionKernel(const InputParameters & params) "setting `two_term_boundary_expansion = false` in the advected variable parameters or " "changing your " "'advected_interp_method' of the kernel to first order methods (`upwind`, `average`)"); + + if (dynamic_cast(_app.getExecutioner())) + { + const MooseEnum not_available_with_steady("sou min_mod vanLeer quick venkatakrishnan"); + const std::string chosen_scheme = + static_cast(getParam("advected_interp_method")); + if (not_available_with_steady.find(chosen_scheme) != not_available_with_steady.items().end()) + paramError("advected_interp_method", + "The given advected interpolation cannot be used with steady-state runs!"); + } } void From e5a7a04756b48697a510a8e9f5af38d3ea514b64 Mon Sep 17 00:00:00 2001 From: tanome Date: Fri, 22 Nov 2024 16:33:53 -0700 Subject: [PATCH 18/20] regolding dispersion tests Refs #28891 --- .../src/fvkernels/INSFVAdvectionKernel.C | 1 + .../dispersion-test/gold/bottom_left_min_mod.e | Bin 0 -> 58872 bytes .../dispersion-test/gold/bottom_left_quick.e | Bin 0 -> 58868 bytes .../dispersion-test/gold/bottom_left_sou.e | Bin 0 -> 58868 bytes .../dispersion-test/gold/bottom_left_vanLeer.e | Bin 0 -> 58872 bytes .../gold/bottom_left_venkatakrishnan.e | Bin 0 -> 58960 bytes .../dispersion-test/gold/top_right_min_mod.e | Bin 0 -> 59112 bytes .../dispersion-test/gold/top_right_quick.e | Bin 0 -> 59028 bytes .../dispersion-test/gold/top_right_sou.e | Bin 0 -> 59024 bytes .../dispersion-test/gold/top_right_vanLeer.e | Bin 0 -> 59112 bytes .../gold/top_right_venkatakrishnan.e | Bin 0 -> 59120 bytes .../mms/advective-outflow/advection-outflow.i | 5 ++++- 12 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 test/tests/fvkernels/dispersion-test/gold/bottom_left_min_mod.e create mode 100644 test/tests/fvkernels/dispersion-test/gold/bottom_left_quick.e create mode 100644 test/tests/fvkernels/dispersion-test/gold/bottom_left_sou.e create mode 100644 test/tests/fvkernels/dispersion-test/gold/bottom_left_vanLeer.e create mode 100644 test/tests/fvkernels/dispersion-test/gold/bottom_left_venkatakrishnan.e create mode 100644 test/tests/fvkernels/dispersion-test/gold/top_right_min_mod.e create mode 100644 test/tests/fvkernels/dispersion-test/gold/top_right_quick.e create mode 100644 test/tests/fvkernels/dispersion-test/gold/top_right_sou.e create mode 100644 test/tests/fvkernels/dispersion-test/gold/top_right_vanLeer.e create mode 100644 test/tests/fvkernels/dispersion-test/gold/top_right_venkatakrishnan.e diff --git a/modules/navier_stokes/src/fvkernels/INSFVAdvectionKernel.C b/modules/navier_stokes/src/fvkernels/INSFVAdvectionKernel.C index eafcf92ed866..a1cfc3f7f1b8 100644 --- a/modules/navier_stokes/src/fvkernels/INSFVAdvectionKernel.C +++ b/modules/navier_stokes/src/fvkernels/INSFVAdvectionKernel.C @@ -14,6 +14,7 @@ #include "NSFVUtils.h" #include "FVBoundaryScalarLagrangeMultiplierConstraint.h" #include "Limiter.h" +#include "Steady.h" InputParameters INSFVAdvectionKernel::validParams() diff --git a/test/tests/fvkernels/dispersion-test/gold/bottom_left_min_mod.e b/test/tests/fvkernels/dispersion-test/gold/bottom_left_min_mod.e new file mode 100644 index 0000000000000000000000000000000000000000..029c5197e5f6526f9560dd8ffd2c8a7317ebbfcf GIT binary patch literal 58872 zcmeHw3z!t;nQr41P(U%pD{BcVC=4*eMIesF00R?R%U-fracUSlH zU(;@Mp`PcR`udydx4-}X|KES9x%1{95ekI{0Yib4fx$5|5l$F!(@}?pWUROuPG`&{ z{^?%FCbIEx)Qa;XzdwYZ6L!>0I}dEdZ7_9a%;ZDsfuYXlaC>a6c!<9_Onxt%HZ$&b zkCOVd6~*rs=!d%;R)RG3f`{BAT%K^!OyM`hKge@D^$t&(%HxW34L-UlKDw!{?l}27 z2|*V+p8C9wbj3Q-73)YRbizKyQMlVkLB}`|@n$7DY((wF{LJ)-SqY>^Xeq$oJQg_4 zNLt};GnKaN1U`n21_m_^dh~YOk1eA=wIgO587t8lPTE!?6YjB7QN+&%ax=cf@8dqC z!-^s9oqu@#$N!%cH+ro&(;Imt4C6X8T~Oz~uR%T@}@ZGBN%j zF6Nz2x7(SF9S2iKCLBk~#_i}t_y0^U4Hzo&U{9Crevx(%@;U~>VCTb2<8U8hw&#Bw zpZP4~M_#mtz%_)%561J!l$~TAk5|{0P4eQi zCpaI5uow--^WNX%v;F;^{Qf39J0xBDd(0E^^8TJEi+JAqdwjOq-`kF7kBQjGDZPT8 zadM=PoIkMrs7;PIA;gj)y#yg{zd4zdErjfL5Xn4LAi>)+bStmot zx(bi-d78p&B!8E2>gAI0UnQ5DoS~Bh7vjsyCF53+>lAVgW!&Z1oNzK6ysG4rkDo!l z<5|y!S?R=$Bt93X2Lf`$Z0K=~5@CthiG&%+FmIEHgr0*(jLjnN|(>Fu8^0PcQ=%hx4&oi^I6wkR@~%eJju($d%>rml)U{tJDbnC zyo^@z4g=)n<&8lpdHZ|z%Y4?!54rdqE=h4G?_}rm1wY1JJ}cv4g!4b~*Zb@rJkQFo zo#6lM_;WnZN_$T%^K2XR!&tCH$G~m$pktmJ>3&D%%PPzM_#5!O6T6LAI>%XWwllNi zA}`~bd0t+q7mnQHe0Yg*mg|mL=lgSA6ygoduZP}>~PAApjMQ1 z*GbTSich!~cy?`fVN9$ z<(*GKrOW%T-2cn_zw^JVPtoQ5MfZ7me_4EewJz_ky5E=g*C*a`&;I{8NtgFGTt0dK zonx6U?+-cOFR{1SzG8cdf4}(m4)cqM*NfAoI2{hhKXcmrlKgr&|5TNKWVw}hS^vm; zvHs)sxukxS^<=H?vL5@W?!PLkzia(j*1I3oUA8M9)m^p|AJtvfuOHQ2wrd~NUA6}w z)m_%3AJJXbCx`0Y@s%8^p$~;pR%ch{&<%blV*Bfla`5!1cfv zfE$3#z>UC7z|FuG;ETX5z?Xnqf!l!FfvvzG;0WMI;3!u<8uw#d9pz(z!LE+-5MZdQ zqkJ52ysM);3>fa}D31V6aCMYro}-Sk%zH8)$~^cf{ExECi_Dj_k+#ZwNtw1Xe^N)8 zwlc3$N13)V-%>}JwlWV>N13)VKT}7Uc4+{0lxf%5fac1yYcxO|W!g0cppG)j%{c&d zEIYL8T;M!crd?xQ9c9`z&ec(-UFW+x%CzeOS4Ww4jdyjFHDCfj9c9{82T(_uc1;AR zqfEOd0n|~Zt&;)jXd`W{2O3%rc4gY7yE@9WYc@a~W!lvQ%ywnk zH3y)MGVPiRP)C_|%>$^TOuL!^>L}B$`2cm4Y1aaPI?A;55`a3|NLv>IpLJ#0b*ZbP zJR4X9P)C_|Ee5EgOuJeD>L}B$R)9Lnv}*}K9c9|J6rheW?OFy)I?7iAF@QSSNL%AT!j);O?dmAg)}*VWOk3BvI?A*)U*jxufSb#=6nwyp;@xH4_M#??`#t$*q2DAU%@yE@9W zb)&1JOk1yYb(CrACV)E1wDme*lPlBK>jCO0)7CEl)KR9bHvrVpM%ua=xY3nq>rJkX zGHt!t)lsIcTU;Gw+WJLTN11lr;_4`G0=@)LN11lr3Q$LxcHIV0N11lr4p2v#wr&Ne z8w4By90?o+91R=;919Evh5$o>_Ji)X+8(`Wn&KZ}CBZi$}qOG)nzh5m> z!p1OF3x?}>fO&H?z`VpfG8bT)GOd^f{C&n#wIDCU#4*_CQjiYaYtR^Po&5VAkLf?Z^Sg^~9dVrg(3V?vZT`wi z{hrHSx#RA({rW9E4fmhB>NY+7&iKEZ?PK7W(CpT0p4_VUJuzy$-SPUKYi3T+cU<-1e|+#52(`I(JZ>bS+9E9P z)tXYB*|?d=q&562bow{+zPA@_-gx&My>G$ym%YB`U-dVJKe=VqLre7iuRmp zOfrj~603&WjkMWVx~3O|2clYCotaA6DS5B6u~0dMb>2|KtoDqZigeXQ&2B4VYLR4? zQMA%o;jAshiYpN@Kh^twee#ZH7G0$Gh3CUM6N{MFihrl#SletTW`zzsw)g0Jn??L= z+jXP^|EhGr+UhRF?6>+0+48X7{69{v999nXyb?+151 z|1Xc=-gUtut9`MV?vlaCQ%;*YW6JcYQ`@Icjzp$SnPE(ApEfl*rM{t~VaALp)7qmm zr`AutaC*aqp`rRyKiO9we(x>t9lT-BlIFJMky1KMn=-MXVPbt~??}Dx>kke-X=Ib$ zcdWhdk#n!t-`ErX_3E?l*AHyGZr?e>=IF0(JMqdx=kN4sv5O%2|FA$JB(~BbAEM%R>m@7;f@q`K#1y-I~};$M*Kvhwy3GCc{#f! zRb8~Om=G&l^X3K#vO^fnQF!t6xG=r+UadQ2`7 z$R&8A#t};O7qU$@%?&B-F*~w0N0T>I-9ncTi-pmc<%y)E9*0~?jw&`R7$r^qj*_yX ztyLw+Wr!rDI-yv|U!GN+kQ)@FIX?GBZ9&tDuwq^_8#Ru2tG_@PiI_>jh^>EU zrFt1^ehTq&@HDHDCpTtM@@!otaPcvW|4TGT@2nh7V9*eiuika;RcQqML~E6ssaK`Bnb z0}#!k7n-nB@vz9L)n-Uq=n%T4cmP}?PC)42(Ud_)kTJ@w{vsi&E&27*I}>I66qRfP zLMu^9BsC(H>#HgxZjjA{7~D#N;yVbd4=9t{-;vaT( z3%#v~Pk|P3s8p5<2xFag%F1-b^WksQoD5oRL~5Fsumg@M?72np$aUY_eePm4J`9Y#c=5zN@KRaL8EH7yqQ$t>PfR&4@e z*hO8E6a|EnaaEgZLbTAY=Fc%YamYEc>Mjt%H|(~@ITnx5s3kB$sE&+J6%dA#Mr18~ zC>}oK!z9k!h*Zs}X^g?%4jf{UO-A8z_mWX=)TTDfoH}#*g$*;S3O5KlI#7R=9q=`3 zJ;|!g6G6tI60i{w#mK}?-z0i;Njo=IL82(6G2;-O>kM4y*(B~}GFK_cpsQC72`6Vq zt#04^!)!BNsXlZGX`UZrU<=FTZjrH-T0K};F1Sv%L68;NDI^N~XsoC?mMBS*Abo5Q zGT(G$6A>Ri*4T=bgG=aZo+v2_N$h0o7UEwy#GIg;rKwKOo!SD2+}`Lir`JNR;Zy z_^S?~Z?)h=qk4U4BY08E=(H0&<^V0d@Vm%16v3^&fpRRgoe8^KvK9&Ii6WYeFeVj| z96s?lKtco=^L$<-8?~`@$%xZNQ0Txw6I~0;3g8eSwj5&%Gl1qaYSO~e(G&<{S*@kD z<%;HItwmohq;fui&~aOo>yL<%qEMW3gg$*u5pwlZb}cN|!BHtCPPWO7@%%eE>Xiek z8lzV@klYmXrg4xiu^>bPkn3?46RJ+oU_5JPSf}`3>WLx-$l>mEc#V;BE}9lDhF7|zKt^-#o7GApsP=Rq|9vEEN~OUuKX1w$fbm$ zrFOe_Y+vD~s;ak%oULiniPo92(WNWNJnGd~8eWvb8Y>@ONR65mPsXf>m8mncvGP-x zvgUz>YprD1?4=`?EuQ0~$#bg5VLD-^;~nTdFe?30S+&)3yv=2M?TuPX^JQ(VT;)~O zg&-q_GCZsLo)2-Tm*a-@@58EBUm&dH3JQ=YqTrSF+yo&sjp%xDHl2xy>5Q|) zCl`(CO#u2ec|xb2@R~b73z0CGQ1EsTMWQGTD`*bSfwb&s7=Ezg-iUfx_7aK^7g7$0 zu#n10mtcf)pjQ-sqzn*;oN@}w@{-FgQczFj3<=S*iHoVDbOx)_B4#>myVK$7W!Xzu zQeQL3stvv4yKwv%2KtchGK_G$*-2-wdXQPK#<32>GT^;0?LY)0#9V85`Qlbo+m6d# zrie&o)lmROW9?WQ=;0_3RW1AkOsUUbIcILVCX?w-8&=JfIw$`4yUv8Mu%LVcSjCzp z)r?)^HB04f5BMKVTQzYK&eP)}p2@XH8)o8)OUcASvZ5r(S>O{25>{MFre0(Bvy@D| z`T}94g$e2ny{47z$}v6~wfQUOSt%>h6*Dt)xPHI##qVIKOpguc12C6~vx~);-Cdj) zBo4(QG9$H~US4q{=&nY|#1V)mlt!&oPivU*F_H3qU! z5EiCIE-r%*%8^Zu#47{|a+$z7w2fMNJ-R;e%DFH9Uw(@%vrOqI*0N)HcK%Xr_4rNS zxp_$$jL?}dlN<$i1X*dv2)|q=eH~sgg~Sd|KAI{@tg$Cfszp^@@n;6`Pj8!2UkgJS zQGweOzmYTv54S0dh5YqNXj9Yr&oGna&i+Z4t^{$iUl7ju%>6`5Hs zx=q-u$RsQ?X5lygtH&v0#i^DW&UUO~;xR-E54S0W8@hrtqaXiq3g6fg#xx!l#)s3{ z4y+$!+PhZ}7eUPjJ|uLu1l!n_2j4ErS#AN?f5(9jM^e}pW@XCx9LA38ov?nwhVvW8 zx#?6tL8e$J}#^45VulVgU)>w<)qjwt9#AHih*L`!;QupK-c`{iim+ zUGu(8&ATFpU_<|jZ{ zKLNfk9tBv7)Rl2tMJhW-`pk0|Hbs}DY;44iJLyexB$acod7|_)SHV>Nvme4%abQLZ zRVQ1mL?o8QOS<7H#=acv*Awl2ZYP8KNXpr-S41NV9xYT|`YSqfVXyBe&jv|7Q5?eJ zZF)J<0E9ds4r}|$7^&`A%DGqkjZ`PZC?%aqWpO-(@e?oP=0~N3(KL}u zP`~C~YPtBMpl)F)Au?l!bAX~CR4#gz)|dt9cWLy|(cZvVQRR zy=Y@V!fbmKr-<=nmf~$l10^i6F#w@BHWMfHX5;Pf1r=|zQ*ZT*ShC9qr)*3COW(CO zz11yjH!~IZ0whXB7eRC~&p0Oi1<}Zag8SV&n>Mhh+&LLoo zQ}sB^H&VG)$!Vl=Z5BwY@87V0h*LeCvr)aNE9D>-lCW$g)~J2%a=yNy+6x^{1KB1D z@1}{4mxK4Y#L}#Xpu4mu9`Rar`CLv}T9VNEOI8-=`Mx=5A+ep$@ zQA?5!w0h;hQvzZ!o-OEmG*Y8BuX%pcibd6)77gEAzLLq?m6sYd_bBTs%N_~+5;w<) zlTVZeDw5FMn~B~wRu^@8mfm3Jf{9&>Rocg*m)a0^YA~bMFKHSzzJjFs%R?v{my*<0 z&xbh+bJczU=>Q0ECLZ>(7O){{)Ct8|1Wrdf+|z|xwy=MvULWGjgN#%;Yn?Qu+iXDwa94eJPekW0`*aapmSL|HETpp`N;CCFi zE+wBUNF1gO9QfXYlW$92o`N4x_bkC#)rDR8@EO`Z1_r7e(&c?3!HQm<(8sSEq@?s> zAmA5Tp$k%$dn=t59VC_4*V@AMwYG3Wtu5S8TMKKvfB6ucd90?2Q+nnj=wlyFWu+AO zuXy-yDi1uCS78SuU$r_D_p=PEL7@mhQ#n2$J-QmHNB+jJ%@_p`5@gnmrxEPyw*`x zPn1ZyyO_lLS)DLycf^e{Z(|8$p|h33#G5O;hUH|O`n#}YVcWu{MOxd!#dy(P^OA6L z%e=BH8!^)BwWHZ`F&HEcbMH*e8C4+2Q;gu6#>vM0Zy>@df_RM+r8ALD#_YoK=CM&d zmAm-D*YcP8IHkr%oN3ycbeRm}SgjspB%Bq;Ipbo%yI4PmGlTL`piWqE_#Gr4I%CnW z)gcapg_9g_gYr0w)hk#W!Px;vgOT)}t~8J!=LzwSs?v9Gs#mZ@gg6N*4radMS6m=e zd@DpTp-AmKW208>iNsE;%Ei;jE8>k@cxeTaM4X==#lj3jWY7RX_7ciNB=gl-P(n;} zb>VDXBhe|AhvwY{>KWS!a_L(Ga-mkUQO04Ouqf1Obad)E7K*fv*`39ItS zkS`^a)CuXeDdZ^lq+Y@1-n7t#Rc&_3fqMZgT%W+{{a6+5A82(8ak6o38!1tC#i6>T z)wM_z)&603W^F+#6n#*S!``S-#8L1u2%%@0L;;uh5P&f5Y2#`^7`DZ`H=XnHaX>Ma zf8mWEhImOS_#5%kF1*{0rtN3W+U~NL1nK*+vpt;x+dr0Usb?>4+~t z9EyGTeD7bhIJh)7xP?jV&d;BKo-;MbXp|=fnCK8D@y=h&5azfL?wQ6(lqW6;s)V(3{Zesq91O zO=xvOxLINr)^v+EL*NBB1#dzU_2J}+Gqi@X9>}6RF4hnTLRnQ8b(qxaL)Q_+p0vox zMSs+@jY}x}AlPOgUZ zwmM;wz4qcgAJRU?;nbp>R{0~mB6Rn4;pIR@Iojn^Pvx=>7Kc$iQ6wSy4CpEq_+LpG zfUvL|hn0i5epoQVbi~5`539p+d?QXk^MBPX6w7yVFQF+}AQOPFe0$;qxqjk>GcTMz zlW$b7;yw3RU}VRzWT{NQAxP!mRL^C{QtJ88Ti@r?A}0kPr0)x_A}+H$EkL5=oN2Cq zBxjruf>_8`DpXkaHMRrqD>QrT)LM=GKF!GX@-@^>pUCY1qet$xVtADZJbmzA$Fgys z%8RM2>}DY$H~JI?Ren;BLt&xM#InnXmtw~-9a6ax^!(QiG8Vr^th5}PNb7i4PZVKc znXZ>0Wbdo`TD#~q7+%{PSv?M&@kwE$7cQt3l{k4gS503~rD=KJmv0+@e5h1?c@n%f zqF5e-?oADsc3`7HC8w#n%e0!E3$0>>O2I;rNeGr-Br&tO3lmD-XCpGAdP(_j@N%VQ zvCP0PzWj8Ir;1+KAaUqfaU;^9;Ez&4hROW0hp==B&j2j6QB9-`yic`Yyb{Dh9IMW( zXeF|C=^Bq9gn4HvszKpK^u%Hy!b&?w)tgc7T&Uo94w5L|@wO+hju?p0b*JUy(z7V2l6jY;zBA4rgkY?Ik${=$}~ zMSfMEua4i6Uf81Uh{HdSAm_$--h>$lp|7ufAaUsHYaft>;uUK}zV?Aw=o=jsa}6NKm=ML0KA5!T z>8mDAk`e2y20)n0Js$g5!79wbxuXC#4hx%Q$r_|h@$de-jDak~c%mm|<=$f>jT84E zgcW`5joK97K1?|!tw7|76*mQz$qzyDVPR?%`fLKFvU56w?<)_3WgEAX3ql`ijs?JF{TV-JmgHc48*$`QxiM~_IIJ`qfU>OQOkaG`joM<{PMb3C&0o39G-74b*qN=6i6TyP7ET;C zTkg67W}7x_7p=fi@Gl0rl(0L$dMQYdja14gvxXp8m$>5bs6i}@7}#PEj+j`_kBxv) zE^f&$Zw!(TBX&G#Ckkj7wayiU5U;uNTTdkkRa-sIr&KuFGl+#9Mnt}26&n;YU3THY zO*rr;Wpq}*odk=2D{T)BVxcpl&nK)*4{;BYZN!=&yz+LvA197{jHx6Gt;qD)VK_wM z@?`b(*r<{;T(4Eo{$Vuh-NEY#v^wF(zq2&^w7YrTslRaW;KBF*?}Pdy7p{N!f4tPK zfA!{Q*In1`(>MHn#c9```I>%t@|}?%4xOscI41PUvd16RKYjna?>zm%i5I`K_K8Op zzx>+8&s?~B+Dlj5e({4%t0tfP-4`yt?HAwr=XLt2`fq2Ru;+jO{V>7*`raM-o;BZl zZ~OM)`U4kC+4=B_dHP+0-??|=^#}BgN4@rD>dO1|NZng!jsC%R^h@eCy=|}Ctxwdl zmv5f;J$>Y#zI*+huhw1s_JW6>Z@Be(z3+_O`+j`(N&0KQSvF_X5yJ)lzQ<$w&+q*1 zqFYBCr$4mimR*~_vQoe2vRCf7yKTRIOHaf7=dQXQ~O*_isbDX!^V} zrw_g4i_`S;zA(G>nkTpFeNT*9@$A+E`Ww$Zye0cL+w}d;nPnq(>Z}s~gd-mUVo_U}CmC(=)bLNlMZ+vvvo(KMRo1PeQYUiJRb)4S! zp9l5V|8SDt_t?7=>Jz`y-+b=6zkT-~-qwGcy8P+WU%XO(^_zot>|FRm!N2pKujx7YON#Jc~bZ@*>8)u*?P(Qo>zi$i0&HtT%{KfC$GKfbK@ z{q~o`-uziq@4Iu%w6>0K=x=T~VWhVCKK;PkKYMW2(iQrv^DZ3}z24#9k-kg+<+$F( zyHEH(`eUcAZfV^#N8dT)+jYC%I$8hP$fMTWJ`VA4@Y!+e_8z16{qYZ9d+J+1)%$*Z z@{VT~U8MJgUv3}u^|SRi$2@w^)ZQ=X2X1csUiW`y^j8i%w)g0Jn}z+`cHOA|(tP&D zSqBH{Ke5`*-E~%r{=n`#8aKXZgZG`6&p&gU-uL0C_aFM|QoZl@FWm9Xy(j2>Km2ju z!cE)tzDWnaHM?s&()IgC?K*LkeqiSQZ^h2rtH1JZCtvi)AOBhK|Mlm0>d(yHH1^%y zH|dWa{r>G8&y4`@2X{UHFOT5fbwTfo|4;Ax)BA7Tx^AA{_sTmjHH=xH_uc#6p5Oh| z1pUqTTGyO7Vvznu@9VQx&U#&c{U846-P`K#(0}v74-V{YT_^Z|dgoC6sh{kt55M;o z_zvE%XLSPiy~!^h91FYe`uWgXzpVGYf7SkVr-ApycVGRdy(9I$uRl2Wq>)W}-?8?- pN6x)oe`8Pl*Q?LIUq7(%x_##io1?$F?Zj8dMRp1P2d*9c{{e=4Rhs|+ literal 0 HcmV?d00001 diff --git a/test/tests/fvkernels/dispersion-test/gold/bottom_left_quick.e b/test/tests/fvkernels/dispersion-test/gold/bottom_left_quick.e new file mode 100644 index 0000000000000000000000000000000000000000..222cb1b385d548efda833b1afb168d3e3dcd0d31 GIT binary patch literal 58868 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

37w zD@S|*;!y0v=X?L+<-w)7!7WT z5)UiL4q=&nj6?MSxD#Y&Bchm_qBlscI1QdCm4qTPnQerJph^v0uBMB?vCutpwKTDZ zlWlwnX{1^#^3|5PNYbu42oG!XI=U7t?(A4NucMyDWPGJyR15+9`on>;jr$@O*;mK; z`B)*;XW@kbZpP-D*UF>5`e)~*hZsW@2+Qh6^~#~#LeaE{cGa~|wSwjP!;HPkze6mt zjne25Z&Ad;^DMj$&VG*y*MoX9nle|>LcVCu=PeVg56xz!S9Mel%1RO%go>%`L+DLt z^;GsD^d_`AA>1qp3v0T?n<4Omo02yniTbc*(n(rtRS#rY9v5o}1fi^|%Q{Tz^`Yws zVozG+Q2aCg~o+y$KeFk)u zO8l>+3_w`gjl;^pLO(1RVK!!A|A*CWIld7mpvAxH7K-INg_qD&ERYF6SiL=Qf;?r? zi8D`}F_Ujpuj4)USYTu)uwaa4XXU49*4q0pNVCc5ii9~U^=9BCFuFD8)PhgjagYaHj&ox zuAV5u!YW-aLCD@${k3-4YcRaFIkI{jI^&blMlVuQD=KmFaIS{Fpi0w#L zzu@Ic^TaX(zxeXgF`jCAVS~h>XT^<3hmt=^1sNvu%O1kYB|O8h&_*?pHSj*wlJQCq z3vsMEv!a#C+m&lPf)Ey+rKkpl8_^Ssfe35u993^dxpSe0<2gv8c*onGz&c_eLf4&E zj7!hjjK&bku`_%xf#T4$(ASeaY{F8PuG4c+b4V6ll8z_a6MsyW;l!b@YkW9CF0)N$ zoB0bm+S>i9K3^TbCB3j^-4Ta>I6*Fq@w^E$9711T`*7mW*VjHQ3&kte%6#p^vC!9( zty=b+ROajO3j3tu;#6zLKNKuuS95!bj2I*i3p3J!q3n

OM`Yxq420;Y6ityu{az zR95uCRuYyp2|?nprmsB+VNKU~kaoE+_$|&bc%o4;5}8SS2#e7eB*;F59?ym%BQ11F z8K!0MVzY`NuKLjd1;VnekM7AiK@!Ea(0@r|kdopO`g^h!qcG%&L)ULYjprIhkTD^O zBYiMw&C^#+oFpUGSq+1*kb6A#v4T~YgL6j#ZXA|2%aS!no8sU7cNqg&i1Ea#j8%A# zjWkZ&gAmsAwTHE-zI~W#N?L))6Dw{?ER!FCVN+l&rZjZ>C};V@4T;AXJ@`a<mDp{{Xejhde9AVp8Kc#+5|i!&P_KV{wbnw5lwgbkky=r)p8 zwYgR_^zCh@FK+8NeO`$nRX@NSa z{>wUOB@UQfuy{#53k98M<#(73t1dqY66Bie?!($b+s>LY@6GR8Y#NEGY3$5a$V3q* zItwQbn=N-;0kh3gY!|J;QSvVaxstH2xOyo_kc~{nsIrD2SeLlw@u)#8j2YNs5Q&*s z&yS6OaV~BtE^iEy4`X&RZKq0T7`4t7gb=T}@>@?O2~}G?&ZpEk+B1lS-9}8lV-*_| zbG>%y!A&^uCu8)~znuh&e`{?I4q~A*qAw<_Ob>Anl5NDAAiVN+z>gD0J|g;wNN z*%3HIlJaEr0c=!B8?M(XX#X&t_wL~J1X`W&^WRyTeZ(eSKha;@zJ2>2Ub|EO(dgcP znQ`{}`fY#t_pOKh%?-NM`-fj2`QX+1>?<;{|9W7L0|-&}OqtlN{j|KY3)|2Qjk?eE%tw%en#+OB+W`m!H=N8ftI2XDNz@auyA9rHZ> z(G9P^8h-L1eZ$yU%U^hXK)>6B^unVY`9J$ctAef(2Tzqb6- z_4?=s?)doq*bB4Xc=&?{Uh5y2^{)IyxUz|8q zfBe3ezu9$ti~d0Dp)-!1^9%is?RRat|DoUOmp5%2-D&=l9{J%tx3w?S^tPt4-+Q66 zML)W2^*PDhWqPP-(x!W&Z|Z}u-#)74o^|@W9T$$B_}gFWZ!TSX=Y;W33jSvgS)%_u z@xeEy*MGZp<9$zU*4N%~)SerkdqGe9@&7)3Ugvau(JxPb=bbsD z^~vk)xvTf-(+59!DVBcoC4KPLfm^;GyH$VZw(CC}*}q)h@|{h&mgPqY{>OgxvHs-B z_uo$pZqtAG=1-*U_~*W9^qv*3UDTZikv zxOVE&-|cdW{_sbS|M;rEdP4v1&F4?=diHqz>)(D|*WWl$A9&{XEB_-q0Nz)p-q~`f zKKN1l(_hm=#U>*0s$CpLz2G`Wrv)UY7mVT*3d3V=mX9 zYWZ+;=%D5LPyXM^#C3PyuW!8i;Qd#J68hJt#Yf$B-ygvH$>ozq-KP)!Df-H@|FBsf zeDCPy_UFH=53c{~OP~K}nf~rK)*o@r{Im3}+N1Y&e0-b!M$el4dS*Q!`0v@cL4WFo zvEw)1{*3<94NV_^WBld%h7TrA={(^%@NS>Ge(WOL@1C-8+arkYAO9e^&CmybyNfmB zk#>FXvhW>8e79eJ_nfg8ZoDt7zy0&S`OfC!N9u2!l6ia2bqT?L?=RQsPj_5#?*F;; ze*KZ3tzGr_MIVy)rXtp^_ k-<`er)UCHauWub?@B625&*)puT=Uk5)C9r*qt=i9KhmURS^xk5 literal 0 HcmV?d00001 diff --git a/test/tests/fvkernels/dispersion-test/gold/bottom_left_sou.e b/test/tests/fvkernels/dispersion-test/gold/bottom_left_sou.e new file mode 100644 index 0000000000000000000000000000000000000000..87477ee54f9770f26496e6bfaaccf342aef7b95b GIT binary patch literal 58868 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 literal 0 HcmV?d00001 diff --git a/test/tests/fvkernels/dispersion-test/gold/bottom_left_vanLeer.e b/test/tests/fvkernels/dispersion-test/gold/bottom_left_vanLeer.e new file mode 100644 index 0000000000000000000000000000000000000000..30d55a6060569deba324d3c1957d629dfd63225e GIT binary patch literal 58872 zcmeHw378wznXSCx1+$waA(#R?v5oh3dnIzYZMUIA+XinWI9QaVQg>lVCA75Lh9oS( z1TfeWhGiz-OJGRyhR1}*42xOABS3};gkkdKK_EOBg7biY-OLM1!sd6*t-4Z4Dyem= z#RSH#?>k+8-7cN_?|$!pw8PxQ(EjnKb#*W?+=_9Em13ikJA!gXHfbIWzD6cBpjE zS#f-~%>7`O!%CB8rr;s>AudlOV`lM9@elHhrn|$FqvL@UZY@4;vwYlIUAF_}chZ6` zG@9-uH_}zQk*?B>biz&O$1sZY7+JV6OhmX@>4c4-UC3v~N770oK0;>z{N`}rKqF&C zddzIjveS4B4Fd+X4f@%3+=th2KPHj1jl7laiezjnosVp?vvGva7IHJZ#P@L@nXr-w zd*>gX|MCAvq>NrG#rQ@Vi9orod^ennztCaWU;2 z6}9tuI|Zgh9>I|AG|lWZ_y3G94HzZT;HGZd{UP-rO72O zHX4EVz2D=z{e4gV{zAMvGFSaQrU`j@zbEn{-uHfw?>73q8}aS|F&inRSI{#|h6u^| z1Ko#S=!he4$K83CxzY*08t)!F1OI2ZGkBRsm=<8mRZTzK|cBVvE&=gayG(3 zCuL;tTp1tm$lyhA$90_WOUzEE%~+mkn?%efBLVsCk)r&`Z_c=Rj_(|B#@e=}qLdP8 zefSQz;X3{;{249YFaN#_JiY{Z&@Kw0(1Z)|XM}h^CkjmJ%6dj#{M{7iVNx9T5uUQT z-n-OC^0Lt7yDTf@<>h?(cVFYXuD&d|$;)t(mxuSHF>sW;{k^-0@4CDUR`MPM z$ji%{grnr`@7){tu9F^$;d`(o#htt}oad7s#a+HD!{HF;f8wwA-M2mOO1~ZI|L)}R zo_D3bht+s@4crf6#u5z!x6*?f)7;_iZ)Cb`Fz-+PHhyx!HahveNrM?{DP)`F=>>+5T_&vyWaT@4}Jp|LnTUJKutn zF7MB}|Cjgw!~dRrv@Y*2yYI{UF7flTb$Nf){k^>ZVcL~{_u75ab$Q?I^2z&Kj%K>N z?{t1&rEjHvmHJeEzw&$g`9;9%mGM#;5BtNPDQ#I*dflIX8cIJh-^#lzf8@Q={nPeb zRX)mcvRQXoj(t-1XDiC@Wdx=G-Vf#N%s%Y

4pteK`R3=l}ire_u}j`+EN0m*alF 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 literal 0 HcmV?d00001 diff --git a/test/tests/fvkernels/dispersion-test/gold/bottom_left_venkatakrishnan.e b/test/tests/fvkernels/dispersion-test/gold/bottom_left_venkatakrishnan.e new file mode 100644 index 0000000000000000000000000000000000000000..d9e50a1b3aeafb22e1f918d72902d7ed33fb92b3 GIT binary patch literal 58960 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 Ee`sunX#fBK literal 0 HcmV?d00001 diff --git a/test/tests/fvkernels/dispersion-test/gold/top_right_quick.e b/test/tests/fvkernels/dispersion-test/gold/top_right_quick.e new file mode 100644 index 0000000000000000000000000000000000000000..369b47b35722b42631ff7faea6bee8f0319356a3 GIT binary patch literal 59028 zcmeHw378wznQdbh+hF#vnMo*?#2CBnc6$K>a=Gz_!R|KRu-QblRNY-zQVA{XZj%rb z%odDcCWIvec|!v8_(C#%ByT3+B@mLy5QcG>@i@R6mXNU7!NwgJc&v%vIk)bWN>WL! zTP-Fqc71)ieqEJL{dd3jzuTHuKGYBF?|qJTCRT}u_|5~>@1j{dCx5$- za?d((ytl;tAj#pRNHa6r7c(QanpvhO--IZ{yoRjK~rd=nMi>`JvafHtrax=Wd`*9!H zr@JQ?y*%&4R!xxKF|G_?f06!H_qg&$)PYdfeh@}@A71(e?j!Ba;*0T_ z&oXS(MO_G7Bjflt0?(&2Zkp*sJeB4uaiqgXVc+=3*qJGQemsfbriYwXV?|kJb%(3yz1mrj~`3E zQ7mJlEO3$*i{tY6fJcVSggdU!^7#=lH zw%MYD5@~%n%W_=D?ZCfL;`!3|tH9$!koS6pLQ~TirqvPR`K%}`sVnOkb@6xOy$@qA z#eIaYoUZlkdOj<8S>WrZftHR-6?>q6||Lh-p&nmys zzv}WmJI;Wk;#K+{svgAM|Lh`sK9CtpGzw&e2REj8E%ORx?MBxYe1K0Sq_=mc! z%Z+C27)nJ|b{!7)&j9KI&p*ucK8#<7JN4kjyC2Gp?`2u(|IYs#^*x_&GJiN{bME4! z=Bm4Jr28+WySno!IGO7HjQn2RU*NYFA7!fh@8t99{)+hd#iqJ%mA_Z_*C*Wgt!@8j zqN(n0NIrFEN}^us{zLEgo~uvaa{bEnDSvsLIJk-BmgEaowLOE5954S(UpV*Im^sAJ<*g6Cc-Im9HPy zUDazJ*Im^IAJ<)#qaV{n{ zHZTX63(Nz~2Id3j0OtY=fQ3Li&;cw0&I1+$OMs=oGGIAyKCl8<30weN2wVhQ3|s<4 zflC1k=mcUw9I$~dpd07`9N;ow6_5bfT2BEkz{cCjkN6P!+ zzMpiXJRBGy-6)R)_Lpvy4**6BH|j`TCjqTermoDNbfZjNrvP-LOkJk} zbfZjNrvY@MOud+&=|-7)F>lk2GWD7c(2X+nVxFfPW$JYXKsU>wMrGDO0a=r5oj$zyg47l&RN3fNqqjS35vA%G9d^pc`fCwFsaaW$JYv zKsUPTIe0n4RKz0Q|zl&RMW=|-7)t(0z*sn-S4jWYGR zP`Xj3UKdF>%GB#(=|-7)T_W8mQ?ICWqfA{d1?WZ{sjCHaN}0OGq#I@G8kcUAsjDsB zC{x!i=|-8lc1t(P)U`*tQKqhrbfZjNFOzPRsn;s$M)^`80nm*)Qr9Gqk}`F5r5k1H znwD;qsq5v^jWTu3NH@yVH7ngHQ`ekyqfA}%(v328?Uinnsn=@hMwzUtHhR?5`%D*)XnQ`f5j zx>2UC>j1h@N9uYFaIKW7>vhtNGIhOPx>2UCH%K?i)b*>Us-6x4nR2z}~<991olToCur*d>;4$Fa|go7z>;N zj0464&AZ^&IJ|#3xRf^16Tx{2P_7b084>oz;fVxURE!g^u6or+PtujRKf9PXL&fm_}v+j8n!H_r3NyG2m)? zao4V0n~rV+L}OOQwsLmd=X+wt$1|Hh8tcs z$$$UT>&(qJj2^r3_RZ#_|9pAk+Pfbzzq8?jsmq@lYu?hg;G^ve)|-hx-nM0BfPyDB z?f2ffcAL3#<_l-;xcymk`?APY9Zz(cThGXBKVZEh`0v|zuerJ9-4~jUxWs(q{U;v2 z>YJO)zg@QT=;p^jXv}hxNh=jM7GP?x(U$4XC+$=&Yv8M<_HE|C@{3-4{L6QnJBR<~ zo6kJ`w7LCP-@f;Slbg(~-RlnRp7DLb|M#Q%&40UQ^3r#PooP($ag+AMoR#7Y(>*W4 ztiSBUr0ZtkYG-qv7^T?krgKKKW5lcsJ~~z^YQ=l;IOY*gaEy5gcfy1TW~Y@{WM!;m zcB1#C9gkv8uboLplXkAhjYq^>U85tPOXu+-F<-dT%G!~#*}TTw<>%TU+>uGyiR?r# zy%%3NvDZ$xF(=m_X`W=@uLaMaH7h$2bF32X>gc42oo+rAw=(_YEq({Wd-#1z@p~~k zB%g5eIsUx(C5H|S&wgI^h<9+-zquZpM)JW*5_`GnkDIhlJCab2G7?=D6MK z#B3v$&NDKXd-Jf3`Is9fqHti>wzjzlKO0l5R|)4#5;L#e)agxIZXMQQ4!n}Pb>*FJ zngh4=-~3=~gSoT)qS51De%5?_*?x21S^k!Y-#6^2`I8YnKbv;mi{`+tT_4`>rDgf9 z(~aWQ?c|IY(i3j+mdVpQt?85Frx|X_Xl-eo(mZKWb8BnUWgGG@wV6Avd~54(7v3iL z-+Og|)49;j_9*p>lvAgiHhJ2VDV@_=VzH@{PqU_UPMs2;JgK#-^|aF_Pwk9PpE9ZC z)M>4(b4sp7bCxcNRni&8_MNrPoI7YkM zYqYi+lct?MdD7{VriW1;MM;Ol) zS$vW{A*u~5AriHYkEbB&hoO~VMU}F-RYwIXry;i;N#ciS}_Br@H zU>H_D=VIv-X6mQnC??z#7QXo+Cq&l!N~fDa(U6K}-2}?RF3U;y)r=VIlh=QNFc!1Zf)NW7QA_oqtKzM0bkJWB)iDai zx>?H!(+>Jc==_A?65f#M5Zx#%g$_gIrC-1@VY4?8i?TmenySICPZ;a5W2>T8zOPa{ zx@ZKS^fEdlXdYq-siz;}yTt4I>5z>jv~I*gSS$**&;^T%sui)Fu#%l|D~eWl7OK+T zGU(;CzRC#`Iaejd5Mk)m%T{MLTBIq4C%kMoPpvx{HWe!RwAa`wGD#`4h8Y`e&Voma zyh6hkn&j%c3?uHKaLq;2X{_eLGR-2DC+R1fxRYf^sw5X@V55lV(F#qunPgO?)Or&n zHS`E&E*=7x2on$nH#C*k;bpB}E(uX=sh?Ng87bo?>m(ZxI;lz`BtL_&e*c0LgtXSMP6_tAzJ~rKm4Cq#@CdI)v%QNto(G;PIJ!G_}FLpn@jN03+~tpr=8k5y)J))u&WE@SJe(*#8{oKTRl8z7%36U2q^j;Ymw7v z(WTu&Uj>n(5yu`OtdN;pJ}tIwDHICI>-vR5%1haCr#CSDFxiaLDi0+gO-VtFp*5_Q zx<$g)s`a2@HSc=K242>vrx44qqp_f7U!o#P!nCnL$h6&+PsIZGSYm4y4w5iXJ&{v1 zqS#B=39OS(h(y@1SPm%pRl25^?PjeipqS~bOg{2kq}71O`(q$+{n={98lC)eZqhwW6&SRVVcB(5EVe7#aT|M zJ3xc}tes<-5`5`Lis&Fmd$ZBYtb%a~%`gmPi#LQMWbYkQ9Z2eSa>7B*?ZzwuI}@UC zfQD?_c*9YgaZu`Y{Q;VcozL1OW@6}7yux_7l2FvtvU$h)6=tfsTAN7OhM|mT-5D26 zx{Ac3Uwma@MJX+@ivEQZF`Q&N;b2-uvz<>=AHq~64>Vlmq@#8p4Y928JR?n!Q$Gx| zDLb3&LhFG+85GO9wVr2fuG(sk80~Y;U)sTWXmwriGD0ZFt@MiC^h^5b5ZjJURBFY7(&~M_lw>0Yz$22yh%ufVAQVy(5@*GdgX*)-63j-h{1q@ zzkw(sMXOsub+}8V{^2m_HY@vsqUThwJBMKVe0AO)u+K^q%d)vtw9jL&|9w(N4RY z#$J6dvs_JL9*ASXdSBUq2uFyq*65Oj9VoUvlf8-&5zD&00QAN>F?-R+Q6lPU_$e4t z7gHY_GMMhwVf75DbKsBf^#+WE2GuLTI_50tChP{!S*osk$Zrhe!U<|NYD**HhKac5 zR5CG6h4pOeNDVzCc)OVuF4}Zx~gZatx0MX8F!`GES@~Vdu`` z3WM4ge}k?vEjAnvz*r`BRu+ABIXN#(7^;}HlnDm`I;eo>912JH9}DaROmV-s3%RrJ#`90p?G~7>J+^#g6KC@(s+xHioO+6 zm;!cBol+WzyJejcRHjrfFd1N~ms}cn^3$F=rF!7WZ$zCU*S$5ON@-%y>(?n#gCKQD zxTj8GC=@T&DYGypiFKQ~C8F8X;VoUP(r4i>|Ev2cV|%oA(HRCf1R>K5mhM@-t`jfvhN)9Z3B}~4p%Lze-CJ+Um$GJK zng{ngz%&mLkYTFP?jARbm0VVT(0b!A{pH=Tv6Qv3y-l?%Or(7BTVK@BTiBW68hWfF z^$miA@$x6#=I}{x&edI4)cc@l+lUD**owgE6+0#jrD@Z|3=+O=Q>F=hLBc(48-_yh zV%ugZ#%H`H;ox!2UpBmL)9|LqZdlQO>g(k(-e{}Aj9Z_ns^LbAJ@xXZuU=+y8NAq1 zPwb9X5o`)r*bs0?6|xM(L26}A;PJoGGdlQPRAi_-Y827C=IT2CHid;+Dq`f*tDRI_ z{a~>BAl1D79L`UH?TcFhHX?Ra*wzut-j+VI<;14=qKu1$*hw$Gsg9!Z?hTKWLB=W= z%YXJw*lKpnsG;s)tCNZ)@;F8umSU{S!FoMW?-y1w==Y?&^?GGAg`5Wsb*KJ{#$42I z`zf+P(vK96uzZ3ve9Yb2a!vL`qE)MwnRc%sYuVcS(~~0Jk>v%_!DS*fDJLm%*3}R|I?I z7RoGd6EKFUei#-jsY0#fRZ@jI3#9e8Z`eM>uAbiBsQ%bhau^LsShWy~7%NutfQfo9 zG&n6Jn>ehSHX2?wcF(l1HGtADOf1J8-$qhJA|>gBAAP~?xf;CR7wR-LGy^>A>8Kwm z-4?daZ)9FpEnp<<95xorV*d^me!S~zn6OjbxgMIH1J~y36LOn`gl%($8@zsbHynAar-;*f=3{7M z?}=rt82GPvcuy=3J(MrR3P$eU+Q8mu&Auq>WgeyJro0z>JyEGdpm#7=B%S6N1VP(@ zvmVv2^?Zcf{Gas+<8D{ds&X1jC=I=(6gEz-@GDl3v0iU}`~0Qz+ZGs0=P$%T zdvg{==d{nRI!yg!z_fF)(p%sV{v44IX6EiH4Ktp)hPpCGLEEZ>B z2{F*sgS~aFRJWKOS~M5vCv4Blm8S+2e66RW3d15{nXmQeXw>yI6mgw!D>o+&<7KxS zS{0+Am`f<>6Vhr^%2D!3zkn^Aw9tcDZEmLAuognY{uFla$E@&RPwQ)losAn?Nr}8G zHr1^xu0^Eiwhw!At4d;_?1O$7_QkC-j*^dI2z}EeO1Q*_5QIrz9oGoLs4LFi^!Cfg z2E~~Eg%dw4aY!lnBRI4RXWMZ%^J0srhBU~gnIzPW<=~%$*Z6EHMKmsJX4*a-f20HWj*g4*Fp@=m~(jQ-4*|$}uTKwu&NAgzG08Md*lQ?khY#M8e7* zUx+Xi>+pH*U%cGAR5!eaX{^pK?torUHB4`mI|bNi5TKv-5j>K6{>8j7k#)T>fM-2#^L4>RuS;0CcsHd?($ zoT7+{=UG@Cy!9RxrU(6MG-a=*hCFC4;FJlLhjz2pQ5}_?vXY1fp=K-x5c(rpKb8Xs z{SmEC2s2Bj^<%lJfyHCgj}%3SHUpYUCH7ZRh9E3$ z#$o1Qp&b^EFdK8Q{=?~VJllxp(c*u74aM}G!XY#j6J$aVRhx2mP3MW~ zb)0jL2}W)LQ?yst4`IIqxN?PgXPZ1)*fzK_RHdu<}w07i>k)?zqH1eQM7uM_!XK;gw$ z);6<{kPCfEy{bOxhoR6gU|?A?;!x}ahC^x>g1&F1mofP@=44ghL}|ynexwKut2Dg? zAzNSdm)d2=VEA?OWc@Jo`X{B8UbLiC)Z*mkTn#;-$}ozyufRG0=}@cq@n*_uJvk%Kspd#65O`w7O^IgeLzr|}8XKiHn^3Xr?G6!mTW`%sa> z317ug`O;_!MOe#tA1VwB#`{v`#HUcnra%}l8W6_I!th*eCTy4zyQU=@gqn8jK`hx} zB1Ig8;q8=L*}w@Ch7C21GilVcWQWOmqQ;B%#Ji>jrbFF|e)n5@yWH~5>~7q;%xX=5 zknUn|!K+6bGrqutQgh{K#Au7hRk(Pg0qRp$o@-X(7ZNsnETGFuI@QKnQPD4Go42^F zecqfBMXG+FhBa54g(-YFV^x_$5UxpFb9>Y<8pbRvF^I-&%;(2Kz&Izj6sI?a zNry2vnRZhpGz?nr3PXrvu7c)MDMH;^kK-vdw)PC8VV4zCXRKm@Vy?$6-M9%G{$#A~ z`j?Yn@^7u>!C^G?di2GJRq-M2VUmrQ6NDpg`-3>KCwHt*&B&l{*@5e%w zv?Z-pVcUoCynh9+&(r#ZpY+Dk%+GD&^{Dycu3fu+()zCX+eRI{lETym;XyPXP*D>$E+|S$C(rFac8eN_y)6SD^TmncFmD>mzUd z;MLW=Gg8;Q)AoyH?dFc*?je5~v)O!Y#iLs`-0-sCzyIlV=H?qlkKK6tX7ka1zC3a5 z-4B`H*>J(s!AG>|w zPw#%kyysi38^5>t1@lWI-yYFn|I$2X(}TN`cl~h2_D$)<+lReq4s2R}_(_kiF$WfJ zdve5q|6=YufAmEgzjvm&!+7le_783|w?5ppEc-XJ1^**|bFBHVm%sUDV&Gl#hksm@ z-Sql8^NwA2ZTtR@-Zxj>xavnYone?qIN$y3vWK>q18*PspPj?kngjnn|BAQ%^CffO zi;+7%_nlsI=Qr;8+|_f>HFsRseB?PB{|MCC(f%&V%lM}~$^i}f* zu^*j%(yS-V8-I7#5pRF~Pv*=kGqK3x{`e=KHwRuG=1lwP z0(0P=|8d2$?=LlXzWV%AqgIVD-)LI)=KBA+)ZBLOrd-R#CkXzhj#^&iRdGzV_!zxlz~26JcoMWe^R{H*!h6-%xYgD4qQyzT z9teBDgb3(!)@ZbCDz3%Gn z>Q=u}Gl8+|=&HVcU483&`+MKpmakYjrmn889vBZC4UCQ3iBQ7owO!}BahX`J9ZF~H zB)*i_p^0p7C>rbKNB({sKPQ~1opvACjoVnd*>Rf>4Fcoc&!KR9yLgE2oTPpiO4}Lv z+k=&RIu^xy3)~Nr9I*sxngkEICrh4C(oW%>;tTRjq`S+LrsISnw`L!=1wL*q(rtoz zPeRbuO{9C?jdaCsq$_qKop2NSF^oceRtjzm6A^B)M3;l0UB=Ihk9aJB_^3M%;5!cm zCRoW>sLxKNV@?7e>plh4x7GjPX50@g<36=3?pT>vqC1pyVu?(s-$_LgK0C&Jm>(2DRIrn=5@N$?HrzQlA%Yrd_wm_k-*-EnJtX2Fh49U8 zm>eV|_aAgWc&96lyAOBwS?0!y&mJ}l-!t49yi6NR11gS`ZsS8MWAXTAE1q=|iYlY< zD4$nJ;7GogVd~{l;a??}jLy2F1Q)`~%ca6rlj|6Ajc3^9*j#_oAH1sMQ;#1{zKJYf zLo951Ef&QL1aEx6BV(4q4c7_6FA*n^up=3!Z4!+I#sTWx<3zcW8BDrCES@>!yiIK@ zMCl~b`k^exah>!A{!J9m7rtKw9v^~S|0;#Lx|vKdW5x4nQBYD>)-USf@8-H6W?zi^ zSWg*U>Dg=ftmI{3%V$|usLRXy2pkpfNYC!!vyztuHhCFN>hkcOMt8+K(zA>CtmI{| zl6MlIE-!Bsj*54rXBjVJ-Sm(P-@_Cs?&NKBKcDs_?&?_;4wK#Q#DDLzZ+o6qemmU% z**Tx_Jgf9QqRg|a;Xa8OOEd^%Wd}E=%OmA)7_K7jtIPXyK9A>*=(FPK9A}dqW@5)h zUUD(bs|)4AK|gXoyv)0so>A|HGFBL$`5Tr)N*{C2Te4Y7t`_D65k6Eei!jbMzOLukW zQ*biX{dxJly8k!7-Fl3v?!S}ItNW|s=UYv6e_j4w-QS#d!`*K@G2c}8y^>Gehh5D~ zb${IbeTlxs`W5R_{Qlzi9pD!MZx+W(aXcIdf2OpRCF%7*`l%}YsC=vLs{B#+V)u{R z=aTYKm6Nr)t8(n4x<6l3e%Jc5DtAAsyQ)_{s=KNuKB~JaUq7n5s@FcMyQ&X9s=F#j zKcc%TPxjY)*vVuZVQ$+$LqOPv_D`=1U&BVWAN#(pE^c>a_U8aNkpE#H-j5T&f&9OJ z=l}gU=^yaA8v?WmDqA3JlC)KFtb=0|v~$w7PaC@!pdKxZI-r8Wv}E| z@27!dfT_T-z;VFw0ByS`04D+`0S0g~Fb$XvoC2H*%m8Krvw+#aX}}y{F3|z0L}!K024C94_4`t29S9$|~)tbg0tc6nsZnrA4Mo>PTHxx};29nLg=8 znYuEq(v328WxAysW$MZ_OgGBZmFbyol&O~i(2X+nIvFseOueQ7bfZkYrUP`N%zSeS zKsV+c>UAnGL(0@^rgWoBy=F-_%G7JNbfZkYPLpnwsn;CoM%e)70(7HHy&3?zQKnw= z0J>48Uh@IEQKqhq0Ntn~b!`HgrA%F!Kj}u9y0!pxqfA{F0(7HHT^9j#qfEV+pXo-K zdNFU)jWYFG0?>^z^nR=PhjWYFG2GET%^=bo_ zNtt?`1<;K$^;!ddZj`Clc>vugQ?CsG-6&J9jR4&! zQ`b&_Zq$*wZUQz-nR=Zs-6&J93#1!m>UE)XqfEUnl5Ui#*B0qUnR;C;-6&J9t9jU7Ygr!VfBhrmBb&X0l%GA}CZj`BOmvo~{UAv_lW$M}^ z-6&Jnm~^8|T`!exl&RNt=|*`Q5C`Z+9jR+CkdQKUb)*|*>Y9{pl&R}w(v328O-VP( z)HN;LC{x#rbfZjNv(k++b?uXGl&M$0bfZjN2c#Qyq^^U&4k=UD&q+7R)b;byjWTup zf^?%yT`!kzl&R|#(v328-3ic*GIiYr?36Nf{X2kel&R~L0Np54*Q)@!QAg_fMc`^F zQ`c*x8)fQxt#qSIU9XdFl&S0W(v33pxB1x#QW&<30ZEC*Hq?Z8T46>v7t0h|Mz3#dt(}yu|#$G|zO*v>65%FFSy%(-A9fr6BFUSN(LKt8Nbib=!XLia#G_3jX@3=Fcwp;MSjBbF%r+@KixI-ui4zgvN5G zx7SKUjn$aeYqX`hv%PjAlQ!^G-AT`x!{3@P<>JA&&Ef8uiQkWZ+uZxxLvEWrEo{DV z{FCO!Z`8Z`kAJ}YFEc!I(f4*6^Lw0Ldw#}B@P_H0mtxjmdVa6tq~U6(Gp-n-*x)2H zMnlYqSSfsrS&5Jp?Ze}kLp(2LtcpAH=FKz1R(!pcvU=0=-7oEE2=jUER5H|SXL_7y zE9U7M>#~_-7OxRAg~L|bZY`L{YpmRSuANHQaS*NWl%M7+QG#U77 z#Peq@PtV8vs<_i1YMLK*vWcjb8YFAscObm8G5@_78In&p*$jW4|B}N7hHE=7dc^a7 z5dN#HLqmg|N;xS*-WwcDqfTKKIvnD$aK=eRdK#j3Uo2u9kz|$;x!Ik6ZFFE>n25eJ zcMY2R-hE`DAlCSE*jix^@z0)cttT!_&;+OEzBrV*EsN_`Z97^1CBenZt|U zox1JugUz?L-o0Y!tzB;X){QkEI(hy39b-<#9ICD-&U4eUeBT*H{_2ipj0n;bZqddC zOTyNY1<}QZlQ5ban_C*1ni`s$>+ZY!lwAwVy)Qhsr|+dl-Sqk4>R5P5QgDBKSs9 zxP8EmWHEg(ZVOJ#ckfLK;zGjaC1)&LQWfDyFZ|no&s5)$K-M=fMcWo>{%@~Tfd*UH z(yQfV7@=$;c3IXAS)!yAle+U6&@ft!wrF&N9T%BA-4jc$u@Y9dUAAsFkYN*^JNvwg_u)N0I1IH9QBWo6@;+0_xoGBGP2>Pk7i zAyLS4Ee4kXiC455tJ^x;H?rYW)kO`92{HFJuWk@8yM)n9p2Z{S6Qb(C@*z?4czAN6 zei&MDR%Qvi8wsP&4qeu7bD2vn!dnf!LJ`R(o5nN{tbKAK+jBHI1p~ygB*b)PRAhM~ zCFzGDC%dDF4GBg?lfNUUZ0cNBRf-W08Acf*MX66HmKv02)hFZ<3Z;(Ez13LNwrL}K zsnuOIFTSdKt;SPZ+-eUE8aq{!vbKr>)@{{$Ufd>%VvmE@1BPK`GY*zMVWxf}iekb^ zV9}c=asp(%kAI1sUKeK5-whd$XI)X>%OfW2&Xko%$B^Bt!pP4&`a`;R!F>4GXJIhIP4$KIt~L@=Q_+tYOMVn=|LpJg?BOaq);@ryekjXbgpG zCX`HKH5Zm?=BZpsKiNcMX?COva&Zbaif9(C(1erf4T+RmZGxnRE}_iDqu>(02BCjL zQ+XX;*6QVw5XF}IdFh>zGG~EKvH@W%QA(s-L@YN|l}V(R?S$yuDuUuW2vv%x>TVcz zA{t^xqL@j324VI7#VbKbiw)}(f4}Q%=&eP3GPDRot-M@781Hscu}n{I-v6zJn?S1y zK;dOCVHb>2SQU)yk!!x|XFV?=E7DlLk3v017lufYwI%c^!$hQL6<@J#gqh8is4=GS zbO-^7N-*Q7T2-%zHH>)3C$V^AS+@#^W1V+NR1^?4;;J^))KNpfl0V1jh9O7ss=Gi4 z>$R+pb1WXA)kvU+P#qbcDj*Cct;lxRP&|A{he_-P5~-TeFc^XZUD#eDn~Y*mz)MEC z)o5v6(z0aH>CH>3@;3;(x=?Mb)A3 zZuJ$Et09K)IINh9)*?YaQbd&z!muZz!-sa1gzz%P`MgTD8Z#S`5x0(@(1ngBnid!p z=*kG!nS}|!a4R*XVQFs)gz>DgcHP>G+Bd8#`f(wZ`w4`u*`i!~MC25W?3^R?X=@6f z>&LRxuv`O2CzrU%CfCRFZ{+9~4k&7@0bxLrG3brsAWdRHhzcOr;w&cA9iTyf*3Pg@ z@xSyVMRbrued*ApR?fJDW*7#t#Tx<=viFXu4kUHLoN$nFx-pBuP6a3&pds5f?r;?6 z929z8e}E=sXVZ3pnHYNIuOMD7B@{KaY~Hbcg_)|V)+SQ6VJIV7cgjJNt|am37hh>u zQ3^|}yni9J8nNDFJcg+m4R$tOeh5>QJkW4^EE%!~XozKv=Nf79ocdvyPT1+*F0>vP zlzy?STkE;j=CZB!R%31Z`JL-H53Q;TUPcIIxQ$-kn_fvj9b(%t*9`05hSe{=Kv>BX z6d+PW#w%;N2|{RF(Lu3$o{fR&j5`S_7mWH<0NOQqLbsgosyj*z5iuB0@HP-dq-b?3 zs1A3ij5*N|>|n*M5&gXEB@{j`q#PAtA(b01!3b4HuPFRT86XTf3pdZT_ z5~5|(D~68J8O)!H*y*$*hr{*rvX`)=yr!3RD|**<;o31Qv?1j*j8NF_rmBek&>al=GhaVnXZNLCaj zISqV#LBfht$@EL?5vG#q7hfQ(G%-QHqBo4PO*w`~D`xtxh^1nYp17Skiz^H&U;GWa z%Cy*UJOE>v*i~8d+2!QCAYrJcFO$6FYBlt>vmpTnGm~*EA|_XrRLwy&tT?h4BvR}F z)O_gcWKyw#l6j4RG!%q|aghtlAcU%ClOyp8LA+eXvo39`ksd_Tr?+zI%YVyXv1V2= z9mQ;WOwZ0=y0spE={q*BD1#BY17?b&;0`Zqt!d$p%fzqCD~6ER;K>J5MTsT$y!o{# zsw=)`6kmGll%`rJ%76-7r}*`xNqC@6VJPIUPePrdw?z>Brb-%j@loElLJCsA9;j0a z1988sQ~b)5@&zUXO!blr15bWBP^Xj+Jo$~NQ{>vWT2v`@40`=KMQY%uE(s6RDGY`D z#X4m<#w4+BGqX`No7TC@7t8cn_{;z4e#%VG0?Ltx9;xAhI;C(ySCDG-hrYTof7p}T0=!LmHqc9G9=6TtpAc6`{Aa+g%Acqq7I7Qw86 zxr1|e%x<0Ke$mi0S3Z%KjKcLUEiHhFsV&|9Ak49N0 zfNCmwH(ZpRScX!`qJH>}ga;~mhC=>gMc<}&S*Rif@Rv2O=>2zckV>MB?PROaOg+M% zi8ZM5_a(O=wVpJY#xNHfOZTikCl<}~2B}jD3B}~4(Gl*4-CK9cm$GJKng{ngz%&mL zkU^@^?j9$Nm0Z@K-+JR9{pJ0zv6Qy4y-m3*NThuHTVK@BUD%o68hWfF^$dap@$$#r z=J0WE&Z(-PW_QuH5ffUl6+x^|?3gf`rcE6)Nbt5zktXye2@kYw7z+7|ZJSPv&$vy( zkrM-dS@X6{&6^_oVMYImua{@Kqpb!rZgr-rnj0|=)XSf|dYQ>(m0$TAQ|sFgW^$NNgx=-_oxk)iIWQAF>WtLwbm6y|EFRwJA2k0qk&2P54_sOI(O zaDD=8U)&0?7O|_swu)GGxAa*dCpJabryMNA?semv>L@DrUh_y9VXT6&{5Ri(tzyTF z8tM+V#uAZu7RQLgQjB#uSg$AQ{oG0h{hpM&UayEIm-C>Z?$lq=m`?Ta%ViQr}dSGq3n7sZWSrN;;FuVtW>`*;zaWlZ)8LPaGM}k6IC97$TLR ze9fEGa^XioU&B&DB*rdx14Tioo%JfsF%6Pa(qikda{Jh6g&zwrxlSsI{qe*ysg#YC zbs4cUS;*?*I9kf?;%>mz<`_wsW69-VMhLHJiBvHwmoFAM2t%{R9F=$7{JRcV8v>#Vk-Buei&L&3^iiQV6M&dS-7oV+IR_BK6vb2 z)G;7oHXOw+V%(Xfcp1`Y2}^VgKq$7@20-Y{%I#mnsUYdtHT?6E>A2SdQhcI}OC zeGS8QrUGApNU3PT2olTTY%Ct-E@`p~;MS&|8O8buJA!TgQW%rrieR_gLYd`m0>&`a z55s&Vm8+H9N-9@pfwcPe4cmv<)zjS@)f>A?4x%9m%NAm-#swGhfQf1^G&n6Jn<%WC zHX2?wcF(l1HGtADNGwNVo{gmPL`u>LKl*~(bJcjiFVtyhX!>~8)lolEx-D#-U(39# zTEIxy8Eh<=#{L~D{CL;bFm5NhGd(mt`>xH`C*(E>aog%D(M^S+#$GfcmJ?V;l8zPC zBzaHk7Y^JdARg!5g1%cLwHhnhSGH|hUF~ks*l{9X$mI3PORa|7%DT$DM?$~I%`sx< z6RnPlB9v=0(b~rBqVB;QACgVN#wx}t^<&mc?FhLgm^I)RHLV5@NvZzw5Q@sBB)0X_ zVNSzbv0p$s3PS9OhqbH)YzRtyLa`Tt+mH_R_n?$5Y~SgZhuCu==h=MZ<|JJWtB<}a zpA@5JC|zr2x}n!b9yMc|eU+-f@)n!<(4<*`>eV<_Y=SUBClv!eweSsZriGk=M_ zQ_>;tG|N04b4v9MC6eX{JtdZxFF4_j0-F4XKpN%^Eg@_)g)UW|4;pF}*meAAfuV)l zzIZ3D>gHtc z+c|KMA%l5e-0qA4A+I2@T(NZ%h_GC?qml?it-QzIB+6yGz=Y+pog~bqv1$bV#x?6w z^0|V9VcNom@BP^Mw&d^>yg=Ww1Y=bXj@E$9(D6|)P~ng+ZxacY_40&1cHJO3WdI!k zKi>+sAbEM9(r(c~VtKIE8V=T4!yUEOa7S%5tnvEg{cz;5nj%i?nUA22eIS;#V&H$` z;RCTe`cU426^z`ywT8XXihWVm%REZcNw_a|d!kYaU+-Y9NHWPY2>iAKXFaN4>v;&d z$usr@DX63MEBc5N_gaMu*o1~!?aeyT{l@k-1y)Tjsea3$Vt+nJb50VfZiH7m%KDKK zN%s|#ct7hCMxCx+tITOEfi!fNQrI}T!mC(L#(KSuwH=)uZL5vWjx{)FuYG-}eeH^} zGaJ#<8*rl8av>Nb409*D=9DTBT8)AOUwyNi*AcS_dTSgh-HB{6?iA)XkB<7W+{43O z%U}Balp1ewW*C>I%On_AYke=H`5NoRKI3A-yO=+RJ%jQ=pifw_`yC`5x_!}5tV?VL z3nMvBgYp=Q^$S>R!Px~vgO&8|t~44i=LvB}Rp}X=`UPweA$Ef51v8KM6&DCKPlYHZ z6tSIWY&ELgk=V`A82-Sxyn7-S4y{0xi2d`Un3!RS1RB80UP85rWWG2HN{E539_+1a zCA!7*(7d@oKViFGELYI9P>hP4114koaBKW2sdds<&Z>}*`yN=oEiv8irpaV;W6 zw|&@`*S3_0TLO?SV1Y*38pUpVo@ z5{Hz6ztzaKro3&UvhoOq3bAD$}D#30-S)B^MK(~VX$BIRnITEj+A1VEu zt|U^oFSWjxF?UYPu*3`$zvi}n%Yh22m7|4+t_h#(ds%iKQO0tAb#L$mB&_)a9(I;l z*p%qzI_QVth$jH*PW@F;E61b|*(!=e5w4$X6k$vpb6?`|Q4*H+_yUBXSclJZ|Dwg- zrMkg2Ok#C@eh2iNszG|A+$q3DgD{CRe=$Os;}YQ+oKS9mQV_+X^0G@bl9^Di zQ??V{YP7H2+_7QZ+BNNKtC>v3BL%~v3*grt4wP)l*p<)eP#P^_V-T134nHPkI&IsY)_^!qo6MY7TAJ>nEaOgvA+>fo;T zC^0?gSEC8LpBnO@IiFJ|SRUF9T1R!1cFGDO8ibm$>_g~{X#H6BA@oMHJ|WC3@fhZG zi<2R6z)itPNTNJ!oVVC$E^C1-O4?!$fgn^xby0&!zdV$NAhx7MN-p}RpKK(du!CTk zfjCYvS6k)?zqH1eQM7ujAQXpTdi=tZil?As6}- zdR2YW4@04$&%m-|#G%-642M)M1U=tMFJtm+B$ifv6Qv#R`jH|uEYtK7glv6PUuqW} zgW=W9mG#5W?Vl7@dZB_+QHztCbJg^KD#OUzzI^Kdq(iOZ%M;UToJfqOiK{1iGaGq*Geow)W9z=xfQ=&3kSv^EkZRI;p7G)!MZW z1xwiF%w8fP1_{I5h_qlR`lmm;&oC;^p3|Q=QED15u(czWHEpn^gauVXkT9%hYY#$L z(KH^UUe0xX^CJwNVAKpmCK4aQd@u&_vJauhvZ2XH4c%OZVHq53R?@}Q-#Q>iShVy} z?wk`OQly6dQyPQh6iMiB$<_?QI!_o%y9r%9*C@P<0a0w}gF$QVzG`D988Odl6ok3d z;=d$EUcClYmhp{zxgj218Iod0ESt#vrR`ybly9obZ(&l`o8z zK!lZy_kqGNXS^>|PJ9ZKY;uG?qX9v@EDX=(X2J$3u`61#L8xiR9>J0wBvQmd817EF zr45`QVOUesIFm+2OLmZ~Cu+Pb7u2+Zwi<2Gs0tT%G(dey%X7^N{6fN-j|FsDy|Hp*t*Gc%x2@XHwsuu}fg)u; zP{WF=&4QHJSR0mMV;x?1XHxSm>IzcY#42sm8>Ga>4vqfPI;bT!nC;lGv6_j3Zm{w< zOonBrp9Jx8#d-Iw#u~>-+bZp?+`PfI;$`F59j#E2B6f5ZMjTdKa$W(GO(&L%R^TZ3 zie4@y?90zy3gTrem9omrAqdtauDCsF5Dg<1mKcO0Hs z1vCs=_XQz=5-T94x?6}I*aqG6X6QD>}Tfnuh|DcraT8~&uM?&_D5VDfLJ z<-tKTbbIvqh*j|+?m?1`m=lB}ZwLK2vE^f2Ct9dQrr!y{AkwRLRv*Mdm82!DRzcf` z(X4j`ugBB+gdg|D(z2sJ4qY^-_TA17Jw&U$m`8;?F6esj|g zhrao5;TvwgxVL}$Omh!Q&EuXhf4;C~LjB|u&F@`(&MU7S`HP{i{rH9N zcYN46^zAt(EZus{`9rt=>b>nli<^den*Vg$gkO&{V^7t;<^1!1n(M!6&3NIG7l-ET zHr_b=)iLHf$(LsDdGzb%>$d&g6@Na=<*%P={_KJeZvE*sCz}sV{>j?Mj-Ebr=OZ0E z|8n}3L-*cv++lD0(_KSf-V=Ff#@Z=n-A&DnegE==8NJb1mH76L%!6;~JnDhp8s_kh z=TErdsafXUn-|@4<+5$&>%ZLj=+xi;(G8zH8_Z{KnLOs9_ue-jIP=x;?F*k7`iI?h zo$U{XhVFUrNAvc6v0>=i+mC5q`lq{0>;9>yp19^UbKO^-+|YQ^bLQ~3CQP|_@NILr zduHPI^!Ilh_uBo}H4SBc^y5VjeferLJmv2Dx11j~hcCQz;t|h$)*Sx+1%G(?rTfg` zzMs!HXx~cnouzHx|J5yq`9^YPU-Nl)xcdLuH2?FfOFww`p%ajxvPHXRn1>HV(8u} zgP)()G%&QYVd%1dZ*|OluRr&h=MTBt9G-aW=gu9!#~eO)*G>QNwX@CPI}>gFJ>M~h z?`k>ql)vmU_np!+>uXcbGXG#NzhutKPfGsT=F=Aq)XzBa*`XUhcVpw08#fKzv8{XX zu^;@}-1q+yGd?)s1aseO<_A-5{;Rp~!+(AH^uF4v3tg+&EYz` z^UPg?=Dv3ySr@6iX__fB))JDsop=9LS~;VFoaho_mtmu$TL#rTQl@O}6E z8{reqbP6cn*6X&(OjQfkb4qf&g==dSyF+vfHfG{w_ebA;DV9?P4l$(h}+nVm0nUe0VwlBjBF|J0@ zpa@1+W1ihjVqE|I{gb%a-zeTM(d@c0YxIATnD`ip3t8d?$HeO+D*yYQs?%NFUER~C zrrqd5J@Za|eY*Os@7&M%&Ta9Mr9(rZ&=BBY;Amh}+)PH2M#6NQL!+}+!i;3HW(r@r z*T`fp5s6s|e&p{*^K;UUnHlGS>v0=JH#2VXp+4YX=X0bZzFs`UcOEK#7s;4e_qW5P zd&Y|4y+!VyaXG9cX_^ENxes%BA}KSCcZx5_GluRCPlk?%l(^0CahvJmHp_K8M7}2} z=t5)YUT`B_sT=7^-AE_ggnkU8NRN?*8^c6|o0aUe5wtD*%=m~~NyJC!9Dwf}2^?ai ztVoZU&RBL5A44O6AuU6Gx()Y{72J>OjN3-mN_It3ww26AHrVMH!e=A78D8T3xR36% z;s|@^3(t4_{>X&UYb6-pNFxy_*Ol#tbN=@lhR3vS6b!QO>$#&CBPZQrVt~B6ak^VMx+wPC310k=2AdGT8>^u(l(Pl^C#rVu; z88-5wE(EU8G5i~a=Tm7r#q=ScWf)T)?&JfZ=diXVaB+Sse@~B(PG-v9N1f!wXAgHi zjE>_z3eS7r$7ct6pZxtLcy@HA{C!Lh^76iK3miw`dGGu9Y_0G6dpvtk)J7`l74!^~ zVM22LLHFU8IpXLa;_f`l9O;B#g=arA72h-58N5s%Ob0TKq;3aCmRj-nS|grw5{oRS z@F<_BD!e|+_cBbqTr&J?8u{eoCy;Lp z%h(7DoP@#RxHLZCk)aFWj_X7|KPqY`lV&u_v`r%BlhJ^D_h?b}WcyN15Q}FHI%iGG z5>Y~lv_6t$Ij(W9;olhXeDV8b;PD~ILv~RJg(fnsjuOvjL}5u?S;xqWznkiOn0z7b zqdetwwP&~RS(lduE}vytAuliQy>OJg13gQ5Vr`BCx?^z3PT*43B6 zO5Q^Od3kwRo=Dz-p8Z=s>!gQ#_S(a0=yXBBJOL;`%^B%^GEa;@l2kx z$?RZa$3kQaFFVf^5ldL{l*4_>@`A>H_1mX+S`yuXp(^ZAgzz4h7b`NuAm zci~9)e{h>Lu^no!>jI9(_yoE7hm;{iW|az%K$`FO8SdcsLOLOleEY((8frQ&akp z`BvU#`6KV8?w_>JW#ywRC+l^W<=Dq{f3BqbuJ>nI?tWZ%S+9ItcUez-Tz6T%eq481 zuYFv1Ss#2{cUg{pOm|tH?63C@JDatI$!-4(0bwKBKfNw|4LjL>?E6qCZgyt(=Kwg6 z|6wEEj}yRw{J($a|NS`WAMm;p0<;NATOe(cv{iDfgJTr5bJDg?8@m|i#GQ6#+JtHA zJshBImbOi4ujF{|F~G3^$IgxiJ_notd>%Lv7z>O8G+;dN1z-Yj67WUfWMCpN378C= z0!#s>0u8`4U^>tU&@@Z?GwsT=fZ4ztU@kBZXa?p3rvkK_hk*rv4lD#(fJMM!U!c3>H>99RLI4V(k41Xcm7fi=Kd;9THKz?XsZfOWuEfb)S1fCz9Q zU;rIJ6o>&P&#07HRcz;IU{f%`$O z8|9I}DA$ehXy9Pijq)MD7}t&Rp}=QcH_C?rhr4c+WtyWKWtsM5I+SVfD11j*rbVVp z>PTH>x};29nLg=8nYuEq(v328WxAysW$MZ_OgGBZmFbyol&O~n(2X+n8V_i$OufDU z(2X+nngGy^GV{$z0Nt2(sMi;PlU*>$5#y-so6C{wQ~t{Y_y zmui8- zl&R|+fNqqj7xOdSC{r)yZMspWUd;gAC{r)ydAd=iUZ(a`4@8)fRX9H1Lz>a_x(8)fQsHb6JZ)ax98 zZj`ClN`P*Zsn;riZj`C(YJhIkk-Dw{*19tFI@fihOufG3x>2THUv}LnQ?K(}H_Fs& zo$E%KdVR%pqfEWdcikvcuM1o^%G4|3x>2UC7Xoynj?~ovI$W8$MqM|`)HUY1QKqh@ z>qeQncDinqscV<(Mwz;HyKa=JtL3^;rmh#cZj`Clde@Eeg+Lsj8+D|v2_Wgp)YW#~ zC{x#z>qeQnUhKM2rmkt%jWTu3xNelGYu0t6OkH!X8)fR+b)!sOFLm80Q`f(7-6&Jn%K*AjrmmL*m$@=^{W?H5 z%GC7=fNqqj>y-fAs3UdV1YG6H)b(oDjWTuphU-R|x^8yeC{x#KTsO+p>sr^1@@2pl zfNqqj*L48hC{wSk0Np54uWbO`C{x$#0lEzVh62NY;lK#sAYddg3K$I>3>*TC0S*N| z0~`h%4jch|7B~_(3OE`#1~?Wt4mck89B=~gdEi7~EHDnxfbqZ=fC<1!z!!m&fr-E* zU@~wDFa?+jGyv0p=|CgU1k3E-~u25 zTnHFI2M`5ffC+R0T|hTr0T%)5fjE!=l7J1Q0GYmJI%e9HX_V=bX>kZJ6c`2!6vuqF zRxnL4uEzt68-_W~!C#sEy4UjUevm_`-@j8n!HI0;}HX1ZirWBR!eU_3MKt^}?JHUU=w zR|DSwHUrlH*8*FB>wvAmHh|AlAL`D0$GpV+!8Ffw%(U47FkUtSS7o9`+(<*(f3G1E ze6G-ref##kIKN$g_P+1TyrF-u{=hxjjtgEnM*oM$7WIYh+^T0+F4}kb#_jsT^Vf{t zKIgX!_P+Y9ok#rT(gnAV+qh+dwm5AXSu>_}^l8ghtXS2mO$fD4{$}e#ll0va8vpCK z$LH$g-*Ln7`ZEu9Jao+iZ|V2$n)k@#*X_`6nf=tJ<{!+{;|p#Ye%gsw=}ouaKIKs# z1t)~Y{yh8L4!yr+eyjGQpX#q|K6TfKZJYJow?2LAxHo<;_+KCMj{eM|#_{(pc~ie< z^Rmua_pQ-yZ0l*g`DqYpi|s_hNXE2wOzqWL(p|ZPnapN1d=7*IY zOn1_J;ic1i%(xx3vVGx(CJld$+S0X)7H6hoo>ko55NVp;Vds)DBi%=4=Q|S0?;8u> zixDFC*LE(;pBKL5@PX#o&`Tb{`$70xu?`IlW;$)BHTT|NV@h=zGt%J@w>q+RI@;Y3 zGkdJ4sYO#cM(A2+F1FT&`C;_(hm6YpefyqTcIU%-|Gp1KTz&tsxIgmBOZU#!`#*TF z@y1nq^!^urch4`zJ)!rHyk+DY?|)l=b=dr0b^YX<`X5jr3?F*9e%I>6Kfg8N3NeRj z$Wlazi8+U_U--gOy1ww^iT-*_uo6$YSjBb`j_qVC$H7} zf78A#dP7p*b5r`v(NmfQ|FC&Z=5Q6CuNAH?E2~A3KyiyT&TQ^5nrFu5X?9YZ(KusP zLsL`33>ItUSG(1*%*=GluqaT@o;7dgoLRFv<}^m5vuDmTW_8S-6`R>KqjSc*c{68s z#F}R{HO`$ggOym(b$09ORnc-fO`ADw#*Arfe<)t7+FQ@AE8*f?I*pvGt;RBmf`1W| zOVgIN-0sn4%+Q+V%%9mbziF-rzJU~O?KPu0%twryf)kVI6DdJlOgN)?{_N(O2nTxM zU;le%pSC2*5e;*`O;HB^^_42pU>%!|^}IAKl1o|_=gf#9ie52GypRDkEv&V~Vk^zK z$mE%BE49o>8eL|^#)5_no6M%|IOei;WxPzT9M;;FuWe~}moW_N7frL0)UC(#A)`}R zo0PO8F|*Ui#j}%ZBeb%X5s!4H?L7+l=JwMF6;VXeJob?Yj&#A>>zVJRUd^A^+% z;$??0mMyS&By~d6L0FR{sxS{vUQ`c5BhFeeX?7uD^q7&0H<(;IlaKJQrdB8-+2k^q zSAqpqc65E7Ca++CSau09KN>Y+fk;Z~VaVC@C}JamQPLFd$SG@9uc#@-h=(+-0+FOt zClqTJDzmB+a!rO*$LAi_PH$PWirwDYuDTarwY^s1sdY}ZhX#$Au1i^4Ljmh_6Fe_& z5k;}b!RrA{GjdrQYpF2xKN&+YVJESY&J#HSvfd}Z#LlefU|+%s8INZjQQgY}ChXN| zBbl*~-MwL7QAVV6*l83E$wR4@8I&T>f$ z9UxI1qfo4wwUjVrq2q<#R1hxV4L2R4UuGoH`zXKE3s@#>_9mhccFu}ZHTcyDqupk7 zeZSz9K?0Ac9V%SJ~gQlKe>C%kMn%&s{ZhVm7C%4uvBm|Q8a zhG`RR&b&tpyh6jqc_krL`J<-AEEKNUNGgTpVOaNBpmHSjWD~P8>_`>m;xvpNu^d{V zNjsg0h?H7uf~1BHp__{b!R03G3Jp!^b$D5+mkSNED7NI!%kPYoDKk})4G67dIgxY` zvD{QsCUL!NCPn8~5|rLSSUHXOe4}Y*G8SP+qLj(~48q#|ix+^9rXSWR{(e{2&|8c6 zWM~nFN_n}6Fy3XSt!#Iq;Qz4ZBv7B=@^#WQFJULFTUcg{?2&K2t7kngAuCd=&_|)3 zg9}5X$odlclwl%Ll!`B_3t?t*X{*H)o{1nJQ3+;kS*xlQv6>c-_#_r@EUQ)laV#7! zi;5z`MqIv0#Ltl$`jz~7Mkfq8ELhtGLYTwd`Z&+x5yDy$J%rlG_*4;LBxOX`!-nGF zLpn@hi;-x}jGD#}?Cr#!9l2BtqYPd$%3*ERjOJO*bLP%yuF2mZ?CeDORk6bt);6SS zR!?|2DPkD`#lXbk<`i0VDLda+L8K_eF~bmz>nuhKaw*)+RK8G)FVYy84--5B079% z2T2GoW1P>cWLTTnkcv8W1cgp?G|{xcs6b~{xK1oi0Gd;&Ne#<;Qy`4zwB;+7pVzu_ zMahqgshm$Bbj%i&+9M*TC}ih6p-)>=_*^}fT@5QWa8z=MlWg*RJpV?Hdf|Yg#^@CW zBsT`VaU7&cEC^8nURNKWNt?NhS!5=LUWF@&m&*x7P3<=C zSiizdRa0vdDO=N|5v?n2qe)kmc+`up46G={C04<|kiwdkNX0G8@n|q}@ybJ(vgCn= z>#bD8?4===HJ)RnDR8QXVJ2y25}jy0Fev?ES+&-4tj!f$?O|$$5}aAI3c7rcxR z%5rbMf;YXAdOE~DW{w%wzYVKie1WiTa!aubBmG-7>XJ3bQw(^+R$Q$85g zs{piX3WQEM;Z=8#8X{sapx|vFibzrFR!|*oduiFR2<%{`tr7LS>?IUFE~Xq5VKJ2x zFTn_9N3SIONEsjuIph?P`6ZuRq@W(lSrVdUlMq8knJgycMa@jcc89~&^Rkz)th}a| zRV#YOcH!7D474HLX&8|Xvx~-FbuY7AO<*2~Wx#r0-hc>3h_Tkls%0xsY&#}<86zT= zReJ&Gjdfr;q=%zORMqfPFr+T#QPyQJ-KoQB8B*uKAK&W?7z+(5SAaFlSyD~db)K_S zS@(e7Xxh4I`Khb*h#My2s#D3tM6!}7$!p-_3ldhHN~T_74=|NXz4!uQwTTJp6}_fa zY|1e_!k99=#7bMy?zov<#3c*WFa8EyWm;@F9)Ph-Y}G9K?C#{eAYmxyL6f}f3TtZn zXgcX=YAvV z6n7C_J*t!tgI>K(aW(K$mxKrE6ox|KVx6)WW0F`1nq4KDO)H#rkQMqY{N;alKV_n4 zCFa0GkJRu$ol?A@D@Zl^$?vD|keUdF@h~wylF4;q{vhMty@Hqs>fZ4op|c9w#ON7Bw8qJ9Hm`e6>QiBZ zb=SSur4se42M6gUDtf1jU09Pp7-g9NYN_a*aFKT6O1lHVcO*Pe(K8eZ7c2S}xotxY zDS*GMdqwZRHH52V7)@|-oLddr@e%$^tU+~uUv>*p>$xUV3v;otbkFFqtyqCKNS#tl zC?+orj&MKh-a1phq%|AUJhd$*fC)+O`8xi zNbt5zi6*kvJJ7Z%E_c|rS&i`-r%5<)Z1dN3Z`;(pDY73{^q=~Ad7?Agsxjl%W~!>Y z5#vC;{OPNgnOp`gw&WB0qg4dE4CZ$j98`tu2I2s5&QUwGsyW-DPlBDq!N^`1(RAn{3xhvSWbw<*y(JbCP8L#wE9u8nO2<*Jk=G+*U7byo4+tJa#YY7?3d65yLKG+?l0x8PZ@0%XADtD7MYSPQAHA z2W&y5%k0!^JtLm#HX>;oL%`B@?Tv4B4Li(i6}|wGQq_bJB$hjJRy@XC(%dS5Tbp`j z6ssrfD7N`aV@!rCf}L^;WtOuE7{gRO3=5T1zE*N7seGLU(%RcMY#(A*PiJpbZ|q7r zh=wGrScrwSFMXLOR@8c-!D%4b#9-Yt(eN^{d!~V{0i=FGVmW4cHj*k3Nl7LA=nHPo zRpEl^PNA*bQGO!naJ@c|`0V82&v9VwV`*+Cj<6T|DxS8zAcGL9iyEb2) zklQ50O{23+HyMTsd(ntkPGT8J#ww{v3Z7Ok9JotBJkGrZeYZvmYfD;}wybHdb+>5j zI8i8M3VIc!u;y-MU1Q!OpTGk>q1f@Em*o(kvNJlnw zqm(Uf->H{}*mEK8*+S&zB~=Y;kG>k86r*M+UF&ALq1Of;HDjCobXkEFEH=}jNvYx_ zJTPj;P$*oma5{l!#)?9+H0amIXTIl-e6gB+V0gN-Qs5aKep6G=&d= zG%OfeBG_mOU8({fG*l|EL;Puxp@rMNcqgu^=4BFAZGY9c9kGn$5DB?`euYXjNO?Fw zgDyy*jDZc`H(=-6vcpsG0(Hw0j8)w@S_3vi z+eg7bg+r#YO(a;>D-inFb%W%TUUUTfd@J07AcwK ziMmSodIxhwQYoH6;I|z(>rwSu&qK&fp0OuLQ5~&b(MRpL*D74ZCNxxPZ-zwo8{69y zSv9?+>Me(={rMoxIhRm&BfQ#CR*#furl*v|`&peZW_Kox3a7CI($HB-VdCTpuVQ%_ z>-E}}x23t!GDCmoKR}vk^VLUOSen6oNs*Fn>&JUa2A>td*S}>zn1I zBW4jK>KrLu$y_RK7w0#Rj_R@8%~NA5U+VpoI&X2NX%}TGBp63)buXj&Y9+AGxR~%R z=Fefzph6I+6IShh2T6xcUo>KMip^kQB*$q`9%He30gEj-J7H)rQr_K_2IJ)dAOh*Clk+Xcq3R_l($PHx8V2gc={6S;6`1)@akpC7}- z3_~Q)0ABVI%1tB-#aU2740Ls4Z(SqVC8mcK%mwNR+wpSwsR4OktLZ4ius~SiYc)C= zbsY^wT*vM5&546}+3tc?g=i?`5=!cXwAvJN6n#=JVDl#}bYoVVoh~)31<KbBas1yn=e9Y~XYyk-B}U)xC_lb7F=iW}x^rx7Aw?R8X!Q zEk1Nj_*~t~Zs!qYEcaLU246tJx=-L?XPJdfnQo4QdKeCP0-);DUm3OTm=q#gMv*AO z)su}Rw8Sy@WgZ_SVR?@)Kp2X3_&oP7R_a}<8(hN_R_7OXK+mfhq&Lc)0!%arQ#kV% zBZPS_5uU*b-R)0`qIghVb_h%KV;HJ;z#T6;3lYWG6s+)JAlkrHw4$%eh zYYzuXHts<#vaOE&^D#rH$HIXDZo=ltYgOZ+=u79&L-e8YgeB#pdf`y2p{QC!z3OVH zTEKGtVcOo{-yjyrMydCRQxq}rJOitPv)-f3^q^jiCe01hkO$5AoHD`k&}>jTs-wJ9 zRus`7RE%XGLT^N?$FdKhH=@-EVP=V2nA0szhQI+gMJFMN^00B*JZ(lr3uIBUW^Ysy z%A&fY!K7Xux`rUOq(w?D`KO+2TtZ<7!7>AJoMOJbrk7Q7N}iBsd6uY$kAXGJM|KHk zV8YU(U-AZyluR^jnm(p%b;1-|?WJozq<##;StTj0`bStrXzuIA;XoxR+T~P_<%$Lt zhfzIJBq7=iXet%iUr8B&u(%nAnS=RuSTMp&)WZ4?tJ899BaTN4|J5}V(|7WR(3DM( z2|!r6K5@LwW7I{0U{-DOmpocdF6x-7Xl}66>ovCfG$Yr`W2l`rk=p=9 zi`=cnaFhrveXw80a|xfqi?OV1W+5RL`V@Oreo_xZp`p*fvdf4=vEvvHsa^Bl{*&JKohJMQB)|=_Lr+`l`LuE;$CntD7UMhoRFyDX#P)MWvz=CpYJ+>j71o zRD)NyJD78+DDnyQ;jYgxIlLd;MpnkX_I-tr41CN_6s zLfLsXA|a~hl>Y&TE47Mg27ck?=f-fVYK09FhMpNWA|8tVDP?4+%pZFQ%ct-RLPHzH zM8?2*szv>kAR1y@btXkCnX}91cmyFV7)wzM3NxZ76ax`fTREy;jdJBe6~l9oNb&Z! zJ)U*MK!mP2tq_);xf%5#lznH|UIK-otD&zYd(ec%CS9lHpk|OPm?RxbwkP};ErSU| zU(@(tyj-H2Og2l~mbbL~6@9*L{FSuAmNZ8k{=s-T-^cSt%wPz8ZS8{zLtk6_pfnUm ztd-c>2cw~{C0jM`IkC*+@bc@VVq#Zo$37G+VOKJHiG&y=4D%z>f}!M}`s_YUt2%p5 zed0v9X}rkRj#yT-!Il#iRS7}Du&S*+2w_#zc#wKI-}xeEia{9igrRFU zp^N7lgqJZOiY4qfx<9vyf0Qxd*y#Qp7v zg@kn<3+OZwR;964RP^mFr>|^TetK(>A{9SS!>X&zf|S@;8JnC-TUH*Ug)KWU?@_T?m){9A2#a1afh9(^HVWqgQxkYpp~1mVcrK0i)u z`50G;7HW~*U`JpONywem`>;?YWw=(WpzXt0&bxxw<7sumPeEg8;fdeowN>A-Z{NO$ z-`=kO{Hqs?Oiceszxy|L&>PzY z|BLh6^=I$<&deM7_v#PaqwTohm1FdOcx+K$=+3QrcIBddmv7vzFFb$E=*eZXK#`S#$GY$)gX_SAOu>tHKwz>7fyATi#E#gnu0x z`->yTr}h55FFe`4^Gdz{xpff5ADoJ=6TCzGvERR?WZvdHqjK$3JoL!J7sD z+oMP7|M8D2C*Cx4ss7_DdXK*C=R@?bAF|@H-(A05pFj4JIX7;4VZo}=U;E;tcRZ%| z@7tc*cKz$%|I`0@;iRwX{W~99Km5JF*Za+%EPL^Pzo+lH`sQ@Q53bVxbn~k{CtNXJ z@c(hg&H7W@?%LP+t!Dj>xo7;}x&QhjJ$2(r-}&v`zh3af*vIcXbnpG({V=j_*^{_G zIqCJK8}$AUpE@h~lBW0XdF!cnGvoFCt#|y>&ptX@-_w8nhn>H;T7UWTM}|H(_5uA5 zsCb9HbCdq$t$Szu-2;pD?~d6w?D?Nf)=%2C<@M{%dlr2A-d?oxPTW7bbNn;^i2G}2 zH2v#p+zg4j8gYgG z2K+PRF#R!l9>s2 z6Cse0Ai^Ue>Y^*^FUbB6KHx693@XY+)LnI9pIuRL*+g#W+-~P`1obOy}(c+Hd>gwu70ONrV0b^rkB9t)VrlYPKm$BkzD4j8r z_@jFrpUB2T5i8D*{Qfw8PS_DM?L2TVZeyu4VBBi+RV7$ z9VPW?D}vuG(4XLPSP9b15}7#ZA5JwKQldIRs!i!cQwG@JRX=} zB(2bPGnKaN1U}Y{21c}v_||^hk1wM?EgG|pjFspLC2cE_3H8{i2;yf4xfx&L_i-N= zwPJ{S=MSF0@$XaPMz0lTdLxg7U|d(G8|vKmHOLb|KDPy##>ixutdbjI-RO*!iSY+< zG4Gs_v6G>c)zzIrXcF6ujIk|crMnYGqES4>G}D0bA|Lj2+wPZX3n8yD5XL$m{!PPu zoY|Q-0H66R<49h#iNG~3hX2Om`DDsYGM~t28P}9YIpsmvJ96n_Xq@lL@3Ux(OQcJF zk2cAR&rWtejLYCY7SDTskIxSEd-D6c@a(vB>F+UL$jkeC_d_`r&wGE5&sO_;e}!kq zgl*)OUO~?|87U;^KiEF%Hb)%yb=;k2Su&mYEA#9LEC`HuMlbUT^MgzyY1{ZvhZT#h zH)2^Q)9@MoJ}<~pJc+-{IQ4SL_^*?~rU*;eP9)55hIyMrEGOdt`P<_}9hB)yI#Dd1 z8FTfzw#6-Y2p9N{zt<5z@_XDTisuV|Uq+t${D?Q5=g;4T`&jXOT2z{}m2Hi@_`Mm< zhYMMejP=ylm7cwy&$_&8C*{d53y- zF`spL8Li}<1jx(F%QTg|Lp}R2pLOy>E`Cptq_~r}$@x6}Mcn1HG9FHJ{wDtSKKuVX z&&se(_J8)G3p~$Cd#99nb|dtYSg=Irz-{=TW4=7e{f^9+RhIpWcH?_fwi~f@j&qjT z$;^(6yo~Fy{NP@w7e+EJaQz!?ck(mZ;84cs#Akko^^mj&qKHSv53U*fJ+yIAJCriR zs1;@1H5K}k`Gk9c=c)T0dB$GcX$LRfy^uQoF6&C~-@MGJ-X`*(SNoqyeYsxI$uxX;V`o8s%6b$S1l`+a%;P2--=|N3ud>hk^{ zE}y&)I+p43{ky*OQp)8SbBGpBWwguT%dNc2 z`bXZ2_3yXOCH14MCu?<=_1JrLf32wguJvbG@4i=e*{-}-ciB$7S9e*zzE^kIuDw@x z*&e)CcUh0VM|WAD9If|GJCm`6>+R@_0pTk;I)g4k4S(5D9QwMtm>JC+%@J^{{KHp# z6lZ{A<^Sj||3`7wKNfT+2Iv!%zCijU>8s>i2j?j0=cI3+K6WwRi97ww^a<0~I~kyF zmcC8tujIV%DZr@!ecFEkOao2_&H&B?J`8*W(15dmvw?cx9N=8wJm7qQ{?rSB>A*$6 z44?sM1ZDzF09~{6Khv+=0?YyC0`q|Rzyjc6;1b|cpcPmM=)h$_8*n+W2v`iX10BE; z;0jO5tAMM4)xa8HEwBz)4{QMFpS}jT7T5$_2W$qe2SUIWzyLad zFc1MuAPRH=-GBvb1-1b(fW7quU<2&D-2kM3G{B}T3v35^fL?$zXFGr!ft!Gvfm?uE zf!l!FfsX<^fnC7IfIEOYf!)Aez}>(efPUwDfPKJz;9g(^a2zla80E^NaUbLAC?5}u zb#;`-0pndAeIeWnQI@GHqqPrH(RfWge!EGHqpkrj9c0(g5lx)2_1s&6R1_*#LEvX;(c! z9c7lAa{%gCc4*hRzSOk3vy)KR8g zEYH+Yrd=%C)KR8g3jpdU(=L{I>L}B$O91L9)7DD?>S!bFY6TX$GVRh`9c9{e89*In z+SLYJ=E}6|a)3I@v}+MS9c9|J7@&?a?P>?8qfEOx0O}~yt|b6p zTf1EyW!h@FI?A+ltE;0-ySBMH%3FXKKpkzQt#KgX%CyyXb(Cpq($!I>tv9$j%Ct4* z>L}CJw5y{`TQjbXGHuPeI?A+lyQ`y2yLwz5W!l>7>S!Zv?E`kWGHt!l)lsIcH@P~> zwDo3JN13+X;_4{V)>~a2W!ichKpkb;dOL8NE7R7G0@P8atvdngDAU$m0ClvHwtft_ z!L}B$eE@ZoY1e*$ zI?A;5UVyq0z;VDxU=%PK7y}#+j0MI4f z4YUArfVsdtU_P(_xEQzuxD;pw76LkO8PEn?4lDu|1MNTuumrdQSPEPTTm>uxmIEt* zmB1?CYG5_623QNM1J(l@fQ`U4z_q|8;5uM4a6J$Lwg3ju3504~nKwHDrppfCj&#_F87W9d?=_;{=c@Zf-KZ@u9=c2a-n3C0zT3T5 z|Llfq*PYwCsQg#5&+PSGNslT=0&id$--|4@o8}kk8xv%Ii$9{5p@|Iim zPj7xTeX!}<{rg93y7}_G&HcOH96R;nix2c0kMvyfjE{l!b&Zd`_Vh-5aN#r0On&GG z`oN_2`}Q9HNBynHPab))emwX`J^b$VNA#D>>mOfmWS)M1;?ukCpEkFD--N&Xr`3x= zs4cSNaU&7YmSKsn)|TqZ#?3?~t>I5~BSz|j)32Gj^xa$Z!7HZsK5_O8ec;?v4}IeC zZvCxCpSbDX!z=WkA9?4osrS|EFSb3t?(nuZwVB;^+?<&)61-u#=T@xxOV5nkb{bkU zopHnv#RfZ>(Hbl*Y^3nfG7=#pvK^0OJ#nL@Es5EUjg5Mz5nE-XjCgvc^G7oh!rERl zl?=trOt&3rEn2gyt;}YUS^T6}LELGi&DQ+-UJwoxKi{$bDl?TZW9gYr8OR$kbGsR{ z!&auRwPBWqe@$A)`pXxkXJXw|%W}%i1a;j5 z%W&r@=d{e9J-4N$b8b^OJZJWNqos3BOJw$}=4kW$`LpMAMi#WpYMM8G1II);Mo)pA|gv|>sp0l7T!l8cf&;NJUhf5QvKQyfQHbp`C z^BYxQ!6tScYk6r}D4Vcu$eJNTRJ~%Ac)kE?TC3I;iL5qbqL8P%t>kheVRV^gI|~{L zY$B7gV_3`DmG&~Za;vs<#rn2o?ly*@!=hWtstG%R9d(|>2~hOj|21}cWhciHPRw`$>xk+>9x`LEO&N)_h2rjw`?4|;rPEHK zYDk3Ab`14l)UaY+Gg~zd@~gi<7!I3B!H6A?Xr+2F_HnjNS{ML{<`|V?)vU#YNecrn zjHZHciD0<-5aTibc%A6)B7qW zjAd+@83V+j(=HpG=}?{~AD;-a*)XT-Y*?3T=#x%oE6?Ogfh|m#=yT=*n&%Z3Hq9@J zsq!B+En=Z^&4iLkY!Ab}&peeQsb`yrmF7UIpcJRz^oV593r*Omcu3^bYBMA)bO_y2 zJPa;3W0&b@%Ah02N~2s@m_fBAzg~K0qFgjvCEI||N|X{wjY#ELRTUC9$Yw$eZY4qS z9falch|ga%%}hi>97q&1xt~E;eR%N$Af&5@ZHj-`)h+b4B0dFL#Gz7IE+C9`*(od2 z9nXiqRdX_^PjvaJG|fvGg*OY^j8Qyt-FNk(=OtuAYURf$v~zfIh#Xm4LZ3QJB#Kh? zWpyFWOm1zpn8VW{L?jx)j4fMLwJKKAVj-W*;!S1MCLo55<0VN^K-h%KH;ecwX`x@u zpJR05kkf+IT_A)z+-;9@EFPg%OJIah9T}f0APgmq@HY5RJbcK9NgOp2u9{KP7=yi0 zoZXR4Mlj3ZC8OM`wKOkiSul5A^Mb0v4Z>&?^;g*eU#r%WtlB&gwo-fgg<(HOCSqNfM-w4MOJaXf_e{;bV=hSUI?azUGON zqL9Q+#*Sg*eN1G+nx(Q&%`fvcgKRb^H39iThXDqrh`P*zfr?rKAc`JZVGPN3pi;DB zSvnn%jiOPf^V->m9ty3jx_&^m!RaAgn7Q&xVv#7-lkry_Lf>k^iAMGM&_?hgmeFM= zc(Mapdf|7GZ770UeFNoKh)F%pP3DrdNKj7{(PV@$kBa2*p&ce6f{b}SuaT|V`3=di z(?(E;VxWnx1!e`J8KFJDFau~#qb4mZ9Zi8Smep3QTybst>Xk)bE~IikfzWYVl}~AU+Re>2FRi9>Cjdq=UhTJ3=`Sn7XlJ;^p3R?B(*!af+1sfVOfHi z3Q#$~LiTN(=_oE-C=9y#1Wn4!rp*F3G3?4;L4sULC|YW_d&l+_ZmOz!o5O5m_38_Rm0Upq5=9ievYwkDgr*Vc6UXtHn3&EutD17rsNMviUy~Itv8!?X|y zg9!z12T>%7(y)T&@c2v1j)dR`EAEY`mt`-Z2yr3hum}sOoOB6BC>>sARL+nPJ)5|gI!b4-ATMmD)3!Suu3nbCgeCPggRI)nJH89Yk71w>=`O`npU(AG$vA z%DFH9SAL5vvrOp-mhWSEcK%Xr_4rNSxp_$$jL?}dlN<$i1X*d548L3^eH~sgg~Sd| zKAI{@tg#zs)}pGe_%p-!qqj|&RSQEIQGweOzmYTvkF_a`h5YqFXj9bA9AemHP2=ol z%7<1+K`Pi|ZAxJz9+hp1U!79E!eoTWQF3AAxu1@;Ddi*2{flT*+}&`sXj1AJ_3CYk zYk{A+Bs|upFc$I`+muC^lf*{Q%o@>cTIuY2EHh@|H~*){Dd&53UJgC=NDGg(DTN!l zf;6M=|8WXmQWL^79u~%j(%C514>IlDD~OAr<^vxRI=i54Y|Ddh7v(Is0PKI`z=tC# zXD_x)hk`p+5nRwaqi@EJ3tKO6{?IUMhWkWb(wZ)Gi+RmQQXdE(th>*>CXJ|HJ2*_8 zXy~0Gc76~3aExUJsHUNJ;zjz2%bf;*(2?+1L(f>qUu@{xn!<_ z-fS%M;CTmF<{=_7NHf~iZKtu5%jomlZyaR2d=z$;(k9N!DR%`)l=pw{ixxT?I}_YP zkA0+`Nsu5xe!u%1-tXPHAzBFaKa0MNSkQu_2(0bm#Dw8=ZR%J+g7jMF6?I@S5jn)hvL-W53t8~P7?yL`Sg+p4kPR_Cg!xfA19yZpgxmziCL zuD0Y8N26B+rwry!7#voE>_*}ctuhzzcz@DyI(RiQG2|UBiWpsUcb)g#!(1!Xs%4Ws zRw5$5Fw}jBW?p>_=Lf*|#iIagk-9Q&t4L+%NT0>-!luZol#PwpaVNcLj-+z#HBXcw z<|>%VfA&MzDh|wOq3UF-l?cbOcrQ6T#n_jF{d%I^&+TMTA4xg;^@?b6B@Y&=F8vjq zxsccQlV^jZo+u7s@ix62X#hg^%+fMOs=KOk?iGI{)d?|5NoP`79M2*SJBwLxxrlT8 z#5>6OQ7K_GP2>{PuX&eRF8(N}TUbhn%oueJP!xp9MX%Bt(;y`!EshQ=caEJ>{ILRa z_en)?KAzYnl`^rjE+bAR3mH+)qovF!j~A}C#JGexmRuQTg7B)ANLI7%wkEN;&S5C} zUp!V((;5Q<|naZ+zK-U(k&@isg4R?mnf zyNyuF#uTvhU3=48-NH^YQ-Lo)qEvKY1WD!2tQCv!lr*;q;L)a@6~*cqJB(xgQkawB zj$o(WLY?It0>(I1kHdT;m1~upMk?24fwcPm4f}^U)zdi})tkCf4q_n*%T{8o+Qw`6 z#)@h$bT|!Un+Uv{COTdwPR}%OG=Q`(NGeAx&p}doA}OiFA49?8xoUjg7uqy*G<^c= z*r=W;T?WqLuVq=5Jz!+)3=S4dhisEDv5T=v`&jf+J3>wkX7u_cO{>PY zu2g?{2u0&klG^I|FlS+|+Akm-1|iPG!(P?`HbkX5p*V}c=}3oqx>3s(_V3i|L!7yg z3v51dbCRls)hAz-Pl{PH)UGvi-7siF&ziB%zC<=)d5_IZSW;{_36IU1F&6R{Je*GC znUR8+ERH+*ncu|ODd~`RnPr}iC8hd~5=nD}o*K)`7o2cM0ZslxAPe)3mJkk_!jLM@ z2Md)d>^gq6z|q2EU%U%fRm(C7EB3#tJdRi$0ZhiL-`zW3nd+me^3;0M$_OK?_oiJ_=_ZtEu9Y zo_P=Y*vC>?DFyx~9zK@J!;j@n*ulutTWdHPtvD8CyUcfU+6m`}osp<(gl}-LRwS9^ zI|%%a17|y`-s*V>dB`))1Sx2v)f@V-9rJpH3)qB(O8w0`G5p5yHU(ZyFR6OZq2hQx zNO#U9l*0(Gb(GZ;C7j+~Oyd2lP8hMHaih%JSOQt-Y^5;q<_fQ2IT`!)mabU3c4^x( zZSB(Kc+p<_s!;oi#bsAEVx-q=N3!K&Fi0HcUJsiysz7Mf@^6i;X8RCU5yWepC|!wc zGG-T+H;;|#soc%C#FoF*$0;>F;!M-Frpsg)$7=N;qx)*ban86{@GjQR;mn|X6sQwc z9DWDMht60uWJSecuyB&&ZBQO(v3doIBRHdQG#E+m=}N;1a-IYjAu?!yAbSbr zA(Hv(EGQu+y1H?;u94^x%R}?-0`-jT1iAFB0l84C*(l>MPgoRcH99(V9ScQT$L!L> ziGu{$?t)eMWXP8iO6r94+7xmWd{VDqb8lMc#;P_uRqR*`U}0YZr}tx3xPPG4EyT&j zwQZzC*%gQCmR8pyQB?bf+cVn=QlaRBdK~sfj3SPLk3k4M%Onc8#D@TcaZejp3&M~s z-o5FZmyZLAvHS~f{4m5zO2OZXmv-UZc0A48cU)4e9OBSS5~`-M|I~ag>>NoYI7}!u zrOamxD|mja*p!(g@e1mR(!=FSB6s^zs|Oit=fnz2tU&SWZmahkXrSCVTKLj65pwk) zyMss6u{>Yh8+`!@YrcSogJo7WCAK*V^*9{z4S=dke`V6Tb5clbnM9%rSI;(*&=Rk? zFA4ZC2}?(O0pd{X!{>YdBE`X_xxp<=Vt0Q21oWJ#K}MrIDZoUBFo}2mVumosCE_zU zp?myEK@txu$PQtVeT+l(0k{)nXCtDRo1!;Jt~d>zD5ZoVGMR0JhoDRiU96^yz_HLh zbG0zBhm&o532CHSEb`TsnNZv=I|y&p+E=V!x_ae`P&vY)`cb`dD7H{EEuvj@EmW;wx&AO^ z_xN{+MYd5IJ>o5jSa_a>*TLEEQQ~?~Z$=Yl4=v=2=6v2V!TQi_P7cA2p+Tsa z%07hNgjP>wA3|?Js}sV_60@+TTf7+pFSsdq6OyP8n;Pe9&1F51MR{DTArOSJsxIm< zsn>_DBZxg|k&}!5Q_nUoq40xXn}K+pVy?bskX1`cj*##2EHV!t16!C&>>|#2S(4eO%e>So|8c z(sFDft>axiQG|tMx?X~iy|3zP?V{IUcx`iJ^*D6KCxwk(sGwF<;^g66HGM&qrsaKK zzHI>Vp;GnbN$}c;VtEX@H#J<^fsF>0oTln7(`t4utQ0F$3KojYM6moKiJ8q^m{9UQ z8<7#!OUnO(mn*f4Wd?rn<)>pjRrJCJi9^qd8<7qL|0xw@n9MJG2uqjn48uYj)kNCB z`&0|YD?u#8vFglx^th94fy&2`sg$j=6Ac^7~Z+imk zh=B-QcUnF!J!>;+Lnz12@Vx|zL)SuIPxi103thTS&q2*0nRiJ#o@`J2Fi8|`g)QoiIQ+v2a&C<0O_<>j`uf_36NkRO_F-8lUa?l> zYafnUod+e>7`AaR(RkroU^|EaI;)3l1K=hPQY zl)A_h1B zY$!6)LZ_5rS_UsRD;eUdA03b*EZX|$o}3dTQCtiCmox?`DK4SECtEQJ>pXGj`c0_u zT*C-5CPZG!@_1+vIc2W{JZ}yV;~DL zp6E$gx%b#eCCpcAe94imrZ@{=GzuDI^LRa2C9ZfpY7h&< z2DTW4!Y0=9VBDB)mD%5DHV?P3}Ru_ z2+Mb@VuNC)+b%q~2?ze9jIQdplVI_0rR~8%EObWn`Gl3}A?`u4jaUWHXpZxdJTmGeg>*1Tfe)|`GrZ+v( z8Tr2TJ$+8!>d$VvYNtMN+!xQh^zCmw`-eSmUGRTio%`(P-u%^Fzw2q$fBW-~zq0U~ zmx6!PmKP7*rGIbQs14uk-m8Ch!?o+qZC%uV--LzVdG4<#_wRn_sR#DG{I&kAb#s2b z@5(py%cI@;lIHXDd0*W&_@f6$Kl_Jw=d^6x_>a#X`05|8_=mGQ^nux{c5bRm>TfN$ zvpzcIcilt>D&GLM{K(J^1aRdyWSi-_2Y{V^c#=# zT=GoxG=1@t;d7QOcvYWn>#sC^>6T~TJ)!Zj*Ph;}4=#M>naL0RKp&XYe&62X|ERwe z`N<nWx{M`1G#(r_Jr(H{mb;Y4zf(`)^zS!{63VTid^) z<;f8PouAbg-aO{^Z(esmpRi-pqi2p7sSi%SX6n*+Z_x*@nBM!u*)#Nkb5A|=iO0M3 zw;p}srh5;s(0_j9oyVr$SFgX=_V~KP+uqdowmf{rl@C1Df9FkOUVQkJANKd&^yQbb zW47qCAN>8qr#`h%pZmbtO;0v}Z_>?6J~`#*`rxeQe?4_{1on@yk29Q)jz zkLqs?+3zG>6!{@o+~^p%75nEuq=1L1F8 zv`g>U^Mk)Rbj?Hhz~SF+edP78>4OvB9eniAWBTBQFCBOKj1TLBmwx#5c;`3uf&FLQ z|H);R{u|@;Gm@YA67x^vcg|R)KmX`$pXvMk&-!=m8Tr%Gl27#C9sd6O(=Tc7U;9-3 z#k&{&CwQ;E`iqa;q7NMGn$q#NqxHeD|M1mo4_%`VYLC5f#hE|S2OIzR+D_{~^ntfG zTEBXuOaINQp%;IB9MiY1?x%-#>ffIHnT20?YDE7hZan*)BXhprzpL?{O;5k@HGSa7 z{=a|ajZcAp{H;IUxl$ka?;kH{d#Otw9QoaU`P|r*`rv6dJ%7=E&esQ;~>kLElFzPg<^ywQvM30F4$^FG`^JmK(y!wAQH z(>lgSz}v9#K;P>K$L5Jk&YYqTj&9ifc;02qf{oSPJ^}!8yoY%7JN&W3FFaOp_ N2VW8KQ#bD9{}0qgSD^p^ literal 0 HcmV?d00001 diff --git a/test/tests/fvkernels/mms/advective-outflow/advection-outflow.i b/test/tests/fvkernels/mms/advective-outflow/advection-outflow.i index 07d9208e5139..31add0f1cbb9 100644 --- a/test/tests/fvkernels/mms/advective-outflow/advection-outflow.i +++ b/test/tests/fvkernels/mms/advective-outflow/advection-outflow.i @@ -93,7 +93,10 @@ a=1.1 [] [Executioner] - type = Steady + type = Transient + dt = 1 + end_time = 10 + steady_state_tolerance = 1e-10 solve_type = 'NEWTON' petsc_options_iname = '-pc_type -pc_factor_shift_type -pc_factor_mat_solver_type' petsc_options_value = 'lu NONZERO mumps' From f76a9b705a29966d900b2b5c54239d82d1f1d5b1 Mon Sep 17 00:00:00 2001 From: Peter German Date: Tue, 26 Nov 2024 10:53:39 -0700 Subject: [PATCH 19/20] Modify linked design file in dispersion test. --- framework/src/fvbcs/FVFunctorDirichletBC.C | 10 ++++++---- test/tests/fvkernels/dispersion-test/tests | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/framework/src/fvbcs/FVFunctorDirichletBC.C b/framework/src/fvbcs/FVFunctorDirichletBC.C index 6bd5c542e0a4..3f75382921fa 100644 --- a/framework/src/fvbcs/FVFunctorDirichletBC.C +++ b/framework/src/fvbcs/FVFunctorDirichletBC.C @@ -59,11 +59,13 @@ FVFunctorDirichletBCTempl::boundaryValue(const FaceInfo & fi, if (!_use_other_side) return _functor(sfa, state); else if (fi.elemPtr() == sfa.face_side) - return _functor({&fi, Moose::FV::LimiterType::CentralDifference, true, false, fi.neighborPtr(), nullptr}, - state); + return _functor( + {&fi, Moose::FV::LimiterType::CentralDifference, true, false, fi.neighborPtr(), nullptr}, + state); else - return _functor({&fi, Moose::FV::LimiterType::CentralDifference, true, false, fi.elemPtr(), nullptr}, - state); + return _functor( + {&fi, Moose::FV::LimiterType::CentralDifference, true, false, fi.elemPtr(), nullptr}, + state); } template class FVFunctorDirichletBCTempl; diff --git a/test/tests/fvkernels/dispersion-test/tests b/test/tests/fvkernels/dispersion-test/tests index 6a94bc822eb2..723515b0e7d5 100644 --- a/test/tests/fvkernels/dispersion-test/tests +++ b/test/tests/fvkernels/dispersion-test/tests @@ -1,5 +1,5 @@ [Tests] - design = 'INSFVScalarFieldAdvection.md' + design = 'FVAdvection.md' issues = '#28891' [bottom_left_limited_scalar_advection] requirement = 'The system shall be able to perform a variety of limiting schemes when solving scalar transport equations in cartesian meshes with bottom-left advection. These schemes include' From fe27fcd6efd4115781d63015bbcb4919e9cd2c83 Mon Sep 17 00:00:00 2001 From: tanome Date: Fri, 29 Nov 2024 19:43:07 -0700 Subject: [PATCH 20/20] regolding for max_treads=1 in segreated lid-driven tests Refs #28891 --- .../lid-driven-segregated/gold/min_mod.e | Bin 0 -> 121736 bytes .../lid-driven-segregated/gold/min_mod_run.e | Bin 0 -> 121740 bytes .../lid-driven-segregated/gold/quick.e | Bin 0 -> 121648 bytes .../lid-driven-segregated/gold/quick_run.e | Bin 0 -> 121736 bytes .../lid-driven-segregated/gold/upwind.e | Bin 0 -> 121652 bytes .../lid-driven-segregated/gold/upwind_run.e | Bin 0 -> 121740 bytes .../lid-driven-segregated/gold/vanLeer.e | Bin 0 -> 89224 bytes .../lid-driven-segregated/gold/vanLeer_run.e | Bin 0 -> 86820 bytes .../mms/advective-outflow/advection-outflow.i | 5 ++++- 9 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/gold/min_mod.e create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/gold/min_mod_run.e create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/gold/quick.e create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/gold/quick_run.e create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/gold/upwind.e create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/gold/upwind_run.e create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/gold/vanLeer.e create mode 100644 modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/gold/vanLeer_run.e diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/gold/min_mod.e b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/gold/min_mod.e new file mode 100644 index 0000000000000000000000000000000000000000..0c5570f3479fc2601c9cf50c999cb8f464e7d525 GIT binary patch literal 121736 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 literal 0 HcmV?d00001 diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/gold/quick.e b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/gold/quick.e new file mode 100644 index 0000000000000000000000000000000000000000..b28b836b88789aeb5dd1f5ab935d83aa69d48044 GIT binary patch literal 121648 zcmeI52bdex)rQwgvrX?EhF;wZHn14u0tPp*F&&|mW_N|vtg`l+P9P!l-aDlCg!E2G zA-#}J5=bwk_x``%ojdAUX=a!FU`x;Q?i_t99o;$S&Ye4V?##@azp%Tjt7{C5hn-<; z(oILw(Uj}SUE>OglpDzx+${gJuPxHWR3x5A>8-v$PVdv1xSKa0=zg5VSZQw3PUpb^%n+^OW${} zx5D|%=~S9%p{TU_zA?KtD<9I`!hda! zp>m==d^3N?xxM8dlM0H5|I+UZUgN&ZpRs&Co6BTXC;ZPUuCh1v>b@!4CX42yc;EHE z{|xWPrSo;ar!x63eRezV&A4x|9Lwh`e@~xn^?UyJf6iyeb-;gB{@&jZ$MX5g z-_vK?{Jrst>*lcxHDjG|ub8M_`Y+19v*W!PzZ*;MvqMH1=Ck|G;uDIy!mB!=-1|B5 z%Qil;Fp*5IiYAL*1<_~ZQ!i}aoPH+n71K&ze*D|?Wz*R;!}uazmA?Gg2J|&szQ!wd zC2!t(YCZI7)1UwG9{Jl!?P^2~Pb!+_eQk_ck?}Xnc~{pQvo5hrI_<^^s@rm;e2xSE zx5t_GrZANCLTo;>`KhPRoo`wtQ`Zl%b#IaC-d5)G)xYltkAG{s8uyfpuCDCg_%qgg zK5rUGl~wx{|E2H6y*KMW#Byv!+dRx?FLLx*>sO7eKC8CEe^vOs=qg0tZ>!I0{d~V_ zsO492@?RBxFJ6r3`)&2vx9hXEyb7!QZVmpc!tW(JA^Lt>eRiEb>(z%+e7EtPvXtKe z@BJmuvh+Xe$6;IVf97w+XD^*!@mYV}Y#pfk?3*h->z8+X^C|C7h2P7xZd+@^G93ZC zlS5Oz+`;>Jsb03&_WdU4vWxlN_Jh%6zT|U?+pEgXOMVq=)p`F#yRhRm=FOOg?`B#3 z-Kp(<_X(%&yVKhJ?x$bRcfIY1{d}Yl?d847s`k&11E$HJt$$Z)J=u@;Wg!XTt@0{B0ptj!E z*7MqWU0aW9>uqg4t*w`}^{}?yb?Teh!0Xzl&i3QAo1OaR?SDG$o41`jW%r+*{f}2K zI_eYwN{G$XSWv$+M??vE$6`#8C=_l;*=*xBK9~W#WOMiS|Ls|O$vJGYF zk4JAPOaHvbhO+d}4{Rt)e;j>7S^DD_8_Lo@FSwyB{r=*Hvh>f>ZYWFteCCF-^v|1b zC`u{V&VKi;{qE_*YDLdIMkwQ)uum*^iTY@DlZ*1C|%Zp3Tf)s=MnHsSag{Oi4RZT>E>E9?fkmR;AM?+JUs-mnks3l8iD`@;cnARGh-!y#}e90rHO z5pX0-fQc{(CW9`i({+Qo9&kF$fSGU<%!1i)G#mrRLJu4VbKrQG3n#!l(Dj82U?H3c zC&3~(8BT%4umqOEGFT3$!fCJqR>JA93eJEt;Vd{C&Vh5`JUAaBZ~;W27h(_x7y6(d z1|R_!!fHr@dh2P(fI4q$AP0F+U#19yuol*Vu6SM#7lE$Ty96$U%iwaj04Q_`!;7+&;?uL8dUbqkLhX>$6cnBVbN8nL- z3?7Hqz-!@k@OpRyyb<06Z-%$PTj6c+c6bN86W#?+z`Nl+@LqTyydORQAA}FVhv6ge zQTP~q9G-+vz*F!^_!N8^J_Ap~XW?`3dH4c+5xxXphOfX^;cM^=d>y_4--K_$x8XbR zU3eD02j7Puz;p0C{1AQwKZc*cPvK|qbNB`P5`G0Qz^~yq@LTvD{2u-Qe}q55pW!d? zSNI$J9sU9Tgnz-m;Xm+Sduinumff%kYzmvf=CB2fg>f(*wuG% zg=sJyX24813TDA4Y7S=!x z@=$;x48mGi2SczPE`p2U61WsDgUjIxxDs9gSHacrN_Z7q1Fwc_;X1e;Zh#x%Cb$`H zfm`7=xE=0*JK-+48}5O7;Xb$@9)JhoA$S-bfk)vncpP2>uZ7pa>){RXMtBpv8QubK zg}1@m;T`Z!co#eY?}qold*OZXe)s@<5IzJShL6BU;bZV|coIGVPr)bQQ}Ai{3_J~= zh0np~;S2CZ_!4{>z5-u`ufa3$b@&E+6TSuChVQ_4;aT_|d>?)Q&%yKXL--N=7=8jj zg`dIC;TP~r_!YbWzlPtyZ{c_Fd-wzV5&i^!hQGjH;cxJF_y_zG{ssSr|Gf(*wuG%g=sJyX24813TDA4Y7S=!x@=$;x48mGi2SczPE`p2U61WsD zgUjIxxDs9gSHacrN_Z7q1Fwc_;X1e;Zh#x%Cb$`Hfm`7=xE=0*JK-+48}5O7;Xb$@ z9)JhoA$S-bfk)vnc)W{>3Ei*>Y-;VzSZ;1L*;~L^tH~Y*Cdso=aYO;5SJ**~sPuR<9viF94tR{P3a6p>u{a}A^ ztbG8>13{YXgWzD0Ci@UL6r{;M3=RirvX6ixL7MCdFcGB5o&=LYn(Qes6{N|Y2Gc>B za-dwyfSJ}-E{?LAY~^B>)nqFdv#lmuxj5QtvXzTttR`EzIM!;im5Uy$$yP3ovzlz> zVvf~hD;LLuG}+3R+Fte zwsMiRnr!7_jn!l;7dflRR^0PeldZTHtR`D=FIr8u;y!3K*^2vGtI1Z}*I7-r;yz?G z*%!cikS1GkzX+tsR@^TJX|fgfOF)`z#r;x{CR=g845Z0c+%E@dvK99$;Bsp#7gvHb zG3q$yP32X*Jo(#jC6)Te-N#YOrwUvuUL7Hsk;xUjWTe)}~q{&t;UIWr(D;KW?X|k1z*MT(I%EjwJnr!9b z4IoXna`8rxCR@396G)S-T)Y{i$yP4j0@7qF7jFe=vXzUsfi&65#oIxeY~|t|AWgP% z@lKE?TXBCENRzF&KLOHYEAH{9|mc%759&TG}(&#M?sow#r{Uj%8g756WJG}+3$*R3X7asP(ZWGn99 zw3=+i{aaR(t+;>NYO+5D-vMc|75DFgG}(&#vmi~j;{H95CR=g;K1h?Txc>m8$yVH- z18K4q_vhg`Yb)+Q1ZlDr_aA{Y*^2v*L7HsE{U;zzw&MO%kS1Gk{~1V=t+@Xjq{&v? ze*w~DD;K{6Y080e@hf=2+RDYRttMN!_>I+MD;K}Dnr!9bcUF_FT>Rc@vXzTJSWUL# z{zt3HR^0z&HQ9>$pRFcaasP|eWGn7}wVG_j{cl#2t+@Z)YO&G;jlKi)ZJ zQ%^HFAQ%3)q{$1pFyoV(@p*5O*_nx+CwE1LAJRQFroe#odgl?#z4TfVi9S)m=PWaW`YFyYgN+AQxubbvJ9X zFk`U0vy`n|>}fUG%Eew*lf4P-Z8h1-#XeTsoF#D|voAQ--h$?AHPqUir zJz%=kWGfdltR`Ezm}xcH%EeJuldW9LvYK+BxX*^8t*y8pV>Q`|`>|G&t+@ACO}65G zoYiD2?sKdrTX8?$YO)pgxmJ^{xSwD(*^2u-tI1Z}=UYwo5wO5&vK9A*R+Fu`pJ+AN ziu*}cldZTfvYKqg{bZ}jR@_gqn(V2t*lMzsizQZ*tz0a%nr!7_nbl+~7t5_CTe&#Z zYOJYWrL~od)2$|3xmaa2*~-NkR+Ftuupa*?x|Y~>Csf$yP3|w3=+?;uTht ztz2AXHQCC=)mD?OT)fh1%7Jq6D!9hl%Eha#CR@3<)@rhqi|ec=Te-O2YO}W< zxwz44vXzUQtR`EzxY=s5m5W=fCR@3<)oQYpi`%RwTe-O1YOfOvXzU6tR`Ezc-U&n zfpYN(JZf#_;xVhqRxTd5nr!9bHCB_YT)ft5vXzV1SxvTb@p`MtRxaLPHQCC=8?7c= zxpcLa`ASn$yP4jVKv#x#XGGgTe*0b)nqFd zPgqU1a`A4f$yP4jV>Q{z#e1zLTe*0j)nqFd@3)$4<>CWYQx24i55kA6tz3NAYOG5rldW7lV>RVKx%fJK!`jNlH?1aHx%igVWGffnwwi3^;yYH8 ztz3N9YOQ{#vXzS;SxvTb z@nfsWRxW;GHQCC=Ppu|fx%ipYWGfdxx0-C_;ultvtz7)lYORc@vXzTJSWUKa@kgu4RxbWzHQCC=pRFcax%i9KWGfec zwVG_@;%`=ytz7)wYOnJ1v94r&E$n#nE3_U z@LqW#7v0-=n#l{fF!K)3OkT)E_YR(B@2CR@3fXf@f&#U!iARxT!6O}26|#cHyZ zi>X$Vtz1mAnr!7_y47SW7c;CTTe+BNHQCC=QC5?!T+FhXY~^CM)nqFdM_Wy{a&e5+ zWGffPT1`1n+jj;$)B}Te&y|q{&t;7K1d|%Ec0pCR@2!3esdN z7t27JY~^A(NRzExoC?xpD;KAMG}+3<3XmpSxmXF(WGfe^gEZO7#VU}d94HrOz?s%o zF3z%=Y~|u?tI1Z}&#{_p#r<56CR=eo52VRf+|LJTvK99TNRzF&UjWi%EACN{CR=gu z1!=Ms_ZUc%t+>ZQnry}01!=Ms_dbv&TXF9PX|fgf0gxtJaZi9W*^2vxAWgR7z8a*- zR@{>yO}65m0%@`p_cTb8t+;1Enr!7F3(}MW$l~$9jxWB?`vK9BMtR`D=zuIcD757(KO}66xDyzv>+^?~kY{mW6 zR+Ft7Y|!awsP@^)nqFdk6KN(a`BkeWGfesds^3+E)3WNHigY# zbJzmL!Z;WYTf$bbHEaXh!gjDd>;OB$POvlV0=vR)usiGld%|9@H|zuZf&=@({%`;s z2nWHza0na6Wk29z^!l_+zxlZop2Z24fnvka39M99=3$7U~AY0wuS9r zd)NVXgq>h#*adcl-C%dv1NMZyU~kw5_5}y_gZ<$EI1mnkgW(W36b^&K;RrYqCcs3P z1e0M3OoeGM9cI8xI0|OLY&aT@fn%Wuj)OUHJj{g?U>?ke1+WlKgp*(qoD8SHVpsx8 zVHqrkQ{gmN0W0BjSOsUmnQ#`I4d=kQa2}iw5x4-N&SO-I}9xj55;S#tME`!VA3b+zp0awA*@Je_UTm!F$YvDS$9&Uge z;U>5lZh>3jHn<(`fIHzXxEt<)d*ME~A0B`Q;URb!9)U;UF?bwa1FwbG!Rz4-@J4tO zycymCZ-uwP+uN8w}ead;9w0Z+jv;ZyKw z_zXM^pM}rC=iv+RMfehY8NLEvg|ERg@OAhGd=tI}--hqNci~z19(*5u0MEhm@I&|! z{1|=$KZT#c&*2yFOZXMM0KbOcz;EGq@O$_J{1N^He}=!nU*T`?clZbV6aEGNhX25S zz1_YUOX$Yl1U7}uU~||4#=;k*OZm>J-0eiw; zus7@j`+@`e!TxXn90&)&!Egv13Wvera0DC)6JR1tg2^xirouFs4l`gT90jvrHXIGd zz_HK+$H5#p9_GRcFc0R#0$2zq!bz|QPKHxpF)V?lund;Nsc;&sfR%7Mtb#M(OgIb9 zhI8OtI1kQ;2wVVB=!F=>!G%8PhXF{yg|Hfukb*R1APZ}{NG6cOu1$a(c9Fv_a@a)< zN39R1-*~a1u9&_Yu{M37OIY3sZ-dXk^Psv+T{HUva%I}mwJdLjH^7tdU0_=6>24@-BEgJPkjDe-dxDeY0<7+cEpLbu4dz zH^L|2S)gq)ZHKn)egOL!_zlG!3;ToGEVU=v)~|)f;X1e;Zh#x%CZPVCW8hm^-UheB9l-Wuj$Q9& zc@NwR_rd+}06Yi}!Nc$fJPMBizhky{BUxRKk!p5@EzO?>B8|~Vg6<7OY zIH19+Yb5v5KfsxnbE5?}?(_~hOO`ELvA{W?%ieP{l-~vg^c}QTlM2za7TH|pLY@MjpOngE@-Bbl#iW~` zl#UK2+*~AI$gHk?HzAWPI1>_1G7+B;pEz;ioLpkiO;53 za+#cCmlHCByidekgk++(kjcdcCdA#rM9g(!*`flq%FX2ynY6Qr=V5!{G4WYQIo!3G z+-mcWTq;`NLr0Gw&t6Tjzjm}!e)T5`PK<1^m@$3E?B3p)?#x*ZC7L>U>huXyrc9W6 zRKxnZIMKVr%@6o1PO|Kdhd+s@o7`0_D!8NYub$7`0VLZ zCLc8uuQl~+`GS=zV)gDEXWGQ6QzuRdUT;<`Ua)*Phc&<7x?avJ=5kbHXJsPgme-e1 zF3csIrI|rz>TGAq?4zg6I(qtS6TVjYTCmQI6?tfS(ltKwg=i{k9M?FUdGyrjWrxF* z+x*}#{}0?w$l+-EyGM0?QJM|NS;+QdYW&Fj2d@_`e(#*~8rJvlad4bSF`ZabbR*H2 zHseT|ZM(byI!=!>Hy%IDO`457Kaj{SiKe6dZmwB595&c=A(u%;3eo<2r6+6mIE$99 zn!9+>{5I=@<0R55+hA3(DjfGXho&=;xZ4*kCJTo(E7zP-doG8GLL!=s^yMB8GoW*ljE?BX$-TKwY;b1gZE@H(hx5%$opUV#8g|e3ltL(5XfA=^}GP9N) zP;aKley_o+CWbBRljB5_xQwK=k0LdZHEUhne6*DC9*0IT!1hVCDYAP^MS7E&*y@s- za#3qa*mAu~4l}tpyRot(-zvwjy>dE^n{?Gvh!~H)oAQz^<@A-yTGv1Qobv2AO&s|y ztwaCwEtigyXLsJLczCUF*fM_FUL2<|lx?=zsgym=iE~e1v4Tvu}yFFS$H+Np!>orU{+h}0DK6Awn&oxbPg;2R4Vbd!XG7*krX=vj# zWSMj#-S5{Klayfnkw7hWi+q^)25qrh<{5|iWxeWHdy%PFS=lca zEML4}X(pZIC?T4go6ozc-sDh|`b$z`F*i%wkdCCH>)5HRqlcc&&_|CX=%$;!C!5RU zCf~2Cm$eSFiC8p8pTEji>+PfL*H#;j9-?V_`1P;g?V)z`i8NgYyV8kr^Dp;W+w$+X z-tJ2+cCZ{w%ZNI zi6_{O3z2L#G8j!3>+)h^*zWrBIXTR$&t6pn8S+ZRi*$I>nOrIo8*n*Nw4Ph7ciEw> zfz5oi&aYPEo_pDirp-Y`T{f)X^&DE2tNedCbaVYf5vollSuD893|m~OmYZrbd4{Pr z?bOGTLw8NlY_}289bM;b!YZUnSpNOi?M}&IQe|vVaZCxPn2Oz&-wKCnY-+YUuY{9% z1*nHMhK;MWS!H*EV%S#sR1dAgtXs&(B8+jco2u-Dm0O$E@l(BN?2s`K|8S-3P# zv;o$PV+>zd$Ek7HXafx5vCd)b2Iy^i?FX@e!|DwXho&ns{EC+U+rVM<253r1SESun zox`f_g;b9?%T*5T1{lQY@Flbx;D{X7Zh%3mjN(iQz2naYy%4jpn4|>iidcsYIt|ug z`*pCYgw?gr`0`8GZjCXYE3I;aeZ23GE^&|@eU|QrKmDLwu#!a#gOota3Pl9ert)s~!4>KEZeNWrwQa8uTiyt_&O=y6(uKBiA3+ zbEw`=o;Z2Rk=B?!+gRq^VRr9dxym^7%cakFui%Fjr4lwiIIF1G-UnJ#?TQj|q9mdwJ{DE)%4f6rkKI^ zDQqZ(Xih8bO;)Hm^ap0iyUGh|#|>mDZ;s|_1WE9o_&64o~jes?ZN<4{q; zq&Y2BJyIOJaj0@w-(3pcI8->S+LBEKwaWepnpSPK_y4M-R5=XQG}L6d+F_Wcp~hkD zVOh9p;|&{nLx@p&>~<1Z~>_wY{x<$~|hLip;@z*&ESDi2~KZ?a{ z=cK>R!s&OtQ`)8k&BN5jIr^$eP|ZEr{{%fp-_qfzf536hnK+4wUHN1p8(B9B$x%ff zcCwq9>Q=wNFYLS-U`;-<_Cup(j*J~I>t32$SAg%I>g{zikR*<$c zm?U<>ykXp_J!E2nf8y3OsS!&Vh$Xio1>;82k7_F0sxJU1`?@|t zw5F1iN+ak#Mc+-NvdKiu_O>dW$qp04Ceia;_c(2h43sLnzQs{!g!vez>cp9-&y4i) zE6ghUJ?pZU3aiHnc5RQo+9bc8*B&RW89u3Yua#1ZJ#o?~wA7^_j2wc4ww7-in{20#0O`p zYVGVsy}0}2!HT7;+h*M(3F`#hB+GTAIRhj zkz{nJ(FM#sPLK&k-eJW{zbnE-glweWEl>|5`C=bez?7>YJ%^wtxtNRLayOc0uP{j& z^+8=Z^ftT@Osy3kM8X93sd@ z@|hx6NR7B-Lu3`hk@Ri6l2oKf4m*7tMWOss-)24+bL9Fp3#lSlO-y~W)3?z+urh|h zTkKBHp|t=DC3^ z2ODEoq!{sTBKZG5%u-PjKR-%Jrz@f;lwbC2#S(jA_gr%eNV4b0tahnyj(S(5@r@^K zA$uHi1IpThG<~nHnOl9?@7FCh&~cjqZsN(^J9CMAArXt@vz14uVODt~>@2nD+iZxV zBBg8nxfyDfTa#5?VAtaWyPvZ*wNW2t$qjeuRqzY1949xBscRETLYUcooq?bieIV%n zeg2`kbDRuF6owiOWe2Z^FN+C{#nM&fBOhDRCKi5Vsa%rMj$aNt-8n^}{Hp2BEw@*U zmtt0H=$oV7og4MuS1iLFsJWM2ezm(c&BcV}^~DNvy!^87+xP?H=5`9TNv(UYc(v%; zY>4AFFGAnOd%{Om{qx_Huk^2re?vjvd+B$UI(?fBzi;z0>52>{^07>w9@vQcBHHvu z(iJI{#NV*xu+tS$6w0rfu1IGBk6&5JO9ksin83r;Yc4mdb=PIN6@x!Z#7oRZ*;xvD zr9Zd!-1z3(nA=NK%oeGtH({#Hs9*Cq>fO0ivD{kKSv}6g$&&;0isc|xY&baJ`R;KT zp-pj1{Wk9uq;I9&wFPd0&TV8GJfkE`QZ~j8rx*Ulf5QxnZ;aEl8b{Al!^E(~yswwQ zaNpX|UFDZWAA9g6bN05PBz|{E`RMeqt7~OVAG>q*)~_t(r2F5ts2!0 zvrlO;!nqNiy=`z8i1LO}XK71$>GuyiXK!DA)A;}2uk_zI&)yEcWX|4}OHyie)Y^2q zbBaRwRnwj8oV_j8mXe`hb7ha2PAm%R;t zW#~$F=PpL2mbsZ>Zoe=XDV;O@e?EI#Q4+tz%4Vl4QmWI&sOgGy&ffZ!rMy&}sz;Va z<@O7mv$vHsG0Z?v=j^SXiCT_gm>vE9`s{7+?p){W?Z|IoG3wV=jQ(`Nay72E!ZZ#W zV-L1Ia%Ck<4BI$++y3^fqKxvTvX1l8K70EzxU1WV$xLrFxtwbXQ=@WYw-ysFHHcC9 zlip3!DwT4-%d@y{!Cb4#U2PiQTdKz?X4fXt@!Bsod*9+1KqU-%$BAK^S2+y&)UaW% zK??5hWl#^7aBKS!A2C*>yp4J|FXwWXr1}2c^_S-|y-7Fa)kqbm!W-s`P;LA>IW)X~ zx3U~`LL<+z=K%=~rjU8Nf#4N;*qx|K7+~U@iD4ogOBUm9giGwANjB(+IhmVC+ed^3 z@4-%iLI!up zAWOcGE9y$Fgp$pr>XE)&CKX9%?At(zu@^P52Phwg*CZuqi*2f1l|w3HA2(0)4yb}B zC6Qldo)zgeA62E(o8VhY-X)6hNG2C|Yo5DloCmMi`PDoHDef|5oOO)k+$;~yOc*=b zr+ek)+`dHGZ96gC7f%jLUP{}rzwRMQ$kSN7XL&rgDL+13s(q+& z8PZ{~H=apFY5(iWI8ujoWenjkndAYmIX7KQ^>UvLf9K?9JNUL7O=bt8kz9tmGFA=P zSdYO=*y|RC@fRY?!(Pf8rrPut6Ulglr+3+1KxVC*tGHuT@GT|AEh}=|Mz`GJ&}PLG zx?Wf@4IabtPO7w5@^(_CeHKpJ@876@NMjvo8p$vvl*6WtSdVk&S!b79rIv{VJy;aG2pyj)`=YH&PSaq3IHP9qGv0 z0b1GW{$23qtEi_4`1`n0Z7CT+OBg7F?R?mr^rv+lwV@lWTI)-;)n`A^-+`4!Y$j2X z+EUA5=cK=)P<}B6>jlq^S4FZmcK&;Pvo{gVM=EcnUUnB|zib^=v{;q?LhR_R!}V2e z%5Q>idZm;8+zE=~@V-6{smlIB?4&9j>L5jvb}P^91>KfamSOu}VQ%lw@Ib1`PBct= z*rG!hCMn)iWmQfN2+S#g{_?X8!o;vYTFmDeknD}}9AECUQ#Gm|5~H+Y4KVV>uYMAjzg7dIH>3_h~N z=+^*a1dJIryvJau5;h+b3AgFxOAZ^Za?o*X$63dLK!bF6QkZRdT`EyAeWk{Am>3R? zb_s_@yM*gUyM*gUw}hj7{qjb5=CPedIM8Qagg$mB%YicRzxZ$`%Oj8SIm?QLY_TvZ z6Io1YS{#dNzdSFK;$|=24|_+Vwh#?hhuJLItjl>lhGH8GRLNnWaiFd$hY_8eidG(_ zgy}iNGRaJ%Q;v539DGNwk@ifo;p)m~D2JR2V6-n<{jkNA2a%r~hpURi_JL%OetRFOf41VbWbhTmW`Szhtr4u?Jb4%5JT$D)x$ zpQ(%tlBWxtxh~c8;A0M1H`k{d`ep~p>set1U*)nx=GxRx{|er~);Nr$7!@)%j`OoT zWpa?J&FPQQDw`5|*)DtRaRQBDbm;~b)D?WC-DplJF%MabbJ9L)DrksRu5`%lv=i}S zG+9b=h@F&ILWY6{BC&yJy5CG-Ee{uj$g(M6I+Jd;*1=ZVk73zi&02>op~-bJW2f|u ztYYUf{kpYzg_BA%cnLLXQ|Y0`4&K1hu_>BKR0B+M%j9YY)=AKN8^K8QF(U-c8|kY5Xo$cop}h>SI@u$sHVqxBkinwJ4Z)d!p5h_}Q%UOo^f(Kau3B{3 zvZYHFENy2pnd2lAz2*?0QGYm8wXvOlzpoyN7nmW$O*ib29a)|nLO3g4mMRM&Kvh+)lFhJWi%N{FZ@U7cU=UGQpS zN0!Vuh-Luy71Mr)T`oh#kS>EA7O5{|=n|HaUE?#f!`i0b_ZvDX`B=_%8%!n$?l7xf zd+jwJe)*J?>BHBPn*Z9duK_pO_(HA_S#CPO;*~OZQhbMv59ldjkikA}de!NTFmtff z4^tU~JIu!tO!rFk@xxf&j||Qu=)PPTjePekD7hd%-QY{(EGQmg>gJ51-{WzNZg{U@O^W5}UDtK#C+1{HnRsRX$P-9>0`D#betltnxDGjFC z@sW|2u++D%cICZeC)LOJi@P?HTkWXd=R}L^$~$x00j5W8_hOFY4L2}|m}<~?Da%23 zQpTY!^l4PSFq@un*xi(AyZmY!t$J; z`YAjkC}D0+jSjz<`W<-t-qhh`YjFCNQK4%1O?-%{bE z(hO4%haGqhla$Ki?aIO#JCwt^f#-_38KdLSKXzv9B~%P;2^)@NkJw>pc-Tf$s~l`V zvOFZ|jbvBEPd-Ny!-hlSBU$B|vU%$qY<$yeZTwN#n(m0_exI^%t#zI9BUs* z3>%KMkEn!=#@a_x!iFQ+LAO2CjhgGE;&}!qBi?{hxQg9u*vnMJFflBhk@l)`_21yL z`y6N3*>hp~Hnk(!l|!(~Nx+fz7Gv#UVpv5Y53^q`4IMHBt4%NHtpiF9>o#fq7!HGu&XpWCp3)d* zOBr?~J75UAv{ogDIyohw@->20=7cD>^x>qno`B_Y2P|_#qY*eP)t<@%jwC77yJg>N zn0-p)?!WaIYLz*jSer|X)|Cs46Aw4m-s4QGIhq^(tyYZSnHe{J*s7Lc>S1*@YDTid z#L&AtMAKV72H%!#C#k_<6e}O5gn4&O(XBg&X(JgXhQm&}4Aa_}Yi}EG$>I7o=9W** zj&Vc9aJaJpY|DWL(-it)2k%2AMH9Xno=h>-Cg>O}B^++>K2!`#gZH-XRW3qRo07u@ zX9L2-&@b_2+2ch9;(aqJE1rhz`M7z{b6sk-M(qmhiEa* z9%i31>^Qp|2E9aa)aPS2xG6+s{bpoo$+BfD7C1I;t>)dd7`WFeFI+H84(jq^=Fa7! zxuN>A^IkcF$B@Z*#v%7kYjo*VaEEr%y+YY&c3SZEFz5Dj9SO6bJkNP^N6KRlU=6$!_ig7l@I^-%nZj0n!{!%Jp+n#K`xhWF&0w3o3 zkKjou-OgHTmrKM7TzO^gYos%q+~21##06PgIzWwV=j3|DZJR0_GQ8_ut{BFl`T0mO z6Jd4$liO=A1rHuW@5X&i&zyz0Q>b@)!)EtY4_?C2zb+t`%dnZGBNs+v8E#IN<}6Zr zy_?JE8bIo3%$xb#?iS+@m~u&Zgd+>8P0bb^ydHYPHFD^0B~@+2NE~{drYd(~_9@;2 zwERY(v<>@4@GSQYMtWm;(;KebF3Jwu+2G210?sbS&9twf(tLZao6Qun`iV$7+2$5p z<*=X2X55G>igDuC9$UoVtDH!s+<1abI5|YeSQn)x(lu>k5T}l_+Rdf8lW9z&H_?8s zfLHs-l+L_&DM;{YQ|r)c{QR5{!suDPZf;xK66rgSLZc%?_f zVbw|pU*%E>?vI^~#x&ii>R2jBm62N<;;BhO zR7ARSMSXxPL!3e1U=mh7Uu1Le{!!V*(>Qy;##f5j=+G zp1Kutc>EC9IgSCsXV#j5Dm}Nt+gx;=R8`Ahwv@K>;XBk!T~mh}{t3Ry+|4p`GA>nnTw6uuuYfh+OQ)xW`<-rF5b9J`F(y;&2!Y`urotaQ7FH( z3s|vm)oB9>cOKU`EaI3qm(6gcTPC-HqhEGN91mAi1AQ~vYmQJ{dfCY$e|e?`$5!_4 zTEX`z{vbh|yCWqy4&%~jGY^a%pAOi#;g1F*+TQW0gu@OJgel>$$D_epY=0t|Sw%gv z$vaL_(e(=69{R_l=2&!{p9{~MaTxprjdwg+o!k*Q^bQ|&hE!KM)V#v1vUSJ-e7(O= zF>De&uc$qovQmGzVq+NA)VKT|bIr>74*h=*>!Xjbgu!hvLDU8w}E41G;~htkCm+zE<{TFS35S(Za{k%4KJIJ~GF0Sn`>#a-RB z%Ky)gsU7xtp1~gv+IjA6tBTv||L3fVG7E^am@m=3myYPqnK;RBPe!8;rj53B@5_&i z*Z1<@@!S(no4fSHHixTJ!eLLug=t`I_oaL;MZe;| zXuc-4f1STKAA8s{dttgF&7K))3dw1>MW?N3=jIh&s`VvJG4e-M{535t!}PwIo~e*m z+k;(h2dDfxSW)w;O?}5tih0VYnOLl;6ztt~EU9XmQDKmpB$>C?pbd8I$DZlyO~fT|TT2Qx9XAR5p{Ya--0CuP_eX1S4s_gW6@7 zp2Mgg1@vhw*X!KSRVoZ*DlZ@Had-%Y#`K$4y{i9c4f}@c+=PjtH?g*y*s3swsn{Gk zvQ`>Gu5#tQ;p*V(G3Kfjtbe0#71m}Vbca*^(|(6Ie9ST+#<5knEyeU;xtnK$@`Z6Y z$`g3%gD^tH^c+k-e>A!c6h?6i-*aei#36^BoGT{LMW%hN)N>em$@Cm* z2JV#QPS2s!bKoS`s=137&2O`Ao5o@I`-+&eW}Tix^MERbot}fDP=0lK4$bR}{f~n6 zzaDe&C%CmNocVxCxRLc7UbN{kbDq9OuX{VoP8>S*ptBux+JR0x&}j!c?Lem;=(Gc! zcA(P^blQPVJJ4wdI_*HG9q6k1UeDuM4%Ia zP6Rp;=tQ6sfldTE5$Hsq6M;?yIuYnZpc8>k1UeDuM4%IaP6Rp;=tQ6sfldTE5$Hsq T6M;?yIuYnZpc8?Yb_D(pDX)80 literal 0 HcmV?d00001 diff --git a/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/gold/quick_run.e b/modules/navier_stokes/test/tests/finite_volume/limiters/lid-driven-segregated/gold/quick_run.e new file mode 100644 index 0000000000000000000000000000000000000000..8a6325e7aa6c9e6ba716ffa8d3467319ed0724e2 GIT binary patch literal 121736 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 z