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