https://mooseframework.inl.gov
Loading...
Searching...
No Matches
INSFVMomentumAdvection.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
11#include "NS.h"
12#include "FVUtils.h"
14#include "SystemBase.h"
15#include "NSFVUtils.h"
16
18
21{
22 auto params = emptyInputParameters();
23 params.addParam<Real>(
24 "characteristic_speed",
25 "The characteristic speed. For porous medium simulations, this characteristic speed should "
26 "correspond to the superficial velocity, not the interstitial.");
27 return params;
28}
29
30std::vector<std::string>
32{
33 return {"characteristic_speed"};
34}
35
38{
42 params.addRequiredParam<MooseFunctorName>(NS::density, "Density functor");
43 params.addClassDescription("Object for advecting momentum, e.g. rho*u");
44 return params;
45}
46
48 : INSFVAdvectionKernel(params),
50 _rho(getFunctor<ADReal>(NS::density)),
51 _approximate_as(isParamValid("characteristic_speed")),
52 _cs(_approximate_as ? getParam<Real>("characteristic_speed") : 0)
53{
54}
55
56void
58{
60
61 _rho_u = std::make_unique<PiecewiseByBlockLambdaFunctor<ADReal>>(
62 "rho_u",
63 [this](const auto & r, const auto & t) -> ADReal
64 { return _rho(r, t) * _var(r, t) / epsilon()(r, t); },
65 std::set<ExecFlagType>({EXEC_ALWAYS}),
66 _mesh,
67 this->blockIDs());
68}
69
72{
73 mooseError("Should never be called");
74}
75
76void
78{
79 mooseAssert(!skipForBoundary(fi),
80 "We shouldn't get in here if we're supposed to skip for a boundary");
81
82 _face_info = &fi;
83 _normal = fi.normal();
84 _face_type = fi.faceType(std::make_pair(_var.number(), _var.sys().number()));
85 const auto state = determineState();
86
87 using namespace Moose::FV;
88
89 const bool correct_skewness = _advected_interp_method == InterpMethod::SkewCorrectedAverage;
90 const bool on_boundary = onBoundary(fi);
91
92 _elem_residual = 0, _neighbor_residual = 0, _ae = 0, _an = 0;
93
94 const auto v_face = velocity();
95 const auto vdotn = _normal * v_face;
96
97 if (on_boundary)
98 {
99 const auto ssf = singleSidedFaceArg();
100 const Elem * const sided_elem = ssf.face_side;
101 const auto dof_number = sided_elem->dof_number(_sys.number(), _var.number(), 0);
102 const auto rho_face = _rho(ssf, state);
103 const auto eps_face = epsilon()(ssf, state);
104 const auto u_face = _var(ssf, state);
105 const Real d_u_face_d_dof = u_face.derivatives()[dof_number];
106 const auto coeff = vdotn * rho_face / eps_face;
107
108 if (sided_elem == fi.elemPtr())
109 {
110 _ae = coeff * d_u_face_d_dof;
111 _elem_residual = coeff * u_face;
112 if (_approximate_as)
113 _ae = _cs / fi.elem().n_sides() * rho_face / eps_face;
114 }
115 else
116 {
117 _an = -coeff * d_u_face_d_dof;
118 _neighbor_residual = -coeff * u_face;
119 if (_approximate_as)
120 _an = _cs / fi.neighborPtr()->n_sides() * rho_face / eps_face;
121 }
122 }
123 else // we are an internal fluid flow face
124 {
125 const bool elem_is_upwind = MetaPhysicL::raw_value(v_face) * _normal > 0;
126 const auto & limiter_time = _subproblem.isTransient()
127 ? Moose::StateArg(1, Moose::SolutionIterationType::Time)
128 : Moose::StateArg(1, Moose::SolutionIterationType::Nonlinear);
129 const Moose::FaceArg advected_face_arg{&fi,
130 limiterType(_advected_interp_method),
131 elem_is_upwind,
132 correct_skewness,
133 nullptr,
134 &limiter_time};
135 if (const auto [is_jump, eps_elem_face, eps_neighbor_face] =
136 NS::isPorosityJumpFace(epsilon(), fi, state);
137 is_jump)
138 {
139 // For a weakly compressible formulation, the density should not depend on pressure and
140 // consequently the density should not be impacted by the pressure jump that occurs at a
141 // porosity jump. Consequently we will allow evaluation of the density using both upstream and
142 // downstream information
143 const auto rho_face = _rho(advected_face_arg, state);
144
145 // We set the + and - sides of the superficial velocity equal to the interpolated value
146 const auto & var_elem_face = v_face(_index);
147 const auto & var_neighbor_face = v_face(_index);
148
149 const auto elem_dof_number = fi.elem().dof_number(_sys.number(), _var.number(), 0);
150 const auto neighbor_dof_number = fi.neighbor().dof_number(_sys.number(), _var.number(), 0);
151
152 const auto d_var_elem_face_d_elem_dof = var_elem_face.derivatives()[elem_dof_number];
153 const auto d_var_neighbor_face_d_neighbor_dof =
154 var_neighbor_face.derivatives()[neighbor_dof_number];
155
156 // We allow a discontintuity in the advective momentum flux at the jump face. Mainly the
157 // advective flux is:
158 // elem side:
159 // rho * v_superficial / eps_elem * v_superficial = rho * v_interstitial_elem * v_superficial
160 // neighbor side:
161 // rho * v_superficial / eps_neigh * v_superficial = rho * v_interstitial_neigh *
162 // v_superficial
163 const auto elem_coeff = vdotn * rho_face / eps_elem_face;
164 const auto neighbor_coeff = vdotn * rho_face / eps_neighbor_face;
165 _ae = elem_coeff * d_var_elem_face_d_elem_dof;
166 _elem_residual = elem_coeff * var_elem_face;
167 _an = -neighbor_coeff * d_var_neighbor_face_d_neighbor_dof;
168 _neighbor_residual = -neighbor_coeff * var_neighbor_face;
169 if (_approximate_as)
170 {
171 _ae = _cs / fi.elem().n_sides() * rho_face / eps_elem_face;
172 _an = _cs / fi.neighborPtr()->n_sides() * rho_face / eps_elem_face;
173 }
174 }
175 else
176 {
177 const auto [interp_coeffs, advected] =
178 interpCoeffsAndAdvected(*_rho_u, advected_face_arg, state);
179
180 const auto elem_arg = elemArg();
181 const auto neighbor_arg = neighborArg();
182
183 const auto rho_elem = _rho(elem_arg, state), rho_neighbor = _rho(neighbor_arg, state);
184 const auto eps_elem = epsilon()(elem_arg, state),
185 eps_neighbor = epsilon()(neighbor_arg, state);
186 const auto var_elem = advected.first / rho_elem * eps_elem,
187 var_neighbor = advected.second / rho_neighbor * eps_neighbor;
188
189 _ae = vdotn * rho_elem / eps_elem * interp_coeffs.first;
190 // Minus sign because we apply a minus sign to the residual in computeResidual
191 _an = -vdotn * rho_neighbor / eps_neighbor * interp_coeffs.second;
192
193 _elem_residual = _ae * var_elem - _an * var_neighbor;
195
196 if (_approximate_as)
197 {
198 _ae = _cs / fi.elem().n_sides() * rho_elem / eps_elem;
199 _an = _cs / fi.neighborPtr()->n_sides() * rho_neighbor / eps_neighbor;
200 }
201 }
202 }
203
204 _ae *= fi.faceArea() * fi.faceCoord();
205 _an *= fi.faceArea() * fi.faceCoord();
206 _elem_residual *= fi.faceArea() * fi.faceCoord();
208}
209
210void
212{
213 if (skipForBoundary(fi))
214 return;
215
217
218 if (_face_type == FaceInfo::VarFaceNeighbors::ELEM ||
219 _face_type == FaceInfo::VarFaceNeighbors::BOTH)
220 {
221 // residual contribution of this kernel to the elem element
225 }
226
227 if (_face_type == FaceInfo::VarFaceNeighbors::NEIGHBOR ||
228 _face_type == FaceInfo::VarFaceNeighbors::BOTH)
229 {
230 // residual contribution of this kernel to the neighbor element
234 }
235}
236
237void
239{
240 if (skipForBoundary(fi))
241 return;
242
244
245 if (_face_type == FaceInfo::VarFaceNeighbors::ELEM ||
246 _face_type == FaceInfo::VarFaceNeighbors::BOTH)
247 {
248 mooseAssert(_var.dofIndices().size() == 1, "We're currently built to use CONSTANT MONOMIALS");
249
251 std::array<ADReal, 1>{{_elem_residual}},
254 }
255
256 if (_face_type == FaceInfo::VarFaceNeighbors::NEIGHBOR ||
257 _face_type == FaceInfo::VarFaceNeighbors::BOTH)
258 {
259 mooseAssert((_face_type == FaceInfo::VarFaceNeighbors::NEIGHBOR) ==
260 (_var.dofIndices().size() == 0),
261 "If the variable is only defined on the neighbor hand side of the face, then that "
262 "means it should have no dof indices on the elem element. Conversely if "
263 "the variable is defined on both sides of the face, then it should have a non-zero "
264 "number of degrees of freedom on the elem element");
265
266 mooseAssert(_var.dofIndicesNeighbor().size() == 1,
267 "We're currently built to use CONSTANT MONOMIALS");
268
270 std::array<ADReal, 1>{{_neighbor_residual}},
273 }
274}
275
276void
278{
279 if (skipForBoundary(fi))
280 return;
281
282 const auto saved_velocity_interp_method = _velocity_interp_method;
283 _velocity_interp_method = Moose::FV::InterpMethod::Average;
284 // Fill-in the coefficients _ae and _an
286 _velocity_interp_method = saved_velocity_interp_method;
287
288 if (_face_type == FaceInfo::VarFaceNeighbors::ELEM ||
289 _face_type == FaceInfo::VarFaceNeighbors::BOTH)
290 _rc_uo.addToA(&fi.elem(), _index, _ae);
291 if (_face_type == FaceInfo::VarFaceNeighbors::NEIGHBOR ||
292 _face_type == FaceInfo::VarFaceNeighbors::BOTH)
294}
DualNumber< Real, DNDerivativeType, true > ADReal
registerMooseObject("NavierStokesApp", INSFVMomentumAdvection)
InputParameters emptyInputParameters()
const ExecFlagType EXEC_ALWAYS
virtual const std::set< SubdomainID > & blockIDs() const
Moose::ElemArg neighborArg(bool correct_skewness=false) const
Moose::ElemArg elemArg(bool correct_skewness=false) const
RealVectorValue _normal
void computeJacobian() override
bool onBoundary(const FaceInfo &fi) const
MooseVariableFV< Real > & _var
Moose::FaceArg singleSidedFaceArg(const FaceInfo *fi=nullptr, Moose::FV::LimiterType limiter_type=Moose::FV::LimiterType::CentralDifference, bool correct_skewness=false, const Moose::StateArg *state_limiter=nullptr) const
void computeResidual() override
const FaceInfo * _face_info
FaceInfo::VarFaceNeighbors _face_type
const Point & normal() const
VarFaceNeighbors faceType(const std::pair< unsigned int, unsigned int > &var_sys) const
const Elem & elem() const
const Elem * neighborPtr() const
Real faceArea() const
Real & faceCoord()
const Elem * elemPtr() const
const Elem & neighbor() const
An advection kernel that implements interpolation schemes specific to Navier-Stokes flow physics.
bool skipForBoundary(const FaceInfo &fi) const override
ADRealVectorValue velocity() const
Moose::FV::InterpMethod _velocity_interp_method
The interpolation method to use for the velocity.
Moose::FV::InterpMethod _advected_interp_method
The interpolation method to use for the advected quantity.
static InputParameters validParams()
An advection kernel that implements interpolation schemes specific to Navier-Stokes flow physics.
void gatherRCData(const Elem &) override final
Should be a non-empty implementation if the residual object is a FVElementalKernel and introduces res...
const Real _cs
Characteristic speed.
ADReal _an
The a coefficient for the neighbor.
ADReal _elem_residual
The element residual.
static InputParameters uniqueParams()
Parameters of this object that should be added to the NSFV action that are unique to this object.
std::unique_ptr< PiecewiseByBlockLambdaFunctor< ADReal > > _rho_u
Our local momentum functor.
static InputParameters validParams()
const Moose::Functor< ADReal > & _rho
Density.
virtual const Moose::FunctorBase< ADReal > & epsilon() const
A virtual method that allows us to reuse all the code from free-flow for porous.
virtual void computeResidualsAndAData(const FaceInfo &fi)
Helper method that computes the 'a' coefficients and AD residuals.
virtual ADReal computeQpResidual() override final
INSFVMomentumAdvection(const InputParameters &params)
const bool _approximate_as
Whether to approximately calculate the 'a' coefficients.
static std::vector< std::string > listOfCommonParams()
ADReal _neighbor_residual
The neighbor residual.
ADReal _ae
The a coefficient for the element.
All objects that contribute to pressure-based (e.g.
const unsigned int _index
index x|y|z
RhieChowInterpolatorBase & _rc_uo
The Rhie Chow user object that is responsible for generating face velocities for advection terms.
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
void mooseError(Args &&... args) const
void scalingFactor(const std::vector< Real > &factor)
SystemBase & sys()
unsigned int number() const
virtual const std::vector< dof_id_type > & dofIndices() const final
virtual const std::vector< dof_id_type > & dofIndicesNeighbor() const final
MooseMesh & _mesh
Assembly & _assembly
SubProblem & _subproblem
SystemBase & _sys
virtual void addToA(const libMesh::Elem *elem, unsigned int component, const ADReal &value)=0
API for momentum residual objects that have on-diagonals for velocity call.
virtual bool isTransient() const=0
unsigned int number() const
void accumulateTaggedLocalResidual()
void addResidualsAndJacobian(Assembly &assembly, const Residuals &residuals, const Indices &dof_indices, Real scaling_factor)
void prepareVectorTagNeighbor(Assembly &assembly, unsigned int ivar)
void prepareVectorTag(Assembly &assembly, unsigned int ivar)
DenseVector< Number > _local_re
Moose::StateArg determineState() const
auto raw_value(const Eigen::Map< T > &in)
static const std::string density
Definition NS.h:34
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.
Definition NSFVUtils.C:119