xref: /petsc/src/ksp/pc/impls/composite/composite.c (revision 9af31e4ad595286b4e2df8194fee047feeccfe42)
1 /*
2       Defines a preconditioner that can consist of a collection of PCs
3 */
4 #include "src/ksp/pc/pcimpl.h"   /*I "petscpc.h" I*/
5 #include "petscksp.h"            /*I "petscksp.h" I*/
6 
7 typedef struct _PC_CompositeLink *PC_CompositeLink;
8 struct _PC_CompositeLink {
9   PC               pc;
10   PC_CompositeLink next;
11 };
12 
13 typedef struct {
14   PC_CompositeLink head;
15   PCCompositeType  type;
16   Vec              work1;
17   Vec              work2;
18   PetscScalar      alpha;
19   PetscTruth       use_true_matrix;
20 } PC_Composite;
21 
22 #undef __FUNCT__
23 #define __FUNCT__ "PCApply_Composite_Multiplicative"
24 static int PCApply_Composite_Multiplicative(PC pc,Vec x,Vec y)
25 {
26   int              ierr;
27   PC_Composite     *jac = (PC_Composite*)pc->data;
28   PC_CompositeLink next = jac->head;
29   PetscScalar      one = 1.0,mone = -1.0;
30   Mat              mat = pc->pmat;
31 
32   PetscFunctionBegin;
33   if (!next) {
34     SETERRQ(1,"No composite preconditioners supplied via PCCompositeAddPC()");
35   }
36   if (next->next && !jac->work2) { /* allocate second work vector */
37     ierr = VecDuplicate(jac->work1,&jac->work2);CHKERRQ(ierr);
38   }
39   ierr = PCApply(next->pc,x,y);CHKERRQ(ierr);
40   if (jac->use_true_matrix) mat = pc->mat;
41   while (next->next) {
42     next = next->next;
43     ierr = MatMult(mat,y,jac->work1);CHKERRQ(ierr);
44     ierr = VecWAXPY(&mone,jac->work1,x,jac->work2);CHKERRQ(ierr);
45     ierr = PCApply(next->pc,jac->work2,jac->work1);CHKERRQ(ierr);
46     ierr = VecAXPY(&one,jac->work1,y);CHKERRQ(ierr);
47   }
48 
49   PetscFunctionReturn(0);
50 }
51 
52 /*
53     This is very special for a matrix of the form alpha I + R + S
54 where first preconditioner is built from alpha I + S and second from
55 alpha I + R
56 */
57 #undef __FUNCT__
58 #define __FUNCT__ "PCApply_Composite_Special"
59 static int PCApply_Composite_Special(PC pc,Vec x,Vec y)
60 {
61   int              ierr;
62   PC_Composite     *jac = (PC_Composite*)pc->data;
63   PC_CompositeLink next = jac->head;
64 
65   PetscFunctionBegin;
66   if (!next) {
67     SETERRQ(1,"No composite preconditioners supplied via PCCompositeAddPC()");
68   }
69   if (!next->next || next->next->next) {
70     SETERRQ(1,"Special composite preconditioners requires exactly two PCs");
71   }
72 
73   ierr = PCApply(next->pc,x,jac->work1);CHKERRQ(ierr);
74   ierr = PCApply(next->next->pc,jac->work1,y);CHKERRQ(ierr);
75   PetscFunctionReturn(0);
76 }
77 
78 #undef __FUNCT__
79 #define __FUNCT__ "PCApply_Composite_Additive"
80 static int PCApply_Composite_Additive(PC pc,Vec x,Vec y)
81 {
82   int              ierr;
83   PC_Composite     *jac = (PC_Composite*)pc->data;
84   PC_CompositeLink next = jac->head;
85   PetscScalar      one = 1.0;
86 
87   PetscFunctionBegin;
88   if (!next) {
89     SETERRQ(1,"No composite preconditioners supplied via PCCompositeAddPC()");
90   }
91   ierr = PCApply(next->pc,x,y);CHKERRQ(ierr);
92   while (next->next) {
93     next = next->next;
94     ierr = PCApply(next->pc,x,jac->work1);CHKERRQ(ierr);
95     ierr = VecAXPY(&one,jac->work1,y);CHKERRQ(ierr);
96   }
97   PetscFunctionReturn(0);
98 }
99 
100 #undef __FUNCT__
101 #define __FUNCT__ "PCSetUp_Composite"
102 static int PCSetUp_Composite(PC pc)
103 {
104   int              ierr;
105   PC_Composite     *jac = (PC_Composite*)pc->data;
106   PC_CompositeLink next = jac->head;
107 
108   PetscFunctionBegin;
109   if (!jac->work1) {
110      ierr = MatGetVecs(pc->pmat,&jac->work1,0);CHKERRQ(ierr);
111   }
112   while (next) {
113     ierr = PCSetOperators(next->pc,pc->mat,pc->pmat,pc->flag);CHKERRQ(ierr);
114     next = next->next;
115   }
116 
117   PetscFunctionReturn(0);
118 }
119 
120 #undef __FUNCT__
121 #define __FUNCT__ "PCDestroy_Composite"
122 static int PCDestroy_Composite(PC pc)
123 {
124   PC_Composite     *jac = (PC_Composite*)pc->data;
125   int              ierr;
126   PC_CompositeLink next = jac->head;
127 
128   PetscFunctionBegin;
129   while (next) {
130     ierr = PCDestroy(next->pc);CHKERRQ(ierr);
131     next = next->next;
132   }
133 
134   if (jac->work1) {ierr = VecDestroy(jac->work1);CHKERRQ(ierr);}
135   if (jac->work2) {ierr = VecDestroy(jac->work2);CHKERRQ(ierr);}
136   ierr = PetscFree(jac);CHKERRQ(ierr);
137   PetscFunctionReturn(0);
138 }
139 
140 #undef __FUNCT__
141 #define __FUNCT__ "PCSetFromOptions_Composite"
142 static int PCSetFromOptions_Composite(PC pc)
143 {
144   PC_Composite     *jac = (PC_Composite*)pc->data;
145   int              ierr,nmax = 8,i,indx;
146   PC_CompositeLink next;
147   char             *pcs[8];
148   const char       *types[] = {"multiplicative","additive","special"};
149   PetscTruth       flg;
150 
151   PetscFunctionBegin;
152   ierr = PetscOptionsHead("Composite preconditioner options");CHKERRQ(ierr);
153     ierr = PetscOptionsEList("-pc_composite_type","Type of composition","PCCompositeSetType",types,3,types[0],&indx,&flg);CHKERRQ(ierr);
154     if (flg) {
155       ierr = PCCompositeSetType(pc,(PCCompositeType)indx);CHKERRQ(ierr);
156     }
157     ierr = PetscOptionsName("-pc_composite_true","Use true matrix for inner solves","PCCompositeSetUseTrue",&flg);CHKERRQ(ierr);
158     if (flg) {
159       ierr = PCCompositeSetUseTrue(pc);CHKERRQ(ierr);
160     }
161     ierr = PetscOptionsStringArray("-pc_composite_pcs","List of composite solvers","PCCompositeAddPC",pcs,&nmax,&flg);CHKERRQ(ierr);
162     if (flg) {
163       for (i=0; i<nmax; i++) {
164         ierr = PCCompositeAddPC(pc,pcs[i]);CHKERRQ(ierr);
165       }
166     }
167   ierr = PetscOptionsTail();CHKERRQ(ierr);
168 
169   next = jac->head;
170   while (next) {
171     ierr = PCSetFromOptions(next->pc);CHKERRQ(ierr);
172     next = next->next;
173   }
174   PetscFunctionReturn(0);
175 }
176 
177 #undef __FUNCT__
178 #define __FUNCT__ "PCView_Composite"
179 static int PCView_Composite(PC pc,PetscViewer viewer)
180 {
181   PC_Composite     *jac = (PC_Composite*)pc->data;
182   int              ierr;
183   PC_CompositeLink next = jac->head;
184   PetscTruth       iascii;
185 
186   PetscFunctionBegin;
187   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
188   if (iascii) {
189     ierr = PetscViewerASCIIPrintf(viewer,"PCs on composite preconditioner follow\n");CHKERRQ(ierr);
190     ierr = PetscViewerASCIIPrintf(viewer,"---------------------------------\n");CHKERRQ(ierr);
191   } else {
192     SETERRQ1(1,"Viewer type %s not supported for PCComposite",((PetscObject)viewer)->type_name);
193   }
194   if (iascii) {
195     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
196   }
197   while (next) {
198     ierr = PCView(next->pc,viewer);CHKERRQ(ierr);
199     next = next->next;
200   }
201   if (iascii) {
202     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
203     ierr = PetscViewerASCIIPrintf(viewer,"---------------------------------\n");CHKERRQ(ierr);
204   }
205   PetscFunctionReturn(0);
206 }
207 
208 /* ------------------------------------------------------------------------------*/
209 
210 EXTERN_C_BEGIN
211 #undef __FUNCT__
212 #define __FUNCT__ "PCCompositeSpecialSetAlpha_Composite"
213 int PCCompositeSpecialSetAlpha_Composite(PC pc,PetscScalar alpha)
214 {
215   PC_Composite *jac = (PC_Composite*)pc->data;
216   PetscFunctionBegin;
217   jac->alpha = alpha;
218   PetscFunctionReturn(0);
219 }
220 EXTERN_C_END
221 
222 EXTERN_C_BEGIN
223 #undef __FUNCT__
224 #define __FUNCT__ "PCCompositeSetType_Composite"
225 int PCCompositeSetType_Composite(PC pc,PCCompositeType type)
226 {
227   PetscFunctionBegin;
228   if (type == PC_COMPOSITE_ADDITIVE) {
229     pc->ops->apply = PCApply_Composite_Additive;
230   } else if (type ==  PC_COMPOSITE_MULTIPLICATIVE) {
231     pc->ops->apply = PCApply_Composite_Multiplicative;
232   } else if (type ==  PC_COMPOSITE_SPECIAL) {
233     pc->ops->apply = PCApply_Composite_Special;
234   } else {
235     SETERRQ(1,"Unkown composite preconditioner type");
236   }
237   PetscFunctionReturn(0);
238 }
239 EXTERN_C_END
240 
241 EXTERN_C_BEGIN
242 #undef __FUNCT__
243 #define __FUNCT__ "PCCompositeAddPC_Composite"
244 int PCCompositeAddPC_Composite(PC pc,PCType type)
245 {
246   PC_Composite     *jac;
247   PC_CompositeLink next,link;
248   int              ierr,cnt = 0;
249   char             *prefix,newprefix[8];
250 
251   PetscFunctionBegin;
252   ierr       = PetscNew(struct _PC_CompositeLink,&link);CHKERRQ(ierr);
253   link->next = 0;
254   ierr = PCCreate(pc->comm,&link->pc);CHKERRQ(ierr);
255 
256   jac  = (PC_Composite*)pc->data;
257   next = jac->head;
258   if (!next) {
259     jac->head = link;
260   } else {
261     cnt++;
262     while (next->next) {
263       next = next->next;
264       cnt++;
265     }
266     next->next = link;
267   }
268   ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
269   ierr = PCSetOptionsPrefix(link->pc,prefix);CHKERRQ(ierr);
270   sprintf(newprefix,"sub_%d_",cnt);
271   ierr = PCAppendOptionsPrefix(link->pc,newprefix);CHKERRQ(ierr);
272   /* type is set after prefix, because some methods may modify prefix, e.g. pcksp */
273   ierr = PCSetType(link->pc,type);CHKERRQ(ierr);
274 
275   PetscFunctionReturn(0);
276 }
277 EXTERN_C_END
278 
279 EXTERN_C_BEGIN
280 #undef __FUNCT__
281 #define __FUNCT__ "PCCompositeGetPC_Composite"
282 int PCCompositeGetPC_Composite(PC pc,int n,PC *subpc)
283 {
284   PC_Composite     *jac;
285   PC_CompositeLink next;
286   int              i;
287 
288   PetscFunctionBegin;
289   jac  = (PC_Composite*)pc->data;
290   next = jac->head;
291   for (i=0; i<n; i++) {
292     if (!next->next) {
293       SETERRQ(1,"Not enough PCs in composite preconditioner");
294     }
295     next = next->next;
296   }
297   *subpc = next->pc;
298   PetscFunctionReturn(0);
299 }
300 EXTERN_C_END
301 
302 EXTERN_C_BEGIN
303 #undef __FUNCT__
304 #define __FUNCT__ "PCCompositeSetUseTrue_Composite"
305 int PCCompositeSetUseTrue_Composite(PC pc)
306 {
307   PC_Composite   *jac;
308 
309   PetscFunctionBegin;
310   jac                  = (PC_Composite*)pc->data;
311   jac->use_true_matrix = PETSC_TRUE;
312   PetscFunctionReturn(0);
313 }
314 EXTERN_C_END
315 
316 /* -------------------------------------------------------------------------------- */
317 #undef __FUNCT__
318 #define __FUNCT__ "PCCompositeSetType"
319 /*@C
320    PCCompositeSetType - Sets the type of composite preconditioner.
321 
322    Collective on PC
323 
324    Input Parameter:
325 .  pc - the preconditioner context
326 .  type - PC_COMPOSITE_ADDITIVE (default), PC_COMPOSITE_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL
327 
328    Options Database Key:
329 .  -pc_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type
330 
331    Level: Developer
332 
333 .keywords: PC, set, type, composite preconditioner, additive, multiplicative
334 @*/
335 int PCCompositeSetType(PC pc,PCCompositeType type)
336 {
337   int ierr,(*f)(PC,PCCompositeType);
338 
339   PetscFunctionBegin;
340   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
341   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCCompositeSetType_C",(void (**)(void))&f);CHKERRQ(ierr);
342   if (f) {
343     ierr = (*f)(pc,type);CHKERRQ(ierr);
344   }
345   PetscFunctionReturn(0);
346 }
347 
348 #undef __FUNCT__
349 #define __FUNCT__ "PCCompositeSpecialSetAlpha"
350 /*@C
351    PCCompositeSpecialSetAlpha - Sets alpha for the special composite preconditioner
352      for alphaI + R + S
353 
354    Collective on PC
355 
356    Input Parameter:
357 +  pc - the preconditioner context
358 -  alpha - scale on identity
359 
360    Level: Developer
361 
362 .keywords: PC, set, type, composite preconditioner, additive, multiplicative
363 @*/
364 int PCCompositeSpecialSetAlpha(PC pc,PetscScalar alpha)
365 {
366   int ierr,(*f)(PC,PetscScalar);
367 
368   PetscFunctionBegin;
369   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
370   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCCompositeSpecialSetAlpha_C",(void (**)(void))&f);CHKERRQ(ierr);
371   if (f) {
372     ierr = (*f)(pc,alpha);CHKERRQ(ierr);
373   }
374   PetscFunctionReturn(0);
375 }
376 
377 #undef __FUNCT__
378 #define __FUNCT__ "PCCompositeAddPC"
379 /*@C
380    PCCompositeAddPC - Adds another PC to the composite PC.
381 
382    Collective on PC
383 
384    Input Parameters:
385 .  pc - the preconditioner context
386 .  type - the type of the new preconditioner
387 
388    Level: Developer
389 
390 .keywords: PC, composite preconditioner, add
391 @*/
392 int PCCompositeAddPC(PC pc,PCType type)
393 {
394   int ierr,(*f)(PC,PCType);
395 
396   PetscFunctionBegin;
397   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
398   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCCompositeAddPC_C",(void (**)(void))&f);CHKERRQ(ierr);
399   if (f) {
400     ierr = (*f)(pc,type);CHKERRQ(ierr);
401   }
402   PetscFunctionReturn(0);
403 }
404 
405 #undef __FUNCT__
406 #define __FUNCT__ "PCCompositeGetPC"
407 /*@C
408    PCCompositeGetPC - Gets one of the PC objects in the composite PC.
409 
410    Not Collective
411 
412    Input Parameter:
413 .  pc - the preconditioner context
414 .  n - the number of the pc requested
415 
416    Output Parameters:
417 .  subpc - the PC requested
418 
419    Level: Developer
420 
421 .keywords: PC, get, composite preconditioner, sub preconditioner
422 
423 .seealso: PCCompositeAddPC()
424 @*/
425 int PCCompositeGetPC(PC pc,int n,PC *subpc)
426 {
427   int ierr,(*f)(PC,int,PC *);
428 
429   PetscFunctionBegin;
430   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
431   PetscValidPointer(subpc,3);
432   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCCompositeGetPC_C",(void (**)(void))&f);CHKERRQ(ierr);
433   if (f) {
434     ierr = (*f)(pc,n,subpc);CHKERRQ(ierr);
435   } else {
436     SETERRQ(1,"Cannot get pc, not composite type");
437   }
438   PetscFunctionReturn(0);
439 }
440 
441 #undef __FUNCT__
442 #define __FUNCT__ "PCCompositeSetUseTrue"
443 /*@
444    PCCompositeSetUseTrue - Sets a flag to indicate that the true matrix (rather than
445                       the matrix used to define the preconditioner) is used to compute
446                       the residual when the multiplicative scheme is used.
447 
448    Collective on PC
449 
450    Input Parameters:
451 .  pc - the preconditioner context
452 
453    Options Database Key:
454 .  -pc_composite_true - Activates PCCompositeSetUseTrue()
455 
456    Note:
457    For the common case in which the preconditioning and linear
458    system matrices are identical, this routine is unnecessary.
459 
460    Level: Developer
461 
462 .keywords: PC, composite preconditioner, set, true, flag
463 
464 .seealso: PCSetOperators(), PCBJacobiSetUseTrueLocal(), PCKSPSetUseTrue()
465 @*/
466 int PCCompositeSetUseTrue(PC pc)
467 {
468   int ierr,(*f)(PC);
469 
470   PetscFunctionBegin;
471   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
472   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCCompositeSetUseTrue_C",(void (**)(void))&f);CHKERRQ(ierr);
473   if (f) {
474     ierr = (*f)(pc);CHKERRQ(ierr);
475   }
476   PetscFunctionReturn(0);
477 }
478 
479 /* -------------------------------------------------------------------------------------------*/
480 
481 /*MC
482      PCCOMPOSITE - Build a preconditioner by composing together several preconditioners
483 
484    Options Database Keys:
485 .  -pc_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type
486 .  -pc_composite_true - Activates PCCompositeSetUseTrue()
487 
488    Level: intermediate
489 
490    Concepts: composing solvers
491 
492    Notes: To use a Krylov method inside the composite preconditioner, set the PCType of one or more
493           inner PCs to be PCKSP.
494           Using a Krylov method inside another Krylov method can be dangerous (you get divergence or
495           the incorrect answer) unless you use KSPFGMRES as the other Krylov method
496 
497 
498 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
499            PCSHELL, PCKSP, PCCompositeSetType(), PCCompositeSpecialSetAlpha(), PCCompositeAddPC(),
500            PCCompositeGetPC(), PCCompositeSetUseTrue()
501 
502 M*/
503 
504 EXTERN_C_BEGIN
505 #undef __FUNCT__
506 #define __FUNCT__ "PCCreate_Composite"
507 int PCCreate_Composite(PC pc)
508 {
509   int            ierr;
510   PC_Composite   *jac;
511 
512   PetscFunctionBegin;
513   ierr = PetscNew(PC_Composite,&jac);CHKERRQ(ierr);
514   PetscLogObjectMemory(pc,sizeof(PC_Composite));
515   pc->ops->apply              = PCApply_Composite_Additive;
516   pc->ops->setup              = PCSetUp_Composite;
517   pc->ops->destroy            = PCDestroy_Composite;
518   pc->ops->setfromoptions     = PCSetFromOptions_Composite;
519   pc->ops->view               = PCView_Composite;
520   pc->ops->applyrichardson    = 0;
521 
522   pc->data               = (void*)jac;
523   jac->type              = PC_COMPOSITE_ADDITIVE;
524   jac->work1             = 0;
525   jac->work2             = 0;
526   jac->head              = 0;
527 
528   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeSetType_C","PCCompositeSetType_Composite",
529                     PCCompositeSetType_Composite);CHKERRQ(ierr);
530   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeAddPC_C","PCCompositeAddPC_Composite",
531                     PCCompositeAddPC_Composite);CHKERRQ(ierr);
532   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeGetPC_C","PCCompositeGetPC_Composite",
533                     PCCompositeGetPC_Composite);CHKERRQ(ierr);
534   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeSetUseTrue_C","PCCompositeSetUseTrue_Composite",
535                     PCCompositeSetUseTrue_Composite);CHKERRQ(ierr);
536   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeSpecialSetAlpha_C","PCCompositeSpecialSetAlpha_Composite",
537                     PCCompositeSpecialSetAlpha_Composite);CHKERRQ(ierr);
538 
539   PetscFunctionReturn(0);
540 }
541 EXTERN_C_END
542 
543