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