xref: /petsc/src/ksp/pc/impls/lsc/lsc.c (revision 7b6bb2c608b6fc6714ef38fda02c2dbb91c82665)
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