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