xref: /petsc/src/ksp/pc/impls/composite/composite.c (revision 6849ba73f22fecb8f92ef896a42e4e8bd4cd6965)
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 PetscErrorCode PCApply_Composite_Multiplicative(PC pc,Vec x,Vec y)
25 {
26   PetscErrorCode 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 PetscErrorCode PCApply_Composite_Special(PC pc,Vec x,Vec y)
60 {
61   PetscErrorCode 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 PetscErrorCode PCApply_Composite_Additive(PC pc,Vec x,Vec y)
81 {
82   PetscErrorCode 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 PetscErrorCode PCSetUp_Composite(PC pc)
103 {
104   PetscErrorCode 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 PetscErrorCode PCDestroy_Composite(PC pc)
123 {
124   PC_Composite     *jac = (PC_Composite*)pc->data;
125   PetscErrorCode 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 PetscErrorCode PCSetFromOptions_Composite(PC pc)
143 {
144   PC_Composite     *jac = (PC_Composite*)pc->data;
145   PetscErrorCode ierr;
146   int nmax = 8,i,indx;
147   PC_CompositeLink next;
148   char             *pcs[8];
149   const char       *types[] = {"multiplicative","additive","special"};
150   PetscTruth       flg;
151 
152   PetscFunctionBegin;
153   ierr = PetscOptionsHead("Composite preconditioner options");CHKERRQ(ierr);
154     ierr = PetscOptionsEList("-pc_composite_type","Type of composition","PCCompositeSetType",types,3,types[0],&indx,&flg);CHKERRQ(ierr);
155     if (flg) {
156       ierr = PCCompositeSetType(pc,(PCCompositeType)indx);CHKERRQ(ierr);
157     }
158     ierr = PetscOptionsName("-pc_composite_true","Use true matrix for inner solves","PCCompositeSetUseTrue",&flg);CHKERRQ(ierr);
159     if (flg) {
160       ierr = PCCompositeSetUseTrue(pc);CHKERRQ(ierr);
161     }
162     ierr = PetscOptionsStringArray("-pc_composite_pcs","List of composite solvers","PCCompositeAddPC",pcs,&nmax,&flg);CHKERRQ(ierr);
163     if (flg) {
164       for (i=0; i<nmax; i++) {
165         ierr = PCCompositeAddPC(pc,pcs[i]);CHKERRQ(ierr);
166       }
167     }
168   ierr = PetscOptionsTail();CHKERRQ(ierr);
169 
170   next = jac->head;
171   while (next) {
172     ierr = PCSetFromOptions(next->pc);CHKERRQ(ierr);
173     next = next->next;
174   }
175   PetscFunctionReturn(0);
176 }
177 
178 #undef __FUNCT__
179 #define __FUNCT__ "PCView_Composite"
180 static PetscErrorCode PCView_Composite(PC pc,PetscViewer viewer)
181 {
182   PC_Composite     *jac = (PC_Composite*)pc->data;
183   PetscErrorCode ierr;
184   PC_CompositeLink next = jac->head;
185   PetscTruth       iascii;
186 
187   PetscFunctionBegin;
188   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
189   if (iascii) {
190     ierr = PetscViewerASCIIPrintf(viewer,"PCs on composite preconditioner follow\n");CHKERRQ(ierr);
191     ierr = PetscViewerASCIIPrintf(viewer,"---------------------------------\n");CHKERRQ(ierr);
192   } else {
193     SETERRQ1(1,"Viewer type %s not supported for PCComposite",((PetscObject)viewer)->type_name);
194   }
195   if (iascii) {
196     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
197   }
198   while (next) {
199     ierr = PCView(next->pc,viewer);CHKERRQ(ierr);
200     next = next->next;
201   }
202   if (iascii) {
203     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
204     ierr = PetscViewerASCIIPrintf(viewer,"---------------------------------\n");CHKERRQ(ierr);
205   }
206   PetscFunctionReturn(0);
207 }
208 
209 /* ------------------------------------------------------------------------------*/
210 
211 EXTERN_C_BEGIN
212 #undef __FUNCT__
213 #define __FUNCT__ "PCCompositeSpecialSetAlpha_Composite"
214 PetscErrorCode PCCompositeSpecialSetAlpha_Composite(PC pc,PetscScalar alpha)
215 {
216   PC_Composite *jac = (PC_Composite*)pc->data;
217   PetscFunctionBegin;
218   jac->alpha = alpha;
219   PetscFunctionReturn(0);
220 }
221 EXTERN_C_END
222 
223 EXTERN_C_BEGIN
224 #undef __FUNCT__
225 #define __FUNCT__ "PCCompositeSetType_Composite"
226 PetscErrorCode PCCompositeSetType_Composite(PC pc,PCCompositeType type)
227 {
228   PetscFunctionBegin;
229   if (type == PC_COMPOSITE_ADDITIVE) {
230     pc->ops->apply = PCApply_Composite_Additive;
231   } else if (type ==  PC_COMPOSITE_MULTIPLICATIVE) {
232     pc->ops->apply = PCApply_Composite_Multiplicative;
233   } else if (type ==  PC_COMPOSITE_SPECIAL) {
234     pc->ops->apply = PCApply_Composite_Special;
235   } else {
236     SETERRQ(1,"Unkown composite preconditioner type");
237   }
238   PetscFunctionReturn(0);
239 }
240 EXTERN_C_END
241 
242 EXTERN_C_BEGIN
243 #undef __FUNCT__
244 #define __FUNCT__ "PCCompositeAddPC_Composite"
245 PetscErrorCode PCCompositeAddPC_Composite(PC pc,PCType type)
246 {
247   PC_Composite     *jac;
248   PC_CompositeLink next,link;
249   PetscErrorCode ierr;
250   int 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 PetscErrorCode 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 PetscErrorCode 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 PetscErrorCode PCCompositeSetType(PC pc,PCCompositeType type)
338 {
339   PetscErrorCode ierr,(*f)(PC,PCCompositeType);
340 
341   PetscFunctionBegin;
342   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
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 PetscErrorCode PCCompositeSpecialSetAlpha(PC pc,PetscScalar alpha)
367 {
368   PetscErrorCode ierr,(*f)(PC,PetscScalar);
369 
370   PetscFunctionBegin;
371   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
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 PetscErrorCode PCCompositeAddPC(PC pc,PCType type)
395 {
396   PetscErrorCode ierr,(*f)(PC,PCType);
397 
398   PetscFunctionBegin;
399   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
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 PetscErrorCode PCCompositeGetPC(PC pc,int n,PC *subpc)
428 {
429   PetscErrorCode ierr,(*f)(PC,int,PC *);
430 
431   PetscFunctionBegin;
432   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
433   PetscValidPointer(subpc,3);
434   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCCompositeGetPC_C",(void (**)(void))&f);CHKERRQ(ierr);
435   if (f) {
436     ierr = (*f)(pc,n,subpc);CHKERRQ(ierr);
437   } else {
438     SETERRQ(1,"Cannot get pc, not composite type");
439   }
440   PetscFunctionReturn(0);
441 }
442 
443 #undef __FUNCT__
444 #define __FUNCT__ "PCCompositeSetUseTrue"
445 /*@
446    PCCompositeSetUseTrue - Sets a flag to indicate that the true matrix (rather than
447                       the matrix used to define the preconditioner) is used to compute
448                       the residual when the multiplicative scheme is used.
449 
450    Collective on PC
451 
452    Input Parameters:
453 .  pc - the preconditioner context
454 
455    Options Database Key:
456 .  -pc_composite_true - Activates PCCompositeSetUseTrue()
457 
458    Note:
459    For the common case in which the preconditioning and linear
460    system matrices are identical, this routine is unnecessary.
461 
462    Level: Developer
463 
464 .keywords: PC, composite preconditioner, set, true, flag
465 
466 .seealso: PCSetOperators(), PCBJacobiSetUseTrueLocal(), PCKSPSetUseTrue()
467 @*/
468 PetscErrorCode PCCompositeSetUseTrue(PC pc)
469 {
470   PetscErrorCode ierr,(*f)(PC);
471 
472   PetscFunctionBegin;
473   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
474   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCCompositeSetUseTrue_C",(void (**)(void))&f);CHKERRQ(ierr);
475   if (f) {
476     ierr = (*f)(pc);CHKERRQ(ierr);
477   }
478   PetscFunctionReturn(0);
479 }
480 
481 /* -------------------------------------------------------------------------------------------*/
482 
483 /*MC
484      PCCOMPOSITE - Build a preconditioner by composing together several preconditioners
485 
486    Options Database Keys:
487 .  -pc_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type
488 .  -pc_composite_true - Activates PCCompositeSetUseTrue()
489 
490    Level: intermediate
491 
492    Concepts: composing solvers
493 
494    Notes: To use a Krylov method inside the composite preconditioner, set the PCType of one or more
495           inner PCs to be PCKSP.
496           Using a Krylov method inside another Krylov method can be dangerous (you get divergence or
497           the incorrect answer) unless you use KSPFGMRES as the other Krylov method
498 
499 
500 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
501            PCSHELL, PCKSP, PCCompositeSetType(), PCCompositeSpecialSetAlpha(), PCCompositeAddPC(),
502            PCCompositeGetPC(), PCCompositeSetUseTrue()
503 
504 M*/
505 
506 EXTERN_C_BEGIN
507 #undef __FUNCT__
508 #define __FUNCT__ "PCCreate_Composite"
509 PetscErrorCode PCCreate_Composite(PC pc)
510 {
511   PetscErrorCode ierr;
512   PC_Composite   *jac;
513 
514   PetscFunctionBegin;
515   ierr = PetscNew(PC_Composite,&jac);CHKERRQ(ierr);
516   PetscLogObjectMemory(pc,sizeof(PC_Composite));
517   pc->ops->apply              = PCApply_Composite_Additive;
518   pc->ops->setup              = PCSetUp_Composite;
519   pc->ops->destroy            = PCDestroy_Composite;
520   pc->ops->setfromoptions     = PCSetFromOptions_Composite;
521   pc->ops->view               = PCView_Composite;
522   pc->ops->applyrichardson    = 0;
523 
524   pc->data               = (void*)jac;
525   jac->type              = PC_COMPOSITE_ADDITIVE;
526   jac->work1             = 0;
527   jac->work2             = 0;
528   jac->head              = 0;
529 
530   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeSetType_C","PCCompositeSetType_Composite",
531                     PCCompositeSetType_Composite);CHKERRQ(ierr);
532   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeAddPC_C","PCCompositeAddPC_Composite",
533                     PCCompositeAddPC_Composite);CHKERRQ(ierr);
534   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeGetPC_C","PCCompositeGetPC_Composite",
535                     PCCompositeGetPC_Composite);CHKERRQ(ierr);
536   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeSetUseTrue_C","PCCompositeSetUseTrue_Composite",
537                     PCCompositeSetUseTrue_Composite);CHKERRQ(ierr);
538   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeSpecialSetAlpha_C","PCCompositeSpecialSetAlpha_Composite",
539                     PCCompositeSpecialSetAlpha_Composite);CHKERRQ(ierr);
540 
541   PetscFunctionReturn(0);
542 }
543 EXTERN_C_END
544 
545