12 #include "libmesh/petsc_matrix.h" 22 params.
addClassDescription(
"A problem that handles Schur complement preconditioning of the " 23 "incompressible Navier-Stokes equations");
25 "mass_matrix",
"",
"The matrix tag name corresponding to the mass matrix.");
29 "The matrix tag name corresponding to the diffusive part of the velocity equations.");
30 params.
addParam<std::vector<unsigned int>>(
33 "if not provided then the top field split is assumed to be the " 34 "Schur split. This is a vector to allow recursive nesting");
35 params.
addParam<
bool>(
"use_pressure_mass_matrix",
37 "Whether to just use the pressure mass matrix as the preconditioner for " 38 "the Schur complement");
42 "Whether to use the commuted form of the LSC preconditioner, created by Olshanskii");
47 #
if PETSC_RELEASE_LESS_THAN(3, 20, 0)
49 mooseError(
"The preconditioning techniques made available through this class require a PETSc " 50 "version of at least 3.20");
65 paramError(
"mass_matrix",
66 "A pressure mass matrix must be provided if we are commuting the LSC commutator.");
68 paramError(
"L_matrix",
69 "A matrix corresponding to the viscous component of the momentum equation must be " 70 "provided if we are commuting the LSC commutator.");
73 paramError(
"L_matrix",
74 "If not commuting the LSC commutator, then the 'L_matrix' should not be provided " 75 "because it will not be used. For Elman LSC preconditioning, L will be computed " 76 "automatically using system matrix data (e.g. the off-diagonal blocks in the " 77 "velocity-pressure system).");
80 paramError(
"mass_matrix",
81 "If 'use_pressure_mass_matrix', then a pressure 'mass_matrix' must be provided");
86 auto ierr = (PetscErrorCode)0;
90 CHKERRABORT(this->
comm().
get(), ierr);
94 ierr = MatDestroy(&
_L);
95 CHKERRABORT(this->
comm().
get(), ierr);
113 auto sub_ksp_index = *it;
116 LibmeshPetscCall(KSPGetPC(node, &fs_pc));
119 LibmeshPetscCall(PetscObjectTypeCompare((PetscObject)fs_pc, PCFIELDSPLIT, &is_fs));
121 mooseError(
"Not a field split. Please check the 'schur_fs_index' parameter");
125 LibmeshPetscCall(PCSetUp(fs_pc));
128 LibmeshPetscCall(PCFieldSplitGetSubKSP(fs_pc, &num_splits, &subksp));
129 next_ksp = subksp[sub_ksp_index];
133 LibmeshPetscCall(PCFieldSplitGetISByIndex(fs_pc, sub_ksp_index, &
is));
140 LibmeshPetscCall(PetscFree(subksp));
151 KSP schur_complement_ksp;
155 IS velocity_is, pressure_is;
156 PetscInt rstart, rend;
157 PetscBool is_lsc, is_fs;
158 std::vector<Mat> intermediate_Qs;
159 std::vector<Mat> intermediate_Ls;
162 LibmeshPetscCall(KSPGetPC(schur_ksp, &schur_pc));
163 LibmeshPetscCall(PetscObjectTypeCompare((PetscObject)schur_pc, PCFIELDSPLIT, &is_fs));
165 mooseError(
"Not a field split. Please check the 'schur_fs_index' parameter");
170 Mat global_Q =
nullptr;
177 Mat global_L =
nullptr;
188 auto process_intermediate_mats = [
this](
auto & intermediate_mats,
auto parent_mat)
190 mooseAssert(parent_mat,
"This should be non-null");
195 Mat intermediate_mat;
196 LibmeshPetscCall(MatCreateSubMatrix(i == 0 ? parent_mat : intermediate_mats[i - 1],
201 intermediate_mats[i] = intermediate_mat;
203 return _index_sets.empty() ? parent_mat : intermediate_mats.back();
206 Mat our_parent_Q =
nullptr;
208 our_parent_Q = process_intermediate_mats(intermediate_Qs, global_Q);
209 Mat our_parent_L =
nullptr;
211 our_parent_L = process_intermediate_mats(intermediate_Ls, global_L);
215 LibmeshPetscCall(PCSetUp(schur_pc));
219 LibmeshPetscCall(PCFieldSplitGetISByIndex(schur_pc, 0, &velocity_is));
222 LibmeshPetscCall(MatGetOwnershipRange(our_parent_Q, &rstart, &rend));
228 mooseAssert(our_parent_L,
"This should be non-null");
233 MatCreateSubMatrix(our_parent_L, velocity_is, velocity_is, MAT_INITIAL_MATRIX, &
_L));
237 MatCreateSubMatrix(our_parent_L, velocity_is, velocity_is, MAT_REUSE_MATRIX, &
_L));
241 LibmeshPetscCall(ISComplement(velocity_is, rstart, rend, &pressure_is));
243 auto create_q_scale_submat =
244 [our_parent_Q,
this, velocity_is, pressure_is](
const auto & mat_initialization)
250 mooseAssert(our_parent_Q,
"This should be non-null");
252 LibmeshPetscCall(MatCreateSubMatrix(
253 our_parent_Q, pressure_is, pressure_is, mat_initialization, &
_Q_scale));
260 mooseAssert(our_parent_Q,
"This should be non-null");
263 LibmeshPetscCall(MatCreateSubMatrix(
264 our_parent_Q, velocity_is, velocity_is, mat_initialization, &
_Q_scale));
270 create_q_scale_submat(MAT_INITIAL_MATRIX);
273 create_q_scale_submat(MAT_REUSE_MATRIX);
276 LibmeshPetscCall(ISDestroy(&pressure_is));
279 for (
auto & mat : intermediate_Qs)
280 LibmeshPetscCall(MatDestroy(&mat));
281 for (
auto & mat : intermediate_Ls)
282 LibmeshPetscCall(MatDestroy(&mat));
286 LibmeshPetscCall(PCFieldSplitGetSubKSP(schur_pc, &num_splits, &subksp));
288 mooseError(
"The number of splits should be two");
291 schur_complement_ksp = subksp[1];
295 mooseAssert(
_Q_scale,
"This should be non-null");
298 LibmeshPetscCall(PCFieldSplitSetSchurPre(schur_pc, PC_FIELDSPLIT_SCHUR_PRE_USER,
_Q_scale));
300 LibmeshPetscCall(KSPGetOperators(schur_complement_ksp, &
S, NULL));
303 LibmeshPetscCall(KSPSetOperators(schur_complement_ksp,
S,
_Q_scale));
308 LibmeshPetscCall(KSPGetPC(schur_complement_ksp, &lsc_pc));
310 LibmeshPetscCall(PetscObjectTypeCompare(PetscObject(lsc_pc), PCLSC, &is_lsc));
312 mooseError(
"Not an LSC PC. Please check the 'schur_fs_index' parameter");
315 LibmeshPetscCall(PCGetOperators(lsc_pc, NULL, &lsc_pc_pmat));
320 mooseAssert(
_L,
"This should be non-null");
323 LibmeshPetscCall(PetscObjectCompose((PetscObject)lsc_pc_pmat,
"LSC_L", (PetscObject)
_L));
325 mooseAssert(
_have_mass_matrix,
"This is to verify we will enter the next conditional");
329 mooseAssert(
_Q_scale,
"This should be non-null");
333 PetscObjectCompose((PetscObject)lsc_pc_pmat,
"LSC_Qscale", (PetscObject)
_Q_scale));
338 LibmeshPetscCall(PetscFree(subksp));
348 auto schur_ksp = ns_problem->findSchurKSP(root_ksp, 0);
349 ns_problem->setupLSCMatrices(schur_ksp);
363 "If we don't have a mass matrix, which is only supported for traditional LSC " 364 "preconditioning (e.g. Elman, not Olshanskii), then we also shouldn't have an L matrix " 365 "because we automatically form the L matrix when doing traditional LSC preconditioning");
372 LibmeshPetscCall(SNESGetKSP(snes, &ksp));
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...
_mass_matrix(getParam< TagName >("mass_matrix"))
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.
KSP findSchurKSP(KSP node, unsigned int tree_position)
_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()
static const std::string S
NonlinearSystemBase & currentNonlinearSystem()
registerMooseObject("NavierStokesApp", NavierStokesProblem)
NavierStokesProblem(const InputParameters ¶meters)
const bool _commute_lsc
Whether to commute operators in the style of Olshanskii.
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.
NonlinearSystemBase & getNonlinearSystemBase(const unsigned int sys_num)
_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)