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