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