Actual source code: classical.c

petsc-3.7.7 2017-09-25
Report Typos and Errors
  1: #include <../src/ksp/pc/impls/gamg/gamg.h>        /*I "petscpc.h" I*/
  2: #include <petsc/private/kspimpl.h>
  3: #include <petscsf.h>

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

  8: typedef struct {
  9:   PetscReal interp_threshold; /* interpolation threshold */
 10:   char      prolongtype[256];
 11:   PetscInt  nsmooths;         /* number of jacobi smoothings on the prolongator */
 12: } PC_GAMG_Classical;

 16: /*@C
 17:    PCGAMGClassicalSetType - Sets the type of classical interpolation to use

 19:    Collective on PC

 21:    Input Parameters:
 22: .  pc - the preconditioner context

 24:    Options Database Key:
 25: .  -pc_gamg_classical_type

 27:    Level: intermediate

 29: .seealso: ()
 30: @*/
 31: PetscErrorCode PCGAMGClassicalSetType(PC pc, PCGAMGClassicalType type)
 32: {

 37:   PetscTryMethod(pc,"PCGAMGClassicalSetType_C",(PC,PCGAMGType),(pc,type));
 38:   return(0);
 39: }

 43: /*@C
 44:    PCGAMGClassicalGetType - Gets the type of classical interpolation to use

 46:    Collective on PC

 48:    Input Parameter:
 49: .  pc - the preconditioner context

 51:    Output Parameter:
 52: .  type - the type used

 54:    Level: intermediate

 56: .seealso: ()
 57: @*/
 58: PetscErrorCode PCGAMGClassicalGetType(PC pc, PCGAMGClassicalType *type)
 59: {

 64:   PetscUseMethod(pc,"PCGAMGClassicalGetType_C",(PC,PCGAMGType*),(pc,type));
 65:   return(0);
 66: }

 70: static PetscErrorCode PCGAMGClassicalSetType_GAMG(PC pc, PCGAMGClassicalType type)
 71: {
 72:   PetscErrorCode    ierr;
 73:   PC_MG             *mg          = (PC_MG*)pc->data;
 74:   PC_GAMG           *pc_gamg     = (PC_GAMG*)mg->innerctx;
 75:   PC_GAMG_Classical *cls         = (PC_GAMG_Classical*)pc_gamg->subctx;

 78:   PetscStrcpy(cls->prolongtype,type);
 79:   return(0);
 80: }

 84: static PetscErrorCode PCGAMGClassicalGetType_GAMG(PC pc, PCGAMGClassicalType *type)
 85: {
 86:   PC_MG             *mg          = (PC_MG*)pc->data;
 87:   PC_GAMG           *pc_gamg     = (PC_GAMG*)mg->innerctx;
 88:   PC_GAMG_Classical *cls         = (PC_GAMG_Classical*)pc_gamg->subctx;

 91:   *type = cls->prolongtype;
 92:   return(0);
 93: }

 97: PetscErrorCode PCGAMGGraph_Classical(PC pc,Mat A,Mat *G)
 98: {
 99:   PetscInt          s,f,n,idx,lidx,gidx;
100:   PetscInt          r,c,ncols;
101:   const PetscInt    *rcol;
102:   const PetscScalar *rval;
103:   PetscInt          *gcol;
104:   PetscScalar       *gval;
105:   PetscReal         rmax;
106:   PetscInt          cmax = 0;
107:   PC_MG             *mg;
108:   PC_GAMG           *gamg;
109:   PetscErrorCode    ierr;
110:   PetscInt          *gsparse,*lsparse;
111:   PetscScalar       *Amax;
112:   MatType           mtype;

115:   mg   = (PC_MG *)pc->data;
116:   gamg = (PC_GAMG *)mg->innerctx;

118:   MatGetOwnershipRange(A,&s,&f);
119:   n=f-s;
120:   PetscMalloc3(n,&lsparse,n,&gsparse,n,&Amax);

122:   for (r = 0;r < n;r++) {
123:     lsparse[r] = 0;
124:     gsparse[r] = 0;
125:   }

127:   for (r = s;r < f;r++) {
128:     /* determine the maximum off-diagonal in each row */
129:     rmax = 0.;
130:     MatGetRow(A,r,&ncols,&rcol,&rval);
131:     for (c = 0; c < ncols; c++) {
132:       if (PetscRealPart(-rval[c]) > rmax && rcol[c] != r) {
133:         rmax = PetscRealPart(-rval[c]);
134:       }
135:     }
136:     Amax[r-s] = rmax;
137:     if (ncols > cmax) cmax = ncols;
138:     lidx = 0;
139:     gidx = 0;
140:     /* create the local and global sparsity patterns */
141:     for (c = 0; c < ncols; c++) {
142:       if (PetscRealPart(-rval[c]) > gamg->threshold*PetscRealPart(Amax[r-s]) || rcol[c] == r) {
143:         if (rcol[c] < f && rcol[c] >= s) {
144:           lidx++;
145:         } else {
146:           gidx++;
147:         }
148:       }
149:     }
150:     MatRestoreRow(A,r,&ncols,&rcol,&rval);
151:     lsparse[r-s] = lidx;
152:     gsparse[r-s] = gidx;
153:   }
154:   PetscMalloc2(cmax,&gval,cmax,&gcol);

156:   MatCreate(PetscObjectComm((PetscObject)A),G);
157:   MatGetType(A,&mtype);
158:   MatSetType(*G,mtype);
159:   MatSetSizes(*G,n,n,PETSC_DETERMINE,PETSC_DETERMINE);
160:   MatMPIAIJSetPreallocation(*G,0,lsparse,0,gsparse);
161:   MatSeqAIJSetPreallocation(*G,0,lsparse);
162:   for (r = s;r < f;r++) {
163:     MatGetRow(A,r,&ncols,&rcol,&rval);
164:     idx = 0;
165:     for (c = 0; c < ncols; c++) {
166:       /* classical strength of connection */
167:       if (PetscRealPart(-rval[c]) > gamg->threshold*PetscRealPart(Amax[r-s]) || rcol[c] == r) {
168:         gcol[idx] = rcol[c];
169:         gval[idx] = rval[c];
170:         idx++;
171:       }
172:     }
173:     MatSetValues(*G,1,&r,idx,gcol,gval,INSERT_VALUES);
174:     MatRestoreRow(A,r,&ncols,&rcol,&rval);
175:   }
176:   MatAssemblyBegin(*G, MAT_FINAL_ASSEMBLY);
177:   MatAssemblyEnd(*G, MAT_FINAL_ASSEMBLY);

179:   PetscFree2(gval,gcol);
180:   PetscFree3(lsparse,gsparse,Amax);
181:   return(0);
182: }


187: PetscErrorCode PCGAMGCoarsen_Classical(PC pc,Mat *G,PetscCoarsenData **agg_lists)
188: {
189:   PetscErrorCode   ierr;
190:   MatCoarsen       crs;
191:   MPI_Comm         fcomm = ((PetscObject)pc)->comm;

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

196:   MatCoarsenCreate(fcomm,&crs);
197:   MatCoarsenSetFromOptions(crs);
198:   MatCoarsenSetAdjacency(crs,*G);
199:   MatCoarsenSetStrictAggs(crs,PETSC_TRUE);
200:   MatCoarsenApply(crs);
201:   MatCoarsenGetData(crs,agg_lists);
202:   MatCoarsenDestroy(&crs);

204:   return(0);
205: }

209: PetscErrorCode PCGAMGProlongator_Classical_Direct(PC pc, Mat A, Mat G, PetscCoarsenData *agg_lists,Mat *P)
210: {
211:   PetscErrorCode    ierr;
212:   PC_MG             *mg          = (PC_MG*)pc->data;
213:   PC_GAMG           *gamg        = (PC_GAMG*)mg->innerctx;
214:   PetscBool         iscoarse,isMPIAIJ,isSEQAIJ;
215:   PetscInt          fn,cn,fs,fe,cs,ce,i,j,ncols,col,row_f,row_c,cmax=0,idx,noff;
216:   PetscInt          *lcid,*gcid,*lsparse,*gsparse,*colmap,*pcols;
217:   const PetscInt    *rcol;
218:   PetscReal         *Amax_pos,*Amax_neg;
219:   PetscScalar       g_pos,g_neg,a_pos,a_neg,diag,invdiag,alpha,beta,pij;
220:   PetscScalar       *pvals;
221:   const PetscScalar *rval;
222:   Mat               lA,gA=NULL;
223:   MatType           mtype;
224:   Vec               C,lvec;
225:   PetscLayout       clayout;
226:   PetscSF           sf;
227:   Mat_MPIAIJ        *mpiaij;

230:   MatGetOwnershipRange(A,&fs,&fe);
231:   fn = fe-fs;
232:   PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&isMPIAIJ);
233:   PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&isSEQAIJ);
234:   if (!isMPIAIJ && !isSEQAIJ) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"Classical AMG requires MPIAIJ matrix");
235:   if (isMPIAIJ) {
236:     mpiaij = (Mat_MPIAIJ*)A->data;
237:     lA = mpiaij->A;
238:     gA = mpiaij->B;
239:     lvec = mpiaij->lvec;
240:     VecGetSize(lvec,&noff);
241:     colmap = mpiaij->garray;
242:     MatGetLayouts(A,NULL,&clayout);
243:     PetscSFCreate(PetscObjectComm((PetscObject)A),&sf);
244:     PetscSFSetGraphLayout(sf,clayout,noff,NULL,PETSC_COPY_VALUES,colmap);
245:     PetscMalloc1(noff,&gcid);
246:   } else {
247:     lA = A;
248:   }
249:   PetscMalloc5(fn,&lsparse,fn,&gsparse,fn,&lcid,fn,&Amax_pos,fn,&Amax_neg);

251:   /* count the number of coarse unknowns */
252:   cn = 0;
253:   for (i=0;i<fn;i++) {
254:     /* filter out singletons */
255:     PetscCDEmptyAt(agg_lists,i,&iscoarse);
256:     lcid[i] = -1;
257:     if (!iscoarse) {
258:       cn++;
259:     }
260:   }

262:    /* create the coarse vector */
263:   VecCreateMPI(PetscObjectComm((PetscObject)A),cn,PETSC_DECIDE,&C);
264:   VecGetOwnershipRange(C,&cs,&ce);

266:   cn = 0;
267:   for (i=0;i<fn;i++) {
268:     PetscCDEmptyAt(agg_lists,i,&iscoarse);
269:     if (!iscoarse) {
270:       lcid[i] = cs+cn;
271:       cn++;
272:     } else {
273:       lcid[i] = -1;
274:     }
275:   }

277:   if (gA) {
278:     PetscSFBcastBegin(sf,MPIU_INT,lcid,gcid);
279:     PetscSFBcastEnd(sf,MPIU_INT,lcid,gcid);
280:   }

282:   /* determine the biggest off-diagonal entries in each row */
283:   for (i=fs;i<fe;i++) {
284:     Amax_pos[i-fs] = 0.;
285:     Amax_neg[i-fs] = 0.;
286:     MatGetRow(A,i,&ncols,&rcol,&rval);
287:     for(j=0;j<ncols;j++){
288:       if ((PetscRealPart(-rval[j]) > Amax_neg[i-fs]) && i != rcol[j]) Amax_neg[i-fs] = PetscAbsScalar(rval[j]);
289:       if ((PetscRealPart(rval[j])  > Amax_pos[i-fs]) && i != rcol[j]) Amax_pos[i-fs] = PetscAbsScalar(rval[j]);
290:     }
291:     if (ncols > cmax) cmax = ncols;
292:     MatRestoreRow(A,i,&ncols,&rcol,&rval);
293:   }
294:   PetscMalloc2(cmax,&pcols,cmax,&pvals);
295:   VecDestroy(&C);

297:   /* count the on and off processor sparsity patterns for the prolongator */
298:   for (i=0;i<fn;i++) {
299:     /* on */
300:     lsparse[i] = 0;
301:     gsparse[i] = 0;
302:     if (lcid[i] >= 0) {
303:       lsparse[i] = 1;
304:       gsparse[i] = 0;
305:     } else {
306:       MatGetRow(lA,i,&ncols,&rcol,&rval);
307:       for (j = 0;j < ncols;j++) {
308:         col = rcol[j];
309:         if (lcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold*Amax_neg[i])) {
310:           lsparse[i] += 1;
311:         }
312:       }
313:       MatRestoreRow(lA,i,&ncols,&rcol,&rval);
314:       /* off */
315:       if (gA) {
316:         MatGetRow(gA,i,&ncols,&rcol,&rval);
317:         for (j = 0; j < ncols; j++) {
318:           col = rcol[j];
319:           if (gcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold*Amax_neg[i])) {
320:             gsparse[i] += 1;
321:           }
322:         }
323:         MatRestoreRow(gA,i,&ncols,&rcol,&rval);
324:       }
325:     }
326:   }

328:   /* preallocate and create the prolongator */
329:   MatCreate(PetscObjectComm((PetscObject)A),P);
330:   MatGetType(G,&mtype);
331:   MatSetType(*P,mtype);
332:   MatSetSizes(*P,fn,cn,PETSC_DETERMINE,PETSC_DETERMINE);
333:   MatMPIAIJSetPreallocation(*P,0,lsparse,0,gsparse);
334:   MatSeqAIJSetPreallocation(*P,0,lsparse);

336:   /* loop over local fine nodes -- get the diagonal, the sum of positive and negative strong and weak weights, and set up the row */
337:   for (i = 0;i < fn;i++) {
338:     /* determine on or off */
339:     row_f = i + fs;
340:     row_c = lcid[i];
341:     if (row_c >= 0) {
342:       pij = 1.;
343:       MatSetValues(*P,1,&row_f,1,&row_c,&pij,INSERT_VALUES);
344:     } else {
345:       g_pos = 0.;
346:       g_neg = 0.;
347:       a_pos = 0.;
348:       a_neg = 0.;
349:       diag = 0.;

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

374:       /* ghosted connections */
375:       if (gA) {
376:         MatGetRow(gA,i,&ncols,&rcol,&rval);
377:         for (j = 0; j < ncols; j++) {
378:           col = rcol[j];
379:           if (gcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold*Amax_neg[i])) {
380:             if (PetscRealPart(rval[j]) > 0.) {
381:               g_pos += rval[j];
382:             } else {
383:               g_neg += rval[j];
384:             }
385:           }
386:           if (PetscRealPart(rval[j]) > 0.) {
387:             a_pos += rval[j];
388:           } else {
389:             a_neg += rval[j];
390:           }
391:         }
392:         MatRestoreRow(gA,i,&ncols,&rcol,&rval);
393:       }

395:       if (g_neg == 0.) {
396:         alpha = 0.;
397:       } else {
398:         alpha = -a_neg/g_neg;
399:       }

401:       if (g_pos == 0.) {
402:         diag += a_pos;
403:         beta = 0.;
404:       } else {
405:         beta = -a_pos/g_pos;
406:       }
407:       if (diag == 0.) {
408:         invdiag = 0.;
409:       } else invdiag = 1. / diag;
410:       /* on */
411:       MatGetRow(lA,i,&ncols,&rcol,&rval);
412:       idx = 0;
413:       for (j = 0;j < ncols;j++) {
414:         col = rcol[j];
415:         if (lcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold*Amax_neg[i])) {
416:           row_f = i + fs;
417:           row_c = lcid[col];
418:           /* set the values for on-processor ones */
419:           if (PetscRealPart(rval[j]) < 0.) {
420:             pij = rval[j]*alpha*invdiag;
421:           } else {
422:             pij = rval[j]*beta*invdiag;
423:           }
424:           if (PetscAbsScalar(pij) != 0.) {
425:             pvals[idx] = pij;
426:             pcols[idx] = row_c;
427:             idx++;
428:           }
429:         }
430:       }
431:       MatRestoreRow(lA,i,&ncols,&rcol,&rval);
432:       /* off */
433:       if (gA) {
434:         MatGetRow(gA,i,&ncols,&rcol,&rval);
435:         for (j = 0; j < ncols; j++) {
436:           col = rcol[j];
437:           if (gcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold*Amax_neg[i])) {
438:             row_f = i + fs;
439:             row_c = gcid[col];
440:             /* set the values for on-processor ones */
441:             if (PetscRealPart(rval[j]) < 0.) {
442:               pij = rval[j]*alpha*invdiag;
443:             } else {
444:               pij = rval[j]*beta*invdiag;
445:             }
446:             if (PetscAbsScalar(pij) != 0.) {
447:               pvals[idx] = pij;
448:               pcols[idx] = row_c;
449:               idx++;
450:             }
451:           }
452:         }
453:         MatRestoreRow(gA,i,&ncols,&rcol,&rval);
454:       }
455:       MatSetValues(*P,1,&row_f,idx,pcols,pvals,INSERT_VALUES);
456:     }
457:   }

459:   MatAssemblyBegin(*P, MAT_FINAL_ASSEMBLY);
460:   MatAssemblyEnd(*P, MAT_FINAL_ASSEMBLY);

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

464:   PetscFree2(pcols,pvals);
465:   if (gA) {
466:     PetscSFDestroy(&sf);
467:     PetscFree(gcid);
468:   }

470:   return(0);
471: }

475: PetscErrorCode PCGAMGTruncateProlongator_Private(PC pc,Mat *P)
476: {
477:   PetscInt          j,i,ps,pf,pn,pcs,pcf,pcn,idx,cmax;
478:   PetscErrorCode    ierr;
479:   const PetscScalar *pval;
480:   const PetscInt    *pcol;
481:   PetscScalar       *pnval;
482:   PetscInt          *pncol;
483:   PetscInt          ncols;
484:   Mat               Pnew;
485:   PetscInt          *lsparse,*gsparse;
486:   PetscReal         pmax_pos,pmax_neg,ptot_pos,ptot_neg,pthresh_pos,pthresh_neg;
487:   PC_MG             *mg          = (PC_MG*)pc->data;
488:   PC_GAMG           *pc_gamg     = (PC_GAMG*)mg->innerctx;
489:   PC_GAMG_Classical *cls         = (PC_GAMG_Classical*)pc_gamg->subctx;
490:   MatType           mtype;

493:   /* trim and rescale with reallocation */
494:   MatGetOwnershipRange(*P,&ps,&pf);
495:   MatGetOwnershipRangeColumn(*P,&pcs,&pcf);
496:   pn = pf-ps;
497:   pcn = pcf-pcs;
498:   PetscMalloc2(pn,&lsparse,pn,&gsparse);
499:   /* allocate */
500:   cmax = 0;
501:   for (i=ps;i<pf;i++) {
502:     lsparse[i-ps] = 0;
503:     gsparse[i-ps] = 0;
504:     MatGetRow(*P,i,&ncols,&pcol,&pval);
505:     if (ncols > cmax) {
506:       cmax = ncols;
507:     }
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:     for (j=0;j<ncols;j++) {
518:       if (PetscRealPart(pval[j]) >= pmax_pos*cls->interp_threshold || PetscRealPart(pval[j]) <= pmax_neg*cls->interp_threshold) {
519:         if (pcol[j] >= pcs && pcol[j] < pcf) {
520:           lsparse[i-ps]++;
521:         } else {
522:           gsparse[i-ps]++;
523:         }
524:       }
525:     }
526:     MatRestoreRow(*P,i,&ncols,&pcol,&pval);
527:   }

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

531:   MatGetType(*P,&mtype);
532:   MatCreate(PetscObjectComm((PetscObject)*P),&Pnew);
533:   MatSetType(Pnew, mtype);
534:   MatSetSizes(Pnew,pn,pcn,PETSC_DETERMINE,PETSC_DETERMINE);
535:   MatSeqAIJSetPreallocation(Pnew,0,lsparse);
536:   MatMPIAIJSetPreallocation(Pnew,0,lsparse,0,gsparse);

538:   for (i=ps;i<pf;i++) {
539:     MatGetRow(*P,i,&ncols,&pcol,&pval);
540:     pmax_pos = 0.;
541:     pmax_neg = 0.;
542:     for (j=0;j<ncols;j++) {
543:       if (PetscRealPart(pval[j]) > pmax_pos) {
544:         pmax_pos = PetscRealPart(pval[j]);
545:       } else if (PetscRealPart(pval[j]) < pmax_neg) {
546:         pmax_neg = PetscRealPart(pval[j]);
547:       }
548:     }
549:     pthresh_pos = 0.;
550:     pthresh_neg = 0.;
551:     ptot_pos = 0.;
552:     ptot_neg = 0.;
553:     for (j=0;j<ncols;j++) {
554:       if (PetscRealPart(pval[j]) >= cls->interp_threshold*pmax_pos) {
555:         pthresh_pos += PetscRealPart(pval[j]);
556:       } else if (PetscRealPart(pval[j]) <= cls->interp_threshold*pmax_neg) {
557:         pthresh_neg += PetscRealPart(pval[j]);
558:       }
559:       if (PetscRealPart(pval[j]) > 0.) {
560:         ptot_pos += PetscRealPart(pval[j]);
561:       } else {
562:         ptot_neg += PetscRealPart(pval[j]);
563:       }
564:     }
565:     if (PetscAbsReal(pthresh_pos) > 0.) ptot_pos /= pthresh_pos;
566:     if (PetscAbsReal(pthresh_neg) > 0.) ptot_neg /= pthresh_neg;
567:     idx=0;
568:     for (j=0;j<ncols;j++) {
569:       if (PetscRealPart(pval[j]) >= pmax_pos*cls->interp_threshold) {
570:         pnval[idx] = ptot_pos*pval[j];
571:         pncol[idx] = pcol[j];
572:         idx++;
573:       } else if (PetscRealPart(pval[j]) <= pmax_neg*cls->interp_threshold) {
574:         pnval[idx] = ptot_neg*pval[j];
575:         pncol[idx] = pcol[j];
576:         idx++;
577:       }
578:     }
579:     MatRestoreRow(*P,i,&ncols,&pcol,&pval);
580:     MatSetValues(Pnew,1,&i,idx,pncol,pnval,INSERT_VALUES);
581:   }

583:   MatAssemblyBegin(Pnew, MAT_FINAL_ASSEMBLY);
584:   MatAssemblyEnd(Pnew, MAT_FINAL_ASSEMBLY);
585:   MatDestroy(P);

587:   *P = Pnew;
588:   PetscFree2(lsparse,gsparse);
589:   PetscFree2(pnval,pncol);
590:   return(0);
591: }

595: PetscErrorCode PCGAMGProlongator_Classical_Standard(PC pc, Mat A, Mat G, PetscCoarsenData *agg_lists,Mat *P)
596: {
597:   PetscErrorCode    ierr;
598:   Mat               lA,*lAs;
599:   MatType           mtype;
600:   Vec               cv;
601:   PetscInt          *gcid,*lcid,*lsparse,*gsparse,*picol;
602:   PetscInt          fs,fe,cs,ce,nl,i,j,k,li,lni,ci,ncols,maxcols,fn,cn,cid;
603:   PetscMPIInt       size;
604:   const PetscInt    *lidx,*icol,*gidx;
605:   PetscBool         iscoarse;
606:   PetscScalar       vi,pentry,pjentry;
607:   PetscScalar       *pcontrib,*pvcol;
608:   const PetscScalar *vcol;
609:   PetscReal         diag,jdiag,jwttotal;
610:   PetscInt          pncols;
611:   PetscSF           sf;
612:   PetscLayout       clayout;
613:   IS                lis;

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

851: PetscErrorCode PCGAMGOptProlongator_Classical_Jacobi(PC pc,Mat A,Mat *P)
852: {

854:   PetscErrorCode    ierr;
855:   PetscInt          f,s,n,cf,cs,i,idx;
856:   PetscInt          *coarserows;
857:   PetscInt          ncols;
858:   const PetscInt    *pcols;
859:   const PetscScalar *pvals;
860:   Mat               Pnew;
861:   Vec               diag;
862:   PC_MG             *mg          = (PC_MG*)pc->data;
863:   PC_GAMG           *pc_gamg     = (PC_GAMG*)mg->innerctx;
864:   PC_GAMG_Classical *cls         = (PC_GAMG_Classical*)pc_gamg->subctx;

867:   if (cls->nsmooths == 0) {
868:     PCGAMGTruncateProlongator_Private(pc,P);
869:     return(0);
870:   }
871:   MatGetOwnershipRange(*P,&s,&f);
872:   n = f-s;
873:   MatGetOwnershipRangeColumn(*P,&cs,&cf);
874:   PetscMalloc1(n,&coarserows);
875:   /* identify the rows corresponding to coarse unknowns */
876:   idx = 0;
877:   for (i=s;i<f;i++) {
878:     MatGetRow(*P,i,&ncols,&pcols,&pvals);
879:     /* assume, for now, that it's a coarse unknown if it has a single unit entry */
880:     if (ncols == 1) {
881:       if (pvals[0] == 1.) {
882:         coarserows[idx] = i;
883:         idx++;
884:       }
885:     }
886:     MatRestoreRow(*P,i,&ncols,&pcols,&pvals);
887:   }
888:   MatCreateVecs(A,&diag,0);
889:   MatGetDiagonal(A,diag);
890:   VecReciprocal(diag);
891:   for (i=0;i<cls->nsmooths;i++) {
892:     MatMatMult(A,*P,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&Pnew);
893:     MatZeroRows(Pnew,idx,coarserows,0.,NULL,NULL);
894:     MatDiagonalScale(Pnew,diag,0);
895:     MatAYPX(Pnew,-1.0,*P,DIFFERENT_NONZERO_PATTERN);
896:     MatDestroy(P);
897:     *P  = Pnew;
898:     Pnew = NULL;
899:   }
900:   VecDestroy(&diag);
901:   PetscFree(coarserows);
902:   PCGAMGTruncateProlongator_Private(pc,P);
903:   return(0);
904: }

908: PetscErrorCode PCGAMGProlongator_Classical(PC pc, Mat A, Mat G, PetscCoarsenData *agg_lists,Mat *P)
909: {
910:   PetscErrorCode    ierr;
911:   PetscErrorCode    (*f)(PC,Mat,Mat,PetscCoarsenData*,Mat*);
912:   PC_MG             *mg          = (PC_MG*)pc->data;
913:   PC_GAMG           *pc_gamg     = (PC_GAMG*)mg->innerctx;
914:   PC_GAMG_Classical *cls         = (PC_GAMG_Classical*)pc_gamg->subctx;

917:   PetscFunctionListFind(PCGAMGClassicalProlongatorList,cls->prolongtype,&f);
918:   if (!f)SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Cannot find PCGAMG Classical prolongator type");
919:   (*f)(pc,A,G,agg_lists,P);
920:   return(0);
921: }

925: PetscErrorCode PCGAMGDestroy_Classical(PC pc)
926: {
928:   PC_MG          *mg          = (PC_MG*)pc->data;
929:   PC_GAMG        *pc_gamg     = (PC_GAMG*)mg->innerctx;

932:   PetscFree(pc_gamg->subctx);
933:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGClassicalSetType_C",NULL);
934:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGClassicalGetType_C",NULL);
935:   return(0);
936: }

940: PetscErrorCode PCGAMGSetFromOptions_Classical(PetscOptionItems *PetscOptionsObject,PC pc)
941: {
942:   PC_MG             *mg          = (PC_MG*)pc->data;
943:   PC_GAMG           *pc_gamg     = (PC_GAMG*)mg->innerctx;
944:   PC_GAMG_Classical *cls         = (PC_GAMG_Classical*)pc_gamg->subctx;
945:   char              tname[256];
946:   PetscErrorCode    ierr;
947:   PetscBool         flg;

950:   PetscOptionsHead(PetscOptionsObject,"GAMG-Classical options");
951:   PetscOptionsFList("-pc_gamg_classical_type","Type of Classical AMG prolongation","PCGAMGClassicalSetType",PCGAMGClassicalProlongatorList,cls->prolongtype, tname, sizeof(tname), &flg);
952:   if (flg) {
953:     PCGAMGClassicalSetType(pc,tname);
954:   }
955:   PetscOptionsReal("-pc_gamg_classical_interp_threshold","Threshold for classical interpolator entries","",cls->interp_threshold,&cls->interp_threshold,NULL);
956:   PetscOptionsInt("-pc_gamg_classical_nsmooths","Threshold for classical interpolator entries","",cls->nsmooths,&cls->nsmooths,NULL);
957:   PetscOptionsTail();
958:   return(0);
959: }

963: PetscErrorCode PCGAMGSetData_Classical(PC pc, Mat A)
964: {
965:   PC_MG          *mg      = (PC_MG*)pc->data;
966:   PC_GAMG        *pc_gamg = (PC_GAMG*)mg->innerctx;

969:   /* no data for classical AMG */
970:   pc_gamg->data = NULL;
971:   pc_gamg->data_cell_cols = 0;
972:   pc_gamg->data_cell_rows = 0;
973:   pc_gamg->data_sz        = 0;
974:   return(0);
975: }


980: PetscErrorCode PCGAMGClassicalFinalizePackage(void)
981: {

985:   PCGAMGClassicalPackageInitialized = PETSC_FALSE;
986:   PetscFunctionListDestroy(&PCGAMGClassicalProlongatorList);
987:   return(0);
988: }

992: PetscErrorCode PCGAMGClassicalInitializePackage(void)
993: {

997:   if (PCGAMGClassicalPackageInitialized) return(0);
998:   PetscFunctionListAdd(&PCGAMGClassicalProlongatorList,PCGAMGCLASSICALDIRECT,PCGAMGProlongator_Classical_Direct);
999:   PetscFunctionListAdd(&PCGAMGClassicalProlongatorList,PCGAMGCLASSICALSTANDARD,PCGAMGProlongator_Classical_Standard);
1000:   PetscRegisterFinalize(PCGAMGClassicalFinalizePackage);
1001:   return(0);
1002: }

1004: /* -------------------------------------------------------------------------- */
1005: /*
1006:    PCCreateGAMG_Classical

1008: */
1011: PetscErrorCode  PCCreateGAMG_Classical(PC pc)
1012: {
1014:   PC_MG             *mg      = (PC_MG*)pc->data;
1015:   PC_GAMG           *pc_gamg = (PC_GAMG*)mg->innerctx;
1016:   PC_GAMG_Classical *pc_gamg_classical;

1019:   PCGAMGClassicalInitializePackage();
1020:   if (pc_gamg->subctx) {
1021:     /* call base class */
1022:     PCDestroy_GAMG(pc);
1023:   }

1025:   /* create sub context for SA */
1026:   PetscNewLog(pc,&pc_gamg_classical);
1027:   pc_gamg->subctx = pc_gamg_classical;
1028:   pc->ops->setfromoptions = PCGAMGSetFromOptions_Classical;
1029:   /* reset does not do anything; setup not virtual */

1031:   /* set internal function pointers */
1032:   pc_gamg->ops->destroy        = PCGAMGDestroy_Classical;
1033:   pc_gamg->ops->graph          = PCGAMGGraph_Classical;
1034:   pc_gamg->ops->coarsen        = PCGAMGCoarsen_Classical;
1035:   pc_gamg->ops->prolongator    = PCGAMGProlongator_Classical;
1036:   pc_gamg->ops->optprolongator = PCGAMGOptProlongator_Classical_Jacobi;
1037:   pc_gamg->ops->setfromoptions = PCGAMGSetFromOptions_Classical;

1039:   pc_gamg->ops->createdefaultdata = PCGAMGSetData_Classical;
1040:   pc_gamg_classical->interp_threshold = 0.2;
1041:   pc_gamg_classical->nsmooths         = 0;
1042:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGClassicalSetType_C",PCGAMGClassicalSetType_GAMG);
1043:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGClassicalGetType_C",PCGAMGClassicalGetType_GAMG);
1044:   PCGAMGClassicalSetType(pc,PCGAMGCLASSICALSTANDARD);
1045:   return(0);
1046: }