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 8 #if defined PETSC_GAMG_USE_LOG 9 PetscLogEvent petsc_gamg_setup_events[NUM_SET]; 10 #endif 11 12 #if defined PETSC_USE_LOG 13 PetscLogEvent PC_GAMGGraph_AGG; 14 PetscLogEvent PC_GAMGGraph_GEO; 15 PetscLogEvent PC_GAMGCoarsen_AGG; 16 PetscLogEvent PC_GAMGCoarsen_GEO; 17 PetscLogEvent PC_GAMGProlongator_AGG; 18 PetscLogEvent PC_GAMGProlongator_GEO; 19 PetscLogEvent PC_GAMGOptProlongator_AGG; 20 #endif 21 22 /* #define GAMG_STAGES */ 23 #if (defined PETSC_GAMG_USE_LOG && defined GAMG_STAGES) 24 static PetscLogStage gamg_stages[PETSC_GAMG_MAXLEVELS]; 25 #endif 26 27 static PetscFunctionList GAMGList = 0; 28 static PetscBool PCGAMGPackageInitialized; 29 30 /* ----------------------------------------------------------------------------- */ 31 PetscErrorCode PCReset_GAMG(PC pc) 32 { 33 PetscErrorCode ierr; 34 PC_MG *mg = (PC_MG*)pc->data; 35 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 36 37 PetscFunctionBegin; 38 if (pc_gamg->data) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_PLIB,"This should not happen, cleaned up in SetUp\n"); 39 pc_gamg->data_sz = 0; 40 ierr = PetscFree(pc_gamg->orig_data);CHKERRQ(ierr); 41 PetscFunctionReturn(0); 42 } 43 44 /* -------------------------------------------------------------------------- */ 45 /* 46 PCGAMGCreateLevel_GAMG: create coarse op with RAP. repartition and/or reduce number 47 of active processors. 48 49 Input Parameter: 50 . pc - parameters + side effect: coarse data in 'pc_gamg->data' and 51 'pc_gamg->data_sz' are changed via repartitioning/reduction. 52 . Amat_fine - matrix on this fine (k) level 53 . cr_bs - coarse block size 54 In/Output Parameter: 55 . a_P_inout - prolongation operator to the next level (k-->k-1) 56 . a_nactive_proc - number of active procs 57 Output Parameter: 58 . a_Amat_crs - coarse matrix that is created (k-1) 59 */ 60 61 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) 62 { 63 PetscErrorCode ierr; 64 PC_MG *mg = (PC_MG*)pc->data; 65 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 66 Mat Cmat,Pold=*a_P_inout; 67 MPI_Comm comm; 68 PetscMPIInt rank,size,new_size,nactive=*a_nactive_proc; 69 PetscInt ncrs_eq,ncrs,f_bs; 70 71 PetscFunctionBegin; 72 ierr = PetscObjectGetComm((PetscObject)Amat_fine,&comm);CHKERRQ(ierr); 73 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 74 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 75 ierr = MatGetBlockSize(Amat_fine, &f_bs);CHKERRQ(ierr); 76 ierr = MatPtAP(Amat_fine, Pold, MAT_INITIAL_MATRIX, 2.0, &Cmat);CHKERRQ(ierr); 77 78 /* set 'ncrs' (nodes), 'ncrs_eq' (equations)*/ 79 ierr = MatGetLocalSize(Cmat, &ncrs_eq, NULL);CHKERRQ(ierr); 80 if (pc_gamg->data_cell_rows>0) { 81 ncrs = pc_gamg->data_sz/pc_gamg->data_cell_cols/pc_gamg->data_cell_rows; 82 } else { 83 PetscInt bs; 84 ierr = MatGetBlockSize(Cmat, &bs);CHKERRQ(ierr); 85 ncrs = ncrs_eq/bs; 86 } 87 88 /* get number of PEs to make active 'new_size', reduce, can be any integer 1-P */ 89 if (is_last && !pc_gamg->use_parallel_coarse_grid_solver) new_size = 1; 90 else { 91 PetscInt ncrs_eq_glob; 92 ierr = MatGetSize(Cmat, &ncrs_eq_glob, NULL);CHKERRQ(ierr); 93 new_size = (PetscMPIInt)((float)ncrs_eq_glob/(float)pc_gamg->min_eq_proc + 0.5); /* hardwire min. number of eq/proc */ 94 if (!new_size) new_size = 1; /* not likely, posible? */ 95 else if (new_size >= nactive) new_size = nactive; /* no change, rare */ 96 } 97 98 if (Pcolumnperm) *Pcolumnperm = NULL; 99 100 if (!pc_gamg->repart && new_size==nactive) { 101 *a_Amat_crs = Cmat; /* output - no repartitioning or reduction - could bail here */ 102 /* we know that the grid structure can be reused in MatPtAP */ 103 } else { 104 /* we know that the grid structure can NOT be reused in MatPtAP */ 105 PetscInt *counts,*newproc_idx,ii,jj,kk,strideNew,*tidx,ncrs_new,ncrs_eq_new,nloc_old; 106 IS is_eq_newproc,is_eq_num,is_eq_num_prim,new_eq_indices; 107 108 nloc_old = ncrs_eq/cr_bs; 109 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); 110 #if defined PETSC_GAMG_USE_LOG 111 ierr = PetscLogEventBegin(petsc_gamg_setup_events[SET12],0,0,0,0);CHKERRQ(ierr); 112 #endif 113 /* make 'is_eq_newproc' */ 114 ierr = PetscMalloc1(size, &counts);CHKERRQ(ierr); 115 if (pc_gamg->repart) { 116 /* Repartition Cmat_{k} and move colums of P^{k}_{k-1} and coordinates of primal part accordingly */ 117 Mat adj; 118 119 ierr = PetscInfo3(pc,"Repartition: size (active): %D --> %D, %D local equations\n",*a_nactive_proc,new_size,ncrs_eq);CHKERRQ(ierr); 120 121 /* get 'adj' */ 122 if (cr_bs == 1) { 123 ierr = MatConvert(Cmat, MATMPIADJ, MAT_INITIAL_MATRIX, &adj);CHKERRQ(ierr); 124 } else { 125 /* make a scalar matrix to partition (no Stokes here) */ 126 Mat tMat; 127 PetscInt Istart_crs,Iend_crs,ncols,jj,Ii; 128 const PetscScalar *vals; 129 const PetscInt *idx; 130 PetscInt *d_nnz, *o_nnz, M, N; 131 static PetscInt llev = 0; 132 MatType mtype; 133 134 ierr = PetscMalloc2(ncrs, &d_nnz,ncrs, &o_nnz);CHKERRQ(ierr); 135 ierr = MatGetOwnershipRange(Cmat, &Istart_crs, &Iend_crs);CHKERRQ(ierr); 136 ierr = MatGetSize(Cmat, &M, &N);CHKERRQ(ierr); 137 for (Ii = Istart_crs, jj = 0; Ii < Iend_crs; Ii += cr_bs, jj++) { 138 ierr = MatGetRow(Cmat,Ii,&ncols,0,0);CHKERRQ(ierr); 139 d_nnz[jj] = ncols/cr_bs; 140 o_nnz[jj] = ncols/cr_bs; 141 ierr = MatRestoreRow(Cmat,Ii,&ncols,0,0);CHKERRQ(ierr); 142 if (d_nnz[jj] > ncrs) d_nnz[jj] = ncrs; 143 if (o_nnz[jj] > (M/cr_bs-ncrs)) o_nnz[jj] = M/cr_bs-ncrs; 144 } 145 146 ierr = MatGetType(Amat_fine,&mtype);CHKERRQ(ierr); 147 ierr = MatCreate(comm, &tMat);CHKERRQ(ierr); 148 ierr = MatSetSizes(tMat, ncrs, ncrs,PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 149 ierr = MatSetType(tMat,mtype);CHKERRQ(ierr); 150 ierr = MatSeqAIJSetPreallocation(tMat,0,d_nnz);CHKERRQ(ierr); 151 ierr = MatMPIAIJSetPreallocation(tMat,0,d_nnz,0,o_nnz);CHKERRQ(ierr); 152 ierr = PetscFree2(d_nnz,o_nnz);CHKERRQ(ierr); 153 154 for (ii = Istart_crs; ii < Iend_crs; ii++) { 155 PetscInt dest_row = ii/cr_bs; 156 ierr = MatGetRow(Cmat,ii,&ncols,&idx,&vals);CHKERRQ(ierr); 157 for (jj = 0; jj < ncols; jj++) { 158 PetscInt dest_col = idx[jj]/cr_bs; 159 PetscScalar v = 1.0; 160 ierr = MatSetValues(tMat,1,&dest_row,1,&dest_col,&v,ADD_VALUES);CHKERRQ(ierr); 161 } 162 ierr = MatRestoreRow(Cmat,ii,&ncols,&idx,&vals);CHKERRQ(ierr); 163 } 164 ierr = MatAssemblyBegin(tMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 165 ierr = MatAssemblyEnd(tMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 166 167 if (llev++ == -1) { 168 PetscViewer viewer; char fname[32]; 169 ierr = PetscSNPrintf(fname,sizeof(fname),"part_mat_%D.mat",llev);CHKERRQ(ierr); 170 PetscViewerBinaryOpen(comm,fname,FILE_MODE_WRITE,&viewer); 171 ierr = MatView(tMat, viewer);CHKERRQ(ierr); 172 ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); 173 } 174 ierr = MatConvert(tMat, MATMPIADJ, MAT_INITIAL_MATRIX, &adj);CHKERRQ(ierr); 175 ierr = MatDestroy(&tMat);CHKERRQ(ierr); 176 } /* create 'adj' */ 177 178 { /* partition: get newproc_idx */ 179 char prefix[256]; 180 const char *pcpre; 181 const PetscInt *is_idx; 182 MatPartitioning mpart; 183 IS proc_is; 184 PetscInt targetPE; 185 186 ierr = MatPartitioningCreate(comm, &mpart);CHKERRQ(ierr); 187 ierr = MatPartitioningSetAdjacency(mpart, adj);CHKERRQ(ierr); 188 ierr = PCGetOptionsPrefix(pc, &pcpre);CHKERRQ(ierr); 189 ierr = PetscSNPrintf(prefix,sizeof(prefix),"%spc_gamg_",pcpre ? pcpre : "");CHKERRQ(ierr); 190 ierr = PetscObjectSetOptionsPrefix((PetscObject)mpart,prefix);CHKERRQ(ierr); 191 ierr = MatPartitioningSetFromOptions(mpart);CHKERRQ(ierr); 192 ierr = MatPartitioningSetNParts(mpart, new_size);CHKERRQ(ierr); 193 ierr = MatPartitioningApply(mpart, &proc_is);CHKERRQ(ierr); 194 ierr = MatPartitioningDestroy(&mpart);CHKERRQ(ierr); 195 196 /* collect IS info */ 197 ierr = PetscMalloc1(ncrs_eq, &newproc_idx);CHKERRQ(ierr); 198 ierr = ISGetIndices(proc_is, &is_idx);CHKERRQ(ierr); 199 targetPE = 1; /* bring to "front" of machine */ 200 /*targetPE = size/new_size;*/ /* spread partitioning across machine */ 201 for (kk = jj = 0 ; kk < nloc_old ; kk++) { 202 for (ii = 0 ; ii < cr_bs ; ii++, jj++) { 203 newproc_idx[jj] = is_idx[kk] * targetPE; /* distribution */ 204 } 205 } 206 ierr = ISRestoreIndices(proc_is, &is_idx);CHKERRQ(ierr); 207 ierr = ISDestroy(&proc_is);CHKERRQ(ierr); 208 } 209 ierr = MatDestroy(&adj);CHKERRQ(ierr); 210 211 ierr = ISCreateGeneral(comm, ncrs_eq, newproc_idx, PETSC_COPY_VALUES, &is_eq_newproc);CHKERRQ(ierr); 212 ierr = PetscFree(newproc_idx);CHKERRQ(ierr); 213 } else { /* simple aggreagtion of parts -- 'is_eq_newproc' */ 214 PetscInt rfactor,targetPE; 215 216 /* find factor */ 217 if (new_size == 1) rfactor = size; /* easy */ 218 else { 219 PetscReal best_fact = 0.; 220 jj = -1; 221 for (kk = 1 ; kk <= size ; kk++) { 222 if (!(size%kk)) { /* a candidate */ 223 PetscReal nactpe = (PetscReal)size/(PetscReal)kk, fact = nactpe/(PetscReal)new_size; 224 if (fact > 1.0) fact = 1./fact; /* keep fact < 1 */ 225 if (fact > best_fact) { 226 best_fact = fact; jj = kk; 227 } 228 } 229 } 230 if (jj != -1) rfactor = jj; 231 else rfactor = 1; /* does this happen .. a prime */ 232 } 233 new_size = size/rfactor; 234 235 if (new_size==nactive) { 236 *a_Amat_crs = Cmat; /* output - no repartitioning or reduction, bail out because nested here */ 237 ierr = PetscFree(counts);CHKERRQ(ierr); 238 ierr = PetscInfo2(pc,"Aggregate processors noop: new_size=%D, neq(loc)=%D\n",new_size,ncrs_eq);CHKERRQ(ierr); 239 #if defined PETSC_GAMG_USE_LOG 240 ierr = PetscLogEventEnd(petsc_gamg_setup_events[SET12],0,0,0,0);CHKERRQ(ierr); 241 #endif 242 PetscFunctionReturn(0); 243 } 244 245 ierr = PetscInfo1(pc,"Number of equations (loc) %D with simple aggregation\n",ncrs_eq);CHKERRQ(ierr); 246 targetPE = rank/rfactor; 247 ierr = ISCreateStride(comm, ncrs_eq, targetPE, 0, &is_eq_newproc);CHKERRQ(ierr); 248 } /* end simple 'is_eq_newproc' */ 249 250 /* 251 Create an index set from the is_eq_newproc index set to indicate the mapping TO 252 */ 253 ierr = ISPartitioningToNumbering(is_eq_newproc, &is_eq_num);CHKERRQ(ierr); 254 is_eq_num_prim = is_eq_num; 255 /* 256 Determine how many equations/vertices are assigned to each processor 257 */ 258 ierr = ISPartitioningCount(is_eq_newproc, size, counts);CHKERRQ(ierr); 259 ncrs_eq_new = counts[rank]; 260 ierr = ISDestroy(&is_eq_newproc);CHKERRQ(ierr); 261 ncrs_new = ncrs_eq_new/cr_bs; /* eqs */ 262 263 ierr = PetscFree(counts);CHKERRQ(ierr); 264 #if defined PETSC_GAMG_USE_LOG 265 ierr = PetscLogEventEnd(petsc_gamg_setup_events[SET12],0,0,0,0);CHKERRQ(ierr); 266 #endif 267 /* 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 */ 268 { 269 Vec src_crd, dest_crd; 270 const PetscInt *idx,ndata_rows=pc_gamg->data_cell_rows,ndata_cols=pc_gamg->data_cell_cols,node_data_sz=ndata_rows*ndata_cols; 271 VecScatter vecscat; 272 PetscScalar *array; 273 IS isscat; 274 275 /* move data (for primal equations only) */ 276 /* Create a vector to contain the newly ordered element information */ 277 ierr = VecCreate(comm, &dest_crd);CHKERRQ(ierr); 278 ierr = VecSetSizes(dest_crd, node_data_sz*ncrs_new, PETSC_DECIDE);CHKERRQ(ierr); 279 ierr = VecSetType(dest_crd,VECSTANDARD);CHKERRQ(ierr); /* this is needed! */ 280 /* 281 There are 'ndata_rows*ndata_cols' data items per node, (one can think of the vectors of having 282 a block size of ...). Note, ISs are expanded into equation space by 'cr_bs'. 283 */ 284 ierr = PetscMalloc1(ncrs*node_data_sz, &tidx);CHKERRQ(ierr); 285 ierr = ISGetIndices(is_eq_num_prim, &idx);CHKERRQ(ierr); 286 for (ii=0,jj=0; ii<ncrs; ii++) { 287 PetscInt id = idx[ii*cr_bs]/cr_bs; /* get node back */ 288 for (kk=0; kk<node_data_sz; kk++, jj++) tidx[jj] = id*node_data_sz + kk; 289 } 290 ierr = ISRestoreIndices(is_eq_num_prim, &idx);CHKERRQ(ierr); 291 ierr = ISCreateGeneral(comm, node_data_sz*ncrs, tidx, PETSC_COPY_VALUES, &isscat);CHKERRQ(ierr); 292 ierr = PetscFree(tidx);CHKERRQ(ierr); 293 /* 294 Create a vector to contain the original vertex information for each element 295 */ 296 ierr = VecCreateSeq(PETSC_COMM_SELF, node_data_sz*ncrs, &src_crd);CHKERRQ(ierr); 297 for (jj=0; jj<ndata_cols; jj++) { 298 const PetscInt stride0=ncrs*pc_gamg->data_cell_rows; 299 for (ii=0; ii<ncrs; ii++) { 300 for (kk=0; kk<ndata_rows; kk++) { 301 PetscInt ix = ii*ndata_rows + kk + jj*stride0, jx = ii*node_data_sz + kk*ndata_cols + jj; 302 PetscScalar tt = (PetscScalar)pc_gamg->data[ix]; 303 ierr = VecSetValues(src_crd, 1, &jx, &tt, INSERT_VALUES);CHKERRQ(ierr); 304 } 305 } 306 } 307 ierr = VecAssemblyBegin(src_crd);CHKERRQ(ierr); 308 ierr = VecAssemblyEnd(src_crd);CHKERRQ(ierr); 309 /* 310 Scatter the element vertex information (still in the original vertex ordering) 311 to the correct processor 312 */ 313 ierr = VecScatterCreateWithData(src_crd, NULL, dest_crd, isscat, &vecscat);CHKERRQ(ierr); 314 ierr = ISDestroy(&isscat);CHKERRQ(ierr); 315 ierr = VecScatterBegin(vecscat,src_crd,dest_crd,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 316 ierr = VecScatterEnd(vecscat,src_crd,dest_crd,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 317 ierr = VecScatterDestroy(&vecscat);CHKERRQ(ierr); 318 ierr = VecDestroy(&src_crd);CHKERRQ(ierr); 319 /* 320 Put the element vertex data into a new allocation of the gdata->ele 321 */ 322 ierr = PetscFree(pc_gamg->data);CHKERRQ(ierr); 323 ierr = PetscMalloc1(node_data_sz*ncrs_new, &pc_gamg->data);CHKERRQ(ierr); 324 325 pc_gamg->data_sz = node_data_sz*ncrs_new; 326 strideNew = ncrs_new*ndata_rows; 327 328 ierr = VecGetArray(dest_crd, &array);CHKERRQ(ierr); 329 for (jj=0; jj<ndata_cols; jj++) { 330 for (ii=0; ii<ncrs_new; ii++) { 331 for (kk=0; kk<ndata_rows; kk++) { 332 PetscInt ix = ii*ndata_rows + kk + jj*strideNew, jx = ii*node_data_sz + kk*ndata_cols + jj; 333 pc_gamg->data[ix] = PetscRealPart(array[jx]); 334 } 335 } 336 } 337 ierr = VecRestoreArray(dest_crd, &array);CHKERRQ(ierr); 338 ierr = VecDestroy(&dest_crd);CHKERRQ(ierr); 339 } 340 /* move A and P (columns) with new layout */ 341 #if defined PETSC_GAMG_USE_LOG 342 ierr = PetscLogEventBegin(petsc_gamg_setup_events[SET13],0,0,0,0);CHKERRQ(ierr); 343 #endif 344 345 /* 346 Invert for MatCreateSubMatrix 347 */ 348 ierr = ISInvertPermutation(is_eq_num, ncrs_eq_new, &new_eq_indices);CHKERRQ(ierr); 349 ierr = ISSort(new_eq_indices);CHKERRQ(ierr); /* is this needed? */ 350 ierr = ISSetBlockSize(new_eq_indices, cr_bs);CHKERRQ(ierr); 351 if (is_eq_num != is_eq_num_prim) { 352 ierr = ISDestroy(&is_eq_num_prim);CHKERRQ(ierr); /* could be same as 'is_eq_num' */ 353 } 354 if (Pcolumnperm) { 355 ierr = PetscObjectReference((PetscObject)new_eq_indices);CHKERRQ(ierr); 356 *Pcolumnperm = new_eq_indices; 357 } 358 ierr = ISDestroy(&is_eq_num);CHKERRQ(ierr); 359 #if defined PETSC_GAMG_USE_LOG 360 ierr = PetscLogEventEnd(petsc_gamg_setup_events[SET13],0,0,0,0);CHKERRQ(ierr); 361 ierr = PetscLogEventBegin(petsc_gamg_setup_events[SET14],0,0,0,0);CHKERRQ(ierr); 362 #endif 363 /* 'a_Amat_crs' output */ 364 { 365 Mat mat; 366 ierr = MatCreateSubMatrix(Cmat, new_eq_indices, new_eq_indices, MAT_INITIAL_MATRIX, &mat);CHKERRQ(ierr); 367 *a_Amat_crs = mat; 368 } 369 ierr = MatDestroy(&Cmat);CHKERRQ(ierr); 370 371 #if defined PETSC_GAMG_USE_LOG 372 ierr = PetscLogEventEnd(petsc_gamg_setup_events[SET14],0,0,0,0);CHKERRQ(ierr); 373 #endif 374 /* prolongator */ 375 { 376 IS findices; 377 PetscInt Istart,Iend; 378 Mat Pnew; 379 380 ierr = MatGetOwnershipRange(Pold, &Istart, &Iend);CHKERRQ(ierr); 381 #if defined PETSC_GAMG_USE_LOG 382 ierr = PetscLogEventBegin(petsc_gamg_setup_events[SET15],0,0,0,0);CHKERRQ(ierr); 383 #endif 384 ierr = ISCreateStride(comm,Iend-Istart,Istart,1,&findices);CHKERRQ(ierr); 385 ierr = ISSetBlockSize(findices,f_bs);CHKERRQ(ierr); 386 ierr = MatCreateSubMatrix(Pold, findices, new_eq_indices, MAT_INITIAL_MATRIX, &Pnew);CHKERRQ(ierr); 387 ierr = ISDestroy(&findices);CHKERRQ(ierr); 388 389 #if defined PETSC_GAMG_USE_LOG 390 ierr = PetscLogEventEnd(petsc_gamg_setup_events[SET15],0,0,0,0);CHKERRQ(ierr); 391 #endif 392 ierr = MatDestroy(a_P_inout);CHKERRQ(ierr); 393 394 /* output - repartitioned */ 395 *a_P_inout = Pnew; 396 } 397 ierr = ISDestroy(&new_eq_indices);CHKERRQ(ierr); 398 399 *a_nactive_proc = new_size; /* output */ 400 } 401 PetscFunctionReturn(0); 402 } 403 404 /* -------------------------------------------------------------------------- */ 405 /* 406 PCSetUp_GAMG - Prepares for the use of the GAMG preconditioner 407 by setting data structures and options. 408 409 Input Parameter: 410 . pc - the preconditioner context 411 412 */ 413 PetscErrorCode PCSetUp_GAMG(PC pc) 414 { 415 PetscErrorCode ierr; 416 PC_MG *mg = (PC_MG*)pc->data; 417 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 418 Mat Pmat = pc->pmat; 419 PetscInt fine_level,level,level1,bs,M,N,qq,lidx,nASMBlocksArr[PETSC_GAMG_MAXLEVELS]; 420 MPI_Comm comm; 421 PetscMPIInt rank,size,nactivepe; 422 Mat Aarr[PETSC_GAMG_MAXLEVELS],Parr[PETSC_GAMG_MAXLEVELS]; 423 IS *ASMLocalIDsArr[PETSC_GAMG_MAXLEVELS]; 424 PetscLogDouble nnz0=0.,nnztot=0.; 425 MatInfo info; 426 PetscBool is_last = PETSC_FALSE; 427 428 PetscFunctionBegin; 429 ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr); 430 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 431 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr); 432 433 if (pc_gamg->setup_count++ > 0) { 434 if ((PetscBool)(!pc_gamg->reuse_prol)) { 435 /* reset everything */ 436 ierr = PCReset_MG(pc);CHKERRQ(ierr); 437 pc->setupcalled = 0; 438 } else { 439 PC_MG_Levels **mglevels = mg->levels; 440 /* just do Galerkin grids */ 441 Mat B,dA,dB; 442 443 if (!pc->setupcalled) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"PCSetUp() has not been called yet"); 444 if (pc_gamg->Nlevels > 1) { 445 /* currently only handle case where mat and pmat are the same on coarser levels */ 446 ierr = KSPGetOperators(mglevels[pc_gamg->Nlevels-1]->smoothd,&dA,&dB);CHKERRQ(ierr); 447 /* (re)set to get dirty flag */ 448 ierr = KSPSetOperators(mglevels[pc_gamg->Nlevels-1]->smoothd,dA,dB);CHKERRQ(ierr); 449 450 for (level=pc_gamg->Nlevels-2; level>=0; level--) { 451 /* 2nd solve, matrix structure can change from repartitioning or process reduction but don't know if we have process reduction here. Should fix */ 452 if (pc_gamg->setup_count==2 /* && pc_gamg->repart||reduction */) { 453 ierr = PetscInfo2(pc,"new RAP after first solve level %D, %D setup\n",level,pc_gamg->setup_count);CHKERRQ(ierr); 454 ierr = MatPtAP(dB,mglevels[level+1]->interpolate,MAT_INITIAL_MATRIX,2.0,&B);CHKERRQ(ierr); 455 ierr = MatDestroy(&mglevels[level]->A);CHKERRQ(ierr); 456 mglevels[level]->A = B; 457 } else { 458 ierr = PetscInfo2(pc,"RAP after first solve reusing matrix level %D, %D setup\n",level,pc_gamg->setup_count);CHKERRQ(ierr); 459 ierr = KSPGetOperators(mglevels[level]->smoothd,NULL,&B);CHKERRQ(ierr); 460 ierr = MatPtAP(dB,mglevels[level+1]->interpolate,MAT_REUSE_MATRIX,1.0,&B);CHKERRQ(ierr); 461 } 462 ierr = KSPSetOperators(mglevels[level]->smoothd,B,B);CHKERRQ(ierr); 463 dB = B; 464 } 465 } 466 467 ierr = PCSetUp_MG(pc);CHKERRQ(ierr); 468 PetscFunctionReturn(0); 469 } 470 } 471 472 if (!pc_gamg->data) { 473 if (pc_gamg->orig_data) { 474 ierr = MatGetBlockSize(Pmat, &bs);CHKERRQ(ierr); 475 ierr = MatGetLocalSize(Pmat, &qq, NULL);CHKERRQ(ierr); 476 477 pc_gamg->data_sz = (qq/bs)*pc_gamg->orig_data_cell_rows*pc_gamg->orig_data_cell_cols; 478 pc_gamg->data_cell_rows = pc_gamg->orig_data_cell_rows; 479 pc_gamg->data_cell_cols = pc_gamg->orig_data_cell_cols; 480 481 ierr = PetscMalloc1(pc_gamg->data_sz, &pc_gamg->data);CHKERRQ(ierr); 482 for (qq=0; qq<pc_gamg->data_sz; qq++) pc_gamg->data[qq] = pc_gamg->orig_data[qq]; 483 } else { 484 if (!pc_gamg->ops->createdefaultdata) SETERRQ(comm,PETSC_ERR_PLIB,"'createdefaultdata' not set(?) need to support NULL data"); 485 ierr = pc_gamg->ops->createdefaultdata(pc,Pmat);CHKERRQ(ierr); 486 } 487 } 488 489 /* cache original data for reuse */ 490 if (!pc_gamg->orig_data && (PetscBool)(!pc_gamg->reuse_prol)) { 491 ierr = PetscMalloc1(pc_gamg->data_sz, &pc_gamg->orig_data);CHKERRQ(ierr); 492 for (qq=0; qq<pc_gamg->data_sz; qq++) pc_gamg->orig_data[qq] = pc_gamg->data[qq]; 493 pc_gamg->orig_data_cell_rows = pc_gamg->data_cell_rows; 494 pc_gamg->orig_data_cell_cols = pc_gamg->data_cell_cols; 495 } 496 497 /* get basic dims */ 498 ierr = MatGetBlockSize(Pmat, &bs);CHKERRQ(ierr); 499 ierr = MatGetSize(Pmat, &M, &N);CHKERRQ(ierr); 500 501 ierr = MatGetInfo(Pmat,MAT_GLOBAL_SUM,&info);CHKERRQ(ierr); /* global reduction */ 502 nnz0 = info.nz_used; 503 nnztot = info.nz_used; 504 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); 505 506 /* Get A_i and R_i */ 507 for (level=0, Aarr[0]=Pmat, nactivepe = size; level < (pc_gamg->Nlevels-1) && (!level || M>pc_gamg->coarse_eq_limit); level++) { 508 pc_gamg->current_level = level; 509 level1 = level + 1; 510 #if defined PETSC_GAMG_USE_LOG 511 ierr = PetscLogEventBegin(petsc_gamg_setup_events[SET1],0,0,0,0);CHKERRQ(ierr); 512 #if (defined GAMG_STAGES) 513 ierr = PetscLogStagePush(gamg_stages[level]);CHKERRQ(ierr); 514 #endif 515 #endif 516 { /* construct prolongator */ 517 Mat Gmat; 518 PetscCoarsenData *agg_lists; 519 Mat Prol11; 520 521 ierr = pc_gamg->ops->graph(pc,Aarr[level], &Gmat);CHKERRQ(ierr); 522 ierr = pc_gamg->ops->coarsen(pc, &Gmat, &agg_lists);CHKERRQ(ierr); 523 ierr = pc_gamg->ops->prolongator(pc,Aarr[level],Gmat,agg_lists,&Prol11);CHKERRQ(ierr); 524 525 /* could have failed to create new level */ 526 if (Prol11) { 527 /* get new block size of coarse matrices */ 528 ierr = MatGetBlockSizes(Prol11, NULL, &bs);CHKERRQ(ierr); 529 530 if (pc_gamg->ops->optprolongator) { 531 /* smooth */ 532 ierr = pc_gamg->ops->optprolongator(pc, Aarr[level], &Prol11);CHKERRQ(ierr); 533 } 534 535 Parr[level1] = Prol11; 536 } else Parr[level1] = NULL; /* failed to coarsen */ 537 538 if (pc_gamg->use_aggs_in_asm) { 539 PetscInt bs; 540 ierr = MatGetBlockSizes(Prol11, &bs, NULL);CHKERRQ(ierr); 541 ierr = PetscCDGetASMBlocks(agg_lists, bs, Gmat, &nASMBlocksArr[level], &ASMLocalIDsArr[level]);CHKERRQ(ierr); 542 } 543 544 ierr = MatDestroy(&Gmat);CHKERRQ(ierr); 545 ierr = PetscCDDestroy(agg_lists);CHKERRQ(ierr); 546 } /* construct prolongator scope */ 547 #if defined PETSC_GAMG_USE_LOG 548 ierr = PetscLogEventEnd(petsc_gamg_setup_events[SET1],0,0,0,0);CHKERRQ(ierr); 549 #endif 550 if (!level) Aarr[0] = Pmat; /* use Pmat for finest level setup */ 551 if (!Parr[level1]) { /* failed to coarsen */ 552 ierr = PetscInfo1(pc,"Stop gridding, level %D\n",level);CHKERRQ(ierr); 553 #if defined PETSC_GAMG_USE_LOG && defined GAMG_STAGES 554 ierr = PetscLogStagePop();CHKERRQ(ierr); 555 #endif 556 break; 557 } 558 #if defined PETSC_GAMG_USE_LOG 559 ierr = PetscLogEventBegin(petsc_gamg_setup_events[SET2],0,0,0,0);CHKERRQ(ierr); 560 #endif 561 ierr = MatGetSize(Parr[level1], &M, &N);CHKERRQ(ierr); /* N is next M, a loop test variables */ 562 if (is_last) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Is last ????????"); 563 if (N <= pc_gamg->coarse_eq_limit) is_last = PETSC_TRUE; 564 if (level1 == pc_gamg->Nlevels-1) is_last = PETSC_TRUE; 565 ierr = pc_gamg->ops->createlevel(pc, Aarr[level], bs, &Parr[level1], &Aarr[level1], &nactivepe, NULL, is_last);CHKERRQ(ierr); 566 567 #if defined PETSC_GAMG_USE_LOG 568 ierr = PetscLogEventEnd(petsc_gamg_setup_events[SET2],0,0,0,0);CHKERRQ(ierr); 569 #endif 570 ierr = MatGetSize(Aarr[level1], &M, &N);CHKERRQ(ierr); /* M is loop test variables */ 571 ierr = MatGetInfo(Aarr[level1], MAT_GLOBAL_SUM, &info);CHKERRQ(ierr); 572 nnztot += info.nz_used; 573 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); 574 575 #if (defined PETSC_GAMG_USE_LOG && defined GAMG_STAGES) 576 ierr = PetscLogStagePop();CHKERRQ(ierr); 577 #endif 578 /* stop if one node or one proc -- could pull back for singular problems */ 579 if ( (pc_gamg->data_cell_cols && M/pc_gamg->data_cell_cols < 2) || (!pc_gamg->data_cell_cols && M/bs < 2) ) { 580 ierr = PetscInfo2(pc,"HARD stop of coarsening on level %D. Grid too small: %D block nodes\n",level,M/bs);CHKERRQ(ierr); 581 level++; 582 break; 583 } 584 } /* levels */ 585 ierr = PetscFree(pc_gamg->data);CHKERRQ(ierr); 586 587 ierr = PetscInfo2(pc,"%D levels, grid complexity = %g\n",level+1,nnztot/nnz0);CHKERRQ(ierr); 588 pc_gamg->Nlevels = level + 1; 589 fine_level = level; 590 ierr = PCMGSetLevels(pc,pc_gamg->Nlevels,NULL);CHKERRQ(ierr); 591 592 if (pc_gamg->Nlevels > 1) { /* don't setup MG if one level */ 593 /* set default smoothers & set operators */ 594 for (lidx = 1, level = pc_gamg->Nlevels-2; lidx <= fine_level; lidx++, level--) { 595 KSP smoother; 596 PC subpc; 597 598 ierr = PCMGGetSmoother(pc, lidx, &smoother);CHKERRQ(ierr); 599 ierr = KSPGetPC(smoother, &subpc);CHKERRQ(ierr); 600 601 ierr = KSPSetNormType(smoother, KSP_NORM_NONE);CHKERRQ(ierr); 602 /* set ops */ 603 ierr = KSPSetOperators(smoother, Aarr[level], Aarr[level]);CHKERRQ(ierr); 604 ierr = PCMGSetInterpolation(pc, lidx, Parr[level+1]);CHKERRQ(ierr); 605 606 /* set defaults */ 607 ierr = KSPSetType(smoother, KSPCHEBYSHEV);CHKERRQ(ierr); 608 609 /* set blocks for ASM smoother that uses the 'aggregates' */ 610 if (pc_gamg->use_aggs_in_asm) { 611 PetscInt sz; 612 IS *iss; 613 614 sz = nASMBlocksArr[level]; 615 iss = ASMLocalIDsArr[level]; 616 ierr = PCSetType(subpc, PCASM);CHKERRQ(ierr); 617 ierr = PCASMSetOverlap(subpc, 0);CHKERRQ(ierr); 618 ierr = PCASMSetType(subpc,PC_ASM_BASIC);CHKERRQ(ierr); 619 if (!sz) { 620 IS is; 621 ierr = ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_COPY_VALUES, &is);CHKERRQ(ierr); 622 ierr = PCASMSetLocalSubdomains(subpc, 1, NULL, &is);CHKERRQ(ierr); 623 ierr = ISDestroy(&is);CHKERRQ(ierr); 624 } else { 625 PetscInt kk; 626 ierr = PCASMSetLocalSubdomains(subpc, sz, NULL, iss);CHKERRQ(ierr); 627 for (kk=0; kk<sz; kk++) { 628 ierr = ISDestroy(&iss[kk]);CHKERRQ(ierr); 629 } 630 ierr = PetscFree(iss);CHKERRQ(ierr); 631 } 632 ASMLocalIDsArr[level] = NULL; 633 nASMBlocksArr[level] = 0; 634 } else { 635 ierr = PCSetType(subpc, PCSOR);CHKERRQ(ierr); 636 } 637 } 638 { 639 /* coarse grid */ 640 KSP smoother,*k2; PC subpc,pc2; PetscInt ii,first; 641 Mat Lmat = Aarr[(level=pc_gamg->Nlevels-1)]; lidx = 0; 642 ierr = PCMGGetSmoother(pc, lidx, &smoother);CHKERRQ(ierr); 643 ierr = KSPSetOperators(smoother, Lmat, Lmat);CHKERRQ(ierr); 644 if (!pc_gamg->use_parallel_coarse_grid_solver) { 645 ierr = KSPSetNormType(smoother, KSP_NORM_NONE);CHKERRQ(ierr); 646 ierr = KSPGetPC(smoother, &subpc);CHKERRQ(ierr); 647 ierr = PCSetType(subpc, PCBJACOBI);CHKERRQ(ierr); 648 ierr = PCSetUp(subpc);CHKERRQ(ierr); 649 ierr = PCBJacobiGetSubKSP(subpc,&ii,&first,&k2);CHKERRQ(ierr); 650 if (ii != 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"ii %D is not one",ii); 651 ierr = KSPGetPC(k2[0],&pc2);CHKERRQ(ierr); 652 ierr = PCSetType(pc2, PCLU);CHKERRQ(ierr); 653 ierr = PCFactorSetShiftType(pc2,MAT_SHIFT_INBLOCKS);CHKERRQ(ierr); 654 ierr = KSPSetTolerances(k2[0],PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,1);CHKERRQ(ierr); 655 ierr = KSPSetType(k2[0], KSPPREONLY);CHKERRQ(ierr); 656 /* This flag gets reset by PCBJacobiGetSubKSP(), but our BJacobi really does the same algorithm everywhere (and in 657 * fact, all but one process will have zero dofs), so we reset the flag to avoid having PCView_BJacobi attempt to 658 * view every subdomain as though they were different. */ 659 ((PC_BJacobi*)subpc->data)->same_local_solves = PETSC_TRUE; 660 } 661 } 662 663 /* should be called in PCSetFromOptions_GAMG(), but cannot be called prior to PCMGSetLevels() */ 664 ierr = PetscObjectOptionsBegin((PetscObject)pc);CHKERRQ(ierr); 665 ierr = PCSetFromOptions_MG(PetscOptionsObject,pc);CHKERRQ(ierr); 666 ierr = PetscOptionsEnd();CHKERRQ(ierr); 667 ierr = PCMGSetGalerkin(pc,PC_MG_GALERKIN_EXTERNAL);CHKERRQ(ierr); 668 669 /* clean up */ 670 for (level=1; level<pc_gamg->Nlevels; level++) { 671 ierr = MatDestroy(&Parr[level]);CHKERRQ(ierr); 672 ierr = MatDestroy(&Aarr[level]);CHKERRQ(ierr); 673 } 674 ierr = PCSetUp_MG(pc);CHKERRQ(ierr); 675 } else { 676 KSP smoother; 677 ierr = PetscInfo(pc,"One level solver used (system is seen as DD). Using default solver.\n");CHKERRQ(ierr); 678 ierr = PCMGGetSmoother(pc, 0, &smoother);CHKERRQ(ierr); 679 ierr = KSPSetOperators(smoother, Aarr[0], Aarr[0]);CHKERRQ(ierr); 680 ierr = KSPSetType(smoother, KSPPREONLY);CHKERRQ(ierr); 681 ierr = PCSetUp_MG(pc);CHKERRQ(ierr); 682 } 683 PetscFunctionReturn(0); 684 } 685 686 /* ------------------------------------------------------------------------- */ 687 /* 688 PCDestroy_GAMG - Destroys the private context for the GAMG preconditioner 689 that was created with PCCreate_GAMG(). 690 691 Input Parameter: 692 . pc - the preconditioner context 693 694 Application Interface Routine: PCDestroy() 695 */ 696 PetscErrorCode PCDestroy_GAMG(PC pc) 697 { 698 PetscErrorCode ierr; 699 PC_MG *mg = (PC_MG*)pc->data; 700 PC_GAMG *pc_gamg= (PC_GAMG*)mg->innerctx; 701 702 PetscFunctionBegin; 703 ierr = PCReset_GAMG(pc);CHKERRQ(ierr); 704 if (pc_gamg->ops->destroy) { 705 ierr = (*pc_gamg->ops->destroy)(pc);CHKERRQ(ierr); 706 } 707 ierr = PetscFree(pc_gamg->ops);CHKERRQ(ierr); 708 ierr = PetscFree(pc_gamg->gamg_type_name);CHKERRQ(ierr); 709 ierr = PetscFree(pc_gamg);CHKERRQ(ierr); 710 ierr = PCDestroy_MG(pc);CHKERRQ(ierr); 711 PetscFunctionReturn(0); 712 } 713 714 /*@ 715 PCGAMGSetProcEqLim - Set number of equations to aim for per process on the coarse grids via processor reduction. 716 717 Logically Collective on PC 718 719 Input Parameters: 720 + pc - the preconditioner context 721 - n - the number of equations 722 723 724 Options Database Key: 725 . -pc_gamg_process_eq_limit <limit> 726 727 Notes: 728 GAMG will reduce the number of MPI processes used directly on the coarse grids so that there are around <limit> equations on each process 729 that has degrees of freedom 730 731 Level: intermediate 732 733 Concepts: Unstructured multigrid preconditioner 734 735 .seealso: PCGAMGSetCoarseEqLim() 736 @*/ 737 PetscErrorCode PCGAMGSetProcEqLim(PC pc, PetscInt n) 738 { 739 PetscErrorCode ierr; 740 741 PetscFunctionBegin; 742 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 743 ierr = PetscTryMethod(pc,"PCGAMGSetProcEqLim_C",(PC,PetscInt),(pc,n));CHKERRQ(ierr); 744 PetscFunctionReturn(0); 745 } 746 747 static PetscErrorCode PCGAMGSetProcEqLim_GAMG(PC pc, PetscInt n) 748 { 749 PC_MG *mg = (PC_MG*)pc->data; 750 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 751 752 PetscFunctionBegin; 753 if (n>0) pc_gamg->min_eq_proc = n; 754 PetscFunctionReturn(0); 755 } 756 757 /*@ 758 PCGAMGSetCoarseEqLim - Set maximum number of equations on coarsest grid. 759 760 Collective on PC 761 762 Input Parameters: 763 + pc - the preconditioner context 764 - n - maximum number of equations to aim for 765 766 Options Database Key: 767 . -pc_gamg_coarse_eq_limit <limit> 768 769 Level: intermediate 770 771 Concepts: Unstructured multigrid preconditioner 772 773 .seealso: PCGAMGSetProcEqLim() 774 @*/ 775 PetscErrorCode PCGAMGSetCoarseEqLim(PC pc, PetscInt n) 776 { 777 PetscErrorCode ierr; 778 779 PetscFunctionBegin; 780 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 781 ierr = PetscTryMethod(pc,"PCGAMGSetCoarseEqLim_C",(PC,PetscInt),(pc,n));CHKERRQ(ierr); 782 PetscFunctionReturn(0); 783 } 784 785 static PetscErrorCode PCGAMGSetCoarseEqLim_GAMG(PC pc, PetscInt n) 786 { 787 PC_MG *mg = (PC_MG*)pc->data; 788 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 789 790 PetscFunctionBegin; 791 if (n>0) pc_gamg->coarse_eq_limit = n; 792 PetscFunctionReturn(0); 793 } 794 795 /*@ 796 PCGAMGSetRepartition - Repartition the degrees of freedom across the processors on the coarser grids 797 798 Collective on PC 799 800 Input Parameters: 801 + pc - the preconditioner context 802 - n - PETSC_TRUE or PETSC_FALSE 803 804 Options Database Key: 805 . -pc_gamg_repartition <true,false> 806 807 Notes: 808 this will generally improve the loading balancing of the work on each level 809 810 Level: intermediate 811 812 Concepts: Unstructured multigrid preconditioner 813 814 .seealso: () 815 @*/ 816 PetscErrorCode PCGAMGSetRepartition(PC pc, PetscBool n) 817 { 818 PetscErrorCode ierr; 819 820 PetscFunctionBegin; 821 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 822 ierr = PetscTryMethod(pc,"PCGAMGSetRepartition_C",(PC,PetscBool),(pc,n));CHKERRQ(ierr); 823 PetscFunctionReturn(0); 824 } 825 826 static PetscErrorCode PCGAMGSetRepartition_GAMG(PC pc, PetscBool n) 827 { 828 PC_MG *mg = (PC_MG*)pc->data; 829 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 830 831 PetscFunctionBegin; 832 pc_gamg->repart = n; 833 PetscFunctionReturn(0); 834 } 835 836 /*@ 837 PCGAMGSetReuseInterpolation - Reuse prolongation when rebuilding algebraic multigrid preconditioner 838 839 Collective on PC 840 841 Input Parameters: 842 + pc - the preconditioner context 843 - n - PETSC_TRUE or PETSC_FALSE 844 845 Options Database Key: 846 . -pc_gamg_reuse_interpolation <true,false> 847 848 Level: intermediate 849 850 Notes: 851 this may negatively affect the convergence rate of the method on new matrices if the matrix entries change a great deal, but allows 852 rebuilding the preconditioner quicker. 853 854 Concepts: Unstructured multigrid preconditioner 855 856 .seealso: () 857 @*/ 858 PetscErrorCode PCGAMGSetReuseInterpolation(PC pc, PetscBool n) 859 { 860 PetscErrorCode ierr; 861 862 PetscFunctionBegin; 863 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 864 ierr = PetscTryMethod(pc,"PCGAMGSetReuseInterpolation_C",(PC,PetscBool),(pc,n));CHKERRQ(ierr); 865 PetscFunctionReturn(0); 866 } 867 868 static PetscErrorCode PCGAMGSetReuseInterpolation_GAMG(PC pc, PetscBool n) 869 { 870 PC_MG *mg = (PC_MG*)pc->data; 871 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 872 873 PetscFunctionBegin; 874 pc_gamg->reuse_prol = n; 875 PetscFunctionReturn(0); 876 } 877 878 /*@ 879 PCGAMGASMSetUseAggs - Have the PCGAMG smoother on each level use the aggregates defined by the coarsening process as the subdomains for the additive Schwarz preconditioner. 880 881 Collective on PC 882 883 Input Parameters: 884 + pc - the preconditioner context 885 - flg - PETSC_TRUE to use aggregates, PETSC_FALSE to not 886 887 Options Database Key: 888 . -pc_gamg_asm_use_agg 889 890 Level: intermediate 891 892 Concepts: Unstructured multigrid preconditioner 893 894 .seealso: () 895 @*/ 896 PetscErrorCode PCGAMGASMSetUseAggs(PC pc, PetscBool flg) 897 { 898 PetscErrorCode ierr; 899 900 PetscFunctionBegin; 901 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 902 ierr = PetscTryMethod(pc,"PCGAMGASMSetUseAggs_C",(PC,PetscBool),(pc,flg));CHKERRQ(ierr); 903 PetscFunctionReturn(0); 904 } 905 906 static PetscErrorCode PCGAMGASMSetUseAggs_GAMG(PC pc, PetscBool flg) 907 { 908 PC_MG *mg = (PC_MG*)pc->data; 909 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 910 911 PetscFunctionBegin; 912 pc_gamg->use_aggs_in_asm = flg; 913 PetscFunctionReturn(0); 914 } 915 916 /*@ 917 PCGAMGSetUseParallelCoarseGridSolve - allow a parallel coarse grid solver 918 919 Collective on PC 920 921 Input Parameters: 922 + pc - the preconditioner context 923 - flg - PETSC_TRUE to not force coarse grid onto one processor 924 925 Options Database Key: 926 . -pc_gamg_use_parallel_coarse_grid_solver 927 928 Level: intermediate 929 930 Concepts: Unstructured multigrid preconditioner 931 932 .seealso: () 933 @*/ 934 PetscErrorCode PCGAMGSetUseParallelCoarseGridSolve(PC pc, PetscBool flg) 935 { 936 PetscErrorCode ierr; 937 938 PetscFunctionBegin; 939 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 940 ierr = PetscTryMethod(pc,"PCGAMGSetUseParallelCoarseGridSolve_C",(PC,PetscBool),(pc,flg));CHKERRQ(ierr); 941 PetscFunctionReturn(0); 942 } 943 944 static PetscErrorCode PCGAMGSetUseParallelCoarseGridSolve_GAMG(PC pc, PetscBool flg) 945 { 946 PC_MG *mg = (PC_MG*)pc->data; 947 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 948 949 PetscFunctionBegin; 950 pc_gamg->use_parallel_coarse_grid_solver = flg; 951 PetscFunctionReturn(0); 952 } 953 954 /*@ 955 PCGAMGSetNlevels - Sets the maximum number of levels PCGAMG will use 956 957 Not collective on PC 958 959 Input Parameters: 960 + pc - the preconditioner 961 - n - the maximum number of levels to use 962 963 Options Database Key: 964 . -pc_mg_levels 965 966 Level: intermediate 967 968 Concepts: Unstructured multigrid preconditioner 969 970 .seealso: () 971 @*/ 972 PetscErrorCode PCGAMGSetNlevels(PC pc, PetscInt n) 973 { 974 PetscErrorCode ierr; 975 976 PetscFunctionBegin; 977 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 978 ierr = PetscTryMethod(pc,"PCGAMGSetNlevels_C",(PC,PetscInt),(pc,n));CHKERRQ(ierr); 979 PetscFunctionReturn(0); 980 } 981 982 static PetscErrorCode PCGAMGSetNlevels_GAMG(PC pc, PetscInt n) 983 { 984 PC_MG *mg = (PC_MG*)pc->data; 985 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 986 987 PetscFunctionBegin; 988 pc_gamg->Nlevels = n; 989 PetscFunctionReturn(0); 990 } 991 992 /*@ 993 PCGAMGSetThreshold - Relative threshold to use for dropping edges in aggregation graph 994 995 Not collective on PC 996 997 Input Parameters: 998 + pc - the preconditioner context 999 - threshold - the threshold value, 0.0 means keep all nonzero entries in the graph; negative means keep even zero entries in the graph 1000 1001 Options Database Key: 1002 . -pc_gamg_threshold <threshold> 1003 1004 Notes: 1005 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. 1006 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. 1007 1008 Level: intermediate 1009 1010 Concepts: Unstructured multigrid preconditioner 1011 1012 .seealso: PCGAMGFilterGraph(), PCGAMGSetSquareGraph() 1013 @*/ 1014 PetscErrorCode PCGAMGSetThreshold(PC pc, PetscReal v[], PetscInt n) 1015 { 1016 PetscErrorCode ierr; 1017 1018 PetscFunctionBegin; 1019 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1020 ierr = PetscTryMethod(pc,"PCGAMGSetThreshold_C",(PC,PetscReal[],PetscInt),(pc,v,n));CHKERRQ(ierr); 1021 PetscFunctionReturn(0); 1022 } 1023 1024 static PetscErrorCode PCGAMGSetThreshold_GAMG(PC pc, PetscReal v[], PetscInt n) 1025 { 1026 PC_MG *mg = (PC_MG*)pc->data; 1027 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1028 PetscInt i; 1029 PetscFunctionBegin; 1030 for (i=0;i<n;i++) pc_gamg->threshold[i] = v[i]; 1031 do {pc_gamg->threshold[i] = pc_gamg->threshold[i-1]*pc_gamg->threshold_scale;} while (++i<PETSC_GAMG_MAXLEVELS); 1032 PetscFunctionReturn(0); 1033 } 1034 1035 /*@ 1036 PCGAMGSetThresholdScale - Relative threshold reduction at each level 1037 1038 Not collective on PC 1039 1040 Input Parameters: 1041 + pc - the preconditioner context 1042 - scale - the threshold value reduction, ussually < 1.0 1043 1044 Options Database Key: 1045 . -pc_gamg_threshold_scale <v> 1046 1047 Level: advanced 1048 1049 Concepts: Unstructured multigrid preconditioner 1050 1051 .seealso: () 1052 @*/ 1053 PetscErrorCode PCGAMGSetThresholdScale(PC pc, PetscReal v) 1054 { 1055 PetscErrorCode ierr; 1056 1057 PetscFunctionBegin; 1058 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1059 ierr = PetscTryMethod(pc,"PCGAMGSetThresholdScale_C",(PC,PetscReal),(pc,v));CHKERRQ(ierr); 1060 PetscFunctionReturn(0); 1061 } 1062 1063 static PetscErrorCode PCGAMGSetThresholdScale_GAMG(PC pc, PetscReal v) 1064 { 1065 PC_MG *mg = (PC_MG*)pc->data; 1066 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1067 PetscFunctionBegin; 1068 pc_gamg->threshold_scale = v; 1069 PetscFunctionReturn(0); 1070 } 1071 1072 /*@C 1073 PCGAMGSetType - Set solution method 1074 1075 Collective on PC 1076 1077 Input Parameters: 1078 + pc - the preconditioner context 1079 - type - PCGAMGAGG, PCGAMGGEO, or PCGAMGCLASSICAL 1080 1081 Options Database Key: 1082 . -pc_gamg_type <agg,geo,classical> - type of algebraic multigrid to apply 1083 1084 Level: intermediate 1085 1086 Concepts: Unstructured multigrid preconditioner 1087 1088 .seealso: PCGAMGGetType(), PCGAMG, PCGAMGType 1089 @*/ 1090 PetscErrorCode PCGAMGSetType(PC pc, PCGAMGType type) 1091 { 1092 PetscErrorCode ierr; 1093 1094 PetscFunctionBegin; 1095 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1096 ierr = PetscTryMethod(pc,"PCGAMGSetType_C",(PC,PCGAMGType),(pc,type));CHKERRQ(ierr); 1097 PetscFunctionReturn(0); 1098 } 1099 1100 /*@C 1101 PCGAMGGetType - Get solution method 1102 1103 Collective on PC 1104 1105 Input Parameter: 1106 . pc - the preconditioner context 1107 1108 Output Parameter: 1109 . type - the type of algorithm used 1110 1111 Level: intermediate 1112 1113 Concepts: Unstructured multigrid preconditioner 1114 1115 .seealso: PCGAMGSetType(), PCGAMGType 1116 @*/ 1117 PetscErrorCode PCGAMGGetType(PC pc, PCGAMGType *type) 1118 { 1119 PetscErrorCode ierr; 1120 1121 PetscFunctionBegin; 1122 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1123 ierr = PetscUseMethod(pc,"PCGAMGGetType_C",(PC,PCGAMGType*),(pc,type));CHKERRQ(ierr); 1124 PetscFunctionReturn(0); 1125 } 1126 1127 static PetscErrorCode PCGAMGGetType_GAMG(PC pc, PCGAMGType *type) 1128 { 1129 PC_MG *mg = (PC_MG*)pc->data; 1130 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1131 1132 PetscFunctionBegin; 1133 *type = pc_gamg->type; 1134 PetscFunctionReturn(0); 1135 } 1136 1137 static PetscErrorCode PCGAMGSetType_GAMG(PC pc, PCGAMGType type) 1138 { 1139 PetscErrorCode ierr,(*r)(PC); 1140 PC_MG *mg = (PC_MG*)pc->data; 1141 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1142 1143 PetscFunctionBegin; 1144 pc_gamg->type = type; 1145 ierr = PetscFunctionListFind(GAMGList,type,&r);CHKERRQ(ierr); 1146 if (!r) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown GAMG type %s given",type); 1147 if (pc_gamg->ops->destroy) { 1148 ierr = (*pc_gamg->ops->destroy)(pc);CHKERRQ(ierr); 1149 ierr = PetscMemzero(pc_gamg->ops,sizeof(struct _PCGAMGOps));CHKERRQ(ierr); 1150 pc_gamg->ops->createlevel = PCGAMGCreateLevel_GAMG; 1151 /* cleaning up common data in pc_gamg - this should disapear someday */ 1152 pc_gamg->data_cell_cols = 0; 1153 pc_gamg->data_cell_rows = 0; 1154 pc_gamg->orig_data_cell_cols = 0; 1155 pc_gamg->orig_data_cell_rows = 0; 1156 ierr = PetscFree(pc_gamg->data);CHKERRQ(ierr); 1157 pc_gamg->data_sz = 0; 1158 } 1159 ierr = PetscFree(pc_gamg->gamg_type_name);CHKERRQ(ierr); 1160 ierr = PetscStrallocpy(type,&pc_gamg->gamg_type_name);CHKERRQ(ierr); 1161 ierr = (*r)(pc);CHKERRQ(ierr); 1162 PetscFunctionReturn(0); 1163 } 1164 1165 /* -------------------------------------------------------------------------- */ 1166 /* 1167 PCMGGetGridComplexity - compute coarse grid complexity of MG hierarchy 1168 1169 Input Parameter: 1170 . pc - the preconditioner context 1171 1172 Output Parameter: 1173 . gc - grid complexity = sum_i(nnz_i) / nnz_0 1174 1175 Level: advanced 1176 */ 1177 static PetscErrorCode PCMGGetGridComplexity(PC pc, PetscReal *gc) 1178 { 1179 PetscErrorCode ierr; 1180 PC_MG *mg = (PC_MG*)pc->data; 1181 PC_MG_Levels **mglevels = mg->levels; 1182 PetscInt lev, nnz0 = -1; 1183 MatInfo info; 1184 PetscFunctionBegin; 1185 if (!mg->nlevels) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"MG has no levels"); 1186 for (lev=0, *gc=0; lev<mg->nlevels; lev++) { 1187 Mat dB; 1188 ierr = KSPGetOperators(mglevels[lev]->smoothd,NULL,&dB);CHKERRQ(ierr); 1189 ierr = MatGetInfo(dB,MAT_GLOBAL_SUM,&info);CHKERRQ(ierr); /* global reduction */ 1190 *gc += (PetscReal)info.nz_used; 1191 if (lev==mg->nlevels-1) nnz0 = info.nz_used; 1192 } 1193 if (nnz0) *gc /= (PetscReal)nnz0; 1194 else *gc = 0; 1195 PetscFunctionReturn(0); 1196 } 1197 1198 static PetscErrorCode PCView_GAMG(PC pc,PetscViewer viewer) 1199 { 1200 PetscErrorCode ierr,i; 1201 PC_MG *mg = (PC_MG*)pc->data; 1202 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1203 PetscReal gc=0; 1204 PetscFunctionBegin; 1205 ierr = PetscViewerASCIIPrintf(viewer," GAMG specific options\n");CHKERRQ(ierr); 1206 ierr = PetscViewerASCIIPrintf(viewer," Threshold for dropping small values in graph on each level =");CHKERRQ(ierr); 1207 for (i=0;i<pc_gamg->current_level;i++) { 1208 ierr = PetscViewerASCIIPrintf(viewer," %g",(double)pc_gamg->threshold[i]);CHKERRQ(ierr); 1209 } 1210 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr); 1211 ierr = PetscViewerASCIIPrintf(viewer," Threshold scaling factor for each level not specified = %g\n",(double)pc_gamg->threshold_scale);CHKERRQ(ierr); 1212 if (pc_gamg->use_aggs_in_asm) { 1213 ierr = PetscViewerASCIIPrintf(viewer," Using aggregates from coarsening process to define subdomains for PCASM\n");CHKERRQ(ierr); 1214 } 1215 if (pc_gamg->use_parallel_coarse_grid_solver) { 1216 ierr = PetscViewerASCIIPrintf(viewer," Using parallel coarse grid solver (all coarse grid equations not put on one process)\n");CHKERRQ(ierr); 1217 } 1218 if (pc_gamg->ops->view) { 1219 ierr = (*pc_gamg->ops->view)(pc,viewer);CHKERRQ(ierr); 1220 } 1221 ierr = PCMGGetGridComplexity(pc,&gc);CHKERRQ(ierr); 1222 ierr = PetscViewerASCIIPrintf(viewer," Complexity: grid = %g\n",gc);CHKERRQ(ierr); 1223 PetscFunctionReturn(0); 1224 } 1225 1226 PetscErrorCode PCSetFromOptions_GAMG(PetscOptionItems *PetscOptionsObject,PC pc) 1227 { 1228 PetscErrorCode ierr; 1229 PC_MG *mg = (PC_MG*)pc->data; 1230 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1231 PetscBool flag; 1232 MPI_Comm comm; 1233 char prefix[256]; 1234 PetscInt i,n; 1235 const char *pcpre; 1236 1237 PetscFunctionBegin; 1238 ierr = PetscObjectGetComm((PetscObject)pc,&comm);CHKERRQ(ierr); 1239 ierr = PetscOptionsHead(PetscOptionsObject,"GAMG options");CHKERRQ(ierr); 1240 { 1241 char tname[256]; 1242 ierr = PetscOptionsFList("-pc_gamg_type","Type of AMG method","PCGAMGSetType",GAMGList, pc_gamg->gamg_type_name, tname, sizeof(tname), &flag);CHKERRQ(ierr); 1243 if (flag) { 1244 ierr = PCGAMGSetType(pc,tname);CHKERRQ(ierr); 1245 } 1246 ierr = PetscOptionsBool("-pc_gamg_repartition","Repartion coarse grids","PCGAMGSetRepartition",pc_gamg->repart,&pc_gamg->repart,NULL);CHKERRQ(ierr); 1247 ierr = PetscOptionsBool("-pc_gamg_reuse_interpolation","Reuse prolongation operator","PCGAMGReuseInterpolation",pc_gamg->reuse_prol,&pc_gamg->reuse_prol,NULL);CHKERRQ(ierr); 1248 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); 1249 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); 1250 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); 1251 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); 1252 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); 1253 n = PETSC_GAMG_MAXLEVELS; 1254 ierr = PetscOptionsRealArray("-pc_gamg_threshold","Relative threshold to use for dropping edges in aggregation graph","PCGAMGSetThreshold",pc_gamg->threshold,&n,&flag);CHKERRQ(ierr); 1255 if (!flag || n < PETSC_GAMG_MAXLEVELS) { 1256 if (!flag) n = 1; 1257 i = n; 1258 do {pc_gamg->threshold[i] = pc_gamg->threshold[i-1]*pc_gamg->threshold_scale;} while (++i<PETSC_GAMG_MAXLEVELS); 1259 } 1260 ierr = PetscOptionsInt("-pc_mg_levels","Set number of MG levels","PCGAMGSetNlevels",pc_gamg->Nlevels,&pc_gamg->Nlevels,NULL);CHKERRQ(ierr); 1261 1262 /* set options for subtype */ 1263 if (pc_gamg->ops->setfromoptions) {ierr = (*pc_gamg->ops->setfromoptions)(PetscOptionsObject,pc);CHKERRQ(ierr);} 1264 } 1265 ierr = PCGetOptionsPrefix(pc, &pcpre);CHKERRQ(ierr); 1266 ierr = PetscSNPrintf(prefix,sizeof(prefix),"%spc_gamg_",pcpre ? pcpre : "");CHKERRQ(ierr); 1267 ierr = PetscOptionsTail();CHKERRQ(ierr); 1268 PetscFunctionReturn(0); 1269 } 1270 1271 /* -------------------------------------------------------------------------- */ 1272 /*MC 1273 PCGAMG - Geometric algebraic multigrid (AMG) preconditioner 1274 1275 Options Database Keys: 1276 + -pc_gamg_type <type> - one of agg, geo, or classical 1277 . -pc_gamg_repartition <true,default=false> - repartition the degrees of freedom accross the coarse grids as they are determined 1278 . -pc_gamg_reuse_interpolation <true,default=false> - when rebuilding the algebraic multigrid preconditioner reuse the previously computed interpolations 1279 . -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 1280 . -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> 1281 equations on each process that has degrees of freedom 1282 . -pc_gamg_coarse_eq_limit <limit, default=50> - Set maximum number of equations on coarsest grid to aim for. 1283 . -pc_gamg_threshold[] <thresh,default=0> - Before aggregating the graph GAMG will remove small values from the graph on each level 1284 - -pc_gamg_threshold_scale <scale,default=1> - Scaling of threshold on each coarser grid if not specified 1285 1286 Options Database Keys for default Aggregation: 1287 + -pc_gamg_agg_nsmooths <nsmooth, default=1> - number of smoothing steps to use with smooth aggregation 1288 . -pc_gamg_sym_graph <true,default=false> - symmetrize the graph before computing the aggregation 1289 - -pc_gamg_square_graph <n,default=1> - number of levels to square the graph before aggregating it 1290 1291 Multigrid options: 1292 + -pc_mg_cycles <v> - v or w, see PCMGSetCycleType() 1293 . -pc_mg_distinct_smoothup - configure the up and down (pre and post) smoothers separately, see PCMGSetDistinctSmoothUp() 1294 . -pc_mg_type <multiplicative> - (one of) additive multiplicative full kascade 1295 - -pc_mg_levels <levels> - Number of levels of multigrid to use. 1296 1297 1298 Notes: 1299 In order to obtain good performance for PCGAMG for vector valued problems you must 1300 Call MatSetBlockSize() to indicate the number of degrees of freedom per grid point 1301 Call MatSetNearNullSpace() (or PCSetCoordinates() if solving the equations of elasticity) to indicate the near null space of the operator 1302 See the Users Manual Chapter 4 for more details 1303 1304 Level: intermediate 1305 1306 Concepts: algebraic multigrid 1307 1308 .seealso: PCCreate(), PCSetType(), MatSetBlockSize(), PCMGType, PCSetCoordinates(), MatSetNearNullSpace(), PCGAMGSetType(), PCGAMGAGG, PCGAMGGEO, PCGAMGCLASSICAL, PCGAMGSetProcEqLim(), 1309 PCGAMGSetCoarseEqLim(), PCGAMGSetRepartition(), PCGAMGRegister(), PCGAMGSetReuseInterpolation(), PCGAMGASMSetUseAggs(), PCGAMGSetUseParallelCoarseGridSolve(), PCGAMGSetNlevels(), PCGAMGSetThreshold(), PCGAMGGetType(), PCGAMGSetReuseInterpolation() 1310 M*/ 1311 1312 PETSC_EXTERN PetscErrorCode PCCreate_GAMG(PC pc) 1313 { 1314 PetscErrorCode ierr,i; 1315 PC_GAMG *pc_gamg; 1316 PC_MG *mg; 1317 1318 PetscFunctionBegin; 1319 /* register AMG type */ 1320 ierr = PCGAMGInitializePackage();CHKERRQ(ierr); 1321 1322 /* PCGAMG is an inherited class of PCMG. Initialize pc as PCMG */ 1323 ierr = PCSetType(pc, PCMG);CHKERRQ(ierr); 1324 ierr = PetscObjectChangeTypeName((PetscObject)pc, PCGAMG);CHKERRQ(ierr); 1325 1326 /* create a supporting struct and attach it to pc */ 1327 ierr = PetscNewLog(pc,&pc_gamg);CHKERRQ(ierr); 1328 ierr = PCMGSetGalerkin(pc,PC_MG_GALERKIN_EXTERNAL);CHKERRQ(ierr); 1329 mg = (PC_MG*)pc->data; 1330 mg->innerctx = pc_gamg; 1331 1332 ierr = PetscNewLog(pc,&pc_gamg->ops);CHKERRQ(ierr); 1333 1334 pc_gamg->setup_count = 0; 1335 /* these should be in subctx but repartitioning needs simple arrays */ 1336 pc_gamg->data_sz = 0; 1337 pc_gamg->data = 0; 1338 1339 /* overwrite the pointers of PCMG by the functions of base class PCGAMG */ 1340 pc->ops->setfromoptions = PCSetFromOptions_GAMG; 1341 pc->ops->setup = PCSetUp_GAMG; 1342 pc->ops->reset = PCReset_GAMG; 1343 pc->ops->destroy = PCDestroy_GAMG; 1344 mg->view = PCView_GAMG; 1345 1346 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetProcEqLim_C",PCGAMGSetProcEqLim_GAMG);CHKERRQ(ierr); 1347 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetCoarseEqLim_C",PCGAMGSetCoarseEqLim_GAMG);CHKERRQ(ierr); 1348 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetRepartition_C",PCGAMGSetRepartition_GAMG);CHKERRQ(ierr); 1349 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetReuseInterpolation_C",PCGAMGSetReuseInterpolation_GAMG);CHKERRQ(ierr); 1350 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGASMSetUseAggs_C",PCGAMGASMSetUseAggs_GAMG);CHKERRQ(ierr); 1351 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetUseParallelCoarseGridSolve_C",PCGAMGSetUseParallelCoarseGridSolve_GAMG);CHKERRQ(ierr); 1352 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetThreshold_C",PCGAMGSetThreshold_GAMG);CHKERRQ(ierr); 1353 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetThresholdScale_C",PCGAMGSetThresholdScale_GAMG);CHKERRQ(ierr); 1354 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetType_C",PCGAMGSetType_GAMG);CHKERRQ(ierr); 1355 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGGetType_C",PCGAMGGetType_GAMG);CHKERRQ(ierr); 1356 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetNlevels_C",PCGAMGSetNlevels_GAMG);CHKERRQ(ierr); 1357 pc_gamg->repart = PETSC_FALSE; 1358 pc_gamg->reuse_prol = PETSC_FALSE; 1359 pc_gamg->use_aggs_in_asm = PETSC_FALSE; 1360 pc_gamg->use_parallel_coarse_grid_solver = PETSC_FALSE; 1361 pc_gamg->min_eq_proc = 50; 1362 pc_gamg->coarse_eq_limit = 50; 1363 for (i=0;i<PETSC_GAMG_MAXLEVELS;i++) pc_gamg->threshold[i] = 0.; 1364 pc_gamg->threshold_scale = 1.; 1365 pc_gamg->Nlevels = PETSC_GAMG_MAXLEVELS; 1366 pc_gamg->current_level = 0; /* don't need to init really */ 1367 pc_gamg->ops->createlevel = PCGAMGCreateLevel_GAMG; 1368 1369 /* PCSetUp_GAMG assumes that the type has been set, so set it to the default now */ 1370 ierr = PCGAMGSetType(pc,PCGAMGAGG);CHKERRQ(ierr); 1371 PetscFunctionReturn(0); 1372 } 1373 1374 /*@C 1375 PCGAMGInitializePackage - This function initializes everything in the PCGAMG package. It is called 1376 from PetscDLLibraryRegister() when using dynamic libraries, and on the first call to PCCreate_GAMG() 1377 when using static libraries. 1378 1379 Level: developer 1380 1381 .keywords: PC, PCGAMG, initialize, package 1382 .seealso: PetscInitialize() 1383 @*/ 1384 PetscErrorCode PCGAMGInitializePackage(void) 1385 { 1386 PetscErrorCode ierr; 1387 1388 PetscFunctionBegin; 1389 if (PCGAMGPackageInitialized) PetscFunctionReturn(0); 1390 PCGAMGPackageInitialized = PETSC_TRUE; 1391 ierr = PetscFunctionListAdd(&GAMGList,PCGAMGGEO,PCCreateGAMG_GEO);CHKERRQ(ierr); 1392 ierr = PetscFunctionListAdd(&GAMGList,PCGAMGAGG,PCCreateGAMG_AGG);CHKERRQ(ierr); 1393 ierr = PetscFunctionListAdd(&GAMGList,PCGAMGCLASSICAL,PCCreateGAMG_Classical);CHKERRQ(ierr); 1394 ierr = PetscRegisterFinalize(PCGAMGFinalizePackage);CHKERRQ(ierr); 1395 1396 /* general events */ 1397 ierr = PetscLogEventRegister("PCGAMGGraph_AGG", 0, &PC_GAMGGraph_AGG);CHKERRQ(ierr); 1398 ierr = PetscLogEventRegister("PCGAMGGraph_GEO", PC_CLASSID, &PC_GAMGGraph_GEO);CHKERRQ(ierr); 1399 ierr = PetscLogEventRegister("PCGAMGCoarse_AGG", PC_CLASSID, &PC_GAMGCoarsen_AGG);CHKERRQ(ierr); 1400 ierr = PetscLogEventRegister("PCGAMGCoarse_GEO", PC_CLASSID, &PC_GAMGCoarsen_GEO);CHKERRQ(ierr); 1401 ierr = PetscLogEventRegister("PCGAMGProl_AGG", PC_CLASSID, &PC_GAMGProlongator_AGG);CHKERRQ(ierr); 1402 ierr = PetscLogEventRegister("PCGAMGProl_GEO", PC_CLASSID, &PC_GAMGProlongator_GEO);CHKERRQ(ierr); 1403 ierr = PetscLogEventRegister("PCGAMGPOpt_AGG", PC_CLASSID, &PC_GAMGOptProlongator_AGG);CHKERRQ(ierr); 1404 1405 #if defined PETSC_GAMG_USE_LOG 1406 ierr = PetscLogEventRegister("GAMG: createProl", PC_CLASSID, &petsc_gamg_setup_events[SET1]);CHKERRQ(ierr); 1407 ierr = PetscLogEventRegister(" Graph", PC_CLASSID, &petsc_gamg_setup_events[GRAPH]);CHKERRQ(ierr); 1408 /* PetscLogEventRegister(" G.Mat", PC_CLASSID, &petsc_gamg_setup_events[GRAPH_MAT]); */ 1409 /* PetscLogEventRegister(" G.Filter", PC_CLASSID, &petsc_gamg_setup_events[GRAPH_FILTER]); */ 1410 /* PetscLogEventRegister(" G.Square", PC_CLASSID, &petsc_gamg_setup_events[GRAPH_SQR]); */ 1411 ierr = PetscLogEventRegister(" MIS/Agg", PC_CLASSID, &petsc_gamg_setup_events[SET4]);CHKERRQ(ierr); 1412 ierr = PetscLogEventRegister(" geo: growSupp", PC_CLASSID, &petsc_gamg_setup_events[SET5]);CHKERRQ(ierr); 1413 ierr = PetscLogEventRegister(" geo: triangle", PC_CLASSID, &petsc_gamg_setup_events[SET6]);CHKERRQ(ierr); 1414 ierr = PetscLogEventRegister(" search-set", PC_CLASSID, &petsc_gamg_setup_events[FIND_V]);CHKERRQ(ierr); 1415 ierr = PetscLogEventRegister(" SA: col data", PC_CLASSID, &petsc_gamg_setup_events[SET7]);CHKERRQ(ierr); 1416 ierr = PetscLogEventRegister(" SA: frmProl0", PC_CLASSID, &petsc_gamg_setup_events[SET8]);CHKERRQ(ierr); 1417 ierr = PetscLogEventRegister(" SA: smooth", PC_CLASSID, &petsc_gamg_setup_events[SET9]);CHKERRQ(ierr); 1418 ierr = PetscLogEventRegister("GAMG: partLevel", PC_CLASSID, &petsc_gamg_setup_events[SET2]);CHKERRQ(ierr); 1419 ierr = PetscLogEventRegister(" repartition", PC_CLASSID, &petsc_gamg_setup_events[SET12]);CHKERRQ(ierr); 1420 ierr = PetscLogEventRegister(" Invert-Sort", PC_CLASSID, &petsc_gamg_setup_events[SET13]);CHKERRQ(ierr); 1421 ierr = PetscLogEventRegister(" Move A", PC_CLASSID, &petsc_gamg_setup_events[SET14]);CHKERRQ(ierr); 1422 ierr = PetscLogEventRegister(" Move P", PC_CLASSID, &petsc_gamg_setup_events[SET15]);CHKERRQ(ierr); 1423 1424 /* PetscLogEventRegister(" PL move data", PC_CLASSID, &petsc_gamg_setup_events[SET13]); */ 1425 /* PetscLogEventRegister("GAMG: fix", PC_CLASSID, &petsc_gamg_setup_events[SET10]); */ 1426 /* PetscLogEventRegister("GAMG: set levels", PC_CLASSID, &petsc_gamg_setup_events[SET11]); */ 1427 /* create timer stages */ 1428 #if defined GAMG_STAGES 1429 { 1430 char str[32]; 1431 PetscInt lidx; 1432 sprintf(str,"MG Level %d (finest)",0); 1433 ierr = PetscLogStageRegister(str, &gamg_stages[0]);CHKERRQ(ierr); 1434 for (lidx=1; lidx<9; lidx++) { 1435 sprintf(str,"MG Level %d",lidx); 1436 ierr = PetscLogStageRegister(str, &gamg_stages[lidx]);CHKERRQ(ierr); 1437 } 1438 } 1439 #endif 1440 #endif 1441 PetscFunctionReturn(0); 1442 } 1443 1444 /*@C 1445 PCGAMGFinalizePackage - This function frees everything from the PCGAMG package. It is 1446 called from PetscFinalize() automatically. 1447 1448 Level: developer 1449 1450 .keywords: Petsc, destroy, package 1451 .seealso: PetscFinalize() 1452 @*/ 1453 PetscErrorCode PCGAMGFinalizePackage(void) 1454 { 1455 PetscErrorCode ierr; 1456 1457 PetscFunctionBegin; 1458 PCGAMGPackageInitialized = PETSC_FALSE; 1459 ierr = PetscFunctionListDestroy(&GAMGList);CHKERRQ(ierr); 1460 PetscFunctionReturn(0); 1461 } 1462 1463 /*@C 1464 PCGAMGRegister - Register a PCGAMG implementation. 1465 1466 Input Parameters: 1467 + type - string that will be used as the name of the GAMG type. 1468 - create - function for creating the gamg context. 1469 1470 Level: advanced 1471 1472 .seealso: PCGAMGType, PCGAMG, PCGAMGSetType() 1473 @*/ 1474 PetscErrorCode PCGAMGRegister(PCGAMGType type, PetscErrorCode (*create)(PC)) 1475 { 1476 PetscErrorCode ierr; 1477 1478 PetscFunctionBegin; 1479 ierr = PCGAMGInitializePackage();CHKERRQ(ierr); 1480 ierr = PetscFunctionListAdd(&GAMGList,type,create);CHKERRQ(ierr); 1481 PetscFunctionReturn(0); 1482 } 1483 1484