1 2 #include <petsc-private/pcimpl.h> /*I "petscpc.h" I*/ 3 4 typedef struct { 5 PetscBool allocated; 6 PetscBool scalediag; 7 KSP kspL; 8 Vec scale; 9 Vec x0,y0,x1; 10 Mat L; /* keep a copy to reuse when obtained with L = A10*A01 */ 11 } PC_LSC; 12 13 #undef __FUNCT__ 14 #define __FUNCT__ "PCLSCAllocate_Private" 15 static PetscErrorCode PCLSCAllocate_Private(PC pc) 16 { 17 PC_LSC *lsc = (PC_LSC*)pc->data; 18 Mat A; 19 PetscErrorCode ierr; 20 21 PetscFunctionBegin; 22 if (lsc->allocated) PetscFunctionReturn(0); 23 ierr = KSPCreate(((PetscObject)pc)->comm,&lsc->kspL);CHKERRQ(ierr); 24 ierr = PetscObjectIncrementTabLevel((PetscObject)lsc->kspL,(PetscObject)pc,1);CHKERRQ(ierr); 25 ierr = KSPSetType(lsc->kspL,KSPPREONLY);CHKERRQ(ierr); 26 ierr = KSPSetOptionsPrefix(lsc->kspL,((PetscObject)pc)->prefix);CHKERRQ(ierr); 27 ierr = KSPAppendOptionsPrefix(lsc->kspL,"lsc_");CHKERRQ(ierr); 28 ierr = KSPSetFromOptions(lsc->kspL);CHKERRQ(ierr); 29 ierr = MatSchurComplementGetSubmatrices(pc->mat,&A,PETSC_NULL,PETSC_NULL,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 30 ierr = MatGetVecs(A,&lsc->x0,&lsc->y0);CHKERRQ(ierr); 31 ierr = MatGetVecs(pc->pmat,&lsc->x1,PETSC_NULL);CHKERRQ(ierr); 32 if (lsc->scalediag) { 33 ierr = VecDuplicate(lsc->x0,&lsc->scale);CHKERRQ(ierr); 34 } 35 lsc->allocated = PETSC_TRUE; 36 PetscFunctionReturn(0); 37 } 38 39 #undef __FUNCT__ 40 #define __FUNCT__ "PCSetUp_LSC" 41 static PetscErrorCode PCSetUp_LSC(PC pc) 42 { 43 PC_LSC *lsc = (PC_LSC*)pc->data; 44 Mat L,Lp,B,C; 45 PetscErrorCode ierr; 46 47 PetscFunctionBegin; 48 ierr = PCLSCAllocate_Private(pc);CHKERRQ(ierr); 49 ierr = PetscObjectQuery((PetscObject)pc->mat,"LSC_L",(PetscObject*)&L);CHKERRQ(ierr); 50 if (!L) {ierr = PetscObjectQuery((PetscObject)pc->pmat,"LSC_L",(PetscObject*)&L);CHKERRQ(ierr);} 51 ierr = PetscObjectQuery((PetscObject)pc->pmat,"LSC_Lp",(PetscObject*)&Lp);CHKERRQ(ierr); 52 if (!Lp) {ierr = PetscObjectQuery((PetscObject)pc->mat,"LSC_Lp",(PetscObject*)&Lp);CHKERRQ(ierr);} 53 if (!L) { 54 ierr = MatSchurComplementGetSubmatrices(pc->mat,PETSC_NULL,PETSC_NULL,&B,&C,PETSC_NULL);CHKERRQ(ierr); 55 if (!lsc->L) { 56 ierr = MatMatMult(C,B,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&lsc->L);CHKERRQ(ierr); 57 } else { 58 ierr = MatMatMult(C,B,MAT_REUSE_MATRIX,PETSC_DEFAULT,&lsc->L);CHKERRQ(ierr); 59 } 60 Lp = L = lsc->L; 61 } 62 if (lsc->scale) { 63 Mat Ap; 64 ierr = MatSchurComplementGetSubmatrices(pc->mat,PETSC_NULL,&Ap,PETSC_NULL,PETSC_NULL,PETSC_NULL);CHKERRQ(ierr); 65 ierr = MatGetDiagonal(Ap,lsc->scale);CHKERRQ(ierr); /* Should be the mass matrix, but we don't have plumbing for that yet */ 66 ierr = VecReciprocal(lsc->scale);CHKERRQ(ierr); 67 } 68 ierr = KSPSetOperators(lsc->kspL,L,Lp,SAME_NONZERO_PATTERN);CHKERRQ(ierr); 69 PetscFunctionReturn(0); 70 } 71 72 #undef __FUNCT__ 73 #define __FUNCT__ "PCApply_LSC" 74 static PetscErrorCode PCApply_LSC(PC pc,Vec x,Vec y) 75 { 76 PC_LSC *lsc = (PC_LSC*)pc->data; 77 Mat A,B,C; 78 PetscErrorCode ierr; 79 80 PetscFunctionBegin; 81 ierr = MatSchurComplementGetSubmatrices(pc->mat,&A,PETSC_NULL,&B,&C,PETSC_NULL);CHKERRQ(ierr); 82 ierr = KSPSolve(lsc->kspL,x,lsc->x1);CHKERRQ(ierr); 83 ierr = MatMult(B,lsc->x1,lsc->x0);CHKERRQ(ierr); 84 if (lsc->scale) { 85 ierr = VecPointwiseMult(lsc->x0,lsc->x0,lsc->scale);CHKERRQ(ierr); 86 } 87 ierr = MatMult(A,lsc->x0,lsc->y0);CHKERRQ(ierr); 88 if (lsc->scale) { 89 ierr = VecPointwiseMult(lsc->y0,lsc->y0,lsc->scale);CHKERRQ(ierr); 90 } 91 ierr = MatMult(C,lsc->y0,lsc->x1);CHKERRQ(ierr); 92 ierr = KSPSolve(lsc->kspL,lsc->x1,y);CHKERRQ(ierr); 93 PetscFunctionReturn(0); 94 } 95 96 #undef __FUNCT__ 97 #define __FUNCT__ "PCReset_LSC" 98 static PetscErrorCode PCReset_LSC(PC pc) 99 { 100 PC_LSC *lsc = (PC_LSC*)pc->data; 101 PetscErrorCode ierr; 102 103 PetscFunctionBegin; 104 ierr = VecDestroy(&lsc->x0);CHKERRQ(ierr); 105 ierr = VecDestroy(&lsc->y0);CHKERRQ(ierr); 106 ierr = VecDestroy(&lsc->x1);CHKERRQ(ierr); 107 ierr = VecDestroy(&lsc->scale);CHKERRQ(ierr); 108 ierr = KSPDestroy(&lsc->kspL);CHKERRQ(ierr); 109 ierr = MatDestroy(&lsc->L);CHKERRQ(ierr); 110 PetscFunctionReturn(0); 111 } 112 113 #undef __FUNCT__ 114 #define __FUNCT__ "PCDestroy_LSC" 115 static PetscErrorCode PCDestroy_LSC(PC pc) 116 { 117 PetscErrorCode ierr; 118 119 PetscFunctionBegin; 120 ierr = PCReset_LSC(pc);CHKERRQ(ierr); 121 ierr = PetscFree(pc->data);CHKERRQ(ierr); 122 PetscFunctionReturn(0); 123 } 124 125 #undef __FUNCT__ 126 #define __FUNCT__ "PCSetFromOptions_LSC" 127 static PetscErrorCode PCSetFromOptions_LSC(PC pc) 128 { 129 PC_LSC *lsc = (PC_LSC*)pc->data; 130 PetscErrorCode ierr; 131 132 PetscFunctionBegin; 133 ierr = PetscOptionsHead("LSC options");CHKERRQ(ierr); 134 { 135 ierr = PetscOptionsBool("-pc_lsc_scale_diag","Use diagonal of velocity block (A) for scaling","None",lsc->scalediag,&lsc->scalediag,PETSC_NULL);CHKERRQ(ierr); 136 } 137 ierr = PetscOptionsTail();CHKERRQ(ierr); 138 PetscFunctionReturn(0); 139 } 140 141 #undef __FUNCT__ 142 #define __FUNCT__ "PCView_LSC" 143 static PetscErrorCode PCView_LSC(PC pc,PetscViewer viewer) 144 { 145 PC_LSC *jac = (PC_LSC*)pc->data; 146 PetscErrorCode ierr; 147 PetscBool iascii; 148 149 PetscFunctionBegin; 150 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 151 if (iascii) { 152 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 153 ierr = KSPView(jac->kspL,viewer);CHKERRQ(ierr); 154 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 155 } 156 PetscFunctionReturn(0); 157 } 158 159 /*MC 160 PCLSC - Preconditioning for Schur complements, based on Least Squares Commutators 161 162 Options Database Key: 163 . -pc_lsc_scale_diag - Use the diagonal of A for scaling 164 165 Level: intermediate 166 167 Notes: 168 This preconditioner will normally be used with PCFieldSplit to precondition the Schur complement, but 169 it can be used for any Schur complement system. Consider the Schur complement 170 171 .vb 172 S = A11 - A10 inv(A00) A01 173 .ve 174 175 PCLSC currently doesn't do anything with A11, so let's assume it is 0. The idea is that a good approximation to 176 inv(S) is given by 177 178 .vb 179 inv(A10 A01) A10 A00 A01 inv(A10 A01) 180 .ve 181 182 The product A10 A01 can be computed for you, but you can provide it (this is 183 usually more efficient anyway). In the case of incompressible flow, A10 A10 is a Laplacian, call it L. The current 184 interface is to hang L and a preconditioning matrix Lp on the preconditioning matrix. 185 186 If you had called KSPSetOperators(ksp,S,Sp,flg), S should have type MATSCHURCOMPLEMENT and Sp can be any type you 187 like (PCLSC doesn't use it directly) but should have matrices composed with it, under the names "LSC_L" and "LSC_Lp". 188 For example, you might have setup code like this 189 190 .vb 191 PetscObjectCompose((PetscObject)Sp,"LSC_L",(PetscObject)L); 192 PetscObjectCompose((PetscObject)Sp,"LSC_Lp",(PetscObject)Lp); 193 .ve 194 195 And then your Jacobian assembly would look like 196 197 .vb 198 PetscObjectQuery((PetscObject)Sp,"LSC_L",(PetscObject*)&L); 199 PetscObjectQuery((PetscObject)Sp,"LSC_Lp",(PetscObject*)&Lp); 200 if (L) { assembly L } 201 if (Lp) { assemble Lp } 202 .ve 203 204 With this, you should be able to choose LSC preconditioning, using e.g. ML's algebraic multigrid to solve with L 205 206 .vb 207 -fieldsplit_1_pc_type lsc -fieldsplit_1_lsc_pc_type ml 208 .ve 209 210 Since we do not use the values in Sp, you can still put an assembled matrix there to use normal preconditioners. 211 212 References: 213 + Elman, Howle, Shadid, Shuttleworth, and Tuminaro, Block preconditioners based on approximate commutators, 2006. 214 - Silvester, Elman, Kay, Wathen, Efficient preconditioning of the linearized Navier-Stokes equations for incompressible flow, 2001. 215 216 Concepts: physics based preconditioners, block preconditioners 217 218 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners, PCFIELDSPLIT, 219 PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition(), 220 MatCreateSchurComplement() 221 M*/ 222 223 EXTERN_C_BEGIN 224 #undef __FUNCT__ 225 #define __FUNCT__ "PCCreate_LSC" 226 PetscErrorCode PCCreate_LSC(PC pc) 227 { 228 PC_LSC *lsc; 229 PetscErrorCode ierr; 230 231 PetscFunctionBegin; 232 ierr = PetscNewLog(pc,PC_LSC,&lsc);CHKERRQ(ierr); 233 pc->data = (void*)lsc; 234 235 pc->ops->apply = PCApply_LSC; 236 pc->ops->applytranspose = 0; 237 pc->ops->setup = PCSetUp_LSC; 238 pc->ops->reset = PCReset_LSC; 239 pc->ops->destroy = PCDestroy_LSC; 240 pc->ops->setfromoptions = PCSetFromOptions_LSC; 241 pc->ops->view = PCView_LSC; 242 pc->ops->applyrichardson = 0; 243 PetscFunctionReturn(0); 244 } 245 EXTERN_C_END 246