13 #include "libmesh/petsc_matrix.h" 14 #include "libmesh/static_condensation.h" 24 params.
addClassDescription(
"A problem that handles Schur complement preconditioning of the " 25 "incompressible Navier-Stokes equations");
27 "mass_matrix",
"",
"The matrix tag name corresponding to the mass matrix.");
31 "The matrix tag name corresponding to the diffusive part of the velocity equations.");
32 params.
addParam<std::vector<unsigned int>>(
35 "if not provided then the top field split is assumed to be the " 36 "Schur split. This is a vector to allow recursive nesting");
37 params.
addParam<
bool>(
"use_pressure_mass_matrix",
39 "Whether to just use the pressure mass matrix as the preconditioner for " 40 "the Schur complement");
44 "Whether to use the commuted form of the LSC preconditioner, created by Olshanskii");
49 #
if PETSC_RELEASE_LESS_THAN(3, 20, 0)
51 mooseError(
"The preconditioning techniques made available through this class require a PETSc " 52 "version of at least 3.20");
67 paramError(
"mass_matrix",
68 "A pressure mass matrix must be provided if we are commuting the LSC commutator.");
70 paramError(
"L_matrix",
71 "A matrix corresponding to the viscous component of the momentum equation must be " 72 "provided if we are commuting the LSC commutator.");
75 paramError(
"L_matrix",
76 "If not commuting the LSC commutator, then the 'L_matrix' should not be provided " 77 "because it will not be used. For Elman LSC preconditioning, L will be computed " 78 "automatically using system matrix data (e.g. the off-diagonal blocks in the " 79 "velocity-pressure system).");
82 paramError(
"mass_matrix",
83 "If 'use_pressure_mass_matrix', then a pressure 'mass_matrix' must be provided");
88 auto ierr = (PetscErrorCode)0;
92 CHKERRABORT(this->
comm().
get(), ierr);
96 ierr = MatDestroy(&
_L);
97 CHKERRABORT(this->
comm().
get(), ierr);
106 if (solver_sys->system().has_static_condensation())
109 mooseError(
"Static condensation and LSC preconditioning not supported together");
111 cast_ref<StaticCondensation &>(solver_sys->getMatrix(
massMatrixTagID()))
112 .uncondensed_dofs_only();
129 auto sub_ksp_index = *it;
132 LibmeshPetscCall(KSPGetPC(node, &fs_pc));
135 LibmeshPetscCall(PetscObjectTypeCompare((PetscObject)fs_pc, PCFIELDSPLIT, &is_fs));
137 mooseError(
"Not a field split. Please check the 'schur_fs_index' parameter");
141 LibmeshPetscCall(PCSetUp(fs_pc));
144 LibmeshPetscCall(PCFieldSplitGetSubKSP(fs_pc, &num_splits, &subksp));
145 next_ksp = subksp[sub_ksp_index];
149 LibmeshPetscCall(PCFieldSplitGetISByIndex(fs_pc, sub_ksp_index, &
is));
156 LibmeshPetscCall(PetscFree(subksp));
167 KSP schur_complement_ksp;
171 IS velocity_is, pressure_is;
172 PetscInt rstart, rend;
173 PetscBool is_lsc, is_fs;
174 std::vector<Mat> intermediate_Qs;
175 std::vector<Mat> intermediate_Ls;
178 LibmeshPetscCall(KSPGetPC(schur_ksp, &schur_pc));
179 LibmeshPetscCall(PetscObjectTypeCompare((PetscObject)schur_pc, PCFIELDSPLIT, &is_fs));
181 mooseError(
"Not a field split. Please check the 'schur_fs_index' parameter");
186 Mat global_Q =
nullptr;
192 cast_ref<StaticCondensation &>(sparse_mass_mat).get_condensed_mat())
195 global_Q = cast_ref<PetscMatrixBase<Number> &>(sparse_mass_mat).mat();
200 Mat global_L =
nullptr;
210 auto process_intermediate_mats = [
this](
auto & intermediate_mats,
auto parent_mat)
212 mooseAssert(parent_mat,
"This should be non-null");
217 Mat intermediate_mat;
218 LibmeshPetscCall(MatCreateSubMatrix(i == 0 ? parent_mat : intermediate_mats[i - 1],
223 intermediate_mats[i] = intermediate_mat;
225 return _index_sets.empty() ? parent_mat : intermediate_mats.back();
228 Mat our_parent_Q =
nullptr;
230 our_parent_Q = process_intermediate_mats(intermediate_Qs, global_Q);
231 Mat our_parent_L =
nullptr;
233 our_parent_L = process_intermediate_mats(intermediate_Ls, global_L);
237 LibmeshPetscCall(PCSetUp(schur_pc));
241 LibmeshPetscCall(PCFieldSplitGetISByIndex(schur_pc, 0, &velocity_is));
244 LibmeshPetscCall(MatGetOwnershipRange(our_parent_Q, &rstart, &rend));
250 mooseAssert(our_parent_L,
"This should be non-null");
255 MatCreateSubMatrix(our_parent_L, velocity_is, velocity_is, MAT_INITIAL_MATRIX, &
_L));
259 MatCreateSubMatrix(our_parent_L, velocity_is, velocity_is, MAT_REUSE_MATRIX, &
_L));
263 LibmeshPetscCall(ISComplement(velocity_is, rstart, rend, &pressure_is));
265 auto create_q_scale_submat =
266 [our_parent_Q,
this, velocity_is, pressure_is](
const auto & mat_initialization)
272 mooseAssert(our_parent_Q,
"This should be non-null");
274 LibmeshPetscCall(MatCreateSubMatrix(
275 our_parent_Q, pressure_is, pressure_is, mat_initialization, &
_Q_scale));
282 mooseAssert(our_parent_Q,
"This should be non-null");
285 LibmeshPetscCall(MatCreateSubMatrix(
286 our_parent_Q, velocity_is, velocity_is, mat_initialization, &
_Q_scale));
292 create_q_scale_submat(MAT_INITIAL_MATRIX);
295 create_q_scale_submat(MAT_REUSE_MATRIX);
298 LibmeshPetscCall(ISDestroy(&pressure_is));
301 for (
auto & mat : intermediate_Qs)
302 LibmeshPetscCall(MatDestroy(&mat));
303 for (
auto & mat : intermediate_Ls)
304 LibmeshPetscCall(MatDestroy(&mat));
308 LibmeshPetscCall(PCFieldSplitGetSubKSP(schur_pc, &num_splits, &subksp));
310 mooseError(
"The number of splits should be two");
313 schur_complement_ksp = subksp[1];
317 mooseAssert(
_Q_scale,
"This should be non-null");
320 LibmeshPetscCall(PCFieldSplitSetSchurPre(schur_pc, PC_FIELDSPLIT_SCHUR_PRE_USER,
_Q_scale));
322 LibmeshPetscCall(KSPGetOperators(schur_complement_ksp, &
S, NULL));
325 LibmeshPetscCall(KSPSetOperators(schur_complement_ksp,
S,
_Q_scale));
330 LibmeshPetscCall(KSPGetPC(schur_complement_ksp, &lsc_pc));
332 LibmeshPetscCall(PetscObjectTypeCompare(PetscObject(lsc_pc), PCLSC, &is_lsc));
334 mooseError(
"Not an LSC PC. Please check the 'schur_fs_index' parameter");
337 LibmeshPetscCall(PCGetOperators(lsc_pc, NULL, &lsc_pc_pmat));
342 mooseAssert(
_L,
"This should be non-null");
345 LibmeshPetscCall(PetscObjectCompose((PetscObject)lsc_pc_pmat,
"LSC_L", (PetscObject)
_L));
347 mooseAssert(
_have_mass_matrix,
"This is to verify we will enter the next conditional");
351 mooseAssert(
_Q_scale,
"This should be non-null");
355 PetscObjectCompose((PetscObject)lsc_pc_pmat,
"LSC_Qscale", (PetscObject)
_Q_scale));
360 LibmeshPetscCall(PetscFree(subksp));
370 auto schur_ksp = ns_problem->findSchurKSP(root_ksp, 0);
371 ns_problem->setupLSCMatrices(schur_ksp);
385 "If we don't have a mass matrix, which is only supported for traditional LSC " 386 "preconditioning (e.g. Elman, not Olshanskii), then we also shouldn't have an L matrix " 387 "because we automatically form the L matrix when doing traditional LSC preconditioning");
virtual void initPetscOutputAndSomeSolverSettings()
const bool _have_mass_matrix
Whether the user attached a mass matrix.
const std::vector< unsigned int > & _schur_fs_index
The length of this vector should correspond to the number of split nesting levels there are in the fi...
virtual void initialSetup() override
_mass_matrix(getParam< TagName >("mass_matrix"))
Tnew cast_ref(Told &oldvar)
void clearIndexSets()
Clear the field split index sets.
std::vector< IS > _index_sets
This will end up being the same length as _schur_fs_index.
Mat _L
The Poisson operator.
const Parallel::Communicator & comm() const
_have_L_matrix(!_L_matrix.empty())
_commute_lsc(getParam< bool >("commute_lsc"))
virtual ~NavierStokesProblem()
Will destroy any matrices we allocated.
std::vector< std::shared_ptr< SolverSystem > > _solver_systems
KSP findSchurKSP(KSP node, unsigned int tree_position)
bool has_static_condensation() const
_have_mass_matrix(!_mass_matrix.empty())
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
_L_matrix(getParam< TagName >("L_matrix"))
static InputParameters validParams()
NonlinearSystemBase * _current_nl_sys
static const std::string S
FieldSplitPreconditionerBase & getFieldSplitPreconditioner()
NonlinearSystemBase & currentNonlinearSystem()
registerMooseObject("NavierStokesApp", NavierStokesProblem)
NavierStokesProblem(const InputParameters ¶meters)
const bool _commute_lsc
Whether to commute operators in the style of Olshanskii.
void initialSetup() override
PetscErrorCode PetscInt const PetscInt IS * is
A problem that handles Schur complement preconditioning of the incompressible Navier-Stokes equations...
const bool _pressure_mass_matrix_as_pre
Whether to directly use the pressure mass matrix to form the Schur complement preconditioner.
_pressure_mass_matrix_as_pre(getParam< bool >("use_pressure_mass_matrix"))
virtual void initPetscOutputAndSomeSolverSettings() override
Reinitialize PETSc output for proper linear/nonlinear iteration display.
Mat _Q_scale
The mass matrix used for scaling.
TagID LMatrixTagID() const
virtual libMesh::SparseMatrix< Number > & getMatrix(TagID tag)
void setupLSCMatrices(KSP schur_ksp)
Setup the Least Squares Commutator (LSC) preconditioner given the Schur complement KSP object...
void mooseError(Args &&... args) const
_schur_fs_index(getParam< std::vector< unsigned int >>("schur_fs_index"))
static InputParameters validParams()
PetscErrorCode navierStokesKSPPreSolve(KSP root_ksp, Vec, Vec, void *context)
TagID massMatrixTagID() const
PetscFunctionReturn(LIBMESH_PETSC_SUCCESS)
const bool _have_L_matrix
Whether the user attached a Poisson operator matrix.
auto index_range(const T &sizable)
virtual libMesh::System & system() override