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