https://mooseframework.inl.gov
INSFVRhieChowInterpolatorSegregated.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 "INSFVAttributes.h"
12 #include "SubProblem.h"
13 #include "MooseMesh.h"
14 #include "NS.h"
15 #include "Assembly.h"
16 #include "INSFVVelocityVariable.h"
17 #include "INSFVPressureVariable.h"
19 #include "VectorCompositeFunctor.h"
21 
22 #include "libmesh/mesh_base.h"
23 #include "libmesh/elem_range.h"
24 #include "metaphysicl/dualsemidynamicsparsenumberarray.h"
25 
26 #include "NonlinearSystem.h"
27 #include "libmesh/petsc_matrix.h"
28 #include "libmesh/petsc_vector.h"
29 
30 using namespace libMesh;
31 
33 
36 {
38 
39  params.addClassDescription("Computes H/A and 1/A together with face velocities for segregated "
40  "momentum-pressure equations.");
41 
42  // We disable the execution of this, should only provide functions
43  // for the SIMPLENonlinearAssembly executioner
44  ExecFlagEnum & exec_enum = params.set<ExecFlagEnum>("execute_on", true);
45  exec_enum.addAvailableFlags(EXEC_NONE);
46  exec_enum = {EXEC_NONE};
47  params.suppressParameter<ExecFlagEnum>("execute_on");
48 
49  return params;
50 }
51 
53  const InputParameters & params)
54  : RhieChowInterpolatorBase(params),
55  _HbyA(_moose_mesh, blockIDs(), "HbyA"),
56  _Ainv(_moose_mesh, blockIDs(), "Ainv", false),
58  name(),
59  [this](const auto & r, const auto & t) -> ADRealVectorValue
60  {
61  ADRealVectorValue velocity((*_u)(r, t));
62  if (_dim >= 2)
63  velocity(1) = (*_v)(r, t);
64  if (_dim >= 3)
65  velocity(2) = (*_w)(r, t);
66  return velocity;
67  },
68  std::set<ExecFlagType>({EXEC_ALWAYS}),
69  _moose_mesh,
70  blockIDs())),
71  _face_velocity(_moose_mesh, blockIDs(), "face_values")
72 {
73  if (_displaced)
74  paramError("use_displaced_mesh",
75  "The segregated Rhie-Chow user object does not currently support operation on a "
76  "displaced mesh");
77 
78  // Register the elemental/face functors which will be queried in the pressure equation
79  for (const auto tid : make_range(libMesh::n_threads()))
80  {
81  UserObject::_subproblem.addFunctor("Ainv", _Ainv, tid);
82  UserObject::_subproblem.addFunctor("HbyA", _HbyA, tid);
83  }
84 
85  if (_velocity_interp_method == Moose::FV::InterpMethod::Average)
86  paramError("velocity_interp_method",
87  "Segregated momentum-pressure solvers do not allow average interpolation methods!");
88 
89  if (!dynamic_cast<SIMPLENonlinearAssembly *>(getMooseApp().getExecutioner()))
90  mooseError(this->name(), " should only be used with a segregated thermal-hydraulics solver!");
91 }
92 
93 void
95  std::vector<NonlinearSystemBase *> momentum_systems,
96  const std::vector<unsigned int> & momentum_system_numbers,
97  const TagID pressure_gradient_tag)
98 {
99  _momentum_systems = momentum_systems;
100  _momentum_system_numbers = momentum_system_numbers;
101  _pressure_gradient_tag = pressure_gradient_tag;
102 
104  for (auto & system : _momentum_systems)
105  _momentum_implicit_systems.push_back(
106  dynamic_cast<NonlinearImplicitSystem *>(&system->system()));
107 }
108 
109 void
111 {
112  _HbyA.clear();
113  _Ainv.clear();
114  _face_velocity.clear();
115 }
116 
117 void
119 {
120  for (const auto & pair : _HbyA)
121  _HbyA[pair.first] = 0;
122 
123  for (const auto & pair : _Ainv)
124  _Ainv[pair.first] = 0;
125 }
126 
127 void
129 {
130  for (auto & fi : _fe_problem.mesh().faceInfo())
131  {
132  if (hasBlocks(fi->elemPtr()->subdomain_id()) ||
133  (fi->neighborPtr() && hasBlocks(fi->neighborPtr()->subdomain_id())))
134  {
135  // On internal face we do a regular interpoaltion with geometric weights
136  if (_u->isInternalFace(*fi))
137  {
138  const Moose::FaceArg face{
139  fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr};
140 
142  }
143  // On the boundary, we just take the boundary values
144  else
145  {
146  const Elem * const boundary_elem =
147  hasBlocks(fi->elemPtr()->subdomain_id()) ? fi->elemPtr() : fi->neighborPtr();
148 
149  const Moose::FaceArg boundary_face{
150  fi, Moose::FV::LimiterType::CentralDifference, true, false, boundary_elem, nullptr};
151 
152  _face_velocity[fi->id()] =
153  MetaPhysicL::raw_value((*_vel)(boundary_face, Moose::currentState()));
154  }
155  }
156  }
157 }
158 
161  const FaceInfo & fi,
162  const Moose::StateArg & /*time*/,
163  const THREAD_ID /*tid*/,
164  const bool /*subtract_mesh_velocity*/) const
165 {
167  mooseError("Segregated solution algorithms only support Rhie-Chow interpolation!");
168  return _face_velocity.evaluate(&fi);
169 }
170 
171 void
173 {
174  const auto time_arg = Moose::currentState();
175 
176  for (auto & fi : _fe_problem.mesh().faceInfo())
177  {
178  if (hasBlocks(fi->elemPtr()->subdomain_id()) ||
179  (fi->neighborPtr() && hasBlocks(fi->neighborPtr()->subdomain_id())))
180  {
181  // On internal face we just use the interpolated H/A and the pressure face gradient
182  // So u_f = -(H/A)_f - (1/A)_f*grad(p)_f
183  // Notice the (-) sign on H/A which is because we use the Jacobian/Residual
184  // computations and we get -H instead of H.
185  if (_u->isInternalFace(*fi))
186  {
187  const Moose::FaceArg face{
188  fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr};
189 
190  RealVectorValue Ainv;
191  RealVectorValue HbyA = MetaPhysicL::raw_value(_HbyA(face, time_arg));
192 
194  Ainv,
195  _Ainv(makeElemArg(fi->elemPtr()), time_arg),
196  _Ainv(makeElemArg(fi->neighborPtr()), time_arg),
197  *fi,
198  true);
199 
200  RealVectorValue grad_p = MetaPhysicL::raw_value(_p->gradient(face, time_arg));
201  for (const auto comp_index : make_range(_dim))
202  _face_velocity[fi->id()](comp_index) =
203  -HbyA(comp_index) - Ainv(comp_index) * grad_p(comp_index);
204  }
205  else
206  {
207  const Elem * const boundary_elem =
208  hasBlocks(fi->elemPtr()->subdomain_id()) ? fi->elemPtr() : fi->neighborPtr();
209  const Moose::FaceArg boundary_face{
210  fi, Moose::FV::LimiterType::CentralDifference, true, false, boundary_elem, nullptr};
211 
212  // If we have a dirichlet boundary conditions, this sill give us the exact value of the
213  // velocity on the face as expected (see populateHbyA())
214  if (_u->isDirichletBoundaryFace(*fi, boundary_elem, time_arg))
215  _face_velocity[fi->id()] = -MetaPhysicL::raw_value(_HbyA(boundary_face, time_arg));
216  else
217  {
218  const RealVectorValue & Ainv = MetaPhysicL::raw_value(_Ainv(boundary_face, time_arg));
219  const RealVectorValue & HbyA = MetaPhysicL::raw_value(_HbyA(boundary_face, time_arg));
220  const RealVectorValue & grad_p =
221  MetaPhysicL::raw_value(_p->gradient(boundary_face, time_arg));
222  for (const auto comp_index : make_range(_dim))
223  _face_velocity[fi->id()](comp_index) =
224  -HbyA(comp_index) - Ainv(comp_index) * grad_p(comp_index);
225  }
226  }
227  }
228  }
229 }
230 
231 void
233 {
234  std::vector<unsigned int> var_nums = {_momentum_implicit_systems[0]->variable_number(_u->name())};
235  if (_v)
236  var_nums.push_back(_momentum_implicit_systems[1]->variable_number(_v->name()));
237  if (_w)
238  var_nums.push_back(_momentum_implicit_systems[2]->variable_number(_w->name()));
239 
240  const auto time_arg = Moose::currentState();
241 
242  for (auto & elem :
243  as_range(_mesh.active_local_elements_begin(), _mesh.active_local_elements_end()))
244  {
245  if (hasBlocks(elem->subdomain_id()))
246  {
247  const auto elem_arg = makeElemArg(elem);
248  const RealVectorValue Ainv = _Ainv(elem_arg, time_arg);
249  const RealVectorValue & grad_p = raw_value(_p->gradient(elem_arg, time_arg));
250 
251  for (auto comp_index : make_range(_dim))
252  {
253  // If we are doing segregated momentum components we need to access different vector
254  // components otherwise everything is in the same vector (with different variable names)
255  const unsigned int system_number = _momentum_implicit_systems[comp_index]->number();
256  const auto index = elem->dof_number(system_number, var_nums[comp_index], 0);
257 
258  // We set the dof value in the solution vector the same logic applies:
259  // u_C = -(H/A)_C - (1/A)_C*grad(p)_C where C is the cell index
260  _momentum_implicit_systems[comp_index]->solution->set(
261  index, -(*_HbyA_raw[comp_index])(index)-Ainv(comp_index) * grad_p(comp_index));
262  }
263  }
264  }
265 
266  for (auto system_i : index_range(_momentum_implicit_systems))
267  {
268  _momentum_implicit_systems[system_i]->solution->close();
269  _momentum_implicit_systems[system_i]->update();
270  _momentum_systems[system_i]->setSolution(
271  *_momentum_implicit_systems[system_i]->current_local_solution);
272  }
273 }
274 
275 void
277  const std::vector<std::unique_ptr<NumericVector<Number>>> & raw_hbya,
278  const std::vector<unsigned int> & var_nums)
279 {
280  for (auto & fi : _fe_problem.mesh().faceInfo())
281  {
282  if (hasBlocks(fi->elemPtr()->subdomain_id()) ||
283  (fi->neighborPtr() && hasBlocks(fi->neighborPtr()->subdomain_id())))
284  {
285  // If we are on an internal face, we just interpolate the values to the faces.
286  // Otherwise, depending on the boundary type, we take the velocity value or
287  // extrapolated HbyA values.
288  if (_u->isInternalFace(*fi))
289  {
290  const Elem * elem = fi->elemPtr();
291  const Elem * neighbor = fi->neighborPtr();
292  for (auto comp_index : make_range(_dim))
293  {
294  unsigned int system_number = _momentum_implicit_systems[comp_index]->number();
295  const auto dof_index_elem = elem->dof_number(system_number, var_nums[comp_index], 0);
296  const auto dof_index_neighbor =
297  neighbor->dof_number(system_number, var_nums[comp_index], 0);
298 
300  _HbyA[fi->id()](comp_index),
301  (*raw_hbya[comp_index])(dof_index_elem),
302  (*raw_hbya[comp_index])(dof_index_neighbor),
303  *fi,
304  true);
305  }
306  }
307  else
308  {
309  const Elem * const boundary_elem =
310  hasBlocks(fi->elemPtr()->subdomain_id()) ? fi->elemPtr() : fi->neighborPtr();
311 
312  const Moose::FaceArg boundary_face{
313  fi, Moose::FV::LimiterType::CentralDifference, true, false, boundary_elem, nullptr};
314 
315  if (_u->isDirichletBoundaryFace(*fi, boundary_elem, Moose::currentState()))
316  _HbyA[fi->id()] = -MetaPhysicL::raw_value((*_vel)(boundary_face, Moose::currentState()));
317  else
318  for (const auto comp_index : make_range(_dim))
319  {
320  unsigned int system_number = _momentum_implicit_systems[comp_index]->number();
321  const auto dof_index_elem =
322  boundary_elem->dof_number(system_number, var_nums[comp_index], 0);
323  _HbyA[fi->id()](comp_index) = (*raw_hbya[comp_index])(dof_index_elem);
324  }
325  }
326  }
327  }
328 }
329 
330 void
332 {
333  if (verbose)
334  {
335  _console << "************************************" << std::endl;
336  _console << "Computing HbyA" << std::endl;
337  _console << "************************************" << std::endl;
338  }
340  "The momentum system shall be linked before calling this function!");
341 
343 
344  std::vector<unsigned int> var_nums = {_momentum_implicit_systems[0]->variable_number(_u->name())};
345  if (_v)
346  var_nums.push_back(_momentum_implicit_systems[1]->variable_number(_v->name()));
347  if (_w)
348  var_nums.push_back(_momentum_implicit_systems[2]->variable_number(_w->name()));
349 
350  _HbyA_raw.clear();
351  for (auto system_i : index_range(_momentum_systems))
352  {
354 
355  momentum_system = _momentum_implicit_systems[system_i];
356 
357  NumericVector<Number> & rhs = *(momentum_system->rhs);
358  NumericVector<Number> & current_local_solution = *(momentum_system->current_local_solution);
359  NumericVector<Number> & solution = *(momentum_system->solution);
360  PetscMatrix<Number> * mmat = dynamic_cast<PetscMatrix<Number> *>(momentum_system->matrix);
361  mooseAssert(mmat,
362  "The matrices used in the segregated INSFVRhieChow objects need to be convertable "
363  "to PetscMAtrix!");
364 
365  if (verbose)
366  {
367  _console << "Matrix in rc object" << std::endl;
368  mmat->print();
369  }
370 
371  auto Ainv = current_local_solution.zero_clone();
372  PetscVector<Number> * Ainv_petsc = dynamic_cast<PetscVector<Number> *>(Ainv.get());
373 
374  mmat->get_diagonal(*Ainv_petsc);
375 
376  auto working_vector = momentum_system->current_local_solution->zero_clone();
377  PetscVector<Number> * working_vector_petsc =
378  dynamic_cast<PetscVector<Number> *>(working_vector.get());
379  mooseAssert(working_vector_petsc,
380  "The vectors used in the segregated INSFVRhieChow objects need to be convertable "
381  "to PetscVectors!");
382 
383  *working_vector_petsc = 1.0;
384  Ainv_petsc->pointwise_divide(*working_vector_petsc, *Ainv_petsc);
385 
386  _HbyA_raw.push_back(current_local_solution.zero_clone());
387  NumericVector<Number> & HbyA = *(_HbyA_raw.back());
388 
389  if (verbose)
390  {
391  _console << "Velocity solution in H(u)" << std::endl;
392  solution.print();
393  }
394 
395  // We fill the 1/A functor
396  auto active_local_begin =
397  _mesh.evaluable_elements_begin(momentum_system->get_dof_map(), var_nums[system_i]);
398  auto active_local_end =
399  _mesh.evaluable_elements_end(momentum_system->get_dof_map(), var_nums[system_i]);
400 
401  const auto & state = Moose::currentState();
402  for (auto it = active_local_begin; it != active_local_end; ++it)
403  {
404  const Elem * elem = *it;
405  if (this->hasBlocks(elem->subdomain_id()))
406  {
407  const Moose::ElemArg & elem_arg = makeElemArg(elem);
408  Real coord_multiplier;
409  const auto coord_type = _fe_problem.getCoordSystem(elem->subdomain_id());
410  const unsigned int rz_radial_coord =
412 
414  elem->vertex_average(), coord_multiplier, coord_type, rz_radial_coord);
415 
416  const Real volume = _moose_mesh.elemInfo(elem->id()).volume();
417  const auto dof_index = elem->dof_number(momentum_system->number(), var_nums[system_i], 0);
418  _Ainv[elem->id()](system_i) = MetaPhysicL::raw_value(epsilon(_tid)(elem_arg, state)) *
419  (*Ainv_petsc)(dof_index)*volume * coord_multiplier;
420  }
421  }
422 
423  // Now we set the diagonal of our system matrix to 0 so we can create H*u
424  // TODO: Add a function for this in libmesh
425  *working_vector_petsc = 0.0;
426  LibmeshPetscCall(MatDiagonalSet(mmat->mat(), working_vector_petsc->vec(), INSERT_VALUES));
427 
428  if (verbose)
429  {
430  _console << "H" << std::endl;
431  mmat->print();
432  }
433 
434  // We need to subtract the contribution of the pressure gradient from the residual (right hand
435  // side). We plug working_vector=0 in here to get the right hand side contribution
436  _fe_problem.computeResidualTag(*working_vector, HbyA, _pressure_gradient_tag);
437 
438  // Now we reorganize the association between tags and vectors to make sure
439  // that the next solve is perfect
440  _momentum_systems[system_i]->associateVectorToTag(
441  momentum_system->get_vector(_fe_problem.vectorTagName(0)), 0);
442  _momentum_systems[system_i]->associateVectorToTag(
443  momentum_system->get_vector(_fe_problem.vectorTagName(_pressure_gradient_tag)),
445  _momentum_systems[system_i]->setSolution(current_local_solution);
446 
447  if (verbose)
448  {
449  _console << "total RHS" << std::endl;
450  rhs.print();
451  _console << "pressure RHS" << std::endl;
452  HbyA.print();
453  }
454 
455  // We correct the right hand side to exclude the pressure contribution
456  HbyA.scale(-1.0);
457  HbyA.add(-1.0, rhs);
458 
459  if (verbose)
460  {
461  _console << "H RHS" << std::endl;
462  HbyA.print();
463  }
464 
465  // Create H(u)
466  mmat->vector_mult(*working_vector_petsc, solution);
467 
468  if (verbose)
469  {
470  _console << " H(u)" << std::endl;
471  working_vector_petsc->print();
472  }
473 
474  // Create H(u) - RHS
475  HbyA.add(*working_vector_petsc);
476 
477  if (verbose)
478  {
479  _console << " H(u)-rhs-relaxation_source" << std::endl;
480  HbyA.print();
481  }
482 
483  // Create 1/A*(H(u)-RHS)
484  HbyA.pointwise_mult(HbyA, *Ainv);
485 
486  if (verbose)
487  {
488  _console << " (H(u)-rhs)/A" << std::endl;
489  HbyA.print();
490  }
491  }
492 
493  populateHbyA(_HbyA_raw, var_nums);
494 
495  if (verbose)
496  {
497  _console << "************************************" << std::endl;
498  _console << "DONE Computing HbyA " << std::endl;
499  _console << "************************************" << std::endl;
500  }
501 }
unsigned int getAxisymmetricRadialCoord() const
registerMooseObject("NavierStokesApp", INSFVRhieChowInterpolatorSegregated)
INSFVPressureVariable *const _p
The thread 0 copy of the pressure variable.
std::vector< libMesh::NonlinearImplicitSystem * > _momentum_implicit_systems
Pointers to the momentum equation implicit system(s)
dof_id_type dof_number(const unsigned int s, const unsigned int var, const unsigned int comp) const
std::vector< NonlinearSystemBase * > _momentum_systems
Pointers to the nonlinear system(s) corresponding to the momentum equation(s)
std::vector< unsigned int > _momentum_system_numbers
Numbers of the momentum system(s)
unsigned int n_threads()
const unsigned int invalid_uint
unsigned int TagID
MooseMesh & _moose_mesh
The MooseMesh that this user object operates on.
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...
void mooseError(Args &&... args)
INSFVVelocityVariable *const _u
The thread 0 copy of the x-velocity variable.
void vector_mult(NumericVector< T > &dest, const NumericVector< T > &arg) const
void coordTransformFactor(const P &point, C &factor, const Moose::CoordinateSystemType coord_type, const unsigned int rz_radial_coord=libMesh::invalid_uint)
INSFVVelocityVariable *const _v
The thread 0 copy of the y-velocity variable (null if the problem is 1D)
virtual std::unique_ptr< NumericVector< T > > zero_clone() const=0
const ExecFlagType EXEC_NONE
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
Get the face velocity (used in advection terms)
void addFunctor(const std::string &name, const Moose::FunctorBase< T > &functor, const THREAD_ID tid)
auto raw_value(const Eigen::Map< T > &in)
const std::string & name() const override
void addAvailableFlags(const ExecFlagType &flag, Args... flags)
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
const ExecFlagType EXEC_ALWAYS
virtual void pointwise_divide(const NumericVector< T > &vec1, const NumericVector< T > &vec2) override
CellCenteredMapFunctor< RealVectorValue, std::unordered_map< dof_id_type, RealVectorValue > > _Ainv
A map functor from element IDs to $1/A_i$.
SubProblem & _subproblem
virtual bool isDirichletBoundaryFace(const FaceInfo &fi, const Elem *elem, const Moose::StateArg &state) const
Moose::ElemArg makeElemArg(const Elem *elem, bool correct_skewnewss=false) const
virtual void scale(const T factor)=0
void computeFaceVelocity()
Update the values of the face velocities in the containers.
bool isInternalFace(const FaceInfo &) const
const std::vector< const FaceInfo *> & faceInfo() const
void setCurrentNonlinearSystem(const unsigned int nl_sys_num)
dof_id_type id() const
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...
FaceCenteredMapFunctor< RealVectorValue, std::unordered_map< dof_id_type, RealVectorValue > > _face_velocity
A map functor from faces to face velocities which are used in the advection terms.
const std::string name
Definition: Setup.h:20
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
const unsigned int _dim
The dimension of the mesh, e.g. 3 for hexes and tets, 2 for quads and tris.
virtual void print(std::ostream &os=libMesh::out) const
Real volume(const MeshBase &mesh, unsigned int dim=libMesh::invalid_uint)
void populateHbyA(const std::vector< std::unique_ptr< NumericVector< Number >>> &raw_hbya, const std::vector< unsigned int > &var_nums)
Populate the face values of the H/A field.
const libMesh::MeshBase & _mesh
The libMesh mesh that this object acts on.
virtual void pointwise_mult(const NumericVector< T > &vec1, const NumericVector< T > &vec2)=0
virtual void get_diagonal(NumericVector< T > &dest) const override
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
subdomain_id_type subdomain_id() const
INSFVVelocityVariable *const _w
The thread 0 copy of the z-velocity variable (null if the problem is not 3D)
FEProblemBase & _fe_problem
FaceCenteredMapFunctor< RealVectorValue, std::unordered_map< dof_id_type, RealVectorValue > > _HbyA
A map functor from faces to $HbyA_{ij} = (A_{offdiag}*{(predicted~velocity)} - {Source})_{ij}/A_{ij}$...
GradientType gradient(const ElemArg &elem, const StateArg &state) const
const THREAD_ID _tid
IntRange< T > make_range(T beg, T end)
virtual MooseMesh & mesh() override
void computeCellVelocity()
Update the cell values of the velocity variables.
TagID _pressure_gradient_tag
Residual tag corresponding to the pressure gradient contribution.
void mooseError(Args &&... args) const
Moose::CoordinateSystemType getCoordSystem(SubdomainID sid) const
static const std::string velocity
Definition: NS.h:45
virtual TagName vectorTagName(const TagID tag) const
const ConsoleStream _console
bool hasBlocks(const SubdomainName &name) const
std::unique_ptr< PiecewiseByBlockLambdaFunctor< ADRealVectorValue > > _vel
A functor for computing the (non-RC corrected) velocity.
virtual void add(const numeric_index_type i, const T value)=0
void interpolate(InterpMethod m, T &result, const T2 &value1, const T3 &value2, const FaceInfo &fi, const bool one_is_elem)
INSFVRhieChowInterpolatorSegregated(const InputParameters &params)
void computeHbyA(bool verbose)
Computes the inverse of the digaonal (1/A) of the system matrix plus the H/A components for the press...
StateArg currentState()
auto index_range(const T &sizable)
static InputParameters validParams()
void print(std::ostream &os=libMesh::out, const bool sparse=false) const
const ElemInfo & elemInfo(const dof_id_type id) const
Point vertex_average() const
A user object which implements the Rhie Chow interpolation for segregated momentum-pressure systems...
void linkMomentumSystem(std::vector< NonlinearSystemBase *> momentum_systems, const std::vector< unsigned int > &momentum_system_numbers, const TagID pressure_gradient_tag)
Update the momentum system-related information.
unsigned int THREAD_ID
virtual void computeResidualTag(const NumericVector< libMesh::Number > &soln, NumericVector< libMesh::Number > &residual, TagID tag)
void initFaceVelocities()
Initialize the container for face velocities.