1b9ac7092SAlp Dener /* 2f7bf01afSAlp Dener This provides a thin wrapper around LMVM matrices in order to use their MatLMVMSolve 3b9ac7092SAlp Dener methods as preconditioner applications in KSP solves. 4b9ac7092SAlp Dener */ 5b9ac7092SAlp Dener 6b9ac7092SAlp Dener #include <petsc/private/pcimpl.h> /*I "petscpc.h" I*/ 7dbf6bb8dSprj- #include <petsc/private/matimpl.h> 8b9ac7092SAlp Dener 9b9ac7092SAlp Dener typedef struct { 10b9ac7092SAlp Dener Vec xwork, ywork; 11b9ac7092SAlp Dener IS inactive; 12b9ac7092SAlp Dener Mat B; 13*970ba202SStefano Zampini Vec X; 14*970ba202SStefano Zampini PetscObjectState Xstate; 15*970ba202SStefano Zampini PetscBool setfromoptionscalled; 16b9ac7092SAlp Dener } PC_LMVM; 17b9ac7092SAlp Dener 18b9ac7092SAlp Dener /*@ 19*970ba202SStefano Zampini PCLMVMSetUpdateVec - Set the vector to be used as solution update for the internal LMVM matrix. 20b9ac7092SAlp Dener 21b9ac7092SAlp Dener Input Parameters: 22*970ba202SStefano Zampini + pc - The preconditioner 23*970ba202SStefano Zampini - X - Solution vector 24b9ac7092SAlp Dener 25b9ac7092SAlp Dener Level: intermediate 26f1580f4eSBarry Smith 27*970ba202SStefano Zampini Notes: 28*970ba202SStefano Zampini This is only needed if you want the preconditioner to automatically update the internal matrix. 29*970ba202SStefano Zampini It is called in some `SNES` implementations to update the preconditioner. 30*970ba202SStefano Zampini The right-hand side of the linear system is used as function vector. 31*970ba202SStefano Zampini 32*970ba202SStefano Zampini .seealso: `MatLMVMUpdate()`, `PCLMVMSetMatLMVM()` 33*970ba202SStefano Zampini @*/ 34*970ba202SStefano Zampini PetscErrorCode PCLMVMSetUpdateVec(PC pc, Vec X) 35*970ba202SStefano Zampini { 36*970ba202SStefano Zampini PC_LMVM *ctx; 37*970ba202SStefano Zampini PetscBool same; 38*970ba202SStefano Zampini 39*970ba202SStefano Zampini PetscFunctionBegin; 40*970ba202SStefano Zampini PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 41*970ba202SStefano Zampini if (X) PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 42*970ba202SStefano Zampini PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCLMVM, &same)); 43*970ba202SStefano Zampini if (!same) PetscFunctionReturn(PETSC_SUCCESS); 44*970ba202SStefano Zampini ctx = (PC_LMVM *)pc->data; 45*970ba202SStefano Zampini PetscCall(PetscObjectReference((PetscObject)X)); 46*970ba202SStefano Zampini PetscCall(VecDestroy(&ctx->X)); 47*970ba202SStefano Zampini ctx->X = X; 48*970ba202SStefano Zampini ctx->Xstate = -1; 49*970ba202SStefano Zampini PetscFunctionReturn(PETSC_SUCCESS); 50*970ba202SStefano Zampini } 51*970ba202SStefano Zampini 52*970ba202SStefano Zampini /*@ 53*970ba202SStefano Zampini PCLMVMSetMatLMVM - Replaces the `MATLMVM` matrix inside the preconditioner with the one provided by the user. 54*970ba202SStefano Zampini 55*970ba202SStefano Zampini Input Parameters: 56*970ba202SStefano Zampini + pc - An `PCLMVM` preconditioner 57*970ba202SStefano Zampini - B - An `MATLMVM` type matrix 58*970ba202SStefano Zampini 59*970ba202SStefano Zampini Level: intermediate 60*970ba202SStefano Zampini 61*970ba202SStefano Zampini .seealso: [](ch_ksp), `PCLMVMGetMatLMVM()` 62b9ac7092SAlp Dener @*/ 63d71ae5a4SJacob Faibussowitsch PetscErrorCode PCLMVMSetMatLMVM(PC pc, Mat B) 64d71ae5a4SJacob Faibussowitsch { 65*970ba202SStefano Zampini PC_LMVM *ctx; 66b9ac7092SAlp Dener PetscBool same; 67b9ac7092SAlp Dener 68b9ac7092SAlp Dener PetscFunctionBegin; 69b9ac7092SAlp Dener PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 70b9ac7092SAlp Dener PetscValidHeaderSpecific(B, MAT_CLASSID, 2); 719566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCLMVM, &same)); 72*970ba202SStefano Zampini if (!same) PetscFunctionReturn(PETSC_SUCCESS); 739566063dSJacob Faibussowitsch PetscCall(PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &same)); 74*970ba202SStefano Zampini PetscCheck(same, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Matrix must be an MATLMVM."); 75*970ba202SStefano Zampini ctx = (PC_LMVM *)pc->data; 769566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)B)); 77*970ba202SStefano Zampini PetscCall(MatDestroy(&ctx->B)); 78b9ac7092SAlp Dener ctx->B = B; 793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 80b9ac7092SAlp Dener } 81b9ac7092SAlp Dener 82b9ac7092SAlp Dener /*@ 83f1580f4eSBarry Smith PCLMVMGetMatLMVM - Returns a pointer to the underlying `MATLMVM` matrix. 84b9ac7092SAlp Dener 85f1580f4eSBarry Smith Input Parameter: 86f1580f4eSBarry Smith . pc - An `PCLMVM` preconditioner 87b9ac7092SAlp Dener 88f1580f4eSBarry Smith Output Parameter: 89*970ba202SStefano Zampini . B - `MATLMVM` matrix used by the preconditioner 90b9ac7092SAlp Dener 91b9ac7092SAlp Dener Level: intermediate 92f1580f4eSBarry Smith 93*970ba202SStefano Zampini .seealso: [](ch_ksp), `PCLMVMSetMatLMVM()` 94b9ac7092SAlp Dener @*/ 95d71ae5a4SJacob Faibussowitsch PetscErrorCode PCLMVMGetMatLMVM(PC pc, Mat *B) 96d71ae5a4SJacob Faibussowitsch { 97*970ba202SStefano Zampini PC_LMVM *ctx; 98b9ac7092SAlp Dener PetscBool same; 99b9ac7092SAlp Dener 100b9ac7092SAlp Dener PetscFunctionBegin; 101b9ac7092SAlp Dener PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1029566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCLMVM, &same)); 10328b400f6SJacob Faibussowitsch PetscCheck(same, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "PC must be a PCLMVM type."); 104*970ba202SStefano Zampini ctx = (PC_LMVM *)pc->data; 105*970ba202SStefano Zampini if (!ctx->B) { 106*970ba202SStefano Zampini Mat J; 107*970ba202SStefano Zampini 108*970ba202SStefano Zampini if (pc->useAmat) J = pc->mat; 109*970ba202SStefano Zampini else J = pc->pmat; 110*970ba202SStefano Zampini PetscCall(PetscObjectBaseTypeCompare((PetscObject)J, MATLMVM, &same)); 111*970ba202SStefano Zampini if (same) *B = J; 112*970ba202SStefano Zampini else { 113*970ba202SStefano Zampini const char *prefix; 114*970ba202SStefano Zampini 115*970ba202SStefano Zampini PetscCall(PCGetOptionsPrefix(pc, &prefix)); 116*970ba202SStefano Zampini PetscCall(MatCreate(PetscObjectComm((PetscObject)pc), &ctx->B)); 117*970ba202SStefano Zampini PetscCall(MatSetOptionsPrefix(ctx->B, prefix)); 118*970ba202SStefano Zampini PetscCall(MatAppendOptionsPrefix(ctx->B, "pc_lmvm_")); 119*970ba202SStefano Zampini PetscCall(MatSetType(ctx->B, MATLMVMBFGS)); 120*970ba202SStefano Zampini PetscCall(PetscObjectIncrementTabLevel((PetscObject)ctx->B, (PetscObject)pc, 1)); 121b9ac7092SAlp Dener *B = ctx->B; 122*970ba202SStefano Zampini } 123*970ba202SStefano Zampini } else *B = ctx->B; 1243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 125b9ac7092SAlp Dener } 126b9ac7092SAlp Dener 127b9ac7092SAlp Dener /*@ 128f1580f4eSBarry Smith PCLMVMSetIS - Sets the index sets that reduce the `PC` application. 129b9ac7092SAlp Dener 130b9ac7092SAlp Dener Input Parameters: 131f1580f4eSBarry Smith + pc - An `PCLMVM` preconditioner 132b9ac7092SAlp Dener - inactive - Index set defining the variables removed from the problem 133b9ac7092SAlp Dener 134b9ac7092SAlp Dener Level: intermediate 135b9ac7092SAlp Dener 136feefa0e1SJacob Faibussowitsch Developer Notes: 137f1580f4eSBarry Smith Need to explain the purpose of this `IS` 138f1580f4eSBarry Smith 139*970ba202SStefano Zampini .seealso: [](ch_ksp), `PCLMVMClearIS()` 140b9ac7092SAlp Dener @*/ 141d71ae5a4SJacob Faibussowitsch PetscErrorCode PCLMVMSetIS(PC pc, IS inactive) 142d71ae5a4SJacob Faibussowitsch { 143*970ba202SStefano Zampini PC_LMVM *ctx; 144b9ac7092SAlp Dener PetscBool same; 145b9ac7092SAlp Dener 146b9ac7092SAlp Dener PetscFunctionBegin; 147b9ac7092SAlp Dener PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 148b2d8c577SAlp Dener PetscValidHeaderSpecific(inactive, IS_CLASSID, 2); 1499566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCLMVM, &same)); 150*970ba202SStefano Zampini if (!same) PetscFunctionReturn(PETSC_SUCCESS); 151*970ba202SStefano Zampini ctx = (PC_LMVM *)pc->data; 1529566063dSJacob Faibussowitsch PetscCall(PCLMVMClearIS(pc)); 1539566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)inactive)); 154b9ac7092SAlp Dener ctx->inactive = inactive; 1553ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 156b9ac7092SAlp Dener } 157b9ac7092SAlp Dener 158b9ac7092SAlp Dener /*@ 159f1580f4eSBarry Smith PCLMVMClearIS - Removes the inactive variable index set from a `PCLMVM` 160b9ac7092SAlp Dener 161f1580f4eSBarry Smith Input Parameter: 162f1580f4eSBarry Smith . pc - An `PCLMVM` preconditioner 163b9ac7092SAlp Dener 164b9ac7092SAlp Dener Level: intermediate 165b9ac7092SAlp Dener 166*970ba202SStefano Zampini .seealso: [](ch_ksp), `PCLMVMSetIS()` 167b9ac7092SAlp Dener @*/ 168d71ae5a4SJacob Faibussowitsch PetscErrorCode PCLMVMClearIS(PC pc) 169d71ae5a4SJacob Faibussowitsch { 170*970ba202SStefano Zampini PC_LMVM *ctx; 171b9ac7092SAlp Dener PetscBool same; 172b9ac7092SAlp Dener 173b9ac7092SAlp Dener PetscFunctionBegin; 174b9ac7092SAlp Dener PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 1759566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCLMVM, &same)); 176*970ba202SStefano Zampini if (!same) PetscFunctionReturn(PETSC_SUCCESS); 177*970ba202SStefano Zampini ctx = (PC_LMVM *)pc->data; 178*970ba202SStefano Zampini PetscCall(ISDestroy(&ctx->inactive)); 1793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 180b9ac7092SAlp Dener } 181b9ac7092SAlp Dener 182d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_LMVM(PC pc, Vec x, Vec y) 183d71ae5a4SJacob Faibussowitsch { 184b9ac7092SAlp Dener PC_LMVM *ctx = (PC_LMVM *)pc->data; 185*970ba202SStefano Zampini Vec xsub, ysub, Bx = x, By = y; 186*970ba202SStefano Zampini Mat B = ctx->B ? ctx->B : (pc->useAmat ? pc->mat : pc->pmat); 187b9ac7092SAlp Dener 188b9ac7092SAlp Dener PetscFunctionBegin; 189b9ac7092SAlp Dener if (ctx->inactive) { 190*970ba202SStefano Zampini if (!ctx->xwork) PetscCall(MatCreateVecs(B, &ctx->xwork, &ctx->ywork)); 1919566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(ctx->xwork)); 1929566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(ctx->xwork, ctx->inactive, &xsub)); 1939566063dSJacob Faibussowitsch PetscCall(VecCopy(x, xsub)); 1949566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(ctx->xwork, ctx->inactive, &xsub)); 195*970ba202SStefano Zampini Bx = ctx->xwork; 196*970ba202SStefano Zampini By = ctx->ywork; 197b9ac7092SAlp Dener } 198*970ba202SStefano Zampini PetscCall(MatSolve(B, Bx, By)); 199b9ac7092SAlp Dener if (ctx->inactive) { 2009566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(ctx->ywork, ctx->inactive, &ysub)); 2019566063dSJacob Faibussowitsch PetscCall(VecCopy(ysub, y)); 2029566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(ctx->ywork, ctx->inactive, &ysub)); 203b9ac7092SAlp Dener } 2043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 205b9ac7092SAlp Dener } 206b9ac7092SAlp Dener 207d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCReset_LMVM(PC pc) 208d71ae5a4SJacob Faibussowitsch { 209b9ac7092SAlp Dener PC_LMVM *ctx = (PC_LMVM *)pc->data; 210b9ac7092SAlp Dener 211b9ac7092SAlp Dener PetscFunctionBegin; 212*970ba202SStefano Zampini PetscCall(VecDestroy(&ctx->xwork)); 213*970ba202SStefano Zampini PetscCall(VecDestroy(&ctx->ywork)); 2143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 215b9ac7092SAlp Dener } 216b9ac7092SAlp Dener 217d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUp_LMVM(PC pc) 218d71ae5a4SJacob Faibussowitsch { 219b9ac7092SAlp Dener PetscInt n, N; 220b2d8c577SAlp Dener PetscBool allocated; 221*970ba202SStefano Zampini Mat B; 222*970ba202SStefano Zampini PC_LMVM *ctx = (PC_LMVM *)pc->data; 223b9ac7092SAlp Dener 224b9ac7092SAlp Dener PetscFunctionBegin; 225*970ba202SStefano Zampini PetscCall(PCLMVMGetMatLMVM(pc, &B)); 226*970ba202SStefano Zampini PetscCall(MatLMVMIsAllocated(B, &allocated)); 227b2d8c577SAlp Dener if (!allocated) { 228*970ba202SStefano Zampini Vec t1, t2; 229*970ba202SStefano Zampini 230*970ba202SStefano Zampini PetscCall(MatCreateVecs(pc->mat, &t1, &t2)); 231*970ba202SStefano Zampini PetscCall(VecGetLocalSize(t1, &n)); 232*970ba202SStefano Zampini PetscCall(VecGetSize(t1, &N)); 233*970ba202SStefano Zampini PetscCall(MatSetSizes(B, n, n, N, N)); 234*970ba202SStefano Zampini PetscCall(MatLMVMAllocate(B, t1, t2)); 235*970ba202SStefano Zampini PetscCall(VecDestroy(&t1)); 236*970ba202SStefano Zampini PetscCall(VecDestroy(&t2)); 237b2d8c577SAlp Dener } 238*970ba202SStefano Zampini /* Only call SetFromOptions if we internally handle the LMVM matrix */ 239*970ba202SStefano Zampini if (B == ctx->B && ctx->setfromoptionscalled) PetscCall(MatSetFromOptions(ctx->B)); 240*970ba202SStefano Zampini ctx->setfromoptionscalled = PETSC_FALSE; 2413ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 242b9ac7092SAlp Dener } 243b9ac7092SAlp Dener 244d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCView_LMVM(PC pc, PetscViewer viewer) 245d71ae5a4SJacob Faibussowitsch { 246b9ac7092SAlp Dener PC_LMVM *ctx = (PC_LMVM *)pc->data; 247b9ac7092SAlp Dener PetscBool iascii; 248b9ac7092SAlp Dener 249b9ac7092SAlp Dener PetscFunctionBegin; 2509566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 251*970ba202SStefano Zampini if (iascii && ctx->B && ctx->B->assembled) { 2529566063dSJacob Faibussowitsch PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INFO)); 2539566063dSJacob Faibussowitsch PetscCall(MatView(ctx->B, viewer)); 2549566063dSJacob Faibussowitsch PetscCall(PetscViewerPopFormat(viewer)); 255b9ac7092SAlp Dener } 2563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 257b9ac7092SAlp Dener } 258b9ac7092SAlp Dener 259d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetFromOptions_LMVM(PC pc, PetscOptionItems *PetscOptionsObject) 260d71ae5a4SJacob Faibussowitsch { 261b9ac7092SAlp Dener PC_LMVM *ctx = (PC_LMVM *)pc->data; 262b9ac7092SAlp Dener 263b9ac7092SAlp Dener PetscFunctionBegin; 264*970ba202SStefano Zampini /* defer SetFromOptions calls to PCSetUp_LMVM */ 265*970ba202SStefano Zampini ctx->setfromoptionscalled = PETSC_TRUE; 266*970ba202SStefano Zampini PetscFunctionReturn(PETSC_SUCCESS); 267*970ba202SStefano Zampini } 268*970ba202SStefano Zampini 269*970ba202SStefano Zampini static PetscErrorCode PCPreSolve_LMVM(PC pc, KSP ksp, Vec F, Vec X) 270*970ba202SStefano Zampini { 271*970ba202SStefano Zampini PC_LMVM *ctx = (PC_LMVM *)pc->data; 272*970ba202SStefano Zampini 273*970ba202SStefano Zampini PetscFunctionBegin; 274*970ba202SStefano Zampini if (ctx->X && ctx->B) { /* Perform update only if requested. Otherwise we assume the user, e.g. TAO, has already taken care of it */ 275*970ba202SStefano Zampini PetscObjectState Xstate; 276*970ba202SStefano Zampini 277*970ba202SStefano Zampini PetscCall(PetscObjectStateGet((PetscObject)ctx->X, &Xstate)); 278*970ba202SStefano Zampini if (ctx->Xstate != Xstate) PetscCall(MatLMVMUpdate(ctx->B, ctx->X, F)); 279*970ba202SStefano Zampini ctx->Xstate = Xstate; 280*970ba202SStefano Zampini } 2813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 282b9ac7092SAlp Dener } 283b9ac7092SAlp Dener 284d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_LMVM(PC pc) 285d71ae5a4SJacob Faibussowitsch { 286b9ac7092SAlp Dener PC_LMVM *ctx = (PC_LMVM *)pc->data; 287b9ac7092SAlp Dener 288b9ac7092SAlp Dener PetscFunctionBegin; 289*970ba202SStefano Zampini PetscCall(ISDestroy(&ctx->inactive)); 2909566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ctx->xwork)); 2919566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ctx->ywork)); 292*970ba202SStefano Zampini PetscCall(VecDestroy(&ctx->X)); 2939566063dSJacob Faibussowitsch PetscCall(MatDestroy(&ctx->B)); 2949566063dSJacob Faibussowitsch PetscCall(PetscFree(pc->data)); 2953ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 296b9ac7092SAlp Dener } 297b9ac7092SAlp Dener 298b9ac7092SAlp Dener /*MC 299*970ba202SStefano Zampini PCLMVM - A preconditioner constructed from a `MATLMVM` matrix. 300*970ba202SStefano Zampini If the preconditioner matrix is not of type `MATLMVM`, an internal matrix is used. 301*970ba202SStefano Zampini Options for the internal `MATLMVM` matrix can be accessed with the -pc_lmvm_ prefix. 302*970ba202SStefano Zampini Alternatively, the user can pass a suitable matrix with `PCLMVMSetMatLMVM()`. 303b9ac7092SAlp Dener 30406dd6b0eSSatish Balay Level: intermediate 30506dd6b0eSSatish Balay 306*970ba202SStefano Zampini .seealso: [](ch_ksp), `PCCreate()`, `PCSetType()`, `PCLMVMSetUpdateVec()`, `PCLMVMSetMatLMVM()`, `PCLMVMGetMatLMVM()` 307b9ac7092SAlp Dener M*/ 308d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_LMVM(PC pc) 309d71ae5a4SJacob Faibussowitsch { 310b9ac7092SAlp Dener PC_LMVM *ctx; 311b9ac7092SAlp Dener 312b9ac7092SAlp Dener PetscFunctionBegin; 3134dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&ctx)); 314b9ac7092SAlp Dener pc->data = (void *)ctx; 315b9ac7092SAlp Dener 316b9ac7092SAlp Dener pc->ops->reset = PCReset_LMVM; 317b9ac7092SAlp Dener pc->ops->setup = PCSetUp_LMVM; 318b9ac7092SAlp Dener pc->ops->destroy = PCDestroy_LMVM; 319b9ac7092SAlp Dener pc->ops->view = PCView_LMVM; 320b9ac7092SAlp Dener pc->ops->apply = PCApply_LMVM; 321b9ac7092SAlp Dener pc->ops->setfromoptions = PCSetFromOptions_LMVM; 3220a545947SLisandro Dalcin pc->ops->applysymmetricleft = NULL; 3230a545947SLisandro Dalcin pc->ops->applysymmetricright = NULL; 3240a545947SLisandro Dalcin pc->ops->applytranspose = NULL; 3250a545947SLisandro Dalcin pc->ops->applyrichardson = NULL; 326*970ba202SStefano Zampini pc->ops->presolve = PCPreSolve_LMVM; 3270a545947SLisandro Dalcin pc->ops->postsolve = NULL; 3283ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 329b9ac7092SAlp Dener } 330