xref: /petsc/src/ksp/pc/impls/deflation/deflation.c (revision 98d6e3de2a57b2d63ec225b2c6f16ca63d47003c)
1 
2 /*  --------------------------------------------------------------------
3 
4      This file implements a Deflation preconditioner in PETSc as part of PC.
5      You can use this as a starting point for implementing your own
6      preconditioner that is not provided with PETSc. (You might also consider
7      just using PCSHELL)
8 
9      The following basic routines are required for each preconditioner.
10           PCCreate_XXX()          - Creates a preconditioner context
11           PCSetFromOptions_XXX()  - Sets runtime options
12           PCApply_XXX()           - Applies the preconditioner
13           PCDestroy_XXX()         - Destroys the preconditioner context
14      where the suffix "_XXX" denotes a particular implementation, in
15      this case we use _Deflation (e.g., PCCreate_Deflation, PCApply_Deflation).
16      These routines are actually called via the common user interface
17      routines PCCreate(), PCSetFromOptions(), PCApply(), and PCDestroy(),
18      so the application code interface remains identical for all
19      preconditioners.
20 
21      Another key routine is:
22           PCSetUp_XXX()           - Prepares for the use of a preconditioner
23      by setting data structures and options.   The interface routine PCSetUp()
24      is not usually called directly by the user, but instead is called by
25      PCApply() if necessary.
26 
27      Additional basic routines are:
28           PCView_XXX()            - Prints details of runtime options that
29                                     have actually been used.
30      These are called by application codes via the interface routines
31      PCView().
32 
33      The various types of solvers (preconditioners, Krylov subspace methods,
34      nonlinear solvers, timesteppers) are all organized similarly, so the
35      above description applies to these categories also.  One exception is
36      that the analogues of PCApply() for these components are KSPSolve(),
37      SNESSolve(), and TSSolve().
38 
39      Additional optional functionality unique to preconditioners is left and
40      right symmetric preconditioner application via PCApplySymmetricLeft()
41      and PCApplySymmetricRight().  The Deflation implementation is
42      PCApplySymmetricLeftOrRight_Deflation().
43 
44     -------------------------------------------------------------------- */
45 
46 /*
47    Include files needed for the Deflation preconditioner:
48      pcimpl.h - private include file intended for use by all preconditioners
49 */
50 
51 #include <../src/ksp/pc/impls/deflation/deflation.h> /*I "petscpc.h" I*/  /* includes for fortran wrappers */
52 
53 const char *const PCDeflationSpaceTypes[] = {
54   "haar",
55   "jacket-haar",
56   "db2",
57   "db4",
58   "db8",
59   "db16",
60   "biorth22",
61   "meyer",
62   "aggregation",
63   "slepc",
64   "slepc-cheap",
65   "user",
66   "DdefSpaceType",
67   "Ddef_SPACE_",
68   0
69 };
70 
71 static PetscErrorCode PCDeflationSetLvl_Deflation(PC pc,PetscInt current,PetscInt max)
72 {
73   PC_Deflation   *def = (PC_Deflation*)pc->data;
74 
75   PetscFunctionBegin;
76   if (current) def->nestedlvl = current;
77   def->maxnestedlvl = max;
78   PetscFunctionReturn(0);
79 }
80 
81 /*@
82    PCDeflationSetMaxLvl - Set maximum level of deflation.
83 
84    Logically Collective on PC
85 
86    Input Parameters:
87 +  pc  - the preconditioner context
88 -  max - maximum deflation level
89 
90    Level: intermediate
91 
92 .seealso: PCDEFLATION
93 @*/
94 PetscErrorCode PCDeflationSetMaxLvl(PC pc,PetscInt max)
95 {
96   PetscErrorCode ierr;
97 
98   PetscFunctionBegin;
99   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
100   PetscValidLogicalCollectiveInt(pc,max,2);
101   ierr = PetscTryMethod(pc,"PCDeflationSetLvl_C",(PC,PetscInt,PetscInt),(pc,0,max));CHKERRQ(ierr);
102   PetscFunctionReturn(0);
103 }
104 
105 static PetscErrorCode PCDeflationSetSpaceToCompute_Deflation(PC pc,PCDeflationSpaceType type,PetscInt size)
106 {
107   PC_Deflation   *def = (PC_Deflation*)pc->data;
108 
109   PetscFunctionBegin;
110   if (type) def->spacetype = type;
111   if (size > 0) def->spacesize = size;
112   PetscFunctionReturn(0);
113 }
114 
115 /*@
116    PCDeflationSetSpaceToCompute - Set deflation space type and size to compute.
117 
118    Logically Collective on PC
119 
120    Input Parameters:
121 +  pc   - the preconditioner context
122 .  type - deflation space type to compute (or PETSC_IGNORE)
123 -  size - size of the space to compute (or PETSC_DEFAULT)
124 
125    Notes:
126     For wavelet-based deflation, size represents number of levels.
127     The deflation space is computed in PCSetUP().
128 
129    Level: intermediate
130 
131 .seealso: PCDEFLATION
132 @*/
133 PetscErrorCode PCDeflationSetSpaceToCompute(PC pc,PCDeflationSpaceType type,PetscInt size)
134 {
135   PetscErrorCode ierr;
136 
137   PetscFunctionBegin;
138   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
139   if (type) PetscValidLogicalCollectiveEnum(pc,type,2);
140   if (size > 0) PetscValidLogicalCollectiveInt(pc,size,3);
141   ierr = PetscTryMethod(pc,"PCDeflationSetSpaceToCompute_C",(PC,PCDeflationSpaceType,PetscInt),(pc,type,size));CHKERRQ(ierr);
142   PetscFunctionReturn(0);
143 }
144 
145 static PetscErrorCode PCDeflationSetSpace_Deflation(PC pc,Mat W,PetscBool transpose)
146 {
147   PC_Deflation   *def = (PC_Deflation*)pc->data;
148   PetscErrorCode ierr;
149 
150   PetscFunctionBegin;
151   if (transpose) {
152     def->Wt = W;
153     def->W = NULL;
154   } else {
155     def->W = W;
156   }
157   ierr = PetscObjectReference((PetscObject)W);CHKERRQ(ierr);
158   PetscFunctionReturn(0);
159 }
160 
161 /* TODO create PCDeflationSetSpaceTranspose? */
162 /*@
163    PCDeflationSetSpace - Set deflation space matrix (or its transpose).
164 
165    Logically Collective on PC
166 
167    Input Parameters:
168 +  pc - the preconditioner context
169 .  W  - deflation matrix
170 -  tranpose - indicates that W is an explicit transpose of the deflation matrix
171 
172    Level: intermediate
173 
174 .seealso: PCDEFLATION
175 @*/
176 PetscErrorCode PCDeflationSetSpace(PC pc,Mat W,PetscBool transpose)
177 {
178   PetscErrorCode ierr;
179 
180   PetscFunctionBegin;
181   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
182   PetscValidHeaderSpecific(W,MAT_CLASSID,2);
183   PetscValidLogicalCollectiveBool(pc,transpose,3);
184   ierr = PetscTryMethod(pc,"PCDeflationSetSpace_C",(PC,Mat,PetscBool),(pc,W,transpose));CHKERRQ(ierr);
185   PetscFunctionReturn(0);
186 }
187 
188 static PetscErrorCode PCDeflationSetProjectionNullSpaceMat_Deflation(PC pc,Mat mat)
189 {
190   PC_Deflation     *def = (PC_Deflation*)pc->data;
191   PetscErrorCode   ierr;
192 
193   PetscFunctionBegin;
194   ierr = MatDestroy(&def->WtA);CHKERRQ(ierr);
195   def->WtA = mat;
196   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
197   ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)def->WtA);CHKERRQ(ierr);
198   PetscFunctionReturn(0);
199 }
200 
201 /*@
202    PCDeflationSetProjectionNullSpaceMat - Set projection null space matrix (W'*A).
203 
204    Not Collective
205 
206    Input Parameters:
207 +  pc  - preconditioner context
208 -  mat - projection null space matrix
209 
210    Level: developer
211 
212 .seealso: PCDEFLATION
213 @*/
214 PetscErrorCode  PCDeflationSetProjectionNullSpaceMat(PC pc,Mat mat)
215 {
216   PetscErrorCode ierr;
217 
218   PetscFunctionBegin;
219   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
220   PetscValidHeaderSpecific(mat,MAT_CLASSID,2);
221   ierr = PetscTryMethod(pc,"PCDeflationSetProjectionNullSpaceMat_C",(PC,Mat),(pc,mat));CHKERRQ(ierr);
222   PetscFunctionReturn(0);
223 }
224 
225 static PetscErrorCode PCDeflationSetCoarseMat_Deflation(PC pc,Mat mat)
226 {
227   PC_Deflation     *def = (PC_Deflation*)pc->data;
228   PetscErrorCode   ierr;
229 
230   PetscFunctionBegin;
231   ierr = MatDestroy(&def->WtAW);CHKERRQ(ierr);
232   def->WtAW = mat;
233   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
234   ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)def->WtAW);CHKERRQ(ierr);
235   PetscFunctionReturn(0);
236 }
237 
238 /*@
239    PCDeflationSetCoarseMat - Set coarse problem Mat.
240 
241    Not Collective
242 
243    Input Parameters:
244 +  pc - preconditioner context
245 -  mat - coarse problem mat
246 
247    Level: developer
248 
249 .seealso: PCDEFLATION
250 @*/
251 PetscErrorCode  PCDeflationSetCoarseMat(PC pc,Mat mat)
252 {
253   PetscErrorCode ierr;
254 
255   PetscFunctionBegin;
256   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
257   PetscValidHeaderSpecific(mat,MAT_CLASSID,2);
258   ierr = PetscTryMethod(pc,"PCDeflationSetCoarseMat_C",(PC,Mat),(pc,mat));CHKERRQ(ierr);
259   PetscFunctionReturn(0);
260 }
261 
262 static PetscErrorCode PCDeflationGetCoarseKSP_Deflation(PC pc,KSP *ksp)
263 {
264   PC_Deflation     *def = (PC_Deflation*)pc->data;
265 
266   PetscFunctionBegin;
267   *ksp = def->WtAWinv;
268   PetscFunctionReturn(0);
269 }
270 
271 /*@
272    PCDeflationGetCoarseKSP - Returns a pointer to the coarse problem KSP.
273 
274    Not Collective
275 
276    Input Parameters:
277 .  pc - preconditioner context
278 
279    Output Parameter:
280 .  ksp - coarse problem KSP context
281 
282    Level: developer
283 
284 .seealso: PCDeflationSetCoarseKSP(), PCDEFLATION
285 @*/
286 PetscErrorCode  PCDeflationGetCoarseKSP(PC pc,KSP *ksp)
287 {
288   PetscErrorCode ierr;
289 
290   PetscFunctionBegin;
291   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
292   PetscValidPointer(ksp,2);
293   ierr = PetscTryMethod(pc,"PCDeflationGetCoarseKSP_C",(PC,KSP*),(pc,ksp));CHKERRQ(ierr);
294   PetscFunctionReturn(0);
295 }
296 
297 static PetscErrorCode PCDeflationSetCoarseKSP_Deflation(PC pc,KSP ksp)
298 {
299   PC_Deflation     *def = (PC_Deflation*)pc->data;
300   PetscErrorCode   ierr;
301 
302   PetscFunctionBegin;
303   ierr = KSPDestroy(&def->WtAWinv);CHKERRQ(ierr);
304   def->WtAWinv = ksp;
305   ierr = PetscObjectReference((PetscObject)ksp);CHKERRQ(ierr);
306   ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)def->WtAWinv);CHKERRQ(ierr);
307   PetscFunctionReturn(0);
308 }
309 
310 /*@
311    PCDeflationSetCoarseKSP - Set coarse problem KSP.
312 
313    Collective on PC
314 
315    Input Parameters:
316 +  pc - preconditioner context
317 -  ksp - coarse problem KSP context
318 
319    Level: developer
320 
321 .seealso: PCDeflationGetCoarseKSP(), PCDEFLATION
322 @*/
323 PetscErrorCode  PCDeflationSetCoarseKSP(PC pc,KSP ksp)
324 {
325   PetscErrorCode ierr;
326 
327   PetscFunctionBegin;
328   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
329   PetscValidHeaderSpecific(ksp,KSP_CLASSID,2);
330   PetscCheckSameComm(pc,1,ksp,2);
331   ierr = PetscTryMethod(pc,"PCDeflationSetCoarseKSP_C",(PC,KSP),(pc,ksp));CHKERRQ(ierr);
332   PetscFunctionReturn(0);
333 }
334 
335 static PetscErrorCode PCDeflationGetPC_Deflation(PC pc,PC *apc)
336 {
337   PC_Deflation   *def = (PC_Deflation*)pc->data;
338 
339   PetscFunctionBegin;
340   *apc = def->pc;
341   PetscFunctionReturn(0);
342 }
343 
344 /*@
345    PCDeflationGetPC - Returns a pointer to additional preconditioner.
346 
347    Not Collective
348 
349    Input Parameters:
350 .  pc  - the preconditioner context
351 
352    Output Parameter:
353 .  apc - additional preconditioner
354 
355    Level: advanced
356 
357 .seealso: PCDeflationSetPC(), PCDEFLATION
358 @*/
359 PetscErrorCode PCDeflationGetPC(PC pc,PC *apc)
360 {
361   PetscErrorCode ierr;
362 
363   PetscFunctionBegin;
364   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
365   PetscValidPointer(pc,2);
366   ierr = PetscTryMethod(pc,"PCDeflationGetPC_C",(PC,PC*),(pc,apc));CHKERRQ(ierr);
367   PetscFunctionReturn(0);
368 }
369 
370 static PetscErrorCode PCDeflationSetPC_Deflation(PC pc,PC apc)
371 {
372   PC_Deflation   *def = (PC_Deflation*)pc->data;
373   PetscErrorCode ierr;
374 
375   PetscFunctionBegin;
376   ierr = PCDestroy(&def->pc);CHKERRQ(ierr);
377   def->pc = apc;
378   ierr = PetscObjectReference((PetscObject)apc);CHKERRQ(ierr);
379   ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)def->pc);CHKERRQ(ierr);
380   PetscFunctionReturn(0);
381 }
382 
383 /*@
384    PCDeflationSetPC - Set additional preconditioner.
385 
386    Collective on PC
387 
388    Input Parameters:
389 +  pc  - the preconditioner context
390 -  apc - additional preconditioner
391 
392    Level: developer
393 
394 .seealso: PCDeflationGetPC(), PCDEFLATION
395 @*/
396 PetscErrorCode PCDeflationSetPC(PC pc,PC apc)
397 {
398   PetscErrorCode ierr;
399 
400   PetscFunctionBegin;
401   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
402   PetscValidHeaderSpecific(apc,PC_CLASSID,2);
403   PetscCheckSameComm(pc,1,apc,2);
404   ierr = PetscTryMethod(pc,"PCDeflationSetPC_C",(PC,PC),(pc,apc));CHKERRQ(ierr);
405   PetscFunctionReturn(0);
406 }
407 
408 /*
409   x <- x + W*(W'*A*W)^{-1}*W'*r  = x + Q*r
410 */
411 static PetscErrorCode PCPreSolve_Deflation(PC pc,KSP ksp,Vec b, Vec x)
412 {
413   PC_Deflation     *def = (PC_Deflation*)pc->data;
414   Mat              A;
415   Vec              r,w1,w2;
416   PetscBool        nonzero;
417   PetscErrorCode   ierr;
418 
419   PetscFunctionBegin;
420   w1 = def->workcoarse[0];
421   w2 = def->workcoarse[1];
422   r  = def->work;
423   ierr = PCGetOperators(pc,NULL,&A);CHKERRQ(ierr);
424 
425   ierr = KSPGetInitialGuessNonzero(ksp,&nonzero);CHKERRQ(ierr);
426   ierr = KSPSetInitialGuessNonzero(ksp,PETSC_TRUE);CHKERRQ(ierr);
427   if (nonzero) {
428     ierr = MatMult(A,x,r);CHKERRQ(ierr);                          /*    r  <- b - Ax              */
429     ierr = VecAYPX(r,-1.0,b);CHKERRQ(ierr);
430   } else {
431     ierr = VecCopy(b,r);CHKERRQ(ierr);                            /*    r  <- b (x is 0)          */
432   }
433 
434   if (def->Wt) {
435     ierr = MatMult(def->Wt,r,w1);CHKERRQ(ierr);                   /*    w1 <- W'*r                */
436   } else {
437     ierr = MatMultHermitianTranspose(def->W,r,w1);CHKERRQ(ierr);  /*    w1 <- W'*r                */
438   }
439   ierr = KSPSolve(def->WtAWinv,w1,w2);CHKERRQ(ierr);              /*    w2 <- (W'*A*W)^{-1}*w1    */
440   ierr = MatMult(def->W,w2,r);CHKERRQ(ierr);                      /*    r  <- W*w2                */
441   ierr = VecAYPX(x,1.0,r);CHKERRQ(ierr);
442   PetscFunctionReturn(0);
443 }
444 
445 /*
446   if (def->correct) {
447     z <- M^{-1}r - W*(W'*A*W)^{-1}*(W'*A*M^{-1}r - l*W'*r) = (P*M^{-1} + l*Q)*r
448   } else {
449     z <- M^{-1}*r - W*(W'*A*W)^{-1}*W'*A*M{-1}*r = P*M^{-1}*r
450   }
451 */
452 static PetscErrorCode PCApply_Deflation(PC pc,Vec r,Vec z)
453 {
454   PC_Deflation     *def = (PC_Deflation*)pc->data;
455   Mat              A;
456   Vec              u,w1,w2;
457   PetscErrorCode   ierr;
458 
459   PetscFunctionBegin;
460   w1 = def->workcoarse[0];
461   w2 = def->workcoarse[1];
462   u  = def->work;
463   ierr = PCGetOperators(pc,NULL,&A);CHKERRQ(ierr);
464 
465   ierr = PCApply(def->pc,r,z);CHKERRQ(ierr);                      /*    z <- M^{-1}*r             */
466   if (!def->init) {
467     ierr = MatMult(def->WtA,z,w1);CHKERRQ(ierr);                  /*    w1 <- W'*A*z              */
468     if (def->correct) {
469       if (def->Wt) {
470         ierr = MatMult(def->Wt,r,w2);CHKERRQ(ierr);               /*    w2 <- W'*r                */
471       } else {
472         ierr = MatMultHermitianTranspose(def->W,r,w2);CHKERRQ(ierr);       /*    w2 <- W'*r                */
473       }
474       ierr = VecAXPY(w1,-1.0*def->correctfact,w2);CHKERRQ(ierr);  /*    w1 <- w1 - l*w2           */
475     }
476     ierr = KSPSolve(def->WtAWinv,w1,w2);CHKERRQ(ierr);            /*    w2 <- (W'*A*W)^{-1}*w1    */
477     ierr = MatMult(def->W,w2,u);CHKERRQ(ierr);                    /*    u  <- W*w2                */
478     ierr = VecAXPY(z,-1.0,u);CHKERRQ(ierr);                       /*    z  <- z - u               */
479   }
480   PetscFunctionReturn(0);
481 }
482 
483 static PetscErrorCode PCSetUp_Deflation(PC pc)
484 {
485   PC_Deflation     *def = (PC_Deflation*)pc->data;
486   KSP              innerksp;
487   PC               pcinner;
488   Mat              Amat,nextDef=NULL,*mats;
489   PetscInt         i,m,red,size,commsize;
490   PetscBool        match,flgspd,transp=PETSC_FALSE;
491   MatCompositeType ctype;
492   MPI_Comm         comm;
493   const char       *prefix;
494   PetscErrorCode   ierr;
495 
496   PetscFunctionBegin;
497   if (pc->setupcalled) PetscFunctionReturn(0);
498   ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr);
499   ierr = PCGetOperators(pc,NULL,&Amat);CHKERRQ(ierr);
500 
501   /* compute a deflation space */
502   if (def->W || def->Wt) {
503     def->spacetype = PC_DEFLATION_SPACE_USER;
504   } else {
505     ierr = PCDeflationComputeSpace(pc);CHKERRQ(ierr);
506   }
507 
508   /* nested deflation */
509   if (def->W) {
510     ierr = PetscObjectTypeCompare((PetscObject)def->W,MATCOMPOSITE,&match);CHKERRQ(ierr);
511     if (match) {
512       ierr = MatCompositeGetType(def->W,&ctype);CHKERRQ(ierr);
513       ierr = MatCompositeGetNumberMat(def->W,&size);CHKERRQ(ierr);
514     }
515   } else {
516     ierr = MatCreateHermitianTranspose(def->Wt,&def->W);CHKERRQ(ierr);
517     ierr = PetscObjectTypeCompare((PetscObject)def->Wt,MATCOMPOSITE,&match);CHKERRQ(ierr);
518     if (match) {
519       ierr = MatCompositeGetType(def->Wt,&ctype);CHKERRQ(ierr);
520       ierr = MatCompositeGetNumberMat(def->Wt,&size);CHKERRQ(ierr);
521     }
522     transp = PETSC_TRUE;
523   }
524   if (match && ctype == MAT_COMPOSITE_MULTIPLICATIVE) {
525     if (!transp) {
526       if (def->nestedlvl < def->maxnestedlvl) {
527         ierr = PetscMalloc1(size,&mats);CHKERRQ(ierr);
528         for (i=0; i<size; i++) {
529           ierr = MatCompositeGetMat(def->W,i,&mats[i]);CHKERRQ(ierr);
530         }
531         size -= 1;
532         ierr = MatDestroy(&def->W);CHKERRQ(ierr);
533         def->W = mats[size];
534         ierr = PetscObjectReference((PetscObject)mats[size]);CHKERRQ(ierr);
535         if (size > 1) {
536           ierr = MatCreateComposite(comm,size,mats,&nextDef);CHKERRQ(ierr);
537           ierr = MatCompositeSetType(nextDef,MAT_COMPOSITE_MULTIPLICATIVE);CHKERRQ(ierr);
538         } else {
539           nextDef = mats[0];
540           ierr = PetscObjectReference((PetscObject)mats[0]);CHKERRQ(ierr);
541         }
542         ierr = PetscFree(mats);CHKERRQ(ierr);
543       } else {
544         /* ierr = MatCompositeSetMergeType(def->W,MAT_COMPOSITE_MERGE_LEFT);CHKERRQ(ierr); */
545         ierr = MatCompositeMerge(def->W);CHKERRQ(ierr);
546       }
547     } else {
548       if (def->nestedlvl < def->maxnestedlvl) {
549         ierr = PetscMalloc1(size,&mats);CHKERRQ(ierr);
550         for (i=0; i<size; i++) {
551           ierr = MatCompositeGetMat(def->Wt,i,&mats[i]);CHKERRQ(ierr);
552         }
553         size -= 1;
554         ierr = MatDestroy(&def->Wt);CHKERRQ(ierr);
555         def->Wt = mats[0];
556         ierr = PetscObjectReference((PetscObject)mats[0]);CHKERRQ(ierr);
557         if (size > 1) {
558           ierr = MatCreateComposite(comm,size,&mats[1],&nextDef);CHKERRQ(ierr);
559           ierr = MatCompositeSetType(nextDef,MAT_COMPOSITE_MULTIPLICATIVE);CHKERRQ(ierr);
560         } else {
561           nextDef = mats[1];
562           ierr = PetscObjectReference((PetscObject)mats[1]);CHKERRQ(ierr);
563         }
564         ierr = PetscFree(mats);CHKERRQ(ierr);
565       } else {
566         /* ierr = MatCompositeSetMergeType(def->W,MAT_COMPOSITE_MERGE_LEFT);CHKERRQ(ierr); */
567         ierr = MatCompositeMerge(def->Wt);CHKERRQ(ierr);
568       }
569     }
570   }
571 
572   if (transp) {
573     ierr = MatDestroy(&def->W);CHKERRQ(ierr);
574     ierr = MatHermitianTranspose(def->Wt,MAT_INITIAL_MATRIX,&def->W);CHKERRQ(ierr);
575   }
576 
577 
578   ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr);
579 
580   /* assemble WtA */
581   if (!def->WtA) {
582     if (def->Wt) {
583       ierr = MatMatMult(def->Wt,Amat,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&def->WtA);CHKERRQ(ierr);
584     } else {
585 #if defined(PETSC_USE_COMPLEX)
586       ierr = MatHermitianTranspose(def->W,MAT_INITIAL_MATRIX,&def->Wt);CHKERRQ(ierr);
587       ierr = MatMatMult(def->W,Amat,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&def->WtA);CHKERRQ(ierr);
588 #else
589       ierr = MatTransposeMatMult(def->W,Amat,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&def->WtA);CHKERRQ(ierr);
590 #endif
591     }
592   }
593   /* setup coarse problem */
594   if (!def->WtAWinv) {
595     ierr = MatGetSize(def->W,NULL,&m);CHKERRQ(ierr);
596     if (!def->WtAW) {
597       ierr = MatMatMult(def->WtA,def->W,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&def->WtAW);CHKERRQ(ierr);
598       /* TODO create MatInheritOption(Mat,MatOption) */
599       ierr = MatGetOption(Amat,MAT_SPD,&flgspd);CHKERRQ(ierr);
600       ierr = MatSetOption(def->WtAW,MAT_SPD,flgspd);CHKERRQ(ierr);
601 #if defined(PETSC_USE_DEBUG)
602       /* Check columns of W are not in kernel of A */
603       PetscReal *norms;
604       ierr = PetscMalloc1(m,&norms);CHKERRQ(ierr);
605       ierr = MatGetColumnNorms(def->WtAW,NORM_INFINITY,norms);CHKERRQ(ierr);
606       for (i=0; i<m; i++) {
607         if (norms[i] < 100*PETSC_MACHINE_EPSILON) {
608           SETERRQ1(comm,PETSC_ERR_SUP,"Column %D of W is in kernel of A.",i);
609         }
610       }
611       ierr = PetscFree(norms);CHKERRQ(ierr);
612 #endif
613     } else {
614       ierr = MatGetOption(def->WtAW,MAT_SPD,&flgspd);CHKERRQ(ierr);
615     }
616     /* TODO use MATINV */
617     ierr = KSPCreate(comm,&def->WtAWinv);CHKERRQ(ierr);
618     ierr = KSPSetOperators(def->WtAWinv,def->WtAW,def->WtAW);CHKERRQ(ierr);
619     ierr = KSPGetPC(def->WtAWinv,&pcinner);CHKERRQ(ierr);
620     /* Setup KSP and PC */
621     if (nextDef) { /* next level for multilevel deflation */
622       innerksp = def->WtAWinv;
623       /* set default KSPtype */
624       if (!def->ksptype) {
625         def->ksptype = KSPFGMRES;
626         if (flgspd) { /* SPD system */
627           def->ksptype = KSPFCG;
628         }
629       }
630       ierr = KSPSetType(innerksp,def->ksptype);CHKERRQ(ierr); /* TODO iherit from KSP + tolerances */
631       ierr = PCSetType(pcinner,PCDEFLATION);CHKERRQ(ierr); /* TODO create coarse preconditinoner M_c = WtMW ? */
632       ierr = PCDeflationSetSpace(pcinner,nextDef,transp);CHKERRQ(ierr);
633       ierr = PCDeflationSetLvl_Deflation(pcinner,def->nestedlvl+1,def->maxnestedlvl);CHKERRQ(ierr);
634       /* inherit options */
635       ((PC_Deflation*)(pcinner->data))->ksptype = def->ksptype;
636       ((PC_Deflation*)(pcinner->data))->correct = def->correct;
637       ierr = MatDestroy(&nextDef);CHKERRQ(ierr);
638     } else { /* the last level */
639       ierr = KSPSetType(def->WtAWinv,KSPPREONLY);CHKERRQ(ierr);
640       ierr = PCSetType(pcinner,PCTELESCOPE);CHKERRQ(ierr);
641       /* ugly hack to not have overwritten PCTELESCOPE */
642       if (prefix) {
643         ierr = KSPSetOptionsPrefix(def->WtAWinv,prefix);CHKERRQ(ierr);
644       }
645       ierr = KSPAppendOptionsPrefix(def->WtAWinv,"tel_");CHKERRQ(ierr);
646       ierr = PCSetFromOptions(pcinner);CHKERRQ(ierr);
647       /* Reduction factor choice */
648       red = def->reductionfact;
649       if (red < 0) {
650         ierr = MPI_Comm_size(comm,&commsize);CHKERRQ(ierr);
651         red  = ceil((float)commsize/ceil((float)m/commsize));
652         ierr = PetscObjectTypeCompareAny((PetscObject)(def->WtAW),&match,MATSEQDENSE,MATMPIDENSE,MATDENSE,"");CHKERRQ(ierr);
653         if (match) red = commsize;
654         ierr = PetscInfo1(pc,"Auto choosing reduction factor %D\n",red);CHKERRQ(ierr); /* TODO add level? */
655       }
656       ierr = PCTelescopeSetReductionFactor(pcinner,red);CHKERRQ(ierr);
657       ierr = PCSetUp(pcinner);CHKERRQ(ierr);
658       ierr = PCTelescopeGetKSP(pcinner,&innerksp);CHKERRQ(ierr);
659       if (innerksp) {
660         ierr = KSPGetPC(innerksp,&pcinner);CHKERRQ(ierr);
661         /* TODO Cholesky if flgspd? */
662         ierr = PCSetType(pcinner,PCLU);CHKERRQ(ierr);
663         //TODO remove explicit matSolverPackage
664         if (commsize == red) {
665           ierr = PCFactorSetMatSolverType(pcinner,MATSOLVERSUPERLU);CHKERRQ(ierr);
666         } else {
667           ierr = PCFactorSetMatSolverType(pcinner,MATSOLVERSUPERLU_DIST);CHKERRQ(ierr);
668         }
669       }
670     }
671 
672     if (innerksp) {
673       /* TODO use def_[lvl]_ if lvl > 0? */
674       if (prefix) {
675         ierr = KSPSetOptionsPrefix(innerksp,prefix);CHKERRQ(ierr);
676       }
677       ierr = KSPAppendOptionsPrefix(innerksp,"def_");CHKERRQ(ierr);
678       ierr = KSPSetFromOptions(innerksp);CHKERRQ(ierr);
679       ierr = KSPSetUp(innerksp);CHKERRQ(ierr);
680     }
681   }
682   ierr = KSPSetFromOptions(def->WtAWinv);CHKERRQ(ierr);
683   ierr = KSPSetUp(def->WtAWinv);CHKERRQ(ierr);
684 
685   if (!def->pc) {
686     ierr = PCCreate(comm,&def->pc);CHKERRQ(ierr);
687     ierr = PCSetOperators(def->pc,Amat,Amat);CHKERRQ(ierr);
688     ierr = PCSetType(def->pc,PCNONE);CHKERRQ(ierr);
689     if (prefix) {
690       ierr = PCSetOptionsPrefix(def->pc,prefix);CHKERRQ(ierr);
691     }
692     ierr = PCAppendOptionsPrefix(def->pc,"def_pc_");CHKERRQ(ierr);
693     ierr = PCSetFromOptions(def->pc);CHKERRQ(ierr);
694     ierr = PCSetUp(def->pc);CHKERRQ(ierr);
695   }
696 
697   /* create work vecs */
698   ierr = MatCreateVecs(Amat,NULL,&def->work);CHKERRQ(ierr);
699   ierr = KSPCreateVecs(def->WtAWinv,2,&def->workcoarse,0,NULL);CHKERRQ(ierr);
700   PetscFunctionReturn(0);
701 }
702 
703 static PetscErrorCode PCReset_Deflation(PC pc)
704 {
705   PC_Deflation      *def = (PC_Deflation*)pc->data;
706   PetscErrorCode    ierr;
707 
708   PetscFunctionBegin;
709   ierr = VecDestroy(&def->work);CHKERRQ(ierr);
710   ierr = VecDestroyVecs(2,&def->workcoarse);CHKERRQ(ierr);
711   ierr = MatDestroy(&def->W);CHKERRQ(ierr);
712   ierr = MatDestroy(&def->Wt);CHKERRQ(ierr);
713   ierr = MatDestroy(&def->WtA);CHKERRQ(ierr);
714   ierr = MatDestroy(&def->WtAW);CHKERRQ(ierr);
715   ierr = KSPDestroy(&def->WtAWinv);CHKERRQ(ierr);
716   ierr = PCDestroy(&def->pc);CHKERRQ(ierr);
717   PetscFunctionReturn(0);
718 }
719 
720 /*
721    PCDestroy_Deflation - Destroys the private context for the Deflation preconditioner
722    that was created with PCCreate_Deflation().
723 
724    Input Parameter:
725 .  pc - the preconditioner context
726 
727    Application Interface Routine: PCDestroy()
728 */
729 static PetscErrorCode PCDestroy_Deflation(PC pc)
730 {
731   PetscErrorCode ierr;
732 
733   PetscFunctionBegin;
734   ierr = PCReset_Deflation(pc);CHKERRQ(ierr);
735   ierr = PetscFree(pc->data);CHKERRQ(ierr);
736   PetscFunctionReturn(0);
737 }
738 
739 static PetscErrorCode PCView_Deflation(PC pc,PetscViewer viewer)
740 {
741   PC_Deflation      *def = (PC_Deflation*)pc->data;
742   PetscBool         iascii;
743   PetscErrorCode    ierr;
744 
745   PetscFunctionBegin;
746   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
747   if (iascii) {
748     //if (cg->adaptiveconv) {
749     //  ierr = PetscViewerASCIIPrintf(viewer,"  DCG: using adaptive precision for inner solve with C=%.1e\n",cg->adaptiveconst);CHKERRQ(ierr);
750     //}
751     if (def->correct) {
752       ierr = PetscViewerASCIIPrintf(viewer,"  Using CP correction\n");CHKERRQ(ierr);
753     }
754     if (!def->nestedlvl) {
755       ierr = PetscViewerASCIIPrintf(viewer,"  Deflation space type: %s\n",PCDeflationSpaceTypes[def->spacetype]);CHKERRQ(ierr);
756       ierr = PetscViewerASCIIPrintf(viewer,"  DCG %s\n",def->extendsp ? "extended" : "truncated");CHKERRQ(ierr);
757     }
758 
759     ierr = PetscViewerASCIIPrintf(viewer,"--- Additional PC\n");CHKERRQ(ierr);
760     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
761     ierr = PCView(def->pc,viewer);CHKERRQ(ierr);
762     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
763 
764     ierr = PetscViewerASCIIPrintf(viewer,"--- Coarse solver\n");CHKERRQ(ierr);
765     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
766     ierr = KSPView(def->WtAWinv,viewer);CHKERRQ(ierr);
767     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
768   }
769   PetscFunctionReturn(0);
770 }
771 
772 static PetscErrorCode PCSetFromOptions_Deflation(PetscOptionItems *PetscOptionsObject,PC pc)
773 {
774   PC_Deflation      *def = (PC_Deflation*)pc->data;
775   PetscErrorCode    ierr;
776 
777   PetscFunctionBegin;
778   ierr = PetscOptionsHead(PetscOptionsObject,"Deflation options");CHKERRQ(ierr);
779   ierr = PetscOptionsEnum("-pc_deflation_compute_space","Compute deflation space","PCDeflationSetSpace",PCDeflationSpaceTypes,(PetscEnum)def->spacetype,(PetscEnum*)&def->spacetype,NULL);CHKERRQ(ierr);
780   ierr = PetscOptionsInt("-pc_deflation_compute_space_size","Set size of the deflation space to compute","PCDeflationSetSpace",def->spacesize,&def->spacesize,NULL);CHKERRQ(ierr);
781   ierr = PetscOptionsBool("-pc_deflation_space_extend","Extend deflation space instead of truncating (wavelets)","PCDeflation",def->extendsp,&def->extendsp,NULL);CHKERRQ(ierr);
782 //TODO add set function and fix manpages
783   ierr = PetscOptionsBool("-pc_deflation_initdef","Use only initialization step - Initdef","PCDeflation",def->init,&def->init,NULL);CHKERRQ(ierr);
784   ierr = PetscOptionsBool("-pc_deflation_correct","Add coarse problem correction Q to P","PCDeflation",def->correct,&def->correct,NULL);CHKERRQ(ierr);
785   ierr = PetscOptionsReal("-pc_deflation_correct_val","Set multiple of Q to use as coarse problem correction","PCDeflation",def->correctfact,&def->correctfact,NULL);CHKERRQ(ierr);
786   ierr = PetscOptionsInt("-pc_deflation_redfact","Reduction factor for coarse problem solution","PCDeflation",def->reductionfact,&def->reductionfact,NULL);CHKERRQ(ierr);
787   ierr = PetscOptionsInt("-pc_deflation_max_nested_lvl","Maximum of nested deflation levels","PCDeflation",def->maxnestedlvl,&def->maxnestedlvl,NULL);CHKERRQ(ierr);
788   ierr = PetscOptionsTail();CHKERRQ(ierr);
789   PetscFunctionReturn(0);
790 }
791 
792 /*MC
793      PCDEFLATION - Deflation preconditioner shifts part of the spectrum to zero (deflates)
794      or to a predefined value
795 
796    Options Database Key:
797 +    -pc_deflation_type <init,pre,post> - selects approach to deflation (default: pre)
798 -    -pc_jacobi_abs - use the absolute value of the diagonal entry
799 
800    Level: beginner
801 
802   Notes:
803     todo
804 
805 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
806            PCDeflationSetType(), PCDeflationSetSpace()
807 M*/
808 
809 PETSC_EXTERN PetscErrorCode PCCreate_Deflation(PC pc)
810 {
811   PC_Deflation   *def;
812   PetscErrorCode ierr;
813 
814   PetscFunctionBegin;
815   ierr     = PetscNewLog(pc,&def);CHKERRQ(ierr);
816   pc->data = (void*)def;
817 
818   def->init          = PETSC_FALSE;
819   def->correct       = PETSC_FALSE;
820   def->correctfact   = 1.0;
821   def->reductionfact = -1;
822   def->spacetype     = PC_DEFLATION_SPACE_HAAR;
823   def->spacesize     = 1;
824   def->extendsp      = PETSC_FALSE;
825   def->nestedlvl     = 0;
826   def->maxnestedlvl  = 0;
827 
828   /*
829       Set the pointers for the functions that are provided above.
830       Now when the user-level routines (such as PCApply(), PCDestroy(), etc.)
831       are called, they will automatically call these functions.  Note we
832       choose not to provide a couple of these functions since they are
833       not needed.
834   */
835   pc->ops->apply               = PCApply_Deflation;
836   pc->ops->applytranspose      = PCApply_Deflation;
837   pc->ops->presolve            = PCPreSolve_Deflation;
838   pc->ops->postsolve           = 0;
839   pc->ops->setup               = PCSetUp_Deflation;
840   pc->ops->reset               = PCReset_Deflation;
841   pc->ops->destroy             = PCDestroy_Deflation;
842   pc->ops->setfromoptions      = PCSetFromOptions_Deflation;
843   pc->ops->view                = PCView_Deflation;
844   pc->ops->applyrichardson     = 0;
845   pc->ops->applysymmetricleft  = 0;
846   pc->ops->applysymmetricright = 0;
847 
848   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetLvl_C",PCDeflationSetLvl_Deflation);CHKERRQ(ierr);
849   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetSpaceToCompute_C",PCDeflationSetSpaceToCompute_Deflation);CHKERRQ(ierr);
850   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetSpace_C",PCDeflationSetSpace_Deflation);CHKERRQ(ierr);
851   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetProjectionNullSpaceMat_C",PCDeflationSetProjectionNullSpaceMat_Deflation);CHKERRQ(ierr);
852   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetCoarseMat_C",PCDeflationSetCoarseMat_Deflation);CHKERRQ(ierr);
853   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCDeflationGetCoarseKSP_C",PCDeflationGetCoarseKSP_Deflation);CHKERRQ(ierr);
854   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetCoarseKSP_C",PCDeflationSetCoarseKSP_Deflation);CHKERRQ(ierr);
855   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCDeflationGetPC_C",PCDeflationGetPC_Deflation);CHKERRQ(ierr);
856   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCDeflationSetPC_C",PCDeflationSetPC_Deflation);CHKERRQ(ierr);
857   PetscFunctionReturn(0);
858 }
859 
860