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