xref: /petsc/src/ksp/pc/impls/deflation/deflation.c (revision c3b5f7ba6bc5ce25a01a67bb37ba5d34b02bbbd7)
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 %D 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) {
638         PetscCall(KSPSetOptionsPrefix(def->WtAWinv,def->prefix));
639       }
640       PetscCall(KSPAppendOptionsPrefix(def->WtAWinv,"deflation_tel_"));
641       PetscCall(PCSetFromOptions(pcinner));
642       PetscCall(PetscObjectTypeCompare((PetscObject)pcinner,PCTELESCOPE,&match));
643       PetscCheck(match,comm,PETSC_ERR_SUP,"User can not owerwrite PCTELESCOPE on bottom level, use reduction factor = 1 instead.");
644       /* Reduction factor choice */
645       red = def->reductionfact;
646       if (red < 0) {
647         PetscCallMPI(MPI_Comm_size(comm,&commsize));
648         red  = PetscCeilInt(commsize,PetscCeilInt(m,commsize));
649         PetscCall(PetscObjectTypeCompareAny((PetscObject)(def->WtAW),&match,MATSEQDENSE,MATMPIDENSE,MATDENSE,""));
650         if (match) red = commsize;
651         PetscCall(PetscInfo(pc,"Auto choosing reduction factor %D\n",red));
652       }
653       PetscCall(PCTelescopeSetReductionFactor(pcinner,red));
654       PetscCall(PCSetUp(pcinner));
655       PetscCall(PCTelescopeGetKSP(pcinner,&innerksp));
656       if (innerksp) {
657         PetscCall(KSPGetPC(innerksp,&pcinner));
658         PetscCall(PCSetType(pcinner,PCLU));
659 #if defined(PETSC_HAVE_SUPERLU)
660         PetscCall(MatGetFactorAvailable(def->WtAW,MATSOLVERSUPERLU,MAT_FACTOR_LU,&match));
661         if (match) {
662           PetscCall(PCFactorSetMatSolverType(pcinner,MATSOLVERSUPERLU));
663         }
664 #endif
665 #if defined(PETSC_HAVE_SUPERLU_DIST)
666         PetscCall(MatGetFactorAvailable(def->WtAW,MATSOLVERSUPERLU_DIST,MAT_FACTOR_LU,&match));
667         if (match) {
668           PetscCall(PCFactorSetMatSolverType(pcinner,MATSOLVERSUPERLU_DIST));
669         }
670 #endif
671       }
672     }
673 
674     if (innerksp) {
675       if (def->prefix) {
676         PetscCall(KSPSetOptionsPrefix(innerksp,def->prefix));
677         PetscCall(KSPAppendOptionsPrefix(innerksp,"deflation_"));
678       } else {
679         PetscCall(KSPSetOptionsPrefix(innerksp,"deflation_"));
680       }
681       PetscCall(KSPAppendOptionsPrefix(innerksp,prefix));
682       PetscCall(KSPSetFromOptions(innerksp));
683       PetscCall(KSPSetUp(innerksp));
684     }
685   }
686   PetscCall(KSPSetFromOptions(def->WtAWinv));
687   PetscCall(KSPSetUp(def->WtAWinv));
688 
689   /* create preconditioner */
690   if (!def->pc) {
691     PetscCall(PCCreate(comm,&def->pc));
692     PetscCall(PCSetOperators(def->pc,Amat,Amat));
693     PetscCall(PCSetType(def->pc,PCNONE));
694     if (def->prefix) {
695       PetscCall(PCSetOptionsPrefix(def->pc,def->prefix));
696     }
697     PetscCall(PCAppendOptionsPrefix(def->pc,"deflation_"));
698     PetscCall(PCAppendOptionsPrefix(def->pc,prefix));
699     PetscCall(PCAppendOptionsPrefix(def->pc,"pc_"));
700     PetscCall(PCSetFromOptions(def->pc));
701     PetscCall(PCSetUp(def->pc));
702   }
703 
704   /* create work vecs */
705   PetscCall(MatCreateVecs(Amat,NULL,&def->work));
706   PetscCall(KSPCreateVecs(def->WtAWinv,2,&def->workcoarse,0,NULL));
707   PetscFunctionReturn(0);
708 }
709 
710 static PetscErrorCode PCReset_Deflation(PC pc)
711 {
712   PC_Deflation      *def = (PC_Deflation*)pc->data;
713 
714   PetscFunctionBegin;
715   PetscCall(VecDestroy(&def->work));
716   PetscCall(VecDestroyVecs(2,&def->workcoarse));
717   PetscCall(MatDestroy(&def->W));
718   PetscCall(MatDestroy(&def->Wt));
719   PetscCall(MatDestroy(&def->WtA));
720   PetscCall(MatDestroy(&def->WtAW));
721   PetscCall(KSPDestroy(&def->WtAWinv));
722   PetscCall(PCDestroy(&def->pc));
723   PetscFunctionReturn(0);
724 }
725 
726 static PetscErrorCode PCDestroy_Deflation(PC pc)
727 {
728   PetscFunctionBegin;
729   PetscCall(PCReset_Deflation(pc));
730   PetscCall(PetscFree(pc->data));
731   PetscFunctionReturn(0);
732 }
733 
734 static PetscErrorCode PCView_Deflation(PC pc,PetscViewer viewer)
735 {
736   PC_Deflation      *def = (PC_Deflation*)pc->data;
737   PetscInt          its;
738   PetscBool         iascii;
739   PetscErrorCode    ierr;
740 
741   PetscFunctionBegin;
742   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
743   if (iascii) {
744     if (def->correct) {
745       ierr = PetscViewerASCIIPrintf(viewer,"using CP correction, factor = %g+%gi\n",
746                                     (double)PetscRealPart(def->correctfact),
747                                     (double)PetscImaginaryPart(def->correctfact));PetscCall(ierr);
748     }
749     if (!def->lvl) {
750       PetscCall(PetscViewerASCIIPrintf(viewer,"deflation space type: %s\n",PCDeflationSpaceTypes[def->spacetype]));
751     }
752 
753     PetscCall(PetscViewerASCIIPrintf(viewer,"--- Additional PC:\n"));
754     PetscCall(PetscViewerASCIIPushTab(viewer));
755     PetscCall(PCView(def->pc,viewer));
756     PetscCall(PetscViewerASCIIPopTab(viewer));
757 
758     PetscCall(PetscViewerASCIIPrintf(viewer,"--- Coarse problem solver:\n"));
759     PetscCall(PetscViewerASCIIPushTab(viewer));
760     PetscCall(KSPGetTotalIterations(def->WtAWinv,&its));
761     PetscCall(PetscViewerASCIIPrintf(viewer,"total number of iterations: %D\n",its));
762     PetscCall(KSPView(def->WtAWinv,viewer));
763     PetscCall(PetscViewerASCIIPopTab(viewer));
764   }
765   PetscFunctionReturn(0);
766 }
767 
768 static PetscErrorCode PCSetFromOptions_Deflation(PetscOptionItems *PetscOptionsObject,PC pc)
769 {
770   PC_Deflation      *def = (PC_Deflation*)pc->data;
771 
772   PetscFunctionBegin;
773   PetscCall(PetscOptionsHead(PetscOptionsObject,"Deflation options"));
774   PetscCall(PetscOptionsBool("-pc_deflation_init_only","Use only initialization step - Initdef","PCDeflationSetInitOnly",def->init,&def->init,NULL));
775   PetscCall(PetscOptionsInt("-pc_deflation_levels","Maximum of deflation levels","PCDeflationSetLevels",def->maxlvl,&def->maxlvl,NULL));
776   PetscCall(PetscOptionsInt("-pc_deflation_reduction_factor","Reduction factor for coarse problem solution using PCTELESCOPE","PCDeflationSetReductionFactor",def->reductionfact,&def->reductionfact,NULL));
777   PetscCall(PetscOptionsBool("-pc_deflation_correction","Add coarse problem correction Q to P","PCDeflationSetCorrectionFactor",def->correct,&def->correct,NULL));
778   PetscCall(PetscOptionsScalar("-pc_deflation_correction_factor","Set multiple of Q to use as coarse problem correction","PCDeflationSetCorrectionFactor",def->correctfact,&def->correctfact,NULL));
779   PetscCall(PetscOptionsEnum("-pc_deflation_compute_space","Compute deflation space","PCDeflationSetSpace",PCDeflationSpaceTypes,(PetscEnum)def->spacetype,(PetscEnum*)&def->spacetype,NULL));
780   PetscCall(PetscOptionsInt("-pc_deflation_compute_space_size","Set size of the deflation space to compute","PCDeflationSetSpace",def->spacesize,&def->spacesize,NULL));
781   PetscCall(PetscOptionsBool("-pc_deflation_space_extend","Extend deflation space instead of truncating (wavelets)","PCDeflation",def->extendsp,&def->extendsp,NULL));
782   PetscCall(PetscOptionsTail());
783   PetscFunctionReturn(0);
784 }
785 
786 /*MC
787    PCDEFLATION - Deflation preconditioner shifts (deflates) part of the spectrum to zero or to a predefined value.
788 
789    Options Database Keys:
790 +    -pc_deflation_init_only          <false> - if true computes only the special guess
791 .    -pc_deflation_max_lvl            <0>     - maximum number of levels for multilevel deflation
792 .    -pc_deflation_reduction_factor <\-1>     - reduction factor on bottom level coarse problem for PCTELESCOPE (default based on the size of the coarse problem)
793 .    -pc_deflation_correction         <false> - if true apply coarse problem correction
794 .    -pc_deflation_correction_factor  <1.0>   - sets coarse problem correction factor
795 .    -pc_deflation_compute_space      <haar>  - compute PCDeflationSpaceType deflation space
796 -    -pc_deflation_compute_space_size <1>     - size of the deflation space (corresponds to number of levels for wavelet-based deflation)
797 
798    Notes:
799     Given a (complex - transpose is always Hermitian) full rank deflation matrix W, the deflation (introduced in [1,2])
800     preconditioner uses projections Q = W*(W'*A*W)^{-1}*W' and P = I - Q*A, where A is pmat.
801 
802     The deflation computes initial guess x0 = x_{-1} - Q*r_{-1}, which is the solution on the deflation space.
803     If PCDeflationSetInitOnly() or -pc_deflation_init_only is set to PETSC_TRUE (InitDef scheme), the application of the
804     preconditioner consists only of application of the additional preconditioner M^{-1}. Otherwise, the preconditioner
805     application consists of P*M^{-1} + factor*Q. The first part of the preconditioner (PM^{-1}) shifts some eigenvalues
806     to zero while the addition of the coarse problem correction (factor*Q) makes the preconditioner to shift some
807     eigenvalues to the given factor. The InitDef scheme is recommended for deflation using high accuracy estimates
808     of eigenvectors of A when it exhibits similar convergence to the full deflation but is cheaper.
809 
810     The deflation matrix is by default automatically computed. The type of deflation matrix and its size to compute can
811     be controlled by PCDeflationSetSpaceToCompute() or -pc_deflation_compute_space and -pc_deflation_compute_space_size.
812     User can set an arbitrary deflation space matrix with PCDeflationSetSpace(). If the deflation matrix
813     is a multiplicative MATCOMPOSITE, a multilevel deflation [3] is used. The first matrix in the composite is used as the
814     deflation matrix, and the coarse problem (W'*A*W)^{-1} is solved by KSPFCG (if A is MAT_SPD) or KSPFGMRES preconditioned
815     by deflation with deflation matrix being the next matrix in the MATCOMPOSITE. This scheme repeats until the maximum
816     level is reached or there are no more matrices. If the maximum level is reached, the remaining matrices are merged
817     (multiplied) to create the last deflation matrix. The maximum level defaults to 0 and can be set by
818     PCDeflationSetLevels() or by -pc_deflation_levels.
819 
820     The coarse problem KSP can be controlled from the command line with prefix -deflation_ for the first level and -deflation_[lvl-1]
821     from the second level onward. You can also use
822     PCDeflationGetCoarseKSP() to control it from code. The bottom level KSP defaults to
823     KSPPREONLY with PCLU direct solver (MATSOLVERSUPERLU/MATSOLVERSUPERLU_DIST if available) wrapped into PCTELESCOPE.
824     For convenience, the reduction factor can be set by PCDeflationSetReductionFactor()
825     or -pc_deflation_recduction_factor. The default is chosen heuristically based on the coarse problem size.
826 
827     The additional preconditioner can be controlled from command line with prefix -deflation_[lvl]_pc (same rules used for
828     coarse problem KSP apply for [lvl]_ part of prefix), e.g., -deflation_1_pc_pc_type bjacobi. You can also use
829     PCDeflationGetPC() to control the additional preconditioner from code. It defaults to PCNONE.
830 
831     The coarse problem correction term (factor*Q) can be turned on by -pc_deflation_correction and the factor value can
832     be set by pc_deflation_correction_factor or by PCDeflationSetCorrectionFactor(). The coarse problem can
833     significantly improve convergence when the deflation coarse problem is not solved with high enough accuracy. We
834     recommend setting factor to some eigenvalue, e.g., the largest eigenvalue so that the preconditioner does not create
835     an isolated eigenvalue.
836 
837     The options are automatically inherited from the previous deflation level.
838 
839     The preconditioner supports KSPMonitorDynamicTolerance(). This is useful for the multilevel scheme for which we also
840     recommend limiting the number of iterations for the coarse problems.
841 
842     See section 3 of [4] for additional references and decription of the algorithm when used for conjugate gradients.
843     Section 4 describes some possible choices for the deflation space.
844 
845    Developer Notes:
846      Contributed by Jakub Kruzik (PERMON), Institute of Geonics of the Czech
847      Academy of Sciences and VSB - TU Ostrava.
848 
849      Developed from PERMON code used in [4] while on a research stay with
850      Prof. Reinhard Nabben at the Institute of Mathematics, TU Berlin.
851 
852    References:
853 +  * - A. Nicolaides. "Deflation of conjugate gradients with applications to boundary value problems", SIAM J. Numer. Anal. 24.2, 1987.
854 .  * - Z. Dostal. "Conjugate gradient method with preconditioning by projector", Int J. Comput. Math. 23.3-4, 1988.
855 .  * - Y. A. Erlangga and R. Nabben. "Multilevel Projection-Based Nested Krylov Iteration for Boundary Value Problems", SIAM J. Sci. Comput. 30.3, 2008.
856 -  * - 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
857 
858    Level: intermediate
859 
860 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
861            PCDeflationSetInitOnly(), PCDeflationSetLevels(), PCDeflationSetReductionFactor(),
862            PCDeflationSetCorrectionFactor(), PCDeflationSetSpaceToCompute(),
863            PCDeflationSetSpace(), PCDeflationSpaceType, PCDeflationSetProjectionNullSpaceMat(),
864            PCDeflationSetCoarseMat(), PCDeflationGetCoarseKSP(), PCDeflationGetPC()
865 M*/
866 
867 PETSC_EXTERN PetscErrorCode PCCreate_Deflation(PC pc)
868 {
869   PC_Deflation   *def;
870 
871   PetscFunctionBegin;
872   PetscCall(PetscNewLog(pc,&def));
873   pc->data = (void*)def;
874 
875   def->init          = PETSC_FALSE;
876   def->correct       = PETSC_FALSE;
877   def->correctfact   = 1.0;
878   def->reductionfact = -1;
879   def->spacetype     = PC_DEFLATION_SPACE_HAAR;
880   def->spacesize     = 1;
881   def->extendsp      = PETSC_FALSE;
882   def->lvl           = 0;
883   def->maxlvl        = 0;
884   def->W             = NULL;
885   def->Wt            = NULL;
886 
887   pc->ops->apply          = PCApply_Deflation;
888   pc->ops->presolve       = PCPreSolve_Deflation;
889   pc->ops->setup          = PCSetUp_Deflation;
890   pc->ops->reset          = PCReset_Deflation;
891   pc->ops->destroy        = PCDestroy_Deflation;
892   pc->ops->setfromoptions = PCSetFromOptions_Deflation;
893   pc->ops->view           = PCView_Deflation;
894 
895   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetInitOnly_C",PCDeflationSetInitOnly_Deflation));
896   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetLevels_C",PCDeflationSetLevels_Deflation));
897   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetReductionFactor_C",PCDeflationSetReductionFactor_Deflation));
898   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetCorrectionFactor_C",PCDeflationSetCorrectionFactor_Deflation));
899   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetSpaceToCompute_C",PCDeflationSetSpaceToCompute_Deflation));
900   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetSpace_C",PCDeflationSetSpace_Deflation));
901   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetProjectionNullSpaceMat_C",PCDeflationSetProjectionNullSpaceMat_Deflation));
902   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetCoarseMat_C",PCDeflationSetCoarseMat_Deflation));
903   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationGetCoarseKSP_C",PCDeflationGetCoarseKSP_Deflation));
904   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCDeflationGetPC_C",PCDeflationGetPC_Deflation));
905   PetscFunctionReturn(0);
906 }
907