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