1 #include <../src/ksp/pc/impls/gamg/gamg.h> /*I "petscpc.h" I*/ 2 #include <petscsf.h> 3 4 PetscFunctionList PCGAMGClassicalProlongatorList = NULL; 5 PetscBool PCGAMGClassicalPackageInitialized = PETSC_FALSE; 6 7 typedef struct { 8 PetscReal interp_threshold; /* interpolation threshold */ 9 char prolongtype[256]; 10 PetscInt nsmooths; /* number of jacobi smoothings on the prolongator */ 11 } PC_GAMG_Classical; 12 13 /*@C 14 PCGAMGClassicalSetType - Sets the type of classical interpolation to use 15 16 Collective on PC 17 18 Input Parameters: 19 . pc - the preconditioner context 20 21 Options Database Key: 22 . -pc_gamg_classical_type <direct,standard> - set type of Classical AMG prolongation 23 24 Level: intermediate 25 26 .seealso: `()` 27 @*/ 28 PetscErrorCode PCGAMGClassicalSetType(PC pc, PCGAMGClassicalType type) 29 { 30 PetscFunctionBegin; 31 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 32 PetscTryMethod(pc,"PCGAMGClassicalSetType_C",(PC,PCGAMGClassicalType),(pc,type)); 33 PetscFunctionReturn(0); 34 } 35 36 /*@C 37 PCGAMGClassicalGetType - Gets the type of classical interpolation to use 38 39 Collective on PC 40 41 Input Parameter: 42 . pc - the preconditioner context 43 44 Output Parameter: 45 . type - the type used 46 47 Level: intermediate 48 49 .seealso: `()` 50 @*/ 51 PetscErrorCode PCGAMGClassicalGetType(PC pc, PCGAMGClassicalType *type) 52 { 53 PetscFunctionBegin; 54 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 55 PetscUseMethod(pc,"PCGAMGClassicalGetType_C",(PC,PCGAMGClassicalType*),(pc,type)); 56 PetscFunctionReturn(0); 57 } 58 59 static PetscErrorCode PCGAMGClassicalSetType_GAMG(PC pc, PCGAMGClassicalType type) 60 { 61 PC_MG *mg = (PC_MG*)pc->data; 62 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 63 PC_GAMG_Classical *cls = (PC_GAMG_Classical*)pc_gamg->subctx; 64 65 PetscFunctionBegin; 66 PetscCall(PetscStrcpy(cls->prolongtype,type)); 67 PetscFunctionReturn(0); 68 } 69 70 static PetscErrorCode PCGAMGClassicalGetType_GAMG(PC pc, PCGAMGClassicalType *type) 71 { 72 PC_MG *mg = (PC_MG*)pc->data; 73 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 74 PC_GAMG_Classical *cls = (PC_GAMG_Classical*)pc_gamg->subctx; 75 76 PetscFunctionBegin; 77 *type = cls->prolongtype; 78 PetscFunctionReturn(0); 79 } 80 81 PetscErrorCode PCGAMGGraph_Classical(PC pc,Mat A,Mat *G) 82 { 83 PetscInt s,f,n,idx,lidx,gidx; 84 PetscInt r,c,ncols; 85 const PetscInt *rcol; 86 const PetscScalar *rval; 87 PetscInt *gcol; 88 PetscScalar *gval; 89 PetscReal rmax; 90 PetscInt cmax = 0; 91 PC_MG *mg = (PC_MG *)pc->data; 92 PC_GAMG *gamg = (PC_GAMG *)mg->innerctx; 93 PetscInt *gsparse,*lsparse; 94 PetscScalar *Amax; 95 MatType mtype; 96 97 PetscFunctionBegin; 98 PetscCall(MatGetOwnershipRange(A,&s,&f)); 99 n=f-s; 100 PetscCall(PetscMalloc3(n,&lsparse,n,&gsparse,n,&Amax)); 101 102 for (r = 0;r < n;r++) { 103 lsparse[r] = 0; 104 gsparse[r] = 0; 105 } 106 107 for (r = s;r < f;r++) { 108 /* determine the maximum off-diagonal in each row */ 109 rmax = 0.; 110 PetscCall(MatGetRow(A,r,&ncols,&rcol,&rval)); 111 for (c = 0; c < ncols; c++) { 112 if (PetscRealPart(-rval[c]) > rmax && rcol[c] != r) { 113 rmax = PetscRealPart(-rval[c]); 114 } 115 } 116 Amax[r-s] = rmax; 117 if (ncols > cmax) cmax = ncols; 118 lidx = 0; 119 gidx = 0; 120 /* create the local and global sparsity patterns */ 121 for (c = 0; c < ncols; c++) { 122 if (PetscRealPart(-rval[c]) > gamg->threshold[0]*PetscRealPart(Amax[r-s]) || rcol[c] == r) { 123 if (rcol[c] < f && rcol[c] >= s) { 124 lidx++; 125 } else { 126 gidx++; 127 } 128 } 129 } 130 PetscCall(MatRestoreRow(A,r,&ncols,&rcol,&rval)); 131 lsparse[r-s] = lidx; 132 gsparse[r-s] = gidx; 133 } 134 PetscCall(PetscMalloc2(cmax,&gval,cmax,&gcol)); 135 136 PetscCall(MatCreate(PetscObjectComm((PetscObject)A),G)); 137 PetscCall(MatGetType(A,&mtype)); 138 PetscCall(MatSetType(*G,mtype)); 139 PetscCall(MatSetSizes(*G,n,n,PETSC_DETERMINE,PETSC_DETERMINE)); 140 PetscCall(MatMPIAIJSetPreallocation(*G,0,lsparse,0,gsparse)); 141 PetscCall(MatSeqAIJSetPreallocation(*G,0,lsparse)); 142 for (r = s;r < f;r++) { 143 PetscCall(MatGetRow(A,r,&ncols,&rcol,&rval)); 144 idx = 0; 145 for (c = 0; c < ncols; c++) { 146 /* classical strength of connection */ 147 if (PetscRealPart(-rval[c]) > gamg->threshold[0]*PetscRealPart(Amax[r-s]) || rcol[c] == r) { 148 gcol[idx] = rcol[c]; 149 gval[idx] = rval[c]; 150 idx++; 151 } 152 } 153 PetscCall(MatSetValues(*G,1,&r,idx,gcol,gval,INSERT_VALUES)); 154 PetscCall(MatRestoreRow(A,r,&ncols,&rcol,&rval)); 155 } 156 PetscCall(MatAssemblyBegin(*G, MAT_FINAL_ASSEMBLY)); 157 PetscCall(MatAssemblyEnd(*G, MAT_FINAL_ASSEMBLY)); 158 159 PetscCall(PetscFree2(gval,gcol)); 160 PetscCall(PetscFree3(lsparse,gsparse,Amax)); 161 PetscFunctionReturn(0); 162 } 163 164 PetscErrorCode PCGAMGCoarsen_Classical(PC pc,Mat *G,PetscCoarsenData **agg_lists) 165 { 166 MatCoarsen crs; 167 MPI_Comm fcomm = ((PetscObject)pc)->comm; 168 169 PetscFunctionBegin; 170 PetscCheck(G,fcomm,PETSC_ERR_ARG_WRONGSTATE,"Must set Graph in PC in PCGAMG before coarsening"); 171 172 PetscCall(MatCoarsenCreate(fcomm,&crs)); 173 PetscCall(MatCoarsenSetFromOptions(crs)); 174 PetscCall(MatCoarsenSetAdjacency(crs,*G)); 175 PetscCall(MatCoarsenSetStrictAggs(crs,PETSC_TRUE)); 176 PetscCall(MatCoarsenApply(crs)); 177 PetscCall(MatCoarsenGetData(crs,agg_lists)); 178 PetscCall(MatCoarsenDestroy(&crs)); 179 PetscFunctionReturn(0); 180 } 181 182 PetscErrorCode PCGAMGProlongator_Classical_Direct(PC pc, Mat A, Mat G, PetscCoarsenData *agg_lists,Mat *P) 183 { 184 PC_MG *mg = (PC_MG*)pc->data; 185 PC_GAMG *gamg = (PC_GAMG*)mg->innerctx; 186 PetscBool iscoarse,isMPIAIJ,isSEQAIJ; 187 PetscInt fn,cn,fs,fe,cs,ce,i,j,ncols,col,row_f,row_c,cmax=0,idx,noff; 188 PetscInt *lcid,*gcid,*lsparse,*gsparse,*colmap,*pcols; 189 const PetscInt *rcol; 190 PetscReal *Amax_pos,*Amax_neg; 191 PetscScalar g_pos,g_neg,a_pos,a_neg,diag,invdiag,alpha,beta,pij; 192 PetscScalar *pvals; 193 const PetscScalar *rval; 194 Mat lA,gA=NULL; 195 MatType mtype; 196 Vec C,lvec; 197 PetscLayout clayout; 198 PetscSF sf; 199 Mat_MPIAIJ *mpiaij; 200 201 PetscFunctionBegin; 202 PetscCall(MatGetOwnershipRange(A,&fs,&fe)); 203 fn = fe-fs; 204 PetscCall(PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&isMPIAIJ)); 205 PetscCall(PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&isSEQAIJ)); 206 PetscCheck(isMPIAIJ || isSEQAIJ,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"Classical AMG requires MPIAIJ matrix"); 207 if (isMPIAIJ) { 208 mpiaij = (Mat_MPIAIJ*)A->data; 209 lA = mpiaij->A; 210 gA = mpiaij->B; 211 lvec = mpiaij->lvec; 212 PetscCall(VecGetSize(lvec,&noff)); 213 colmap = mpiaij->garray; 214 PetscCall(MatGetLayouts(A,NULL,&clayout)); 215 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A),&sf)); 216 PetscCall(PetscSFSetGraphLayout(sf,clayout,noff,NULL,PETSC_COPY_VALUES,colmap)); 217 PetscCall(PetscMalloc1(noff,&gcid)); 218 } else { 219 lA = A; 220 } 221 PetscCall(PetscMalloc5(fn,&lsparse,fn,&gsparse,fn,&lcid,fn,&Amax_pos,fn,&Amax_neg)); 222 223 /* count the number of coarse unknowns */ 224 cn = 0; 225 for (i=0;i<fn;i++) { 226 /* filter out singletons */ 227 PetscCall(PetscCDEmptyAt(agg_lists,i,&iscoarse)); 228 lcid[i] = -1; 229 if (!iscoarse) { 230 cn++; 231 } 232 } 233 234 /* create the coarse vector */ 235 PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)A),cn,PETSC_DECIDE,&C)); 236 PetscCall(VecGetOwnershipRange(C,&cs,&ce)); 237 238 cn = 0; 239 for (i=0;i<fn;i++) { 240 PetscCall(PetscCDEmptyAt(agg_lists,i,&iscoarse)); 241 if (!iscoarse) { 242 lcid[i] = cs+cn; 243 cn++; 244 } else { 245 lcid[i] = -1; 246 } 247 } 248 249 if (gA) { 250 PetscCall(PetscSFBcastBegin(sf,MPIU_INT,lcid,gcid,MPI_REPLACE)); 251 PetscCall(PetscSFBcastEnd(sf,MPIU_INT,lcid,gcid,MPI_REPLACE)); 252 } 253 254 /* determine the largest off-diagonal entries in each row */ 255 for (i=fs;i<fe;i++) { 256 Amax_pos[i-fs] = 0.; 257 Amax_neg[i-fs] = 0.; 258 PetscCall(MatGetRow(A,i,&ncols,&rcol,&rval)); 259 for (j=0;j<ncols;j++) { 260 if ((PetscRealPart(-rval[j]) > Amax_neg[i-fs]) && i != rcol[j]) Amax_neg[i-fs] = PetscAbsScalar(rval[j]); 261 if ((PetscRealPart(rval[j]) > Amax_pos[i-fs]) && i != rcol[j]) Amax_pos[i-fs] = PetscAbsScalar(rval[j]); 262 } 263 if (ncols > cmax) cmax = ncols; 264 PetscCall(MatRestoreRow(A,i,&ncols,&rcol,&rval)); 265 } 266 PetscCall(PetscMalloc2(cmax,&pcols,cmax,&pvals)); 267 PetscCall(VecDestroy(&C)); 268 269 /* count the on and off processor sparsity patterns for the prolongator */ 270 for (i=0;i<fn;i++) { 271 /* on */ 272 lsparse[i] = 0; 273 gsparse[i] = 0; 274 if (lcid[i] >= 0) { 275 lsparse[i] = 1; 276 gsparse[i] = 0; 277 } else { 278 PetscCall(MatGetRow(lA,i,&ncols,&rcol,&rval)); 279 for (j = 0;j < ncols;j++) { 280 col = rcol[j]; 281 if (lcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold[0]*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold[0]*Amax_neg[i])) { 282 lsparse[i] += 1; 283 } 284 } 285 PetscCall(MatRestoreRow(lA,i,&ncols,&rcol,&rval)); 286 /* off */ 287 if (gA) { 288 PetscCall(MatGetRow(gA,i,&ncols,&rcol,&rval)); 289 for (j = 0; j < ncols; j++) { 290 col = rcol[j]; 291 if (gcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold[0]*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold[0]*Amax_neg[i])) { 292 gsparse[i] += 1; 293 } 294 } 295 PetscCall(MatRestoreRow(gA,i,&ncols,&rcol,&rval)); 296 } 297 } 298 } 299 300 /* preallocate and create the prolongator */ 301 PetscCall(MatCreate(PetscObjectComm((PetscObject)A),P)); 302 PetscCall(MatGetType(G,&mtype)); 303 PetscCall(MatSetType(*P,mtype)); 304 PetscCall(MatSetSizes(*P,fn,cn,PETSC_DETERMINE,PETSC_DETERMINE)); 305 PetscCall(MatMPIAIJSetPreallocation(*P,0,lsparse,0,gsparse)); 306 PetscCall(MatSeqAIJSetPreallocation(*P,0,lsparse)); 307 308 /* loop over local fine nodes -- get the diagonal, the sum of positive and negative strong and weak weights, and set up the row */ 309 for (i = 0;i < fn;i++) { 310 /* determine on or off */ 311 row_f = i + fs; 312 row_c = lcid[i]; 313 if (row_c >= 0) { 314 pij = 1.; 315 PetscCall(MatSetValues(*P,1,&row_f,1,&row_c,&pij,INSERT_VALUES)); 316 } else { 317 g_pos = 0.; 318 g_neg = 0.; 319 a_pos = 0.; 320 a_neg = 0.; 321 diag = 0.; 322 323 /* local connections */ 324 PetscCall(MatGetRow(lA,i,&ncols,&rcol,&rval)); 325 for (j = 0; j < ncols; j++) { 326 col = rcol[j]; 327 if (lcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold[0]*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold[0]*Amax_neg[i])) { 328 if (PetscRealPart(rval[j]) > 0.) { 329 g_pos += rval[j]; 330 } else { 331 g_neg += rval[j]; 332 } 333 } 334 if (col != i) { 335 if (PetscRealPart(rval[j]) > 0.) { 336 a_pos += rval[j]; 337 } else { 338 a_neg += rval[j]; 339 } 340 } else { 341 diag = rval[j]; 342 } 343 } 344 PetscCall(MatRestoreRow(lA,i,&ncols,&rcol,&rval)); 345 346 /* ghosted connections */ 347 if (gA) { 348 PetscCall(MatGetRow(gA,i,&ncols,&rcol,&rval)); 349 for (j = 0; j < ncols; j++) { 350 col = rcol[j]; 351 if (gcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold[0]*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold[0]*Amax_neg[i])) { 352 if (PetscRealPart(rval[j]) > 0.) { 353 g_pos += rval[j]; 354 } else { 355 g_neg += rval[j]; 356 } 357 } 358 if (PetscRealPart(rval[j]) > 0.) { 359 a_pos += rval[j]; 360 } else { 361 a_neg += rval[j]; 362 } 363 } 364 PetscCall(MatRestoreRow(gA,i,&ncols,&rcol,&rval)); 365 } 366 367 if (g_neg == 0.) { 368 alpha = 0.; 369 } else { 370 alpha = -a_neg/g_neg; 371 } 372 373 if (g_pos == 0.) { 374 diag += a_pos; 375 beta = 0.; 376 } else { 377 beta = -a_pos/g_pos; 378 } 379 if (diag == 0.) { 380 invdiag = 0.; 381 } else invdiag = 1. / diag; 382 /* on */ 383 PetscCall(MatGetRow(lA,i,&ncols,&rcol,&rval)); 384 idx = 0; 385 for (j = 0;j < ncols;j++) { 386 col = rcol[j]; 387 if (lcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold[0]*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold[0]*Amax_neg[i])) { 388 row_f = i + fs; 389 row_c = lcid[col]; 390 /* set the values for on-processor ones */ 391 if (PetscRealPart(rval[j]) < 0.) { 392 pij = rval[j]*alpha*invdiag; 393 } else { 394 pij = rval[j]*beta*invdiag; 395 } 396 if (PetscAbsScalar(pij) != 0.) { 397 pvals[idx] = pij; 398 pcols[idx] = row_c; 399 idx++; 400 } 401 } 402 } 403 PetscCall(MatRestoreRow(lA,i,&ncols,&rcol,&rval)); 404 /* off */ 405 if (gA) { 406 PetscCall(MatGetRow(gA,i,&ncols,&rcol,&rval)); 407 for (j = 0; j < ncols; j++) { 408 col = rcol[j]; 409 if (gcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold[0]*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold[0]*Amax_neg[i])) { 410 row_f = i + fs; 411 row_c = gcid[col]; 412 /* set the values for on-processor ones */ 413 if (PetscRealPart(rval[j]) < 0.) { 414 pij = rval[j]*alpha*invdiag; 415 } else { 416 pij = rval[j]*beta*invdiag; 417 } 418 if (PetscAbsScalar(pij) != 0.) { 419 pvals[idx] = pij; 420 pcols[idx] = row_c; 421 idx++; 422 } 423 } 424 } 425 PetscCall(MatRestoreRow(gA,i,&ncols,&rcol,&rval)); 426 } 427 PetscCall(MatSetValues(*P,1,&row_f,idx,pcols,pvals,INSERT_VALUES)); 428 } 429 } 430 431 PetscCall(MatAssemblyBegin(*P, MAT_FINAL_ASSEMBLY)); 432 PetscCall(MatAssemblyEnd(*P, MAT_FINAL_ASSEMBLY)); 433 434 PetscCall(PetscFree5(lsparse,gsparse,lcid,Amax_pos,Amax_neg)); 435 436 PetscCall(PetscFree2(pcols,pvals)); 437 if (gA) { 438 PetscCall(PetscSFDestroy(&sf)); 439 PetscCall(PetscFree(gcid)); 440 } 441 PetscFunctionReturn(0); 442 } 443 444 PetscErrorCode PCGAMGTruncateProlongator_Private(PC pc,Mat *P) 445 { 446 PetscInt j,i,ps,pf,pn,pcs,pcf,pcn,idx,cmax; 447 const PetscScalar *pval; 448 const PetscInt *pcol; 449 PetscScalar *pnval; 450 PetscInt *pncol; 451 PetscInt ncols; 452 Mat Pnew; 453 PetscInt *lsparse,*gsparse; 454 PetscReal pmax_pos,pmax_neg,ptot_pos,ptot_neg,pthresh_pos,pthresh_neg; 455 PC_MG *mg = (PC_MG*)pc->data; 456 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 457 PC_GAMG_Classical *cls = (PC_GAMG_Classical*)pc_gamg->subctx; 458 MatType mtype; 459 460 PetscFunctionBegin; 461 /* trim and rescale with reallocation */ 462 PetscCall(MatGetOwnershipRange(*P,&ps,&pf)); 463 PetscCall(MatGetOwnershipRangeColumn(*P,&pcs,&pcf)); 464 pn = pf-ps; 465 pcn = pcf-pcs; 466 PetscCall(PetscMalloc2(pn,&lsparse,pn,&gsparse)); 467 /* allocate */ 468 cmax = 0; 469 for (i=ps;i<pf;i++) { 470 lsparse[i-ps] = 0; 471 gsparse[i-ps] = 0; 472 PetscCall(MatGetRow(*P,i,&ncols,&pcol,&pval)); 473 if (ncols > cmax) { 474 cmax = ncols; 475 } 476 pmax_pos = 0.; 477 pmax_neg = 0.; 478 for (j=0;j<ncols;j++) { 479 if (PetscRealPart(pval[j]) > pmax_pos) { 480 pmax_pos = PetscRealPart(pval[j]); 481 } else if (PetscRealPart(pval[j]) < pmax_neg) { 482 pmax_neg = PetscRealPart(pval[j]); 483 } 484 } 485 for (j=0;j<ncols;j++) { 486 if (PetscRealPart(pval[j]) >= pmax_pos*cls->interp_threshold || PetscRealPart(pval[j]) <= pmax_neg*cls->interp_threshold) { 487 if (pcol[j] >= pcs && pcol[j] < pcf) { 488 lsparse[i-ps]++; 489 } else { 490 gsparse[i-ps]++; 491 } 492 } 493 } 494 PetscCall(MatRestoreRow(*P,i,&ncols,&pcol,&pval)); 495 } 496 497 PetscCall(PetscMalloc2(cmax,&pnval,cmax,&pncol)); 498 499 PetscCall(MatGetType(*P,&mtype)); 500 PetscCall(MatCreate(PetscObjectComm((PetscObject)*P),&Pnew)); 501 PetscCall(MatSetType(Pnew, mtype)); 502 PetscCall(MatSetSizes(Pnew,pn,pcn,PETSC_DETERMINE,PETSC_DETERMINE)); 503 PetscCall(MatSeqAIJSetPreallocation(Pnew,0,lsparse)); 504 PetscCall(MatMPIAIJSetPreallocation(Pnew,0,lsparse,0,gsparse)); 505 506 for (i=ps;i<pf;i++) { 507 PetscCall(MatGetRow(*P,i,&ncols,&pcol,&pval)); 508 pmax_pos = 0.; 509 pmax_neg = 0.; 510 for (j=0;j<ncols;j++) { 511 if (PetscRealPart(pval[j]) > pmax_pos) { 512 pmax_pos = PetscRealPart(pval[j]); 513 } else if (PetscRealPart(pval[j]) < pmax_neg) { 514 pmax_neg = PetscRealPart(pval[j]); 515 } 516 } 517 pthresh_pos = 0.; 518 pthresh_neg = 0.; 519 ptot_pos = 0.; 520 ptot_neg = 0.; 521 for (j=0;j<ncols;j++) { 522 if (PetscRealPart(pval[j]) >= cls->interp_threshold*pmax_pos) { 523 pthresh_pos += PetscRealPart(pval[j]); 524 } else if (PetscRealPart(pval[j]) <= cls->interp_threshold*pmax_neg) { 525 pthresh_neg += PetscRealPart(pval[j]); 526 } 527 if (PetscRealPart(pval[j]) > 0.) { 528 ptot_pos += PetscRealPart(pval[j]); 529 } else { 530 ptot_neg += PetscRealPart(pval[j]); 531 } 532 } 533 if (PetscAbsReal(pthresh_pos) > 0.) ptot_pos /= pthresh_pos; 534 if (PetscAbsReal(pthresh_neg) > 0.) ptot_neg /= pthresh_neg; 535 idx=0; 536 for (j=0;j<ncols;j++) { 537 if (PetscRealPart(pval[j]) >= pmax_pos*cls->interp_threshold) { 538 pnval[idx] = ptot_pos*pval[j]; 539 pncol[idx] = pcol[j]; 540 idx++; 541 } else if (PetscRealPart(pval[j]) <= pmax_neg*cls->interp_threshold) { 542 pnval[idx] = ptot_neg*pval[j]; 543 pncol[idx] = pcol[j]; 544 idx++; 545 } 546 } 547 PetscCall(MatRestoreRow(*P,i,&ncols,&pcol,&pval)); 548 PetscCall(MatSetValues(Pnew,1,&i,idx,pncol,pnval,INSERT_VALUES)); 549 } 550 551 PetscCall(MatAssemblyBegin(Pnew, MAT_FINAL_ASSEMBLY)); 552 PetscCall(MatAssemblyEnd(Pnew, MAT_FINAL_ASSEMBLY)); 553 PetscCall(MatDestroy(P)); 554 555 *P = Pnew; 556 PetscCall(PetscFree2(lsparse,gsparse)); 557 PetscCall(PetscFree2(pnval,pncol)); 558 PetscFunctionReturn(0); 559 } 560 561 PetscErrorCode PCGAMGProlongator_Classical_Standard(PC pc, Mat A, Mat G, PetscCoarsenData *agg_lists,Mat *P) 562 { 563 Mat lA,*lAs; 564 MatType mtype; 565 Vec cv; 566 PetscInt *gcid,*lcid,*lsparse,*gsparse,*picol; 567 PetscInt fs,fe,cs,ce,nl,i,j,k,li,lni,ci,ncols,maxcols,fn,cn,cid; 568 PetscMPIInt size; 569 const PetscInt *lidx,*icol,*gidx; 570 PetscBool iscoarse; 571 PetscScalar vi,pentry,pjentry; 572 PetscScalar *pcontrib,*pvcol; 573 const PetscScalar *vcol; 574 PetscReal diag,jdiag,jwttotal; 575 PetscInt pncols; 576 PetscSF sf; 577 PetscLayout clayout; 578 IS lis; 579 580 PetscFunctionBegin; 581 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A),&size)); 582 PetscCall(MatGetOwnershipRange(A,&fs,&fe)); 583 fn = fe-fs; 584 PetscCall(ISCreateStride(PETSC_COMM_SELF,fe-fs,fs,1,&lis)); 585 if (size > 1) { 586 PetscCall(MatGetLayouts(A,NULL,&clayout)); 587 /* increase the overlap by two to get neighbors of neighbors */ 588 PetscCall(MatIncreaseOverlap(A,1,&lis,2)); 589 PetscCall(ISSort(lis)); 590 /* get the local part of A */ 591 PetscCall(MatCreateSubMatrices(A,1,&lis,&lis,MAT_INITIAL_MATRIX,&lAs)); 592 lA = lAs[0]; 593 /* build an SF out of it */ 594 PetscCall(ISGetLocalSize(lis,&nl)); 595 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A),&sf)); 596 PetscCall(ISGetIndices(lis,&lidx)); 597 PetscCall(PetscSFSetGraphLayout(sf,clayout,nl,NULL,PETSC_COPY_VALUES,lidx)); 598 PetscCall(ISRestoreIndices(lis,&lidx)); 599 } else { 600 lA = A; 601 nl = fn; 602 } 603 /* create a communication structure for the overlapped portion and transmit coarse indices */ 604 PetscCall(PetscMalloc3(fn,&lsparse,fn,&gsparse,nl,&pcontrib)); 605 /* create coarse vector */ 606 cn = 0; 607 for (i=0;i<fn;i++) { 608 PetscCall(PetscCDEmptyAt(agg_lists,i,&iscoarse)); 609 if (!iscoarse) { 610 cn++; 611 } 612 } 613 PetscCall(PetscMalloc1(fn,&gcid)); 614 PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)A),cn,PETSC_DECIDE,&cv)); 615 PetscCall(VecGetOwnershipRange(cv,&cs,&ce)); 616 cn = 0; 617 for (i=0;i<fn;i++) { 618 PetscCall(PetscCDEmptyAt(agg_lists,i,&iscoarse)); 619 if (!iscoarse) { 620 gcid[i] = cs+cn; 621 cn++; 622 } else { 623 gcid[i] = -1; 624 } 625 } 626 if (size > 1) { 627 PetscCall(PetscMalloc1(nl,&lcid)); 628 PetscCall(PetscSFBcastBegin(sf,MPIU_INT,gcid,lcid,MPI_REPLACE)); 629 PetscCall(PetscSFBcastEnd(sf,MPIU_INT,gcid,lcid,MPI_REPLACE)); 630 } else { 631 lcid = gcid; 632 } 633 /* count to preallocate the prolongator */ 634 PetscCall(ISGetIndices(lis,&gidx)); 635 maxcols = 0; 636 /* count the number of unique contributing coarse cells for each fine */ 637 for (i=0;i<nl;i++) { 638 pcontrib[i] = 0.; 639 PetscCall(MatGetRow(lA,i,&ncols,&icol,NULL)); 640 if (gidx[i] >= fs && gidx[i] < fe) { 641 li = gidx[i] - fs; 642 lsparse[li] = 0; 643 gsparse[li] = 0; 644 cid = lcid[i]; 645 if (cid >= 0) { 646 lsparse[li] = 1; 647 } else { 648 for (j=0;j<ncols;j++) { 649 if (lcid[icol[j]] >= 0) { 650 pcontrib[icol[j]] = 1.; 651 } else { 652 ci = icol[j]; 653 PetscCall(MatRestoreRow(lA,i,&ncols,&icol,NULL)); 654 PetscCall(MatGetRow(lA,ci,&ncols,&icol,NULL)); 655 for (k=0;k<ncols;k++) { 656 if (lcid[icol[k]] >= 0) { 657 pcontrib[icol[k]] = 1.; 658 } 659 } 660 PetscCall(MatRestoreRow(lA,ci,&ncols,&icol,NULL)); 661 PetscCall(MatGetRow(lA,i,&ncols,&icol,NULL)); 662 } 663 } 664 for (j=0;j<ncols;j++) { 665 if (lcid[icol[j]] >= 0 && pcontrib[icol[j]] != 0.) { 666 lni = lcid[icol[j]]; 667 if (lni >= cs && lni < ce) { 668 lsparse[li]++; 669 } else { 670 gsparse[li]++; 671 } 672 pcontrib[icol[j]] = 0.; 673 } else { 674 ci = icol[j]; 675 PetscCall(MatRestoreRow(lA,i,&ncols,&icol,NULL)); 676 PetscCall(MatGetRow(lA,ci,&ncols,&icol,NULL)); 677 for (k=0;k<ncols;k++) { 678 if (lcid[icol[k]] >= 0 && pcontrib[icol[k]] != 0.) { 679 lni = lcid[icol[k]]; 680 if (lni >= cs && lni < ce) { 681 lsparse[li]++; 682 } else { 683 gsparse[li]++; 684 } 685 pcontrib[icol[k]] = 0.; 686 } 687 } 688 PetscCall(MatRestoreRow(lA,ci,&ncols,&icol,NULL)); 689 PetscCall(MatGetRow(lA,i,&ncols,&icol,NULL)); 690 } 691 } 692 } 693 if (lsparse[li] + gsparse[li] > maxcols) maxcols = lsparse[li]+gsparse[li]; 694 } 695 PetscCall(MatRestoreRow(lA,i,&ncols,&icol,&vcol)); 696 } 697 PetscCall(PetscMalloc2(maxcols,&picol,maxcols,&pvcol)); 698 PetscCall(MatCreate(PetscObjectComm((PetscObject)A),P)); 699 PetscCall(MatGetType(A,&mtype)); 700 PetscCall(MatSetType(*P,mtype)); 701 PetscCall(MatSetSizes(*P,fn,cn,PETSC_DETERMINE,PETSC_DETERMINE)); 702 PetscCall(MatMPIAIJSetPreallocation(*P,0,lsparse,0,gsparse)); 703 PetscCall(MatSeqAIJSetPreallocation(*P,0,lsparse)); 704 for (i=0;i<nl;i++) { 705 diag = 0.; 706 if (gidx[i] >= fs && gidx[i] < fe) { 707 pncols=0; 708 cid = lcid[i]; 709 if (cid >= 0) { 710 pncols = 1; 711 picol[0] = cid; 712 pvcol[0] = 1.; 713 } else { 714 PetscCall(MatGetRow(lA,i,&ncols,&icol,&vcol)); 715 for (j=0;j<ncols;j++) { 716 pentry = vcol[j]; 717 if (lcid[icol[j]] >= 0) { 718 /* coarse neighbor */ 719 pcontrib[icol[j]] += pentry; 720 } else if (icol[j] != i) { 721 /* the neighbor is a strongly connected fine node */ 722 ci = icol[j]; 723 vi = vcol[j]; 724 PetscCall(MatRestoreRow(lA,i,&ncols,&icol,&vcol)); 725 PetscCall(MatGetRow(lA,ci,&ncols,&icol,&vcol)); 726 jwttotal=0.; 727 jdiag = 0.; 728 for (k=0;k<ncols;k++) { 729 if (ci == icol[k]) { 730 jdiag = PetscRealPart(vcol[k]); 731 } 732 } 733 for (k=0;k<ncols;k++) { 734 if (lcid[icol[k]] >= 0 && jdiag*PetscRealPart(vcol[k]) < 0.) { 735 pjentry = vcol[k]; 736 jwttotal += PetscRealPart(pjentry); 737 } 738 } 739 if (jwttotal != 0.) { 740 jwttotal = PetscRealPart(vi)/jwttotal; 741 for (k=0;k<ncols;k++) { 742 if (lcid[icol[k]] >= 0 && jdiag*PetscRealPart(vcol[k]) < 0.) { 743 pjentry = vcol[k]*jwttotal; 744 pcontrib[icol[k]] += pjentry; 745 } 746 } 747 } else { 748 diag += PetscRealPart(vi); 749 } 750 PetscCall(MatRestoreRow(lA,ci,&ncols,&icol,&vcol)); 751 PetscCall(MatGetRow(lA,i,&ncols,&icol,&vcol)); 752 } else { 753 diag += PetscRealPart(vcol[j]); 754 } 755 } 756 if (diag != 0.) { 757 diag = 1./diag; 758 for (j=0;j<ncols;j++) { 759 if (lcid[icol[j]] >= 0 && pcontrib[icol[j]] != 0.) { 760 /* the neighbor is a coarse node */ 761 if (PetscAbsScalar(pcontrib[icol[j]]) > 0.0) { 762 lni = lcid[icol[j]]; 763 pvcol[pncols] = -pcontrib[icol[j]]*diag; 764 picol[pncols] = lni; 765 pncols++; 766 } 767 pcontrib[icol[j]] = 0.; 768 } else { 769 /* the neighbor is a strongly connected fine node */ 770 ci = icol[j]; 771 PetscCall(MatRestoreRow(lA,i,&ncols,&icol,&vcol)); 772 PetscCall(MatGetRow(lA,ci,&ncols,&icol,&vcol)); 773 for (k=0;k<ncols;k++) { 774 if (lcid[icol[k]] >= 0 && pcontrib[icol[k]] != 0.) { 775 if (PetscAbsScalar(pcontrib[icol[k]]) > 0.0) { 776 lni = lcid[icol[k]]; 777 pvcol[pncols] = -pcontrib[icol[k]]*diag; 778 picol[pncols] = lni; 779 pncols++; 780 } 781 pcontrib[icol[k]] = 0.; 782 } 783 } 784 PetscCall(MatRestoreRow(lA,ci,&ncols,&icol,&vcol)); 785 PetscCall(MatGetRow(lA,i,&ncols,&icol,&vcol)); 786 } 787 pcontrib[icol[j]] = 0.; 788 } 789 PetscCall(MatRestoreRow(lA,i,&ncols,&icol,&vcol)); 790 } 791 } 792 ci = gidx[i]; 793 if (pncols > 0) { 794 PetscCall(MatSetValues(*P,1,&ci,pncols,picol,pvcol,INSERT_VALUES)); 795 } 796 } 797 } 798 PetscCall(ISRestoreIndices(lis,&gidx)); 799 PetscCall(PetscFree2(picol,pvcol)); 800 PetscCall(PetscFree3(lsparse,gsparse,pcontrib)); 801 PetscCall(ISDestroy(&lis)); 802 PetscCall(PetscFree(gcid)); 803 if (size > 1) { 804 PetscCall(PetscFree(lcid)); 805 PetscCall(MatDestroyMatrices(1,&lAs)); 806 PetscCall(PetscSFDestroy(&sf)); 807 } 808 PetscCall(VecDestroy(&cv)); 809 PetscCall(MatAssemblyBegin(*P, MAT_FINAL_ASSEMBLY)); 810 PetscCall(MatAssemblyEnd(*P, MAT_FINAL_ASSEMBLY)); 811 PetscFunctionReturn(0); 812 } 813 814 PetscErrorCode PCGAMGOptProlongator_Classical_Jacobi(PC pc,Mat A,Mat *P) 815 { 816 817 PetscInt f,s,n,cf,cs,i,idx; 818 PetscInt *coarserows; 819 PetscInt ncols; 820 const PetscInt *pcols; 821 const PetscScalar *pvals; 822 Mat Pnew; 823 Vec diag; 824 PC_MG *mg = (PC_MG*)pc->data; 825 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 826 PC_GAMG_Classical *cls = (PC_GAMG_Classical*)pc_gamg->subctx; 827 828 PetscFunctionBegin; 829 if (cls->nsmooths == 0) { 830 PetscCall(PCGAMGTruncateProlongator_Private(pc,P)); 831 PetscFunctionReturn(0); 832 } 833 PetscCall(MatGetOwnershipRange(*P,&s,&f)); 834 n = f-s; 835 PetscCall(MatGetOwnershipRangeColumn(*P,&cs,&cf)); 836 PetscCall(PetscMalloc1(n,&coarserows)); 837 /* identify the rows corresponding to coarse unknowns */ 838 idx = 0; 839 for (i=s;i<f;i++) { 840 PetscCall(MatGetRow(*P,i,&ncols,&pcols,&pvals)); 841 /* assume, for now, that it's a coarse unknown if it has a single unit entry */ 842 if (ncols == 1) { 843 if (pvals[0] == 1.) { 844 coarserows[idx] = i; 845 idx++; 846 } 847 } 848 PetscCall(MatRestoreRow(*P,i,&ncols,&pcols,&pvals)); 849 } 850 PetscCall(MatCreateVecs(A,&diag,NULL)); 851 PetscCall(MatGetDiagonal(A,diag)); 852 PetscCall(VecReciprocal(diag)); 853 for (i=0;i<cls->nsmooths;i++) { 854 PetscCall(MatMatMult(A,*P,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&Pnew)); 855 PetscCall(MatZeroRows(Pnew,idx,coarserows,0.,NULL,NULL)); 856 PetscCall(MatDiagonalScale(Pnew,diag,NULL)); 857 PetscCall(MatAYPX(Pnew,-1.0,*P,DIFFERENT_NONZERO_PATTERN)); 858 PetscCall(MatDestroy(P)); 859 *P = Pnew; 860 Pnew = NULL; 861 } 862 PetscCall(VecDestroy(&diag)); 863 PetscCall(PetscFree(coarserows)); 864 PetscCall(PCGAMGTruncateProlongator_Private(pc,P)); 865 PetscFunctionReturn(0); 866 } 867 868 static PetscErrorCode PCGAMGProlongator_Classical(PC pc, Mat A, Mat G, PetscCoarsenData *agg_lists,Mat *P) 869 { 870 PetscErrorCode (*f)(PC,Mat,Mat,PetscCoarsenData*,Mat*); 871 PC_MG *mg = (PC_MG*)pc->data; 872 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 873 PC_GAMG_Classical *cls = (PC_GAMG_Classical*)pc_gamg->subctx; 874 875 PetscFunctionBegin; 876 PetscCall(PetscFunctionListFind(PCGAMGClassicalProlongatorList,cls->prolongtype,&f)); 877 PetscCheck(f,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Cannot find PCGAMG Classical prolongator type"); 878 PetscCall((*f)(pc,A,G,agg_lists,P)); 879 PetscFunctionReturn(0); 880 } 881 882 static PetscErrorCode PCGAMGDestroy_Classical(PC pc) 883 { 884 PC_MG *mg = (PC_MG*)pc->data; 885 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 886 887 PetscFunctionBegin; 888 PetscCall(PetscFree(pc_gamg->subctx)); 889 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCGAMGClassicalSetType_C",NULL)); 890 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCGAMGClassicalGetType_C",NULL)); 891 PetscFunctionReturn(0); 892 } 893 894 PetscErrorCode PCGAMGSetFromOptions_Classical(PetscOptionItems *PetscOptionsObject,PC pc) 895 { 896 PC_MG *mg = (PC_MG*)pc->data; 897 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 898 PC_GAMG_Classical *cls = (PC_GAMG_Classical*)pc_gamg->subctx; 899 char tname[256]; 900 PetscBool flg; 901 902 PetscFunctionBegin; 903 PetscOptionsHeadBegin(PetscOptionsObject,"GAMG-Classical options"); 904 PetscCall(PetscOptionsFList("-pc_gamg_classical_type","Type of Classical AMG prolongation","PCGAMGClassicalSetType",PCGAMGClassicalProlongatorList,cls->prolongtype, tname, sizeof(tname), &flg)); 905 if (flg) PetscCall(PCGAMGClassicalSetType(pc,tname)); 906 PetscCall(PetscOptionsReal("-pc_gamg_classical_interp_threshold","Threshold for classical interpolator entries","",cls->interp_threshold,&cls->interp_threshold,NULL)); 907 PetscCall(PetscOptionsInt("-pc_gamg_classical_nsmooths","Threshold for classical interpolator entries","",cls->nsmooths,&cls->nsmooths,NULL)); 908 PetscOptionsHeadEnd(); 909 PetscFunctionReturn(0); 910 } 911 912 static PetscErrorCode PCGAMGSetData_Classical(PC pc, Mat A) 913 { 914 PC_MG *mg = (PC_MG*)pc->data; 915 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 916 917 PetscFunctionBegin; 918 /* no data for classical AMG */ 919 pc_gamg->data = NULL; 920 pc_gamg->data_cell_cols = 0; 921 pc_gamg->data_cell_rows = 0; 922 pc_gamg->data_sz = 0; 923 PetscFunctionReturn(0); 924 } 925 926 PetscErrorCode PCGAMGClassicalFinalizePackage(void) 927 { 928 PetscFunctionBegin; 929 PCGAMGClassicalPackageInitialized = PETSC_FALSE; 930 PetscCall(PetscFunctionListDestroy(&PCGAMGClassicalProlongatorList)); 931 PetscFunctionReturn(0); 932 } 933 934 PetscErrorCode PCGAMGClassicalInitializePackage(void) 935 { 936 PetscFunctionBegin; 937 if (PCGAMGClassicalPackageInitialized) PetscFunctionReturn(0); 938 PetscCall(PetscFunctionListAdd(&PCGAMGClassicalProlongatorList,PCGAMGCLASSICALDIRECT,PCGAMGProlongator_Classical_Direct)); 939 PetscCall(PetscFunctionListAdd(&PCGAMGClassicalProlongatorList,PCGAMGCLASSICALSTANDARD,PCGAMGProlongator_Classical_Standard)); 940 PetscCall(PetscRegisterFinalize(PCGAMGClassicalFinalizePackage)); 941 PetscFunctionReturn(0); 942 } 943 944 /* -------------------------------------------------------------------------- */ 945 /* 946 PCCreateGAMG_Classical 947 948 */ 949 PetscErrorCode PCCreateGAMG_Classical(PC pc) 950 { 951 PC_MG *mg = (PC_MG*)pc->data; 952 PC_GAMG *pc_gamg = (PC_GAMG*)mg->innerctx; 953 PC_GAMG_Classical *pc_gamg_classical; 954 955 PetscFunctionBegin; 956 PetscCall(PCGAMGClassicalInitializePackage()); 957 if (pc_gamg->subctx) { 958 /* call base class */ 959 PetscCall(PCDestroy_GAMG(pc)); 960 } 961 962 /* create sub context for SA */ 963 PetscCall(PetscNewLog(pc,&pc_gamg_classical)); 964 pc_gamg->subctx = pc_gamg_classical; 965 pc->ops->setfromoptions = PCGAMGSetFromOptions_Classical; 966 /* reset does not do anything; setup not virtual */ 967 968 /* set internal function pointers */ 969 pc_gamg->ops->destroy = PCGAMGDestroy_Classical; 970 pc_gamg->ops->graph = PCGAMGGraph_Classical; 971 pc_gamg->ops->coarsen = PCGAMGCoarsen_Classical; 972 pc_gamg->ops->prolongator = PCGAMGProlongator_Classical; 973 pc_gamg->ops->optprolongator = PCGAMGOptProlongator_Classical_Jacobi; 974 pc_gamg->ops->setfromoptions = PCGAMGSetFromOptions_Classical; 975 976 pc_gamg->ops->createdefaultdata = PCGAMGSetData_Classical; 977 pc_gamg_classical->interp_threshold = 0.2; 978 pc_gamg_classical->nsmooths = 0; 979 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCGAMGClassicalSetType_C",PCGAMGClassicalSetType_GAMG)); 980 PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCGAMGClassicalGetType_C",PCGAMGClassicalGetType_GAMG)); 981 PetscCall(PCGAMGClassicalSetType(pc,PCGAMGCLASSICALSTANDARD)); 982 PetscFunctionReturn(0); 983 } 984