25#include "libmesh/mesh_base.h"
26#include "libmesh/elem_range.h"
27#include "libmesh/parallel_algebra.h"
28#include "libmesh/remote_elem.h"
29#include "metaphysicl/metaphysicl_version.h"
30#include "metaphysicl/dualsemidynamicsparsenumberarray.h"
31#include "metaphysicl/parallel_dualnumber.h"
32#if METAPHYSICL_MAJOR_VERSION < 2
33#include "metaphysicl/parallel_dynamic_std_array_wrapper.h"
35#include "metaphysicl/parallel_dynamic_array_wrapper.h"
37#include "metaphysicl/parallel_semidynamicsparsenumberarray.h"
46 params.addParam<
bool>(
47 "pull_all_nonlocal_a",
49 "Whether to pull all nonlocal 'a' coefficient data to our process. Note that 'nonlocal' "
50 "means elements that we have access to (this may not be all the elements in the mesh if the "
51 "mesh is distributed) but that we do not own.");
52 params.addParamNamesToGroup(
"pull_all_nonlocal_a",
"Parallel Execution Tuning");
54 params.addParam<
bool>(
55 "correct_volumetric_force",
false,
"Flag to activate volume force corrections.");
56 MooseEnum volume_force_correction_method(
"force-consistent pressure-consistent",
59 "volume_force_correction_method",
60 volume_force_correction_method,
61 "The method used for correcting the Rhie-Chow coefficients for a volume force.");
62 params.addParam<std::vector<MooseFunctorName>>(
63 "volumetric_force_functors",
"The names of the functors with the volumetric force sources.");
67std::vector<std::string>
70 return {
"pull_all_nonlocal_a",
71 "correct_volumetric_force",
72 "volume_force_correction_method",
73 "volumetric_force_functors"};
82 params.addClassDescription(
83 "Computes the Rhie-Chow velocity based on gathered 'a' coefficient data.");
90 params.addParam<MooseFunctorName>(
92 "For simulations in which the advecting velocities are aux variables, this parameter must be "
93 "supplied. It represents the on-diagonal coefficients for the 'x' component velocity, solved "
94 "via the Navier-Stokes equations.");
95 params.addParam<MooseFunctorName>(
97 "For simulations in which the advecting velocities are aux variables, this parameter must be "
98 "supplied when the mesh dimension is greater than 1. It represents the on-diagonal "
99 "coefficients for the 'y' component velocity, solved via the Navier-Stokes equations.");
100 params.addParam<MooseFunctorName>(
102 "For simulations in which the advecting velocities are aux variables, this parameter must be "
103 "supplied when the mesh dimension is greater than 2. It represents the on-diagonal "
104 "coefficients for the 'z' component velocity, solved via the Navier-Stokes equations.");
105 params.addParam<VariableName>(
"disp_x",
"The x-component of displacement");
106 params.addParam<VariableName>(
"disp_y",
"The y-component of displacement");
107 params.addParam<VariableName>(
"disp_z",
"The z-component of displacement");
114 _a(_moose_mesh, blockIDs(),
"a", true),
118 _momentum_sys_number(_fe_problem.systemNumForVariable(getParam<VariableName>(
"u"))),
120 _a_data_provided(false),
121 _pull_all_nonlocal(getParam<bool>(
"pull_all_nonlocal_a")),
122 _bool_correct_vf(getParam<bool>(
"correct_volumetric_force")),
123 _volume_force_correction_method(getParam<
MooseEnum>(
"volume_force_correction_method")),
124 _volumetric_force_functors(
125 isParamValid(
"volumetric_force_functors")
126 ? &getParam<
std::vector<MooseFunctorName>>(
"volumetric_force_functors")
129 auto process_displacement = [
this](
const auto & disp_name,
auto & disp_container)
133 "Displacement provided but we are not running on the displaced mesh. If you "
134 "really want this object to run on the displaced mesh, then set "
135 "'use_displaced_mesh = true', otherwise remove this displacement parameter");
142 process_displacement(
"disp_x",
_disp_xs);
147 process_displacement(
"disp_y",
_disp_ys);
149 paramError(
"disp_y",
"If 'disp_x' is provided, then 'disp_y' must be as well");
155 process_displacement(
"disp_z",
_disp_zs);
157 paramError(
"disp_z",
"If 'disp_x' is provided, then 'disp_z' must be as well");
162 _vel[tid] = std::make_unique<PiecewiseByBlockLambdaFunctor<ADRealVectorValue>>(
163 name() + std::to_string(tid),
168 velocity(1) = (*
_vs[tid])(r, t);
170 velocity(2) = (*
_ws[tid])(r, t);
179 name() +
"_disp_" + std::to_string(tid),
182 : libMesh::cast_ref<const Moose::FunctorBase<ADReal> &>(
_zero_functor),
184 : libMesh::cast_ref<const Moose::FunctorBase<ADReal> &>(
_zero_functor)));
189 "Rhie Chow coefficients may not be specified for average velocity interpolation");
196 "At least one volumetric force functor must be specified if "
197 "'correct_volumetric_force' is true.");
202 const unsigned int num_volume_forces = (*_volumetric_force_functors).size();
204 for (
const auto i : make_range(num_volume_forces))
217 mooseError(
"If a_u is provided, then a_v must be provided");
220 mooseError(
"If a_u is provided, then a_w must be provided");
226 paramError(
"a_v",
"If the a_v coefficients are provided, then a_u must be provided");
228 paramError(
"a_w",
"If the a_w coefficients are provided, then a_u must be provided");
246 _a_aux[tid] = std::make_unique<Moose::VectorCompositeFunctor<ADReal>>(
276 std::vector<MooseObject *> var_objects;
279 .template condition<AttribVar>(
static_cast<int>(var_num))
280 .template condition<AttribResidualObject>(
true)
281 .template condition<AttribSysNum>(
_u->
sys().
number())
282 .queryInto(var_objects);
283 for (
auto *
const var_object : var_objects)
290 " is not a INSFVMomentumResidualObject. Make sure that all the objects applied "
291 "to the momentum equation are INSFV or derived objects.");
297 " is not a INSFVMomentumResidualObject. Make sure that all the objects applied "
298 "to the momentum equation are INSFV or derived objects.");
302 mooseError(
"No INSFVKernels detected for the velocity variables. If you are trying to use "
303 "auxiliary variables for advection, please specify the a_u/v/w coefficients. If "
304 "not, please specify INSFVKernels for the momentum equations.");
313 Real elem_value = 0.0;
330 std::make_unique<ConstElemRange>(
_mesh.active_local_subdomain_set_elements_begin(
blockIDs()),
357 for (
auto & pair :
_a)
360 for (
auto & pair :
_a)
362 auto & a_val = pair.second;
376 "a-coefficient data should not be provided if the velocity variables are in the "
377 "nonlinear system and we are running kernels that compute said a-coefficients");
384 TIME_SECTION(
"execute", 1,
"Computing Rhie-Chow coefficients");
390 const auto saved_do_derivatives = ADReal::do_derivatives;
391 ADReal::do_derivatives =
true;
402 using FVRange = StoredRange<MooseMesh::const_face_info_iterator, const FaceInfo *>;
406 Threads::parallel_reduce(faces, fvr);
410 ADReal::do_derivatives = saved_do_derivatives;
424 using Datum = std::pair<dof_id_type, VectorValue<ADReal>>;
425 std::unordered_map<processor_id_type, std::vector<Datum>> push_data;
426 std::unordered_map<processor_id_type, std::vector<dof_id_type>> pull_requests;
427 static const VectorValue<ADReal> example;
432 const auto id = elem->id();
433 const auto pid = elem->processor_id();
434 auto it =
_a.find(
id);
435 mooseAssert(it !=
_a.end(),
"We definitely should have found something");
436 push_data[pid].push_back(std::make_pair(
id, it->second));
442 for (
const auto *
const elem :
443 as_range(
_mesh.active_not_local_elements_begin(),
_mesh.active_not_local_elements_end()))
444 if (
blockIDs().count(elem->subdomain_id()))
445 pull_requests[elem->processor_id()].push_back(elem->id());
450 pull_requests[elem->processor_id()].push_back(elem->id());
455 auto action_functor =
456 [
this](
const processor_id_type libmesh_dbg_var(pid),
const std::vector<Datum> & sent_data)
458 mooseAssert(pid != this->
processor_id(),
"We do not send messages to ourself here");
459 for (
const auto & pr : sent_data)
460 _a[pr.first] += pr.second;
467 auto gather_functor = [
this](
const processor_id_type libmesh_dbg_var(pid),
468 const std::vector<dof_id_type> & elem_ids,
469 std::vector<VectorValue<ADReal>> & data_to_fill)
471 mooseAssert(pid != this->
processor_id(),
"We shouldn't be gathering from ourselves.");
472 data_to_fill.resize(elem_ids.size());
473 for (
const auto i : index_range(elem_ids))
475 const auto id = elem_ids[i];
476 auto it =
_a.find(
id);
477 mooseAssert(it !=
_a.end(),
"We should hold the value for this locally");
478 data_to_fill[i] = it->second;
482 auto action_functor = [
this](
const processor_id_type libmesh_dbg_var(pid),
483 const std::vector<dof_id_type> & elem_ids,
484 const std::vector<VectorValue<ADReal>> & filled_data)
486 mooseAssert(pid != this->
processor_id(),
"The request filler shouldn't have been ourselves");
487 mooseAssert(elem_ids.size() == filled_data.size(),
"I think these should be the same size");
488 for (
const auto i : index_range(elem_ids))
489 _a[elem_ids[i]] = filled_data[i];
492 _communicator, pull_requests, gather_functor, action_functor, &example);
529 const bool subtract_mesh_velocity)
const
531 const Elem *
const elem = &fi.
elem();
534 auto &
p = *
_ps[tid];
535 auto *
const u =
_us[tid];
540 auto incorporate_mesh_velocity =
541 [
this, tid, subtract_mesh_velocity, &time](
const auto & space,
auto & velocity)
543 if (
_disps.size() && subtract_mesh_velocity)
544 velocity -=
_disps[tid]->dot(space, time);
549 const Elem *
const boundary_elem =
hasBlocks(elem->subdomain_id()) ? elem : neighbor;
551 Moose::FV::LimiterType::CentralDifference,
556 auto velocity =
vel(boundary_face, time);
557 incorporate_mesh_velocity(boundary_face, velocity);
566 VectorValue<ADReal> velocity;
569 &fi, Moose::FV::LimiterType::CentralDifference,
true, correct_skewness,
nullptr,
nullptr};
571 velocity(0) = (*u)(face, time);
573 velocity(1) = (*v)(face, time);
575 velocity(2) = (*w)(face, time);
577 incorporate_mesh_velocity(face, velocity);
584 if (m == Moose::FV::InterpMethod::Average ||
591 mooseDoOnce(
mooseWarning(
"Cannot compute Rhie Chow coefficients on initial. Returning linearly "
592 "interpolated velocities"););
597 mooseDoOnce(
mooseWarning(
"Cannot compute Rhie Chow coefficients if not solving. Returning "
598 "linearly interpolated velocities"););
602 mooseAssert(((m == Moose::FV::InterpMethod::RhieChow) &&
605 "The 'a' coefficients have not been generated or provided for "
606 "Rhie Chow velocity interpolation.");
608 mooseAssert(neighbor && this->
hasBlocks(neighbor->subdomain_id()),
609 "We should be on an internal face...");
614 const auto & grad_p =
p.adGradSln(fi, time, correct_skewness_p);
618 const auto & unc_grad_p =
p.uncorrectedAdGradSln(fi, time, correct_skewness_p);
626 auto vf_indicator_pressure_based =
627 [
this, &elem, &neighbor, &time, &fi, &correct_skewness](
const Point & unit_basis_vector)
631 Real uncorrected_interp_vf;
635 &fi, Moose::FV::LimiterType::CentralDifference,
true, correct_skewness,
nullptr,
nullptr};
645 Real elem_value = 0.0;
646 Real neigh_value = 0.0;
650 Real coord_multiplier;
652 const unsigned int rz_radial_coord =
655 for (
const auto side : make_range(elem->n_sides()))
657 const Elem *
const loc_neighbor = elem->neighbor_ptr(side);
661 elem_has_fi ? side : loc_neighbor->which_neighbor_am_i(elem));
664 fi_loc, Moose::FV::LimiterType::CentralDifference,
true, correct_skewness, elem,
nullptr};
667 elem->vertex_average(), coord_multiplier, coord_type, rz_radial_coord);
669 Real face_volume_contribution = fi_loc->
faceArea() *
670 (neighbor->vertex_average() - elem->vertex_average()).norm() *
682 elem_value += (*this->
_volumetric_force[i])(loc_face, time) * face_volume_contribution *
683 (fi_loc->
normal() * unit_basis_vector);
686 elem_value = elem_value / elem->volume();
690 for (
const auto side : make_range(neighbor->n_sides()))
692 const Elem *
const loc_elem = neighbor->neighbor_ptr(side);
696 elem_has_fi ? side : loc_elem->which_neighbor_am_i(neighbor));
699 fi_loc, Moose::FV::LimiterType::CentralDifference,
true, correct_skewness, elem,
nullptr};
702 neighbor->vertex_average(), coord_multiplier, coord_type, rz_radial_coord);
704 Real face_volume_contribution = fi_loc->
faceArea() *
705 (elem->vertex_average() - neighbor->vertex_average()).norm() *
715 neigh_value += (*this->
_volumetric_force[i])(loc_face, time) * face_volume_contribution *
716 (fi_loc->
normal() * unit_basis_vector);
719 neigh_value = neigh_value / neighbor->volume();
724 fi.
faceCentroid(), coord_multiplier, coord_type, rz_radial_coord);
726 Moose::FV::InterpMethod::Average, uncorrected_interp_vf, elem_value, neigh_value, fi,
true);
729 return MooseUtils::relativeFuzzyEqual(interp_vf, uncorrected_interp_vf, 1e-10) ? 0.0 : 1.0;
736 auto vf_indicator_force_based = [
this, &time, &fi, &correct_skewness](Point & face_normal)
740 &fi, Moose::FV::LimiterType::CentralDifference,
true, correct_skewness,
nullptr,
nullptr};
760 "Coordinate systems must be the same between the two elements");
765 elem_volume *= coord;
767 VectorValue<ADReal> elem_D = 0;
768 for (
const auto i : make_range(
_dim))
770 mooseAssert(elem_a(i).value() != 0,
"We should not be dividing by zero");
771 elem_D(i) = elem_volume / elem_a(i);
774 VectorValue<ADReal> face_D;
779 neighbor_volume *= coord;
781 VectorValue<ADReal> neighbor_D = 0;
782 for (
const auto i : make_range(
_dim))
784 mooseAssert(neighbor_a(i).value() != 0,
"We should not be dividing by zero");
785 neighbor_D(i) = neighbor_volume / neighbor_a(i);
792 ? Moose::FV::InterpMethod::SkewCorrectedAverage
793 : Moose::FV::InterpMethod::Average;
797 const auto face_eps =
epsilon(tid)(face, time);
802 for (
const auto i : make_range(
_dim))
805 velocity(i) -= face_D(i) * face_eps * (grad_p(i) - unc_grad_p(i));
811 Point unit_basis_vector;
812 unit_basis_vector(i) = 1.0;
815 Real correction_indicator;
817 correction_indicator = vf_indicator_force_based(unit_basis_vector);
819 correction_indicator = vf_indicator_pressure_based(unit_basis_vector);
822 velocity(i) += face_D(i) * face_eps * (grad_p(i) - unc_grad_p(i)) * correction_indicator;
DualNumber< Real, DNDerivativeType, true > ADReal
void coordTransformFactor(const SubProblem &s, SubdomainID sub_id, const P &point, C &factor, SubdomainID neighbor_sub_id=libMesh::Elem::invalid_subdomain_id)
boundary_id_type BoundaryID
registerMooseObject("NavierStokesApp", INSFVRhieChowInterpolator)
const ExecFlagType EXEC_ALWAYS
const ExecFlagType EXEC_INITIAL
const ExecFlagType EXEC_PRE_KERNELS
bool hasBlocks(const SubdomainName &name) const
virtual const std::set< SubdomainID > & blockIDs() const
void addAvailableFlags(const ExecFlagType &flag, Args... flags)
const ExecFlagType & getCurrentExecuteOnFlag() const
virtual unsigned int currentNlSysNum() const override
TheWarehouse & theWarehouse() const
Real neighborVolume() const
const Point & normal() const
const Elem & elem() const
const Elem * neighborPtr() const
const Elem * elemPtr() const
const Point & neighborCentroid() const
const Point & elemCentroid() const
const Point & faceCentroid() const
static std::string deduceFunctorName(const std::string &name, const InputParameters ¶ms)
Moose::ElemArg makeElemArg(const Elem *elem, bool correct_skewnewss=false) const
A class that gathers body force data from elemental kernels contributing to the Navier-Stokes momentu...
A class that gathers 'a' coefficient data from flux kernels, boundary conditions, and interface kerne...
All objects that contribute to pressure-based (e.g.
This user-object gathers 'a' (on-diagonal velocity coefficients) data.
std::vector< std::unique_ptr< PiecewiseByBlockLambdaFunctor< ADRealVectorValue > > > _vel
A functor for computing the (non-RC corrected) velocity.
INSFVRhieChowInterpolator(const InputParameters ¶ms)
virtual void ghostADataOnBoundary(const BoundaryID boundary_id) override
makes sure coefficient data gets communicated on both sides of a given boundary
bool pressureSkewCorrection(THREAD_ID tid) const
Whether central differencing face interpolations of pressure should include a skewness correction.
virtual void initialSetup() override
virtual void finalize() override
std::unordered_set< const Elem * > _elements_to_push_pull
Non-local elements that we should push and pull data for across processes.
std::vector< std::unique_ptr< Moose::VectorCompositeFunctor< ADReal > > > _disps
A functor for computing the displacement.
virtual void execute() override
Moose::VectorComponentFunctor< ADReal > _ax
std::vector< MooseVariableField< Real > * > _disp_zs
All the thread copies of the z-displacement variable.
std::vector< MooseVariableField< Real > * > _disp_ys
All the thread copies of the y-displacement variable.
std::unique_ptr< ConstElemRange > _elem_range
All the active and elements local to this process that exist on this object's subdomains.
std::vector< MooseVariableField< Real > * > _disp_xs
All the thread copies of the x-displacement variable.
static InputParameters validParams()
const MooseEnum _volume_force_correction_method
– Method used for computing the properties average
const bool & _bool_correct_vf
Correct Rhie-Chow coefficients for volumetric force flag.
virtual void initialize() override
const unsigned int _momentum_sys_number
The number of the nonlinear system in which the monolithic momentum and continuity equations are loca...
bool velocitySkewCorrection(THREAD_ID tid) const
Whether central differencing face interpolations of velocity should include a skewness correction Als...
bool _a_data_provided
Whether 'a' data has been provided by the user.
Moose::VectorComponentFunctor< ADReal > _ay
The y-component of 'a'.
std::vector< std::unique_ptr< Moose::FunctorBase< VectorValue< ADReal > > > > _a_aux
A vector sized according to the number of threads that holds vector composites of 'a' component funct...
static InputParameters uniqueParams()
Parameters of this object that should be added to the NSFV action that are unique to this object.
Moose::VectorComponentFunctor< ADReal > _az
The z-component of 'a'.
bool needAComputation() const
Whether we need 'a' coefficient computation.
std::vector< const Moose::Functor< Real > * > _volumetric_force
Values of the functors storing the volumetric forces.
virtual void meshChanged() override
const std::vector< MooseFunctorName > * _volumetric_force_functors
Names of the functors storing the volumetric forces.
std::vector< const Moose::FunctorBase< VectorValue< ADReal > > * > _a_read
A vector sized according to the number of threads that holds the 'a' data we will read from when comp...
CellCenteredMapFunctor< ADRealVectorValue, std::unordered_map< dof_id_type, ADRealVectorValue > > _a
A map from element IDs to 'a' coefficient data.
virtual VectorValue< ADReal > getVelocity(const Moose::FV::InterpMethod m, const FaceInfo &fi, const Moose::StateArg &time, const THREAD_ID tid, bool subtract_mesh_velocity) const override
Retrieve a face velocity.
virtual void addToA(const libMesh::Elem *elem, unsigned int component, const ADReal &value) override
API that momentum residual objects that have on-diagonals for velocity call.
Real _baseline_volume_force
Minimum absolute RC force over the domain.
void insfvSetup()
perform the setup of this object
bool _pull_all_nonlocal
Whether we want to pull all nonlocal 'a' coefficient data.
void fillARead()
Fills the _a_read data member at construction time with the appropriate functors.
static std::vector< std::string > listOfCommonParams()
const Moose::ConstantFunctor< ADReal > _zero_functor
A zero functor potentially used in _a_read.
const std::string & name() const
void paramError(const std::string ¶m, Args... args) const
void mooseError(Args &&... args) const
void mooseWarning(Args &&... args) const
bool isParamValid(const std::string &name) const
std::unordered_set< dof_id_type > getBoundaryActiveSemiLocalElemIds(BoundaryID bid) const
face_info_iterator ownedFaceInfoEnd()
virtual Elem * elemPtr(const dof_id_type i)
face_info_iterator ownedFaceInfoBegin()
const std::vector< const FaceInfo * > & faceInfo() const
virtual Elem * queryElemPtr(const dof_id_type i)
std::unordered_set< dof_id_type > getBoundaryActiveNeighborElemIds(BoundaryID bid) const
const bool _displaced
Whether this object is operating on the displaced mesh.
Moose::FV::InterpMethod _velocity_interp_method
The interpolation method to use for the velocity.
INSFVVelocityVariable *const _w
The thread 0 copy of the z-velocity variable (null if the problem is not 3D)
std::vector< MooseVariableFVReal * > _ws
All the thread copies of the z-velocity variable.
void fillContainer(const std::string &var_name, Container &container)
Fill the passed-in variable container with the thread copies of var_name.
const INSFVVelocityVariable * vel() const
MooseMesh & _moose_mesh
The MooseMesh that this user object operates on.
const libMesh::MeshBase & _mesh
The libMesh mesh that this object acts on.
std::vector< unsigned int > _var_numbers
The velocity variable numbers.
std::vector< MooseVariableFVReal * > _vs
All the thread copies of the y-velocity variable.
static InputParameters validParams()
void checkBlocks(const VarType &var) const
Check the block consistency between the passed in var and us.
virtual const Moose::FunctorBase< ADReal > & epsilon(THREAD_ID tid) const
A virtual method that allows us to only implement getVelocity once for free and porous flows.
INSFVVelocityVariable *const _v
The thread 0 copy of the y-velocity variable (null if the problem is 1D)
std::vector< MooseVariableFVReal * > _us
All the thread copies of the x-velocity variable.
INSFVVelocityVariable *const _u
The thread 0 copy of the x-velocity variable.
const unsigned int _dim
The dimension of the mesh, e.g. 3 for hexes and tets, 2 for quads and tris.
std::vector< MooseVariableFVReal * > _ps
All the thread copies of the pressure variable.
const Moose::Functor< T > & getFunctor(const std::string &name, const THREAD_ID tid, const std::string &requestor_name, bool requestor_is_ad)
unsigned int getAxisymmetricRadialCoord() const
Moose::CoordinateSystemType getCoordSystem(SubdomainID sid) const
void addFunctor(const std::string &name, const Moose::FunctorBase< T > &functor, const THREAD_ID tid)
unsigned int number() const
void min(const T &r, T &o, Request &req) const
Moose::StateArg determineState() const
FEProblemBase & _fe_problem
const Parallel::Communicator & _communicator
processor_id_type processor_id() const
processor_id_type n_processors() const
void coordTransformFactor(const P &point, C &factor, const Moose::CoordinateSystemType coord_type, const unsigned int rz_radial_coord=libMesh::invalid_uint)
void interpolate(InterpMethod m, T &result, const T2 &value1, const T3 &value2, const FaceInfo &fi, const bool one_is_elem)
bool elemHasFaceInfo(const Elem &elem, const Elem *const neighbor)
bool onBoundary(const SubdomainRestrictable &obj, const FaceInfo &fi)
std::tuple< bool, T, T > isPorosityJumpFace(const Moose::FunctorBase< T > &porosity, const FaceInfo &fi, const Moose::StateArg &time)
Checks to see whether the porosity value jumps from one side to the other of the provided face.
void pull_parallel_vector_data(const Communicator &comm, const MapToVectors &queries, GatherFunctor &gather_data, const ActionFunctor &act_on_data, const datum *example)
void push_parallel_vector_data(const Communicator &comm, MapToVectors &&data, const ActionFunctor &act_on_data)
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
Tnew cast_ref(Told &oldvar)
const unsigned int invalid_uint