xref: /petsc/src/ksp/pc/impls/gamg/gamg.c (revision 6c34c54da54b871490d53431febd29f9a9a182eb)
15b89ad90SMark F. Adams /*
20cd22d39SHong Zhang  GAMG geometric-algebric multigrid PC - Mark Adams 2011
35b89ad90SMark F. Adams  */
4389730f3SMark F. Adams #include <../src/ksp/pc/impls/gamg/gamg.h>            /*I "petscpc.h" I*/
518c3aa7eSMark #include <../src/ksp/ksp/impls/cheby/chebyshevimpl.h> /*I "petscksp.h" I*/
6f96513f1SMatthew G Knepley 
7c9567895SMark #if defined(PETSC_HAVE_CUDA)
8c9567895SMark   #include <cuda_runtime.h>
9c9567895SMark #endif
10c9567895SMark 
11c9567895SMark #if defined(PETSC_HAVE_HIP)
12c9567895SMark   #include <hip/hip_runtime.h>
13c9567895SMark #endif
14c9567895SMark 
15849bee69SMark Adams PetscLogEvent petsc_gamg_setup_events[GAMG_NUM_SET];
164555aa8cSStefano Zampini PetscLogEvent petsc_gamg_setup_matmat_events[PETSC_MG_MAXLEVELS][3];
170cbbd2e1SMark F. Adams 
18849bee69SMark Adams // #define GAMG_STAGES
194555aa8cSStefano Zampini #if defined(GAMG_STAGES)
2018c3aa7eSMark static PetscLogStage gamg_stages[PETSC_MG_MAXLEVELS];
21b4fbaa2aSMark F. Adams #endif
22f96513f1SMatthew G Knepley 
230a545947SLisandro Dalcin static PetscFunctionList GAMGList = NULL;
243e3471ccSMark Adams static PetscBool         PCGAMGPackageInitialized;
259d5b6da9SMark F. Adams 
2666976f2fSJacob Faibussowitsch static PetscErrorCode PCReset_GAMG(PC pc)
27d71ae5a4SJacob Faibussowitsch {
28d3d6bff4SMark F. Adams   PC_MG   *mg      = (PC_MG *)pc->data;
29d3d6bff4SMark F. Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
30d3d6bff4SMark F. Adams 
31d3d6bff4SMark F. Adams   PetscFunctionBegin;
329566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc_gamg->data));
331c1aac46SBarry Smith   pc_gamg->data_sz = 0;
349566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc_gamg->orig_data));
355f80ce2aSJacob Faibussowitsch   for (PetscInt level = 0; level < PETSC_MG_MAXLEVELS; level++) {
3618c3aa7eSMark     mg->min_eigen_DinvA[level] = 0;
3718c3aa7eSMark     mg->max_eigen_DinvA[level] = 0;
3818c3aa7eSMark   }
3918c3aa7eSMark   pc_gamg->emin = 0;
4018c3aa7eSMark   pc_gamg->emax = 0;
41978e3cbaSStefano Zampini   PetscCall(PCReset_MG(pc));
42e0b7e82fSBarry Smith   PetscCall(MatCoarsenDestroy(&pc_gamg->asm_crs));
433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
44a2f3521dSMark F. Adams }
45a2f3521dSMark F. Adams 
465b89ad90SMark F. Adams /*
47c238b0ebSToby Isaac    PCGAMGCreateLevel_GAMG: create coarse op with RAP.  repartition and/or reduce number
48a147abb0SMark F. Adams      of active processors.
495b89ad90SMark F. Adams 
505b89ad90SMark F. Adams    Input Parameter:
51a2f3521dSMark F. Adams    . pc - parameters + side effect: coarse data in 'pc_gamg->data' and
52a2f3521dSMark F. Adams           'pc_gamg->data_sz' are changed via repartitioning/reduction.
539d5b6da9SMark F. Adams    . Amat_fine - matrix on this fine (k) level
54c5bfad50SMark F. Adams    . cr_bs - coarse block size
553530afc2SMark F. Adams    In/Output Parameter:
56a2f3521dSMark F. Adams    . a_P_inout - prolongation operator to the next level (k-->k-1)
57afc97cdcSMark F. Adams    . a_nactive_proc - number of active procs
5811e60469SMark F. Adams    Output Parameter:
593530afc2SMark F. Adams    . a_Amat_crs - coarse matrix that is created (k-1)
605b89ad90SMark F. Adams */
61d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGCreateLevel_GAMG(PC pc, Mat Amat_fine, PetscInt cr_bs, Mat *a_P_inout, Mat *a_Amat_crs, PetscMPIInt *a_nactive_proc, IS *Pcolumnperm, PetscBool is_last)
62d71ae5a4SJacob Faibussowitsch {
639d5b6da9SMark F. Adams   PC_MG      *mg      = (PC_MG *)pc->data;
64486a8d0bSJed Brown   PC_GAMG    *pc_gamg = (PC_GAMG *)mg->innerctx;
65*6c34c54dSStefano Zampini   Mat         Cmat = NULL, Pold = *a_P_inout;
663b4367a7SBarry Smith   MPI_Comm    comm;
67c5df96a5SBarry Smith   PetscMPIInt rank, size, new_size, nactive = *a_nactive_proc;
683ae0bb68SMark Adams   PetscInt    ncrs_eq, ncrs, f_bs;
695b89ad90SMark F. Adams 
705b89ad90SMark F. Adams   PetscFunctionBegin;
719566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)Amat_fine, &comm));
729566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
739566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
749566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(Amat_fine, &f_bs));
75038e3b61SMark F. Adams 
76ce7c7f2fSMark Adams   if (Pcolumnperm) *Pcolumnperm = NULL;
77ce7c7f2fSMark Adams 
783ae0bb68SMark Adams   /* set 'ncrs' (nodes), 'ncrs_eq' (equations)*/
79*6c34c54dSStefano Zampini   PetscCall(MatGetLocalSize(Pold, NULL, &ncrs_eq));
803ae0bb68SMark Adams   if (pc_gamg->data_cell_rows > 0) {
813ae0bb68SMark Adams     ncrs = pc_gamg->data_sz / pc_gamg->data_cell_cols / pc_gamg->data_cell_rows;
8273911c69SBarry Smith   } else {
833ae0bb68SMark Adams     PetscInt bs;
84*6c34c54dSStefano Zampini     PetscCall(MatGetBlockSizes(Pold, NULL, &bs));
853ae0bb68SMark Adams     ncrs = ncrs_eq / bs;
863ae0bb68SMark Adams   }
87c5df96a5SBarry Smith   /* get number of PEs to make active 'new_size', reduce, can be any integer 1-P */
88c9567895SMark   if (pc_gamg->level_reduction_factors[pc_gamg->current_level] == 0 && PetscDefined(HAVE_CUDA) && pc_gamg->current_level == 0) { /* 0 turns reducing to 1 process/device on; do for HIP, etc. */
89c9567895SMark #if defined(PETSC_HAVE_CUDA)
90c9567895SMark     PetscShmComm pshmcomm;
91c9567895SMark     PetscMPIInt  locrank;
92c9567895SMark     MPI_Comm     loccomm;
93c9567895SMark     PetscInt     s_nnodes, r_nnodes, new_new_size;
94c9567895SMark     cudaError_t  cerr;
95c9567895SMark     int          devCount;
969566063dSJacob Faibussowitsch     PetscCall(PetscShmCommGet(comm, &pshmcomm));
979566063dSJacob Faibussowitsch     PetscCall(PetscShmCommGetMpiShmComm(pshmcomm, &loccomm));
989566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(loccomm, &locrank));
99c9567895SMark     s_nnodes = !locrank;
100712fec58SPierre Jolivet     PetscCall(MPIU_Allreduce(&s_nnodes, &r_nnodes, 1, MPIU_INT, MPI_SUM, comm));
10163a3b9bcSJacob Faibussowitsch     PetscCheck((size % r_nnodes) == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "odd number of nodes np=%d nnodes%" PetscInt_FMT, size, r_nnodes);
102c9567895SMark     devCount = 0;
103c9567895SMark     cerr     = cudaGetDeviceCount(&devCount);
104c9567895SMark     cudaGetLastError();                         /* Reset the last error */
105c9567895SMark     if (cerr == cudaSuccess && devCount >= 1) { /* There are devices, else go to heuristic */
106c9567895SMark       new_new_size = r_nnodes * devCount;
107c9567895SMark       new_size     = new_new_size;
10863a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(pc, "%s: Fine grid with Cuda. %" PetscInt_FMT " nodes. Change new active set size %d --> %d (devCount=%d #nodes=%" PetscInt_FMT ")\n", ((PetscObject)pc)->prefix, r_nnodes, nactive, new_size, devCount, r_nnodes));
109c9567895SMark     } else {
1109d3446b2SPierre Jolivet       PetscCall(PetscInfo(pc, "%s: With Cuda but no device. Use heuristics.\n", ((PetscObject)pc)->prefix));
111c9567895SMark       goto HEURISTIC;
112c9567895SMark     }
113c9567895SMark #else
114c9567895SMark     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "should not be here");
115c9567895SMark #endif
116c9567895SMark   } else if (pc_gamg->level_reduction_factors[pc_gamg->current_level] > 0) {
1177509f629SMark Adams     if (nactive < pc_gamg->level_reduction_factors[pc_gamg->current_level]) {
1187509f629SMark Adams       new_size = 1;
1197509f629SMark Adams       PetscCall(PetscInfo(pc, "%s: reduction factor too small for %d active processes: reduce to one process\n", ((PetscObject)pc)->prefix, new_size));
1207509f629SMark Adams     } else {
12163a3b9bcSJacob Faibussowitsch       PetscCheck(nactive % pc_gamg->level_reduction_factors[pc_gamg->current_level] == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "odd number of active process %d wrt reduction factor %" PetscInt_FMT, nactive, pc_gamg->level_reduction_factors[pc_gamg->current_level]);
122c9567895SMark       new_size = nactive / pc_gamg->level_reduction_factors[pc_gamg->current_level];
12363a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(pc, "%s: Manually setting reduction to %d active processes (%d/%" PetscInt_FMT ")\n", ((PetscObject)pc)->prefix, new_size, nactive, pc_gamg->level_reduction_factors[pc_gamg->current_level]));
1247509f629SMark Adams     }
125c9567895SMark   } else if (is_last && !pc_gamg->use_parallel_coarse_grid_solver) {
126c9567895SMark     new_size = 1;
1279566063dSJacob Faibussowitsch     PetscCall(PetscInfo(pc, "%s: Force coarsest grid reduction to %d active processes\n", ((PetscObject)pc)->prefix, new_size));
128c9567895SMark   } else {
129472110cdSMark F. Adams     PetscInt ncrs_eq_glob;
130c9567895SMark #if defined(PETSC_HAVE_CUDA)
131c9567895SMark   HEURISTIC:
132c9567895SMark #endif
133*6c34c54dSStefano Zampini     PetscCall(MatGetSize(Pold, NULL, &ncrs_eq_glob));
134a90e85d9SMark Adams     new_size = (PetscMPIInt)((float)ncrs_eq_glob / (float)pc_gamg->min_eq_proc + 0.5); /* hardwire min. number of eq/proc */
135da81f932SPierre Jolivet     if (!new_size) new_size = 1;                                                       /* not likely, possible? */
136c5df96a5SBarry Smith     else if (new_size >= nactive) new_size = nactive;                                  /* no change, rare */
1379566063dSJacob Faibussowitsch     PetscCall(PetscInfo(pc, "%s: Coarse grid reduction from %d to %d active processes\n", ((PetscObject)pc)->prefix, nactive, new_size));
138a2f3521dSMark F. Adams   }
1392e3501ffSMark Adams   if (new_size == nactive) {
140*6c34c54dSStefano Zampini     /* output - no repartitioning or reduction - could bail here
141*6c34c54dSStefano Zampini        we know that the grid structure can be reused in MatPtAP */
142*6c34c54dSStefano Zampini     PetscCall(PetscLogEventBegin(petsc_gamg_setup_events[GAMG_PTAP], 0, 0, 0, 0));
143*6c34c54dSStefano Zampini     PetscCall(PetscLogEventBegin(petsc_gamg_setup_matmat_events[pc_gamg->current_level][1], 0, 0, 0, 0));
144*6c34c54dSStefano Zampini     PetscCall(MatPtAP(Amat_fine, Pold, MAT_INITIAL_MATRIX, 2.0, a_Amat_crs));
145*6c34c54dSStefano Zampini     PetscCall(PetscLogEventEnd(petsc_gamg_setup_matmat_events[pc_gamg->current_level][1], 0, 0, 0, 0));
146*6c34c54dSStefano Zampini     PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_PTAP], 0, 0, 0, 0));
147ce7c7f2fSMark Adams     if (new_size < size) {
148ce7c7f2fSMark Adams       /* odd case where multiple coarse grids are on one processor or no coarsening ... */
1499566063dSJacob Faibussowitsch       PetscCall(PetscInfo(pc, "%s: reduced grid using same number of processors (%d) as last grid (use larger coarse grid)\n", ((PetscObject)pc)->prefix, nactive));
150ce7c7f2fSMark Adams       if (pc_gamg->cpu_pin_coarse_grids) {
1519566063dSJacob Faibussowitsch         PetscCall(MatBindToCPU(*a_Amat_crs, PETSC_TRUE));
1529566063dSJacob Faibussowitsch         PetscCall(MatBindToCPU(*a_P_inout, PETSC_TRUE));
153ce7c7f2fSMark Adams       }
154ce7c7f2fSMark Adams     }
1552e3501ffSMark Adams   } else { /* reduce active processors - we know that the grid structure can NOT be reused in MatPtAP */
156192c0e8bSMark Adams     PetscInt *counts, *newproc_idx, ii, jj, kk, strideNew, *tidx, ncrs_new, ncrs_eq_new, nloc_old, expand_factor = 1, rfactor = 1;
157*6c34c54dSStefano Zampini     IS        is_eq_newproc, is_eq_num, new_eq_indices;
158849bee69SMark Adams     PetscCall(PetscLogEventBegin(petsc_gamg_setup_events[GAMG_REDUCE], 0, 0, 0, 0));
15971959b99SBarry Smith     nloc_old = ncrs_eq / cr_bs;
16063a3b9bcSJacob Faibussowitsch     PetscCheck(ncrs_eq % cr_bs == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "ncrs_eq %" PetscInt_FMT " not divisible by cr_bs %" PetscInt_FMT, ncrs_eq, cr_bs);
161ce7c7f2fSMark Adams     /* get new_size and rfactor */
162ce7c7f2fSMark Adams     if (pc_gamg->layout_type == PCGAMG_LAYOUT_SPREAD || !pc_gamg->repart) {
163ce7c7f2fSMark Adams       /* find factor */
164ce7c7f2fSMark Adams       if (new_size == 1) rfactor = size; /* don't modify */
165ce7c7f2fSMark Adams       else {
166ce7c7f2fSMark Adams         PetscReal best_fact = 0.;
167ce7c7f2fSMark Adams         jj                  = -1;
168ce7c7f2fSMark Adams         for (kk = 1; kk <= size; kk++) {
169ce7c7f2fSMark Adams           if (!(size % kk)) { /* a candidate */
170ce7c7f2fSMark Adams             PetscReal nactpe = (PetscReal)size / (PetscReal)kk, fact = nactpe / (PetscReal)new_size;
171ce7c7f2fSMark Adams             if (fact > 1.0) fact = 1. / fact; /* keep fact < 1 */
172ce7c7f2fSMark Adams             if (fact > best_fact) {
1739371c9d4SSatish Balay               best_fact = fact;
1749371c9d4SSatish Balay               jj        = kk;
175ce7c7f2fSMark Adams             }
176ce7c7f2fSMark Adams           }
177ce7c7f2fSMark Adams         }
178ce7c7f2fSMark Adams         if (jj != -1) rfactor = jj;
179ce7c7f2fSMark Adams         else rfactor = 1; /* a prime */
180ce7c7f2fSMark Adams         if (pc_gamg->layout_type == PCGAMG_LAYOUT_COMPACT) expand_factor = 1;
181ce7c7f2fSMark Adams         else expand_factor = rfactor;
182ce7c7f2fSMark Adams       }
183ce7c7f2fSMark Adams       new_size = size / rfactor; /* make new size one that is factor */
1844cdfd227SMark       if (new_size == nactive) { /* no repartitioning or reduction, bail out because nested here (rare) */
18563a3b9bcSJacob Faibussowitsch         PetscCall(PetscInfo(pc, "%s: Finding factorable processor set stopped reduction: new_size=%d, neq(loc)=%" PetscInt_FMT "\n", ((PetscObject)pc)->prefix, new_size, ncrs_eq));
186849bee69SMark Adams         PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_REDUCE], 0, 0, 0, 0));
187*6c34c54dSStefano Zampini         PetscCall(PetscLogEventBegin(petsc_gamg_setup_events[GAMG_PTAP], 0, 0, 0, 0));
188*6c34c54dSStefano Zampini         PetscCall(PetscLogEventBegin(petsc_gamg_setup_matmat_events[pc_gamg->current_level][1], 0, 0, 0, 0));
189*6c34c54dSStefano Zampini         PetscCall(MatPtAP(Amat_fine, Pold, MAT_INITIAL_MATRIX, 2.0, a_Amat_crs));
190*6c34c54dSStefano Zampini         PetscCall(PetscLogEventEnd(petsc_gamg_setup_matmat_events[pc_gamg->current_level][1], 0, 0, 0, 0));
191*6c34c54dSStefano Zampini         PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_PTAP], 0, 0, 0, 0));
1923ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
193ce7c7f2fSMark Adams       }
194ce7c7f2fSMark Adams     }
195a2f3521dSMark F. Adams     /* make 'is_eq_newproc' */
196849bee69SMark Adams     if (pc_gamg->repart) { /* Repartition Cmat_{k} and move columns of P^{k}_{k-1} and coordinates of primal part accordingly */
1975a9b9e01SMark F. Adams       Mat adj;
198*6c34c54dSStefano Zampini 
199*6c34c54dSStefano Zampini       PetscCall(PetscLogEventBegin(petsc_gamg_setup_events[GAMG_PTAP], 0, 0, 0, 0));
200*6c34c54dSStefano Zampini       PetscCall(PetscLogEventBegin(petsc_gamg_setup_matmat_events[pc_gamg->current_level][1], 0, 0, 0, 0));
201*6c34c54dSStefano Zampini       PetscCall(MatPtAP(Amat_fine, Pold, MAT_INITIAL_MATRIX, 2.0, &Cmat));
202*6c34c54dSStefano Zampini       PetscCall(PetscLogEventEnd(petsc_gamg_setup_matmat_events[pc_gamg->current_level][1], 0, 0, 0, 0));
203*6c34c54dSStefano Zampini       PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_PTAP], 0, 0, 0, 0));
204849bee69SMark Adams       PetscCall(PetscLogEventBegin(petsc_gamg_setup_events[GAMG_REPART], 0, 0, 0, 0));
20563a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(pc, "%s: Repartition: size (active): %d --> %d, %" PetscInt_FMT " local equations, using %s process layout\n", ((PetscObject)pc)->prefix, *a_nactive_proc, new_size, ncrs_eq, (pc_gamg->layout_type == PCGAMG_LAYOUT_COMPACT) ? "compact" : "spread"));
206a2f3521dSMark F. Adams       /* get 'adj' */
207c5bfad50SMark F. Adams       if (cr_bs == 1) {
2089566063dSJacob Faibussowitsch         PetscCall(MatConvert(Cmat, MATMPIADJ, MAT_INITIAL_MATRIX, &adj));
209806fa848SBarry Smith       } else {
210a2f3521dSMark F. Adams         /* make a scalar matrix to partition (no Stokes here) */
211eb07cef2SMark F. Adams         Mat                tMat;
212a2f3521dSMark F. Adams         PetscInt           Istart_crs, Iend_crs, ncols, jj, Ii;
213b4fbaa2aSMark F. Adams         const PetscScalar *vals;
214b4fbaa2aSMark F. Adams         const PetscInt    *idx;
215a2f3521dSMark F. Adams         PetscInt          *d_nnz, *o_nnz, M, N;
21639d09545SMark Adams         static PetscInt    llev = 0; /* ugly but just used for debugging */
217d9558ea9SBarry Smith         MatType            mtype;
218b4fbaa2aSMark F. Adams 
2199566063dSJacob Faibussowitsch         PetscCall(PetscMalloc2(ncrs, &d_nnz, ncrs, &o_nnz));
2209566063dSJacob Faibussowitsch         PetscCall(MatGetOwnershipRange(Cmat, &Istart_crs, &Iend_crs));
2219566063dSJacob Faibussowitsch         PetscCall(MatGetSize(Cmat, &M, &N));
222c5bfad50SMark F. Adams         for (Ii = Istart_crs, jj = 0; Ii < Iend_crs; Ii += cr_bs, jj++) {
2239566063dSJacob Faibussowitsch           PetscCall(MatGetRow(Cmat, Ii, &ncols, NULL, NULL));
224c5bfad50SMark F. Adams           d_nnz[jj] = ncols / cr_bs;
225c5bfad50SMark F. Adams           o_nnz[jj] = ncols / cr_bs;
2269566063dSJacob Faibussowitsch           PetscCall(MatRestoreRow(Cmat, Ii, &ncols, NULL, NULL));
2273ae0bb68SMark Adams           if (d_nnz[jj] > ncrs) d_nnz[jj] = ncrs;
2283ae0bb68SMark Adams           if (o_nnz[jj] > (M / cr_bs - ncrs)) o_nnz[jj] = M / cr_bs - ncrs;
22958471d46SMark F. Adams         }
2306876a03eSMark F. Adams 
2319566063dSJacob Faibussowitsch         PetscCall(MatGetType(Amat_fine, &mtype));
2329566063dSJacob Faibussowitsch         PetscCall(MatCreate(comm, &tMat));
2339566063dSJacob Faibussowitsch         PetscCall(MatSetSizes(tMat, ncrs, ncrs, PETSC_DETERMINE, PETSC_DETERMINE));
2349566063dSJacob Faibussowitsch         PetscCall(MatSetType(tMat, mtype));
2359566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJSetPreallocation(tMat, 0, d_nnz));
2369566063dSJacob Faibussowitsch         PetscCall(MatMPIAIJSetPreallocation(tMat, 0, d_nnz, 0, o_nnz));
2379566063dSJacob Faibussowitsch         PetscCall(PetscFree2(d_nnz, o_nnz));
238eb07cef2SMark F. Adams 
239a2f3521dSMark F. Adams         for (ii = Istart_crs; ii < Iend_crs; ii++) {
240c5bfad50SMark F. Adams           PetscInt dest_row = ii / cr_bs;
2419566063dSJacob Faibussowitsch           PetscCall(MatGetRow(Cmat, ii, &ncols, &idx, &vals));
242eb07cef2SMark F. Adams           for (jj = 0; jj < ncols; jj++) {
243c5bfad50SMark F. Adams             PetscInt    dest_col = idx[jj] / cr_bs;
244eb07cef2SMark F. Adams             PetscScalar v        = 1.0;
2459566063dSJacob Faibussowitsch             PetscCall(MatSetValues(tMat, 1, &dest_row, 1, &dest_col, &v, ADD_VALUES));
246eb07cef2SMark F. Adams           }
2479566063dSJacob Faibussowitsch           PetscCall(MatRestoreRow(Cmat, ii, &ncols, &idx, &vals));
248eb07cef2SMark F. Adams         }
2499566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(tMat, MAT_FINAL_ASSEMBLY));
2509566063dSJacob Faibussowitsch         PetscCall(MatAssemblyEnd(tMat, MAT_FINAL_ASSEMBLY));
251eb07cef2SMark F. Adams 
252b4fbaa2aSMark F. Adams         if (llev++ == -1) {
2539371c9d4SSatish Balay           PetscViewer viewer;
2549371c9d4SSatish Balay           char        fname[32];
25563a3b9bcSJacob Faibussowitsch           PetscCall(PetscSNPrintf(fname, sizeof(fname), "part_mat_%" PetscInt_FMT ".mat", llev));
2563ba16761SJacob Faibussowitsch           PetscCall(PetscViewerBinaryOpen(comm, fname, FILE_MODE_WRITE, &viewer));
2579566063dSJacob Faibussowitsch           PetscCall(MatView(tMat, viewer));
2589566063dSJacob Faibussowitsch           PetscCall(PetscViewerDestroy(&viewer));
259b4fbaa2aSMark F. Adams         }
2609566063dSJacob Faibussowitsch         PetscCall(MatConvert(tMat, MATMPIADJ, MAT_INITIAL_MATRIX, &adj));
2619566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&tMat));
262a2f3521dSMark F. Adams       } /* create 'adj' */
263f150b916SMark F. Adams 
264a2f3521dSMark F. Adams       { /* partition: get newproc_idx */
2655a9b9e01SMark F. Adams         char            prefix[256];
2665a9b9e01SMark F. Adams         const char     *pcpre;
267b4fbaa2aSMark F. Adams         const PetscInt *is_idx;
268b4fbaa2aSMark F. Adams         MatPartitioning mpart;
269a4b7d37bSMark F. Adams         IS              proc_is;
2702f03bc48SMark F. Adams 
2719566063dSJacob Faibussowitsch         PetscCall(MatPartitioningCreate(comm, &mpart));
2729566063dSJacob Faibussowitsch         PetscCall(MatPartitioningSetAdjacency(mpart, adj));
2739566063dSJacob Faibussowitsch         PetscCall(PCGetOptionsPrefix(pc, &pcpre));
2749566063dSJacob Faibussowitsch         PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%spc_gamg_", pcpre ? pcpre : ""));
2759566063dSJacob Faibussowitsch         PetscCall(PetscObjectSetOptionsPrefix((PetscObject)mpart, prefix));
2769566063dSJacob Faibussowitsch         PetscCall(MatPartitioningSetFromOptions(mpart));
2779566063dSJacob Faibussowitsch         PetscCall(MatPartitioningSetNParts(mpart, new_size));
2789566063dSJacob Faibussowitsch         PetscCall(MatPartitioningApply(mpart, &proc_is));
2799566063dSJacob Faibussowitsch         PetscCall(MatPartitioningDestroy(&mpart));
2805a9b9e01SMark F. Adams 
2815ef31b24SMark F. Adams         /* collect IS info */
2829566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(ncrs_eq, &newproc_idx));
2839566063dSJacob Faibussowitsch         PetscCall(ISGetIndices(proc_is, &is_idx));
284a2f3521dSMark F. Adams         for (kk = jj = 0; kk < nloc_old; kk++) {
2859371c9d4SSatish Balay           for (ii = 0; ii < cr_bs; ii++, jj++) { newproc_idx[jj] = is_idx[kk] * expand_factor; /* distribution */ }
2865ef31b24SMark F. Adams         }
2879566063dSJacob Faibussowitsch         PetscCall(ISRestoreIndices(proc_is, &is_idx));
2889566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&proc_is));
2895ef31b24SMark F. Adams       }
2909566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&adj));
2915a9b9e01SMark F. Adams 
292*6c34c54dSStefano Zampini       PetscCall(ISCreateGeneral(comm, ncrs_eq, newproc_idx, PETSC_OWN_POINTER, &is_eq_newproc));
29311e60469SMark F. Adams       /*
294a2f3521dSMark F. Adams         Create an index set from the is_eq_newproc index set to indicate the mapping TO
29511e60469SMark F. Adams       */
2969566063dSJacob Faibussowitsch       PetscCall(ISPartitioningToNumbering(is_eq_newproc, &is_eq_num));
29711e60469SMark F. Adams       /*
298a2f3521dSMark F. Adams         Determine how many equations/vertices are assigned to each processor
29911e60469SMark F. Adams       */
300*6c34c54dSStefano Zampini       PetscCall(PetscMalloc1(size, &counts));
3019566063dSJacob Faibussowitsch       PetscCall(ISPartitioningCount(is_eq_newproc, size, counts));
302c5df96a5SBarry Smith       ncrs_eq_new = counts[rank];
3039566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&is_eq_newproc));
304*6c34c54dSStefano Zampini       PetscCall(PetscFree(counts));
305*6c34c54dSStefano Zampini       PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_REPART], 0, 0, 0, 0));
306*6c34c54dSStefano Zampini     } else { /* simple aggregation of parts -- 'is_eq_newproc' */
307*6c34c54dSStefano Zampini       const PetscInt *ranges;
308*6c34c54dSStefano Zampini       PetscInt        newstart = 0;
309*6c34c54dSStefano Zampini       PetscLayout     ilay;
310*6c34c54dSStefano Zampini 
311*6c34c54dSStefano Zampini       PetscCheck(new_size != nactive, PETSC_COMM_SELF, PETSC_ERR_PLIB, "new_size==nactive. Should not happen");
312*6c34c54dSStefano Zampini       PetscCall(PetscInfo(pc, "%s: Number of equations (loc) %" PetscInt_FMT " with simple aggregation\n", ((PetscObject)pc)->prefix, ncrs_eq));
313*6c34c54dSStefano Zampini       PetscCallMPI(MPI_Exscan(&ncrs_eq, &newstart, 1, MPIU_INT, MPI_SUM, comm));
314*6c34c54dSStefano Zampini       PetscCall(ISCreateStride(comm, ncrs_eq, newstart, 1, &is_eq_num));
315*6c34c54dSStefano Zampini       PetscCall(ISSetPermutation(is_eq_num));
316*6c34c54dSStefano Zampini       PetscCall(ISGetLayout(is_eq_num, &ilay));
317*6c34c54dSStefano Zampini       PetscCall(PetscLayoutGetRanges(ilay, &ranges));
318*6c34c54dSStefano Zampini       ncrs_eq_new = 0;
319*6c34c54dSStefano Zampini       for (PetscInt r = 0; r < size; r++)
320*6c34c54dSStefano Zampini         if (rank == (r / rfactor) * expand_factor) ncrs_eq_new += ranges[r + 1] - ranges[r];
321*6c34c54dSStefano Zampini       //targetPE = (rank / rfactor) * expand_factor;
322*6c34c54dSStefano Zampini       //PetscCall(ISCreateStride(comm, ncrs_eq, targetPE, 0, &is_eq_newproc));
323*6c34c54dSStefano Zampini       //PetscCall(ISPartitioningToNumbering(is_eq_newproc, &is_eq_num));
324*6c34c54dSStefano Zampini       //PetscCall(PetscMalloc1(size, &counts));
325*6c34c54dSStefano Zampini       //PetscCall(ISPartitioningCount(is_eq_newproc, size, counts));
326*6c34c54dSStefano Zampini       //ncrs_eq_new = counts[rank];
327*6c34c54dSStefano Zampini       //PetscCall(ISDestroy(&is_eq_newproc));
328*6c34c54dSStefano Zampini       //PetscCall(PetscFree(counts));
329*6c34c54dSStefano Zampini     } /* end simple 'is_eq_newproc' */
330*6c34c54dSStefano Zampini 
331ce7c7f2fSMark Adams     ncrs_new = ncrs_eq_new / cr_bs;
332a2f3521dSMark F. Adams 
3336aad120cSJose E. Roman     /* data movement scope -- this could be moved to subclasses so that we don't try to cram all auxiliary data into some complex abstracted thing */
334885364a3SMark Adams     {
335885364a3SMark Adams       Vec             src_crd, dest_crd;
336885364a3SMark Adams       const PetscInt *idx, ndata_rows = pc_gamg->data_cell_rows, ndata_cols = pc_gamg->data_cell_cols, node_data_sz = ndata_rows * ndata_cols;
337885364a3SMark Adams       VecScatter      vecscat;
338885364a3SMark Adams       PetscScalar    *array;
339885364a3SMark Adams       IS              isscat;
340a2f3521dSMark F. Adams       /* move data (for primal equations only) */
34122063be5SMark F. Adams       /* Create a vector to contain the newly ordered element information */
3429566063dSJacob Faibussowitsch       PetscCall(VecCreate(comm, &dest_crd));
3439566063dSJacob Faibussowitsch       PetscCall(VecSetSizes(dest_crd, node_data_sz * ncrs_new, PETSC_DECIDE));
3449566063dSJacob Faibussowitsch       PetscCall(VecSetType(dest_crd, VECSTANDARD)); /* this is needed! */
34511e60469SMark F. Adams       /*
3469d5b6da9SMark F. Adams         There are 'ndata_rows*ndata_cols' data items per node, (one can think of the vectors of having
347c5bfad50SMark F. Adams         a block size of ...).  Note, ISs are expanded into equation space by 'cr_bs'.
34811e60469SMark F. Adams       */
3499566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(ncrs * node_data_sz, &tidx));
350*6c34c54dSStefano Zampini       PetscCall(ISGetIndices(is_eq_num, &idx));
3513ae0bb68SMark Adams       for (ii = 0, jj = 0; ii < ncrs; ii++) {
352c5bfad50SMark F. Adams         PetscInt id = idx[ii * cr_bs] / cr_bs; /* get node back */
353a2f3521dSMark F. Adams         for (kk = 0; kk < node_data_sz; kk++, jj++) tidx[jj] = id * node_data_sz + kk;
35411e60469SMark F. Adams       }
355*6c34c54dSStefano Zampini       PetscCall(ISRestoreIndices(is_eq_num, &idx));
3569566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, node_data_sz * ncrs, tidx, PETSC_COPY_VALUES, &isscat));
3579566063dSJacob Faibussowitsch       PetscCall(PetscFree(tidx));
35811e60469SMark F. Adams       /*
35911e60469SMark F. Adams         Create a vector to contain the original vertex information for each element
36011e60469SMark F. Adams       */
3619566063dSJacob Faibussowitsch       PetscCall(VecCreateSeq(PETSC_COMM_SELF, node_data_sz * ncrs, &src_crd));
3629d5b6da9SMark F. Adams       for (jj = 0; jj < ndata_cols; jj++) {
3633ae0bb68SMark Adams         const PetscInt stride0 = ncrs * pc_gamg->data_cell_rows;
3643ae0bb68SMark Adams         for (ii = 0; ii < ncrs; ii++) {
3659d5b6da9SMark F. Adams           for (kk = 0; kk < ndata_rows; kk++) {
366a2f3521dSMark F. Adams             PetscInt    ix = ii * ndata_rows + kk + jj * stride0, jx = ii * node_data_sz + kk * ndata_cols + jj;
367c8b0795cSMark F. Adams             PetscScalar tt = (PetscScalar)pc_gamg->data[ix];
3689566063dSJacob Faibussowitsch             PetscCall(VecSetValues(src_crd, 1, &jx, &tt, INSERT_VALUES));
369d3d6bff4SMark F. Adams           }
370038e3b61SMark F. Adams         }
371eb07cef2SMark F. Adams       }
3729566063dSJacob Faibussowitsch       PetscCall(VecAssemblyBegin(src_crd));
3739566063dSJacob Faibussowitsch       PetscCall(VecAssemblyEnd(src_crd));
37411e60469SMark F. Adams       /*
37511e60469SMark F. Adams         Scatter the element vertex information (still in the original vertex ordering)
37611e60469SMark F. Adams         to the correct processor
37711e60469SMark F. Adams       */
3789566063dSJacob Faibussowitsch       PetscCall(VecScatterCreate(src_crd, NULL, dest_crd, isscat, &vecscat));
3799566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isscat));
3809566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(vecscat, src_crd, dest_crd, INSERT_VALUES, SCATTER_FORWARD));
3819566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(vecscat, src_crd, dest_crd, INSERT_VALUES, SCATTER_FORWARD));
3829566063dSJacob Faibussowitsch       PetscCall(VecScatterDestroy(&vecscat));
3839566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&src_crd));
38411e60469SMark F. Adams       /*
38511e60469SMark F. Adams         Put the element vertex data into a new allocation of the gdata->ele
38611e60469SMark F. Adams       */
3879566063dSJacob Faibussowitsch       PetscCall(PetscFree(pc_gamg->data));
3889566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(node_data_sz * ncrs_new, &pc_gamg->data));
3892fa5cd67SKarl Rupp 
3903ae0bb68SMark Adams       pc_gamg->data_sz = node_data_sz * ncrs_new;
3913ae0bb68SMark Adams       strideNew        = ncrs_new * ndata_rows;
3922fa5cd67SKarl Rupp 
3939566063dSJacob Faibussowitsch       PetscCall(VecGetArray(dest_crd, &array));
3949d5b6da9SMark F. Adams       for (jj = 0; jj < ndata_cols; jj++) {
3953ae0bb68SMark Adams         for (ii = 0; ii < ncrs_new; ii++) {
3969d5b6da9SMark F. Adams           for (kk = 0; kk < ndata_rows; kk++) {
397a2f3521dSMark F. Adams             PetscInt ix = ii * ndata_rows + kk + jj * strideNew, jx = ii * node_data_sz + kk * ndata_cols + jj;
398c8b0795cSMark F. Adams             pc_gamg->data[ix] = PetscRealPart(array[jx]);
399d3d6bff4SMark F. Adams           }
400038e3b61SMark F. Adams         }
401038e3b61SMark F. Adams       }
4029566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(dest_crd, &array));
4039566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&dest_crd));
404885364a3SMark Adams     }
405a2f3521dSMark F. Adams     /* move A and P (columns) with new layout */
40611e60469SMark F. Adams     /*
4077dae84e0SHong Zhang       Invert for MatCreateSubMatrix
40811e60469SMark F. Adams     */
4099566063dSJacob Faibussowitsch     PetscCall(ISInvertPermutation(is_eq_num, ncrs_eq_new, &new_eq_indices));
410*6c34c54dSStefano Zampini     PetscCall(ISSort(new_eq_indices));
4119566063dSJacob Faibussowitsch     PetscCall(ISSetBlockSize(new_eq_indices, cr_bs));
4123cb8563fSToby Isaac     if (Pcolumnperm) {
4139566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)new_eq_indices));
4143cb8563fSToby Isaac       *Pcolumnperm = new_eq_indices;
4153cb8563fSToby Isaac     }
4169566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_eq_num));
417849bee69SMark Adams 
418a2f3521dSMark F. Adams     /* 'a_Amat_crs' output */
419*6c34c54dSStefano Zampini     if (Cmat) { /* repartitioning from Cmat adjacency case */
420a2f3521dSMark F. Adams       Mat       mat;
421b94d7dedSBarry Smith       PetscBool isset, isspd, isher;
42290db8557SMark Adams #if !defined(PETSC_USE_COMPLEX)
423b94d7dedSBarry Smith       PetscBool issym;
424b94d7dedSBarry Smith #endif
425b94d7dedSBarry Smith 
426b94d7dedSBarry Smith       PetscCall(MatCreateSubMatrix(Cmat, new_eq_indices, new_eq_indices, MAT_INITIAL_MATRIX, &mat));
427b94d7dedSBarry Smith       PetscCall(MatIsSPDKnown(Cmat, &isset, &isspd)); // like MatPropagateSymmetryOptions, but should set MAT_STRUCTURALLY_SYMMETRIC ?
428b94d7dedSBarry Smith       if (isset) PetscCall(MatSetOption(mat, MAT_SPD, isspd));
429b94d7dedSBarry Smith       else {
430b94d7dedSBarry Smith         PetscCall(MatIsHermitianKnown(Cmat, &isset, &isher));
431b94d7dedSBarry Smith         if (isset) PetscCall(MatSetOption(mat, MAT_HERMITIAN, isher));
432b94d7dedSBarry Smith         else {
433b94d7dedSBarry Smith #if !defined(PETSC_USE_COMPLEX)
434b94d7dedSBarry Smith           PetscCall(MatIsSymmetricKnown(Cmat, &isset, &issym));
435b94d7dedSBarry Smith           if (isset) PetscCall(MatSetOption(mat, MAT_SYMMETRIC, issym));
43690db8557SMark Adams #endif
43790db8557SMark Adams         }
43890db8557SMark Adams       }
439a2f3521dSMark F. Adams       *a_Amat_crs = mat;
440a2f3521dSMark F. Adams     }
441a2f3521dSMark F. Adams 
44211e60469SMark F. Adams     /* prolongator */
44311e60469SMark F. Adams     {
44411e60469SMark F. Adams       IS       findices;
445a2f3521dSMark F. Adams       PetscInt Istart, Iend;
446a2f3521dSMark F. Adams       Mat      Pnew;
44762294041SBarry Smith 
4489566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(Pold, &Istart, &Iend));
4499566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(comm, Iend - Istart, Istart, 1, &findices));
4509566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(findices, f_bs));
4519566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(Pold, findices, new_eq_indices, MAT_INITIAL_MATRIX, &Pnew));
4529566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&findices));
4539566063dSJacob Faibussowitsch       PetscCall(MatSetOption(Pnew, MAT_FORM_EXPLICIT_TRANSPOSE, PETSC_TRUE));
454c5bfad50SMark F. Adams 
4559566063dSJacob Faibussowitsch       PetscCall(MatDestroy(a_P_inout));
456a2f3521dSMark F. Adams 
457a2f3521dSMark F. Adams       /* output - repartitioned */
458a2f3521dSMark F. Adams       *a_P_inout = Pnew;
459e33ef3b1SMark F. Adams     }
460*6c34c54dSStefano Zampini 
461*6c34c54dSStefano Zampini     if (!Cmat) { /* simple repartitioning case */
462*6c34c54dSStefano Zampini       PetscCall(PetscLogEventBegin(petsc_gamg_setup_events[GAMG_PTAP], 0, 0, 0, 0));
463*6c34c54dSStefano Zampini       PetscCall(PetscLogEventBegin(petsc_gamg_setup_matmat_events[pc_gamg->current_level][1], 0, 0, 0, 0));
464*6c34c54dSStefano Zampini       PetscCall(MatPtAP(Amat_fine, *a_P_inout, MAT_INITIAL_MATRIX, 2.0, a_Amat_crs));
465*6c34c54dSStefano Zampini       PetscCall(PetscLogEventEnd(petsc_gamg_setup_matmat_events[pc_gamg->current_level][1], 0, 0, 0, 0));
466*6c34c54dSStefano Zampini       PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_PTAP], 0, 0, 0, 0));
467*6c34c54dSStefano Zampini     }
468*6c34c54dSStefano Zampini     PetscCall(MatDestroy(&Cmat));
4699566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&new_eq_indices));
4705b89ad90SMark F. Adams 
471c5df96a5SBarry Smith     *a_nactive_proc = new_size; /* output */
472ce7c7f2fSMark Adams 
473ce7c7f2fSMark Adams     /* pinning on reduced grids, not a bad heuristic and optimization gets folded into process reduction optimization */
474ce7c7f2fSMark Adams     if (pc_gamg->cpu_pin_coarse_grids) {
475ce7c7f2fSMark Adams #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
4768bca76a6SMark Adams       static PetscInt llev = 2;
47763a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(pc, "%s: Pinning level %" PetscInt_FMT " to the CPU\n", ((PetscObject)pc)->prefix, llev++));
478ce7c7f2fSMark Adams #endif
4799566063dSJacob Faibussowitsch       PetscCall(MatBindToCPU(*a_Amat_crs, PETSC_TRUE));
4809566063dSJacob Faibussowitsch       PetscCall(MatBindToCPU(*a_P_inout, PETSC_TRUE));
481adf5291fSStefano Zampini       if (1) { /* HACK: move this to MatBindCPU_MPIAIJXXX; lvec is created, need to pin it, this is done in MatSetUpMultiply_MPIAIJ. Hack */
482ce7c7f2fSMark Adams         Mat         A = *a_Amat_crs, P = *a_P_inout;
483ce7c7f2fSMark Adams         PetscMPIInt size;
4849566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
485ce7c7f2fSMark Adams         if (size > 1) {
486ce7c7f2fSMark Adams           Mat_MPIAIJ *a = (Mat_MPIAIJ *)A->data, *p = (Mat_MPIAIJ *)P->data;
4879566063dSJacob Faibussowitsch           PetscCall(VecBindToCPU(a->lvec, PETSC_TRUE));
4889566063dSJacob Faibussowitsch           PetscCall(VecBindToCPU(p->lvec, PETSC_TRUE));
489ce7c7f2fSMark Adams         }
490ce7c7f2fSMark Adams       }
491ce7c7f2fSMark Adams     }
492849bee69SMark Adams     PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_REDUCE], 0, 0, 0, 0));
493849bee69SMark Adams   } // processor reduce
4943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4955b89ad90SMark F. Adams }
4965b89ad90SMark F. Adams 
497bae903cbSmarkadams4 // used in GEO
498d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGSquareGraph_GAMG(PC a_pc, Mat Gmat1, Mat *Gmat2)
499d71ae5a4SJacob Faibussowitsch {
5004b1575e2SStefano Zampini   const char *prefix;
5014b1575e2SStefano Zampini   char        addp[32];
5024b1575e2SStefano Zampini   PC_MG      *mg      = (PC_MG *)a_pc->data;
5034b1575e2SStefano Zampini   PC_GAMG    *pc_gamg = (PC_GAMG *)mg->innerctx;
5044b1575e2SStefano Zampini 
5054b1575e2SStefano Zampini   PetscFunctionBegin;
5069566063dSJacob Faibussowitsch   PetscCall(PCGetOptionsPrefix(a_pc, &prefix));
50763a3b9bcSJacob Faibussowitsch   PetscCall(PetscInfo(a_pc, "%s: Square Graph on level %" PetscInt_FMT "\n", ((PetscObject)a_pc)->prefix, pc_gamg->current_level + 1));
5089566063dSJacob Faibussowitsch   PetscCall(MatProductCreate(Gmat1, Gmat1, NULL, Gmat2));
5099566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(*Gmat2, prefix));
51063a3b9bcSJacob Faibussowitsch   PetscCall(PetscSNPrintf(addp, sizeof(addp), "pc_gamg_square_%" PetscInt_FMT "_", pc_gamg->current_level));
5119566063dSJacob Faibussowitsch   PetscCall(MatAppendOptionsPrefix(*Gmat2, addp));
512b94d7dedSBarry Smith   if ((*Gmat2)->structurally_symmetric == PETSC_BOOL3_TRUE) {
5139566063dSJacob Faibussowitsch     PetscCall(MatProductSetType(*Gmat2, MATPRODUCT_AB));
514b4da3a1bSStefano Zampini   } else {
5159566063dSJacob Faibussowitsch     PetscCall(MatSetOption(Gmat1, MAT_FORM_EXPLICIT_TRANSPOSE, PETSC_TRUE));
5169566063dSJacob Faibussowitsch     PetscCall(MatProductSetType(*Gmat2, MATPRODUCT_AtB));
517b4da3a1bSStefano Zampini   }
5189566063dSJacob Faibussowitsch   PetscCall(MatProductSetFromOptions(*Gmat2));
5199566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(petsc_gamg_setup_matmat_events[pc_gamg->current_level][0], 0, 0, 0, 0));
5209566063dSJacob Faibussowitsch   PetscCall(MatProductSymbolic(*Gmat2));
5219566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(petsc_gamg_setup_matmat_events[pc_gamg->current_level][0], 0, 0, 0, 0));
5229566063dSJacob Faibussowitsch   PetscCall(MatProductClear(*Gmat2));
5234b1575e2SStefano Zampini   /* we only need the sparsity, cheat and tell PETSc the matrix has been assembled */
5244b1575e2SStefano Zampini   (*Gmat2)->assembled = PETSC_TRUE;
5253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5264b1575e2SStefano Zampini }
5274b1575e2SStefano Zampini 
5285b89ad90SMark F. Adams /*
5295b89ad90SMark F. Adams    PCSetUp_GAMG - Prepares for the use of the GAMG preconditioner
5305b89ad90SMark F. Adams                     by setting data structures and options.
5315b89ad90SMark F. Adams 
5325b89ad90SMark F. Adams    Input Parameter:
5335b89ad90SMark F. Adams .  pc - the preconditioner context
5345b89ad90SMark F. Adams 
5355b89ad90SMark F. Adams */
53666976f2fSJacob Faibussowitsch static PetscErrorCode PCSetUp_GAMG(PC pc)
537d71ae5a4SJacob Faibussowitsch {
5389d5b6da9SMark F. Adams   PC_MG      *mg      = (PC_MG *)pc->data;
5395b89ad90SMark F. Adams   PC_GAMG    *pc_gamg = (PC_GAMG *)mg->innerctx;
5402adcac29SMark F. Adams   Mat         Pmat    = pc->pmat;
541b65aec2dSMark Adams   PetscInt    fine_level, level, level1, bs, M, N, qq, lidx, nASMBlocksArr[PETSC_MG_MAXLEVELS], cr_bs;
5423b4367a7SBarry Smith   MPI_Comm    comm;
543c5df96a5SBarry Smith   PetscMPIInt rank, size, nactivepe;
54418c3aa7eSMark   Mat         Aarr[PETSC_MG_MAXLEVELS], Parr[PETSC_MG_MAXLEVELS];
54518c3aa7eSMark   IS         *ASMLocalIDsArr[PETSC_MG_MAXLEVELS];
5464279555eSSatish Balay   PetscBool   is_last = PETSC_FALSE;
5474279555eSSatish Balay #if defined(PETSC_USE_INFO)
548a2f3521dSMark F. Adams   PetscLogDouble nnz0 = 0., nnztot = 0.;
549569f4572SMark Adams   MatInfo        info;
5504279555eSSatish Balay #endif
5515ef31b24SMark F. Adams 
5525b89ad90SMark F. Adams   PetscFunctionBegin;
5539566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
5549566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5559566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
556849bee69SMark Adams   PetscCall(PetscLogEventBegin(petsc_gamg_setup_events[GAMG_SETUP], 0, 0, 0, 0));
5578abdc6daSStefano Zampini   if (pc->setupcalled) {
5588abdc6daSStefano Zampini     if (!pc_gamg->reuse_prol || pc->flag == DIFFERENT_NONZERO_PATTERN) {
559878e152fSMark F. Adams       /* reset everything */
5609566063dSJacob Faibussowitsch       PetscCall(PCReset_MG(pc));
561878e152fSMark F. Adams       pc->setupcalled = 0;
562806fa848SBarry Smith     } else {
56384d3f75bSMark F. Adams       PC_MG_Levels **mglevels = mg->levels;
56403a628feSMark F. Adams       /* just do Galerkin grids */
56558471d46SMark F. Adams       Mat B, dA, dB;
5669d5b6da9SMark F. Adams       if (pc_gamg->Nlevels > 1) {
5674555aa8cSStefano Zampini         PetscInt gl;
56858471d46SMark F. Adams         /* currently only handle case where mat and pmat are the same on coarser levels */
5699566063dSJacob Faibussowitsch         PetscCall(KSPGetOperators(mglevels[pc_gamg->Nlevels - 1]->smoothd, &dA, &dB));
57058471d46SMark F. Adams         /* (re)set to get dirty flag */
5719566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(mglevels[pc_gamg->Nlevels - 1]->smoothd, dA, dB));
57258471d46SMark F. Adams 
5734555aa8cSStefano Zampini         for (level = pc_gamg->Nlevels - 2, gl = 0; level >= 0; level--, gl++) {
5748abdc6daSStefano Zampini           MatReuse reuse = MAT_INITIAL_MATRIX;
575849bee69SMark Adams #if defined(GAMG_STAGES)
576849bee69SMark Adams           PetscCall(PetscLogStagePush(gamg_stages[gl]));
577849bee69SMark Adams #endif
5788abdc6daSStefano Zampini           /* matrix structure can change from repartitioning or process reduction but don't know if we have process reduction here. Should fix */
5799566063dSJacob Faibussowitsch           PetscCall(KSPGetOperators(mglevels[level]->smoothd, NULL, &B));
5808abdc6daSStefano Zampini           if (B->product) {
581ad540459SPierre Jolivet             if (B->product->A == dB && B->product->B == mglevels[level + 1]->interpolate) reuse = MAT_REUSE_MATRIX;
5828abdc6daSStefano Zampini           }
5839566063dSJacob Faibussowitsch           if (reuse == MAT_INITIAL_MATRIX) PetscCall(MatDestroy(&mglevels[level]->A));
5848abdc6daSStefano Zampini           if (reuse == MAT_REUSE_MATRIX) {
585e02fb3cdSMark Adams             PetscCall(PetscInfo(pc, "%s: RAP after initial setup, reuse matrix level %" PetscInt_FMT "\n", ((PetscObject)pc)->prefix, level));
5868abdc6daSStefano Zampini           } else {
587e02fb3cdSMark Adams             PetscCall(PetscInfo(pc, "%s: RAP after initial setup, with repartitioning (new matrix) level %" PetscInt_FMT "\n", ((PetscObject)pc)->prefix, level));
5888abdc6daSStefano Zampini           }
5899566063dSJacob Faibussowitsch           PetscCall(PetscLogEventBegin(petsc_gamg_setup_matmat_events[gl][1], 0, 0, 0, 0));
590fb842aefSJose E. Roman           PetscCall(MatPtAP(dB, mglevels[level + 1]->interpolate, reuse, PETSC_DETERMINE, &B));
5919566063dSJacob Faibussowitsch           PetscCall(PetscLogEventEnd(petsc_gamg_setup_matmat_events[gl][1], 0, 0, 0, 0));
59263b77682SMark Adams           if (reuse == MAT_INITIAL_MATRIX) mglevels[level]->A = B;
5939566063dSJacob Faibussowitsch           PetscCall(KSPSetOperators(mglevels[level]->smoothd, B, B));
594e1cf1444SMark Adams           // check for redoing eigen estimates
595e1cf1444SMark Adams           if (pc_gamg->recompute_esteig) {
596e1cf1444SMark Adams             PetscBool ischeb;
597e1cf1444SMark Adams             KSP       smoother;
598e1cf1444SMark Adams             PetscCall(PCMGGetSmoother(pc, level + 1, &smoother));
599e1cf1444SMark Adams             PetscCall(PetscObjectTypeCompare((PetscObject)smoother, KSPCHEBYSHEV, &ischeb));
600e1cf1444SMark Adams             if (ischeb) {
601e1cf1444SMark Adams               KSP_Chebyshev *cheb = (KSP_Chebyshev *)smoother->data;
602e1cf1444SMark Adams               cheb->emin_provided = 0;
603e1cf1444SMark Adams               cheb->emax_provided = 0;
604e1cf1444SMark Adams             }
605e1cf1444SMark Adams             /* we could call PetscCall(KSPChebyshevSetEigenvalues(smoother, 0, 0)); but the logic does not work properly */
606e1cf1444SMark Adams           }
607e1cf1444SMark Adams           // inc
60858471d46SMark F. Adams           dB = B;
609849bee69SMark Adams #if defined(GAMG_STAGES)
610849bee69SMark Adams           PetscCall(PetscLogStagePop());
611849bee69SMark Adams #endif
61258471d46SMark F. Adams         }
6135f8cf99dSMark F. Adams       }
614d5280255SMark F. Adams 
6159566063dSJacob Faibussowitsch       PetscCall(PCSetUp_MG(pc));
616849bee69SMark Adams       PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_SETUP], 0, 0, 0, 0));
6173ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
618eb07cef2SMark F. Adams     }
619878e152fSMark F. Adams   }
620f6536408SMark F. Adams 
621878e152fSMark F. Adams   if (!pc_gamg->data) {
622878e152fSMark F. Adams     if (pc_gamg->orig_data) {
6239566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSize(Pmat, &bs));
6249566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(Pmat, &qq, NULL));
6252fa5cd67SKarl Rupp 
626878e152fSMark F. Adams       pc_gamg->data_sz        = (qq / bs) * pc_gamg->orig_data_cell_rows * pc_gamg->orig_data_cell_cols;
627878e152fSMark F. Adams       pc_gamg->data_cell_rows = pc_gamg->orig_data_cell_rows;
628878e152fSMark F. Adams       pc_gamg->data_cell_cols = pc_gamg->orig_data_cell_cols;
6292fa5cd67SKarl Rupp 
6309566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pc_gamg->data_sz, &pc_gamg->data));
631878e152fSMark F. Adams       for (qq = 0; qq < pc_gamg->data_sz; qq++) pc_gamg->data[qq] = pc_gamg->orig_data[qq];
632806fa848SBarry Smith     } else {
6335f80ce2aSJacob Faibussowitsch       PetscCheck(pc_gamg->ops->createdefaultdata, comm, PETSC_ERR_PLIB, "'createdefaultdata' not set(?) need to support NULL data");
6349566063dSJacob Faibussowitsch       PetscCall(pc_gamg->ops->createdefaultdata(pc, Pmat));
6359d5b6da9SMark F. Adams     }
636878e152fSMark F. Adams   }
637878e152fSMark F. Adams 
638878e152fSMark F. Adams   /* cache original data for reuse */
6391c1aac46SBarry Smith   if (!pc_gamg->orig_data && (PetscBool)(!pc_gamg->reuse_prol)) {
6409566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pc_gamg->data_sz, &pc_gamg->orig_data));
641878e152fSMark F. Adams     for (qq = 0; qq < pc_gamg->data_sz; qq++) pc_gamg->orig_data[qq] = pc_gamg->data[qq];
642878e152fSMark F. Adams     pc_gamg->orig_data_cell_rows = pc_gamg->data_cell_rows;
643878e152fSMark F. Adams     pc_gamg->orig_data_cell_cols = pc_gamg->data_cell_cols;
644878e152fSMark F. Adams   }
645038e3b61SMark F. Adams 
646302f38e8SMark F. Adams   /* get basic dims */
6479566063dSJacob Faibussowitsch   PetscCall(MatGetBlockSize(Pmat, &bs));
648b65aec2dSMark Adams   PetscCall(MatGetSize(Pmat, &M, NULL));
64984d3f75bSMark F. Adams 
6504279555eSSatish Balay #if defined(PETSC_USE_INFO)
6519566063dSJacob Faibussowitsch   PetscCall(MatGetInfo(Pmat, MAT_GLOBAL_SUM, &info)); /* global reduction */
652569f4572SMark Adams   nnz0   = info.nz_used;
653569f4572SMark Adams   nnztot = info.nz_used;
6544279555eSSatish Balay #endif
655b65aec2dSMark Adams   PetscCall(PetscInfo(pc, "%s: level %d) N=%" PetscInt_FMT ", n data rows=%" PetscInt_FMT ", n data cols=%" PetscInt_FMT ", nnz/row (ave)=%" PetscInt_FMT ", block size %d, np=%d\n", ((PetscObject)pc)->prefix, 0, M, pc_gamg->data_cell_rows, pc_gamg->data_cell_cols, (PetscInt)(nnz0 / (PetscReal)M + 0.5), (int)bs, size));
656569f4572SMark Adams 
657a2f3521dSMark F. Adams   /* Get A_i and R_i */
658b65aec2dSMark Adams   for (level = 0, Aarr[0] = Pmat, nactivepe = size; level < (pc_gamg->Nlevels - 1) && (level == 0 || M > pc_gamg->coarse_eq_limit); level++) {
6599ab59c8bSMark Adams     pc_gamg->current_level = level;
6605b89ad90SMark F. Adams     level1                 = level + 1;
6614555aa8cSStefano Zampini #if defined(GAMG_STAGES)
662849bee69SMark Adams     if (!gamg_stages[level]) {
663849bee69SMark Adams       char str[32];
664a364092eSJacob Faibussowitsch       PetscCall(PetscSNPrintf(str, PETSC_STATIC_ARRAY_LENGTH(str), "GAMG Level %d", (int)level));
665849bee69SMark Adams       PetscCall(PetscLogStageRegister(str, &gamg_stages[level]));
666849bee69SMark Adams     }
6679566063dSJacob Faibussowitsch     PetscCall(PetscLogStagePush(gamg_stages[level]));
668b4fbaa2aSMark F. Adams #endif
669b65aec2dSMark Adams     /* construct prolongator - Parr[level1] */
670b65aec2dSMark Adams     if (level == 0 && pc_gamg->injection_index_size > 0) {
671b65aec2dSMark Adams       Mat      Prol;
672b65aec2dSMark Adams       MatType  mtype;
673b65aec2dSMark Adams       PetscInt prol_m, prol_n, Prol_N = (M / bs) * pc_gamg->injection_index_size, Istart, Iend, nn, row;
674b65aec2dSMark Adams       PetscCall(PetscInfo(pc, "Create fine grid injection space prolongation %" PetscInt_FMT " x %" PetscInt_FMT ". %s\n", M, Prol_N, pc_gamg->data ? "delete null space data" : ""));
675b65aec2dSMark Adams       PetscCall(MatGetOwnershipRange(Pmat, &Istart, &Iend));
676b65aec2dSMark Adams       PetscCall(MatGetLocalSize(Pmat, &prol_m, NULL)); // rows m x n
677b65aec2dSMark Adams       prol_n = (prol_m / bs) * pc_gamg->injection_index_size;
678b65aec2dSMark Adams       PetscCheck(pc_gamg->injection_index_size < bs, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Injection size %d must be less that block size %d", (int)pc_gamg->injection_index_size, (int)bs);
679b65aec2dSMark Adams       PetscCall(MatGetType(Pmat, &mtype));
680b65aec2dSMark Adams       PetscCall(MatCreate(PetscObjectComm((PetscObject)pc), &Prol));
681b65aec2dSMark Adams       PetscCall(MatSetBlockSizes(Prol, bs, pc_gamg->injection_index_size));
682b65aec2dSMark Adams       PetscCall(MatSetSizes(Prol, prol_m, prol_n, M, Prol_N));
683b65aec2dSMark Adams       PetscCall(MatSetType(Prol, mtype));
684b65aec2dSMark Adams #if PetscDefined(HAVE_DEVICE)
685b65aec2dSMark Adams       PetscBool flg;
686b65aec2dSMark Adams       PetscCall(MatBoundToCPU(Pmat, &flg));
687b65aec2dSMark Adams       PetscCall(MatBindToCPU(Prol, flg));
688b65aec2dSMark Adams       if (flg) PetscCall(MatSetBindingPropagates(Prol, PETSC_TRUE));
689b65aec2dSMark Adams #endif
690b65aec2dSMark Adams       PetscCall(MatSeqAIJSetPreallocation(Prol, 1, NULL));
691b65aec2dSMark Adams       PetscCall(MatMPIAIJSetPreallocation(Prol, 1, NULL, 0, NULL));
692b65aec2dSMark Adams       // set I \kron [1, 1, ... ]^T
693b65aec2dSMark Adams       for (PetscInt ii = Istart, col = (Istart / bs) * pc_gamg->injection_index_size; ii < Iend; ii += bs) {
694b65aec2dSMark Adams         const PetscScalar one = 1;
695b65aec2dSMark Adams         for (PetscInt jj = 0; jj < pc_gamg->injection_index_size; jj++, col++) {
696b65aec2dSMark Adams           PetscInt row = ii + pc_gamg->injection_index[jj];
697b65aec2dSMark Adams           PetscCall(MatSetValues(Prol, 1, &row, 1, &col, &one, INSERT_VALUES));
698b65aec2dSMark Adams         }
699b65aec2dSMark Adams       }
700b65aec2dSMark Adams       PetscCall(MatAssemblyBegin(Prol, MAT_FINAL_ASSEMBLY));
701b65aec2dSMark Adams       PetscCall(MatAssemblyEnd(Prol, MAT_FINAL_ASSEMBLY));
702b65aec2dSMark Adams       PetscCall(MatViewFromOptions(Prol, NULL, "-mat_view_injection"));
703b65aec2dSMark Adams       PetscCall(MatGetBlockSizes(Prol, NULL, &cr_bs)); // column size
704b65aec2dSMark Adams       Parr[level1] = Prol;
705b65aec2dSMark Adams       // can not deal with null space -- with array of 'injection cols' we could take 'injection rows and 'injection cols' to 'data'
706b65aec2dSMark Adams       if (pc_gamg->data) {
707b65aec2dSMark Adams         pc_gamg->data_cell_cols      = pc_gamg->injection_index_size;
708b65aec2dSMark Adams         pc_gamg->data_cell_rows      = pc_gamg->injection_index_size;
709b65aec2dSMark Adams         pc_gamg->orig_data_cell_cols = 0;
710b65aec2dSMark Adams         pc_gamg->orig_data_cell_rows = 0;
711b65aec2dSMark Adams         PetscCall(PetscFree(pc_gamg->data));
712b65aec2dSMark Adams         pc_gamg->data_sz = pc_gamg->injection_index_size * prol_n;
713b65aec2dSMark Adams         PetscCall(PetscMalloc1(pc_gamg->data_sz, &pc_gamg->data));
714b65aec2dSMark Adams         for (row = nn = 0; row < prol_n; row += pc_gamg->injection_index_size) {
715b65aec2dSMark Adams           for (int jj = 0; jj < pc_gamg->injection_index_size; jj++) {
716b65aec2dSMark Adams             int idx = row * pc_gamg->injection_index_size + jj * pc_gamg->injection_index_size;
717b65aec2dSMark Adams             for (int kk = 0; kk < pc_gamg->injection_index_size; kk++, nn++) { pc_gamg->data[idx + kk] = (jj == kk) ? 1 : 0; }
718b65aec2dSMark Adams           }
719b65aec2dSMark Adams         }
720b65aec2dSMark Adams         PetscCheck(nn == pc_gamg->data_sz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "nn != pc_gamg->data_sz %" PetscInt_FMT " %" PetscInt_FMT, pc_gamg->data_sz, nn);
721b65aec2dSMark Adams       }
722b65aec2dSMark Adams     } else {
7238926f930SMark Adams       Mat               Gmat, mat;
7240cbbd2e1SMark F. Adams       PetscCoarsenData *agg_lists;
7257700e67bSMark Adams       Mat               Prol11;
726c8b0795cSMark F. Adams 
7272d776b49SBarry Smith       PetscCall(PCGAMGCreateGraph(pc, Aarr[level], &Gmat));
7289c15c1aeSMark Adams       PetscCall(pc_gamg->ops->coarsen(pc, &Gmat, &agg_lists)); // Gmat may have ghosts for QR aggregates not in matrix
7298926f930SMark Adams       PetscCall(PetscCDGetMat(agg_lists, &mat));
7308926f930SMark Adams       if (!mat) PetscCall(PetscCDSetMat(agg_lists, Gmat));
7318926f930SMark Adams       PetscCall(pc_gamg->ops->prolongator(pc, Aarr[level], agg_lists, &Prol11));
732a2f3521dSMark F. Adams       /* could have failed to create new level */
733a2f3521dSMark F. Adams       if (Prol11) {
734f7df55f0SStefano Zampini         const char *prefix;
735f7df55f0SStefano Zampini         char        addp[32];
736f7df55f0SStefano Zampini 
7379d5b6da9SMark F. Adams         /* get new block size of coarse matrices */
738b65aec2dSMark Adams         PetscCall(MatGetBlockSizes(Prol11, NULL, &cr_bs)); // column size
739a2f3521dSMark F. Adams 
740fd1112cbSBarry Smith         if (pc_gamg->ops->optprolongator) {
741c8b0795cSMark F. Adams           /* smooth */
7429566063dSJacob Faibussowitsch           PetscCall(pc_gamg->ops->optprolongator(pc, Aarr[level], &Prol11));
743c8b0795cSMark F. Adams         }
744c8b0795cSMark F. Adams 
7450c3bc534SBarry Smith         if (pc_gamg->use_aggs_in_asm) {
7468926f930SMark Adams           PetscInt bs;
7478926f930SMark Adams           PetscCall(MatGetBlockSizes(Prol11, &bs, NULL)); // row block size
7489c15c1aeSMark Adams           PetscCall(PetscCDGetASMBlocks(agg_lists, bs, &nASMBlocksArr[level], &ASMLocalIDsArr[level]));
7499c15c1aeSMark Adams           PetscCall(PetscInfo(pc, "%d: %" PetscInt_FMT " ASM local domains,  bs = %d\n", (int)level, nASMBlocksArr[level], (int)bs));
7508926f930SMark Adams         } else if (pc_gamg->asm_hem_aggs) {
7518926f930SMark Adams           const char *prefix;
7528926f930SMark Adams           PetscInt    bs;
753e0b7e82fSBarry Smith 
754e0b7e82fSBarry Smith           /*
755e0b7e82fSBarry Smith              Do not use aggs created for defining coarser problems, instead create aggs specifically to use
756e0b7e82fSBarry Smith              to define PCASM blocks.
757e0b7e82fSBarry Smith           */
7588926f930SMark Adams           PetscCall(PetscCDGetMat(agg_lists, &mat));
7598926f930SMark Adams           if (mat == Gmat) PetscCall(PetscCDClearMat(agg_lists)); // take the Mat away from the list (yuck)
7608926f930SMark Adams           PetscCall(PetscCDDestroy(agg_lists));
7618926f930SMark Adams           PetscCall(PetscInfo(pc, "HEM ASM passes = %d\n", (int)pc_gamg->asm_hem_aggs));
762e0b7e82fSBarry Smith           PetscCall(MatCoarsenDestroy(&pc_gamg->asm_crs));
763e0b7e82fSBarry Smith           PetscCall(MatCoarsenCreate(PetscObjectComm((PetscObject)pc), &pc_gamg->asm_crs));
7648926f930SMark Adams           PetscCall(PetscObjectGetOptionsPrefix((PetscObject)pc, &prefix));
765e0b7e82fSBarry Smith           PetscCall(PetscObjectSetOptionsPrefix((PetscObject)pc_gamg->asm_crs, prefix));
766e0b7e82fSBarry Smith           PetscCall(MatCoarsenSetFromOptions(pc_gamg->asm_crs)); // get strength args
767e0b7e82fSBarry Smith           PetscCall(MatCoarsenSetType(pc_gamg->asm_crs, MATCOARSENHEM));
768e0b7e82fSBarry Smith           PetscCall(MatCoarsenSetMaximumIterations(pc_gamg->asm_crs, pc_gamg->asm_hem_aggs));
769e0b7e82fSBarry Smith           PetscCall(MatCoarsenSetAdjacency(pc_gamg->asm_crs, Gmat));
770e0b7e82fSBarry Smith           PetscCall(MatCoarsenSetStrictAggs(pc_gamg->asm_crs, PETSC_TRUE));
771e0b7e82fSBarry Smith           PetscCall(MatCoarsenApply(pc_gamg->asm_crs));
772e0b7e82fSBarry Smith           PetscCall(MatCoarsenGetData(pc_gamg->asm_crs, &agg_lists)); /* output */
7738926f930SMark Adams           // create aggregates
7748926f930SMark Adams           PetscCall(MatGetBlockSizes(Aarr[level], &bs, NULL)); // row block size
7758926f930SMark Adams           PetscCall(PetscCDGetASMBlocks(agg_lists, bs, &nASMBlocksArr[level], &ASMLocalIDsArr[level]));
776ffc955d6SMark F. Adams         }
7779566063dSJacob Faibussowitsch         PetscCall(PCGetOptionsPrefix(pc, &prefix));
7789566063dSJacob Faibussowitsch         PetscCall(MatSetOptionsPrefix(Prol11, prefix));
7799566063dSJacob Faibussowitsch         PetscCall(PetscSNPrintf(addp, sizeof(addp), "pc_gamg_prolongator_%d_", (int)level));
7809566063dSJacob Faibussowitsch         PetscCall(MatAppendOptionsPrefix(Prol11, addp));
78191f31d3dSStefano Zampini         /* Always generate the transpose with CUDA
782f7df55f0SStefano Zampini            Such behaviour can be adapted with -pc_gamg_prolongator_ prefixed options */
7839566063dSJacob Faibussowitsch         PetscCall(MatSetOption(Prol11, MAT_FORM_EXPLICIT_TRANSPOSE, PETSC_TRUE));
7849566063dSJacob Faibussowitsch         PetscCall(MatSetFromOptions(Prol11));
7854bde40a0SMark Adams         Parr[level1] = Prol11;
7864bde40a0SMark Adams       } else Parr[level1] = NULL; /* failed to coarsen */
7878926f930SMark Adams       PetscCall(PetscCDGetMat(agg_lists, &mat));
7888926f930SMark Adams       if (mat == Gmat) PetscCall(PetscCDClearMat(agg_lists)); // take the Mat away from the list (yuck)
7899566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&Gmat));
7909566063dSJacob Faibussowitsch       PetscCall(PetscCDDestroy(agg_lists));
791a2f3521dSMark F. Adams     } /* construct prolongator scope */
792b65aec2dSMark Adams     if (level == 0) Aarr[0] = Pmat; /* use Pmat for finest level setup */
793171cca9aSMark Adams     if (!Parr[level1]) {            /* failed to coarsen */
79463a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(pc, "%s: Stop gridding, level %" PetscInt_FMT "\n", ((PetscObject)pc)->prefix, level));
7954555aa8cSStefano Zampini #if defined(GAMG_STAGES)
7969566063dSJacob Faibussowitsch       PetscCall(PetscLogStagePop());
797a90e85d9SMark Adams #endif
798c8b0795cSMark F. Adams       break;
799c8b0795cSMark F. Adams     }
8009566063dSJacob Faibussowitsch     PetscCall(MatGetSize(Parr[level1], &M, &N)); /* N is next M, a loop test variables */
8012472a847SBarry Smith     PetscCheck(!is_last, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Is last ?");
802171cca9aSMark Adams     if (N <= pc_gamg->coarse_eq_limit) is_last = PETSC_TRUE;
8030e2909e1SMark Adams     if (level1 == pc_gamg->Nlevels - 1) is_last = PETSC_TRUE;
804e323ae0aSPierre Jolivet     if (level == PETSC_MG_MAXLEVELS - 2) is_last = PETSC_TRUE;
805849bee69SMark Adams     PetscCall(PetscLogEventBegin(petsc_gamg_setup_events[GAMG_LEVEL], 0, 0, 0, 0));
806b65aec2dSMark Adams     PetscCall(pc_gamg->ops->createlevel(pc, Aarr[level], cr_bs, &Parr[level1], &Aarr[level1], &nactivepe, NULL, is_last));
807849bee69SMark Adams     PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_LEVEL], 0, 0, 0, 0));
808a2f3521dSMark F. Adams 
8099566063dSJacob Faibussowitsch     PetscCall(MatGetSize(Aarr[level1], &M, &N)); /* M is loop test variables */
8104279555eSSatish Balay #if defined(PETSC_USE_INFO)
8119566063dSJacob Faibussowitsch     PetscCall(MatGetInfo(Aarr[level1], MAT_GLOBAL_SUM, &info));
812569f4572SMark Adams     nnztot += info.nz_used;
8134279555eSSatish Balay #endif
814bae903cbSmarkadams4     PetscCall(PetscInfo(pc, "%s: %d) N=%" PetscInt_FMT ", n data cols=%" PetscInt_FMT ", nnz/row (ave)=%" PetscInt_FMT ", %d active pes\n", ((PetscObject)pc)->prefix, (int)level1, M, pc_gamg->data_cell_cols, (PetscInt)(info.nz_used / (PetscReal)M), nactivepe));
815569f4572SMark Adams 
8164555aa8cSStefano Zampini #if defined(GAMG_STAGES)
8179566063dSJacob Faibussowitsch     PetscCall(PetscLogStagePop());
818b4fbaa2aSMark F. Adams #endif
819a90e85d9SMark Adams     /* stop if one node or one proc -- could pull back for singular problems */
8209ab59c8bSMark Adams     if ((pc_gamg->data_cell_cols && M / pc_gamg->data_cell_cols < 2) || (!pc_gamg->data_cell_cols && M / bs < 2)) {
82163a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(pc, "%s: HARD stop of coarsening on level %" PetscInt_FMT ".  Grid too small: %" PetscInt_FMT " block nodes\n", ((PetscObject)pc)->prefix, level, M / bs));
822a90e85d9SMark Adams       level++;
823a90e85d9SMark Adams       break;
824e323ae0aSPierre Jolivet     } else if (level == PETSC_MG_MAXLEVELS - 2) { /* stop if we are limited by PC_MG_MAXLEVELS */
825e323ae0aSPierre Jolivet       PetscCall(PetscInfo(pc, "%s: HARD stop of coarsening on level %" PetscInt_FMT ".  PC_MG_MAXLEVELS reached\n", ((PetscObject)pc)->prefix, level));
826e323ae0aSPierre Jolivet       level++;
827e323ae0aSPierre Jolivet       break;
828a90e85d9SMark Adams     }
829c8b0795cSMark F. Adams   } /* levels */
8309566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc_gamg->data));
831c8b0795cSMark F. Adams 
832ba4ceb06Smarkadams4   PetscCall(PetscInfo(pc, "%s: %" PetscInt_FMT " levels, operator complexity = %g\n", ((PetscObject)pc)->prefix, level + 1, nnztot / nnz0));
8339d5b6da9SMark F. Adams   pc_gamg->Nlevels = level + 1;
8345b89ad90SMark F. Adams   fine_level       = level;
8359566063dSJacob Faibussowitsch   PetscCall(PCMGSetLevels(pc, pc_gamg->Nlevels, NULL));
8365b89ad90SMark F. Adams 
83762294041SBarry Smith   if (pc_gamg->Nlevels > 1) { /* don't setup MG if one level */
8380ed2132dSStefano Zampini 
839d5280255SMark F. Adams     /* set default smoothers & set operators */
84062294041SBarry Smith     for (lidx = 1, level = pc_gamg->Nlevels - 2; lidx <= fine_level; lidx++, level--) {
841ffc955d6SMark F. Adams       KSP smoother;
842ffc955d6SMark F. Adams       PC  subpc;
843a2f3521dSMark F. Adams 
8449566063dSJacob Faibussowitsch       PetscCall(PCMGGetSmoother(pc, lidx, &smoother));
8459566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(smoother, &subpc));
846ffc955d6SMark F. Adams 
8479566063dSJacob Faibussowitsch       PetscCall(KSPSetNormType(smoother, KSP_NORM_NONE));
848a2f3521dSMark F. Adams       /* set ops */
8499566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(smoother, Aarr[level], Aarr[level]));
8509566063dSJacob Faibussowitsch       PetscCall(PCMGSetInterpolation(pc, lidx, Parr[level + 1]));
851a2f3521dSMark F. Adams 
852a2f3521dSMark F. Adams       /* set defaults */
8539566063dSJacob Faibussowitsch       PetscCall(KSPSetType(smoother, KSPCHEBYSHEV));
854a2f3521dSMark F. Adams 
8550c3bc534SBarry Smith       /* set blocks for ASM smoother that uses the 'aggregates' */
8568926f930SMark Adams       if (pc_gamg->use_aggs_in_asm || pc_gamg->asm_hem_aggs) {
8572d3561bbSSatish Balay         PetscInt sz;
8587a28f3e5SMark Adams         IS      *iss;
859a2f3521dSMark F. Adams 
8602d3561bbSSatish Balay         sz  = nASMBlocksArr[level];
8617a28f3e5SMark Adams         iss = ASMLocalIDsArr[level];
8629566063dSJacob Faibussowitsch         PetscCall(PCSetType(subpc, PCASM));
8639566063dSJacob Faibussowitsch         PetscCall(PCASMSetOverlap(subpc, 0));
8649566063dSJacob Faibussowitsch         PetscCall(PCASMSetType(subpc, PC_ASM_BASIC));
8657f66b68fSMark Adams         if (!sz) {
866ffc955d6SMark F. Adams           IS is;
8679566063dSJacob Faibussowitsch           PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_COPY_VALUES, &is));
8689566063dSJacob Faibussowitsch           PetscCall(PCASMSetLocalSubdomains(subpc, 1, NULL, &is));
8699566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&is));
870806fa848SBarry Smith         } else {
871a94c3b12SMark F. Adams           PetscInt kk;
8722eab5cd7Smarkadams4           PetscCall(PCASMSetLocalSubdomains(subpc, sz, iss, NULL));
87348a46eb9SPierre Jolivet           for (kk = 0; kk < sz; kk++) PetscCall(ISDestroy(&iss[kk]));
8749566063dSJacob Faibussowitsch           PetscCall(PetscFree(iss));
875ffc955d6SMark F. Adams         }
8760298fd71SBarry Smith         ASMLocalIDsArr[level] = NULL;
877ffc955d6SMark F. Adams         nASMBlocksArr[level]  = 0;
878806fa848SBarry Smith       } else {
8799566063dSJacob Faibussowitsch         PetscCall(PCSetType(subpc, PCJACOBI));
880ffc955d6SMark F. Adams       }
881d5280255SMark F. Adams     }
882d5280255SMark F. Adams     {
883d5280255SMark F. Adams       /* coarse grid */
8849371c9d4SSatish Balay       KSP      smoother, *k2;
8859371c9d4SSatish Balay       PC       subpc, pc2;
8869371c9d4SSatish Balay       PetscInt ii, first;
8879371c9d4SSatish Balay       Mat      Lmat = Aarr[(level = pc_gamg->Nlevels - 1)];
8889371c9d4SSatish Balay       lidx          = 0;
8890ed2132dSStefano Zampini 
8909566063dSJacob Faibussowitsch       PetscCall(PCMGGetSmoother(pc, lidx, &smoother));
8919566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(smoother, Lmat, Lmat));
892cf8ae1d3SMark Adams       if (!pc_gamg->use_parallel_coarse_grid_solver) {
8939566063dSJacob Faibussowitsch         PetscCall(KSPSetNormType(smoother, KSP_NORM_NONE));
8949566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(smoother, &subpc));
8959566063dSJacob Faibussowitsch         PetscCall(PCSetType(subpc, PCBJACOBI));
8969566063dSJacob Faibussowitsch         PetscCall(PCSetUp(subpc));
8979566063dSJacob Faibussowitsch         PetscCall(PCBJacobiGetSubKSP(subpc, &ii, &first, &k2));
89863a3b9bcSJacob Faibussowitsch         PetscCheck(ii == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "ii %" PetscInt_FMT " is not one", ii);
8999566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(k2[0], &pc2));
9009566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc2, PCLU));
9019566063dSJacob Faibussowitsch         PetscCall(PCFactorSetShiftType(pc2, MAT_SHIFT_INBLOCKS));
902fb842aefSJose E. Roman         PetscCall(KSPSetTolerances(k2[0], PETSC_CURRENT, PETSC_CURRENT, PETSC_CURRENT, 1));
9039566063dSJacob Faibussowitsch         PetscCall(KSPSetType(k2[0], KSPPREONLY));
904d5280255SMark F. Adams       }
905cf8ae1d3SMark Adams     }
906d5280255SMark F. Adams 
907d5280255SMark F. Adams     /* should be called in PCSetFromOptions_GAMG(), but cannot be called prior to PCMGSetLevels() */
908d0609cedSBarry Smith     PetscObjectOptionsBegin((PetscObject)pc);
909dbbe0bcdSBarry Smith     PetscCall(PCSetFromOptions_MG(pc, PetscOptionsObject));
910d0609cedSBarry Smith     PetscOptionsEnd();
9119566063dSJacob Faibussowitsch     PetscCall(PCMGSetGalerkin(pc, PC_MG_GALERKIN_EXTERNAL));
912d5280255SMark F. Adams 
913f1580f4eSBarry Smith     /* set cheby eigen estimates from SA to use in the solver */
9147e6512fdSJed Brown     if (pc_gamg->use_sa_esteig) {
91518c3aa7eSMark       for (lidx = 1, level = pc_gamg->Nlevels - 2; level >= 0; lidx++, level--) {
91618c3aa7eSMark         KSP       smoother;
91718c3aa7eSMark         PetscBool ischeb;
9180ed2132dSStefano Zampini 
9199566063dSJacob Faibussowitsch         PetscCall(PCMGGetSmoother(pc, lidx, &smoother));
9209566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)smoother, KSPCHEBYSHEV, &ischeb));
92118c3aa7eSMark         if (ischeb) {
92218c3aa7eSMark           KSP_Chebyshev *cheb = (KSP_Chebyshev *)smoother->data;
9230ed2132dSStefano Zampini 
9242de708cbSJed Brown           // The command line will override these settings because KSPSetFromOptions is called in PCSetUp_MG
925efe053fcSJed Brown           if (mg->max_eigen_DinvA[level] > 0) {
9267e6512fdSJed Brown             // SA uses Jacobi for P; we use SA estimates if the smoother is also Jacobi or if the user explicitly requested it.
9277e6512fdSJed Brown             // TODO: This should test whether it's the same Jacobi variant (DIAG, ROWSUM, etc.)
92818c3aa7eSMark             PetscReal emax, emin;
9290ed2132dSStefano Zampini 
93018c3aa7eSMark             emin = mg->min_eigen_DinvA[level];
93118c3aa7eSMark             emax = mg->max_eigen_DinvA[level];
93263a3b9bcSJacob Faibussowitsch             PetscCall(PetscInfo(pc, "%s: PCSetUp_GAMG: call KSPChebyshevSetEigenvalues on level %" PetscInt_FMT " (N=%" PetscInt_FMT ") with emax = %g emin = %g\n", ((PetscObject)pc)->prefix, level, Aarr[level]->rmap->N, (double)emax, (double)emin));
9330a94a983SJed Brown             cheb->emin_provided = emin;
9340a94a983SJed Brown             cheb->emax_provided = emax;
93518c3aa7eSMark           }
93618c3aa7eSMark         }
93718c3aa7eSMark       }
93818c3aa7eSMark     }
9390ed2132dSStefano Zampini 
9409566063dSJacob Faibussowitsch     PetscCall(PCSetUp_MG(pc));
9410ed2132dSStefano Zampini 
942d5280255SMark F. Adams     /* clean up */
943d5280255SMark F. Adams     for (level = 1; level < pc_gamg->Nlevels; level++) {
9449566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&Parr[level]));
9459566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&Aarr[level]));
9465b89ad90SMark F. Adams     }
947806fa848SBarry Smith   } else {
9485f8cf99dSMark F. Adams     KSP smoother;
9490ed2132dSStefano Zampini 
95063a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(pc, "%s: One level solver used (system is seen as DD). Using default solver.\n", ((PetscObject)pc)->prefix));
9519566063dSJacob Faibussowitsch     PetscCall(PCMGGetSmoother(pc, 0, &smoother));
9529566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(smoother, Aarr[0], Aarr[0]));
9539566063dSJacob Faibussowitsch     PetscCall(KSPSetType(smoother, KSPPREONLY));
9549566063dSJacob Faibussowitsch     PetscCall(PCSetUp_MG(pc));
9555f8cf99dSMark F. Adams   }
956849bee69SMark Adams   PetscCall(PetscLogEventEnd(petsc_gamg_setup_events[GAMG_SETUP], 0, 0, 0, 0));
9573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
9585b89ad90SMark F. Adams }
9595b89ad90SMark F. Adams 
9605b89ad90SMark F. Adams /*
9615b89ad90SMark F. Adams  PCDestroy_GAMG - Destroys the private context for the GAMG preconditioner
9625b89ad90SMark F. Adams    that was created with PCCreate_GAMG().
9635b89ad90SMark F. Adams 
9645b89ad90SMark F. Adams    Input Parameter:
9655b89ad90SMark F. Adams .  pc - the preconditioner context
9665b89ad90SMark F. Adams 
9675b89ad90SMark F. Adams    Application Interface Routine: PCDestroy()
9685b89ad90SMark F. Adams */
969d71ae5a4SJacob Faibussowitsch PetscErrorCode PCDestroy_GAMG(PC pc)
970d71ae5a4SJacob Faibussowitsch {
9715b89ad90SMark F. Adams   PC_MG   *mg      = (PC_MG *)pc->data;
9725b89ad90SMark F. Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
9735b89ad90SMark F. Adams 
9745b89ad90SMark F. Adams   PetscFunctionBegin;
9759566063dSJacob Faibussowitsch   PetscCall(PCReset_GAMG(pc));
9761baa6e33SBarry Smith   if (pc_gamg->ops->destroy) PetscCall((*pc_gamg->ops->destroy)(pc));
9779566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc_gamg->ops));
9789566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc_gamg->gamg_type_name));
9799566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc_gamg));
9802e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetProcEqLim_C", NULL));
9812e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetCoarseEqLim_C", NULL));
9822e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetRepartition_C", NULL));
9832e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetEigenvalues_C", NULL));
9842e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetUseSAEstEig_C", NULL));
985e1cf1444SMark Adams   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetRecomputeEstEig_C", NULL));
9862e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetReuseInterpolation_C", NULL));
9872e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGASMSetUseAggs_C", NULL));
988d529f056Smarkadams4   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetParallelCoarseGridSolve_C", NULL));
9892e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetCpuPinCoarseGrids_C", NULL));
9902e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetCoarseGridLayoutType_C", NULL));
9912e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetThreshold_C", NULL));
9922e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetRankReductionFactors_C", NULL));
9932e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetThresholdScale_C", NULL));
9942e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetType_C", NULL));
9952e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGGetType_C", NULL));
9962e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetNlevels_C", NULL));
9978926f930SMark Adams   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGASMSetHEM_C", NULL));
998b65aec2dSMark Adams   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetInjectionIndices_C", NULL));
999b65aec2dSMark Adams   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetInjectionIndex_C", NULL));
10009566063dSJacob Faibussowitsch   PetscCall(PCDestroy_MG(pc));
10013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
10025b89ad90SMark F. Adams }
10035b89ad90SMark F. Adams 
1004676e1743SMark F. Adams /*@
1005f1580f4eSBarry Smith   PCGAMGSetProcEqLim - Set number of equations to aim for per process on the coarse grids via processor reduction in `PCGAMG`
1006676e1743SMark F. Adams 
1007c3339decSBarry Smith   Logically Collective
1008676e1743SMark F. Adams 
1009676e1743SMark F. Adams   Input Parameters:
10101cc46a46SBarry Smith + pc - the preconditioner context
10111cc46a46SBarry Smith - n  - the number of equations
1012676e1743SMark F. Adams 
1013676e1743SMark F. Adams   Options Database Key:
1014147403d9SBarry Smith . -pc_gamg_process_eq_limit <limit> - set the limit
1015676e1743SMark F. Adams 
101620f4b53cSBarry Smith   Level: intermediate
101720f4b53cSBarry Smith 
1018f1580f4eSBarry Smith   Note:
1019f1580f4eSBarry Smith   `PCGAMG` will reduce the number of MPI processes used directly on the coarse grids so that there are around <limit> equations on each process
1020cab9ed1eSBarry Smith   that has degrees of freedom
1021cab9ed1eSBarry Smith 
1022a077d33dSBarry Smith   Developer Note:
1023a077d33dSBarry Smith   Should be named `PCGAMGSetProcessEquationLimit()`.
1024a077d33dSBarry Smith 
1025a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMG`, `PCGAMGSetCoarseEqLim()`, `PCGAMGSetRankReductionFactors()`, `PCGAMGSetRepartition()`
1026676e1743SMark F. Adams @*/
1027d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGSetProcEqLim(PC pc, PetscInt n)
1028d71ae5a4SJacob Faibussowitsch {
1029676e1743SMark F. Adams   PetscFunctionBegin;
1030676e1743SMark F. Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1031cac4c232SBarry Smith   PetscTryMethod(pc, "PCGAMGSetProcEqLim_C", (PC, PetscInt), (pc, n));
10323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1033676e1743SMark F. Adams }
1034676e1743SMark F. Adams 
1035d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGSetProcEqLim_GAMG(PC pc, PetscInt n)
1036d71ae5a4SJacob Faibussowitsch {
1037c20e4228SMark F. Adams   PC_MG   *mg      = (PC_MG *)pc->data;
1038c20e4228SMark F. Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
1039676e1743SMark F. Adams 
1040676e1743SMark F. Adams   PetscFunctionBegin;
10419d5b6da9SMark F. Adams   if (n > 0) pc_gamg->min_eq_proc = n;
10423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1043676e1743SMark F. Adams }
1044676e1743SMark F. Adams 
1045389730f3SMark F. Adams /*@
1046f1580f4eSBarry Smith   PCGAMGSetCoarseEqLim - Set maximum number of equations on the coarsest grid of `PCGAMG`
1047389730f3SMark F. Adams 
1048c3339decSBarry Smith   Collective
1049389730f3SMark F. Adams 
1050389730f3SMark F. Adams   Input Parameters:
10511cc46a46SBarry Smith + pc - the preconditioner context
10521cc46a46SBarry Smith - n  - maximum number of equations to aim for
1053389730f3SMark F. Adams 
1054389730f3SMark F. Adams   Options Database Key:
1055147403d9SBarry Smith . -pc_gamg_coarse_eq_limit <limit> - set the limit
1056389730f3SMark F. Adams 
105720f4b53cSBarry Smith   Level: intermediate
105820f4b53cSBarry Smith 
1059f1580f4eSBarry Smith   Note:
1060f1580f4eSBarry Smith   For example -pc_gamg_coarse_eq_limit 1000 will stop coarsening once the coarse grid
106174329af1SBarry Smith   has less than 1000 unknowns.
106274329af1SBarry Smith 
1063a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMG`, `PCGAMGSetProcEqLim()`, `PCGAMGSetRankReductionFactors()`, `PCGAMGSetRepartition()`,
1064a077d33dSBarry Smith           `PCGAMGSetParallelCoarseGridSolve()`
1065389730f3SMark F. Adams @*/
1066d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGSetCoarseEqLim(PC pc, PetscInt n)
1067d71ae5a4SJacob Faibussowitsch {
1068389730f3SMark F. Adams   PetscFunctionBegin;
1069389730f3SMark F. Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1070cac4c232SBarry Smith   PetscTryMethod(pc, "PCGAMGSetCoarseEqLim_C", (PC, PetscInt), (pc, n));
10713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1072389730f3SMark F. Adams }
1073389730f3SMark F. Adams 
1074d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGSetCoarseEqLim_GAMG(PC pc, PetscInt n)
1075d71ae5a4SJacob Faibussowitsch {
1076389730f3SMark F. Adams   PC_MG   *mg      = (PC_MG *)pc->data;
1077389730f3SMark F. Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
1078389730f3SMark F. Adams 
1079389730f3SMark F. Adams   PetscFunctionBegin;
10809d5b6da9SMark F. Adams   if (n > 0) pc_gamg->coarse_eq_limit = n;
10813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1082389730f3SMark F. Adams }
1083389730f3SMark F. Adams 
1084676e1743SMark F. Adams /*@
1085f1580f4eSBarry Smith   PCGAMGSetRepartition - Repartition the degrees of freedom across the processors on the coarser grids when reducing the number of MPI ranks to use
1086676e1743SMark F. Adams 
1087c3339decSBarry Smith   Collective
1088676e1743SMark F. Adams 
1089676e1743SMark F. Adams   Input Parameters:
10901cc46a46SBarry Smith + pc - the preconditioner context
1091f1580f4eSBarry Smith - n  - `PETSC_TRUE` or `PETSC_FALSE`
1092676e1743SMark F. Adams 
1093676e1743SMark F. Adams   Options Database Key:
1094147403d9SBarry Smith . -pc_gamg_repartition <true,false> - turn on the repartitioning
1095676e1743SMark F. Adams 
109620f4b53cSBarry Smith   Level: intermediate
109720f4b53cSBarry Smith 
1098f1580f4eSBarry Smith   Note:
1099a077d33dSBarry Smith   This will generally improve the loading balancing of the work on each level so the solves will be faster but it adds to the
1100a077d33dSBarry Smith   preconditioner setup time.
1101cab9ed1eSBarry Smith 
1102a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMG`, `PCGAMGSetProcEqLim()`, `PCGAMGSetRankReductionFactors()`
1103676e1743SMark F. Adams @*/
1104d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGSetRepartition(PC pc, PetscBool n)
1105d71ae5a4SJacob Faibussowitsch {
1106676e1743SMark F. Adams   PetscFunctionBegin;
1107676e1743SMark F. Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1108cac4c232SBarry Smith   PetscTryMethod(pc, "PCGAMGSetRepartition_C", (PC, PetscBool), (pc, n));
11093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1110676e1743SMark F. Adams }
1111676e1743SMark F. Adams 
1112d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGSetRepartition_GAMG(PC pc, PetscBool n)
1113d71ae5a4SJacob Faibussowitsch {
1114c20e4228SMark F. Adams   PC_MG   *mg      = (PC_MG *)pc->data;
1115c20e4228SMark F. Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
1116676e1743SMark F. Adams 
1117676e1743SMark F. Adams   PetscFunctionBegin;
11189d5b6da9SMark F. Adams   pc_gamg->repart = n;
11193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1120676e1743SMark F. Adams }
1121676e1743SMark F. Adams 
1122dfd5c07aSMark F. Adams /*@
1123f1580f4eSBarry Smith   PCGAMGSetUseSAEstEig - Use the eigen estimate from smoothed aggregation for the Chebyshev smoother during the solution process
112418c3aa7eSMark 
1125c3339decSBarry Smith   Collective
112618c3aa7eSMark 
112718c3aa7eSMark   Input Parameters:
112818c3aa7eSMark + pc - the preconditioner context
1129e1cf1444SMark Adams - b  - flag
113018c3aa7eSMark 
113118c3aa7eSMark   Options Database Key:
1132147403d9SBarry Smith . -pc_gamg_use_sa_esteig <true,false> - use the eigen estimate
113318c3aa7eSMark 
113420f4b53cSBarry Smith   Level: advanced
113520f4b53cSBarry Smith 
113618c3aa7eSMark   Notes:
11377e6512fdSJed Brown   Smoothed aggregation constructs the smoothed prolongator $P = (I - \omega D^{-1} A) T$ where $T$ is the tentative prolongator and $D$ is the diagonal of $A$.
1138f1580f4eSBarry Smith   Eigenvalue estimates (based on a few `PCCG` or `PCGMRES` iterations) are computed to choose $\omega$ so that this is a stable smoothing operation.
1139a077d33dSBarry Smith   If `KSPCHEBYSHEV` with `PCJACOBI` (diagonal) preconditioning is used for smoothing on the finest level, then the eigenvalue estimates
1140a077d33dSBarry Smith   can be reused during the solution process.
1141a077d33dSBarry Smith   This option is only used when the smoother uses `PCJACOBI`, and should be turned off when a different `PCJacobiType` is used.
1142efe053fcSJed Brown   It became default in PETSc 3.17.
114318c3aa7eSMark 
1144a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMG`, `KSPChebyshevSetEigenvalues()`, `KSPChebyshevEstEigSet()`, `PCGAMGSetRecomputeEstEig()`
114518c3aa7eSMark @*/
1146e1cf1444SMark Adams PetscErrorCode PCGAMGSetUseSAEstEig(PC pc, PetscBool b)
1147d71ae5a4SJacob Faibussowitsch {
114818c3aa7eSMark   PetscFunctionBegin;
114918c3aa7eSMark   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1150e1cf1444SMark Adams   PetscTryMethod(pc, "PCGAMGSetUseSAEstEig_C", (PC, PetscBool), (pc, b));
11513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
115218c3aa7eSMark }
115318c3aa7eSMark 
1154e1cf1444SMark Adams static PetscErrorCode PCGAMGSetUseSAEstEig_GAMG(PC pc, PetscBool b)
1155d71ae5a4SJacob Faibussowitsch {
115618c3aa7eSMark   PC_MG   *mg      = (PC_MG *)pc->data;
115718c3aa7eSMark   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
115818c3aa7eSMark 
115918c3aa7eSMark   PetscFunctionBegin;
1160e1cf1444SMark Adams   pc_gamg->use_sa_esteig = b;
1161e1cf1444SMark Adams   PetscFunctionReturn(PETSC_SUCCESS);
1162e1cf1444SMark Adams }
1163e1cf1444SMark Adams 
1164e1cf1444SMark Adams /*@
1165a077d33dSBarry Smith   PCGAMGSetRecomputeEstEig - Set flag for Chebyshev smoothers to recompute the eigen estimates when a new matrix is used
1166e1cf1444SMark Adams 
1167e1cf1444SMark Adams   Collective
1168e1cf1444SMark Adams 
1169e1cf1444SMark Adams   Input Parameters:
1170e1cf1444SMark Adams + pc - the preconditioner context
1171a077d33dSBarry Smith - b  - flag, default is `PETSC_TRUE`
1172e1cf1444SMark Adams 
1173e1cf1444SMark Adams   Options Database Key:
1174e1cf1444SMark Adams . -pc_gamg_recompute_esteig <true> - use the eigen estimate
1175e1cf1444SMark Adams 
1176e1cf1444SMark Adams   Level: advanced
1177e1cf1444SMark Adams 
1178a077d33dSBarry Smith   Note:
1179a077d33dSBarry Smith   If the matrix changes only slightly in a new solve using ``PETSC_FALSE`` will save time in the setting up of the preconditioner
1180a077d33dSBarry Smith   and may not affect the solution time much.
1181a077d33dSBarry Smith 
1182a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMG`, `KSPChebyshevSetEigenvalues()`, `KSPChebyshevEstEigSet()`
1183e1cf1444SMark Adams @*/
1184e1cf1444SMark Adams PetscErrorCode PCGAMGSetRecomputeEstEig(PC pc, PetscBool b)
1185e1cf1444SMark Adams {
1186e1cf1444SMark Adams   PetscFunctionBegin;
1187e1cf1444SMark Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1188e1cf1444SMark Adams   PetscTryMethod(pc, "PCGAMGSetRecomputeEstEig_C", (PC, PetscBool), (pc, b));
1189e1cf1444SMark Adams   PetscFunctionReturn(PETSC_SUCCESS);
1190e1cf1444SMark Adams }
1191e1cf1444SMark Adams 
1192e1cf1444SMark Adams static PetscErrorCode PCGAMGSetRecomputeEstEig_GAMG(PC pc, PetscBool b)
1193e1cf1444SMark Adams {
1194e1cf1444SMark Adams   PC_MG   *mg      = (PC_MG *)pc->data;
1195e1cf1444SMark Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
1196e1cf1444SMark Adams 
1197e1cf1444SMark Adams   PetscFunctionBegin;
1198e1cf1444SMark Adams   pc_gamg->recompute_esteig = b;
11993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
120018c3aa7eSMark }
120118c3aa7eSMark 
120218c3aa7eSMark /*@
1203f1580f4eSBarry Smith   PCGAMGSetEigenvalues - Set WHAT eigenvalues WHY?
120418c3aa7eSMark 
1205c3339decSBarry Smith   Collective
120618c3aa7eSMark 
120718c3aa7eSMark   Input Parameters:
120818c3aa7eSMark + pc   - the preconditioner context
1209feefa0e1SJacob Faibussowitsch . emax - max eigenvalue
1210feefa0e1SJacob Faibussowitsch - emin - min eigenvalue
121118c3aa7eSMark 
121218c3aa7eSMark   Options Database Key:
1213147403d9SBarry Smith . -pc_gamg_eigenvalues <emin,emax> - estimates of the eigenvalues
121418c3aa7eSMark 
121518c3aa7eSMark   Level: intermediate
121618c3aa7eSMark 
1217a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMG`, `PCGAMGSetUseSAEstEig()`
121818c3aa7eSMark @*/
1219d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGSetEigenvalues(PC pc, PetscReal emax, PetscReal emin)
1220d71ae5a4SJacob Faibussowitsch {
122118c3aa7eSMark   PetscFunctionBegin;
122218c3aa7eSMark   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1223cac4c232SBarry Smith   PetscTryMethod(pc, "PCGAMGSetEigenvalues_C", (PC, PetscReal, PetscReal), (pc, emax, emin));
12243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
122518c3aa7eSMark }
122641ffd417SStefano Zampini 
1227d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGSetEigenvalues_GAMG(PC pc, PetscReal emax, PetscReal emin)
1228d71ae5a4SJacob Faibussowitsch {
122918c3aa7eSMark   PC_MG   *mg      = (PC_MG *)pc->data;
123018c3aa7eSMark   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
123118c3aa7eSMark 
123218c3aa7eSMark   PetscFunctionBegin;
12335f80ce2aSJacob Faibussowitsch   PetscCheck(emax > emin, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Maximum eigenvalue must be larger than minimum: max %g min %g", (double)emax, (double)emin);
12345f80ce2aSJacob Faibussowitsch   PetscCheck(emax * emin > 0.0, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Both eigenvalues must be of the same sign: max %g min %g", (double)emax, (double)emin);
123518c3aa7eSMark   pc_gamg->emax = emax;
123618c3aa7eSMark   pc_gamg->emin = emin;
12373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
123818c3aa7eSMark }
123918c3aa7eSMark 
124018c3aa7eSMark /*@
1241f1580f4eSBarry Smith   PCGAMGSetReuseInterpolation - Reuse prolongation when rebuilding a `PCGAMG` algebraic multigrid preconditioner
1242dfd5c07aSMark F. Adams 
1243c3339decSBarry Smith   Collective
1244dfd5c07aSMark F. Adams 
1245dfd5c07aSMark F. Adams   Input Parameters:
12461cc46a46SBarry Smith + pc - the preconditioner context
1247f1580f4eSBarry Smith - n  - `PETSC_TRUE` or `PETSC_FALSE`
1248dfd5c07aSMark F. Adams 
1249dfd5c07aSMark F. Adams   Options Database Key:
1250147403d9SBarry Smith . -pc_gamg_reuse_interpolation <true,false> - reuse the previous interpolation
1251dfd5c07aSMark F. Adams 
1252dfd5c07aSMark F. Adams   Level: intermediate
1253dfd5c07aSMark F. Adams 
1254f1580f4eSBarry Smith   Note:
1255147403d9SBarry Smith   May negatively affect the convergence rate of the method on new matrices if the matrix entries change a great deal, but allows
1256cab9ed1eSBarry Smith   rebuilding the preconditioner quicker.
1257cab9ed1eSBarry Smith 
1258a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMG`
1259dfd5c07aSMark F. Adams @*/
1260d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGSetReuseInterpolation(PC pc, PetscBool n)
1261d71ae5a4SJacob Faibussowitsch {
1262dfd5c07aSMark F. Adams   PetscFunctionBegin;
1263dfd5c07aSMark F. Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1264cac4c232SBarry Smith   PetscTryMethod(pc, "PCGAMGSetReuseInterpolation_C", (PC, PetscBool), (pc, n));
12653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1266dfd5c07aSMark F. Adams }
1267dfd5c07aSMark F. Adams 
1268d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGSetReuseInterpolation_GAMG(PC pc, PetscBool n)
1269d71ae5a4SJacob Faibussowitsch {
1270dfd5c07aSMark F. Adams   PC_MG   *mg      = (PC_MG *)pc->data;
1271dfd5c07aSMark F. Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
1272dfd5c07aSMark F. Adams 
1273dfd5c07aSMark F. Adams   PetscFunctionBegin;
1274dfd5c07aSMark F. Adams   pc_gamg->reuse_prol = n;
12753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1276dfd5c07aSMark F. Adams }
1277dfd5c07aSMark F. Adams 
1278ffc955d6SMark F. Adams /*@
1279a077d33dSBarry Smith   PCGAMGASMSetUseAggs - Have the `PCGAMG` smoother on each level use `PCASM` where the aggregates defined by the coarsening process are
1280a077d33dSBarry Smith   the subdomains for the additive Schwarz preconditioner used as the smoother
1281ffc955d6SMark F. Adams 
1282c3339decSBarry Smith   Collective
1283ffc955d6SMark F. Adams 
1284ffc955d6SMark F. Adams   Input Parameters:
1285cab9ed1eSBarry Smith + pc  - the preconditioner context
1286f1580f4eSBarry Smith - flg - `PETSC_TRUE` to use aggregates, `PETSC_FALSE` to not
1287ffc955d6SMark F. Adams 
1288ffc955d6SMark F. Adams   Options Database Key:
1289147403d9SBarry Smith . -pc_gamg_asm_use_agg <true,false> - use aggregates to define the additive Schwarz subdomains
1290ffc955d6SMark F. Adams 
1291ffc955d6SMark F. Adams   Level: intermediate
1292ffc955d6SMark F. Adams 
1293a077d33dSBarry Smith   Note:
1294a077d33dSBarry Smith   This option automatically sets the preconditioner on the levels to be `PCASM`.
1295a077d33dSBarry Smith 
1296a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMG`, `PCASM`, `PCSetType`
1297ffc955d6SMark F. Adams @*/
1298d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGASMSetUseAggs(PC pc, PetscBool flg)
1299d71ae5a4SJacob Faibussowitsch {
1300ffc955d6SMark F. Adams   PetscFunctionBegin;
1301ffc955d6SMark F. Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1302cac4c232SBarry Smith   PetscTryMethod(pc, "PCGAMGASMSetUseAggs_C", (PC, PetscBool), (pc, flg));
13033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1304ffc955d6SMark F. Adams }
1305ffc955d6SMark F. Adams 
1306d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGASMSetUseAggs_GAMG(PC pc, PetscBool flg)
1307d71ae5a4SJacob Faibussowitsch {
1308ffc955d6SMark F. Adams   PC_MG   *mg      = (PC_MG *)pc->data;
1309ffc955d6SMark F. Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
1310ffc955d6SMark F. Adams 
1311ffc955d6SMark F. Adams   PetscFunctionBegin;
1312cab9ed1eSBarry Smith   pc_gamg->use_aggs_in_asm = flg;
13133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1314ffc955d6SMark F. Adams }
1315ffc955d6SMark F. Adams 
1316171cca9aSMark Adams /*@
1317d529f056Smarkadams4   PCGAMGSetParallelCoarseGridSolve - allow a parallel coarse grid solver
1318171cca9aSMark Adams 
1319c3339decSBarry Smith   Collective
1320171cca9aSMark Adams 
1321171cca9aSMark Adams   Input Parameters:
1322171cca9aSMark Adams + pc  - the preconditioner context
1323f1580f4eSBarry Smith - flg - `PETSC_TRUE` to not force coarse grid onto one processor
1324171cca9aSMark Adams 
1325171cca9aSMark Adams   Options Database Key:
1326a077d33dSBarry Smith . -pc_gamg_parallel_coarse_grid_solver - use a parallel coarse grid solver
1327171cca9aSMark Adams 
1328171cca9aSMark Adams   Level: intermediate
1329171cca9aSMark Adams 
1330a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMG`, `PCGAMGSetCoarseGridLayoutType()`, `PCGAMGSetCpuPinCoarseGrids()`, `PCGAMGSetRankReductionFactors()`
1331171cca9aSMark Adams @*/
1332d529f056Smarkadams4 PetscErrorCode PCGAMGSetParallelCoarseGridSolve(PC pc, PetscBool flg)
1333d71ae5a4SJacob Faibussowitsch {
1334171cca9aSMark Adams   PetscFunctionBegin;
1335171cca9aSMark Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1336d529f056Smarkadams4   PetscTryMethod(pc, "PCGAMGSetParallelCoarseGridSolve_C", (PC, PetscBool), (pc, flg));
13373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1338171cca9aSMark Adams }
1339171cca9aSMark Adams 
1340d529f056Smarkadams4 static PetscErrorCode PCGAMGSetParallelCoarseGridSolve_GAMG(PC pc, PetscBool flg)
1341d71ae5a4SJacob Faibussowitsch {
1342171cca9aSMark Adams   PC_MG   *mg      = (PC_MG *)pc->data;
1343171cca9aSMark Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
1344171cca9aSMark Adams 
1345171cca9aSMark Adams   PetscFunctionBegin;
1346171cca9aSMark Adams   pc_gamg->use_parallel_coarse_grid_solver = flg;
13473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1348ffc955d6SMark F. Adams }
1349ffc955d6SMark F. Adams 
13504ef23d27SMark F. Adams /*@
1351f1580f4eSBarry Smith   PCGAMGSetCpuPinCoarseGrids - pin the coarse grids created in `PCGAMG` to run only on the CPU since the problems may be too small to run efficiently on the GPUs
1352ce7c7f2fSMark Adams 
1353c3339decSBarry Smith   Collective
1354ce7c7f2fSMark Adams 
1355ce7c7f2fSMark Adams   Input Parameters:
1356ce7c7f2fSMark Adams + pc  - the preconditioner context
1357f1580f4eSBarry Smith - flg - `PETSC_TRUE` to pin coarse grids to the CPU
1358ce7c7f2fSMark Adams 
1359ce7c7f2fSMark Adams   Options Database Key:
1360147403d9SBarry Smith . -pc_gamg_cpu_pin_coarse_grids - pin the coarse grids to the CPU
1361ce7c7f2fSMark Adams 
1362ce7c7f2fSMark Adams   Level: intermediate
1363ce7c7f2fSMark Adams 
1364a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMG`, `PCGAMGSetCoarseGridLayoutType()`, `PCGAMGSetParallelCoarseGridSolve()`
1365ce7c7f2fSMark Adams @*/
1366d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGSetCpuPinCoarseGrids(PC pc, PetscBool flg)
1367d71ae5a4SJacob Faibussowitsch {
1368ce7c7f2fSMark Adams   PetscFunctionBegin;
1369ce7c7f2fSMark Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1370cac4c232SBarry Smith   PetscTryMethod(pc, "PCGAMGSetCpuPinCoarseGrids_C", (PC, PetscBool), (pc, flg));
13713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1372ce7c7f2fSMark Adams }
1373ce7c7f2fSMark Adams 
1374d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGSetCpuPinCoarseGrids_GAMG(PC pc, PetscBool flg)
1375d71ae5a4SJacob Faibussowitsch {
1376ce7c7f2fSMark Adams   PC_MG   *mg      = (PC_MG *)pc->data;
1377ce7c7f2fSMark Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
1378ce7c7f2fSMark Adams 
1379ce7c7f2fSMark Adams   PetscFunctionBegin;
1380ce7c7f2fSMark Adams   pc_gamg->cpu_pin_coarse_grids = flg;
13813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1382ce7c7f2fSMark Adams }
1383ce7c7f2fSMark Adams 
1384ce7c7f2fSMark Adams /*@
1385147403d9SBarry Smith   PCGAMGSetCoarseGridLayoutType - place coarse grids on processors with natural order (compact type)
1386ce7c7f2fSMark Adams 
1387c3339decSBarry Smith   Collective
1388ce7c7f2fSMark Adams 
1389ce7c7f2fSMark Adams   Input Parameters:
1390ce7c7f2fSMark Adams + pc  - the preconditioner context
1391f1580f4eSBarry Smith - flg - `PCGAMGLayoutType` type, either `PCGAMG_LAYOUT_COMPACT` or `PCGAMG_LAYOUT_SPREAD`
1392ce7c7f2fSMark Adams 
1393ce7c7f2fSMark Adams   Options Database Key:
1394147403d9SBarry Smith . -pc_gamg_coarse_grid_layout_type - place the coarse grids with natural ordering
1395ce7c7f2fSMark Adams 
1396ce7c7f2fSMark Adams   Level: intermediate
1397ce7c7f2fSMark Adams 
1398a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMG`, `PCGAMGSetParallelCoarseGridSolve()`, `PCGAMGSetCpuPinCoarseGrids()`, `PCGAMGLayoutType`, `PCGAMG_LAYOUT_COMPACT`, `PCGAMG_LAYOUT_SPREAD`
1399ce7c7f2fSMark Adams @*/
1400d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGSetCoarseGridLayoutType(PC pc, PCGAMGLayoutType flg)
1401d71ae5a4SJacob Faibussowitsch {
1402ce7c7f2fSMark Adams   PetscFunctionBegin;
1403ce7c7f2fSMark Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1404cac4c232SBarry Smith   PetscTryMethod(pc, "PCGAMGSetCoarseGridLayoutType_C", (PC, PCGAMGLayoutType), (pc, flg));
14053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1406ce7c7f2fSMark Adams }
1407ce7c7f2fSMark Adams 
1408d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGSetCoarseGridLayoutType_GAMG(PC pc, PCGAMGLayoutType flg)
1409d71ae5a4SJacob Faibussowitsch {
1410ce7c7f2fSMark Adams   PC_MG   *mg      = (PC_MG *)pc->data;
1411ce7c7f2fSMark Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
1412ce7c7f2fSMark Adams 
1413ce7c7f2fSMark Adams   PetscFunctionBegin;
1414ce7c7f2fSMark Adams   pc_gamg->layout_type = flg;
14153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1416ce7c7f2fSMark Adams }
1417ce7c7f2fSMark Adams 
1418ce7c7f2fSMark Adams /*@
1419f1580f4eSBarry Smith   PCGAMGSetNlevels -  Sets the maximum number of levels `PCGAMG` will use
14204ef23d27SMark F. Adams 
14218926f930SMark Adams   Collective
14224ef23d27SMark F. Adams 
14234ef23d27SMark F. Adams   Input Parameters:
14241cc46a46SBarry Smith + pc - the preconditioner
14251cc46a46SBarry Smith - n  - the maximum number of levels to use
14264ef23d27SMark F. Adams 
14274ef23d27SMark F. Adams   Options Database Key:
1428147403d9SBarry Smith . -pc_mg_levels <n> - set the maximum number of levels to allow
14294ef23d27SMark F. Adams 
14304ef23d27SMark F. Adams   Level: intermediate
14314ef23d27SMark F. Adams 
1432feefa0e1SJacob Faibussowitsch   Developer Notes:
1433f1580f4eSBarry Smith   Should be called `PCGAMGSetMaximumNumberlevels()` and possible be shared with `PCMG`
1434f1580f4eSBarry Smith 
1435a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMG`
14364ef23d27SMark F. Adams @*/
1437d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGSetNlevels(PC pc, PetscInt n)
1438d71ae5a4SJacob Faibussowitsch {
14394ef23d27SMark F. Adams   PetscFunctionBegin;
14404ef23d27SMark F. Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1441cac4c232SBarry Smith   PetscTryMethod(pc, "PCGAMGSetNlevels_C", (PC, PetscInt), (pc, n));
14423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14434ef23d27SMark F. Adams }
14444ef23d27SMark F. Adams 
1445d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGSetNlevels_GAMG(PC pc, PetscInt n)
1446d71ae5a4SJacob Faibussowitsch {
14474ef23d27SMark F. Adams   PC_MG   *mg      = (PC_MG *)pc->data;
14484ef23d27SMark F. Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
14494ef23d27SMark F. Adams 
14504ef23d27SMark F. Adams   PetscFunctionBegin;
14519d5b6da9SMark F. Adams   pc_gamg->Nlevels = n;
14523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14534ef23d27SMark F. Adams }
14544ef23d27SMark F. Adams 
14553542efc5SMark F. Adams /*@
14568926f930SMark Adams   PCGAMGASMSetHEM -  Sets the number of HEM matching passed
14578926f930SMark Adams 
14588926f930SMark Adams   Collective
14598926f930SMark Adams 
14608926f930SMark Adams   Input Parameters:
14618926f930SMark Adams + pc - the preconditioner
14628926f930SMark Adams - n  - number of HEM matching passed to construct ASM subdomains
14638926f930SMark Adams 
14648926f930SMark Adams   Options Database Key:
14658926f930SMark Adams . -pc_gamg_asm_hem <n> - set the number of HEM matching passed
14668926f930SMark Adams 
14678926f930SMark Adams   Level: intermediate
14688926f930SMark Adams 
14698926f930SMark Adams   Developer Notes:
14708926f930SMark Adams   Should be called `PCGAMGSetMaximumNumberlevels()` and possible be shared with `PCMG`
14718926f930SMark Adams 
1472a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMG`
14738926f930SMark Adams @*/
14748926f930SMark Adams PetscErrorCode PCGAMGASMSetHEM(PC pc, PetscInt n)
14758926f930SMark Adams {
14768926f930SMark Adams   PetscFunctionBegin;
14778926f930SMark Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
14788926f930SMark Adams   PetscTryMethod(pc, "PCGAMGASMSetHEM_C", (PC, PetscInt), (pc, n));
14798926f930SMark Adams   PetscFunctionReturn(PETSC_SUCCESS);
14808926f930SMark Adams }
14818926f930SMark Adams 
14828926f930SMark Adams static PetscErrorCode PCGAMGASMSetHEM_GAMG(PC pc, PetscInt n)
14838926f930SMark Adams {
14848926f930SMark Adams   PC_MG   *mg      = (PC_MG *)pc->data;
14858926f930SMark Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
14868926f930SMark Adams 
14878926f930SMark Adams   PetscFunctionBegin;
14888926f930SMark Adams   pc_gamg->asm_hem_aggs = n;
14898926f930SMark Adams   PetscFunctionReturn(PETSC_SUCCESS);
14908926f930SMark Adams }
14918926f930SMark Adams 
14928926f930SMark Adams /*@
14933542efc5SMark F. Adams   PCGAMGSetThreshold - Relative threshold to use for dropping edges in aggregation graph
14943542efc5SMark F. Adams 
149520f4b53cSBarry Smith   Not Collective
14963542efc5SMark F. Adams 
14973542efc5SMark F. Adams   Input Parameters:
14981cc46a46SBarry Smith + pc - the preconditioner context
1499c9567895SMark . v  - array of threshold values for finest n levels; 0.0 means keep all nonzero entries in the graph; negative means keep even zero entries in the graph
1500055c8bd0SJed Brown - n  - number of threshold values provided in array
15013542efc5SMark F. Adams 
15023542efc5SMark F. Adams   Options Database Key:
1503147403d9SBarry Smith . -pc_gamg_threshold <threshold> - the threshold to drop edges
15043542efc5SMark F. Adams 
150520f4b53cSBarry Smith   Level: intermediate
150620f4b53cSBarry Smith 
150795452b02SPatrick Sanan   Notes:
1508af3c827dSMark Adams   Increasing the threshold decreases the rate of coarsening. Conversely reducing the threshold increases the rate of coarsening (aggressive coarsening) and thereby reduces the complexity of the coarse grids, and generally results in slower solver converge rates. Reducing coarse grid complexity reduced the complexity of Galerkin coarse grid construction considerably.
1509f1580f4eSBarry Smith   Before coarsening or aggregating the graph, `PCGAMG` removes small values from the graph with this threshold, and thus reducing the coupling in the graph and a different (perhaps better) coarser set of points.
1510cab9ed1eSBarry Smith 
151120f4b53cSBarry Smith   If `n` is less than the total number of coarsenings (see `PCGAMGSetNlevels()`), then threshold scaling (see `PCGAMGSetThresholdScale()`) is used for each successive coarsening.
1512f1580f4eSBarry Smith   In this case, `PCGAMGSetThresholdScale()` must be called before `PCGAMGSetThreshold()`.
151320f4b53cSBarry Smith   If `n` is greater than the total number of levels, the excess entries in threshold will not be used.
15143542efc5SMark F. Adams 
1515a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMG`, `PCGAMGSetAggressiveLevels()`, `PCGAMGMISkSetAggressive()`, `PCGAMGSetMinDegreeOrderingMISk()`, `PCGAMGSetThresholdScale()`
15163542efc5SMark F. Adams @*/
1517d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGSetThreshold(PC pc, PetscReal v[], PetscInt n)
1518d71ae5a4SJacob Faibussowitsch {
15193542efc5SMark F. Adams   PetscFunctionBegin;
15203542efc5SMark F. Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
15214f572ea9SToby Isaac   if (n) PetscAssertPointer(v, 2);
1522cac4c232SBarry Smith   PetscTryMethod(pc, "PCGAMGSetThreshold_C", (PC, PetscReal[], PetscInt), (pc, v, n));
15233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15243542efc5SMark F. Adams }
15253542efc5SMark F. Adams 
1526d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGSetThreshold_GAMG(PC pc, PetscReal v[], PetscInt n)
1527d71ae5a4SJacob Faibussowitsch {
1528c20e4228SMark F. Adams   PC_MG   *mg      = (PC_MG *)pc->data;
1529c20e4228SMark F. Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
1530c1eae691SMark Adams   PetscInt i;
15314d86920dSPierre Jolivet 
1532c1eae691SMark Adams   PetscFunctionBegin;
1533055c8bd0SJed Brown   for (i = 0; i < PetscMin(n, PETSC_MG_MAXLEVELS); i++) pc_gamg->threshold[i] = v[i];
1534055c8bd0SJed Brown   for (; i < PETSC_MG_MAXLEVELS; i++) pc_gamg->threshold[i] = pc_gamg->threshold[i - 1] * pc_gamg->threshold_scale;
15353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1536c1eae691SMark Adams }
1537c1eae691SMark Adams 
1538c1eae691SMark Adams /*@
1539f1580f4eSBarry Smith   PCGAMGSetRankReductionFactors - Set a manual schedule for MPI rank reduction on coarse grids
1540c9567895SMark 
1541c3339decSBarry Smith   Collective
1542c9567895SMark 
1543c9567895SMark   Input Parameters:
1544c9567895SMark + pc - the preconditioner context
1545f1580f4eSBarry Smith . v  - array of reduction factors. 0 for first value forces a reduction to one process/device on first level in CUDA
1546c9567895SMark - n  - number of values provided in array
1547c9567895SMark 
1548c9567895SMark   Options Database Key:
1549147403d9SBarry Smith . -pc_gamg_rank_reduction_factors <factors> - provide the schedule
1550c9567895SMark 
1551c9567895SMark   Level: intermediate
1552c9567895SMark 
1553a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMG`, `PCGAMGSetProcEqLim()`, `PCGAMGSetCoarseEqLim()`, `PCGAMGSetParallelCoarseGridSolve()`
1554c9567895SMark @*/
1555d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGSetRankReductionFactors(PC pc, PetscInt v[], PetscInt n)
1556d71ae5a4SJacob Faibussowitsch {
1557c9567895SMark   PetscFunctionBegin;
1558c9567895SMark   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
15594f572ea9SToby Isaac   if (n) PetscAssertPointer(v, 2);
1560cac4c232SBarry Smith   PetscTryMethod(pc, "PCGAMGSetRankReductionFactors_C", (PC, PetscInt[], PetscInt), (pc, v, n));
15613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1562c9567895SMark }
1563c9567895SMark 
1564d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGSetRankReductionFactors_GAMG(PC pc, PetscInt v[], PetscInt n)
1565d71ae5a4SJacob Faibussowitsch {
1566c9567895SMark   PC_MG   *mg      = (PC_MG *)pc->data;
1567c9567895SMark   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
1568c9567895SMark   PetscInt i;
15694d86920dSPierre Jolivet 
1570c9567895SMark   PetscFunctionBegin;
1571c9567895SMark   for (i = 0; i < PetscMin(n, PETSC_MG_MAXLEVELS); i++) pc_gamg->level_reduction_factors[i] = v[i];
1572c9567895SMark   for (; i < PETSC_MG_MAXLEVELS; i++) pc_gamg->level_reduction_factors[i] = -1; /* 0 stop putting one process/device on first level */
15733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1574c9567895SMark }
1575c9567895SMark 
1576c9567895SMark /*@
1577c1eae691SMark Adams   PCGAMGSetThresholdScale - Relative threshold reduction at each level
1578c1eae691SMark Adams 
157920f4b53cSBarry Smith   Not Collective
1580c1eae691SMark Adams 
1581c1eae691SMark Adams   Input Parameters:
1582c1eae691SMark Adams + pc - the preconditioner context
1583feefa0e1SJacob Faibussowitsch - v  - the threshold value reduction, usually < 1.0
1584c1eae691SMark Adams 
1585c1eae691SMark Adams   Options Database Key:
1586147403d9SBarry Smith . -pc_gamg_threshold_scale <v> - set the relative threshold reduction on each level
1587c1eae691SMark Adams 
158820f4b53cSBarry Smith   Level: advanced
158920f4b53cSBarry Smith 
1590f1580f4eSBarry Smith   Note:
1591f1580f4eSBarry Smith   The initial threshold (for an arbitrary number of levels starting from the finest) can be set with `PCGAMGSetThreshold()`.
1592f1580f4eSBarry Smith   This scaling is used for each subsequent coarsening, but must be called before `PCGAMGSetThreshold()`.
1593055c8bd0SJed Brown 
1594a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMG`, `PCGAMGSetThreshold()`
1595c1eae691SMark Adams @*/
1596d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGSetThresholdScale(PC pc, PetscReal v)
1597d71ae5a4SJacob Faibussowitsch {
15983542efc5SMark F. Adams   PetscFunctionBegin;
1599c1eae691SMark Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1600cac4c232SBarry Smith   PetscTryMethod(pc, "PCGAMGSetThresholdScale_C", (PC, PetscReal), (pc, v));
16013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1602c1eae691SMark Adams }
1603c1eae691SMark Adams 
1604d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGSetThresholdScale_GAMG(PC pc, PetscReal v)
1605d71ae5a4SJacob Faibussowitsch {
1606c1eae691SMark Adams   PC_MG   *mg      = (PC_MG *)pc->data;
1607c1eae691SMark Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
16084d86920dSPierre Jolivet 
1609c1eae691SMark Adams   PetscFunctionBegin;
1610c1eae691SMark Adams   pc_gamg->threshold_scale = v;
16113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16123542efc5SMark F. Adams }
16133542efc5SMark F. Adams 
1614cc4c1da9SBarry Smith /*@
1615f1580f4eSBarry Smith   PCGAMGSetType - Set the type of algorithm `PCGAMG` should use
1616676e1743SMark F. Adams 
1617c3339decSBarry Smith   Collective
1618676e1743SMark F. Adams 
1619676e1743SMark F. Adams   Input Parameters:
1620c60c7ad4SBarry Smith + pc   - the preconditioner context
1621f1580f4eSBarry Smith - type - `PCGAMGAGG`, `PCGAMGGEO`, or `PCGAMGCLASSICAL`
1622676e1743SMark F. Adams 
1623676e1743SMark F. Adams   Options Database Key:
1624a077d33dSBarry Smith . -pc_gamg_type <agg,geo,classical> - type of algebraic multigrid to apply - only agg is supported
1625676e1743SMark F. Adams 
1626676e1743SMark F. Adams   Level: intermediate
1627676e1743SMark F. Adams 
1628a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMGGetType()`, `PCGAMG`, `PCGAMGType`
1629676e1743SMark F. Adams @*/
1630d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGSetType(PC pc, PCGAMGType type)
1631d71ae5a4SJacob Faibussowitsch {
1632676e1743SMark F. Adams   PetscFunctionBegin;
1633676e1743SMark F. Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1634cac4c232SBarry Smith   PetscTryMethod(pc, "PCGAMGSetType_C", (PC, PCGAMGType), (pc, type));
16353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1636676e1743SMark F. Adams }
1637676e1743SMark F. Adams 
1638cc4c1da9SBarry Smith /*@
1639f1580f4eSBarry Smith   PCGAMGGetType - Get the type of algorithm `PCGAMG` will use
1640c60c7ad4SBarry Smith 
1641c3339decSBarry Smith   Collective
1642c60c7ad4SBarry Smith 
1643c60c7ad4SBarry Smith   Input Parameter:
1644c60c7ad4SBarry Smith . pc - the preconditioner context
1645c60c7ad4SBarry Smith 
1646c60c7ad4SBarry Smith   Output Parameter:
1647c60c7ad4SBarry Smith . type - the type of algorithm used
1648c60c7ad4SBarry Smith 
1649c60c7ad4SBarry Smith   Level: intermediate
1650c60c7ad4SBarry Smith 
1651a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCGAMG`, `PCGAMGSetType()`, `PCGAMGType`
1652c60c7ad4SBarry Smith @*/
1653d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGGetType(PC pc, PCGAMGType *type)
1654d71ae5a4SJacob Faibussowitsch {
1655c60c7ad4SBarry Smith   PetscFunctionBegin;
1656c60c7ad4SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1657cac4c232SBarry Smith   PetscUseMethod(pc, "PCGAMGGetType_C", (PC, PCGAMGType *), (pc, type));
16583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1659c60c7ad4SBarry Smith }
1660c60c7ad4SBarry Smith 
1661d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGGetType_GAMG(PC pc, PCGAMGType *type)
1662d71ae5a4SJacob Faibussowitsch {
1663c60c7ad4SBarry Smith   PC_MG   *mg      = (PC_MG *)pc->data;
1664c60c7ad4SBarry Smith   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
1665c60c7ad4SBarry Smith 
1666c60c7ad4SBarry Smith   PetscFunctionBegin;
1667c60c7ad4SBarry Smith   *type = pc_gamg->type;
16683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1669c60c7ad4SBarry Smith }
1670c60c7ad4SBarry Smith 
1671d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCGAMGSetType_GAMG(PC pc, PCGAMGType type)
1672d71ae5a4SJacob Faibussowitsch {
16731ab5ffc9SJed Brown   PC_MG   *mg      = (PC_MG *)pc->data;
16741ab5ffc9SJed Brown   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
16755f80ce2aSJacob Faibussowitsch   PetscErrorCode (*r)(PC);
1676676e1743SMark F. Adams 
1677676e1743SMark F. Adams   PetscFunctionBegin;
1678c60c7ad4SBarry Smith   pc_gamg->type = type;
16799566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListFind(GAMGList, type, &r));
16806adde796SStefano Zampini   PetscCheck(r, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown GAMG type %s given", type);
16811ab5ffc9SJed Brown   if (pc_gamg->ops->destroy) {
16829566063dSJacob Faibussowitsch     PetscCall((*pc_gamg->ops->destroy)(pc));
16839566063dSJacob Faibussowitsch     PetscCall(PetscMemzero(pc_gamg->ops, sizeof(struct _PCGAMGOps)));
1684e616c208SToby Isaac     pc_gamg->ops->createlevel = PCGAMGCreateLevel_GAMG;
1685da81f932SPierre Jolivet     /* cleaning up common data in pc_gamg - this should disappear someday */
16863ae0bb68SMark Adams     pc_gamg->data_cell_cols      = 0;
16873ae0bb68SMark Adams     pc_gamg->data_cell_rows      = 0;
16883ae0bb68SMark Adams     pc_gamg->orig_data_cell_cols = 0;
16893ae0bb68SMark Adams     pc_gamg->orig_data_cell_rows = 0;
16909566063dSJacob Faibussowitsch     PetscCall(PetscFree(pc_gamg->data));
16913ae0bb68SMark Adams     pc_gamg->data_sz = 0;
16921ab5ffc9SJed Brown   }
16939566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc_gamg->gamg_type_name));
16949566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(type, &pc_gamg->gamg_type_name));
16959566063dSJacob Faibussowitsch   PetscCall((*r)(pc));
16963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1697676e1743SMark F. Adams }
1698676e1743SMark F. Adams 
1699d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCView_GAMG(PC pc, PetscViewer viewer)
1700d71ae5a4SJacob Faibussowitsch {
17015adeb434SBarry Smith   PC_MG         *mg       = (PC_MG *)pc->data;
1702*6c34c54dSStefano Zampini   PC_MG_Levels **mglevels = mg->levels;
17035adeb434SBarry Smith   PC_GAMG       *pc_gamg  = (PC_GAMG *)mg->innerctx;
1704*6c34c54dSStefano Zampini   PetscReal      gc, oc;
170590db8557SMark Adams 
17065adeb434SBarry Smith   PetscFunctionBegin;
17079566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "    GAMG specific options\n"));
17089566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "      Threshold for dropping small values in graph on each level ="));
17099566063dSJacob Faibussowitsch   for (PetscInt i = 0; i < mg->nlevels; i++) PetscCall(PetscViewerASCIIPrintf(viewer, " %g", (double)pc_gamg->threshold[i]));
17109566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
17119566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "      Threshold scaling factor for each level not specified = %g\n", (double)pc_gamg->threshold_scale));
1712e0b7e82fSBarry Smith   if (pc_gamg->use_aggs_in_asm) PetscCall(PetscViewerASCIIPrintf(viewer, "      Using aggregates from GAMG coarsening process to define subdomains for PCASM\n")); // this take presedence
1713e0b7e82fSBarry Smith   else if (pc_gamg->asm_hem_aggs) {
1714e0b7e82fSBarry Smith     PetscCall(PetscViewerASCIIPrintf(viewer, "      Using aggregates made with %d applications of heavy edge matching (HEM) to define subdomains for PCASM\n", (int)pc_gamg->asm_hem_aggs));
1715e0b7e82fSBarry Smith     PetscCall(PetscViewerASCIIPushTab(viewer));
1716e0b7e82fSBarry Smith     PetscCall(PetscViewerASCIIPushTab(viewer));
1717e0b7e82fSBarry Smith     PetscCall(PetscViewerASCIIPushTab(viewer));
1718e0b7e82fSBarry Smith     PetscCall(PetscViewerASCIIPushTab(viewer));
1719e0b7e82fSBarry Smith     PetscCall(MatCoarsenView(pc_gamg->asm_crs, viewer));
1720e0b7e82fSBarry Smith     PetscCall(PetscViewerASCIIPopTab(viewer));
1721e0b7e82fSBarry Smith     PetscCall(PetscViewerASCIIPopTab(viewer));
1722e0b7e82fSBarry Smith     PetscCall(PetscViewerASCIIPopTab(viewer));
1723e0b7e82fSBarry Smith   }
172448a46eb9SPierre Jolivet   if (pc_gamg->use_parallel_coarse_grid_solver) PetscCall(PetscViewerASCIIPrintf(viewer, "      Using parallel coarse grid solver (all coarse grid equations not put on one process)\n"));
1725b65aec2dSMark Adams   if (pc_gamg->injection_index_size) {
1726b65aec2dSMark Adams     PetscCall(PetscViewerASCIIPrintf(viewer, "      Using injection restriction/prolongation on first level, dofs:"));
1727b65aec2dSMark Adams     for (int i = 0; i < pc_gamg->injection_index_size; i++) PetscCall(PetscViewerASCIIPrintf(viewer, " %d", (int)pc_gamg->injection_index[i]));
1728b65aec2dSMark Adams     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
1729b65aec2dSMark Adams   }
17301baa6e33SBarry Smith   if (pc_gamg->ops->view) PetscCall((*pc_gamg->ops->view)(pc, viewer));
1731*6c34c54dSStefano Zampini   gc = oc = 0;
17329566063dSJacob Faibussowitsch   PetscCall(PCMGGetGridComplexity(pc, &gc, &oc));
173363a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "      Complexity:    grid = %g    operator = %g\n", (double)gc, (double)oc));
1734*6c34c54dSStefano Zampini   PetscCall(PetscViewerASCIIPrintf(viewer, "      Per-level complexity: op = operator, int = interpolation\n"));
1735*6c34c54dSStefano Zampini   PetscCall(PetscViewerASCIIPrintf(viewer, "          #equations  | #active PEs | avg nnz/row op | avg nnz/row int\n"));
1736*6c34c54dSStefano Zampini   for (PetscInt i = 0; i < mg->nlevels; i++) {
1737*6c34c54dSStefano Zampini     MatInfo   info;
1738*6c34c54dSStefano Zampini     Mat       A;
1739*6c34c54dSStefano Zampini     PetscReal rd[3];
1740*6c34c54dSStefano Zampini     PetscInt  rst, ren, N;
1741*6c34c54dSStefano Zampini 
1742*6c34c54dSStefano Zampini     PetscCall(KSPGetOperators(mglevels[i]->smoothd, NULL, &A));
1743*6c34c54dSStefano Zampini     PetscCall(MatGetOwnershipRange(A, &rst, &ren));
1744*6c34c54dSStefano Zampini     PetscCall(MatGetSize(A, &N, NULL));
1745*6c34c54dSStefano Zampini     PetscCall(MatGetInfo(A, MAT_LOCAL, &info));
1746*6c34c54dSStefano Zampini     rd[0] = (ren - rst > 0) ? 1 : 0;
1747*6c34c54dSStefano Zampini     rd[1] = info.nz_used;
1748*6c34c54dSStefano Zampini     rd[2] = 0;
1749*6c34c54dSStefano Zampini     if (i) {
1750*6c34c54dSStefano Zampini       Mat P;
1751*6c34c54dSStefano Zampini       PetscCall(PCMGGetInterpolation(pc, i, &P));
1752*6c34c54dSStefano Zampini       PetscCall(MatGetInfo(P, MAT_LOCAL, &info));
1753*6c34c54dSStefano Zampini       rd[2] = info.nz_used;
1754*6c34c54dSStefano Zampini     }
1755*6c34c54dSStefano Zampini     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, rd, 3, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)pc)));
1756*6c34c54dSStefano Zampini     PetscCall(PetscViewerASCIIPrintf(viewer, "     %12" PetscInt_FMT " %12" PetscInt_FMT "   %12" PetscInt_FMT "     %12" PetscInt_FMT "\n", N, (PetscInt)rd[0], (PetscInt)PetscCeilReal(rd[1] / N), (PetscInt)PetscCeilReal(rd[2] / N)));
1757*6c34c54dSStefano Zampini   }
17583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17595adeb434SBarry Smith }
17605adeb434SBarry Smith 
1761b65aec2dSMark Adams /*@
1762b65aec2dSMark Adams   PCGAMGSetInjectionIndex - Array of subset of variables per vertex to inject into coarse grid space
1763b65aec2dSMark Adams 
1764b65aec2dSMark Adams   Logically Collective
1765b65aec2dSMark Adams 
1766b65aec2dSMark Adams   Input Parameters:
1767b65aec2dSMark Adams + pc  - the coarsen context
1768b65aec2dSMark Adams . n   - number of indices
1769b65aec2dSMark Adams - idx - array of indices
1770b65aec2dSMark Adams 
1771b65aec2dSMark Adams   Options Database Key:
1772b65aec2dSMark Adams . -pc_gamg_injection_index - array of subset of variables per vertex to use for injection coarse grid space
1773b65aec2dSMark Adams 
1774b65aec2dSMark Adams   Level: intermediate
1775b65aec2dSMark Adams 
1776a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), `PCGAMG`
1777b65aec2dSMark Adams @*/
1778b65aec2dSMark Adams PetscErrorCode PCGAMGSetInjectionIndex(PC pc, PetscInt n, PetscInt idx[])
1779b65aec2dSMark Adams {
1780b65aec2dSMark Adams   PetscFunctionBegin;
1781b65aec2dSMark Adams   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1782b65aec2dSMark Adams   PetscValidLogicalCollectiveInt(pc, n, 2);
1783b65aec2dSMark Adams   PetscTryMethod(pc, "PCGAMGSetInjectionIndex_C", (PC, PetscInt, PetscInt[]), (pc, n, idx));
1784b65aec2dSMark Adams   PetscFunctionReturn(PETSC_SUCCESS);
1785b65aec2dSMark Adams }
1786b65aec2dSMark Adams 
1787b65aec2dSMark Adams static PetscErrorCode PCGAMGSetInjectionIndex_GAMG(PC pc, PetscInt n, PetscInt idx[])
1788b65aec2dSMark Adams {
1789b65aec2dSMark Adams   PC_MG   *mg      = (PC_MG *)pc->data;
1790b65aec2dSMark Adams   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
17914d86920dSPierre Jolivet 
1792b65aec2dSMark Adams   PetscFunctionBegin;
1793b65aec2dSMark Adams   pc_gamg->injection_index_size = n;
1794b65aec2dSMark Adams   PetscCheck(n < MAT_COARSEN_STRENGTH_INDEX_SIZE, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "array size %d larger than max %d", (int)n, MAT_COARSEN_STRENGTH_INDEX_SIZE);
17954d86920dSPierre Jolivet   for (PetscInt i = 0; i < n; i++) pc_gamg->injection_index[i] = idx[i];
1796b65aec2dSMark Adams   PetscFunctionReturn(PETSC_SUCCESS);
1797b65aec2dSMark Adams }
1798b65aec2dSMark Adams 
179966976f2fSJacob Faibussowitsch static PetscErrorCode PCSetFromOptions_GAMG(PC pc, PetscOptionItems *PetscOptionsObject)
1800d71ae5a4SJacob Faibussowitsch {
1801676e1743SMark F. Adams   PC_MG             *mg      = (PC_MG *)pc->data;
1802676e1743SMark F. Adams   PC_GAMG           *pc_gamg = (PC_GAMG *)mg->innerctx;
18037e6512fdSJed Brown   PetscBool          flag;
18043b4367a7SBarry Smith   MPI_Comm           comm;
180518c3aa7eSMark   char               prefix[256], tname[32];
1806c1eae691SMark Adams   PetscInt           i, n;
180714a9496bSBarry Smith   const char        *pcpre;
18080a545947SLisandro Dalcin   static const char *LayoutTypes[] = {"compact", "spread", "PCGAMGLayoutType", "PC_GAMG_LAYOUT", NULL};
18098926f930SMark Adams 
18105b89ad90SMark F. Adams   PetscFunctionBegin;
18119566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)pc, &comm));
1812d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "GAMG options");
18135fb461b6SMatthew Knepley   PetscCall(PetscOptionsInt("-pc_mg_levels", "Number of Levels", "PCMGSetLevels", -1, &n, &flag));
18145fb461b6SMatthew Knepley   PetscCheck(!flag, comm, PETSC_ERR_ARG_WRONG, "Invalid flag -pc_mg_levels. GAMG does not allow the number of levels to be set.");
18155e4ac8c8Smarkadams4   PetscCall(PetscOptionsFList("-pc_gamg_type", "Type of AMG method (only 'agg' supported and useful)", "PCGAMGSetType", GAMGList, pc_gamg->gamg_type_name, tname, sizeof(tname), &flag));
18161baa6e33SBarry Smith   if (flag) PetscCall(PCGAMGSetType(pc, tname));
18179566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_gamg_repartition", "Repartion coarse grids", "PCGAMGSetRepartition", pc_gamg->repart, &pc_gamg->repart, NULL));
1818f1580f4eSBarry Smith   PetscCall(PetscOptionsBool("-pc_gamg_use_sa_esteig", "Use eigen estimate from smoothed aggregation for smoother", "PCGAMGSetUseSAEstEig", pc_gamg->use_sa_esteig, &pc_gamg->use_sa_esteig, NULL));
1819e1cf1444SMark Adams   PetscCall(PetscOptionsBool("-pc_gamg_recompute_esteig", "Set flag to recompute eigen estimates for Chebyshev when matrix changes", "PCGAMGSetRecomputeEstEig", pc_gamg->recompute_esteig, &pc_gamg->recompute_esteig, NULL));
18209566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_gamg_reuse_interpolation", "Reuse prolongation operator", "PCGAMGReuseInterpolation", pc_gamg->reuse_prol, &pc_gamg->reuse_prol, NULL));
18219566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_gamg_asm_use_agg", "Use aggregation aggregates for ASM smoother", "PCGAMGASMSetUseAggs", pc_gamg->use_aggs_in_asm, &pc_gamg->use_aggs_in_asm, NULL));
1822d529f056Smarkadams4   PetscCall(PetscOptionsBool("-pc_gamg_parallel_coarse_grid_solver", "Use parallel coarse grid solver (otherwise put last grid on one process)", "PCGAMGSetParallelCoarseGridSolve", pc_gamg->use_parallel_coarse_grid_solver, &pc_gamg->use_parallel_coarse_grid_solver, NULL));
18239566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_gamg_cpu_pin_coarse_grids", "Pin coarse grids to the CPU", "PCGAMGSetCpuPinCoarseGrids", pc_gamg->cpu_pin_coarse_grids, &pc_gamg->cpu_pin_coarse_grids, NULL));
18249371c9d4SSatish Balay   PetscCall(PetscOptionsEnum("-pc_gamg_coarse_grid_layout_type", "compact: place reduced grids on processes in natural order; spread: distribute to whole machine for more memory bandwidth", "PCGAMGSetCoarseGridLayoutType", LayoutTypes,
18259371c9d4SSatish Balay                              (PetscEnum)pc_gamg->layout_type, (PetscEnum *)&pc_gamg->layout_type, NULL));
18269566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_gamg_process_eq_limit", "Limit (goal) on number of equations per process on coarse grids", "PCGAMGSetProcEqLim", pc_gamg->min_eq_proc, &pc_gamg->min_eq_proc, NULL));
18279566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_gamg_coarse_eq_limit", "Limit on number of equations for the coarse grid", "PCGAMGSetCoarseEqLim", pc_gamg->coarse_eq_limit, &pc_gamg->coarse_eq_limit, NULL));
18288926f930SMark Adams   PetscCall(PetscOptionsInt("-pc_gamg_asm_hem_aggs", "Number of HEM matching passed in aggregates for ASM smoother", "PCGAMGASMSetHEM", pc_gamg->asm_hem_aggs, &pc_gamg->asm_hem_aggs, NULL));
18299566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-pc_gamg_threshold_scale", "Scaling of threshold for each level not specified", "PCGAMGSetThresholdScale", pc_gamg->threshold_scale, &pc_gamg->threshold_scale, NULL));
183018c3aa7eSMark   n = PETSC_MG_MAXLEVELS;
18319566063dSJacob Faibussowitsch   PetscCall(PetscOptionsRealArray("-pc_gamg_threshold", "Relative threshold to use for dropping edges in aggregation graph", "PCGAMGSetThreshold", pc_gamg->threshold, &n, &flag));
183218c3aa7eSMark   if (!flag || n < PETSC_MG_MAXLEVELS) {
1833efd3c5ceSMark Adams     if (!flag) n = 1;
1834c1eae691SMark Adams     i = n;
1835d71ae5a4SJacob Faibussowitsch     do {
1836d71ae5a4SJacob Faibussowitsch       pc_gamg->threshold[i] = pc_gamg->threshold[i - 1] * pc_gamg->threshold_scale;
1837d71ae5a4SJacob Faibussowitsch     } while (++i < PETSC_MG_MAXLEVELS);
1838c1eae691SMark Adams   }
18399c15c1aeSMark Adams   PetscCall(PetscOptionsInt("-pc_mg_levels", "Set number of MG levels (should get from base class)", "PCGAMGSetNlevels", pc_gamg->Nlevels, &pc_gamg->Nlevels, NULL));
18409c15c1aeSMark Adams   PetscCheck(pc_gamg->Nlevels <= PETSC_MG_MAXLEVELS, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "-pc_mg_levels (%d) >= PETSC_MG_MAXLEVELS (%d)", (int)pc_gamg->Nlevels, (int)PETSC_MG_MAXLEVELS);
1841c9567895SMark   n = PETSC_MG_MAXLEVELS;
18429566063dSJacob Faibussowitsch   PetscCall(PetscOptionsIntArray("-pc_gamg_rank_reduction_factors", "Manual schedule of coarse grid reduction factors that overrides internal heuristics (0 for first reduction puts one process/device)", "PCGAMGSetRankReductionFactors", pc_gamg->level_reduction_factors, &n, &flag));
1843c9567895SMark   if (!flag) i = 0;
1844c9567895SMark   else i = n;
1845d71ae5a4SJacob Faibussowitsch   do {
1846d71ae5a4SJacob Faibussowitsch     pc_gamg->level_reduction_factors[i] = -1;
1847d71ae5a4SJacob Faibussowitsch   } while (++i < PETSC_MG_MAXLEVELS);
184818c3aa7eSMark   {
184918c3aa7eSMark     PetscReal eminmax[2] = {0., 0.};
185018c3aa7eSMark     n                    = 2;
18519566063dSJacob Faibussowitsch     PetscCall(PetscOptionsRealArray("-pc_gamg_eigenvalues", "extreme eigenvalues for smoothed aggregation", "PCGAMGSetEigenvalues", eminmax, &n, &flag));
185218c3aa7eSMark     if (flag) {
185308401ef6SPierre Jolivet       PetscCheck(n == 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "-pc_gamg_eigenvalues: must specify 2 parameters, min and max eigenvalues");
18549566063dSJacob Faibussowitsch       PetscCall(PCGAMGSetEigenvalues(pc, eminmax[1], eminmax[0]));
185518c3aa7eSMark     }
185618c3aa7eSMark   }
1857b65aec2dSMark Adams   pc_gamg->injection_index_size = MAT_COARSEN_STRENGTH_INDEX_SIZE;
1858b65aec2dSMark Adams   PetscCall(PetscOptionsIntArray("-pc_gamg_injection_index", "Array of indices to use to use injection coarse grid space", "PCGAMGSetInjectionIndex", pc_gamg->injection_index, &pc_gamg->injection_index_size, NULL));
1859b7cbab4eSMark Adams   /* set options for subtype */
1860dbbe0bcdSBarry Smith   PetscCall((*pc_gamg->ops->setfromoptions)(pc, PetscOptionsObject));
186118c3aa7eSMark 
18629566063dSJacob Faibussowitsch   PetscCall(PCGetOptionsPrefix(pc, &pcpre));
18639566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%spc_gamg_", pcpre ? pcpre : ""));
1864d0609cedSBarry Smith   PetscOptionsHeadEnd();
18653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18665b89ad90SMark F. Adams }
18675b89ad90SMark F. Adams 
18685b89ad90SMark F. Adams /*MC
18691cc46a46SBarry Smith   PCGAMG - Geometric algebraic multigrid (AMG) preconditioner
18705b89ad90SMark F. Adams 
1871280d9858SJed Brown   Options Database Keys:
18725e4ac8c8Smarkadams4 + -pc_gamg_type <type,default=agg> - one of agg, geo, or classical (only smoothed aggregation, agg, supported)
1873da81f932SPierre Jolivet . -pc_gamg_repartition  <bool,default=false> - repartition the degrees of freedom across the coarse grids as they are determined
187421d928e4Smarkadams4 . -pc_gamg_asm_use_agg <bool,default=false> - use the aggregates from the coasening process to defined the subdomains on each level for the PCASM smoother
1875da81f932SPierre Jolivet . -pc_gamg_process_eq_limit <limit, default=50> - `PCGAMG` will reduce the number of MPI ranks used directly on the coarse grids so that there are around <limit>
1876cab9ed1eSBarry Smith                                         equations on each process that has degrees of freedom
18772d776b49SBarry Smith . -pc_gamg_coarse_eq_limit <limit, default=50> - Set maximum number of equations on coarsest grid to aim for.
187821d928e4Smarkadams4 . -pc_gamg_reuse_interpolation <bool,default=true> - when rebuilding the algebraic multigrid preconditioner reuse the previously computed interpolations (should always be true)
187921d928e4Smarkadams4 . -pc_gamg_threshold[] <thresh,default=[-1,...]> - Before aggregating the graph `PCGAMG` will remove small values from the graph on each level (< 0 does no filtering)
18802d776b49SBarry Smith - -pc_gamg_threshold_scale <scale,default=1> - Scaling of threshold on each coarser grid if not specified
1881cab9ed1eSBarry Smith 
1882f1580f4eSBarry Smith   Options Database Keys for Aggregation:
1883a077d33dSBarry Smith + -pc_gamg_agg_nsmooths <nsmooth, default=1> - number of smoothing steps to use with smooth aggregation to construct prolongation
1884d529f056Smarkadams4 . -pc_gamg_aggressive_coarsening <n,default=1> - number of aggressive coarsening (MIS-2) levels from finest.
1885d529f056Smarkadams4 . -pc_gamg_aggressive_square_graph <bool,default=false> - Use square graph (A'A) or MIS-k (k=2) for aggressive coarsening
1886d529f056Smarkadams4 . -pc_gamg_mis_k_minimum_degree_ordering <bool,default=true> - Use minimum degree ordering in greedy MIS algorithm
18878926f930SMark Adams . -pc_gamg_pc_gamg_asm_hem_aggs <n,default=0> - Number of HEM aggregation steps for ASM smoother
1888d529f056Smarkadams4 - -pc_gamg_aggressive_mis_k <n,default=2> - Number (k) distance in MIS coarsening (>2 is 'aggressive')
1889cab9ed1eSBarry Smith 
1890f1580f4eSBarry Smith   Options Database Keys for Multigrid:
1891a9f5add0SYANG Zongze + -pc_mg_cycle_type <v> - v or w, see `PCMGSetCycleType()`
1892db9745e2SBarry Smith . -pc_mg_distinct_smoothup - configure the up and down (pre and post) smoothers separately, see PCMGSetDistinctSmoothUp()
1893db9745e2SBarry Smith . -pc_mg_type <multiplicative> - (one of) additive multiplicative full kascade
189421d928e4Smarkadams4 - -pc_mg_levels <levels> - Number of levels of multigrid to use. GAMG has a heuristic so pc_mg_levels is not usually used with GAMG
18955b89ad90SMark F. Adams 
189620f4b53cSBarry Smith   Level: intermediate
189720f4b53cSBarry Smith 
189895452b02SPatrick Sanan   Notes:
1899f1580f4eSBarry Smith   To obtain good performance for `PCGAMG` for vector valued problems you must
1900f1580f4eSBarry Smith   call `MatSetBlockSize()` to indicate the number of degrees of freedom per grid point
1901f1580f4eSBarry Smith   call `MatSetNearNullSpace()` (or `PCSetCoordinates()` if solving the equations of elasticity) to indicate the near null space of the operator
1902f1580f4eSBarry Smith 
190304c3f3b8SBarry Smith   The many options for `PCMG` also work directly for `PCGAMG` such as controlling the smoothers on each level etc.
190404c3f3b8SBarry Smith 
1905a077d33dSBarry Smith .seealso: [the Users Manual section on PCGAMG](sec_amg), [the Users Manual section on PCMG](sec_mg), [](ch_ksp), `PCCreate()`, `PCSetType()`,
1906a077d33dSBarry Smith           `MatSetBlockSize()`,
1907a077d33dSBarry Smith           `PCMGType`, `PCSetCoordinates()`, `MatSetNearNullSpace()`, `PCGAMGSetType()`, `PCGAMGAGG`, `PCGAMGGEO`, `PCGAMGCLASSICAL`, `PCGAMGSetProcEqLim()`,
1908a077d33dSBarry Smith           `PCGAMGSetCoarseEqLim()`, `PCGAMGSetRepartition()`, `PCGAMGRegister()`, `PCGAMGSetReuseInterpolation()`, `PCGAMGASMSetUseAggs()`,
1909a077d33dSBarry Smith           `PCGAMGSetParallelCoarseGridSolve()`, `PCGAMGSetNlevels()`, `PCGAMGSetThreshold()`, `PCGAMGGetType()`, `PCGAMGSetUseSAEstEig()`
19105b89ad90SMark F. Adams M*/
1911d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_GAMG(PC pc)
1912d71ae5a4SJacob Faibussowitsch {
19135b89ad90SMark F. Adams   PC_GAMG *pc_gamg;
19145b89ad90SMark F. Adams   PC_MG   *mg;
19155b89ad90SMark F. Adams 
19165b89ad90SMark F. Adams   PetscFunctionBegin;
19171c1aac46SBarry Smith   /* register AMG type */
19189566063dSJacob Faibussowitsch   PetscCall(PCGAMGInitializePackage());
19191c1aac46SBarry Smith 
19205b89ad90SMark F. Adams   /* PCGAMG is an inherited class of PCMG. Initialize pc as PCMG */
19219566063dSJacob Faibussowitsch   PetscCall(PCSetType(pc, PCMG));
19229566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)pc, PCGAMG));
19235b89ad90SMark F. Adams 
19245b89ad90SMark F. Adams   /* create a supporting struct and attach it to pc */
19254dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&pc_gamg));
19269566063dSJacob Faibussowitsch   PetscCall(PCMGSetGalerkin(pc, PC_MG_GALERKIN_EXTERNAL));
19275b89ad90SMark F. Adams   mg           = (PC_MG *)pc->data;
19285b89ad90SMark F. Adams   mg->innerctx = pc_gamg;
19295b89ad90SMark F. Adams 
19304dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&pc_gamg->ops));
19311ab5ffc9SJed Brown 
19329d5b6da9SMark F. Adams   /* these should be in subctx but repartitioning needs simple arrays */
19339d5b6da9SMark F. Adams   pc_gamg->data_sz = 0;
19340a545947SLisandro Dalcin   pc_gamg->data    = NULL;
19355b89ad90SMark F. Adams 
19369d5b6da9SMark F. Adams   /* overwrite the pointers of PCMG by the functions of base class PCGAMG */
19375b89ad90SMark F. Adams   pc->ops->setfromoptions = PCSetFromOptions_GAMG;
19385b89ad90SMark F. Adams   pc->ops->setup          = PCSetUp_GAMG;
19395b89ad90SMark F. Adams   pc->ops->reset          = PCReset_GAMG;
19405b89ad90SMark F. Adams   pc->ops->destroy        = PCDestroy_GAMG;
19415adeb434SBarry Smith   mg->view                = PCView_GAMG;
19425b89ad90SMark F. Adams 
19439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetProcEqLim_C", PCGAMGSetProcEqLim_GAMG));
19449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetCoarseEqLim_C", PCGAMGSetCoarseEqLim_GAMG));
19459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetRepartition_C", PCGAMGSetRepartition_GAMG));
19469566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetEigenvalues_C", PCGAMGSetEigenvalues_GAMG));
19479566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetUseSAEstEig_C", PCGAMGSetUseSAEstEig_GAMG));
1948e1cf1444SMark Adams   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetRecomputeEstEig_C", PCGAMGSetRecomputeEstEig_GAMG));
19499566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetReuseInterpolation_C", PCGAMGSetReuseInterpolation_GAMG));
19509566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGASMSetUseAggs_C", PCGAMGASMSetUseAggs_GAMG));
1951d529f056Smarkadams4   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetParallelCoarseGridSolve_C", PCGAMGSetParallelCoarseGridSolve_GAMG));
19529566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetCpuPinCoarseGrids_C", PCGAMGSetCpuPinCoarseGrids_GAMG));
19539566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetCoarseGridLayoutType_C", PCGAMGSetCoarseGridLayoutType_GAMG));
19549566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetThreshold_C", PCGAMGSetThreshold_GAMG));
19559566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetRankReductionFactors_C", PCGAMGSetRankReductionFactors_GAMG));
19569566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetThresholdScale_C", PCGAMGSetThresholdScale_GAMG));
19579566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetType_C", PCGAMGSetType_GAMG));
19589566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGGetType_C", PCGAMGGetType_GAMG));
19599566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetNlevels_C", PCGAMGSetNlevels_GAMG));
19608926f930SMark Adams   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGASMSetHEM_C", PCGAMGASMSetHEM_GAMG));
1961b65aec2dSMark Adams   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCGAMGSetInjectionIndex_C", PCGAMGSetInjectionIndex_GAMG));
19629d5b6da9SMark F. Adams   pc_gamg->repart                          = PETSC_FALSE;
196321d928e4Smarkadams4   pc_gamg->reuse_prol                      = PETSC_TRUE;
19640c3bc534SBarry Smith   pc_gamg->use_aggs_in_asm                 = PETSC_FALSE;
1965171cca9aSMark Adams   pc_gamg->use_parallel_coarse_grid_solver = PETSC_FALSE;
1966a0095786SMark   pc_gamg->cpu_pin_coarse_grids            = PETSC_FALSE;
1967a0095786SMark   pc_gamg->layout_type                     = PCGAMG_LAYOUT_SPREAD;
1968038f3aa4SMark F. Adams   pc_gamg->min_eq_proc                     = 50;
19698926f930SMark Adams   pc_gamg->asm_hem_aggs                    = 0;
197025a145a7SMark Adams   pc_gamg->coarse_eq_limit                 = 50;
197153134ebeSMark Adams   for (int i = 0; i < PETSC_MG_MAXLEVELS; i++) pc_gamg->threshold[i] = -1;
1972c1eae691SMark Adams   pc_gamg->threshold_scale  = 1.;
197318c3aa7eSMark   pc_gamg->Nlevels          = PETSC_MG_MAXLEVELS;
19749ab59c8bSMark Adams   pc_gamg->current_level    = 0; /* don't need to init really */
19757e6512fdSJed Brown   pc_gamg->use_sa_esteig    = PETSC_TRUE;
1976e1cf1444SMark Adams   pc_gamg->recompute_esteig = PETSC_TRUE;
197718c3aa7eSMark   pc_gamg->emin             = 0;
197818c3aa7eSMark   pc_gamg->emax             = 0;
197918c3aa7eSMark 
1980c238b0ebSToby Isaac   pc_gamg->ops->createlevel = PCGAMGCreateLevel_GAMG;
19819d5b6da9SMark F. Adams 
1982bd94a7aaSJed Brown   /* PCSetUp_GAMG assumes that the type has been set, so set it to the default now */
19839566063dSJacob Faibussowitsch   PetscCall(PCGAMGSetType(pc, PCGAMGAGG));
19843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19855b89ad90SMark F. Adams }
19863e3471ccSMark Adams 
19873e3471ccSMark Adams /*@C
1988f1580f4eSBarry Smith   PCGAMGInitializePackage - This function initializes everything in the `PCGAMG` package. It is called
1989f1580f4eSBarry Smith   from `PCInitializePackage()`.
19903e3471ccSMark Adams 
19913e3471ccSMark Adams   Level: developer
19923e3471ccSMark Adams 
1993562efe2eSBarry Smith .seealso: [](ch_ksp), `PetscInitialize()`
19943e3471ccSMark Adams @*/
1995d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGInitializePackage(void)
1996d71ae5a4SJacob Faibussowitsch {
19974555aa8cSStefano Zampini   PetscInt l;
19983e3471ccSMark Adams 
19993e3471ccSMark Adams   PetscFunctionBegin;
20003ba16761SJacob Faibussowitsch   if (PCGAMGPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS);
20013e3471ccSMark Adams   PCGAMGPackageInitialized = PETSC_TRUE;
20029566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&GAMGList, PCGAMGGEO, PCCreateGAMG_GEO));
20039566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&GAMGList, PCGAMGAGG, PCCreateGAMG_AGG));
20049566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&GAMGList, PCGAMGCLASSICAL, PCCreateGAMG_Classical));
20059566063dSJacob Faibussowitsch   PetscCall(PetscRegisterFinalize(PCGAMGFinalizePackage));
2006c1c463dbSMark Adams 
2007c1c463dbSMark Adams   /* general events */
2008849bee69SMark Adams   PetscCall(PetscLogEventRegister("PCSetUp_GAMG+", PC_CLASSID, &petsc_gamg_setup_events[GAMG_SETUP]));
2009849bee69SMark Adams   PetscCall(PetscLogEventRegister(" PCGAMGCreateG", PC_CLASSID, &petsc_gamg_setup_events[GAMG_GRAPH]));
2010849bee69SMark Adams   PetscCall(PetscLogEventRegister(" GAMG Coarsen", PC_CLASSID, &petsc_gamg_setup_events[GAMG_COARSEN]));
2011849bee69SMark Adams   PetscCall(PetscLogEventRegister("  GAMG MIS/Agg", PC_CLASSID, &petsc_gamg_setup_events[GAMG_MIS]));
2012849bee69SMark Adams   PetscCall(PetscLogEventRegister(" PCGAMGProl", PC_CLASSID, &petsc_gamg_setup_events[GAMG_PROL]));
2013849bee69SMark Adams   PetscCall(PetscLogEventRegister("  GAMG Prol-col", PC_CLASSID, &petsc_gamg_setup_events[GAMG_PROLA]));
2014849bee69SMark Adams   PetscCall(PetscLogEventRegister("  GAMG Prol-lift", PC_CLASSID, &petsc_gamg_setup_events[GAMG_PROLB]));
2015849bee69SMark Adams   PetscCall(PetscLogEventRegister(" PCGAMGOptProl", PC_CLASSID, &petsc_gamg_setup_events[GAMG_OPT]));
2016849bee69SMark Adams   PetscCall(PetscLogEventRegister("  GAMG smooth", PC_CLASSID, &petsc_gamg_setup_events[GAMG_OPTSM]));
2017849bee69SMark Adams   PetscCall(PetscLogEventRegister(" PCGAMGCreateL", PC_CLASSID, &petsc_gamg_setup_events[GAMG_LEVEL]));
2018849bee69SMark Adams   PetscCall(PetscLogEventRegister("  GAMG PtAP", PC_CLASSID, &petsc_gamg_setup_events[GAMG_PTAP]));
2019849bee69SMark Adams   PetscCall(PetscLogEventRegister("  GAMG Reduce", PC_CLASSID, &petsc_gamg_setup_events[GAMG_REDUCE]));
2020849bee69SMark Adams   PetscCall(PetscLogEventRegister("   GAMG Repart", PC_CLASSID, &petsc_gamg_setup_events[GAMG_REPART]));
2021849bee69SMark Adams   /* PetscCall(PetscLogEventRegister("   GAMG Inv-Srt", PC_CLASSID, &petsc_gamg_setup_events[SET13])); */
2022849bee69SMark Adams   /* PetscCall(PetscLogEventRegister("   GAMG Move A", PC_CLASSID, &petsc_gamg_setup_events[SET14])); */
2023849bee69SMark Adams   /* PetscCall(PetscLogEventRegister("   GAMG Move P", PC_CLASSID, &petsc_gamg_setup_events[SET15])); */
20244555aa8cSStefano Zampini   for (l = 0; l < PETSC_MG_MAXLEVELS; l++) {
20254555aa8cSStefano Zampini     char ename[32];
20265b89ad90SMark F. Adams 
202763a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(ename, sizeof(ename), "PCGAMG Squ l%02" PetscInt_FMT, l));
20289566063dSJacob Faibussowitsch     PetscCall(PetscLogEventRegister(ename, PC_CLASSID, &petsc_gamg_setup_matmat_events[l][0]));
202963a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(ename, sizeof(ename), "PCGAMG Gal l%02" PetscInt_FMT, l));
20309566063dSJacob Faibussowitsch     PetscCall(PetscLogEventRegister(ename, PC_CLASSID, &petsc_gamg_setup_matmat_events[l][1]));
203163a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(ename, sizeof(ename), "PCGAMG Opt l%02" PetscInt_FMT, l));
20329566063dSJacob Faibussowitsch     PetscCall(PetscLogEventRegister(ename, PC_CLASSID, &petsc_gamg_setup_matmat_events[l][2]));
20334555aa8cSStefano Zampini   }
20344555aa8cSStefano Zampini #if defined(GAMG_STAGES)
2035849bee69SMark Adams   { /* create timer stages */
20365b89ad90SMark F. Adams     char str[32];
2037a364092eSJacob Faibussowitsch     PetscCall(PetscSNPrintf(str, PETSC_STATIC_ARRAY_LENGTH(str), "GAMG Level %d", 0));
20389566063dSJacob Faibussowitsch     PetscCall(PetscLogStageRegister(str, &gamg_stages[0]));
20395b89ad90SMark F. Adams   }
20405b89ad90SMark F. Adams #endif
20413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20423e3471ccSMark Adams }
20433e3471ccSMark Adams 
20443e3471ccSMark Adams /*@C
2045f1580f4eSBarry Smith   PCGAMGFinalizePackage - This function frees everything from the `PCGAMG` package. It is
2046f1580f4eSBarry Smith   called from `PetscFinalize()` automatically.
20473e3471ccSMark Adams 
20483e3471ccSMark Adams   Level: developer
20493e3471ccSMark Adams 
2050562efe2eSBarry Smith .seealso: [](ch_ksp), `PetscFinalize()`
20513e3471ccSMark Adams @*/
2052d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGFinalizePackage(void)
2053d71ae5a4SJacob Faibussowitsch {
20543e3471ccSMark Adams   PetscFunctionBegin;
20553e3471ccSMark Adams   PCGAMGPackageInitialized = PETSC_FALSE;
20569566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDestroy(&GAMGList));
20573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20583e3471ccSMark Adams }
2059a36cf38bSToby Isaac 
2060a36cf38bSToby Isaac /*@C
2061f1580f4eSBarry Smith   PCGAMGRegister - Register a `PCGAMG` implementation.
2062a36cf38bSToby Isaac 
2063a36cf38bSToby Isaac   Input Parameters:
2064f1580f4eSBarry Smith + type   - string that will be used as the name of the `PCGAMG` type.
2065a36cf38bSToby Isaac - create - function for creating the gamg context.
2066a36cf38bSToby Isaac 
2067f1580f4eSBarry Smith   Level: developer
2068a36cf38bSToby Isaac 
2069562efe2eSBarry Smith .seealso: [](ch_ksp), `PCGAMGType`, `PCGAMG`, `PCGAMGSetType()`
2070a36cf38bSToby Isaac @*/
2071d71ae5a4SJacob Faibussowitsch PetscErrorCode PCGAMGRegister(PCGAMGType type, PetscErrorCode (*create)(PC))
2072d71ae5a4SJacob Faibussowitsch {
2073a36cf38bSToby Isaac   PetscFunctionBegin;
20749566063dSJacob Faibussowitsch   PetscCall(PCGAMGInitializePackage());
20759566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListAdd(&GAMGList, type, create));
20763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2077a36cf38bSToby Isaac }
20782d776b49SBarry Smith 
2079cc4c1da9SBarry Smith /*@
20802d776b49SBarry Smith   PCGAMGCreateGraph - Creates a graph that is used by the ``PCGAMGType`` in the coarsening process
20812d776b49SBarry Smith 
20822d776b49SBarry Smith   Input Parameters:
20832d776b49SBarry Smith + pc - the `PCGAMG`
20842d776b49SBarry Smith - A  - the matrix, for any level
20852d776b49SBarry Smith 
20862d776b49SBarry Smith   Output Parameter:
20872d776b49SBarry Smith . G - the graph
20882d776b49SBarry Smith 
20892d776b49SBarry Smith   Level: advanced
20902d776b49SBarry Smith 
2091562efe2eSBarry Smith .seealso: [](ch_ksp), `PCGAMGType`, `PCGAMG`, `PCGAMGSetType()`
20922d776b49SBarry Smith @*/
20932d776b49SBarry Smith PetscErrorCode PCGAMGCreateGraph(PC pc, Mat A, Mat *G)
20942d776b49SBarry Smith {
20952d776b49SBarry Smith   PC_MG   *mg      = (PC_MG *)pc->data;
20962d776b49SBarry Smith   PC_GAMG *pc_gamg = (PC_GAMG *)mg->innerctx;
20972d776b49SBarry Smith 
20982d776b49SBarry Smith   PetscFunctionBegin;
20992d776b49SBarry Smith   PetscCall(pc_gamg->ops->creategraph(pc, A, G));
21003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21012d776b49SBarry Smith }
2102