xref: /petsc/src/ksp/pc/impls/deflation/deflation.c (revision 8fb5bd83c3955fefcf33a54e3bb66920a9fa884b)
1 #include <../src/ksp/pc/impls/deflation/deflation.h> /*I "petscksp.h" I*/  /* includes for fortran wrappers */
2 
3 const char *const PCDeflationSpaceTypes[] = {
4   "haar",
5   "db2",
6   "db4",
7   "db8",
8   "db16",
9   "biorth22",
10   "meyer",
11   "aggregation",
12   "user",
13   "PCDeflationSpaceType",
14   "PC_DEFLATION_SPACE_",
15   NULL
16 };
17 
18 static PetscErrorCode PCDeflationSetInitOnly_Deflation(PC pc,PetscBool flg)
19 {
20   PC_Deflation   *def = (PC_Deflation*)pc->data;
21 
22   PetscFunctionBegin;
23   def->init = flg;
24   PetscFunctionReturn(0);
25 }
26 
27 /*@
28    PCDeflationSetInitOnly - Do only initialization step.
29     Sets initial guess to the solution on the deflation space but does not apply
30     the deflation preconditioner. The additional preconditioner is still applied.
31 
32    Logically Collective
33 
34    Input Parameters:
35 +  pc  - the preconditioner context
36 -  flg - default PETSC_FALSE
37 
38    Options Database Keys:
39 .    -pc_deflation_init_only <false> - if true computes only the special guess
40 
41    Level: intermediate
42 
43 .seealso: `PCDEFLATION`
44 @*/
45 PetscErrorCode PCDeflationSetInitOnly(PC pc,PetscBool flg)
46 {
47   PetscFunctionBegin;
48   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
49   PetscValidLogicalCollectiveBool(pc,flg,2);
50   PetscTryMethod(pc,"PCDeflationSetInitOnly_C",(PC,PetscBool),(pc,flg));
51   PetscFunctionReturn(0);
52 }
53 
54 static PetscErrorCode PCDeflationSetLevels_Deflation(PC pc,PetscInt current,PetscInt max)
55 {
56   PC_Deflation   *def = (PC_Deflation*)pc->data;
57 
58   PetscFunctionBegin;
59   if (current) def->lvl = current;
60   def->maxlvl = max;
61   PetscFunctionReturn(0);
62 }
63 
64 /*@
65    PCDeflationSetLevels - Set the maximum level of deflation nesting.
66 
67    Logically Collective
68 
69    Input Parameters:
70 +  pc  - the preconditioner context
71 -  max - maximum deflation level
72 
73    Options Database Keys:
74 .    -pc_deflation_max_lvl <0> - maximum number of levels for multilevel deflation
75 
76    Level: intermediate
77 
78 .seealso: `PCDeflationSetSpaceToCompute()`, `PCDeflationSetSpace()`, `PCDEFLATION`
79 @*/
80 PetscErrorCode PCDeflationSetLevels(PC pc,PetscInt max)
81 {
82   PetscFunctionBegin;
83   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
84   PetscValidLogicalCollectiveInt(pc,max,2);
85   PetscTryMethod(pc,"PCDeflationSetLevels_C",(PC,PetscInt,PetscInt),(pc,0,max));
86   PetscFunctionReturn(0);
87 }
88 
89 static PetscErrorCode PCDeflationSetReductionFactor_Deflation(PC pc,PetscInt red)
90 {
91   PC_Deflation   *def = (PC_Deflation*)pc->data;
92 
93   PetscFunctionBegin;
94   def->reductionfact = red;
95   PetscFunctionReturn(0);
96 }
97 
98 /*@
99    PCDeflationSetReductionFactor - Set reduction factor for the bottom PCTELESCOPE coarse problem solver.
100 
101    Logically Collective
102 
103    Input Parameters:
104 +  pc  - the preconditioner context
105 -  red - reduction factor (or PETSC_DETERMINE)
106 
107    Options Database Keys:
108 .    -pc_deflation_reduction_factor <\-1> - reduction factor on bottom level coarse problem for PCTELESCOPE
109 
110    Notes:
111      Default is computed based on the size of the coarse problem.
112 
113    Level: intermediate
114 
115 .seealso: `PCTELESCOPE`, `PCDEFLATION`
116 @*/
117 PetscErrorCode PCDeflationSetReductionFactor(PC pc,PetscInt red)
118 {
119   PetscFunctionBegin;
120   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
121   PetscValidLogicalCollectiveInt(pc,red,2);
122   PetscTryMethod(pc,"PCDeflationSetReductionFactor_C",(PC,PetscInt),(pc,red));
123   PetscFunctionReturn(0);
124 }
125 
126 static PetscErrorCode PCDeflationSetCorrectionFactor_Deflation(PC pc,PetscScalar fact)
127 {
128   PC_Deflation   *def = (PC_Deflation*)pc->data;
129 
130   PetscFunctionBegin;
131   /* TODO PETSC_DETERMINE -> compute max eigenvalue with power method */
132   def->correct = PETSC_TRUE;
133   def->correctfact = fact;
134   if (def->correct == 0.0) {
135     def->correct = PETSC_FALSE;
136   }
137   PetscFunctionReturn(0);
138 }
139 
140 /*@
141    PCDeflationSetCorrectionFactor - Set coarse problem correction factor.
142     The Preconditioner becomes P*M^{-1} + fact*Q.
143 
144    Logically Collective
145 
146    Input Parameters:
147 +  pc   - the preconditioner context
148 -  fact - correction factor
149 
150    Options Database Keys:
151 +    -pc_deflation_correction        <false> - if true apply coarse problem correction
152 -    -pc_deflation_correction_factor <1.0>   - sets coarse problem correction factor
153 
154    Notes:
155     Any non-zero fact enables the coarse problem correction.
156 
157    Level: intermediate
158 
159 .seealso: `PCDEFLATION`
160 @*/
161 PetscErrorCode PCDeflationSetCorrectionFactor(PC pc,PetscScalar fact)
162 {
163   PetscFunctionBegin;
164   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
165   PetscValidLogicalCollectiveScalar(pc,fact,2);
166   PetscTryMethod(pc,"PCDeflationSetCorrectionFactor_C",(PC,PetscScalar),(pc,fact));
167   PetscFunctionReturn(0);
168 }
169 
170 static PetscErrorCode PCDeflationSetSpaceToCompute_Deflation(PC pc,PCDeflationSpaceType type,PetscInt size)
171 {
172   PC_Deflation   *def = (PC_Deflation*)pc->data;
173 
174   PetscFunctionBegin;
175   if (type) def->spacetype = type;
176   if (size > 0) def->spacesize = size;
177   PetscFunctionReturn(0);
178 }
179 
180 /*@
181    PCDeflationSetSpaceToCompute - Set deflation space type and size to compute.
182 
183    Logically Collective
184 
185    Input Parameters:
186 +  pc   - the preconditioner context
187 .  type - deflation space type to compute (or PETSC_IGNORE)
188 -  size - size of the space to compute (or PETSC_DEFAULT)
189 
190    Options Database Keys:
191 +    -pc_deflation_compute_space      <haar> - compute PCDeflationSpaceType deflation space
192 -    -pc_deflation_compute_space_size <1>    - size of the deflation space
193 
194    Notes:
195     For wavelet-based deflation, size represents number of levels.
196 
197     The deflation space is computed in PCSetUp().
198 
199    Level: intermediate
200 
201 .seealso: `PCDeflationSetLevels()`, `PCDEFLATION`
202 @*/
203 PetscErrorCode PCDeflationSetSpaceToCompute(PC pc,PCDeflationSpaceType type,PetscInt size)
204 {
205   PetscFunctionBegin;
206   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
207   if (type) PetscValidLogicalCollectiveEnum(pc,type,2);
208   if (size > 0) PetscValidLogicalCollectiveInt(pc,size,3);
209   PetscTryMethod(pc,"PCDeflationSetSpaceToCompute_C",(PC,PCDeflationSpaceType,PetscInt),(pc,type,size));
210   PetscFunctionReturn(0);
211 }
212 
213 static PetscErrorCode PCDeflationSetSpace_Deflation(PC pc,Mat W,PetscBool transpose)
214 {
215   PC_Deflation   *def = (PC_Deflation*)pc->data;
216 
217   PetscFunctionBegin;
218   /* possibly allows W' = Wt (which is valid but not tested) */
219   PetscCall(PetscObjectReference((PetscObject)W));
220   if (transpose) {
221     PetscCall(MatDestroy(&def->Wt));
222     def->Wt = W;
223   } else {
224     PetscCall(MatDestroy(&def->W));
225     def->W = W;
226   }
227   PetscFunctionReturn(0);
228 }
229 
230 /*@
231    PCDeflationSetSpace - Set the deflation space matrix (or its (Hermitian) transpose).
232 
233    Logically Collective
234 
235    Input Parameters:
236 +  pc        - the preconditioner context
237 .  W         - deflation matrix
238 -  transpose - indicates that W is an explicit transpose of the deflation matrix
239 
240    Notes:
241     Setting W as a multipliplicative MATCOMPOSITE enables use of the multilevel
242     deflation. If W = W0*W1*W2*...*Wn, W0 is taken as the first deflation space and
243     the coarse problem (W0'*A*W0)^{-1} is again preconditioned by deflation with
244     W1 as the deflation matrix. This repeats until the maximum level set by
245     PCDeflationSetLevels() is reached or there are no more matrices available.
246     If there are matrices left after reaching the maximum level,
247     they are merged into a deflation matrix ...*W{n-1}*Wn.
248 
249    Level: intermediate
250 
251 .seealso: `PCDeflationSetLevels()`, `PCDEFLATION`
252 @*/
253 PetscErrorCode PCDeflationSetSpace(PC pc,Mat W,PetscBool transpose)
254 {
255   PetscFunctionBegin;
256   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
257   PetscValidHeaderSpecific(W,MAT_CLASSID,2);
258   PetscValidLogicalCollectiveBool(pc,transpose,3);
259   PetscTryMethod(pc,"PCDeflationSetSpace_C",(PC,Mat,PetscBool),(pc,W,transpose));
260   PetscFunctionReturn(0);
261 }
262 
263 static PetscErrorCode PCDeflationSetProjectionNullSpaceMat_Deflation(PC pc,Mat mat)
264 {
265   PC_Deflation     *def = (PC_Deflation*)pc->data;
266 
267   PetscFunctionBegin;
268   PetscCall(PetscObjectReference((PetscObject)mat));
269   PetscCall(MatDestroy(&def->WtA));
270   def->WtA = mat;
271   PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)def->WtA));
272   PetscFunctionReturn(0);
273 }
274 
275 /*@
276    PCDeflationSetProjectionNullSpaceMat - Set the projection null space matrix (W'*A).
277 
278    Collective
279 
280    Input Parameters:
281 +  pc  - preconditioner context
282 -  mat - projection null space matrix
283 
284    Level: developer
285 
286 .seealso: `PCDEFLATION`
287 @*/
288 PetscErrorCode  PCDeflationSetProjectionNullSpaceMat(PC pc,Mat mat)
289 {
290   PetscFunctionBegin;
291   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
292   PetscValidHeaderSpecific(mat,MAT_CLASSID,2);
293   PetscTryMethod(pc,"PCDeflationSetProjectionNullSpaceMat_C",(PC,Mat),(pc,mat));
294   PetscFunctionReturn(0);
295 }
296 
297 static PetscErrorCode PCDeflationSetCoarseMat_Deflation(PC pc,Mat mat)
298 {
299   PC_Deflation     *def = (PC_Deflation*)pc->data;
300 
301   PetscFunctionBegin;
302   PetscCall(PetscObjectReference((PetscObject)mat));
303   PetscCall(MatDestroy(&def->WtAW));
304   def->WtAW = mat;
305   PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)def->WtAW));
306   PetscFunctionReturn(0);
307 }
308 
309 /*@
310    PCDeflationSetCoarseMat - Set the coarse problem Mat.
311 
312    Collective
313 
314    Input Parameters:
315 +  pc  - preconditioner context
316 -  mat - coarse problem mat
317 
318    Level: developer
319 
320 .seealso: `PCDEFLATION`
321 @*/
322 PetscErrorCode  PCDeflationSetCoarseMat(PC pc,Mat mat)
323 {
324   PetscFunctionBegin;
325   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
326   PetscValidHeaderSpecific(mat,MAT_CLASSID,2);
327   PetscTryMethod(pc,"PCDeflationSetCoarseMat_C",(PC,Mat),(pc,mat));
328   PetscFunctionReturn(0);
329 }
330 
331 static PetscErrorCode PCDeflationGetCoarseKSP_Deflation(PC pc,KSP *ksp)
332 {
333   PC_Deflation     *def = (PC_Deflation*)pc->data;
334 
335   PetscFunctionBegin;
336   *ksp = def->WtAWinv;
337   PetscFunctionReturn(0);
338 }
339 
340 /*@
341    PCDeflationGetCoarseKSP - Returns the coarse problem KSP.
342 
343    Not Collective
344 
345    Input Parameters:
346 .  pc - preconditioner context
347 
348    Output Parameters:
349 .  ksp - coarse problem KSP context
350 
351    Level: advanced
352 
353 .seealso: `PCDEFLATION`
354 @*/
355 PetscErrorCode  PCDeflationGetCoarseKSP(PC pc,KSP *ksp)
356 {
357   PetscFunctionBegin;
358   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
359   PetscValidPointer(ksp,2);
360   PetscTryMethod(pc,"PCDeflationGetCoarseKSP_C",(PC,KSP*),(pc,ksp));
361   PetscFunctionReturn(0);
362 }
363 
364 static PetscErrorCode PCDeflationGetPC_Deflation(PC pc,PC *apc)
365 {
366   PC_Deflation   *def = (PC_Deflation*)pc->data;
367 
368   PetscFunctionBegin;
369   *apc = def->pc;
370   PetscFunctionReturn(0);
371 }
372 
373 /*@
374    PCDeflationGetPC - Returns the additional preconditioner M^{-1}.
375 
376    Not Collective
377 
378    Input Parameters:
379 .  pc  - the preconditioner context
380 
381    Output Parameters:
382 .  apc - additional preconditioner
383 
384    Level: advanced
385 
386 .seealso: `PCDEFLATION`
387 @*/
388 PetscErrorCode PCDeflationGetPC(PC pc,PC *apc)
389 {
390   PetscFunctionBegin;
391   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
392   PetscValidPointer(pc,1);
393   PetscTryMethod(pc,"PCDeflationGetPC_C",(PC,PC*),(pc,apc));
394   PetscFunctionReturn(0);
395 }
396 
397 /*
398   x <- x + W*(W'*A*W)^{-1}*W'*r  = x + Q*r
399 */
400 static PetscErrorCode PCPreSolve_Deflation(PC pc,KSP ksp,Vec b, Vec x)
401 {
402   PC_Deflation     *def = (PC_Deflation*)pc->data;
403   Mat              A;
404   Vec              r,w1,w2;
405   PetscBool        nonzero;
406 
407   PetscFunctionBegin;
408   w1 = def->workcoarse[0];
409   w2 = def->workcoarse[1];
410   r  = def->work;
411   PetscCall(PCGetOperators(pc,NULL,&A));
412 
413   PetscCall(KSPGetInitialGuessNonzero(ksp,&nonzero));
414   PetscCall(KSPSetInitialGuessNonzero(ksp,PETSC_TRUE));
415   if (nonzero) {
416     PetscCall(MatMult(A,x,r));                          /*    r  <- b - Ax              */
417     PetscCall(VecAYPX(r,-1.0,b));
418   } else {
419     PetscCall(VecCopy(b,r));                            /*    r  <- b (x is 0)          */
420   }
421 
422   if (def->Wt) {
423     PetscCall(MatMult(def->Wt,r,w1));                   /*    w1 <- W'*r                */
424   } else {
425     PetscCall(MatMultHermitianTranspose(def->W,r,w1));  /*    w1 <- W'*r                */
426   }
427   PetscCall(KSPSolve(def->WtAWinv,w1,w2));              /*    w2 <- (W'*A*W)^{-1}*w1    */
428   PetscCall(MatMult(def->W,w2,r));                      /*    r  <- W*w2                */
429   PetscCall(VecAYPX(x,1.0,r));
430   PetscFunctionReturn(0);
431 }
432 
433 /*
434   if (def->correct) {
435     z <- M^{-1}r - W*(W'*A*W)^{-1}*(W'*A*M^{-1}r - l*W'*r) = (P*M^{-1} + l*Q)*r
436   } else {
437     z <- M^{-1}*r - W*(W'*A*W)^{-1}*W'*A*M{-1}*r = P*M^{-1}*r
438   }
439 */
440 static PetscErrorCode PCApply_Deflation(PC pc,Vec r,Vec z)
441 {
442   PC_Deflation     *def = (PC_Deflation*)pc->data;
443   Mat              A;
444   Vec              u,w1,w2;
445 
446   PetscFunctionBegin;
447   w1 = def->workcoarse[0];
448   w2 = def->workcoarse[1];
449   u  = def->work;
450   PetscCall(PCGetOperators(pc,NULL,&A));
451 
452   PetscCall(PCApply(def->pc,r,z));                          /*    z <- M^{-1}*r             */
453   if (!def->init) {
454     PetscCall(MatMult(def->WtA,z,w1));                      /*    w1 <- W'*A*z              */
455     if (def->correct) {
456       if (def->Wt) {
457         PetscCall(MatMult(def->Wt,r,w2));                   /*    w2 <- W'*r                */
458       } else {
459         PetscCall(MatMultHermitianTranspose(def->W,r,w2));  /*    w2 <- W'*r                */
460       }
461       PetscCall(VecAXPY(w1,-1.0*def->correctfact,w2));      /*    w1 <- w1 - l*w2           */
462     }
463     PetscCall(KSPSolve(def->WtAWinv,w1,w2));                /*    w2 <- (W'*A*W)^{-1}*w1    */
464     PetscCall(MatMult(def->W,w2,u));                        /*    u  <- W*w2                */
465     PetscCall(VecAXPY(z,-1.0,u));                           /*    z  <- z - u               */
466   }
467   PetscFunctionReturn(0);
468 }
469 
470 static PetscErrorCode PCSetUp_Deflation(PC pc)
471 {
472   PC_Deflation     *def = (PC_Deflation*)pc->data;
473   KSP              innerksp;
474   PC               pcinner;
475   Mat              Amat,nextDef=NULL,*mats;
476   PetscInt         i,m,red,size;
477   PetscMPIInt      commsize;
478   PetscBool        match,flgspd,transp=PETSC_FALSE;
479   MatCompositeType ctype;
480   MPI_Comm         comm;
481   char             prefix[128]="";
482 
483   PetscFunctionBegin;
484   if (pc->setupcalled) PetscFunctionReturn(0);
485   PetscCall(PetscObjectGetComm((PetscObject)pc,&comm));
486   PetscCall(PCGetOperators(pc,NULL,&Amat));
487   if (!def->lvl && !def->prefix) {
488     PetscCall(PCGetOptionsPrefix(pc,&def->prefix));
489   }
490   if (def->lvl) {
491     PetscCall(PetscSNPrintf(prefix,sizeof(prefix),"%d_",(int)def->lvl));
492   }
493 
494   /* compute a deflation space */
495   if (def->W || def->Wt) {
496     def->spacetype = PC_DEFLATION_SPACE_USER;
497   } else {
498     PetscCall(PCDeflationComputeSpace(pc));
499   }
500 
501   /* nested deflation */
502   if (def->W) {
503     PetscCall(PetscObjectTypeCompare((PetscObject)def->W,MATCOMPOSITE,&match));
504     if (match) {
505       PetscCall(MatCompositeGetType(def->W,&ctype));
506       PetscCall(MatCompositeGetNumberMat(def->W,&size));
507     }
508   } else {
509     PetscCall(MatCreateHermitianTranspose(def->Wt,&def->W));
510     PetscCall(PetscObjectTypeCompare((PetscObject)def->Wt,MATCOMPOSITE,&match));
511     if (match) {
512       PetscCall(MatCompositeGetType(def->Wt,&ctype));
513       PetscCall(MatCompositeGetNumberMat(def->Wt,&size));
514     }
515     transp = PETSC_TRUE;
516   }
517   if (match && ctype == MAT_COMPOSITE_MULTIPLICATIVE) {
518     if (!transp) {
519       if (def->lvl < def->maxlvl) {
520         PetscCall(PetscMalloc1(size,&mats));
521         for (i=0; i<size; i++) {
522           PetscCall(MatCompositeGetMat(def->W,i,&mats[i]));
523         }
524         size -= 1;
525         PetscCall(MatDestroy(&def->W));
526         def->W = mats[size];
527         PetscCall(PetscObjectReference((PetscObject)mats[size]));
528         if (size > 1) {
529           PetscCall(MatCreateComposite(comm,size,mats,&nextDef));
530           PetscCall(MatCompositeSetType(nextDef,MAT_COMPOSITE_MULTIPLICATIVE));
531         } else {
532           nextDef = mats[0];
533           PetscCall(PetscObjectReference((PetscObject)mats[0]));
534         }
535         PetscCall(PetscFree(mats));
536       } else {
537         /* TODO test merge side performance */
538         /* PetscCall(MatCompositeSetMergeType(def->W,MAT_COMPOSITE_MERGE_LEFT)); */
539         PetscCall(MatCompositeMerge(def->W));
540       }
541     } else {
542       if (def->lvl < def->maxlvl) {
543         PetscCall(PetscMalloc1(size,&mats));
544         for (i=0; i<size; i++) {
545           PetscCall(MatCompositeGetMat(def->Wt,i,&mats[i]));
546         }
547         size -= 1;
548         PetscCall(MatDestroy(&def->Wt));
549         def->Wt = mats[0];
550         PetscCall(PetscObjectReference((PetscObject)mats[0]));
551         if (size > 1) {
552           PetscCall(MatCreateComposite(comm,size,&mats[1],&nextDef));
553           PetscCall(MatCompositeSetType(nextDef,MAT_COMPOSITE_MULTIPLICATIVE));
554         } else {
555           nextDef = mats[1];
556           PetscCall(PetscObjectReference((PetscObject)mats[1]));
557         }
558         PetscCall(PetscFree(mats));
559       } else {
560         /* PetscCall(MatCompositeSetMergeType(def->W,MAT_COMPOSITE_MERGE_LEFT)); */
561         PetscCall(MatCompositeMerge(def->Wt));
562       }
563     }
564   }
565 
566   if (transp) {
567     PetscCall(MatDestroy(&def->W));
568     PetscCall(MatHermitianTranspose(def->Wt,MAT_INITIAL_MATRIX,&def->W));
569   }
570 
571   /* assemble WtA */
572   if (!def->WtA) {
573     if (def->Wt) {
574       PetscCall(MatMatMult(def->Wt,Amat,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&def->WtA));
575     } else {
576 #if defined(PETSC_USE_COMPLEX)
577       PetscCall(MatHermitianTranspose(def->W,MAT_INITIAL_MATRIX,&def->Wt));
578       PetscCall(MatMatMult(def->Wt,Amat,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&def->WtA));
579 #else
580       PetscCall(MatTransposeMatMult(def->W,Amat,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&def->WtA));
581 #endif
582     }
583   }
584   /* setup coarse problem */
585   if (!def->WtAWinv) {
586     PetscCall(MatGetSize(def->W,NULL,&m));
587     if (!def->WtAW) {
588       PetscCall(MatMatMult(def->WtA,def->W,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&def->WtAW));
589       /* TODO create MatInheritOption(Mat,MatOption) */
590       PetscCall(MatGetOption(Amat,MAT_SPD,&flgspd));
591       PetscCall(MatSetOption(def->WtAW,MAT_SPD,flgspd));
592       if (PetscDefined(USE_DEBUG)) {
593         /* Check columns of W are not in kernel of A */
594         PetscReal *norms;
595         PetscCall(PetscMalloc1(m,&norms));
596         PetscCall(MatGetColumnNorms(def->WtAW,NORM_INFINITY,norms));
597         for (i=0; i<m; i++) {
598           if (norms[i] < 100*PETSC_MACHINE_EPSILON) {
599             SETERRQ(comm,PETSC_ERR_SUP,"Column %" PetscInt_FMT " of W is in kernel of A.",i);
600           }
601         }
602         PetscCall(PetscFree(norms));
603       }
604     } else {
605       PetscCall(MatGetOption(def->WtAW,MAT_SPD,&flgspd));
606     }
607     /* TODO use MATINV ? */
608     PetscCall(KSPCreate(comm,&def->WtAWinv));
609     PetscCall(KSPSetOperators(def->WtAWinv,def->WtAW,def->WtAW));
610     PetscCall(KSPGetPC(def->WtAWinv,&pcinner));
611     /* Setup KSP and PC */
612     if (nextDef) { /* next level for multilevel deflation */
613       innerksp = def->WtAWinv;
614       /* set default KSPtype */
615       if (!def->ksptype) {
616         def->ksptype = KSPFGMRES;
617         if (flgspd) { /* SPD system */
618           def->ksptype = KSPFCG;
619         }
620       }
621       PetscCall(KSPSetType(innerksp,def->ksptype)); /* TODO iherit from KSP + tolerances */
622       PetscCall(PCSetType(pcinner,PCDEFLATION)); /* TODO create coarse preconditinoner M_c = WtMW ? */
623       PetscCall(PCDeflationSetSpace(pcinner,nextDef,transp));
624       PetscCall(PCDeflationSetLevels_Deflation(pcinner,def->lvl+1,def->maxlvl));
625       /* inherit options */
626       if (def->prefix) ((PC_Deflation*)(pcinner->data))->prefix = def->prefix;
627       ((PC_Deflation*)(pcinner->data))->init          = def->init;
628       ((PC_Deflation*)(pcinner->data))->ksptype       = def->ksptype;
629       ((PC_Deflation*)(pcinner->data))->correct       = def->correct;
630       ((PC_Deflation*)(pcinner->data))->correctfact   = def->correctfact;
631       ((PC_Deflation*)(pcinner->data))->reductionfact = def->reductionfact;
632       PetscCall(MatDestroy(&nextDef));
633     } else { /* the last level */
634       PetscCall(KSPSetType(def->WtAWinv,KSPPREONLY));
635       PetscCall(PCSetType(pcinner,PCTELESCOPE));
636       /* do not overwrite PCTELESCOPE */
637       if (def->prefix) PetscCall(KSPSetOptionsPrefix(def->WtAWinv,def->prefix));
638       PetscCall(KSPAppendOptionsPrefix(def->WtAWinv,"deflation_tel_"));
639       PetscCall(PCSetFromOptions(pcinner));
640       PetscCall(PetscObjectTypeCompare((PetscObject)pcinner,PCTELESCOPE,&match));
641       PetscCheck(match,comm,PETSC_ERR_SUP,"User can not owerwrite PCTELESCOPE on bottom level, use reduction factor = 1 instead.");
642       /* Reduction factor choice */
643       red = def->reductionfact;
644       if (red < 0) {
645         PetscCallMPI(MPI_Comm_size(comm,&commsize));
646         red  = PetscCeilInt(commsize,PetscCeilInt(m,commsize));
647         PetscCall(PetscObjectTypeCompareAny((PetscObject)(def->WtAW),&match,MATSEQDENSE,MATMPIDENSE,MATDENSE,""));
648         if (match) red = commsize;
649         PetscCall(PetscInfo(pc,"Auto choosing reduction factor %" PetscInt_FMT "\n",red));
650       }
651       PetscCall(PCTelescopeSetReductionFactor(pcinner,red));
652       PetscCall(PCSetUp(pcinner));
653       PetscCall(PCTelescopeGetKSP(pcinner,&innerksp));
654       if (innerksp) {
655         PetscCall(KSPGetPC(innerksp,&pcinner));
656         PetscCall(PCSetType(pcinner,PCLU));
657 #if defined(PETSC_HAVE_SUPERLU)
658         PetscCall(MatGetFactorAvailable(def->WtAW,MATSOLVERSUPERLU,MAT_FACTOR_LU,&match));
659         if (match) PetscCall(PCFactorSetMatSolverType(pcinner,MATSOLVERSUPERLU));
660 #endif
661 #if defined(PETSC_HAVE_SUPERLU_DIST)
662         PetscCall(MatGetFactorAvailable(def->WtAW,MATSOLVERSUPERLU_DIST,MAT_FACTOR_LU,&match));
663         if (match) PetscCall(PCFactorSetMatSolverType(pcinner,MATSOLVERSUPERLU_DIST));
664 #endif
665       }
666     }
667 
668     if (innerksp) {
669       if (def->prefix) {
670         PetscCall(KSPSetOptionsPrefix(innerksp,def->prefix));
671         PetscCall(KSPAppendOptionsPrefix(innerksp,"deflation_"));
672       } else {
673         PetscCall(KSPSetOptionsPrefix(innerksp,"deflation_"));
674       }
675       PetscCall(KSPAppendOptionsPrefix(innerksp,prefix));
676       PetscCall(KSPSetFromOptions(innerksp));
677       PetscCall(KSPSetUp(innerksp));
678     }
679   }
680   PetscCall(KSPSetFromOptions(def->WtAWinv));
681   PetscCall(KSPSetUp(def->WtAWinv));
682 
683   /* create preconditioner */
684   if (!def->pc) {
685     PetscCall(PCCreate(comm,&def->pc));
686     PetscCall(PCSetOperators(def->pc,Amat,Amat));
687     PetscCall(PCSetType(def->pc,PCNONE));
688     if (def->prefix) PetscCall(PCSetOptionsPrefix(def->pc,def->prefix));
689     PetscCall(PCAppendOptionsPrefix(def->pc,"deflation_"));
690     PetscCall(PCAppendOptionsPrefix(def->pc,prefix));
691     PetscCall(PCAppendOptionsPrefix(def->pc,"pc_"));
692     PetscCall(PCSetFromOptions(def->pc));
693     PetscCall(PCSetUp(def->pc));
694   }
695 
696   /* create work vecs */
697   PetscCall(MatCreateVecs(Amat,NULL,&def->work));
698   PetscCall(KSPCreateVecs(def->WtAWinv,2,&def->workcoarse,0,NULL));
699   PetscFunctionReturn(0);
700 }
701 
702 static PetscErrorCode PCReset_Deflation(PC pc)
703 {
704   PC_Deflation      *def = (PC_Deflation*)pc->data;
705 
706   PetscFunctionBegin;
707   PetscCall(VecDestroy(&def->work));
708   PetscCall(VecDestroyVecs(2,&def->workcoarse));
709   PetscCall(MatDestroy(&def->W));
710   PetscCall(MatDestroy(&def->Wt));
711   PetscCall(MatDestroy(&def->WtA));
712   PetscCall(MatDestroy(&def->WtAW));
713   PetscCall(KSPDestroy(&def->WtAWinv));
714   PetscCall(PCDestroy(&def->pc));
715   PetscFunctionReturn(0);
716 }
717 
718 static PetscErrorCode PCDestroy_Deflation(PC pc)
719 {
720   PetscFunctionBegin;
721   PetscCall(PCReset_Deflation(pc));
722   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetInitOnly_C",NULL));
723   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetLevels_C",NULL));
724   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetReductionFactor_C",NULL));
725   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetCorrectionFactor_C",NULL));
726   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetSpaceToCompute_C",NULL));
727   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetSpace_C",NULL));
728   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetProjectionNullSpaceMat_C",NULL));
729   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetCoarseMat_C",NULL));
730   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationGetCoarseKSP_C",NULL));
731   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationGetPC_C",NULL));
732   PetscCall(PetscFree(pc->data));
733   PetscFunctionReturn(0);
734 }
735 
736 static PetscErrorCode PCView_Deflation(PC pc,PetscViewer viewer)
737 {
738   PC_Deflation      *def = (PC_Deflation*)pc->data;
739   PetscInt          its;
740   PetscBool         iascii;
741 
742   PetscFunctionBegin;
743   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
744   if (iascii) {
745     if (def->correct) {
746       PetscCall(PetscViewerASCIIPrintf(viewer,"using CP correction, factor = %g+%gi\n",(double)PetscRealPart(def->correctfact),(double)PetscImaginaryPart(def->correctfact)));
747     }
748     if (!def->lvl) {
749       PetscCall(PetscViewerASCIIPrintf(viewer,"deflation space type: %s\n",PCDeflationSpaceTypes[def->spacetype]));
750     }
751 
752     PetscCall(PetscViewerASCIIPrintf(viewer,"--- Additional PC:\n"));
753     PetscCall(PetscViewerASCIIPushTab(viewer));
754     PetscCall(PCView(def->pc,viewer));
755     PetscCall(PetscViewerASCIIPopTab(viewer));
756 
757     PetscCall(PetscViewerASCIIPrintf(viewer,"--- Coarse problem solver:\n"));
758     PetscCall(PetscViewerASCIIPushTab(viewer));
759     PetscCall(KSPGetTotalIterations(def->WtAWinv,&its));
760     PetscCall(PetscViewerASCIIPrintf(viewer,"total number of iterations: %" PetscInt_FMT "\n",its));
761     PetscCall(KSPView(def->WtAWinv,viewer));
762     PetscCall(PetscViewerASCIIPopTab(viewer));
763   }
764   PetscFunctionReturn(0);
765 }
766 
767 static PetscErrorCode PCSetFromOptions_Deflation(PetscOptionItems *PetscOptionsObject,PC pc)
768 {
769   PC_Deflation      *def = (PC_Deflation*)pc->data;
770 
771   PetscFunctionBegin;
772   PetscOptionsHeadBegin(PetscOptionsObject,"Deflation options");
773   PetscCall(PetscOptionsBool("-pc_deflation_init_only","Use only initialization step - Initdef","PCDeflationSetInitOnly",def->init,&def->init,NULL));
774   PetscCall(PetscOptionsInt("-pc_deflation_levels","Maximum of deflation levels","PCDeflationSetLevels",def->maxlvl,&def->maxlvl,NULL));
775   PetscCall(PetscOptionsInt("-pc_deflation_reduction_factor","Reduction factor for coarse problem solution using PCTELESCOPE","PCDeflationSetReductionFactor",def->reductionfact,&def->reductionfact,NULL));
776   PetscCall(PetscOptionsBool("-pc_deflation_correction","Add coarse problem correction Q to P","PCDeflationSetCorrectionFactor",def->correct,&def->correct,NULL));
777   PetscCall(PetscOptionsScalar("-pc_deflation_correction_factor","Set multiple of Q to use as coarse problem correction","PCDeflationSetCorrectionFactor",def->correctfact,&def->correctfact,NULL));
778   PetscCall(PetscOptionsEnum("-pc_deflation_compute_space","Compute deflation space","PCDeflationSetSpace",PCDeflationSpaceTypes,(PetscEnum)def->spacetype,(PetscEnum*)&def->spacetype,NULL));
779   PetscCall(PetscOptionsInt("-pc_deflation_compute_space_size","Set size of the deflation space to compute","PCDeflationSetSpace",def->spacesize,&def->spacesize,NULL));
780   PetscCall(PetscOptionsBool("-pc_deflation_space_extend","Extend deflation space instead of truncating (wavelets)","PCDeflation",def->extendsp,&def->extendsp,NULL));
781   PetscOptionsHeadEnd();
782   PetscFunctionReturn(0);
783 }
784 
785 /*MC
786    PCDEFLATION - Deflation preconditioner shifts (deflates) part of the spectrum to zero or to a predefined value.
787 
788    Options Database Keys:
789 +    -pc_deflation_init_only          <false> - if true computes only the special guess
790 .    -pc_deflation_max_lvl            <0>     - maximum number of levels for multilevel deflation
791 .    -pc_deflation_reduction_factor <\-1>     - reduction factor on bottom level coarse problem for PCTELESCOPE (default based on the size of the coarse problem)
792 .    -pc_deflation_correction         <false> - if true apply coarse problem correction
793 .    -pc_deflation_correction_factor  <1.0>   - sets coarse problem correction factor
794 .    -pc_deflation_compute_space      <haar>  - compute PCDeflationSpaceType deflation space
795 -    -pc_deflation_compute_space_size <1>     - size of the deflation space (corresponds to number of levels for wavelet-based deflation)
796 
797    Notes:
798     Given a (complex - transpose is always Hermitian) full rank deflation matrix W, the deflation (introduced in [1,2])
799     preconditioner uses projections Q = W*(W'*A*W)^{-1}*W' and P = I - Q*A, where A is pmat.
800 
801     The deflation computes initial guess x0 = x_{-1} - Q*r_{-1}, which is the solution on the deflation space.
802     If PCDeflationSetInitOnly() or -pc_deflation_init_only is set to PETSC_TRUE (InitDef scheme), the application of the
803     preconditioner consists only of application of the additional preconditioner M^{-1}. Otherwise, the preconditioner
804     application consists of P*M^{-1} + factor*Q. The first part of the preconditioner (PM^{-1}) shifts some eigenvalues
805     to zero while the addition of the coarse problem correction (factor*Q) makes the preconditioner to shift some
806     eigenvalues to the given factor. The InitDef scheme is recommended for deflation using high accuracy estimates
807     of eigenvectors of A when it exhibits similar convergence to the full deflation but is cheaper.
808 
809     The deflation matrix is by default automatically computed. The type of deflation matrix and its size to compute can
810     be controlled by PCDeflationSetSpaceToCompute() or -pc_deflation_compute_space and -pc_deflation_compute_space_size.
811     User can set an arbitrary deflation space matrix with PCDeflationSetSpace(). If the deflation matrix
812     is a multiplicative MATCOMPOSITE, a multilevel deflation [3] is used. The first matrix in the composite is used as the
813     deflation matrix, and the coarse problem (W'*A*W)^{-1} is solved by KSPFCG (if A is MAT_SPD) or KSPFGMRES preconditioned
814     by deflation with deflation matrix being the next matrix in the MATCOMPOSITE. This scheme repeats until the maximum
815     level is reached or there are no more matrices. If the maximum level is reached, the remaining matrices are merged
816     (multiplied) to create the last deflation matrix. The maximum level defaults to 0 and can be set by
817     PCDeflationSetLevels() or by -pc_deflation_levels.
818 
819     The coarse problem KSP can be controlled from the command line with prefix -deflation_ for the first level and -deflation_[lvl-1]
820     from the second level onward. You can also use
821     PCDeflationGetCoarseKSP() to control it from code. The bottom level KSP defaults to
822     KSPPREONLY with PCLU direct solver (MATSOLVERSUPERLU/MATSOLVERSUPERLU_DIST if available) wrapped into PCTELESCOPE.
823     For convenience, the reduction factor can be set by PCDeflationSetReductionFactor()
824     or -pc_deflation_recduction_factor. The default is chosen heuristically based on the coarse problem size.
825 
826     The additional preconditioner can be controlled from command line with prefix -deflation_[lvl]_pc (same rules used for
827     coarse problem KSP apply for [lvl]_ part of prefix), e.g., -deflation_1_pc_pc_type bjacobi. You can also use
828     PCDeflationGetPC() to control the additional preconditioner from code. It defaults to PCNONE.
829 
830     The coarse problem correction term (factor*Q) can be turned on by -pc_deflation_correction and the factor value can
831     be set by pc_deflation_correction_factor or by PCDeflationSetCorrectionFactor(). The coarse problem can
832     significantly improve convergence when the deflation coarse problem is not solved with high enough accuracy. We
833     recommend setting factor to some eigenvalue, e.g., the largest eigenvalue so that the preconditioner does not create
834     an isolated eigenvalue.
835 
836     The options are automatically inherited from the previous deflation level.
837 
838     The preconditioner supports KSPMonitorDynamicTolerance(). This is useful for the multilevel scheme for which we also
839     recommend limiting the number of iterations for the coarse problems.
840 
841     See section 3 of [4] for additional references and decription of the algorithm when used for conjugate gradients.
842     Section 4 describes some possible choices for the deflation space.
843 
844    Developer Notes:
845      Contributed by Jakub Kruzik (PERMON), Institute of Geonics of the Czech
846      Academy of Sciences and VSB - TU Ostrava.
847 
848      Developed from PERMON code used in [4] while on a research stay with
849      Prof. Reinhard Nabben at the Institute of Mathematics, TU Berlin.
850 
851    References:
852 +  * - A. Nicolaides. "Deflation of conjugate gradients with applications to boundary value problems", SIAM J. Numer. Anal. 24.2, 1987.
853 .  * - Z. Dostal. "Conjugate gradient method with preconditioning by projector", Int J. Comput. Math. 23.3-4, 1988.
854 .  * - Y. A. Erlangga and R. Nabben. "Multilevel Projection-Based Nested Krylov Iteration for Boundary Value Problems", SIAM J. Sci. Comput. 30.3, 2008.
855 -  * - J. Kruzik "Implementation of the Deflated Variants of the Conjugate Gradient Method", Master's thesis, VSB-TUO, 2018 - http://dspace5.vsb.cz/bitstream/handle/10084/130303/KRU0097_USP_N2658_2612T078_2018.pdf
856 
857    Level: intermediate
858 
859 .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`,
860           `PCDeflationSetInitOnly()`, `PCDeflationSetLevels()`, `PCDeflationSetReductionFactor()`,
861           `PCDeflationSetCorrectionFactor()`, `PCDeflationSetSpaceToCompute()`,
862           `PCDeflationSetSpace()`, `PCDeflationSpaceType`, `PCDeflationSetProjectionNullSpaceMat()`,
863           `PCDeflationSetCoarseMat()`, `PCDeflationGetCoarseKSP()`, `PCDeflationGetPC()`
864 M*/
865 
866 PETSC_EXTERN PetscErrorCode PCCreate_Deflation(PC pc)
867 {
868   PC_Deflation   *def;
869 
870   PetscFunctionBegin;
871   PetscCall(PetscNewLog(pc,&def));
872   pc->data = (void*)def;
873 
874   def->init          = PETSC_FALSE;
875   def->correct       = PETSC_FALSE;
876   def->correctfact   = 1.0;
877   def->reductionfact = -1;
878   def->spacetype     = PC_DEFLATION_SPACE_HAAR;
879   def->spacesize     = 1;
880   def->extendsp      = PETSC_FALSE;
881   def->lvl           = 0;
882   def->maxlvl        = 0;
883   def->W             = NULL;
884   def->Wt            = NULL;
885 
886   pc->ops->apply          = PCApply_Deflation;
887   pc->ops->presolve       = PCPreSolve_Deflation;
888   pc->ops->setup          = PCSetUp_Deflation;
889   pc->ops->reset          = PCReset_Deflation;
890   pc->ops->destroy        = PCDestroy_Deflation;
891   pc->ops->setfromoptions = PCSetFromOptions_Deflation;
892   pc->ops->view           = PCView_Deflation;
893 
894   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetInitOnly_C",PCDeflationSetInitOnly_Deflation));
895   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetLevels_C",PCDeflationSetLevels_Deflation));
896   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetReductionFactor_C",PCDeflationSetReductionFactor_Deflation));
897   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetCorrectionFactor_C",PCDeflationSetCorrectionFactor_Deflation));
898   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetSpaceToCompute_C",PCDeflationSetSpaceToCompute_Deflation));
899   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetSpace_C",PCDeflationSetSpace_Deflation));
900   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetProjectionNullSpaceMat_C",PCDeflationSetProjectionNullSpaceMat_Deflation));
901   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetCoarseMat_C",PCDeflationSetCoarseMat_Deflation));
902   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationGetCoarseKSP_C",PCDeflationGetCoarseKSP_Deflation));
903   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationGetPC_C",PCDeflationGetPC_Deflation));
904   PetscFunctionReturn(0);
905 }
906