xref: /petsc/src/ksp/pc/impls/galerkin/galerkin.c (revision a4e35b1925eceef64945ea472b84f2bf06a67b5e)
1 
2 /*
3       Defines a preconditioner defined by R^T S R
4 */
5 #include <petsc/private/pcimpl.h>
6 #include <petscksp.h> /*I "petscksp.h" I*/
7 
8 typedef struct {
9   KSP ksp;
10   Mat R, P;
11   Vec b, x;
12   PetscErrorCode (*computeasub)(PC, Mat, Mat, Mat *, void *);
13   void *computeasub_ctx;
14 } PC_Galerkin;
15 
16 static PetscErrorCode PCApply_Galerkin(PC pc, Vec x, Vec y)
17 {
18   PC_Galerkin *jac = (PC_Galerkin *)pc->data;
19 
20   PetscFunctionBegin;
21   if (jac->R) {
22     PetscCall(MatRestrict(jac->R, x, jac->b));
23   } else {
24     PetscCall(MatRestrict(jac->P, x, jac->b));
25   }
26   PetscCall(KSPSolve(jac->ksp, jac->b, jac->x));
27   PetscCall(KSPCheckSolve(jac->ksp, pc, jac->x));
28   if (jac->P) {
29     PetscCall(MatInterpolate(jac->P, jac->x, y));
30   } else {
31     PetscCall(MatInterpolate(jac->R, jac->x, y));
32   }
33   PetscFunctionReturn(PETSC_SUCCESS);
34 }
35 
36 static PetscErrorCode PCSetUp_Galerkin(PC pc)
37 {
38   PC_Galerkin *jac = (PC_Galerkin *)pc->data;
39   PetscBool    a;
40   Vec         *xx, *yy;
41 
42   PetscFunctionBegin;
43   if (jac->computeasub) {
44     Mat Ap;
45     if (!pc->setupcalled) {
46       PetscCall((*jac->computeasub)(pc, pc->pmat, NULL, &Ap, jac->computeasub_ctx));
47       PetscCall(KSPSetOperators(jac->ksp, Ap, Ap));
48       PetscCall(MatDestroy(&Ap));
49     } else {
50       PetscCall(KSPGetOperators(jac->ksp, NULL, &Ap));
51       PetscCall((*jac->computeasub)(pc, pc->pmat, Ap, NULL, jac->computeasub_ctx));
52     }
53   }
54 
55   if (!jac->x) {
56     PetscCall(KSPGetOperatorsSet(jac->ksp, &a, NULL));
57     PetscCheck(a, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set operator of PCGALERKIN KSP with PCGalerkinGetKSP()/KSPSetOperators()");
58     PetscCall(KSPCreateVecs(jac->ksp, 1, &xx, 1, &yy));
59     jac->x = *xx;
60     jac->b = *yy;
61     PetscCall(PetscFree(xx));
62     PetscCall(PetscFree(yy));
63   }
64   PetscCheck(jac->R || jac->P, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set restriction or interpolation of PCGALERKIN with PCGalerkinSetRestriction()/Interpolation()");
65   /* should check here that sizes of R/P match size of a */
66 
67   PetscFunctionReturn(PETSC_SUCCESS);
68 }
69 
70 static PetscErrorCode PCReset_Galerkin(PC pc)
71 {
72   PC_Galerkin *jac = (PC_Galerkin *)pc->data;
73 
74   PetscFunctionBegin;
75   PetscCall(MatDestroy(&jac->R));
76   PetscCall(MatDestroy(&jac->P));
77   PetscCall(VecDestroy(&jac->x));
78   PetscCall(VecDestroy(&jac->b));
79   PetscCall(KSPReset(jac->ksp));
80   PetscFunctionReturn(PETSC_SUCCESS);
81 }
82 
83 static PetscErrorCode PCDestroy_Galerkin(PC pc)
84 {
85   PC_Galerkin *jac = (PC_Galerkin *)pc->data;
86 
87   PetscFunctionBegin;
88   PetscCall(PCReset_Galerkin(pc));
89   PetscCall(KSPDestroy(&jac->ksp));
90   PetscCall(PetscFree(pc->data));
91   PetscFunctionReturn(PETSC_SUCCESS);
92 }
93 
94 static PetscErrorCode PCView_Galerkin(PC pc, PetscViewer viewer)
95 {
96   PC_Galerkin *jac = (PC_Galerkin *)pc->data;
97   PetscBool    iascii;
98 
99   PetscFunctionBegin;
100   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
101   if (iascii) {
102     PetscCall(PetscViewerASCIIPrintf(viewer, "  KSP on Galerkin follow\n"));
103     PetscCall(PetscViewerASCIIPrintf(viewer, "  ---------------------------------\n"));
104   }
105   PetscCall(KSPView(jac->ksp, viewer));
106   PetscFunctionReturn(PETSC_SUCCESS);
107 }
108 
109 static PetscErrorCode PCGalerkinGetKSP_Galerkin(PC pc, KSP *ksp)
110 {
111   PC_Galerkin *jac = (PC_Galerkin *)pc->data;
112 
113   PetscFunctionBegin;
114   *ksp = jac->ksp;
115   PetscFunctionReturn(PETSC_SUCCESS);
116 }
117 
118 static PetscErrorCode PCGalerkinSetRestriction_Galerkin(PC pc, Mat R)
119 {
120   PC_Galerkin *jac = (PC_Galerkin *)pc->data;
121 
122   PetscFunctionBegin;
123   PetscCall(PetscObjectReference((PetscObject)R));
124   PetscCall(MatDestroy(&jac->R));
125   jac->R = R;
126   PetscFunctionReturn(PETSC_SUCCESS);
127 }
128 
129 static PetscErrorCode PCGalerkinSetInterpolation_Galerkin(PC pc, Mat P)
130 {
131   PC_Galerkin *jac = (PC_Galerkin *)pc->data;
132 
133   PetscFunctionBegin;
134   PetscCall(PetscObjectReference((PetscObject)P));
135   PetscCall(MatDestroy(&jac->P));
136   jac->P = P;
137   PetscFunctionReturn(PETSC_SUCCESS);
138 }
139 
140 static PetscErrorCode PCGalerkinSetComputeSubmatrix_Galerkin(PC pc, PetscErrorCode (*computeAsub)(PC, Mat, Mat, Mat *, void *), void *ctx)
141 {
142   PC_Galerkin *jac = (PC_Galerkin *)pc->data;
143 
144   PetscFunctionBegin;
145   jac->computeasub     = computeAsub;
146   jac->computeasub_ctx = ctx;
147   PetscFunctionReturn(PETSC_SUCCESS);
148 }
149 
150 /*@
151   PCGalerkinSetRestriction - Sets the restriction operator for the `PCGALERKIN` preconditioner
152 
153   Logically Collective
154 
155   Input Parameters:
156 + pc - the preconditioner context
157 - R  - the restriction operator
158 
159   Level: intermediate
160 
161   Note:
162   Either this or `PCGalerkinSetInterpolation()` or both must be called
163 
164 .seealso: `PC`, `PCCreate()`, `PCSetType()`, `PCType`, `PCGALERKIN`,
165           `PCGalerkinSetInterpolation()`, `PCGalerkinGetKSP()`
166 @*/
167 PetscErrorCode PCGalerkinSetRestriction(PC pc, Mat R)
168 {
169   PetscFunctionBegin;
170   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
171   PetscTryMethod(pc, "PCGalerkinSetRestriction_C", (PC, Mat), (pc, R));
172   PetscFunctionReturn(PETSC_SUCCESS);
173 }
174 
175 /*@
176   PCGalerkinSetInterpolation - Sets the interpolation operator for the `PCGALERKIN` preconditioner
177 
178   Logically Collective
179 
180   Input Parameters:
181 + pc - the preconditioner context
182 - P  - the interpolation operator
183 
184   Level: intermediate
185 
186   Note:
187   Either this or `PCGalerkinSetRestriction()` or both must be called
188 
189 .seealso: `PC`, `PCCreate()`, `PCSetType()`, `PCType`, `PCGALERKIN`,
190           `PCGalerkinSetRestriction()`, `PCGalerkinGetKSP()`
191 @*/
192 PetscErrorCode PCGalerkinSetInterpolation(PC pc, Mat P)
193 {
194   PetscFunctionBegin;
195   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
196   PetscTryMethod(pc, "PCGalerkinSetInterpolation_C", (PC, Mat), (pc, P));
197   PetscFunctionReturn(PETSC_SUCCESS);
198 }
199 
200 /*@C
201   PCGalerkinSetComputeSubmatrix - Provide a routine that will be called to compute the Galerkin submatrix
202 
203   Logically Collective
204 
205   Input Parameters:
206 + pc          - the preconditioner context
207 . computeAsub - routine that computes the submatrix from the global matrix
208 - ctx         - context used by the routine, or `NULL`
209 
210   Calling sequence of `computeAsub`:
211 + pc  - the `PCGALERKIN` preconditioner
212 . A   - the matrix in the `PCGALERKIN`
213 . Ap  - the computed submatrix from any previous computation, if `NULL` it has not previously been computed
214 . cAp - the submatrix computed by this routine
215 - ctx - optional user-defined function context
216 
217   Level: intermediate
218 
219   Notes:
220   Instead of providing this routine you can call `PCGalerkinGetKSP()` and then `KSPSetOperators()` to provide the submatrix,
221   but that will not work for multiple `KSPSolve()`s with different matrices unless you call it for each solve.
222 
223   This routine is called each time the outer matrix is changed. In the first call the Ap argument is `NULL` and the routine should create the
224   matrix and computes its values in cAp. On each subsequent call the routine should up the Ap matrix.
225 
226   Developer Notes:
227   If the user does not call this routine nor call `PCGalerkinGetKSP()` and `KSPSetOperators()` then `PCGALERKIN`
228   could automatically compute the submatrix via calls to `MatGalerkin()` or `MatRARt()`
229 
230 .seealso: `PC`, `PCCreate()`, `PCSetType()`, `PCType`, `PCGALERKIN`,
231           `PCGalerkinSetRestriction()`, `PCGalerkinSetInterpolation()`, `PCGalerkinGetKSP()`
232 @*/
233 PetscErrorCode PCGalerkinSetComputeSubmatrix(PC pc, PetscErrorCode (*computeAsub)(PC pc, Mat A, Mat Ap, Mat *cAp, void *ctx), void *ctx)
234 {
235   PetscFunctionBegin;
236   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
237   PetscTryMethod(pc, "PCGalerkinSetComputeSubmatrix_C", (PC, PetscErrorCode(*)(PC, Mat, Mat, Mat *, void *), void *), (pc, computeAsub, ctx));
238   PetscFunctionReturn(PETSC_SUCCESS);
239 }
240 
241 /*@
242   PCGalerkinGetKSP - Gets the `KSP` object in the `PCGALERKIN`
243 
244   Not Collective
245 
246   Input Parameter:
247 . pc - the preconditioner context
248 
249   Output Parameter:
250 . ksp - the `KSP` object
251 
252   Level: intermediate
253 
254   Note:
255   Once you have called this routine you can call `KSPSetOperators()` on the resulting `KSP` to provide the operator for the Galerkin problem,
256   an alternative is to use `PCGalerkinSetComputeSubmatrix()` to provide a routine that computes the submatrix as needed.
257 
258 .seealso: `PC`, `PCCreate()`, `PCSetType()`, `PCType`, `PCGALERKIN`,
259           `PCGalerkinSetRestriction()`, `PCGalerkinSetInterpolation()`, `PCGalerkinSetComputeSubmatrix()`
260 @*/
261 PetscErrorCode PCGalerkinGetKSP(PC pc, KSP *ksp)
262 {
263   PetscFunctionBegin;
264   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
265   PetscAssertPointer(ksp, 2);
266   PetscUseMethod(pc, "PCGalerkinGetKSP_C", (PC, KSP *), (pc, ksp));
267   PetscFunctionReturn(PETSC_SUCCESS);
268 }
269 
270 static PetscErrorCode PCSetFromOptions_Galerkin(PC pc, PetscOptionItems *PetscOptionsObject)
271 {
272   PC_Galerkin *jac = (PC_Galerkin *)pc->data;
273   const char  *prefix;
274   PetscBool    flg;
275 
276   PetscFunctionBegin;
277   PetscCall(KSPGetOptionsPrefix(jac->ksp, &prefix));
278   PetscCall(PetscStrendswith(prefix, "galerkin_", &flg));
279   if (!flg) {
280     PetscCall(PCGetOptionsPrefix(pc, &prefix));
281     PetscCall(KSPSetOptionsPrefix(jac->ksp, prefix));
282     PetscCall(KSPAppendOptionsPrefix(jac->ksp, "galerkin_"));
283   }
284 
285   PetscOptionsHeadBegin(PetscOptionsObject, "Galerkin options");
286   if (jac->ksp) PetscCall(KSPSetFromOptions(jac->ksp));
287   PetscOptionsHeadEnd();
288   PetscFunctionReturn(PETSC_SUCCESS);
289 }
290 
291 /*MC
292      PCGALERKIN - Build (part of) a preconditioner by P S R (where P is often R^T)
293 
294     Level: intermediate
295 
296     Note:
297     Use
298 .vb
299      `PCGalerkinSetRestriction`(pc,R) and/or `PCGalerkinSetInterpolation`(pc,P)
300      `PCGalerkinGetKSP`(pc,&ksp);
301      `KSPSetOperators`(ksp,A,....)
302      ...
303 .ve
304 
305     Developer Notes:
306     If `KSPSetOperators()` has not been called on the inner `KSP` then `PCGALERKIN` could use `MatRARt()` or `MatPtAP()` to compute
307     the operators automatically.
308 
309     Should there be a prefix for the inner `KSP`?
310 
311     There is no `KSPSetFromOptions_Galerkin()` that calls `KSPSetFromOptions()` on the inner `KSP`
312 
313 .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`,
314           `PCSHELL`, `PCKSP`, `PCGalerkinSetRestriction()`, `PCGalerkinSetInterpolation()`, `PCGalerkinGetKSP()`
315 M*/
316 
317 PETSC_EXTERN PetscErrorCode PCCreate_Galerkin(PC pc)
318 {
319   PC_Galerkin *jac;
320 
321   PetscFunctionBegin;
322   PetscCall(PetscNew(&jac));
323 
324   pc->ops->apply           = PCApply_Galerkin;
325   pc->ops->setup           = PCSetUp_Galerkin;
326   pc->ops->reset           = PCReset_Galerkin;
327   pc->ops->destroy         = PCDestroy_Galerkin;
328   pc->ops->view            = PCView_Galerkin;
329   pc->ops->setfromoptions  = PCSetFromOptions_Galerkin;
330   pc->ops->applyrichardson = NULL;
331 
332   PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &jac->ksp));
333   PetscCall(KSPSetNestLevel(jac->ksp, pc->kspnestlevel));
334   PetscCall(KSPSetErrorIfNotConverged(jac->ksp, pc->erroriffailure));
335   PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->ksp, (PetscObject)pc, 1));
336 
337   pc->data = (void *)jac;
338 
339   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGalerkinSetRestriction_C", PCGalerkinSetRestriction_Galerkin));
340   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGalerkinSetInterpolation_C", PCGalerkinSetInterpolation_Galerkin));
341   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGalerkinGetKSP_C", PCGalerkinGetKSP_Galerkin));
342   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGalerkinSetComputeSubmatrix_C", PCGalerkinSetComputeSubmatrix_Galerkin));
343   PetscFunctionReturn(PETSC_SUCCESS);
344 }
345