xref: /petsc/src/ksp/pc/impls/gamg/gamg.c (revision 132e898922c2be89d54473fc59c64523e803026d)
1 /*
2  GAMG geometric-algebric multiogrid PC - Mark Adams 2011
3  */
4 #include <private/pcimpl.h>   /*I "petscpc.h" I*/
5 #include <../src/ksp/pc/impls/mg/mgimpl.h>                    /*I "petscpcmg.h" I*/
6 #include <../src/mat/impls/aij/seq/aij.h>
7 #include <../src/mat/impls/aij/mpi/mpiaij.h>
8 
9 /* Private context for the GAMG preconditioner */
10 typedef struct gamg_TAG {
11 gamg_TAG() : m_dim(0), m_Nlevels(-1), m_data(0)
12     {}
13   PetscInt       m_dim;
14   PetscInt       m_Nlevels;
15   PetscInt       m_data_sz;
16   PetscReal     *m_data; /* blocked vector of vertex data on fine grid (coordinates) */
17 } PC_GAMG;
18 
19 /* -----------------------------------------------------------------------------*/
20 #undef __FUNCT__
21 #define __FUNCT__ "PCReset_GAMG"
22 PetscErrorCode PCReset_GAMG(PC pc)
23 {
24   PetscErrorCode  ierr;
25   PC_MG           *mg = (PC_MG*)pc->data;
26   PC_GAMG         *pc_gamg = (PC_GAMG*)mg->innerctx;
27 
28   PetscFunctionBegin;
29   if (pc_gamg->m_data) {
30     ierr = PetscFree(pc_gamg->m_data);CHKERRQ(ierr);
31     pc_gamg->m_data = 0;
32   }
33   PetscFunctionReturn(0);
34 }
35 
36 /* -------------------------------------------------------------------------- */
37 /*
38    PCSetCoordinates_GAMG
39 
40    Input Parameter:
41    .  pc - the preconditioner context
42 */
43 #undef __FUNCT__
44 #define __FUNCT__ "PCSetCoordinates_GAMG"
45 PetscErrorCode PCSetCoordinates_GAMG( PC pc, const int ndm,
46                                       PetscReal *coords )
47 {
48   PC_MG           *mg = (PC_MG*)pc->data;
49   PC_GAMG         *pc_gamg = (PC_GAMG*)mg->innerctx;
50   PetscErrorCode ierr;  PetscInt bs, my0, tt;
51 
52   PetscFunctionBegin;
53   Mat mat = pc->pmat;
54   ierr = MatGetBlockSize( mat, &bs );               CHKERRQ( ierr );
55   ierr = MatGetOwnershipRange( mat, &my0, &tt ); CHKERRQ(ierr);
56   const PetscInt arrsz = (tt-my0)/bs*ndm;
57 
58   // put coordinates
59   if ( pc_gamg->m_data==0 || pc_gamg->m_data_sz != arrsz ) {
60     if( pc_gamg->m_data != 0 ) {
61       ierr = PetscFree( pc_gamg->m_data );  CHKERRQ(ierr);
62     }
63     ierr = PetscMalloc( (arrsz+1)*sizeof(double), &pc_gamg->m_data ); CHKERRQ(ierr);
64   }
65 
66   /* copy data in */
67   for(tt=0;tt<arrsz;tt++){
68     pc_gamg->m_data[tt] = coords[tt];
69   }
70   pc_gamg->m_data_sz = arrsz;
71   pc_gamg->m_dim = ndm;
72 
73   PetscFunctionReturn(0);
74 }
75 
76 /* -------------------------------------------------------------------------- */
77 /*
78    createCrsOp
79 
80    Input Parameter:
81    . Amat - matrix on this fine level
82    . P_out - prolongation operator to the next level
83    . Acrs - coarse matrix that is created
84 */
85 #undef __FUNCT__
86 #define __FUNCT__ "createCrsOp"
87 PetscErrorCode createCrsOp( Mat Amat, Mat P_inout, Mat *Acrs )
88 {
89   PetscErrorCode ierr;
90 
91   PetscFunctionBegin;
92   Mat H;
93   ierr = MatPtAP( Amat, P_inout, MAT_INITIAL_MATRIX, 2.0, &H); CHKERRQ(ierr);
94   *Acrs = H;
95 
96   PetscFunctionReturn(0);
97 }
98 
99 /* -------------------------------------------------------------------------- */
100 /*
101    PCSetUp_GAMG - Prepares for the use of the GAMG preconditioner
102                     by setting data structures and options.
103 
104    Input Parameter:
105 .  pc - the preconditioner context
106 
107    Application Interface Routine: PCSetUp()
108 
109    Notes:
110    The interface routine PCSetUp() is not usually called directly by
111    the user, but instead is called by PCApply() if necessary.
112 */
113 extern PetscErrorCode PCSetFromOptions_MG(PC);
114 extern PetscErrorCode PCReset_MG(PC);
115 extern PetscErrorCode createProlongation( Mat, Mat *, PetscReal [], PetscReal **, const PetscInt);
116 #undef __FUNCT__
117 #define __FUNCT__ "PCSetUp_GAMG"
118 PetscErrorCode PCSetUp_GAMG( PC pc )
119 {
120   PetscErrorCode  ierr;
121   PC_MG           *mg = (PC_MG*)pc->data;
122   PC_GAMG         *pc_gamg = (PC_GAMG*)mg->innerctx;
123   Mat              Amat = pc->mat, Pmat = pc->pmat;
124   PetscBool        isSeq, isMPI;
125   PetscInt         fine_level, level, level1, M, N, bs, lidx;
126   MPI_Comm         wcomm = ((PetscObject)pc)->comm;
127 
128   PetscFunctionBegin;
129   if (pc->setupcalled){
130     /* no state data in GAMG to destroy (now) */
131     ierr = PCReset_MG(pc);CHKERRQ(ierr);
132   }
133   if ( pc_gamg->m_data==0 ) {
134     SETERRQ(wcomm,PETSC_ERR_SUP,"PCSetUp_GAMG called before PCSetCoordinates");
135   }
136   /* setup special features of PCGAMG */
137   ierr = PetscTypeCompare((PetscObject) Amat, MATSEQAIJ, &isSeq);CHKERRQ(ierr);
138   ierr = PetscTypeCompare((PetscObject) Amat, MATMPIAIJ, &isMPI);CHKERRQ(ierr);
139   if (isMPI) {
140   } else if (isSeq) {
141   } else SETERRQ1(wcomm,PETSC_ERR_ARG_WRONG, "Matrix type '%s' cannot be used with GAMG. GAMG can only handle AIJ matrices.",((PetscObject)Amat)->type_name);
142 
143   /* GAMG requires input of fine-grid matrix. It determines nlevels. */
144   ierr = MatGetSize( Amat, &M, &N );CHKERRQ(ierr);
145   ierr = MatGetBlockSize( Amat, &bs ); CHKERRQ(ierr);
146   if(bs!=1) SETERRQ1(wcomm,PETSC_ERR_ARG_WRONG, "GAMG only supports scalar prblems bs = '%d'.",bs);
147 
148   /* Get A_i and R_i */
149 #define GAMG_MAXLEVELS 10
150   Mat Aarr[GAMG_MAXLEVELS], Rarr[GAMG_MAXLEVELS];  PetscReal *coarse_crds = 0, *crds = pc_gamg->m_data;
151   for (level=0, Aarr[0] = Pmat; level < GAMG_MAXLEVELS-1; level++ ){
152     ierr = MatGetSize( Aarr[level], &M, &N );CHKERRQ(ierr);
153     if( M < 100 ) { /* hard wire this for now */
154       break;
155     }
156     level1 = level + 1;
157     ierr = createProlongation( Aarr[level], &Rarr[level1], crds, &coarse_crds, pc_gamg->m_dim );
158     CHKERRQ(ierr);
159     if(level==0)  Aarr[0] = Amat; /* use Pmat for finest level setup, but use mat for solver */
160     ierr = createCrsOp( Aarr[level], Rarr[level1], &Aarr[level1] ); CHKERRQ(ierr);
161     ierr = PetscFree( crds ); CHKERRQ( ierr );
162     crds = coarse_crds;
163   }
164   if( coarse_crds != 0 ) {
165     ierr = PetscFree( coarse_crds ); CHKERRQ( ierr );
166   }
167   pc_gamg->m_data = 0; /* destroyed coordinate data */
168   pc_gamg->m_Nlevels = level + 1;
169   fine_level = level;
170   ierr = PCMGSetLevels(pc,pc_gamg->m_Nlevels,PETSC_NULL);CHKERRQ(ierr);
171 
172   /* set default smoothers */
173   PetscReal emax = 2.0, emin;
174   for (level=1; level<=fine_level; level++){
175     KSP smoother; PC subpc;
176     ierr = PCMGGetSmoother(pc,level,&smoother);CHKERRQ(ierr);
177     ierr = KSPSetType(smoother,KSPCHEBYCHEV);CHKERRQ(ierr);
178     emin = emax/5.0;
179     ierr = KSPGetPC(smoother,&subpc);CHKERRQ(ierr);
180     ierr = PCSetType(subpc,PCJACOBI);CHKERRQ(ierr);
181     ierr = KSPChebychevSetEigenvalues(smoother, emax, emin);CHKERRQ(ierr); /* need auto !!!!*/
182   }
183   ierr = PCSetFromOptions_MG(pc); CHKERRQ(ierr); /* should be called in PCSetFromOptions_GAMG(), but cannot be called prior to PCMGSetLevels() */
184   {
185     PetscBool galerkin;
186     ierr = PCMGGetGalerkin( pc,  &galerkin); CHKERRQ(ierr);
187     if(galerkin){
188       SETERRQ(wcomm,PETSC_ERR_ARG_WRONG, "GAMG does galerkin manually so it must not be used in PC_MG.");
189     }
190   }
191   /* create coarse level and the interpolation between the levels */
192   for (level=0,lidx=pc_gamg->m_Nlevels-1; level<fine_level; level++,lidx--){
193     level1 = level + 1;
194     /* PetscInt MM,NN; */
195     /* ierr = MatGetSize( Rarr[lidx], &MM, &NN );CHKERRQ(ierr); */
196     /* PetscPrintf(PETSC_COMM_WORLD,"%s Set P(%d,%d) on level %d (%d)\n",__FUNCT__,MM,NN,level1,lidx); */
197     ierr = PCMGSetInterpolation(pc,level1,Rarr[lidx]);CHKERRQ(ierr);
198     if(!true) {
199       PetscViewer        viewer;
200       ierr = PetscViewerASCIIOpen(PETSC_COMM_SELF, "Rmat.m", &viewer);  CHKERRQ(ierr);
201       ierr = PetscViewerSetFormat( viewer, PETSC_VIEWER_ASCII_MATLAB);  CHKERRQ(ierr);
202       ierr = MatView(Rarr[level1],viewer);CHKERRQ(ierr);
203       ierr = PetscViewerDestroy( &viewer );
204     }
205     KSP smoother;
206     ierr = PCMGGetSmoother(pc,level,&smoother); CHKERRQ(ierr);
207     ierr = KSPSetOperators( smoother, Aarr[lidx], Aarr[lidx], DIFFERENT_NONZERO_PATTERN );
208     CHKERRQ(ierr);
209     /* ierr = MatGetSize( Aarr[lidx], &MM, &NN ); CHKERRQ(ierr); */
210     /* PetscPrintf(PETSC_COMM_WORLD,"%s Set A(%d,%d) on level %d (%d)\n",__FUNCT__,MM,NN,level,lidx); */
211   }
212   { /* fine level (no P) */
213     KSP smoother;
214     ierr = PCMGGetSmoother(pc,fine_level,&smoother); CHKERRQ(ierr);
215     ierr = KSPSetOperators( smoother, Aarr[0], Aarr[0], DIFFERENT_NONZERO_PATTERN );
216     CHKERRQ(ierr);
217     /* PetscInt MM,NN; */
218     /* ierr = MatGetSize( Aarr[0], &MM, &NN );CHKERRQ(ierr); */
219     /* PetscPrintf(PETSC_COMM_WORLD,"%s Set A(%d,%d) on level %d (%d)\n",__FUNCT__,MM,NN,fine_level,0); */
220   }
221 
222   /* setupcalled is set to 0 so that MG is setup from scratch */
223   pc->setupcalled = 0;
224   ierr = PCSetUp_MG(pc);CHKERRQ(ierr);
225   PetscFunctionReturn(0);
226 }
227 
228 /* -------------------------------------------------------------------------- */
229 /*
230    PCDestroy_GAMG - Destroys the private context for the GAMG preconditioner
231    that was created with PCCreate_GAMG().
232 
233    Input Parameter:
234 .  pc - the preconditioner context
235 
236    Application Interface Routine: PCDestroy()
237 */
238 #undef __FUNCT__
239 #define __FUNCT__ "PCDestroy_GAMG"
240 PetscErrorCode PCDestroy_GAMG(PC pc)
241 {
242   PetscErrorCode  ierr;
243   PC_MG           *mg = (PC_MG*)pc->data;
244   PC_GAMG         *pc_gamg= (PC_GAMG*)mg->innerctx;
245 
246   PetscFunctionBegin;
247   ierr = PCReset_GAMG(pc);CHKERRQ(ierr);
248   if (pc_gamg->m_data) {
249     ierr = PetscFree(pc_gamg->m_data);CHKERRQ(ierr);
250   }
251   ierr = PetscFree(pc_gamg);CHKERRQ(ierr);
252   ierr = PCDestroy_MG(pc);CHKERRQ(ierr);
253   PetscFunctionReturn(0);
254 }
255 
256 #undef __FUNCT__
257 #define __FUNCT__ "PCSetFromOptions_GAMG"
258 PetscErrorCode PCSetFromOptions_GAMG(PC pc)
259 {
260   /* PetscErrorCode  ierr; */
261   /* PC_MG           *mg = (PC_MG*)pc->data; */
262   /* PC_GAMG         *pc_gamg = (PC_GAMG*)mg->innerctx; */
263   /* MPI_Comm        comm = ((PetscObject)pc)->comm; */
264 
265   PetscFunctionBegin;
266   PetscFunctionReturn(0);
267 }
268 
269 /* -------------------------------------------------------------------------- */
270 /*
271  PCCreate_GAMG - Creates a GAMG preconditioner context, PC_GAMG
272 
273    Input Parameter:
274 .  pc - the preconditioner context
275 
276    Application Interface Routine: PCCreate()
277 
278   */
279  /* MC
280      PCGAMG - Use algebraic multigrid preconditioning. This preconditioner requires you provide
281        fine grid discretization matrix and coordinates on the fine grid.
282 
283    Options Database Key:
284    Multigrid options(inherited)
285 +  -pc_mg_cycles <1>: 1 for V cycle, 2 for W-cycle (MGSetCycles)
286 .  -pc_mg_smoothup <1>: Number of post-smoothing steps (MGSetNumberSmoothUp)
287 .  -pc_mg_smoothdown <1>: Number of pre-smoothing steps (MGSetNumberSmoothDown)
288    -pc_mg_type <multiplicative>: (one of) additive multiplicative full cascade kascade
289    GAMG options:
290 
291    Level: intermediate
292   Concepts: multigrid
293 
294 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, PCMGType,
295            PCMGSetLevels(), PCMGGetLevels(), PCMGSetType(), MPSetCycles(), PCMGSetNumberSmoothDown(),
296            PCMGSetNumberSmoothUp(), PCMGGetCoarseSolve(), PCMGSetResidual(), PCMGSetInterpolation(),
297            PCMGSetRestriction(), PCMGGetSmoother(), PCMGGetSmootherUp(), PCMGGetSmootherDown(),
298            PCMGSetCyclesOnLevel(), PCMGSetRhs(), PCMGSetX(), PCMGSetR()
299 M */
300 
301 EXTERN_C_BEGIN
302 #undef __FUNCT__
303 #define __FUNCT__ "PCCreate_GAMG"
304 PetscErrorCode  PCCreate_GAMG(PC pc)
305 {
306   PetscErrorCode  ierr;
307   PC_GAMG         *pc_gamg;
308   PC_MG           *mg;
309 
310   PetscFunctionBegin;
311   /* PCGAMG is an inherited class of PCMG. Initialize pc as PCMG */
312   ierr = PCSetType(pc,PCMG);CHKERRQ(ierr); /* calls PCCreate_MG() and MGCreate_Private() */
313   ierr = PetscObjectChangeTypeName((PetscObject)pc,PCGAMG);CHKERRQ(ierr);
314 
315   /* create a supporting struct and attach it to pc */
316   ierr = PetscNewLog(pc,PC_GAMG,&pc_gamg);CHKERRQ(ierr);
317   mg = (PC_MG*)pc->data;
318   mg->innerctx = pc_gamg;
319 
320   pc_gamg->m_data     = 0;
321   pc_gamg->m_Nlevels    = -1;
322 
323   /* overwrite the pointers of PCMG by the functions of PCGAMG */
324   pc->ops->setfromoptions = PCSetFromOptions_GAMG;
325   pc->ops->setup          = PCSetUp_GAMG;
326   pc->ops->reset          = PCReset_GAMG;
327   pc->ops->destroy        = PCDestroy_GAMG;
328 
329   ierr = PetscObjectComposeFunctionDynamic( (PetscObject)pc,
330 					    "PCSetCoordinates_C",
331 					    "PCSetCoordinates_GAMG",
332 					    PCSetCoordinates_GAMG);CHKERRQ(ierr);
333   PetscFunctionReturn(0);
334 }
335 EXTERN_C_END
336