xref: /petsc/src/ksp/pc/impls/composite/composite.c (revision 2a6744eb01855f5aa328eb8fdf4b0d01e72ad151)
1 #define PETSCKSP_DLL
2 
3 /*
4       Defines a preconditioner that can consist of a collection of PCs
5 */
6 #include "private/pcimpl.h"   /*I "petscpc.h" I*/
7 #include "petscksp.h"            /*I "petscksp.h" I*/
8 
9 typedef struct _PC_CompositeLink *PC_CompositeLink;
10 struct _PC_CompositeLink {
11   PC               pc;
12   PC_CompositeLink next;
13 };
14 
15 typedef struct {
16   PC_CompositeLink head;
17   PCCompositeType  type;
18   Vec              work1;
19   Vec              work2;
20   PetscScalar      alpha;
21   PetscTruth       use_true_matrix;
22 } PC_Composite;
23 
24 #undef __FUNCT__
25 #define __FUNCT__ "PCApply_Composite_Multiplicative"
26 static PetscErrorCode PCApply_Composite_Multiplicative(PC pc,Vec x,Vec y)
27 {
28   PetscErrorCode   ierr;
29   PC_Composite     *jac = (PC_Composite*)pc->data;
30   PC_CompositeLink next = jac->head;
31   Mat              mat = pc->pmat;
32 
33   PetscFunctionBegin;
34   if (!next) {
35     SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"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);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(jac->work2,-1.0,jac->work1,x);CHKERRQ(ierr);
46     ierr = PCApply(next->pc,jac->work2,jac->work1);CHKERRQ(ierr);
47     ierr = VecAXPY(y,1.0,jac->work1);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 PetscErrorCode PCApply_Composite_Special(PC pc,Vec x,Vec y)
61 {
62   PetscErrorCode   ierr;
63   PC_Composite     *jac = (PC_Composite*)pc->data;
64   PC_CompositeLink next = jac->head;
65 
66   PetscFunctionBegin;
67   if (!next) {
68     SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No composite preconditioners supplied via PCCompositeAddPC()");
69   }
70   if (!next->next || next->next->next) {
71     SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Special composite preconditioners requires exactly two PCs");
72   }
73 
74   ierr = PCApply(next->pc,x,jac->work1);CHKERRQ(ierr);
75   ierr = PCApply(next->next->pc,jac->work1,y);CHKERRQ(ierr);
76   PetscFunctionReturn(0);
77 }
78 
79 #undef __FUNCT__
80 #define __FUNCT__ "PCApply_Composite_Additive"
81 static PetscErrorCode PCApply_Composite_Additive(PC pc,Vec x,Vec y)
82 {
83   PetscErrorCode   ierr;
84   PC_Composite     *jac = (PC_Composite*)pc->data;
85   PC_CompositeLink next = jac->head;
86 
87   PetscFunctionBegin;
88   if (!next) {
89     SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"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(y,1.0,jac->work1);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   PetscInt         nmax = 8,i;
147   PC_CompositeLink next;
148   char             *pcs[8];
149   PetscTruth       flg;
150 
151   PetscFunctionBegin;
152   ierr = PetscOptionsHead("Composite preconditioner options");CHKERRQ(ierr);
153   ierr = PetscOptionsEnum("-pc_composite_type","Type of composition","PCCompositeSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&jac->type,&flg);CHKERRQ(ierr);
154     ierr = PetscOptionsName("-pc_composite_true","Use true matrix for inner solves","PCCompositeSetUseTrue",&flg);CHKERRQ(ierr);
155     if (flg) {
156       ierr = PCCompositeSetUseTrue(pc);CHKERRQ(ierr);
157     }
158     ierr = PetscOptionsStringArray("-pc_composite_pcs","List of composite solvers","PCCompositeAddPC",pcs,&nmax,&flg);CHKERRQ(ierr);
159     if (flg) {
160       for (i=0; i<nmax; i++) {
161         ierr = PCCompositeAddPC(pc,pcs[i]);CHKERRQ(ierr);
162       }
163     }
164   ierr = PetscOptionsTail();CHKERRQ(ierr);
165 
166   next = jac->head;
167   while (next) {
168     ierr = PCSetFromOptions(next->pc);CHKERRQ(ierr);
169     next = next->next;
170   }
171   PetscFunctionReturn(0);
172 }
173 
174 #undef __FUNCT__
175 #define __FUNCT__ "PCView_Composite"
176 static PetscErrorCode PCView_Composite(PC pc,PetscViewer viewer)
177 {
178   PC_Composite     *jac = (PC_Composite*)pc->data;
179   PetscErrorCode   ierr;
180   PC_CompositeLink next = jac->head;
181   PetscTruth       iascii;
182 
183   PetscFunctionBegin;
184   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
185   if (iascii) {
186     ierr = PetscViewerASCIIPrintf(viewer,"Composite PC type - %s\n",PCCompositeTypes[jac->type]);CHKERRQ(ierr);
187     ierr = PetscViewerASCIIPrintf(viewer,"PCs on composite preconditioner follow\n");CHKERRQ(ierr);
188     ierr = PetscViewerASCIIPrintf(viewer,"---------------------------------\n");CHKERRQ(ierr);
189   } else {
190     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCComposite",((PetscObject)viewer)->type_name);
191   }
192   if (iascii) {
193     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
194   }
195   while (next) {
196     ierr = PCView(next->pc,viewer);CHKERRQ(ierr);
197     next = next->next;
198   }
199   if (iascii) {
200     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
201     ierr = PetscViewerASCIIPrintf(viewer,"---------------------------------\n");CHKERRQ(ierr);
202   }
203   PetscFunctionReturn(0);
204 }
205 
206 /* ------------------------------------------------------------------------------*/
207 
208 EXTERN_C_BEGIN
209 #undef __FUNCT__
210 #define __FUNCT__ "PCCompositeSpecialSetAlpha_Composite"
211 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeSpecialSetAlpha_Composite(PC pc,PetscScalar alpha)
212 {
213   PC_Composite *jac = (PC_Composite*)pc->data;
214   PetscFunctionBegin;
215   jac->alpha = alpha;
216   PetscFunctionReturn(0);
217 }
218 EXTERN_C_END
219 
220 EXTERN_C_BEGIN
221 #undef __FUNCT__
222 #define __FUNCT__ "PCCompositeSetType_Composite"
223 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeSetType_Composite(PC pc,PCCompositeType type)
224 {
225   PetscFunctionBegin;
226   if (type == PC_COMPOSITE_ADDITIVE) {
227     pc->ops->apply = PCApply_Composite_Additive;
228   } else if (type ==  PC_COMPOSITE_MULTIPLICATIVE) {
229     pc->ops->apply = PCApply_Composite_Multiplicative;
230   } else if (type ==  PC_COMPOSITE_SPECIAL) {
231     pc->ops->apply = PCApply_Composite_Special;
232   } else {
233     SETERRQ(PETSC_ERR_ARG_WRONG,"Unkown composite preconditioner type");
234   }
235   PetscFunctionReturn(0);
236 }
237 EXTERN_C_END
238 
239 EXTERN_C_BEGIN
240 #undef __FUNCT__
241 #define __FUNCT__ "PCCompositeAddPC_Composite"
242 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeAddPC_Composite(PC pc,PCType type)
243 {
244   PC_Composite     *jac;
245   PC_CompositeLink next,ilink;
246   PetscErrorCode   ierr;
247   PetscInt         cnt = 0;
248   const char       *prefix;
249   char             newprefix[8];
250 
251   PetscFunctionBegin;
252   ierr       = PetscNew(struct _PC_CompositeLink,&ilink);CHKERRQ(ierr);
253   ilink->next = 0;
254   ierr = PCCreate(pc->comm,&ilink->pc);CHKERRQ(ierr);
255 
256   jac  = (PC_Composite*)pc->data;
257   next = jac->head;
258   if (!next) {
259     jac->head = ilink;
260   } else {
261     cnt++;
262     while (next->next) {
263       next = next->next;
264       cnt++;
265     }
266     next->next = ilink;
267   }
268   ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
269   ierr = PCSetOptionsPrefix(ilink->pc,prefix);CHKERRQ(ierr);
270   sprintf(newprefix,"sub_%d_",(int)cnt);
271   ierr = PCAppendOptionsPrefix(ilink->pc,newprefix);CHKERRQ(ierr);
272   /* type is set after prefix, because some methods may modify prefix, e.g. pcksp */
273   ierr = PCSetType(ilink->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 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeGetPC_Composite(PC pc,PetscInt n,PC *subpc)
283 {
284   PC_Composite     *jac;
285   PC_CompositeLink next;
286   PetscInt         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(PETSC_ERR_ARG_INCOMP,"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 PetscErrorCode PETSCKSP_DLLEXPORT 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 /*@
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 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeSetType(PC pc,PCCompositeType type)
336 {
337   PetscErrorCode 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 /*@
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 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeSpecialSetAlpha(PC pc,PetscScalar alpha)
365 {
366   PetscErrorCode 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 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeAddPC(PC pc,PCType type)
393 {
394   PetscErrorCode 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 /*@
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 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeGetPC(PC pc,PetscInt n,PC *subpc)
426 {
427   PetscErrorCode ierr,(*f)(PC,PetscInt,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(PETSC_ERR_ARG_WRONG,"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 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeSetUseTrue(PC pc)
467 {
468   PetscErrorCode 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 outter 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 PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_Composite(PC pc)
508 {
509   PetscErrorCode ierr;
510   PC_Composite   *jac;
511 
512   PetscFunctionBegin;
513   ierr = PetscNew(PC_Composite,&jac);CHKERRQ(ierr);
514   ierr = PetscLogObjectMemory(pc,sizeof(PC_Composite));CHKERRQ(ierr);
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