Actual source code: composite.c
petsc-3.9.4 2018-09-11
2: /*
3: Defines a preconditioner that can consist of a collection of PCs
4: */
5: #include <petsc/private/pcimpl.h>
6: #include <petscksp.h>
8: typedef struct _PC_CompositeLink *PC_CompositeLink;
9: struct _PC_CompositeLink {
10: PC pc;
11: PC_CompositeLink next;
12: PC_CompositeLink previous;
13: };
15: typedef struct {
16: PC_CompositeLink head;
17: PCCompositeType type;
18: Vec work1;
19: Vec work2;
20: PetscScalar alpha;
21: } PC_Composite;
23: static PetscErrorCode PCApply_Composite_Multiplicative(PC pc,Vec x,Vec y)
24: {
25: PetscErrorCode ierr;
26: PC_Composite *jac = (PC_Composite*)pc->data;
27: PC_CompositeLink next = jac->head;
28: Mat mat = pc->pmat;
32: if (!next) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"No composite preconditioners supplied via PCCompositeAddPC() or -pc_composite_pcs");
34: /* Set the reuse flag on children PCs */
35: while (next) {
36: PCSetReusePreconditioner(next->pc,pc->reusepreconditioner);
37: next = next->next;
38: }
39: next = jac->head;
41: if (next->next && !jac->work2) { /* allocate second work vector */
42: VecDuplicate(jac->work1,&jac->work2);
43: }
44: if (pc->useAmat) mat = pc->mat;
45: PCApply(next->pc,x,y); /* y <- B x */
46: while (next->next) {
47: next = next->next;
48: MatMult(mat,y,jac->work1); /* work1 <- A y */
49: VecWAXPY(jac->work2,-1.0,jac->work1,x); /* work2 <- x - work1 */
50: PCApply(next->pc,jac->work2,jac->work1); /* work1 <- C work2 */
51: VecAXPY(y,1.0,jac->work1); /* y <- y + work1 = B x + C (x - A B x) = (B + C (1 - A B)) x */
52: }
53: if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
54: while (next->previous) {
55: next = next->previous;
56: MatMult(mat,y,jac->work1);
57: VecWAXPY(jac->work2,-1.0,jac->work1,x);
58: PCApply(next->pc,jac->work2,jac->work1);
59: VecAXPY(y,1.0,jac->work1);
60: }
61: }
62: return(0);
63: }
65: static PetscErrorCode PCApplyTranspose_Composite_Multiplicative(PC pc,Vec x,Vec y)
66: {
67: PetscErrorCode ierr;
68: PC_Composite *jac = (PC_Composite*)pc->data;
69: PC_CompositeLink next = jac->head;
70: Mat mat = pc->pmat;
73: if (!next) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"No composite preconditioners supplied via PCCompositeAddPC() or -pc_composite_pcs");
74: if (next->next && !jac->work2) { /* allocate second work vector */
75: VecDuplicate(jac->work1,&jac->work2);
76: }
77: if (pc->useAmat) mat = pc->mat;
78: /* locate last PC */
79: while (next->next) {
80: next = next->next;
81: }
82: PCApplyTranspose(next->pc,x,y);
83: while (next->previous) {
84: next = next->previous;
85: MatMultTranspose(mat,y,jac->work1);
86: VecWAXPY(jac->work2,-1.0,jac->work1,x);
87: PCApplyTranspose(next->pc,jac->work2,jac->work1);
88: VecAXPY(y,1.0,jac->work1);
89: }
90: if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
91: next = jac->head;
92: while (next->next) {
93: next = next->next;
94: MatMultTranspose(mat,y,jac->work1);
95: VecWAXPY(jac->work2,-1.0,jac->work1,x);
96: PCApplyTranspose(next->pc,jac->work2,jac->work1);
97: VecAXPY(y,1.0,jac->work1);
98: }
99: }
100: return(0);
101: }
103: /*
104: This is very special for a matrix of the form alpha I + R + S
105: where first preconditioner is built from alpha I + S and second from
106: alpha I + R
107: */
108: static PetscErrorCode PCApply_Composite_Special(PC pc,Vec x,Vec y)
109: {
110: PetscErrorCode ierr;
111: PC_Composite *jac = (PC_Composite*)pc->data;
112: PC_CompositeLink next = jac->head;
115: if (!next) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"No composite preconditioners supplied via PCCompositeAddPC() or -pc_composite_pcs");
116: if (!next->next || next->next->next) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Special composite preconditioners requires exactly two PCs");
118: /* Set the reuse flag on children PCs */
119: PCSetReusePreconditioner(next->pc,pc->reusepreconditioner);
120: PCSetReusePreconditioner(next->next->pc,pc->reusepreconditioner);
122: PCApply(next->pc,x,jac->work1);
123: PCApply(next->next->pc,jac->work1,y);
124: return(0);
125: }
127: static PetscErrorCode PCApply_Composite_Additive(PC pc,Vec x,Vec y)
128: {
129: PetscErrorCode ierr;
130: PC_Composite *jac = (PC_Composite*)pc->data;
131: PC_CompositeLink next = jac->head;
134: if (!next) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"No composite preconditioners supplied via PCCompositeAddPC() or -pc_composite_pcs");
136: /* Set the reuse flag on children PCs */
137: while (next) {
138: PCSetReusePreconditioner(next->pc,pc->reusepreconditioner);
139: next = next->next;
140: }
141: next = jac->head;
143: PCApply(next->pc,x,y);
144: while (next->next) {
145: next = next->next;
146: PCApply(next->pc,x,jac->work1);
147: VecAXPY(y,1.0,jac->work1);
148: }
149: return(0);
150: }
152: static PetscErrorCode PCApplyTranspose_Composite_Additive(PC pc,Vec x,Vec y)
153: {
154: PetscErrorCode ierr;
155: PC_Composite *jac = (PC_Composite*)pc->data;
156: PC_CompositeLink next = jac->head;
159: if (!next) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"No composite preconditioners supplied via PCCompositeAddPC() or -pc_composite_pcs");
160: PCApplyTranspose(next->pc,x,y);
161: while (next->next) {
162: next = next->next;
163: PCApplyTranspose(next->pc,x,jac->work1);
164: VecAXPY(y,1.0,jac->work1);
165: }
166: return(0);
167: }
169: static PetscErrorCode PCSetUp_Composite(PC pc)
170: {
171: PetscErrorCode ierr;
172: PC_Composite *jac = (PC_Composite*)pc->data;
173: PC_CompositeLink next = jac->head;
174: DM dm;
177: if (!jac->work1) {
178: MatCreateVecs(pc->pmat,&jac->work1,0);
179: }
180: PCGetDM(pc,&dm);
181: while (next) {
182: if (!next->pc->dm) {
183: PCSetDM(next->pc,dm);
184: }
185: if (!next->pc->mat) {
186: PCSetOperators(next->pc,pc->mat,pc->pmat);
187: }
188: next = next->next;
189: }
190: return(0);
191: }
193: static PetscErrorCode PCReset_Composite(PC pc)
194: {
195: PC_Composite *jac = (PC_Composite*)pc->data;
196: PetscErrorCode ierr;
197: PC_CompositeLink next = jac->head;
200: while (next) {
201: PCReset(next->pc);
202: next = next->next;
203: }
204: VecDestroy(&jac->work1);
205: VecDestroy(&jac->work2);
206: return(0);
207: }
209: static PetscErrorCode PCDestroy_Composite(PC pc)
210: {
211: PC_Composite *jac = (PC_Composite*)pc->data;
212: PetscErrorCode ierr;
213: PC_CompositeLink next = jac->head,next_tmp;
216: PCReset_Composite(pc);
217: while (next) {
218: PCDestroy(&next->pc);
219: next_tmp = next;
220: next = next->next;
221: PetscFree(next_tmp);
222: }
223: PetscFree(pc->data);
224: return(0);
225: }
227: static PetscErrorCode PCSetFromOptions_Composite(PetscOptionItems *PetscOptionsObject,PC pc)
228: {
229: PC_Composite *jac = (PC_Composite*)pc->data;
230: PetscErrorCode ierr;
231: PetscInt nmax = 8,i;
232: PC_CompositeLink next;
233: char *pcs[8];
234: PetscBool flg;
237: PetscOptionsHead(PetscOptionsObject,"Composite preconditioner options");
238: PetscOptionsEnum("-pc_composite_type","Type of composition","PCCompositeSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&jac->type,&flg);
239: if (flg) {
240: PCCompositeSetType(pc,jac->type);
241: }
242: PetscOptionsStringArray("-pc_composite_pcs","List of composite solvers","PCCompositeAddPC",pcs,&nmax,&flg);
243: if (flg) {
244: for (i=0; i<nmax; i++) {
245: PCCompositeAddPC(pc,pcs[i]);
246: PetscFree(pcs[i]); /* deallocate string pcs[i], which is allocated in PetscOptionsStringArray() */
247: }
248: }
249: PetscOptionsTail();
251: next = jac->head;
252: while (next) {
253: PCSetFromOptions(next->pc);
254: next = next->next;
255: }
256: return(0);
257: }
259: static PetscErrorCode PCView_Composite(PC pc,PetscViewer viewer)
260: {
261: PC_Composite *jac = (PC_Composite*)pc->data;
262: PetscErrorCode ierr;
263: PC_CompositeLink next = jac->head;
264: PetscBool iascii;
267: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
268: if (iascii) {
269: PetscViewerASCIIPrintf(viewer,"Composite PC type - %s\n",PCCompositeTypes[jac->type]);
270: PetscViewerASCIIPrintf(viewer,"PCs on composite preconditioner follow\n");
271: PetscViewerASCIIPrintf(viewer,"---------------------------------\n");
272: }
273: if (iascii) {
274: PetscViewerASCIIPushTab(viewer);
275: }
276: while (next) {
277: PCView(next->pc,viewer);
278: next = next->next;
279: }
280: if (iascii) {
281: PetscViewerASCIIPopTab(viewer);
282: PetscViewerASCIIPrintf(viewer,"---------------------------------\n");
283: }
284: return(0);
285: }
287: /* ------------------------------------------------------------------------------*/
289: static PetscErrorCode PCCompositeSpecialSetAlpha_Composite(PC pc,PetscScalar alpha)
290: {
291: PC_Composite *jac = (PC_Composite*)pc->data;
294: jac->alpha = alpha;
295: return(0);
296: }
298: static PetscErrorCode PCCompositeSetType_Composite(PC pc,PCCompositeType type)
299: {
300: PC_Composite *jac = (PC_Composite*)pc->data;
303: if (type == PC_COMPOSITE_ADDITIVE) {
304: pc->ops->apply = PCApply_Composite_Additive;
305: pc->ops->applytranspose = PCApplyTranspose_Composite_Additive;
306: } else if (type == PC_COMPOSITE_MULTIPLICATIVE || type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
307: pc->ops->apply = PCApply_Composite_Multiplicative;
308: pc->ops->applytranspose = PCApplyTranspose_Composite_Multiplicative;
309: } else if (type == PC_COMPOSITE_SPECIAL) {
310: pc->ops->apply = PCApply_Composite_Special;
311: pc->ops->applytranspose = NULL;
312: } else SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONG,"Unkown composite preconditioner type");
313: jac->type = type;
314: return(0);
315: }
317: static PetscErrorCode PCCompositeGetType_Composite(PC pc,PCCompositeType *type)
318: {
319: PC_Composite *jac = (PC_Composite*)pc->data;
322: *type = jac->type;
323: return(0);
324: }
326: static PetscErrorCode PCCompositeAddPC_Composite(PC pc,PCType type)
327: {
328: PC_Composite *jac;
329: PC_CompositeLink next,ilink;
330: PetscErrorCode ierr;
331: PetscInt cnt = 0;
332: const char *prefix;
333: char newprefix[20];
336: PetscNewLog(pc,&ilink);
337: ilink->next = 0;
338: PCCreate(PetscObjectComm((PetscObject)pc),&ilink->pc);
339: PetscObjectIncrementTabLevel((PetscObject)ilink->pc,(PetscObject)pc,1);
340: PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->pc);
342: jac = (PC_Composite*)pc->data;
343: next = jac->head;
344: if (!next) {
345: jac->head = ilink;
346: ilink->previous = NULL;
347: } else {
348: cnt++;
349: while (next->next) {
350: next = next->next;
351: cnt++;
352: }
353: next->next = ilink;
354: ilink->previous = next;
355: }
356: PCGetOptionsPrefix(pc,&prefix);
357: PCSetOptionsPrefix(ilink->pc,prefix);
358: sprintf(newprefix,"sub_%d_",(int)cnt);
359: PCAppendOptionsPrefix(ilink->pc,newprefix);
360: /* type is set after prefix, because some methods may modify prefix, e.g. pcksp */
361: PCSetType(ilink->pc,type);
362: return(0);
363: }
365: static PetscErrorCode PCCompositeGetNumberPC_Composite(PC pc,PetscInt *n)
366: {
367: PC_Composite *jac;
368: PC_CompositeLink next;
371: jac = (PC_Composite*)pc->data;
372: next = jac->head;
373: *n = 0;
374: while (next) {
375: next = next->next;
376: (*n) ++;
377: }
378: return(0);
379: }
381: static PetscErrorCode PCCompositeGetPC_Composite(PC pc,PetscInt n,PC *subpc)
382: {
383: PC_Composite *jac;
384: PC_CompositeLink next;
385: PetscInt i;
388: jac = (PC_Composite*)pc->data;
389: next = jac->head;
390: for (i=0; i<n; i++) {
391: if (!next->next) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Not enough PCs in composite preconditioner");
392: next = next->next;
393: }
394: *subpc = next->pc;
395: return(0);
396: }
398: /* -------------------------------------------------------------------------------- */
399: /*@
400: PCCompositeSetType - Sets the type of composite preconditioner.
402: Logically Collective on PC
404: Input Parameters:
405: + pc - the preconditioner context
406: - type - PC_COMPOSITE_ADDITIVE (default), PC_COMPOSITE_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL
408: Options Database Key:
409: . -pc_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type
411: Level: Developer
413: .keywords: PC, set, type, composite preconditioner, additive, multiplicative
414: @*/
415: PetscErrorCode PCCompositeSetType(PC pc,PCCompositeType type)
416: {
422: PetscTryMethod(pc,"PCCompositeSetType_C",(PC,PCCompositeType),(pc,type));
423: return(0);
424: }
426: /*@
427: PCCompositeGetType - Gets the type of composite preconditioner.
429: Logically Collective on PC
431: Input Parameter:
432: . pc - the preconditioner context
434: Output Parameter:
435: . type - PC_COMPOSITE_ADDITIVE (default), PC_COMPOSITE_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL
437: Options Database Key:
438: . -pc_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type
440: Level: Developer
442: .keywords: PC, set, type, composite preconditioner, additive, multiplicative
443: @*/
444: PetscErrorCode PCCompositeGetType(PC pc,PCCompositeType *type)
445: {
450: PetscUseMethod(pc,"PCCompositeGetType_C",(PC,PCCompositeType*),(pc,type));
451: return(0);
452: }
454: /*@
455: PCCompositeSpecialSetAlpha - Sets alpha for the special composite preconditioner
456: for alphaI + R + S
458: Logically Collective on PC
460: Input Parameter:
461: + pc - the preconditioner context
462: - alpha - scale on identity
464: Level: Developer
466: .keywords: PC, set, type, composite preconditioner, additive, multiplicative
467: @*/
468: PetscErrorCode PCCompositeSpecialSetAlpha(PC pc,PetscScalar alpha)
469: {
475: PetscTryMethod(pc,"PCCompositeSpecialSetAlpha_C",(PC,PetscScalar),(pc,alpha));
476: return(0);
477: }
479: /*@C
480: PCCompositeAddPC - Adds another PC to the composite PC.
482: Collective on PC
484: Input Parameters:
485: + pc - the preconditioner context
486: - type - the type of the new preconditioner
488: Level: Developer
490: .keywords: PC, composite preconditioner, add
491: @*/
492: PetscErrorCode PCCompositeAddPC(PC pc,PCType type)
493: {
498: PetscTryMethod(pc,"PCCompositeAddPC_C",(PC,PCType),(pc,type));
499: return(0);
500: }
502: /*@
503: PCCompositeGetNumberPC - Gets the number of PC objects in the composite PC.
505: Not Collective
507: Input Parameter:
508: . pc - the preconditioner context
510: Output Parameter:
511: . num - the number of sub pcs
513: Level: Developer
515: .keywords: PC, get, composite preconditioner, sub preconditioner
517: .seealso: PCCompositeGetPC()
518: @*/
519: PetscErrorCode PCCompositeGetNumberPC(PC pc,PetscInt *num)
520: {
526: PetscUseMethod(pc,"PCCompositeGetNumberPC_C",(PC,PetscInt*),(pc,num));
527: return(0);
528: }
530: /*@
531: PCCompositeGetPC - Gets one of the PC objects in the composite PC.
533: Not Collective
535: Input Parameter:
536: + pc - the preconditioner context
537: - n - the number of the pc requested
539: Output Parameters:
540: . subpc - the PC requested
542: Level: Developer
544: Notes: To use a different operator to construct one of the inner preconditioners first call PCCompositeGetPC(), then
545: call PCSetOperators() on that PC.
547: .keywords: PC, get, composite preconditioner, sub preconditioner
549: .seealso: PCCompositeAddPC(), PCCompositeGetNumberPC(), PCSetOperators()
550: @*/
551: PetscErrorCode PCCompositeGetPC(PC pc,PetscInt n,PC *subpc)
552: {
558: PetscUseMethod(pc,"PCCompositeGetPC_C",(PC,PetscInt,PC*),(pc,n,subpc));
559: return(0);
560: }
562: /* -------------------------------------------------------------------------------------------*/
564: /*MC
565: PCCOMPOSITE - Build a preconditioner by composing together several preconditioners
567: Options Database Keys:
568: + -pc_composite_type <type: one of multiplicative, additive, symmetric_multiplicative, special> - Sets composite preconditioner type
569: . -pc_use_amat - activates PCSetUseAmat()
570: - -pc_composite_pcs - <pc0,pc1,...> list of PCs to compose
572: Level: intermediate
574: Concepts: composing solvers
576: Notes: To use a Krylov method inside the composite preconditioner, set the PCType of one or more
577: inner PCs to be PCKSP.
578: Using a Krylov method inside another Krylov method can be dangerous (you get divergence or
579: the incorrect answer) unless you use KSPFGMRES as the outer Krylov method
580: To use a different operator to construct one of the inner preconditioners first call PCCompositeGetPC(), then
581: call PCSetOperators() on that PC.
584: .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC,
585: PCSHELL, PCKSP, PCCompositeSetType(), PCCompositeSpecialSetAlpha(), PCCompositeAddPC(),
586: PCCompositeGetPC(), PCSetUseAmat()
588: M*/
590: PETSC_EXTERN PetscErrorCode PCCreate_Composite(PC pc)
591: {
593: PC_Composite *jac;
596: PetscNewLog(pc,&jac);
598: pc->ops->apply = PCApply_Composite_Additive;
599: pc->ops->applytranspose = PCApplyTranspose_Composite_Additive;
600: pc->ops->setup = PCSetUp_Composite;
601: pc->ops->reset = PCReset_Composite;
602: pc->ops->destroy = PCDestroy_Composite;
603: pc->ops->setfromoptions = PCSetFromOptions_Composite;
604: pc->ops->view = PCView_Composite;
605: pc->ops->applyrichardson = 0;
607: pc->data = (void*)jac;
608: jac->type = PC_COMPOSITE_ADDITIVE;
609: jac->work1 = 0;
610: jac->work2 = 0;
611: jac->head = 0;
613: PetscObjectComposeFunction((PetscObject)pc,"PCCompositeSetType_C",PCCompositeSetType_Composite);
614: PetscObjectComposeFunction((PetscObject)pc,"PCCompositeGetType_C",PCCompositeGetType_Composite);
615: PetscObjectComposeFunction((PetscObject)pc,"PCCompositeAddPC_C",PCCompositeAddPC_Composite);
616: PetscObjectComposeFunction((PetscObject)pc,"PCCompositeGetNumberPC_C",PCCompositeGetNumberPC_Composite);
617: PetscObjectComposeFunction((PetscObject)pc,"PCCompositeGetPC_C",PCCompositeGetPC_Composite);
618: PetscObjectComposeFunction((PetscObject)pc,"PCCompositeSpecialSetAlpha_C",PCCompositeSpecialSetAlpha_Composite);
619: return(0);
620: }