xref: /petsc/src/ksp/pc/impls/hypre/hypre.c (revision f7a087814f99396ec53a0bad244374eaa0312225)
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 EXTERN_C_BEGIN
995 #undef __FUNCT__
996 #define __FUNCT__ "PCCreate_HYPRE"
997 PetscErrorCode  PCCreate_HYPRE(PC pc)
998 {
999   PC_HYPRE       *jac;
1000   PetscErrorCode ierr;
1001 
1002   PetscFunctionBegin;
1003   ierr = PetscNewLog(pc,PC_HYPRE,&jac);CHKERRQ(ierr);
1004 
1005   pc->data                = jac;
1006   pc->ops->destroy        = PCDestroy_HYPRE;
1007   pc->ops->setfromoptions = PCSetFromOptions_HYPRE;
1008   pc->ops->setup          = PCSetUp_HYPRE;
1009   pc->ops->apply          = PCApply_HYPRE;
1010   jac->comm_hypre         = MPI_COMM_NULL;
1011   jac->hypre_type         = NULL;
1012   /* duplicate communicator for hypre */
1013   ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)pc),&(jac->comm_hypre));CHKERRQ(ierr);
1014   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetType_C","PCHYPRESetType_HYPRE",PCHYPRESetType_HYPRE);CHKERRQ(ierr);
1015   ierr = PetscObjectComposeFunction((PetscObject)pc,"PCHYPREGetType_C","PCHYPREGetType_HYPRE",PCHYPREGetType_HYPRE);CHKERRQ(ierr);
1016   PetscFunctionReturn(0);
1017 }
1018 EXTERN_C_END
1019 
1020 /* ---------------------------------------------------------------------------------------------------------------------------------*/
1021 
1022 /* this include is needed ONLY to allow access to the private data inside the Mat object specific to hypre */
1023 #include <petsc-private/matimpl.h>
1024 
1025 typedef struct {
1026   MPI_Comm           hcomm;        /* does not share comm with HYPRE_StructMatrix because need to create solver before getting matrix */
1027   HYPRE_StructSolver hsolver;
1028 
1029   /* keep copy of PFMG options used so may view them */
1030   PetscInt its;
1031   double   tol;
1032   PetscInt relax_type;
1033   PetscInt rap_type;
1034   PetscInt num_pre_relax,num_post_relax;
1035   PetscInt max_levels;
1036 } PC_PFMG;
1037 
1038 #undef __FUNCT__
1039 #define __FUNCT__ "PCDestroy_PFMG"
1040 PetscErrorCode PCDestroy_PFMG(PC pc)
1041 {
1042   PetscErrorCode ierr;
1043   PC_PFMG        *ex = (PC_PFMG*) pc->data;
1044 
1045   PetscFunctionBegin;
1046   if (ex->hsolver) PetscStackCallStandard(HYPRE_StructPFMGDestroy,(ex->hsolver));
1047   ierr = MPI_Comm_free(&ex->hcomm);CHKERRQ(ierr);
1048   ierr = PetscFree(pc->data);CHKERRQ(ierr);
1049   PetscFunctionReturn(0);
1050 }
1051 
1052 static const char *PFMGRelaxType[] = {"Jacobi","Weighted-Jacobi","symmetric-Red/Black-Gauss-Seidel","Red/Black-Gauss-Seidel"};
1053 static const char *PFMGRAPType[] = {"Galerkin","non-Galerkin"};
1054 
1055 #undef __FUNCT__
1056 #define __FUNCT__ "PCView_PFMG"
1057 PetscErrorCode PCView_PFMG(PC pc,PetscViewer viewer)
1058 {
1059   PetscErrorCode ierr;
1060   PetscBool      iascii;
1061   PC_PFMG        *ex = (PC_PFMG*) pc->data;
1062 
1063   PetscFunctionBegin;
1064   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
1065   if (iascii) {
1066     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE PFMG preconditioning\n");CHKERRQ(ierr);
1067     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE PFMG: max iterations %d\n",ex->its);CHKERRQ(ierr);
1068     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE PFMG: tolerance %g\n",ex->tol);CHKERRQ(ierr);
1069     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE PFMG: relax type %s\n",PFMGRelaxType[ex->relax_type]);CHKERRQ(ierr);
1070     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE PFMG: RAP type %s\n",PFMGRAPType[ex->rap_type]);CHKERRQ(ierr);
1071     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE PFMG: number pre-relax %d post-relax %d\n",ex->num_pre_relax,ex->num_post_relax);CHKERRQ(ierr);
1072     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE PFMG: max levels %d\n",ex->max_levels);CHKERRQ(ierr);
1073   }
1074   PetscFunctionReturn(0);
1075 }
1076 
1077 
1078 #undef __FUNCT__
1079 #define __FUNCT__ "PCSetFromOptions_PFMG"
1080 PetscErrorCode PCSetFromOptions_PFMG(PC pc)
1081 {
1082   PetscErrorCode ierr;
1083   PC_PFMG        *ex = (PC_PFMG*) pc->data;
1084   PetscBool      flg = PETSC_FALSE;
1085 
1086   PetscFunctionBegin;
1087   ierr = PetscOptionsHead("PFMG options");CHKERRQ(ierr);
1088   ierr = PetscOptionsBool("-pc_pfmg_print_statistics","Print statistics","HYPRE_StructPFMGSetPrintLevel",flg,&flg,NULL);CHKERRQ(ierr);
1089   if (flg) {
1090     int level=3;
1091     PetscStackCallStandard(HYPRE_StructPFMGSetPrintLevel,(ex->hsolver,level));
1092   }
1093   ierr = PetscOptionsInt("-pc_pfmg_its","Number of iterations of PFMG to use as preconditioner","HYPRE_StructPFMGSetMaxIter",ex->its,&ex->its,NULL);CHKERRQ(ierr);
1094   PetscStackCallStandard(HYPRE_StructPFMGSetMaxIter,(ex->hsolver,ex->its));
1095   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);
1096   PetscStackCallStandard(HYPRE_StructPFMGSetNumPreRelax,(ex->hsolver,ex->num_pre_relax));
1097   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);
1098   PetscStackCallStandard(HYPRE_StructPFMGSetNumPostRelax,(ex->hsolver,ex->num_post_relax));
1099 
1100   ierr = PetscOptionsInt("-pc_pfmg_max_levels","Max Levels for MG hierarchy","HYPRE_StructPFMGSetMaxLevels",ex->max_levels,&ex->max_levels,NULL);CHKERRQ(ierr);
1101   PetscStackCallStandard(HYPRE_StructPFMGSetMaxLevels,(ex->hsolver,ex->max_levels));
1102 
1103   ierr = PetscOptionsReal("-pc_pfmg_tol","Tolerance of PFMG","HYPRE_StructPFMGSetTol",ex->tol,&ex->tol,NULL);CHKERRQ(ierr);
1104   PetscStackCallStandard(HYPRE_StructPFMGSetTol,(ex->hsolver,ex->tol));
1105   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);
1106   PetscStackCallStandard(HYPRE_StructPFMGSetRelaxType,(ex->hsolver, ex->relax_type));
1107   ierr = PetscOptionsEList("-pc_pfmg_rap_type","RAP type","HYPRE_StructPFMGSetRAPType",PFMGRAPType,ALEN(PFMGRAPType),PFMGRAPType[ex->rap_type],&ex->rap_type,NULL);CHKERRQ(ierr);
1108   PetscStackCallStandard(HYPRE_StructPFMGSetRAPType,(ex->hsolver, ex->rap_type));
1109   ierr = PetscOptionsTail();CHKERRQ(ierr);
1110   PetscFunctionReturn(0);
1111 }
1112 
1113 #undef __FUNCT__
1114 #define __FUNCT__ "PCApply_PFMG"
1115 PetscErrorCode PCApply_PFMG(PC pc,Vec x,Vec y)
1116 {
1117   PetscErrorCode  ierr;
1118   PC_PFMG         *ex = (PC_PFMG*) pc->data;
1119   PetscScalar     *xx,*yy;
1120   PetscInt        ilower[3],iupper[3];
1121   Mat_HYPREStruct *mx = (Mat_HYPREStruct*)(pc->pmat->data);
1122 
1123   PetscFunctionBegin;
1124   ierr       = DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr);
1125   iupper[0] += ilower[0] - 1;
1126   iupper[1] += ilower[1] - 1;
1127   iupper[2] += ilower[2] - 1;
1128 
1129   /* copy x values over to hypre */
1130   PetscStackCallStandard(HYPRE_StructVectorSetConstantValues,(mx->hb,0.0));
1131   ierr = VecGetArray(x,&xx);CHKERRQ(ierr);
1132   PetscStackCallStandard(HYPRE_StructVectorSetBoxValues,(mx->hb,ilower,iupper,xx));
1133   ierr = VecRestoreArray(x,&xx);CHKERRQ(ierr);
1134   PetscStackCallStandard(HYPRE_StructVectorAssemble,(mx->hb));
1135   PetscStackCallStandard(HYPRE_StructPFMGSolve,(ex->hsolver,mx->hmat,mx->hb,mx->hx));
1136 
1137   /* copy solution values back to PETSc */
1138   ierr = VecGetArray(y,&yy);CHKERRQ(ierr);
1139   PetscStackCallStandard(HYPRE_StructVectorGetBoxValues,(mx->hx,ilower,iupper,yy));
1140   ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr);
1141   PetscFunctionReturn(0);
1142 }
1143 
1144 #undef __FUNCT__
1145 #define __FUNCT__ "PCApplyRichardson_PFMG"
1146 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)
1147 {
1148   PC_PFMG        *jac = (PC_PFMG*)pc->data;
1149   PetscErrorCode ierr;
1150   PetscInt       oits;
1151 
1152   PetscFunctionBegin;
1153   PetscStackCallStandard(HYPRE_StructPFMGSetMaxIter,(jac->hsolver,its*jac->its));
1154   PetscStackCallStandard(HYPRE_StructPFMGSetTol,(jac->hsolver,rtol));
1155 
1156   ierr = PCApply_PFMG(pc,b,y);CHKERRQ(ierr);
1157   PetscStackCallStandard(HYPRE_StructPFMGGetNumIterations,(jac->hsolver,&oits));
1158   *outits = oits;
1159   if (oits == its) *reason = PCRICHARDSON_CONVERGED_ITS;
1160   else             *reason = PCRICHARDSON_CONVERGED_RTOL;
1161   PetscStackCallStandard(HYPRE_StructPFMGSetTol,(jac->hsolver,jac->tol));
1162   PetscStackCallStandard(HYPRE_StructPFMGSetMaxIter,(jac->hsolver,jac->its));
1163   PetscFunctionReturn(0);
1164 }
1165 
1166 
1167 #undef __FUNCT__
1168 #define __FUNCT__ "PCSetUp_PFMG"
1169 PetscErrorCode PCSetUp_PFMG(PC pc)
1170 {
1171   PetscErrorCode  ierr;
1172   PC_PFMG         *ex = (PC_PFMG*) pc->data;
1173   Mat_HYPREStruct *mx = (Mat_HYPREStruct*)(pc->pmat->data);
1174   PetscBool       flg;
1175 
1176   PetscFunctionBegin;
1177   ierr = PetscObjectTypeCompare((PetscObject)pc->pmat,MATHYPRESTRUCT,&flg);CHKERRQ(ierr);
1178   if (!flg) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Must use MATHYPRESTRUCT with this preconditioner");
1179 
1180   /* create the hypre solver object and set its information */
1181   if (ex->hsolver) PetscStackCallStandard(HYPRE_StructPFMGDestroy,(ex->hsolver));
1182   PetscStackCallStandard(HYPRE_StructPFMGCreate,(ex->hcomm,&ex->hsolver));
1183   ierr = PCSetFromOptions_PFMG(pc);CHKERRQ(ierr);
1184   PetscStackCallStandard(HYPRE_StructPFMGSetup,(ex->hsolver,mx->hmat,mx->hb,mx->hx));
1185   PetscStackCallStandard(HYPRE_StructPFMGSetZeroGuess,(ex->hsolver));
1186   PetscFunctionReturn(0);
1187 }
1188 
1189 
1190 /*MC
1191      PCPFMG - the hypre PFMG multigrid solver
1192 
1193    Level: advanced
1194 
1195    Options Database:
1196 + -pc_pfmg_its <its> number of iterations of PFMG to use as preconditioner
1197 . -pc_pfmg_num_pre_relax <steps> number of smoothing steps before coarse grid
1198 . -pc_pfmg_num_post_relax <steps> number of smoothing steps after coarse grid
1199 . -pc_pfmg_tol <tol> tolerance of PFMG
1200 . -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
1201 - -pc_pfmg_rap_type - type of coarse matrix generation, one of Galerkin,non-Galerkin
1202 
1203    Notes:  This is for CELL-centered descretizations
1204 
1205            This must be used with the MATHYPRESTRUCT matrix type.
1206            This is less general than in hypre, it supports only one block per process defined by a PETSc DMDA.
1207 
1208 .seealso:  PCMG, MATHYPRESTRUCT
1209 M*/
1210 
1211 EXTERN_C_BEGIN
1212 #undef __FUNCT__
1213 #define __FUNCT__ "PCCreate_PFMG"
1214 PetscErrorCode  PCCreate_PFMG(PC pc)
1215 {
1216   PetscErrorCode ierr;
1217   PC_PFMG        *ex;
1218 
1219   PetscFunctionBegin;
1220   ierr     = PetscNew(PC_PFMG,&ex);CHKERRQ(ierr); \
1221   pc->data = ex;
1222 
1223   ex->its            = 1;
1224   ex->tol            = 1.e-8;
1225   ex->relax_type     = 1;
1226   ex->rap_type       = 0;
1227   ex->num_pre_relax  = 1;
1228   ex->num_post_relax = 1;
1229   ex->max_levels     = 0;
1230 
1231   pc->ops->setfromoptions  = PCSetFromOptions_PFMG;
1232   pc->ops->view            = PCView_PFMG;
1233   pc->ops->destroy         = PCDestroy_PFMG;
1234   pc->ops->apply           = PCApply_PFMG;
1235   pc->ops->applyrichardson = PCApplyRichardson_PFMG;
1236   pc->ops->setup           = PCSetUp_PFMG;
1237 
1238   ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)pc),&(ex->hcomm));CHKERRQ(ierr);
1239   PetscStackCallStandard(HYPRE_StructPFMGCreate,(ex->hcomm,&ex->hsolver));
1240   PetscFunctionReturn(0);
1241 }
1242 EXTERN_C_END
1243 
1244 /* ---------------------------------------------------------------------------------------------------------------------------------------------------*/
1245 
1246 /* we know we are working with a HYPRE_SStructMatrix */
1247 typedef struct {
1248   MPI_Comm            hcomm;       /* does not share comm with HYPRE_SStructMatrix because need to create solver before getting matrix */
1249   HYPRE_SStructSolver ss_solver;
1250 
1251   /* keep copy of SYSPFMG options used so may view them */
1252   PetscInt its;
1253   double   tol;
1254   PetscInt relax_type;
1255   PetscInt num_pre_relax,num_post_relax;
1256 } PC_SysPFMG;
1257 
1258 #undef __FUNCT__
1259 #define __FUNCT__ "PCDestroy_SysPFMG"
1260 PetscErrorCode PCDestroy_SysPFMG(PC pc)
1261 {
1262   PetscErrorCode ierr;
1263   PC_SysPFMG     *ex = (PC_SysPFMG*) pc->data;
1264 
1265   PetscFunctionBegin;
1266   if (ex->ss_solver) PetscStackCallStandard(HYPRE_SStructSysPFMGDestroy,(ex->ss_solver));
1267   ierr = MPI_Comm_free(&ex->hcomm);CHKERRQ(ierr);
1268   ierr = PetscFree(pc->data);CHKERRQ(ierr);
1269   PetscFunctionReturn(0);
1270 }
1271 
1272 static const char *SysPFMGRelaxType[] = {"Weighted-Jacobi","Red/Black-Gauss-Seidel"};
1273 
1274 #undef __FUNCT__
1275 #define __FUNCT__ "PCView_SysPFMG"
1276 PetscErrorCode PCView_SysPFMG(PC pc,PetscViewer viewer)
1277 {
1278   PetscErrorCode ierr;
1279   PetscBool      iascii;
1280   PC_SysPFMG     *ex = (PC_SysPFMG*) pc->data;
1281 
1282   PetscFunctionBegin;
1283   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
1284   if (iascii) {
1285     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE SysPFMG preconditioning\n");CHKERRQ(ierr);
1286     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE SysPFMG: max iterations %d\n",ex->its);CHKERRQ(ierr);
1287     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE SysPFMG: tolerance %g\n",ex->tol);CHKERRQ(ierr);
1288     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE SysPFMG: relax type %s\n",PFMGRelaxType[ex->relax_type]);CHKERRQ(ierr);
1289     ierr = PetscViewerASCIIPrintf(viewer,"  HYPRE SysPFMG: number pre-relax %d post-relax %d\n",ex->num_pre_relax,ex->num_post_relax);CHKERRQ(ierr);
1290   }
1291   PetscFunctionReturn(0);
1292 }
1293 
1294 
1295 #undef __FUNCT__
1296 #define __FUNCT__ "PCSetFromOptions_SysPFMG"
1297 PetscErrorCode PCSetFromOptions_SysPFMG(PC pc)
1298 {
1299   PetscErrorCode ierr;
1300   PC_SysPFMG     *ex = (PC_SysPFMG*) pc->data;
1301   PetscBool      flg = PETSC_FALSE;
1302 
1303   PetscFunctionBegin;
1304   ierr = PetscOptionsHead("SysPFMG options");CHKERRQ(ierr);
1305   ierr = PetscOptionsBool("-pc_syspfmg_print_statistics","Print statistics","HYPRE_SStructSysPFMGSetPrintLevel",flg,&flg,NULL);CHKERRQ(ierr);
1306   if (flg) {
1307     int level=3;
1308     PetscStackCallStandard(HYPRE_SStructSysPFMGSetPrintLevel,(ex->ss_solver,level));
1309   }
1310   ierr = PetscOptionsInt("-pc_syspfmg_its","Number of iterations of SysPFMG to use as preconditioner","HYPRE_SStructSysPFMGSetMaxIter",ex->its,&ex->its,NULL);CHKERRQ(ierr);
1311   PetscStackCallStandard(HYPRE_SStructSysPFMGSetMaxIter,(ex->ss_solver,ex->its));
1312   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);
1313   PetscStackCallStandard(HYPRE_SStructSysPFMGSetNumPreRelax,(ex->ss_solver,ex->num_pre_relax));
1314   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);
1315   PetscStackCallStandard(HYPRE_SStructSysPFMGSetNumPostRelax,(ex->ss_solver,ex->num_post_relax));
1316 
1317   ierr = PetscOptionsReal("-pc_syspfmg_tol","Tolerance of SysPFMG","HYPRE_SStructSysPFMGSetTol",ex->tol,&ex->tol,NULL);CHKERRQ(ierr);
1318   PetscStackCallStandard(HYPRE_SStructSysPFMGSetTol,(ex->ss_solver,ex->tol));
1319   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);
1320   PetscStackCallStandard(HYPRE_SStructSysPFMGSetRelaxType,(ex->ss_solver, ex->relax_type));
1321   ierr = PetscOptionsTail();CHKERRQ(ierr);
1322   PetscFunctionReturn(0);
1323 }
1324 
1325 #undef __FUNCT__
1326 #define __FUNCT__ "PCApply_SysPFMG"
1327 PetscErrorCode PCApply_SysPFMG(PC pc,Vec x,Vec y)
1328 {
1329   PetscErrorCode   ierr;
1330   PC_SysPFMG       *ex = (PC_SysPFMG*) pc->data;
1331   PetscScalar      *xx,*yy;
1332   PetscInt         ilower[3],iupper[3];
1333   Mat_HYPRESStruct *mx     = (Mat_HYPRESStruct*)(pc->pmat->data);
1334   PetscInt         ordering= mx->dofs_order;
1335   PetscInt         nvars   = mx->nvars;
1336   PetscInt         part    = 0;
1337   PetscInt         size;
1338   PetscInt         i;
1339 
1340   PetscFunctionBegin;
1341   ierr       = DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]);CHKERRQ(ierr);
1342   iupper[0] += ilower[0] - 1;
1343   iupper[1] += ilower[1] - 1;
1344   iupper[2] += ilower[2] - 1;
1345 
1346   size = 1;
1347   for (i= 0; i< 3; i++) size *= (iupper[i]-ilower[i]+1);
1348 
1349   /* copy x values over to hypre for variable ordering */
1350   if (ordering) {
1351     PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,(mx->ss_b,0.0));
1352     ierr = VecGetArray(x,&xx);CHKERRQ(ierr);
1353     for (i= 0; i< nvars; i++) PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,(mx->ss_b,part,ilower,iupper,i,xx+(size*i)));
1354     ierr = VecRestoreArray(x,&xx);CHKERRQ(ierr);
1355     PetscStackCallStandard(HYPRE_SStructVectorAssemble,(mx->ss_b));
1356     PetscStackCallStandard(HYPRE_SStructMatrixMatvec,(1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x));
1357     PetscStackCallStandard(HYPRE_SStructSysPFMGSolve,(ex->ss_solver,mx->ss_mat,mx->ss_b,mx->ss_x));
1358 
1359     /* copy solution values back to PETSc */
1360     ierr = VecGetArray(y,&yy);CHKERRQ(ierr);
1361     for (i= 0; i< nvars; i++) PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,(mx->ss_x,part,ilower,iupper,i,yy+(size*i)));
1362     ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr);
1363   } else {      /* nodal ordering must be mapped to variable ordering for sys_pfmg */
1364     PetscScalar *z;
1365     PetscInt    j, k;
1366 
1367     ierr = PetscMalloc(nvars*size*sizeof(PetscScalar),&z);CHKERRQ(ierr);
1368     PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,(mx->ss_b,0.0));
1369     ierr = VecGetArray(x,&xx);CHKERRQ(ierr);
1370 
1371     /* transform nodal to hypre's variable ordering for sys_pfmg */
1372     for (i= 0; i< size; i++) {
1373       k= i*nvars;
1374       for (j= 0; j< nvars; j++) z[j*size+i]= xx[k+j];
1375     }
1376     for (i= 0; i< nvars; i++) PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,(mx->ss_b,part,ilower,iupper,i,z+(size*i)));
1377     ierr = VecRestoreArray(x,&xx);CHKERRQ(ierr);
1378     PetscStackCallStandard(HYPRE_SStructVectorAssemble,(mx->ss_b));
1379     PetscStackCallStandard(HYPRE_SStructSysPFMGSolve,(ex->ss_solver,mx->ss_mat,mx->ss_b,mx->ss_x));
1380 
1381     /* copy solution values back to PETSc */
1382     ierr = VecGetArray(y,&yy);CHKERRQ(ierr);
1383     for (i= 0; i< nvars; i++) PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,(mx->ss_x,part,ilower,iupper,i,z+(size*i)));
1384     /* transform hypre's variable ordering for sys_pfmg to nodal ordering */
1385     for (i= 0; i< size; i++) {
1386       k= i*nvars;
1387       for (j= 0; j< nvars; j++) yy[k+j]= z[j*size+i];
1388     }
1389     ierr = VecRestoreArray(y,&yy);CHKERRQ(ierr);
1390     ierr = PetscFree(z);CHKERRQ(ierr);
1391   }
1392   PetscFunctionReturn(0);
1393 }
1394 
1395 #undef __FUNCT__
1396 #define __FUNCT__ "PCApplyRichardson_SysPFMG"
1397 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)
1398 {
1399   PC_SysPFMG     *jac = (PC_SysPFMG*)pc->data;
1400   PetscErrorCode ierr;
1401   PetscInt       oits;
1402 
1403   PetscFunctionBegin;
1404   PetscStackCallStandard(HYPRE_SStructSysPFMGSetMaxIter,(jac->ss_solver,its*jac->its));
1405   PetscStackCallStandard(HYPRE_SStructSysPFMGSetTol,(jac->ss_solver,rtol));
1406   ierr = PCApply_SysPFMG(pc,b,y);CHKERRQ(ierr);
1407   PetscStackCallStandard(HYPRE_SStructSysPFMGGetNumIterations,(jac->ss_solver,&oits));
1408   *outits = oits;
1409   if (oits == its) *reason = PCRICHARDSON_CONVERGED_ITS;
1410   else             *reason = PCRICHARDSON_CONVERGED_RTOL;
1411   PetscStackCallStandard(HYPRE_SStructSysPFMGSetTol,(jac->ss_solver,jac->tol));
1412   PetscStackCallStandard(HYPRE_SStructSysPFMGSetMaxIter,(jac->ss_solver,jac->its));
1413   PetscFunctionReturn(0);
1414 }
1415 
1416 
1417 #undef __FUNCT__
1418 #define __FUNCT__ "PCSetUp_SysPFMG"
1419 PetscErrorCode PCSetUp_SysPFMG(PC pc)
1420 {
1421   PetscErrorCode   ierr;
1422   PC_SysPFMG       *ex = (PC_SysPFMG*) pc->data;
1423   Mat_HYPRESStruct *mx = (Mat_HYPRESStruct*)(pc->pmat->data);
1424   PetscBool        flg;
1425 
1426   PetscFunctionBegin;
1427   ierr = PetscObjectTypeCompare((PetscObject)pc->pmat,MATHYPRESSTRUCT,&flg);CHKERRQ(ierr);
1428   if (!flg) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Must use MATHYPRESSTRUCT with this preconditioner");
1429 
1430   /* create the hypre sstruct solver object and set its information */
1431   if (ex->ss_solver) PetscStackCallStandard(HYPRE_SStructSysPFMGDestroy,(ex->ss_solver));
1432   PetscStackCallStandard(HYPRE_SStructSysPFMGCreate,(ex->hcomm,&ex->ss_solver));
1433   ierr = PCSetFromOptions_SysPFMG(pc);CHKERRQ(ierr);
1434   PetscStackCallStandard(HYPRE_SStructSysPFMGSetZeroGuess,(ex->ss_solver));
1435   PetscStackCallStandard(HYPRE_SStructSysPFMGSetup,(ex->ss_solver,mx->ss_mat,mx->ss_b,mx->ss_x));
1436   PetscFunctionReturn(0);
1437 }
1438 
1439 
1440 /*MC
1441      PCSysPFMG - the hypre SysPFMG multigrid solver
1442 
1443    Level: advanced
1444 
1445    Options Database:
1446 + -pc_syspfmg_its <its> number of iterations of SysPFMG to use as preconditioner
1447 . -pc_syspfmg_num_pre_relax <steps> number of smoothing steps before coarse grid
1448 . -pc_syspfmg_num_post_relax <steps> number of smoothing steps after coarse grid
1449 . -pc_syspfmg_tol <tol> tolerance of SysPFMG
1450 . -pc_syspfmg_relax_type -relaxation type for the up and down cycles, one of Weighted-Jacobi,Red/Black-Gauss-Seidel
1451 
1452    Notes:  This is for CELL-centered descretizations
1453 
1454            This must be used with the MATHYPRESSTRUCT matrix type.
1455            This is less general than in hypre, it supports only one part, and one block per process defined by a PETSc DMDA.
1456            Also, only cell-centered variables.
1457 
1458 .seealso:  PCMG, MATHYPRESSTRUCT
1459 M*/
1460 
1461 EXTERN_C_BEGIN
1462 #undef __FUNCT__
1463 #define __FUNCT__ "PCCreate_SysPFMG"
1464 PetscErrorCode  PCCreate_SysPFMG(PC pc)
1465 {
1466   PetscErrorCode ierr;
1467   PC_SysPFMG     *ex;
1468 
1469   PetscFunctionBegin;
1470   ierr     = PetscNew(PC_SysPFMG,&ex);CHKERRQ(ierr); \
1471   pc->data = ex;
1472 
1473   ex->its            = 1;
1474   ex->tol            = 1.e-8;
1475   ex->relax_type     = 1;
1476   ex->num_pre_relax  = 1;
1477   ex->num_post_relax = 1;
1478 
1479   pc->ops->setfromoptions  = PCSetFromOptions_SysPFMG;
1480   pc->ops->view            = PCView_SysPFMG;
1481   pc->ops->destroy         = PCDestroy_SysPFMG;
1482   pc->ops->apply           = PCApply_SysPFMG;
1483   pc->ops->applyrichardson = PCApplyRichardson_SysPFMG;
1484   pc->ops->setup           = PCSetUp_SysPFMG;
1485 
1486   ierr = MPI_Comm_dup(PetscObjectComm((PetscObject)pc),&(ex->hcomm));CHKERRQ(ierr);
1487   PetscStackCallStandard(HYPRE_SStructSysPFMGCreate,(ex->hcomm,&ex->ss_solver));
1488   PetscFunctionReturn(0);
1489 }
1490 EXTERN_C_END
1491