xref: /petsc/src/ksp/pc/impls/lsc/lsc.c (revision 3e7ff0edd3573be01c8c0fa32db97c3db8fa5c8d)
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(PetscObjectComm((PetscObject)pc),&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,NULL,NULL,NULL,NULL);CHKERRQ(ierr);
30   ierr = MatCreateVecs(A,&lsc->x0,&lsc->y0);CHKERRQ(ierr);
31   ierr = MatCreateVecs(pc->pmat,&lsc->x1,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,NULL,NULL,&B,&C,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,NULL,&Ap,NULL,NULL,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);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,NULL,&B,&C,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     ierr = PetscOptionsBool("-pc_lsc_scale_diag","Use diagonal of velocity block (A) for scaling","None",lsc->scalediag,&lsc->scalediag,NULL);CHKERRQ(ierr);
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 = PetscObjectTypeCompare((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   }
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), 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    References:
211 +  Elman, Howle, Shadid, Shuttleworth, and Tuminaro, Block preconditioners based on approximate commutators, 2006.
212 -  Silvester, Elman, Kay, Wathen, Efficient preconditioning of the linearized Navier-Stokes equations for incompressible flow, 2001.
213 
214    Concepts: physics based preconditioners, block preconditioners
215 
216 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners, PCFIELDSPLIT,
217            PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSetSchurPre(),
218            MatCreateSchurComplement()
219 M*/
220 
221 #undef __FUNCT__
222 #define __FUNCT__ "PCCreate_LSC"
223 PETSC_EXTERN PetscErrorCode PCCreate_LSC(PC pc)
224 {
225   PC_LSC         *lsc;
226   PetscErrorCode ierr;
227 
228   PetscFunctionBegin;
229   ierr     = PetscNewLog(pc,&lsc);CHKERRQ(ierr);
230   pc->data = (void*)lsc;
231 
232   pc->ops->apply           = PCApply_LSC;
233   pc->ops->applytranspose  = 0;
234   pc->ops->setup           = PCSetUp_LSC;
235   pc->ops->reset           = PCReset_LSC;
236   pc->ops->destroy         = PCDestroy_LSC;
237   pc->ops->setfromoptions  = PCSetFromOptions_LSC;
238   pc->ops->view            = PCView_LSC;
239   pc->ops->applyrichardson = 0;
240   PetscFunctionReturn(0);
241 }
242