Actual source code: lsc.c

  1: #define PETSCKSP_DLL


 4:  #include private/pcimpl.h

  6: typedef struct {
  7:   PetscTruth allocated;
  8:   PetscTruth scalediag;
  9:   KSP        kspL;
 10:   Vec        scale;
 11:   Vec        x0,y0,x1;
 12: } PC_LSC;

 16: static PetscErrorCode PCLSCAllocate_Private(PC pc)
 17: {
 18:   PC_LSC         *lsc = (PC_LSC*)pc->data;
 19:   Mat             A;
 20:   PetscErrorCode  ierr;

 23:   if (lsc->allocated) return(0);
 24:   KSPCreate(((PetscObject)pc)->comm,&lsc->kspL);
 25:   KSPSetType(lsc->kspL,KSPPREONLY);
 26:   KSPSetOptionsPrefix(lsc->kspL,((PetscObject)pc)->prefix);
 27:   KSPAppendOptionsPrefix(lsc->kspL,"lsc_");
 28:   KSPSetFromOptions(lsc->kspL);
 29:   MatSchurComplementGetSubmatrices(pc->mat,&A,PETSC_NULL,PETSC_NULL,PETSC_NULL,PETSC_NULL);
 30:   MatGetVecs(A,&lsc->x0,&lsc->y0);
 31:   MatGetVecs(pc->pmat,&lsc->x1,PETSC_NULL);
 32:   if (lsc->scalediag) {
 33:     VecDuplicate(lsc->x0,&lsc->scale);
 34:   }
 35:   lsc->allocated = PETSC_TRUE;
 36:   return(0);
 37: }

 41: static PetscErrorCode PCSetUp_LSC(PC pc)
 42: {
 43:   PC_LSC         *lsc = (PC_LSC*)pc->data;
 44:   Mat             L,Lp;
 45:   PetscErrorCode  ierr;

 48:   PCLSCAllocate_Private(pc);
 49:   PetscObjectQuery((PetscObject)pc->pmat,"LSC_L",(PetscObject*)&L);
 50:   PetscObjectQuery((PetscObject)pc->pmat,"LSC_Lp",(PetscObject*)&Lp);
 51:   if (lsc->scale) {
 52:     Mat Ap;
 53:     MatSchurComplementGetSubmatrices(pc->mat,PETSC_NULL,&Ap,PETSC_NULL,PETSC_NULL,PETSC_NULL);
 54:     MatGetDiagonal(Ap,lsc->scale); /* Should be the mass matrix, but we don't have plumbing for that yet */
 55:     VecReciprocal(lsc->scale);
 56:   }
 57:   KSPSetOperators(lsc->kspL,L,Lp,SAME_NONZERO_PATTERN);
 58:   return(0);
 59: }

 63: static PetscErrorCode PCApply_LSC(PC pc,Vec x,Vec y)
 64: {
 65:   PC_LSC        *lsc = (PC_LSC*)pc->data;
 66:   Mat            A,B,C;

 70:   MatSchurComplementGetSubmatrices(pc->mat,&A,PETSC_NULL,&B,&C,PETSC_NULL);
 71:   KSPSolve(lsc->kspL,x,lsc->x1);
 72:   MatMult(B,lsc->x1,lsc->x0);
 73:   if (lsc->scale) {
 74:     VecPointwiseMult(lsc->x0,lsc->x0,lsc->scale);
 75:   }
 76:   MatMult(A,lsc->x0,lsc->y0);
 77:   if (lsc->scale) {
 78:     VecPointwiseMult(lsc->y0,lsc->y0,lsc->scale);
 79:   }
 80:   MatMult(C,lsc->y0,lsc->x1);
 81:   KSPSolve(lsc->kspL,lsc->x1,y);
 82:   return(0);
 83: }

 87: static PetscErrorCode PCDestroy_LSC(PC pc)
 88: {
 89:   PC_LSC         *lsc = (PC_LSC*)pc->data;

 93:   if (lsc->x0)    {VecDestroy(lsc->x0);}
 94:   if (lsc->y0)    {VecDestroy(lsc->y0);}
 95:   if (lsc->x1)    {VecDestroy(lsc->x1);}
 96:   if (lsc->scale) {VecDestroy(lsc->scale);}
 97:   if (lsc->kspL)  {KSPDestroy(lsc->kspL);}
 98:   PetscFree(lsc);
 99:   return(0);
100: }

104: static PetscErrorCode PCSetFromOptions_LSC(PC pc)
105: {
106:   PC_LSC         *lsc = (PC_LSC*)pc->data;
107:   PetscErrorCode  ierr;

110:   PetscOptionsHead("LSC options");
111:   {
112:     PetscOptionsTruth("-pc_lsc_scale_diag","Use diagonal of velocity block (A) for scaling","None",lsc->scalediag,&lsc->scalediag,PETSC_NULL);
113:   }
114:   PetscOptionsTail();
115:   return(0);
116: }

118: /*MC
119:      PCLSC - Preconditioning for Schur complements, based on Least Squares Commutators

121:    Options Database Key:
122: .    -pc_lsc_scale_diag - Use the diagonal of A for scaling

124:    Level: intermediate

126:    Notes:
127:    This preconditioner will normally be used with PCFieldSplit to precondition the Schur complement, but
128:    it can be used for any Schur complement system.  Consider the Schur complement

130: .vb
131:    S = D - C inv(A) B
132: .ve

134:    PCLSC currently doesn't do anything with D, so let's assume it is 0.  The idea is that a good approximation to
135:    inv(S) is given by

137: .vb
138:    inv(CB) C A B inv(CB)
139: .ve

141:    At some point, we'll be able to form the product CB for you, but for now the application has to provide it (this is
142:    usually more efficient anyway).  In the case of incompressible flow, CB is a Laplacian, call it L.  The current
143:    interface is to hang L and a preconditioning matrix Lp on the preconditioning matrix.

145:    If you had called KSPSetOperators(ksp,S,Sp,flg), S should have type MATSCHURCOMPLEMENT and Sp can be any type you
146:    like (PCLSC doesn't use it directly) but should have matrices composed with it, under the names "LSC_L" and "LSC_Lp".
147:    For example, you might have setup code like this

149: .vb
150:    PetscObjectCompose((PetscObject)Sp,"LSC_L",(PetscObject)L);
151:    PetscObjectCompose((PetscObject)Sp,"LSC_Lp",(PetscObject)Lp);
152: .ve

154:    And then your Jacobian assembly would look like

156: .vb
157:    PetscObjectQuery((PetscObject)Sp,"LSC_L",(PetscObject*)&L);
158:    PetscObjectQuery((PetscObject)Sp,"LSC_Lp",(PetscObject*)&Lp);
159:    if (L) { assembly L }
160:    if (Lp) { assemble Lp }
161: .ve

163:    With this, you should be able to choose LSC preconditioning, using e.g. ML's algebraic multigrid to solve with L

165: .vb
166:    -fieldsplit_1_pc_type lsc -fieldsplit_1_lsc_pc_type ml
167: .ve

169:    Since we do not use the values in Sp, you can still put an assembled matrix there to use normal preconditioners.

171:    Concepts: physics based preconditioners, block preconditioners

173: .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners, PCFIELDSPLIT,
174:            PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition(),
175:            MatCreateSchurComplement()
176: M*/

181: PetscErrorCode  PCCreate_LSC(PC pc)
182: {
183:   PC_LSC         *lsc;

187:   PetscNewLog(pc,PC_LSC,&lsc);
188:   pc->data  = (void*)lsc;

190:   pc->ops->apply               = PCApply_LSC;
191:   pc->ops->applytranspose      = 0;
192:   pc->ops->setup               = PCSetUp_LSC;
193:   pc->ops->destroy             = PCDestroy_LSC;
194:   pc->ops->setfromoptions      = PCSetFromOptions_LSC;
195:   pc->ops->view                = 0;
196:   pc->ops->applyrichardson     = 0;
197:   return(0);
198: }