Actual source code: gamg.c

petsc-master 2019-11-13
Report Typos and Errors
  1: /*
  2:  GAMG geometric-algebric multigrid PC - Mark Adams 2011
  3:  */
  4:  #include <petsc/private/matimpl.h>
  5:  #include <../src/ksp/pc/impls/gamg/gamg.h>
  6: #include <../src/ksp/pc/impls/bjacobi/bjacobi.h> /* Hack to access same_local_solves */
  7:  #include <../src/ksp/ksp/impls/cheby/chebyshevimpl.h>

  9: #if defined PETSC_GAMG_USE_LOG
 10: PetscLogEvent petsc_gamg_setup_events[NUM_SET];
 11: #endif

 13: #if defined PETSC_USE_LOG
 14: PetscLogEvent PC_GAMGGraph_AGG;
 15: PetscLogEvent PC_GAMGGraph_GEO;
 16: PetscLogEvent PC_GAMGCoarsen_AGG;
 17: PetscLogEvent PC_GAMGCoarsen_GEO;
 18: PetscLogEvent PC_GAMGProlongator_AGG;
 19: PetscLogEvent PC_GAMGProlongator_GEO;
 20: PetscLogEvent PC_GAMGOptProlongator_AGG;
 21: #endif

 23: /* #define GAMG_STAGES */
 24: #if (defined PETSC_GAMG_USE_LOG && defined GAMG_STAGES)
 25: static PetscLogStage gamg_stages[PETSC_MG_MAXLEVELS];
 26: #endif

 28: static PetscFunctionList GAMGList = 0;
 29: static PetscBool PCGAMGPackageInitialized;

 31: /* ----------------------------------------------------------------------------- */
 32: PetscErrorCode PCReset_GAMG(PC pc)
 33: {
 34:   PetscErrorCode ierr, level;
 35:   PC_MG          *mg      = (PC_MG*)pc->data;
 36:   PC_GAMG        *pc_gamg = (PC_GAMG*)mg->innerctx;

 39:   PetscFree(pc_gamg->data);
 40:   pc_gamg->data_sz = 0;
 41:   PetscFree(pc_gamg->orig_data);
 42:   for (level = 0; level < PETSC_MG_MAXLEVELS ; level++) {
 43:     mg->min_eigen_DinvA[level] = 0;
 44:     mg->max_eigen_DinvA[level] = 0;
 45:   }
 46:   pc_gamg->emin = 0;
 47:   pc_gamg->emax = 0;
 48:   return(0);
 49: }

 51: /* -------------------------------------------------------------------------- */
 52: /*
 53:    PCGAMGCreateLevel_GAMG: create coarse op with RAP.  repartition and/or reduce number
 54:      of active processors.

 56:    Input Parameter:
 57:    . pc - parameters + side effect: coarse data in 'pc_gamg->data' and
 58:           'pc_gamg->data_sz' are changed via repartitioning/reduction.
 59:    . Amat_fine - matrix on this fine (k) level
 60:    . cr_bs - coarse block size
 61:    In/Output Parameter:
 62:    . a_P_inout - prolongation operator to the next level (k-->k-1)
 63:    . a_nactive_proc - number of active procs
 64:    Output Parameter:
 65:    . a_Amat_crs - coarse matrix that is created (k-1)
 66: */

 68: 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)
 69: {
 70:   PetscErrorCode  ierr;
 71:   PC_MG           *mg         = (PC_MG*)pc->data;
 72:   PC_GAMG         *pc_gamg    = (PC_GAMG*)mg->innerctx;
 73:   Mat             Cmat,Pold=*a_P_inout;
 74:   MPI_Comm        comm;
 75:   PetscMPIInt     rank,size,new_size,nactive=*a_nactive_proc;
 76:   PetscInt        ncrs_eq,ncrs,f_bs;

 79:   PetscObjectGetComm((PetscObject)Amat_fine,&comm);
 80:   MPI_Comm_rank(comm, &rank);
 81:   MPI_Comm_size(comm, &size);
 82:   MatGetBlockSize(Amat_fine, &f_bs);
 83:   MatPtAP(Amat_fine, Pold, MAT_INITIAL_MATRIX, 2.0, &Cmat);

 85:   if (Pcolumnperm) *Pcolumnperm = NULL;

 87:   /* set 'ncrs' (nodes), 'ncrs_eq' (equations)*/
 88:   MatGetLocalSize(Cmat, &ncrs_eq, NULL);
 89:   if (pc_gamg->data_cell_rows>0) {
 90:     ncrs = pc_gamg->data_sz/pc_gamg->data_cell_cols/pc_gamg->data_cell_rows;
 91:   } else {
 92:     PetscInt  bs;
 93:     MatGetBlockSize(Cmat, &bs);
 94:     ncrs = ncrs_eq/bs;
 95:   }
 96:   /* get number of PEs to make active 'new_size', reduce, can be any integer 1-P */
 97:   if (is_last && !pc_gamg->use_parallel_coarse_grid_solver) new_size = 1;
 98:   else {
 99:     PetscInt ncrs_eq_glob;
100:     MatGetSize(Cmat, &ncrs_eq_glob, NULL);
101:     new_size = (PetscMPIInt)((float)ncrs_eq_glob/(float)pc_gamg->min_eq_proc + 0.5); /* hardwire min. number of eq/proc */
102:     if (!new_size) new_size = 1; /* not likely, posible? */
103:     else if (new_size >= nactive) new_size = nactive; /* no change, rare */
104:   }

106:   if (new_size==nactive) {
107:     *a_Amat_crs = Cmat; /* output - no repartitioning or reduction - could bail here */
108:     if (new_size < size) {
109:       /* odd case where multiple coarse grids are on one processor or no coarsening ... */
110:       PetscInfo1(pc,"reduced grid using same number of processors (%d) as last grid (use larger coarse grid)\n",nactive);
111:       if (pc_gamg->cpu_pin_coarse_grids) {
112:         MatPinToCPU(*a_Amat_crs,PETSC_TRUE);
113:         MatPinToCPU(*a_P_inout,PETSC_TRUE);
114:       }
115:     }
116:     /* we know that the grid structure can be reused in MatPtAP */
117:   } else { /* reduce active processors - we know that the grid structure can NOT be reused in MatPtAP */
118:     PetscInt       *counts,*newproc_idx,ii,jj,kk,strideNew,*tidx,ncrs_new,ncrs_eq_new,nloc_old,expand_factor=1,rfactor=1;
119:     IS             is_eq_newproc,is_eq_num,is_eq_num_prim,new_eq_indices;
120:     nloc_old = ncrs_eq/cr_bs;
121:     if (ncrs_eq % cr_bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"ncrs_eq %D not divisible by cr_bs %D",ncrs_eq,cr_bs);
122:     /* get new_size and rfactor */
123:     if (pc_gamg->layout_type==PCGAMG_LAYOUT_SPREAD || !pc_gamg->repart) {
124:       /* find factor */
125:       if (new_size == 1) rfactor = size; /* don't modify */
126:       else {
127:         PetscReal best_fact = 0.;
128:         jj = -1;
129:         for (kk = 1 ; kk <= size ; kk++) {
130:           if (!(size%kk)) { /* a candidate */
131:             PetscReal nactpe = (PetscReal)size/(PetscReal)kk, fact = nactpe/(PetscReal)new_size;
132:             if (fact > 1.0) fact = 1./fact; /* keep fact < 1 */
133:             if (fact > best_fact) {
134:               best_fact = fact; jj = kk;
135:             }
136:           }
137:         }
138:         if (jj != -1) rfactor = jj;
139:         else rfactor = 1; /* a prime */
140:         if (pc_gamg->layout_type == PCGAMG_LAYOUT_COMPACT) expand_factor = 1;
141:         else expand_factor = rfactor;
142:       }
143:       new_size = size/rfactor; /* make new size one that is factor */
144:       if (new_size==nactive) { /* no repartitioning or reduction, bail out because nested here (rare) */
145:         *a_Amat_crs = Cmat;
146:         PetscInfo2(pc,"Finding factorable processor set stopped reduction: new_size=%d, neq(loc)=%D\n",new_size,ncrs_eq);
147:         return(0);
148:       }
149:     }
150: #if defined PETSC_GAMG_USE_LOG
151:     PetscLogEventBegin(petsc_gamg_setup_events[SET12],0,0,0,0);
152: #endif
153:     /* make 'is_eq_newproc' */
154:     PetscMalloc1(size, &counts);
155:     if (pc_gamg->repart) {
156:       /* Repartition Cmat_{k} and move colums of P^{k}_{k-1} and coordinates of primal part accordingly */
157:       Mat      adj;
158:       PetscInfo4(pc,"Repartition: size (active): %d --> %d, %D local equations, using %s process layout\n",*a_nactive_proc, new_size, ncrs_eq, (pc_gamg->layout_type==PCGAMG_LAYOUT_COMPACT) ? "compact" : "spread");
159:       /* get 'adj' */
160:       if (cr_bs == 1) {
161:         MatConvert(Cmat, MATMPIADJ, MAT_INITIAL_MATRIX, &adj);
162:       } else {
163:         /* make a scalar matrix to partition (no Stokes here) */
164:         Mat               tMat;
165:         PetscInt          Istart_crs,Iend_crs,ncols,jj,Ii;
166:         const PetscScalar *vals;
167:         const PetscInt    *idx;
168:         PetscInt          *d_nnz, *o_nnz, M, N;
169:         static PetscInt   llev = 0; /* ugly but just used for debugging */
170:         MatType           mtype;

172:         PetscMalloc2(ncrs, &d_nnz,ncrs, &o_nnz);
173:         MatGetOwnershipRange(Cmat, &Istart_crs, &Iend_crs);
174:         MatGetSize(Cmat, &M, &N);
175:         for (Ii = Istart_crs, jj = 0; Ii < Iend_crs; Ii += cr_bs, jj++) {
176:           MatGetRow(Cmat,Ii,&ncols,0,0);
177:           d_nnz[jj] = ncols/cr_bs;
178:           o_nnz[jj] = ncols/cr_bs;
179:           MatRestoreRow(Cmat,Ii,&ncols,0,0);
180:           if (d_nnz[jj] > ncrs) d_nnz[jj] = ncrs;
181:           if (o_nnz[jj] > (M/cr_bs-ncrs)) o_nnz[jj] = M/cr_bs-ncrs;
182:         }

184:         MatGetType(Amat_fine,&mtype);
185:         MatCreate(comm, &tMat);
186:         MatSetSizes(tMat, ncrs, ncrs,PETSC_DETERMINE, PETSC_DETERMINE);
187:         MatSetType(tMat,mtype);
188:         MatSeqAIJSetPreallocation(tMat,0,d_nnz);
189:         MatMPIAIJSetPreallocation(tMat,0,d_nnz,0,o_nnz);
190:         PetscFree2(d_nnz,o_nnz);

192:         for (ii = Istart_crs; ii < Iend_crs; ii++) {
193:           PetscInt dest_row = ii/cr_bs;
194:           MatGetRow(Cmat,ii,&ncols,&idx,&vals);
195:           for (jj = 0; jj < ncols; jj++) {
196:             PetscInt    dest_col = idx[jj]/cr_bs;
197:             PetscScalar v        = 1.0;
198:             MatSetValues(tMat,1,&dest_row,1,&dest_col,&v,ADD_VALUES);
199:           }
200:           MatRestoreRow(Cmat,ii,&ncols,&idx,&vals);
201:         }
202:         MatAssemblyBegin(tMat,MAT_FINAL_ASSEMBLY);
203:         MatAssemblyEnd(tMat,MAT_FINAL_ASSEMBLY);

205:         if (llev++ == -1) {
206:           PetscViewer viewer; char fname[32];
207:           PetscSNPrintf(fname,sizeof(fname),"part_mat_%D.mat",llev);
208:           PetscViewerBinaryOpen(comm,fname,FILE_MODE_WRITE,&viewer);
209:           MatView(tMat, viewer);
210:           PetscViewerDestroy(&viewer);
211:         }
212:         MatConvert(tMat, MATMPIADJ, MAT_INITIAL_MATRIX, &adj);
213:         MatDestroy(&tMat);
214:       } /* create 'adj' */

216:       { /* partition: get newproc_idx */
217:         char            prefix[256];
218:         const char      *pcpre;
219:         const PetscInt  *is_idx;
220:         MatPartitioning mpart;
221:         IS              proc_is;

223:         MatPartitioningCreate(comm, &mpart);
224:         MatPartitioningSetAdjacency(mpart, adj);
225:         PCGetOptionsPrefix(pc, &pcpre);
226:         PetscSNPrintf(prefix,sizeof(prefix),"%spc_gamg_",pcpre ? pcpre : "");
227:         PetscObjectSetOptionsPrefix((PetscObject)mpart,prefix);
228:         MatPartitioningSetFromOptions(mpart);
229:         MatPartitioningSetNParts(mpart, new_size);
230:         MatPartitioningApply(mpart, &proc_is);
231:         MatPartitioningDestroy(&mpart);

233:         /* collect IS info */
234:         PetscMalloc1(ncrs_eq, &newproc_idx);
235:         ISGetIndices(proc_is, &is_idx);
236:         for (kk = jj = 0 ; kk < nloc_old ; kk++) {
237:           for (ii = 0 ; ii < cr_bs ; ii++, jj++) {
238:             newproc_idx[jj] = is_idx[kk] * expand_factor; /* distribution */
239:           }
240:         }
241:         ISRestoreIndices(proc_is, &is_idx);
242:         ISDestroy(&proc_is);
243:       }
244:       MatDestroy(&adj);

246:       ISCreateGeneral(comm, ncrs_eq, newproc_idx, PETSC_COPY_VALUES, &is_eq_newproc);
247:       PetscFree(newproc_idx);
248:     } else { /* simple aggregation of parts -- 'is_eq_newproc' */
249:       PetscInt targetPE;
250:       if (new_size==nactive) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"new_size==nactive. Should not happen");
251:       PetscInfo1(pc,"Number of equations (loc) %D with simple aggregation\n",ncrs_eq);
252:       targetPE = (rank/rfactor)*expand_factor;
253:       ISCreateStride(comm, ncrs_eq, targetPE, 0, &is_eq_newproc);
254:     } /* end simple 'is_eq_newproc' */

256:     /*
257:       Create an index set from the is_eq_newproc index set to indicate the mapping TO
258:     */
259:     ISPartitioningToNumbering(is_eq_newproc, &is_eq_num);
260:     is_eq_num_prim = is_eq_num;
261:     /*
262:       Determine how many equations/vertices are assigned to each processor
263:     */
264:     ISPartitioningCount(is_eq_newproc, size, counts);
265:     ncrs_eq_new = counts[rank];
266:     ISDestroy(&is_eq_newproc);
267:     ncrs_new = ncrs_eq_new/cr_bs;

269:     PetscFree(counts);
270:     /* data movement scope -- this could be moved to subclasses so that we don't try to cram all auxilary data into some complex abstracted thing */
271:     {
272:       Vec            src_crd, dest_crd;
273:       const PetscInt *idx,ndata_rows=pc_gamg->data_cell_rows,ndata_cols=pc_gamg->data_cell_cols,node_data_sz=ndata_rows*ndata_cols;
274:       VecScatter     vecscat;
275:       PetscScalar    *array;
276:       IS isscat;
277:       /* move data (for primal equations only) */
278:       /* Create a vector to contain the newly ordered element information */
279:       VecCreate(comm, &dest_crd);
280:       VecSetSizes(dest_crd, node_data_sz*ncrs_new, PETSC_DECIDE);
281:       VecSetType(dest_crd,VECSTANDARD); /* this is needed! */
282:       /*
283:         There are 'ndata_rows*ndata_cols' data items per node, (one can think of the vectors of having
284:         a block size of ...).  Note, ISs are expanded into equation space by 'cr_bs'.
285:       */
286:       PetscMalloc1(ncrs*node_data_sz, &tidx);
287:       ISGetIndices(is_eq_num_prim, &idx);
288:       for (ii=0,jj=0; ii<ncrs; ii++) {
289:         PetscInt id = idx[ii*cr_bs]/cr_bs; /* get node back */
290:         for (kk=0; kk<node_data_sz; kk++, jj++) tidx[jj] = id*node_data_sz + kk;
291:       }
292:       ISRestoreIndices(is_eq_num_prim, &idx);
293:       ISCreateGeneral(comm, node_data_sz*ncrs, tidx, PETSC_COPY_VALUES, &isscat);
294:       PetscFree(tidx);
295:       /*
296:         Create a vector to contain the original vertex information for each element
297:       */
298:       VecCreateSeq(PETSC_COMM_SELF, node_data_sz*ncrs, &src_crd);
299:       for (jj=0; jj<ndata_cols; jj++) {
300:         const PetscInt stride0=ncrs*pc_gamg->data_cell_rows;
301:         for (ii=0; ii<ncrs; ii++) {
302:           for (kk=0; kk<ndata_rows; kk++) {
303:             PetscInt    ix = ii*ndata_rows + kk + jj*stride0, jx = ii*node_data_sz + kk*ndata_cols + jj;
304:             PetscScalar tt = (PetscScalar)pc_gamg->data[ix];
305:             VecSetValues(src_crd, 1, &jx, &tt, INSERT_VALUES);
306:           }
307:         }
308:       }
309:       VecAssemblyBegin(src_crd);
310:       VecAssemblyEnd(src_crd);
311:       /*
312:         Scatter the element vertex information (still in the original vertex ordering)
313:         to the correct processor
314:       */
315:       VecScatterCreate(src_crd, NULL, dest_crd, isscat, &vecscat);
316:       ISDestroy(&isscat);
317:       VecScatterBegin(vecscat,src_crd,dest_crd,INSERT_VALUES,SCATTER_FORWARD);
318:       VecScatterEnd(vecscat,src_crd,dest_crd,INSERT_VALUES,SCATTER_FORWARD);
319:       VecScatterDestroy(&vecscat);
320:       VecDestroy(&src_crd);
321:       /*
322:         Put the element vertex data into a new allocation of the gdata->ele
323:       */
324:       PetscFree(pc_gamg->data);
325:       PetscMalloc1(node_data_sz*ncrs_new, &pc_gamg->data);

327:       pc_gamg->data_sz = node_data_sz*ncrs_new;
328:       strideNew        = ncrs_new*ndata_rows;

330:       VecGetArray(dest_crd, &array);
331:       for (jj=0; jj<ndata_cols; jj++) {
332:         for (ii=0; ii<ncrs_new; ii++) {
333:           for (kk=0; kk<ndata_rows; kk++) {
334:             PetscInt ix = ii*ndata_rows + kk + jj*strideNew, jx = ii*node_data_sz + kk*ndata_cols + jj;
335:             pc_gamg->data[ix] = PetscRealPart(array[jx]);
336:           }
337:         }
338:       }
339:       VecRestoreArray(dest_crd, &array);
340:       VecDestroy(&dest_crd);
341:     }
342:     /* move A and P (columns) with new layout */
343: #if defined PETSC_GAMG_USE_LOG
344:     PetscLogEventBegin(petsc_gamg_setup_events[SET13],0,0,0,0);
345: #endif
346:     /*
347:       Invert for MatCreateSubMatrix
348:     */
349:     ISInvertPermutation(is_eq_num, ncrs_eq_new, &new_eq_indices);
350:     ISSort(new_eq_indices); /* is this needed? */
351:     ISSetBlockSize(new_eq_indices, cr_bs);
352:     if (is_eq_num != is_eq_num_prim) {
353:       ISDestroy(&is_eq_num_prim); /* could be same as 'is_eq_num' */
354:     }
355:     if (Pcolumnperm) {
356:       PetscObjectReference((PetscObject)new_eq_indices);
357:       *Pcolumnperm = new_eq_indices;
358:     }
359:     ISDestroy(&is_eq_num);
360: #if defined PETSC_GAMG_USE_LOG
361:     PetscLogEventEnd(petsc_gamg_setup_events[SET13],0,0,0,0);
362:     PetscLogEventBegin(petsc_gamg_setup_events[SET14],0,0,0,0);
363: #endif
364:     /* 'a_Amat_crs' output */
365:     {
366:       Mat mat;
367:       MatCreateSubMatrix(Cmat, new_eq_indices, new_eq_indices, MAT_INITIAL_MATRIX, &mat);
368:       *a_Amat_crs = mat;
369:     }
370:     MatDestroy(&Cmat);

372: #if defined PETSC_GAMG_USE_LOG
373:     PetscLogEventEnd(petsc_gamg_setup_events[SET14],0,0,0,0);
374: #endif
375:     /* prolongator */
376:     {
377:       IS       findices;
378:       PetscInt Istart,Iend;
379:       Mat      Pnew;

381:       MatGetOwnershipRange(Pold, &Istart, &Iend);
382: #if defined PETSC_GAMG_USE_LOG
383:       PetscLogEventBegin(petsc_gamg_setup_events[SET15],0,0,0,0);
384: #endif
385:       ISCreateStride(comm,Iend-Istart,Istart,1,&findices);
386:       ISSetBlockSize(findices,f_bs);
387:       MatCreateSubMatrix(Pold, findices, new_eq_indices, MAT_INITIAL_MATRIX, &Pnew);
388:       ISDestroy(&findices);

390: #if defined PETSC_GAMG_USE_LOG
391:       PetscLogEventEnd(petsc_gamg_setup_events[SET15],0,0,0,0);
392: #endif
393:       MatDestroy(a_P_inout);

395:       /* output - repartitioned */
396:       *a_P_inout = Pnew;
397:     }
398:     ISDestroy(&new_eq_indices);

400:     *a_nactive_proc = new_size; /* output */

402:     /* pinning on reduced grids, not a bad heuristic and optimization gets folded into process reduction optimization */
403:     if (pc_gamg->cpu_pin_coarse_grids) {
404: #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
405:       static PetscInt llev = 2;
406:       PetscInfo1(pc,"Pinning level %D to the CPU\n",llev++);
407: #endif
408:       MatPinToCPU(*a_Amat_crs,PETSC_TRUE);
409:       MatPinToCPU(*a_P_inout,PETSC_TRUE);
410:       if (1) { /* lvec is created, need to pin it, this is done in MatSetUpMultiply_MPIAIJ. Hack */
411:         Mat         A = *a_Amat_crs, P = *a_P_inout;
412:         PetscMPIInt size;
413:         MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);
414:         if (size > 1) {
415:           Mat_MPIAIJ     *a = (Mat_MPIAIJ*)A->data, *p = (Mat_MPIAIJ*)P->data;
416:           VecPinToCPU(a->lvec,PETSC_TRUE);
417:           VecPinToCPU(p->lvec,PETSC_TRUE);
418:         }
419:       }
420:     }
421: #if defined PETSC_GAMG_USE_LOG
422:     PetscLogEventEnd(petsc_gamg_setup_events[SET12],0,0,0,0);
423: #endif
424:   }
425:   return(0);
426: }

428: /* -------------------------------------------------------------------------- */
429: /*
430:    PCSetUp_GAMG - Prepares for the use of the GAMG preconditioner
431:                     by setting data structures and options.

433:    Input Parameter:
434: .  pc - the preconditioner context

436: */
437: PetscErrorCode PCSetUp_GAMG(PC pc)
438: {
440:   PC_MG          *mg      = (PC_MG*)pc->data;
441:   PC_GAMG        *pc_gamg = (PC_GAMG*)mg->innerctx;
442:   Mat            Pmat     = pc->pmat;
443:   PetscInt       fine_level,level,level1,bs,M,N,qq,lidx,nASMBlocksArr[PETSC_MG_MAXLEVELS];
444:   MPI_Comm       comm;
445:   PetscMPIInt    rank,size,nactivepe;
446:   Mat            Aarr[PETSC_MG_MAXLEVELS],Parr[PETSC_MG_MAXLEVELS];
447:   IS             *ASMLocalIDsArr[PETSC_MG_MAXLEVELS];
448:   PetscLogDouble nnz0=0.,nnztot=0.;
449:   MatInfo        info;
450:   PetscBool      is_last = PETSC_FALSE;

453:   PetscObjectGetComm((PetscObject)pc,&comm);
454:   MPI_Comm_rank(comm,&rank);
455:   MPI_Comm_size(comm,&size);

457:   if (pc_gamg->setup_count++ > 0) {
458:     if ((PetscBool)(!pc_gamg->reuse_prol)) {
459:       /* reset everything */
460:       PCReset_MG(pc);
461:       pc->setupcalled = 0;
462:     } else {
463:       PC_MG_Levels **mglevels = mg->levels;
464:       /* just do Galerkin grids */
465:       Mat          B,dA,dB;

467:       if (!pc->setupcalled) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"PCSetUp() has not been called yet");
468:       if (pc_gamg->Nlevels > 1) {
469:         /* currently only handle case where mat and pmat are the same on coarser levels */
470:         KSPGetOperators(mglevels[pc_gamg->Nlevels-1]->smoothd,&dA,&dB);
471:         /* (re)set to get dirty flag */
472:         KSPSetOperators(mglevels[pc_gamg->Nlevels-1]->smoothd,dA,dB);

474:         for (level=pc_gamg->Nlevels-2; level>=0; level--) {
475:           /* 2nd solve, matrix structure can change from repartitioning or process reduction but don't know if we have process reduction here. Should fix */
476:           if (pc_gamg->setup_count==2 /* && pc_gamg->repart||reduction */) {
477:             PetscInfo2(pc,"new RAP after first solve level %D, %D setup\n",level,pc_gamg->setup_count);
478:             MatPtAP(dB,mglevels[level+1]->interpolate,MAT_INITIAL_MATRIX,2.0,&B);
479:             MatDestroy(&mglevels[level]->A);
480:             mglevels[level]->A = B;
481:           } else {
482:             PetscInfo2(pc,"RAP after first solve reusing matrix level %D, %D setup\n",level,pc_gamg->setup_count);
483:             KSPGetOperators(mglevels[level]->smoothd,NULL,&B);
484:             MatPtAP(dB,mglevels[level+1]->interpolate,MAT_REUSE_MATRIX,1.0,&B);
485:           }
486:           KSPSetOperators(mglevels[level]->smoothd,B,B);
487:           dB   = B;
488:         }
489:       }

491:       PCSetUp_MG(pc);
492:       return(0);
493:     }
494:   }

496:   if (!pc_gamg->data) {
497:     if (pc_gamg->orig_data) {
498:       MatGetBlockSize(Pmat, &bs);
499:       MatGetLocalSize(Pmat, &qq, NULL);

501:       pc_gamg->data_sz        = (qq/bs)*pc_gamg->orig_data_cell_rows*pc_gamg->orig_data_cell_cols;
502:       pc_gamg->data_cell_rows = pc_gamg->orig_data_cell_rows;
503:       pc_gamg->data_cell_cols = pc_gamg->orig_data_cell_cols;

505:       PetscMalloc1(pc_gamg->data_sz, &pc_gamg->data);
506:       for (qq=0; qq<pc_gamg->data_sz; qq++) pc_gamg->data[qq] = pc_gamg->orig_data[qq];
507:     } else {
508:       if (!pc_gamg->ops->createdefaultdata) SETERRQ(comm,PETSC_ERR_PLIB,"'createdefaultdata' not set(?) need to support NULL data");
509:       pc_gamg->ops->createdefaultdata(pc,Pmat);
510:     }
511:   }

513:   /* cache original data for reuse */
514:   if (!pc_gamg->orig_data && (PetscBool)(!pc_gamg->reuse_prol)) {
515:     PetscMalloc1(pc_gamg->data_sz, &pc_gamg->orig_data);
516:     for (qq=0; qq<pc_gamg->data_sz; qq++) pc_gamg->orig_data[qq] = pc_gamg->data[qq];
517:     pc_gamg->orig_data_cell_rows = pc_gamg->data_cell_rows;
518:     pc_gamg->orig_data_cell_cols = pc_gamg->data_cell_cols;
519:   }

521:   /* get basic dims */
522:   MatGetBlockSize(Pmat, &bs);
523:   MatGetSize(Pmat, &M, &N);

525:   MatGetInfo(Pmat,MAT_GLOBAL_SUM,&info); /* global reduction */
526:   nnz0   = info.nz_used;
527:   nnztot = info.nz_used;
528:   PetscInfo6(pc,"level %d) N=%D, n data rows=%d, n data cols=%d, nnz/row (ave)=%d, np=%d\n",0,M,pc_gamg->data_cell_rows,pc_gamg->data_cell_cols,(int)(nnz0/(PetscReal)M+0.5),size);

530:   /* Get A_i and R_i */
531:   for (level=0, Aarr[0]=Pmat, nactivepe = size; level < (pc_gamg->Nlevels-1) && (!level || M>pc_gamg->coarse_eq_limit); level++) {
532:     pc_gamg->current_level = level;
533:     if (level >= PETSC_MG_MAXLEVELS) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Too many levels %D",level);
534:     level1 = level + 1;
535: #if defined PETSC_GAMG_USE_LOG
536:     PetscLogEventBegin(petsc_gamg_setup_events[SET1],0,0,0,0);
537: #if (defined GAMG_STAGES)
538:     PetscLogStagePush(gamg_stages[level]);
539: #endif
540: #endif
541:     { /* construct prolongator */
542:       Mat              Gmat;
543:       PetscCoarsenData *agg_lists;
544:       Mat              Prol11;

546:       pc_gamg->ops->graph(pc,Aarr[level], &Gmat);
547:       pc_gamg->ops->coarsen(pc, &Gmat, &agg_lists);
548:       pc_gamg->ops->prolongator(pc,Aarr[level],Gmat,agg_lists,&Prol11);

550:       /* could have failed to create new level */
551:       if (Prol11) {
552:         /* get new block size of coarse matrices */
553:         MatGetBlockSizes(Prol11, NULL, &bs);

555:         if (pc_gamg->ops->optprolongator) {
556:           /* smooth */
557:           pc_gamg->ops->optprolongator(pc, Aarr[level], &Prol11);
558:         }

560:         if (pc_gamg->use_aggs_in_asm) {
561:           PetscInt bs;
562:           MatGetBlockSizes(Prol11, &bs, NULL);
563:           PetscCDGetASMBlocks(agg_lists, bs, Gmat, &nASMBlocksArr[level], &ASMLocalIDsArr[level]);
564:         }

566:         Parr[level1] = Prol11;
567:       } else Parr[level1] = NULL; /* failed to coarsen */

569:       MatDestroy(&Gmat);
570:       PetscCDDestroy(agg_lists);
571:     } /* construct prolongator scope */
572: #if defined PETSC_GAMG_USE_LOG
573:     PetscLogEventEnd(petsc_gamg_setup_events[SET1],0,0,0,0);
574: #endif
575:     if (!level) Aarr[0] = Pmat; /* use Pmat for finest level setup */
576:     if (!Parr[level1]) { /* failed to coarsen */
577:        PetscInfo1(pc,"Stop gridding, level %D\n",level);
578: #if defined PETSC_GAMG_USE_LOG && defined GAMG_STAGES
579:       PetscLogStagePop();
580: #endif
581:       break;
582:     }
583: #if defined PETSC_GAMG_USE_LOG
584:     PetscLogEventBegin(petsc_gamg_setup_events[SET2],0,0,0,0);
585: #endif
586:     MatGetSize(Parr[level1], &M, &N); /* N is next M, a loop test variables */
587:     if (is_last) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Is last ????????");
588:     if (N <= pc_gamg->coarse_eq_limit) is_last = PETSC_TRUE;
589:     if (level1 == pc_gamg->Nlevels-1) is_last = PETSC_TRUE;
590:     pc_gamg->ops->createlevel(pc, Aarr[level], bs, &Parr[level1], &Aarr[level1], &nactivepe, NULL, is_last);

592: #if defined PETSC_GAMG_USE_LOG
593:     PetscLogEventEnd(petsc_gamg_setup_events[SET2],0,0,0,0);
594: #endif
595:     MatGetSize(Aarr[level1], &M, &N); /* M is loop test variables */
596:     MatGetInfo(Aarr[level1], MAT_GLOBAL_SUM, &info);
597:     nnztot += info.nz_used;
598:     PetscInfo5(pc,"%d) N=%D, n data cols=%d, nnz/row (ave)=%d, %d active pes\n",level1,M,pc_gamg->data_cell_cols,(int)(info.nz_used/(PetscReal)M),nactivepe);

600: #if (defined PETSC_GAMG_USE_LOG && defined GAMG_STAGES)
601:     PetscLogStagePop();
602: #endif
603:     /* stop if one node or one proc -- could pull back for singular problems */
604:     if ( (pc_gamg->data_cell_cols && M/pc_gamg->data_cell_cols < 2) || (!pc_gamg->data_cell_cols && M/bs < 2) ) {
605:        PetscInfo2(pc,"HARD stop of coarsening on level %D.  Grid too small: %D block nodes\n",level,M/bs);
606:       level++;
607:       break;
608:     }
609:   } /* levels */
610:   PetscFree(pc_gamg->data);

612:   PetscInfo2(pc,"%D levels, grid complexity = %g\n",level+1,nnztot/nnz0);
613:   pc_gamg->Nlevels = level + 1;
614:   fine_level       = level;
615:   PCMGSetLevels(pc,pc_gamg->Nlevels,NULL);

617:   if (pc_gamg->Nlevels > 1) { /* don't setup MG if one level */
618:     /* set default smoothers & set operators */
619:     for (lidx = 1, level = pc_gamg->Nlevels-2; lidx <= fine_level; lidx++, level--) {
620:       KSP smoother;
621:       PC  subpc;

623:       PCMGGetSmoother(pc, lidx, &smoother);
624:       KSPGetPC(smoother, &subpc);

626:       KSPSetNormType(smoother, KSP_NORM_NONE);
627:       /* set ops */
628:       KSPSetOperators(smoother, Aarr[level], Aarr[level]);
629:       PCMGSetInterpolation(pc, lidx, Parr[level+1]);

631:       /* set defaults */
632:       KSPSetType(smoother, KSPCHEBYSHEV);

634:       /* set blocks for ASM smoother that uses the 'aggregates' */
635:       if (pc_gamg->use_aggs_in_asm) {
636:         PetscInt sz;
637:         IS       *iss;

639:         sz   = nASMBlocksArr[level];
640:         iss  = ASMLocalIDsArr[level];
641:         PCSetType(subpc, PCASM);
642:         PCASMSetOverlap(subpc, 0);
643:         PCASMSetType(subpc,PC_ASM_BASIC);
644:         if (!sz) {
645:           IS       is;
646:           ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_COPY_VALUES, &is);
647:           PCASMSetLocalSubdomains(subpc, 1, NULL, &is);
648:           ISDestroy(&is);
649:         } else {
650:           PetscInt kk;
651:           PCASMSetLocalSubdomains(subpc, sz, NULL, iss);
652:           for (kk=0; kk<sz; kk++) {
653:             ISDestroy(&iss[kk]);
654:           }
655:           PetscFree(iss);
656:         }
657:         ASMLocalIDsArr[level] = NULL;
658:         nASMBlocksArr[level]  = 0;
659:       } else {
660:         PCSetType(subpc, PCSOR);
661:       }
662:     }
663:     {
664:       /* coarse grid */
665:       KSP smoother,*k2; PC subpc,pc2; PetscInt ii,first;
666:       Mat Lmat = Aarr[(level=pc_gamg->Nlevels-1)]; lidx = 0;
667:       PCMGGetSmoother(pc, lidx, &smoother);
668:       KSPSetOperators(smoother, Lmat, Lmat);
669:       if (!pc_gamg->use_parallel_coarse_grid_solver) {
670:         KSPSetNormType(smoother, KSP_NORM_NONE);
671:         KSPGetPC(smoother, &subpc);
672:         PCSetType(subpc, PCBJACOBI);
673:         PCSetUp(subpc);
674:         PCBJacobiGetSubKSP(subpc,&ii,&first,&k2);
675:         if (ii != 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"ii %D is not one",ii);
676:         KSPGetPC(k2[0],&pc2);
677:         PCSetType(pc2, PCLU);
678:         PCFactorSetShiftType(pc2,MAT_SHIFT_INBLOCKS);
679:         KSPSetTolerances(k2[0],PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,1);
680:         KSPSetType(k2[0], KSPPREONLY);
681:         /* This flag gets reset by PCBJacobiGetSubKSP(), but our BJacobi really does the same algorithm everywhere (and in
682:          * fact, all but one process will have zero dofs), so we reset the flag to avoid having PCView_BJacobi attempt to
683:          * view every subdomain as though they were different. */
684:         ((PC_BJacobi*)subpc->data)->same_local_solves = PETSC_TRUE;
685:       }
686:     }

688:     /* should be called in PCSetFromOptions_GAMG(), but cannot be called prior to PCMGSetLevels() */
689:     PetscObjectOptionsBegin((PetscObject)pc);
690:     PCSetFromOptions_MG(PetscOptionsObject,pc);
691:     PetscOptionsEnd();
692:     PCMGSetGalerkin(pc,PC_MG_GALERKIN_EXTERNAL);

694:     PCSetUp_MG(pc);

696:     /* setup cheby eigen estimates from SA */
697:     for (lidx = 1, level = pc_gamg->Nlevels-2; level >= 0 ; lidx++, level--) {
698:       KSP       smoother;
699:       PetscBool ischeb;
700:       PCMGGetSmoother(pc, lidx, &smoother);
701:       PetscObjectTypeCompare((PetscObject)smoother,KSPCHEBYSHEV,&ischeb);
702:       if (ischeb) {
703:         KSP_Chebyshev  *cheb = (KSP_Chebyshev*)smoother->data;
704:         if (mg->max_eigen_DinvA[level] > 0 && cheb->emax == 0.) { /* let command line emax override using SA's eigenvalues */
705:           PC        subpc;
706:           PetscBool isjac;
707:           KSPGetPC(smoother, &subpc);
708:           PetscObjectTypeCompare((PetscObject)subpc,PCJACOBI,&isjac);
709:           if ( (isjac && pc_gamg->use_sa_esteig==-1) || pc_gamg->use_sa_esteig==1) {
710:             PetscReal       emax,emin;
711:             emin = mg->min_eigen_DinvA[level];
712:             emax = mg->max_eigen_DinvA[level];
713:             PetscInfo4(pc,"PCSetUp_GAMG: call KSPChebyshevSetEigenvalues on level %D (N=%D) with emax = %g emin = %g\n",level,Aarr[level]->rmap->N,(double)emax,(double)emin);
714:             cheb->emin_computed = emin;
715:             cheb->emax_computed = emax;
716:             KSPChebyshevSetEigenvalues(smoother, cheb->tform[2]*emin + cheb->tform[3]*emax, cheb->tform[0]*emin + cheb->tform[1]*emax);
717:           }
718:         }
719:       }
720:     }

722:     /* clean up */
723:     for (level=1; level<pc_gamg->Nlevels; level++) {
724:       MatDestroy(&Parr[level]);
725:       MatDestroy(&Aarr[level]);
726:     }

728:   } else {
729:     KSP smoother;
730:     PetscInfo(pc,"One level solver used (system is seen as DD). Using default solver.\n");
731:     PCMGGetSmoother(pc, 0, &smoother);
732:     KSPSetOperators(smoother, Aarr[0], Aarr[0]);
733:     KSPSetType(smoother, KSPPREONLY);
734:     PCSetUp_MG(pc);
735:   }
736:   return(0);
737: }

739: /* ------------------------------------------------------------------------- */
740: /*
741:  PCDestroy_GAMG - Destroys the private context for the GAMG preconditioner
742:    that was created with PCCreate_GAMG().

744:    Input Parameter:
745: .  pc - the preconditioner context

747:    Application Interface Routine: PCDestroy()
748: */
749: PetscErrorCode PCDestroy_GAMG(PC pc)
750: {
752:   PC_MG          *mg     = (PC_MG*)pc->data;
753:   PC_GAMG        *pc_gamg= (PC_GAMG*)mg->innerctx;

756:   PCReset_GAMG(pc);
757:   if (pc_gamg->ops->destroy) {
758:     (*pc_gamg->ops->destroy)(pc);
759:   }
760:   PetscFree(pc_gamg->ops);
761:   PetscFree(pc_gamg->gamg_type_name);
762:   PetscFree(pc_gamg);
763:   PCDestroy_MG(pc);
764:   return(0);
765: }

767: /*@
768:    PCGAMGSetProcEqLim - Set number of equations to aim for per process on the coarse grids via processor reduction.

770:    Logically Collective on PC

772:    Input Parameters:
773: +  pc - the preconditioner context
774: -  n - the number of equations


777:    Options Database Key:
778: .  -pc_gamg_process_eq_limit <limit>

780:    Notes:
781:     GAMG will reduce the number of MPI processes used directly on the coarse grids so that there are around <limit> equations on each process
782:           that has degrees of freedom

784:    Level: intermediate

786: .seealso: PCGAMGSetCoarseEqLim()
787: @*/
788: PetscErrorCode  PCGAMGSetProcEqLim(PC pc, PetscInt n)
789: {

794:   PetscTryMethod(pc,"PCGAMGSetProcEqLim_C",(PC,PetscInt),(pc,n));
795:   return(0);
796: }

798: static PetscErrorCode PCGAMGSetProcEqLim_GAMG(PC pc, PetscInt n)
799: {
800:   PC_MG   *mg      = (PC_MG*)pc->data;
801:   PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;

804:   if (n>0) pc_gamg->min_eq_proc = n;
805:   return(0);
806: }

808: /*@
809:    PCGAMGSetCoarseEqLim - Set maximum number of equations on coarsest grid.

811:  Collective on PC

813:    Input Parameters:
814: +  pc - the preconditioner context
815: -  n - maximum number of equations to aim for

817:    Options Database Key:
818: .  -pc_gamg_coarse_eq_limit <limit>

820:    Notes: For example -pc_gamg_coarse_eq_limit 1000 will stop coarsening once the coarse grid
821:      has less than 1000 unknowns.

823:    Level: intermediate

825: .seealso: PCGAMGSetProcEqLim()
826: @*/
827: PetscErrorCode PCGAMGSetCoarseEqLim(PC pc, PetscInt n)
828: {

833:   PetscTryMethod(pc,"PCGAMGSetCoarseEqLim_C",(PC,PetscInt),(pc,n));
834:   return(0);
835: }

837: static PetscErrorCode PCGAMGSetCoarseEqLim_GAMG(PC pc, PetscInt n)
838: {
839:   PC_MG   *mg      = (PC_MG*)pc->data;
840:   PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;

843:   if (n>0) pc_gamg->coarse_eq_limit = n;
844:   return(0);
845: }

847: /*@
848:    PCGAMGSetRepartition - Repartition the degrees of freedom across the processors on the coarser grids

850:    Collective on PC

852:    Input Parameters:
853: +  pc - the preconditioner context
854: -  n - PETSC_TRUE or PETSC_FALSE

856:    Options Database Key:
857: .  -pc_gamg_repartition <true,false>

859:    Notes:
860:     this will generally improve the loading balancing of the work on each level

862:    Level: intermediate

864: .seealso: ()
865: @*/
866: PetscErrorCode PCGAMGSetRepartition(PC pc, PetscBool n)
867: {

872:   PetscTryMethod(pc,"PCGAMGSetRepartition_C",(PC,PetscBool),(pc,n));
873:   return(0);
874: }

876: static PetscErrorCode PCGAMGSetRepartition_GAMG(PC pc, PetscBool n)
877: {
878:   PC_MG   *mg      = (PC_MG*)pc->data;
879:   PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;

882:   pc_gamg->repart = n;
883:   return(0);
884: }

886: /*@
887:    PCGAMGSetEstEigKSPMaxIt - Set number of KSP iterations in eigen estimator (for Cheby)

889:    Collective on PC

891:    Input Parameters:
892: +  pc - the preconditioner context
893: -  n - number of its

895:    Options Database Key:
896: .  -pc_gamg_esteig_ksp_max_it <its>

898:    Notes:

900:    Level: intermediate

902: .seealso: ()
903: @*/
904: PetscErrorCode PCGAMGSetEstEigKSPMaxIt(PC pc, PetscInt n)
905: {

910:   PetscTryMethod(pc,"PCGAMGSetEstEigKSPMaxIt_C",(PC,PetscInt),(pc,n));
911:   return(0);
912: }

914: static PetscErrorCode PCGAMGSetEstEigKSPMaxIt_GAMG(PC pc, PetscInt n)
915: {
916:   PC_MG   *mg      = (PC_MG*)pc->data;
917:   PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;

920:   pc_gamg->esteig_max_it = n;
921:   return(0);
922: }

924: /*@
925:    PCGAMGSetUseSAEstEig - Use eigen estimate from smoothed aggregation for Cheby smoother

927:    Collective on PC

929:    Input Parameters:
930: +  pc - the preconditioner context
931: -  n - number of its

933:    Options Database Key:
934: .  -pc_gamg_use_sa_esteig <true,false>

936:    Notes:

938:    Level: intermediate

940: .seealso: ()
941: @*/
942: PetscErrorCode PCGAMGSetUseSAEstEig(PC pc, PetscBool n)
943: {

948:   PetscTryMethod(pc,"PCGAMGSetUseSAEstEig_C",(PC,PetscBool),(pc,n));
949:   return(0);
950: }

952: static PetscErrorCode PCGAMGSetUseSAEstEig_GAMG(PC pc, PetscInt n)
953: {
954:   PC_MG   *mg      = (PC_MG*)pc->data;
955:   PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;

958:   pc_gamg->use_sa_esteig = n ? 1 : 0;
959:   return(0);
960: }

962: /*@C
963:    PCGAMGSetEstEigKSPType - Set type of KSP in eigen estimator (for Cheby)

965:    Collective on PC

967:    Input Parameters:
968: +  pc - the preconditioner context
969: -  t - ksp type

971:    Options Database Key:
972: .  -pc_gamg_esteig_ksp_type <type>

974:    Notes:

976:    Level: intermediate

978: .seealso: ()
979: @*/
980: PetscErrorCode PCGAMGSetEstEigKSPType(PC pc, char t[])
981: {

986:   PetscTryMethod(pc,"PCGAMGSetEstEigKSPType_C",(PC,char[]),(pc,t));
987:   return(0);
988: }

990: static PetscErrorCode PCGAMGSetEstEigKSPType_GAMG(PC pc, char t[])
991: {
993:   PC_MG   *mg      = (PC_MG*)pc->data;
994:   PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;

997:   PetscStrcpy(pc_gamg->esteig_type,t);
998:   return(0);
999: }

1001: /*@
1002:    PCGAMGSetEigenvalues - Set eigenvalues

1004:    Collective on PC

1006:    Input Parameters:
1007: +  pc - the preconditioner context
1008: -  emax - max eigenvalue
1009: .  emin - min eigenvalue

1011:    Options Database Key:
1012: .  -pc_gamg_eigenvalues

1014:    Level: intermediate

1016: .seealso: PCGAMGSetEstEigKSPMaxIt(), PCGAMGSetUseSAEstEig(), PCGAMGSetEstEigKSPType()
1017: @*/
1018: PetscErrorCode PCGAMGSetEigenvalues(PC pc, PetscReal emax,PetscReal emin)
1019: {

1024:   PetscTryMethod(pc,"PCGAMGSetEigenvalues_C",(PC,PetscReal,PetscReal),(pc,emax,emin));
1025:   return(0);
1026: }
1027: static PetscErrorCode PCGAMGSetEigenvalues_GAMG(PC pc,PetscReal emax,PetscReal emin)
1028: {
1029:   PC_MG          *mg      = (PC_MG*)pc->data;
1030:   PC_GAMG        *pc_gamg = (PC_GAMG*)mg->innerctx;

1033:   if (emax <= emin) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Maximum eigenvalue must be larger than minimum: max %g min %g",(double)emax,(double)emin);
1034:   if (emax*emin <= 0.0) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Both eigenvalues must be of the same sign: max %g min %g",(double)emax,(double)emin);
1035:   pc_gamg->emax = emax;
1036:   pc_gamg->emin = emin;

1038:   return(0);
1039: }

1041: /*@
1042:    PCGAMGSetReuseInterpolation - Reuse prolongation when rebuilding algebraic multigrid preconditioner

1044:    Collective on PC

1046:    Input Parameters:
1047: +  pc - the preconditioner context
1048: -  n - PETSC_TRUE or PETSC_FALSE

1050:    Options Database Key:
1051: .  -pc_gamg_reuse_interpolation <true,false>

1053:    Level: intermediate

1055:    Notes:
1056:     this may negatively affect the convergence rate of the method on new matrices if the matrix entries change a great deal, but allows
1057:           rebuilding the preconditioner quicker.

1059: .seealso: ()
1060: @*/
1061: PetscErrorCode PCGAMGSetReuseInterpolation(PC pc, PetscBool n)
1062: {

1067:   PetscTryMethod(pc,"PCGAMGSetReuseInterpolation_C",(PC,PetscBool),(pc,n));
1068:   return(0);
1069: }

1071: static PetscErrorCode PCGAMGSetReuseInterpolation_GAMG(PC pc, PetscBool n)
1072: {
1073:   PC_MG   *mg      = (PC_MG*)pc->data;
1074:   PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;

1077:   pc_gamg->reuse_prol = n;
1078:   return(0);
1079: }

1081: /*@
1082:    PCGAMGASMSetUseAggs - Have the PCGAMG smoother on each level use the aggregates defined by the coarsening process as the subdomains for the additive Schwarz preconditioner.

1084:    Collective on PC

1086:    Input Parameters:
1087: +  pc - the preconditioner context
1088: -  flg - PETSC_TRUE to use aggregates, PETSC_FALSE to not

1090:    Options Database Key:
1091: .  -pc_gamg_asm_use_agg

1093:    Level: intermediate

1095: .seealso: ()
1096: @*/
1097: PetscErrorCode PCGAMGASMSetUseAggs(PC pc, PetscBool flg)
1098: {

1103:   PetscTryMethod(pc,"PCGAMGASMSetUseAggs_C",(PC,PetscBool),(pc,flg));
1104:   return(0);
1105: }

1107: static PetscErrorCode PCGAMGASMSetUseAggs_GAMG(PC pc, PetscBool flg)
1108: {
1109:   PC_MG   *mg      = (PC_MG*)pc->data;
1110:   PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;

1113:   pc_gamg->use_aggs_in_asm = flg;
1114:   return(0);
1115: }

1117: /*@
1118:    PCGAMGSetUseParallelCoarseGridSolve - allow a parallel coarse grid solver

1120:    Collective on PC

1122:    Input Parameters:
1123: +  pc - the preconditioner context
1124: -  flg - PETSC_TRUE to not force coarse grid onto one processor

1126:    Options Database Key:
1127: .  -pc_gamg_use_parallel_coarse_grid_solver

1129:    Level: intermediate

1131: .seealso: PCGAMGSetCoarseGridLayoutType(), PCGAMGSetCpuPinCoarseGrids()
1132: @*/
1133: PetscErrorCode PCGAMGSetUseParallelCoarseGridSolve(PC pc, PetscBool flg)
1134: {

1139:   PetscTryMethod(pc,"PCGAMGSetUseParallelCoarseGridSolve_C",(PC,PetscBool),(pc,flg));
1140:   return(0);
1141: }

1143: static PetscErrorCode PCGAMGSetUseParallelCoarseGridSolve_GAMG(PC pc, PetscBool flg)
1144: {
1145:   PC_MG   *mg      = (PC_MG*)pc->data;
1146:   PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;

1149:   pc_gamg->use_parallel_coarse_grid_solver = flg;
1150:   return(0);
1151: }

1153: /*@
1154:    PCGAMGSetCpuPinCoarseGrids - pin reduced grids to CPU

1156:    Collective on PC

1158:    Input Parameters:
1159: +  pc - the preconditioner context
1160: -  flg - PETSC_TRUE to pin coarse grids to CPU

1162:    Options Database Key:
1163: .  -pc_gamg_cpu_pin_coarse_grids

1165:    Level: intermediate

1167: .seealso: PCGAMGSetCoarseGridLayoutType(), PCGAMGSetUseParallelCoarseGridSolve()
1168: @*/
1169: PetscErrorCode PCGAMGSetCpuPinCoarseGrids(PC pc, PetscBool flg)
1170: {

1175:   PetscTryMethod(pc,"PCGAMGSetCpuPinCoarseGrids_C",(PC,PetscBool),(pc,flg));
1176:   return(0);
1177: }

1179: static PetscErrorCode PCGAMGSetCpuPinCoarseGrids_GAMG(PC pc, PetscBool flg)
1180: {
1181:   PC_MG   *mg      = (PC_MG*)pc->data;
1182:   PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;

1185:   pc_gamg->cpu_pin_coarse_grids = flg;
1186:   return(0);
1187: }

1189: /*@
1190:    PCGAMGSetCoarseGridLayoutType - place reduce grids on processors with natural order (compact type)

1192:    Collective on PC

1194:    Input Parameters:
1195: +  pc - the preconditioner context
1196: -  flg - Layout type

1198:    Options Database Key:
1199: .  -pc_gamg_coarse_grid_layout_type

1201:    Level: intermediate

1203: .seealso: PCGAMGSetUseParallelCoarseGridSolve(), PCGAMGSetCpuPinCoarseGrids()
1204: @*/
1205: PetscErrorCode PCGAMGSetCoarseGridLayoutType(PC pc, PCGAMGLayoutType flg)
1206: {

1211:   PetscTryMethod(pc,"PCGAMGSetCoarseGridLayoutType_C",(PC,PCGAMGLayoutType),(pc,flg));
1212:   return(0);
1213: }

1215: static PetscErrorCode PCGAMGSetCoarseGridLayoutType_GAMG(PC pc, PCGAMGLayoutType flg)
1216: {
1217:   PC_MG   *mg      = (PC_MG*)pc->data;
1218:   PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;

1221:   pc_gamg->layout_type = flg;
1222:   return(0);
1223: }

1225: /*@
1226:    PCGAMGSetNlevels -  Sets the maximum number of levels PCGAMG will use

1228:    Not collective on PC

1230:    Input Parameters:
1231: +  pc - the preconditioner
1232: -  n - the maximum number of levels to use

1234:    Options Database Key:
1235: .  -pc_mg_levels

1237:    Level: intermediate

1239: .seealso: ()
1240: @*/
1241: PetscErrorCode PCGAMGSetNlevels(PC pc, PetscInt n)
1242: {

1247:   PetscTryMethod(pc,"PCGAMGSetNlevels_C",(PC,PetscInt),(pc,n));
1248:   return(0);
1249: }

1251: static PetscErrorCode PCGAMGSetNlevels_GAMG(PC pc, PetscInt n)
1252: {
1253:   PC_MG   *mg      = (PC_MG*)pc->data;
1254:   PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;

1257:   pc_gamg->Nlevels = n;
1258:   return(0);
1259: }

1261: /*@
1262:    PCGAMGSetThreshold - Relative threshold to use for dropping edges in aggregation graph

1264:    Not collective on PC

1266:    Input Parameters:
1267: +  pc - the preconditioner context
1268: -  threshold - the threshold value, 0.0 means keep all nonzero entries in the graph; negative means keep even zero entries in the graph

1270:    Options Database Key:
1271: .  -pc_gamg_threshold <threshold>

1273:    Notes:
1274:     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.
1275:     Before coarsening or aggregating the graph, GAMG 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.

1277:    Level: intermediate

1279: .seealso: PCGAMGFilterGraph(), PCGAMGSetSquareGraph()
1280: @*/
1281: PetscErrorCode PCGAMGSetThreshold(PC pc, PetscReal v[], PetscInt n)
1282: {

1287:   PetscTryMethod(pc,"PCGAMGSetThreshold_C",(PC,PetscReal[],PetscInt),(pc,v,n));
1288:   return(0);
1289: }

1291: static PetscErrorCode PCGAMGSetThreshold_GAMG(PC pc, PetscReal v[], PetscInt n)
1292: {
1293:   PC_MG   *mg      = (PC_MG*)pc->data;
1294:   PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;
1295:   PetscInt i;
1297:   for (i=0;i<n;i++) pc_gamg->threshold[i] = v[i];
1298:   do {pc_gamg->threshold[i] = pc_gamg->threshold[i-1]*pc_gamg->threshold_scale;} while (++i<PETSC_MG_MAXLEVELS);
1299:   return(0);
1300: }

1302: /*@
1303:    PCGAMGSetThresholdScale - Relative threshold reduction at each level

1305:    Not collective on PC

1307:    Input Parameters:
1308: +  pc - the preconditioner context
1309: -  scale - the threshold value reduction, ussually < 1.0

1311:    Options Database Key:
1312: .  -pc_gamg_threshold_scale <v>

1314:    Level: advanced

1316: .seealso: ()
1317: @*/
1318: PetscErrorCode PCGAMGSetThresholdScale(PC pc, PetscReal v)
1319: {

1324:   PetscTryMethod(pc,"PCGAMGSetThresholdScale_C",(PC,PetscReal),(pc,v));
1325:   return(0);
1326: }

1328: static PetscErrorCode PCGAMGSetThresholdScale_GAMG(PC pc, PetscReal v)
1329: {
1330:   PC_MG   *mg      = (PC_MG*)pc->data;
1331:   PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx;
1333:   pc_gamg->threshold_scale = v;
1334:   return(0);
1335: }

1337: /*@C
1338:    PCGAMGSetType - Set solution method

1340:    Collective on PC

1342:    Input Parameters:
1343: +  pc - the preconditioner context
1344: -  type - PCGAMGAGG, PCGAMGGEO, or PCGAMGCLASSICAL

1346:    Options Database Key:
1347: .  -pc_gamg_type <agg,geo,classical> - type of algebraic multigrid to apply

1349:    Level: intermediate

1351: .seealso: PCGAMGGetType(), PCGAMG, PCGAMGType
1352: @*/
1353: PetscErrorCode PCGAMGSetType(PC pc, PCGAMGType type)
1354: {

1359:   PetscTryMethod(pc,"PCGAMGSetType_C",(PC,PCGAMGType),(pc,type));
1360:   return(0);
1361: }

1363: /*@C
1364:    PCGAMGGetType - Get solution method

1366:    Collective on PC

1368:    Input Parameter:
1369: .  pc - the preconditioner context

1371:    Output Parameter:
1372: .  type - the type of algorithm used

1374:    Level: intermediate

1376: .seealso: PCGAMGSetType(), PCGAMGType
1377: @*/
1378: PetscErrorCode PCGAMGGetType(PC pc, PCGAMGType *type)
1379: {

1384:   PetscUseMethod(pc,"PCGAMGGetType_C",(PC,PCGAMGType*),(pc,type));
1385:   return(0);
1386: }

1388: static PetscErrorCode PCGAMGGetType_GAMG(PC pc, PCGAMGType *type)
1389: {
1390:   PC_MG          *mg      = (PC_MG*)pc->data;
1391:   PC_GAMG        *pc_gamg = (PC_GAMG*)mg->innerctx;

1394:   *type = pc_gamg->type;
1395:   return(0);
1396: }

1398: static PetscErrorCode PCGAMGSetType_GAMG(PC pc, PCGAMGType type)
1399: {
1400:   PetscErrorCode ierr,(*r)(PC);
1401:   PC_MG          *mg      = (PC_MG*)pc->data;
1402:   PC_GAMG        *pc_gamg = (PC_GAMG*)mg->innerctx;

1405:   pc_gamg->type = type;
1406:   PetscFunctionListFind(GAMGList,type,&r);
1407:   if (!r) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown GAMG type %s given",type);
1408:   if (pc_gamg->ops->destroy) {
1409:     (*pc_gamg->ops->destroy)(pc);
1410:     PetscMemzero(pc_gamg->ops,sizeof(struct _PCGAMGOps));
1411:     pc_gamg->ops->createlevel = PCGAMGCreateLevel_GAMG;
1412:     /* cleaning up common data in pc_gamg - this should disapear someday */
1413:     pc_gamg->data_cell_cols = 0;
1414:     pc_gamg->data_cell_rows = 0;
1415:     pc_gamg->orig_data_cell_cols = 0;
1416:     pc_gamg->orig_data_cell_rows = 0;
1417:     PetscFree(pc_gamg->data);
1418:     pc_gamg->data_sz = 0;
1419:   }
1420:   PetscFree(pc_gamg->gamg_type_name);
1421:   PetscStrallocpy(type,&pc_gamg->gamg_type_name);
1422:   (*r)(pc);
1423:   return(0);
1424: }

1426: /* -------------------------------------------------------------------------- */
1427: /*
1428:    PCMGGetGridComplexity - compute coarse grid complexity of MG hierarchy

1430:    Input Parameter:
1431: .  pc - the preconditioner context

1433:    Output Parameter:
1434: .  gc - grid complexity = sum_i(nnz_i) / nnz_0

1436:    Level: advanced
1437: */
1438: static PetscErrorCode PCMGGetGridComplexity(PC pc, PetscReal *gc)
1439: {
1441:   PC_MG          *mg      = (PC_MG*)pc->data;
1442:   PC_MG_Levels   **mglevels = mg->levels;
1443:   PetscInt       lev;
1444:   PetscLogDouble nnz0 = 0, sgc = 0;
1445:   MatInfo        info;

1448:   if (!mg->nlevels) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"MG has no levels");
1449:   for (lev=0; lev<mg->nlevels; lev++) {
1450:     Mat dB;
1451:     KSPGetOperators(mglevels[lev]->smoothd,NULL,&dB);
1452:     MatGetInfo(dB,MAT_GLOBAL_SUM,&info); /* global reduction */
1453:     sgc += info.nz_used;
1454:     if (lev==mg->nlevels-1) nnz0 = info.nz_used;
1455:   }
1456:   if (nnz0 > 0) *gc = (PetscReal)(sgc/nnz0);
1457:   else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Number for grid points on finest level is not available");
1458:   return(0);
1459: }

1461: static PetscErrorCode PCView_GAMG(PC pc,PetscViewer viewer)
1462: {
1463:   PetscErrorCode ierr,i;
1464:   PC_MG          *mg      = (PC_MG*)pc->data;
1465:   PC_GAMG        *pc_gamg = (PC_GAMG*)mg->innerctx;
1466:   PetscReal       gc=0;
1468:   PetscViewerASCIIPrintf(viewer,"    GAMG specific options\n");
1469:   PetscViewerASCIIPrintf(viewer,"      Threshold for dropping small values in graph on each level =");
1470:   for (i=0;i<pc_gamg->current_level;i++) {
1471:     PetscViewerASCIIPrintf(viewer," %g",(double)pc_gamg->threshold[i]);
1472:   }
1473:   PetscViewerASCIIPrintf(viewer,"\n");
1474:   PetscViewerASCIIPrintf(viewer,"      Threshold scaling factor for each level not specified = %g\n",(double)pc_gamg->threshold_scale);
1475:   if (pc_gamg->use_aggs_in_asm) {
1476:     PetscViewerASCIIPrintf(viewer,"      Using aggregates from coarsening process to define subdomains for PCASM\n");
1477:   }
1478:   if (pc_gamg->use_parallel_coarse_grid_solver) {
1479:     PetscViewerASCIIPrintf(viewer,"      Using parallel coarse grid solver (all coarse grid equations not put on one process)\n");
1480:   }
1481: #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA)
1482:   if (pc_gamg->cpu_pin_coarse_grids) {
1483:     /* PetscViewerASCIIPrintf(viewer,"      Pinning coarse grids to the CPU)\n"); */
1484:   }
1485: #endif
1486:   /* if (pc_gamg->layout_type==PCGAMG_LAYOUT_COMPACT) { */
1487:   /*   PetscViewerASCIIPrintf(viewer,"      Put reduced grids on processes in natural order (ie, 0,1,2...)\n"); */
1488:   /* } else { */
1489:   /*   PetscViewerASCIIPrintf(viewer,"      Put reduced grids on whole machine (ie, 0,1*f,2*f...,np-f)\n"); */
1490:   /* } */
1491:   if (pc_gamg->ops->view) {
1492:     (*pc_gamg->ops->view)(pc,viewer);
1493:   }
1494:   PCMGGetGridComplexity(pc,&gc);
1495:   PetscViewerASCIIPrintf(viewer,"      Complexity:    grid = %g\n",gc);
1496:   return(0);
1497: }

1499: PetscErrorCode PCSetFromOptions_GAMG(PetscOptionItems *PetscOptionsObject,PC pc)
1500: {
1502:   PC_MG          *mg      = (PC_MG*)pc->data;
1503:   PC_GAMG        *pc_gamg = (PC_GAMG*)mg->innerctx;
1504:   PetscBool      flag,f2;
1505:   MPI_Comm       comm;
1506:   char           prefix[256],tname[32];
1507:   PetscInt       i,n;
1508:   const char     *pcpre;
1509:   static const char *LayoutTypes[] = {"compact","spread","PCGAMGLayoutType","PC_GAMG_LAYOUT",0};
1511:   PetscObjectGetComm((PetscObject)pc,&comm);
1512:   PetscOptionsHead(PetscOptionsObject,"GAMG options");
1513:   PetscOptionsFList("-pc_gamg_type","Type of AMG method","PCGAMGSetType",GAMGList, pc_gamg->gamg_type_name, tname, sizeof(tname), &flag);
1514:   if (flag) {
1515:     PCGAMGSetType(pc,tname);
1516:   }
1517:   PetscOptionsFList("-pc_gamg_esteig_ksp_type","Krylov method for eigen estimator","PCGAMGSetEstEigKSPType",KSPList,pc_gamg->esteig_type,tname,sizeof(tname),&flag);
1518:   if (flag) {
1519:     PCGAMGSetEstEigKSPType(pc,tname);
1520:   }
1521:   PetscOptionsBool("-pc_gamg_repartition","Repartion coarse grids","PCGAMGSetRepartition",pc_gamg->repart,&pc_gamg->repart,NULL);
1522:   f2 = PETSC_TRUE;
1523:   PetscOptionsBool("-pc_gamg_use_sa_esteig","Use eigen estimate from Smoothed aggregation for smoother","PCGAMGSetUseSAEstEig",f2,&f2,&flag);
1524:   if (flag) pc_gamg->use_sa_esteig = f2 ? 1 : 0;
1525:   PetscOptionsBool("-pc_gamg_reuse_interpolation","Reuse prolongation operator","PCGAMGReuseInterpolation",pc_gamg->reuse_prol,&pc_gamg->reuse_prol,NULL);
1526:   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);
1527:   PetscOptionsBool("-pc_gamg_use_parallel_coarse_grid_solver","Use parallel coarse grid solver (otherwise put last grid on one process)","PCGAMGSetUseParallelCoarseGridSolve",pc_gamg->use_parallel_coarse_grid_solver,&pc_gamg->use_parallel_coarse_grid_solver,NULL);
1528:   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);
1529:   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,(PetscEnum)pc_gamg->layout_type,(PetscEnum*)&pc_gamg->layout_type,NULL);
1530:   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);
1531:   PetscOptionsInt("-pc_gamg_esteig_ksp_max_it","Number of iterations of eigen estimator","PCGAMGSetEstEigKSPMaxIt",pc_gamg->esteig_max_it,&pc_gamg->esteig_max_it,NULL);
1532:   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);
1533:   PetscOptionsReal("-pc_gamg_threshold_scale","Scaling of threshold for each level not specified","PCGAMGSetThresholdScale",pc_gamg->threshold_scale,&pc_gamg->threshold_scale,NULL);
1534:   n = PETSC_MG_MAXLEVELS;
1535:   PetscOptionsRealArray("-pc_gamg_threshold","Relative threshold to use for dropping edges in aggregation graph","PCGAMGSetThreshold",pc_gamg->threshold,&n,&flag);
1536:   if (!flag || n < PETSC_MG_MAXLEVELS) {
1537:     if (!flag) n = 1;
1538:     i = n;
1539:     do {pc_gamg->threshold[i] = pc_gamg->threshold[i-1]*pc_gamg->threshold_scale;} while (++i<PETSC_MG_MAXLEVELS);
1540:   }
1541:   PetscOptionsInt("-pc_mg_levels","Set number of MG levels","PCGAMGSetNlevels",pc_gamg->Nlevels,&pc_gamg->Nlevels,NULL);
1542:   {
1543:     PetscReal eminmax[2] = {0., 0.};
1544:     n = 2;
1545:     PetscOptionsRealArray("-pc_gamg_eigenvalues","extreme eigenvalues for smoothed aggregation","PCGAMGSetEigenvalues",eminmax,&n,&flag);
1546:     if (flag) {
1547:       if (n != 2) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"-pc_gamg_eigenvalues: must specify 2 parameters, min and max eigenvalues");
1548:       PCGAMGSetEigenvalues(pc, eminmax[1], eminmax[0]);
1549:     }
1550:   }
1551:   /* set options for subtype */
1552:   if (pc_gamg->ops->setfromoptions) {(*pc_gamg->ops->setfromoptions)(PetscOptionsObject,pc);}

1554:   PCGetOptionsPrefix(pc, &pcpre);
1555:   PetscSNPrintf(prefix,sizeof(prefix),"%spc_gamg_",pcpre ? pcpre : "");
1556:   PetscOptionsTail();
1557:   return(0);
1558: }

1560: /* -------------------------------------------------------------------------- */
1561: /*MC
1562:      PCGAMG - Geometric algebraic multigrid (AMG) preconditioner

1564:    Options Database Keys:
1565: +   -pc_gamg_type <type> - one of agg, geo, or classical
1566: .   -pc_gamg_repartition  <true,default=false> - repartition the degrees of freedom accross the coarse grids as they are determined
1567: .   -pc_gamg_reuse_interpolation <true,default=false> - when rebuilding the algebraic multigrid preconditioner reuse the previously computed interpolations
1568: .   -pc_gamg_asm_use_agg <true,default=false> - use the aggregates from the coasening process to defined the subdomains on each level for the PCASM smoother
1569: .   -pc_gamg_process_eq_limit <limit, default=50> - GAMG will reduce the number of MPI processes used directly on the coarse grids so that there are around <limit>
1570:                                         equations on each process that has degrees of freedom
1571: .   -pc_gamg_coarse_eq_limit <limit, default=50> - Set maximum number of equations on coarsest grid to aim for.
1572: .   -pc_gamg_threshold[] <thresh,default=0> - Before aggregating the graph GAMG will remove small values from the graph on each level
1573: -   -pc_gamg_threshold_scale <scale,default=1> - Scaling of threshold on each coarser grid if not specified

1575:    Options Database Keys for default Aggregation:
1576: +  -pc_gamg_agg_nsmooths <nsmooth, default=1> - number of smoothing steps to use with smooth aggregation
1577: .  -pc_gamg_sym_graph <true,default=false> - symmetrize the graph before computing the aggregation
1578: -  -pc_gamg_square_graph <n,default=1> - number of levels to square the graph before aggregating it

1580:    Multigrid options:
1581: +  -pc_mg_cycles <v> - v or w, see PCMGSetCycleType()
1582: .  -pc_mg_distinct_smoothup - configure the up and down (pre and post) smoothers separately, see PCMGSetDistinctSmoothUp()
1583: .  -pc_mg_type <multiplicative> - (one of) additive multiplicative full kascade
1584: -  -pc_mg_levels <levels> - Number of levels of multigrid to use.


1587:   Notes:
1588:     In order to obtain good performance for PCGAMG for vector valued problems you must
1589:        Call MatSetBlockSize() to indicate the number of degrees of freedom per grid point
1590:        Call MatSetNearNullSpace() (or PCSetCoordinates() if solving the equations of elasticity) to indicate the near null space of the operator
1591:        See the Users Manual Chapter 4 for more details

1593:   Level: intermediate

1595: .seealso:  PCCreate(), PCSetType(), MatSetBlockSize(), PCMGType, PCSetCoordinates(), MatSetNearNullSpace(), PCGAMGSetType(), PCGAMGAGG, PCGAMGGEO, PCGAMGCLASSICAL, PCGAMGSetProcEqLim(),
1596:            PCGAMGSetCoarseEqLim(), PCGAMGSetRepartition(), PCGAMGRegister(), PCGAMGSetReuseInterpolation(), PCGAMGASMSetUseAggs(), PCGAMGSetUseParallelCoarseGridSolve(), PCGAMGSetNlevels(), PCGAMGSetThreshold(), PCGAMGGetType(), PCGAMGSetReuseInterpolation(), PCGAMGSetUseSAEstEig(), PCGAMGSetEstEigKSPMaxIt(), PCGAMGSetEstEigKSPType()
1597: M*/

1599: PETSC_EXTERN PetscErrorCode PCCreate_GAMG(PC pc)
1600: {
1601:   PetscErrorCode ierr,i;
1602:   PC_GAMG        *pc_gamg;
1603:   PC_MG          *mg;

1606:    /* register AMG type */
1607:   PCGAMGInitializePackage();

1609:   /* PCGAMG is an inherited class of PCMG. Initialize pc as PCMG */
1610:   PCSetType(pc, PCMG);
1611:   PetscObjectChangeTypeName((PetscObject)pc, PCGAMG);

1613:   /* create a supporting struct and attach it to pc */
1614:   PetscNewLog(pc,&pc_gamg);
1615:   PCMGSetGalerkin(pc,PC_MG_GALERKIN_EXTERNAL);
1616:   mg           = (PC_MG*)pc->data;
1617:   mg->innerctx = pc_gamg;

1619:   PetscNewLog(pc,&pc_gamg->ops);

1621:   pc_gamg->setup_count = 0;
1622:   /* these should be in subctx but repartitioning needs simple arrays */
1623:   pc_gamg->data_sz = 0;
1624:   pc_gamg->data    = 0;

1626:   /* overwrite the pointers of PCMG by the functions of base class PCGAMG */
1627:   pc->ops->setfromoptions = PCSetFromOptions_GAMG;
1628:   pc->ops->setup          = PCSetUp_GAMG;
1629:   pc->ops->reset          = PCReset_GAMG;
1630:   pc->ops->destroy        = PCDestroy_GAMG;
1631:   mg->view                = PCView_GAMG;

1633:   PetscObjectComposeFunction((PetscObject)pc,"PCMGGetLevels_C",PCMGGetLevels_MG);
1634:   PetscObjectComposeFunction((PetscObject)pc,"PCMGSetLevels_C",PCMGSetLevels_MG);
1635:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetProcEqLim_C",PCGAMGSetProcEqLim_GAMG);
1636:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetCoarseEqLim_C",PCGAMGSetCoarseEqLim_GAMG);
1637:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetRepartition_C",PCGAMGSetRepartition_GAMG);
1638:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetEstEigKSPType_C",PCGAMGSetEstEigKSPType_GAMG);
1639:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetEstEigKSPMaxIt_C",PCGAMGSetEstEigKSPMaxIt_GAMG);
1640:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetEigenvalues_C",PCGAMGSetEigenvalues_GAMG);
1641:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetUseSAEstEig_C",PCGAMGSetUseSAEstEig_GAMG);
1642:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetReuseInterpolation_C",PCGAMGSetReuseInterpolation_GAMG);
1643:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGASMSetUseAggs_C",PCGAMGASMSetUseAggs_GAMG);
1644:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetUseParallelCoarseGridSolve_C",PCGAMGSetUseParallelCoarseGridSolve_GAMG);
1645:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetCpuPinCoarseGrids_C",PCGAMGSetCpuPinCoarseGrids_GAMG);
1646:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetCoarseGridLayoutType_C",PCGAMGSetCoarseGridLayoutType_GAMG);
1647:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetThreshold_C",PCGAMGSetThreshold_GAMG);
1648:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetThresholdScale_C",PCGAMGSetThresholdScale_GAMG);
1649:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetType_C",PCGAMGSetType_GAMG);
1650:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGGetType_C",PCGAMGGetType_GAMG);
1651:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetNlevels_C",PCGAMGSetNlevels_GAMG);
1652:   pc_gamg->repart           = PETSC_FALSE;
1653:   pc_gamg->reuse_prol       = PETSC_FALSE;
1654:   pc_gamg->use_aggs_in_asm  = PETSC_FALSE;
1655:   pc_gamg->use_parallel_coarse_grid_solver = PETSC_FALSE;
1656:   pc_gamg->cpu_pin_coarse_grids = PETSC_FALSE;
1657:   pc_gamg->layout_type      = PCGAMG_LAYOUT_SPREAD;
1658:   pc_gamg->min_eq_proc      = 50;
1659:   pc_gamg->coarse_eq_limit  = 50;
1660:   for (i=0;i<PETSC_MG_MAXLEVELS;i++) pc_gamg->threshold[i] = 0.;
1661:   pc_gamg->threshold_scale = 1.;
1662:   pc_gamg->Nlevels          = PETSC_MG_MAXLEVELS;
1663:   pc_gamg->current_level    = 0; /* don't need to init really */
1664:   PetscStrcpy(pc_gamg->esteig_type,KSPGMRES);
1665:   pc_gamg->esteig_max_it    = 10;
1666:   pc_gamg->use_sa_esteig    = -1;
1667:   pc_gamg->emin             = 0;
1668:   pc_gamg->emax             = 0;

1670:   pc_gamg->ops->createlevel = PCGAMGCreateLevel_GAMG;

1672:   /* PCSetUp_GAMG assumes that the type has been set, so set it to the default now */
1673:   PCGAMGSetType(pc,PCGAMGAGG);
1674:   return(0);
1675: }

1677: /*@C
1678:  PCGAMGInitializePackage - This function initializes everything in the PCGAMG package. It is called
1679:     from PCInitializePackage().

1681:  Level: developer

1683:  .seealso: PetscInitialize()
1684: @*/
1685: PetscErrorCode PCGAMGInitializePackage(void)
1686: {

1690:   if (PCGAMGPackageInitialized) return(0);
1691:   PCGAMGPackageInitialized = PETSC_TRUE;
1692:   PetscFunctionListAdd(&GAMGList,PCGAMGGEO,PCCreateGAMG_GEO);
1693:   PetscFunctionListAdd(&GAMGList,PCGAMGAGG,PCCreateGAMG_AGG);
1694:   PetscFunctionListAdd(&GAMGList,PCGAMGCLASSICAL,PCCreateGAMG_Classical);
1695:   PetscRegisterFinalize(PCGAMGFinalizePackage);

1697:   /* general events */
1698:   PetscLogEventRegister("PCGAMGGraph_AGG", 0, &PC_GAMGGraph_AGG);
1699:   PetscLogEventRegister("PCGAMGGraph_GEO", PC_CLASSID, &PC_GAMGGraph_GEO);
1700:   PetscLogEventRegister("PCGAMGCoarse_AGG", PC_CLASSID, &PC_GAMGCoarsen_AGG);
1701:   PetscLogEventRegister("PCGAMGCoarse_GEO", PC_CLASSID, &PC_GAMGCoarsen_GEO);
1702:   PetscLogEventRegister("PCGAMGProl_AGG", PC_CLASSID, &PC_GAMGProlongator_AGG);
1703:   PetscLogEventRegister("PCGAMGProl_GEO", PC_CLASSID, &PC_GAMGProlongator_GEO);
1704:   PetscLogEventRegister("PCGAMGPOpt_AGG", PC_CLASSID, &PC_GAMGOptProlongator_AGG);

1706: #if defined PETSC_GAMG_USE_LOG
1707:   PetscLogEventRegister("GAMG: createProl", PC_CLASSID, &petsc_gamg_setup_events[SET1]);
1708:   PetscLogEventRegister("  Graph", PC_CLASSID, &petsc_gamg_setup_events[GRAPH]);
1709:   /* PetscLogEventRegister("    G.Mat", PC_CLASSID, &petsc_gamg_setup_events[GRAPH_MAT]); */
1710:   /* PetscLogEventRegister("    G.Filter", PC_CLASSID, &petsc_gamg_setup_events[GRAPH_FILTER]); */
1711:   /* PetscLogEventRegister("    G.Square", PC_CLASSID, &petsc_gamg_setup_events[GRAPH_SQR]); */
1712:   PetscLogEventRegister("  MIS/Agg", PC_CLASSID, &petsc_gamg_setup_events[SET4]);
1713:   PetscLogEventRegister("  geo: growSupp", PC_CLASSID, &petsc_gamg_setup_events[SET5]);
1714:   PetscLogEventRegister("  geo: triangle", PC_CLASSID, &petsc_gamg_setup_events[SET6]);
1715:   PetscLogEventRegister("    search-set", PC_CLASSID, &petsc_gamg_setup_events[FIND_V]);
1716:   PetscLogEventRegister("  SA: col data", PC_CLASSID, &petsc_gamg_setup_events[SET7]);
1717:   PetscLogEventRegister("  SA: frmProl0", PC_CLASSID, &petsc_gamg_setup_events[SET8]);
1718:   PetscLogEventRegister("  SA: smooth", PC_CLASSID, &petsc_gamg_setup_events[SET9]);
1719:   PetscLogEventRegister("GAMG: partLevel", PC_CLASSID, &petsc_gamg_setup_events[SET2]);
1720:   PetscLogEventRegister("  repartition", PC_CLASSID, &petsc_gamg_setup_events[SET12]);
1721:   PetscLogEventRegister("  Invert-Sort", PC_CLASSID, &petsc_gamg_setup_events[SET13]);
1722:   PetscLogEventRegister("  Move A", PC_CLASSID, &petsc_gamg_setup_events[SET14]);
1723:   PetscLogEventRegister("  Move P", PC_CLASSID, &petsc_gamg_setup_events[SET15]);

1725:   /* PetscLogEventRegister(" PL move data", PC_CLASSID, &petsc_gamg_setup_events[SET13]); */
1726:   /* PetscLogEventRegister("GAMG: fix", PC_CLASSID, &petsc_gamg_setup_events[SET10]); */
1727:   /* PetscLogEventRegister("GAMG: set levels", PC_CLASSID, &petsc_gamg_setup_events[SET11]); */
1728:   /* create timer stages */
1729: #if defined GAMG_STAGES
1730:   {
1731:     char     str[32];
1732:     PetscInt lidx;
1733:     sprintf(str,"MG Level %d (finest)",0);
1734:     PetscLogStageRegister(str, &gamg_stages[0]);
1735:     for (lidx=1; lidx<9; lidx++) {
1736:       sprintf(str,"MG Level %d",lidx);
1737:       PetscLogStageRegister(str, &gamg_stages[lidx]);
1738:     }
1739:   }
1740: #endif
1741: #endif
1742:   return(0);
1743: }

1745: /*@C
1746:  PCGAMGFinalizePackage - This function frees everything from the PCGAMG package. It is
1747:     called from PetscFinalize() automatically.

1749:  Level: developer

1751:  .seealso: PetscFinalize()
1752: @*/
1753: PetscErrorCode PCGAMGFinalizePackage(void)
1754: {

1758:   PCGAMGPackageInitialized = PETSC_FALSE;
1759:   PetscFunctionListDestroy(&GAMGList);
1760:   return(0);
1761: }

1763: /*@C
1764:  PCGAMGRegister - Register a PCGAMG implementation.

1766:  Input Parameters:
1767:  + type - string that will be used as the name of the GAMG type.
1768:  - create - function for creating the gamg context.

1770:   Level: advanced

1772:  .seealso: PCGAMGType, PCGAMG, PCGAMGSetType()
1773: @*/
1774: PetscErrorCode PCGAMGRegister(PCGAMGType type, PetscErrorCode (*create)(PC))
1775: {

1779:   PCGAMGInitializePackage();
1780:   PetscFunctionListAdd(&GAMGList,type,create);
1781:   return(0);
1782: }