xref: /petsc/src/ksp/pc/impls/hmg/hmg.c (revision 4fea3358ad0a88178037f832c05a8ae6ae5e4c1e)
1 #include <petscdm.h>
2 #include <petscctable.h>
3 #include <petsc/private/matimpl.h>
4 #include <petsc/private/pcmgimpl.h>
5 #include <petsc/private/pcimpl.h>      /*I "petscpc.h" I*/
6 
7 typedef struct {
8   PC               innerpc;            /* A MG inner PC (Hypre or PCGAMG) to setup interpolations and coarse operators  */
9   char*            innerpctype;        /* PCGAMG or PCHYPRE */
10   PetscBool        reuseinterp;        /* A flag indicates if or not to reuse the interpolations */
11   PetscBool        subcoarsening;      /* If or not to use a subspace-based coarsening algorithm */
12   PetscBool        usematmaij;         /* If or not to use MatMAIJ for saving memory */
13   PetscInt         component;          /* Which subspace is used for the subspace-based coarsening algorithm? */
14 } PC_HMG;
15 
16 PetscErrorCode PCSetFromOptions_HMG(PetscOptionItems*,PC);
17 PetscErrorCode PCReset_MG(PC);
18 
19 static PetscErrorCode PCHMGExtractSubMatrix_Private(Mat pmat,Mat *submat,MatReuse reuse,PetscInt component,PetscInt blocksize)
20 {
21   IS             isrow;
22   PetscErrorCode ierr;
23   PetscInt       rstart,rend;
24   MPI_Comm       comm;
25 
26   PetscFunctionBegin;
27   ierr = PetscObjectGetComm((PetscObject)pmat,&comm);CHKERRQ(ierr);
28   if (component>=blocksize) SETERRQ2(comm,PETSC_ERR_ARG_INCOMP,"Component %d should be less than block size %d \n",component,blocksize);
29   ierr = MatGetOwnershipRange(pmat,&rstart,&rend);CHKERRQ(ierr);
30   if ((rend-rstart)%blocksize != 0) SETERRQ3(comm,PETSC_ERR_ARG_INCOMP,"Block size %d is inconsisent for [%d, %d) \n",blocksize,rstart,rend);
31   ierr = ISCreateStride(comm,(rend-rstart)/blocksize,rstart+component,blocksize,&isrow);
32   ierr = MatCreateSubMatrix(pmat,isrow,isrow,reuse,submat);CHKERRQ(ierr);
33   ierr = ISDestroy(&isrow);CHKERRQ(ierr);
34   PetscFunctionReturn(0);
35 }
36 
37 static PetscErrorCode PCHMGExpandInterpolation_Private(Mat subinterp, Mat *interp, PetscInt blocksize)
38 {
39   PetscInt              subrstart,subrend,subrowsize,subcolsize,subcstart,subcend,rowsize,colsize;
40   PetscInt              subrow,row,nz,*d_nnz,*o_nnz,i,j,dnz,onz,max_nz,*indices;
41   const PetscInt        *idx;
42   const PetscScalar     *values;
43   PetscErrorCode        ierr;
44   MPI_Comm              comm;
45 
46   PetscFunctionBegin;
47   ierr = PetscObjectGetComm((PetscObject)subinterp,&comm);CHKERRQ(ierr);
48   ierr = MatGetOwnershipRange(subinterp,&subrstart,&subrend);CHKERRQ(ierr);
49   subrowsize = subrend-subrstart;
50   rowsize = subrowsize*blocksize;
51   ierr = PetscCalloc2(rowsize,&d_nnz,rowsize,&o_nnz);CHKERRQ(ierr);
52   ierr = MatGetOwnershipRangeColumn(subinterp,&subcstart,&subcend);CHKERRQ(ierr);
53   subcolsize = subcend - subcstart;
54   colsize    = subcolsize*blocksize;
55   max_nz = 0;
56   for (subrow=subrstart;subrow<subrend;subrow++) {
57     ierr = MatGetRow(subinterp,subrow,&nz,&idx,NULL);CHKERRQ(ierr);
58     if (max_nz<nz) max_nz = nz;
59     dnz = 0; onz = 0;
60     for (i=0;i<nz;i++) {
61       if(idx[i]>=subcstart && idx[i]<subcend) dnz++;
62       else onz++;
63     }
64     for (i=0;i<blocksize;i++) {
65       d_nnz[(subrow-subrstart)*blocksize+i] = dnz;
66       o_nnz[(subrow-subrstart)*blocksize+i] = onz;
67     }
68     ierr = MatRestoreRow(subinterp,subrow,&nz,&idx,NULL);CHKERRQ(ierr);
69   }
70   ierr = MatCreateAIJ(comm,rowsize,colsize,PETSC_DETERMINE,PETSC_DETERMINE,0,d_nnz,0,o_nnz,interp);CHKERRQ(ierr);
71   ierr = MatSetOption(*interp,MAT_IGNORE_OFF_PROC_ENTRIES,PETSC_TRUE);CHKERRQ(ierr);
72   ierr = MatSetOption(*interp,MAT_IGNORE_ZERO_ENTRIES,PETSC_TRUE);CHKERRQ(ierr);
73   ierr = MatSetOption(*interp,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
74   ierr = MatSetFromOptions(*interp);CHKERRQ(ierr);
75 
76   ierr = MatSetUp(*interp);CHKERRQ(ierr);
77   ierr = PetscFree2(d_nnz,o_nnz);CHKERRQ(ierr);
78   ierr = PetscMalloc1(max_nz,&indices);CHKERRQ(ierr);
79   for (subrow=subrstart; subrow<subrend; subrow++) {
80     ierr = MatGetRow(subinterp,subrow,&nz,&idx,&values);CHKERRQ(ierr);
81     for (i=0;i<blocksize;i++) {
82       row = subrow*blocksize+i;
83       for (j=0;j<nz;j++) {
84         indices[j] = idx[j]*blocksize+i;
85       }
86       ierr = MatSetValues(*interp,1,&row,nz,indices,values,INSERT_VALUES);CHKERRQ(ierr);
87     }
88     ierr = MatRestoreRow(subinterp,subrow,&nz,&idx,&values);CHKERRQ(ierr);
89   }
90   ierr = PetscFree(indices);CHKERRQ(ierr);
91   ierr = MatAssemblyBegin(*interp,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
92   ierr = MatAssemblyEnd(*interp,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
93   PetscFunctionReturn(0);
94 }
95 
96 PetscErrorCode PCSetUp_HMG(PC pc)
97 {
98   PetscErrorCode     ierr;
99   Mat                PA, submat;
100   PC_MG              *mg   = (PC_MG*)pc->data;
101   PC_HMG             *hmg   = (PC_HMG*) mg->innerctx;
102   MPI_Comm           comm;
103   PetscInt           level;
104   PetscInt           num_levels;
105   Mat                *operators,*interpolations;
106   PetscInt           blocksize;
107   const char         *prefix;
108   PCMGGalerkinType   galerkin;
109 
110   PetscFunctionBegin;
111   ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr);
112   if (pc->setupcalled) {
113    if (hmg->reuseinterp) {
114      /* If we did not use Galerkin in the last call or we have a different sparsity pattern now,
115       * we have to build from scratch
116       * */
117      ierr = PCMGGetGalerkin(pc,&galerkin);CHKERRQ(ierr);
118      if (galerkin == PC_MG_GALERKIN_NONE || pc->flag != SAME_NONZERO_PATTERN) pc->setupcalled = PETSC_FALSE;
119      ierr = PCMGSetGalerkin(pc,PC_MG_GALERKIN_PMAT);CHKERRQ(ierr);
120      ierr = PCSetUp_MG(pc);CHKERRQ(ierr);
121      PetscFunctionReturn(0);
122     } else {
123      ierr = PCReset_MG(pc);CHKERRQ(ierr);
124      pc->setupcalled = PETSC_FALSE;
125     }
126   }
127 
128   /* Create an inner PC (GAMG or HYPRE) */
129   if (!hmg->innerpc) {
130     ierr = PCCreate(comm,&hmg->innerpc);CHKERRQ(ierr);
131     /* If users do not set an inner pc type, we need to set a default value */
132     if (!hmg->innerpctype) {
133     /* If hypre is available, use hypre, otherwise, use gamg */
134 #if PETSC_HAVE_HYPRE
135       ierr = PetscStrallocpy(PCHYPRE,&(hmg->innerpctype));CHKERRQ(ierr);
136 #else
137       ierr = PetscStrallocpy(PCGAMG,&(hmg->innerpctype));CHKERRQ(ierr);
138 #endif
139     }
140     ierr = PCSetType(hmg->innerpc,hmg->innerpctype);CHKERRQ(ierr);
141   }
142   ierr = PCGetOperators(pc,NULL,&PA);CHKERRQ(ierr);
143   /* Users need to correctly set a block size of matrix in order to use subspace coarsening */
144   ierr = MatGetBlockSize(PA,&blocksize);CHKERRQ(ierr);
145   if (blocksize<=1) hmg->subcoarsening = PETSC_FALSE;
146   /* Extract a submatrix for constructing subinterpolations */
147   if (hmg->subcoarsening) {
148     ierr = PCHMGExtractSubMatrix_Private(PA,&submat,MAT_INITIAL_MATRIX,hmg->component,blocksize);CHKERRQ(ierr);
149     PA = submat;
150   }
151   ierr = PCSetOperators(hmg->innerpc,PA,PA);CHKERRQ(ierr);
152   if (hmg->subcoarsening) {
153    ierr = MatDestroy(&PA);CHKERRQ(ierr);
154   }
155   /* Setup inner PC correctly. During this step, matrix will be coarsened */
156   ierr = PCSetUseAmat(hmg->innerpc,PETSC_FALSE);CHKERRQ(ierr);
157   ierr = PetscObjectGetOptionsPrefix((PetscObject)pc,&prefix);CHKERRQ(ierr);
158   ierr = PetscObjectSetOptionsPrefix((PetscObject)hmg->innerpc,prefix);CHKERRQ(ierr);
159   ierr = PetscObjectAppendOptionsPrefix((PetscObject)hmg->innerpc,"hmg_inner_");CHKERRQ(ierr);
160   ierr = PCSetFromOptions(hmg->innerpc);CHKERRQ(ierr);
161   ierr = PCSetUp(hmg->innerpc);
162 
163   /* Obtain interpolations IN PLACE. For BoomerAMG, (I,J,data) is reused to avoid memory overhead */
164   ierr = PCGetInterpolations(hmg->innerpc,&num_levels,&interpolations);CHKERRQ(ierr);
165   /* We can reuse the coarse operators when we do the full space coarsening */
166   if (!hmg->subcoarsening) {
167     ierr = PCGetCoarseOperators(hmg->innerpc,&num_levels,&operators);CHKERRQ(ierr);
168   }
169 
170   ierr = PCDestroy(&hmg->innerpc);CHKERRQ(ierr);
171   hmg->innerpc = 0;
172   ierr = PCMGSetLevels_MG(pc,num_levels,NULL);CHKERRQ(ierr);
173   /* Set coarse matrices and interpolations to PCMG */
174   for (level=num_levels-1; level>0; level--) {
175     Mat P=0, pmat=0;
176     Vec b, x,r;
177     if (hmg->subcoarsening) {
178       if (hmg->usematmaij) {
179         ierr = MatCreateMAIJ(interpolations[level-1],blocksize,&P);CHKERRQ(ierr);
180         ierr = MatDestroy(&interpolations[level-1]);CHKERRQ(ierr);
181       } else {
182         /* Grow interpolation. In the future, we should use MAIJ */
183         ierr = PCHMGExpandInterpolation_Private(interpolations[level-1],&P,blocksize);CHKERRQ(ierr);
184         ierr = MatDestroy(&interpolations[level-1]);CHKERRQ(ierr);
185       }
186     } else {
187       P = interpolations[level-1];
188     }
189     ierr = MatCreateVecs(P,&b,&r);CHKERRQ(ierr);
190     ierr = PCMGSetInterpolation(pc,level,P);CHKERRQ(ierr);
191     ierr = PCMGSetRestriction(pc,level,P);CHKERRQ(ierr);
192     ierr = MatDestroy(&P);CHKERRQ(ierr);
193     /* We reuse the matrices when we do not do subspace coarsening */
194     if ((level-1)>=0 && !hmg->subcoarsening) {
195       pmat = operators[level-1];
196       ierr = PCMGSetOperators(pc,level-1,pmat,pmat);CHKERRQ(ierr);
197       ierr = MatDestroy(&pmat);CHKERRQ(ierr);
198     }
199     ierr = PCMGSetRhs(pc,level-1,b);CHKERRQ(ierr);
200 
201     ierr = PCMGSetR(pc,level,r);CHKERRQ(ierr);
202     ierr = VecDestroy(&r);CHKERRQ(ierr);
203 
204     ierr = VecDuplicate(b,&x);CHKERRQ(ierr);
205     ierr = PCMGSetX(pc,level-1,x);CHKERRQ(ierr);
206     ierr = VecDestroy(&x);CHKERRQ(ierr);
207     ierr = VecDestroy(&b);CHKERRQ(ierr);
208   }
209   ierr = PetscFree(interpolations);CHKERRQ(ierr);
210   if (!hmg->subcoarsening) {
211     ierr = PetscFree(operators);CHKERRQ(ierr);
212   }
213   /* Turn Galerkin off when we already have coarse operators */
214   ierr = PCMGSetGalerkin(pc,hmg->subcoarsening ? PC_MG_GALERKIN_PMAT:PC_MG_GALERKIN_NONE);CHKERRQ(ierr);
215   ierr = PCSetDM(pc,NULL);CHKERRQ(ierr);
216   ierr = PCSetUseAmat(pc,PETSC_FALSE);CHKERRQ(ierr);
217   ierr = PetscObjectOptionsBegin((PetscObject)pc);CHKERRQ(ierr);
218   ierr = PCSetFromOptions_MG(PetscOptionsObject,pc);CHKERRQ(ierr); /* should be called in PCSetFromOptions_HMG(), but cannot be called prior to PCMGSetLevels() */
219   ierr = PetscOptionsEnd();CHKERRQ(ierr);
220   ierr = PCSetUp_MG(pc);CHKERRQ(ierr);
221   PetscFunctionReturn(0);
222 }
223 
224 PetscErrorCode PCDestroy_HMG(PC pc)
225 {
226   PetscErrorCode ierr;
227   PC_MG          *mg  = (PC_MG*)pc->data;
228   PC_HMG         *hmg = (PC_HMG*) mg->innerctx;
229 
230   PetscFunctionBegin;
231   ierr = PCDestroy(&hmg->innerpc);CHKERRQ(ierr);
232   ierr = PetscFree(hmg->innerpctype);CHKERRQ(ierr);
233   ierr = PetscFree(hmg);CHKERRQ(ierr);
234   ierr = PCDestroy_MG(pc);CHKERRQ(ierr);
235 
236   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCHMGSetReuseInterpolation_C",NULL);CHKERRQ(ierr);
237   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCHMGSetUseSubspaceCoarsening_C",NULL);CHKERRQ(ierr);
238   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCHMGSetInnerPCType_C",NULL);CHKERRQ(ierr);
239   PetscFunctionReturn(0);
240 }
241 
242 PetscErrorCode PCView_HMG(PC pc,PetscViewer viewer)
243 {
244   PC_MG          *mg = (PC_MG*)pc->data;
245   PC_HMG         *hmg = (PC_HMG*) mg->innerctx;
246   PetscErrorCode ierr;
247   PetscBool      iascii;
248 
249   PetscFunctionBegin;
250   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
251   if (iascii) {
252     ierr = PetscViewerASCIIPrintf(viewer," Reuse interpolation: %s\n",hmg->reuseinterp? "true":"false");CHKERRQ(ierr);
253     ierr = PetscViewerASCIIPrintf(viewer," Use subspace coarsening: %s\n",hmg->subcoarsening? "true":"false");CHKERRQ(ierr);
254     ierr = PetscViewerASCIIPrintf(viewer," Coarsening component: %d \n",hmg->component);CHKERRQ(ierr);
255     ierr = PetscViewerASCIIPrintf(viewer," Use MatMAIJ: %s \n",hmg->usematmaij? "true":"false");CHKERRQ(ierr);
256     ierr = PetscViewerASCIIPrintf(viewer," Inner PC type: %s \n",hmg->innerpctype);CHKERRQ(ierr);
257   }
258   ierr = PCView_MG(pc,viewer);CHKERRQ(ierr);
259   PetscFunctionReturn(0);
260 }
261 
262 PetscErrorCode PCSetFromOptions_HMG(PetscOptionItems *PetscOptionsObject,PC pc)
263 {
264   PetscErrorCode ierr;
265   PC_MG          *mg = (PC_MG*)pc->data;
266   PC_HMG         *hmg = (PC_HMG*) mg->innerctx;
267 
268   PetscFunctionBegin;
269   ierr = PetscOptionsHead(PetscOptionsObject,"HMG");CHKERRQ(ierr);
270   ierr = PetscOptionsBool("-pc_hmg_reuse_interpolation","Reuse the interpolation operators when possible (cheaper, weaker when matrix entries change a lot)","None",hmg->reuseinterp,&hmg->reuseinterp,NULL);CHKERRQ(ierr);
271   ierr = PetscOptionsBool("-pc_hmg_use_subspace_coarsening","Use the subspace coarsening to compute the interpolations","None",hmg->subcoarsening,&hmg->subcoarsening,NULL);CHKERRQ(ierr);
272   ierr = PetscOptionsBool("-pc_hmg_use_matmaij","Use MatMAIJ store interpolation for saving memory","None",hmg->usematmaij,&hmg->usematmaij,NULL);CHKERRQ(ierr);
273   ierr = PetscOptionsInt("-pc_hmg_coarsening_component","Which component is chosen for the subspace-based coarsening algorithm","None",hmg->component,&hmg->component,NULL);CHKERRQ(ierr);
274   ierr = PetscOptionsTail();CHKERRQ(ierr);
275   PetscFunctionReturn(0);
276 }
277 
278 static PetscErrorCode PCHMGSetReuseInterpolation_HMG(PC pc, PetscBool reuse)
279 {
280   PC_MG          *mg  = (PC_MG*)pc->data;
281   PC_HMG         *hmg = (PC_HMG*) mg->innerctx;
282 
283   PetscFunctionBegin;
284   hmg->reuseinterp = reuse;
285   PetscFunctionReturn(0);
286 }
287 
288 /*MC
289    PCHMGSetReuseInterpolation - Reuse interpolation matrices in HMG
290 
291    Logically Collective on PC
292 
293    Input Parameters:
294 +  pc - the HMG context
295 -  reuse - True indicates that HMG will reuse the interpolations
296 
297    Options Database Keys:
298 .  -pc_hmg_reuse_interpolation <true | false> - Whether or not to reuse the interpolations. If true, it potentially save the compute time.
299 
300    Level: beginner
301 
302 .keywords: HMG, multigrid, interpolation, reuse, set
303 
304 .seealso: PCHMG
305 M*/
306 PetscErrorCode PCHMGSetReuseInterpolation(PC pc, PetscBool reuse)
307 {
308   PetscErrorCode ierr;
309 
310   PetscFunctionBegin;
311   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
312   ierr = PetscUseMethod(pc,"PCHMGSetReuseInterpolation_C",(PC,PetscBool),(pc,reuse));CHKERRQ(ierr);
313   PetscFunctionReturn(0);
314 }
315 
316 static PetscErrorCode PCHMGSetUseSubspaceCoarsening_HMG(PC pc, PetscBool subspace)
317 {
318   PC_MG          *mg  = (PC_MG*)pc->data;
319   PC_HMG         *hmg = (PC_HMG*) mg->innerctx;
320 
321   PetscFunctionBegin;
322   hmg->subcoarsening = subspace;
323   PetscFunctionReturn(0);
324 }
325 
326 /*MC
327    PCHMGSetUseSubspaceCoarsening - Use subspace coarsening in HMG
328 
329    Logically Collective on PC
330 
331    Input Parameters:
332 +  pc - the HMG context
333 -  reuse - True indicates that HMG will use the subspace coarsening
334 
335    Options Database Keys:
336 .  -pc_hmg_use_subspace_coarsening  <true | false> - Whether or not to use subspace coarsening (that is, coarsen a submatrix).
337 
338    Level: beginner
339 
340 .keywords: HMG, multigrid, interpolation, subspace, coarsening
341 
342 .seealso: PCHMG
343 M*/
344 PetscErrorCode PCHMGSetUseSubspaceCoarsening(PC pc, PetscBool subspace)
345 {
346   PetscErrorCode ierr;
347 
348   PetscFunctionBegin;
349   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
350   ierr = PetscUseMethod(pc,"PCHMGSetUseSubspaceCoarsening_C",(PC,PetscBool),(pc,subspace));CHKERRQ(ierr);
351   PetscFunctionReturn(0);
352 }
353 
354 static PetscErrorCode PCHMGSetInnerPCType_HMG(PC pc, PCType type)
355 {
356   PC_MG           *mg  = (PC_MG*)pc->data;
357   PC_HMG          *hmg = (PC_HMG*) mg->innerctx;
358   PetscErrorCode  ierr;
359 
360   PetscFunctionBegin;
361   ierr = PetscStrallocpy(type,&(hmg->innerpctype));CHKERRQ(ierr);
362   PetscFunctionReturn(0);
363 }
364 
365 /*MC
366    PCHMGSetInnerPCType - Set an inner PC type
367 
368    Logically Collective on PC
369 
370    Input Parameters:
371 +  pc - the HMG context
372 -  type - <hypre, gamg> coarsening algorithm
373 
374    Options Database Keys:
375 .  -hmg_inner_pc_type <hypre, gamg> - What method is used to coarsen matrix
376 
377    Level: beginner
378 
379 .keywords: HMG, multigrid, interpolation, coarsening
380 
381 .seealso: PCHMG, PCType
382 M*/
383 PetscErrorCode PCHMGSetInnerPCType(PC pc, PCType type)
384 {
385   PetscErrorCode  ierr;
386 
387   PetscFunctionBegin;
388   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
389   ierr = PetscUseMethod(pc,"PCHMGSetInnerPCType_C",(PC,PCType),(pc,type));CHKERRQ(ierr);
390   PetscFunctionReturn(0);
391 }
392 
393 static PetscErrorCode PCHMGSetCoarseningComponent_HMG(PC pc, PetscInt component)
394 {
395   PC_MG           *mg  = (PC_MG*)pc->data;
396   PC_HMG          *hmg = (PC_HMG*) mg->innerctx;
397 
398   PetscFunctionBegin;
399   hmg->component = component;
400   PetscFunctionReturn(0);
401 }
402 
403 /*MC
404    PCHMGSetCoarseningComponent - Set which component is used for the subspace-based coarsening algorithm
405 
406    Logically Collective on PC
407 
408    Input Parameters:
409 +  pc - the HMG context
410 -  component - which component PC will coarsen
411 
412    Options Database Keys:
413 .  -pc_hmg_coarsening_component - Which component is chosen for the subspace-based coarsening algorithm
414 
415    Level: beginner
416 
417 .keywords: HMG, multigrid, interpolation, coarsening, component
418 
419 .seealso: PCHMG, PCType
420 M*/
421 PetscErrorCode PCHMGSetCoarseningComponent(PC pc, PetscInt component)
422 {
423   PetscErrorCode  ierr;
424 
425   PetscFunctionBegin;
426   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
427   ierr = PetscUseMethod(pc,"PCHMGSetCoarseningComponent_C",(PC,PetscInt),(pc,component));CHKERRQ(ierr);
428   PetscFunctionReturn(0);
429 }
430 
431 static PetscErrorCode PCHMGUseMatMAIJ_HMG(PC pc, PetscBool usematmaij)
432 {
433   PC_MG           *mg  = (PC_MG*)pc->data;
434   PC_HMG          *hmg = (PC_HMG*) mg->innerctx;
435 
436   PetscFunctionBegin;
437   hmg->usematmaij = usematmaij;
438   PetscFunctionReturn(0);
439 }
440 
441 /*MC
442    PCHMGUseMatMAIJ - Set a flag that indicates if or not to use MatMAIJ for interpolations for saving memory
443 
444    Logically Collective on PC
445 
446    Input Parameters:
447 +  pc - the HMG context
448 -  usematmaij - if or not to use MatMAIJ for interpolations. By default, it is true for saving memory
449 
450    Options Database Keys:
451 .  -pc_hmg_use_matmaij - <true | false >
452 
453    Level: beginner
454 
455 .keywords: HMG, multigrid, interpolation, coarsening, MatMAIJ
456 
457 .seealso: PCHMG, PCType
458 M*/
459 PetscErrorCode PCHMGUseMatMAIJ(PC pc, PetscBool usematmaij)
460 {
461   PetscErrorCode  ierr;
462 
463   PetscFunctionBegin;
464   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
465   ierr = PetscUseMethod(pc,"PCHMGUseMatMAIJ_C",(PC,PetscBool),(pc,usematmaij));CHKERRQ(ierr);
466   PetscFunctionReturn(0);
467 }
468 
469 /*MC
470    PCHMG - Hybrid of PETSc preconditioners (such as ASM, BJacobi, SOR, etc.) and Hypre BoomerAMG, GAMG or other multilevel methods. BoomerAMG, GAMG
471            or other multilevel methods is used to coarsen matrix and generate a sequence of coarse matrices and interpolations. The matrices and
472            interpolations are employed to construct PCMG, and then any available PETSc preconditioners can be chosen as smoothers and the coarse solver.
473 
474    Options Database Keys:
475 +  -pc_hmg_reuse_interpolation <true | false> - Whether or not to reuse the interpolations. If true, it potentially save the compute time.
476 .  -pc_hmg_use_subspace_coarsening  <true | false> - Whether or not to use subspace coarsening (that is, coarsen a submatrix).
477 .  -hmg_inner_pc_type <hypre, gamg, ...> - What method is used to coarsen matrix
478 -  -pc_hmg_use_matmaij <true | false> - Whether or not to use MatMAIJ for multicomponent problems for saving memory
479 
480 
481    Notes:
482     For multicomponent problems, we can just coarsen one submatrix associated with one particular component. In this way, the preconditioner setup
483     time is significantly reduced. One typical use case is neutron transport equations. There are many variables on each mesh vertex due to the
484     of angle and energy. Each variable, in fact, corresponds to the same PDEs but with different material properties.
485 
486    Level: beginner
487 
488    Concepts: Hybrid of ASM and MG, Subspace Coarsening
489 
490     References:
491 .   1. - Fande Kong, Yaqi Wang, Derek R Gaston, Cody J Permann, Andrew E Slaughter, Alexander D Lindsay, Richard C Martineau, A highly parallel multilevel
492     Newton-Krylov-Schwarz method with subspace-based coarsening and partition-based balancing for the multigroup neutron transport equations on
493     3D unstructured meshes, arXiv preprint arXiv:1903.03659, 2019
494 
495 .seealso:  PCCreate(), PCSetType(), PCType, PC, PCMG, PCHYPRE, PCHMG, PCGetCoarseOperators(), PCGetInterpolations(), PCHMGSetReuseInterpolation(), PCHMGSetUseSubspaceCoarsening(),
496            PCHMGSetInnerPCType()
497 
498 M*/
499 PETSC_EXTERN PetscErrorCode PCCreate_HMG(PC pc)
500 {
501   PetscErrorCode ierr;
502   PC_HMG         *hmg;
503   PC_MG          *mg;
504 
505   PetscFunctionBegin;
506   /* if type was previously mg; must manually destroy it because call to PCSetType(pc,PCMG) will not destroy it */
507   if (pc->ops->destroy) {
508     ierr =  (*pc->ops->destroy)(pc);CHKERRQ(ierr);
509     pc->data = 0;
510   }
511   ierr = PetscFree(((PetscObject)pc)->type_name);CHKERRQ(ierr);
512 
513   ierr = PCSetType(pc,PCMG);CHKERRQ(ierr);
514   ierr = PetscObjectChangeTypeName((PetscObject)pc, PCHMG);CHKERRQ(ierr);
515   ierr = PetscNew(&hmg);CHKERRQ(ierr);
516 
517   mg                      = (PC_MG*) pc->data;
518   mg->innerctx            = hmg;
519   hmg->reuseinterp        = PETSC_FALSE;
520   hmg->subcoarsening      = PETSC_FALSE;
521   hmg->usematmaij         = PETSC_TRUE;
522   hmg->component          = 0;
523   hmg->innerpc            = NULL;
524 
525   pc->ops->setfromoptions = PCSetFromOptions_HMG;
526   pc->ops->view           = PCView_HMG;
527   pc->ops->destroy        = PCDestroy_HMG;
528   pc->ops->setup          = PCSetUp_HMG;
529 
530   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCHMGSetReuseInterpolation_C",PCHMGSetReuseInterpolation_HMG);CHKERRQ(ierr);
531   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCHMGSetUseSubspaceCoarsening_C",PCHMGSetUseSubspaceCoarsening_HMG);CHKERRQ(ierr);
532   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCHMGSetInnerPCType_C",PCHMGSetInnerPCType_HMG);CHKERRQ(ierr);
533   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCHMGSetCoarseningComponent_C",PCHMGSetCoarseningComponent_HMG);CHKERRQ(ierr);
534   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCHMGUseMatMAIJ_C",PCHMGUseMatMAIJ_HMG);CHKERRQ(ierr);
535   PetscFunctionReturn(0);
536 }
537