xref: /petsc/src/ksp/pc/impls/hypre/hypre.c (revision 0a7e80ddf00b85a8bec408344d0bbd42e7f7dbd2)
1 
2 /*
3    Provides an interface to the LLNL package hypre
4 */
5 
6 /* Must use hypre 2.0.0 or more recent. */
7 
8 #include <petsc-private/pcimpl.h>          /*I "petscpc.h" I*/
9 #include <../src/dm/impls/da/hypre/mhyp.h>
10 
11 /*
12    Private context (data structure) for the  preconditioner.
13 */
14 typedef struct {
15   HYPRE_Solver   hsolver;
16   HYPRE_IJMatrix ij;
17   HYPRE_IJVector b,x;
18 
19   HYPRE_Int (*destroy)(HYPRE_Solver);
20   HYPRE_Int (*solve)(HYPRE_Solver,HYPRE_ParCSRMatrix,HYPRE_ParVector,HYPRE_ParVector);
21   HYPRE_Int (*setup)(HYPRE_Solver,HYPRE_ParCSRMatrix,HYPRE_ParVector,HYPRE_ParVector);
22 
23   MPI_Comm comm_hypre;
24   char     *hypre_type;
25 
26   /* options for Pilut and BoomerAMG*/
27   PetscInt maxiter;
28   double   tol;
29 
30   /* options for Pilut */
31   PetscInt factorrowsize;
32 
33   /* options for ParaSails */
34   PetscInt nlevels;
35   double   threshhold;
36   double   filter;
37   PetscInt sym;
38   double   loadbal;
39   PetscInt logging;
40   PetscInt ruse;
41   PetscInt symt;
42 
43   /* options for Euclid */
44   PetscBool bjilu;
45   PetscInt  levels;
46 
47   /* options for Euclid and BoomerAMG */
48   PetscBool printstatistics;
49 
50   /* options for BoomerAMG */
51   PetscInt  cycletype;
52   PetscInt  maxlevels;
53   double    strongthreshold;
54   double    maxrowsum;
55   PetscInt  gridsweeps[3];
56   PetscInt  coarsentype;
57   PetscInt  measuretype;
58   PetscInt  relaxtype[3];
59   double    relaxweight;
60   double    outerrelaxweight;
61   PetscInt  relaxorder;
62   double    truncfactor;
63   PetscBool applyrichardson;
64   PetscInt  pmax;
65   PetscInt  interptype;
66   PetscInt  agg_nl;
67   PetscInt  agg_num_paths;
68   PetscInt  nodal_coarsen;
69   PetscBool nodal_relax;
70   PetscInt  nodal_relax_levels;
71 } PC_HYPRE;
72 
73 #undef __FUNCT__
74 #define __FUNCT__ "PCHYPREGetSolver"
75 PetscErrorCode PCHYPREGetSolver(PC pc,HYPRE_Solver *hsolver)
76 {
77   PC_HYPRE *jac = (PC_HYPRE*)pc->data;
78 
79   PetscFunctionBegin;
80   *hsolver = jac->hsolver;
81   PetscFunctionReturn(0);
82 }
83 
84 #undef __FUNCT__
85 #define __FUNCT__ "PCSetUp_HYPRE"
86 static PetscErrorCode PCSetUp_HYPRE(PC pc)
87 {
88   PC_HYPRE           *jac = (PC_HYPRE*)pc->data;
89   PetscErrorCode     ierr;
90   HYPRE_ParCSRMatrix hmat;
91   HYPRE_ParVector    bv,xv;
92   PetscInt           bs;
93 
94   PetscFunctionBegin;
95   if (!jac->hypre_type) {
96     ierr = PCHYPRESetType(pc,"boomeramg");CHKERRQ(ierr);
97   }
98 
99   if (pc->setupcalled) {
100     /* always destroy the old matrix and create a new memory;
101        hope this does not churn the memory too much. The problem
102        is I do not know if it is possible to put the matrix back to
103        its initial state so that we can directly copy the values
104        the second time through. */
105     PetscStackCallStandard(HYPRE_IJMatrixDestroy,(jac->ij));
106     jac->ij = 0;
107   }
108 
109   if (!jac->ij) { /* create the matrix the first time through */
110     ierr = MatHYPRE_IJMatrixCreate(pc->pmat,&jac->ij);CHKERRQ(ierr);
111   }
112   if (!jac->b) { /* create the vectors the first time through */
113     Vec x,b;
114     ierr = MatGetVecs(pc->pmat,&x,&b);CHKERRQ(ierr);
115     ierr = VecHYPRE_IJVectorCreate(x,&jac->x);CHKERRQ(ierr);
116     ierr = VecHYPRE_IJVectorCreate(b,&jac->b);CHKERRQ(ierr);
117     ierr = VecDestroy(&x);CHKERRQ(ierr);
118     ierr = VecDestroy(&b);CHKERRQ(ierr);
119   }
120 
121   /* special case for BoomerAMG */
122   if (jac->setup == HYPRE_BoomerAMGSetup) {
123     ierr = MatGetBlockSize(pc->pmat,&bs);CHKERRQ(ierr);
124     if (bs > 1) PetscStackCallStandard(HYPRE_BoomerAMGSetNumFunctions,(jac->hsolver,bs));
125   };
126   ierr = MatHYPRE_IJMatrixCopy(pc->pmat,jac->ij);CHKERRQ(ierr);
127   PetscStackCallStandard(HYPRE_IJMatrixGetObject,(jac->ij,(void**)&hmat));
128   PetscStackCallStandard(HYPRE_IJVectorGetObject,(jac->b,(void**)&bv));
129   PetscStackCallStandard(HYPRE_IJVectorGetObject,(jac->x,(void**)&xv));
130   PetscStackCall("HYPRE_SetupXXX",ierr = (*jac->setup)(jac->hsolver,hmat,bv,xv);CHKERRQ(ierr););
131   PetscFunctionReturn(0);
132 }
133 
134 /*
135     Replaces the address where the HYPRE vector points to its data with the address of
136   PETSc's data. Saves the old address so it can be reset when we are finished with it.
137   Allows use to get the data into a HYPRE vector without the cost of memcopies
138 */
139 #define HYPREReplacePointer(b,newvalue,savedvalue) { \
140     hypre_ParVector *par_vector   = (hypre_ParVector*)hypre_IJVectorObject(((hypre_IJVector*)b)); \
141     hypre_Vector    *local_vector = hypre_ParVectorLocalVector(par_vector); \
142     savedvalue         = local_vector->data; \
143     local_vector->data = newvalue;          \
144 }
145 
146 #undef __FUNCT__
147 #define __FUNCT__ "PCApply_HYPRE"
148 static PetscErrorCode PCApply_HYPRE(PC pc,Vec b,Vec x)
149 {
150   PC_HYPRE           *jac = (PC_HYPRE*)pc->data;
151   PetscErrorCode     ierr;
152   HYPRE_ParCSRMatrix hmat;
153   PetscScalar        *bv,*xv;
154   HYPRE_ParVector    jbv,jxv;
155   PetscScalar        *sbv,*sxv;
156   PetscInt           hierr;
157 
158   PetscFunctionBegin;
159   if (!jac->applyrichardson) {ierr = VecSet(x,0.0);CHKERRQ(ierr);}
160   ierr = VecGetArray(b,&bv);CHKERRQ(ierr);
161   ierr = VecGetArray(x,&xv);CHKERRQ(ierr);
162   HYPREReplacePointer(jac->b,bv,sbv);
163   HYPREReplacePointer(jac->x,xv,sxv);
164 
165   PetscStackCallStandard(HYPRE_IJMatrixGetObject,(jac->ij,(void**)&hmat));
166   PetscStackCallStandard(HYPRE_IJVectorGetObject,(jac->b,(void**)&jbv));
167   PetscStackCallStandard(HYPRE_IJVectorGetObject,(jac->x,(void**)&jxv));
168   PetscStackCall("Hypre solve",hierr = (*jac->solve)(jac->hsolver,hmat,jbv,jxv);
169                                if (hierr && hierr != HYPRE_ERROR_CONV) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in HYPRE solver, error code %d",hierr);
170                                if (hierr) hypre__global_error = 0;);
171 
172   HYPREReplacePointer(jac->b,sbv,bv);
173   HYPREReplacePointer(jac->x,sxv,xv);
174   ierr = VecRestoreArray(x,&xv);CHKERRQ(ierr);
175   ierr = VecRestoreArray(b,&bv);CHKERRQ(ierr);
176   PetscFunctionReturn(0);
177 }
178 
179 #undef __FUNCT__
180 #define __FUNCT__ "PCDestroy_HYPRE"
181 static PetscErrorCode PCDestroy_HYPRE(PC pc)
182 {
183   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
184   PetscErrorCode ierr;
185 
186   PetscFunctionBegin;
187   if (jac->ij) PetscStackCallStandard(HYPRE_IJMatrixDestroy,(jac->ij));
188   if (jac->b) PetscStackCallStandard(HYPRE_IJVectorDestroy,(jac->b));
189   if (jac->x) PetscStackCallStandard(HYPRE_IJVectorDestroy,(jac->x));
190   if (jac->destroy) PetscStackCall("HYPRE_DistroyXXX",ierr = (*jac->destroy)(jac->hsolver);CHKERRQ(ierr););
191   ierr = PetscFree(jac->hypre_type);CHKERRQ(ierr);
192   if (jac->comm_hypre != MPI_COMM_NULL) { ierr = MPI_Comm_free(&(jac->comm_hypre));CHKERRQ(ierr);}
193   ierr = PetscFree(pc->data);CHKERRQ(ierr);
194 
195   ierr = PetscObjectChangeTypeName((PetscObject)pc,0);CHKERRQ(ierr);
196   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetType_C",NULL);CHKERRQ(ierr);
197   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCHYPREGetType_C",NULL);CHKERRQ(ierr);
198   PetscFunctionReturn(0);
199 }
200 
201 /* --------------------------------------------------------------------------------------------*/
202 #undef __FUNCT__
203 #define __FUNCT__ "PCSetFromOptions_HYPRE_Pilut"
204 static PetscErrorCode PCSetFromOptions_HYPRE_Pilut(PC pc)
205 {
206   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
207   PetscErrorCode ierr;
208   PetscBool      flag;
209 
210   PetscFunctionBegin;
211   ierr = PetscOptionsHead("HYPRE Pilut Options");CHKERRQ(ierr);
212   ierr = PetscOptionsInt("-pc_hypre_pilut_maxiter","Number of iterations","None",jac->maxiter,&jac->maxiter,&flag);CHKERRQ(ierr);
213   if (flag) PetscStackCallStandard(HYPRE_ParCSRPilutSetMaxIter,(jac->hsolver,jac->maxiter));
214   ierr = PetscOptionsReal("-pc_hypre_pilut_tol","Drop tolerance","None",jac->tol,&jac->tol,&flag);CHKERRQ(ierr);
215   if (flag) PetscStackCallStandard(HYPRE_ParCSRPilutSetDropTolerance,(jac->hsolver,jac->tol));
216   ierr = PetscOptionsInt("-pc_hypre_pilut_factorrowsize","FactorRowSize","None",jac->factorrowsize,&jac->factorrowsize,&flag);CHKERRQ(ierr);
217   if (flag) PetscStackCallStandard(HYPRE_ParCSRPilutSetFactorRowSize,(jac->hsolver,jac->factorrowsize));
218   ierr = PetscOptionsTail();CHKERRQ(ierr);
219   PetscFunctionReturn(0);
220 }
221 
222 #undef __FUNCT__
223 #define __FUNCT__ "PCView_HYPRE_Pilut"
224 static PetscErrorCode PCView_HYPRE_Pilut(PC pc,PetscViewer viewer)
225 {
226   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
227   PetscErrorCode ierr;
228   PetscBool      iascii;
229 
230   PetscFunctionBegin;
231   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
232   if (iascii) {
233     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE Pilut preconditioning\n");CHKERRQ(ierr);
234     if (jac->maxiter != PETSC_DEFAULT) {
235       ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE Pilut: maximum number of iterations %d\n",jac->maxiter);CHKERRQ(ierr);
236     } else {
237       ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE Pilut: default maximum number of iterations \n");CHKERRQ(ierr);
238     }
239     if (jac->tol != PETSC_DEFAULT) {
240       ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE Pilut: drop tolerance %G\n",jac->tol);CHKERRQ(ierr);
241     } else {
242       ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE Pilut: default drop tolerance \n");CHKERRQ(ierr);
243     }
244     if (jac->factorrowsize != PETSC_DEFAULT) {
245       ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE Pilut: factor row size %d\n",jac->factorrowsize);CHKERRQ(ierr);
246     } else {
247       ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE Pilut: default factor row size \n");CHKERRQ(ierr);
248     }
249   }
250   PetscFunctionReturn(0);
251 }
252 
253 /* --------------------------------------------------------------------------------------------*/
254 #undef __FUNCT__
255 #define __FUNCT__ "PCSetFromOptions_HYPRE_Euclid"
256 static PetscErrorCode PCSetFromOptions_HYPRE_Euclid(PC pc)
257 {
258   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
259   PetscErrorCode ierr;
260   PetscBool      flag;
261   char           *args[8],levels[16];
262   PetscInt       cnt = 0;
263 
264   PetscFunctionBegin;
265   ierr = PetscOptionsHead("HYPRE Euclid Options");CHKERRQ(ierr);
266   ierr = PetscOptionsInt("-pc_hypre_euclid_levels","Number of levels of fill ILU(k)","None",jac->levels,&jac->levels,&flag);CHKERRQ(ierr);
267   if (flag) {
268     if (jac->levels < 0) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Number of levels %d must be nonegative",jac->levels);
269     ierr        = PetscSNPrintf(levels,sizeof(levels),"%D",jac->levels);CHKERRQ(ierr);
270     args[cnt++] = (char*)"-level"; args[cnt++] = levels;
271   }
272   ierr = PetscOptionsBool("-pc_hypre_euclid_bj","Use block Jacobi ILU(k)","None",jac->bjilu,&jac->bjilu,NULL);CHKERRQ(ierr);
273   if (jac->bjilu) {
274     args[cnt++] =(char*) "-bj"; args[cnt++] = (char*)"1";
275   }
276 
277   ierr = PetscOptionsBool("-pc_hypre_euclid_print_statistics","Print statistics","None",jac->printstatistics,&jac->printstatistics,NULL);CHKERRQ(ierr);
278   if (jac->printstatistics) {
279     args[cnt++] = (char*)"-eu_stats"; args[cnt++] = (char*)"1";
280     args[cnt++] = (char*)"-eu_mem"; args[cnt++] = (char*)"1";
281   }
282   ierr = PetscOptionsTail();CHKERRQ(ierr);
283   if (cnt) PetscStackCallStandard(HYPRE_EuclidSetParams,(jac->hsolver,cnt,args));
284   PetscFunctionReturn(0);
285 }
286 
287 #undef __FUNCT__
288 #define __FUNCT__ "PCView_HYPRE_Euclid"
289 static PetscErrorCode PCView_HYPRE_Euclid(PC pc,PetscViewer viewer)
290 {
291   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
292   PetscErrorCode ierr;
293   PetscBool      iascii;
294 
295   PetscFunctionBegin;
296   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
297   if (iascii) {
298     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE Euclid preconditioning\n");CHKERRQ(ierr);
299     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE Euclid: number of levels %d\n",jac->levels);CHKERRQ(ierr);
300     if (jac->bjilu) {
301       ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE Euclid: Using block Jacobi ILU instead of parallel ILU\n");CHKERRQ(ierr);
302     }
303   }
304   PetscFunctionReturn(0);
305 }
306 
307 /* --------------------------------------------------------------------------------------------*/
308 
309 #undef __FUNCT__
310 #define __FUNCT__ "PCApplyTranspose_HYPRE_BoomerAMG"
311 static PetscErrorCode PCApplyTranspose_HYPRE_BoomerAMG(PC pc,Vec b,Vec x)
312 {
313   PC_HYPRE           *jac = (PC_HYPRE*)pc->data;
314   PetscErrorCode     ierr;
315   HYPRE_ParCSRMatrix hmat;
316   PetscScalar        *bv,*xv;
317   HYPRE_ParVector    jbv,jxv;
318   PetscScalar        *sbv,*sxv;
319   PetscInt           hierr;
320 
321   PetscFunctionBegin;
322   ierr = VecSet(x,0.0);CHKERRQ(ierr);
323   ierr = VecGetArray(b,&bv);CHKERRQ(ierr);
324   ierr = VecGetArray(x,&xv);CHKERRQ(ierr);
325   HYPREReplacePointer(jac->b,bv,sbv);
326   HYPREReplacePointer(jac->x,xv,sxv);
327 
328   PetscStackCallStandard(HYPRE_IJMatrixGetObject,(jac->ij,(void**)&hmat));
329   PetscStackCallStandard(HYPRE_IJVectorGetObject,(jac->b,(void**)&jbv));
330   PetscStackCallStandard(HYPRE_IJVectorGetObject,(jac->x,(void**)&jxv));
331 
332   hierr = HYPRE_BoomerAMGSolveT(jac->hsolver,hmat,jbv,jxv);
333   /* error code of 1 in BoomerAMG merely means convergence not achieved */
334   if (hierr && (hierr != 1)) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in HYPRE solver, error code %d",hierr);
335   if (hierr) hypre__global_error = 0;
336 
337   HYPREReplacePointer(jac->b,sbv,bv);
338   HYPREReplacePointer(jac->x,sxv,xv);
339   ierr = VecRestoreArray(x,&xv);CHKERRQ(ierr);
340   ierr = VecRestoreArray(b,&bv);CHKERRQ(ierr);
341   PetscFunctionReturn(0);
342 }
343 
344 /* static array length */
345 #define ALEN(a) (sizeof(a)/sizeof((a)[0]))
346 
347 static const char *HYPREBoomerAMGCycleType[]   = {"","V","W"};
348 static const char *HYPREBoomerAMGCoarsenType[] = {"CLJP","Ruge-Stueben","","modifiedRuge-Stueben","","","Falgout", "", "PMIS", "", "HMIS"};
349 static const char *HYPREBoomerAMGMeasureType[] = {"local","global"};
350 /* The following corresponds to HYPRE_BoomerAMGSetRelaxType which has many missing numbers in the enum */
351 static const char *HYPREBoomerAMGRelaxType[]   = {"Jacobi","sequential-Gauss-Seidel","seqboundary-Gauss-Seidel","SOR/Jacobi","backward-SOR/Jacobi",
352                                                   "" /* [5] hybrid chaotic Gauss-Seidel (works only with OpenMP) */,"symmetric-SOR/Jacobi",
353                                                   "" /* 7 */,"l1scaled-SOR/Jacobi","Gaussian-elimination",
354                                                   "" /* 10 */, "" /* 11 */, "" /* 12 */, "" /* 13 */, "" /* 14 */,
355                                                   "CG" /* non-stationary */,"Chebyshev","FCF-Jacobi","l1scaled-Jacobi"};
356 static const char *HYPREBoomerAMGInterpType[]  = {"classical", "", "", "direct", "multipass", "multipass-wts", "ext+i",
357                                                   "ext+i-cc", "standard", "standard-wts", "", "", "FF", "FF1"};
358 #undef __FUNCT__
359 #define __FUNCT__ "PCSetFromOptions_HYPRE_BoomerAMG"
360 static PetscErrorCode PCSetFromOptions_HYPRE_BoomerAMG(PC pc)
361 {
362   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
363   PetscErrorCode ierr;
364   PetscInt       n,indx,level;
365   PetscBool      flg, tmp_truth;
366   double         tmpdbl, twodbl[2];
367 
368   PetscFunctionBegin;
369   ierr = PetscOptionsHead("HYPRE BoomerAMG Options");CHKERRQ(ierr);
370   ierr = PetscOptionsEList("-pc_hypre_boomeramg_cycle_type","Cycle type","None",HYPREBoomerAMGCycleType+1,2,HYPREBoomerAMGCycleType[jac->cycletype],&indx,&flg);CHKERRQ(ierr);
371   if (flg) {
372     jac->cycletype = indx+1;
373     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleType,(jac->hsolver,jac->cycletype));
374   }
375   ierr = PetscOptionsInt("-pc_hypre_boomeramg_max_levels","Number of levels (of grids) allowed","None",jac->maxlevels,&jac->maxlevels,&flg);CHKERRQ(ierr);
376   if (flg) {
377     if (jac->maxlevels < 2) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Number of levels %d must be at least two",jac->maxlevels);
378     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxLevels,(jac->hsolver,jac->maxlevels));
379   }
380   ierr = PetscOptionsInt("-pc_hypre_boomeramg_max_iter","Maximum iterations used PER hypre call","None",jac->maxiter,&jac->maxiter,&flg);CHKERRQ(ierr);
381   if (flg) {
382     if (jac->maxiter < 1) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Number of iterations %d must be at least one",jac->maxiter);
383     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxIter,(jac->hsolver,jac->maxiter));
384   }
385   ierr = PetscOptionsScalar("-pc_hypre_boomeramg_tol","Convergence tolerance PER hypre call (0.0 = use a fixed number of iterations)","None",jac->tol,&jac->tol,&flg);CHKERRQ(ierr);
386   if (flg) {
387     if (jac->tol < 0.0) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Tolerance %G must be greater than or equal to zero",jac->tol);
388     PetscStackCallStandard(HYPRE_BoomerAMGSetTol,(jac->hsolver,jac->tol));
389   }
390 
391   ierr = PetscOptionsScalar("-pc_hypre_boomeramg_truncfactor","Truncation factor for interpolation (0=no truncation)","None",jac->truncfactor,&jac->truncfactor,&flg);CHKERRQ(ierr);
392   if (flg) {
393     if (jac->truncfactor < 0.0) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Truncation factor %G must be great than or equal zero",jac->truncfactor);
394     PetscStackCallStandard(HYPRE_BoomerAMGSetTruncFactor,(jac->hsolver,jac->truncfactor));
395   }
396 
397   ierr = PetscOptionsInt("-pc_hypre_boomeramg_P_max","Max elements per row for interpolation operator (0=unlimited)","None",jac->pmax,&jac->pmax,&flg);CHKERRQ(ierr);
398   if (flg) {
399     if (jac->pmax < 0) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"P_max %G must be greater than or equal to zero",jac->pmax);
400     PetscStackCallStandard(HYPRE_BoomerAMGSetPMaxElmts,(jac->hsolver,jac->pmax));
401   }
402 
403   ierr = PetscOptionsInt("-pc_hypre_boomeramg_agg_nl","Number of levels of aggressive coarsening","None",jac->agg_nl,&jac->agg_nl,&flg);CHKERRQ(ierr);
404   if (flg) {
405     if (jac->agg_nl < 0) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Number of levels %G must be greater than or equal to zero",jac->agg_nl);
406 
407     PetscStackCallStandard(HYPRE_BoomerAMGSetAggNumLevels,(jac->hsolver,jac->agg_nl));
408   }
409 
410 
411   ierr = PetscOptionsInt("-pc_hypre_boomeramg_agg_num_paths","Number of paths for aggressive coarsening","None",jac->agg_num_paths,&jac->agg_num_paths,&flg);CHKERRQ(ierr);
412   if (flg) {
413     if (jac->agg_num_paths < 1) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Number of paths %G must be greater than or equal to 1",jac->agg_num_paths);
414 
415     PetscStackCallStandard(HYPRE_BoomerAMGSetNumPaths,(jac->hsolver,jac->agg_num_paths));
416   }
417 
418 
419   ierr = PetscOptionsScalar("-pc_hypre_boomeramg_strong_threshold","Threshold for being strongly connected","None",jac->strongthreshold,&jac->strongthreshold,&flg);CHKERRQ(ierr);
420   if (flg) {
421     if (jac->strongthreshold < 0.0) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Strong threshold %G must be great than or equal zero",jac->strongthreshold);
422     PetscStackCallStandard(HYPRE_BoomerAMGSetStrongThreshold,(jac->hsolver,jac->strongthreshold));
423   }
424   ierr = PetscOptionsScalar("-pc_hypre_boomeramg_max_row_sum","Maximum row sum","None",jac->maxrowsum,&jac->maxrowsum,&flg);CHKERRQ(ierr);
425   if (flg) {
426     if (jac->maxrowsum < 0.0) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Maximum row sum %G must be greater than zero",jac->maxrowsum);
427     if (jac->maxrowsum > 1.0) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Maximum row sum %G must be less than or equal one",jac->maxrowsum);
428     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxRowSum,(jac->hsolver,jac->maxrowsum));
429   }
430 
431   /* Grid sweeps */
432   ierr = PetscOptionsInt("-pc_hypre_boomeramg_grid_sweeps_all","Number of sweeps for the up and down grid levels","None",jac->gridsweeps[0],&indx,&flg);CHKERRQ(ierr);
433   if (flg) {
434     PetscStackCallStandard(HYPRE_BoomerAMGSetNumSweeps,(jac->hsolver,indx));
435     /* modify the jac structure so we can view the updated options with PC_View */
436     jac->gridsweeps[0] = indx;
437     jac->gridsweeps[1] = indx;
438     /*defaults coarse to 1 */
439     jac->gridsweeps[2] = 1;
440   }
441 
442   ierr = PetscOptionsInt("-pc_hypre_boomeramg_grid_sweeps_down","Number of sweeps for the down cycles","None",jac->gridsweeps[0], &indx,&flg);CHKERRQ(ierr);
443   if (flg) {
444     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleNumSweeps,(jac->hsolver,indx, 1));
445     jac->gridsweeps[0] = indx;
446   }
447   ierr = PetscOptionsInt("-pc_hypre_boomeramg_grid_sweeps_up","Number of sweeps for the up cycles","None",jac->gridsweeps[1],&indx,&flg);CHKERRQ(ierr);
448   if (flg) {
449     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleNumSweeps,(jac->hsolver,indx, 2));
450     jac->gridsweeps[1] = indx;
451   }
452   ierr = PetscOptionsInt("-pc_hypre_boomeramg_grid_sweeps_coarse","Number of sweeps for the coarse level","None",jac->gridsweeps[2],&indx,&flg);CHKERRQ(ierr);
453   if (flg) {
454     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleNumSweeps,(jac->hsolver,indx, 3));
455     jac->gridsweeps[2] = indx;
456   }
457 
458   /* Relax type */
459   ierr = PetscOptionsEList("-pc_hypre_boomeramg_relax_type_all","Relax type for the up and down cycles","None",HYPREBoomerAMGRelaxType,ALEN(HYPREBoomerAMGRelaxType),HYPREBoomerAMGRelaxType[6],&indx,&flg);CHKERRQ(ierr);
460   if (flg) {
461     jac->relaxtype[0] = jac->relaxtype[1]  = indx;
462     PetscStackCallStandard(HYPRE_BoomerAMGSetRelaxType,(jac->hsolver, indx));
463     /* by default, coarse type set to 9 */
464     jac->relaxtype[2] = 9;
465 
466   }
467   ierr = PetscOptionsEList("-pc_hypre_boomeramg_relax_type_down","Relax type for the down cycles","None",HYPREBoomerAMGRelaxType,ALEN(HYPREBoomerAMGRelaxType),HYPREBoomerAMGRelaxType[6],&indx,&flg);CHKERRQ(ierr);
468   if (flg) {
469     jac->relaxtype[0] = indx;
470     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleRelaxType,(jac->hsolver, indx, 1));
471   }
472   ierr = PetscOptionsEList("-pc_hypre_boomeramg_relax_type_up","Relax type for the up cycles","None",HYPREBoomerAMGRelaxType,ALEN(HYPREBoomerAMGRelaxType),HYPREBoomerAMGRelaxType[6],&indx,&flg);CHKERRQ(ierr);
473   if (flg) {
474     jac->relaxtype[1] = indx;
475     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleRelaxType,(jac->hsolver, indx, 2));
476   }
477   ierr = PetscOptionsEList("-pc_hypre_boomeramg_relax_type_coarse","Relax type on coarse grid","None",HYPREBoomerAMGRelaxType,ALEN(HYPREBoomerAMGRelaxType),HYPREBoomerAMGRelaxType[9],&indx,&flg);CHKERRQ(ierr);
478   if (flg) {
479     jac->relaxtype[2] = indx;
480     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleRelaxType,(jac->hsolver, indx, 3));
481   }
482 
483   /* Relaxation Weight */
484   ierr = PetscOptionsReal("-pc_hypre_boomeramg_relax_weight_all","Relaxation weight for all levels (0 = hypre estimates, -k = determined with k CG steps)","None",jac->relaxweight, &tmpdbl,&flg);CHKERRQ(ierr);
485   if (flg) {
486     PetscStackCallStandard(HYPRE_BoomerAMGSetRelaxWt,(jac->hsolver,tmpdbl));
487     jac->relaxweight = tmpdbl;
488   }
489 
490   n         = 2;
491   twodbl[0] = twodbl[1] = 1.0;
492   ierr      = PetscOptionsRealArray("-pc_hypre_boomeramg_relax_weight_level","Set the relaxation weight for a particular level (weight,level)","None",twodbl, &n, &flg);CHKERRQ(ierr);
493   if (flg) {
494     if (n == 2) {
495       indx =  (int)PetscAbsReal(twodbl[1]);
496       PetscStackCallStandard(HYPRE_BoomerAMGSetLevelRelaxWt,(jac->hsolver,twodbl[0],indx));
497     } else SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Relax weight level: you must provide 2 values separated by a comma (and no space), you provided %d",n);
498   }
499 
500   /* Outer relaxation Weight */
501   ierr = PetscOptionsReal("-pc_hypre_boomeramg_outer_relax_weight_all","Outer relaxation weight for all levels (-k = determined with k CG steps)","None",jac->outerrelaxweight, &tmpdbl,&flg);CHKERRQ(ierr);
502   if (flg) {
503     PetscStackCallStandard(HYPRE_BoomerAMGSetOuterWt,(jac->hsolver, tmpdbl));
504     jac->outerrelaxweight = tmpdbl;
505   }
506 
507   n         = 2;
508   twodbl[0] = twodbl[1] = 1.0;
509   ierr      = PetscOptionsRealArray("-pc_hypre_boomeramg_outer_relax_weight_level","Set the outer relaxation weight for a particular level (weight,level)","None",twodbl, &n, &flg);CHKERRQ(ierr);
510   if (flg) {
511     if (n == 2) {
512       indx =  (int)PetscAbsReal(twodbl[1]);
513       PetscStackCallStandard(HYPRE_BoomerAMGSetLevelOuterWt,(jac->hsolver, twodbl[0], indx));
514     } else SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Relax weight outer level: You must provide 2 values separated by a comma (and no space), you provided %d",n);
515   }
516 
517   /* the Relax Order */
518   ierr = PetscOptionsBool("-pc_hypre_boomeramg_no_CF", "Do not use CF-relaxation", "None", PETSC_FALSE, &tmp_truth, &flg);CHKERRQ(ierr);
519 
520   if (flg) {
521     jac->relaxorder = 0;
522     PetscStackCallStandard(HYPRE_BoomerAMGSetRelaxOrder,(jac->hsolver, jac->relaxorder));
523   }
524   ierr = PetscOptionsEList("-pc_hypre_boomeramg_measure_type","Measure type","None",HYPREBoomerAMGMeasureType,ALEN(HYPREBoomerAMGMeasureType),HYPREBoomerAMGMeasureType[0],&indx,&flg);CHKERRQ(ierr);
525   if (flg) {
526     jac->measuretype = indx;
527     PetscStackCallStandard(HYPRE_BoomerAMGSetMeasureType,(jac->hsolver,jac->measuretype));
528   }
529   /* update list length 3/07 */
530   ierr = PetscOptionsEList("-pc_hypre_boomeramg_coarsen_type","Coarsen type","None",HYPREBoomerAMGCoarsenType,ALEN(HYPREBoomerAMGCoarsenType),HYPREBoomerAMGCoarsenType[6],&indx,&flg);CHKERRQ(ierr);
531   if (flg) {
532     jac->coarsentype = indx;
533     PetscStackCallStandard(HYPRE_BoomerAMGSetCoarsenType,(jac->hsolver,jac->coarsentype));
534   }
535 
536   /* new 3/07 */
537   ierr = PetscOptionsEList("-pc_hypre_boomeramg_interp_type","Interpolation type","None",HYPREBoomerAMGInterpType,ALEN(HYPREBoomerAMGInterpType),HYPREBoomerAMGInterpType[0],&indx,&flg);CHKERRQ(ierr);
538   if (flg) {
539     jac->interptype = indx;
540     PetscStackCallStandard(HYPRE_BoomerAMGSetInterpType,(jac->hsolver,jac->interptype));
541   }
542 
543   ierr = PetscOptionsName("-pc_hypre_boomeramg_print_statistics","Print statistics","None",&flg);CHKERRQ(ierr);
544   if (flg) {
545     level = 3;
546     ierr = PetscOptionsInt("-pc_hypre_boomeramg_print_statistics","Print statistics","None",level,&level,NULL);CHKERRQ(ierr);
547 
548     jac->printstatistics = PETSC_TRUE;
549     PetscStackCallStandard(HYPRE_BoomerAMGSetPrintLevel,(jac->hsolver,level));
550   }
551 
552   ierr = PetscOptionsName("-pc_hypre_boomeramg_print_debug","Print debug information","None",&flg);CHKERRQ(ierr);
553   if (flg) {
554     level = 3;
555     ierr = PetscOptionsInt("-pc_hypre_boomeramg_print_debug","Print debug information","None",level,&level,NULL);CHKERRQ(ierr);
556 
557     jac->printstatistics = PETSC_TRUE;
558     PetscStackCallStandard(HYPRE_BoomerAMGSetDebugFlag,(jac->hsolver,level));
559   }
560 
561   ierr = PetscOptionsBool("-pc_hypre_boomeramg_nodal_coarsen", "HYPRE_BoomerAMGSetNodal()", "None", PETSC_FALSE, &tmp_truth, &flg);CHKERRQ(ierr);
562   if (flg && tmp_truth) {
563     jac->nodal_coarsen = 1;
564     PetscStackCallStandard(HYPRE_BoomerAMGSetNodal,(jac->hsolver,1));
565   }
566 
567   ierr = PetscOptionsBool("-pc_hypre_boomeramg_nodal_relaxation", "Nodal relaxation via Schwarz", "None", PETSC_FALSE, &tmp_truth, &flg);CHKERRQ(ierr);
568   if (flg && tmp_truth) {
569     PetscInt tmp_int;
570     ierr = PetscOptionsInt("-pc_hypre_boomeramg_nodal_relaxation", "Nodal relaxation via Schwarz", "None",jac->nodal_relax_levels,&tmp_int,&flg);CHKERRQ(ierr);
571     if (flg) jac->nodal_relax_levels = tmp_int;
572     PetscStackCallStandard(HYPRE_BoomerAMGSetSmoothType,(jac->hsolver,6));
573     PetscStackCallStandard(HYPRE_BoomerAMGSetDomainType,(jac->hsolver,1));
574     PetscStackCallStandard(HYPRE_BoomerAMGSetOverlap,(jac->hsolver,0));
575     PetscStackCallStandard(HYPRE_BoomerAMGSetSmoothNumLevels,(jac->hsolver,jac->nodal_relax_levels));
576   }
577 
578   ierr = PetscOptionsTail();CHKERRQ(ierr);
579   PetscFunctionReturn(0);
580 }
581 
582 #undef __FUNCT__
583 #define __FUNCT__ "PCApplyRichardson_HYPRE_BoomerAMG"
584 static PetscErrorCode PCApplyRichardson_HYPRE_BoomerAMG(PC pc,Vec b,Vec y,Vec w,PetscReal rtol,PetscReal abstol, PetscReal dtol,PetscInt its,PetscBool guesszero,PetscInt *outits,PCRichardsonConvergedReason *reason)
585 {
586   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
587   PetscErrorCode ierr;
588   PetscInt       oits;
589 
590   PetscFunctionBegin;
591   PetscStackCallStandard(HYPRE_BoomerAMGSetMaxIter,(jac->hsolver,its*jac->maxiter));
592   PetscStackCallStandard(HYPRE_BoomerAMGSetTol,(jac->hsolver,rtol));
593   jac->applyrichardson = PETSC_TRUE;
594   ierr                 = PCApply_HYPRE(pc,b,y);CHKERRQ(ierr);
595   jac->applyrichardson = PETSC_FALSE;
596   PetscStackCallStandard(HYPRE_BoomerAMGGetNumIterations,(jac->hsolver,&oits));
597   *outits = oits;
598   if (oits == its) *reason = PCRICHARDSON_CONVERGED_ITS;
599   else             *reason = PCRICHARDSON_CONVERGED_RTOL;
600   PetscStackCallStandard(HYPRE_BoomerAMGSetTol,(jac->hsolver,jac->tol));
601   PetscStackCallStandard(HYPRE_BoomerAMGSetMaxIter,(jac->hsolver,jac->maxiter));
602   PetscFunctionReturn(0);
603 }
604 
605 
606 #undef __FUNCT__
607 #define __FUNCT__ "PCView_HYPRE_BoomerAMG"
608 static PetscErrorCode PCView_HYPRE_BoomerAMG(PC pc,PetscViewer viewer)
609 {
610   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
611   PetscErrorCode ierr;
612   PetscBool      iascii;
613 
614   PetscFunctionBegin;
615   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
616   if (iascii) {
617     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG preconditioning\n");CHKERRQ(ierr);
618     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Cycle type %s\n",HYPREBoomerAMGCycleType[jac->cycletype]);CHKERRQ(ierr);
619     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Maximum number of levels %d\n",jac->maxlevels);CHKERRQ(ierr);
620     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Maximum number of iterations PER hypre call %d\n",jac->maxiter);CHKERRQ(ierr);
621     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Convergence tolerance PER hypre call %G\n",jac->tol);CHKERRQ(ierr);
622     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Threshold for strong coupling %G\n",jac->strongthreshold);CHKERRQ(ierr);
623     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Interpolation truncation factor %G\n",jac->truncfactor);CHKERRQ(ierr);
624     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Interpolation: max elements per row %d\n",jac->pmax);CHKERRQ(ierr);
625     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Number of levels of aggressive coarsening %d\n",jac->agg_nl);CHKERRQ(ierr);
626     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Number of paths for aggressive coarsening %d\n",jac->agg_num_paths);CHKERRQ(ierr);
627 
628     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Maximum row sums %G\n",jac->maxrowsum);CHKERRQ(ierr);
629 
630     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Sweeps down         %d\n",jac->gridsweeps[0]);CHKERRQ(ierr);
631     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Sweeps up           %d\n",jac->gridsweeps[1]);CHKERRQ(ierr);
632     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Sweeps on coarse    %d\n",jac->gridsweeps[2]);CHKERRQ(ierr);
633 
634     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Relax down          %s\n",HYPREBoomerAMGRelaxType[jac->relaxtype[0]]);CHKERRQ(ierr);
635     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Relax up            %s\n",HYPREBoomerAMGRelaxType[jac->relaxtype[1]]);CHKERRQ(ierr);
636     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Relax on coarse     %s\n",HYPREBoomerAMGRelaxType[jac->relaxtype[2]]);CHKERRQ(ierr);
637 
638     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Relax weight  (all)      %G\n",jac->relaxweight);CHKERRQ(ierr);
639     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Outer relax weight (all) %G\n",jac->outerrelaxweight);CHKERRQ(ierr);
640 
641     if (jac->relaxorder) {
642       ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Using CF-relaxation\n");CHKERRQ(ierr);
643     } else {
644       ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Not using CF-relaxation\n");CHKERRQ(ierr);
645     }
646     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Measure type        %s\n",HYPREBoomerAMGMeasureType[jac->measuretype]);CHKERRQ(ierr);
647     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Coarsen type        %s\n",HYPREBoomerAMGCoarsenType[jac->coarsentype]);CHKERRQ(ierr);
648     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG: Interpolation type  %s\n",HYPREBoomerAMGInterpType[jac->interptype]);CHKERRQ(ierr);
649     if (jac->nodal_coarsen) {
650       ierr = PetscViewerASCIIPrintf(viewer," HYPRE BoomerAMG: Using nodal coarsening (with HYPRE_BOOMERAMGSetNodal())\n");CHKERRQ(ierr);
651     }
652     if (jac->nodal_relax) {
653       ierr = PetscViewerASCIIPrintf(viewer," HYPRE BoomerAMG: Using nodal relaxation via Schwarz smoothing on levels %d\n",jac->nodal_relax_levels);CHKERRQ(ierr);
654     }
655   }
656   PetscFunctionReturn(0);
657 }
658 
659 /* --------------------------------------------------------------------------------------------*/
660 #undef __FUNCT__
661 #define __FUNCT__ "PCSetFromOptions_HYPRE_ParaSails"
662 static PetscErrorCode PCSetFromOptions_HYPRE_ParaSails(PC pc)
663 {
664   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
665   PetscErrorCode ierr;
666   PetscInt       indx;
667   PetscBool      flag;
668   const char     *symtlist[] = {"nonsymmetric","SPD","nonsymmetric,SPD"};
669 
670   PetscFunctionBegin;
671   ierr = PetscOptionsHead("HYPRE ParaSails Options");CHKERRQ(ierr);
672   ierr = PetscOptionsInt("-pc_hypre_parasails_nlevels","Number of number of levels","None",jac->nlevels,&jac->nlevels,0);CHKERRQ(ierr);
673   ierr = PetscOptionsReal("-pc_hypre_parasails_thresh","Threshold","None",jac->threshhold,&jac->threshhold,&flag);CHKERRQ(ierr);
674   if (flag) PetscStackCallStandard(HYPRE_ParaSailsSetParams,(jac->hsolver,jac->threshhold,jac->nlevels));
675 
676   ierr = PetscOptionsReal("-pc_hypre_parasails_filter","filter","None",jac->filter,&jac->filter,&flag);CHKERRQ(ierr);
677   if (flag) PetscStackCallStandard(HYPRE_ParaSailsSetFilter,(jac->hsolver,jac->filter));
678 
679   ierr = PetscOptionsReal("-pc_hypre_parasails_loadbal","Load balance","None",jac->loadbal,&jac->loadbal,&flag);CHKERRQ(ierr);
680   if (flag) PetscStackCallStandard(HYPRE_ParaSailsSetLoadbal,(jac->hsolver,jac->loadbal));
681 
682   ierr = PetscOptionsBool("-pc_hypre_parasails_logging","Print info to screen","None",(PetscBool)jac->logging,(PetscBool*)&jac->logging,&flag);CHKERRQ(ierr);
683   if (flag) PetscStackCallStandard(HYPRE_ParaSailsSetLogging,(jac->hsolver,jac->logging));
684 
685   ierr = PetscOptionsBool("-pc_hypre_parasails_reuse","Reuse nonzero pattern in preconditioner","None",(PetscBool)jac->ruse,(PetscBool*)&jac->ruse,&flag);CHKERRQ(ierr);
686   if (flag) PetscStackCallStandard(HYPRE_ParaSailsSetReuse,(jac->hsolver,jac->ruse));
687 
688   ierr = PetscOptionsEList("-pc_hypre_parasails_sym","Symmetry of matrix and preconditioner","None",symtlist,ALEN(symtlist),symtlist[0],&indx,&flag);CHKERRQ(ierr);
689   if (flag) {
690     jac->symt = indx;
691     PetscStackCallStandard(HYPRE_ParaSailsSetSym,(jac->hsolver,jac->symt));
692   }
693 
694   ierr = PetscOptionsTail();CHKERRQ(ierr);
695   PetscFunctionReturn(0);
696 }
697 
698 #undef __FUNCT__
699 #define __FUNCT__ "PCView_HYPRE_ParaSails"
700 static PetscErrorCode PCView_HYPRE_ParaSails(PC pc,PetscViewer viewer)
701 {
702   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
703   PetscErrorCode ierr;
704   PetscBool      iascii;
705   const char     *symt = 0;;
706 
707   PetscFunctionBegin;
708   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
709   if (iascii) {
710     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE ParaSails preconditioning\n");CHKERRQ(ierr);
711     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE ParaSails: nlevels %d\n",jac->nlevels);CHKERRQ(ierr);
712     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE ParaSails: threshold %G\n",jac->threshhold);CHKERRQ(ierr);
713     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE ParaSails: filter %G\n",jac->filter);CHKERRQ(ierr);
714     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE ParaSails: load balance %G\n",jac->loadbal);CHKERRQ(ierr);
715     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE ParaSails: reuse nonzero structure %s\n",PetscBools[jac->ruse]);CHKERRQ(ierr);
716     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE ParaSails: print info to screen %s\n",PetscBools[jac->logging]);CHKERRQ(ierr);
717     if (!jac->symt) symt = "nonsymmetric matrix and preconditioner";
718     else if (jac->symt == 1) symt = "SPD matrix and preconditioner";
719     else if (jac->symt == 2) symt = "nonsymmetric matrix but SPD preconditioner";
720     else SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONG,"Unknown HYPRE ParaSails symmetric option %d",jac->symt);
721     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE ParaSails: %s\n",symt);CHKERRQ(ierr);
722   }
723   PetscFunctionReturn(0);
724 }
725 /* ---------------------------------------------------------------------------------*/
726 
727 #undef __FUNCT__
728 #define __FUNCT__ "PCHYPREGetType_HYPRE"
729 static PetscErrorCode  PCHYPREGetType_HYPRE(PC pc,const char *name[])
730 {
731   PC_HYPRE *jac = (PC_HYPRE*)pc->data;
732 
733   PetscFunctionBegin;
734   *name = jac->hypre_type;
735   PetscFunctionReturn(0);
736 }
737 
738 #undef __FUNCT__
739 #define __FUNCT__ "PCHYPRESetType_HYPRE"
740 static PetscErrorCode  PCHYPRESetType_HYPRE(PC pc,const char name[])
741 {
742   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
743   PetscErrorCode ierr;
744   PetscBool      flag;
745 
746   PetscFunctionBegin;
747   if (jac->hypre_type) {
748     ierr = PetscStrcmp(jac->hypre_type,name,&flag);CHKERRQ(ierr);
749     if (!flag) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Cannot reset the HYPRE preconditioner type once it has been set");
750     PetscFunctionReturn(0);
751   } else {
752     ierr = PetscStrallocpy(name, &jac->hypre_type);CHKERRQ(ierr);
753   }
754 
755   jac->maxiter         = PETSC_DEFAULT;
756   jac->tol             = PETSC_DEFAULT;
757   jac->printstatistics = PetscLogPrintInfo;
758 
759   ierr = PetscStrcmp("pilut",jac->hypre_type,&flag);CHKERRQ(ierr);
760   if (flag) {
761     PetscStackCallStandard(HYPRE_ParCSRPilutCreate,(jac->comm_hypre,&jac->hsolver));
762     pc->ops->setfromoptions = PCSetFromOptions_HYPRE_Pilut;
763     pc->ops->view           = PCView_HYPRE_Pilut;
764     jac->destroy            = HYPRE_ParCSRPilutDestroy;
765     jac->setup              = HYPRE_ParCSRPilutSetup;
766     jac->solve              = HYPRE_ParCSRPilutSolve;
767     jac->factorrowsize      = PETSC_DEFAULT;
768     PetscFunctionReturn(0);
769   }
770   ierr = PetscStrcmp("parasails",jac->hypre_type,&flag);CHKERRQ(ierr);
771   if (flag) {
772     PetscStackCallStandard(HYPRE_ParaSailsCreate,(jac->comm_hypre,&jac->hsolver));
773     pc->ops->setfromoptions = PCSetFromOptions_HYPRE_ParaSails;
774     pc->ops->view           = PCView_HYPRE_ParaSails;
775     jac->destroy            = HYPRE_ParaSailsDestroy;
776     jac->setup              = HYPRE_ParaSailsSetup;
777     jac->solve              = HYPRE_ParaSailsSolve;
778     /* initialize */
779     jac->nlevels    = 1;
780     jac->threshhold = .1;
781     jac->filter     = .1;
782     jac->loadbal    = 0;
783     if (PetscLogPrintInfo) jac->logging = (int) PETSC_TRUE;
784     else jac->logging = (int) PETSC_FALSE;
785 
786     jac->ruse = (int) PETSC_FALSE;
787     jac->symt = 0;
788     PetscStackCallStandard(HYPRE_ParaSailsSetParams,(jac->hsolver,jac->threshhold,jac->nlevels));
789     PetscStackCallStandard(HYPRE_ParaSailsSetFilter,(jac->hsolver,jac->filter));
790     PetscStackCallStandard(HYPRE_ParaSailsSetLoadbal,(jac->hsolver,jac->loadbal));
791     PetscStackCallStandard(HYPRE_ParaSailsSetLogging,(jac->hsolver,jac->logging));
792     PetscStackCallStandard(HYPRE_ParaSailsSetReuse,(jac->hsolver,jac->ruse));
793     PetscStackCallStandard(HYPRE_ParaSailsSetSym,(jac->hsolver,jac->symt));
794     PetscFunctionReturn(0);
795   }
796   ierr = PetscStrcmp("euclid",jac->hypre_type,&flag);CHKERRQ(ierr);
797   if (flag) {
798     ierr                    = HYPRE_EuclidCreate(jac->comm_hypre,&jac->hsolver);
799     pc->ops->setfromoptions = PCSetFromOptions_HYPRE_Euclid;
800     pc->ops->view           = PCView_HYPRE_Euclid;
801     jac->destroy            = HYPRE_EuclidDestroy;
802     jac->setup              = HYPRE_EuclidSetup;
803     jac->solve              = HYPRE_EuclidSolve;
804     /* initialization */
805     jac->bjilu              = PETSC_FALSE;
806     jac->levels             = 1;
807     PetscFunctionReturn(0);
808   }
809   ierr = PetscStrcmp("boomeramg",jac->hypre_type,&flag);CHKERRQ(ierr);
810   if (flag) {
811     ierr                     = HYPRE_BoomerAMGCreate(&jac->hsolver);
812     pc->ops->setfromoptions  = PCSetFromOptions_HYPRE_BoomerAMG;
813     pc->ops->view            = PCView_HYPRE_BoomerAMG;
814     pc->ops->applytranspose  = PCApplyTranspose_HYPRE_BoomerAMG;
815     pc->ops->applyrichardson = PCApplyRichardson_HYPRE_BoomerAMG;
816     jac->destroy             = HYPRE_BoomerAMGDestroy;
817     jac->setup               = HYPRE_BoomerAMGSetup;
818     jac->solve               = HYPRE_BoomerAMGSolve;
819     jac->applyrichardson     = PETSC_FALSE;
820     /* these defaults match the hypre defaults */
821     jac->cycletype        = 1;
822     jac->maxlevels        = 25;
823     jac->maxiter          = 1;
824     jac->tol              = 0.0; /* tolerance of zero indicates use as preconditioner (suppresses convergence errors) */
825     jac->truncfactor      = 0.0;
826     jac->strongthreshold  = .25;
827     jac->maxrowsum        = .9;
828     jac->coarsentype      = 6;
829     jac->measuretype      = 0;
830     jac->gridsweeps[0]    = jac->gridsweeps[1] = jac->gridsweeps[2] = 1;
831     jac->relaxtype[0]     = jac->relaxtype[1] = 6; /* Defaults to SYMMETRIC since in PETSc we are using a a PC - most likely with CG */
832     jac->relaxtype[2]     = 9; /*G.E. */
833     jac->relaxweight      = 1.0;
834     jac->outerrelaxweight = 1.0;
835     jac->relaxorder       = 1;
836     jac->interptype       = 0;
837     jac->agg_nl           = 0;
838     jac->pmax             = 0;
839     jac->truncfactor      = 0.0;
840     jac->agg_num_paths    = 1;
841 
842     jac->nodal_coarsen      = 0;
843     jac->nodal_relax        = PETSC_FALSE;
844     jac->nodal_relax_levels = 1;
845     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleType,(jac->hsolver,jac->cycletype));
846     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxLevels,(jac->hsolver,jac->maxlevels));
847     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxIter,(jac->hsolver,jac->maxiter));
848     PetscStackCallStandard(HYPRE_BoomerAMGSetTol,(jac->hsolver,jac->tol));
849     PetscStackCallStandard(HYPRE_BoomerAMGSetTruncFactor,(jac->hsolver,jac->truncfactor));
850     PetscStackCallStandard(HYPRE_BoomerAMGSetStrongThreshold,(jac->hsolver,jac->strongthreshold));
851     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxRowSum,(jac->hsolver,jac->maxrowsum));
852     PetscStackCallStandard(HYPRE_BoomerAMGSetCoarsenType,(jac->hsolver,jac->coarsentype));
853     PetscStackCallStandard(HYPRE_BoomerAMGSetMeasureType,(jac->hsolver,jac->measuretype));
854     PetscStackCallStandard(HYPRE_BoomerAMGSetRelaxOrder,(jac->hsolver, jac->relaxorder));
855     PetscStackCallStandard(HYPRE_BoomerAMGSetInterpType,(jac->hsolver,jac->interptype));
856     PetscStackCallStandard(HYPRE_BoomerAMGSetAggNumLevels,(jac->hsolver,jac->agg_nl));
857     PetscStackCallStandard(HYPRE_BoomerAMGSetPMaxElmts,(jac->hsolver,jac->pmax));
858     PetscStackCallStandard(HYPRE_BoomerAMGSetNumPaths,(jac->hsolver,jac->agg_num_paths));
859     PetscStackCallStandard(HYPRE_BoomerAMGSetRelaxType,(jac->hsolver, jac->relaxtype[0]));  /*defaults coarse to 9*/
860     PetscStackCallStandard(HYPRE_BoomerAMGSetNumSweeps,(jac->hsolver, jac->gridsweeps[0])); /*defaults coarse to 1 */
861     PetscFunctionReturn(0);
862   }
863   ierr = PetscFree(jac->hypre_type);CHKERRQ(ierr);
864 
865   jac->hypre_type = NULL;
866   SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown HYPRE preconditioner %s; Choices are pilut, parasails, euclid, boomeramg",name);
867   PetscFunctionReturn(0);
868 }
869 
870 /*
871     It only gets here if the HYPRE type has not been set before the call to
872    ...SetFromOptions() which actually is most of the time
873 */
874 #undef __FUNCT__
875 #define __FUNCT__ "PCSetFromOptions_HYPRE"
876 static PetscErrorCode PCSetFromOptions_HYPRE(PC pc)
877 {
878   PetscErrorCode ierr;
879   PetscInt       indx;
880   const char     *type[] = {"pilut","parasails","boomeramg","euclid"};
881   PetscBool      flg;
882 
883   PetscFunctionBegin;
884   ierr = PetscOptionsHead("HYPRE preconditioner options");CHKERRQ(ierr);
885   ierr = PetscOptionsEList("-pc_hypre_type","HYPRE preconditioner type","PCHYPRESetType",type,4,"boomeramg",&indx,&flg);CHKERRQ(ierr);
886   if (flg) {
887     ierr = PCHYPRESetType_HYPRE(pc,type[indx]);CHKERRQ(ierr);
888   } else {
889     ierr = PCHYPRESetType_HYPRE(pc,"boomeramg");CHKERRQ(ierr);
890   }
891   if (pc->ops->setfromoptions) {
892     ierr = pc->ops->setfromoptions(pc);CHKERRQ(ierr);
893   }
894   ierr = PetscOptionsTail();CHKERRQ(ierr);
895   PetscFunctionReturn(0);
896 }
897 
898 #undef __FUNCT__
899 #define __FUNCT__ "PCHYPRESetType"
900 /*@C
901      PCHYPRESetType - Sets which hypre preconditioner you wish to use
902 
903    Input Parameters:
904 +     pc - the preconditioner context
905 -     name - either  pilut, parasails, boomeramg, euclid
906 
907    Options Database Keys:
908    -pc_hypre_type - One of pilut, parasails, boomeramg, euclid
909 
910    Level: intermediate
911 
912 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
913            PCHYPRE
914 
915 @*/
916 PetscErrorCode  PCHYPRESetType(PC pc,const char name[])
917 {
918   PetscErrorCode ierr;
919 
920   PetscFunctionBegin;
921   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
922   PetscValidCharPointer(name,2);
923   ierr = PetscTryMethod(pc,"PCHYPRESetType_C",(PC,const char[]),(pc,name));CHKERRQ(ierr);
924   PetscFunctionReturn(0);
925 }
926 
927 #undef __FUNCT__
928 #define __FUNCT__ "PCHYPREGetType"
929 /*@C
930      PCHYPREGetType - Gets which hypre preconditioner you are using
931 
932    Input Parameter:
933 .     pc - the preconditioner context
934 
935    Output Parameter:
936 .     name - either  pilut, parasails, boomeramg, euclid
937 
938    Level: intermediate
939 
940 .seealso:  PCCreate(), PCHYPRESetType(), PCType (for list of available types), PC,
941            PCHYPRE
942 
943 @*/
944 PetscErrorCode  PCHYPREGetType(PC pc,const char *name[])
945 {
946   PetscErrorCode ierr;
947 
948   PetscFunctionBegin;
949   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
950   PetscValidPointer(name,2);
951   ierr = PetscTryMethod(pc,"PCHYPREGetType_C",(PC,const char*[]),(pc,name));CHKERRQ(ierr);
952   PetscFunctionReturn(0);
953 }
954 
955 /*MC
956      PCHYPRE - Allows you to use the matrix element based preconditioners in the LLNL package hypre
957 
958    Options Database Keys:
959 +   -pc_hypre_type - One of pilut, parasails, boomeramg, euclid
960 -   Too many others to list, run with -pc_type hypre -pc_hypre_type XXX -help to see options for the XXX
961           preconditioner
962 
963    Level: intermediate
964 
965    Notes: Apart from pc_hypre_type (for which there is PCHYPRESetType()),
966           the many hypre options can ONLY be set via the options database (e.g. the command line
967           or with PetscOptionsSetValue(), there are no functions to set them)
968 
969           The options -pc_hypre_boomeramg_max_iter and -pc_hypre_boomeramg_rtol refer to the number of iterations
970           (V-cycles) and tolerance that boomeramg does EACH time it is called. So for example, if
971           -pc_hypre_boomeramg_max_iter is set to 2 then 2-V-cycles are being used to define the preconditioner
972           (-pc_hypre_boomeramg_rtol should be set to 0.0 - the default - to strictly use a fixed number of
973           iterations per hypre call). -ksp_max_it and -ksp_rtol STILL determine the total number of iterations
974           and tolerance for the Krylov solver. For example, if -pc_hypre_boomeramg_max_iter is 2 and -ksp_max_it is 10
975           then AT MOST twenty V-cycles of boomeramg will be called.
976 
977            Note that the option -pc_hypre_boomeramg_relax_type_all defaults to symmetric relaxation
978            (symmetric-SOR/Jacobi), which is required for Krylov solvers like CG that expect symmetry.
979            Otherwise, you may want to use -pc_hypre_boomeramg_relax_type_all SOR/Jacobi.
980           If you wish to use BoomerAMG WITHOUT a Krylov method use -ksp_type richardson NOT -ksp_type preonly
981           and use -ksp_max_it to control the number of V-cycles.
982           (see the PETSc FAQ.html at the PETSc website under the Documentation tab).
983 
984           2007-02-03 Using HYPRE-1.11.1b, the routine HYPRE_BoomerAMGSolveT and the option
985           -pc_hypre_parasails_reuse were failing with SIGSEGV. Dalcin L.
986 
987           See PCPFMG for access to the hypre Struct PFMG solver
988 
989 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
990            PCHYPRESetType(), PCPFMG
991 
992 M*/
993 
994 #undef __FUNCT__
995 #define __FUNCT__ "PCCreate_HYPRE"
996 PETSC_EXTERN PetscErrorCode PCCreate_HYPRE(PC pc)
997 {
998   PC_HYPRE       *jac;
999   PetscErrorCode ierr;
1000 
1001   PetscFunctionBegin;
1002   ierr = PetscNewLog(pc,PC_HYPRE,&jac);CHKERRQ(ierr);
1003 
1004   pc->data                = jac;
1005   pc->ops->destroy        = PCDestroy_HYPRE;
1006   pc->ops->setfromoptions = PCSetFromOptions_HYPRE;
1007   pc->ops->setup          = PCSetUp_HYPRE;
1008   pc->ops->apply          = PCApply_HYPRE;
1009   jac->comm_hypre         = MPI_COMM_NULL;
1010   jac->hypre_type         = NULL;
1011   /* duplicate communicator for hypre */
1012   ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)pc),&(jac->comm_hypre));CHKERRQ(ierr);
1013   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetType_C",PCHYPRESetType_HYPRE);CHKERRQ(ierr);
1014   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCHYPREGetType_C",PCHYPREGetType_HYPRE);CHKERRQ(ierr);
1015   PetscFunctionReturn(0);
1016 }
1017 
1018 /* ---------------------------------------------------------------------------------------------------------------------------------*/
1019 
1020 /* this include is needed ONLY to allow access to the private data inside the Mat object specific to hypre */
1021 #include <petsc-private/matimpl.h>
1022 
1023 typedef struct {
1024   MPI_Comm           hcomm;        /* does not share comm with HYPRE_StructMatrix because need to create solver before getting matrix */
1025   HYPRE_StructSolver hsolver;
1026 
1027   /* keep copy of PFMG options used so may view them */
1028   PetscInt its;
1029   double   tol;
1030   PetscInt relax_type;
1031   PetscInt rap_type;
1032   PetscInt num_pre_relax,num_post_relax;
1033   PetscInt max_levels;
1034 } PC_PFMG;
1035 
1036 #undef __FUNCT__
1037 #define __FUNCT__ "PCDestroy_PFMG"
1038 PetscErrorCode PCDestroy_PFMG(PC pc)
1039 {
1040   PetscErrorCode ierr;
1041   PC_PFMG        *ex = (PC_PFMG*) pc->data;
1042 
1043   PetscFunctionBegin;
1044   if (ex->hsolver) PetscStackCallStandard(HYPRE_StructPFMGDestroy,(ex->hsolver));
1045   ierr = MPI_Comm_free(&ex->hcomm);CHKERRQ(ierr);
1046   ierr = PetscFree(pc->data);CHKERRQ(ierr);
1047   PetscFunctionReturn(0);
1048 }
1049 
1050 static const char *PFMGRelaxType[] = {"Jacobi","Weighted-Jacobi","symmetric-Red/Black-Gauss-Seidel","Red/Black-Gauss-Seidel"};
1051 static const char *PFMGRAPType[] = {"Galerkin","non-Galerkin"};
1052 
1053 #undef __FUNCT__
1054 #define __FUNCT__ "PCView_PFMG"
1055 PetscErrorCode PCView_PFMG(PC pc,PetscViewer viewer)
1056 {
1057   PetscErrorCode ierr;
1058   PetscBool      iascii;
1059   PC_PFMG        *ex = (PC_PFMG*) pc->data;
1060 
1061   PetscFunctionBegin;
1062   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
1063   if (iascii) {
1064     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE PFMG preconditioning\n");CHKERRQ(ierr);
1065     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE PFMG: max iterations %d\n",ex->its);CHKERRQ(ierr);
1066     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE PFMG: tolerance %g\n",ex->tol);CHKERRQ(ierr);
1067     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE PFMG: relax type %s\n",PFMGRelaxType[ex->relax_type]);CHKERRQ(ierr);
1068     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE PFMG: RAP type %s\n",PFMGRAPType[ex->rap_type]);CHKERRQ(ierr);
1069     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE PFMG: number pre-relax %d post-relax %d\n",ex->num_pre_relax,ex->num_post_relax);CHKERRQ(ierr);
1070     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE PFMG: max levels %d\n",ex->max_levels);CHKERRQ(ierr);
1071   }
1072   PetscFunctionReturn(0);
1073 }
1074 
1075 
1076 #undef __FUNCT__
1077 #define __FUNCT__ "PCSetFromOptions_PFMG"
1078 PetscErrorCode PCSetFromOptions_PFMG(PC pc)
1079 {
1080   PetscErrorCode ierr;
1081   PC_PFMG        *ex = (PC_PFMG*) pc->data;
1082   PetscBool      flg = PETSC_FALSE;
1083 
1084   PetscFunctionBegin;
1085   ierr = PetscOptionsHead("PFMG options");CHKERRQ(ierr);
1086   ierr = PetscOptionsBool("-pc_pfmg_print_statistics","Print statistics","HYPRE_StructPFMGSetPrintLevel",flg,&flg,NULL);CHKERRQ(ierr);
1087   if (flg) {
1088     int level=3;
1089     PetscStackCallStandard(HYPRE_StructPFMGSetPrintLevel,(ex->hsolver,level));
1090   }
1091   ierr = PetscOptionsInt("-pc_pfmg_its","Number of iterations of PFMG to use as preconditioner","HYPRE_StructPFMGSetMaxIter",ex->its,&ex->its,NULL);CHKERRQ(ierr);
1092   PetscStackCallStandard(HYPRE_StructPFMGSetMaxIter,(ex->hsolver,ex->its));
1093   ierr = PetscOptionsInt("-pc_pfmg_num_pre_relax","Number of smoothing steps before coarse grid","HYPRE_StructPFMGSetNumPreRelax",ex->num_pre_relax,&ex->num_pre_relax,NULL);CHKERRQ(ierr);
1094   PetscStackCallStandard(HYPRE_StructPFMGSetNumPreRelax,(ex->hsolver,ex->num_pre_relax));
1095   ierr = PetscOptionsInt("-pc_pfmg_num_post_relax","Number of smoothing steps after coarse grid","HYPRE_StructPFMGSetNumPostRelax",ex->num_post_relax,&ex->num_post_relax,NULL);CHKERRQ(ierr);
1096   PetscStackCallStandard(HYPRE_StructPFMGSetNumPostRelax,(ex->hsolver,ex->num_post_relax));
1097 
1098   ierr = PetscOptionsInt("-pc_pfmg_max_levels","Max Levels for MG hierarchy","HYPRE_StructPFMGSetMaxLevels",ex->max_levels,&ex->max_levels,NULL);CHKERRQ(ierr);
1099   PetscStackCallStandard(HYPRE_StructPFMGSetMaxLevels,(ex->hsolver,ex->max_levels));
1100 
1101   ierr = PetscOptionsReal("-pc_pfmg_tol","Tolerance of PFMG","HYPRE_StructPFMGSetTol",ex->tol,&ex->tol,NULL);CHKERRQ(ierr);
1102   PetscStackCallStandard(HYPRE_StructPFMGSetTol,(ex->hsolver,ex->tol));
1103   ierr = PetscOptionsEList("-pc_pfmg_relax_type","Relax type for the up and down cycles","HYPRE_StructPFMGSetRelaxType",PFMGRelaxType,ALEN(PFMGRelaxType),PFMGRelaxType[ex->relax_type],&ex->relax_type,NULL);CHKERRQ(ierr);
1104   PetscStackCallStandard(HYPRE_StructPFMGSetRelaxType,(ex->hsolver, ex->relax_type));
1105   ierr = PetscOptionsEList("-pc_pfmg_rap_type","RAP type","HYPRE_StructPFMGSetRAPType",PFMGRAPType,ALEN(PFMGRAPType),PFMGRAPType[ex->rap_type],&ex->rap_type,NULL);CHKERRQ(ierr);
1106   PetscStackCallStandard(HYPRE_StructPFMGSetRAPType,(ex->hsolver, ex->rap_type));
1107   ierr = PetscOptionsTail();CHKERRQ(ierr);
1108   PetscFunctionReturn(0);
1109 }
1110 
1111 #undef __FUNCT__
1112 #define __FUNCT__ "PCApply_PFMG"
1113 PetscErrorCode PCApply_PFMG(PC pc,Vec x,Vec y)
1114 {
1115   PetscErrorCode  ierr;
1116   PC_PFMG         *ex = (PC_PFMG*) pc->data;
1117   PetscScalar     *xx,*yy;
1118   PetscInt        ilower[3],iupper[3];
1119   Mat_HYPREStruct *mx = (Mat_HYPREStruct*)(pc->pmat->data);
1120 
1121   PetscFunctionBegin;
1122   ierr       = DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr);
1123   iupper[0] += ilower[0] - 1;
1124   iupper[1] += ilower[1] - 1;
1125   iupper[2] += ilower[2] - 1;
1126 
1127   /* copy x values over to hypre */
1128   PetscStackCallStandard(HYPRE_StructVectorSetConstantValues,(mx->hb,0.0));
1129   ierr = VecGetArray(x,&xx);CHKERRQ(ierr);
1130   PetscStackCallStandard(HYPRE_StructVectorSetBoxValues,(mx->hb,ilower,iupper,xx));
1131   ierr = VecRestoreArray(x,&xx);CHKERRQ(ierr);
1132   PetscStackCallStandard(HYPRE_StructVectorAssemble,(mx->hb));
1133   PetscStackCallStandard(HYPRE_StructPFMGSolve,(ex->hsolver,mx->hmat,mx->hb,mx->hx));
1134 
1135   /* copy solution values back to PETSc */
1136   ierr = VecGetArray(y,&yy);CHKERRQ(ierr);
1137   PetscStackCallStandard(HYPRE_StructVectorGetBoxValues,(mx->hx,ilower,iupper,yy));
1138   ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr);
1139   PetscFunctionReturn(0);
1140 }
1141 
1142 #undef __FUNCT__
1143 #define __FUNCT__ "PCApplyRichardson_PFMG"
1144 static PetscErrorCode PCApplyRichardson_PFMG(PC pc,Vec b,Vec y,Vec w,PetscReal rtol,PetscReal abstol, PetscReal dtol,PetscInt its,PetscBool guesszero,PetscInt *outits,PCRichardsonConvergedReason *reason)
1145 {
1146   PC_PFMG        *jac = (PC_PFMG*)pc->data;
1147   PetscErrorCode ierr;
1148   PetscInt       oits;
1149 
1150   PetscFunctionBegin;
1151   PetscStackCallStandard(HYPRE_StructPFMGSetMaxIter,(jac->hsolver,its*jac->its));
1152   PetscStackCallStandard(HYPRE_StructPFMGSetTol,(jac->hsolver,rtol));
1153 
1154   ierr = PCApply_PFMG(pc,b,y);CHKERRQ(ierr);
1155   PetscStackCallStandard(HYPRE_StructPFMGGetNumIterations,(jac->hsolver,&oits));
1156   *outits = oits;
1157   if (oits == its) *reason = PCRICHARDSON_CONVERGED_ITS;
1158   else             *reason = PCRICHARDSON_CONVERGED_RTOL;
1159   PetscStackCallStandard(HYPRE_StructPFMGSetTol,(jac->hsolver,jac->tol));
1160   PetscStackCallStandard(HYPRE_StructPFMGSetMaxIter,(jac->hsolver,jac->its));
1161   PetscFunctionReturn(0);
1162 }
1163 
1164 
1165 #undef __FUNCT__
1166 #define __FUNCT__ "PCSetUp_PFMG"
1167 PetscErrorCode PCSetUp_PFMG(PC pc)
1168 {
1169   PetscErrorCode  ierr;
1170   PC_PFMG         *ex = (PC_PFMG*) pc->data;
1171   Mat_HYPREStruct *mx = (Mat_HYPREStruct*)(pc->pmat->data);
1172   PetscBool       flg;
1173 
1174   PetscFunctionBegin;
1175   ierr = PetscObjectTypeCompare((PetscObject)pc->pmat,MATHYPRESTRUCT,&flg);CHKERRQ(ierr);
1176   if (!flg) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Must use MATHYPRESTRUCT with this preconditioner");
1177 
1178   /* create the hypre solver object and set its information */
1179   if (ex->hsolver) PetscStackCallStandard(HYPRE_StructPFMGDestroy,(ex->hsolver));
1180   PetscStackCallStandard(HYPRE_StructPFMGCreate,(ex->hcomm,&ex->hsolver));
1181   ierr = PCSetFromOptions_PFMG(pc);CHKERRQ(ierr);
1182   PetscStackCallStandard(HYPRE_StructPFMGSetup,(ex->hsolver,mx->hmat,mx->hb,mx->hx));
1183   PetscStackCallStandard(HYPRE_StructPFMGSetZeroGuess,(ex->hsolver));
1184   PetscFunctionReturn(0);
1185 }
1186 
1187 
1188 /*MC
1189      PCPFMG - the hypre PFMG multigrid solver
1190 
1191    Level: advanced
1192 
1193    Options Database:
1194 + -pc_pfmg_its <its> number of iterations of PFMG to use as preconditioner
1195 . -pc_pfmg_num_pre_relax <steps> number of smoothing steps before coarse grid
1196 . -pc_pfmg_num_post_relax <steps> number of smoothing steps after coarse grid
1197 . -pc_pfmg_tol <tol> tolerance of PFMG
1198 . -pc_pfmg_relax_type -relaxation type for the up and down cycles, one of Jacobi,Weighted-Jacobi,symmetric-Red/Black-Gauss-Seidel,Red/Black-Gauss-Seidel
1199 - -pc_pfmg_rap_type - type of coarse matrix generation, one of Galerkin,non-Galerkin
1200 
1201    Notes:  This is for CELL-centered descretizations
1202 
1203            This must be used with the MATHYPRESTRUCT matrix type.
1204            This is less general than in hypre, it supports only one block per process defined by a PETSc DMDA.
1205 
1206 .seealso:  PCMG, MATHYPRESTRUCT
1207 M*/
1208 
1209 #undef __FUNCT__
1210 #define __FUNCT__ "PCCreate_PFMG"
1211 PETSC_EXTERN PetscErrorCode PCCreate_PFMG(PC pc)
1212 {
1213   PetscErrorCode ierr;
1214   PC_PFMG        *ex;
1215 
1216   PetscFunctionBegin;
1217   ierr     = PetscNew(PC_PFMG,&ex);CHKERRQ(ierr); \
1218   pc->data = ex;
1219 
1220   ex->its            = 1;
1221   ex->tol            = 1.e-8;
1222   ex->relax_type     = 1;
1223   ex->rap_type       = 0;
1224   ex->num_pre_relax  = 1;
1225   ex->num_post_relax = 1;
1226   ex->max_levels     = 0;
1227 
1228   pc->ops->setfromoptions  = PCSetFromOptions_PFMG;
1229   pc->ops->view            = PCView_PFMG;
1230   pc->ops->destroy         = PCDestroy_PFMG;
1231   pc->ops->apply           = PCApply_PFMG;
1232   pc->ops->applyrichardson = PCApplyRichardson_PFMG;
1233   pc->ops->setup           = PCSetUp_PFMG;
1234 
1235   ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)pc),&(ex->hcomm));CHKERRQ(ierr);
1236   PetscStackCallStandard(HYPRE_StructPFMGCreate,(ex->hcomm,&ex->hsolver));
1237   PetscFunctionReturn(0);
1238 }
1239 
1240 /* ---------------------------------------------------------------------------------------------------------------------------------------------------*/
1241 
1242 /* we know we are working with a HYPRE_SStructMatrix */
1243 typedef struct {
1244   MPI_Comm            hcomm;       /* does not share comm with HYPRE_SStructMatrix because need to create solver before getting matrix */
1245   HYPRE_SStructSolver ss_solver;
1246 
1247   /* keep copy of SYSPFMG options used so may view them */
1248   PetscInt its;
1249   double   tol;
1250   PetscInt relax_type;
1251   PetscInt num_pre_relax,num_post_relax;
1252 } PC_SysPFMG;
1253 
1254 #undef __FUNCT__
1255 #define __FUNCT__ "PCDestroy_SysPFMG"
1256 PetscErrorCode PCDestroy_SysPFMG(PC pc)
1257 {
1258   PetscErrorCode ierr;
1259   PC_SysPFMG     *ex = (PC_SysPFMG*) pc->data;
1260 
1261   PetscFunctionBegin;
1262   if (ex->ss_solver) PetscStackCallStandard(HYPRE_SStructSysPFMGDestroy,(ex->ss_solver));
1263   ierr = MPI_Comm_free(&ex->hcomm);CHKERRQ(ierr);
1264   ierr = PetscFree(pc->data);CHKERRQ(ierr);
1265   PetscFunctionReturn(0);
1266 }
1267 
1268 static const char *SysPFMGRelaxType[] = {"Weighted-Jacobi","Red/Black-Gauss-Seidel"};
1269 
1270 #undef __FUNCT__
1271 #define __FUNCT__ "PCView_SysPFMG"
1272 PetscErrorCode PCView_SysPFMG(PC pc,PetscViewer viewer)
1273 {
1274   PetscErrorCode ierr;
1275   PetscBool      iascii;
1276   PC_SysPFMG     *ex = (PC_SysPFMG*) pc->data;
1277 
1278   PetscFunctionBegin;
1279   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
1280   if (iascii) {
1281     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE SysPFMG preconditioning\n");CHKERRQ(ierr);
1282     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE SysPFMG: max iterations %d\n",ex->its);CHKERRQ(ierr);
1283     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE SysPFMG: tolerance %g\n",ex->tol);CHKERRQ(ierr);
1284     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE SysPFMG: relax type %s\n",PFMGRelaxType[ex->relax_type]);CHKERRQ(ierr);
1285     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE SysPFMG: number pre-relax %d post-relax %d\n",ex->num_pre_relax,ex->num_post_relax);CHKERRQ(ierr);
1286   }
1287   PetscFunctionReturn(0);
1288 }
1289 
1290 
1291 #undef __FUNCT__
1292 #define __FUNCT__ "PCSetFromOptions_SysPFMG"
1293 PetscErrorCode PCSetFromOptions_SysPFMG(PC pc)
1294 {
1295   PetscErrorCode ierr;
1296   PC_SysPFMG     *ex = (PC_SysPFMG*) pc->data;
1297   PetscBool      flg = PETSC_FALSE;
1298 
1299   PetscFunctionBegin;
1300   ierr = PetscOptionsHead("SysPFMG options");CHKERRQ(ierr);
1301   ierr = PetscOptionsBool("-pc_syspfmg_print_statistics","Print statistics","HYPRE_SStructSysPFMGSetPrintLevel",flg,&flg,NULL);CHKERRQ(ierr);
1302   if (flg) {
1303     int level=3;
1304     PetscStackCallStandard(HYPRE_SStructSysPFMGSetPrintLevel,(ex->ss_solver,level));
1305   }
1306   ierr = PetscOptionsInt("-pc_syspfmg_its","Number of iterations of SysPFMG to use as preconditioner","HYPRE_SStructSysPFMGSetMaxIter",ex->its,&ex->its,NULL);CHKERRQ(ierr);
1307   PetscStackCallStandard(HYPRE_SStructSysPFMGSetMaxIter,(ex->ss_solver,ex->its));
1308   ierr = PetscOptionsInt("-pc_syspfmg_num_pre_relax","Number of smoothing steps before coarse grid","HYPRE_SStructSysPFMGSetNumPreRelax",ex->num_pre_relax,&ex->num_pre_relax,NULL);CHKERRQ(ierr);
1309   PetscStackCallStandard(HYPRE_SStructSysPFMGSetNumPreRelax,(ex->ss_solver,ex->num_pre_relax));
1310   ierr = PetscOptionsInt("-pc_syspfmg_num_post_relax","Number of smoothing steps after coarse grid","HYPRE_SStructSysPFMGSetNumPostRelax",ex->num_post_relax,&ex->num_post_relax,NULL);CHKERRQ(ierr);
1311   PetscStackCallStandard(HYPRE_SStructSysPFMGSetNumPostRelax,(ex->ss_solver,ex->num_post_relax));
1312 
1313   ierr = PetscOptionsReal("-pc_syspfmg_tol","Tolerance of SysPFMG","HYPRE_SStructSysPFMGSetTol",ex->tol,&ex->tol,NULL);CHKERRQ(ierr);
1314   PetscStackCallStandard(HYPRE_SStructSysPFMGSetTol,(ex->ss_solver,ex->tol));
1315   ierr = PetscOptionsEList("-pc_syspfmg_relax_type","Relax type for the up and down cycles","HYPRE_SStructSysPFMGSetRelaxType",SysPFMGRelaxType,4,SysPFMGRelaxType[ex->relax_type],&ex->relax_type,NULL);CHKERRQ(ierr);
1316   PetscStackCallStandard(HYPRE_SStructSysPFMGSetRelaxType,(ex->ss_solver, ex->relax_type));
1317   ierr = PetscOptionsTail();CHKERRQ(ierr);
1318   PetscFunctionReturn(0);
1319 }
1320 
1321 #undef __FUNCT__
1322 #define __FUNCT__ "PCApply_SysPFMG"
1323 PetscErrorCode PCApply_SysPFMG(PC pc,Vec x,Vec y)
1324 {
1325   PetscErrorCode   ierr;
1326   PC_SysPFMG       *ex = (PC_SysPFMG*) pc->data;
1327   PetscScalar      *xx,*yy;
1328   PetscInt         ilower[3],iupper[3];
1329   Mat_HYPRESStruct *mx     = (Mat_HYPRESStruct*)(pc->pmat->data);
1330   PetscInt         ordering= mx->dofs_order;
1331   PetscInt         nvars   = mx->nvars;
1332   PetscInt         part    = 0;
1333   PetscInt         size;
1334   PetscInt         i;
1335 
1336   PetscFunctionBegin;
1337   ierr       = DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr);
1338   iupper[0] += ilower[0] - 1;
1339   iupper[1] += ilower[1] - 1;
1340   iupper[2] += ilower[2] - 1;
1341 
1342   size = 1;
1343   for (i= 0; i< 3; i++) size *= (iupper[i]-ilower[i]+1);
1344 
1345   /* copy x values over to hypre for variable ordering */
1346   if (ordering) {
1347     PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,(mx->ss_b,0.0));
1348     ierr = VecGetArray(x,&xx);CHKERRQ(ierr);
1349     for (i= 0; i< nvars; i++) PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,(mx->ss_b,part,ilower,iupper,i,xx+(size*i)));
1350     ierr = VecRestoreArray(x,&xx);CHKERRQ(ierr);
1351     PetscStackCallStandard(HYPRE_SStructVectorAssemble,(mx->ss_b));
1352     PetscStackCallStandard(HYPRE_SStructMatrixMatvec,(1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x));
1353     PetscStackCallStandard(HYPRE_SStructSysPFMGSolve,(ex->ss_solver,mx->ss_mat,mx->ss_b,mx->ss_x));
1354 
1355     /* copy solution values back to PETSc */
1356     ierr = VecGetArray(y,&yy);CHKERRQ(ierr);
1357     for (i= 0; i< nvars; i++) PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,(mx->ss_x,part,ilower,iupper,i,yy+(size*i)));
1358     ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr);
1359   } else {      /* nodal ordering must be mapped to variable ordering for sys_pfmg */
1360     PetscScalar *z;
1361     PetscInt    j, k;
1362 
1363     ierr = PetscMalloc(nvars*size*sizeof(PetscScalar),&z);CHKERRQ(ierr);
1364     PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,(mx->ss_b,0.0));
1365     ierr = VecGetArray(x,&xx);CHKERRQ(ierr);
1366 
1367     /* transform nodal to hypre's variable ordering for sys_pfmg */
1368     for (i= 0; i< size; i++) {
1369       k= i*nvars;
1370       for (j= 0; j< nvars; j++) z[j*size+i]= xx[k+j];
1371     }
1372     for (i= 0; i< nvars; i++) PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,(mx->ss_b,part,ilower,iupper,i,z+(size*i)));
1373     ierr = VecRestoreArray(x,&xx);CHKERRQ(ierr);
1374     PetscStackCallStandard(HYPRE_SStructVectorAssemble,(mx->ss_b));
1375     PetscStackCallStandard(HYPRE_SStructSysPFMGSolve,(ex->ss_solver,mx->ss_mat,mx->ss_b,mx->ss_x));
1376 
1377     /* copy solution values back to PETSc */
1378     ierr = VecGetArray(y,&yy);CHKERRQ(ierr);
1379     for (i= 0; i< nvars; i++) PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,(mx->ss_x,part,ilower,iupper,i,z+(size*i)));
1380     /* transform hypre's variable ordering for sys_pfmg to nodal ordering */
1381     for (i= 0; i< size; i++) {
1382       k= i*nvars;
1383       for (j= 0; j< nvars; j++) yy[k+j]= z[j*size+i];
1384     }
1385     ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr);
1386     ierr = PetscFree(z);CHKERRQ(ierr);
1387   }
1388   PetscFunctionReturn(0);
1389 }
1390 
1391 #undef __FUNCT__
1392 #define __FUNCT__ "PCApplyRichardson_SysPFMG"
1393 static PetscErrorCode PCApplyRichardson_SysPFMG(PC pc,Vec b,Vec y,Vec w,PetscReal rtol,PetscReal abstol, PetscReal dtol,PetscInt its,PetscBool guesszero,PetscInt *outits,PCRichardsonConvergedReason *reason)
1394 {
1395   PC_SysPFMG     *jac = (PC_SysPFMG*)pc->data;
1396   PetscErrorCode ierr;
1397   PetscInt       oits;
1398 
1399   PetscFunctionBegin;
1400   PetscStackCallStandard(HYPRE_SStructSysPFMGSetMaxIter,(jac->ss_solver,its*jac->its));
1401   PetscStackCallStandard(HYPRE_SStructSysPFMGSetTol,(jac->ss_solver,rtol));
1402   ierr = PCApply_SysPFMG(pc,b,y);CHKERRQ(ierr);
1403   PetscStackCallStandard(HYPRE_SStructSysPFMGGetNumIterations,(jac->ss_solver,&oits));
1404   *outits = oits;
1405   if (oits == its) *reason = PCRICHARDSON_CONVERGED_ITS;
1406   else             *reason = PCRICHARDSON_CONVERGED_RTOL;
1407   PetscStackCallStandard(HYPRE_SStructSysPFMGSetTol,(jac->ss_solver,jac->tol));
1408   PetscStackCallStandard(HYPRE_SStructSysPFMGSetMaxIter,(jac->ss_solver,jac->its));
1409   PetscFunctionReturn(0);
1410 }
1411 
1412 
1413 #undef __FUNCT__
1414 #define __FUNCT__ "PCSetUp_SysPFMG"
1415 PetscErrorCode PCSetUp_SysPFMG(PC pc)
1416 {
1417   PetscErrorCode   ierr;
1418   PC_SysPFMG       *ex = (PC_SysPFMG*) pc->data;
1419   Mat_HYPRESStruct *mx = (Mat_HYPRESStruct*)(pc->pmat->data);
1420   PetscBool        flg;
1421 
1422   PetscFunctionBegin;
1423   ierr = PetscObjectTypeCompare((PetscObject)pc->pmat,MATHYPRESSTRUCT,&flg);CHKERRQ(ierr);
1424   if (!flg) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Must use MATHYPRESSTRUCT with this preconditioner");
1425 
1426   /* create the hypre sstruct solver object and set its information */
1427   if (ex->ss_solver) PetscStackCallStandard(HYPRE_SStructSysPFMGDestroy,(ex->ss_solver));
1428   PetscStackCallStandard(HYPRE_SStructSysPFMGCreate,(ex->hcomm,&ex->ss_solver));
1429   ierr = PCSetFromOptions_SysPFMG(pc);CHKERRQ(ierr);
1430   PetscStackCallStandard(HYPRE_SStructSysPFMGSetZeroGuess,(ex->ss_solver));
1431   PetscStackCallStandard(HYPRE_SStructSysPFMGSetup,(ex->ss_solver,mx->ss_mat,mx->ss_b,mx->ss_x));
1432   PetscFunctionReturn(0);
1433 }
1434 
1435 
1436 /*MC
1437      PCSysPFMG - the hypre SysPFMG multigrid solver
1438 
1439    Level: advanced
1440 
1441    Options Database:
1442 + -pc_syspfmg_its <its> number of iterations of SysPFMG to use as preconditioner
1443 . -pc_syspfmg_num_pre_relax <steps> number of smoothing steps before coarse grid
1444 . -pc_syspfmg_num_post_relax <steps> number of smoothing steps after coarse grid
1445 . -pc_syspfmg_tol <tol> tolerance of SysPFMG
1446 . -pc_syspfmg_relax_type -relaxation type for the up and down cycles, one of Weighted-Jacobi,Red/Black-Gauss-Seidel
1447 
1448    Notes:  This is for CELL-centered descretizations
1449 
1450            This must be used with the MATHYPRESSTRUCT matrix type.
1451            This is less general than in hypre, it supports only one part, and one block per process defined by a PETSc DMDA.
1452            Also, only cell-centered variables.
1453 
1454 .seealso:  PCMG, MATHYPRESSTRUCT
1455 M*/
1456 
1457 #undef __FUNCT__
1458 #define __FUNCT__ "PCCreate_SysPFMG"
1459 PETSC_EXTERN PetscErrorCode PCCreate_SysPFMG(PC pc)
1460 {
1461   PetscErrorCode ierr;
1462   PC_SysPFMG     *ex;
1463 
1464   PetscFunctionBegin;
1465   ierr     = PetscNew(PC_SysPFMG,&ex);CHKERRQ(ierr); \
1466   pc->data = ex;
1467 
1468   ex->its            = 1;
1469   ex->tol            = 1.e-8;
1470   ex->relax_type     = 1;
1471   ex->num_pre_relax  = 1;
1472   ex->num_post_relax = 1;
1473 
1474   pc->ops->setfromoptions  = PCSetFromOptions_SysPFMG;
1475   pc->ops->view            = PCView_SysPFMG;
1476   pc->ops->destroy         = PCDestroy_SysPFMG;
1477   pc->ops->apply           = PCApply_SysPFMG;
1478   pc->ops->applyrichardson = PCApplyRichardson_SysPFMG;
1479   pc->ops->setup           = PCSetUp_SysPFMG;
1480 
1481   ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)pc),&(ex->hcomm));CHKERRQ(ierr);
1482   PetscStackCallStandard(HYPRE_SStructSysPFMGCreate,(ex->hcomm,&ex->ss_solver));
1483   PetscFunctionReturn(0);
1484 }
1485