xref: /petsc/src/ksp/pc/impls/lsc/lsc.c (revision ea5d4fccf296dd2bbd0f9c3a3343651cb1066da7)
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->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 = PetscTypeCompare((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   } else SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for LSC",((PetscObject)viewer)->type_name);
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    Concepts: physics based preconditioners, block preconditioners
213 
214 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners, PCFIELDSPLIT,
215            PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition(),
216            MatCreateSchurComplement()
217 M*/
218 
219 EXTERN_C_BEGIN
220 #undef __FUNCT__
221 #define __FUNCT__ "PCCreate_LSC"
222 PetscErrorCode  PCCreate_LSC(PC pc)
223 {
224   PC_LSC         *lsc;
225   PetscErrorCode ierr;
226 
227   PetscFunctionBegin;
228   ierr      = PetscNewLog(pc,PC_LSC,&lsc);CHKERRQ(ierr);
229   pc->data  = (void*)lsc;
230 
231   pc->ops->apply               = PCApply_LSC;
232   pc->ops->applytranspose      = 0;
233   pc->ops->setup               = PCSetUp_LSC;
234   pc->ops->reset               = PCReset_LSC;
235   pc->ops->destroy             = PCDestroy_LSC;
236   pc->ops->setfromoptions      = PCSetFromOptions_LSC;
237   pc->ops->view                = PCView_LSC;
238   pc->ops->applyrichardson     = 0;
239   PetscFunctionReturn(0);
240 }
241 EXTERN_C_END
242