xref: /petsc/src/ksp/pc/impls/gamg/agg.c (revision 3ba1676111f5c958fe6c2729b46ca4d523958bb3)
12e68589bSMark F. Adams /*
2b817416eSBarry Smith  GAMG geometric-algebric multigrid PC - Mark Adams 2011
32e68589bSMark F. Adams  */
42e68589bSMark F. Adams 
52e68589bSMark F. Adams #include <../src/ksp/pc/impls/gamg/gamg.h> /*I "petscpc.h" I*/
62e68589bSMark F. Adams #include <petscblaslapack.h>
7539c167fSBarry Smith #include <petscdm.h>
873f7197eSJed Brown #include <petsc/private/kspimpl.h>
92e68589bSMark F. Adams 
102e68589bSMark F. Adams typedef struct {
11c8b0795cSMark F. Adams   PetscInt   nsmooths;
12bae903cbSmarkadams4   PetscInt   aggressive_coarsening_levels; // number of aggressive coarsening levels (square or MISk)
132d776b49SBarry Smith   MatCoarsen crs;
142e68589bSMark F. Adams } PC_GAMG_AGG;
152e68589bSMark F. Adams 
162e68589bSMark F. Adams /*@
17f1580f4eSBarry Smith    PCGAMGSetNSmooths - Set number of smoothing steps (1 is typical) used for multigrid on all the levels
182e68589bSMark F. Adams 
19c3339decSBarry Smith    Logically Collective
202e68589bSMark F. Adams 
212e68589bSMark F. Adams    Input Parameters:
222e68589bSMark F. Adams .  pc - the preconditioner context
232e68589bSMark F. Adams 
242e68589bSMark F. Adams    Options Database Key:
25cab9ed1eSBarry Smith .  -pc_gamg_agg_nsmooths <nsmooth, default=1> - number of smoothing steps to use with smooth aggregation
262e68589bSMark F. Adams 
272e68589bSMark F. Adams    Level: intermediate
282e68589bSMark F. Adams 
29f1580f4eSBarry Smith .seealso: `PCMG`, `PCGAMG`
302e68589bSMark F. Adams @*/
31d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGSetNSmooths(PC pc, PetscInt n)
32d71ae5a4SJacob Faibussowitsch {
332e68589bSMark F. Adams   PetscFunctionBegin;
342e68589bSMark F. Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
35d5d25401SBarry Smith   PetscValidLogicalCollectiveInt(pc, n, 2);
36cac4c232SBarry Smith   PetscTryMethod(pc, "PCGAMGSetNSmooths_C", (PC, PetscInt), (pc, n));
37*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
382e68589bSMark F. Adams }
392e68589bSMark F. Adams 
40d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGSetNSmooths_AGG(PC pc, PetscInt n)
41d71ae5a4SJacob Faibussowitsch {
422e68589bSMark F. Adams   PC_MG       *mg          = (PC_MG *)pc->data;
432e68589bSMark F. Adams   PC_GAMG     *pc_gamg     = (PC_GAMG *)mg->innerctx;
44c8b0795cSMark F. Adams   PC_GAMG_AGG *pc_gamg_agg = (PC_GAMG_AGG *)pc_gamg->subctx;
452e68589bSMark F. Adams 
462e68589bSMark F. Adams   PetscFunctionBegin;
47c8b0795cSMark F. Adams   pc_gamg_agg->nsmooths = n;
48*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49c8b0795cSMark F. Adams }
50c8b0795cSMark F. Adams 
51c8b0795cSMark F. Adams /*@
52f1580f4eSBarry Smith    PCGAMGSetAggressiveLevels -  Use aggressive coarsening on first n levels
53ef4ad70eSMark F. Adams 
54c3339decSBarry Smith    Logically Collective
55ef4ad70eSMark F. Adams 
56ef4ad70eSMark F. Adams    Input Parameters:
57cab9ed1eSBarry Smith +  pc - the preconditioner context
58d5d25401SBarry Smith -  n - 0, 1 or more
59ef4ad70eSMark F. Adams 
60ef4ad70eSMark F. Adams    Options Database Key:
61bae903cbSmarkadams4 .  -pc_gamg_aggressive_coarsening <n,default = 1> - Number of levels to square the graph on before aggregating it
62af3c827dSMark Adams 
63ef4ad70eSMark F. Adams    Level: intermediate
64ef4ad70eSMark F. Adams 
652d776b49SBarry Smith .seealso: `PCGAMG`, `PCGAMGSetThreshold()`
66ef4ad70eSMark F. Adams @*/
67d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGSetAggressiveLevels(PC pc, PetscInt n)
68d71ae5a4SJacob Faibussowitsch {
69ef4ad70eSMark F. Adams   PetscFunctionBegin;
70ef4ad70eSMark F. Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
71d5d25401SBarry Smith   PetscValidLogicalCollectiveInt(pc, n, 2);
72bae903cbSmarkadams4   PetscTryMethod(pc, "PCGAMGSetAggressiveLevels_C", (PC, PetscInt), (pc, n));
73*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
74ef4ad70eSMark F. Adams }
75ef4ad70eSMark F. Adams 
76d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGSetAggressiveLevels_AGG(PC pc, PetscInt n)
77d71ae5a4SJacob Faibussowitsch {
78ef4ad70eSMark F. Adams   PC_MG       *mg          = (PC_MG *)pc->data;
79ef4ad70eSMark F. Adams   PC_GAMG     *pc_gamg     = (PC_GAMG *)mg->innerctx;
80ef4ad70eSMark F. Adams   PC_GAMG_AGG *pc_gamg_agg = (PC_GAMG_AGG *)pc_gamg->subctx;
81ef4ad70eSMark F. Adams 
82ef4ad70eSMark F. Adams   PetscFunctionBegin;
83bae903cbSmarkadams4   pc_gamg_agg->aggressive_coarsening_levels = n;
84*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
85ef4ad70eSMark F. Adams }
86ef4ad70eSMark F. Adams 
87d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetFromOptions_GAMG_AGG(PC pc, PetscOptionItems *PetscOptionsObject)
88d71ae5a4SJacob Faibussowitsch {
892e68589bSMark F. Adams   PC_MG       *mg          = (PC_MG *)pc->data;
902e68589bSMark F. Adams   PC_GAMG     *pc_gamg     = (PC_GAMG *)mg->innerctx;
91c8b0795cSMark F. Adams   PC_GAMG_AGG *pc_gamg_agg = (PC_GAMG_AGG *)pc_gamg->subctx;
922e68589bSMark F. Adams 
932e68589bSMark F. Adams   PetscFunctionBegin;
94d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "GAMG-AGG options");
952e68589bSMark F. Adams   {
96bae903cbSmarkadams4     PetscBool flg;
979566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-pc_gamg_agg_nsmooths", "smoothing steps for smoothed aggregation, usually 1", "PCGAMGSetNSmooths", pc_gamg_agg->nsmooths, &pc_gamg_agg->nsmooths, NULL));
989371c9d4SSatish Balay     PetscCall(
999371c9d4SSatish Balay       PetscOptionsInt("-pc_gamg_square_graph", "Number of aggressive coarsening (MIS-2) levels from finest (alias for -pc_gamg_aggressive_coarsening, deprecated)", "PCGAMGSetAggressiveLevels", pc_gamg_agg->aggressive_coarsening_levels, &pc_gamg_agg->aggressive_coarsening_levels, &flg));
100bae903cbSmarkadams4     if (!flg) {
101bae903cbSmarkadams4       PetscCall(PetscOptionsInt("-pc_gamg_aggressive_coarsening", "Number of aggressive coarsening (MIS-2) levels from finest", "PCGAMGSetAggressiveLevels", pc_gamg_agg->aggressive_coarsening_levels, &pc_gamg_agg->aggressive_coarsening_levels, NULL));
102bae903cbSmarkadams4     } else {
103bae903cbSmarkadams4       PetscCall(PetscOptionsInt("-pc_gamg_aggressive_coarsening", "Number of aggressive coarsening (MIS-2) levels from finest", "PCGAMGSetAggressiveLevels", pc_gamg_agg->aggressive_coarsening_levels, &pc_gamg_agg->aggressive_coarsening_levels, &flg));
104bae903cbSmarkadams4       if (flg) PetscCall(PetscInfo(pc, "Warning: both -pc_gamg_square_graph and -pc_gamg_aggressive_coarsening are used. -pc_gamg_square_graph is deprecated, Number of aggressive levels is %d\n", (int)pc_gamg_agg->aggressive_coarsening_levels));
105bae903cbSmarkadams4     }
1062e68589bSMark F. Adams   }
107d0609cedSBarry Smith   PetscOptionsHeadEnd();
108*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1092e68589bSMark F. Adams }
1102e68589bSMark F. Adams 
111d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_GAMG_AGG(PC pc)
112d71ae5a4SJacob Faibussowitsch {
1132e68589bSMark F. Adams   PC_MG   *mg      = (PC_MG *)pc->data;
1142e68589bSMark F. Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
1152e68589bSMark F. Adams 
1162e68589bSMark F. Adams   PetscFunctionBegin;
1179566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc_gamg->subctx));
1182e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetNSmooths_C", NULL));
119bae903cbSmarkadams4   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetAggressiveLevels_C", NULL));
120bae903cbSmarkadams4   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", NULL));
121*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1222e68589bSMark F. Adams }
1232e68589bSMark F. Adams 
1242e68589bSMark F. Adams /*
1252e68589bSMark F. Adams    PCSetCoordinates_AGG
126302f38e8SMark F. Adams      - collective
1272e68589bSMark F. Adams 
1282e68589bSMark F. Adams    Input Parameter:
1292e68589bSMark F. Adams    . pc - the preconditioner context
130a2f3521dSMark F. Adams    . ndm - dimesion of data (used for dof/vertex for Stokes)
131302f38e8SMark F. Adams    . a_nloc - number of vertices local
132302f38e8SMark F. Adams    . coords - [a_nloc][ndm] - interleaved coordinate data: {x_0, y_0, z_0, x_1, y_1, ...}
1332e68589bSMark F. Adams */
1341e6b0712SBarry Smith 
135d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetCoordinates_AGG(PC pc, PetscInt ndm, PetscInt a_nloc, PetscReal *coords)
136d71ae5a4SJacob Faibussowitsch {
1372e68589bSMark F. Adams   PC_MG   *mg      = (PC_MG *)pc->data;
1382e68589bSMark F. Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
13969344418SMark F. Adams   PetscInt arrsz, kk, ii, jj, nloc, ndatarows, ndf;
140a2f3521dSMark F. Adams   Mat      mat = pc->pmat;
1412e68589bSMark F. Adams 
1422e68589bSMark F. Adams   PetscFunctionBegin;
143a2f3521dSMark F. Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
144a2f3521dSMark F. Adams   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
145302f38e8SMark F. Adams   nloc = a_nloc;
1462e68589bSMark F. Adams 
1472e68589bSMark F. Adams   /* SA: null space vectors */
1489566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(mat, &ndf));               /* this does not work for Stokes */
14969344418SMark F. Adams   if (coords && ndf == 1) pc_gamg->data_cell_cols = 1; /* scalar w/ coords and SA (not needed) */
150a2f3521dSMark F. Adams   else if (coords) {
15163a3b9bcSJacob Faibussowitsch     PetscCheck(ndm <= ndf, PETSC_COMM_SELF, PETSC_ERR_PLIB, "degrees of motion %" PetscInt_FMT " > block size %" PetscInt_FMT, ndm, ndf);
15269344418SMark F. Adams     pc_gamg->data_cell_cols = (ndm == 2 ? 3 : 6); /* displacement elasticity */
153ad540459SPierre Jolivet     if (ndm != ndf) PetscCheck(pc_gamg->data_cell_cols == ndf, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Don't know how to create null space for ndm=%" PetscInt_FMT ", ndf=%" PetscInt_FMT ".  Use MatSetNearNullSpace().", ndm, ndf);
154806fa848SBarry Smith   } else pc_gamg->data_cell_cols = ndf; /* no data, force SA with constant null space vectors */
15571959b99SBarry Smith   pc_gamg->data_cell_rows = ndatarows = ndf;
15663a3b9bcSJacob Faibussowitsch   PetscCheck(pc_gamg->data_cell_cols > 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "pc_gamg->data_cell_cols %" PetscInt_FMT " <= 0", pc_gamg->data_cell_cols);
157c8b0795cSMark F. Adams   arrsz = nloc * pc_gamg->data_cell_rows * pc_gamg->data_cell_cols;
1582e68589bSMark F. Adams 
1597f66b68fSMark Adams   if (!pc_gamg->data || (pc_gamg->data_sz != arrsz)) {
1609566063dSJacob Faibussowitsch     PetscCall(PetscFree(pc_gamg->data));
1619566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(arrsz + 1, &pc_gamg->data));
1622e68589bSMark F. Adams   }
1632e68589bSMark F. Adams   /* copy data in - column oriented */
1642e68589bSMark F. Adams   for (kk = 0; kk < nloc; kk++) {
16569344418SMark F. Adams     const PetscInt M    = nloc * pc_gamg->data_cell_rows; /* stride into data */
16669344418SMark F. Adams     PetscReal     *data = &pc_gamg->data[kk * ndatarows]; /* start of cell */
167c8b0795cSMark F. Adams     if (pc_gamg->data_cell_cols == 1) *data = 1.0;
1682e68589bSMark F. Adams     else {
16969344418SMark F. Adams       /* translational modes */
1702fa5cd67SKarl Rupp       for (ii = 0; ii < ndatarows; ii++) {
1712fa5cd67SKarl Rupp         for (jj = 0; jj < ndatarows; jj++) {
17269344418SMark F. Adams           if (ii == jj) data[ii * M + jj] = 1.0;
1732e68589bSMark F. Adams           else data[ii * M + jj] = 0.0;
1742fa5cd67SKarl Rupp         }
1752fa5cd67SKarl Rupp       }
17669344418SMark F. Adams 
17769344418SMark F. Adams       /* rotational modes */
1782e68589bSMark F. Adams       if (coords) {
17969344418SMark F. Adams         if (ndm == 2) {
1802e68589bSMark F. Adams           data += 2 * M;
1812e68589bSMark F. Adams           data[0] = -coords[2 * kk + 1];
1822e68589bSMark F. Adams           data[1] = coords[2 * kk];
183806fa848SBarry Smith         } else {
1842e68589bSMark F. Adams           data += 3 * M;
1859371c9d4SSatish Balay           data[0]         = 0.0;
1869371c9d4SSatish Balay           data[M + 0]     = coords[3 * kk + 2];
1879371c9d4SSatish Balay           data[2 * M + 0] = -coords[3 * kk + 1];
1889371c9d4SSatish Balay           data[1]         = -coords[3 * kk + 2];
1899371c9d4SSatish Balay           data[M + 1]     = 0.0;
1909371c9d4SSatish Balay           data[2 * M + 1] = coords[3 * kk];
1919371c9d4SSatish Balay           data[2]         = coords[3 * kk + 1];
1929371c9d4SSatish Balay           data[M + 2]     = -coords[3 * kk];
1939371c9d4SSatish Balay           data[2 * M + 2] = 0.0;
1942e68589bSMark F. Adams         }
1952e68589bSMark F. Adams       }
1962e68589bSMark F. Adams     }
1972e68589bSMark F. Adams   }
1982e68589bSMark F. Adams   pc_gamg->data_sz = arrsz;
199*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2002e68589bSMark F. Adams }
2012e68589bSMark F. Adams 
2022e68589bSMark F. Adams /*
203a2f3521dSMark F. Adams    PCSetData_AGG - called if data is not set with PCSetCoordinates.
204a2f3521dSMark F. Adams       Looks in Mat for near null space.
205a2f3521dSMark F. Adams       Does not work for Stokes
2062e68589bSMark F. Adams 
2072e68589bSMark F. Adams   Input Parameter:
2082e68589bSMark F. Adams    . pc -
209a2f3521dSMark F. Adams    . a_A - matrix to get (near) null space out of.
2102e68589bSMark F. Adams */
211d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetData_AGG(PC pc, Mat a_A)
212d71ae5a4SJacob Faibussowitsch {
213b8cd405aSMark F. Adams   PC_MG       *mg      = (PC_MG *)pc->data;
214b8cd405aSMark F. Adams   PC_GAMG     *pc_gamg = (PC_GAMG *)mg->innerctx;
215b8cd405aSMark F. Adams   MatNullSpace mnull;
21666f2ef4bSMark Adams 
217b817416eSBarry Smith   PetscFunctionBegin;
2189566063dSJacob Faibussowitsch   PetscCall(MatGetNearNullSpace(a_A, &mnull));
219b8cd405aSMark F. Adams   if (!mnull) {
22066f2ef4bSMark Adams     DM dm;
2219566063dSJacob Faibussowitsch     PetscCall(PCGetDM(pc, &dm));
22248a46eb9SPierre Jolivet     if (!dm) PetscCall(MatGetDM(a_A, &dm));
22366f2ef4bSMark Adams     if (dm) {
22466f2ef4bSMark Adams       PetscObject deformation;
225b0d30dd6SMatthew G. Knepley       PetscInt    Nf;
226b0d30dd6SMatthew G. Knepley 
2279566063dSJacob Faibussowitsch       PetscCall(DMGetNumFields(dm, &Nf));
228b0d30dd6SMatthew G. Knepley       if (Nf) {
2299566063dSJacob Faibussowitsch         PetscCall(DMGetField(dm, 0, NULL, &deformation));
2309566063dSJacob Faibussowitsch         PetscCall(PetscObjectQuery((PetscObject)deformation, "nearnullspace", (PetscObject *)&mnull));
23148a46eb9SPierre Jolivet         if (!mnull) PetscCall(PetscObjectQuery((PetscObject)deformation, "nullspace", (PetscObject *)&mnull));
23266f2ef4bSMark Adams       }
23366f2ef4bSMark Adams     }
234b0d30dd6SMatthew G. Knepley   }
23566f2ef4bSMark Adams 
23666f2ef4bSMark Adams   if (!mnull) {
237a2f3521dSMark F. Adams     PetscInt bs, NN, MM;
2389566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(a_A, &bs));
2399566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(a_A, &MM, &NN));
24063a3b9bcSJacob Faibussowitsch     PetscCheck(MM % bs == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MM %" PetscInt_FMT " must be divisible by bs %" PetscInt_FMT, MM, bs);
2419566063dSJacob Faibussowitsch     PetscCall(PCSetCoordinates_AGG(pc, bs, MM / bs, NULL));
242806fa848SBarry Smith   } else {
243b8cd405aSMark F. Adams     PetscReal         *nullvec;
244b8cd405aSMark F. Adams     PetscBool          has_const;
245b8cd405aSMark F. Adams     PetscInt           i, j, mlocal, nvec, bs;
246d5d25401SBarry Smith     const Vec         *vecs;
247d5d25401SBarry Smith     const PetscScalar *v;
248b817416eSBarry Smith 
2499566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(a_A, &mlocal, NULL));
2509566063dSJacob Faibussowitsch     PetscCall(MatNullSpaceGetVecs(mnull, &has_const, &nvec, &vecs));
251d19c4ebbSmarkadams4     for (i = 0; i < nvec; i++) {
252d19c4ebbSmarkadams4       PetscCall(VecGetLocalSize(vecs[i], &j));
253d19c4ebbSmarkadams4       PetscCheck(j == mlocal, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Attached null space vector size %" PetscInt_FMT " != matrix size %" PetscInt_FMT, j, mlocal);
254d19c4ebbSmarkadams4     }
255a0dea87dSMark Adams     pc_gamg->data_sz = (nvec + !!has_const) * mlocal;
2569566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1((nvec + !!has_const) * mlocal, &nullvec));
2579371c9d4SSatish Balay     if (has_const)
2589371c9d4SSatish Balay       for (i = 0; i < mlocal; i++) nullvec[i] = 1.0;
259b8cd405aSMark F. Adams     for (i = 0; i < nvec; i++) {
2609566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(vecs[i], &v));
261b8cd405aSMark F. Adams       for (j = 0; j < mlocal; j++) nullvec[(i + !!has_const) * mlocal + j] = PetscRealPart(v[j]);
2629566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(vecs[i], &v));
263b8cd405aSMark F. Adams     }
264b8cd405aSMark F. Adams     pc_gamg->data           = nullvec;
265b8cd405aSMark F. Adams     pc_gamg->data_cell_cols = (nvec + !!has_const);
2669566063dSJacob Faibussowitsch     PetscCall(MatGetBlockSize(a_A, &bs));
267b8cd405aSMark F. Adams     pc_gamg->data_cell_rows = bs;
268b8cd405aSMark F. Adams   }
269*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2702e68589bSMark F. Adams }
2712e68589bSMark F. Adams 
2722e68589bSMark F. Adams /*
273bae903cbSmarkadams4   formProl0 - collect null space data for each aggregate, do QR, put R in coarse grid data and Q in P_0
2742e68589bSMark F. Adams 
2752e68589bSMark F. Adams   Input Parameter:
2762adfe9d3SBarry Smith    . agg_llists - list of arrays with aggregates -- list from selected vertices of aggregate unselected vertices
2772adfe9d3SBarry Smith    . bs - row block size
2780cbbd2e1SMark F. Adams    . nSAvec - column bs of new P
2790cbbd2e1SMark F. Adams    . my0crs - global index of start of locals
2802adfe9d3SBarry Smith    . data_stride - bs*(nloc nodes + ghost nodes) [data_stride][nSAvec]
2812e68589bSMark F. Adams    . data_in[data_stride*nSAvec] - local data on fine grid
2822e68589bSMark F. Adams    . flid_fgid[data_stride/bs] - make local to global IDs, includes ghosts in 'locals_llist'
283bae903cbSmarkadams4 
2842e68589bSMark F. Adams   Output Parameter:
2852e68589bSMark F. Adams    . a_data_out - in with fine grid data (w/ghosts), out with coarse grid data
2862e68589bSMark F. Adams    . a_Prol - prolongation operator
2872e68589bSMark F. Adams */
288d71ae5a4SJacob Faibussowitsch static PetscErrorCode formProl0(PetscCoarsenData *agg_llists, PetscInt bs, PetscInt nSAvec, PetscInt my0crs, PetscInt data_stride, PetscReal data_in[], const PetscInt flid_fgid[], PetscReal **a_data_out, Mat a_Prol)
289d71ae5a4SJacob Faibussowitsch {
290bd026e97SJed Brown   PetscInt        Istart, my0, Iend, nloc, clid, flid = 0, aggID, kk, jj, ii, mm, nSelected, minsz, nghosts, out_data_stride;
2913b4367a7SBarry Smith   MPI_Comm        comm;
2922e68589bSMark F. Adams   PetscReal      *out_data;
293539c167fSBarry Smith   PetscCDIntNd   *pos;
2941943db53SBarry Smith   PCGAMGHashTable fgid_flid;
2950cbbd2e1SMark F. Adams 
2962e68589bSMark F. Adams   PetscFunctionBegin;
2979566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)a_Prol, &comm));
2989566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(a_Prol, &Istart, &Iend));
2999371c9d4SSatish Balay   nloc = (Iend - Istart) / bs;
3009371c9d4SSatish Balay   my0  = Istart / bs;
30163a3b9bcSJacob Faibussowitsch   PetscCheck((Iend - Istart) % bs == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Iend %" PetscInt_FMT " - Istart %" PetscInt_FMT " must be divisible by bs %" PetscInt_FMT, Iend, Istart, bs);
3020cbbd2e1SMark F. Adams   Iend /= bs;
3030cbbd2e1SMark F. Adams   nghosts = data_stride / bs - nloc;
3042e68589bSMark F. Adams 
3059566063dSJacob Faibussowitsch   PetscCall(PCGAMGHashTableCreate(2 * nghosts + 1, &fgid_flid));
30648a46eb9SPierre Jolivet   for (kk = 0; kk < nghosts; kk++) PetscCall(PCGAMGHashTableAdd(&fgid_flid, flid_fgid[nloc + kk], nloc + kk));
3072e68589bSMark F. Adams 
3080cbbd2e1SMark F. Adams   /* count selected -- same as number of cols of P */
3090cbbd2e1SMark F. Adams   for (nSelected = mm = 0; mm < nloc; mm++) {
310e78576d6SMark F. Adams     PetscBool ise;
3119566063dSJacob Faibussowitsch     PetscCall(PetscCDEmptyAt(agg_llists, mm, &ise));
312e78576d6SMark F. Adams     if (!ise) nSelected++;
3130cbbd2e1SMark F. Adams   }
3149566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(a_Prol, &ii, &jj));
31563a3b9bcSJacob Faibussowitsch   PetscCheck((ii / nSAvec) == my0crs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "ii %" PetscInt_FMT " /nSAvec %" PetscInt_FMT "  != my0crs %" PetscInt_FMT, ii, nSAvec, my0crs);
31663a3b9bcSJacob Faibussowitsch   PetscCheck(nSelected == (jj - ii) / nSAvec, PETSC_COMM_SELF, PETSC_ERR_PLIB, "nSelected %" PetscInt_FMT " != (jj %" PetscInt_FMT " - ii %" PetscInt_FMT ")/nSAvec %" PetscInt_FMT, nSelected, jj, ii, nSAvec);
3170cbbd2e1SMark F. Adams 
3182e68589bSMark F. Adams   /* aloc space for coarse point data (output) */
3190cbbd2e1SMark F. Adams   out_data_stride = nSelected * nSAvec;
3202fa5cd67SKarl Rupp 
3219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(out_data_stride * nSAvec, &out_data));
32233812677SSatish Balay   for (ii = 0; ii < out_data_stride * nSAvec; ii++) out_data[ii] = PETSC_MAX_REAL;
3230cbbd2e1SMark F. Adams   *a_data_out = out_data; /* output - stride nSelected*nSAvec */
3242e68589bSMark F. Adams 
3252e68589bSMark F. Adams   /* find points and set prolongation */
326c8b0795cSMark F. Adams   minsz = 100;
3270cbbd2e1SMark F. Adams   for (mm = clid = 0; mm < nloc; mm++) {
3289566063dSJacob Faibussowitsch     PetscCall(PetscCDSizeAt(agg_llists, mm, &jj));
329e78576d6SMark F. Adams     if (jj > 0) {
3300cbbd2e1SMark F. Adams       const PetscInt lid = mm, cgid = my0crs + clid;
3310cbbd2e1SMark F. Adams       PetscInt       cids[100]; /* max bs */
3320cbbd2e1SMark F. Adams       PetscBLASInt   asz = jj, M = asz * bs, N = nSAvec, INFO;
3332e68589bSMark F. Adams       PetscBLASInt   Mdata = M + ((N - M > 0) ? N - M : 0), LDA = Mdata, LWORK = N * bs;
3342e68589bSMark F. Adams       PetscScalar   *qqc, *qqr, *TAU, *WORK;
3352e68589bSMark F. Adams       PetscInt      *fids;
33665d7b583SSatish Balay       PetscReal     *data;
337b817416eSBarry Smith 
3380cbbd2e1SMark F. Adams       /* count agg */
3390cbbd2e1SMark F. Adams       if (asz < minsz) minsz = asz;
3400cbbd2e1SMark F. Adams 
3410cbbd2e1SMark F. Adams       /* get block */
3429566063dSJacob Faibussowitsch       PetscCall(PetscMalloc5(Mdata * N, &qqc, M * N, &qqr, N, &TAU, LWORK, &WORK, M, &fids));
3432e68589bSMark F. Adams 
3442e68589bSMark F. Adams       aggID = 0;
3459566063dSJacob Faibussowitsch       PetscCall(PetscCDGetHeadPos(agg_llists, lid, &pos));
346e78576d6SMark F. Adams       while (pos) {
347e78576d6SMark F. Adams         PetscInt gid1;
3489566063dSJacob Faibussowitsch         PetscCall(PetscCDIntNdGetID(pos, &gid1));
3499566063dSJacob Faibussowitsch         PetscCall(PetscCDGetNextPos(agg_llists, lid, &pos));
350e78576d6SMark F. Adams 
3510cbbd2e1SMark F. Adams         if (gid1 >= my0 && gid1 < Iend) flid = gid1 - my0;
3520cbbd2e1SMark F. Adams         else {
3539566063dSJacob Faibussowitsch           PetscCall(PCGAMGHashTableFind(&fgid_flid, gid1, &flid));
35408401ef6SPierre Jolivet           PetscCheck(flid >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot find gid1 in table");
3550cbbd2e1SMark F. Adams         }
3562e68589bSMark F. Adams         /* copy in B_i matrix - column oriented */
35765d7b583SSatish Balay         data = &data_in[flid * bs];
3583d3eaba7SBarry Smith         for (ii = 0; ii < bs; ii++) {
3592e68589bSMark F. Adams           for (jj = 0; jj < N; jj++) {
3600cbbd2e1SMark F. Adams             PetscReal d                       = data[jj * data_stride + ii];
3610cbbd2e1SMark F. Adams             qqc[jj * Mdata + aggID * bs + ii] = d;
3622e68589bSMark F. Adams           }
3632e68589bSMark F. Adams         }
3642e68589bSMark F. Adams         /* set fine IDs */
3652e68589bSMark F. Adams         for (kk = 0; kk < bs; kk++) fids[aggID * bs + kk] = flid_fgid[flid] * bs + kk;
3662e68589bSMark F. Adams         aggID++;
3670cbbd2e1SMark F. Adams       }
3682e68589bSMark F. Adams 
3692e68589bSMark F. Adams       /* pad with zeros */
3702e68589bSMark F. Adams       for (ii = asz * bs; ii < Mdata; ii++) {
371ad540459SPierre Jolivet         for (jj = 0; jj < N; jj++, kk++) qqc[jj * Mdata + ii] = .0;
3722e68589bSMark F. Adams       }
3732e68589bSMark F. Adams 
3742e68589bSMark F. Adams       /* QR */
3759566063dSJacob Faibussowitsch       PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
376792fecdfSBarry Smith       PetscCallBLAS("LAPACKgeqrf", LAPACKgeqrf_(&Mdata, &N, qqc, &LDA, TAU, WORK, &LWORK, &INFO));
3779566063dSJacob Faibussowitsch       PetscCall(PetscFPTrapPop());
37808401ef6SPierre Jolivet       PetscCheck(INFO == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "xGEQRF error");
3792e68589bSMark F. Adams       /* get R - column oriented - output B_{i+1} */
3802e68589bSMark F. Adams       {
3812e68589bSMark F. Adams         PetscReal *data = &out_data[clid * nSAvec];
3822e68589bSMark F. Adams         for (jj = 0; jj < nSAvec; jj++) {
3832e68589bSMark F. Adams           for (ii = 0; ii < nSAvec; ii++) {
38408401ef6SPierre Jolivet             PetscCheck(data[jj * out_data_stride + ii] == PETSC_MAX_REAL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "data[jj*out_data_stride + ii] != %e", (double)PETSC_MAX_REAL);
3850cbbd2e1SMark F. Adams             if (ii <= jj) data[jj * out_data_stride + ii] = PetscRealPart(qqc[jj * Mdata + ii]);
3860cbbd2e1SMark F. Adams             else data[jj * out_data_stride + ii] = 0.;
3872e68589bSMark F. Adams           }
3882e68589bSMark F. Adams         }
3892e68589bSMark F. Adams       }
3902e68589bSMark F. Adams 
3912e68589bSMark F. Adams       /* get Q - row oriented */
392792fecdfSBarry Smith       PetscCallBLAS("LAPACKorgqr", LAPACKorgqr_(&Mdata, &N, &N, qqc, &LDA, TAU, WORK, &LWORK, &INFO));
39363a3b9bcSJacob Faibussowitsch       PetscCheck(INFO == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "xORGQR error arg %" PetscBLASInt_FMT, -INFO);
3942e68589bSMark F. Adams 
3952e68589bSMark F. Adams       for (ii = 0; ii < M; ii++) {
396ad540459SPierre Jolivet         for (jj = 0; jj < N; jj++) qqr[N * ii + jj] = qqc[jj * Mdata + ii];
3972e68589bSMark F. Adams       }
3982e68589bSMark F. Adams 
3992e68589bSMark F. Adams       /* add diagonal block of P0 */
4009371c9d4SSatish Balay       for (kk = 0; kk < N; kk++) { cids[kk] = N * cgid + kk; /* global col IDs in P0 */ }
4019566063dSJacob Faibussowitsch       PetscCall(MatSetValues(a_Prol, M, fids, N, cids, qqr, INSERT_VALUES));
4029566063dSJacob Faibussowitsch       PetscCall(PetscFree5(qqc, qqr, TAU, WORK, fids));
403b43b03e9SMark F. Adams       clid++;
4040cbbd2e1SMark F. Adams     } /* coarse agg */
4050cbbd2e1SMark F. Adams   }   /* for all fine nodes */
4069566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(a_Prol, MAT_FINAL_ASSEMBLY));
4079566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(a_Prol, MAT_FINAL_ASSEMBLY));
4089566063dSJacob Faibussowitsch   PetscCall(PCGAMGHashTableDestroy(&fgid_flid));
409*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4102e68589bSMark F. Adams }
4112e68589bSMark F. Adams 
412d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCView_GAMG_AGG(PC pc, PetscViewer viewer)
413d71ae5a4SJacob Faibussowitsch {
4145adeb434SBarry Smith   PC_MG       *mg          = (PC_MG *)pc->data;
4155adeb434SBarry Smith   PC_GAMG     *pc_gamg     = (PC_GAMG *)mg->innerctx;
4165adeb434SBarry Smith   PC_GAMG_AGG *pc_gamg_agg = (PC_GAMG_AGG *)pc_gamg->subctx;
4175adeb434SBarry Smith 
4185adeb434SBarry Smith   PetscFunctionBegin;
4199566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "      AGG specific options\n"));
420bae903cbSmarkadams4   PetscCall(PetscViewerASCIIPrintf(viewer, "        Number of levels to square graph %d\n", (int)pc_gamg_agg->aggressive_coarsening_levels));
421bae903cbSmarkadams4   PetscCall(PetscViewerASCIIPrintf(viewer, "        Number smoothing steps %d\n", (int)pc_gamg_agg->nsmooths));
422*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4235adeb434SBarry Smith }
4245adeb434SBarry Smith 
4252d776b49SBarry Smith static PetscErrorCode PCGAMGCreateGraph_AGG(PC pc, Mat Amat, Mat *a_Gmat)
426d71ae5a4SJacob Faibussowitsch {
427c8b0795cSMark F. Adams   PC_MG          *mg          = (PC_MG *)pc->data;
428c8b0795cSMark F. Adams   PC_GAMG        *pc_gamg     = (PC_GAMG *)mg->innerctx;
429c8b0795cSMark F. Adams   PC_GAMG_AGG    *pc_gamg_agg = (PC_GAMG_AGG *)pc_gamg->subctx;
4302d776b49SBarry Smith   const PetscReal vfilter     = pc_gamg->threshold[pc_gamg->current_level];
4312d776b49SBarry Smith   PetscBool       ishem;
4322d776b49SBarry Smith   const char     *prefix;
433c8b0795cSMark F. Adams 
434c8b0795cSMark F. Adams   PetscFunctionBegin;
435849bee69SMark Adams   PetscCall(PetscLogEventBegin(petsc_gamg_setup_events[GAMG_GRAPH], 0, 0, 0, 0));
4362d776b49SBarry Smith   /* Note: depending on the algorithm that will be used for computing the coarse grid points this should pass PETSC_TRUE or PETSC_FALSE as the first argument */
4372d776b49SBarry Smith 
4382d776b49SBarry Smith   /* MATCOARSENHEM requires numerical weights for edges so ensure they are computed */
4392d776b49SBarry Smith   PetscCall(MatCoarsenCreate(PetscObjectComm((PetscObject)pc), &pc_gamg_agg->crs));
4402d776b49SBarry Smith   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)pc, &prefix));
4412d776b49SBarry Smith   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)pc_gamg_agg->crs, prefix));
4422d776b49SBarry Smith   PetscCall(MatCoarsenSetFromOptions(pc_gamg_agg->crs));
4432d776b49SBarry Smith   PetscCall(PetscObjectTypeCompare((PetscObject)pc_gamg_agg->crs, MATCOARSENHEM, &ishem));
4442d776b49SBarry Smith 
4452d776b49SBarry Smith   PetscCall(MatCreateGraph(Amat, PETSC_TRUE, (vfilter >= 0 || ishem) ? PETSC_TRUE : PETSC_FALSE, vfilter, a_Gmat));
446849bee69SMark Adams   PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_GRAPH], 0, 0, 0, 0));
447*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
448c8b0795cSMark F. Adams }
449c8b0795cSMark F. Adams 
450c8b0795cSMark F. Adams /*
451bae903cbSmarkadams4    PCGAMGCoarsen_AGG - supports squaring the graph (deprecated) and new graph for
452bae903cbSmarkadams4      communication of QR data used with HEM and MISk coarsening
453c8b0795cSMark F. Adams 
454c8b0795cSMark F. Adams   Input Parameter:
455e0940f08SMark F. Adams    . a_pc - this
456bae903cbSmarkadams4 
457e0940f08SMark F. Adams   Input/Output Parameter:
458bae903cbSmarkadams4    . a_Gmat1 - graph to coarsen (in), graph off processor edges for QR gather scatter (out)
459bae903cbSmarkadams4 
460c8b0795cSMark F. Adams   Output Parameter:
4610cbbd2e1SMark F. Adams    . agg_lists - list of aggregates
462bae903cbSmarkadams4 
463c8b0795cSMark F. Adams */
464d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGCoarsen_AGG(PC a_pc, Mat *a_Gmat1, PetscCoarsenData **agg_lists)
465d71ae5a4SJacob Faibussowitsch {
466e0940f08SMark F. Adams   PC_MG       *mg          = (PC_MG *)a_pc->data;
467c8b0795cSMark F. Adams   PC_GAMG     *pc_gamg     = (PC_GAMG *)mg->innerctx;
468c8b0795cSMark F. Adams   PC_GAMG_AGG *pc_gamg_agg = (PC_GAMG_AGG *)pc_gamg->subctx;
469bae903cbSmarkadams4   Mat          mat, Gmat1 = *a_Gmat1; /* aggressive graph */
4700cbbd2e1SMark F. Adams   IS           perm;
471bae903cbSmarkadams4   PetscInt     Istart, Iend, Ii, nloc, bs, nn;
472bae903cbSmarkadams4   PetscInt    *permute, *degree;
473c8b0795cSMark F. Adams   PetscBool   *bIndexSet;
474aea53286SMark Adams   PetscReal    hashfact;
475e2c00dcbSBarry Smith   PetscInt     iSwapIndex;
4763b50add6SMark Adams   PetscRandom  random;
477c8b0795cSMark F. Adams 
478c8b0795cSMark F. Adams   PetscFunctionBegin;
479849bee69SMark Adams   PetscCall(PetscLogEventBegin(petsc_gamg_setup_events[GAMG_COARSEN], 0, 0, 0, 0));
480bae903cbSmarkadams4   PetscCall(MatGetLocalSize(Gmat1, &nn, NULL));
4819566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(Gmat1, &bs));
48263a3b9bcSJacob Faibussowitsch   PetscCheck(bs == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "bs %" PetscInt_FMT " must be 1", bs);
483bae903cbSmarkadams4   nloc = nn / bs;
484c8b0795cSMark F. Adams 
4855cfd4bd9SMark Adams   /* get MIS aggs - randomize */
486bae903cbSmarkadams4   PetscCall(PetscMalloc2(nloc, &permute, nloc, &degree));
4879566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nloc, &bIndexSet));
4886e09b0e3SStefano Zampini   for (Ii = 0; Ii < nloc; Ii++) permute[Ii] = Ii;
4899566063dSJacob Faibussowitsch   PetscCall(PetscRandomCreate(PETSC_COMM_SELF, &random));
4909566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(Gmat1, &Istart, &Iend));
491c8b0795cSMark F. Adams   for (Ii = 0; Ii < nloc; Ii++) {
492bae903cbSmarkadams4     PetscInt nc;
493bae903cbSmarkadams4     PetscCall(MatGetRow(Gmat1, Istart + Ii, &nc, NULL, NULL));
494bae903cbSmarkadams4     degree[Ii] = nc;
495bae903cbSmarkadams4     PetscCall(MatRestoreRow(Gmat1, Istart + Ii, &nc, NULL, NULL));
496bae903cbSmarkadams4   }
497bae903cbSmarkadams4   for (Ii = 0; Ii < nloc; Ii++) {
4989566063dSJacob Faibussowitsch     PetscCall(PetscRandomGetValueReal(random, &hashfact));
499aea53286SMark Adams     iSwapIndex = (PetscInt)(hashfact * nloc) % nloc;
500c8b0795cSMark F. Adams     if (!bIndexSet[iSwapIndex] && iSwapIndex != Ii) {
501c8b0795cSMark F. Adams       PetscInt iTemp        = permute[iSwapIndex];
502c8b0795cSMark F. Adams       permute[iSwapIndex]   = permute[Ii];
503c8b0795cSMark F. Adams       permute[Ii]           = iTemp;
504bae903cbSmarkadams4       iTemp                 = degree[iSwapIndex];
505bae903cbSmarkadams4       degree[iSwapIndex]    = degree[Ii];
506bae903cbSmarkadams4       degree[Ii]            = iTemp;
507c8b0795cSMark F. Adams       bIndexSet[iSwapIndex] = PETSC_TRUE;
508c8b0795cSMark F. Adams     }
509c8b0795cSMark F. Adams   }
510bae903cbSmarkadams4   // create minimum degree ordering
511bae903cbSmarkadams4   PetscCall(PetscSortIntWithArray(nloc, degree, permute));
512bae903cbSmarkadams4 
5139566063dSJacob Faibussowitsch   PetscCall(PetscFree(bIndexSet));
5149566063dSJacob Faibussowitsch   PetscCall(PetscRandomDestroy(&random));
5159566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nloc, permute, PETSC_USE_POINTER, &perm));
516849bee69SMark Adams   PetscCall(PetscLogEventBegin(petsc_gamg_setup_events[GAMG_MIS], 0, 0, 0, 0));
5172d776b49SBarry Smith   PetscCall(MatCoarsenSetGreedyOrdering(pc_gamg_agg->crs, perm));
5182d776b49SBarry Smith   PetscCall(MatCoarsenSetAdjacency(pc_gamg_agg->crs, Gmat1));
5192d776b49SBarry Smith   PetscCall(MatCoarsenSetStrictAggs(pc_gamg_agg->crs, PETSC_TRUE));
5202d776b49SBarry Smith   if (pc_gamg->current_level < pc_gamg_agg->aggressive_coarsening_levels) PetscCall(MatCoarsenMISKSetDistance(pc_gamg_agg->crs, 2)); // hardwire to MIS-2
5212d776b49SBarry Smith   else PetscCall(MatCoarsenMISKSetDistance(pc_gamg_agg->crs, 1));                                                                    // MIS
5222d776b49SBarry Smith   PetscCall(MatCoarsenApply(pc_gamg_agg->crs));
5232d776b49SBarry Smith   PetscCall(MatCoarsenViewFromOptions(pc_gamg_agg->crs, NULL, "-mat_coarsen_view"));
5242d776b49SBarry Smith   PetscCall(MatCoarsenGetData(pc_gamg_agg->crs, agg_lists)); /* output */
5252d776b49SBarry Smith   PetscCall(MatCoarsenDestroy(&pc_gamg_agg->crs));
526b43b03e9SMark F. Adams 
5279566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&perm));
528bae903cbSmarkadams4   PetscCall(PetscFree2(permute, degree));
529849bee69SMark Adams   PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_MIS], 0, 0, 0, 0));
5309f3f12c8SMark F. Adams 
531bae903cbSmarkadams4   {
532bae903cbSmarkadams4     PetscCoarsenData *llist = *agg_lists;
5339ab59c8bSMark Adams     /* see if we have a matrix that takes precedence (returned from MatCoarsenApply) */
5349566063dSJacob Faibussowitsch     PetscCall(PetscCDGetMat(llist, &mat));
5350cbbd2e1SMark F. Adams     if (mat) {
5369566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&Gmat1));
5370cbbd2e1SMark F. Adams       *a_Gmat1 = mat; /* output */
5380cbbd2e1SMark F. Adams     }
5390cbbd2e1SMark F. Adams   }
540849bee69SMark Adams   PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_COARSEN], 0, 0, 0, 0));
541*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
542c8b0795cSMark F. Adams }
543c8b0795cSMark F. Adams 
544c8b0795cSMark F. Adams /*
5450cbbd2e1SMark F. Adams  PCGAMGProlongator_AGG
546c8b0795cSMark F. Adams 
547c8b0795cSMark F. Adams  Input Parameter:
548c8b0795cSMark F. Adams  . pc - this
549c8b0795cSMark F. Adams  . Amat - matrix on this fine level
550c8b0795cSMark F. Adams  . Graph - used to get ghost data for nodes in
5510cbbd2e1SMark F. Adams  . agg_lists - list of aggregates
552c8b0795cSMark F. Adams  Output Parameter:
553c8b0795cSMark F. Adams  . a_P_out - prolongation operator to the next level
554c8b0795cSMark F. Adams  */
555d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGProlongator_AGG(PC pc, Mat Amat, Mat Gmat, PetscCoarsenData *agg_lists, Mat *a_P_out)
556d71ae5a4SJacob Faibussowitsch {
5572e68589bSMark F. Adams   PC_MG         *mg      = (PC_MG *)pc->data;
5582e68589bSMark F. Adams   PC_GAMG       *pc_gamg = (PC_GAMG *)mg->innerctx;
5594a2f8832SBarry Smith   const PetscInt col_bs  = pc_gamg->data_cell_cols;
560c8b0795cSMark F. Adams   PetscInt       Istart, Iend, nloc, ii, jj, kk, my0, nLocalSelected, bs;
561c8b0795cSMark F. Adams   Mat            Prol;
562d5d25401SBarry Smith   PetscMPIInt    size;
5633b4367a7SBarry Smith   MPI_Comm       comm;
564c8b0795cSMark F. Adams   PetscReal     *data_w_ghost;
565c8b0795cSMark F. Adams   PetscInt       myCrs0, nbnodes = 0, *flid_fgid;
566d9558ea9SBarry Smith   MatType        mtype;
5672e68589bSMark F. Adams 
5682e68589bSMark F. Adams   PetscFunctionBegin;
5699566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)Amat, &comm));
57008401ef6SPierre Jolivet   PetscCheck(col_bs >= 1, comm, PETSC_ERR_PLIB, "Column bs cannot be less than 1");
571849bee69SMark Adams   PetscCall(PetscLogEventBegin(petsc_gamg_setup_events[GAMG_PROL], 0, 0, 0, 0));
5729566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
5739566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(Amat, &Istart, &Iend));
5749566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(Amat, &bs));
5759371c9d4SSatish Balay   nloc = (Iend - Istart) / bs;
5769371c9d4SSatish Balay   my0  = Istart / bs;
57763a3b9bcSJacob Faibussowitsch   PetscCheck((Iend - Istart) % bs == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "(Iend %" PetscInt_FMT " - Istart %" PetscInt_FMT ") not divisible by bs %" PetscInt_FMT, Iend, Istart, bs);
5782e68589bSMark F. Adams 
5792e68589bSMark F. Adams   /* get 'nLocalSelected' */
5800cbbd2e1SMark F. Adams   for (ii = 0, nLocalSelected = 0; ii < nloc; ii++) {
581e78576d6SMark F. Adams     PetscBool ise;
5820cbbd2e1SMark F. Adams     /* filter out singletons 0 or 1? */
5839566063dSJacob Faibussowitsch     PetscCall(PetscCDEmptyAt(agg_lists, ii, &ise));
584e78576d6SMark F. Adams     if (!ise) nLocalSelected++;
5852e68589bSMark F. Adams   }
5862e68589bSMark F. Adams 
5872e68589bSMark F. Adams   /* create prolongator, create P matrix */
5889566063dSJacob Faibussowitsch   PetscCall(MatGetType(Amat, &mtype));
5899566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, &Prol));
5909566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(Prol, nloc * bs, nLocalSelected * col_bs, PETSC_DETERMINE, PETSC_DETERMINE));
5919566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizes(Prol, bs, col_bs));
5929566063dSJacob Faibussowitsch   PetscCall(MatSetType(Prol, mtype));
5939566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(Prol, col_bs, NULL));
5949566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(Prol, col_bs, NULL, col_bs, NULL));
5952e68589bSMark F. Adams 
5962e68589bSMark F. Adams   /* can get all points "removed" */
5979566063dSJacob Faibussowitsch   PetscCall(MatGetSize(Prol, &kk, &ii));
5987f66b68fSMark Adams   if (!ii) {
59963a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(pc, "%s: No selected points on coarse grid\n", ((PetscObject)pc)->prefix));
6009566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Prol));
6010298fd71SBarry Smith     *a_P_out = NULL; /* out */
602849bee69SMark Adams     PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_PROL], 0, 0, 0, 0));
603*3ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
6042e68589bSMark F. Adams   }
60563a3b9bcSJacob Faibussowitsch   PetscCall(PetscInfo(pc, "%s: New grid %" PetscInt_FMT " nodes\n", ((PetscObject)pc)->prefix, ii / col_bs));
6069566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(Prol, &myCrs0, &kk));
6070cbbd2e1SMark F. Adams 
60863a3b9bcSJacob Faibussowitsch   PetscCheck((kk - myCrs0) % col_bs == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "(kk %" PetscInt_FMT " -myCrs0 %" PetscInt_FMT ") not divisible by col_bs %" PetscInt_FMT, kk, myCrs0, col_bs);
609c8b0795cSMark F. Adams   myCrs0 = myCrs0 / col_bs;
61063a3b9bcSJacob Faibussowitsch   PetscCheck((kk / col_bs - myCrs0) == nLocalSelected, PETSC_COMM_SELF, PETSC_ERR_PLIB, "(kk %" PetscInt_FMT "/col_bs %" PetscInt_FMT " - myCrs0 %" PetscInt_FMT ") != nLocalSelected %" PetscInt_FMT ")", kk, col_bs, myCrs0, nLocalSelected);
6112e68589bSMark F. Adams 
6122e68589bSMark F. Adams   /* create global vector of data in 'data_w_ghost' */
613849bee69SMark Adams   PetscCall(PetscLogEventBegin(petsc_gamg_setup_events[GAMG_PROLA], 0, 0, 0, 0));
614bae903cbSmarkadams4   if (size > 1) { /* get ghost null space data */
6152e68589bSMark F. Adams     PetscReal *tmp_gdata, *tmp_ldata, *tp2;
6169566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nloc, &tmp_ldata));
6174a2f8832SBarry Smith     for (jj = 0; jj < col_bs; jj++) {
618c8b0795cSMark F. Adams       for (kk = 0; kk < bs; kk++) {
619a2f3521dSMark F. Adams         PetscInt         ii, stride;
620c8b0795cSMark F. Adams         const PetscReal *tp = pc_gamg->data + jj * bs * nloc + kk;
6212fa5cd67SKarl Rupp         for (ii = 0; ii < nloc; ii++, tp += bs) tmp_ldata[ii] = *tp;
6222fa5cd67SKarl Rupp 
6239566063dSJacob Faibussowitsch         PetscCall(PCGAMGGetDataWithGhosts(Gmat, 1, tmp_ldata, &stride, &tmp_gdata));
624a2f3521dSMark F. Adams 
625bae903cbSmarkadams4         if (!jj && !kk) { /* now I know how many total nodes - allocate TODO: move below and do in one 'col_bs' call */
6269566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(stride * bs * col_bs, &data_w_ghost));
627a2f3521dSMark F. Adams           nbnodes = bs * stride;
6282e68589bSMark F. Adams         }
629a2f3521dSMark F. Adams         tp2 = data_w_ghost + jj * bs * stride + kk;
6302fa5cd67SKarl Rupp         for (ii = 0; ii < stride; ii++, tp2 += bs) *tp2 = tmp_gdata[ii];
6319566063dSJacob Faibussowitsch         PetscCall(PetscFree(tmp_gdata));
6322e68589bSMark F. Adams       }
6332e68589bSMark F. Adams     }
6349566063dSJacob Faibussowitsch     PetscCall(PetscFree(tmp_ldata));
635806fa848SBarry Smith   } else {
636c8b0795cSMark F. Adams     nbnodes      = bs * nloc;
637c8b0795cSMark F. Adams     data_w_ghost = (PetscReal *)pc_gamg->data;
6382e68589bSMark F. Adams   }
6392e68589bSMark F. Adams 
640bae903cbSmarkadams4   /* get 'flid_fgid' TODO - move up to get 'stride' and do get null space data above in one step (jj loop) */
641c5df96a5SBarry Smith   if (size > 1) {
6422e68589bSMark F. Adams     PetscReal *fid_glid_loc, *fiddata;
643a2f3521dSMark F. Adams     PetscInt   stride;
6442e68589bSMark F. Adams 
6459566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nloc, &fid_glid_loc));
6462e68589bSMark F. Adams     for (kk = 0; kk < nloc; kk++) fid_glid_loc[kk] = (PetscReal)(my0 + kk);
6479566063dSJacob Faibussowitsch     PetscCall(PCGAMGGetDataWithGhosts(Gmat, 1, fid_glid_loc, &stride, &fiddata));
648bae903cbSmarkadams4     PetscCall(PetscMalloc1(stride, &flid_fgid)); /* copy real data to in */
649a2f3521dSMark F. Adams     for (kk = 0; kk < stride; kk++) flid_fgid[kk] = (PetscInt)fiddata[kk];
6509566063dSJacob Faibussowitsch     PetscCall(PetscFree(fiddata));
651a2f3521dSMark F. Adams 
65263a3b9bcSJacob Faibussowitsch     PetscCheck(stride == nbnodes / bs, PETSC_COMM_SELF, PETSC_ERR_PLIB, "stride %" PetscInt_FMT " != nbnodes %" PetscInt_FMT "/bs %" PetscInt_FMT, stride, nbnodes, bs);
6539566063dSJacob Faibussowitsch     PetscCall(PetscFree(fid_glid_loc));
654806fa848SBarry Smith   } else {
6559566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nloc, &flid_fgid));
6562e68589bSMark F. Adams     for (kk = 0; kk < nloc; kk++) flid_fgid[kk] = my0 + kk;
6572e68589bSMark F. Adams   }
658849bee69SMark Adams   PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_PROLA], 0, 0, 0, 0));
659bae903cbSmarkadams4   /* get P0 */
660849bee69SMark Adams   PetscCall(PetscLogEventBegin(petsc_gamg_setup_events[GAMG_PROLB], 0, 0, 0, 0));
661c8b0795cSMark F. Adams   {
6620298fd71SBarry Smith     PetscReal *data_out = NULL;
6639566063dSJacob Faibussowitsch     PetscCall(formProl0(agg_lists, bs, col_bs, myCrs0, nbnodes, data_w_ghost, flid_fgid, &data_out, Prol));
6649566063dSJacob Faibussowitsch     PetscCall(PetscFree(pc_gamg->data));
6652fa5cd67SKarl Rupp 
666c8b0795cSMark F. Adams     pc_gamg->data           = data_out;
6674a2f8832SBarry Smith     pc_gamg->data_cell_rows = col_bs;
6684a2f8832SBarry Smith     pc_gamg->data_sz        = col_bs * col_bs * nLocalSelected;
669c8b0795cSMark F. Adams   }
670849bee69SMark Adams   PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_PROLB], 0, 0, 0, 0));
67148a46eb9SPierre Jolivet   if (size > 1) PetscCall(PetscFree(data_w_ghost));
6729566063dSJacob Faibussowitsch   PetscCall(PetscFree(flid_fgid));
6732e68589bSMark F. Adams 
674c8b0795cSMark F. Adams   *a_P_out = Prol; /* out */
675ed4e82eaSPeter Brune 
676849bee69SMark Adams   PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_PROL], 0, 0, 0, 0));
677*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
678c8b0795cSMark F. Adams }
679c8b0795cSMark F. Adams 
680c8b0795cSMark F. Adams /*
681fd1112cbSBarry Smith    PCGAMGOptProlongator_AGG
682c8b0795cSMark F. Adams 
683c8b0795cSMark F. Adams   Input Parameter:
684c8b0795cSMark F. Adams    . pc - this
685c8b0795cSMark F. Adams    . Amat - matrix on this fine level
686c8b0795cSMark F. Adams  In/Output Parameter:
6872a808120SBarry Smith    . a_P - prolongation operator to the next level
688c8b0795cSMark F. Adams */
689d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGOptProlongator_AGG(PC pc, Mat Amat, Mat *a_P)
690d71ae5a4SJacob Faibussowitsch {
691c8b0795cSMark F. Adams   PC_MG       *mg          = (PC_MG *)pc->data;
692c8b0795cSMark F. Adams   PC_GAMG     *pc_gamg     = (PC_GAMG *)mg->innerctx;
693c8b0795cSMark F. Adams   PC_GAMG_AGG *pc_gamg_agg = (PC_GAMG_AGG *)pc_gamg->subctx;
694c8b0795cSMark F. Adams   PetscInt     jj;
695c8b0795cSMark F. Adams   Mat          Prol = *a_P;
6963b4367a7SBarry Smith   MPI_Comm     comm;
6972a808120SBarry Smith   KSP          eksp;
6982a808120SBarry Smith   Vec          bb, xx;
6992a808120SBarry Smith   PC           epc;
7002a808120SBarry Smith   PetscReal    alpha, emax, emin;
701c8b0795cSMark F. Adams 
702c8b0795cSMark F. Adams   PetscFunctionBegin;
7039566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)Amat, &comm));
704849bee69SMark Adams   PetscCall(PetscLogEventBegin(petsc_gamg_setup_events[GAMG_OPT], 0, 0, 0, 0));
705c8b0795cSMark F. Adams 
706d5d25401SBarry Smith   /* compute maximum singular value of operator to be used in smoother */
7072a808120SBarry Smith   if (0 < pc_gamg_agg->nsmooths) {
70818c3aa7eSMark     /* get eigen estimates */
70918c3aa7eSMark     if (pc_gamg->emax > 0) {
71018c3aa7eSMark       emin = pc_gamg->emin;
71118c3aa7eSMark       emax = pc_gamg->emax;
71218c3aa7eSMark     } else {
7130ed2132dSStefano Zampini       const char *prefix;
7140ed2132dSStefano Zampini 
7159566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(Amat, &bb, NULL));
7169566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(Amat, &xx, NULL));
7179566063dSJacob Faibussowitsch       PetscCall(KSPSetNoisy_Private(bb));
718e696ed0bSMark F. Adams 
7199566063dSJacob Faibussowitsch       PetscCall(KSPCreate(comm, &eksp));
7209566063dSJacob Faibussowitsch       PetscCall(PCGetOptionsPrefix(pc, &prefix));
7219566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(eksp, prefix));
7229566063dSJacob Faibussowitsch       PetscCall(KSPAppendOptionsPrefix(eksp, "pc_gamg_esteig_"));
72373f7197eSJed Brown       {
724b94d7dedSBarry Smith         PetscBool isset, sflg;
725b94d7dedSBarry Smith         PetscCall(MatIsSPDKnown(Amat, &isset, &sflg));
726b94d7dedSBarry Smith         if (isset && sflg) PetscCall(KSPSetType(eksp, KSPCG));
727d24ecf33SMark       }
7289566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(eksp, pc->erroriffailure));
7299566063dSJacob Faibussowitsch       PetscCall(KSPSetNormType(eksp, KSP_NORM_NONE));
730c2436cacSMark F. Adams 
7319566063dSJacob Faibussowitsch       PetscCall(KSPSetInitialGuessNonzero(eksp, PETSC_FALSE));
7329566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(eksp, Amat, Amat));
7332e68589bSMark F. Adams 
7349566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(eksp, &epc));
7359566063dSJacob Faibussowitsch       PetscCall(PCSetType(epc, PCJACOBI)); /* smoother in smoothed agg. */
736c2436cacSMark F. Adams 
7379566063dSJacob Faibussowitsch       PetscCall(KSPSetTolerances(eksp, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, 10)); // 10 is safer, but 5 is often fine, can override with -pc_gamg_esteig_ksp_max_it -mg_levels_ksp_chebyshev_esteig 0,0.25,0,1.2
738074aec55SMark Adams 
7399566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(eksp));
7409566063dSJacob Faibussowitsch       PetscCall(KSPSetComputeSingularValues(eksp, PETSC_TRUE));
7419566063dSJacob Faibussowitsch       PetscCall(KSPSolve(eksp, bb, xx));
7429566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(eksp, pc, xx));
7432e68589bSMark F. Adams 
7449566063dSJacob Faibussowitsch       PetscCall(KSPComputeExtremeSingularValues(eksp, &emax, &emin));
7459566063dSJacob Faibussowitsch       PetscCall(PetscInfo(pc, "%s: Smooth P0: max eigen=%e min=%e PC=%s\n", ((PetscObject)pc)->prefix, (double)emax, (double)emin, PCJACOBI));
7469566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&xx));
7479566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&bb));
7489566063dSJacob Faibussowitsch       PetscCall(KSPDestroy(&eksp));
7492e68589bSMark F. Adams     }
75018c3aa7eSMark     if (pc_gamg->use_sa_esteig) {
75118c3aa7eSMark       mg->min_eigen_DinvA[pc_gamg->current_level] = emin;
75218c3aa7eSMark       mg->max_eigen_DinvA[pc_gamg->current_level] = emax;
75363a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(pc, "%s: Smooth P0: level %" PetscInt_FMT ", cache spectra %g %g\n", ((PetscObject)pc)->prefix, pc_gamg->current_level, (double)emin, (double)emax));
75418c3aa7eSMark     } else {
75518c3aa7eSMark       mg->min_eigen_DinvA[pc_gamg->current_level] = 0;
75618c3aa7eSMark       mg->max_eigen_DinvA[pc_gamg->current_level] = 0;
75718c3aa7eSMark     }
75818c3aa7eSMark   } else {
75918c3aa7eSMark     mg->min_eigen_DinvA[pc_gamg->current_level] = 0;
76018c3aa7eSMark     mg->max_eigen_DinvA[pc_gamg->current_level] = 0;
76118c3aa7eSMark   }
7622e68589bSMark F. Adams 
7632a808120SBarry Smith   /* smooth P0 */
7642a808120SBarry Smith   for (jj = 0; jj < pc_gamg_agg->nsmooths; jj++) {
7652a808120SBarry Smith     Mat tMat;
7662a808120SBarry Smith     Vec diag;
7672a808120SBarry Smith 
768849bee69SMark Adams     PetscCall(PetscLogEventBegin(petsc_gamg_setup_events[GAMG_OPTSM], 0, 0, 0, 0));
7692a808120SBarry Smith 
7702e68589bSMark F. Adams     /* smooth P1 := (I - omega/lam D^{-1}A)P0 */
7719566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(petsc_gamg_setup_matmat_events[pc_gamg->current_level][2], 0, 0, 0, 0));
7729566063dSJacob Faibussowitsch     PetscCall(MatMatMult(Amat, Prol, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &tMat));
7739566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(petsc_gamg_setup_matmat_events[pc_gamg->current_level][2], 0, 0, 0, 0));
7749566063dSJacob Faibussowitsch     PetscCall(MatProductClear(tMat));
7759566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(Amat, &diag, NULL));
7769566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(Amat, diag)); /* effectively PCJACOBI */
7779566063dSJacob Faibussowitsch     PetscCall(VecReciprocal(diag));
7789566063dSJacob Faibussowitsch     PetscCall(MatDiagonalScale(tMat, diag, NULL));
7799566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&diag));
780b4da3a1bSStefano Zampini 
781d5d25401SBarry Smith     /* TODO: Set a PCFailedReason and exit the building of the AMG preconditioner */
78208401ef6SPierre Jolivet     PetscCheck(emax != 0.0, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Computed maximum singular value as zero");
783d5d25401SBarry Smith     /* TODO: Document the 1.4 and don't hardwire it in this routine */
784b4ec6429SMark F. Adams     alpha = -1.4 / emax;
785b4da3a1bSStefano Zampini 
7869566063dSJacob Faibussowitsch     PetscCall(MatAYPX(tMat, alpha, Prol, SUBSET_NONZERO_PATTERN));
7879566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&Prol));
7882e68589bSMark F. Adams     Prol = tMat;
789849bee69SMark Adams     PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_OPTSM], 0, 0, 0, 0));
7902e68589bSMark F. Adams   }
791849bee69SMark Adams   PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_OPT], 0, 0, 0, 0));
792c8b0795cSMark F. Adams   *a_P = Prol;
793*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7942e68589bSMark F. Adams }
7952e68589bSMark F. Adams 
796c8b0795cSMark F. Adams /*
797c8b0795cSMark F. Adams    PCCreateGAMG_AGG
7982e68589bSMark F. Adams 
799c8b0795cSMark F. Adams   Input Parameter:
800c8b0795cSMark F. Adams    . pc -
801c8b0795cSMark F. Adams */
802d71ae5a4SJacob Faibussowitsch PetscErrorCode PCCreateGAMG_AGG(PC pc)
803d71ae5a4SJacob Faibussowitsch {
804c8b0795cSMark F. Adams   PC_MG       *mg      = (PC_MG *)pc->data;
805c8b0795cSMark F. Adams   PC_GAMG     *pc_gamg = (PC_GAMG *)mg->innerctx;
806c8b0795cSMark F. Adams   PC_GAMG_AGG *pc_gamg_agg;
8072e68589bSMark F. Adams 
808c8b0795cSMark F. Adams   PetscFunctionBegin;
809c8b0795cSMark F. Adams   /* create sub context for SA */
8104dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&pc_gamg_agg));
811c8b0795cSMark F. Adams   pc_gamg->subctx = pc_gamg_agg;
812c8b0795cSMark F. Adams 
8131ab5ffc9SJed Brown   pc_gamg->ops->setfromoptions = PCSetFromOptions_GAMG_AGG;
8149b8ffb57SJed Brown   pc_gamg->ops->destroy        = PCDestroy_GAMG_AGG;
815c8b0795cSMark F. Adams   /* reset does not do anything; setup not virtual */
816c8b0795cSMark F. Adams 
817c8b0795cSMark F. Adams   /* set internal function pointers */
8182d776b49SBarry Smith   pc_gamg->ops->creategraph       = PCGAMGCreateGraph_AGG;
8191ab5ffc9SJed Brown   pc_gamg->ops->coarsen           = PCGAMGCoarsen_AGG;
8201ab5ffc9SJed Brown   pc_gamg->ops->prolongator       = PCGAMGProlongator_AGG;
821fd1112cbSBarry Smith   pc_gamg->ops->optprolongator    = PCGAMGOptProlongator_AGG;
8221ab5ffc9SJed Brown   pc_gamg->ops->createdefaultdata = PCSetData_AGG;
8235adeb434SBarry Smith   pc_gamg->ops->view              = PCView_GAMG_AGG;
824c8b0795cSMark F. Adams 
825599482c2Smarkadams4   pc_gamg_agg->aggressive_coarsening_levels = 1;
826cab9ed1eSBarry Smith   pc_gamg_agg->nsmooths                     = 1;
827cab9ed1eSBarry Smith 
8289566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetNSmooths_C", PCGAMGSetNSmooths_AGG));
829bae903cbSmarkadams4   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetAggressiveLevels_C", PCGAMGSetAggressiveLevels_AGG));
8309566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", PCSetCoordinates_AGG));
831*3ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
8322e68589bSMark F. Adams }
833