1 /* 2 GAMG geometric-algebric multigrid PC - Mark Adams 2011 3 */ 4 5 #include <../src/ksp/pc/impls/gamg/gamg.h> /*I "petscpc.h" I*/ 6 #include <petscblaslapack.h> 7 #include <petscdm.h> 8 #include <petsc/private/kspimpl.h> 9 10 typedef struct { 11 PetscInt nsmooths; 12 PetscBool sym_graph; 13 PetscInt square_graph; 14 } PC_GAMG_AGG; 15 16 /*@ 17 PCGAMGSetNSmooths - Set number of smoothing steps (1 is typical) 18 19 Logically Collective on PC 20 21 Input Parameters: 22 . pc - the preconditioner context 23 24 Options Database Key: 25 . -pc_gamg_agg_nsmooths <nsmooth, default=1> - number of smoothing steps to use with smooth aggregation 26 27 Level: intermediate 28 29 .seealso: () 30 @*/ 31 PetscErrorCode PCGAMGSetNSmooths(PC pc, PetscInt n) 32 { 33 PetscFunctionBegin; 34 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 35 PetscValidLogicalCollectiveInt(pc,n,2); 36 CHKERRQ(PetscTryMethod(pc,"PCGAMGSetNSmooths_C",(PC,PetscInt),(pc,n))); 37 PetscFunctionReturn(0); 38 } 39 40 static PetscErrorCode PCGAMGSetNSmooths_AGG(PC pc, PetscInt n) 41 { 42 PC_MG *mg = (PC_MG*)pc->data; 43 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 44 PC_GAMG_AGG *pc_gamg_agg = (PC_GAMG_AGG*)pc_gamg->subctx; 45 46 PetscFunctionBegin; 47 pc_gamg_agg->nsmooths = n; 48 PetscFunctionReturn(0); 49 } 50 51 /*@ 52 PCGAMGSetSymGraph - Symmetrize the graph before computing the aggregation. Some algorithms require the graph be symmetric 53 54 Logically Collective on PC 55 56 Input Parameters: 57 + pc - the preconditioner context 58 - n - PETSC_TRUE or PETSC_FALSE 59 60 Options Database Key: 61 . -pc_gamg_sym_graph <true,default=false> - symmetrize the graph before computing the aggregation 62 63 Level: intermediate 64 65 .seealso: PCGAMGSetSquareGraph() 66 @*/ 67 PetscErrorCode PCGAMGSetSymGraph(PC pc, PetscBool n) 68 { 69 PetscFunctionBegin; 70 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 71 PetscValidLogicalCollectiveBool(pc,n,2); 72 CHKERRQ(PetscTryMethod(pc,"PCGAMGSetSymGraph_C",(PC,PetscBool),(pc,n))); 73 PetscFunctionReturn(0); 74 } 75 76 static PetscErrorCode PCGAMGSetSymGraph_AGG(PC pc, PetscBool n) 77 { 78 PC_MG *mg = (PC_MG*)pc->data; 79 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 80 PC_GAMG_AGG *pc_gamg_agg = (PC_GAMG_AGG*)pc_gamg->subctx; 81 82 PetscFunctionBegin; 83 pc_gamg_agg->sym_graph = n; 84 PetscFunctionReturn(0); 85 } 86 87 /*@ 88 PCGAMGSetSquareGraph - Square the graph, ie. compute A'*A before aggregating it 89 90 Logically Collective on PC 91 92 Input Parameters: 93 + pc - the preconditioner context 94 - n - 0, 1 or more 95 96 Options Database Key: 97 . -pc_gamg_square_graph <n,default = 1> - number of levels to square the graph on before aggregating it 98 99 Notes: 100 Squaring the graph 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. 101 102 Level: intermediate 103 104 .seealso: PCGAMGSetSymGraph(), PCGAMGSetThreshold() 105 @*/ 106 PetscErrorCode PCGAMGSetSquareGraph(PC pc, PetscInt n) 107 { 108 PetscFunctionBegin; 109 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 110 PetscValidLogicalCollectiveInt(pc,n,2); 111 CHKERRQ(PetscTryMethod(pc,"PCGAMGSetSquareGraph_C",(PC,PetscInt),(pc,n))); 112 PetscFunctionReturn(0); 113 } 114 115 static PetscErrorCode PCGAMGSetSquareGraph_AGG(PC pc, PetscInt n) 116 { 117 PC_MG *mg = (PC_MG*)pc->data; 118 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 119 PC_GAMG_AGG *pc_gamg_agg = (PC_GAMG_AGG*)pc_gamg->subctx; 120 121 PetscFunctionBegin; 122 pc_gamg_agg->square_graph = n; 123 PetscFunctionReturn(0); 124 } 125 126 static PetscErrorCode PCSetFromOptions_GAMG_AGG(PetscOptionItems *PetscOptionsObject,PC pc) 127 { 128 PC_MG *mg = (PC_MG*)pc->data; 129 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 130 PC_GAMG_AGG *pc_gamg_agg = (PC_GAMG_AGG*)pc_gamg->subctx; 131 132 PetscFunctionBegin; 133 CHKERRQ(PetscOptionsHead(PetscOptionsObject,"GAMG-AGG options")); 134 { 135 CHKERRQ(PetscOptionsInt("-pc_gamg_agg_nsmooths","smoothing steps for smoothed aggregation, usually 1","PCGAMGSetNSmooths",pc_gamg_agg->nsmooths,&pc_gamg_agg->nsmooths,NULL)); 136 CHKERRQ(PetscOptionsBool("-pc_gamg_sym_graph","Set for asymmetric matrices","PCGAMGSetSymGraph",pc_gamg_agg->sym_graph,&pc_gamg_agg->sym_graph,NULL)); 137 CHKERRQ(PetscOptionsInt("-pc_gamg_square_graph","Number of levels to square graph for faster coarsening and lower coarse grid complexity","PCGAMGSetSquareGraph",pc_gamg_agg->square_graph,&pc_gamg_agg->square_graph,NULL)); 138 } 139 CHKERRQ(PetscOptionsTail()); 140 PetscFunctionReturn(0); 141 } 142 143 /* -------------------------------------------------------------------------- */ 144 static PetscErrorCode PCDestroy_GAMG_AGG(PC pc) 145 { 146 PC_MG *mg = (PC_MG*)pc->data; 147 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 148 149 PetscFunctionBegin; 150 CHKERRQ(PetscFree(pc_gamg->subctx)); 151 CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCSetCoordinates_C",NULL)); 152 PetscFunctionReturn(0); 153 } 154 155 /* -------------------------------------------------------------------------- */ 156 /* 157 PCSetCoordinates_AGG 158 - collective 159 160 Input Parameter: 161 . pc - the preconditioner context 162 . ndm - dimesion of data (used for dof/vertex for Stokes) 163 . a_nloc - number of vertices local 164 . coords - [a_nloc][ndm] - interleaved coordinate data: {x_0, y_0, z_0, x_1, y_1, ...} 165 */ 166 167 static PetscErrorCode PCSetCoordinates_AGG(PC pc, PetscInt ndm, PetscInt a_nloc, PetscReal *coords) 168 { 169 PC_MG *mg = (PC_MG*)pc->data; 170 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 171 PetscInt arrsz,kk,ii,jj,nloc,ndatarows,ndf; 172 Mat mat = pc->pmat; 173 174 PetscFunctionBegin; 175 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 176 PetscValidHeaderSpecific(mat,MAT_CLASSID,1); 177 nloc = a_nloc; 178 179 /* SA: null space vectors */ 180 CHKERRQ(MatGetBlockSize(mat, &ndf)); /* this does not work for Stokes */ 181 if (coords && ndf==1) pc_gamg->data_cell_cols = 1; /* scalar w/ coords and SA (not needed) */ 182 else if (coords) { 183 PetscCheckFalse(ndm > ndf,PETSC_COMM_SELF,PETSC_ERR_PLIB,"degrees of motion %D > block size %D",ndm,ndf); 184 pc_gamg->data_cell_cols = (ndm==2 ? 3 : 6); /* displacement elasticity */ 185 if (ndm != ndf) { 186 PetscCheckFalse(pc_gamg->data_cell_cols != ndf,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Don't know how to create null space for ndm=%D, ndf=%D. Use MatSetNearNullSpace().",ndm,ndf); 187 } 188 } else pc_gamg->data_cell_cols = ndf; /* no data, force SA with constant null space vectors */ 189 pc_gamg->data_cell_rows = ndatarows = ndf; 190 PetscCheckFalse(pc_gamg->data_cell_cols <= 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"pc_gamg->data_cell_cols %D <= 0",pc_gamg->data_cell_cols); 191 arrsz = nloc*pc_gamg->data_cell_rows*pc_gamg->data_cell_cols; 192 193 if (!pc_gamg->data || (pc_gamg->data_sz != arrsz)) { 194 CHKERRQ(PetscFree(pc_gamg->data)); 195 CHKERRQ(PetscMalloc1(arrsz+1, &pc_gamg->data)); 196 } 197 /* copy data in - column oriented */ 198 for (kk=0; kk<nloc; kk++) { 199 const PetscInt M = nloc*pc_gamg->data_cell_rows; /* stride into data */ 200 PetscReal *data = &pc_gamg->data[kk*ndatarows]; /* start of cell */ 201 if (pc_gamg->data_cell_cols==1) *data = 1.0; 202 else { 203 /* translational modes */ 204 for (ii=0;ii<ndatarows;ii++) { 205 for (jj=0;jj<ndatarows;jj++) { 206 if (ii==jj)data[ii*M + jj] = 1.0; 207 else data[ii*M + jj] = 0.0; 208 } 209 } 210 211 /* rotational modes */ 212 if (coords) { 213 if (ndm == 2) { 214 data += 2*M; 215 data[0] = -coords[2*kk+1]; 216 data[1] = coords[2*kk]; 217 } else { 218 data += 3*M; 219 data[0] = 0.0; data[M+0] = coords[3*kk+2]; data[2*M+0] = -coords[3*kk+1]; 220 data[1] = -coords[3*kk+2]; data[M+1] = 0.0; data[2*M+1] = coords[3*kk]; 221 data[2] = coords[3*kk+1]; data[M+2] = -coords[3*kk]; data[2*M+2] = 0.0; 222 } 223 } 224 } 225 } 226 pc_gamg->data_sz = arrsz; 227 PetscFunctionReturn(0); 228 } 229 230 typedef PetscInt NState; 231 static const NState NOT_DONE=-2; 232 static const NState DELETED =-1; 233 static const NState REMOVED =-3; 234 #define IS_SELECTED(s) (s!=DELETED && s!=NOT_DONE && s!=REMOVED) 235 236 /* -------------------------------------------------------------------------- */ 237 /* 238 smoothAggs - greedy grab of with G1 (unsquared graph) -- AIJ specific 239 - AGG-MG specific: clears singletons out of 'selected_2' 240 241 Input Parameter: 242 . Gmat_2 - global matrix of graph (data not defined) base (squared) graph 243 . Gmat_1 - base graph to grab with base graph 244 Input/Output Parameter: 245 . aggs_2 - linked list of aggs with gids) 246 */ 247 static PetscErrorCode smoothAggs(PC pc,Mat Gmat_2, Mat Gmat_1,PetscCoarsenData *aggs_2) 248 { 249 PetscBool isMPI; 250 Mat_SeqAIJ *matA_1, *matB_1=NULL; 251 MPI_Comm comm; 252 PetscInt lid,*ii,*idx,ix,Iend,my0,kk,n,j; 253 Mat_MPIAIJ *mpimat_2 = NULL, *mpimat_1=NULL; 254 const PetscInt nloc = Gmat_2->rmap->n; 255 PetscScalar *cpcol_1_state,*cpcol_2_state,*cpcol_2_par_orig,*lid_parent_gid; 256 PetscInt *lid_cprowID_1; 257 NState *lid_state; 258 Vec ghost_par_orig2; 259 260 PetscFunctionBegin; 261 CHKERRQ(PetscObjectGetComm((PetscObject)Gmat_2,&comm)); 262 CHKERRQ(MatGetOwnershipRange(Gmat_1,&my0,&Iend)); 263 264 /* get submatrices */ 265 CHKERRQ(PetscStrbeginswith(((PetscObject)Gmat_1)->type_name,MATMPIAIJ,&isMPI)); 266 if (isMPI) { 267 /* grab matrix objects */ 268 mpimat_2 = (Mat_MPIAIJ*)Gmat_2->data; 269 mpimat_1 = (Mat_MPIAIJ*)Gmat_1->data; 270 matA_1 = (Mat_SeqAIJ*)mpimat_1->A->data; 271 matB_1 = (Mat_SeqAIJ*)mpimat_1->B->data; 272 273 /* force compressed row storage for B matrix in AuxMat */ 274 CHKERRQ(MatCheckCompressedRow(mpimat_1->B,matB_1->nonzerorowcnt,&matB_1->compressedrow,matB_1->i,Gmat_1->rmap->n,-1.0)); 275 276 CHKERRQ(PetscMalloc1(nloc, &lid_cprowID_1)); 277 for (lid = 0; lid < nloc; lid++) lid_cprowID_1[lid] = -1; 278 for (ix=0; ix<matB_1->compressedrow.nrows; ix++) { 279 PetscInt lid = matB_1->compressedrow.rindex[ix]; 280 lid_cprowID_1[lid] = ix; 281 } 282 } else { 283 PetscBool isAIJ; 284 CHKERRQ(PetscStrbeginswith(((PetscObject)Gmat_1)->type_name,MATSEQAIJ,&isAIJ)); 285 PetscCheck(isAIJ,PETSC_COMM_SELF,PETSC_ERR_USER,"Require AIJ matrix."); 286 matA_1 = (Mat_SeqAIJ*)Gmat_1->data; 287 lid_cprowID_1 = NULL; 288 } 289 if (nloc>0) { 290 PetscCheckFalse(matB_1 && !matB_1->compressedrow.use,PETSC_COMM_SELF,PETSC_ERR_PLIB,"matB_1 && !matB_1->compressedrow.use: PETSc bug???"); 291 } 292 /* get state of locals and selected gid for deleted */ 293 CHKERRQ(PetscMalloc2(nloc, &lid_state,nloc, &lid_parent_gid)); 294 for (lid = 0; lid < nloc; lid++) { 295 lid_parent_gid[lid] = -1.0; 296 lid_state[lid] = DELETED; 297 } 298 299 /* set lid_state */ 300 for (lid = 0; lid < nloc; lid++) { 301 PetscCDIntNd *pos; 302 CHKERRQ(PetscCDGetHeadPos(aggs_2,lid,&pos)); 303 if (pos) { 304 PetscInt gid1; 305 306 CHKERRQ(PetscCDIntNdGetID(pos, &gid1)); 307 PetscCheckFalse(gid1 != lid+my0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"gid1 %D != lid %D + my0 %D",gid1,lid,my0); 308 lid_state[lid] = gid1; 309 } 310 } 311 312 /* map local to selected local, DELETED means a ghost owns it */ 313 for (lid=kk=0; lid<nloc; lid++) { 314 NState state = lid_state[lid]; 315 if (IS_SELECTED(state)) { 316 PetscCDIntNd *pos; 317 CHKERRQ(PetscCDGetHeadPos(aggs_2,lid,&pos)); 318 while (pos) { 319 PetscInt gid1; 320 CHKERRQ(PetscCDIntNdGetID(pos, &gid1)); 321 CHKERRQ(PetscCDGetNextPos(aggs_2,lid,&pos)); 322 if (gid1 >= my0 && gid1 < Iend) lid_parent_gid[gid1-my0] = (PetscScalar)(lid + my0); 323 } 324 } 325 } 326 /* get 'cpcol_1/2_state' & cpcol_2_par_orig - uses mpimat_1/2->lvec for temp space */ 327 if (isMPI) { 328 Vec tempVec; 329 /* get 'cpcol_1_state' */ 330 CHKERRQ(MatCreateVecs(Gmat_1, &tempVec, NULL)); 331 for (kk=0,j=my0; kk<nloc; kk++,j++) { 332 PetscScalar v = (PetscScalar)lid_state[kk]; 333 CHKERRQ(VecSetValues(tempVec, 1, &j, &v, INSERT_VALUES)); 334 } 335 CHKERRQ(VecAssemblyBegin(tempVec)); 336 CHKERRQ(VecAssemblyEnd(tempVec)); 337 CHKERRQ(VecScatterBegin(mpimat_1->Mvctx,tempVec, mpimat_1->lvec,INSERT_VALUES,SCATTER_FORWARD)); 338 CHKERRQ(VecScatterEnd(mpimat_1->Mvctx,tempVec, mpimat_1->lvec,INSERT_VALUES,SCATTER_FORWARD)); 339 CHKERRQ(VecGetArray(mpimat_1->lvec, &cpcol_1_state)); 340 /* get 'cpcol_2_state' */ 341 CHKERRQ(VecScatterBegin(mpimat_2->Mvctx,tempVec, mpimat_2->lvec,INSERT_VALUES,SCATTER_FORWARD)); 342 CHKERRQ(VecScatterEnd(mpimat_2->Mvctx,tempVec, mpimat_2->lvec,INSERT_VALUES,SCATTER_FORWARD)); 343 CHKERRQ(VecGetArray(mpimat_2->lvec, &cpcol_2_state)); 344 /* get 'cpcol_2_par_orig' */ 345 for (kk=0,j=my0; kk<nloc; kk++,j++) { 346 PetscScalar v = (PetscScalar)lid_parent_gid[kk]; 347 CHKERRQ(VecSetValues(tempVec, 1, &j, &v, INSERT_VALUES)); 348 } 349 CHKERRQ(VecAssemblyBegin(tempVec)); 350 CHKERRQ(VecAssemblyEnd(tempVec)); 351 CHKERRQ(VecDuplicate(mpimat_2->lvec, &ghost_par_orig2)); 352 CHKERRQ(VecScatterBegin(mpimat_2->Mvctx,tempVec, ghost_par_orig2,INSERT_VALUES,SCATTER_FORWARD)); 353 CHKERRQ(VecScatterEnd(mpimat_2->Mvctx,tempVec, ghost_par_orig2,INSERT_VALUES,SCATTER_FORWARD)); 354 CHKERRQ(VecGetArray(ghost_par_orig2, &cpcol_2_par_orig)); 355 356 CHKERRQ(VecDestroy(&tempVec)); 357 } /* ismpi */ 358 for (lid=0; lid<nloc; lid++) { 359 NState state = lid_state[lid]; 360 if (IS_SELECTED(state)) { 361 /* steal locals */ 362 ii = matA_1->i; n = ii[lid+1] - ii[lid]; 363 idx = matA_1->j + ii[lid]; 364 for (j=0; j<n; j++) { 365 PetscInt lidj = idx[j], sgid; 366 NState statej = lid_state[lidj]; 367 if (statej==DELETED && (sgid=(PetscInt)PetscRealPart(lid_parent_gid[lidj])) != lid+my0) { /* steal local */ 368 lid_parent_gid[lidj] = (PetscScalar)(lid+my0); /* send this if sgid is not local */ 369 if (sgid >= my0 && sgid < Iend) { /* I'm stealing this local from a local sgid */ 370 PetscInt hav=0,slid=sgid-my0,gidj=lidj+my0; 371 PetscCDIntNd *pos,*last=NULL; 372 /* looking for local from local so id_llist_2 works */ 373 CHKERRQ(PetscCDGetHeadPos(aggs_2,slid,&pos)); 374 while (pos) { 375 PetscInt gid; 376 CHKERRQ(PetscCDIntNdGetID(pos, &gid)); 377 if (gid == gidj) { 378 PetscCheck(last,PETSC_COMM_SELF,PETSC_ERR_PLIB,"last cannot be null"); 379 CHKERRQ(PetscCDRemoveNextNode(aggs_2, slid, last)); 380 CHKERRQ(PetscCDAppendNode(aggs_2, lid, pos)); 381 hav = 1; 382 break; 383 } else last = pos; 384 CHKERRQ(PetscCDGetNextPos(aggs_2,slid,&pos)); 385 } 386 if (hav != 1) { 387 PetscCheck(hav,PETSC_COMM_SELF,PETSC_ERR_PLIB,"failed to find adj in 'selected' lists - structurally unsymmetric matrix"); 388 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"found node %D times???",hav); 389 } 390 } else { /* I'm stealing this local, owned by a ghost */ 391 PetscCheckFalse(sgid != -1,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Mat has an un-symmetric graph. Use '-%spc_gamg_sym_graph true' to symmetrize the graph or '-%spc_gamg_threshold -1' if the matrix is structurally symmetric.",((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "",((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : ""); 392 CHKERRQ(PetscCDAppendID(aggs_2, lid, lidj+my0)); 393 } 394 } 395 } /* local neighbors */ 396 } else if (state == DELETED && lid_cprowID_1) { 397 PetscInt sgidold = (PetscInt)PetscRealPart(lid_parent_gid[lid]); 398 /* see if I have a selected ghost neighbor that will steal me */ 399 if ((ix=lid_cprowID_1[lid]) != -1) { 400 ii = matB_1->compressedrow.i; n = ii[ix+1] - ii[ix]; 401 idx = matB_1->j + ii[ix]; 402 for (j=0; j<n; j++) { 403 PetscInt cpid = idx[j]; 404 NState statej = (NState)PetscRealPart(cpcol_1_state[cpid]); 405 if (IS_SELECTED(statej) && sgidold != (PetscInt)statej) { /* ghost will steal this, remove from my list */ 406 lid_parent_gid[lid] = (PetscScalar)statej; /* send who selected */ 407 if (sgidold>=my0 && sgidold<Iend) { /* this was mine */ 408 PetscInt hav=0,oldslidj=sgidold-my0; 409 PetscCDIntNd *pos,*last=NULL; 410 /* remove from 'oldslidj' list */ 411 CHKERRQ(PetscCDGetHeadPos(aggs_2,oldslidj,&pos)); 412 while (pos) { 413 PetscInt gid; 414 CHKERRQ(PetscCDIntNdGetID(pos, &gid)); 415 if (lid+my0 == gid) { 416 /* id_llist_2[lastid] = id_llist_2[flid]; /\* remove lid from oldslidj list *\/ */ 417 PetscCheck(last,PETSC_COMM_SELF,PETSC_ERR_PLIB,"last cannot be null"); 418 CHKERRQ(PetscCDRemoveNextNode(aggs_2, oldslidj, last)); 419 /* ghost (PetscScalar)statej will add this later */ 420 hav = 1; 421 break; 422 } else last = pos; 423 CHKERRQ(PetscCDGetNextPos(aggs_2,oldslidj,&pos)); 424 } 425 if (hav != 1) { 426 PetscCheck(hav,PETSC_COMM_SELF,PETSC_ERR_PLIB,"failed to find adj in 'selected' lists - structurally unsymmetric matrix"); 427 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"found node %D times???",hav); 428 } 429 } else { 430 /* TODO: ghosts remove this later */ 431 } 432 } 433 } 434 } 435 } /* selected/deleted */ 436 } /* node loop */ 437 438 if (isMPI) { 439 PetscScalar *cpcol_2_parent,*cpcol_2_gid; 440 Vec tempVec,ghostgids2,ghostparents2; 441 PetscInt cpid,nghost_2; 442 PCGAMGHashTable gid_cpid; 443 444 CHKERRQ(VecGetSize(mpimat_2->lvec, &nghost_2)); 445 CHKERRQ(MatCreateVecs(Gmat_2, &tempVec, NULL)); 446 447 /* get 'cpcol_2_parent' */ 448 for (kk=0,j=my0; kk<nloc; kk++,j++) { 449 CHKERRQ(VecSetValues(tempVec, 1, &j, &lid_parent_gid[kk], INSERT_VALUES)); 450 } 451 CHKERRQ(VecAssemblyBegin(tempVec)); 452 CHKERRQ(VecAssemblyEnd(tempVec)); 453 CHKERRQ(VecDuplicate(mpimat_2->lvec, &ghostparents2)); 454 CHKERRQ(VecScatterBegin(mpimat_2->Mvctx,tempVec, ghostparents2,INSERT_VALUES,SCATTER_FORWARD)); 455 CHKERRQ(VecScatterEnd(mpimat_2->Mvctx,tempVec, ghostparents2,INSERT_VALUES,SCATTER_FORWARD)); 456 CHKERRQ(VecGetArray(ghostparents2, &cpcol_2_parent)); 457 458 /* get 'cpcol_2_gid' */ 459 for (kk=0,j=my0; kk<nloc; kk++,j++) { 460 PetscScalar v = (PetscScalar)j; 461 CHKERRQ(VecSetValues(tempVec, 1, &j, &v, INSERT_VALUES)); 462 } 463 CHKERRQ(VecAssemblyBegin(tempVec)); 464 CHKERRQ(VecAssemblyEnd(tempVec)); 465 CHKERRQ(VecDuplicate(mpimat_2->lvec, &ghostgids2)); 466 CHKERRQ(VecScatterBegin(mpimat_2->Mvctx,tempVec, ghostgids2,INSERT_VALUES,SCATTER_FORWARD)); 467 CHKERRQ(VecScatterEnd(mpimat_2->Mvctx,tempVec, ghostgids2,INSERT_VALUES,SCATTER_FORWARD)); 468 CHKERRQ(VecGetArray(ghostgids2, &cpcol_2_gid)); 469 CHKERRQ(VecDestroy(&tempVec)); 470 471 /* look for deleted ghosts and add to table */ 472 CHKERRQ(PCGAMGHashTableCreate(2*nghost_2+1, &gid_cpid)); 473 for (cpid = 0; cpid < nghost_2; cpid++) { 474 NState state = (NState)PetscRealPart(cpcol_2_state[cpid]); 475 if (state==DELETED) { 476 PetscInt sgid_new = (PetscInt)PetscRealPart(cpcol_2_parent[cpid]); 477 PetscInt sgid_old = (PetscInt)PetscRealPart(cpcol_2_par_orig[cpid]); 478 if (sgid_old == -1 && sgid_new != -1) { 479 PetscInt gid = (PetscInt)PetscRealPart(cpcol_2_gid[cpid]); 480 CHKERRQ(PCGAMGHashTableAdd(&gid_cpid, gid, cpid)); 481 } 482 } 483 } 484 485 /* look for deleted ghosts and see if they moved - remove it */ 486 for (lid=0; lid<nloc; lid++) { 487 NState state = lid_state[lid]; 488 if (IS_SELECTED(state)) { 489 PetscCDIntNd *pos,*last=NULL; 490 /* look for deleted ghosts and see if they moved */ 491 CHKERRQ(PetscCDGetHeadPos(aggs_2,lid,&pos)); 492 while (pos) { 493 PetscInt gid; 494 CHKERRQ(PetscCDIntNdGetID(pos, &gid)); 495 496 if (gid < my0 || gid >= Iend) { 497 CHKERRQ(PCGAMGHashTableFind(&gid_cpid, gid, &cpid)); 498 if (cpid != -1) { 499 /* a moved ghost - */ 500 /* id_llist_2[lastid] = id_llist_2[flid]; /\* remove 'flid' from list *\/ */ 501 CHKERRQ(PetscCDRemoveNextNode(aggs_2, lid, last)); 502 } else last = pos; 503 } else last = pos; 504 505 CHKERRQ(PetscCDGetNextPos(aggs_2,lid,&pos)); 506 } /* loop over list of deleted */ 507 } /* selected */ 508 } 509 CHKERRQ(PCGAMGHashTableDestroy(&gid_cpid)); 510 511 /* look at ghosts, see if they changed - and it */ 512 for (cpid = 0; cpid < nghost_2; cpid++) { 513 PetscInt sgid_new = (PetscInt)PetscRealPart(cpcol_2_parent[cpid]); 514 if (sgid_new >= my0 && sgid_new < Iend) { /* this is mine */ 515 PetscInt gid = (PetscInt)PetscRealPart(cpcol_2_gid[cpid]); 516 PetscInt slid_new=sgid_new-my0,hav=0; 517 PetscCDIntNd *pos; 518 519 /* search for this gid to see if I have it */ 520 CHKERRQ(PetscCDGetHeadPos(aggs_2,slid_new,&pos)); 521 while (pos) { 522 PetscInt gidj; 523 CHKERRQ(PetscCDIntNdGetID(pos, &gidj)); 524 CHKERRQ(PetscCDGetNextPos(aggs_2,slid_new,&pos)); 525 526 if (gidj == gid) { hav = 1; break; } 527 } 528 if (hav != 1) { 529 /* insert 'flidj' into head of llist */ 530 CHKERRQ(PetscCDAppendID(aggs_2, slid_new, gid)); 531 } 532 } 533 } 534 535 CHKERRQ(VecRestoreArray(mpimat_1->lvec, &cpcol_1_state)); 536 CHKERRQ(VecRestoreArray(mpimat_2->lvec, &cpcol_2_state)); 537 CHKERRQ(VecRestoreArray(ghostparents2, &cpcol_2_parent)); 538 CHKERRQ(VecRestoreArray(ghostgids2, &cpcol_2_gid)); 539 CHKERRQ(PetscFree(lid_cprowID_1)); 540 CHKERRQ(VecDestroy(&ghostgids2)); 541 CHKERRQ(VecDestroy(&ghostparents2)); 542 CHKERRQ(VecDestroy(&ghost_par_orig2)); 543 } 544 545 CHKERRQ(PetscFree2(lid_state,lid_parent_gid)); 546 PetscFunctionReturn(0); 547 } 548 549 /* -------------------------------------------------------------------------- */ 550 /* 551 PCSetData_AGG - called if data is not set with PCSetCoordinates. 552 Looks in Mat for near null space. 553 Does not work for Stokes 554 555 Input Parameter: 556 . pc - 557 . a_A - matrix to get (near) null space out of. 558 */ 559 static PetscErrorCode PCSetData_AGG(PC pc, Mat a_A) 560 { 561 PC_MG *mg = (PC_MG*)pc->data; 562 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 563 MatNullSpace mnull; 564 565 PetscFunctionBegin; 566 CHKERRQ(MatGetNearNullSpace(a_A, &mnull)); 567 if (!mnull) { 568 DM dm; 569 CHKERRQ(PCGetDM(pc, &dm)); 570 if (!dm) { 571 CHKERRQ(MatGetDM(a_A, &dm)); 572 } 573 if (dm) { 574 PetscObject deformation; 575 PetscInt Nf; 576 577 CHKERRQ(DMGetNumFields(dm, &Nf)); 578 if (Nf) { 579 CHKERRQ(DMGetField(dm, 0, NULL, &deformation)); 580 CHKERRQ(PetscObjectQuery((PetscObject)deformation,"nearnullspace",(PetscObject*)&mnull)); 581 if (!mnull) { 582 CHKERRQ(PetscObjectQuery((PetscObject)deformation,"nullspace",(PetscObject*)&mnull)); 583 } 584 } 585 } 586 } 587 588 if (!mnull) { 589 PetscInt bs,NN,MM; 590 CHKERRQ(MatGetBlockSize(a_A, &bs)); 591 CHKERRQ(MatGetLocalSize(a_A, &MM, &NN)); 592 PetscCheckFalse(MM % bs,PETSC_COMM_SELF,PETSC_ERR_PLIB,"MM %D must be divisible by bs %D",MM,bs); 593 CHKERRQ(PCSetCoordinates_AGG(pc, bs, MM/bs, NULL)); 594 } else { 595 PetscReal *nullvec; 596 PetscBool has_const; 597 PetscInt i,j,mlocal,nvec,bs; 598 const Vec *vecs; 599 const PetscScalar *v; 600 601 CHKERRQ(MatGetLocalSize(a_A,&mlocal,NULL)); 602 CHKERRQ(MatNullSpaceGetVecs(mnull, &has_const, &nvec, &vecs)); 603 pc_gamg->data_sz = (nvec+!!has_const)*mlocal; 604 CHKERRQ(PetscMalloc1((nvec+!!has_const)*mlocal,&nullvec)); 605 if (has_const) for (i=0; i<mlocal; i++) nullvec[i] = 1.0; 606 for (i=0; i<nvec; i++) { 607 CHKERRQ(VecGetArrayRead(vecs[i],&v)); 608 for (j=0; j<mlocal; j++) nullvec[(i+!!has_const)*mlocal + j] = PetscRealPart(v[j]); 609 CHKERRQ(VecRestoreArrayRead(vecs[i],&v)); 610 } 611 pc_gamg->data = nullvec; 612 pc_gamg->data_cell_cols = (nvec+!!has_const); 613 CHKERRQ(MatGetBlockSize(a_A, &bs)); 614 pc_gamg->data_cell_rows = bs; 615 } 616 PetscFunctionReturn(0); 617 } 618 619 /* -------------------------------------------------------------------------- */ 620 /* 621 formProl0 622 623 Input Parameter: 624 . agg_llists - list of arrays with aggregates -- list from selected vertices of aggregate unselected vertices 625 . bs - row block size 626 . nSAvec - column bs of new P 627 . my0crs - global index of start of locals 628 . data_stride - bs*(nloc nodes + ghost nodes) [data_stride][nSAvec] 629 . data_in[data_stride*nSAvec] - local data on fine grid 630 . flid_fgid[data_stride/bs] - make local to global IDs, includes ghosts in 'locals_llist' 631 Output Parameter: 632 . a_data_out - in with fine grid data (w/ghosts), out with coarse grid data 633 . a_Prol - prolongation operator 634 */ 635 static PetscErrorCode formProl0(PetscCoarsenData *agg_llists,PetscInt bs,PetscInt nSAvec,PetscInt my0crs,PetscInt data_stride,PetscReal data_in[],const PetscInt flid_fgid[],PetscReal **a_data_out,Mat a_Prol) 636 { 637 PetscInt Istart,my0,Iend,nloc,clid,flid = 0,aggID,kk,jj,ii,mm,nSelected,minsz,nghosts,out_data_stride; 638 MPI_Comm comm; 639 PetscReal *out_data; 640 PetscCDIntNd *pos; 641 PCGAMGHashTable fgid_flid; 642 643 PetscFunctionBegin; 644 CHKERRQ(PetscObjectGetComm((PetscObject)a_Prol,&comm)); 645 CHKERRQ(MatGetOwnershipRange(a_Prol, &Istart, &Iend)); 646 nloc = (Iend-Istart)/bs; my0 = Istart/bs; 647 PetscCheckFalse((Iend-Istart) % bs,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Iend %D - Istart %D must be divisible by bs %D",Iend,Istart,bs); 648 Iend /= bs; 649 nghosts = data_stride/bs - nloc; 650 651 CHKERRQ(PCGAMGHashTableCreate(2*nghosts+1, &fgid_flid)); 652 for (kk=0; kk<nghosts; kk++) { 653 CHKERRQ(PCGAMGHashTableAdd(&fgid_flid, flid_fgid[nloc+kk], nloc+kk)); 654 } 655 656 /* count selected -- same as number of cols of P */ 657 for (nSelected=mm=0; mm<nloc; mm++) { 658 PetscBool ise; 659 CHKERRQ(PetscCDEmptyAt(agg_llists, mm, &ise)); 660 if (!ise) nSelected++; 661 } 662 CHKERRQ(MatGetOwnershipRangeColumn(a_Prol, &ii, &jj)); 663 PetscCheckFalse((ii/nSAvec) != my0crs,PETSC_COMM_SELF,PETSC_ERR_PLIB,"ii %D /nSAvec %D != my0crs %D",ii,nSAvec,my0crs); 664 PetscCheckFalse(nSelected != (jj-ii)/nSAvec,PETSC_COMM_SELF,PETSC_ERR_PLIB,"nSelected %D != (jj %D - ii %D)/nSAvec %D",nSelected,jj,ii,nSAvec); 665 666 /* aloc space for coarse point data (output) */ 667 out_data_stride = nSelected*nSAvec; 668 669 CHKERRQ(PetscMalloc1(out_data_stride*nSAvec, &out_data)); 670 for (ii=0;ii<out_data_stride*nSAvec;ii++) out_data[ii]=PETSC_MAX_REAL; 671 *a_data_out = out_data; /* output - stride nSelected*nSAvec */ 672 673 /* find points and set prolongation */ 674 minsz = 100; 675 for (mm = clid = 0; mm < nloc; mm++) { 676 CHKERRQ(PetscCDSizeAt(agg_llists, mm, &jj)); 677 if (jj > 0) { 678 const PetscInt lid = mm, cgid = my0crs + clid; 679 PetscInt cids[100]; /* max bs */ 680 PetscBLASInt asz =jj,M=asz*bs,N=nSAvec,INFO; 681 PetscBLASInt Mdata=M+((N-M>0) ? N-M : 0),LDA=Mdata,LWORK=N*bs; 682 PetscScalar *qqc,*qqr,*TAU,*WORK; 683 PetscInt *fids; 684 PetscReal *data; 685 686 /* count agg */ 687 if (asz<minsz) minsz = asz; 688 689 /* get block */ 690 CHKERRQ(PetscMalloc5(Mdata*N, &qqc,M*N, &qqr,N, &TAU,LWORK, &WORK,M, &fids)); 691 692 aggID = 0; 693 CHKERRQ(PetscCDGetHeadPos(agg_llists,lid,&pos)); 694 while (pos) { 695 PetscInt gid1; 696 CHKERRQ(PetscCDIntNdGetID(pos, &gid1)); 697 CHKERRQ(PetscCDGetNextPos(agg_llists,lid,&pos)); 698 699 if (gid1 >= my0 && gid1 < Iend) flid = gid1 - my0; 700 else { 701 CHKERRQ(PCGAMGHashTableFind(&fgid_flid, gid1, &flid)); 702 PetscCheckFalse(flid < 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cannot find gid1 in table"); 703 } 704 /* copy in B_i matrix - column oriented */ 705 data = &data_in[flid*bs]; 706 for (ii = 0; ii < bs; ii++) { 707 for (jj = 0; jj < N; jj++) { 708 PetscReal d = data[jj*data_stride + ii]; 709 qqc[jj*Mdata + aggID*bs + ii] = d; 710 } 711 } 712 /* set fine IDs */ 713 for (kk=0; kk<bs; kk++) fids[aggID*bs + kk] = flid_fgid[flid]*bs + kk; 714 aggID++; 715 } 716 717 /* pad with zeros */ 718 for (ii = asz*bs; ii < Mdata; ii++) { 719 for (jj = 0; jj < N; jj++, kk++) { 720 qqc[jj*Mdata + ii] = .0; 721 } 722 } 723 724 /* QR */ 725 CHKERRQ(PetscFPTrapPush(PETSC_FP_TRAP_OFF)); 726 PetscStackCallBLAS("LAPACKgeqrf",LAPACKgeqrf_(&Mdata, &N, qqc, &LDA, TAU, WORK, &LWORK, &INFO)); 727 CHKERRQ(PetscFPTrapPop()); 728 PetscCheckFalse(INFO != 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"xGEQRF error"); 729 /* get R - column oriented - output B_{i+1} */ 730 { 731 PetscReal *data = &out_data[clid*nSAvec]; 732 for (jj = 0; jj < nSAvec; jj++) { 733 for (ii = 0; ii < nSAvec; ii++) { 734 PetscCheckFalse(data[jj*out_data_stride + ii] != PETSC_MAX_REAL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"data[jj*out_data_stride + ii] != %e",(double)PETSC_MAX_REAL); 735 if (ii <= jj) data[jj*out_data_stride + ii] = PetscRealPart(qqc[jj*Mdata + ii]); 736 else data[jj*out_data_stride + ii] = 0.; 737 } 738 } 739 } 740 741 /* get Q - row oriented */ 742 PetscStackCallBLAS("LAPACKorgqr",LAPACKorgqr_(&Mdata, &N, &N, qqc, &LDA, TAU, WORK, &LWORK, &INFO)); 743 PetscCheckFalse(INFO != 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"xORGQR error arg %d",-INFO); 744 745 for (ii = 0; ii < M; ii++) { 746 for (jj = 0; jj < N; jj++) { 747 qqr[N*ii + jj] = qqc[jj*Mdata + ii]; 748 } 749 } 750 751 /* add diagonal block of P0 */ 752 for (kk=0; kk<N; kk++) { 753 cids[kk] = N*cgid + kk; /* global col IDs in P0 */ 754 } 755 CHKERRQ(MatSetValues(a_Prol,M,fids,N,cids,qqr,INSERT_VALUES)); 756 CHKERRQ(PetscFree5(qqc,qqr,TAU,WORK,fids)); 757 clid++; 758 } /* coarse agg */ 759 } /* for all fine nodes */ 760 CHKERRQ(MatAssemblyBegin(a_Prol,MAT_FINAL_ASSEMBLY)); 761 CHKERRQ(MatAssemblyEnd(a_Prol,MAT_FINAL_ASSEMBLY)); 762 CHKERRQ(PCGAMGHashTableDestroy(&fgid_flid)); 763 PetscFunctionReturn(0); 764 } 765 766 static PetscErrorCode PCView_GAMG_AGG(PC pc,PetscViewer viewer) 767 { 768 PC_MG *mg = (PC_MG*)pc->data; 769 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 770 PC_GAMG_AGG *pc_gamg_agg = (PC_GAMG_AGG*)pc_gamg->subctx; 771 772 PetscFunctionBegin; 773 CHKERRQ(PetscViewerASCIIPrintf(viewer," AGG specific options\n")); 774 CHKERRQ(PetscViewerASCIIPrintf(viewer," Symmetric graph %s\n",pc_gamg_agg->sym_graph ? "true" : "false")); 775 CHKERRQ(PetscViewerASCIIPrintf(viewer," Number of levels to square graph %D\n",pc_gamg_agg->square_graph)); 776 CHKERRQ(PetscViewerASCIIPrintf(viewer," Number smoothing steps %D\n",pc_gamg_agg->nsmooths)); 777 PetscFunctionReturn(0); 778 } 779 780 /* -------------------------------------------------------------------------- */ 781 /* 782 PCGAMGGraph_AGG 783 784 Input Parameter: 785 . pc - this 786 . Amat - matrix on this fine level 787 Output Parameter: 788 . a_Gmat - 789 */ 790 static PetscErrorCode PCGAMGGraph_AGG(PC pc,Mat Amat,Mat *a_Gmat) 791 { 792 PC_MG *mg = (PC_MG*)pc->data; 793 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 794 const PetscReal vfilter = pc_gamg->threshold[pc_gamg->current_level]; 795 PC_GAMG_AGG *pc_gamg_agg = (PC_GAMG_AGG*)pc_gamg->subctx; 796 Mat Gmat; 797 MPI_Comm comm; 798 PetscBool /* set,flg , */ symm; 799 800 PetscFunctionBegin; 801 CHKERRQ(PetscObjectGetComm((PetscObject)Amat,&comm)); 802 CHKERRQ(PetscLogEventBegin(PC_GAMGGraph_AGG,0,0,0,0)); 803 804 /* CHKERRQ(MatIsSymmetricKnown(Amat, &set, &flg)); || !(set && flg) -- this causes lot of symm calls */ 805 symm = (PetscBool)(pc_gamg_agg->sym_graph); /* && !pc_gamg_agg->square_graph; */ 806 807 CHKERRQ(PCGAMGCreateGraph(Amat, &Gmat)); 808 CHKERRQ(PCGAMGFilterGraph(&Gmat, vfilter, symm)); 809 *a_Gmat = Gmat; 810 CHKERRQ(PetscLogEventEnd(PC_GAMGGraph_AGG,0,0,0,0)); 811 PetscFunctionReturn(0); 812 } 813 814 /* -------------------------------------------------------------------------- */ 815 /* 816 PCGAMGCoarsen_AGG 817 818 Input Parameter: 819 . a_pc - this 820 Input/Output Parameter: 821 . a_Gmat1 - graph on this fine level - coarsening can change this (squares it) 822 Output Parameter: 823 . agg_lists - list of aggregates 824 */ 825 static PetscErrorCode PCGAMGCoarsen_AGG(PC a_pc,Mat *a_Gmat1,PetscCoarsenData **agg_lists) 826 { 827 PC_MG *mg = (PC_MG*)a_pc->data; 828 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 829 PC_GAMG_AGG *pc_gamg_agg = (PC_GAMG_AGG*)pc_gamg->subctx; 830 Mat mat,Gmat2, Gmat1 = *a_Gmat1; /* squared graph */ 831 IS perm; 832 PetscInt Istart,Iend,Ii,nloc,bs,n,m; 833 PetscInt *permute; 834 PetscBool *bIndexSet; 835 MatCoarsen crs; 836 MPI_Comm comm; 837 PetscReal hashfact; 838 PetscInt iSwapIndex; 839 PetscRandom random; 840 841 PetscFunctionBegin; 842 CHKERRQ(PetscLogEventBegin(PC_GAMGCoarsen_AGG,0,0,0,0)); 843 CHKERRQ(PetscObjectGetComm((PetscObject)Gmat1,&comm)); 844 CHKERRQ(MatGetLocalSize(Gmat1, &n, &m)); 845 CHKERRQ(MatGetBlockSize(Gmat1, &bs)); 846 PetscCheckFalse(bs != 1,PETSC_COMM_SELF,PETSC_ERR_PLIB,"bs %D must be 1",bs); 847 nloc = n/bs; 848 849 if (pc_gamg->current_level < pc_gamg_agg->square_graph) { 850 CHKERRQ(PCGAMGSquareGraph_GAMG(a_pc,Gmat1,&Gmat2)); 851 } else Gmat2 = Gmat1; 852 853 /* get MIS aggs - randomize */ 854 CHKERRQ(PetscMalloc1(nloc, &permute)); 855 CHKERRQ(PetscCalloc1(nloc, &bIndexSet)); 856 for (Ii = 0; Ii < nloc; Ii++) permute[Ii] = Ii; 857 CHKERRQ(PetscRandomCreate(PETSC_COMM_SELF,&random)); 858 CHKERRQ(MatGetOwnershipRange(Gmat1, &Istart, &Iend)); 859 for (Ii = 0; Ii < nloc; Ii++) { 860 CHKERRQ(PetscRandomGetValueReal(random,&hashfact)); 861 iSwapIndex = (PetscInt) (hashfact*nloc)%nloc; 862 if (!bIndexSet[iSwapIndex] && iSwapIndex != Ii) { 863 PetscInt iTemp = permute[iSwapIndex]; 864 permute[iSwapIndex] = permute[Ii]; 865 permute[Ii] = iTemp; 866 bIndexSet[iSwapIndex] = PETSC_TRUE; 867 } 868 } 869 CHKERRQ(PetscFree(bIndexSet)); 870 CHKERRQ(PetscRandomDestroy(&random)); 871 CHKERRQ(ISCreateGeneral(PETSC_COMM_SELF, nloc, permute, PETSC_USE_POINTER, &perm)); 872 CHKERRQ(PetscLogEventBegin(petsc_gamg_setup_events[SET4],0,0,0,0)); 873 CHKERRQ(MatCoarsenCreate(comm, &crs)); 874 CHKERRQ(MatCoarsenSetFromOptions(crs)); 875 CHKERRQ(MatCoarsenSetGreedyOrdering(crs, perm)); 876 CHKERRQ(MatCoarsenSetAdjacency(crs, Gmat2)); 877 CHKERRQ(MatCoarsenSetStrictAggs(crs, PETSC_TRUE)); 878 CHKERRQ(MatCoarsenApply(crs)); 879 CHKERRQ(MatCoarsenGetData(crs, agg_lists)); /* output */ 880 CHKERRQ(MatCoarsenDestroy(&crs)); 881 882 CHKERRQ(ISDestroy(&perm)); 883 CHKERRQ(PetscFree(permute)); 884 CHKERRQ(PetscLogEventEnd(petsc_gamg_setup_events[SET4],0,0,0,0)); 885 886 /* smooth aggs */ 887 if (Gmat2 != Gmat1) { 888 const PetscCoarsenData *llist = *agg_lists; 889 CHKERRQ(smoothAggs(a_pc,Gmat2, Gmat1, *agg_lists)); 890 CHKERRQ(MatDestroy(&Gmat1)); 891 *a_Gmat1 = Gmat2; /* output */ 892 CHKERRQ(PetscCDGetMat(llist, &mat)); 893 PetscCheck(!mat,comm,PETSC_ERR_ARG_WRONG, "Auxilary matrix with squared graph????"); 894 } else { 895 const PetscCoarsenData *llist = *agg_lists; 896 /* see if we have a matrix that takes precedence (returned from MatCoarsenApply) */ 897 CHKERRQ(PetscCDGetMat(llist, &mat)); 898 if (mat) { 899 CHKERRQ(MatDestroy(&Gmat1)); 900 *a_Gmat1 = mat; /* output */ 901 } 902 } 903 CHKERRQ(PetscLogEventEnd(PC_GAMGCoarsen_AGG,0,0,0,0)); 904 PetscFunctionReturn(0); 905 } 906 907 /* -------------------------------------------------------------------------- */ 908 /* 909 PCGAMGProlongator_AGG 910 911 Input Parameter: 912 . pc - this 913 . Amat - matrix on this fine level 914 . Graph - used to get ghost data for nodes in 915 . agg_lists - list of aggregates 916 Output Parameter: 917 . a_P_out - prolongation operator to the next level 918 */ 919 static PetscErrorCode PCGAMGProlongator_AGG(PC pc,Mat Amat,Mat Gmat,PetscCoarsenData *agg_lists,Mat *a_P_out) 920 { 921 PC_MG *mg = (PC_MG*)pc->data; 922 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 923 const PetscInt col_bs = pc_gamg->data_cell_cols; 924 PetscInt Istart,Iend,nloc,ii,jj,kk,my0,nLocalSelected,bs; 925 Mat Prol; 926 PetscMPIInt size; 927 MPI_Comm comm; 928 PetscReal *data_w_ghost; 929 PetscInt myCrs0, nbnodes=0, *flid_fgid; 930 MatType mtype; 931 932 PetscFunctionBegin; 933 CHKERRQ(PetscObjectGetComm((PetscObject)Amat,&comm)); 934 PetscCheckFalse(col_bs < 1,comm,PETSC_ERR_PLIB,"Column bs cannot be less than 1"); 935 CHKERRQ(PetscLogEventBegin(PC_GAMGProlongator_AGG,0,0,0,0)); 936 CHKERRMPI(MPI_Comm_size(comm, &size)); 937 CHKERRQ(MatGetOwnershipRange(Amat, &Istart, &Iend)); 938 CHKERRQ(MatGetBlockSize(Amat, &bs)); 939 nloc = (Iend-Istart)/bs; my0 = Istart/bs; 940 PetscCheckFalse((Iend-Istart) % bs,PETSC_COMM_SELF,PETSC_ERR_PLIB,"(Iend %D - Istart %D) not divisible by bs %D",Iend,Istart,bs); 941 942 /* get 'nLocalSelected' */ 943 for (ii=0, nLocalSelected = 0; ii < nloc; ii++) { 944 PetscBool ise; 945 /* filter out singletons 0 or 1? */ 946 CHKERRQ(PetscCDEmptyAt(agg_lists, ii, &ise)); 947 if (!ise) nLocalSelected++; 948 } 949 950 /* create prolongator, create P matrix */ 951 CHKERRQ(MatGetType(Amat,&mtype)); 952 CHKERRQ(MatCreate(comm, &Prol)); 953 CHKERRQ(MatSetSizes(Prol,nloc*bs,nLocalSelected*col_bs,PETSC_DETERMINE,PETSC_DETERMINE)); 954 CHKERRQ(MatSetBlockSizes(Prol, bs, col_bs)); 955 CHKERRQ(MatSetType(Prol, mtype)); 956 CHKERRQ(MatSeqAIJSetPreallocation(Prol,col_bs, NULL)); 957 CHKERRQ(MatMPIAIJSetPreallocation(Prol,col_bs, NULL, col_bs, NULL)); 958 959 /* can get all points "removed" */ 960 CHKERRQ(MatGetSize(Prol, &kk, &ii)); 961 if (!ii) { 962 CHKERRQ(PetscInfo(pc,"%s: No selected points on coarse grid\n")); 963 CHKERRQ(MatDestroy(&Prol)); 964 *a_P_out = NULL; /* out */ 965 CHKERRQ(PetscLogEventEnd(PC_GAMGProlongator_AGG,0,0,0,0)); 966 PetscFunctionReturn(0); 967 } 968 CHKERRQ(PetscInfo(pc,"%s: New grid %D nodes\n",((PetscObject)pc)->prefix,ii/col_bs)); 969 CHKERRQ(MatGetOwnershipRangeColumn(Prol, &myCrs0, &kk)); 970 971 PetscCheckFalse((kk-myCrs0) % col_bs,PETSC_COMM_SELF,PETSC_ERR_PLIB,"(kk %D -myCrs0 %D) not divisible by col_bs %D",kk,myCrs0,col_bs); 972 myCrs0 = myCrs0/col_bs; 973 PetscCheckFalse((kk/col_bs-myCrs0) != nLocalSelected,PETSC_COMM_SELF,PETSC_ERR_PLIB,"(kk %D/col_bs %D - myCrs0 %D) != nLocalSelected %D)",kk,col_bs,myCrs0,nLocalSelected); 974 975 /* create global vector of data in 'data_w_ghost' */ 976 CHKERRQ(PetscLogEventBegin(petsc_gamg_setup_events[SET7],0,0,0,0)); 977 if (size > 1) { /* */ 978 PetscReal *tmp_gdata,*tmp_ldata,*tp2; 979 CHKERRQ(PetscMalloc1(nloc, &tmp_ldata)); 980 for (jj = 0; jj < col_bs; jj++) { 981 for (kk = 0; kk < bs; kk++) { 982 PetscInt ii,stride; 983 const PetscReal *tp = pc_gamg->data + jj*bs*nloc + kk; 984 for (ii = 0; ii < nloc; ii++, tp += bs) tmp_ldata[ii] = *tp; 985 986 CHKERRQ(PCGAMGGetDataWithGhosts(Gmat, 1, tmp_ldata, &stride, &tmp_gdata)); 987 988 if (!jj && !kk) { /* now I know how many todal nodes - allocate */ 989 CHKERRQ(PetscMalloc1(stride*bs*col_bs, &data_w_ghost)); 990 nbnodes = bs*stride; 991 } 992 tp2 = data_w_ghost + jj*bs*stride + kk; 993 for (ii = 0; ii < stride; ii++, tp2 += bs) *tp2 = tmp_gdata[ii]; 994 CHKERRQ(PetscFree(tmp_gdata)); 995 } 996 } 997 CHKERRQ(PetscFree(tmp_ldata)); 998 } else { 999 nbnodes = bs*nloc; 1000 data_w_ghost = (PetscReal*)pc_gamg->data; 1001 } 1002 1003 /* get P0 */ 1004 if (size > 1) { 1005 PetscReal *fid_glid_loc,*fiddata; 1006 PetscInt stride; 1007 1008 CHKERRQ(PetscMalloc1(nloc, &fid_glid_loc)); 1009 for (kk=0; kk<nloc; kk++) fid_glid_loc[kk] = (PetscReal)(my0+kk); 1010 CHKERRQ(PCGAMGGetDataWithGhosts(Gmat, 1, fid_glid_loc, &stride, &fiddata)); 1011 CHKERRQ(PetscMalloc1(stride, &flid_fgid)); 1012 for (kk=0; kk<stride; kk++) flid_fgid[kk] = (PetscInt)fiddata[kk]; 1013 CHKERRQ(PetscFree(fiddata)); 1014 1015 PetscCheckFalse(stride != nbnodes/bs,PETSC_COMM_SELF,PETSC_ERR_PLIB,"stride %D != nbnodes %D/bs %D",stride,nbnodes,bs); 1016 CHKERRQ(PetscFree(fid_glid_loc)); 1017 } else { 1018 CHKERRQ(PetscMalloc1(nloc, &flid_fgid)); 1019 for (kk=0; kk<nloc; kk++) flid_fgid[kk] = my0 + kk; 1020 } 1021 CHKERRQ(PetscLogEventEnd(petsc_gamg_setup_events[SET7],0,0,0,0)); 1022 CHKERRQ(PetscLogEventBegin(petsc_gamg_setup_events[SET8],0,0,0,0)); 1023 { 1024 PetscReal *data_out = NULL; 1025 CHKERRQ(formProl0(agg_lists, bs, col_bs, myCrs0, nbnodes,data_w_ghost, flid_fgid, &data_out, Prol)); 1026 CHKERRQ(PetscFree(pc_gamg->data)); 1027 1028 pc_gamg->data = data_out; 1029 pc_gamg->data_cell_rows = col_bs; 1030 pc_gamg->data_sz = col_bs*col_bs*nLocalSelected; 1031 } 1032 CHKERRQ(PetscLogEventEnd(petsc_gamg_setup_events[SET8],0,0,0,0)); 1033 if (size > 1) CHKERRQ(PetscFree(data_w_ghost)); 1034 CHKERRQ(PetscFree(flid_fgid)); 1035 1036 *a_P_out = Prol; /* out */ 1037 1038 CHKERRQ(PetscLogEventEnd(PC_GAMGProlongator_AGG,0,0,0,0)); 1039 PetscFunctionReturn(0); 1040 } 1041 1042 /* -------------------------------------------------------------------------- */ 1043 /* 1044 PCGAMGOptProlongator_AGG 1045 1046 Input Parameter: 1047 . pc - this 1048 . Amat - matrix on this fine level 1049 In/Output Parameter: 1050 . a_P - prolongation operator to the next level 1051 */ 1052 static PetscErrorCode PCGAMGOptProlongator_AGG(PC pc,Mat Amat,Mat *a_P) 1053 { 1054 PC_MG *mg = (PC_MG*)pc->data; 1055 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1056 PC_GAMG_AGG *pc_gamg_agg = (PC_GAMG_AGG*)pc_gamg->subctx; 1057 PetscInt jj; 1058 Mat Prol = *a_P; 1059 MPI_Comm comm; 1060 KSP eksp; 1061 Vec bb, xx; 1062 PC epc; 1063 PetscReal alpha, emax, emin; 1064 1065 PetscFunctionBegin; 1066 CHKERRQ(PetscObjectGetComm((PetscObject)Amat,&comm)); 1067 CHKERRQ(PetscLogEventBegin(PC_GAMGOptProlongator_AGG,0,0,0,0)); 1068 1069 /* compute maximum singular value of operator to be used in smoother */ 1070 if (0 < pc_gamg_agg->nsmooths) { 1071 /* get eigen estimates */ 1072 if (pc_gamg->emax > 0) { 1073 emin = pc_gamg->emin; 1074 emax = pc_gamg->emax; 1075 } else { 1076 const char *prefix; 1077 1078 CHKERRQ(MatCreateVecs(Amat, &bb, NULL)); 1079 CHKERRQ(MatCreateVecs(Amat, &xx, NULL)); 1080 CHKERRQ(KSPSetNoisy_Private(bb)); 1081 1082 CHKERRQ(KSPCreate(comm,&eksp)); 1083 CHKERRQ(PCGetOptionsPrefix(pc,&prefix)); 1084 CHKERRQ(KSPSetOptionsPrefix(eksp,prefix)); 1085 CHKERRQ(KSPAppendOptionsPrefix(eksp,"pc_gamg_esteig_")); 1086 { 1087 PetscBool sflg; 1088 CHKERRQ(MatGetOption(Amat, MAT_SPD, &sflg)); 1089 if (sflg) { 1090 CHKERRQ(KSPSetType(eksp, KSPCG)); 1091 } 1092 } 1093 CHKERRQ(KSPSetErrorIfNotConverged(eksp,pc->erroriffailure)); 1094 CHKERRQ(KSPSetNormType(eksp, KSP_NORM_NONE)); 1095 1096 CHKERRQ(KSPSetInitialGuessNonzero(eksp, PETSC_FALSE)); 1097 CHKERRQ(KSPSetOperators(eksp, Amat, Amat)); 1098 1099 CHKERRQ(KSPGetPC(eksp, &epc)); 1100 CHKERRQ(PCSetType(epc, PCJACOBI)); /* smoother in smoothed agg. */ 1101 1102 CHKERRQ(KSPSetTolerances(eksp,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT, 10)); // 10 is safer, but 5 is often fine, can override with -pc_gamg_esteig_ksp_max_it -mg_levels_ksp_chebyshev_esteig 0,0.25,0,1.2 1103 1104 CHKERRQ(KSPSetFromOptions(eksp)); 1105 CHKERRQ(KSPSetComputeSingularValues(eksp,PETSC_TRUE)); 1106 CHKERRQ(KSPSolve(eksp, bb, xx)); 1107 CHKERRQ(KSPCheckSolve(eksp,pc,xx)); 1108 1109 CHKERRQ(KSPComputeExtremeSingularValues(eksp, &emax, &emin)); 1110 CHKERRQ(PetscInfo(pc,"%s: Smooth P0: max eigen=%e min=%e PC=%s\n",((PetscObject)pc)->prefix,(double)emax,(double)emin,PCJACOBI)); 1111 CHKERRQ(VecDestroy(&xx)); 1112 CHKERRQ(VecDestroy(&bb)); 1113 CHKERRQ(KSPDestroy(&eksp)); 1114 } 1115 if (pc_gamg->use_sa_esteig) { 1116 mg->min_eigen_DinvA[pc_gamg->current_level] = emin; 1117 mg->max_eigen_DinvA[pc_gamg->current_level] = emax; 1118 CHKERRQ(PetscInfo(pc,"%s: Smooth P0: level %D, cache spectra %g %g\n",((PetscObject)pc)->prefix,pc_gamg->current_level,(double)emin,(double)emax)); 1119 } else { 1120 mg->min_eigen_DinvA[pc_gamg->current_level] = 0; 1121 mg->max_eigen_DinvA[pc_gamg->current_level] = 0; 1122 } 1123 } else { 1124 mg->min_eigen_DinvA[pc_gamg->current_level] = 0; 1125 mg->max_eigen_DinvA[pc_gamg->current_level] = 0; 1126 } 1127 1128 /* smooth P0 */ 1129 for (jj = 0; jj < pc_gamg_agg->nsmooths; jj++) { 1130 Mat tMat; 1131 Vec diag; 1132 1133 CHKERRQ(PetscLogEventBegin(petsc_gamg_setup_events[SET9],0,0,0,0)); 1134 1135 /* smooth P1 := (I - omega/lam D^{-1}A)P0 */ 1136 CHKERRQ(PetscLogEventBegin(petsc_gamg_setup_matmat_events[pc_gamg->current_level][2],0,0,0,0)); 1137 CHKERRQ(MatMatMult(Amat, Prol, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &tMat)); 1138 CHKERRQ(PetscLogEventEnd(petsc_gamg_setup_matmat_events[pc_gamg->current_level][2],0,0,0,0)); 1139 CHKERRQ(MatProductClear(tMat)); 1140 CHKERRQ(MatCreateVecs(Amat, &diag, NULL)); 1141 CHKERRQ(MatGetDiagonal(Amat, diag)); /* effectively PCJACOBI */ 1142 CHKERRQ(VecReciprocal(diag)); 1143 CHKERRQ(MatDiagonalScale(tMat, diag, NULL)); 1144 CHKERRQ(VecDestroy(&diag)); 1145 1146 /* TODO: Set a PCFailedReason and exit the building of the AMG preconditioner */ 1147 PetscCheckFalse(emax == 0.0,PetscObjectComm((PetscObject)pc),PETSC_ERR_PLIB,"Computed maximum singular value as zero"); 1148 /* TODO: Document the 1.4 and don't hardwire it in this routine */ 1149 alpha = -1.4/emax; 1150 1151 CHKERRQ(MatAYPX(tMat, alpha, Prol, SUBSET_NONZERO_PATTERN)); 1152 CHKERRQ(MatDestroy(&Prol)); 1153 Prol = tMat; 1154 CHKERRQ(PetscLogEventEnd(petsc_gamg_setup_events[SET9],0,0,0,0)); 1155 } 1156 CHKERRQ(PetscLogEventEnd(PC_GAMGOptProlongator_AGG,0,0,0,0)); 1157 *a_P = Prol; 1158 PetscFunctionReturn(0); 1159 } 1160 1161 /* -------------------------------------------------------------------------- */ 1162 /* 1163 PCCreateGAMG_AGG 1164 1165 Input Parameter: 1166 . pc - 1167 */ 1168 PetscErrorCode PCCreateGAMG_AGG(PC pc) 1169 { 1170 PC_MG *mg = (PC_MG*)pc->data; 1171 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 1172 PC_GAMG_AGG *pc_gamg_agg; 1173 1174 PetscFunctionBegin; 1175 /* create sub context for SA */ 1176 CHKERRQ(PetscNewLog(pc,&pc_gamg_agg)); 1177 pc_gamg->subctx = pc_gamg_agg; 1178 1179 pc_gamg->ops->setfromoptions = PCSetFromOptions_GAMG_AGG; 1180 pc_gamg->ops->destroy = PCDestroy_GAMG_AGG; 1181 /* reset does not do anything; setup not virtual */ 1182 1183 /* set internal function pointers */ 1184 pc_gamg->ops->graph = PCGAMGGraph_AGG; 1185 pc_gamg->ops->coarsen = PCGAMGCoarsen_AGG; 1186 pc_gamg->ops->prolongator = PCGAMGProlongator_AGG; 1187 pc_gamg->ops->optprolongator = PCGAMGOptProlongator_AGG; 1188 pc_gamg->ops->createdefaultdata = PCSetData_AGG; 1189 pc_gamg->ops->view = PCView_GAMG_AGG; 1190 1191 pc_gamg_agg->square_graph = 1; 1192 pc_gamg_agg->sym_graph = PETSC_FALSE; 1193 pc_gamg_agg->nsmooths = 1; 1194 1195 CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetNSmooths_C",PCGAMGSetNSmooths_AGG)); 1196 CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetSymGraph_C",PCGAMGSetSymGraph_AGG)); 1197 CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCGAMGSetSquareGraph_C",PCGAMGSetSquareGraph_AGG)); 1198 CHKERRQ(PetscObjectComposeFunction((PetscObject)pc,"PCSetCoordinates_C",PCSetCoordinates_AGG)); 1199 PetscFunctionReturn(0); 1200 } 1201