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