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