26#include "libmesh/mesh_base.h"
27#include "libmesh/elem_range.h"
28#include "libmesh/petsc_matrix.h"
40 params.addClassDescription(
"Computes H/A and 1/A together with face mass fluxes for segregated "
41 "momentum-pressure equations using linear systems.");
43 params.addRequiredParam<VariableName>(
NS::pressure,
"The pressure variable.");
44 params.addRequiredParam<VariableName>(
"u",
"The x-component of velocity");
45 params.addParam<VariableName>(
"v",
"The y-component of velocity");
46 params.addParam<VariableName>(
"w",
"The z-component of velocity");
47 params.addRequiredParam<std::string>(
49 "The LinearFVPressureCorrectionDiffusion kernel acting on the pressure.");
51 params.addRequiredParam<MooseFunctorName>(
NS::density,
"Density functor");
61 params.addParam<
MooseEnum>(
"pressure_projection_method",
62 MooseEnum(
"standard consistent",
"standard"),
63 "The method to use in the pressure projection for Ainv - "
64 "standard (SIMPLE) or consistent (SIMPLEC)");
66 "pressure_diffusion_interpolation",
68 "The face interpolation method for Ainv in the pressure correction diffusion term.");
76 _mesh(_moose_mesh.getMesh()),
77 _dim(blocksMaxDimension()),
79 &
UserObject::_subproblem.getVariable(0, getParam<VariableName>(
NS::pressure)))),
81 _HbyA_flux(_moose_mesh, blockIDs(),
"HbyA_flux"),
82 _Ainv(_moose_mesh, blockIDs(),
"Ainv"),
85 "face_flux", _moose_mesh, blockIDs(),
"face_values")),
86 _rho(getFunctor<
Real>(
NS::density)),
87 _pressure_projection_method(getParam<
MooseEnum>(
"pressure_projection_method")),
88 _pressure_diffusion_interp_method(getParam<
MooseEnum>(
"pressure_diffusion_interpolation") ==
90 ?
Moose::FV::InterpMethod::HarmonicAverage
91 :
Moose::FV::InterpMethod::Average)
97 std::vector<std::string> vel_names = {
"u",
"v",
"w"};
104 paramError(vel_names[i],
"the velocity must be a MOOSELinearVariableFVReal.");
118 " should only be used with a linear segregated thermal-hydraulics solver!");
123 const std::vector<LinearSystem *> & momentum_systems,
125 const std::vector<unsigned int> & momentum_system_numbers)
141 std::set<BoundaryID> velocity_boundary_ids;
143 for (
const auto & [boundary_id, _] :
_vel[dim_i]->getBoundaryConditionMap())
144 velocity_boundary_ids.insert(boundary_id);
146 const auto is_dirichlet =
155 for (
const auto boundary_id : velocity_boundary_ids)
161 const bool velocity_is_dirichlet = is_dirichlet(*
_vel[0], boundary_id);
163 if (is_dirichlet(*
_vel[dim_i], boundary_id) != velocity_is_dirichlet)
164 mooseError(
"All velocity components must either have Dirichlet boundary conditions or "
165 "non-Dirichlet boundary conditions on boundary '",
167 "' when the pressure boundary condition is not a LinearFVPressureFluxBC.");
185 std::vector<LinearFVFluxKernel *> flux_kernel;
188 .template condition<AttribThread>(
_tid)
189 .template condition<AttribSysNum>(
_p->
sys().
number())
190 .template condition<AttribSystem>(
"LinearFVFluxKernel")
191 .template condition<AttribName>(getParam<std::string>(
"p_diffusion_kernel"))
192 .queryInto(flux_kernel);
193 if (flux_kernel.size() != 1)
195 "p_diffusion_kernel",
196 "The kernel with the given name could not be found or multiple instances were identified.");
200 "The provided diffusion kernel must be of type "
201 "LinearFVPressureCorrectionDiffusion.");
213 if (
hasBlocks(elem_info->subdomain_id()))
216 _cell_volumes->set(elem_dof, elem_info->volume() * elem_info->coordFactor());
223 if (
hasBlocks(fi->elemPtr()->subdomain_id()) ||
224 (fi->neighborPtr() &&
hasBlocks(fi->neighborPtr()->subdomain_id())))
234 for (
const auto & pair :
_Ainv)
235 _Ainv[pair.first] = 0;
252 if (
_vel[0]->isInternalFace(*fi))
254 const auto & elem_info = *fi->elemInfo();
255 const auto & neighbor_info = *fi->neighborInfo();
261 interpolate(InterpMethod::Average,
262 density_times_velocity(dim_i),
263 _vel[dim_i]->getElemValue(elem_info, time_arg) * elem_rho,
264 _vel[dim_i]->getElemValue(neighbor_info, time_arg) * neighbor_rho,
271 const bool elem_is_fluid =
hasBlocks(fi->elemPtr()->subdomain_id());
272 const Elem *
const boundary_elem = elem_is_fluid ? fi->elemPtr() : fi->neighborPtr();
275 const Real boundary_normal_multiplier = elem_is_fluid ? 1.0 : -1.0;
277 fi, Moose::FV::LimiterType::CentralDifference,
true,
false, boundary_elem,
nullptr};
279 const Real face_rho =
_rho(boundary_face, time_arg);
281 density_times_velocity(dim_i) = boundary_normal_multiplier * face_rho *
282 raw_value((*
_vel[dim_i])(boundary_face, time_arg));
299 Moose::FV::LimiterType::CentralDifference,
313 bool libmesh_dbg_var(subtract_mesh_velocity))
const
315 mooseAssert(!subtract_mesh_velocity,
"RhieChowMassFlux does not support moving meshes yet!");
317 if (m != Moose::FV::InterpMethod::RhieChow)
318 mooseError(
"Interpolation methods other than Rhie-Chow are not supported!");
320 mooseError(
"Older interpolation times are not supported!");
346 Real p_grad_flux = 0.0;
349 const auto & elem_info = *fi->
elemInfo();
357 const auto p_elem_value = p_reader(elem_dof);
358 const auto p_neighbor_value = p_reader(neighbor_dof);
362 const auto neighbor_matrix_contribution =
364 const auto elem_rhs_contribution =
368 p_grad_flux = (p_neighbor_value * neighbor_matrix_contribution +
369 p_elem_value * elem_matrix_contribution) -
370 elem_rhs_contribution;
374 mooseAssert(fi->
boundaryIDs().size() == 1,
"We should only have one boundary on every face.");
376 bc_pointer->setupFaceData(
382 const auto matrix_contribution =
384 const auto rhs_contribution =
388 p_grad_flux = (p_elem_value * matrix_contribution - rhs_contribution);
404 auto working_vector =
_Ainv_raw[system_i]->clone();
405 working_vector->pointwise_mult(*working_vector, *pressure_gradient[system_i]);
406 working_vector->add(*
_HbyA_raw[system_i]);
407 working_vector->scale(-1.0);
439 std::vector<PetscVectorReader> hbya_reader;
441 hbya_reader.emplace_back(*raw_hbya[dim_i]);
443 std::vector<PetscVectorReader> ainv_reader;
445 ainv_reader.emplace_back(*raw_Ainv[dim_i]);
457 if (
_vel[0]->isInternalFace(*fi))
460 const auto & elem_info = *fi->
elemInfo();
471 interpolate(Moose::FV::InterpMethod::Average, face_rho, elem_rho, neighbor_rho, *fi,
true);
474 interpolate(Moose::FV::InterpMethod::Average,
476 hbya_reader[dim_i](elem_dof),
477 hbya_reader[dim_i](neighbor_dof),
482 elem_rho * ainv_reader[dim_i](elem_dof),
483 neighbor_rho * ainv_reader[dim_i](neighbor_dof),
493 const Real boundary_normal_multiplier = elem_is_fluid ? 1.0 : -1.0;
498 mooseAssert(fi->
boundaryIDs().size() == 1,
"We should only have one boundary on every face.");
505 if (
_vel[0]->isDirichletBoundaryFace(*fi) &&
509 fi, Moose::FV::LimiterType::CentralDifference,
true,
false, elem_info.
elem(),
nullptr};
517 face_hbya(dim_i) *= boundary_normal_multiplier;
527 face_hbya(dim_i) = boundary_normal_multiplier * hbya_reader[dim_i](elem_dof);
533 Ainv(dim_i) = elem_rho * ainv_reader[dim_i](elem_dof);
545 _console <<
"************************************" << std::endl;
546 _console <<
"Computing HbyA" << std::endl;
547 _console <<
"************************************" << std::endl;
550 "The momentum system shall be linked before calling this function!");
566 "The matrices used in the segregated INSFVRhieChow objects need to be convertable "
571 _console <<
"Matrix in rc object" << std::endl;
583 _console <<
"Velocity solution in H(u)" << std::endl;
601 mooseAssert(working_vector_petsc,
602 "The vectors used in the RhieChowMassFlux objects need to be convertable "
607 HbyA.
add(-1.0, *working_vector_petsc);
621 HbyA.
add(-1.0, *working_vector_petsc);
625 _console <<
"total RHS" << std::endl;
627 _console <<
"pressure RHS" << std::endl;
628 pressure_gradient[system_i]->print();
629 _console <<
" H(u)-rhs-relaxation_source" << std::endl;
634 *working_vector_petsc = 1.0;
642 _console <<
" (H(u)-rhs)/A" << std::endl;
654 _console <<
"Performing SIMPLEC projection." << std::endl;
663 const auto local_size = mmat->
local_m();
665 for (
const auto row_i :
make_range(local_size))
668 const auto global_index = mmat->
row_start() + row_i;
669 std::vector<numeric_index_type> indices;
677 sum_vector.add(global_index, row_sum);
683 auto row_sum = current_local_solution.
zero_clone();
684 get_row_sum(*row_sum);
687 auto Ainv_full = current_local_solution.
zero_clone();
688 *working_vector_petsc = 1.0;
690 const auto Ainv_full_old = Ainv_full->clone();
693 Ainv_full->add(-1.0, Ainv);
694 working_vector_petsc->
pointwise_mult(*Ainv_full, *pressure_gradient[system_i]);
696 HbyA.
add(-1.0, *working_vector_petsc);
699 Ainv = *Ainv_full_old;
716 _console <<
"************************************" << std::endl;
717 _console <<
"DONE Computing HbyA " << std::endl;
718 _console <<
"************************************" << std::endl;
722std::vector<std::unique_ptr<NumericVector<Number>>> &
725 if (updated_pressure)
boundary_id_type BoundaryID
const ExecFlagType EXEC_NONE
std::array< Real, 2 > values
registerMooseObject("NavierStokesApp", RhieChowMassFlux)
bool hasBlocks(const SubdomainName &name) const
const ConsoleStream _console
const Elem * elem() const
const std::vector< std::vector< dof_id_type > > & dofIndices() const
void addAvailableFlags(const ExecFlagType &flag, Args... flags)
virtual MooseMesh & mesh() override
TheWarehouse & theWarehouse() const
A functor whose evaluation relies on querying a map where the keys are face info ids and the values c...
ValueType evaluate(const FaceInfo *const fi) const
Evaluate the face functor using a FaceInfo argument.
const Point & normal() const
VarFaceNeighbors faceType(const std::pair< unsigned int, unsigned int > &var_sys) const
const std::set< BoundaryID > & boundaryIDs() const
const Elem & elem() const
const Elem * neighborPtr() const
const ElemInfo * elemInfo() const
const ElemInfo * neighborInfo() const
const Elem * elemPtr() const
Moose::ElemArg makeElemArg(const Elem *elem, bool correct_skewnewss=false) const
virtual Real computeBoundaryRHSContribution(const LinearFVBoundaryCondition &bc) override
virtual Real computeElemMatrixContribution() override
virtual Real computeNeighborMatrixContribution() override
virtual Real computeElemRightHandSideContribution() override
virtual Real computeBoundaryMatrixContribution(const LinearFVBoundaryCondition &bc) override
virtual void setupFaceData(const FaceInfo *face_info)
void setCurrentFaceArea(const Real area)
const std::vector< std::unique_ptr< libMesh::NumericVector< libMesh::Number > > > & linearFVGradientContainer() const
Pressure correction diffusion kernel for the linear finite volume SIMPLE algorithm.
Class implementing a flux boundary condition for linear finite volume pressure variables used in the ...
virtual System & system() override
Executioner * getExecutioner() const
const std::string & name() const
void paramError(const std::string ¶m, Args... args) const
void mooseError(Args &&... args) const
MooseApp & getMooseApp() const
Real getElemValue(const ElemInfo &elem_info, const StateArg &state) const
LinearFVBoundaryCondition * getBoundaryCondition(const BoundaryID bd_id) const
const std::string & getBoundaryName(const BoundaryID boundary_id) const
const std::vector< const FaceInfo * > & faceInfo() const
const std::vector< const ElemInfo * > & elemInfoVector() const
unsigned int number() const
bool isInternalFace(const FaceInfo &) const
static InputParameters validParams()
Executioner set up to solve a transient thermal-hydraulics problem using the PIMPLE algorithm.
static InputParameters validParams()
User object responsible for determining the face fluxes using the Rhie-Chow interpolation in a segreg...
const MooseMesh & _moose_mesh
The MooseMesh that this user object operates on.
const Moose::FV::InterpMethod _pressure_diffusion_interp_method
Interpolation method used for the pressure diffusion coefficient on faces.
std::vector< std::unique_ptr< NumericVector< Number > > > _grad_p_current
for a PISO iteration we need to hold on to the original pressure gradient field.
std::vector< std::unique_ptr< NumericVector< Number > > > & selectPressureGradient(const bool updated_pressure)
Select the right pressure gradient field and return a reference to the container.
std::vector< const MooseLinearVariableFVReal * > _vel
The thread 0 copy of the x-velocity variable.
void initFaceMassFlux()
Initialize the container for face velocities.
LinearFVPressureCorrectionDiffusion * _p_diffusion_kernel
Pointer to the pressure diffusion term in the pressure Poisson equation.
std::vector< unsigned int > _momentum_system_numbers
Numbers of the momentum system(s)
virtual void initialize() override
unsigned int _global_pressure_system_number
Global number of the pressure system.
const MooseLinearVariableFVReal *const _p
The thread 0 copy of the pressure variable.
Real getMassFlux(const FaceInfo &fi) const
Get the face velocity times density (used in advection terms)
std::vector< LinearSystem * > _momentum_systems
Pointers to the linear system(s) in moose corresponding to the momentum equation(s)
std::unique_ptr< NumericVector< Number > > _cell_volumes
We will hold a vector of cell volumes to make sure we can do volume corrections rapidly.
virtual void meshChanged() override
void populateCouplingFunctors(const std::vector< std::unique_ptr< NumericVector< Number > > > &raw_hbya, const std::vector< std::unique_ptr< NumericVector< Number > > > &raw_Ainv)
Populate the face values of the H/A and 1/A fields.
virtual void initialSetup() override
Real getVolumetricFaceFlux(const FaceInfo &fi) const
Get the volumetric face flux (used in advection terms)
void computeHbyA(const bool with_updated_pressure, const bool verbose)
Computes the inverse of the diagonal (1/A) of the system matrix plus the H/A components for the press...
void computeCellVelocity()
Update the cell values of the velocity variables.
void computeFaceMassFlux()
Update the values of the face velocities in the containers.
std::vector< std::unique_ptr< NumericVector< Number > > > _Ainv_raw
We hold on to the cell-based 1/A vectors so that we can easily reconstruct the cell velocities as wel...
const LinearSystem * _pressure_system
Pointer to the pressure system.
std::vector< const FaceInfo * > _flow_face_info
The subset of the FaceInfo objects that actually cover the subdomains which the flow field is defined...
std::vector< std::unique_ptr< NumericVector< Number > > > _HbyA_raw
We hold on to the cell-based HbyA vectors so that we can easily reconstruct the cell velocities as we...
void checkBlocks(const VarType &var) const
Check the block consistency between the passed in var and us.
void setupMeshInformation()
Compute the cell volumes on the mesh.
const Moose::Functor< Real > & _rho
Functor describing the density of the fluid.
std::vector< libMesh::LinearImplicitSystem * > _momentum_implicit_systems
Pointers to the momentum equation implicit system(s) from libmesh.
void initCouplingField()
Initialize the coupling fields (HbyA and Ainv)
FaceCenteredMapFunctor< RealVectorValue, std::unordered_map< dof_id_type, RealVectorValue > > _Ainv
A map functor from faces to $(1/A)_f$.
const unsigned int _dim
The dimension of the mesh, e.g. 3 for hexes and tets, 2 for quads and tris.
RhieChowMassFlux(const InputParameters ¶ms)
FaceCenteredMapFunctor< Real, std::unordered_map< dof_id_type, Real > > & _face_mass_flux
A map functor from faces to mass fluxes which are used in the advection terms.
static InputParameters validParams()
FaceCenteredMapFunctor< Real, std::unordered_map< dof_id_type, Real > > _HbyA_flux
A map functor from faces to $HbyA_{ij} = (A_{offdiag}*\mathrm{(predicted~velocity)} - \mathrm{Source}...
const MooseEnum _pressure_projection_method
Enumerator for the method used for pressure projection.
std::vector< unsigned int > _global_momentum_system_numbers
Global numbers of the momentum system(s)
void linkMomentumPressureSystems(const std::vector< LinearSystem * > &momentum_systems, const LinearSystem &pressure_system, const std::vector< unsigned int > &momentum_system_numbers)
Update the momentum system-related information.
Executioner set up to solve a thermal-hydraulics problem using the SIMPLE algorithm.
virtual const NumericVector< Number > *const & currentSolution() const override final
virtual const MooseVariableFieldBase & getVariable(const THREAD_ID tid, const std::string &var_name, Moose::VarKindType expected_var_type=Moose::VarKindType::VAR_ANY, Moose::VarFieldType expected_var_field_type=Moose::VarFieldType::VAR_FIELD_ANY) const=0
void addFunctor(const std::string &name, const Moose::FunctorBase< T > &functor, const THREAD_ID tid)
unsigned int number() const
FEProblemBase & _fe_problem
subdomain_id_type subdomain_id() const
NumericVector< Number > * rhs
SparseMatrix< Number > * matrix
virtual void pointwise_mult(const NumericVector< T > &vec1, const NumericVector< T > &vec2)=0
virtual void print(std::ostream &os=libMesh::out) const
virtual std::unique_ptr< NumericVector< T > > zero_clone() const=0
virtual void add(const numeric_index_type i, const T value)=0
virtual void pointwise_divide(const NumericVector< T > &vec1, const NumericVector< T > &vec2)=0
virtual numeric_index_type local_m() const final
virtual numeric_index_type row_start() const override
virtual void get_row(numeric_index_type i, std::vector< numeric_index_type > &indices, std::vector< T > &values) const override
virtual void get_diagonal(NumericVector< T > &dest) const override
virtual void pointwise_mult(const NumericVector< T > &vec1, const NumericVector< T > &vec2) override
virtual void pointwise_divide(const NumericVector< T > &vec1, const NumericVector< T > &vec2) override
void vector_mult(NumericVector< T > &dest, const NumericVector< T > &arg) const
void print(std::ostream &os=libMesh::out, const bool sparse=false) const
std::unique_ptr< NumericVector< Number > > current_local_solution
std::unique_ptr< NumericVector< Number > > solution
static const std::string density
static const std::string pressure
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
auto index_range(const T &sizable)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)