Actual source code: classical.c

petsc-dev 2014-02-02
Report Typos and Errors
  1: #include <../src/ksp/pc/impls/gamg/gamg.h>        /*I "petscpc.h" I*/
  2: #include <petsc-private/kspimpl.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;

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

 18:    Collective on PC

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

 23:    Options Database Key:
 24: .  -pc_gamg_classical_type

 26:    Level: intermediate

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

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

 42: static PetscErrorCode PCGAMGClassicalSetType_GAMG(PC pc, PCGAMGClassicalType type)
 43: {
 44:   PetscErrorCode    ierr;
 45:   PC_MG             *mg          = (PC_MG*)pc->data;
 46:   PC_GAMG           *pc_gamg     = (PC_GAMG*)mg->innerctx;
 47:   PC_GAMG_Classical *cls         = (PC_GAMG_Classical*)pc_gamg->subctx;

 50:   PetscStrcpy(cls->prolongtype,type);
 51:   return(0);
 52: }

 56: PetscErrorCode PCGAMGClassicalCreateGhostVector_Private(Mat G,Vec *gvec,PetscInt **global)
 57: {
 58:   Mat_MPIAIJ     *aij = (Mat_MPIAIJ*)G->data;
 60:   PetscBool      isMPIAIJ;

 63:   PetscObjectTypeCompare((PetscObject)G, MATMPIAIJ, &isMPIAIJ);
 64:   if (isMPIAIJ) {
 65:     if (gvec)VecDuplicate(aij->lvec,gvec);
 66:     if (global)*global = aij->garray;
 67:   } else {
 68:     /* no off-processor nodes */
 69:     if (gvec)*gvec = NULL;
 70:     if (global)*global = NULL;
 71:   }
 72:   return(0);
 73: }

 77: /*
 78:  Split the relevant graph into diagonal and off-diagonal parts in local numbering; for now this
 79:  a roundabout private interface to the mats' internal diag and offdiag mats.
 80:  */
 81: PetscErrorCode PCGAMGClassicalGraphSplitting_Private(Mat G,Mat *Gd, Mat *Go)
 82: {
 83:   Mat_MPIAIJ     *aij = (Mat_MPIAIJ*)G->data;
 85:   PetscBool      isMPIAIJ;
 87:   PetscObjectTypeCompare((PetscObject)G, MATMPIAIJ, &isMPIAIJ );
 88:   if (isMPIAIJ) {
 89:     *Gd = aij->A;
 90:     *Go = aij->B;
 91:   } else {
 92:     *Gd = G;
 93:     *Go = NULL;
 94:   }
 95:   return(0);
 96: }

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

118:   mg   = (PC_MG *)pc->data;
119:   gamg = (PC_GAMG *)mg->innerctx;

121:   MatGetOwnershipRange(A,&s,&f);
122:   n=f-s;
123:   PetscMalloc(sizeof(PetscInt)*n,&lsparse);
124:   PetscMalloc(sizeof(PetscInt)*n,&gsparse);
125:   PetscMalloc(sizeof(PetscScalar)*n,&Amax);

127:   for (r = 0;r < n;r++) {
128:     lsparse[r] = 0;
129:     gsparse[r] = 0;
130:   }

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

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

185:   PetscFree(gval);
186:   PetscFree(gcol);
187:   PetscFree(lsparse);
188:   PetscFree(gsparse);
189:   PetscFree(Amax);
190:   return(0);
191: }


196: PetscErrorCode PCGAMGCoarsen_Classical(PC pc,Mat *G,PetscCoarsenData **agg_lists)
197: {
198:   PetscErrorCode   ierr;
199:   MatCoarsen       crs;
200:   MPI_Comm         fcomm = ((PetscObject)pc)->comm;



205:   /* construct the graph if necessary */
206:   if (!G) {
207:     SETERRQ(fcomm,PETSC_ERR_ARG_WRONGSTATE,"Must set Graph in PC in PCGAMG before coarsening");
208:   }

210:   MatCoarsenCreate(fcomm,&crs);
211:   MatCoarsenSetFromOptions(crs);
212:   MatCoarsenSetAdjacency(crs,*G);
213:   MatCoarsenSetStrictAggs(crs,PETSC_TRUE);
214:   MatCoarsenApply(crs);
215:   MatCoarsenGetData(crs,agg_lists);
216:   MatCoarsenDestroy(&crs);

218:   return(0);
219: }

223: /*
224:  Find all ghost nodes that are coarse and output the fine/coarse splitting for those as well

226:  Input:
227:  G - graph;
228:  gvec - Global Vector
229:  avec - Local part of the scattered vec
230:  bvec - Global part of the scattered vec

232:  Output:
233:  findx - indirection t

235:  */
236: PetscErrorCode PCGAMGClassicalGhost_Private(Mat G,Vec v,Vec gv)
237: {
239:   Mat_MPIAIJ     *aij = (Mat_MPIAIJ*)G->data;
240:   PetscBool      isMPIAIJ;

243:   PetscObjectTypeCompare((PetscObject)G, MATMPIAIJ, &isMPIAIJ );
244:   if (isMPIAIJ) {
245:     VecScatterBegin(aij->Mvctx,v,gv,INSERT_VALUES,SCATTER_FORWARD);
246:     VecScatterEnd(aij->Mvctx,v,gv,INSERT_VALUES,SCATTER_FORWARD);
247:   }
248:   return(0);
249: }

253: PetscErrorCode PCGAMGProlongator_Classical_Direct(PC pc, const Mat A, const Mat G, PetscCoarsenData *agg_lists,Mat *P)
254: {
255:   PetscErrorCode    ierr;
256:   MPI_Comm          comm;
257:   PetscReal         *Amax_pos,*Amax_neg;
258:   Mat               lA,gA;                     /* on and off diagonal matrices */
259:   PetscInt          fn;                        /* fine local blocked sizes */
260:   PetscInt          cn;                        /* coarse local blocked sizes */
261:   PetscInt          gn;                        /* size of the off-diagonal fine vector */
262:   PetscInt          fs,fe;                     /* fine (row) ownership range*/
263:   PetscInt          cs,ce;                     /* coarse (column) ownership range */
264:   PetscInt          i,j;                       /* indices! */
265:   PetscBool         iscoarse;                  /* flag for determining if a node is coarse */
266:   PetscInt          *lcid,*gcid;               /* on and off-processor coarse unknown IDs */
267:   PetscInt          *lsparse,*gsparse;         /* on and off-processor sparsity patterns for prolongator */
268:   PetscScalar       pij;
269:   const PetscScalar *rval;
270:   const PetscInt    *rcol;
271:   PetscScalar       g_pos,g_neg,a_pos,a_neg,diag,invdiag,alpha,beta;
272:   Vec               F;   /* vec of coarse size */
273:   Vec               C;   /* vec of fine size */
274:   Vec               gF;  /* vec of off-diagonal fine size */
275:   MatType           mtype;
276:   PetscInt          c_indx;
277:   PetscScalar       c_scalar;
278:   PetscInt          ncols,col;
279:   PetscInt          row_f,row_c;
280:   PetscInt          cmax=0,idx;
281:   PetscScalar       *pvals;
282:   PetscInt          *pcols;
283:   PC_MG             *mg          = (PC_MG*)pc->data;
284:   PC_GAMG           *gamg        = (PC_GAMG*)mg->innerctx;

287:   comm = ((PetscObject)pc)->comm;
288:   MatGetOwnershipRange(A,&fs,&fe);
289:   fn = (fe - fs);

291:   MatGetVecs(A,&F,NULL);

293:   /* get the number of local unknowns and the indices of the local unknowns */

295:   PetscMalloc(sizeof(PetscInt)*fn,&lsparse);
296:   PetscMalloc(sizeof(PetscInt)*fn,&gsparse);
297:   PetscMalloc(sizeof(PetscInt)*fn,&lcid);
298:   PetscMalloc(sizeof(PetscReal)*fn,&Amax_pos);
299:   PetscMalloc(sizeof(PetscReal)*fn,&Amax_neg);

301:   /* count the number of coarse unknowns */
302:   cn = 0;
303:   for (i=0;i<fn;i++) {
304:     /* filter out singletons */
305:     PetscCDEmptyAt(agg_lists,i,&iscoarse);
306:     lcid[i] = -1;
307:     if (!iscoarse) {
308:       cn++;
309:     }
310:   }

312:    /* create the coarse vector */
313:   VecCreateMPI(comm,cn,PETSC_DECIDE,&C);
314:   VecGetOwnershipRange(C,&cs,&ce);

316:   /* construct a global vector indicating the global indices of the coarse unknowns */
317:   cn = 0;
318:   for (i=0;i<fn;i++) {
319:     PetscCDEmptyAt(agg_lists,i,&iscoarse);
320:     if (!iscoarse) {
321:       lcid[i] = cs+cn;
322:       cn++;
323:     } else {
324:       lcid[i] = -1;
325:     }
326:     *((PetscInt *)&c_scalar) = lcid[i];
327:     c_indx = fs+i;
328:     VecSetValues(F,1,&c_indx,&c_scalar,INSERT_VALUES);
329:   }

331:   VecAssemblyBegin(F);
332:   VecAssemblyEnd(F);

334:   /* determine the biggest off-diagonal entries in each row */
335:   for (i=fs;i<fe;i++) {
336:     Amax_pos[i-fs] = 0.;
337:     Amax_neg[i-fs] = 0.;
338:     MatGetRow(A,i,&ncols,&rcol,&rval);
339:     for(j=0;j<ncols;j++){
340:       if ((PetscRealPart(-rval[j]) > Amax_neg[i-fs]) && i != rcol[j]) Amax_neg[i-fs] = PetscAbsScalar(rval[j]);
341:       if ((PetscRealPart(rval[j])  > Amax_pos[i-fs]) && i != rcol[j]) Amax_pos[i-fs] = PetscAbsScalar(rval[j]);
342:     }
343:     if (ncols > cmax) cmax = ncols;
344:     MatRestoreRow(A,i,&ncols,&rcol,&rval);
345:   }
346:   PetscMalloc(sizeof(PetscInt)*cmax,&pcols);
347:   PetscMalloc(sizeof(PetscScalar)*cmax,&pvals);

349:   /* split the operator into two */
350:   PCGAMGClassicalGraphSplitting_Private(A,&lA,&gA);

352:   /* scatter to the ghost vector */
353:   PCGAMGClassicalCreateGhostVector_Private(A,&gF,NULL);
354:   PCGAMGClassicalGhost_Private(A,F,gF);

356:   if (gA) {
357:     VecGetSize(gF,&gn);
358:     PetscMalloc(sizeof(PetscInt)*gn,&gcid);
359:     for (i=0;i<gn;i++) {
360:       VecGetValues(gF,1,&i,&c_scalar);
361:       gcid[i] = *((PetscInt *)&c_scalar);
362:     }
363:   }

365:   VecDestroy(&F);
366:   VecDestroy(&gF);
367:   VecDestroy(&C);

369:   /* count the on and off processor sparsity patterns for the prolongator */
370:   for (i=0;i<fn;i++) {
371:     /* on */
372:     lsparse[i] = 0;
373:     gsparse[i] = 0;
374:     if (lcid[i] >= 0) {
375:       lsparse[i] = 1;
376:       gsparse[i] = 0;
377:     } else {
378:       MatGetRow(lA,i,&ncols,&rcol,&rval);
379:       for (j = 0;j < ncols;j++) {
380:         col = rcol[j];
381:         if (lcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold*Amax_neg[i])) {
382:           lsparse[i] += 1;
383:         }
384:       }
385:       MatRestoreRow(lA,i,&ncols,&rcol,&rval);
386:       /* off */
387:       if (gA) {
388:         MatGetRow(gA,i,&ncols,&rcol,&rval);
389:         for (j = 0; j < ncols; j++) {
390:           col = rcol[j];
391:           if (gcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold*Amax_neg[i])) {
392:             gsparse[i] += 1;
393:           }
394:         }
395:         MatRestoreRow(gA,i,&ncols,&rcol,&rval);
396:       }
397:     }
398:   }

400:   /* preallocate and create the prolongator */
401:   MatCreate(comm,P);
402:   MatGetType(G,&mtype);
403:   MatSetType(*P,mtype);

405:   MatSetSizes(*P,fn,cn,PETSC_DETERMINE,PETSC_DETERMINE);
406:   MatMPIAIJSetPreallocation(*P,0,lsparse,0,gsparse);
407:   MatSeqAIJSetPreallocation(*P,0,lsparse);

409:   /* loop over local fine nodes -- get the diagonal, the sum of positive and negative strong and weak weights, and set up the row */
410:   for (i = 0;i < fn;i++) {
411:     /* determine on or off */
412:     row_f = i + fs;
413:     row_c = lcid[i];
414:     if (row_c >= 0) {
415:       pij = 1.;
416:       MatSetValues(*P,1,&row_f,1,&row_c,&pij,INSERT_VALUES);
417:     } else {
418:       g_pos = 0.;
419:       g_neg = 0.;
420:       a_pos = 0.;
421:       a_neg = 0.;
422:       diag = 0.;

424:       /* local connections */
425:       MatGetRow(lA,i,&ncols,&rcol,&rval);
426:       for (j = 0; j < ncols; j++) {
427:         col = rcol[j];
428:         if (lcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold*Amax_neg[i])) {
429:           if (PetscRealPart(rval[j]) > 0.) {
430:             g_pos += rval[j];
431:           } else {
432:             g_neg += rval[j];
433:           }
434:         }
435:         if (col != i) {
436:           if (PetscRealPart(rval[j]) > 0.) {
437:             a_pos += rval[j];
438:           } else {
439:             a_neg += rval[j];
440:           }
441:         } else {
442:           diag = rval[j];
443:         }
444:       }
445:       MatRestoreRow(lA,i,&ncols,&rcol,&rval);

447:       /* ghosted connections */
448:       if (gA) {
449:         MatGetRow(gA,i,&ncols,&rcol,&rval);
450:         for (j = 0; j < ncols; j++) {
451:           col = rcol[j];
452:           if (gcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold*Amax_neg[i])) {
453:             if (PetscRealPart(rval[j]) > 0.) {
454:               g_pos += rval[j];
455:             } else {
456:               g_neg += rval[j];
457:             }
458:           }
459:           if (PetscRealPart(rval[j]) > 0.) {
460:             a_pos += rval[j];
461:           } else {
462:             a_neg += rval[j];
463:           }
464:         }
465:         MatRestoreRow(gA,i,&ncols,&rcol,&rval);
466:       }

468:       if (g_neg == 0.) {
469:         alpha = 0.;
470:       } else {
471:         alpha = -a_neg/g_neg;
472:       }

474:       if (g_pos == 0.) {
475:         diag += a_pos;
476:         beta = 0.;
477:       } else {
478:         beta = -a_pos/g_pos;
479:       }
480:       if (diag == 0.) {
481:         invdiag = 0.;
482:       } else invdiag = 1. / diag;
483:       /* on */
484:       MatGetRow(lA,i,&ncols,&rcol,&rval);
485:       idx = 0;
486:       for (j = 0;j < ncols;j++) {
487:         col = rcol[j];
488:         if (lcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold*Amax_neg[i])) {
489:           row_f = i + fs;
490:           row_c = lcid[col];
491:           /* set the values for on-processor ones */
492:           if (PetscRealPart(rval[j]) < 0.) {
493:             pij = rval[j]*alpha*invdiag;
494:           } else {
495:             pij = rval[j]*beta*invdiag;
496:           }
497:           if (PetscAbsScalar(pij) != 0.) {
498:             pvals[idx] = pij;
499:             pcols[idx] = row_c;
500:             idx++;
501:           }
502:         }
503:       }
504:       MatRestoreRow(lA,i,&ncols,&rcol,&rval);
505:       /* off */
506:       if (gA) {
507:         MatGetRow(gA,i,&ncols,&rcol,&rval);
508:         for (j = 0; j < ncols; j++) {
509:           col = rcol[j];
510:           if (gcid[col] >= 0 && (PetscRealPart(rval[j]) > gamg->threshold*Amax_pos[i] || PetscRealPart(-rval[j]) > gamg->threshold*Amax_neg[i])) {
511:             row_f = i + fs;
512:             row_c = gcid[col];
513:             /* set the values for on-processor ones */
514:             if (PetscRealPart(rval[j]) < 0.) {
515:               pij = rval[j]*alpha*invdiag;
516:             } else {
517:               pij = rval[j]*beta*invdiag;
518:             }
519:             if (PetscAbsScalar(pij) != 0.) {
520:               pvals[idx] = pij;
521:               pcols[idx] = row_c;
522:               idx++;
523:             }
524:           }
525:         }
526:         MatRestoreRow(gA,i,&ncols,&rcol,&rval);
527:       }
528:       MatSetValues(*P,1,&row_f,idx,pcols,pvals,INSERT_VALUES);
529:     }
530:   }

532:   MatAssemblyBegin(*P, MAT_FINAL_ASSEMBLY);
533:   MatAssemblyEnd(*P, MAT_FINAL_ASSEMBLY);

535:   PetscFree(lsparse);
536:   PetscFree(gsparse);
537:   PetscFree(pcols);
538:   PetscFree(pvals);
539:   PetscFree(Amax_pos);
540:   PetscFree(Amax_neg);
541:   PetscFree(lcid);
542:   if (gA) {PetscFree(gcid);}

544:   return(0);
545: }

549: PetscErrorCode PCGAMGTruncateProlongator_Private(PC pc,Mat *P)
550: {
551:   PetscInt          j,i,ps,pf,pn,pcs,pcf,pcn,idx,cmax;
552:   PetscErrorCode    ierr;
553:   const PetscScalar *pval;
554:   const PetscInt    *pcol;
555:   PetscScalar       *pnval;
556:   PetscInt          *pncol;
557:   PetscInt          ncols;
558:   Mat               Pnew;
559:   PetscInt          *lsparse,*gsparse;
560:   PetscReal         pmax_pos,pmax_neg,ptot_pos,ptot_neg,pthresh_pos,pthresh_neg;
561:   PC_MG             *mg          = (PC_MG*)pc->data;
562:   PC_GAMG           *pc_gamg     = (PC_GAMG*)mg->innerctx;
563:   PC_GAMG_Classical *cls         = (PC_GAMG_Classical*)pc_gamg->subctx;

566:   /* trim and rescale with reallocation */
567:   MatGetOwnershipRange(*P,&ps,&pf);
568:   MatGetOwnershipRangeColumn(*P,&pcs,&pcf);
569:   pn = pf-ps;
570:   pcn = pcf-pcs;
571:   PetscMalloc(sizeof(PetscInt)*pn,&lsparse);
572:   PetscMalloc(sizeof(PetscInt)*pn,&gsparse);
573:   /* allocate */
574:   cmax = 0;
575:   for (i=ps;i<pf;i++) {
576:     lsparse[i-ps] = 0;
577:     gsparse[i-ps] = 0;
578:     MatGetRow(*P,i,&ncols,&pcol,&pval);
579:     if (ncols > cmax) {
580:       cmax = ncols;
581:     }
582:     pmax_pos = 0.;
583:     pmax_neg = 0.;
584:     for (j=0;j<ncols;j++) {
585:       if (PetscRealPart(pval[j]) > pmax_pos) {
586:         pmax_pos = PetscRealPart(pval[j]);
587:       } else if (PetscRealPart(pval[j]) < pmax_neg) {
588:         pmax_neg = PetscRealPart(pval[j]);
589:       }
590:     }
591:     for (j=0;j<ncols;j++) {
592:       if (PetscRealPart(pval[j]) >= pmax_pos*cls->interp_threshold || PetscRealPart(pval[j]) <= pmax_neg*cls->interp_threshold) {
593:         if (pcol[j] >= pcs && pcol[j] < pcf) {
594:           lsparse[i-ps]++;
595:         } else {
596:           gsparse[i-ps]++;
597:         }
598:       }
599:     }
600:     MatRestoreRow(*P,i,&ncols,&pcol,&pval);
601:   }

603:   PetscMalloc(sizeof(PetscScalar)*cmax,&pnval);
604:   PetscMalloc(sizeof(PetscInt)*cmax,&pncol);

606:   MatCreate(PetscObjectComm((PetscObject)*P),&Pnew);
607:   MatSetType(Pnew, MATAIJ);
608:   MatSetSizes(Pnew,pn,pcn,PETSC_DETERMINE,PETSC_DETERMINE);
609:   MatSeqAIJSetPreallocation(Pnew,0,lsparse);
610:   MatMPIAIJSetPreallocation(Pnew,0,lsparse,0,gsparse);

612:   for (i=ps;i<pf;i++) {
613:     MatGetRow(*P,i,&ncols,&pcol,&pval);
614:     pmax_pos = 0.;
615:     pmax_neg = 0.;
616:     for (j=0;j<ncols;j++) {
617:       if (PetscRealPart(pval[j]) > pmax_pos) {
618:         pmax_pos = PetscRealPart(pval[j]);
619:       } else if (PetscRealPart(pval[j]) < pmax_neg) {
620:         pmax_neg = PetscRealPart(pval[j]);
621:       }
622:     }
623:     pthresh_pos = 0.;
624:     pthresh_neg = 0.;
625:     ptot_pos = 0.;
626:     ptot_neg = 0.;
627:     for (j=0;j<ncols;j++) {
628:       if (PetscRealPart(pval[j]) >= cls->interp_threshold*pmax_pos) {
629:         pthresh_pos += PetscRealPart(pval[j]);
630:       } else if (PetscRealPart(pval[j]) <= cls->interp_threshold*pmax_neg) {
631:         pthresh_neg += PetscRealPart(pval[j]);
632:       }
633:       if (PetscRealPart(pval[j]) > 0.) {
634:         ptot_pos += PetscRealPart(pval[j]);
635:       } else {
636:         ptot_neg += PetscRealPart(pval[j]);
637:       }
638:     }
639:     if (PetscAbsReal(pthresh_pos) > 0.) ptot_pos /= pthresh_pos;
640:     if (PetscAbsReal(pthresh_neg) > 0.) ptot_neg /= pthresh_neg;
641:     idx=0;
642:     for (j=0;j<ncols;j++) {
643:       if (PetscRealPart(pval[j]) >= pmax_pos*cls->interp_threshold) {
644:         pnval[idx] = ptot_pos*pval[j];
645:         pncol[idx] = pcol[j];
646:         idx++;
647:       } else if (PetscRealPart(pval[j]) <= pmax_neg*cls->interp_threshold) {
648:         pnval[idx] = ptot_neg*pval[j];
649:         pncol[idx] = pcol[j];
650:         idx++;
651:       }
652:     }
653:     MatRestoreRow(*P,i,&ncols,&pcol,&pval);
654:     MatSetValues(Pnew,1,&i,idx,pncol,pnval,INSERT_VALUES);
655:   }

657:   MatAssemblyBegin(Pnew, MAT_FINAL_ASSEMBLY);
658:   MatAssemblyEnd(Pnew, MAT_FINAL_ASSEMBLY);
659:   MatDestroy(P);

661:   *P = Pnew;
662:   PetscFree(lsparse);
663:   PetscFree(gsparse);
664:   PetscFree(pncol);
665:   PetscFree(pnval);
666:   return(0);
667: }

671: PetscErrorCode PCGAMGProlongator_Classical_Standard(PC pc, const Mat A, const Mat G, PetscCoarsenData *agg_lists,Mat *P)
672: {
673:   PetscErrorCode    ierr;
674:   Mat               *lA;
675:   Vec               lv,v,cv;
676:   PetscScalar       *lcid;
677:   IS                lis;
678:   PetscInt          fs,fe,cs,ce,nl,i,j,k,li,lni,ci;
679:   VecScatter        lscat;
680:   PetscInt          fn,cn,cid,c_indx;
681:   PetscBool         iscoarse;
682:   PetscScalar       c_scalar;
683:   const PetscScalar *vcol;
684:   const PetscInt    *icol;
685:   const PetscInt    *gidx;
686:   PetscInt          ncols;
687:   PetscInt          *lsparse,*gsparse;
688:   MatType           mtype;
689:   PetscInt          maxcols;
690:   PetscReal         diag,jdiag,jwttotal;
691:   PetscScalar       *pvcol,vi;
692:   PetscInt          *picol;
693:   PetscInt          pncols;
694:   PetscScalar       *pcontrib,pentry,pjentry;
695:   /* PC_MG             *mg          = (PC_MG*)pc->data; */
696:   /* PC_GAMG           *gamg        = (PC_GAMG*)mg->innerctx; */


700:   MatGetOwnershipRange(A,&fs,&fe);
701:   fn = fe-fs;
702:   MatGetVecs(A,NULL,&v);
703:   ISCreateStride(PETSC_COMM_SELF,fe-fs,fs,1,&lis);
704:   /* increase the overlap by two to get neighbors of neighbors */
705:   MatIncreaseOverlap(A,1,&lis,2);
706:   ISSort(lis);
707:   /* get the local part of A */
708:   MatGetSubMatrices(A,1,&lis,&lis,MAT_INITIAL_MATRIX,&lA);
709:   /* build the scatter out of it */
710:   ISGetLocalSize(lis,&nl);
711:   VecCreateSeq(PETSC_COMM_SELF,nl,&lv);
712:   VecScatterCreate(v,lis,lv,NULL,&lscat);

714:   PetscMalloc(sizeof(PetscInt)*fn,&lsparse);
715:   PetscMalloc(sizeof(PetscInt)*fn,&gsparse);
716:   PetscMalloc(sizeof(PetscScalar)*nl,&pcontrib);

718:   /* create coarse vector */
719:   cn = 0;
720:   for (i=0;i<fn;i++) {
721:     PetscCDEmptyAt(agg_lists,i,&iscoarse);
722:     if (!iscoarse) {
723:       cn++;
724:     }
725:   }
726:   VecCreateMPI(PetscObjectComm((PetscObject)A),cn,PETSC_DECIDE,&cv);
727:   VecGetOwnershipRange(cv,&cs,&ce);
728:   cn = 0;
729:   for (i=0;i<fn;i++) {
730:     PetscCDEmptyAt(agg_lists,i,&iscoarse);
731:     if (!iscoarse) {
732:       cid = cs+cn;
733:       cn++;
734:     } else {
735:       cid = -1;
736:     }
737:     *(PetscInt*)&c_scalar = cid;
738:     c_indx = fs+i;
739:     VecSetValues(v,1,&c_indx,&c_scalar,INSERT_VALUES);
740:   }
741:   VecScatterBegin(lscat,v,lv,INSERT_VALUES,SCATTER_FORWARD);
742:   VecScatterEnd(lscat,v,lv,INSERT_VALUES,SCATTER_FORWARD);
743:   /* count to preallocate the prolongator */
744:   ISGetIndices(lis,&gidx);
745:   VecGetArray(lv,&lcid);
746:   maxcols = 0;
747:   /* count the number of unique contributing coarse cells for each fine */
748:   for (i=0;i<nl;i++) {
749:     pcontrib[i] = 0.;
750:     MatGetRow(lA[0],i,&ncols,&icol,NULL);
751:     if (gidx[i] >= fs && gidx[i] < fe) {
752:       li = gidx[i] - fs;
753:       lsparse[li] = 0;
754:       gsparse[li] = 0;
755:       cid = *(PetscInt*)&(lcid[i]);
756:       if (cid >= 0) {
757:         lsparse[li] = 1;
758:       } else {
759:         for (j=0;j<ncols;j++) {
760:           if (*(PetscInt*)&(lcid[icol[j]]) >= 0) {
761:             pcontrib[icol[j]] = 1.;
762:           } else {
763:             ci = icol[j];
764:             MatRestoreRow(lA[0],i,&ncols,&icol,NULL);
765:             MatGetRow(lA[0],ci,&ncols,&icol,NULL);
766:             for (k=0;k<ncols;k++) {
767:               if (*(PetscInt*)&(lcid[icol[k]]) >= 0) {
768:                 pcontrib[icol[k]] = 1.;
769:               }
770:             }
771:             MatRestoreRow(lA[0],ci,&ncols,&icol,NULL);
772:             MatGetRow(lA[0],i,&ncols,&icol,NULL);
773:           }
774:         }
775:         for (j=0;j<ncols;j++) {
776:           if (*(PetscInt*)&(lcid[icol[j]]) >= 0 && pcontrib[icol[j]] != 0.) {
777:             lni = *(PetscInt*)&(lcid[icol[j]]);
778:             if (lni >= cs && lni < ce) {
779:               lsparse[li]++;
780:             } else {
781:               gsparse[li]++;
782:             }
783:             pcontrib[icol[j]] = 0.;
784:           } else {
785:             ci = icol[j];
786:             MatRestoreRow(lA[0],i,&ncols,&icol,NULL);
787:             MatGetRow(lA[0],ci,&ncols,&icol,NULL);
788:             for (k=0;k<ncols;k++) {
789:               if (*(PetscInt*)&(lcid[icol[k]]) >= 0 && pcontrib[icol[k]] != 0.) {
790:                 lni = *(PetscInt*)&(lcid[icol[k]]);
791:                 if (lni >= cs && lni < ce) {
792:                   lsparse[li]++;
793:                 } else {
794:                   gsparse[li]++;
795:                 }
796:                 pcontrib[icol[k]] = 0.;
797:               }
798:             }
799:             MatRestoreRow(lA[0],ci,&ncols,&icol,NULL);
800:             MatGetRow(lA[0],i,&ncols,&icol,NULL);
801:           }
802:         }
803:       }
804:       if (lsparse[li] + gsparse[li] > maxcols) maxcols = lsparse[li]+gsparse[li];
805:     }
806:     MatRestoreRow(lA[0],i,&ncols,&icol,&vcol);
807:   }
808:   PetscMalloc(sizeof(PetscInt)*maxcols,&picol);
809:   PetscMalloc(sizeof(PetscScalar)*maxcols,&pvcol);
810:   MatCreate(PetscObjectComm((PetscObject)A),P);
811:   MatGetType(A,&mtype);
812:   MatSetType(*P,mtype);
813:   MatSetSizes(*P,fn,cn,PETSC_DETERMINE,PETSC_DETERMINE);
814:   MatMPIAIJSetPreallocation(*P,0,lsparse,0,gsparse);
815:   MatSeqAIJSetPreallocation(*P,0,lsparse);
816:   for (i=0;i<nl;i++) {
817:     diag = 0.;
818:     if (gidx[i] >= fs && gidx[i] < fe) {
819:       li = gidx[i] - fs;
820:       pncols=0;
821:       cid = *(PetscInt*)&(lcid[i]);
822:       if (cid >= 0) {
823:         pncols = 1;
824:         picol[0] = cid;
825:         pvcol[0] = 1.;
826:       } else {
827:         MatGetRow(lA[0],i,&ncols,&icol,&vcol);
828:         for (j=0;j<ncols;j++) {
829:           pentry = vcol[j];
830:           if (*(PetscInt*)&(lcid[icol[j]]) >= 0) {
831:             /* coarse neighbor */
832:             pcontrib[icol[j]] += pentry;
833:           } else if (icol[j] != i) {
834:             /* the neighbor is a strongly connected fine node */
835:             ci = icol[j];
836:             vi = vcol[j];
837:             MatRestoreRow(lA[0],i,&ncols,&icol,&vcol);
838:             MatGetRow(lA[0],ci,&ncols,&icol,&vcol);
839:             jwttotal=0.;
840:             jdiag = 0.;
841:             for (k=0;k<ncols;k++) {
842:               if (ci == icol[k]) {
843:                 jdiag = PetscRealPart(vcol[k]);
844:               }
845:             }
846:             for (k=0;k<ncols;k++) {
847:               if (*(PetscInt*)&(lcid[icol[k]]) >= 0 && jdiag*PetscRealPart(vcol[k]) < 0.) {
848:                 pjentry = vcol[k];
849:                 jwttotal += PetscRealPart(pjentry);
850:               }
851:             }
852:             if (jwttotal != 0.) {
853:               jwttotal = PetscRealPart(vi)/jwttotal;
854:               for (k=0;k<ncols;k++) {
855:                 if (*(PetscInt*)&(lcid[icol[k]]) >= 0 && jdiag*PetscRealPart(vcol[k]) < 0.) {
856:                   pjentry = vcol[k]*jwttotal;
857:                   pcontrib[icol[k]] += pjentry;
858:                 }
859:               }
860:             } else {
861:               diag += PetscRealPart(vi);
862:             }
863:             MatRestoreRow(lA[0],ci,&ncols,&icol,&vcol);
864:             MatGetRow(lA[0],i,&ncols,&icol,&vcol);
865:           } else {
866:             diag += PetscRealPart(vcol[j]);
867:           }
868:         }
869:         if (diag != 0.) {
870:           diag = 1./diag;
871:           for (j=0;j<ncols;j++) {
872:             if (*(PetscInt*)&(lcid[icol[j]]) >= 0 && pcontrib[icol[j]] != 0.) {
873:               /* the neighbor is a coarse node */
874:               if (PetscAbsScalar(pcontrib[icol[j]]) > 0.0) {
875:                 lni = *(PetscInt*)&(lcid[icol[j]]);
876:                 pvcol[pncols] = -pcontrib[icol[j]]*diag;
877:                 picol[pncols] = lni;
878:                 pncols++;
879:               }
880:               pcontrib[icol[j]] = 0.;
881:             } else {
882:               /* the neighbor is a strongly connected fine node */
883:               ci = icol[j];
884:               MatRestoreRow(lA[0],i,&ncols,&icol,&vcol);
885:               MatGetRow(lA[0],ci,&ncols,&icol,&vcol);
886:               for (k=0;k<ncols;k++) {
887:                 if (*(PetscInt*)&(lcid[icol[k]]) >= 0 && pcontrib[icol[k]] != 0.) {
888:                   if (PetscAbsScalar(pcontrib[icol[k]]) > 0.0) {
889:                     lni = *(PetscInt*)&(lcid[icol[k]]);
890:                     pvcol[pncols] = -pcontrib[icol[k]]*diag;
891:                     picol[pncols] = lni;
892:                     pncols++;
893:                   }
894:                   pcontrib[icol[k]] = 0.;
895:                 }
896:               }
897:               MatRestoreRow(lA[0],ci,&ncols,&icol,&vcol);
898:               MatGetRow(lA[0],i,&ncols,&icol,&vcol);
899:             }
900:             pcontrib[icol[j]] = 0.;
901:           }
902:           MatRestoreRow(lA[0],i,&ncols,&icol,&vcol);
903:         }
904:       }
905:       ci = gidx[i];
906:       li = gidx[i] - fs;
907:       if (pncols > 0) {
908:         MatSetValues(*P,1,&ci,pncols,picol,pvcol,INSERT_VALUES);
909:       }
910:     }
911:   }
912:   ISRestoreIndices(lis,&gidx);
913:   VecRestoreArray(lv,&lcid);

915:   PetscFree(pcontrib);
916:   PetscFree(picol);
917:   PetscFree(pvcol);
918:   PetscFree(lsparse);
919:   PetscFree(gsparse);
920:   ISDestroy(&lis);
921:   MatDestroyMatrices(1,&lA);
922:   VecDestroy(&lv);
923:   VecDestroy(&cv);
924:   VecDestroy(&v);
925:   VecScatterDestroy(&lscat);

927:   MatAssemblyBegin(*P, MAT_FINAL_ASSEMBLY);
928:   MatAssemblyEnd(*P, MAT_FINAL_ASSEMBLY);

930:   /*
931:   Mat Pold;
932:   PCGAMGProlongator_Classical(pc,A,G,agg_lists,&Pold);
933:   MatView(Pold,PETSC_VIEWER_STDOUT_WORLD);
934:   MatView(*P,PETSC_VIEWER_STDOUT_WORLD);
935:   MatDestroy(&Pold);
936:    */
937:   return(0);
938: }

942: PetscErrorCode PCGAMGOptProl_Classical_Jacobi(PC pc,const Mat A,Mat *P)
943: {

945:   PetscErrorCode    ierr;
946:   PetscInt          f,s,n,cf,cs,i,idx;
947:   PetscInt          *coarserows;
948:   PetscInt          ncols;
949:   const PetscInt    *pcols;
950:   const PetscScalar *pvals;
951:   Mat               Pnew;
952:   Vec               diag;
953:   PC_MG             *mg          = (PC_MG*)pc->data;
954:   PC_GAMG           *pc_gamg     = (PC_GAMG*)mg->innerctx;
955:   PC_GAMG_Classical *cls         = (PC_GAMG_Classical*)pc_gamg->subctx;

958:   if (cls->nsmooths == 0) {
959:     PCGAMGTruncateProlongator_Private(pc,P);
960:     return(0);
961:   }
962:   MatGetOwnershipRange(*P,&s,&f);
963:   n = f-s;
964:   MatGetOwnershipRangeColumn(*P,&cs,&cf);
965:   PetscMalloc(sizeof(PetscInt)*n,&coarserows);
966:   /* identify the rows corresponding to coarse unknowns */
967:   idx = 0;
968:   for (i=s;i<f;i++) {
969:     MatGetRow(*P,i,&ncols,&pcols,&pvals);
970:     /* assume, for now, that it's a coarse unknown if it has a single unit entry */
971:     if (ncols == 1) {
972:       if (pvals[0] == 1.) {
973:         coarserows[idx] = i;
974:         idx++;
975:       }
976:     }
977:     MatRestoreRow(*P,i,&ncols,&pcols,&pvals);
978:   }
979:   MatGetVecs(A,&diag,0);
980:   MatGetDiagonal(A,diag);
981:   VecReciprocal(diag);
982:   for (i=0;i<cls->nsmooths;i++) {
983:     MatMatMult(A,*P,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&Pnew);
984:     MatZeroRows(Pnew,idx,coarserows,0.,NULL,NULL);
985:     MatDiagonalScale(Pnew,diag,0);
986:     MatAYPX(Pnew,-1.0,*P,DIFFERENT_NONZERO_PATTERN);
987:     MatDestroy(P);
988:     *P  = Pnew;
989:     Pnew = NULL;
990:   }
991:   VecDestroy(&diag);
992:   PetscFree(coarserows);
993:   PCGAMGTruncateProlongator_Private(pc,P);
994:   return(0);
995: }

999: PetscErrorCode PCGAMGProlongator_Classical(PC pc, const Mat A, const Mat G, PetscCoarsenData *agg_lists,Mat *P)
1000: {
1001:   PetscErrorCode    ierr;
1002:   PetscErrorCode    (*f)(PC,Mat,Mat,PetscCoarsenData*,Mat*);
1003:   PC_MG             *mg          = (PC_MG*)pc->data;
1004:   PC_GAMG           *pc_gamg     = (PC_GAMG*)mg->innerctx;
1005:   PC_GAMG_Classical *cls         = (PC_GAMG_Classical*)pc_gamg->subctx;

1008:   PetscFunctionListFind(PCGAMGClassicalProlongatorList,cls->prolongtype,&f);
1009:   if (!f)SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Cannot find PCGAMG Classical prolongator type");
1010:   (*f)(pc,A,G,agg_lists,P);
1011:   return(0);
1012: }

1016: PetscErrorCode PCGAMGDestroy_Classical(PC pc)
1017: {
1019:   PC_MG          *mg          = (PC_MG*)pc->data;
1020:   PC_GAMG        *pc_gamg     = (PC_GAMG*)mg->innerctx;

1023:   PetscFree(pc_gamg->subctx);
1024:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGClassicalSetType_C",NULL);
1025:   return(0);
1026: }

1030: PetscErrorCode PCGAMGSetFromOptions_Classical(PC pc)
1031: {
1032:   PC_MG             *mg          = (PC_MG*)pc->data;
1033:   PC_GAMG           *pc_gamg     = (PC_GAMG*)mg->innerctx;
1034:   PC_GAMG_Classical *cls         = (PC_GAMG_Classical*)pc_gamg->subctx;
1035:   char              tname[256];
1036:   PetscErrorCode    ierr;
1037:   PetscBool         flg;

1040:   PetscOptionsHead("GAMG-Classical options");
1041:   PetscOptionsFList("-pc_gamg_classical_type","Type of Classical AMG prolongation",
1042:                           "PCGAMGClassicalSetType",PCGAMGClassicalProlongatorList,cls->prolongtype, tname, sizeof(tname), &flg);
1043:   if (flg) {
1044:     PCGAMGClassicalSetType(pc,tname);
1045:   }
1046:   PetscOptionsReal("-pc_gamg_classical_interp_threshold","Threshold for classical interpolator entries","",cls->interp_threshold,&cls->interp_threshold,NULL);
1047:   PetscOptionsInt("-pc_gamg_classical_nsmooths","Threshold for classical interpolator entries","",cls->nsmooths,&cls->nsmooths,NULL);
1048:   PetscOptionsTail();
1049:   return(0);
1050: }

1054: PetscErrorCode PCGAMGSetData_Classical(PC pc, Mat A)
1055: {
1056:   PC_MG          *mg      = (PC_MG*)pc->data;
1057:   PC_GAMG        *pc_gamg = (PC_GAMG*)mg->innerctx;

1060:   /* no data for classical AMG */
1061:   pc_gamg->data = NULL;
1062:   pc_gamg->data_cell_cols = 0;
1063:   pc_gamg->data_cell_rows = 0;
1064:   pc_gamg->data_sz        = 0;
1065:   return(0);
1066: }


1071: PetscErrorCode PCGAMGClassicalFinalizePackage(void)
1072: {

1076:   PCGAMGClassicalPackageInitialized = PETSC_FALSE;
1077:   PetscFunctionListDestroy(&PCGAMGClassicalProlongatorList);
1078:   return(0);
1079: }

1083: PetscErrorCode PCGAMGClassicalInitializePackage(void)
1084: {

1088:   if (PCGAMGClassicalPackageInitialized) return(0);
1089:   PetscFunctionListAdd(&PCGAMGClassicalProlongatorList,PCGAMGCLASSICALDIRECT,PCGAMGProlongator_Classical_Direct);
1090:   PetscFunctionListAdd(&PCGAMGClassicalProlongatorList,PCGAMGCLASSICALSTANDARD,PCGAMGProlongator_Classical_Standard);
1091:   PetscRegisterFinalize(PCGAMGClassicalFinalizePackage);
1092:   return(0);
1093: }

1095: /* -------------------------------------------------------------------------- */
1096: /*
1097:    PCCreateGAMG_Classical

1099: */
1102: PetscErrorCode  PCCreateGAMG_Classical(PC pc)
1103: {
1105:   PC_MG             *mg      = (PC_MG*)pc->data;
1106:   PC_GAMG           *pc_gamg = (PC_GAMG*)mg->innerctx;
1107:   PC_GAMG_Classical *pc_gamg_classical;

1110:   PCGAMGClassicalInitializePackage();
1111:   if (pc_gamg->subctx) {
1112:     /* call base class */
1113:     PCDestroy_GAMG(pc);
1114:   }

1116:   /* create sub context for SA */
1117:   PetscNewLog(pc,&pc_gamg_classical);
1118:   pc_gamg->subctx = pc_gamg_classical;
1119:   pc->ops->setfromoptions = PCGAMGSetFromOptions_Classical;
1120:   /* reset does not do anything; setup not virtual */

1122:   /* set internal function pointers */
1123:   pc_gamg->ops->destroy        = PCGAMGDestroy_Classical;
1124:   pc_gamg->ops->graph          = PCGAMGGraph_Classical;
1125:   pc_gamg->ops->coarsen        = PCGAMGCoarsen_Classical;
1126:   pc_gamg->ops->prolongator    = PCGAMGProlongator_Classical;
1127:   pc_gamg->ops->optprol        = PCGAMGOptProl_Classical_Jacobi;
1128:   pc_gamg->ops->setfromoptions = PCGAMGSetFromOptions_Classical;

1130:   pc_gamg->ops->createdefaultdata = PCGAMGSetData_Classical;
1131:   pc_gamg_classical->interp_threshold = 0.2;
1132:   pc_gamg_classical->nsmooths         = 0;
1133:   PetscObjectComposeFunction((PetscObject)pc,"PCGAMGClassicalSetType_C",PCGAMGClassicalSetType_GAMG);
1134:   PCGAMGClassicalSetType(pc,PCGAMGCLASSICALSTANDARD);
1135:   return(0);
1136: }