https://mooseframework.inl.gov
Loading...
Searching...
No Matches
Classes | Functions
NS::FV Namespace Reference

Classes

class  CHTHandler
 This class provides an interface for managing conjugate heat transfer (CHT) between fluid and solid domains. More...
 

Functions

void relaxMatrix (SparseMatrix< Number > &matrix_in, const Real relaxation_parameter, NumericVector< Number > &diff_diagonal)
 Relax the matrix to ensure diagonal dominance, we hold onto the difference in diagonals for later use in relaxing the right hand side.
 
void relaxRightHandSide (NumericVector< Number > &rhs_in, const NumericVector< Number > &solution_in, const NumericVector< Number > &diff_diagonal)
 Relax the right hand side of an equation, this needs to be called once and the system matrix has been relaxed and the field describing the difference in the diagonals of the system matrix is already available.
 
void relaxSolutionUpdate (NumericVector< Number > &vec_new, const NumericVector< Number > &vec_old, const Real relaxation_factor)
 Relax the update on a solution field using the following approach: $u = u_{old}+\lambda (u - u_{old})$.
 
void limitSolutionUpdate (NumericVector< Number > &solution, const Real min_limit=std::numeric_limits< Real >::epsilon(), const Real max_limit=1e10)
 Limit a solution to its minimum and maximum bounds: $u = min(max(u, min_limit), max_limit)$.
 
Real computeNormalizationFactor (const NumericVector< Number > &solution, const SparseMatrix< Number > &mat, const NumericVector< Number > &rhs)
 Compute a normalization factor which is applied to the linear residual to determine convergence.
 
void constrainSystem (SparseMatrix< Number > &mx, NumericVector< Number > &rhs, const Real desired_value, const dof_id_type dof_id)
 Implicitly constrain the system by adding a factor*(u-u_desired) to it at a desired dof value.
 
dof_id_type findPointDoFID (const MooseVariableFieldBase &variable, const MooseMesh &mesh, const Point &point)
 Find the ID of the degree of freedom which corresponds to the variable and a given point on the mesh.
 
bool converged (const std::vector< std::pair< unsigned int, Real > > &residuals, const std::vector< Real > &abs_tolerances)
 Based on the residuals, determine if the iterative process converged or not.
 

Function Documentation

◆ computeNormalizationFactor()

Real NS::FV::computeNormalizationFactor ( const NumericVector< Number > &  solution,
const SparseMatrix< Number > &  mat,
const NumericVector< Number > &  rhs 
)

Compute a normalization factor which is applied to the linear residual to determine convergence.

This function is based on the description provided here: @article{greenshields2022notes, title={Notes on computational fluid dynamics: General principles}, author={Greenshields, Christopher J and Weller, Henry G}, journal={(No Title)}, year={2022} }

Parameters
solutionThe solution vector
matThe system matrix
rhsThe system right hand side

Definition at line 135 of file SegregatedSolverUtils.C.

138{
139 // This function is based on the description provided here:
140 // @article{greenshields2022notes,
141 // title={Notes on computational fluid dynamics: General principles},
142 // author={Greenshields, Christopher J and Weller, Henry G},
143 // journal={(No Title)},
144 // year={2022}
145 // }
146 // so basically we normalize the residual with the following number:
147 // sum(|Ax-Ax_avg|+|b-Ax_avg|)
148 // where A is the system matrix, b is the system right hand side while x and x_avg are
149 // the solution and average solution vectors
150
151 // We create a vector for Ax_avg and Ax
152 auto A_times_average_solution = solution.zero_clone();
153 auto A_times_solution = solution.zero_clone();
154
155 // Beware, trickery here! To avoid allocating unused vectors, we
156 // first compute Ax_avg using the storage used for Ax, then we
157 // overwrite Ax with the right value
158 *A_times_solution = solution.sum() / solution.size();
159 mat.vector_mult(*A_times_average_solution, *A_times_solution);
160 mat.vector_mult(*A_times_solution, solution);
161
162 // We create Ax-Ax_avg
163 A_times_solution->add(-1.0, *A_times_average_solution);
164 // We create Ax_avg - b (ordering shouldn't matter we will take absolute value soon)
165 A_times_average_solution->add(-1.0, rhs);
166 A_times_solution->abs();
167 A_times_average_solution->abs();
168
169 // Create |Ax-Ax_avg|+|b-Ax_avg|
170 A_times_average_solution->add(*A_times_solution);
171
172 // Since use the l2 norm of the solution vectors in the linear solver, we will
173 // make this consistent and use the l2 norm of the vector. We add a small number to
174 // avoid normalizing with 0.
175 // TODO: Would be nice to see if we can do l1 norms in the linear solve.
176 return (A_times_average_solution->l2_norm() + libMesh::TOLERANCE * libMesh::TOLERANCE);
177}
virtual numeric_index_type size() const=0
virtual std::unique_ptr< NumericVector< T > > zero_clone() const=0
virtual T sum() const=0
void vector_mult(NumericVector< T > &dest, const NumericVector< T > &arg) const
static constexpr Real TOLERANCE

Referenced by LinearAssemblySegregatedSolve::solveAdvectedSystem(), SIMPLESolveNonlinearAssembly::solveAdvectedSystem(), LinearAssemblySegregatedSolve::solveMomentumPredictor(), SIMPLESolveNonlinearAssembly::solveMomentumPredictor(), LinearAssemblySegregatedSolve::solvePressureCorrector(), SIMPLESolveNonlinearAssembly::solvePressureCorrector(), LinearAssemblySegregatedSolve::solveSolidEnergy(), and SIMPLESolveNonlinearAssembly::solveSolidEnergySystem().

◆ constrainSystem()

void NS::FV::constrainSystem ( SparseMatrix< Number > &  mx,
NumericVector< Number > &  rhs,
const Real  desired_value,
const dof_id_type  dof_id 
)

Implicitly constrain the system by adding a factor*(u-u_desired) to it at a desired dof value.

To make sure the conditioning of the matrix does not change significantly, factor is chosen to be the diagonal component of the matrix coefficients for a given dof.

Parameters
mxThe matrix of the system which needs to be constrained
rhsThe right hand side of the system which needs to be constrained
valueThe desired value for the solution field at a dof
dof_idThe ID of the dof which needs to be constrained

Definition at line 180 of file SegregatedSolverUtils.C.

184{
185 // Modify the given matrix and right hand side. We use the matrix diagonal
186 // to enforce the constraint instead of 1, to make sure we don't mess up the matrix conditioning
187 // too much.
188 if (dof_id >= mx.row_start() && dof_id < mx.row_stop())
189 {
190 Real diag = mx(dof_id, dof_id);
191 rhs.add(dof_id, desired_value * diag);
192 mx.add(dof_id, dof_id, diag);
193 }
194}
virtual void add(const numeric_index_type i, const T value)=0
virtual numeric_index_type row_stop() const=0
virtual void add(const numeric_index_type i, const numeric_index_type j, const T value)=0
virtual numeric_index_type row_start() const=0

Referenced by LinearAssemblySegregatedSolve::solvePressureCorrector(), and SIMPLESolveNonlinearAssembly::solvePressureCorrector().

◆ converged()

bool NS::FV::converged ( const std::vector< std::pair< unsigned int, Real > > &  residuals,
const std::vector< Real > &  abs_tolerances 
)

Based on the residuals, determine if the iterative process converged or not.

Parameters
residualsThe current (number of iterations, residual) pairs
abs_tolerancesThe corresponding absolute tolerances.

Definition at line 229 of file SegregatedSolverUtils.C.

231{
232 mooseAssert(its_and_residuals.size() == abs_tolerances.size(),
233 "The number of residuals should (now " + std::to_string(its_and_residuals.size()) +
234 ") be the same as the number of tolerances (" +
235 std::to_string(abs_tolerances.size()) + ")!");
236
237 bool converged = true;
238 for (const auto system_i : index_range(its_and_residuals))
239 {
240 converged = converged && (its_and_residuals[system_i].second < abs_tolerances[system_i]);
241 if (!converged)
242 return converged;
243 }
244 return converged;
245}
bool converged(const std::vector< std::pair< unsigned int, Real > > &residuals, const std::vector< Real > &abs_tolerances)
Based on the residuals, determine if the iterative process converged or not.

Referenced by converged(), LinearAssemblySegregatedSolve::solve(), and SIMPLESolveNonlinearAssembly::solve().

◆ findPointDoFID()

dof_id_type NS::FV::findPointDoFID ( const MooseVariableFieldBase variable,
const MooseMesh mesh,
const Point &  point 
)

Find the ID of the degree of freedom which corresponds to the variable and a given point on the mesh.

Parameters
variableReference to the moose variable whose dof should be fetched
meshThe moose mesh where the element is
pointThe point on the mesh

Definition at line 197 of file SegregatedSolverUtils.C.

198{
199 // Find the element containing the point
200 auto point_locator = PointLocatorBase::build(TREE_LOCAL_ELEMENTS, mesh);
201 point_locator->enable_out_of_mesh_mode();
202
203 unsigned int var_num = variable.sys().system().variable_number(variable.name());
204
205 // We only check in the restricted blocks, if needed
206 const bool block_restricted =
207 variable.blockIDs().find(Moose::ANY_BLOCK_ID) == variable.blockIDs().end();
208 const Elem * elem =
209 block_restricted ? (*point_locator)(point, &variable.blockIDs()) : (*point_locator)(point);
210
211 // We communicate the results and if there is conflict between processes,
212 // the minimum cell ID is chosen
213 const dof_id_type elem_id = elem ? elem->id() : DofObject::invalid_id;
214 dof_id_type min_elem_id = elem_id;
215 variable.sys().comm().min(min_elem_id);
216
217 if (min_elem_id == DofObject::invalid_id)
218 mooseError("Variable ",
219 variable.name(),
220 " is not defined at ",
221 Moose::stringify(point),
222 "! Try alleviating block restrictions or using another point!");
223
224 return min_elem_id == elem_id ? elem->dof_number(variable.sys().number(), var_num, 0)
225 : DofObject::invalid_id;
226}
void mooseError(Args &&... args)
virtual const std::set< SubdomainID > & blockIDs() const
const std::string & name() const
SystemBase & sys()
unsigned int number() const
virtual libMesh::System & system()=0
void min(const T &r, T &o, Request &req) const
const Parallel::Communicator & comm() const
unsigned int variable_number(std::string_view var) const
const SubdomainID ANY_BLOCK_ID
std::string stringify(const T &t)

Referenced by SIMPLESolveBase::setupPressurePin().

◆ limitSolutionUpdate()

void NS::FV::limitSolutionUpdate ( NumericVector< Number > &  solution,
const Real  min_limit = std::numeric_limits<Real>::epsilon(),
const Real  max_limit = 1e10 
)

Limit a solution to its minimum and maximum bounds: $u = min(max(u, min_limit), max_limit)$.

Parameters
system_inThe system whose solution shall be limited
min_limit= 0.0 The minimum limit for the solution
max_limit= 1e10 The maximum limit for the solution

Definition at line 123 of file SegregatedSolverUtils.C.

124{
125 PetscVector<Number> & solution_vector = dynamic_cast<PetscVector<Number> &>(solution);
126 auto value = solution_vector.get_array();
127
128 for (auto i : make_range(solution_vector.local_size()))
129 value[i] = std::min(std::max(min_limit, value[i]), max_limit);
130
131 solution_vector.restore_array();
132}

Referenced by SIMPLESolveNonlinearAssembly::solve(), and LinearAssemblySegregatedSolve::solveAdvectedSystem().

◆ relaxMatrix()

void NS::FV::relaxMatrix ( SparseMatrix< Number > &  matrix_in,
const Real  relaxation_parameter,
NumericVector< Number > &  diff_diagonal 
)

Relax the matrix to ensure diagonal dominance, we hold onto the difference in diagonals for later use in relaxing the right hand side.

For the details of this relaxation process, see

Juretic, Franjo. Error analysis in finite volume CFD. Diss. Imperial College London (University of London), 2005.

Parameters
matrix_inThe matrix that needs to be relaxed
relaxation_parameterThe scale which described how much the matrix is relaxed
diff_diagonalA vector holding the $A_{diag}-A_{diag, relaxed}$ entries for further use in the relaxation of the right hand side

Definition at line 25 of file SegregatedSolverUtils.C.

28{
29 PetscMatrix<Number> * mat = dynamic_cast<PetscMatrix<Number> *>(&matrix);
30 mooseAssert(mat, "This should be a PetscMatrix!");
31 PetscVector<Number> * diff_diag = dynamic_cast<PetscVector<Number> *>(&diff_diagonal);
32 mooseAssert(diff_diag, "This should be a PetscVector!");
33
34 // Zero the diagonal difference vector
35 *diff_diag = 0;
36
37 // Get the diagonal of the matrix
38 mat->get_diagonal(*diff_diag);
39
40 // Create a copy of the diagonal for later use and cast it
41 auto original_diagonal = diff_diag->clone();
42
43 // We cache the inverse of the relaxation parameter because doing divisions might
44 // be more expensive for every row
45 const Real inverse_relaxation = 1 / relaxation_parameter;
46
47 // Now we loop over the matrix row by row and sum the absolute values of the
48 // offdiagonal values, If these sums are larger than the diagonal entry,
49 // we switch the diagonal value with the sum. At the same time we increase the
50 // diagonal by dividing it with the relaxation parameter. So the new diagonal will be:
51 // D* = 1/lambda*max(|D|,sum(|Offdiag|))
52 // For more information see
53 //
54 // Juretic, Franjo. Error analysis in finite volume CFD. Diss.
55 // Imperial College London (University of London), 2005.
56 //
57 // The trickery comes with storing everything in the diff-diagonal vector
58 // to avoid the allocation and manipulation of a third vector
59 const unsigned int local_size = matrix.row_stop() - matrix.row_start();
60 std::vector<dof_id_type> indices(local_size);
61 std::iota(indices.begin(), indices.end(), matrix.row_start());
62 std::vector<Real> new_diagonal(local_size, 0.0);
63
64 {
65 PetscVectorReader diff_diga_reader(*diff_diag);
66 for (const auto row_i : make_range(local_size))
67 {
68 const unsigned int global_index = matrix.row_start() + row_i;
69 std::vector<numeric_index_type> indices;
70 std::vector<Real> values;
71 mat->get_row(global_index, indices, values);
72 const Real abs_sum = std::accumulate(
73 values.cbegin(), values.cend(), 0.0, [](Real a, Real b) { return a + std::abs(b); });
74 const Real abs_diagonal = std::abs(diff_diga_reader(global_index));
75 new_diagonal[row_i] = inverse_relaxation * std::max(abs_sum - abs_diagonal, abs_diagonal);
76 }
77 }
78 diff_diag->insert(new_diagonal, indices);
79
80 // Time to modify the diagonal of the matrix. TODO: add this function to libmesh
81 LibmeshPetscCallA(mat->comm().get(), MatDiagonalSet(mat->mat(), diff_diag->vec(), INSERT_VALUES));
82 mat->close();
83 diff_diag->close();
84
85 // Finally, we can create (D*-D) vector which is used for the relaxation of the
86 // right hand side later
87 diff_diag->add(-1.0, *original_diagonal);
88}
std::array< Real, 2 > values

Referenced by LinearAssemblySegregatedSolve::solveAdvectedSystem(), SIMPLESolveNonlinearAssembly::solveAdvectedSystem(), LinearAssemblySegregatedSolve::solveMomentumPredictor(), and SIMPLESolveNonlinearAssembly::solveMomentumPredictor().

◆ relaxRightHandSide()

void NS::FV::relaxRightHandSide ( NumericVector< Number > &  rhs_in,
const NumericVector< Number > &  solution_in,
const NumericVector< Number > &  diff_diagonal 
)

Relax the right hand side of an equation, this needs to be called once and the system matrix has been relaxed and the field describing the difference in the diagonals of the system matrix is already available.

The relaxation process needs modification to both the system matrix and the right hand side. For more information see:

Juretic, Franjo. Error analysis in finite volume CFD. Diss. Imperial College London (University of London), 2005.

Parameters
rhs_inThe unrelaxed right hand side that needs to be relaxed
solution_inThe solution
diff_diagonalThe diagonal correction used for the corresponding system matrix

Definition at line 91 of file SegregatedSolverUtils.C.

94{
95
96 // We need a working vector here to make sure we don't modify the
97 // (D*-D) vector
98 auto working_vector = diff_diagonal.clone();
99 working_vector->pointwise_mult(solution, *working_vector);
100
101 // The correction to the right hand side is just
102 // (D*-D)*old_solution
103 // For more information see
104 //
105 // Juretic, Franjo. Error analysis in finite volume CFD. Diss.
106 // Imperial College London (University of London), 2005.
107 rhs.add(*working_vector);
108 rhs.close();
109}
virtual std::unique_ptr< NumericVector< T > > clone() const=0

Referenced by LinearAssemblySegregatedSolve::solveAdvectedSystem(), SIMPLESolveNonlinearAssembly::solveAdvectedSystem(), LinearAssemblySegregatedSolve::solveMomentumPredictor(), and SIMPLESolveNonlinearAssembly::solveMomentumPredictor().

◆ relaxSolutionUpdate()

void NS::FV::relaxSolutionUpdate ( NumericVector< Number > &  vec_new,
const NumericVector< Number > &  vec_old,
const Real  relaxation_factor 
)

Relax the update on a solution field using the following approach: $u = u_{old}+\lambda (u - u_{old})$.

Parameters
vector_newThe new solution vector
vec_oldThe old solution vector
relaxation_factorThe lambda parameter in the expression above

Definition at line 112 of file SegregatedSolverUtils.C.

115{
116 // The relaxation is just u = lambda * u* + (1-lambda) u_old
117 vec_new.scale(relaxation_factor);
118 vec_new.add(1 - relaxation_factor, vec_old);
119 vec_new.close();
120}
virtual void close()=0
virtual void scale(const T factor)=0

Referenced by LinearAssemblySegregatedSolve::correctVelocity(), SIMPLESolveNonlinearAssembly::solve(), and LinearAssemblySegregatedSolve::solveAdvectedSystem().