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> /*I "petscpc.h" I*/ 6 #include <../src/ksp/pc/impls/bjacobi/bjacobi.h> /* Hack to access same_local_solves */ 7 #include <../src/ksp/ksp/impls/cheby/chebyshevimpl.h> /*I "petscksp.h" I*/ 8 9 #if defined PETSC_GAMG_USE_LOG 10 PetscLogEvent petsc_gamg_setup_events[NUM_SET]; 11 #endif 12 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 22 23 /* #define GAMG_STAGES */ 24 #if (defined PETSC_GAMG_USE_LOG && defined GAMG_STAGES) 25 static PetscLogStage gamg_stages[PETSC_MG_MAXLEVELS]; 26 #endif 27 28 static PetscFunctionList GAMGList = NULL; 29 static PetscBool PCGAMGPackageInitialized; 30 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; 37 38 PetscFunctionBegin; 39 ierr = PetscFree(pc_gamg->data);CHKERRQ(ierr); 40 pc_gamg->data_sz = 0; 41 ierr = PetscFree(pc_gamg->orig_data);CHKERRQ(ierr); 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 PetscFunctionReturn(0); 49 } 50 51 /* -------------------------------------------------------------------------- */ 52 /* 53 PCGAMGCreateLevel_GAMG: create coarse op with RAP. repartition and/or reduce number 54 of active processors. 55 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 */ 67 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; 77 78 PetscFunctionBegin; 79 ierr = PetscObjectGetComm((PetscObject)Amat_fine,&comm);CHKERRQ(ierr); 80 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 81 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 82 ierr = MatGetBlockSize(Amat_fine, &f_bs);CHKERRQ(ierr); 83 ierr = MatPtAP(Amat_fine, Pold, MAT_INITIAL_MATRIX, 2.0, &Cmat);CHKERRQ(ierr); 84 85 if (Pcolumnperm) *Pcolumnperm = NULL; 86 87 /* set 'ncrs' (nodes), 'ncrs_eq' (equations)*/ 88 ierr = MatGetLocalSize(Cmat, &ncrs_eq, NULL);CHKERRQ(ierr); 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 ierr = MatGetBlockSize(Cmat, &bs);CHKERRQ(ierr); 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 ierr = MatGetSize(Cmat, &ncrs_eq_glob, NULL);CHKERRQ(ierr); 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 } 105 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 ierr = PetscInfo1(pc,"reduced grid using same number of processors (%d) as last grid (use larger coarse grid)\n",nactive);CHKERRQ(ierr); 111 if (pc_gamg->cpu_pin_coarse_grids) { 112 ierr = MatBindToCPU(*a_Amat_crs,PETSC_TRUE);CHKERRQ(ierr); 113 ierr = MatBindToCPU(*a_P_inout,PETSC_TRUE);CHKERRQ(ierr); 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 ierr = PetscInfo2(pc,"Finding factorable processor set stopped reduction: new_size=%d, neq(loc)=%D\n",new_size,ncrs_eq);CHKERRQ(ierr); 147 PetscFunctionReturn(0); 148 } 149 } 150 #if defined PETSC_GAMG_USE_LOG 151 ierr = PetscLogEventBegin(petsc_gamg_setup_events[SET12],0,0,0,0);CHKERRQ(ierr); 152 #endif 153 /* make 'is_eq_newproc' */ 154 ierr = PetscMalloc1(size, &counts);CHKERRQ(ierr); 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 ierr = 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");CHKERRQ(ierr); 159 /* get 'adj' */ 160 if (cr_bs == 1) { 161 ierr = MatConvert(Cmat, MATMPIADJ, MAT_INITIAL_MATRIX, &adj);CHKERRQ(ierr); 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; 171 172 ierr = PetscMalloc2(ncrs, &d_nnz,ncrs, &o_nnz);CHKERRQ(ierr); 173 ierr = MatGetOwnershipRange(Cmat, &Istart_crs, &Iend_crs);CHKERRQ(ierr); 174 ierr = MatGetSize(Cmat, &M, &N);CHKERRQ(ierr); 175 for (Ii = Istart_crs, jj = 0; Ii < Iend_crs; Ii += cr_bs, jj++) { 176 ierr = MatGetRow(Cmat,Ii,&ncols,NULL,NULL);CHKERRQ(ierr); 177 d_nnz[jj] = ncols/cr_bs; 178 o_nnz[jj] = ncols/cr_bs; 179 ierr = MatRestoreRow(Cmat,Ii,&ncols,NULL,NULL);CHKERRQ(ierr); 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 } 183 184 ierr = MatGetType(Amat_fine,&mtype);CHKERRQ(ierr); 185 ierr = MatCreate(comm, &tMat);CHKERRQ(ierr); 186 ierr = MatSetSizes(tMat, ncrs, ncrs,PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 187 ierr = MatSetType(tMat,mtype);CHKERRQ(ierr); 188 ierr = MatSeqAIJSetPreallocation(tMat,0,d_nnz);CHKERRQ(ierr); 189 ierr = MatMPIAIJSetPreallocation(tMat,0,d_nnz,0,o_nnz);CHKERRQ(ierr); 190 ierr = PetscFree2(d_nnz,o_nnz);CHKERRQ(ierr); 191 192 for (ii = Istart_crs; ii < Iend_crs; ii++) { 193 PetscInt dest_row = ii/cr_bs; 194 ierr = MatGetRow(Cmat,ii,&ncols,&idx,&vals);CHKERRQ(ierr); 195 for (jj = 0; jj < ncols; jj++) { 196 PetscInt dest_col = idx[jj]/cr_bs; 197 PetscScalar v = 1.0; 198 ierr = MatSetValues(tMat,1,&dest_row,1,&dest_col,&v,ADD_VALUES);CHKERRQ(ierr); 199 } 200 ierr = MatRestoreRow(Cmat,ii,&ncols,&idx,&vals);CHKERRQ(ierr); 201 } 202 ierr = MatAssemblyBegin(tMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 203 ierr = MatAssemblyEnd(tMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 204 205 if (llev++ == -1) { 206 PetscViewer viewer; char fname[32]; 207 ierr = PetscSNPrintf(fname,sizeof(fname),"part_mat_%D.mat",llev);CHKERRQ(ierr); 208 PetscViewerBinaryOpen(comm,fname,FILE_MODE_WRITE,&viewer); 209 ierr = MatView(tMat, viewer);CHKERRQ(ierr); 210 ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); 211 } 212 ierr = MatConvert(tMat, MATMPIADJ, MAT_INITIAL_MATRIX, &adj);CHKERRQ(ierr); 213 ierr = MatDestroy(&tMat);CHKERRQ(ierr); 214 } /* create 'adj' */ 215 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; 222 223 ierr = MatPartitioningCreate(comm, &mpart);CHKERRQ(ierr); 224 ierr = MatPartitioningSetAdjacency(mpart, adj);CHKERRQ(ierr); 225 ierr = PCGetOptionsPrefix(pc, &pcpre);CHKERRQ(ierr); 226 ierr = PetscSNPrintf(prefix,sizeof(prefix),"%spc_gamg_",pcpre ? pcpre : "");CHKERRQ(ierr); 227 ierr = PetscObjectSetOptionsPrefix((PetscObject)mpart,prefix);CHKERRQ(ierr); 228 ierr = MatPartitioningSetFromOptions(mpart);CHKERRQ(ierr); 229 ierr = MatPartitioningSetNParts(mpart, new_size);CHKERRQ(ierr); 230 ierr = MatPartitioningApply(mpart, &proc_is);CHKERRQ(ierr); 231 ierr = MatPartitioningDestroy(&mpart);CHKERRQ(ierr); 232 233 /* collect IS info */ 234 ierr = PetscMalloc1(ncrs_eq, &newproc_idx);CHKERRQ(ierr); 235 ierr = ISGetIndices(proc_is, &is_idx);CHKERRQ(ierr); 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 ierr = ISRestoreIndices(proc_is, &is_idx);CHKERRQ(ierr); 242 ierr = ISDestroy(&proc_is);CHKERRQ(ierr); 243 } 244 ierr = MatDestroy(&adj);CHKERRQ(ierr); 245 246 ierr = ISCreateGeneral(comm, ncrs_eq, newproc_idx, PETSC_COPY_VALUES, &is_eq_newproc);CHKERRQ(ierr); 247 ierr = PetscFree(newproc_idx);CHKERRQ(ierr); 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 ierr = PetscInfo1(pc,"Number of equations (loc) %D with simple aggregation\n",ncrs_eq);CHKERRQ(ierr); 252 targetPE = (rank/rfactor)*expand_factor; 253 ierr = ISCreateStride(comm, ncrs_eq, targetPE, 0, &is_eq_newproc);CHKERRQ(ierr); 254 } /* end simple 'is_eq_newproc' */ 255 256 /* 257 Create an index set from the is_eq_newproc index set to indicate the mapping TO 258 */ 259 ierr = ISPartitioningToNumbering(is_eq_newproc, &is_eq_num);CHKERRQ(ierr); 260 is_eq_num_prim = is_eq_num; 261 /* 262 Determine how many equations/vertices are assigned to each processor 263 */ 264 ierr = ISPartitioningCount(is_eq_newproc, size, counts);CHKERRQ(ierr); 265 ncrs_eq_new = counts[rank]; 266 ierr = ISDestroy(&is_eq_newproc);CHKERRQ(ierr); 267 ncrs_new = ncrs_eq_new/cr_bs; 268 269 ierr = PetscFree(counts);CHKERRQ(ierr); 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 ierr = VecCreate(comm, &dest_crd);CHKERRQ(ierr); 280 ierr = VecSetSizes(dest_crd, node_data_sz*ncrs_new, PETSC_DECIDE);CHKERRQ(ierr); 281 ierr = VecSetType(dest_crd,VECSTANDARD);CHKERRQ(ierr); /* 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 ierr = PetscMalloc1(ncrs*node_data_sz, &tidx);CHKERRQ(ierr); 287 ierr = ISGetIndices(is_eq_num_prim, &idx);CHKERRQ(ierr); 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 ierr = ISRestoreIndices(is_eq_num_prim, &idx);CHKERRQ(ierr); 293 ierr = ISCreateGeneral(comm, node_data_sz*ncrs, tidx, PETSC_COPY_VALUES, &isscat);CHKERRQ(ierr); 294 ierr = PetscFree(tidx);CHKERRQ(ierr); 295 /* 296 Create a vector to contain the original vertex information for each element 297 */ 298 ierr = VecCreateSeq(PETSC_COMM_SELF, node_data_sz*ncrs, &src_crd);CHKERRQ(ierr); 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 ierr = VecSetValues(src_crd, 1, &jx, &tt, INSERT_VALUES);CHKERRQ(ierr); 306 } 307 } 308 } 309 ierr = VecAssemblyBegin(src_crd);CHKERRQ(ierr); 310 ierr = VecAssemblyEnd(src_crd);CHKERRQ(ierr); 311 /* 312 Scatter the element vertex information (still in the original vertex ordering) 313 to the correct processor 314 */ 315 ierr = VecScatterCreate(src_crd, NULL, dest_crd, isscat, &vecscat);CHKERRQ(ierr); 316 ierr = ISDestroy(&isscat);CHKERRQ(ierr); 317 ierr = VecScatterBegin(vecscat,src_crd,dest_crd,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 318 ierr = VecScatterEnd(vecscat,src_crd,dest_crd,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 319 ierr = VecScatterDestroy(&vecscat);CHKERRQ(ierr); 320 ierr = VecDestroy(&src_crd);CHKERRQ(ierr); 321 /* 322 Put the element vertex data into a new allocation of the gdata->ele 323 */ 324 ierr = PetscFree(pc_gamg->data);CHKERRQ(ierr); 325 ierr = PetscMalloc1(node_data_sz*ncrs_new, &pc_gamg->data);CHKERRQ(ierr); 326 327 pc_gamg->data_sz = node_data_sz*ncrs_new; 328 strideNew = ncrs_new*ndata_rows; 329 330 ierr = VecGetArray(dest_crd, &array);CHKERRQ(ierr); 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 ierr = VecRestoreArray(dest_crd, &array);CHKERRQ(ierr); 340 ierr = VecDestroy(&dest_crd);CHKERRQ(ierr); 341 } 342 /* move A and P (columns) with new layout */ 343 #if defined PETSC_GAMG_USE_LOG 344 ierr = PetscLogEventBegin(petsc_gamg_setup_events[SET13],0,0,0,0);CHKERRQ(ierr); 345 #endif 346 /* 347 Invert for MatCreateSubMatrix 348 */ 349 ierr = ISInvertPermutation(is_eq_num, ncrs_eq_new, &new_eq_indices);CHKERRQ(ierr); 350 ierr = ISSort(new_eq_indices);CHKERRQ(ierr); /* is this needed? */ 351 ierr = ISSetBlockSize(new_eq_indices, cr_bs);CHKERRQ(ierr); 352 if (is_eq_num != is_eq_num_prim) { 353 ierr = ISDestroy(&is_eq_num_prim);CHKERRQ(ierr); /* could be same as 'is_eq_num' */ 354 } 355 if (Pcolumnperm) { 356 ierr = PetscObjectReference((PetscObject)new_eq_indices);CHKERRQ(ierr); 357 *Pcolumnperm = new_eq_indices; 358 } 359 ierr = ISDestroy(&is_eq_num);CHKERRQ(ierr); 360 #if defined PETSC_GAMG_USE_LOG 361 ierr = PetscLogEventEnd(petsc_gamg_setup_events[SET13],0,0,0,0);CHKERRQ(ierr); 362 ierr = PetscLogEventBegin(petsc_gamg_setup_events[SET14],0,0,0,0);CHKERRQ(ierr); 363 #endif 364 /* 'a_Amat_crs' output */ 365 { 366 Mat mat; 367 ierr = MatCreateSubMatrix(Cmat, new_eq_indices, new_eq_indices, MAT_INITIAL_MATRIX, &mat);CHKERRQ(ierr); 368 *a_Amat_crs = mat; 369 } 370 ierr = MatDestroy(&Cmat);CHKERRQ(ierr); 371 372 #if defined PETSC_GAMG_USE_LOG 373 ierr = PetscLogEventEnd(petsc_gamg_setup_events[SET14],0,0,0,0);CHKERRQ(ierr); 374 #endif 375 /* prolongator */ 376 { 377 IS findices; 378 PetscInt Istart,Iend; 379 Mat Pnew; 380 381 ierr = MatGetOwnershipRange(Pold, &Istart, &Iend);CHKERRQ(ierr); 382 #if defined PETSC_GAMG_USE_LOG 383 ierr = PetscLogEventBegin(petsc_gamg_setup_events[SET15],0,0,0,0);CHKERRQ(ierr); 384 #endif 385 ierr = ISCreateStride(comm,Iend-Istart,Istart,1,&findices);CHKERRQ(ierr); 386 ierr = ISSetBlockSize(findices,f_bs);CHKERRQ(ierr); 387 ierr = MatCreateSubMatrix(Pold, findices, new_eq_indices, MAT_INITIAL_MATRIX, &Pnew);CHKERRQ(ierr); 388 ierr = ISDestroy(&findices);CHKERRQ(ierr); 389 390 #if defined PETSC_GAMG_USE_LOG 391 ierr = PetscLogEventEnd(petsc_gamg_setup_events[SET15],0,0,0,0);CHKERRQ(ierr); 392 #endif 393 ierr = MatDestroy(a_P_inout);CHKERRQ(ierr); 394 395 /* output - repartitioned */ 396 *a_P_inout = Pnew; 397 } 398 ierr = ISDestroy(&new_eq_indices);CHKERRQ(ierr); 399 400 *a_nactive_proc = new_size; /* output */ 401 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 ierr = PetscInfo1(pc,"Pinning level %D to the CPU\n",llev++);CHKERRQ(ierr); 407 #endif 408 ierr = MatBindToCPU(*a_Amat_crs,PETSC_TRUE);CHKERRQ(ierr); 409 ierr = MatBindToCPU(*a_P_inout,PETSC_TRUE);CHKERRQ(ierr); 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 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRQ(ierr); 414 if (size > 1) { 415 Mat_MPIAIJ *a = (Mat_MPIAIJ*)A->data, *p = (Mat_MPIAIJ*)P->data; 416 ierr = VecBindToCPU(a->lvec,PETSC_TRUE);CHKERRQ(ierr); 417 ierr = VecBindToCPU(p->lvec,PETSC_TRUE);CHKERRQ(ierr); 418 } 419 } 420 } 421 #if defined PETSC_GAMG_USE_LOG 422 ierr = PetscLogEventEnd(petsc_gamg_setup_events[SET12],0,0,0,0);CHKERRQ(ierr); 423 #endif 424 } 425 PetscFunctionReturn(0); 426 } 427 428 PetscErrorCode PCGAMGSquareGraph_GAMG(PC a_pc, Mat Gmat1, Mat* Gmat2) 429 { 430 PetscErrorCode ierr; 431 const char *prefix; 432 char addp[32]; 433 PC_MG *mg = (PC_MG*)a_pc->data; 434 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 435 436 PetscFunctionBegin; 437 ierr = PCGetOptionsPrefix(a_pc,&prefix);CHKERRQ(ierr); 438 ierr = PetscInfo1(a_pc,"Square Graph on level %D\n",pc_gamg->current_level+1);CHKERRQ(ierr); 439 ierr = MatProductCreate(Gmat1,Gmat1,NULL,Gmat2);CHKERRQ(ierr); 440 ierr = MatSetOptionsPrefix(*Gmat2,prefix);CHKERRQ(ierr); 441 ierr = PetscSNPrintf(addp,sizeof(addp),"pc_gamg_square_%d_",pc_gamg->current_level);CHKERRQ(ierr); 442 ierr = MatAppendOptionsPrefix(*Gmat2,addp);CHKERRQ(ierr); 443 ierr = MatProductSetType(*Gmat2,MATPRODUCT_AtB);CHKERRQ(ierr); 444 ierr = MatProductSetFromOptions(*Gmat2);CHKERRQ(ierr); 445 ierr = MatProductSymbolic(*Gmat2);CHKERRQ(ierr); 446 /* we only need the sparsity, cheat and tell PETSc the matrix has been assembled */ 447 (*Gmat2)->assembled = PETSC_TRUE; 448 PetscFunctionReturn(0); 449 } 450 451 /* -------------------------------------------------------------------------- */ 452 /* 453 PCSetUp_GAMG - Prepares for the use of the GAMG preconditioner 454 by setting data structures and options. 455 456 Input Parameter: 457 . pc - the preconditioner context 458 459 */ 460 PetscErrorCode PCSetUp_GAMG(PC pc) 461 { 462 PetscErrorCode ierr; 463 PC_MG *mg = (PC_MG*)pc->data; 464 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 465 Mat Pmat = pc->pmat; 466 PetscInt fine_level,level,level1,bs,M,N,qq,lidx,nASMBlocksArr[PETSC_MG_MAXLEVELS]; 467 MPI_Comm comm; 468 PetscMPIInt rank,size,nactivepe; 469 Mat Aarr[PETSC_MG_MAXLEVELS],Parr[PETSC_MG_MAXLEVELS]; 470 IS *ASMLocalIDsArr[PETSC_MG_MAXLEVELS]; 471 PetscLogDouble nnz0=0.,nnztot=0.; 472 MatInfo info; 473 PetscBool is_last = PETSC_FALSE; 474 475 PetscFunctionBegin; 476 ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr); 477 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 478 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr); 479 480 if (pc_gamg->setup_count++ > 0) { 481 if ((PetscBool)(!pc_gamg->reuse_prol)) { 482 /* reset everything */ 483 ierr = PCReset_MG(pc);CHKERRQ(ierr); 484 pc->setupcalled = 0; 485 } else { 486 PC_MG_Levels **mglevels = mg->levels; 487 /* just do Galerkin grids */ 488 Mat B,dA,dB; 489 490 if (!pc->setupcalled) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"PCSetUp() has not been called yet"); 491 if (pc_gamg->Nlevels > 1) { 492 /* currently only handle case where mat and pmat are the same on coarser levels */ 493 ierr = KSPGetOperators(mglevels[pc_gamg->Nlevels-1]->smoothd,&dA,&dB);CHKERRQ(ierr); 494 /* (re)set to get dirty flag */ 495 ierr = KSPSetOperators(mglevels[pc_gamg->Nlevels-1]->smoothd,dA,dB);CHKERRQ(ierr); 496 497 for (level=pc_gamg->Nlevels-2; level>=0; level--) { 498 /* 2nd solve, matrix structure can change from repartitioning or process reduction but don't know if we have process reduction here. Should fix */ 499 if (pc_gamg->setup_count==2 /* && pc_gamg->repart||reduction */) { 500 ierr = PetscInfo2(pc,"new RAP after first solve level %D, %D setup\n",level,pc_gamg->setup_count);CHKERRQ(ierr); 501 ierr = MatPtAP(dB,mglevels[level+1]->interpolate,MAT_INITIAL_MATRIX,2.0,&B);CHKERRQ(ierr); 502 ierr = MatDestroy(&mglevels[level]->A);CHKERRQ(ierr); 503 mglevels[level]->A = B; 504 } else { 505 ierr = PetscInfo2(pc,"RAP after first solve reusing matrix level %D, %D setup\n",level,pc_gamg->setup_count);CHKERRQ(ierr); 506 ierr = KSPGetOperators(mglevels[level]->smoothd,NULL,&B);CHKERRQ(ierr); 507 ierr = MatPtAP(dB,mglevels[level+1]->interpolate,MAT_REUSE_MATRIX,1.0,&B);CHKERRQ(ierr); 508 } 509 ierr = KSPSetOperators(mglevels[level]->smoothd,B,B);CHKERRQ(ierr); 510 dB = B; 511 } 512 } 513 514 ierr = PCSetUp_MG(pc);CHKERRQ(ierr); 515 PetscFunctionReturn(0); 516 } 517 } 518 519 if (!pc_gamg->data) { 520 if (pc_gamg->orig_data) { 521 ierr = MatGetBlockSize(Pmat, &bs);CHKERRQ(ierr); 522 ierr = MatGetLocalSize(Pmat, &qq, NULL);CHKERRQ(ierr); 523 524 pc_gamg->data_sz = (qq/bs)*pc_gamg->orig_data_cell_rows*pc_gamg->orig_data_cell_cols; 525 pc_gamg->data_cell_rows = pc_gamg->orig_data_cell_rows; 526 pc_gamg->data_cell_cols = pc_gamg->orig_data_cell_cols; 527 528 ierr = PetscMalloc1(pc_gamg->data_sz, &pc_gamg->data);CHKERRQ(ierr); 529 for (qq=0; qq<pc_gamg->data_sz; qq++) pc_gamg->data[qq] = pc_gamg->orig_data[qq]; 530 } else { 531 if (!pc_gamg->ops->createdefaultdata) SETERRQ(comm,PETSC_ERR_PLIB,"'createdefaultdata' not set(?) need to support NULL data"); 532 ierr = pc_gamg->ops->createdefaultdata(pc,Pmat);CHKERRQ(ierr); 533 } 534 } 535 536 /* cache original data for reuse */ 537 if (!pc_gamg->orig_data && (PetscBool)(!pc_gamg->reuse_prol)) { 538 ierr = PetscMalloc1(pc_gamg->data_sz, &pc_gamg->orig_data);CHKERRQ(ierr); 539 for (qq=0; qq<pc_gamg->data_sz; qq++) pc_gamg->orig_data[qq] = pc_gamg->data[qq]; 540 pc_gamg->orig_data_cell_rows = pc_gamg->data_cell_rows; 541 pc_gamg->orig_data_cell_cols = pc_gamg->data_cell_cols; 542 } 543 544 /* get basic dims */ 545 ierr = MatGetBlockSize(Pmat, &bs);CHKERRQ(ierr); 546 ierr = MatGetSize(Pmat, &M, &N);CHKERRQ(ierr); 547 548 ierr = MatGetInfo(Pmat,MAT_GLOBAL_SUM,&info);CHKERRQ(ierr); /* global reduction */ 549 nnz0 = info.nz_used; 550 nnztot = info.nz_used; 551 ierr = 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);CHKERRQ(ierr); 552 553 /* Get A_i and R_i */ 554 for (level=0, Aarr[0]=Pmat, nactivepe = size; level < (pc_gamg->Nlevels-1) && (!level || M>pc_gamg->coarse_eq_limit); level++) { 555 pc_gamg->current_level = level; 556 if (level >= PETSC_MG_MAXLEVELS) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Too many levels %D",level); 557 level1 = level + 1; 558 #if defined PETSC_GAMG_USE_LOG 559 ierr = PetscLogEventBegin(petsc_gamg_setup_events[SET1],0,0,0,0);CHKERRQ(ierr); 560 #if (defined GAMG_STAGES) 561 ierr = PetscLogStagePush(gamg_stages[level]);CHKERRQ(ierr); 562 #endif 563 #endif 564 { /* construct prolongator */ 565 Mat Gmat; 566 PetscCoarsenData *agg_lists; 567 Mat Prol11; 568 569 ierr = pc_gamg->ops->graph(pc,Aarr[level], &Gmat);CHKERRQ(ierr); 570 ierr = pc_gamg->ops->coarsen(pc, &Gmat, &agg_lists);CHKERRQ(ierr); 571 ierr = pc_gamg->ops->prolongator(pc,Aarr[level],Gmat,agg_lists,&Prol11);CHKERRQ(ierr); 572 573 /* could have failed to create new level */ 574 if (Prol11) { 575 const char *prefix; 576 char addp[32]; 577 578 /* get new block size of coarse matrices */ 579 ierr = MatGetBlockSizes(Prol11, NULL, &bs);CHKERRQ(ierr); 580 581 if (pc_gamg->ops->optprolongator) { 582 /* smooth */ 583 ierr = pc_gamg->ops->optprolongator(pc, Aarr[level], &Prol11);CHKERRQ(ierr); 584 } 585 586 if (pc_gamg->use_aggs_in_asm) { 587 PetscInt bs; 588 ierr = MatGetBlockSizes(Prol11, &bs, NULL);CHKERRQ(ierr); 589 ierr = PetscCDGetASMBlocks(agg_lists, bs, Gmat, &nASMBlocksArr[level], &ASMLocalIDsArr[level]);CHKERRQ(ierr); 590 } 591 592 ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr); 593 ierr = MatSetOptionsPrefix(Prol11,prefix);CHKERRQ(ierr); 594 ierr = PetscSNPrintf(addp,sizeof(addp),"pc_gamg_prolongator_%d_",level);CHKERRQ(ierr); 595 ierr = MatAppendOptionsPrefix(Prol11,addp);CHKERRQ(ierr); 596 /* if we reuse the prolongator, then it is better to generate the transpose by default with CUDA 597 Such behaviour can be adapted with -pc_gamg_prolongator_ prefixed options */ 598 #if defined(PETSC_HAVE_CUDA) 599 { 600 PetscBool ismpiaij; 601 602 ierr = PetscObjectBaseTypeCompare((PetscObject)Prol11,MATMPIAIJ,&ismpiaij);CHKERRQ(ierr); 603 if (ismpiaij) { 604 Mat Prol_d,Prol_o; 605 606 ierr = MatMPIAIJGetSeqAIJ(Prol11,&Prol_d,&Prol_o,NULL);CHKERRQ(ierr); 607 ierr = MatSeqAIJCUSPARSESetGenerateTranspose(Prol_d,pc_gamg->reuse_prol);CHKERRQ(ierr); 608 ierr = MatSeqAIJCUSPARSESetGenerateTranspose(Prol_o,pc_gamg->reuse_prol);CHKERRQ(ierr); 609 } else { 610 ierr = MatSeqAIJCUSPARSESetGenerateTranspose(Prol11,pc_gamg->reuse_prol);CHKERRQ(ierr); 611 } 612 } 613 #endif 614 ierr = MatSetFromOptions(Prol11);CHKERRQ(ierr); 615 Parr[level1] = Prol11; 616 } else Parr[level1] = NULL; /* failed to coarsen */ 617 618 ierr = MatDestroy(&Gmat);CHKERRQ(ierr); 619 ierr = PetscCDDestroy(agg_lists);CHKERRQ(ierr); 620 } /* construct prolongator scope */ 621 #if defined PETSC_GAMG_USE_LOG 622 ierr = PetscLogEventEnd(petsc_gamg_setup_events[SET1],0,0,0,0);CHKERRQ(ierr); 623 #endif 624 if (!level) Aarr[0] = Pmat; /* use Pmat for finest level setup */ 625 if (!Parr[level1]) { /* failed to coarsen */ 626 ierr = PetscInfo1(pc,"Stop gridding, level %D\n",level);CHKERRQ(ierr); 627 #if defined PETSC_GAMG_USE_LOG && defined GAMG_STAGES 628 ierr = PetscLogStagePop();CHKERRQ(ierr); 629 #endif 630 break; 631 } 632 #if defined PETSC_GAMG_USE_LOG 633 ierr = PetscLogEventBegin(petsc_gamg_setup_events[SET2],0,0,0,0);CHKERRQ(ierr); 634 #endif 635 ierr = MatGetSize(Parr[level1], &M, &N);CHKERRQ(ierr); /* N is next M, a loop test variables */ 636 if (is_last) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Is last ????????"); 637 if (N <= pc_gamg->coarse_eq_limit) is_last = PETSC_TRUE; 638 if (level1 == pc_gamg->Nlevels-1) is_last = PETSC_TRUE; 639 ierr = pc_gamg->ops->createlevel(pc, Aarr[level], bs, &Parr[level1], &Aarr[level1], &nactivepe, NULL, is_last);CHKERRQ(ierr); 640 641 #if defined PETSC_GAMG_USE_LOG 642 ierr = PetscLogEventEnd(petsc_gamg_setup_events[SET2],0,0,0,0);CHKERRQ(ierr); 643 #endif 644 ierr = MatGetSize(Aarr[level1], &M, &N);CHKERRQ(ierr); /* M is loop test variables */ 645 ierr = MatGetInfo(Aarr[level1], MAT_GLOBAL_SUM, &info);CHKERRQ(ierr); 646 nnztot += info.nz_used; 647 ierr = 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);CHKERRQ(ierr); 648 649 #if (defined PETSC_GAMG_USE_LOG && defined GAMG_STAGES) 650 ierr = PetscLogStagePop();CHKERRQ(ierr); 651 #endif 652 /* stop if one node or one proc -- could pull back for singular problems */ 653 if ((pc_gamg->data_cell_cols && M/pc_gamg->data_cell_cols < 2) || (!pc_gamg->data_cell_cols && M/bs < 2)) { 654 ierr = PetscInfo2(pc,"HARD stop of coarsening on level %D. Grid too small: %D block nodes\n",level,M/bs);CHKERRQ(ierr); 655 level++; 656 break; 657 } 658 } /* levels */ 659 ierr = PetscFree(pc_gamg->data);CHKERRQ(ierr); 660 661 ierr = PetscInfo2(pc,"%D levels, grid complexity = %g\n",level+1,nnztot/nnz0);CHKERRQ(ierr); 662 pc_gamg->Nlevels = level + 1; 663 fine_level = level; 664 ierr = PCMGSetLevels(pc,pc_gamg->Nlevels,NULL);CHKERRQ(ierr); 665 666 if (pc_gamg->Nlevels > 1) { /* don't setup MG if one level */ 667 PetscErrorCode (*savesetfromoptions[PETSC_MG_MAXLEVELS])(PetscOptionItems*,KSP); 668 669 /* set default smoothers & set operators */ 670 for (lidx = 1, level = pc_gamg->Nlevels-2; lidx <= fine_level; lidx++, level--) { 671 KSP smoother; 672 PC subpc; 673 674 ierr = PCMGGetSmoother(pc, lidx, &smoother);CHKERRQ(ierr); 675 ierr = KSPGetPC(smoother, &subpc);CHKERRQ(ierr); 676 677 ierr = KSPSetNormType(smoother, KSP_NORM_NONE);CHKERRQ(ierr); 678 /* set ops */ 679 ierr = KSPSetOperators(smoother, Aarr[level], Aarr[level]);CHKERRQ(ierr); 680 ierr = PCMGSetInterpolation(pc, lidx, Parr[level+1]);CHKERRQ(ierr); 681 682 /* set defaults */ 683 ierr = KSPSetType(smoother, KSPCHEBYSHEV);CHKERRQ(ierr); 684 685 /* set blocks for ASM smoother that uses the 'aggregates' */ 686 if (pc_gamg->use_aggs_in_asm) { 687 PetscInt sz; 688 IS *iss; 689 690 sz = nASMBlocksArr[level]; 691 iss = ASMLocalIDsArr[level]; 692 ierr = PCSetType(subpc, PCASM);CHKERRQ(ierr); 693 ierr = PCASMSetOverlap(subpc, 0);CHKERRQ(ierr); 694 ierr = PCASMSetType(subpc,PC_ASM_BASIC);CHKERRQ(ierr); 695 if (!sz) { 696 IS is; 697 ierr = ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_COPY_VALUES, &is);CHKERRQ(ierr); 698 ierr = PCASMSetLocalSubdomains(subpc, 1, NULL, &is);CHKERRQ(ierr); 699 ierr = ISDestroy(&is);CHKERRQ(ierr); 700 } else { 701 PetscInt kk; 702 ierr = PCASMSetLocalSubdomains(subpc, sz, NULL, iss);CHKERRQ(ierr); 703 for (kk=0; kk<sz; kk++) { 704 ierr = ISDestroy(&iss[kk]);CHKERRQ(ierr); 705 } 706 ierr = PetscFree(iss);CHKERRQ(ierr); 707 } 708 ASMLocalIDsArr[level] = NULL; 709 nASMBlocksArr[level] = 0; 710 } else { 711 ierr = PCSetType(subpc, PCSOR);CHKERRQ(ierr); 712 } 713 } 714 { 715 /* coarse grid */ 716 KSP smoother,*k2; PC subpc,pc2; PetscInt ii,first; 717 Mat Lmat = Aarr[(level=pc_gamg->Nlevels-1)]; lidx = 0; 718 719 ierr = PCMGGetSmoother(pc, lidx, &smoother);CHKERRQ(ierr); 720 ierr = KSPSetOperators(smoother, Lmat, Lmat);CHKERRQ(ierr); 721 if (!pc_gamg->use_parallel_coarse_grid_solver) { 722 ierr = KSPSetNormType(smoother, KSP_NORM_NONE);CHKERRQ(ierr); 723 ierr = KSPGetPC(smoother, &subpc);CHKERRQ(ierr); 724 ierr = PCSetType(subpc, PCBJACOBI);CHKERRQ(ierr); 725 ierr = PCSetUp(subpc);CHKERRQ(ierr); 726 ierr = PCBJacobiGetSubKSP(subpc,&ii,&first,&k2);CHKERRQ(ierr); 727 if (ii != 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"ii %D is not one",ii); 728 ierr = KSPGetPC(k2[0],&pc2);CHKERRQ(ierr); 729 ierr = PCSetType(pc2, PCLU);CHKERRQ(ierr); 730 ierr = PCFactorSetShiftType(pc2,MAT_SHIFT_INBLOCKS);CHKERRQ(ierr); 731 ierr = KSPSetTolerances(k2[0],PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,1);CHKERRQ(ierr); 732 ierr = KSPSetType(k2[0], KSPPREONLY);CHKERRQ(ierr); 733 /* This flag gets reset by PCBJacobiGetSubKSP(), but our BJacobi really does the same algorithm everywhere (and in 734 * fact, all but one process will have zero dofs), so we reset the flag to avoid having PCView_BJacobi attempt to 735 * view every subdomain as though they were different. */ 736 ((PC_BJacobi*)subpc->data)->same_local_solves = PETSC_TRUE; 737 } 738 } 739 740 /* should be called in PCSetFromOptions_GAMG(), but cannot be called prior to PCMGSetLevels() */ 741 ierr = PetscObjectOptionsBegin((PetscObject)pc);CHKERRQ(ierr); 742 ierr = PCSetFromOptions_MG(PetscOptionsObject,pc);CHKERRQ(ierr); 743 ierr = PetscOptionsEnd();CHKERRQ(ierr); 744 ierr = PCMGSetGalerkin(pc,PC_MG_GALERKIN_EXTERNAL);CHKERRQ(ierr); 745 746 /* setup cheby eigen estimates from SA */ 747 if (pc_gamg->use_sa_esteig==1) { 748 for (lidx = 1, level = pc_gamg->Nlevels-2; level >= 0 ; lidx++, level--) { 749 KSP smoother; 750 PetscBool ischeb; 751 752 savesetfromoptions[level] = NULL; 753 ierr = PCMGGetSmoother(pc, lidx, &smoother);CHKERRQ(ierr); 754 ierr = PetscObjectTypeCompare((PetscObject)smoother,KSPCHEBYSHEV,&ischeb);CHKERRQ(ierr); 755 if (ischeb) { 756 KSP_Chebyshev *cheb = (KSP_Chebyshev*)smoother->data; 757 758 ierr = KSPSetFromOptions(smoother);CHKERRQ(ierr); /* let command line emax override using SA's eigenvalues */ 759 if (mg->max_eigen_DinvA[level] > 0 && cheb->emax == 0.) { 760 PC subpc; 761 PetscBool isjac; 762 ierr = KSPGetPC(smoother, &subpc);CHKERRQ(ierr); 763 ierr = PetscObjectTypeCompare((PetscObject)subpc,PCJACOBI,&isjac);CHKERRQ(ierr); 764 if (isjac && pc_gamg->use_sa_esteig==1) { 765 PetscReal emax,emin; 766 767 emin = mg->min_eigen_DinvA[level]; 768 emax = mg->max_eigen_DinvA[level]; 769 ierr = 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);CHKERRQ(ierr); 770 cheb->emin_computed = emin; 771 cheb->emax_computed = emax; 772 ierr = KSPChebyshevSetEigenvalues(smoother, cheb->tform[2]*emin + cheb->tform[3]*emax, cheb->tform[0]*emin + cheb->tform[1]*emax);CHKERRQ(ierr); 773 774 /* We have set the eigenvalues and consumed the transformation values 775 prevent from flagging the recomputation of the eigenvalues again in PCSetUp_MG 776 below when setfromoptions will be called again */ 777 savesetfromoptions[level] = smoother->ops->setfromoptions; 778 smoother->ops->setfromoptions = NULL; 779 } 780 } 781 } 782 } 783 } 784 785 ierr = PCSetUp_MG(pc);CHKERRQ(ierr); 786 787 /* restore Chebyshev smoother for next calls */ 788 if (pc_gamg->use_sa_esteig==1) { 789 for (lidx = 1, level = pc_gamg->Nlevels-2; level >= 0 ; lidx++, level--) { 790 if (savesetfromoptions[level]) { 791 KSP smoother; 792 ierr = PCMGGetSmoother(pc, lidx, &smoother);CHKERRQ(ierr); 793 smoother->ops->setfromoptions = savesetfromoptions[level]; 794 } 795 } 796 } 797 798 /* clean up */ 799 for (level=1; level<pc_gamg->Nlevels; level++) { 800 ierr = MatDestroy(&Parr[level]);CHKERRQ(ierr); 801 ierr = MatDestroy(&Aarr[level]);CHKERRQ(ierr); 802 } 803 } else { 804 KSP smoother; 805 806 ierr = PetscInfo(pc,"One level solver used (system is seen as DD). Using default solver.\n");CHKERRQ(ierr); 807 ierr = PCMGGetSmoother(pc, 0, &smoother);CHKERRQ(ierr); 808 ierr = KSPSetOperators(smoother, Aarr[0], Aarr[0]);CHKERRQ(ierr); 809 ierr = KSPSetType(smoother, KSPPREONLY);CHKERRQ(ierr); 810 ierr = PCSetUp_MG(pc);CHKERRQ(ierr); 811 } 812 PetscFunctionReturn(0); 813 } 814 815 /* ------------------------------------------------------------------------- */ 816 /* 817 PCDestroy_GAMG - Destroys the private context for the GAMG preconditioner 818 that was created with PCCreate_GAMG(). 819 820 Input Parameter: 821 . pc - the preconditioner context 822 823 Application Interface Routine: PCDestroy() 824 */ 825 PetscErrorCode PCDestroy_GAMG(PC pc) 826 { 827 PetscErrorCode ierr; 828 PC_MG *mg = (PC_MG*)pc->data; 829 PC_GAMG *pc_gamg= (PC_GAMG*)mg->innerctx; 830 831 PetscFunctionBegin; 832 ierr = PCReset_GAMG(pc);CHKERRQ(ierr); 833 if (pc_gamg->ops->destroy) { 834 ierr = (*pc_gamg->ops->destroy)(pc);CHKERRQ(ierr); 835 } 836 ierr = PetscFree(pc_gamg->ops);CHKERRQ(ierr); 837 ierr = PetscFree(pc_gamg->gamg_type_name);CHKERRQ(ierr); 838 ierr = PetscFree(pc_gamg);CHKERRQ(ierr); 839 ierr = PCDestroy_MG(pc);CHKERRQ(ierr); 840 PetscFunctionReturn(0); 841 } 842 843 /*@ 844 PCGAMGSetProcEqLim - Set number of equations to aim for per process on the coarse grids via processor reduction. 845 846 Logically Collective on PC 847 848 Input Parameters: 849 + pc - the preconditioner context 850 - n - the number of equations 851 852 853 Options Database Key: 854 . -pc_gamg_process_eq_limit <limit> 855 856 Notes: 857 GAMG will reduce the number of MPI processes used directly on the coarse grids so that there are around <limit> equations on each process 858 that has degrees of freedom 859 860 Level: intermediate 861 862 .seealso: PCGAMGSetCoarseEqLim() 863 @*/ 864 PetscErrorCode PCGAMGSetProcEqLim(PC pc, PetscInt n) 865 { 866 PetscErrorCode ierr; 867 868 PetscFunctionBegin; 869 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 870 ierr = PetscTryMethod(pc,"PCGAMGSetProcEqLim_C",(PC,PetscInt),(pc,n));CHKERRQ(ierr); 871 PetscFunctionReturn(0); 872 } 873 874 static PetscErrorCode PCGAMGSetProcEqLim_GAMG(PC pc, PetscInt n) 875 { 876 PC_MG *mg = (PC_MG*)pc->data; 877 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 878 879 PetscFunctionBegin; 880 if (n>0) pc_gamg->min_eq_proc = n; 881 PetscFunctionReturn(0); 882 } 883 884 /*@ 885 PCGAMGSetCoarseEqLim - Set maximum number of equations on coarsest grid. 886 887 Collective on PC 888 889 Input Parameters: 890 + pc - the preconditioner context 891 - n - maximum number of equations to aim for 892 893 Options Database Key: 894 . -pc_gamg_coarse_eq_limit <limit> 895 896 Notes: For example -pc_gamg_coarse_eq_limit 1000 will stop coarsening once the coarse grid 897 has less than 1000 unknowns. 898 899 Level: intermediate 900 901 .seealso: PCGAMGSetProcEqLim() 902 @*/ 903 PetscErrorCode PCGAMGSetCoarseEqLim(PC pc, PetscInt n) 904 { 905 PetscErrorCode ierr; 906 907 PetscFunctionBegin; 908 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 909 ierr = PetscTryMethod(pc,"PCGAMGSetCoarseEqLim_C",(PC,PetscInt),(pc,n));CHKERRQ(ierr); 910 PetscFunctionReturn(0); 911 } 912 913 static PetscErrorCode PCGAMGSetCoarseEqLim_GAMG(PC pc, PetscInt n) 914 { 915 PC_MG *mg = (PC_MG*)pc->data; 916 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 917 918 PetscFunctionBegin; 919 if (n>0) pc_gamg->coarse_eq_limit = n; 920 PetscFunctionReturn(0); 921 } 922 923 /*@ 924 PCGAMGSetRepartition - Repartition the degrees of freedom across the processors on the coarser grids 925 926 Collective on PC 927 928 Input Parameters: 929 + pc - the preconditioner context 930 - n - PETSC_TRUE or PETSC_FALSE 931 932 Options Database Key: 933 . -pc_gamg_repartition <true,false> 934 935 Notes: 936 this will generally improve the loading balancing of the work on each level 937 938 Level: intermediate 939 940 .seealso: () 941 @*/ 942 PetscErrorCode PCGAMGSetRepartition(PC pc, PetscBool n) 943 { 944 PetscErrorCode ierr; 945 946 PetscFunctionBegin; 947 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 948 ierr = PetscTryMethod(pc,"PCGAMGSetRepartition_C",(PC,PetscBool),(pc,n));CHKERRQ(ierr); 949 PetscFunctionReturn(0); 950 } 951 952 static PetscErrorCode PCGAMGSetRepartition_GAMG(PC pc, PetscBool n) 953 { 954 PC_MG *mg = (PC_MG*)pc->data; 955 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 956 957 PetscFunctionBegin; 958 pc_gamg->repart = n; 959 PetscFunctionReturn(0); 960 } 961 962 /*@ 963 PCGAMGSetEstEigKSPMaxIt - Set number of KSP iterations in eigen estimator (for Cheby) 964 965 Collective on PC 966 967 Input Parameters: 968 + pc - the preconditioner context 969 - n - number of its 970 971 Options Database Key: 972 . -pc_gamg_esteig_ksp_max_it <its> 973 974 Notes: 975 976 Level: intermediate 977 978 .seealso: () 979 @*/ 980 PetscErrorCode PCGAMGSetEstEigKSPMaxIt(PC pc, PetscInt n) 981 { 982 PetscErrorCode ierr; 983 984 PetscFunctionBegin; 985 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 986 ierr = PetscTryMethod(pc,"PCGAMGSetEstEigKSPMaxIt_C",(PC,PetscInt),(pc,n));CHKERRQ(ierr); 987 PetscFunctionReturn(0); 988 } 989 990 static PetscErrorCode PCGAMGSetEstEigKSPMaxIt_GAMG(PC pc, PetscInt n) 991 { 992 PC_MG *mg = (PC_MG*)pc->data; 993 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 994 995 PetscFunctionBegin; 996 pc_gamg->esteig_max_it = n; 997 PetscFunctionReturn(0); 998 } 999 1000 /*@ 1001 PCGAMGSetUseSAEstEig - Use eigen estimate from smoothed aggregation for Cheby smoother 1002 1003 Collective on PC 1004 1005 Input Parameters: 1006 + pc - the preconditioner context 1007 - n - number of its 1008 1009 Options Database Key: 1010 . -pc_gamg_use_sa_esteig <true,false> 1011 1012 Notes: 1013 1014 Level: intermediate 1015 1016 .seealso: () 1017 @*/ 1018 PetscErrorCode PCGAMGSetUseSAEstEig(PC pc, PetscBool n) 1019 { 1020 PetscErrorCode ierr; 1021 1022 PetscFunctionBegin; 1023 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1024 ierr = PetscTryMethod(pc,"PCGAMGSetUseSAEstEig_C",(PC,PetscBool),(pc,n));CHKERRQ(ierr); 1025 PetscFunctionReturn(0); 1026 } 1027 1028 static PetscErrorCode PCGAMGSetUseSAEstEig_GAMG(PC pc, PetscBool n) 1029 { 1030 PC_MG *mg = (PC_MG*)pc->data; 1031 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1032 1033 PetscFunctionBegin; 1034 pc_gamg->use_sa_esteig = n ? 1 : 0; 1035 PetscFunctionReturn(0); 1036 } 1037 1038 /*@C 1039 PCGAMGSetEstEigKSPType - Set type of KSP in eigen estimator (for Cheby) 1040 1041 Collective on PC 1042 1043 Input Parameters: 1044 + pc - the preconditioner context 1045 - t - ksp type 1046 1047 Options Database Key: 1048 . -pc_gamg_esteig_ksp_type <type> 1049 1050 Notes: 1051 1052 Level: intermediate 1053 1054 .seealso: () 1055 @*/ 1056 PetscErrorCode PCGAMGSetEstEigKSPType(PC pc, char t[]) 1057 { 1058 PetscErrorCode ierr; 1059 1060 PetscFunctionBegin; 1061 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1062 ierr = PetscTryMethod(pc,"PCGAMGSetEstEigKSPType_C",(PC,char[]),(pc,t));CHKERRQ(ierr); 1063 PetscFunctionReturn(0); 1064 } 1065 1066 static PetscErrorCode PCGAMGSetEstEigKSPType_GAMG(PC pc, char t[]) 1067 { 1068 PetscErrorCode ierr; 1069 PC_MG *mg = (PC_MG*)pc->data; 1070 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1071 1072 PetscFunctionBegin; 1073 ierr = PetscStrcpy(pc_gamg->esteig_type,t);CHKERRQ(ierr); 1074 PetscFunctionReturn(0); 1075 } 1076 1077 /*@ 1078 PCGAMGSetEigenvalues - Set eigenvalues 1079 1080 Collective on PC 1081 1082 Input Parameters: 1083 + pc - the preconditioner context 1084 - emax - max eigenvalue 1085 . emin - min eigenvalue 1086 1087 Options Database Key: 1088 . -pc_gamg_eigenvalues 1089 1090 Level: intermediate 1091 1092 .seealso: PCGAMGSetEstEigKSPMaxIt(), PCGAMGSetUseSAEstEig(), PCGAMGSetEstEigKSPType() 1093 @*/ 1094 PetscErrorCode PCGAMGSetEigenvalues(PC pc, PetscReal emax,PetscReal emin) 1095 { 1096 PetscErrorCode ierr; 1097 1098 PetscFunctionBegin; 1099 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1100 ierr = PetscTryMethod(pc,"PCGAMGSetEigenvalues_C",(PC,PetscReal,PetscReal),(pc,emax,emin));CHKERRQ(ierr); 1101 PetscFunctionReturn(0); 1102 } 1103 static PetscErrorCode PCGAMGSetEigenvalues_GAMG(PC pc,PetscReal emax,PetscReal emin) 1104 { 1105 PC_MG *mg = (PC_MG*)pc->data; 1106 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1107 1108 PetscFunctionBegin; 1109 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); 1110 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); 1111 pc_gamg->emax = emax; 1112 pc_gamg->emin = emin; 1113 1114 PetscFunctionReturn(0); 1115 } 1116 1117 /*@ 1118 PCGAMGSetReuseInterpolation - Reuse prolongation when rebuilding algebraic multigrid preconditioner 1119 1120 Collective on PC 1121 1122 Input Parameters: 1123 + pc - the preconditioner context 1124 - n - PETSC_TRUE or PETSC_FALSE 1125 1126 Options Database Key: 1127 . -pc_gamg_reuse_interpolation <true,false> 1128 1129 Level: intermediate 1130 1131 Notes: 1132 this may negatively affect the convergence rate of the method on new matrices if the matrix entries change a great deal, but allows 1133 rebuilding the preconditioner quicker. 1134 1135 .seealso: () 1136 @*/ 1137 PetscErrorCode PCGAMGSetReuseInterpolation(PC pc, PetscBool n) 1138 { 1139 PetscErrorCode ierr; 1140 1141 PetscFunctionBegin; 1142 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1143 ierr = PetscTryMethod(pc,"PCGAMGSetReuseInterpolation_C",(PC,PetscBool),(pc,n));CHKERRQ(ierr); 1144 PetscFunctionReturn(0); 1145 } 1146 1147 static PetscErrorCode PCGAMGSetReuseInterpolation_GAMG(PC pc, PetscBool n) 1148 { 1149 PC_MG *mg = (PC_MG*)pc->data; 1150 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1151 1152 PetscFunctionBegin; 1153 pc_gamg->reuse_prol = n; 1154 PetscFunctionReturn(0); 1155 } 1156 1157 /*@ 1158 PCGAMGASMSetUseAggs - Have the PCGAMG smoother on each level use the aggregates defined by the coarsening process as the subdomains for the additive Schwarz preconditioner. 1159 1160 Collective on PC 1161 1162 Input Parameters: 1163 + pc - the preconditioner context 1164 - flg - PETSC_TRUE to use aggregates, PETSC_FALSE to not 1165 1166 Options Database Key: 1167 . -pc_gamg_asm_use_agg 1168 1169 Level: intermediate 1170 1171 .seealso: () 1172 @*/ 1173 PetscErrorCode PCGAMGASMSetUseAggs(PC pc, PetscBool flg) 1174 { 1175 PetscErrorCode ierr; 1176 1177 PetscFunctionBegin; 1178 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1179 ierr = PetscTryMethod(pc,"PCGAMGASMSetUseAggs_C",(PC,PetscBool),(pc,flg));CHKERRQ(ierr); 1180 PetscFunctionReturn(0); 1181 } 1182 1183 static PetscErrorCode PCGAMGASMSetUseAggs_GAMG(PC pc, PetscBool flg) 1184 { 1185 PC_MG *mg = (PC_MG*)pc->data; 1186 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1187 1188 PetscFunctionBegin; 1189 pc_gamg->use_aggs_in_asm = flg; 1190 PetscFunctionReturn(0); 1191 } 1192 1193 /*@ 1194 PCGAMGSetUseParallelCoarseGridSolve - allow a parallel coarse grid solver 1195 1196 Collective on PC 1197 1198 Input Parameters: 1199 + pc - the preconditioner context 1200 - flg - PETSC_TRUE to not force coarse grid onto one processor 1201 1202 Options Database Key: 1203 . -pc_gamg_use_parallel_coarse_grid_solver 1204 1205 Level: intermediate 1206 1207 .seealso: PCGAMGSetCoarseGridLayoutType(), PCGAMGSetCpuPinCoarseGrids() 1208 @*/ 1209 PetscErrorCode PCGAMGSetUseParallelCoarseGridSolve(PC pc, PetscBool flg) 1210 { 1211 PetscErrorCode ierr; 1212 1213 PetscFunctionBegin; 1214 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1215 ierr = PetscTryMethod(pc,"PCGAMGSetUseParallelCoarseGridSolve_C",(PC,PetscBool),(pc,flg));CHKERRQ(ierr); 1216 PetscFunctionReturn(0); 1217 } 1218 1219 static PetscErrorCode PCGAMGSetUseParallelCoarseGridSolve_GAMG(PC pc, PetscBool flg) 1220 { 1221 PC_MG *mg = (PC_MG*)pc->data; 1222 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1223 1224 PetscFunctionBegin; 1225 pc_gamg->use_parallel_coarse_grid_solver = flg; 1226 PetscFunctionReturn(0); 1227 } 1228 1229 /*@ 1230 PCGAMGSetCpuPinCoarseGrids - pin reduced grids to CPU 1231 1232 Collective on PC 1233 1234 Input Parameters: 1235 + pc - the preconditioner context 1236 - flg - PETSC_TRUE to pin coarse grids to CPU 1237 1238 Options Database Key: 1239 . -pc_gamg_cpu_pin_coarse_grids 1240 1241 Level: intermediate 1242 1243 .seealso: PCGAMGSetCoarseGridLayoutType(), PCGAMGSetUseParallelCoarseGridSolve() 1244 @*/ 1245 PetscErrorCode PCGAMGSetCpuPinCoarseGrids(PC pc, PetscBool flg) 1246 { 1247 PetscErrorCode ierr; 1248 1249 PetscFunctionBegin; 1250 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1251 ierr = PetscTryMethod(pc,"PCGAMGSetCpuPinCoarseGrids_C",(PC,PetscBool),(pc,flg));CHKERRQ(ierr); 1252 PetscFunctionReturn(0); 1253 } 1254 1255 static PetscErrorCode PCGAMGSetCpuPinCoarseGrids_GAMG(PC pc, PetscBool flg) 1256 { 1257 PC_MG *mg = (PC_MG*)pc->data; 1258 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1259 1260 PetscFunctionBegin; 1261 pc_gamg->cpu_pin_coarse_grids = flg; 1262 PetscFunctionReturn(0); 1263 } 1264 1265 /*@ 1266 PCGAMGSetCoarseGridLayoutType - place reduce grids on processors with natural order (compact type) 1267 1268 Collective on PC 1269 1270 Input Parameters: 1271 + pc - the preconditioner context 1272 - flg - Layout type 1273 1274 Options Database Key: 1275 . -pc_gamg_coarse_grid_layout_type 1276 1277 Level: intermediate 1278 1279 .seealso: PCGAMGSetUseParallelCoarseGridSolve(), PCGAMGSetCpuPinCoarseGrids() 1280 @*/ 1281 PetscErrorCode PCGAMGSetCoarseGridLayoutType(PC pc, PCGAMGLayoutType flg) 1282 { 1283 PetscErrorCode ierr; 1284 1285 PetscFunctionBegin; 1286 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1287 ierr = PetscTryMethod(pc,"PCGAMGSetCoarseGridLayoutType_C",(PC,PCGAMGLayoutType),(pc,flg));CHKERRQ(ierr); 1288 PetscFunctionReturn(0); 1289 } 1290 1291 static PetscErrorCode PCGAMGSetCoarseGridLayoutType_GAMG(PC pc, PCGAMGLayoutType flg) 1292 { 1293 PC_MG *mg = (PC_MG*)pc->data; 1294 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1295 1296 PetscFunctionBegin; 1297 pc_gamg->layout_type = flg; 1298 PetscFunctionReturn(0); 1299 } 1300 1301 /*@ 1302 PCGAMGSetNlevels - Sets the maximum number of levels PCGAMG will use 1303 1304 Not collective on PC 1305 1306 Input Parameters: 1307 + pc - the preconditioner 1308 - n - the maximum number of levels to use 1309 1310 Options Database Key: 1311 . -pc_mg_levels 1312 1313 Level: intermediate 1314 1315 .seealso: () 1316 @*/ 1317 PetscErrorCode PCGAMGSetNlevels(PC pc, PetscInt n) 1318 { 1319 PetscErrorCode ierr; 1320 1321 PetscFunctionBegin; 1322 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1323 ierr = PetscTryMethod(pc,"PCGAMGSetNlevels_C",(PC,PetscInt),(pc,n));CHKERRQ(ierr); 1324 PetscFunctionReturn(0); 1325 } 1326 1327 static PetscErrorCode PCGAMGSetNlevels_GAMG(PC pc, PetscInt n) 1328 { 1329 PC_MG *mg = (PC_MG*)pc->data; 1330 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1331 1332 PetscFunctionBegin; 1333 pc_gamg->Nlevels = n; 1334 PetscFunctionReturn(0); 1335 } 1336 1337 /*@ 1338 PCGAMGSetThreshold - Relative threshold to use for dropping edges in aggregation graph 1339 1340 Not collective on PC 1341 1342 Input Parameters: 1343 + pc - the preconditioner context 1344 . threshold - 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 1345 - n - number of threshold values provided in array 1346 1347 Options Database Key: 1348 . -pc_gamg_threshold <threshold> 1349 1350 Notes: 1351 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. 1352 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. 1353 1354 If n is less than the total number of coarsenings (see PCGAMGSetNlevels()), then threshold scaling (see PCGAMGSetThresholdScale()) is used for each successive coarsening. 1355 In this case, PCGAMGSetThresholdScale() must be called before PCGAMGSetThreshold(). 1356 If n is greater than the total number of levels, the excess entries in threshold will not be used. 1357 1358 Level: intermediate 1359 1360 .seealso: PCGAMGFilterGraph(), PCGAMGSetSquareGraph() 1361 @*/ 1362 PetscErrorCode PCGAMGSetThreshold(PC pc, PetscReal v[], PetscInt n) 1363 { 1364 PetscErrorCode ierr; 1365 1366 PetscFunctionBegin; 1367 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1368 if (n) PetscValidRealPointer(v,2); 1369 ierr = PetscTryMethod(pc,"PCGAMGSetThreshold_C",(PC,PetscReal[],PetscInt),(pc,v,n));CHKERRQ(ierr); 1370 PetscFunctionReturn(0); 1371 } 1372 1373 static PetscErrorCode PCGAMGSetThreshold_GAMG(PC pc, PetscReal v[], PetscInt n) 1374 { 1375 PC_MG *mg = (PC_MG*)pc->data; 1376 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1377 PetscInt i; 1378 PetscFunctionBegin; 1379 for (i=0; i<PetscMin(n,PETSC_MG_MAXLEVELS); i++) pc_gamg->threshold[i] = v[i]; 1380 for (; i<PETSC_MG_MAXLEVELS; i++) pc_gamg->threshold[i] = pc_gamg->threshold[i-1]*pc_gamg->threshold_scale; 1381 PetscFunctionReturn(0); 1382 } 1383 1384 /*@ 1385 PCGAMGSetThresholdScale - Relative threshold reduction at each level 1386 1387 Not collective on PC 1388 1389 Input Parameters: 1390 + pc - the preconditioner context 1391 - scale - the threshold value reduction, ussually < 1.0 1392 1393 Options Database Key: 1394 . -pc_gamg_threshold_scale <v> 1395 1396 Notes: 1397 The initial threshold (for an arbitrary number of levels starting from the finest) can be set with PCGAMGSetThreshold(). 1398 This scaling is used for each subsequent coarsening, but must be called before PCGAMGSetThreshold(). 1399 1400 Level: advanced 1401 1402 .seealso: PCGAMGSetThreshold() 1403 @*/ 1404 PetscErrorCode PCGAMGSetThresholdScale(PC pc, PetscReal v) 1405 { 1406 PetscErrorCode ierr; 1407 1408 PetscFunctionBegin; 1409 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1410 ierr = PetscTryMethod(pc,"PCGAMGSetThresholdScale_C",(PC,PetscReal),(pc,v));CHKERRQ(ierr); 1411 PetscFunctionReturn(0); 1412 } 1413 1414 static PetscErrorCode PCGAMGSetThresholdScale_GAMG(PC pc, PetscReal v) 1415 { 1416 PC_MG *mg = (PC_MG*)pc->data; 1417 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1418 PetscFunctionBegin; 1419 pc_gamg->threshold_scale = v; 1420 PetscFunctionReturn(0); 1421 } 1422 1423 /*@C 1424 PCGAMGSetType - Set solution method 1425 1426 Collective on PC 1427 1428 Input Parameters: 1429 + pc - the preconditioner context 1430 - type - PCGAMGAGG, PCGAMGGEO, or PCGAMGCLASSICAL 1431 1432 Options Database Key: 1433 . -pc_gamg_type <agg,geo,classical> - type of algebraic multigrid to apply 1434 1435 Level: intermediate 1436 1437 .seealso: PCGAMGGetType(), PCGAMG, PCGAMGType 1438 @*/ 1439 PetscErrorCode PCGAMGSetType(PC pc, PCGAMGType type) 1440 { 1441 PetscErrorCode ierr; 1442 1443 PetscFunctionBegin; 1444 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1445 ierr = PetscTryMethod(pc,"PCGAMGSetType_C",(PC,PCGAMGType),(pc,type));CHKERRQ(ierr); 1446 PetscFunctionReturn(0); 1447 } 1448 1449 /*@C 1450 PCGAMGGetType - Get solution method 1451 1452 Collective on PC 1453 1454 Input Parameter: 1455 . pc - the preconditioner context 1456 1457 Output Parameter: 1458 . type - the type of algorithm used 1459 1460 Level: intermediate 1461 1462 .seealso: PCGAMGSetType(), PCGAMGType 1463 @*/ 1464 PetscErrorCode PCGAMGGetType(PC pc, PCGAMGType *type) 1465 { 1466 PetscErrorCode ierr; 1467 1468 PetscFunctionBegin; 1469 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1470 ierr = PetscUseMethod(pc,"PCGAMGGetType_C",(PC,PCGAMGType*),(pc,type));CHKERRQ(ierr); 1471 PetscFunctionReturn(0); 1472 } 1473 1474 static PetscErrorCode PCGAMGGetType_GAMG(PC pc, PCGAMGType *type) 1475 { 1476 PC_MG *mg = (PC_MG*)pc->data; 1477 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1478 1479 PetscFunctionBegin; 1480 *type = pc_gamg->type; 1481 PetscFunctionReturn(0); 1482 } 1483 1484 static PetscErrorCode PCGAMGSetType_GAMG(PC pc, PCGAMGType type) 1485 { 1486 PetscErrorCode ierr,(*r)(PC); 1487 PC_MG *mg = (PC_MG*)pc->data; 1488 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1489 1490 PetscFunctionBegin; 1491 pc_gamg->type = type; 1492 ierr = PetscFunctionListFind(GAMGList,type,&r);CHKERRQ(ierr); 1493 if (!r) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown GAMG type %s given",type); 1494 if (pc_gamg->ops->destroy) { 1495 ierr = (*pc_gamg->ops->destroy)(pc);CHKERRQ(ierr); 1496 ierr = PetscMemzero(pc_gamg->ops,sizeof(struct _PCGAMGOps));CHKERRQ(ierr); 1497 pc_gamg->ops->createlevel = PCGAMGCreateLevel_GAMG; 1498 /* cleaning up common data in pc_gamg - this should disapear someday */ 1499 pc_gamg->data_cell_cols = 0; 1500 pc_gamg->data_cell_rows = 0; 1501 pc_gamg->orig_data_cell_cols = 0; 1502 pc_gamg->orig_data_cell_rows = 0; 1503 ierr = PetscFree(pc_gamg->data);CHKERRQ(ierr); 1504 pc_gamg->data_sz = 0; 1505 } 1506 ierr = PetscFree(pc_gamg->gamg_type_name);CHKERRQ(ierr); 1507 ierr = PetscStrallocpy(type,&pc_gamg->gamg_type_name);CHKERRQ(ierr); 1508 ierr = (*r)(pc);CHKERRQ(ierr); 1509 PetscFunctionReturn(0); 1510 } 1511 1512 /* -------------------------------------------------------------------------- */ 1513 /* 1514 PCMGGetGridComplexity - compute coarse grid complexity of MG hierarchy 1515 1516 Input Parameter: 1517 . pc - the preconditioner context 1518 1519 Output Parameter: 1520 . gc - grid complexity = sum_i(nnz_i) / nnz_0 1521 1522 Level: advanced 1523 */ 1524 static PetscErrorCode PCMGGetGridComplexity(PC pc, PetscReal *gc) 1525 { 1526 PetscErrorCode ierr; 1527 PC_MG *mg = (PC_MG*)pc->data; 1528 PC_MG_Levels **mglevels = mg->levels; 1529 PetscInt lev; 1530 PetscLogDouble nnz0 = 0, sgc = 0; 1531 MatInfo info; 1532 1533 PetscFunctionBegin; 1534 if (!pc->setupcalled) { 1535 *gc = 0; 1536 PetscFunctionReturn(0); 1537 } 1538 if (!mg->nlevels) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"MG has no levels"); 1539 for (lev=0; lev<mg->nlevels; lev++) { 1540 Mat dB; 1541 ierr = KSPGetOperators(mglevels[lev]->smoothd,NULL,&dB);CHKERRQ(ierr); 1542 ierr = MatGetInfo(dB,MAT_GLOBAL_SUM,&info);CHKERRQ(ierr); /* global reduction */ 1543 sgc += info.nz_used; 1544 if (lev==mg->nlevels-1) nnz0 = info.nz_used; 1545 } 1546 if (nnz0 > 0) *gc = (PetscReal)(sgc/nnz0); 1547 else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Number for grid points on finest level is not available"); 1548 PetscFunctionReturn(0); 1549 } 1550 1551 static PetscErrorCode PCView_GAMG(PC pc,PetscViewer viewer) 1552 { 1553 PetscErrorCode ierr,i; 1554 PC_MG *mg = (PC_MG*)pc->data; 1555 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1556 PetscReal gc=0; 1557 PetscFunctionBegin; 1558 ierr = PetscViewerASCIIPrintf(viewer," GAMG specific options\n");CHKERRQ(ierr); 1559 ierr = PetscViewerASCIIPrintf(viewer," Threshold for dropping small values in graph on each level =");CHKERRQ(ierr); 1560 for (i=0;i<pc_gamg->current_level;i++) { 1561 ierr = PetscViewerASCIIPrintf(viewer," %g",(double)pc_gamg->threshold[i]);CHKERRQ(ierr); 1562 } 1563 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr); 1564 ierr = PetscViewerASCIIPrintf(viewer," Threshold scaling factor for each level not specified = %g\n",(double)pc_gamg->threshold_scale);CHKERRQ(ierr); 1565 if (pc_gamg->use_aggs_in_asm) { 1566 ierr = PetscViewerASCIIPrintf(viewer," Using aggregates from coarsening process to define subdomains for PCASM\n");CHKERRQ(ierr); 1567 } 1568 if (pc_gamg->use_parallel_coarse_grid_solver) { 1569 ierr = PetscViewerASCIIPrintf(viewer," Using parallel coarse grid solver (all coarse grid equations not put on one process)\n");CHKERRQ(ierr); 1570 } 1571 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) 1572 if (pc_gamg->cpu_pin_coarse_grids) { 1573 /* ierr = PetscViewerASCIIPrintf(viewer," Pinning coarse grids to the CPU)\n");CHKERRQ(ierr); */ 1574 } 1575 #endif 1576 /* if (pc_gamg->layout_type==PCGAMG_LAYOUT_COMPACT) { */ 1577 /* ierr = PetscViewerASCIIPrintf(viewer," Put reduced grids on processes in natural order (ie, 0,1,2...)\n");CHKERRQ(ierr); */ 1578 /* } else { */ 1579 /* ierr = PetscViewerASCIIPrintf(viewer," Put reduced grids on whole machine (ie, 0,1*f,2*f...,np-f)\n");CHKERRQ(ierr); */ 1580 /* } */ 1581 if (pc_gamg->ops->view) { 1582 ierr = (*pc_gamg->ops->view)(pc,viewer);CHKERRQ(ierr); 1583 } 1584 ierr = PCMGGetGridComplexity(pc,&gc);CHKERRQ(ierr); 1585 ierr = PetscViewerASCIIPrintf(viewer," Complexity: grid = %g\n",gc);CHKERRQ(ierr); 1586 PetscFunctionReturn(0); 1587 } 1588 1589 PetscErrorCode PCSetFromOptions_GAMG(PetscOptionItems *PetscOptionsObject,PC pc) 1590 { 1591 PetscErrorCode ierr; 1592 PC_MG *mg = (PC_MG*)pc->data; 1593 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1594 PetscBool flag,f2; 1595 MPI_Comm comm; 1596 char prefix[256],tname[32]; 1597 PetscInt i,n; 1598 const char *pcpre; 1599 static const char *LayoutTypes[] = {"compact","spread","PCGAMGLayoutType","PC_GAMG_LAYOUT",NULL}; 1600 PetscFunctionBegin; 1601 ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr); 1602 ierr = PetscOptionsHead(PetscOptionsObject,"GAMG options");CHKERRQ(ierr); 1603 ierr = PetscOptionsFList("-pc_gamg_type","Type of AMG method","PCGAMGSetType",GAMGList, pc_gamg->gamg_type_name, tname, sizeof(tname), &flag);CHKERRQ(ierr); 1604 if (flag) { 1605 ierr = PCGAMGSetType(pc,tname);CHKERRQ(ierr); 1606 } 1607 ierr = PetscOptionsFList("-pc_gamg_esteig_ksp_type","Krylov method for eigen estimator","PCGAMGSetEstEigKSPType",KSPList,pc_gamg->esteig_type,tname,sizeof(tname),&flag);CHKERRQ(ierr); 1608 if (flag) { 1609 ierr = PCGAMGSetEstEigKSPType(pc,tname);CHKERRQ(ierr); 1610 } 1611 ierr = PetscOptionsBool("-pc_gamg_repartition","Repartion coarse grids","PCGAMGSetRepartition",pc_gamg->repart,&pc_gamg->repart,NULL);CHKERRQ(ierr); 1612 f2 = PETSC_TRUE; 1613 ierr = PetscOptionsBool("-pc_gamg_use_sa_esteig","Use eigen estimate from Smoothed aggregation for smoother","PCGAMGSetUseSAEstEig",f2,&f2,&flag);CHKERRQ(ierr); 1614 if (flag) pc_gamg->use_sa_esteig = f2 ? 1 : 0; 1615 ierr = PetscOptionsBool("-pc_gamg_reuse_interpolation","Reuse prolongation operator","PCGAMGReuseInterpolation",pc_gamg->reuse_prol,&pc_gamg->reuse_prol,NULL);CHKERRQ(ierr); 1616 ierr = 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);CHKERRQ(ierr); 1617 ierr = 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);CHKERRQ(ierr); 1618 ierr = 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);CHKERRQ(ierr); 1619 ierr = 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);CHKERRQ(ierr); 1620 ierr = 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);CHKERRQ(ierr); 1621 ierr = 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);CHKERRQ(ierr); 1622 ierr = 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);CHKERRQ(ierr); 1623 ierr = PetscOptionsReal("-pc_gamg_threshold_scale","Scaling of threshold for each level not specified","PCGAMGSetThresholdScale",pc_gamg->threshold_scale,&pc_gamg->threshold_scale,NULL);CHKERRQ(ierr); 1624 n = PETSC_MG_MAXLEVELS; 1625 ierr = PetscOptionsRealArray("-pc_gamg_threshold","Relative threshold to use for dropping edges in aggregation graph","PCGAMGSetThreshold",pc_gamg->threshold,&n,&flag);CHKERRQ(ierr); 1626 if (!flag || n < PETSC_MG_MAXLEVELS) { 1627 if (!flag) n = 1; 1628 i = n; 1629 do {pc_gamg->threshold[i] = pc_gamg->threshold[i-1]*pc_gamg->threshold_scale;} while (++i<PETSC_MG_MAXLEVELS); 1630 } 1631 ierr = PetscOptionsInt("-pc_mg_levels","Set number of MG levels","PCGAMGSetNlevels",pc_gamg->Nlevels,&pc_gamg->Nlevels,NULL);CHKERRQ(ierr); 1632 { 1633 PetscReal eminmax[2] = {0., 0.}; 1634 n = 2; 1635 ierr = PetscOptionsRealArray("-pc_gamg_eigenvalues","extreme eigenvalues for smoothed aggregation","PCGAMGSetEigenvalues",eminmax,&n,&flag);CHKERRQ(ierr); 1636 if (flag) { 1637 if (n != 2) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"-pc_gamg_eigenvalues: must specify 2 parameters, min and max eigenvalues"); 1638 ierr = PCGAMGSetEigenvalues(pc, eminmax[1], eminmax[0]);CHKERRQ(ierr); 1639 } 1640 } 1641 /* set options for subtype */ 1642 if (pc_gamg->ops->setfromoptions) {ierr = (*pc_gamg->ops->setfromoptions)(PetscOptionsObject,pc);CHKERRQ(ierr);} 1643 1644 ierr = PCGetOptionsPrefix(pc, &pcpre);CHKERRQ(ierr); 1645 ierr = PetscSNPrintf(prefix,sizeof(prefix),"%spc_gamg_",pcpre ? pcpre : "");CHKERRQ(ierr); 1646 ierr = PetscOptionsTail();CHKERRQ(ierr); 1647 PetscFunctionReturn(0); 1648 } 1649 1650 /* -------------------------------------------------------------------------- */ 1651 /*MC 1652 PCGAMG - Geometric algebraic multigrid (AMG) preconditioner 1653 1654 Options Database Keys: 1655 + -pc_gamg_type <type> - one of agg, geo, or classical 1656 . -pc_gamg_repartition <true,default=false> - repartition the degrees of freedom accross the coarse grids as they are determined 1657 . -pc_gamg_reuse_interpolation <true,default=false> - when rebuilding the algebraic multigrid preconditioner reuse the previously computed interpolations 1658 . -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 1659 . -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> 1660 equations on each process that has degrees of freedom 1661 . -pc_gamg_coarse_eq_limit <limit, default=50> - Set maximum number of equations on coarsest grid to aim for. 1662 . -pc_gamg_threshold[] <thresh,default=0> - Before aggregating the graph GAMG will remove small values from the graph on each level 1663 - -pc_gamg_threshold_scale <scale,default=1> - Scaling of threshold on each coarser grid if not specified 1664 1665 Options Database Keys for default Aggregation: 1666 + -pc_gamg_agg_nsmooths <nsmooth, default=1> - number of smoothing steps to use with smooth aggregation 1667 . -pc_gamg_sym_graph <true,default=false> - symmetrize the graph before computing the aggregation 1668 - -pc_gamg_square_graph <n,default=1> - number of levels to square the graph before aggregating it 1669 1670 Multigrid options: 1671 + -pc_mg_cycles <v> - v or w, see PCMGSetCycleType() 1672 . -pc_mg_distinct_smoothup - configure the up and down (pre and post) smoothers separately, see PCMGSetDistinctSmoothUp() 1673 . -pc_mg_type <multiplicative> - (one of) additive multiplicative full kascade 1674 - -pc_mg_levels <levels> - Number of levels of multigrid to use. 1675 1676 1677 Notes: 1678 In order to obtain good performance for PCGAMG for vector valued problems you must 1679 Call MatSetBlockSize() to indicate the number of degrees of freedom per grid point 1680 Call MatSetNearNullSpace() (or PCSetCoordinates() if solving the equations of elasticity) to indicate the near null space of the operator 1681 See the Users Manual Chapter 4 for more details 1682 1683 Level: intermediate 1684 1685 .seealso: PCCreate(), PCSetType(), MatSetBlockSize(), PCMGType, PCSetCoordinates(), MatSetNearNullSpace(), PCGAMGSetType(), PCGAMGAGG, PCGAMGGEO, PCGAMGCLASSICAL, PCGAMGSetProcEqLim(), 1686 PCGAMGSetCoarseEqLim(), PCGAMGSetRepartition(), PCGAMGRegister(), PCGAMGSetReuseInterpolation(), PCGAMGASMSetUseAggs(), PCGAMGSetUseParallelCoarseGridSolve(), PCGAMGSetNlevels(), PCGAMGSetThreshold(), PCGAMGGetType(), PCGAMGSetReuseInterpolation(), PCGAMGSetUseSAEstEig(), PCGAMGSetEstEigKSPMaxIt(), PCGAMGSetEstEigKSPType() 1687 M*/ 1688 1689 PETSC_EXTERN PetscErrorCode PCCreate_GAMG(PC pc) 1690 { 1691 PetscErrorCode ierr,i; 1692 PC_GAMG *pc_gamg; 1693 PC_MG *mg; 1694 1695 PetscFunctionBegin; 1696 /* register AMG type */ 1697 ierr = PCGAMGInitializePackage();CHKERRQ(ierr); 1698 1699 /* PCGAMG is an inherited class of PCMG. Initialize pc as PCMG */ 1700 ierr = PCSetType(pc, PCMG);CHKERRQ(ierr); 1701 ierr = PetscObjectChangeTypeName((PetscObject)pc, PCGAMG);CHKERRQ(ierr); 1702 1703 /* create a supporting struct and attach it to pc */ 1704 ierr = PetscNewLog(pc,&pc_gamg);CHKERRQ(ierr); 1705 ierr = PCMGSetGalerkin(pc,PC_MG_GALERKIN_EXTERNAL);CHKERRQ(ierr); 1706 mg = (PC_MG*)pc->data; 1707 mg->innerctx = pc_gamg; 1708 1709 ierr = PetscNewLog(pc,&pc_gamg->ops);CHKERRQ(ierr); 1710 1711 pc_gamg->setup_count = 0; 1712 /* these should be in subctx but repartitioning needs simple arrays */ 1713 pc_gamg->data_sz = 0; 1714 pc_gamg->data = NULL; 1715 1716 /* overwrite the pointers of PCMG by the functions of base class PCGAMG */ 1717 pc->ops->setfromoptions = PCSetFromOptions_GAMG; 1718 pc->ops->setup = PCSetUp_GAMG; 1719 pc->ops->reset = PCReset_GAMG; 1720 pc->ops->destroy = PCDestroy_GAMG; 1721 mg->view = PCView_GAMG; 1722 1723 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCMGGetLevels_C",PCMGGetLevels_MG);CHKERRQ(ierr); 1724 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCMGSetLevels_C",PCMGSetLevels_MG);CHKERRQ(ierr); 1725 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetProcEqLim_C",PCGAMGSetProcEqLim_GAMG);CHKERRQ(ierr); 1726 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetCoarseEqLim_C",PCGAMGSetCoarseEqLim_GAMG);CHKERRQ(ierr); 1727 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetRepartition_C",PCGAMGSetRepartition_GAMG);CHKERRQ(ierr); 1728 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetEstEigKSPType_C",PCGAMGSetEstEigKSPType_GAMG);CHKERRQ(ierr); 1729 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetEstEigKSPMaxIt_C",PCGAMGSetEstEigKSPMaxIt_GAMG);CHKERRQ(ierr); 1730 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetEigenvalues_C",PCGAMGSetEigenvalues_GAMG);CHKERRQ(ierr); 1731 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetUseSAEstEig_C",PCGAMGSetUseSAEstEig_GAMG);CHKERRQ(ierr); 1732 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetReuseInterpolation_C",PCGAMGSetReuseInterpolation_GAMG);CHKERRQ(ierr); 1733 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGASMSetUseAggs_C",PCGAMGASMSetUseAggs_GAMG);CHKERRQ(ierr); 1734 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetUseParallelCoarseGridSolve_C",PCGAMGSetUseParallelCoarseGridSolve_GAMG);CHKERRQ(ierr); 1735 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetCpuPinCoarseGrids_C",PCGAMGSetCpuPinCoarseGrids_GAMG);CHKERRQ(ierr); 1736 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetCoarseGridLayoutType_C",PCGAMGSetCoarseGridLayoutType_GAMG);CHKERRQ(ierr); 1737 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetThreshold_C",PCGAMGSetThreshold_GAMG);CHKERRQ(ierr); 1738 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetThresholdScale_C",PCGAMGSetThresholdScale_GAMG);CHKERRQ(ierr); 1739 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetType_C",PCGAMGSetType_GAMG);CHKERRQ(ierr); 1740 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGGetType_C",PCGAMGGetType_GAMG);CHKERRQ(ierr); 1741 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetNlevels_C",PCGAMGSetNlevels_GAMG);CHKERRQ(ierr); 1742 pc_gamg->repart = PETSC_FALSE; 1743 pc_gamg->reuse_prol = PETSC_FALSE; 1744 pc_gamg->use_aggs_in_asm = PETSC_FALSE; 1745 pc_gamg->use_parallel_coarse_grid_solver = PETSC_FALSE; 1746 pc_gamg->cpu_pin_coarse_grids = PETSC_FALSE; 1747 pc_gamg->layout_type = PCGAMG_LAYOUT_SPREAD; 1748 pc_gamg->min_eq_proc = 50; 1749 pc_gamg->coarse_eq_limit = 50; 1750 for (i=0;i<PETSC_MG_MAXLEVELS;i++) pc_gamg->threshold[i] = 0.; 1751 pc_gamg->threshold_scale = 1.; 1752 pc_gamg->Nlevels = PETSC_MG_MAXLEVELS; 1753 pc_gamg->current_level = 0; /* don't need to init really */ 1754 ierr = PetscStrcpy(pc_gamg->esteig_type,NULL);CHKERRQ(ierr); 1755 pc_gamg->esteig_max_it = 10; 1756 pc_gamg->use_sa_esteig = -1; 1757 pc_gamg->emin = 0; 1758 pc_gamg->emax = 0; 1759 1760 pc_gamg->ops->createlevel = PCGAMGCreateLevel_GAMG; 1761 1762 /* PCSetUp_GAMG assumes that the type has been set, so set it to the default now */ 1763 ierr = PCGAMGSetType(pc,PCGAMGAGG);CHKERRQ(ierr); 1764 PetscFunctionReturn(0); 1765 } 1766 1767 /*@C 1768 PCGAMGInitializePackage - This function initializes everything in the PCGAMG package. It is called 1769 from PCInitializePackage(). 1770 1771 Level: developer 1772 1773 .seealso: PetscInitialize() 1774 @*/ 1775 PetscErrorCode PCGAMGInitializePackage(void) 1776 { 1777 PetscErrorCode ierr; 1778 1779 PetscFunctionBegin; 1780 if (PCGAMGPackageInitialized) PetscFunctionReturn(0); 1781 PCGAMGPackageInitialized = PETSC_TRUE; 1782 ierr = PetscFunctionListAdd(&GAMGList,PCGAMGGEO,PCCreateGAMG_GEO);CHKERRQ(ierr); 1783 ierr = PetscFunctionListAdd(&GAMGList,PCGAMGAGG,PCCreateGAMG_AGG);CHKERRQ(ierr); 1784 ierr = PetscFunctionListAdd(&GAMGList,PCGAMGCLASSICAL,PCCreateGAMG_Classical);CHKERRQ(ierr); 1785 ierr = PetscRegisterFinalize(PCGAMGFinalizePackage);CHKERRQ(ierr); 1786 1787 /* general events */ 1788 ierr = PetscLogEventRegister("PCGAMGGraph_AGG", 0, &PC_GAMGGraph_AGG);CHKERRQ(ierr); 1789 ierr = PetscLogEventRegister("PCGAMGGraph_GEO", PC_CLASSID, &PC_GAMGGraph_GEO);CHKERRQ(ierr); 1790 ierr = PetscLogEventRegister("PCGAMGCoarse_AGG", PC_CLASSID, &PC_GAMGCoarsen_AGG);CHKERRQ(ierr); 1791 ierr = PetscLogEventRegister("PCGAMGCoarse_GEO", PC_CLASSID, &PC_GAMGCoarsen_GEO);CHKERRQ(ierr); 1792 ierr = PetscLogEventRegister("PCGAMGProl_AGG", PC_CLASSID, &PC_GAMGProlongator_AGG);CHKERRQ(ierr); 1793 ierr = PetscLogEventRegister("PCGAMGProl_GEO", PC_CLASSID, &PC_GAMGProlongator_GEO);CHKERRQ(ierr); 1794 ierr = PetscLogEventRegister("PCGAMGPOpt_AGG", PC_CLASSID, &PC_GAMGOptProlongator_AGG);CHKERRQ(ierr); 1795 1796 #if defined PETSC_GAMG_USE_LOG 1797 ierr = PetscLogEventRegister("GAMG: createProl", PC_CLASSID, &petsc_gamg_setup_events[SET1]);CHKERRQ(ierr); 1798 ierr = PetscLogEventRegister(" Graph", PC_CLASSID, &petsc_gamg_setup_events[GRAPH]);CHKERRQ(ierr); 1799 /* PetscLogEventRegister(" G.Mat", PC_CLASSID, &petsc_gamg_setup_events[GRAPH_MAT]); */ 1800 /* PetscLogEventRegister(" G.Filter", PC_CLASSID, &petsc_gamg_setup_events[GRAPH_FILTER]); */ 1801 /* PetscLogEventRegister(" G.Square", PC_CLASSID, &petsc_gamg_setup_events[GRAPH_SQR]); */ 1802 ierr = PetscLogEventRegister(" MIS/Agg", PC_CLASSID, &petsc_gamg_setup_events[SET4]);CHKERRQ(ierr); 1803 ierr = PetscLogEventRegister(" geo: growSupp", PC_CLASSID, &petsc_gamg_setup_events[SET5]);CHKERRQ(ierr); 1804 ierr = PetscLogEventRegister(" geo: triangle", PC_CLASSID, &petsc_gamg_setup_events[SET6]);CHKERRQ(ierr); 1805 ierr = PetscLogEventRegister(" search-set", PC_CLASSID, &petsc_gamg_setup_events[FIND_V]);CHKERRQ(ierr); 1806 ierr = PetscLogEventRegister(" SA: col data", PC_CLASSID, &petsc_gamg_setup_events[SET7]);CHKERRQ(ierr); 1807 ierr = PetscLogEventRegister(" SA: frmProl0", PC_CLASSID, &petsc_gamg_setup_events[SET8]);CHKERRQ(ierr); 1808 ierr = PetscLogEventRegister(" SA: smooth", PC_CLASSID, &petsc_gamg_setup_events[SET9]);CHKERRQ(ierr); 1809 ierr = PetscLogEventRegister("GAMG: partLevel", PC_CLASSID, &petsc_gamg_setup_events[SET2]);CHKERRQ(ierr); 1810 ierr = PetscLogEventRegister(" repartition", PC_CLASSID, &petsc_gamg_setup_events[SET12]);CHKERRQ(ierr); 1811 ierr = PetscLogEventRegister(" Invert-Sort", PC_CLASSID, &petsc_gamg_setup_events[SET13]);CHKERRQ(ierr); 1812 ierr = PetscLogEventRegister(" Move A", PC_CLASSID, &petsc_gamg_setup_events[SET14]);CHKERRQ(ierr); 1813 ierr = PetscLogEventRegister(" Move P", PC_CLASSID, &petsc_gamg_setup_events[SET15]);CHKERRQ(ierr); 1814 1815 /* PetscLogEventRegister(" PL move data", PC_CLASSID, &petsc_gamg_setup_events[SET13]); */ 1816 /* PetscLogEventRegister("GAMG: fix", PC_CLASSID, &petsc_gamg_setup_events[SET10]); */ 1817 /* PetscLogEventRegister("GAMG: set levels", PC_CLASSID, &petsc_gamg_setup_events[SET11]); */ 1818 /* create timer stages */ 1819 #if defined GAMG_STAGES 1820 { 1821 char str[32]; 1822 PetscInt lidx; 1823 sprintf(str,"MG Level %d (finest)",0); 1824 ierr = PetscLogStageRegister(str, &gamg_stages[0]);CHKERRQ(ierr); 1825 for (lidx=1; lidx<9; lidx++) { 1826 sprintf(str,"MG Level %d",lidx); 1827 ierr = PetscLogStageRegister(str, &gamg_stages[lidx]);CHKERRQ(ierr); 1828 } 1829 } 1830 #endif 1831 #endif 1832 PetscFunctionReturn(0); 1833 } 1834 1835 /*@C 1836 PCGAMGFinalizePackage - This function frees everything from the PCGAMG package. It is 1837 called from PetscFinalize() automatically. 1838 1839 Level: developer 1840 1841 .seealso: PetscFinalize() 1842 @*/ 1843 PetscErrorCode PCGAMGFinalizePackage(void) 1844 { 1845 PetscErrorCode ierr; 1846 1847 PetscFunctionBegin; 1848 PCGAMGPackageInitialized = PETSC_FALSE; 1849 ierr = PetscFunctionListDestroy(&GAMGList);CHKERRQ(ierr); 1850 PetscFunctionReturn(0); 1851 } 1852 1853 /*@C 1854 PCGAMGRegister - Register a PCGAMG implementation. 1855 1856 Input Parameters: 1857 + type - string that will be used as the name of the GAMG type. 1858 - create - function for creating the gamg context. 1859 1860 Level: advanced 1861 1862 .seealso: PCGAMGType, PCGAMG, PCGAMGSetType() 1863 @*/ 1864 PetscErrorCode PCGAMGRegister(PCGAMGType type, PetscErrorCode (*create)(PC)) 1865 { 1866 PetscErrorCode ierr; 1867 1868 PetscFunctionBegin; 1869 ierr = PCGAMGInitializePackage();CHKERRQ(ierr); 1870 ierr = PetscFunctionListAdd(&GAMGList,type,create);CHKERRQ(ierr); 1871 PetscFunctionReturn(0); 1872 } 1873 1874