1 #include <petsc/private/pcmgimpl.h> /*I "petscksp.h" I*/
2
3 /*@
4 PCMGResidualDefault - Default routine to calculate the residual.
5
6 Collective
7
8 Input Parameters:
9 + mat - the matrix
10 . b - the right-hand side
11 - x - the approximate solution
12
13 Output Parameter:
14 . r - location to store the residual
15
16 Level: developer
17
18 .seealso: [](ch_ksp), `PCMG`, `PCMGSetResidual()`, `PCMGSetMatResidual()`
19 @*/
PCMGResidualDefault(Mat mat,Vec b,Vec x,Vec r)20 PetscErrorCode PCMGResidualDefault(Mat mat, Vec b, Vec x, Vec r)
21 {
22 PetscFunctionBegin;
23 PetscCall(MatResidual(mat, b, x, r));
24 PetscFunctionReturn(PETSC_SUCCESS);
25 }
26
27 /*@
28 PCMGResidualTransposeDefault - Default routine to calculate the residual of the transposed linear system
29
30 Collective
31
32 Input Parameters:
33 + mat - the matrix
34 . b - the right-hand side
35 - x - the approximate solution
36
37 Output Parameter:
38 . r - location to store the residual
39
40 Level: developer
41
42 .seealso: [](ch_ksp), `PCMG`, `PCMGSetResidualTranspose()`, `PCMGMatResidualTransposeDefault()`
43 @*/
PCMGResidualTransposeDefault(Mat mat,Vec b,Vec x,Vec r)44 PetscErrorCode PCMGResidualTransposeDefault(Mat mat, Vec b, Vec x, Vec r)
45 {
46 PetscFunctionBegin;
47 PetscCall(MatMultTranspose(mat, x, r));
48 PetscCall(VecAYPX(r, -1.0, b));
49 PetscFunctionReturn(PETSC_SUCCESS);
50 }
51
52 /*@
53 PCMGMatResidualDefault - Default routine to calculate the residual.
54
55 Collective
56
57 Input Parameters:
58 + mat - the matrix
59 . b - the right-hand side
60 - x - the approximate solution
61
62 Output Parameter:
63 . r - location to store the residual
64
65 Level: developer
66
67 .seealso: [](ch_ksp), `PCMG`, `PCMGSetMatResidual()`, `PCMGResidualDefault()`
68 @*/
PCMGMatResidualDefault(Mat mat,Mat b,Mat x,Mat r)69 PetscErrorCode PCMGMatResidualDefault(Mat mat, Mat b, Mat x, Mat r)
70 {
71 PetscFunctionBegin;
72 PetscCall(MatMatMult(mat, x, MAT_REUSE_MATRIX, PETSC_CURRENT, &r));
73 PetscCall(MatAYPX(r, -1.0, b, UNKNOWN_NONZERO_PATTERN));
74 PetscFunctionReturn(PETSC_SUCCESS);
75 }
76
77 /*@
78 PCMGMatResidualTransposeDefault - Default routine to calculate the residual of the transposed linear system
79
80 Collective
81
82 Input Parameters:
83 + mat - the matrix
84 . b - the right-hand side
85 - x - the approximate solution
86
87 Output Parameter:
88 . r - location to store the residual
89
90 Level: developer
91
92 .seealso: [](ch_ksp), `PCMG`, `PCMGSetMatResidualTranspose()`
93 @*/
PCMGMatResidualTransposeDefault(Mat mat,Mat b,Mat x,Mat r)94 PetscErrorCode PCMGMatResidualTransposeDefault(Mat mat, Mat b, Mat x, Mat r)
95 {
96 PetscFunctionBegin;
97 PetscCall(MatTransposeMatMult(mat, x, MAT_REUSE_MATRIX, PETSC_CURRENT, &r));
98 PetscCall(MatAYPX(r, -1.0, b, UNKNOWN_NONZERO_PATTERN));
99 PetscFunctionReturn(PETSC_SUCCESS);
100 }
101 /*@
102 PCMGGetCoarseSolve - Gets the solver context to be used on the coarse grid.
103
104 Not Collective
105
106 Input Parameter:
107 . pc - the multigrid context
108
109 Output Parameter:
110 . ksp - the coarse grid solver context
111
112 Level: advanced
113
114 .seealso: [](ch_ksp), `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`, `PCMGGetSmoother()`
115 @*/
PCMGGetCoarseSolve(PC pc,KSP * ksp)116 PetscErrorCode PCMGGetCoarseSolve(PC pc, KSP *ksp)
117 {
118 PC_MG *mg = (PC_MG *)pc->data;
119 PC_MG_Levels **mglevels = mg->levels;
120
121 PetscFunctionBegin;
122 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
123 *ksp = mglevels[0]->smoothd;
124 PetscFunctionReturn(PETSC_SUCCESS);
125 }
126
127 /*@C
128 PCMGSetResidual - Sets the function to be used to calculate the residual on the lth level.
129
130 Logically Collective
131
132 Input Parameters:
133 + pc - the multigrid context
134 . l - the level (0 is coarsest) to supply
135 . residual - function used to form residual, if none is provided the previously provide one is used, if no
136 previous one were provided then a default is used
137 - mat - matrix associated with residual
138
139 Level: advanced
140
141 .seealso: [](ch_ksp), `PCMG`, `PCMGResidualDefault()`
142 @*/
PCMGSetResidual(PC pc,PetscInt l,PetscErrorCode (* residual)(Mat,Vec,Vec,Vec),Mat mat)143 PetscErrorCode PCMGSetResidual(PC pc, PetscInt l, PetscErrorCode (*residual)(Mat, Vec, Vec, Vec), Mat mat)
144 {
145 PC_MG *mg = (PC_MG *)pc->data;
146 PC_MG_Levels **mglevels = mg->levels;
147
148 PetscFunctionBegin;
149 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
150 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
151 if (residual) mglevels[l]->residual = residual;
152 if (!mglevels[l]->residual) mglevels[l]->residual = PCMGResidualDefault;
153 mglevels[l]->matresidual = PCMGMatResidualDefault;
154 if (mat) PetscCall(PetscObjectReference((PetscObject)mat));
155 PetscCall(MatDestroy(&mglevels[l]->A));
156 mglevels[l]->A = mat;
157 PetscFunctionReturn(PETSC_SUCCESS);
158 }
159
160 /*@C
161 PCMGSetResidualTranspose - Sets the function to be used to calculate the residual of the transposed linear system
162 on the lth level.
163
164 Logically Collective
165
166 Input Parameters:
167 + pc - the multigrid context
168 . l - the level (0 is coarsest) to supply
169 . residualt - function used to form transpose of residual, if none is provided the previously provide one is used, if no
170 previous one were provided then a default is used
171 - mat - matrix associated with residual
172
173 Level: advanced
174
175 .seealso: [](ch_ksp), `PCMG`, `PCMGResidualTransposeDefault()`
176 @*/
PCMGSetResidualTranspose(PC pc,PetscInt l,PetscErrorCode (* residualt)(Mat,Vec,Vec,Vec),Mat mat)177 PetscErrorCode PCMGSetResidualTranspose(PC pc, PetscInt l, PetscErrorCode (*residualt)(Mat, Vec, Vec, Vec), Mat mat)
178 {
179 PC_MG *mg = (PC_MG *)pc->data;
180 PC_MG_Levels **mglevels = mg->levels;
181
182 PetscFunctionBegin;
183 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
184 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
185 if (residualt) mglevels[l]->residualtranspose = residualt;
186 if (!mglevels[l]->residualtranspose) mglevels[l]->residualtranspose = PCMGResidualTransposeDefault;
187 mglevels[l]->matresidualtranspose = PCMGMatResidualTransposeDefault;
188 if (mat) PetscCall(PetscObjectReference((PetscObject)mat));
189 PetscCall(MatDestroy(&mglevels[l]->A));
190 mglevels[l]->A = mat;
191 PetscFunctionReturn(PETSC_SUCCESS);
192 }
193
194 /*@
195 PCMGSetInterpolation - Sets the function to be used to calculate the
196 interpolation from l-1 to the lth level
197
198 Logically Collective
199
200 Input Parameters:
201 + pc - the multigrid context
202 . mat - the interpolation operator
203 - l - the level (0 is coarsest) to supply [do not supply 0]
204
205 Level: advanced
206
207 Notes:
208 Usually this is the same matrix used also to set the restriction
209 for the same level.
210
211 One can pass in the interpolation matrix or its transpose; PETSc figures
212 out from the matrix size which one it is.
213
214 .seealso: [](ch_ksp), `PCMG`, `PCMGSetRestriction()`
215 @*/
PCMGSetInterpolation(PC pc,PetscInt l,Mat mat)216 PetscErrorCode PCMGSetInterpolation(PC pc, PetscInt l, Mat mat)
217 {
218 PC_MG *mg = (PC_MG *)pc->data;
219 PC_MG_Levels **mglevels = mg->levels;
220
221 PetscFunctionBegin;
222 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
223 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
224 PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set interpolation routine for coarsest level");
225 PetscCall(PetscObjectReference((PetscObject)mat));
226 PetscCall(MatDestroy(&mglevels[l]->interpolate));
227
228 mglevels[l]->interpolate = mat;
229 PetscFunctionReturn(PETSC_SUCCESS);
230 }
231
232 /*@
233 PCMGSetOperators - Sets operator and matrix from which to construct a preconditioner for lth level
234
235 Logically Collective
236
237 Input Parameters:
238 + pc - the multigrid context
239 . Amat - the operator
240 . Pmat - the preconditioning operator
241 - l - the level (0 is the coarsest) to supply
242
243 Level: advanced
244
245 .seealso: [](ch_ksp), `PCMG`, `PCMGSetGalerkin()`, `PCMGSetRestriction()`, `PCMGSetInterpolation()`
246 @*/
PCMGSetOperators(PC pc,PetscInt l,Mat Amat,Mat Pmat)247 PetscErrorCode PCMGSetOperators(PC pc, PetscInt l, Mat Amat, Mat Pmat)
248 {
249 PC_MG *mg = (PC_MG *)pc->data;
250 PC_MG_Levels **mglevels = mg->levels;
251
252 PetscFunctionBegin;
253 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
254 PetscValidHeaderSpecific(Amat, MAT_CLASSID, 3);
255 PetscValidHeaderSpecific(Pmat, MAT_CLASSID, 4);
256 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
257 PetscCall(KSPSetOperators(mglevels[l]->smoothd, Amat, Pmat));
258 PetscFunctionReturn(PETSC_SUCCESS);
259 }
260
261 /*@
262 PCMGGetInterpolation - Gets the function to be used to calculate the
263 interpolation from l-1 to the lth level
264
265 Logically Collective
266
267 Input Parameters:
268 + pc - the multigrid context
269 - l - the level (0 is coarsest) to supply [Do not supply 0]
270
271 Output Parameter:
272 . mat - the interpolation matrix, can be `NULL`
273
274 Level: advanced
275
276 .seealso: [](ch_ksp), `PCMG`, `PCMGGetRestriction()`, `PCMGSetInterpolation()`, `PCMGGetRScale()`
277 @*/
PCMGGetInterpolation(PC pc,PetscInt l,Mat * mat)278 PetscErrorCode PCMGGetInterpolation(PC pc, PetscInt l, Mat *mat)
279 {
280 PC_MG *mg = (PC_MG *)pc->data;
281 PC_MG_Levels **mglevels = mg->levels;
282
283 PetscFunctionBegin;
284 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
285 if (mat) PetscAssertPointer(mat, 3);
286 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
287 PetscCheck(l > 0 && l < mg->nlevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Level %" PetscInt_FMT " must be in range {1,...,%" PetscInt_FMT "}", l, mg->nlevels - 1);
288 if (!mglevels[l]->interpolate && mglevels[l]->restrct) PetscCall(PCMGSetInterpolation(pc, l, mglevels[l]->restrct));
289 if (mat) *mat = mglevels[l]->interpolate;
290 PetscFunctionReturn(PETSC_SUCCESS);
291 }
292
293 /*@
294 PCMGSetRestriction - Sets the function to be used to restrict dual vectors
295 from level l to l-1.
296
297 Logically Collective
298
299 Input Parameters:
300 + pc - the multigrid context
301 . l - the level (0 is coarsest) to supply [Do not supply 0]
302 - mat - the restriction matrix
303
304 Level: advanced
305
306 Notes:
307 Usually this is the same matrix used also to set the interpolation
308 for the same level.
309
310 One can pass in the interpolation matrix or its transpose; PETSc figures
311 out from the matrix size which one it is.
312
313 If you do not set this, the transpose of the `Mat` set with `PCMGSetInterpolation()`
314 is used.
315
316 .seealso: [](ch_ksp), `PCMG`, `PCMGSetInterpolation()`
317 @*/
PCMGSetRestriction(PC pc,PetscInt l,Mat mat)318 PetscErrorCode PCMGSetRestriction(PC pc, PetscInt l, Mat mat)
319 {
320 PC_MG *mg = (PC_MG *)pc->data;
321 PC_MG_Levels **mglevels = mg->levels;
322
323 PetscFunctionBegin;
324 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
325 PetscValidHeaderSpecific(mat, MAT_CLASSID, 3);
326 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
327 PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set restriction routine for coarsest level");
328 PetscCall(PetscObjectReference((PetscObject)mat));
329 PetscCall(MatDestroy(&mglevels[l]->restrct));
330
331 mglevels[l]->restrct = mat;
332 PetscFunctionReturn(PETSC_SUCCESS);
333 }
334
335 /*@
336 PCMGGetRestriction - Gets the function to be used to restrict dual (i.e. residual) vectors
337 from level l to l-1.
338
339 Logically Collective
340
341 Input Parameters:
342 + pc - the multigrid context
343 - l - the level (0 is coarsest) to supply [Do not supply 0]
344
345 Output Parameter:
346 . mat - the restriction matrix
347
348 Level: advanced
349
350 .seealso: [](ch_ksp), `PCMG`, `PCMGGetInterpolation()`, `PCMGSetRestriction()`, `PCMGGetRScale()`, `PCMGGetInjection()`
351 @*/
PCMGGetRestriction(PC pc,PetscInt l,Mat * mat)352 PetscErrorCode PCMGGetRestriction(PC pc, PetscInt l, Mat *mat)
353 {
354 PC_MG *mg = (PC_MG *)pc->data;
355 PC_MG_Levels **mglevels = mg->levels;
356
357 PetscFunctionBegin;
358 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
359 if (mat) PetscAssertPointer(mat, 3);
360 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
361 PetscCheck(l > 0 && l < mg->nlevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Level %" PetscInt_FMT " must be in range {1,...,%" PetscInt_FMT "}", l, mg->nlevels - 1);
362 if (!mglevels[l]->restrct && mglevels[l]->interpolate) PetscCall(PCMGSetRestriction(pc, l, mglevels[l]->interpolate));
363 if (mat) *mat = mglevels[l]->restrct;
364 PetscFunctionReturn(PETSC_SUCCESS);
365 }
366
367 /*@
368 PCMGSetRScale - Sets the pointwise scaling for the restriction operator from level l to l-1.
369
370 Logically Collective
371
372 Input Parameters:
373 + pc - the multigrid context
374 . l - the level (0 is coarsest) to supply [Do not supply 0]
375 - rscale - the scaling
376
377 Level: advanced
378
379 Note:
380 When evaluating a function on a coarse level one does not want to do F(R * x) one does F(rscale * R * x) where rscale is 1 over the row sums of R.
381 It is preferable to use `PCMGSetInjection()` to control moving primal vectors.
382
383 .seealso: [](ch_ksp), `PCMG`, `PCMGSetInterpolation()`, `PCMGSetRestriction()`, `PCMGGetRScale()`, `PCMGSetInjection()`
384 @*/
PCMGSetRScale(PC pc,PetscInt l,Vec rscale)385 PetscErrorCode PCMGSetRScale(PC pc, PetscInt l, Vec rscale)
386 {
387 PC_MG *mg = (PC_MG *)pc->data;
388 PC_MG_Levels **mglevels = mg->levels;
389
390 PetscFunctionBegin;
391 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
392 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
393 PetscCheck(l > 0 && l < mg->nlevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Level %" PetscInt_FMT " must be in range {1,...,%" PetscInt_FMT "}", l, mg->nlevels - 1);
394 PetscCall(PetscObjectReference((PetscObject)rscale));
395 PetscCall(VecDestroy(&mglevels[l]->rscale));
396
397 mglevels[l]->rscale = rscale;
398 PetscFunctionReturn(PETSC_SUCCESS);
399 }
400
401 /*@
402 PCMGGetRScale - Gets the pointwise scaling for the restriction operator from level l to l-1.
403
404 Collective
405
406 Input Parameters:
407 + pc - the multigrid context
408 . rscale - the scaling
409 - l - the level (0 is coarsest) to supply [Do not supply 0]
410
411 Level: advanced
412
413 Note:
414 When evaluating a function on a coarse level one does not want to do F(R * x) one does F(rscale * R * x) where rscale is 1 over the row sums of R.
415 It is preferable to use `PCMGGetInjection()` to control moving primal vectors.
416
417 .seealso: [](ch_ksp), `PCMG`, `PCMGSetInterpolation()`, `PCMGGetRestriction()`, `PCMGGetInjection()`
418 @*/
PCMGGetRScale(PC pc,PetscInt l,Vec * rscale)419 PetscErrorCode PCMGGetRScale(PC pc, PetscInt l, Vec *rscale)
420 {
421 PC_MG *mg = (PC_MG *)pc->data;
422 PC_MG_Levels **mglevels = mg->levels;
423
424 PetscFunctionBegin;
425 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
426 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
427 PetscCheck(l > 0 && l < mg->nlevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Level %" PetscInt_FMT " must be in range {1,...,%" PetscInt_FMT "}", l, mg->nlevels - 1);
428 if (!mglevels[l]->rscale) {
429 Mat R;
430 Vec X, Y, coarse, fine;
431 PetscInt M, N;
432
433 PetscCall(PCMGGetRestriction(pc, l, &R));
434 PetscCall(MatCreateVecs(R, &X, &Y));
435 PetscCall(MatGetSize(R, &M, &N));
436 PetscCheck(N != M, PetscObjectComm((PetscObject)R), PETSC_ERR_SUP, "Restriction matrix is square, cannot determine which Vec is coarser");
437 if (M < N) {
438 fine = X;
439 coarse = Y;
440 } else {
441 fine = Y;
442 coarse = X;
443 }
444 PetscCall(VecSet(fine, 1.));
445 PetscCall(MatRestrict(R, fine, coarse));
446 PetscCall(VecDestroy(&fine));
447 PetscCall(VecReciprocal(coarse));
448 mglevels[l]->rscale = coarse;
449 }
450 *rscale = mglevels[l]->rscale;
451 PetscFunctionReturn(PETSC_SUCCESS);
452 }
453
454 /*@
455 PCMGSetInjection - Sets the function to be used to inject primal (i.e. solution) vectors
456 from level l to l-1.
457
458 Logically Collective
459
460 Input Parameters:
461 + pc - the multigrid context
462 . l - the level (0 is coarsest) to supply [Do not supply 0]
463 - mat - the injection matrix
464
465 Level: advanced
466
467 .seealso: [](ch_ksp), `PCMG`, `PCMGSetRestriction()`
468 @*/
PCMGSetInjection(PC pc,PetscInt l,Mat mat)469 PetscErrorCode PCMGSetInjection(PC pc, PetscInt l, Mat mat)
470 {
471 PC_MG *mg = (PC_MG *)pc->data;
472 PC_MG_Levels **mglevels = mg->levels;
473
474 PetscFunctionBegin;
475 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
476 PetscValidHeaderSpecific(mat, MAT_CLASSID, 3);
477 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
478 PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Do not set restriction routine for coarsest level");
479 PetscCall(PetscObjectReference((PetscObject)mat));
480 PetscCall(MatDestroy(&mglevels[l]->inject));
481
482 mglevels[l]->inject = mat;
483 PetscFunctionReturn(PETSC_SUCCESS);
484 }
485
486 /*@
487 PCMGGetInjection - Gets the function to be used to inject primal vectors (i.e. solutions)
488 from level l to l-1.
489
490 Logically Collective
491
492 Input Parameters:
493 + pc - the multigrid context
494 - l - the level (0 is coarsest) to supply [Do not supply 0]
495
496 Output Parameter:
497 . mat - the restriction matrix (may be `NULL` if no injection is available).
498
499 Level: advanced
500
501 .seealso: [](ch_ksp), `PCMG`, `PCMGSetInjection()`, `PCMGetGetRestriction()`
502 @*/
PCMGGetInjection(PC pc,PetscInt l,Mat * mat)503 PetscErrorCode PCMGGetInjection(PC pc, PetscInt l, Mat *mat)
504 {
505 PC_MG *mg = (PC_MG *)pc->data;
506 PC_MG_Levels **mglevels = mg->levels;
507
508 PetscFunctionBegin;
509 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
510 if (mat) PetscAssertPointer(mat, 3);
511 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
512 PetscCheck(l > 0 && l < mg->nlevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Level %" PetscInt_FMT " must be in range {1,...,%" PetscInt_FMT "}", l, mg->nlevels - 1);
513 if (mat) *mat = mglevels[l]->inject;
514 PetscFunctionReturn(PETSC_SUCCESS);
515 }
516
517 /*@
518 PCMGGetSmoother - Gets the `KSP` context to be used as smoother for
519 both pre- and post-smoothing. Call both `PCMGGetSmootherUp()` and
520 `PCMGGetSmootherDown()` to use different functions for pre- and
521 post-smoothing.
522
523 Not Collective, ksp returned is parallel if pc is
524
525 Input Parameters:
526 + pc - the multigrid context
527 - l - the level (0 is coarsest) to supply
528
529 Output Parameter:
530 . ksp - the smoother
531
532 Note:
533 Once you have called this routine, you can call `KSPSetOperators()` on the resulting ksp to provide the operators for the smoother for this level.
534 You can also modify smoother options by calling the various KSPSetXXX() options on this ksp. In addition you can call `KSPGetPC`(ksp,&pc)
535 and modify PC options for the smoother; for example `PCSetType`(pc,`PCSOR`); to use SOR smoothing.
536
537 Level: advanced
538
539 .seealso: [](ch_ksp), `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmootherDown()`, `PCMGGetCoarseSolve()`
540 @*/
PCMGGetSmoother(PC pc,PetscInt l,KSP * ksp)541 PetscErrorCode PCMGGetSmoother(PC pc, PetscInt l, KSP *ksp)
542 {
543 PC_MG *mg = (PC_MG *)pc->data;
544 PC_MG_Levels **mglevels = mg->levels;
545
546 PetscFunctionBegin;
547 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
548 *ksp = mglevels[l]->smoothd;
549 PetscFunctionReturn(PETSC_SUCCESS);
550 }
551
552 /*@
553 PCMGGetSmootherUp - Gets the KSP context to be used as smoother after
554 coarse grid correction (post-smoother).
555
556 Not Collective, ksp returned is parallel if pc is
557
558 Input Parameters:
559 + pc - the multigrid context
560 - l - the level (0 is coarsest) to supply
561
562 Output Parameter:
563 . ksp - the smoother
564
565 Level: advanced
566
567 Note:
568 Calling this will result in a different pre and post smoother so you may need to set options on the pre smoother also
569
570 .seealso: [](ch_ksp), `PCMG`, `PCMGGetSmootherDown()`
571 @*/
PCMGGetSmootherUp(PC pc,PetscInt l,KSP * ksp)572 PetscErrorCode PCMGGetSmootherUp(PC pc, PetscInt l, KSP *ksp)
573 {
574 PC_MG *mg = (PC_MG *)pc->data;
575 PC_MG_Levels **mglevels = mg->levels;
576 const char *prefix;
577 MPI_Comm comm;
578
579 PetscFunctionBegin;
580 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
581 /*
582 This is called only if user wants a different pre-smoother from post.
583 Thus we check if a different one has already been allocated,
584 if not we allocate it.
585 */
586 PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "There is no such thing as a up smoother on the coarse grid");
587 if (mglevels[l]->smoothu == mglevels[l]->smoothd) {
588 KSPType ksptype;
589 PCType pctype;
590 PC ipc;
591 PetscReal rtol, abstol, dtol;
592 PetscInt maxits;
593 KSPNormType normtype;
594 PetscCall(PetscObjectGetComm((PetscObject)mglevels[l]->smoothd, &comm));
595 PetscCall(KSPGetOptionsPrefix(mglevels[l]->smoothd, &prefix));
596 PetscCall(KSPGetTolerances(mglevels[l]->smoothd, &rtol, &abstol, &dtol, &maxits));
597 PetscCall(KSPGetType(mglevels[l]->smoothd, &ksptype));
598 PetscCall(KSPGetNormType(mglevels[l]->smoothd, &normtype));
599 PetscCall(KSPGetPC(mglevels[l]->smoothd, &ipc));
600 PetscCall(PCGetType(ipc, &pctype));
601
602 PetscCall(KSPCreate(comm, &mglevels[l]->smoothu));
603 PetscCall(KSPSetNestLevel(mglevels[l]->smoothu, pc->kspnestlevel));
604 PetscCall(KSPSetErrorIfNotConverged(mglevels[l]->smoothu, pc->erroriffailure));
605 PetscCall(PetscObjectIncrementTabLevel((PetscObject)mglevels[l]->smoothu, (PetscObject)pc, mglevels[0]->levels - l));
606 PetscCall(KSPSetOptionsPrefix(mglevels[l]->smoothu, prefix));
607 PetscCall(KSPSetTolerances(mglevels[l]->smoothu, rtol, abstol, dtol, maxits));
608 PetscCall(KSPSetType(mglevels[l]->smoothu, ksptype));
609 PetscCall(KSPSetNormType(mglevels[l]->smoothu, normtype));
610 PetscCall(KSPSetConvergenceTest(mglevels[l]->smoothu, KSPConvergedSkip, NULL, NULL));
611 PetscCall(KSPGetPC(mglevels[l]->smoothu, &ipc));
612 PetscCall(PCSetType(ipc, pctype));
613 PetscCall(PetscObjectComposedDataSetInt((PetscObject)mglevels[l]->smoothu, PetscMGLevelId, mglevels[l]->level));
614 }
615 if (ksp) *ksp = mglevels[l]->smoothu;
616 PetscFunctionReturn(PETSC_SUCCESS);
617 }
618
619 /*@
620 PCMGGetSmootherDown - Gets the `KSP` context to be used as smoother before
621 coarse grid correction (pre-smoother).
622
623 Not Collective, ksp returned is parallel if pc is
624
625 Input Parameters:
626 + pc - the multigrid context
627 - l - the level (0 is coarsest) to supply
628
629 Output Parameter:
630 . ksp - the smoother
631
632 Level: advanced
633
634 Note:
635 Calling this will result in a different pre and post smoother so you may need to
636 set options on the post smoother also
637
638 .seealso: [](ch_ksp), `PCMG`, `PCMGGetSmootherUp()`, `PCMGGetSmoother()`
639 @*/
PCMGGetSmootherDown(PC pc,PetscInt l,KSP * ksp)640 PetscErrorCode PCMGGetSmootherDown(PC pc, PetscInt l, KSP *ksp)
641 {
642 PC_MG *mg = (PC_MG *)pc->data;
643 PC_MG_Levels **mglevels = mg->levels;
644
645 PetscFunctionBegin;
646 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
647 /* make sure smoother up and down are different */
648 if (l) PetscCall(PCMGGetSmootherUp(pc, l, NULL));
649 *ksp = mglevels[l]->smoothd;
650 PetscFunctionReturn(PETSC_SUCCESS);
651 }
652
653 /*@
654 PCMGSetCycleTypeOnLevel - Sets the type of cycle (aka cycle index) to run on the specified level.
655
656 Logically Collective
657
658 Input Parameters:
659 + pc - the multigrid context
660 . l - the level (0 is coarsest)
661 - c - either `PC_MG_CYCLE_V` or `PC_MG_CYCLE_W`
662
663 Level: advanced
664
665 .seealso: [](ch_ksp), `PCMG`, `PCMGCycleType`, `PCMGSetCycleType()`
666 @*/
PCMGSetCycleTypeOnLevel(PC pc,PetscInt l,PCMGCycleType c)667 PetscErrorCode PCMGSetCycleTypeOnLevel(PC pc, PetscInt l, PCMGCycleType c)
668 {
669 PC_MG *mg = (PC_MG *)pc->data;
670 PC_MG_Levels **mglevels = mg->levels;
671
672 PetscFunctionBegin;
673 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
674 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
675 PetscValidLogicalCollectiveInt(pc, l, 2);
676 PetscValidLogicalCollectiveEnum(pc, c, 3);
677 mglevels[l]->cycles = c;
678 PetscFunctionReturn(PETSC_SUCCESS);
679 }
680
681 /*@
682 PCMGSetRhs - Sets the vector to be used to store the right-hand side on a particular level.
683
684 Logically Collective
685
686 Input Parameters:
687 + pc - the multigrid context
688 . l - the level (0 is coarsest) this is to be used for
689 - c - the Vec
690
691 Level: advanced
692
693 Note:
694 If this is not provided PETSc will automatically generate one. You do not need to keep a reference to this vector if you do not need it. `PCDestroy()` will properly free it.
695
696 .seealso: [](ch_ksp), `PCMG`, `PCMGSetX()`, `PCMGSetR()`
697 @*/
PCMGSetRhs(PC pc,PetscInt l,Vec c)698 PetscErrorCode PCMGSetRhs(PC pc, PetscInt l, Vec c)
699 {
700 PC_MG *mg = (PC_MG *)pc->data;
701 PC_MG_Levels **mglevels = mg->levels;
702
703 PetscFunctionBegin;
704 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
705 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
706 PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set rhs for finest level");
707 PetscCall(PetscObjectReference((PetscObject)c));
708 PetscCall(VecDestroy(&mglevels[l]->b));
709
710 mglevels[l]->b = c;
711 PetscFunctionReturn(PETSC_SUCCESS);
712 }
713
714 /*@
715 PCMGSetX - Sets the vector to be used to store the solution on a particular level.
716
717 Logically Collective
718
719 Input Parameters:
720 + pc - the multigrid context
721 . l - the level (0 is coarsest) this is to be used for (do not supply the finest level)
722 - c - the Vec
723
724 Level: advanced
725
726 Note:
727 If this is not provided PETSc will automatically generate one. You do not need to keep a reference to this vector if you do not need it. `PCDestroy()` will properly free it.
728
729 .seealso: [](ch_ksp), `PCMG`, `PCMGSetRhs()`, `PCMGSetR()`
730 @*/
PCMGSetX(PC pc,PetscInt l,Vec c)731 PetscErrorCode PCMGSetX(PC pc, PetscInt l, Vec c)
732 {
733 PC_MG *mg = (PC_MG *)pc->data;
734 PC_MG_Levels **mglevels = mg->levels;
735
736 PetscFunctionBegin;
737 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
738 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
739 PetscCheck(l != mglevels[0]->levels - 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Do not set x for finest level");
740 PetscCall(PetscObjectReference((PetscObject)c));
741 PetscCall(VecDestroy(&mglevels[l]->x));
742
743 mglevels[l]->x = c;
744 PetscFunctionReturn(PETSC_SUCCESS);
745 }
746
747 /*@
748 PCMGSetR - Sets the vector to be used to store the residual on a particular level.
749
750 Logically Collective
751
752 Input Parameters:
753 + pc - the multigrid context
754 . l - the level (0 is coarsest) this is to be used for
755 - c - the Vec
756
757 Level: advanced
758
759 Note:
760 If this is not provided PETSc will automatically generate one. You do not need to keep a reference to this vector if you do not need it. `PCDestroy()` will properly free it.
761
762 .seealso: [](ch_ksp), `PCMG`, `PCMGSetRhs()`, `PCMGSetX()`
763 @*/
PCMGSetR(PC pc,PetscInt l,Vec c)764 PetscErrorCode PCMGSetR(PC pc, PetscInt l, Vec c)
765 {
766 PC_MG *mg = (PC_MG *)pc->data;
767 PC_MG_Levels **mglevels = mg->levels;
768
769 PetscFunctionBegin;
770 PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
771 PetscCheck(mglevels, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must set MG levels before calling");
772 PetscCheck(l, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Need not set residual vector for coarse grid");
773 PetscCall(PetscObjectReference((PetscObject)c));
774 PetscCall(VecDestroy(&mglevels[l]->r));
775
776 mglevels[l]->r = c;
777 PetscFunctionReturn(PETSC_SUCCESS);
778 }
779