Date: 2022-03-04T17:38:56+00:00

Actual source code: classical.c

      1: #include <../src/ksp/pc/impls/gamg/gamg.h>
      2: #include <petscsf.h>

      4: PetscFunctionList PCGAMGClassicalProlongatorList    = NULL;
      5: PetscBool         PCGAMGClassicalPackageInitialized = PETSC_FALSE;

      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;

     13: /*@C
     14:    PCGAMGClassicalSetType - Sets the type of classical interpolation to use

     16:    Collective on PC

     18:    Input Parameters:
     19: .  pc - the preconditioner context

     21:    Options Database Key:
     22: .  -pc_gamg_classical_type

     24:    Level: intermediate

     26: .seealso: ()
     27: @*/
     28: PetscErrorCode PCGAMGClassicalSetType(PC pc, PCGAMGClassicalType type)
     29: {

     34:   PetscTryMethod(pc,"PCGAMGClassicalSetType_C",(PC,PCGAMGClassicalType),(pc,type));
     35:   return(0);
     36: }

     38: /*@C
     39:    PCGAMGClassicalGetType - Gets the type of classical interpolation to use

     41:    Collective on PC

     43:    Input Parameter:
     44: .  pc - the preconditioner context

     46:    Output Parameter:
     47: .  type - the type used

     49:    Level: intermediate

     51: .seealso: ()
     52: @*/
     53: PetscErrorCode PCGAMGClassicalGetType(PC pc, PCGAMGClassicalType *type)
     54: {

     59:   PetscUseMethod(pc,"PCGAMGClassicalGetType_C",(PC,PCGAMGClassicalType*),(pc,type));
     60:   return(0);
     61: }

     63: static PetscErrorCode PCGAMGClassicalSetType_GAMG(PC pc, PCGAMGClassicalType type)
     64: {
     65:   PetscErrorCode    ierr;
     66:   PC_MG             *mg          = (PC_MG*)pc->data;
     67:   PC_GAMG           *pc_gamg     = (PC_GAMG*)mg->innerctx;
     68:   PC_GAMG_Classical *cls         = (PC_GAMG_Classical*)pc_gamg->subctx;

     71:   PetscStrcpy(cls->prolongtype,type);
     72:   return(0);
     73: }

     75: static PetscErrorCode PCGAMGClassicalGetType_GAMG(PC pc, PCGAMGClassicalType *type)
     76: {
     77:   PC_MG             *mg          = (PC_MG*)pc->data;
     78:   PC_GAMG           *pc_gamg     = (PC_GAMG*)mg->innerctx;
     79:   PC_GAMG_Classical *cls         = (PC_GAMG_Classical*)pc_gamg->subctx;

     82:   *type = cls->prolongtype;
     83:   return(0);
     84: }

     86: PetscErrorCode PCGAMGGraph_Classical(PC pc,Mat A,Mat *G)
     87: {
     88:   PetscInt          s,f,n,idx,lidx,gidx;
     89:   PetscInt          r,c,ncols;
     90:   const PetscInt    *rcol;
     91:   const PetscScalar *rval;
     92:   PetscInt          *gcol;
     93:   PetscScalar       *gval;
     94:   PetscReal         rmax;
     95:   PetscInt          cmax = 0;
     96:   PC_MG             *mg = (PC_MG *)pc->data;
     97:   PC_GAMG           *gamg = (PC_GAMG *)mg->innerctx;
     98:   PetscErrorCode    ierr;
     99:   PetscInt          *gsparse,*lsparse;
    100:   PetscScalar       *Amax;
    101:   MatType           mtype;

    104:   MatGetOwnershipRange(A,&s,&f);
    105:   n=f-s;
    106:   PetscMalloc3(n,&lsparse,n,&gsparse,n,&Amax);

    108:   for (r = 0;r < n;r++) {
    109:     lsparse[r] = 0;
    110:     gsparse[r] = 0;
    111:   }

    113:   for (r = s;r < f;r++) {
    114:     /* determine the maximum off-diagonal in each row */
    115:     rmax = 0.;
    116:     MatGetRow(A,r,&ncols,&rcol,&rval);
    117:     for (c = 0; c < ncols; c++) {
    118:       if (PetscRealPart(-rval[c]) > rmax && rcol[c] != r) {
    119:         rmax = PetscRealPart(-rval[c]);
    120:       }
    121:     }
    122:     Amax[r-s] = rmax;
    123:     if (ncols > cmax) cmax = ncols;
    124:     lidx = 0;
    125:     gidx = 0;
    126:     /* create the local and global sparsity patterns */
    127:     for (c = 0; c < ncols; c++) {
    128:       if (PetscRealPart(-rval[c]) > gamg->threshold[0]*PetscRealPart(Amax[r-s]) || rcol[c] == r) {
    129:         if (rcol[c] < f && rcol[c] >= s) {
    130:           lidx++;
    131:         } else {
    132:           gidx++;
    133:         }
    134:       }
    135:     }
    136:     MatRestoreRow(A,r,&ncols,&rcol,&rval);
    137:     lsparse[r-s] = lidx;
    138:     gsparse[r-s] = gidx;
    139:   }
    140:   PetscMalloc2(cmax,&gval,cmax,&gcol);

    142:   MatCreate(PetscObjectComm((PetscObject)A),G);
    143:   MatGetType(A,&mtype);
    144:   MatSetType(*G,mtype);
    145:   MatSetSizes(*G,n,n,PETSC_DETERMINE,PETSC_DETERMINE);
    146:   MatMPIAIJSetPreallocation(*G,0,lsparse,0,gsparse);
    147:   MatSeqAIJSetPreallocation(*G,0,lsparse);
    148:   for (r = s;r < f;r++) {
    149:     MatGetRow(A,r,&ncols,&rcol,&rval);
    150:     idx = 0;
    151:     for (c = 0; c < ncols; c++) {
    152:       /* classical strength of connection */
    153:       if (PetscRealPart(-rval[c]) > gamg->threshold[0]*PetscRealPart(Amax[r-s]) || rcol[c] == r) {
    154:         gcol[idx] = rcol[c];
    155:         gval[idx] = rval[c];
    156:         idx++;
    157:       }
    158:     }
    159:     MatSetValues(*G,1,&r,idx,gcol,gval,INSERT_VALUES);
    160:     MatRestoreRow(A,r,&ncols,&rcol,&rval);
    161:   }
    162:   MatAssemblyBegin(*G, MAT_FINAL_ASSEMBLY);
    163:   MatAssemblyEnd(*G, MAT_FINAL_ASSEMBLY);

    165:   PetscFree2(gval,gcol);
    166:   PetscFree3(lsparse,gsparse,Amax);
    167:   return(0);
    168: }

    170: PetscErrorCode PCGAMGCoarsen_Classical(PC pc,Mat *G,PetscCoarsenData **agg_lists)
    171: {
    172:   PetscErrorCode   ierr;
    173:   MatCoarsen       crs;
    174:   MPI_Comm         fcomm = ((PetscObject)pc)->comm;

    177:   if (!G) SETERRQ(fcomm,PETSC_ERR_ARG_WRONGSTATE,"Must set Graph in PC in PCGAMG before coarsening");

    179:   MatCoarsenCreate(fcomm,&crs);
    180:   MatCoarsenSetFromOptions(crs);
    181:   MatCoarsenSetAdjacency(crs,*G);
    182:   MatCoarsenSetStrictAggs(crs,PETSC_TRUE);
    183:   MatCoarsenApply(crs);
    184:   MatCoarsenGetData(crs,agg_lists);
    185:   MatCoarsenDestroy(&crs);
    186:   return(0);
    187: }

    189: PetscErrorCode PCGAMGProlongator_Classical_Direct(PC pc, Mat A, Mat G, PetscCoarsenData *agg_lists,Mat *P)
    190: {
    191:   PetscErrorCode    ierr;
    192:   PC_MG             *mg          = (PC_MG*)pc->data;
    193:   PC_GAMG           *gamg        = (PC_GAMG*)mg->innerctx;
    194:   PetscBool         iscoarse,isMPIAIJ,isSEQAIJ;
    195:   PetscInt          fn,cn,fs,fe,cs,ce,i,j,ncols,col,row_f,row_c,cmax=0,idx,noff;
    196:   PetscInt          *lcid,*gcid,*lsparse,*gsparse,*colmap,*pcols;
    197:   const PetscInt    *rcol;
    198:   PetscReal         *Amax_pos,*Amax_neg;
    199:   PetscScalar       g_pos,g_neg,a_pos,a_neg,diag,invdiag,alpha,beta,pij;
    200:   PetscScalar       *pvals;
    201:   const PetscScalar *rval;
    202:   Mat               lA,gA=NULL;
    203:   MatType           mtype;
    204:   Vec               C,lvec;
    205:   PetscLayout       clayout;
    206:   PetscSF           sf;
    207:   Mat_MPIAIJ        *mpiaij;

    210:   MatGetOwnershipRange(A,&fs,&fe);
    211:   fn = fe-fs;
    212:   PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&isMPIAIJ);
    213:   PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&isSEQAIJ);
    214:   if (!isMPIAIJ && !isSEQAIJ) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"Classical AMG requires MPIAIJ matrix");
    215:   if (isMPIAIJ) {
    216:     mpiaij = (Mat_MPIAIJ*)A->data;
    217:     lA = mpiaij->A;
    218:     gA = mpiaij->B;
    219:     lvec = mpiaij->lvec;
    220:     VecGetSize(lvec,&noff);
    221:     colmap = mpiaij->garray;
    222:     MatGetLayouts(A,NULL,&clayout);
    223:     PetscSFCreate(PetscObjectComm((PetscObject)A),&sf);
    224:     PetscSFSetGraphLayout(sf,clayout,noff,NULL,PETSC_COPY_VALUES,colmap);
    225:     PetscMalloc1(noff,&gcid);
    226:   } else {
    227:     lA = A;
    228:   }
    229:   PetscMalloc5(fn,&lsparse,fn,&gsparse,fn,&lcid,fn,&Amax_pos,fn,&Amax_neg);

    231:   /* count the number of coarse unknowns */
    232:   cn = 0;
    233:   for (i=0;i<fn;i++) {
    234:     /* filter out singletons */
    235:     PetscCDEmptyAt(agg_lists,i,&iscoarse);
    236:     lcid[i] = -1;
    237:     if (!iscoarse) {
    238:       cn++;
    239:     }
    240:   }

    242:    /* create the coarse vector */
    243:   VecCreateMPI(PetscObjectComm((PetscObject)A),cn,PETSC_DECIDE,&C);
    244:   VecGetOwnershipRange(C,&cs,&ce);

    246:   cn = 0;
    247:   for (i=0;i<fn;i++) {
    248:     PetscCDEmptyAt(agg_lists,i,&iscoarse);
    249:     if (!iscoarse) {
    250:       lcid[i] = cs+cn;
    251:       cn++;
    252:     } else {
    253:       lcid[i] = -1;
    254:     }
    255:   }

    257:   if (gA) {
    258:     PetscSFBcastBegin(sf,MPIU_INT,lcid,gcid,MPI_REPLACE);
    259:     PetscSFBcastEnd(sf,MPIU_INT,lcid,gcid,MPI_REPLACE);
    260:   }

    262:   /* determine the largest off-diagonal entries in each row */
    263:   for (i=fs;i<fe;i++) {
    264:     Amax_pos[i-fs] = 0.;
    265:     Amax_neg[i-fs] = 0.;
    266:     MatGetRow(A,i,&ncols,&rcol,&rval);
    267:     for (j=0;j<ncols;j++) {
    268:       if ((PetscRealPart(-rval[j]) > Amax_neg[i-fs]) && i != rcol[j]) Amax_neg[i-fs] = PetscAbsScalar(rval[j]);
    269:       if ((PetscRealPart(rval[j])  > Amax_pos[i-fs]) && i != rcol[j]) Amax_pos[i-fs] = PetscAbsScalar(rval[j]);
    270:     }
    271:     if (ncols > cmax) cmax = ncols;
    272:     MatRestoreRow(A,i,&ncols,&rcol,&rval);
    273:   }
    274:   PetscMalloc2(cmax,&pcols,cmax,&pvals);
    275:   VecDestroy(&C);

    277:   /* count the on and off processor sparsity patterns for the prolongator */
    278:   for (i=0;i<fn;i++) {
    279:     /* on */
    280:     lsparse[i] = 0;
    281:     gsparse[i] = 0;
    282:     if (lcid[i] >= 0) {
    283:       lsparse[i] = 1;
    284:       gsparse[i] = 0;
    285:     } else {
    286:       MatGetRow(lA,i,&ncols,&rcol,&rval);
    287:       for (j = 0;j < ncols;j++) {
    288:         col = rcol[j];
    289:         if (lcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold[0]*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold[0]*Amax_neg[i])) {
    290:           lsparse[i] += 1;
    291:         }
    292:       }
    293:       MatRestoreRow(lA,i,&ncols,&rcol,&rval);
    294:       /* off */
    295:       if (gA) {
    296:         MatGetRow(gA,i,&ncols,&rcol,&rval);
    297:         for (j = 0; j < ncols; j++) {
    298:           col = rcol[j];
    299:           if (gcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold[0]*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold[0]*Amax_neg[i])) {
    300:             gsparse[i] += 1;
    301:           }
    302:         }
    303:         MatRestoreRow(gA,i,&ncols,&rcol,&rval);
    304:       }
    305:     }
    306:   }

    308:   /* preallocate and create the prolongator */
    309:   MatCreate(PetscObjectComm((PetscObject)A),P);
    310:   MatGetType(G,&mtype);
    311:   MatSetType(*P,mtype);
    312:   MatSetSizes(*P,fn,cn,PETSC_DETERMINE,PETSC_DETERMINE);
    313:   MatMPIAIJSetPreallocation(*P,0,lsparse,0,gsparse);
    314:   MatSeqAIJSetPreallocation(*P,0,lsparse);

    316:   /* loop over local fine nodes -- get the diagonal, the sum of positive and negative strong and weak weights, and set up the row */
    317:   for (i = 0;i < fn;i++) {
    318:     /* determine on or off */
    319:     row_f = i + fs;
    320:     row_c = lcid[i];
    321:     if (row_c >= 0) {
    322:       pij = 1.;
    323:       MatSetValues(*P,1,&row_f,1,&row_c,&pij,INSERT_VALUES);
    324:     } else {
    325:       g_pos = 0.;
    326:       g_neg = 0.;
    327:       a_pos = 0.;
    328:       a_neg = 0.;
    329:       diag  = 0.;

    331:       /* local connections */
    332:       MatGetRow(lA,i,&ncols,&rcol,&rval);
    333:       for (j = 0; j < ncols; j++) {
    334:         col = rcol[j];
    335:         if (lcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold[0]*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold[0]*Amax_neg[i])) {
    336:           if (PetscRealPart(rval[j]) > 0.) {
    337:             g_pos += rval[j];
    338:           } else {
    339:             g_neg += rval[j];
    340:           }
    341:         }
    342:         if (col != i) {
    343:           if (PetscRealPart(rval[j]) > 0.) {
    344:             a_pos += rval[j];
    345:           } else {
    346:             a_neg += rval[j];
    347:           }
    348:         } else {
    349:           diag = rval[j];
    350:         }
    351:       }
    352:       MatRestoreRow(lA,i,&ncols,&rcol,&rval);

    354:       /* ghosted connections */
    355:       if (gA) {
    356:         MatGetRow(gA,i,&ncols,&rcol,&rval);
    357:         for (j = 0; j < ncols; j++) {
    358:           col = rcol[j];
    359:           if (gcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold[0]*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold[0]*Amax_neg[i])) {
    360:             if (PetscRealPart(rval[j]) > 0.) {
    361:               g_pos += rval[j];
    362:             } else {
    363:               g_neg += rval[j];
    364:             }
    365:           }
    366:           if (PetscRealPart(rval[j]) > 0.) {
    367:             a_pos += rval[j];
    368:           } else {
    369:             a_neg += rval[j];
    370:           }
    371:         }
    372:         MatRestoreRow(gA,i,&ncols,&rcol,&rval);
    373:       }

    375:       if (g_neg == 0.) {
    376:         alpha = 0.;
    377:       } else {
    378:         alpha = -a_neg/g_neg;
    379:       }

    381:       if (g_pos == 0.) {
    382:         diag += a_pos;
    383:         beta = 0.;
    384:       } else {
    385:         beta = -a_pos/g_pos;
    386:       }
    387:       if (diag == 0.) {
    388:         invdiag = 0.;
    389:       } else invdiag = 1. / diag;
    390:       /* on */
    391:       MatGetRow(lA,i,&ncols,&rcol,&rval);
    392:       idx = 0;
    393:       for (j = 0;j < ncols;j++) {
    394:         col = rcol[j];
    395:         if (lcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold[0]*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold[0]*Amax_neg[i])) {
    396:           row_f = i + fs;
    397:           row_c = lcid[col];
    398:           /* set the values for on-processor ones */
    399:           if (PetscRealPart(rval[j]) < 0.) {
    400:             pij = rval[j]*alpha*invdiag;
    401:           } else {
    402:             pij = rval[j]*beta*invdiag;
    403:           }
    404:           if (PetscAbsScalar(pij) != 0.) {
    405:             pvals[idx] = pij;
    406:             pcols[idx] = row_c;
    407:             idx++;
    408:           }
    409:         }
    410:       }
    411:       MatRestoreRow(lA,i,&ncols,&rcol,&rval);
    412:       /* off */
    413:       if (gA) {
    414:         MatGetRow(gA,i,&ncols,&rcol,&rval);
    415:         for (j = 0; j < ncols; j++) {
    416:           col = rcol[j];
    417:           if (gcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold[0]*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold[0]*Amax_neg[i])) {
    418:             row_f = i + fs;
    419:             row_c = gcid[col];
    420:             /* set the values for on-processor ones */
    421:             if (PetscRealPart(rval[j]) < 0.) {
    422:               pij = rval[j]*alpha*invdiag;
    423:             } else {
    424:               pij = rval[j]*beta*invdiag;
    425:             }
    426:             if (PetscAbsScalar(pij) != 0.) {
    427:               pvals[idx] = pij;
    428:               pcols[idx] = row_c;
    429:               idx++;
    430:             }
    431:           }
    432:         }
    433:         MatRestoreRow(gA,i,&ncols,&rcol,&rval);
    434:       }
    435:       MatSetValues(*P,1,&row_f,idx,pcols,pvals,INSERT_VALUES);
    436:     }
    437:   }

    439:   MatAssemblyBegin(*P, MAT_FINAL_ASSEMBLY);
    440:   MatAssemblyEnd(*P, MAT_FINAL_ASSEMBLY);

    442:   PetscFree5(lsparse,gsparse,lcid,Amax_pos,Amax_neg);

    444:   PetscFree2(pcols,pvals);
    445:   if (gA) {
    446:     PetscSFDestroy(&sf);
    447:     PetscFree(gcid);
    448:   }
    449:   return(0);
    450: }

    452: PetscErrorCode PCGAMGTruncateProlongator_Private(PC pc,Mat *P)
    453: {
    454:   PetscInt          j,i,ps,pf,pn,pcs,pcf,pcn,idx,cmax;
    455:   PetscErrorCode    ierr;
    456:   const PetscScalar *pval;
    457:   const PetscInt    *pcol;
    458:   PetscScalar       *pnval;
    459:   PetscInt          *pncol;
    460:   PetscInt          ncols;
    461:   Mat               Pnew;
    462:   PetscInt          *lsparse,*gsparse;
    463:   PetscReal         pmax_pos,pmax_neg,ptot_pos,ptot_neg,pthresh_pos,pthresh_neg;
    464:   PC_MG             *mg          = (PC_MG*)pc->data;
    465:   PC_GAMG           *pc_gamg     = (PC_GAMG*)mg->innerctx;
    466:   PC_GAMG_Classical *cls         = (PC_GAMG_Classical*)pc_gamg->subctx;
    467:   MatType           mtype;

    470:   /* trim and rescale with reallocation */
    471:   MatGetOwnershipRange(*P,&ps,&pf);
    472:   MatGetOwnershipRangeColumn(*P,&pcs,&pcf);
    473:   pn = pf-ps;
    474:   pcn = pcf-pcs;
    475:   PetscMalloc2(pn,&lsparse,pn,&gsparse);
    476:   /* allocate */
    477:   cmax = 0;
    478:   for (i=ps;i<pf;i++) {
    479:     lsparse[i-ps] = 0;
    480:     gsparse[i-ps] = 0;
    481:     MatGetRow(*P,i,&ncols,&pcol,&pval);
    482:     if (ncols > cmax) {
    483:       cmax = ncols;
    484:     }
    485:     pmax_pos = 0.;
    486:     pmax_neg = 0.;
    487:     for (j=0;j<ncols;j++) {
    488:       if (PetscRealPart(pval[j]) > pmax_pos) {
    489:         pmax_pos = PetscRealPart(pval[j]);
    490:       } else if (PetscRealPart(pval[j]) < pmax_neg) {
    491:         pmax_neg = PetscRealPart(pval[j]);
    492:       }
    493:     }
    494:     for (j=0;j<ncols;j++) {
    495:       if (PetscRealPart(pval[j]) >= pmax_pos*cls->interp_threshold || PetscRealPart(pval[j]) <= pmax_neg*cls->interp_threshold) {
    496:         if (pcol[j] >= pcs && pcol[j] < pcf) {
    497:           lsparse[i-ps]++;
    498:         } else {
    499:           gsparse[i-ps]++;
    500:         }
    501:       }
    502:     }
    503:     MatRestoreRow(*P,i,&ncols,&pcol,&pval);
    504:   }

    506:   PetscMalloc2(cmax,&pnval,cmax,&pncol);

    508:   MatGetType(*P,&mtype);
    509:   MatCreate(PetscObjectComm((PetscObject)*P),&Pnew);
    510:   MatSetType(Pnew, mtype);
    511:   MatSetSizes(Pnew,pn,pcn,PETSC_DETERMINE,PETSC_DETERMINE);
    512:   MatSeqAIJSetPreallocation(Pnew,0,lsparse);
    513:   MatMPIAIJSetPreallocation(Pnew,0,lsparse,0,gsparse);

    515:   for (i=ps;i<pf;i++) {
    516:     MatGetRow(*P,i,&ncols,&pcol,&pval);
    517:     pmax_pos = 0.;
    518:     pmax_neg = 0.;
    519:     for (j=0;j<ncols;j++) {
    520:       if (PetscRealPart(pval[j]) > pmax_pos) {
    521:         pmax_pos = PetscRealPart(pval[j]);
    522:       } else if (PetscRealPart(pval[j]) < pmax_neg) {
    523:         pmax_neg = PetscRealPart(pval[j]);
    524:       }
    525:     }
    526:     pthresh_pos = 0.;
    527:     pthresh_neg = 0.;
    528:     ptot_pos = 0.;
    529:     ptot_neg = 0.;
    530:     for (j=0;j<ncols;j++) {
    531:       if (PetscRealPart(pval[j]) >= cls->interp_threshold*pmax_pos) {
    532:         pthresh_pos += PetscRealPart(pval[j]);
    533:       } else if (PetscRealPart(pval[j]) <= cls->interp_threshold*pmax_neg) {
    534:         pthresh_neg += PetscRealPart(pval[j]);
    535:       }
    536:       if (PetscRealPart(pval[j]) > 0.) {
    537:         ptot_pos += PetscRealPart(pval[j]);
    538:       } else {
    539:         ptot_neg += PetscRealPart(pval[j]);
    540:       }
    541:     }
    542:     if (PetscAbsReal(pthresh_pos) > 0.) ptot_pos /= pthresh_pos;
    543:     if (PetscAbsReal(pthresh_neg) > 0.) ptot_neg /= pthresh_neg;
    544:     idx=0;
    545:     for (j=0;j<ncols;j++) {
    546:       if (PetscRealPart(pval[j]) >= pmax_pos*cls->interp_threshold) {
    547:         pnval[idx] = ptot_pos*pval[j];
    548:         pncol[idx] = pcol[j];
    549:         idx++;
    550:       } else if (PetscRealPart(pval[j]) <= pmax_neg*cls->interp_threshold) {
    551:         pnval[idx] = ptot_neg*pval[j];
    552:         pncol[idx] = pcol[j];
    553:         idx++;
    554:       }
    555:     }
    556:     MatRestoreRow(*P,i,&ncols,&pcol,&pval);
    557:     MatSetValues(Pnew,1,&i,idx,pncol,pnval,INSERT_VALUES);
    558:   }

    560:   MatAssemblyBegin(Pnew, MAT_FINAL_ASSEMBLY);
    561:   MatAssemblyEnd(Pnew, MAT_FINAL_ASSEMBLY);
    562:   MatDestroy(P);

    564:   *P = Pnew;
    565:   PetscFree2(lsparse,gsparse);
    566:   PetscFree2(pnval,pncol);
    567:   return(0);
    568: }

    570: PetscErrorCode PCGAMGProlongator_Classical_Standard(PC pc, Mat A, Mat G, PetscCoarsenData *agg_lists,Mat *P)
    571: {
    572:   PetscErrorCode    ierr;
    573:   Mat               lA,*lAs;
    574:   MatType           mtype;
    575:   Vec               cv;
    576:   PetscInt          *gcid,*lcid,*lsparse,*gsparse,*picol;
    577:   PetscInt          fs,fe,cs,ce,nl,i,j,k,li,lni,ci,ncols,maxcols,fn,cn,cid;
    578:   PetscMPIInt       size;
    579:   const PetscInt    *lidx,*icol,*gidx;
    580:   PetscBool         iscoarse;
    581:   PetscScalar       vi,pentry,pjentry;
    582:   PetscScalar       *pcontrib,*pvcol;
    583:   const PetscScalar *vcol;
    584:   PetscReal         diag,jdiag,jwttotal;
    585:   PetscInt          pncols;
    586:   PetscSF           sf;
    587:   PetscLayout       clayout;
    588:   IS                lis;

    591:   MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);
    592:   MatGetOwnershipRange(A,&fs,&fe);
    593:   fn = fe-fs;
    594:   ISCreateStride(PETSC_COMM_SELF,fe-fs,fs,1,&lis);
    595:   if (size > 1) {
    596:     MatGetLayouts(A,NULL,&clayout);
    597:     /* increase the overlap by two to get neighbors of neighbors */
    598:     MatIncreaseOverlap(A,1,&lis,2);
    599:     ISSort(lis);
    600:     /* get the local part of A */
    601:     MatCreateSubMatrices(A,1,&lis,&lis,MAT_INITIAL_MATRIX,&lAs);
    602:     lA = lAs[0];
    603:     /* build an SF out of it */
    604:     ISGetLocalSize(lis,&nl);
    605:     PetscSFCreate(PetscObjectComm((PetscObject)A),&sf);
    606:     ISGetIndices(lis,&lidx);
    607:     PetscSFSetGraphLayout(sf,clayout,nl,NULL,PETSC_COPY_VALUES,lidx);
    608:     ISRestoreIndices(lis,&lidx);
    609:   } else {
    610:     lA = A;
    611:     nl = fn;
    612:   }
    613:   /* create a communication structure for the overlapped portion and transmit coarse indices */
    614:   PetscMalloc3(fn,&lsparse,fn,&gsparse,nl,&pcontrib);
    615:   /* create coarse vector */
    616:   cn = 0;
    617:   for (i=0;i<fn;i++) {
    618:     PetscCDEmptyAt(agg_lists,i,&iscoarse);
    619:     if (!iscoarse) {
    620:       cn++;
    621:     }
    622:   }
    623:   PetscMalloc1(fn,&gcid);
    624:   VecCreateMPI(PetscObjectComm((PetscObject)A),cn,PETSC_DECIDE,&cv);
    625:   VecGetOwnershipRange(cv,&cs,&ce);
    626:   cn = 0;
    627:   for (i=0;i<fn;i++) {
    628:     PetscCDEmptyAt(agg_lists,i,&iscoarse);
    629:     if (!iscoarse) {
    630:       gcid[i] = cs+cn;
    631:       cn++;
    632:     } else {
    633:       gcid[i] = -1;
    634:     }
    635:   }
    636:   if (size > 1) {
    637:     PetscMalloc1(nl,&lcid);
    638:     PetscSFBcastBegin(sf,MPIU_INT,gcid,lcid,MPI_REPLACE);
    639:     PetscSFBcastEnd(sf,MPIU_INT,gcid,lcid,MPI_REPLACE);
    640:   } else {
    641:     lcid = gcid;
    642:   }
    643:   /* count to preallocate the prolongator */
    644:   ISGetIndices(lis,&gidx);
    645:   maxcols = 0;
    646:   /* count the number of unique contributing coarse cells for each fine */
    647:   for (i=0;i<nl;i++) {
    648:     pcontrib[i] = 0.;
    649:     MatGetRow(lA,i,&ncols,&icol,NULL);
    650:     if (gidx[i] >= fs && gidx[i] < fe) {
    651:       li = gidx[i] - fs;
    652:       lsparse[li] = 0;
    653:       gsparse[li] = 0;
    654:       cid = lcid[i];
    655:       if (cid >= 0) {
    656:         lsparse[li] = 1;
    657:       } else {
    658:         for (j=0;j<ncols;j++) {
    659:           if (lcid[icol[j]] >= 0) {
    660:             pcontrib[icol[j]] = 1.;
    661:           } else {
    662:             ci = icol[j];
    663:             MatRestoreRow(lA,i,&ncols,&icol,NULL);
    664:             MatGetRow(lA,ci,&ncols,&icol,NULL);
    665:             for (k=0;k<ncols;k++) {
    666:               if (lcid[icol[k]] >= 0) {
    667:                 pcontrib[icol[k]] = 1.;
    668:               }
    669:             }
    670:             MatRestoreRow(lA,ci,&ncols,&icol,NULL);
    671:             MatGetRow(lA,i,&ncols,&icol,NULL);
    672:           }
    673:         }
    674:         for (j=0;j<ncols;j++) {
    675:           if (lcid[icol[j]] >= 0 && pcontrib[icol[j]] != 0.) {
    676:             lni = lcid[icol[j]];
    677:             if (lni >= cs && lni < ce) {
    678:               lsparse[li]++;
    679:             } else {
    680:               gsparse[li]++;
    681:             }
    682:             pcontrib[icol[j]] = 0.;
    683:           } else {
    684:             ci = icol[j];
    685:             MatRestoreRow(lA,i,&ncols,&icol,NULL);
    686:             MatGetRow(lA,ci,&ncols,&icol,NULL);
    687:             for (k=0;k<ncols;k++) {
    688:               if (lcid[icol[k]] >= 0 && pcontrib[icol[k]] != 0.) {
    689:                 lni = lcid[icol[k]];
    690:                 if (lni >= cs && lni < ce) {
    691:                   lsparse[li]++;
    692:                 } else {
    693:                   gsparse[li]++;
    694:                 }
    695:                 pcontrib[icol[k]] = 0.;
    696:               }
    697:             }
    698:             MatRestoreRow(lA,ci,&ncols,&icol,NULL);
    699:             MatGetRow(lA,i,&ncols,&icol,NULL);
    700:           }
    701:         }
    702:       }
    703:       if (lsparse[li] + gsparse[li] > maxcols) maxcols = lsparse[li]+gsparse[li];
    704:     }
    705:     MatRestoreRow(lA,i,&ncols,&icol,&vcol);
    706:   }
    707:   PetscMalloc2(maxcols,&picol,maxcols,&pvcol);
    708:   MatCreate(PetscObjectComm((PetscObject)A),P);
    709:   MatGetType(A,&mtype);
    710:   MatSetType(*P,mtype);
    711:   MatSetSizes(*P,fn,cn,PETSC_DETERMINE,PETSC_DETERMINE);
    712:   MatMPIAIJSetPreallocation(*P,0,lsparse,0,gsparse);
    713:   MatSeqAIJSetPreallocation(*P,0,lsparse);
    714:   for (i=0;i<nl;i++) {
    715:     diag = 0.;
    716:     if (gidx[i] >= fs && gidx[i] < fe) {
    717:       pncols=0;
    718:       cid = lcid[i];
    719:       if (cid >= 0) {
    720:         pncols = 1;
    721:         picol[0] = cid;
    722:         pvcol[0] = 1.;
    723:       } else {
    724:         MatGetRow(lA,i,&ncols,&icol,&vcol);
    725:         for (j=0;j<ncols;j++) {
    726:           pentry = vcol[j];
    727:           if (lcid[icol[j]] >= 0) {
    728:             /* coarse neighbor */
    729:             pcontrib[icol[j]] += pentry;
    730:           } else if (icol[j] != i) {
    731:             /* the neighbor is a strongly connected fine node */
    732:             ci = icol[j];
    733:             vi = vcol[j];
    734:             MatRestoreRow(lA,i,&ncols,&icol,&vcol);
    735:             MatGetRow(lA,ci,&ncols,&icol,&vcol);
    736:             jwttotal=0.;
    737:             jdiag = 0.;
    738:             for (k=0;k<ncols;k++) {
    739:               if (ci == icol[k]) {
    740:                 jdiag = PetscRealPart(vcol[k]);
    741:               }
    742:             }
    743:             for (k=0;k<ncols;k++) {
    744:               if (lcid[icol[k]] >= 0 && jdiag*PetscRealPart(vcol[k]) < 0.) {
    745:                 pjentry = vcol[k];
    746:                 jwttotal += PetscRealPart(pjentry);
    747:               }
    748:             }
    749:             if (jwttotal != 0.) {
    750:               jwttotal = PetscRealPart(vi)/jwttotal;
    751:               for (k=0;k<ncols;k++) {
    752:                 if (lcid[icol[k]] >= 0 && jdiag*PetscRealPart(vcol[k]) < 0.) {
    753:                   pjentry = vcol[k]*jwttotal;
    754:                   pcontrib[icol[k]] += pjentry;
    755:                 }
    756:               }
    757:             } else {
    758:               diag += PetscRealPart(vi);
    759:             }
    760:             MatRestoreRow(lA,ci,&ncols,&icol,&vcol);
    761:             MatGetRow(lA,i,&ncols,&icol,&vcol);
    762:           } else {
    763:             diag += PetscRealPart(vcol[j]);
    764:           }
    765:         }
    766:         if (diag != 0.) {
    767:           diag = 1./diag;
    768:           for (j=0;j<ncols;j++) {
    769:             if (lcid[icol[j]] >= 0 && pcontrib[icol[j]] != 0.) {
    770:               /* the neighbor is a coarse node */
    771:               if (PetscAbsScalar(pcontrib[icol[j]]) > 0.0) {
    772:                 lni = lcid[icol[j]];
    773:                 pvcol[pncols] = -pcontrib[icol[j]]*diag;
    774:                 picol[pncols] = lni;
    775:                 pncols++;
    776:               }
    777:               pcontrib[icol[j]] = 0.;
    778:             } else {
    779:               /* the neighbor is a strongly connected fine node */
    780:               ci = icol[j];
    781:               MatRestoreRow(lA,i,&ncols,&icol,&vcol);
    782:               MatGetRow(lA,ci,&ncols,&icol,&vcol);
    783:               for (k=0;k<ncols;k++) {
    784:                 if (lcid[icol[k]] >= 0 && pcontrib[icol[k]] != 0.) {
    785:                   if (PetscAbsScalar(pcontrib[icol[k]]) > 0.0) {
    786:                     lni = lcid[icol[k]];
    787:                     pvcol[pncols] = -pcontrib[icol[k]]*diag;
    788:                     picol[pncols] = lni;
    789:                     pncols++;
    790:                   }
    791:                   pcontrib[icol[k]] = 0.;
    792:                 }
    793:               }
    794:               MatRestoreRow(lA,ci,&ncols,&icol,&vcol);
    795:               MatGetRow(lA,i,&ncols,&icol,&vcol);
    796:             }
    797:             pcontrib[icol[j]] = 0.;
    798:           }
    799:           MatRestoreRow(lA,i,&ncols,&icol,&vcol);
    800:         }
    801:       }
    802:       ci = gidx[i];
    803:       if (pncols > 0) {
    804:         MatSetValues(*P,1,&ci,pncols,picol,pvcol,INSERT_VALUES);
    805:       }
    806:     }
    807:   }
    808:   ISRestoreIndices(lis,&gidx);
    809:   PetscFree2(picol,pvcol);
    810:   PetscFree3(lsparse,gsparse,pcontrib);
    811:   ISDestroy(&lis);
    812:   PetscFree(gcid);
    813:   if (size > 1) {
    814:     PetscFree(lcid);
    815:     MatDestroyMatrices(1,&lAs);
    816:     PetscSFDestroy(&sf);
    817:   }
    818:   VecDestroy(&cv);
    819:   MatAssemblyBegin(*P, MAT_FINAL_ASSEMBLY);
    820:   MatAssemblyEnd(*P, MAT_FINAL_ASSEMBLY);
    821:   return(0);
    822: }

    824: PetscErrorCode PCGAMGOptProlongator_Classical_Jacobi(PC pc,Mat A,Mat *P)
    825: {

    827:   PetscErrorCode    ierr;
    828:   PetscInt          f,s,n,cf,cs,i,idx;
    829:   PetscInt          *coarserows;
    830:   PetscInt          ncols;
    831:   const PetscInt    *pcols;
    832:   const PetscScalar *pvals;
    833:   Mat               Pnew;
    834:   Vec               diag;
    835:   PC_MG             *mg          = (PC_MG*)pc->data;
    836:   PC_GAMG           *pc_gamg     = (PC_GAMG*)mg->innerctx;
    837:   PC_GAMG_Classical *cls         = (PC_GAMG_Classical*)pc_gamg->subctx;

    840:   if (cls->nsmooths == 0) {
    841:     PCGAMGTruncateProlongator_Private(pc,P);
    842:     return(0);
    843:   }
    844:   MatGetOwnershipRange(*P,&s,&f);
    845:   n = f-s;
    846:   MatGetOwnershipRangeColumn(*P,&cs,&cf);
    847:   PetscMalloc1(n,&coarserows);
    848:   /* identify the rows corresponding to coarse unknowns */
    849:   idx = 0;
    850:   for (i=s;i<f;i++) {
    851:     MatGetRow(*P,i,&ncols,&pcols,&pvals);
    852:     /* assume, for now, that it's a coarse unknown if it has a single unit entry */
    853:     if (ncols == 1) {
    854:       if (pvals[0] == 1.) {
    855:         coarserows[idx] = i;
    856:         idx++;
    857:       }
    858:     }
    859:     MatRestoreRow(*P,i,&ncols,&pcols,&pvals);
    860:   }
    861:   MatCreateVecs(A,&diag,NULL);
    862:   MatGetDiagonal(A,diag);
    863:   VecReciprocal(diag);
    864:   for (i=0;i<cls->nsmooths;i++) {
    865:     MatMatMult(A,*P,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&Pnew);
    866:     MatZeroRows(Pnew,idx,coarserows,0.,NULL,NULL);
    867:     MatDiagonalScale(Pnew,diag,NULL);
    868:     MatAYPX(Pnew,-1.0,*P,DIFFERENT_NONZERO_PATTERN);
    869:     MatDestroy(P);
    870:     *P  = Pnew;
    871:     Pnew = NULL;
    872:   }
    873:   VecDestroy(&diag);
    874:   PetscFree(coarserows);
    875:   PCGAMGTruncateProlongator_Private(pc,P);
    876:   return(0);
    877: }

    879: PetscErrorCode PCGAMGProlongator_Classical(PC pc, Mat A, Mat G, PetscCoarsenData *agg_lists,Mat *P)
    880: {
    881:   PetscErrorCode    ierr;
    882:   PetscErrorCode    (*f)(PC,Mat,Mat,PetscCoarsenData*,Mat*);
    883:   PC_MG             *mg          = (PC_MG*)pc->data;
    884:   PC_GAMG           *pc_gamg     = (PC_GAMG*)mg->innerctx;
    885:   PC_GAMG_Classical *cls         = (PC_GAMG_Classical*)pc_gamg->subctx;

    888:   PetscFunctionListFind(PCGAMGClassicalProlongatorList,cls->prolongtype,&f);
    889:   if (!f)SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Cannot find PCGAMG Classical prolongator type");
    890:   (*f)(pc,A,G,agg_lists,P);
    891:   return(0);
    892: }

    894: PetscErrorCode PCGAMGDestroy_Classical(PC pc)
    895: {
    897:   PC_MG          *mg          = (PC_MG*)pc->data;
    898:   PC_GAMG        *pc_gamg     = (PC_GAMG*)mg->innerctx;

    901:   PetscFree(pc_gamg->subctx);
    902:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGClassicalSetType_C",NULL);
    903:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGClassicalGetType_C",NULL);
    904:   return(0);
    905: }

    907: PetscErrorCode PCGAMGSetFromOptions_Classical(PetscOptionItems *PetscOptionsObject,PC pc)
    908: {
    909:   PC_MG             *mg          = (PC_MG*)pc->data;
    910:   PC_GAMG           *pc_gamg     = (PC_GAMG*)mg->innerctx;
    911:   PC_GAMG_Classical *cls         = (PC_GAMG_Classical*)pc_gamg->subctx;
    912:   char              tname[256];
    913:   PetscErrorCode    ierr;
    914:   PetscBool         flg;

    917:   PetscOptionsHead(PetscOptionsObject,"GAMG-Classical options");
    918:   PetscOptionsFList("-pc_gamg_classical_type","Type of Classical AMG prolongation","PCGAMGClassicalSetType",PCGAMGClassicalProlongatorList,cls->prolongtype, tname, sizeof(tname), &flg);
    919:   if (flg) {
    920:     PCGAMGClassicalSetType(pc,tname);
    921:   }
    922:   PetscOptionsReal("-pc_gamg_classical_interp_threshold","Threshold for classical interpolator entries","",cls->interp_threshold,&cls->interp_threshold,NULL);
    923:   PetscOptionsInt("-pc_gamg_classical_nsmooths","Threshold for classical interpolator entries","",cls->nsmooths,&cls->nsmooths,NULL);
    924:   PetscOptionsTail();
    925:   return(0);
    926: }

    928: PetscErrorCode PCGAMGSetData_Classical(PC pc, Mat A)
    929: {
    930:   PC_MG          *mg      = (PC_MG*)pc->data;
    931:   PC_GAMG        *pc_gamg = (PC_GAMG*)mg->innerctx;

    934:   /* no data for classical AMG */
    935:   pc_gamg->data           = NULL;
    936:   pc_gamg->data_cell_cols = 0;
    937:   pc_gamg->data_cell_rows = 0;
    938:   pc_gamg->data_sz        = 0;
    939:   return(0);
    940: }

    942: PetscErrorCode PCGAMGClassicalFinalizePackage(void)
    943: {

    947:   PCGAMGClassicalPackageInitialized = PETSC_FALSE;
    948:   PetscFunctionListDestroy(&PCGAMGClassicalProlongatorList);
    949:   return(0);
    950: }

    952: PetscErrorCode PCGAMGClassicalInitializePackage(void)
    953: {

    957:   if (PCGAMGClassicalPackageInitialized) return(0);
    958:   PetscFunctionListAdd(&PCGAMGClassicalProlongatorList,PCGAMGCLASSICALDIRECT,PCGAMGProlongator_Classical_Direct);
    959:   PetscFunctionListAdd(&PCGAMGClassicalProlongatorList,PCGAMGCLASSICALSTANDARD,PCGAMGProlongator_Classical_Standard);
    960:   PetscRegisterFinalize(PCGAMGClassicalFinalizePackage);
    961:   return(0);
    962: }

    964: /* -------------------------------------------------------------------------- */
    965: /*
    966:    PCCreateGAMG_Classical

    968: */
    969: PetscErrorCode  PCCreateGAMG_Classical(PC pc)
    970: {
    972:   PC_MG             *mg      = (PC_MG*)pc->data;
    973:   PC_GAMG           *pc_gamg = (PC_GAMG*)mg->innerctx;
    974:   PC_GAMG_Classical *pc_gamg_classical;

    977:   PCGAMGClassicalInitializePackage();
    978:   if (pc_gamg->subctx) {
    979:     /* call base class */
    980:     PCDestroy_GAMG(pc);
    981:   }

    983:   /* create sub context for SA */
    984:   PetscNewLog(pc,&pc_gamg_classical);
    985:   pc_gamg->subctx = pc_gamg_classical;
    986:   pc->ops->setfromoptions = PCGAMGSetFromOptions_Classical;
    987:   /* reset does not do anything; setup not virtual */

    989:   /* set internal function pointers */
    990:   pc_gamg->ops->destroy        = PCGAMGDestroy_Classical;
    991:   pc_gamg->ops->graph          = PCGAMGGraph_Classical;
    992:   pc_gamg->ops->coarsen        = PCGAMGCoarsen_Classical;
    993:   pc_gamg->ops->prolongator    = PCGAMGProlongator_Classical;
    994:   pc_gamg->ops->optprolongator = PCGAMGOptProlongator_Classical_Jacobi;
    995:   pc_gamg->ops->setfromoptions = PCGAMGSetFromOptions_Classical;

    997:   pc_gamg->ops->createdefaultdata = PCGAMGSetData_Classical;
    998:   pc_gamg_classical->interp_threshold = 0.2;
    999:   pc_gamg_classical->nsmooths         = 0;
    1000:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGClassicalSetType_C",PCGAMGClassicalSetType_GAMG);
    1001:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGClassicalGetType_C",PCGAMGClassicalGetType_GAMG);
    1002:   PCGAMGClassicalSetType(pc,PCGAMGCLASSICALSTANDARD);
    1003:   return(0);
    1004: }