xref: /petsc/src/ksp/pc/impls/hypre/hypre.c (revision c3b5f7ba6bc5ce25a01a67bb37ba5d34b02bbbd7)
1 /*
2    Provides an interface to the LLNL package hypre
3 */
4 
5 #include <petscpkg_version.h>
6 #include <petsc/private/pcimpl.h>          /*I "petscpc.h" I*/
7 /* this include is needed ONLY to allow access to the private data inside the Mat object specific to hypre */
8 #include <petsc/private/matimpl.h>
9 #include <petsc/private/vecimpl.h>
10 #include <../src/vec/vec/impls/hypre/vhyp.h>
11 #include <../src/mat/impls/hypre/mhypre.h>
12 #include <../src/dm/impls/da/hypre/mhyp.h>
13 #include <_hypre_parcsr_ls.h>
14 #include <petscmathypre.h>
15 
16 #if defined(PETSC_HAVE_HYPRE_DEVICE)
17 #include <petsc/private/deviceimpl.h>
18 #endif
19 
20 static PetscBool cite = PETSC_FALSE;
21 static const char hypreCitation[] = "@manual{hypre-web-page,\n  title  = {{\\sl hypre}: High Performance Preconditioners},\n  organization = {Lawrence Livermore National Laboratory},\n  note  = {\\url{https://computation.llnl.gov/projects/hypre-scalable-linear-solvers-multigrid-methods}}\n}\n";
22 
23 /*
24    Private context (data structure) for the  preconditioner.
25 */
26 typedef struct {
27   HYPRE_Solver   hsolver;
28   Mat            hpmat; /* MatHYPRE */
29 
30   HYPRE_Int (*destroy)(HYPRE_Solver);
31   HYPRE_Int (*solve)(HYPRE_Solver,HYPRE_ParCSRMatrix,HYPRE_ParVector,HYPRE_ParVector);
32   HYPRE_Int (*setup)(HYPRE_Solver,HYPRE_ParCSRMatrix,HYPRE_ParVector,HYPRE_ParVector);
33 
34   MPI_Comm comm_hypre;
35   char     *hypre_type;
36 
37   /* options for Pilut and BoomerAMG*/
38   PetscInt  maxiter;
39   PetscReal tol;
40 
41   /* options for Pilut */
42   PetscInt factorrowsize;
43 
44   /* options for ParaSails */
45   PetscInt  nlevels;
46   PetscReal threshold;
47   PetscReal filter;
48   PetscReal loadbal;
49   PetscInt  logging;
50   PetscInt  ruse;
51   PetscInt  symt;
52 
53   /* options for BoomerAMG */
54   PetscBool printstatistics;
55 
56   /* options for BoomerAMG */
57   PetscInt  cycletype;
58   PetscInt  maxlevels;
59   PetscReal strongthreshold;
60   PetscReal maxrowsum;
61   PetscInt  gridsweeps[3];
62   PetscInt  coarsentype;
63   PetscInt  measuretype;
64   PetscInt  smoothtype;
65   PetscInt  smoothnumlevels;
66   PetscInt  eu_level;   /* Number of levels for ILU(k) in Euclid */
67   PetscReal eu_droptolerance; /* Drop tolerance for ILU(k) in Euclid */
68   PetscInt  eu_bj;      /* Defines use of Block Jacobi ILU in Euclid */
69   PetscInt  relaxtype[3];
70   PetscReal relaxweight;
71   PetscReal outerrelaxweight;
72   PetscInt  relaxorder;
73   PetscReal truncfactor;
74   PetscBool applyrichardson;
75   PetscInt  pmax;
76   PetscInt  interptype;
77   PetscInt  maxc;
78   PetscInt  minc;
79 #if PETSC_PKG_HYPRE_VERSION_GE(2,23,0)
80   char      *spgemm_type; // this is a global hypre parameter but is closely associated with BoomerAMG
81 #endif
82   /* GPU */
83   PetscBool keeptranspose;
84   PetscInt  rap2;
85   PetscInt  mod_rap2;
86 
87   /* AIR */
88   PetscInt  Rtype;
89   PetscReal Rstrongthreshold;
90   PetscReal Rfilterthreshold;
91   PetscInt  Adroptype;
92   PetscReal Adroptol;
93 
94   PetscInt  agg_nl;
95   PetscInt  agg_interptype;
96   PetscInt  agg_num_paths;
97   PetscBool nodal_relax;
98   PetscInt  nodal_relax_levels;
99 
100   PetscInt  nodal_coarsening;
101   PetscInt  nodal_coarsening_diag;
102   PetscInt  vec_interp_variant;
103   PetscInt  vec_interp_qmax;
104   PetscBool vec_interp_smooth;
105   PetscInt  interp_refine;
106 
107   /* NearNullSpace support */
108   VecHYPRE_IJVector *hmnull;
109   HYPRE_ParVector   *phmnull;
110   PetscInt          n_hmnull;
111   Vec               hmnull_constant;
112 
113   /* options for AS (Auxiliary Space preconditioners) */
114   PetscInt  as_print;
115   PetscInt  as_max_iter;
116   PetscReal as_tol;
117   PetscInt  as_relax_type;
118   PetscInt  as_relax_times;
119   PetscReal as_relax_weight;
120   PetscReal as_omega;
121   PetscInt  as_amg_alpha_opts[5]; /* AMG coarsen type, agg_levels, relax_type, interp_type, Pmax for vector Poisson (AMS) or Curl problem (ADS) */
122   PetscReal as_amg_alpha_theta;   /* AMG strength for vector Poisson (AMS) or Curl problem (ADS) */
123   PetscInt  as_amg_beta_opts[5];  /* AMG coarsen type, agg_levels, relax_type, interp_type, Pmax for scalar Poisson (AMS) or vector Poisson (ADS) */
124   PetscReal as_amg_beta_theta;    /* AMG strength for scalar Poisson (AMS) or vector Poisson (ADS)  */
125   PetscInt  ams_cycle_type;
126   PetscInt  ads_cycle_type;
127 
128   /* additional data */
129   Mat G;             /* MatHYPRE */
130   Mat C;             /* MatHYPRE */
131   Mat alpha_Poisson; /* MatHYPRE */
132   Mat beta_Poisson;  /* MatHYPRE */
133 
134   /* extra information for AMS */
135   PetscInt          dim; /* geometrical dimension */
136   VecHYPRE_IJVector coords[3];
137   VecHYPRE_IJVector constants[3];
138   Mat               RT_PiFull, RT_Pi[3];
139   Mat               ND_PiFull, ND_Pi[3];
140   PetscBool         ams_beta_is_zero;
141   PetscBool         ams_beta_is_zero_part;
142   PetscInt          ams_proj_freq;
143 } PC_HYPRE;
144 
145 PetscErrorCode PCHYPREGetSolver(PC pc,HYPRE_Solver *hsolver)
146 {
147   PC_HYPRE *jac = (PC_HYPRE*)pc->data;
148 
149   PetscFunctionBegin;
150   *hsolver = jac->hsolver;
151   PetscFunctionReturn(0);
152 }
153 
154 /*
155   Matrices with AIJ format are created IN PLACE with using (I,J,data) from BoomerAMG. Since the data format in hypre_ParCSRMatrix
156   is different from that used in PETSc, the original hypre_ParCSRMatrix can not be used any more after call this routine.
157   It is used in PCHMG. Other users should avoid using this function.
158 */
159 static PetscErrorCode PCGetCoarseOperators_BoomerAMG(PC pc,PetscInt *nlevels,Mat *operators[])
160 {
161   PC_HYPRE             *jac  = (PC_HYPRE*)pc->data;
162   PetscBool            same = PETSC_FALSE;
163   PetscInt             num_levels,l;
164   Mat                  *mattmp;
165   hypre_ParCSRMatrix   **A_array;
166 
167   PetscFunctionBegin;
168   PetscCall(PetscStrcmp(jac->hypre_type,"boomeramg",&same));
169   PetscCheck(same,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_NOTSAMETYPE,"Hypre type is not BoomerAMG ");
170   num_levels = hypre_ParAMGDataNumLevels((hypre_ParAMGData*) (jac->hsolver));
171   PetscCall(PetscMalloc1(num_levels,&mattmp));
172   A_array    = hypre_ParAMGDataAArray((hypre_ParAMGData*) (jac->hsolver));
173   for (l=1; l<num_levels; l++) {
174     PetscCall(MatCreateFromParCSR(A_array[l],MATAIJ,PETSC_OWN_POINTER, &(mattmp[num_levels-1-l])));
175     /* We want to own the data, and HYPRE can not touch this matrix any more */
176     A_array[l] = NULL;
177   }
178   *nlevels = num_levels;
179   *operators = mattmp;
180   PetscFunctionReturn(0);
181 }
182 
183 /*
184   Matrices with AIJ format are created IN PLACE with using (I,J,data) from BoomerAMG. Since the data format in hypre_ParCSRMatrix
185   is different from that used in PETSc, the original hypre_ParCSRMatrix can not be used any more after call this routine.
186   It is used in PCHMG. Other users should avoid using this function.
187 */
188 static PetscErrorCode PCGetInterpolations_BoomerAMG(PC pc,PetscInt *nlevels,Mat *interpolations[])
189 {
190   PC_HYPRE             *jac  = (PC_HYPRE*)pc->data;
191   PetscBool            same = PETSC_FALSE;
192   PetscInt             num_levels,l;
193   Mat                  *mattmp;
194   hypre_ParCSRMatrix   **P_array;
195 
196   PetscFunctionBegin;
197   PetscCall(PetscStrcmp(jac->hypre_type,"boomeramg",&same));
198   PetscCheck(same,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_NOTSAMETYPE,"Hypre type is not BoomerAMG ");
199   num_levels = hypre_ParAMGDataNumLevels((hypre_ParAMGData*) (jac->hsolver));
200   PetscCall(PetscMalloc1(num_levels,&mattmp));
201   P_array  = hypre_ParAMGDataPArray((hypre_ParAMGData*) (jac->hsolver));
202   for (l=1; l<num_levels; l++) {
203     PetscCall(MatCreateFromParCSR(P_array[num_levels-1-l],MATAIJ,PETSC_OWN_POINTER, &(mattmp[l-1])));
204     /* We want to own the data, and HYPRE can not touch this matrix any more */
205     P_array[num_levels-1-l] = NULL;
206   }
207   *nlevels = num_levels;
208   *interpolations = mattmp;
209   PetscFunctionReturn(0);
210 }
211 
212 /* Resets (frees) Hypre's representation of the near null space */
213 static PetscErrorCode PCHYPREResetNearNullSpace_Private(PC pc)
214 {
215   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
216   PetscInt       i;
217 
218   PetscFunctionBegin;
219   for (i=0; i<jac->n_hmnull; i++) {
220     PetscCall(VecHYPRE_IJVectorDestroy(&jac->hmnull[i]));
221   }
222   PetscCall(PetscFree(jac->hmnull));
223   PetscCall(PetscFree(jac->phmnull));
224   PetscCall(VecDestroy(&jac->hmnull_constant));
225   jac->n_hmnull = 0;
226   PetscFunctionReturn(0);
227 }
228 
229 static PetscErrorCode PCSetUp_HYPRE(PC pc)
230 {
231   PC_HYPRE           *jac = (PC_HYPRE*)pc->data;
232   Mat_HYPRE          *hjac;
233   HYPRE_ParCSRMatrix hmat;
234   HYPRE_ParVector    bv,xv;
235   PetscBool          ishypre;
236 
237   PetscFunctionBegin;
238   if (!jac->hypre_type) {
239     PetscCall(PCHYPRESetType(pc,"boomeramg"));
240   }
241 
242   PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat,MATHYPRE,&ishypre));
243   if (!ishypre) {
244     PetscCall(MatDestroy(&jac->hpmat));
245     PetscCall(MatConvert(pc->pmat,MATHYPRE,MAT_INITIAL_MATRIX,&jac->hpmat));
246     PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)jac->hpmat));
247   } else {
248     PetscCall(PetscObjectReference((PetscObject)pc->pmat));
249     PetscCall(MatDestroy(&jac->hpmat));
250     jac->hpmat = pc->pmat;
251   }
252   /* allow debug */
253   PetscCall(MatViewFromOptions(jac->hpmat,NULL,"-pc_hypre_mat_view"));
254   hjac = (Mat_HYPRE*)(jac->hpmat->data);
255 
256   /* special case for BoomerAMG */
257   if (jac->setup == HYPRE_BoomerAMGSetup) {
258     MatNullSpace mnull;
259     PetscBool    has_const;
260     PetscInt     bs,nvec,i;
261     const Vec    *vecs;
262 
263     PetscCall(MatGetBlockSize(pc->pmat,&bs));
264     if (bs > 1) PetscStackCallStandard(HYPRE_BoomerAMGSetNumFunctions,jac->hsolver,bs);
265     PetscCall(MatGetNearNullSpace(pc->mat, &mnull));
266     if (mnull) {
267       PetscCall(PCHYPREResetNearNullSpace_Private(pc));
268       PetscCall(MatNullSpaceGetVecs(mnull, &has_const, &nvec, &vecs));
269       PetscCall(PetscMalloc1(nvec+1,&jac->hmnull));
270       PetscCall(PetscMalloc1(nvec+1,&jac->phmnull));
271       for (i=0; i<nvec; i++) {
272         PetscCall(VecHYPRE_IJVectorCreate(vecs[i]->map,&jac->hmnull[i]));
273         PetscCall(VecHYPRE_IJVectorCopy(vecs[i],jac->hmnull[i]));
274         PetscStackCallStandard(HYPRE_IJVectorGetObject,jac->hmnull[i]->ij,(void**)&jac->phmnull[i]);
275       }
276       if (has_const) {
277         PetscCall(MatCreateVecs(pc->pmat,&jac->hmnull_constant,NULL));
278         PetscCall(PetscLogObjectParent((PetscObject)pc,(PetscObject)jac->hmnull_constant));
279         PetscCall(VecSet(jac->hmnull_constant,1));
280         PetscCall(VecNormalize(jac->hmnull_constant,NULL));
281         PetscCall(VecHYPRE_IJVectorCreate(jac->hmnull_constant->map,&jac->hmnull[nvec]));
282         PetscCall(VecHYPRE_IJVectorCopy(jac->hmnull_constant,jac->hmnull[nvec]));
283         PetscStackCallStandard(HYPRE_IJVectorGetObject,jac->hmnull[nvec]->ij,(void**)&jac->phmnull[nvec]);
284         nvec++;
285       }
286       PetscStackCallStandard(HYPRE_BoomerAMGSetInterpVectors,jac->hsolver,nvec,jac->phmnull);
287       jac->n_hmnull = nvec;
288     }
289   }
290 
291   /* special case for AMS */
292   if (jac->setup == HYPRE_AMSSetup) {
293     Mat_HYPRE          *hm;
294     HYPRE_ParCSRMatrix parcsr;
295     if (!jac->coords[0] && !jac->constants[0] && !(jac->ND_PiFull || (jac->ND_Pi[0] && jac->ND_Pi[1]))) {
296       SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_USER,"HYPRE AMS preconditioner needs either the coordinate vectors via PCSetCoordinates() or the edge constant vectors via PCHYPRESetEdgeConstantVectors() or the interpolation matrix via PCHYPRESetInterpolations");
297     }
298     if (jac->dim) {
299       PetscStackCallStandard(HYPRE_AMSSetDimension,jac->hsolver,jac->dim);
300     }
301     if (jac->constants[0]) {
302       HYPRE_ParVector ozz,zoz,zzo = NULL;
303       PetscStackCallStandard(HYPRE_IJVectorGetObject,jac->constants[0]->ij,(void**)(&ozz));
304       PetscStackCallStandard(HYPRE_IJVectorGetObject,jac->constants[1]->ij,(void**)(&zoz));
305       if (jac->constants[2]) {
306         PetscStackCallStandard(HYPRE_IJVectorGetObject,jac->constants[2]->ij,(void**)(&zzo));
307       }
308       PetscStackCallStandard(HYPRE_AMSSetEdgeConstantVectors,jac->hsolver,ozz,zoz,zzo);
309     }
310     if (jac->coords[0]) {
311       HYPRE_ParVector coords[3];
312       coords[0] = NULL;
313       coords[1] = NULL;
314       coords[2] = NULL;
315       if (jac->coords[0]) PetscStackCallStandard(HYPRE_IJVectorGetObject,jac->coords[0]->ij,(void**)(&coords[0]));
316       if (jac->coords[1]) PetscStackCallStandard(HYPRE_IJVectorGetObject,jac->coords[1]->ij,(void**)(&coords[1]));
317       if (jac->coords[2]) PetscStackCallStandard(HYPRE_IJVectorGetObject,jac->coords[2]->ij,(void**)(&coords[2]));
318       PetscStackCallStandard(HYPRE_AMSSetCoordinateVectors,jac->hsolver,coords[0],coords[1],coords[2]);
319     }
320     PetscCheck(jac->G,PetscObjectComm((PetscObject)pc),PETSC_ERR_USER,"HYPRE AMS preconditioner needs the discrete gradient operator via PCHYPRESetDiscreteGradient");
321     hm = (Mat_HYPRE*)(jac->G->data);
322     PetscStackCallStandard(HYPRE_IJMatrixGetObject,hm->ij,(void**)(&parcsr));
323     PetscStackCallStandard(HYPRE_AMSSetDiscreteGradient,jac->hsolver,parcsr);
324     if (jac->alpha_Poisson) {
325       hm = (Mat_HYPRE*)(jac->alpha_Poisson->data);
326       PetscStackCallStandard(HYPRE_IJMatrixGetObject,hm->ij,(void**)(&parcsr));
327       PetscStackCallStandard(HYPRE_AMSSetAlphaPoissonMatrix,jac->hsolver,parcsr);
328     }
329     if (jac->ams_beta_is_zero) {
330       PetscStackCallStandard(HYPRE_AMSSetBetaPoissonMatrix,jac->hsolver,NULL);
331     } else if (jac->beta_Poisson) {
332       hm = (Mat_HYPRE*)(jac->beta_Poisson->data);
333       PetscStackCallStandard(HYPRE_IJMatrixGetObject,hm->ij,(void**)(&parcsr));
334       PetscStackCallStandard(HYPRE_AMSSetBetaPoissonMatrix,jac->hsolver,parcsr);
335     }
336     if (jac->ND_PiFull || (jac->ND_Pi[0] && jac->ND_Pi[1])) {
337       PetscInt           i;
338       HYPRE_ParCSRMatrix nd_parcsrfull, nd_parcsr[3];
339       if (jac->ND_PiFull) {
340         hm = (Mat_HYPRE*)(jac->ND_PiFull->data);
341         PetscStackCallStandard(HYPRE_IJMatrixGetObject,hm->ij,(void**)(&nd_parcsrfull));
342       } else {
343         nd_parcsrfull = NULL;
344       }
345       for (i=0;i<3;++i) {
346         if (jac->ND_Pi[i]) {
347           hm = (Mat_HYPRE*)(jac->ND_Pi[i]->data);
348           PetscStackCallStandard(HYPRE_IJMatrixGetObject,hm->ij,(void**)(&nd_parcsr[i]));
349         } else {
350           nd_parcsr[i] = NULL;
351         }
352       }
353       PetscStackCallStandard(HYPRE_AMSSetInterpolations,jac->hsolver,nd_parcsrfull,nd_parcsr[0],nd_parcsr[1],nd_parcsr[2]);
354     }
355   }
356   /* special case for ADS */
357   if (jac->setup == HYPRE_ADSSetup) {
358     Mat_HYPRE          *hm;
359     HYPRE_ParCSRMatrix parcsr;
360     if (!jac->coords[0] && !((jac->RT_PiFull || (jac->RT_Pi[0] && jac->RT_Pi[1])) && (jac->ND_PiFull || (jac->ND_Pi[0] && jac->ND_Pi[1])))) {
361       SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_USER,"HYPRE ADS preconditioner needs either the coordinate vectors via PCSetCoordinates() or the interpolation matrices via PCHYPRESetInterpolations");
362     }
363     else PetscCheck(jac->coords[1] && jac->coords[2],PetscObjectComm((PetscObject)pc),PETSC_ERR_USER,"HYPRE ADS preconditioner has been designed for three dimensional problems! For two dimensional problems, use HYPRE AMS instead");
364     PetscCheck(jac->G,PetscObjectComm((PetscObject)pc),PETSC_ERR_USER,"HYPRE ADS preconditioner needs the discrete gradient operator via PCHYPRESetDiscreteGradient");
365     PetscCheck(jac->C,PetscObjectComm((PetscObject)pc),PETSC_ERR_USER,"HYPRE ADS preconditioner needs the discrete curl operator via PCHYPRESetDiscreteGradient");
366     if (jac->coords[0]) {
367       HYPRE_ParVector coords[3];
368       coords[0] = NULL;
369       coords[1] = NULL;
370       coords[2] = NULL;
371       if (jac->coords[0]) PetscStackCallStandard(HYPRE_IJVectorGetObject,jac->coords[0]->ij,(void**)(&coords[0]));
372       if (jac->coords[1]) PetscStackCallStandard(HYPRE_IJVectorGetObject,jac->coords[1]->ij,(void**)(&coords[1]));
373       if (jac->coords[2]) PetscStackCallStandard(HYPRE_IJVectorGetObject,jac->coords[2]->ij,(void**)(&coords[2]));
374       PetscStackCallStandard(HYPRE_ADSSetCoordinateVectors,jac->hsolver,coords[0],coords[1],coords[2]);
375     }
376     hm = (Mat_HYPRE*)(jac->G->data);
377     PetscStackCallStandard(HYPRE_IJMatrixGetObject,hm->ij,(void**)(&parcsr));
378     PetscStackCallStandard(HYPRE_ADSSetDiscreteGradient,jac->hsolver,parcsr);
379     hm = (Mat_HYPRE*)(jac->C->data);
380     PetscStackCallStandard(HYPRE_IJMatrixGetObject,hm->ij,(void**)(&parcsr));
381     PetscStackCallStandard(HYPRE_ADSSetDiscreteCurl,jac->hsolver,parcsr);
382     if ((jac->RT_PiFull || (jac->RT_Pi[0] && jac->RT_Pi[1])) && (jac->ND_PiFull || (jac->ND_Pi[0] && jac->ND_Pi[1]))) {
383       PetscInt           i;
384       HYPRE_ParCSRMatrix rt_parcsrfull, rt_parcsr[3];
385       HYPRE_ParCSRMatrix nd_parcsrfull, nd_parcsr[3];
386       if (jac->RT_PiFull) {
387         hm = (Mat_HYPRE*)(jac->RT_PiFull->data);
388         PetscStackCallStandard(HYPRE_IJMatrixGetObject,hm->ij,(void**)(&rt_parcsrfull));
389       } else {
390         rt_parcsrfull = NULL;
391       }
392       for (i=0;i<3;++i) {
393         if (jac->RT_Pi[i]) {
394           hm = (Mat_HYPRE*)(jac->RT_Pi[i]->data);
395           PetscStackCallStandard(HYPRE_IJMatrixGetObject,hm->ij,(void**)(&rt_parcsr[i]));
396         } else {
397           rt_parcsr[i] = NULL;
398         }
399       }
400       if (jac->ND_PiFull) {
401         hm = (Mat_HYPRE*)(jac->ND_PiFull->data);
402         PetscStackCallStandard(HYPRE_IJMatrixGetObject,hm->ij,(void**)(&nd_parcsrfull));
403       } else {
404         nd_parcsrfull = NULL;
405       }
406       for (i=0;i<3;++i) {
407         if (jac->ND_Pi[i]) {
408           hm = (Mat_HYPRE*)(jac->ND_Pi[i]->data);
409           PetscStackCallStandard(HYPRE_IJMatrixGetObject,hm->ij,(void**)(&nd_parcsr[i]));
410         } else {
411           nd_parcsr[i] = NULL;
412         }
413       }
414       PetscStackCallStandard(HYPRE_ADSSetInterpolations,jac->hsolver,rt_parcsrfull,rt_parcsr[0],rt_parcsr[1],rt_parcsr[2],nd_parcsrfull,nd_parcsr[0],nd_parcsr[1],nd_parcsr[2]);
415     }
416   }
417   PetscStackCallStandard(HYPRE_IJMatrixGetObject,hjac->ij,(void**)&hmat);
418   PetscStackCallStandard(HYPRE_IJVectorGetObject,hjac->b->ij,(void**)&bv);
419   PetscStackCallStandard(HYPRE_IJVectorGetObject,hjac->x->ij,(void**)&xv);
420   PetscStackCallStandard(jac->setup,jac->hsolver,hmat,bv,xv);
421   PetscFunctionReturn(0);
422 }
423 
424 static PetscErrorCode PCApply_HYPRE(PC pc,Vec b,Vec x)
425 {
426   PC_HYPRE           *jac = (PC_HYPRE*)pc->data;
427   Mat_HYPRE          *hjac = (Mat_HYPRE*)(jac->hpmat->data);
428   HYPRE_ParCSRMatrix hmat;
429   HYPRE_ParVector    jbv,jxv;
430 
431   PetscFunctionBegin;
432   PetscCall(PetscCitationsRegister(hypreCitation,&cite));
433   if (!jac->applyrichardson) PetscCall(VecSet(x,0.0));
434   PetscCall(VecHYPRE_IJVectorPushVecRead(hjac->b,b));
435   if (jac->applyrichardson) PetscCall(VecHYPRE_IJVectorPushVec(hjac->x,x));
436   else PetscCall(VecHYPRE_IJVectorPushVecWrite(hjac->x,x));
437   PetscStackCallStandard(HYPRE_IJMatrixGetObject,hjac->ij,(void**)&hmat);
438   PetscStackCallStandard(HYPRE_IJVectorGetObject,hjac->b->ij,(void**)&jbv);
439   PetscStackCallStandard(HYPRE_IJVectorGetObject,hjac->x->ij,(void**)&jxv);
440   PetscStackCall("Hypre solve",do {
441       HYPRE_Int hierr = (*jac->solve)(jac->hsolver,hmat,jbv,jxv);
442       if (hierr) {
443         PetscCheck(hierr == HYPRE_ERROR_CONV,PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in HYPRE solver, error code %d",(int)hierr);
444         hypre__global_error = 0;
445       }
446     } while (0));
447 
448   if (jac->setup == HYPRE_AMSSetup && jac->ams_beta_is_zero_part) {
449     PetscStackCallStandard(HYPRE_AMSProjectOutGradients,jac->hsolver,jxv);
450   }
451   PetscCall(VecHYPRE_IJVectorPopVec(hjac->x));
452   PetscCall(VecHYPRE_IJVectorPopVec(hjac->b));
453   PetscFunctionReturn(0);
454 }
455 
456 static PetscErrorCode PCReset_HYPRE(PC pc)
457 {
458   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
459 
460   PetscFunctionBegin;
461   PetscCall(MatDestroy(&jac->hpmat));
462   PetscCall(MatDestroy(&jac->G));
463   PetscCall(MatDestroy(&jac->C));
464   PetscCall(MatDestroy(&jac->alpha_Poisson));
465   PetscCall(MatDestroy(&jac->beta_Poisson));
466   PetscCall(MatDestroy(&jac->RT_PiFull));
467   PetscCall(MatDestroy(&jac->RT_Pi[0]));
468   PetscCall(MatDestroy(&jac->RT_Pi[1]));
469   PetscCall(MatDestroy(&jac->RT_Pi[2]));
470   PetscCall(MatDestroy(&jac->ND_PiFull));
471   PetscCall(MatDestroy(&jac->ND_Pi[0]));
472   PetscCall(MatDestroy(&jac->ND_Pi[1]));
473   PetscCall(MatDestroy(&jac->ND_Pi[2]));
474   PetscCall(VecHYPRE_IJVectorDestroy(&jac->coords[0]));
475   PetscCall(VecHYPRE_IJVectorDestroy(&jac->coords[1]));
476   PetscCall(VecHYPRE_IJVectorDestroy(&jac->coords[2]));
477   PetscCall(VecHYPRE_IJVectorDestroy(&jac->constants[0]));
478   PetscCall(VecHYPRE_IJVectorDestroy(&jac->constants[1]));
479   PetscCall(VecHYPRE_IJVectorDestroy(&jac->constants[2]));
480   PetscCall(PCHYPREResetNearNullSpace_Private(pc));
481   jac->ams_beta_is_zero = PETSC_FALSE;
482   jac->dim = 0;
483   PetscFunctionReturn(0);
484 }
485 
486 static PetscErrorCode PCDestroy_HYPRE(PC pc)
487 {
488   PC_HYPRE                 *jac = (PC_HYPRE*)pc->data;
489 
490   PetscFunctionBegin;
491   PetscCall(PCReset_HYPRE(pc));
492   if (jac->destroy) PetscStackCallStandard(jac->destroy,jac->hsolver);
493   PetscCall(PetscFree(jac->hypre_type));
494 #if PETSC_PKG_HYPRE_VERSION_GE(2,23,0)
495   PetscCall(PetscFree(jac->spgemm_type));
496 #endif
497   if (jac->comm_hypre != MPI_COMM_NULL) PetscCall(PetscCommRestoreComm(PetscObjectComm((PetscObject)pc),&jac->comm_hypre));
498   PetscCall(PetscFree(pc->data));
499 
500   PetscCall(PetscObjectChangeTypeName((PetscObject)pc,0));
501   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetType_C",NULL));
502   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPREGetType_C",NULL));
503   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetCoordinates_C",NULL));
504   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetDiscreteGradient_C",NULL));
505   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetDiscreteCurl_C",NULL));
506   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetInterpolations_C",NULL));
507   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetConstantEdgeVectors_C",NULL));
508   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetPoissonMatrix_C",NULL));
509   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCGetInterpolations_C",NULL));
510   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCGetCoarseOperators_C",NULL));
511   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGGalerkinSetMatProductAlgorithm_C",NULL));
512   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGGalerkinGetMatProductAlgorithm_C",NULL));
513 
514   PetscFunctionReturn(0);
515 }
516 
517 /* --------------------------------------------------------------------------------------------*/
518 static PetscErrorCode PCSetFromOptions_HYPRE_Pilut(PetscOptionItems *PetscOptionsObject,PC pc)
519 {
520   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
521   PetscBool      flag;
522 
523   PetscFunctionBegin;
524   PetscCall(PetscOptionsHead(PetscOptionsObject,"HYPRE Pilut Options"));
525   PetscCall(PetscOptionsInt("-pc_hypre_pilut_maxiter","Number of iterations","None",jac->maxiter,&jac->maxiter,&flag));
526   if (flag) PetscStackCallStandard(HYPRE_ParCSRPilutSetMaxIter,jac->hsolver,jac->maxiter);
527   PetscCall(PetscOptionsReal("-pc_hypre_pilut_tol","Drop tolerance","None",jac->tol,&jac->tol,&flag));
528   if (flag) PetscStackCallStandard(HYPRE_ParCSRPilutSetDropTolerance,jac->hsolver,jac->tol);
529   PetscCall(PetscOptionsInt("-pc_hypre_pilut_factorrowsize","FactorRowSize","None",jac->factorrowsize,&jac->factorrowsize,&flag));
530   if (flag) PetscStackCallStandard(HYPRE_ParCSRPilutSetFactorRowSize,jac->hsolver,jac->factorrowsize);
531   PetscCall(PetscOptionsTail());
532   PetscFunctionReturn(0);
533 }
534 
535 static PetscErrorCode PCView_HYPRE_Pilut(PC pc,PetscViewer viewer)
536 {
537   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
538   PetscBool      iascii;
539 
540   PetscFunctionBegin;
541   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
542   if (iascii) {
543     PetscCall(PetscViewerASCIIPrintf(viewer,"  HYPRE Pilut preconditioning\n"));
544     if (jac->maxiter != PETSC_DEFAULT) {
545       PetscCall(PetscViewerASCIIPrintf(viewer,"    maximum number of iterations %d\n",jac->maxiter));
546     } else {
547       PetscCall(PetscViewerASCIIPrintf(viewer,"    default maximum number of iterations \n"));
548     }
549     if (jac->tol != PETSC_DEFAULT) {
550       PetscCall(PetscViewerASCIIPrintf(viewer,"    drop tolerance %g\n",(double)jac->tol));
551     } else {
552       PetscCall(PetscViewerASCIIPrintf(viewer,"    default drop tolerance \n"));
553     }
554     if (jac->factorrowsize != PETSC_DEFAULT) {
555       PetscCall(PetscViewerASCIIPrintf(viewer,"    factor row size %d\n",jac->factorrowsize));
556     } else {
557       PetscCall(PetscViewerASCIIPrintf(viewer,"    default factor row size \n"));
558     }
559   }
560   PetscFunctionReturn(0);
561 }
562 
563 /* --------------------------------------------------------------------------------------------*/
564 static PetscErrorCode PCSetFromOptions_HYPRE_Euclid(PetscOptionItems *PetscOptionsObject,PC pc)
565 {
566   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
567   PetscBool      flag,eu_bj = jac->eu_bj ? PETSC_TRUE : PETSC_FALSE;
568 
569   PetscFunctionBegin;
570   PetscCall(PetscOptionsHead(PetscOptionsObject,"HYPRE Euclid Options"));
571   PetscCall(PetscOptionsInt("-pc_hypre_euclid_level","Factorization levels","None",jac->eu_level,&jac->eu_level,&flag));
572   if (flag) PetscStackCallStandard(HYPRE_EuclidSetLevel,jac->hsolver,jac->eu_level);
573 
574   PetscCall(PetscOptionsReal("-pc_hypre_euclid_droptolerance","Drop tolerance for ILU(k) in Euclid","None",jac->eu_droptolerance,&jac->eu_droptolerance,&flag));
575   if (flag) {
576     PetscMPIInt size;
577 
578     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc),&size));
579     PetscCheck(size == 1,PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"hypre's Euclid does not support a parallel drop tolerance");
580     PetscStackCallStandard(HYPRE_EuclidSetILUT,jac->hsolver,jac->eu_droptolerance);
581   }
582 
583   PetscCall(PetscOptionsBool("-pc_hypre_euclid_bj", "Use Block Jacobi for ILU in Euclid", "None", eu_bj,&eu_bj,&flag));
584   if (flag) {
585     jac->eu_bj = eu_bj ? 1 : 0;
586     PetscStackCallStandard(HYPRE_EuclidSetBJ,jac->hsolver,jac->eu_bj);
587   }
588   PetscCall(PetscOptionsTail());
589   PetscFunctionReturn(0);
590 }
591 
592 static PetscErrorCode PCView_HYPRE_Euclid(PC pc,PetscViewer viewer)
593 {
594   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
595   PetscBool      iascii;
596 
597   PetscFunctionBegin;
598   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
599   if (iascii) {
600     PetscCall(PetscViewerASCIIPrintf(viewer,"  HYPRE Euclid preconditioning\n"));
601     if (jac->eu_level != PETSC_DEFAULT) {
602       PetscCall(PetscViewerASCIIPrintf(viewer,"    factorization levels %d\n",jac->eu_level));
603     } else {
604       PetscCall(PetscViewerASCIIPrintf(viewer,"    default factorization levels \n"));
605     }
606     PetscCall(PetscViewerASCIIPrintf(viewer,"    drop tolerance %g\n",(double)jac->eu_droptolerance));
607     PetscCall(PetscViewerASCIIPrintf(viewer,"    use Block-Jacobi? %D\n",jac->eu_bj));
608   }
609   PetscFunctionReturn(0);
610 }
611 
612 /* --------------------------------------------------------------------------------------------*/
613 
614 static PetscErrorCode PCApplyTranspose_HYPRE_BoomerAMG(PC pc,Vec b,Vec x)
615 {
616   PC_HYPRE           *jac = (PC_HYPRE*)pc->data;
617   Mat_HYPRE          *hjac = (Mat_HYPRE*)(jac->hpmat->data);
618   HYPRE_ParCSRMatrix hmat;
619   HYPRE_ParVector    jbv,jxv;
620 
621   PetscFunctionBegin;
622   PetscCall(PetscCitationsRegister(hypreCitation,&cite));
623   PetscCall(VecSet(x,0.0));
624   PetscCall(VecHYPRE_IJVectorPushVecRead(hjac->x,b));
625   PetscCall(VecHYPRE_IJVectorPushVecWrite(hjac->b,x));
626 
627   PetscStackCallStandard(HYPRE_IJMatrixGetObject,hjac->ij,(void**)&hmat);
628   PetscStackCallStandard(HYPRE_IJVectorGetObject,hjac->b->ij,(void**)&jbv);
629   PetscStackCallStandard(HYPRE_IJVectorGetObject,hjac->x->ij,(void**)&jxv);
630 
631   PetscStackCall("Hypre Transpose solve",do {
632       HYPRE_Int hierr = HYPRE_BoomerAMGSolveT(jac->hsolver,hmat,jbv,jxv);
633       if (hierr) {
634         /* error code of 1 in BoomerAMG merely means convergence not achieved */
635         PetscCheck(hierr == 1,PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in HYPRE solver, error code %d",(int)hierr);
636         hypre__global_error = 0;
637       }
638     } while (0));
639 
640   PetscCall(VecHYPRE_IJVectorPopVec(hjac->x));
641   PetscCall(VecHYPRE_IJVectorPopVec(hjac->b));
642   PetscFunctionReturn(0);
643 }
644 
645 /* static array length */
646 #define ALEN(a) (sizeof(a)/sizeof((a)[0]))
647 
648 static PetscErrorCode PCMGGalerkinSetMatProductAlgorithm_HYPRE_BoomerAMG(PC pc,const char name[])
649 {
650   PC_HYPRE *jac  = (PC_HYPRE*)pc->data;
651   PetscBool      flag;
652 
653 #if PETSC_PKG_HYPRE_VERSION_GE(2,23,0)
654   PetscFunctionBegin;
655   if (jac->spgemm_type) {
656     PetscCall(PetscStrcmp(jac->spgemm_type,name,&flag));
657     PetscCheck(flag,PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Cannot reset the HYPRE SpGEMM (really we can)");
658     PetscFunctionReturn(0);
659   } else {
660     PetscCall(PetscStrallocpy(name, &jac->spgemm_type));
661   }
662   PetscCall(PetscStrcmp("cusparse",jac->spgemm_type,&flag));
663   if (flag) {
664     PetscStackCallStandard(HYPRE_SetSpGemmUseCusparse,1);
665     PetscFunctionReturn(0);
666   }
667   PetscCall(PetscStrcmp("hypre",jac->spgemm_type,&flag));
668   if (flag) {
669     PetscStackCallStandard(HYPRE_SetSpGemmUseCusparse,0);
670     PetscFunctionReturn(0);
671   }
672   jac->spgemm_type = NULL;
673   SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown HYPRE SpGEM type %s; Choices are cusparse, hypre",name);
674 #endif
675 }
676 
677 static PetscErrorCode PCMGGalerkinGetMatProductAlgorithm_HYPRE_BoomerAMG(PC pc, const char *spgemm[])
678 {
679   PC_HYPRE *jac  = (PC_HYPRE*)pc->data;
680 
681   PetscFunctionBegin;
682   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
683 #if PETSC_PKG_HYPRE_VERSION_GE(2,23,0)
684   *spgemm = jac->spgemm_type;
685 #endif
686   PetscFunctionReturn(0);
687 }
688 
689 static const char *HYPREBoomerAMGCycleType[]   = {"","V","W"};
690 static const char *HYPREBoomerAMGCoarsenType[] = {"CLJP","Ruge-Stueben","","modifiedRuge-Stueben","","","Falgout", "", "PMIS", "", "HMIS"};
691 static const char *HYPREBoomerAMGMeasureType[] = {"local","global"};
692 /* The following corresponds to HYPRE_BoomerAMGSetRelaxType which has many missing numbers in the enum */
693 static const char *HYPREBoomerAMGSmoothType[]  = {"Schwarz-smoothers","Pilut","ParaSails","Euclid"};
694 static const char *HYPREBoomerAMGRelaxType[]   = {"Jacobi","sequential-Gauss-Seidel","seqboundary-Gauss-Seidel","SOR/Jacobi","backward-SOR/Jacobi",
695                                                   "" /* [5] hybrid chaotic Gauss-Seidel (works only with OpenMP) */,"symmetric-SOR/Jacobi",
696                                                   "" /* 7 */,"l1scaled-SOR/Jacobi","Gaussian-elimination",
697                                                   "" /* 10 */, "" /* 11 */, "" /* 12 */, "l1-Gauss-Seidel" /* nonsymmetric */, "backward-l1-Gauss-Seidel" /* nonsymmetric */,
698                                                   "CG" /* non-stationary */,"Chebyshev","FCF-Jacobi","l1scaled-Jacobi"};
699 static const char *HYPREBoomerAMGInterpType[]  = {"classical", "", "", "direct", "multipass", "multipass-wts", "ext+i",
700                                                   "ext+i-cc", "standard", "standard-wts", "block", "block-wtd", "FF", "FF1",
701                                                   "ext", "ad-wts", "ext-mm", "ext+i-mm", "ext+e-mm"};
702 static PetscErrorCode PCSetFromOptions_HYPRE_BoomerAMG(PetscOptionItems *PetscOptionsObject,PC pc)
703 {
704   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
705   PetscInt       bs,n,indx,level;
706   PetscBool      flg, tmp_truth;
707   double         tmpdbl, twodbl[2];
708   const char     *symtlist[] = {"nonsymmetric","SPD","nonsymmetric,SPD"};
709   const char     *PCHYPRESpgemmTypes[] = {"cusparse","hypre"};
710 
711   PetscFunctionBegin;
712   PetscCall(PetscOptionsHead(PetscOptionsObject,"HYPRE BoomerAMG Options"));
713   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_cycle_type","Cycle type","None",HYPREBoomerAMGCycleType+1,2,HYPREBoomerAMGCycleType[jac->cycletype],&indx,&flg));
714   if (flg) {
715     jac->cycletype = indx+1;
716     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleType,jac->hsolver,jac->cycletype);
717   }
718   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_max_levels","Number of levels (of grids) allowed","None",jac->maxlevels,&jac->maxlevels,&flg));
719   if (flg) {
720     PetscCheckFalse(jac->maxlevels < 2,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Number of levels %d must be at least two",jac->maxlevels);
721     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxLevels,jac->hsolver,jac->maxlevels);
722   }
723   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_max_iter","Maximum iterations used PER hypre call","None",jac->maxiter,&jac->maxiter,&flg));
724   if (flg) {
725     PetscCheckFalse(jac->maxiter < 1,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Number of iterations %d must be at least one",jac->maxiter);
726     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxIter,jac->hsolver,jac->maxiter);
727   }
728   PetscCall(PetscOptionsReal("-pc_hypre_boomeramg_tol","Convergence tolerance PER hypre call (0.0 = use a fixed number of iterations)","None",jac->tol,&jac->tol,&flg));
729   if (flg) {
730     PetscCheckFalse(jac->tol < 0.0,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Tolerance %g must be greater than or equal to zero",(double)jac->tol);
731     PetscStackCallStandard(HYPRE_BoomerAMGSetTol,jac->hsolver,jac->tol);
732   }
733   bs = 1;
734   if (pc->pmat) {
735     PetscCall(MatGetBlockSize(pc->pmat,&bs));
736   }
737   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_numfunctions","Number of functions","HYPRE_BoomerAMGSetNumFunctions",bs,&bs,&flg));
738   if (flg) {
739     PetscStackCallStandard(HYPRE_BoomerAMGSetNumFunctions,jac->hsolver,bs);
740   }
741 
742   PetscCall(PetscOptionsReal("-pc_hypre_boomeramg_truncfactor","Truncation factor for interpolation (0=no truncation)","None",jac->truncfactor,&jac->truncfactor,&flg));
743   if (flg) {
744     PetscCheckFalse(jac->truncfactor < 0.0,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Truncation factor %g must be great than or equal zero",(double)jac->truncfactor);
745     PetscStackCallStandard(HYPRE_BoomerAMGSetTruncFactor,jac->hsolver,jac->truncfactor);
746   }
747 
748   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_P_max","Max elements per row for interpolation operator (0=unlimited)","None",jac->pmax,&jac->pmax,&flg));
749   if (flg) {
750     PetscCheckFalse(jac->pmax < 0,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"P_max %D must be greater than or equal to zero",jac->pmax);
751     PetscStackCallStandard(HYPRE_BoomerAMGSetPMaxElmts,jac->hsolver,jac->pmax);
752   }
753 
754   PetscCall(PetscOptionsRangeInt("-pc_hypre_boomeramg_agg_nl","Number of levels of aggressive coarsening","None",jac->agg_nl,&jac->agg_nl,&flg,0,jac->maxlevels));
755   if (flg) PetscStackCallStandard(HYPRE_BoomerAMGSetAggNumLevels,jac->hsolver,jac->agg_nl);
756 
757   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_agg_num_paths","Number of paths for aggressive coarsening","None",jac->agg_num_paths,&jac->agg_num_paths,&flg));
758   if (flg) {
759     PetscCheckFalse(jac->agg_num_paths < 1,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Number of paths %D must be greater than or equal to 1",jac->agg_num_paths);
760     PetscStackCallStandard(HYPRE_BoomerAMGSetNumPaths,jac->hsolver,jac->agg_num_paths);
761   }
762 
763   PetscCall(PetscOptionsReal("-pc_hypre_boomeramg_strong_threshold","Threshold for being strongly connected","None",jac->strongthreshold,&jac->strongthreshold,&flg));
764   if (flg) {
765     PetscCheckFalse(jac->strongthreshold < 0.0,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Strong threshold %g must be great than or equal zero",(double)jac->strongthreshold);
766     PetscStackCallStandard(HYPRE_BoomerAMGSetStrongThreshold,jac->hsolver,jac->strongthreshold);
767   }
768   PetscCall(PetscOptionsReal("-pc_hypre_boomeramg_max_row_sum","Maximum row sum","None",jac->maxrowsum,&jac->maxrowsum,&flg));
769   if (flg) {
770     PetscCheckFalse(jac->maxrowsum < 0.0,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Maximum row sum %g must be greater than zero",(double)jac->maxrowsum);
771     PetscCheckFalse(jac->maxrowsum > 1.0,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Maximum row sum %g must be less than or equal one",(double)jac->maxrowsum);
772     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxRowSum,jac->hsolver,jac->maxrowsum);
773   }
774 
775   /* Grid sweeps */
776   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_grid_sweeps_all","Number of sweeps for the up and down grid levels","None",jac->gridsweeps[0],&indx,&flg));
777   if (flg) {
778     PetscStackCallStandard(HYPRE_BoomerAMGSetNumSweeps,jac->hsolver,indx);
779     /* modify the jac structure so we can view the updated options with PC_View */
780     jac->gridsweeps[0] = indx;
781     jac->gridsweeps[1] = indx;
782     /*defaults coarse to 1 */
783     jac->gridsweeps[2] = 1;
784   }
785   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_nodal_coarsen","Use a nodal based coarsening 1-6","HYPRE_BoomerAMGSetNodal",jac->nodal_coarsening,&jac->nodal_coarsening,&flg));
786   if (flg) {
787     PetscStackCallStandard(HYPRE_BoomerAMGSetNodal,jac->hsolver,jac->nodal_coarsening);
788   }
789   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_nodal_coarsen_diag","Diagonal in strength matrix for nodal based coarsening 0-2","HYPRE_BoomerAMGSetNodalDiag",jac->nodal_coarsening_diag,&jac->nodal_coarsening_diag,&flg));
790   if (flg) {
791     PetscStackCallStandard(HYPRE_BoomerAMGSetNodalDiag,jac->hsolver,jac->nodal_coarsening_diag);
792   }
793   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_vec_interp_variant","Variant of algorithm 1-3","HYPRE_BoomerAMGSetInterpVecVariant",jac->vec_interp_variant, &jac->vec_interp_variant,&flg));
794   if (flg) {
795     PetscStackCallStandard(HYPRE_BoomerAMGSetInterpVecVariant,jac->hsolver,jac->vec_interp_variant);
796   }
797   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_vec_interp_qmax","Max elements per row for each Q","HYPRE_BoomerAMGSetInterpVecQMax",jac->vec_interp_qmax, &jac->vec_interp_qmax,&flg));
798   if (flg) {
799     PetscStackCallStandard(HYPRE_BoomerAMGSetInterpVecQMax,jac->hsolver,jac->vec_interp_qmax);
800   }
801   PetscCall(PetscOptionsBool("-pc_hypre_boomeramg_vec_interp_smooth","Whether to smooth the interpolation vectors","HYPRE_BoomerAMGSetSmoothInterpVectors",jac->vec_interp_smooth, &jac->vec_interp_smooth,&flg));
802   if (flg) {
803     PetscStackCallStandard(HYPRE_BoomerAMGSetSmoothInterpVectors,jac->hsolver,jac->vec_interp_smooth);
804   }
805   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_interp_refine","Preprocess the interpolation matrix through iterative weight refinement","HYPRE_BoomerAMGSetInterpRefine",jac->interp_refine, &jac->interp_refine,&flg));
806   if (flg) {
807     PetscStackCallStandard(HYPRE_BoomerAMGSetInterpRefine,jac->hsolver,jac->interp_refine);
808   }
809   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_grid_sweeps_down","Number of sweeps for the down cycles","None",jac->gridsweeps[0], &indx,&flg));
810   if (flg) {
811     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleNumSweeps,jac->hsolver,indx, 1);
812     jac->gridsweeps[0] = indx;
813   }
814   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_grid_sweeps_up","Number of sweeps for the up cycles","None",jac->gridsweeps[1],&indx,&flg));
815   if (flg) {
816     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleNumSweeps,jac->hsolver,indx, 2);
817     jac->gridsweeps[1] = indx;
818   }
819   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_grid_sweeps_coarse","Number of sweeps for the coarse level","None",jac->gridsweeps[2],&indx,&flg));
820   if (flg) {
821     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleNumSweeps,jac->hsolver,indx, 3);
822     jac->gridsweeps[2] = indx;
823   }
824 
825   /* Smooth type */
826   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_smooth_type","Enable more complex smoothers","None",HYPREBoomerAMGSmoothType,ALEN(HYPREBoomerAMGSmoothType),HYPREBoomerAMGSmoothType[0],&indx,&flg));
827   if (flg) {
828     jac->smoothtype = indx;
829     PetscStackCallStandard(HYPRE_BoomerAMGSetSmoothType,jac->hsolver,indx+6);
830     jac->smoothnumlevels = 25;
831     PetscStackCallStandard(HYPRE_BoomerAMGSetSmoothNumLevels,jac->hsolver,25);
832   }
833 
834   /* Number of smoothing levels */
835   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_smooth_num_levels","Number of levels on which more complex smoothers are used","None",25,&indx,&flg));
836   if (flg && (jac->smoothtype != -1)) {
837     jac->smoothnumlevels = indx;
838     PetscStackCallStandard(HYPRE_BoomerAMGSetSmoothNumLevels,jac->hsolver,indx);
839   }
840 
841   /* Number of levels for ILU(k) for Euclid */
842   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_eu_level","Number of levels for ILU(k) in Euclid smoother","None",0,&indx,&flg));
843   if (flg && (jac->smoothtype == 3)) {
844     jac->eu_level = indx;
845     PetscStackCallStandard(HYPRE_BoomerAMGSetEuLevel,jac->hsolver,indx);
846   }
847 
848   /* Filter for ILU(k) for Euclid */
849   double droptolerance;
850   PetscCall(PetscOptionsReal("-pc_hypre_boomeramg_eu_droptolerance","Drop tolerance for ILU(k) in Euclid smoother","None",0,&droptolerance,&flg));
851   if (flg && (jac->smoothtype == 3)) {
852     jac->eu_droptolerance = droptolerance;
853     PetscStackCallStandard(HYPRE_BoomerAMGSetEuLevel,jac->hsolver,droptolerance);
854   }
855 
856   /* Use Block Jacobi ILUT for Euclid */
857   PetscCall(PetscOptionsBool("-pc_hypre_boomeramg_eu_bj", "Use Block Jacobi for ILU in Euclid smoother?", "None", PETSC_FALSE, &tmp_truth, &flg));
858   if (flg && (jac->smoothtype == 3)) {
859     jac->eu_bj = tmp_truth;
860     PetscStackCallStandard(HYPRE_BoomerAMGSetEuBJ,jac->hsolver,jac->eu_bj);
861   }
862 
863   /* Relax type */
864   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_relax_type_all","Relax type for the up and down cycles","None",HYPREBoomerAMGRelaxType,ALEN(HYPREBoomerAMGRelaxType),HYPREBoomerAMGRelaxType[6],&indx,&flg));
865   if (flg) {
866     jac->relaxtype[0] = jac->relaxtype[1]  = indx;
867     PetscStackCallStandard(HYPRE_BoomerAMGSetRelaxType,jac->hsolver, indx);
868     /* by default, coarse type set to 9 */
869     jac->relaxtype[2] = 9;
870     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleRelaxType,jac->hsolver, 9, 3);
871   }
872   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_relax_type_down","Relax type for the down cycles","None",HYPREBoomerAMGRelaxType,ALEN(HYPREBoomerAMGRelaxType),HYPREBoomerAMGRelaxType[6],&indx,&flg));
873   if (flg) {
874     jac->relaxtype[0] = indx;
875     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleRelaxType,jac->hsolver, indx, 1);
876   }
877   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_relax_type_up","Relax type for the up cycles","None",HYPREBoomerAMGRelaxType,ALEN(HYPREBoomerAMGRelaxType),HYPREBoomerAMGRelaxType[6],&indx,&flg));
878   if (flg) {
879     jac->relaxtype[1] = indx;
880     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleRelaxType,jac->hsolver, indx, 2);
881   }
882   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_relax_type_coarse","Relax type on coarse grid","None",HYPREBoomerAMGRelaxType,ALEN(HYPREBoomerAMGRelaxType),HYPREBoomerAMGRelaxType[9],&indx,&flg));
883   if (flg) {
884     jac->relaxtype[2] = indx;
885     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleRelaxType,jac->hsolver, indx, 3);
886   }
887 
888   /* Relaxation Weight */
889   PetscCall(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));
890   if (flg) {
891     PetscStackCallStandard(HYPRE_BoomerAMGSetRelaxWt,jac->hsolver,tmpdbl);
892     jac->relaxweight = tmpdbl;
893   }
894 
895   n         = 2;
896   twodbl[0] = twodbl[1] = 1.0;
897   PetscCall(PetscOptionsRealArray("-pc_hypre_boomeramg_relax_weight_level","Set the relaxation weight for a particular level (weight,level)","None",twodbl, &n, &flg));
898   if (flg) {
899     if (n == 2) {
900       indx =  (int)PetscAbsReal(twodbl[1]);
901       PetscStackCallStandard(HYPRE_BoomerAMGSetLevelRelaxWt,jac->hsolver,twodbl[0],indx);
902     } else SETERRQ(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);
903   }
904 
905   /* Outer relaxation Weight */
906   PetscCall(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));
907   if (flg) {
908     PetscStackCallStandard(HYPRE_BoomerAMGSetOuterWt,jac->hsolver, tmpdbl);
909     jac->outerrelaxweight = tmpdbl;
910   }
911 
912   n         = 2;
913   twodbl[0] = twodbl[1] = 1.0;
914   PetscCall(PetscOptionsRealArray("-pc_hypre_boomeramg_outer_relax_weight_level","Set the outer relaxation weight for a particular level (weight,level)","None",twodbl, &n, &flg));
915   if (flg) {
916     if (n == 2) {
917       indx =  (int)PetscAbsReal(twodbl[1]);
918       PetscStackCallStandard(HYPRE_BoomerAMGSetLevelOuterWt,jac->hsolver, twodbl[0], indx);
919     } else SETERRQ(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);
920   }
921 
922   /* the Relax Order */
923   PetscCall(PetscOptionsBool("-pc_hypre_boomeramg_no_CF", "Do not use CF-relaxation", "None", PETSC_FALSE, &tmp_truth, &flg));
924 
925   if (flg && tmp_truth) {
926     jac->relaxorder = 0;
927     PetscStackCallStandard(HYPRE_BoomerAMGSetRelaxOrder,jac->hsolver, jac->relaxorder);
928   }
929   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_measure_type","Measure type","None",HYPREBoomerAMGMeasureType,ALEN(HYPREBoomerAMGMeasureType),HYPREBoomerAMGMeasureType[0],&indx,&flg));
930   if (flg) {
931     jac->measuretype = indx;
932     PetscStackCallStandard(HYPRE_BoomerAMGSetMeasureType,jac->hsolver,jac->measuretype);
933   }
934   /* update list length 3/07 */
935   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_coarsen_type","Coarsen type","None",HYPREBoomerAMGCoarsenType,ALEN(HYPREBoomerAMGCoarsenType),HYPREBoomerAMGCoarsenType[6],&indx,&flg));
936   if (flg) {
937     jac->coarsentype = indx;
938     PetscStackCallStandard(HYPRE_BoomerAMGSetCoarsenType,jac->hsolver,jac->coarsentype);
939   }
940 
941   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_max_coarse_size", "Maximum size of coarsest grid", "None", jac->maxc, &jac->maxc, &flg));
942   if (flg) {
943     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxCoarseSize,jac->hsolver, jac->maxc);
944   }
945   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_min_coarse_size", "Minimum size of coarsest grid", "None", jac->minc, &jac->minc, &flg));
946   if (flg) {
947     PetscStackCallStandard(HYPRE_BoomerAMGSetMinCoarseSize,jac->hsolver, jac->minc);
948   }
949 #if PETSC_PKG_HYPRE_VERSION_GE(2,23,0)
950   // global parameter but is closely associated with BoomerAMG
951   PetscCall(PetscOptionsEList("-pc_mg_galerkin_mat_product_algorithm","Type of SpGEMM to use in hypre (only for now)","PCMGGalerkinSetMatProductAlgorithm",PCHYPRESpgemmTypes,ALEN(PCHYPRESpgemmTypes),PCHYPRESpgemmTypes[0],&indx,&flg));
952   if (!flg) indx = 0;
953   PetscCall(PCMGGalerkinSetMatProductAlgorithm_HYPRE_BoomerAMG(pc,PCHYPRESpgemmTypes[indx]));
954 #endif
955   /* AIR */
956 #if PETSC_PKG_HYPRE_VERSION_GE(2,18,0)
957   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_restriction_type", "Type of AIR method (distance 1 or 2, 0 means no AIR)", "None", jac->Rtype, &jac->Rtype, NULL));
958   PetscStackCallStandard(HYPRE_BoomerAMGSetRestriction,jac->hsolver,jac->Rtype);
959   if (jac->Rtype) {
960     jac->interptype = 100; /* no way we can pass this with strings... Set it as default as in MFEM, then users can still customize it back to a different one */
961 
962     PetscCall(PetscOptionsReal("-pc_hypre_boomeramg_strongthresholdR","Threshold for R","None",jac->Rstrongthreshold,&jac->Rstrongthreshold,NULL));
963     PetscStackCallStandard(HYPRE_BoomerAMGSetStrongThresholdR,jac->hsolver,jac->Rstrongthreshold);
964 
965     PetscCall(PetscOptionsReal("-pc_hypre_boomeramg_filterthresholdR","Filter threshold for R","None",jac->Rfilterthreshold,&jac->Rfilterthreshold,NULL));
966     PetscStackCallStandard(HYPRE_BoomerAMGSetFilterThresholdR,jac->hsolver,jac->Rfilterthreshold);
967 
968     PetscCall(PetscOptionsReal("-pc_hypre_boomeramg_Adroptol","Defines the drop tolerance for the A-matrices from the 2nd level of AMG","None",jac->Adroptol,&jac->Adroptol,NULL));
969     PetscStackCallStandard(HYPRE_BoomerAMGSetADropTol,jac->hsolver,jac->Adroptol);
970 
971     PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_Adroptype","Drops the entries that are not on the diagonal and smaller than its row norm: type 1: 1-norm, 2: 2-norm, -1: infinity norm","None",jac->Adroptype,&jac->Adroptype,NULL));
972     PetscStackCallStandard(HYPRE_BoomerAMGSetADropType,jac->hsolver,jac->Adroptype);
973   }
974 #endif
975 
976 #if PETSC_PKG_HYPRE_VERSION_LE(9,9,9)
977   PetscCheckFalse(jac->Rtype && jac->agg_nl,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"-pc_hypre_boomeramg_restriction_type (%D) and -pc_hypre_boomeramg_agg_nl (%D)",jac->Rtype,jac->agg_nl);
978 #endif
979 
980   /* new 3/07 */
981   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_interp_type","Interpolation type","None",HYPREBoomerAMGInterpType,ALEN(HYPREBoomerAMGInterpType),HYPREBoomerAMGInterpType[0],&indx,&flg));
982   if (flg || jac->Rtype) {
983     if (flg) jac->interptype = indx;
984     PetscStackCallStandard(HYPRE_BoomerAMGSetInterpType,jac->hsolver,jac->interptype);
985   }
986 
987   PetscCall(PetscOptionsName("-pc_hypre_boomeramg_print_statistics","Print statistics","None",&flg));
988   if (flg) {
989     level = 3;
990     PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_print_statistics","Print statistics","None",level,&level,NULL));
991 
992     jac->printstatistics = PETSC_TRUE;
993     PetscStackCallStandard(HYPRE_BoomerAMGSetPrintLevel,jac->hsolver,level);
994   }
995 
996   PetscCall(PetscOptionsName("-pc_hypre_boomeramg_print_debug","Print debug information","None",&flg));
997   if (flg) {
998     level = 3;
999     PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_print_debug","Print debug information","None",level,&level,NULL));
1000 
1001     jac->printstatistics = PETSC_TRUE;
1002     PetscStackCallStandard(HYPRE_BoomerAMGSetDebugFlag,jac->hsolver,level);
1003   }
1004 
1005   PetscCall(PetscOptionsBool("-pc_hypre_boomeramg_nodal_relaxation", "Nodal relaxation via Schwarz", "None", PETSC_FALSE, &tmp_truth, &flg));
1006   if (flg && tmp_truth) {
1007     PetscInt tmp_int;
1008     PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_nodal_relaxation", "Nodal relaxation via Schwarz", "None",jac->nodal_relax_levels,&tmp_int,&flg));
1009     if (flg) jac->nodal_relax_levels = tmp_int;
1010     PetscStackCallStandard(HYPRE_BoomerAMGSetSmoothType,jac->hsolver,6);
1011     PetscStackCallStandard(HYPRE_BoomerAMGSetDomainType,jac->hsolver,1);
1012     PetscStackCallStandard(HYPRE_BoomerAMGSetOverlap,jac->hsolver,0);
1013     PetscStackCallStandard(HYPRE_BoomerAMGSetSmoothNumLevels,jac->hsolver,jac->nodal_relax_levels);
1014   }
1015 
1016   PetscCall(PetscOptionsBool("-pc_hypre_boomeramg_keeptranspose", "Avoid transpose matvecs in preconditioner application", "None", jac->keeptranspose, &jac->keeptranspose, NULL));
1017   PetscStackCallStandard(HYPRE_BoomerAMGSetKeepTranspose,jac->hsolver,jac->keeptranspose ? 1 : 0);
1018 
1019   /* options for ParaSails solvers */
1020   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_parasails_sym","Symmetry of matrix and preconditioner","None",symtlist,ALEN(symtlist),symtlist[0],&indx,&flg));
1021   if (flg) {
1022     jac->symt = indx;
1023     PetscStackCallStandard(HYPRE_BoomerAMGSetSym,jac->hsolver,jac->symt);
1024   }
1025 
1026   PetscCall(PetscOptionsTail());
1027   PetscFunctionReturn(0);
1028 }
1029 
1030 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)
1031 {
1032   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1033   HYPRE_Int      oits;
1034 
1035   PetscFunctionBegin;
1036   PetscCall(PetscCitationsRegister(hypreCitation,&cite));
1037   PetscStackCallStandard(HYPRE_BoomerAMGSetMaxIter,jac->hsolver,its*jac->maxiter);
1038   PetscStackCallStandard(HYPRE_BoomerAMGSetTol,jac->hsolver,rtol);
1039   jac->applyrichardson = PETSC_TRUE;
1040   PetscCall(PCApply_HYPRE(pc,b,y));
1041   jac->applyrichardson = PETSC_FALSE;
1042   PetscStackCallStandard(HYPRE_BoomerAMGGetNumIterations,jac->hsolver,&oits);
1043   *outits = oits;
1044   if (oits == its) *reason = PCRICHARDSON_CONVERGED_ITS;
1045   else             *reason = PCRICHARDSON_CONVERGED_RTOL;
1046   PetscStackCallStandard(HYPRE_BoomerAMGSetTol,jac->hsolver,jac->tol);
1047   PetscStackCallStandard(HYPRE_BoomerAMGSetMaxIter,jac->hsolver,jac->maxiter);
1048   PetscFunctionReturn(0);
1049 }
1050 
1051 static PetscErrorCode PCView_HYPRE_BoomerAMG(PC pc,PetscViewer viewer)
1052 {
1053   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1054   PetscBool      iascii;
1055 
1056   PetscFunctionBegin;
1057   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
1058   if (iascii) {
1059     PetscCall(PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG preconditioning\n"));
1060     PetscCall(PetscViewerASCIIPrintf(viewer,"    Cycle type %s\n",HYPREBoomerAMGCycleType[jac->cycletype]));
1061     PetscCall(PetscViewerASCIIPrintf(viewer,"    Maximum number of levels %D\n",jac->maxlevels));
1062     PetscCall(PetscViewerASCIIPrintf(viewer,"    Maximum number of iterations PER hypre call %D\n",jac->maxiter));
1063     PetscCall(PetscViewerASCIIPrintf(viewer,"    Convergence tolerance PER hypre call %g\n",(double)jac->tol));
1064     PetscCall(PetscViewerASCIIPrintf(viewer,"    Threshold for strong coupling %g\n",(double)jac->strongthreshold));
1065     PetscCall(PetscViewerASCIIPrintf(viewer,"    Interpolation truncation factor %g\n",(double)jac->truncfactor));
1066     PetscCall(PetscViewerASCIIPrintf(viewer,"    Interpolation: max elements per row %D\n",jac->pmax));
1067     if (jac->interp_refine) {
1068       PetscCall(PetscViewerASCIIPrintf(viewer,"    Interpolation: number of steps of weighted refinement %D\n",jac->interp_refine));
1069     }
1070     PetscCall(PetscViewerASCIIPrintf(viewer,"    Number of levels of aggressive coarsening %D\n",jac->agg_nl));
1071     PetscCall(PetscViewerASCIIPrintf(viewer,"    Number of paths for aggressive coarsening %D\n",jac->agg_num_paths));
1072 
1073     PetscCall(PetscViewerASCIIPrintf(viewer,"    Maximum row sums %g\n",(double)jac->maxrowsum));
1074 
1075     PetscCall(PetscViewerASCIIPrintf(viewer,"    Sweeps down         %D\n",jac->gridsweeps[0]));
1076     PetscCall(PetscViewerASCIIPrintf(viewer,"    Sweeps up           %D\n",jac->gridsweeps[1]));
1077     PetscCall(PetscViewerASCIIPrintf(viewer,"    Sweeps on coarse    %D\n",jac->gridsweeps[2]));
1078 
1079     PetscCall(PetscViewerASCIIPrintf(viewer,"    Relax down          %s\n",HYPREBoomerAMGRelaxType[jac->relaxtype[0]]));
1080     PetscCall(PetscViewerASCIIPrintf(viewer,"    Relax up            %s\n",HYPREBoomerAMGRelaxType[jac->relaxtype[1]]));
1081     PetscCall(PetscViewerASCIIPrintf(viewer,"    Relax on coarse     %s\n",HYPREBoomerAMGRelaxType[jac->relaxtype[2]]));
1082 
1083     PetscCall(PetscViewerASCIIPrintf(viewer,"    Relax weight  (all)      %g\n",(double)jac->relaxweight));
1084     PetscCall(PetscViewerASCIIPrintf(viewer,"    Outer relax weight (all) %g\n",(double)jac->outerrelaxweight));
1085 
1086     if (jac->relaxorder) {
1087       PetscCall(PetscViewerASCIIPrintf(viewer,"    Using CF-relaxation\n"));
1088     } else {
1089       PetscCall(PetscViewerASCIIPrintf(viewer,"    Not using CF-relaxation\n"));
1090     }
1091     if (jac->smoothtype!=-1) {
1092       PetscCall(PetscViewerASCIIPrintf(viewer,"    Smooth type          %s\n",HYPREBoomerAMGSmoothType[jac->smoothtype]));
1093       PetscCall(PetscViewerASCIIPrintf(viewer,"    Smooth num levels    %D\n",jac->smoothnumlevels));
1094     } else {
1095       PetscCall(PetscViewerASCIIPrintf(viewer,"    Not using more complex smoothers.\n"));
1096     }
1097     if (jac->smoothtype==3) {
1098       PetscCall(PetscViewerASCIIPrintf(viewer,"    Euclid ILU(k) levels %D\n",jac->eu_level));
1099       PetscCall(PetscViewerASCIIPrintf(viewer,"    Euclid ILU(k) drop tolerance %g\n",(double)jac->eu_droptolerance));
1100       PetscCall(PetscViewerASCIIPrintf(viewer,"    Euclid ILU use Block-Jacobi? %D\n",jac->eu_bj));
1101     }
1102     PetscCall(PetscViewerASCIIPrintf(viewer,"    Measure type        %s\n",HYPREBoomerAMGMeasureType[jac->measuretype]));
1103     PetscCall(PetscViewerASCIIPrintf(viewer,"    Coarsen type        %s\n",HYPREBoomerAMGCoarsenType[jac->coarsentype]));
1104     PetscCall(PetscViewerASCIIPrintf(viewer,"    Interpolation type  %s\n",jac->interptype != 100 ? HYPREBoomerAMGInterpType[jac->interptype] : "1pt"));
1105     if (jac->nodal_coarsening) {
1106       PetscCall(PetscViewerASCIIPrintf(viewer,"    Using nodal coarsening with HYPRE_BOOMERAMGSetNodal() %D\n",jac->nodal_coarsening));
1107     }
1108     if (jac->vec_interp_variant) {
1109       PetscCall(PetscViewerASCIIPrintf(viewer,"    HYPRE_BoomerAMGSetInterpVecVariant() %D\n",jac->vec_interp_variant));
1110       PetscCall(PetscViewerASCIIPrintf(viewer,"    HYPRE_BoomerAMGSetInterpVecQMax() %D\n",jac->vec_interp_qmax));
1111       PetscCall(PetscViewerASCIIPrintf(viewer,"    HYPRE_BoomerAMGSetSmoothInterpVectors() %d\n",jac->vec_interp_smooth));
1112     }
1113     if (jac->nodal_relax) {
1114       PetscCall(PetscViewerASCIIPrintf(viewer,"    Using nodal relaxation via Schwarz smoothing on levels %D\n",jac->nodal_relax_levels));
1115     }
1116 #if PETSC_PKG_HYPRE_VERSION_GE(2,23,0)
1117     PetscCall(PetscViewerASCIIPrintf(viewer,"    SpGEMM type         %s\n",jac->spgemm_type));
1118 #endif
1119     /* AIR */
1120     if (jac->Rtype) {
1121       PetscCall(PetscViewerASCIIPrintf(viewer,"    Using approximate ideal restriction type %D\n",jac->Rtype));
1122       PetscCall(PetscViewerASCIIPrintf(viewer,"      Threshold for R %g\n",(double)jac->Rstrongthreshold));
1123       PetscCall(PetscViewerASCIIPrintf(viewer,"      Filter for R %g\n",(double)jac->Rfilterthreshold));
1124       PetscCall(PetscViewerASCIIPrintf(viewer,"      A drop tolerance %g\n",(double)jac->Adroptol));
1125       PetscCall(PetscViewerASCIIPrintf(viewer,"      A drop type %D\n",jac->Adroptype));
1126     }
1127   }
1128   PetscFunctionReturn(0);
1129 }
1130 
1131 /* --------------------------------------------------------------------------------------------*/
1132 static PetscErrorCode PCSetFromOptions_HYPRE_ParaSails(PetscOptionItems *PetscOptionsObject,PC pc)
1133 {
1134   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1135   PetscInt       indx;
1136   PetscBool      flag;
1137   const char     *symtlist[] = {"nonsymmetric","SPD","nonsymmetric,SPD"};
1138 
1139   PetscFunctionBegin;
1140   PetscCall(PetscOptionsHead(PetscOptionsObject,"HYPRE ParaSails Options"));
1141   PetscCall(PetscOptionsInt("-pc_hypre_parasails_nlevels","Number of number of levels","None",jac->nlevels,&jac->nlevels,0));
1142   PetscCall(PetscOptionsReal("-pc_hypre_parasails_thresh","Threshold","None",jac->threshold,&jac->threshold,&flag));
1143   if (flag) PetscStackCallStandard(HYPRE_ParaSailsSetParams,jac->hsolver,jac->threshold,jac->nlevels);
1144 
1145   PetscCall(PetscOptionsReal("-pc_hypre_parasails_filter","filter","None",jac->filter,&jac->filter,&flag));
1146   if (flag) PetscStackCallStandard(HYPRE_ParaSailsSetFilter,jac->hsolver,jac->filter);
1147 
1148   PetscCall(PetscOptionsReal("-pc_hypre_parasails_loadbal","Load balance","None",jac->loadbal,&jac->loadbal,&flag));
1149   if (flag) PetscStackCallStandard(HYPRE_ParaSailsSetLoadbal,jac->hsolver,jac->loadbal);
1150 
1151   PetscCall(PetscOptionsBool("-pc_hypre_parasails_logging","Print info to screen","None",(PetscBool)jac->logging,(PetscBool*)&jac->logging,&flag));
1152   if (flag) PetscStackCallStandard(HYPRE_ParaSailsSetLogging,jac->hsolver,jac->logging);
1153 
1154   PetscCall(PetscOptionsBool("-pc_hypre_parasails_reuse","Reuse nonzero pattern in preconditioner","None",(PetscBool)jac->ruse,(PetscBool*)&jac->ruse,&flag));
1155   if (flag) PetscStackCallStandard(HYPRE_ParaSailsSetReuse,jac->hsolver,jac->ruse);
1156 
1157   PetscCall(PetscOptionsEList("-pc_hypre_parasails_sym","Symmetry of matrix and preconditioner","None",symtlist,ALEN(symtlist),symtlist[0],&indx,&flag));
1158   if (flag) {
1159     jac->symt = indx;
1160     PetscStackCallStandard(HYPRE_ParaSailsSetSym,jac->hsolver,jac->symt);
1161   }
1162 
1163   PetscCall(PetscOptionsTail());
1164   PetscFunctionReturn(0);
1165 }
1166 
1167 static PetscErrorCode PCView_HYPRE_ParaSails(PC pc,PetscViewer viewer)
1168 {
1169   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1170   PetscBool      iascii;
1171   const char     *symt = 0;
1172 
1173   PetscFunctionBegin;
1174   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
1175   if (iascii) {
1176     PetscCall(PetscViewerASCIIPrintf(viewer,"  HYPRE ParaSails preconditioning\n"));
1177     PetscCall(PetscViewerASCIIPrintf(viewer,"    nlevels %d\n",jac->nlevels));
1178     PetscCall(PetscViewerASCIIPrintf(viewer,"    threshold %g\n",(double)jac->threshold));
1179     PetscCall(PetscViewerASCIIPrintf(viewer,"    filter %g\n",(double)jac->filter));
1180     PetscCall(PetscViewerASCIIPrintf(viewer,"    load balance %g\n",(double)jac->loadbal));
1181     PetscCall(PetscViewerASCIIPrintf(viewer,"    reuse nonzero structure %s\n",PetscBools[jac->ruse]));
1182     PetscCall(PetscViewerASCIIPrintf(viewer,"    print info to screen %s\n",PetscBools[jac->logging]));
1183     if (!jac->symt) symt = "nonsymmetric matrix and preconditioner";
1184     else if (jac->symt == 1) symt = "SPD matrix and preconditioner";
1185     else if (jac->symt == 2) symt = "nonsymmetric matrix but SPD preconditioner";
1186     else SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONG,"Unknown HYPRE ParaSails symmetric option %d",jac->symt);
1187     PetscCall(PetscViewerASCIIPrintf(viewer,"    %s\n",symt));
1188   }
1189   PetscFunctionReturn(0);
1190 }
1191 /* --------------------------------------------------------------------------------------------*/
1192 static PetscErrorCode PCSetFromOptions_HYPRE_AMS(PetscOptionItems *PetscOptionsObject,PC pc)
1193 {
1194   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1195   PetscInt       n;
1196   PetscBool      flag,flag2,flag3,flag4;
1197 
1198   PetscFunctionBegin;
1199   PetscCall(PetscOptionsHead(PetscOptionsObject,"HYPRE AMS Options"));
1200   PetscCall(PetscOptionsInt("-pc_hypre_ams_print_level","Debugging output level for AMS","None",jac->as_print,&jac->as_print,&flag));
1201   if (flag) PetscStackCallStandard(HYPRE_AMSSetPrintLevel,jac->hsolver,jac->as_print);
1202   PetscCall(PetscOptionsInt("-pc_hypre_ams_max_iter","Maximum number of AMS multigrid iterations within PCApply","None",jac->as_max_iter,&jac->as_max_iter,&flag));
1203   if (flag) PetscStackCallStandard(HYPRE_AMSSetMaxIter,jac->hsolver,jac->as_max_iter);
1204   PetscCall(PetscOptionsInt("-pc_hypre_ams_cycle_type","Cycle type for AMS multigrid","None",jac->ams_cycle_type,&jac->ams_cycle_type,&flag));
1205   if (flag) PetscStackCallStandard(HYPRE_AMSSetCycleType,jac->hsolver,jac->ams_cycle_type);
1206   PetscCall(PetscOptionsReal("-pc_hypre_ams_tol","Error tolerance for AMS multigrid","None",jac->as_tol,&jac->as_tol,&flag));
1207   if (flag) PetscStackCallStandard(HYPRE_AMSSetTol,jac->hsolver,jac->as_tol);
1208   PetscCall(PetscOptionsInt("-pc_hypre_ams_relax_type","Relaxation type for AMS smoother","None",jac->as_relax_type,&jac->as_relax_type,&flag));
1209   PetscCall(PetscOptionsInt("-pc_hypre_ams_relax_times","Number of relaxation steps for AMS smoother","None",jac->as_relax_times,&jac->as_relax_times,&flag2));
1210   PetscCall(PetscOptionsReal("-pc_hypre_ams_relax_weight","Relaxation weight for AMS smoother","None",jac->as_relax_weight,&jac->as_relax_weight,&flag3));
1211   PetscCall(PetscOptionsReal("-pc_hypre_ams_omega","SSOR coefficient for AMS smoother","None",jac->as_omega,&jac->as_omega,&flag4));
1212   if (flag || flag2 || flag3 || flag4) {
1213     PetscStackCallStandard(HYPRE_AMSSetSmoothingOptions,jac->hsolver,jac->as_relax_type,
1214                                                                       jac->as_relax_times,
1215                                                                       jac->as_relax_weight,
1216                                                                       jac->as_omega);
1217   }
1218   PetscCall(PetscOptionsReal("-pc_hypre_ams_amg_alpha_theta","Threshold for strong coupling of vector Poisson AMG solver","None",jac->as_amg_alpha_theta,&jac->as_amg_alpha_theta,&flag));
1219   n = 5;
1220   PetscCall(PetscOptionsIntArray("-pc_hypre_ams_amg_alpha_options","AMG options for vector Poisson","None",jac->as_amg_alpha_opts,&n,&flag2));
1221   if (flag || flag2) {
1222     PetscStackCallStandard(HYPRE_AMSSetAlphaAMGOptions,jac->hsolver,jac->as_amg_alpha_opts[0],       /* AMG coarsen type */
1223                                                                      jac->as_amg_alpha_opts[1],       /* AMG agg_levels */
1224                                                                      jac->as_amg_alpha_opts[2],       /* AMG relax_type */
1225                                                                      jac->as_amg_alpha_theta,
1226                                                                      jac->as_amg_alpha_opts[3],       /* AMG interp_type */
1227                                                                      jac->as_amg_alpha_opts[4]);     /* AMG Pmax */
1228   }
1229   PetscCall(PetscOptionsReal("-pc_hypre_ams_amg_beta_theta","Threshold for strong coupling of scalar Poisson AMG solver","None",jac->as_amg_beta_theta,&jac->as_amg_beta_theta,&flag));
1230   n = 5;
1231   PetscCall(PetscOptionsIntArray("-pc_hypre_ams_amg_beta_options","AMG options for scalar Poisson solver","None",jac->as_amg_beta_opts,&n,&flag2));
1232   if (flag || flag2) {
1233     PetscStackCallStandard(HYPRE_AMSSetBetaAMGOptions,jac->hsolver,jac->as_amg_beta_opts[0],       /* AMG coarsen type */
1234                                                                     jac->as_amg_beta_opts[1],       /* AMG agg_levels */
1235                                                                     jac->as_amg_beta_opts[2],       /* AMG relax_type */
1236                                                                     jac->as_amg_beta_theta,
1237                                                                     jac->as_amg_beta_opts[3],       /* AMG interp_type */
1238                                                                     jac->as_amg_beta_opts[4]);     /* AMG Pmax */
1239   }
1240   PetscCall(PetscOptionsInt("-pc_hypre_ams_projection_frequency","Frequency at which a projection onto the compatible subspace for problems with zero conductivity regions is performed","None",jac->ams_proj_freq,&jac->ams_proj_freq,&flag));
1241   if (flag) { /* override HYPRE's default only if the options is used */
1242     PetscStackCallStandard(HYPRE_AMSSetProjectionFrequency,jac->hsolver,jac->ams_proj_freq);
1243   }
1244   PetscCall(PetscOptionsTail());
1245   PetscFunctionReturn(0);
1246 }
1247 
1248 static PetscErrorCode PCView_HYPRE_AMS(PC pc,PetscViewer viewer)
1249 {
1250   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1251   PetscBool      iascii;
1252 
1253   PetscFunctionBegin;
1254   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
1255   if (iascii) {
1256     PetscCall(PetscViewerASCIIPrintf(viewer,"  HYPRE AMS preconditioning\n"));
1257     PetscCall(PetscViewerASCIIPrintf(viewer,"    subspace iterations per application %d\n",jac->as_max_iter));
1258     PetscCall(PetscViewerASCIIPrintf(viewer,"    subspace cycle type %d\n",jac->ams_cycle_type));
1259     PetscCall(PetscViewerASCIIPrintf(viewer,"    subspace iteration tolerance %g\n",jac->as_tol));
1260     PetscCall(PetscViewerASCIIPrintf(viewer,"    smoother type %d\n",jac->as_relax_type));
1261     PetscCall(PetscViewerASCIIPrintf(viewer,"    number of smoothing steps %d\n",jac->as_relax_times));
1262     PetscCall(PetscViewerASCIIPrintf(viewer,"    smoother weight %g\n",jac->as_relax_weight));
1263     PetscCall(PetscViewerASCIIPrintf(viewer,"    smoother omega %g\n",jac->as_omega));
1264     if (jac->alpha_Poisson) {
1265       PetscCall(PetscViewerASCIIPrintf(viewer,"    vector Poisson solver (passed in by user)\n"));
1266     } else {
1267       PetscCall(PetscViewerASCIIPrintf(viewer,"    vector Poisson solver (computed) \n"));
1268     }
1269     PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG coarsening type %d\n",jac->as_amg_alpha_opts[0]));
1270     PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG levels of aggressive coarsening %d\n",jac->as_amg_alpha_opts[1]));
1271     PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG relaxation type %d\n",jac->as_amg_alpha_opts[2]));
1272     PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG interpolation type %d\n",jac->as_amg_alpha_opts[3]));
1273     PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG max nonzero elements in interpolation rows %d\n",jac->as_amg_alpha_opts[4]));
1274     PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG strength threshold %g\n",jac->as_amg_alpha_theta));
1275     if (!jac->ams_beta_is_zero) {
1276       if (jac->beta_Poisson) {
1277         PetscCall(PetscViewerASCIIPrintf(viewer,"    scalar Poisson solver (passed in by user)\n"));
1278       } else {
1279         PetscCall(PetscViewerASCIIPrintf(viewer,"    scalar Poisson solver (computed) \n"));
1280       }
1281       PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG coarsening type %d\n",jac->as_amg_beta_opts[0]));
1282       PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG levels of aggressive coarsening %d\n",jac->as_amg_beta_opts[1]));
1283       PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG relaxation type %d\n",jac->as_amg_beta_opts[2]));
1284       PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG interpolation type %d\n",jac->as_amg_beta_opts[3]));
1285       PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG max nonzero elements in interpolation rows %d\n",jac->as_amg_beta_opts[4]));
1286       PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG strength threshold %g\n",jac->as_amg_beta_theta));
1287       if (jac->ams_beta_is_zero_part) {
1288         PetscCall(PetscViewerASCIIPrintf(viewer,"        compatible subspace projection frequency %d (-1 HYPRE uses default)\n",jac->ams_proj_freq));
1289       }
1290     } else {
1291       PetscCall(PetscViewerASCIIPrintf(viewer,"    scalar Poisson solver not used (zero-conductivity everywhere) \n"));
1292     }
1293   }
1294   PetscFunctionReturn(0);
1295 }
1296 
1297 static PetscErrorCode PCSetFromOptions_HYPRE_ADS(PetscOptionItems *PetscOptionsObject,PC pc)
1298 {
1299   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1300   PetscInt       n;
1301   PetscBool      flag,flag2,flag3,flag4;
1302 
1303   PetscFunctionBegin;
1304   PetscCall(PetscOptionsHead(PetscOptionsObject,"HYPRE ADS Options"));
1305   PetscCall(PetscOptionsInt("-pc_hypre_ads_print_level","Debugging output level for ADS","None",jac->as_print,&jac->as_print,&flag));
1306   if (flag) PetscStackCallStandard(HYPRE_ADSSetPrintLevel,jac->hsolver,jac->as_print);
1307   PetscCall(PetscOptionsInt("-pc_hypre_ads_max_iter","Maximum number of ADS multigrid iterations within PCApply","None",jac->as_max_iter,&jac->as_max_iter,&flag));
1308   if (flag) PetscStackCallStandard(HYPRE_ADSSetMaxIter,jac->hsolver,jac->as_max_iter);
1309   PetscCall(PetscOptionsInt("-pc_hypre_ads_cycle_type","Cycle type for ADS multigrid","None",jac->ads_cycle_type,&jac->ads_cycle_type,&flag));
1310   if (flag) PetscStackCallStandard(HYPRE_ADSSetCycleType,jac->hsolver,jac->ads_cycle_type);
1311   PetscCall(PetscOptionsReal("-pc_hypre_ads_tol","Error tolerance for ADS multigrid","None",jac->as_tol,&jac->as_tol,&flag));
1312   if (flag) PetscStackCallStandard(HYPRE_ADSSetTol,jac->hsolver,jac->as_tol);
1313   PetscCall(PetscOptionsInt("-pc_hypre_ads_relax_type","Relaxation type for ADS smoother","None",jac->as_relax_type,&jac->as_relax_type,&flag));
1314   PetscCall(PetscOptionsInt("-pc_hypre_ads_relax_times","Number of relaxation steps for ADS smoother","None",jac->as_relax_times,&jac->as_relax_times,&flag2));
1315   PetscCall(PetscOptionsReal("-pc_hypre_ads_relax_weight","Relaxation weight for ADS smoother","None",jac->as_relax_weight,&jac->as_relax_weight,&flag3));
1316   PetscCall(PetscOptionsReal("-pc_hypre_ads_omega","SSOR coefficient for ADS smoother","None",jac->as_omega,&jac->as_omega,&flag4));
1317   if (flag || flag2 || flag3 || flag4) {
1318     PetscStackCallStandard(HYPRE_ADSSetSmoothingOptions,jac->hsolver,jac->as_relax_type,
1319                                                                       jac->as_relax_times,
1320                                                                       jac->as_relax_weight,
1321                                                                       jac->as_omega);
1322   }
1323   PetscCall(PetscOptionsReal("-pc_hypre_ads_ams_theta","Threshold for strong coupling of AMS solver inside ADS","None",jac->as_amg_alpha_theta,&jac->as_amg_alpha_theta,&flag));
1324   n = 5;
1325   PetscCall(PetscOptionsIntArray("-pc_hypre_ads_ams_options","AMG options for AMS solver inside ADS","None",jac->as_amg_alpha_opts,&n,&flag2));
1326   PetscCall(PetscOptionsInt("-pc_hypre_ads_ams_cycle_type","Cycle type for AMS solver inside ADS","None",jac->ams_cycle_type,&jac->ams_cycle_type,&flag3));
1327   if (flag || flag2 || flag3) {
1328     PetscStackCallStandard(HYPRE_ADSSetAMSOptions,jac->hsolver,jac->ams_cycle_type,             /* AMS cycle type */
1329                                                                 jac->as_amg_alpha_opts[0],       /* AMG coarsen type */
1330                                                                 jac->as_amg_alpha_opts[1],       /* AMG agg_levels */
1331                                                                 jac->as_amg_alpha_opts[2],       /* AMG relax_type */
1332                                                                 jac->as_amg_alpha_theta,
1333                                                                 jac->as_amg_alpha_opts[3],       /* AMG interp_type */
1334                                                                 jac->as_amg_alpha_opts[4]);     /* AMG Pmax */
1335   }
1336   PetscCall(PetscOptionsReal("-pc_hypre_ads_amg_theta","Threshold for strong coupling of vector AMG solver inside ADS","None",jac->as_amg_beta_theta,&jac->as_amg_beta_theta,&flag));
1337   n = 5;
1338   PetscCall(PetscOptionsIntArray("-pc_hypre_ads_amg_options","AMG options for vector AMG solver inside ADS","None",jac->as_amg_beta_opts,&n,&flag2));
1339   if (flag || flag2) {
1340     PetscStackCallStandard(HYPRE_ADSSetAMGOptions,jac->hsolver,jac->as_amg_beta_opts[0],       /* AMG coarsen type */
1341                                                                 jac->as_amg_beta_opts[1],       /* AMG agg_levels */
1342                                                                 jac->as_amg_beta_opts[2],       /* AMG relax_type */
1343                                                                 jac->as_amg_beta_theta,
1344                                                                 jac->as_amg_beta_opts[3],       /* AMG interp_type */
1345                                                                 jac->as_amg_beta_opts[4]);     /* AMG Pmax */
1346   }
1347   PetscCall(PetscOptionsTail());
1348   PetscFunctionReturn(0);
1349 }
1350 
1351 static PetscErrorCode PCView_HYPRE_ADS(PC pc,PetscViewer viewer)
1352 {
1353   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1354   PetscBool      iascii;
1355 
1356   PetscFunctionBegin;
1357   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
1358   if (iascii) {
1359     PetscCall(PetscViewerASCIIPrintf(viewer,"  HYPRE ADS preconditioning\n"));
1360     PetscCall(PetscViewerASCIIPrintf(viewer,"    subspace iterations per application %d\n",jac->as_max_iter));
1361     PetscCall(PetscViewerASCIIPrintf(viewer,"    subspace cycle type %d\n",jac->ads_cycle_type));
1362     PetscCall(PetscViewerASCIIPrintf(viewer,"    subspace iteration tolerance %g\n",jac->as_tol));
1363     PetscCall(PetscViewerASCIIPrintf(viewer,"    smoother type %d\n",jac->as_relax_type));
1364     PetscCall(PetscViewerASCIIPrintf(viewer,"    number of smoothing steps %d\n",jac->as_relax_times));
1365     PetscCall(PetscViewerASCIIPrintf(viewer,"    smoother weight %g\n",jac->as_relax_weight));
1366     PetscCall(PetscViewerASCIIPrintf(viewer,"    smoother omega %g\n",jac->as_omega));
1367     PetscCall(PetscViewerASCIIPrintf(viewer,"    AMS solver using boomerAMG\n"));
1368     PetscCall(PetscViewerASCIIPrintf(viewer,"        subspace cycle type %d\n",jac->ams_cycle_type));
1369     PetscCall(PetscViewerASCIIPrintf(viewer,"        coarsening type %d\n",jac->as_amg_alpha_opts[0]));
1370     PetscCall(PetscViewerASCIIPrintf(viewer,"        levels of aggressive coarsening %d\n",jac->as_amg_alpha_opts[1]));
1371     PetscCall(PetscViewerASCIIPrintf(viewer,"        relaxation type %d\n",jac->as_amg_alpha_opts[2]));
1372     PetscCall(PetscViewerASCIIPrintf(viewer,"        interpolation type %d\n",jac->as_amg_alpha_opts[3]));
1373     PetscCall(PetscViewerASCIIPrintf(viewer,"        max nonzero elements in interpolation rows %d\n",jac->as_amg_alpha_opts[4]));
1374     PetscCall(PetscViewerASCIIPrintf(viewer,"        strength threshold %g\n",jac->as_amg_alpha_theta));
1375     PetscCall(PetscViewerASCIIPrintf(viewer,"    vector Poisson solver using boomerAMG\n"));
1376     PetscCall(PetscViewerASCIIPrintf(viewer,"        coarsening type %d\n",jac->as_amg_beta_opts[0]));
1377     PetscCall(PetscViewerASCIIPrintf(viewer,"        levels of aggressive coarsening %d\n",jac->as_amg_beta_opts[1]));
1378     PetscCall(PetscViewerASCIIPrintf(viewer,"        relaxation type %d\n",jac->as_amg_beta_opts[2]));
1379     PetscCall(PetscViewerASCIIPrintf(viewer,"        interpolation type %d\n",jac->as_amg_beta_opts[3]));
1380     PetscCall(PetscViewerASCIIPrintf(viewer,"        max nonzero elements in interpolation rows %d\n",jac->as_amg_beta_opts[4]));
1381     PetscCall(PetscViewerASCIIPrintf(viewer,"        strength threshold %g\n",jac->as_amg_beta_theta));
1382   }
1383   PetscFunctionReturn(0);
1384 }
1385 
1386 static PetscErrorCode PCHYPRESetDiscreteGradient_HYPRE(PC pc, Mat G)
1387 {
1388   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1389   PetscBool      ishypre;
1390 
1391   PetscFunctionBegin;
1392   PetscCall(PetscObjectTypeCompare((PetscObject)G,MATHYPRE,&ishypre));
1393   if (ishypre) {
1394     PetscCall(PetscObjectReference((PetscObject)G));
1395     PetscCall(MatDestroy(&jac->G));
1396     jac->G = G;
1397   } else {
1398     PetscCall(MatDestroy(&jac->G));
1399     PetscCall(MatConvert(G,MATHYPRE,MAT_INITIAL_MATRIX,&jac->G));
1400   }
1401   PetscFunctionReturn(0);
1402 }
1403 
1404 /*@
1405  PCHYPRESetDiscreteGradient - Set discrete gradient matrix
1406 
1407    Collective on PC
1408 
1409    Input Parameters:
1410 +  pc - the preconditioning context
1411 -  G - the discrete gradient
1412 
1413    Level: intermediate
1414 
1415    Notes:
1416     G should have as many rows as the number of edges and as many columns as the number of vertices in the mesh
1417 
1418     Each row of G has 2 nonzeros, with column indexes being the global indexes of edge's endpoints: matrix entries are +1 and -1 depending on edge orientation
1419 
1420 .seealso: PCHYPRESetDiscreteCurl()
1421 @*/
1422 PetscErrorCode PCHYPRESetDiscreteGradient(PC pc, Mat G)
1423 {
1424   PetscFunctionBegin;
1425   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1426   PetscValidHeaderSpecific(G,MAT_CLASSID,2);
1427   PetscCheckSameComm(pc,1,G,2);
1428   PetscTryMethod(pc,"PCHYPRESetDiscreteGradient_C",(PC,Mat),(pc,G));
1429   PetscFunctionReturn(0);
1430 }
1431 
1432 static PetscErrorCode PCHYPRESetDiscreteCurl_HYPRE(PC pc, Mat C)
1433 {
1434   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1435   PetscBool      ishypre;
1436 
1437   PetscFunctionBegin;
1438   PetscCall(PetscObjectTypeCompare((PetscObject)C,MATHYPRE,&ishypre));
1439   if (ishypre) {
1440     PetscCall(PetscObjectReference((PetscObject)C));
1441     PetscCall(MatDestroy(&jac->C));
1442     jac->C = C;
1443   } else {
1444     PetscCall(MatDestroy(&jac->C));
1445     PetscCall(MatConvert(C,MATHYPRE,MAT_INITIAL_MATRIX,&jac->C));
1446   }
1447   PetscFunctionReturn(0);
1448 }
1449 
1450 /*@
1451  PCHYPRESetDiscreteCurl - Set discrete curl matrix
1452 
1453    Collective on PC
1454 
1455    Input Parameters:
1456 +  pc - the preconditioning context
1457 -  C - the discrete curl
1458 
1459    Level: intermediate
1460 
1461    Notes:
1462     C should have as many rows as the number of faces and as many columns as the number of edges in the mesh
1463 
1464     Each row of G has as many nonzeros as the number of edges of a face, with column indexes being the global indexes of the corresponding edge: matrix entries are +1 and -1 depending on edge orientation with respect to the face orientation
1465 
1466 .seealso: PCHYPRESetDiscreteGradient()
1467 @*/
1468 PetscErrorCode PCHYPRESetDiscreteCurl(PC pc, Mat C)
1469 {
1470   PetscFunctionBegin;
1471   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1472   PetscValidHeaderSpecific(C,MAT_CLASSID,2);
1473   PetscCheckSameComm(pc,1,C,2);
1474   PetscTryMethod(pc,"PCHYPRESetDiscreteCurl_C",(PC,Mat),(pc,C));
1475   PetscFunctionReturn(0);
1476 }
1477 
1478 static PetscErrorCode PCHYPRESetInterpolations_HYPRE(PC pc, PetscInt dim, Mat RT_PiFull, Mat RT_Pi[], Mat ND_PiFull, Mat ND_Pi[])
1479 {
1480   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1481   PetscBool      ishypre;
1482   PetscInt       i;
1483   PetscFunctionBegin;
1484 
1485   PetscCall(MatDestroy(&jac->RT_PiFull));
1486   PetscCall(MatDestroy(&jac->ND_PiFull));
1487   for (i=0;i<3;++i) {
1488     PetscCall(MatDestroy(&jac->RT_Pi[i]));
1489     PetscCall(MatDestroy(&jac->ND_Pi[i]));
1490   }
1491 
1492   jac->dim = dim;
1493   if (RT_PiFull) {
1494     PetscCall(PetscObjectTypeCompare((PetscObject)RT_PiFull,MATHYPRE,&ishypre));
1495     if (ishypre) {
1496       PetscCall(PetscObjectReference((PetscObject)RT_PiFull));
1497       jac->RT_PiFull = RT_PiFull;
1498     } else {
1499       PetscCall(MatConvert(RT_PiFull,MATHYPRE,MAT_INITIAL_MATRIX,&jac->RT_PiFull));
1500     }
1501   }
1502   if (RT_Pi) {
1503     for (i=0;i<dim;++i) {
1504       if (RT_Pi[i]) {
1505         PetscCall(PetscObjectTypeCompare((PetscObject)RT_Pi[i],MATHYPRE,&ishypre));
1506         if (ishypre) {
1507           PetscCall(PetscObjectReference((PetscObject)RT_Pi[i]));
1508           jac->RT_Pi[i] = RT_Pi[i];
1509         } else {
1510           PetscCall(MatConvert(RT_Pi[i],MATHYPRE,MAT_INITIAL_MATRIX,&jac->RT_Pi[i]));
1511         }
1512       }
1513     }
1514   }
1515   if (ND_PiFull) {
1516     PetscCall(PetscObjectTypeCompare((PetscObject)ND_PiFull,MATHYPRE,&ishypre));
1517     if (ishypre) {
1518       PetscCall(PetscObjectReference((PetscObject)ND_PiFull));
1519       jac->ND_PiFull = ND_PiFull;
1520     } else {
1521       PetscCall(MatConvert(ND_PiFull,MATHYPRE,MAT_INITIAL_MATRIX,&jac->ND_PiFull));
1522     }
1523   }
1524   if (ND_Pi) {
1525     for (i=0;i<dim;++i) {
1526       if (ND_Pi[i]) {
1527         PetscCall(PetscObjectTypeCompare((PetscObject)ND_Pi[i],MATHYPRE,&ishypre));
1528         if (ishypre) {
1529           PetscCall(PetscObjectReference((PetscObject)ND_Pi[i]));
1530           jac->ND_Pi[i] = ND_Pi[i];
1531         } else {
1532           PetscCall(MatConvert(ND_Pi[i],MATHYPRE,MAT_INITIAL_MATRIX,&jac->ND_Pi[i]));
1533         }
1534       }
1535     }
1536   }
1537 
1538   PetscFunctionReturn(0);
1539 }
1540 
1541 /*@
1542  PCHYPRESetInterpolations - Set interpolation matrices for AMS/ADS preconditioner
1543 
1544    Collective on PC
1545 
1546    Input Parameters:
1547 +  pc - the preconditioning context
1548 -  dim - the dimension of the problem, only used in AMS
1549 -  RT_PiFull - Raviart-Thomas interpolation matrix
1550 -  RT_Pi - x/y/z component of Raviart-Thomas interpolation matrix
1551 -  ND_PiFull - Nedelec interpolation matrix
1552 -  ND_Pi - x/y/z component of Nedelec interpolation matrix
1553 
1554    Notes:
1555     For AMS, only Nedelec interpolation matrices are needed, the Raviart-Thomas interpolation matrices can be set to NULL.
1556 
1557     For ADS, both type of interpolation matrices are needed.
1558 
1559    Level: intermediate
1560 
1561 @*/
1562 PetscErrorCode PCHYPRESetInterpolations(PC pc, PetscInt dim, Mat RT_PiFull, Mat RT_Pi[], Mat ND_PiFull, Mat ND_Pi[])
1563 {
1564   PetscInt       i;
1565 
1566   PetscFunctionBegin;
1567   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1568   if (RT_PiFull) {
1569     PetscValidHeaderSpecific(RT_PiFull,MAT_CLASSID,3);
1570     PetscCheckSameComm(pc,1,RT_PiFull,3);
1571   }
1572   if (RT_Pi) {
1573     PetscValidPointer(RT_Pi,4);
1574     for (i=0;i<dim;++i) {
1575       if (RT_Pi[i]) {
1576         PetscValidHeaderSpecific(RT_Pi[i],MAT_CLASSID,4);
1577         PetscCheckSameComm(pc,1,RT_Pi[i],4);
1578       }
1579     }
1580   }
1581   if (ND_PiFull) {
1582     PetscValidHeaderSpecific(ND_PiFull,MAT_CLASSID,5);
1583     PetscCheckSameComm(pc,1,ND_PiFull,5);
1584   }
1585   if (ND_Pi) {
1586     PetscValidPointer(ND_Pi,6);
1587     for (i=0;i<dim;++i) {
1588       if (ND_Pi[i]) {
1589         PetscValidHeaderSpecific(ND_Pi[i],MAT_CLASSID,6);
1590         PetscCheckSameComm(pc,1,ND_Pi[i],6);
1591       }
1592     }
1593   }
1594   PetscTryMethod(pc,"PCHYPRESetInterpolations_C",(PC,PetscInt,Mat,Mat[],Mat,Mat[]),(pc,dim,RT_PiFull,RT_Pi,ND_PiFull,ND_Pi));
1595   PetscFunctionReturn(0);
1596 }
1597 
1598 static PetscErrorCode PCHYPRESetPoissonMatrix_HYPRE(PC pc, Mat A, PetscBool isalpha)
1599 {
1600   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1601   PetscBool      ishypre;
1602 
1603   PetscFunctionBegin;
1604   PetscCall(PetscObjectTypeCompare((PetscObject)A,MATHYPRE,&ishypre));
1605   if (ishypre) {
1606     if (isalpha) {
1607       PetscCall(PetscObjectReference((PetscObject)A));
1608       PetscCall(MatDestroy(&jac->alpha_Poisson));
1609       jac->alpha_Poisson = A;
1610     } else {
1611       if (A) {
1612         PetscCall(PetscObjectReference((PetscObject)A));
1613       } else {
1614         jac->ams_beta_is_zero = PETSC_TRUE;
1615       }
1616       PetscCall(MatDestroy(&jac->beta_Poisson));
1617       jac->beta_Poisson = A;
1618     }
1619   } else {
1620     if (isalpha) {
1621       PetscCall(MatDestroy(&jac->alpha_Poisson));
1622       PetscCall(MatConvert(A,MATHYPRE,MAT_INITIAL_MATRIX,&jac->alpha_Poisson));
1623     } else {
1624       if (A) {
1625         PetscCall(MatDestroy(&jac->beta_Poisson));
1626         PetscCall(MatConvert(A,MATHYPRE,MAT_INITIAL_MATRIX,&jac->beta_Poisson));
1627       } else {
1628         PetscCall(MatDestroy(&jac->beta_Poisson));
1629         jac->ams_beta_is_zero = PETSC_TRUE;
1630       }
1631     }
1632   }
1633   PetscFunctionReturn(0);
1634 }
1635 
1636 /*@
1637  PCHYPRESetAlphaPoissonMatrix - Set vector Poisson matrix
1638 
1639    Collective on PC
1640 
1641    Input Parameters:
1642 +  pc - the preconditioning context
1643 -  A - the matrix
1644 
1645    Level: intermediate
1646 
1647    Notes:
1648     A should be obtained by discretizing the vector valued Poisson problem with linear finite elements
1649 
1650 .seealso: PCHYPRESetDiscreteGradient(), PCHYPRESetDiscreteCurl(), PCHYPRESetBetaPoissonMatrix()
1651 @*/
1652 PetscErrorCode PCHYPRESetAlphaPoissonMatrix(PC pc, Mat A)
1653 {
1654   PetscFunctionBegin;
1655   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1656   PetscValidHeaderSpecific(A,MAT_CLASSID,2);
1657   PetscCheckSameComm(pc,1,A,2);
1658   PetscTryMethod(pc,"PCHYPRESetPoissonMatrix_C",(PC,Mat,PetscBool),(pc,A,PETSC_TRUE));
1659   PetscFunctionReturn(0);
1660 }
1661 
1662 /*@
1663  PCHYPRESetBetaPoissonMatrix - Set Poisson matrix
1664 
1665    Collective on PC
1666 
1667    Input Parameters:
1668 +  pc - the preconditioning context
1669 -  A - the matrix
1670 
1671    Level: intermediate
1672 
1673    Notes:
1674     A should be obtained by discretizing the Poisson problem with linear finite elements.
1675           Following HYPRE convention, the scalar Poisson solver of AMS can be turned off by passing NULL.
1676 
1677 .seealso: PCHYPRESetDiscreteGradient(), PCHYPRESetDiscreteCurl(), PCHYPRESetAlphaPoissonMatrix()
1678 @*/
1679 PetscErrorCode PCHYPRESetBetaPoissonMatrix(PC pc, Mat A)
1680 {
1681   PetscFunctionBegin;
1682   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1683   if (A) {
1684     PetscValidHeaderSpecific(A,MAT_CLASSID,2);
1685     PetscCheckSameComm(pc,1,A,2);
1686   }
1687   PetscTryMethod(pc,"PCHYPRESetPoissonMatrix_C",(PC,Mat,PetscBool),(pc,A,PETSC_FALSE));
1688   PetscFunctionReturn(0);
1689 }
1690 
1691 static PetscErrorCode PCHYPRESetEdgeConstantVectors_HYPRE(PC pc,Vec ozz, Vec zoz, Vec zzo)
1692 {
1693   PC_HYPRE           *jac = (PC_HYPRE*)pc->data;
1694 
1695   PetscFunctionBegin;
1696   /* throw away any vector if already set */
1697   PetscCall(VecHYPRE_IJVectorDestroy(&jac->constants[0]));
1698   PetscCall(VecHYPRE_IJVectorDestroy(&jac->constants[1]));
1699   PetscCall(VecHYPRE_IJVectorDestroy(&jac->constants[2]));
1700   PetscCall(VecHYPRE_IJVectorCreate(ozz->map,&jac->constants[0]));
1701   PetscCall(VecHYPRE_IJVectorCopy(ozz,jac->constants[0]));
1702   PetscCall(VecHYPRE_IJVectorCreate(zoz->map,&jac->constants[1]));
1703   PetscCall(VecHYPRE_IJVectorCopy(zoz,jac->constants[1]));
1704   jac->dim = 2;
1705   if (zzo) {
1706     PetscCall(VecHYPRE_IJVectorCreate(zzo->map,&jac->constants[2]));
1707     PetscCall(VecHYPRE_IJVectorCopy(zzo,jac->constants[2]));
1708     jac->dim++;
1709   }
1710   PetscFunctionReturn(0);
1711 }
1712 
1713 /*@
1714  PCHYPRESetEdgeConstantVectors - Set the representation of the constant vector fields in the edge element basis
1715 
1716    Collective on PC
1717 
1718    Input Parameters:
1719 +  pc - the preconditioning context
1720 -  ozz - vector representing (1,0,0) (or (1,0) in 2D)
1721 -  zoz - vector representing (0,1,0) (or (0,1) in 2D)
1722 -  zzo - vector representing (0,0,1) (use NULL in 2D)
1723 
1724    Level: intermediate
1725 
1726 @*/
1727 PetscErrorCode PCHYPRESetEdgeConstantVectors(PC pc, Vec ozz, Vec zoz, Vec zzo)
1728 {
1729   PetscFunctionBegin;
1730   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1731   PetscValidHeaderSpecific(ozz,VEC_CLASSID,2);
1732   PetscValidHeaderSpecific(zoz,VEC_CLASSID,3);
1733   if (zzo) PetscValidHeaderSpecific(zzo,VEC_CLASSID,4);
1734   PetscCheckSameComm(pc,1,ozz,2);
1735   PetscCheckSameComm(pc,1,zoz,3);
1736   if (zzo) PetscCheckSameComm(pc,1,zzo,4);
1737   PetscTryMethod(pc,"PCHYPRESetEdgeConstantVectors_C",(PC,Vec,Vec,Vec),(pc,ozz,zoz,zzo));
1738   PetscFunctionReturn(0);
1739 }
1740 
1741 static PetscErrorCode PCSetCoordinates_HYPRE(PC pc, PetscInt dim, PetscInt nloc, PetscReal *coords)
1742 {
1743   PC_HYPRE        *jac = (PC_HYPRE*)pc->data;
1744   Vec             tv;
1745   PetscInt        i;
1746 
1747   PetscFunctionBegin;
1748   /* throw away any coordinate vector if already set */
1749   PetscCall(VecHYPRE_IJVectorDestroy(&jac->coords[0]));
1750   PetscCall(VecHYPRE_IJVectorDestroy(&jac->coords[1]));
1751   PetscCall(VecHYPRE_IJVectorDestroy(&jac->coords[2]));
1752   jac->dim = dim;
1753 
1754   /* compute IJ vector for coordinates */
1755   PetscCall(VecCreate(PetscObjectComm((PetscObject)pc),&tv));
1756   PetscCall(VecSetType(tv,VECSTANDARD));
1757   PetscCall(VecSetSizes(tv,nloc,PETSC_DECIDE));
1758   for (i=0;i<dim;i++) {
1759     PetscScalar *array;
1760     PetscInt    j;
1761 
1762     PetscCall(VecHYPRE_IJVectorCreate(tv->map,&jac->coords[i]));
1763     PetscCall(VecGetArrayWrite(tv,&array));
1764     for (j=0;j<nloc;j++) array[j] = coords[j*dim+i];
1765     PetscCall(VecRestoreArrayWrite(tv,&array));
1766     PetscCall(VecHYPRE_IJVectorCopy(tv,jac->coords[i]));
1767   }
1768   PetscCall(VecDestroy(&tv));
1769   PetscFunctionReturn(0);
1770 }
1771 
1772 /* ---------------------------------------------------------------------------------*/
1773 
1774 static PetscErrorCode  PCHYPREGetType_HYPRE(PC pc,const char *name[])
1775 {
1776   PC_HYPRE *jac = (PC_HYPRE*)pc->data;
1777 
1778   PetscFunctionBegin;
1779   *name = jac->hypre_type;
1780   PetscFunctionReturn(0);
1781 }
1782 
1783 static PetscErrorCode  PCHYPRESetType_HYPRE(PC pc,const char name[])
1784 {
1785   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1786   PetscBool      flag;
1787 
1788   PetscFunctionBegin;
1789   if (jac->hypre_type) {
1790     PetscCall(PetscStrcmp(jac->hypre_type,name,&flag));
1791     PetscCheck(flag,PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Cannot reset the HYPRE preconditioner type once it has been set");
1792     PetscFunctionReturn(0);
1793   } else {
1794     PetscCall(PetscStrallocpy(name, &jac->hypre_type));
1795   }
1796 
1797   jac->maxiter         = PETSC_DEFAULT;
1798   jac->tol             = PETSC_DEFAULT;
1799   jac->printstatistics = PetscLogPrintInfo;
1800 
1801   PetscCall(PetscStrcmp("pilut",jac->hypre_type,&flag));
1802   if (flag) {
1803     PetscCall(PetscCommGetComm(PetscObjectComm((PetscObject)pc),&jac->comm_hypre));
1804     PetscStackCallStandard(HYPRE_ParCSRPilutCreate,jac->comm_hypre,&jac->hsolver);
1805     pc->ops->setfromoptions = PCSetFromOptions_HYPRE_Pilut;
1806     pc->ops->view           = PCView_HYPRE_Pilut;
1807     jac->destroy            = HYPRE_ParCSRPilutDestroy;
1808     jac->setup              = HYPRE_ParCSRPilutSetup;
1809     jac->solve              = HYPRE_ParCSRPilutSolve;
1810     jac->factorrowsize      = PETSC_DEFAULT;
1811     PetscFunctionReturn(0);
1812   }
1813   PetscCall(PetscStrcmp("euclid",jac->hypre_type,&flag));
1814   if (flag) {
1815 #if defined(PETSC_USE_64BIT_INDICES)
1816     SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Hypre Euclid does not support 64 bit indices");
1817 #endif
1818     PetscCall(PetscCommGetComm(PetscObjectComm((PetscObject)pc),&jac->comm_hypre));
1819     PetscStackCallStandard(HYPRE_EuclidCreate,jac->comm_hypre,&jac->hsolver);
1820     pc->ops->setfromoptions = PCSetFromOptions_HYPRE_Euclid;
1821     pc->ops->view           = PCView_HYPRE_Euclid;
1822     jac->destroy            = HYPRE_EuclidDestroy;
1823     jac->setup              = HYPRE_EuclidSetup;
1824     jac->solve              = HYPRE_EuclidSolve;
1825     jac->factorrowsize      = PETSC_DEFAULT;
1826     jac->eu_level           = PETSC_DEFAULT; /* default */
1827     PetscFunctionReturn(0);
1828   }
1829   PetscCall(PetscStrcmp("parasails",jac->hypre_type,&flag));
1830   if (flag) {
1831     PetscCall(PetscCommGetComm(PetscObjectComm((PetscObject)pc),&jac->comm_hypre));
1832     PetscStackCallStandard(HYPRE_ParaSailsCreate,jac->comm_hypre,&jac->hsolver);
1833     pc->ops->setfromoptions = PCSetFromOptions_HYPRE_ParaSails;
1834     pc->ops->view           = PCView_HYPRE_ParaSails;
1835     jac->destroy            = HYPRE_ParaSailsDestroy;
1836     jac->setup              = HYPRE_ParaSailsSetup;
1837     jac->solve              = HYPRE_ParaSailsSolve;
1838     /* initialize */
1839     jac->nlevels   = 1;
1840     jac->threshold = .1;
1841     jac->filter    = .1;
1842     jac->loadbal   = 0;
1843     if (PetscLogPrintInfo) jac->logging = (int) PETSC_TRUE;
1844     else jac->logging = (int) PETSC_FALSE;
1845 
1846     jac->ruse = (int) PETSC_FALSE;
1847     jac->symt = 0;
1848     PetscStackCallStandard(HYPRE_ParaSailsSetParams,jac->hsolver,jac->threshold,jac->nlevels);
1849     PetscStackCallStandard(HYPRE_ParaSailsSetFilter,jac->hsolver,jac->filter);
1850     PetscStackCallStandard(HYPRE_ParaSailsSetLoadbal,jac->hsolver,jac->loadbal);
1851     PetscStackCallStandard(HYPRE_ParaSailsSetLogging,jac->hsolver,jac->logging);
1852     PetscStackCallStandard(HYPRE_ParaSailsSetReuse,jac->hsolver,jac->ruse);
1853     PetscStackCallStandard(HYPRE_ParaSailsSetSym,jac->hsolver,jac->symt);
1854     PetscFunctionReturn(0);
1855   }
1856   PetscCall(PetscStrcmp("boomeramg",jac->hypre_type,&flag));
1857   if (flag) {
1858     PetscStackCallStandard(HYPRE_BoomerAMGCreate,&jac->hsolver);
1859     pc->ops->setfromoptions  = PCSetFromOptions_HYPRE_BoomerAMG;
1860     pc->ops->view            = PCView_HYPRE_BoomerAMG;
1861     pc->ops->applytranspose  = PCApplyTranspose_HYPRE_BoomerAMG;
1862     pc->ops->applyrichardson = PCApplyRichardson_HYPRE_BoomerAMG;
1863     PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCGetInterpolations_C",PCGetInterpolations_BoomerAMG));
1864     PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCGetCoarseOperators_C",PCGetCoarseOperators_BoomerAMG));
1865     jac->destroy             = HYPRE_BoomerAMGDestroy;
1866     jac->setup               = HYPRE_BoomerAMGSetup;
1867     jac->solve               = HYPRE_BoomerAMGSolve;
1868     jac->applyrichardson     = PETSC_FALSE;
1869     /* these defaults match the hypre defaults */
1870     jac->cycletype        = 1;
1871     jac->maxlevels        = 25;
1872     jac->maxiter          = 1;
1873     jac->tol              = 0.0; /* tolerance of zero indicates use as preconditioner (suppresses convergence errors) */
1874     jac->truncfactor      = 0.0;
1875     jac->strongthreshold  = .25;
1876     jac->maxrowsum        = .9;
1877     jac->coarsentype      = 6;
1878     jac->measuretype      = 0;
1879     jac->gridsweeps[0]    = jac->gridsweeps[1] = jac->gridsweeps[2] = 1;
1880     jac->smoothtype       = -1; /* Not set by default */
1881     jac->smoothnumlevels  = 25;
1882     jac->eu_level         = 0;
1883     jac->eu_droptolerance = 0;
1884     jac->eu_bj            = 0;
1885     jac->relaxtype[0]     = jac->relaxtype[1] = 6; /* Defaults to SYMMETRIC since in PETSc we are using a PC - most likely with CG */
1886     jac->relaxtype[2]     = 9; /*G.E. */
1887     jac->relaxweight      = 1.0;
1888     jac->outerrelaxweight = 1.0;
1889     jac->relaxorder       = 1;
1890     jac->interptype       = 0;
1891     jac->Rtype            = 0;
1892     jac->Rstrongthreshold = 0.25;
1893     jac->Rfilterthreshold = 0.0;
1894     jac->Adroptype        = -1;
1895     jac->Adroptol         = 0.0;
1896     jac->agg_nl           = 0;
1897     jac->agg_interptype   = 4;
1898     jac->pmax             = 0;
1899     jac->truncfactor      = 0.0;
1900     jac->agg_num_paths    = 1;
1901     jac->maxc             = 9;
1902     jac->minc             = 1;
1903     jac->nodal_coarsening      = 0;
1904     jac->nodal_coarsening_diag = 0;
1905     jac->vec_interp_variant    = 0;
1906     jac->vec_interp_qmax       = 0;
1907     jac->vec_interp_smooth     = PETSC_FALSE;
1908     jac->interp_refine         = 0;
1909     jac->nodal_relax           = PETSC_FALSE;
1910     jac->nodal_relax_levels    = 1;
1911     jac->rap2                  = 0;
1912 
1913     /* GPU defaults
1914          from https://hypre.readthedocs.io/en/latest/solvers-boomeramg.html#gpu-supported-options
1915          and /src/parcsr_ls/par_amg.c */
1916 #if defined(PETSC_HAVE_HYPRE_DEVICE)
1917     jac->keeptranspose         = PETSC_TRUE;
1918     jac->mod_rap2              = 1;
1919     jac->coarsentype           = 8;
1920     jac->relaxorder            = 0;
1921     jac->interptype            = 6;
1922     jac->relaxtype[0]          = 18;
1923     jac->relaxtype[1]          = 18;
1924     jac->agg_interptype        = 7;
1925 #else
1926     jac->keeptranspose         = PETSC_FALSE;
1927     jac->mod_rap2              = 0;
1928 #endif
1929     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleType,jac->hsolver,jac->cycletype);
1930     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxLevels,jac->hsolver,jac->maxlevels);
1931     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxIter,jac->hsolver,jac->maxiter);
1932     PetscStackCallStandard(HYPRE_BoomerAMGSetTol,jac->hsolver,jac->tol);
1933     PetscStackCallStandard(HYPRE_BoomerAMGSetTruncFactor,jac->hsolver,jac->truncfactor);
1934     PetscStackCallStandard(HYPRE_BoomerAMGSetStrongThreshold,jac->hsolver,jac->strongthreshold);
1935     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxRowSum,jac->hsolver,jac->maxrowsum);
1936     PetscStackCallStandard(HYPRE_BoomerAMGSetCoarsenType,jac->hsolver,jac->coarsentype);
1937     PetscStackCallStandard(HYPRE_BoomerAMGSetMeasureType,jac->hsolver,jac->measuretype);
1938     PetscStackCallStandard(HYPRE_BoomerAMGSetRelaxOrder,jac->hsolver, jac->relaxorder);
1939     PetscStackCallStandard(HYPRE_BoomerAMGSetInterpType,jac->hsolver,jac->interptype);
1940     PetscStackCallStandard(HYPRE_BoomerAMGSetAggNumLevels,jac->hsolver,jac->agg_nl);
1941     PetscStackCallStandard(HYPRE_BoomerAMGSetAggInterpType,jac->hsolver,jac->agg_interptype);
1942     PetscStackCallStandard(HYPRE_BoomerAMGSetPMaxElmts,jac->hsolver,jac->pmax);
1943     PetscStackCallStandard(HYPRE_BoomerAMGSetNumPaths,jac->hsolver,jac->agg_num_paths);
1944     PetscStackCallStandard(HYPRE_BoomerAMGSetRelaxType,jac->hsolver, jac->relaxtype[0]);  /* defaults coarse to 9 */
1945     PetscStackCallStandard(HYPRE_BoomerAMGSetNumSweeps,jac->hsolver, jac->gridsweeps[0]); /* defaults coarse to 1 */
1946     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxCoarseSize,jac->hsolver, jac->maxc);
1947     PetscStackCallStandard(HYPRE_BoomerAMGSetMinCoarseSize,jac->hsolver, jac->minc);
1948     /* GPU */
1949 #if PETSC_PKG_HYPRE_VERSION_GE(2,18,0)
1950     PetscStackCallStandard(HYPRE_BoomerAMGSetKeepTranspose,jac->hsolver,jac->keeptranspose ? 1 : 0);
1951     PetscStackCallStandard(HYPRE_BoomerAMGSetRAP2,jac->hsolver, jac->rap2);
1952     PetscStackCallStandard(HYPRE_BoomerAMGSetModuleRAP2,jac->hsolver, jac->mod_rap2);
1953 #endif
1954 
1955     /* AIR */
1956 #if PETSC_PKG_HYPRE_VERSION_GE(2,18,0)
1957     PetscStackCallStandard(HYPRE_BoomerAMGSetRestriction,jac->hsolver,jac->Rtype);
1958     PetscStackCallStandard(HYPRE_BoomerAMGSetStrongThresholdR,jac->hsolver,jac->Rstrongthreshold);
1959     PetscStackCallStandard(HYPRE_BoomerAMGSetFilterThresholdR,jac->hsolver,jac->Rfilterthreshold);
1960     PetscStackCallStandard(HYPRE_BoomerAMGSetADropTol,jac->hsolver,jac->Adroptol);
1961     PetscStackCallStandard(HYPRE_BoomerAMGSetADropType,jac->hsolver,jac->Adroptype);
1962 #endif
1963     PetscFunctionReturn(0);
1964   }
1965   PetscCall(PetscStrcmp("ams",jac->hypre_type,&flag));
1966   if (flag) {
1967     PetscCall(HYPRE_AMSCreate(&jac->hsolver));
1968     pc->ops->setfromoptions  = PCSetFromOptions_HYPRE_AMS;
1969     pc->ops->view            = PCView_HYPRE_AMS;
1970     jac->destroy             = HYPRE_AMSDestroy;
1971     jac->setup               = HYPRE_AMSSetup;
1972     jac->solve               = HYPRE_AMSSolve;
1973     jac->coords[0]           = NULL;
1974     jac->coords[1]           = NULL;
1975     jac->coords[2]           = NULL;
1976     /* solver parameters: these are borrowed from mfem package, and they are not the default values from HYPRE AMS */
1977     jac->as_print           = 0;
1978     jac->as_max_iter        = 1; /* used as a preconditioner */
1979     jac->as_tol             = 0.; /* used as a preconditioner */
1980     jac->ams_cycle_type     = 13;
1981     /* Smoothing options */
1982     jac->as_relax_type      = 2;
1983     jac->as_relax_times     = 1;
1984     jac->as_relax_weight    = 1.0;
1985     jac->as_omega           = 1.0;
1986     /* Vector valued Poisson AMG solver parameters: coarsen type, agg_levels, relax_type, interp_type, Pmax */
1987     jac->as_amg_alpha_opts[0] = 10;
1988     jac->as_amg_alpha_opts[1] = 1;
1989     jac->as_amg_alpha_opts[2] = 6;
1990     jac->as_amg_alpha_opts[3] = 6;
1991     jac->as_amg_alpha_opts[4] = 4;
1992     jac->as_amg_alpha_theta   = 0.25;
1993     /* Scalar Poisson AMG solver parameters: coarsen type, agg_levels, relax_type, interp_type, Pmax */
1994     jac->as_amg_beta_opts[0] = 10;
1995     jac->as_amg_beta_opts[1] = 1;
1996     jac->as_amg_beta_opts[2] = 6;
1997     jac->as_amg_beta_opts[3] = 6;
1998     jac->as_amg_beta_opts[4] = 4;
1999     jac->as_amg_beta_theta   = 0.25;
2000     PetscStackCallStandard(HYPRE_AMSSetPrintLevel,jac->hsolver,jac->as_print);
2001     PetscStackCallStandard(HYPRE_AMSSetMaxIter,jac->hsolver,jac->as_max_iter);
2002     PetscStackCallStandard(HYPRE_AMSSetCycleType,jac->hsolver,jac->ams_cycle_type);
2003     PetscStackCallStandard(HYPRE_AMSSetTol,jac->hsolver,jac->as_tol);
2004     PetscStackCallStandard(HYPRE_AMSSetSmoothingOptions,jac->hsolver,jac->as_relax_type,
2005                                                                       jac->as_relax_times,
2006                                                                       jac->as_relax_weight,
2007                                                                       jac->as_omega);
2008     PetscStackCallStandard(HYPRE_AMSSetAlphaAMGOptions,jac->hsolver,jac->as_amg_alpha_opts[0],       /* AMG coarsen type */
2009                                                                      jac->as_amg_alpha_opts[1],       /* AMG agg_levels */
2010                                                                      jac->as_amg_alpha_opts[2],       /* AMG relax_type */
2011                                                                      jac->as_amg_alpha_theta,
2012                                                                      jac->as_amg_alpha_opts[3],       /* AMG interp_type */
2013                                                                      jac->as_amg_alpha_opts[4]);     /* AMG Pmax */
2014     PetscStackCallStandard(HYPRE_AMSSetBetaAMGOptions,jac->hsolver,jac->as_amg_beta_opts[0],       /* AMG coarsen type */
2015                                                                     jac->as_amg_beta_opts[1],       /* AMG agg_levels */
2016                                                                     jac->as_amg_beta_opts[2],       /* AMG relax_type */
2017                                                                     jac->as_amg_beta_theta,
2018                                                                     jac->as_amg_beta_opts[3],       /* AMG interp_type */
2019                                                                     jac->as_amg_beta_opts[4]);     /* AMG Pmax */
2020     /* Zero conductivity */
2021     jac->ams_beta_is_zero      = PETSC_FALSE;
2022     jac->ams_beta_is_zero_part = PETSC_FALSE;
2023     PetscFunctionReturn(0);
2024   }
2025   PetscCall(PetscStrcmp("ads",jac->hypre_type,&flag));
2026   if (flag) {
2027     PetscCall(HYPRE_ADSCreate(&jac->hsolver));
2028     pc->ops->setfromoptions  = PCSetFromOptions_HYPRE_ADS;
2029     pc->ops->view            = PCView_HYPRE_ADS;
2030     jac->destroy             = HYPRE_ADSDestroy;
2031     jac->setup               = HYPRE_ADSSetup;
2032     jac->solve               = HYPRE_ADSSolve;
2033     jac->coords[0]           = NULL;
2034     jac->coords[1]           = NULL;
2035     jac->coords[2]           = NULL;
2036     /* solver parameters: these are borrowed from mfem package, and they are not the default values from HYPRE ADS */
2037     jac->as_print           = 0;
2038     jac->as_max_iter        = 1; /* used as a preconditioner */
2039     jac->as_tol             = 0.; /* used as a preconditioner */
2040     jac->ads_cycle_type     = 13;
2041     /* Smoothing options */
2042     jac->as_relax_type      = 2;
2043     jac->as_relax_times     = 1;
2044     jac->as_relax_weight    = 1.0;
2045     jac->as_omega           = 1.0;
2046     /* AMS solver parameters: cycle_type, coarsen type, agg_levels, relax_type, interp_type, Pmax */
2047     jac->ams_cycle_type       = 14;
2048     jac->as_amg_alpha_opts[0] = 10;
2049     jac->as_amg_alpha_opts[1] = 1;
2050     jac->as_amg_alpha_opts[2] = 6;
2051     jac->as_amg_alpha_opts[3] = 6;
2052     jac->as_amg_alpha_opts[4] = 4;
2053     jac->as_amg_alpha_theta   = 0.25;
2054     /* Vector Poisson AMG solver parameters: coarsen type, agg_levels, relax_type, interp_type, Pmax */
2055     jac->as_amg_beta_opts[0] = 10;
2056     jac->as_amg_beta_opts[1] = 1;
2057     jac->as_amg_beta_opts[2] = 6;
2058     jac->as_amg_beta_opts[3] = 6;
2059     jac->as_amg_beta_opts[4] = 4;
2060     jac->as_amg_beta_theta   = 0.25;
2061     PetscStackCallStandard(HYPRE_ADSSetPrintLevel,jac->hsolver,jac->as_print);
2062     PetscStackCallStandard(HYPRE_ADSSetMaxIter,jac->hsolver,jac->as_max_iter);
2063     PetscStackCallStandard(HYPRE_ADSSetCycleType,jac->hsolver,jac->ams_cycle_type);
2064     PetscStackCallStandard(HYPRE_ADSSetTol,jac->hsolver,jac->as_tol);
2065     PetscStackCallStandard(HYPRE_ADSSetSmoothingOptions,jac->hsolver,jac->as_relax_type,
2066                                                                       jac->as_relax_times,
2067                                                                       jac->as_relax_weight,
2068                                                                       jac->as_omega);
2069     PetscStackCallStandard(HYPRE_ADSSetAMSOptions,jac->hsolver,jac->ams_cycle_type,             /* AMG coarsen type */
2070                                                                 jac->as_amg_alpha_opts[0],       /* AMG coarsen type */
2071                                                                 jac->as_amg_alpha_opts[1],       /* AMG agg_levels */
2072                                                                 jac->as_amg_alpha_opts[2],       /* AMG relax_type */
2073                                                                 jac->as_amg_alpha_theta,
2074                                                                 jac->as_amg_alpha_opts[3],       /* AMG interp_type */
2075                                                                 jac->as_amg_alpha_opts[4]);     /* AMG Pmax */
2076     PetscStackCallStandard(HYPRE_ADSSetAMGOptions,jac->hsolver,jac->as_amg_beta_opts[0],       /* AMG coarsen type */
2077                                                                 jac->as_amg_beta_opts[1],       /* AMG agg_levels */
2078                                                                 jac->as_amg_beta_opts[2],       /* AMG relax_type */
2079                                                                 jac->as_amg_beta_theta,
2080                                                                 jac->as_amg_beta_opts[3],       /* AMG interp_type */
2081                                                                 jac->as_amg_beta_opts[4]);     /* AMG Pmax */
2082     PetscFunctionReturn(0);
2083   }
2084   PetscCall(PetscFree(jac->hypre_type));
2085 
2086   jac->hypre_type = NULL;
2087   SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown HYPRE preconditioner %s; Choices are euclid, pilut, parasails, boomeramg, ams",name);
2088 }
2089 
2090 /*
2091     It only gets here if the HYPRE type has not been set before the call to
2092    ...SetFromOptions() which actually is most of the time
2093 */
2094 PetscErrorCode PCSetFromOptions_HYPRE(PetscOptionItems *PetscOptionsObject,PC pc)
2095 {
2096   PetscInt       indx;
2097   const char     *type[] = {"euclid","pilut","parasails","boomeramg","ams","ads"};
2098   PetscBool      flg;
2099 
2100   PetscFunctionBegin;
2101   PetscCall(PetscOptionsHead(PetscOptionsObject,"HYPRE preconditioner options"));
2102   PetscCall(PetscOptionsEList("-pc_hypre_type","HYPRE preconditioner type","PCHYPRESetType",type,ALEN(type),"boomeramg",&indx,&flg));
2103   if (flg) {
2104     PetscCall(PCHYPRESetType_HYPRE(pc,type[indx]));
2105   } else {
2106     PetscCall(PCHYPRESetType_HYPRE(pc,"boomeramg"));
2107   }
2108   if (pc->ops->setfromoptions) {
2109     PetscCall(pc->ops->setfromoptions(PetscOptionsObject,pc));
2110   }
2111   PetscCall(PetscOptionsTail());
2112   PetscFunctionReturn(0);
2113 }
2114 
2115 /*@C
2116      PCHYPRESetType - Sets which hypre preconditioner you wish to use
2117 
2118    Input Parameters:
2119 +     pc - the preconditioner context
2120 -     name - either  euclid, pilut, parasails, boomeramg, ams, ads
2121 
2122    Options Database Keys:
2123    -pc_hypre_type - One of euclid, pilut, parasails, boomeramg, ams, ads
2124 
2125    Level: intermediate
2126 
2127 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
2128            PCHYPRE
2129 
2130 @*/
2131 PetscErrorCode  PCHYPRESetType(PC pc,const char name[])
2132 {
2133   PetscFunctionBegin;
2134   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
2135   PetscValidCharPointer(name,2);
2136   PetscTryMethod(pc,"PCHYPRESetType_C",(PC,const char[]),(pc,name));
2137   PetscFunctionReturn(0);
2138 }
2139 
2140 /*@C
2141      PCHYPREGetType - Gets which hypre preconditioner you are using
2142 
2143    Input Parameter:
2144 .     pc - the preconditioner context
2145 
2146    Output Parameter:
2147 .     name - either  euclid, pilut, parasails, boomeramg, ams, ads
2148 
2149    Level: intermediate
2150 
2151 .seealso:  PCCreate(), PCHYPRESetType(), PCType (for list of available types), PC,
2152            PCHYPRE
2153 
2154 @*/
2155 PetscErrorCode  PCHYPREGetType(PC pc,const char *name[])
2156 {
2157   PetscFunctionBegin;
2158   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
2159   PetscValidPointer(name,2);
2160   PetscTryMethod(pc,"PCHYPREGetType_C",(PC,const char*[]),(pc,name));
2161   PetscFunctionReturn(0);
2162 }
2163 
2164 /*@C
2165    PCMGGalerkinSetMatProductAlgorithm - Set type of SpGEMM for hypre to use
2166 
2167    Logically Collective on PC
2168 
2169    Input Parameters:
2170 +  pc - the hypre context
2171 -  type - one of 'cusparse', 'hypre'
2172 
2173    Options Database Key:
2174 .  -pc_mg_galerkin_mat_product_algorithm <cusparse,hypre> - Type of SpGEMM to use in hypre
2175 
2176    Level: intermediate
2177 
2178 .seealso: PCMGGalerkinGetMatProductAlgorithm()
2179 
2180 @*/
2181 PetscErrorCode PCMGGalerkinSetMatProductAlgorithm(PC pc,const char name[])
2182 {
2183   PetscFunctionBegin;
2184   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
2185   PetscTryMethod(pc,"PCMGGalerkinSetMatProductAlgorithm_C",(PC,const char[]),(pc,name));
2186   PetscFunctionReturn(0);
2187 }
2188 
2189 /*@C
2190    PCMGGalerkinGetMatProductAlgorithm - Get type of SpGEMM for hypre
2191 
2192    Not Collective
2193 
2194    Input Parameter:
2195 .  pc - the multigrid context
2196 
2197    Output Parameter:
2198 .  name - one of 'cusparse', 'hypre'
2199 
2200    Level: intermediate
2201 
2202 .seealso: PCMGGalerkinSetMatProductAlgorithm()
2203 
2204 @*/
2205 PetscErrorCode PCMGGalerkinGetMatProductAlgorithm(PC pc,const char *name[])
2206 {
2207   PetscFunctionBegin;
2208   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
2209   PetscTryMethod(pc,"PCMGGalerkinGetMatProductAlgorithm_C",(PC,const char*[]),(pc,name));
2210   PetscFunctionReturn(0);
2211 }
2212 
2213 /*MC
2214      PCHYPRE - Allows you to use the matrix element based preconditioners in the LLNL package hypre
2215 
2216    Options Database Keys:
2217 +   -pc_hypre_type - One of euclid, pilut, parasails, boomeramg, ams, ads
2218 .   -pc_hypre_boomeramg_nodal_coarsen <n> - where n is from 1 to 6 (see HYPRE_BOOMERAMGSetNodal())
2219 .   -pc_hypre_boomeramg_vec_interp_variant <v> - where v is from 1 to 3 (see HYPRE_BoomerAMGSetInterpVecVariant())
2220 -   Many others, run with -pc_type hypre -pc_hypre_type XXX -help to see options for the XXX preconditioner
2221 
2222    Level: intermediate
2223 
2224    Notes:
2225     Apart from pc_hypre_type (for which there is PCHYPRESetType()),
2226           the many hypre options can ONLY be set via the options database (e.g. the command line
2227           or with PetscOptionsSetValue(), there are no functions to set them)
2228 
2229           The options -pc_hypre_boomeramg_max_iter and -pc_hypre_boomeramg_tol refer to the number of iterations
2230           (V-cycles) and tolerance that boomeramg does EACH time it is called. So for example, if
2231           -pc_hypre_boomeramg_max_iter is set to 2 then 2-V-cycles are being used to define the preconditioner
2232           (-pc_hypre_boomeramg_tol should be set to 0.0 - the default - to strictly use a fixed number of
2233           iterations per hypre call). -ksp_max_it and -ksp_rtol STILL determine the total number of iterations
2234           and tolerance for the Krylov solver. For example, if -pc_hypre_boomeramg_max_iter is 2 and -ksp_max_it is 10
2235           then AT MOST twenty V-cycles of boomeramg will be called.
2236 
2237            Note that the option -pc_hypre_boomeramg_relax_type_all defaults to symmetric relaxation
2238            (symmetric-SOR/Jacobi), which is required for Krylov solvers like CG that expect symmetry.
2239            Otherwise, you may want to use -pc_hypre_boomeramg_relax_type_all SOR/Jacobi.
2240           If you wish to use BoomerAMG WITHOUT a Krylov method use -ksp_type richardson NOT -ksp_type preonly
2241           and use -ksp_max_it to control the number of V-cycles.
2242           (see the PETSc FAQ.html at the PETSc website under the Documentation tab).
2243 
2244           2007-02-03 Using HYPRE-1.11.1b, the routine HYPRE_BoomerAMGSolveT and the option
2245           -pc_hypre_parasails_reuse were failing with SIGSEGV. Dalcin L.
2246 
2247           MatSetNearNullSpace() - if you provide a near null space to your matrix it is ignored by hypre UNLESS you also use
2248           the following two options:
2249 
2250           See PCPFMG for access to the hypre Struct PFMG solver
2251 
2252    GPU Notes:
2253      To configure hypre BoomerAMG so that it can utilize NVIDIA GPUs run ./configure --download-hypre --with-cuda
2254      Then pass VECCUDA vectors and MATAIJCUSPARSE matrices to the solvers and PETSc will automatically utilize hypre's GPU solvers.
2255 
2256      To configure hypre BoomerAMG so that it can utilize AMD GPUs run ./configure --download-hypre --with-hip
2257      Then pass VECHIP vectors to the solvers and PETSc will automatically utilize hypre's GPU solvers.
2258 
2259 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
2260            PCHYPRESetType(), PCPFMG
2261 
2262 M*/
2263 
2264 PETSC_EXTERN PetscErrorCode PCCreate_HYPRE(PC pc)
2265 {
2266   PC_HYPRE       *jac;
2267 
2268   PetscFunctionBegin;
2269   PetscCall(PetscNewLog(pc,&jac));
2270 
2271   pc->data                = jac;
2272   pc->ops->reset          = PCReset_HYPRE;
2273   pc->ops->destroy        = PCDestroy_HYPRE;
2274   pc->ops->setfromoptions = PCSetFromOptions_HYPRE;
2275   pc->ops->setup          = PCSetUp_HYPRE;
2276   pc->ops->apply          = PCApply_HYPRE;
2277   jac->comm_hypre         = MPI_COMM_NULL;
2278   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetType_C",PCHYPRESetType_HYPRE));
2279   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPREGetType_C",PCHYPREGetType_HYPRE));
2280   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSetCoordinates_C",PCSetCoordinates_HYPRE));
2281   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetDiscreteGradient_C",PCHYPRESetDiscreteGradient_HYPRE));
2282   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetDiscreteCurl_C",PCHYPRESetDiscreteCurl_HYPRE));
2283   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetInterpolations_C",PCHYPRESetInterpolations_HYPRE));
2284   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetEdgeConstantVectors_C",PCHYPRESetEdgeConstantVectors_HYPRE));
2285   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetPoissonMatrix_C",PCHYPRESetPoissonMatrix_HYPRE));
2286   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGGalerkinSetMatProductAlgorithm_C",PCMGGalerkinSetMatProductAlgorithm_HYPRE_BoomerAMG));
2287   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGGalerkinGetMatProductAlgorithm_C",PCMGGalerkinGetMatProductAlgorithm_HYPRE_BoomerAMG));
2288 #if defined(PETSC_HAVE_HYPRE_DEVICE)
2289 #if defined(HYPRE_USING_HIP)
2290   PetscCall(PetscDeviceInitialize(PETSC_DEVICE_HIP));
2291 #endif
2292 #if defined(HYPRE_USING_CUDA)
2293   PetscCall(PetscDeviceInitialize(PETSC_DEVICE_CUDA));
2294 #endif
2295 #endif
2296   PetscFunctionReturn(0);
2297 }
2298 
2299 /* ---------------------------------------------------------------------------------------------------------------------------------*/
2300 
2301 typedef struct {
2302   MPI_Comm           hcomm;        /* does not share comm with HYPRE_StructMatrix because need to create solver before getting matrix */
2303   HYPRE_StructSolver hsolver;
2304 
2305   /* keep copy of PFMG options used so may view them */
2306   PetscInt its;
2307   double   tol;
2308   PetscInt relax_type;
2309   PetscInt rap_type;
2310   PetscInt num_pre_relax,num_post_relax;
2311   PetscInt max_levels;
2312 } PC_PFMG;
2313 
2314 PetscErrorCode PCDestroy_PFMG(PC pc)
2315 {
2316   PC_PFMG        *ex = (PC_PFMG*) pc->data;
2317 
2318   PetscFunctionBegin;
2319   if (ex->hsolver) PetscStackCallStandard(HYPRE_StructPFMGDestroy,ex->hsolver);
2320   PetscCall(PetscCommRestoreComm(PetscObjectComm((PetscObject)pc),&ex->hcomm));
2321   PetscCall(PetscFree(pc->data));
2322   PetscFunctionReturn(0);
2323 }
2324 
2325 static const char *PFMGRelaxType[] = {"Jacobi","Weighted-Jacobi","symmetric-Red/Black-Gauss-Seidel","Red/Black-Gauss-Seidel"};
2326 static const char *PFMGRAPType[] = {"Galerkin","non-Galerkin"};
2327 
2328 PetscErrorCode PCView_PFMG(PC pc,PetscViewer viewer)
2329 {
2330   PetscBool      iascii;
2331   PC_PFMG        *ex = (PC_PFMG*) pc->data;
2332 
2333   PetscFunctionBegin;
2334   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
2335   if (iascii) {
2336     PetscCall(PetscViewerASCIIPrintf(viewer,"  HYPRE PFMG preconditioning\n"));
2337     PetscCall(PetscViewerASCIIPrintf(viewer,"    max iterations %d\n",ex->its));
2338     PetscCall(PetscViewerASCIIPrintf(viewer,"    tolerance %g\n",ex->tol));
2339     PetscCall(PetscViewerASCIIPrintf(viewer,"    relax type %s\n",PFMGRelaxType[ex->relax_type]));
2340     PetscCall(PetscViewerASCIIPrintf(viewer,"    RAP type %s\n",PFMGRAPType[ex->rap_type]));
2341     PetscCall(PetscViewerASCIIPrintf(viewer,"    number pre-relax %d post-relax %d\n",ex->num_pre_relax,ex->num_post_relax));
2342     PetscCall(PetscViewerASCIIPrintf(viewer,"    max levels %d\n",ex->max_levels));
2343   }
2344   PetscFunctionReturn(0);
2345 }
2346 
2347 PetscErrorCode PCSetFromOptions_PFMG(PetscOptionItems *PetscOptionsObject,PC pc)
2348 {
2349   PC_PFMG        *ex = (PC_PFMG*) pc->data;
2350   PetscBool      flg = PETSC_FALSE;
2351 
2352   PetscFunctionBegin;
2353   PetscCall(PetscOptionsHead(PetscOptionsObject,"PFMG options"));
2354   PetscCall(PetscOptionsBool("-pc_pfmg_print_statistics","Print statistics","HYPRE_StructPFMGSetPrintLevel",flg,&flg,NULL));
2355   if (flg) {
2356     PetscStackCallStandard(HYPRE_StructPFMGSetPrintLevel,ex->hsolver,3);
2357   }
2358   PetscCall(PetscOptionsInt("-pc_pfmg_its","Number of iterations of PFMG to use as preconditioner","HYPRE_StructPFMGSetMaxIter",ex->its,&ex->its,NULL));
2359   PetscStackCallStandard(HYPRE_StructPFMGSetMaxIter,ex->hsolver,ex->its);
2360   PetscCall(PetscOptionsInt("-pc_pfmg_num_pre_relax","Number of smoothing steps before coarse grid","HYPRE_StructPFMGSetNumPreRelax",ex->num_pre_relax,&ex->num_pre_relax,NULL));
2361   PetscStackCallStandard(HYPRE_StructPFMGSetNumPreRelax,ex->hsolver,ex->num_pre_relax);
2362   PetscCall(PetscOptionsInt("-pc_pfmg_num_post_relax","Number of smoothing steps after coarse grid","HYPRE_StructPFMGSetNumPostRelax",ex->num_post_relax,&ex->num_post_relax,NULL));
2363   PetscStackCallStandard(HYPRE_StructPFMGSetNumPostRelax,ex->hsolver,ex->num_post_relax);
2364 
2365   PetscCall(PetscOptionsInt("-pc_pfmg_max_levels","Max Levels for MG hierarchy","HYPRE_StructPFMGSetMaxLevels",ex->max_levels,&ex->max_levels,NULL));
2366   PetscStackCallStandard(HYPRE_StructPFMGSetMaxLevels,ex->hsolver,ex->max_levels);
2367 
2368   PetscCall(PetscOptionsReal("-pc_pfmg_tol","Tolerance of PFMG","HYPRE_StructPFMGSetTol",ex->tol,&ex->tol,NULL));
2369   PetscStackCallStandard(HYPRE_StructPFMGSetTol,ex->hsolver,ex->tol);
2370   PetscCall(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));
2371   PetscStackCallStandard(HYPRE_StructPFMGSetRelaxType,ex->hsolver, ex->relax_type);
2372   PetscCall(PetscOptionsEList("-pc_pfmg_rap_type","RAP type","HYPRE_StructPFMGSetRAPType",PFMGRAPType,ALEN(PFMGRAPType),PFMGRAPType[ex->rap_type],&ex->rap_type,NULL));
2373   PetscStackCallStandard(HYPRE_StructPFMGSetRAPType,ex->hsolver, ex->rap_type);
2374   PetscCall(PetscOptionsTail());
2375   PetscFunctionReturn(0);
2376 }
2377 
2378 PetscErrorCode PCApply_PFMG(PC pc,Vec x,Vec y)
2379 {
2380   PC_PFMG           *ex = (PC_PFMG*) pc->data;
2381   PetscScalar       *yy;
2382   const PetscScalar *xx;
2383   PetscInt          ilower[3],iupper[3];
2384   HYPRE_Int         hlower[3],hupper[3];
2385   Mat_HYPREStruct   *mx = (Mat_HYPREStruct*)(pc->pmat->data);
2386 
2387   PetscFunctionBegin;
2388   PetscCall(PetscCitationsRegister(hypreCitation,&cite));
2389   PetscCall(DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]));
2390   /* when HYPRE_MIXEDINT is defined, sizeof(HYPRE_Int) == 32 */
2391   iupper[0] += ilower[0] - 1;
2392   iupper[1] += ilower[1] - 1;
2393   iupper[2] += ilower[2] - 1;
2394   hlower[0]  = (HYPRE_Int)ilower[0];
2395   hlower[1]  = (HYPRE_Int)ilower[1];
2396   hlower[2]  = (HYPRE_Int)ilower[2];
2397   hupper[0]  = (HYPRE_Int)iupper[0];
2398   hupper[1]  = (HYPRE_Int)iupper[1];
2399   hupper[2]  = (HYPRE_Int)iupper[2];
2400 
2401   /* copy x values over to hypre */
2402   PetscStackCallStandard(HYPRE_StructVectorSetConstantValues,mx->hb,0.0);
2403   PetscCall(VecGetArrayRead(x,&xx));
2404   PetscStackCallStandard(HYPRE_StructVectorSetBoxValues,mx->hb,hlower,hupper,(HYPRE_Complex*)xx);
2405   PetscCall(VecRestoreArrayRead(x,&xx));
2406   PetscStackCallStandard(HYPRE_StructVectorAssemble,mx->hb);
2407   PetscStackCallStandard(HYPRE_StructPFMGSolve,ex->hsolver,mx->hmat,mx->hb,mx->hx);
2408 
2409   /* copy solution values back to PETSc */
2410   PetscCall(VecGetArray(y,&yy));
2411   PetscStackCallStandard(HYPRE_StructVectorGetBoxValues,mx->hx,hlower,hupper,(HYPRE_Complex*)yy);
2412   PetscCall(VecRestoreArray(y,&yy));
2413   PetscFunctionReturn(0);
2414 }
2415 
2416 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)
2417 {
2418   PC_PFMG        *jac = (PC_PFMG*)pc->data;
2419   HYPRE_Int      oits;
2420 
2421   PetscFunctionBegin;
2422   PetscCall(PetscCitationsRegister(hypreCitation,&cite));
2423   PetscStackCallStandard(HYPRE_StructPFMGSetMaxIter,jac->hsolver,its*jac->its);
2424   PetscStackCallStandard(HYPRE_StructPFMGSetTol,jac->hsolver,rtol);
2425 
2426   PetscCall(PCApply_PFMG(pc,b,y));
2427   PetscStackCallStandard(HYPRE_StructPFMGGetNumIterations,jac->hsolver,&oits);
2428   *outits = oits;
2429   if (oits == its) *reason = PCRICHARDSON_CONVERGED_ITS;
2430   else             *reason = PCRICHARDSON_CONVERGED_RTOL;
2431   PetscStackCallStandard(HYPRE_StructPFMGSetTol,jac->hsolver,jac->tol);
2432   PetscStackCallStandard(HYPRE_StructPFMGSetMaxIter,jac->hsolver,jac->its);
2433   PetscFunctionReturn(0);
2434 }
2435 
2436 PetscErrorCode PCSetUp_PFMG(PC pc)
2437 {
2438   PC_PFMG         *ex = (PC_PFMG*) pc->data;
2439   Mat_HYPREStruct *mx = (Mat_HYPREStruct*)(pc->pmat->data);
2440   PetscBool       flg;
2441 
2442   PetscFunctionBegin;
2443   PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat,MATHYPRESTRUCT,&flg));
2444   PetscCheck(flg,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Must use MATHYPRESTRUCT with this preconditioner");
2445 
2446   /* create the hypre solver object and set its information */
2447   if (ex->hsolver) PetscStackCallStandard(HYPRE_StructPFMGDestroy,ex->hsolver);
2448   PetscStackCallStandard(HYPRE_StructPFMGCreate,ex->hcomm,&ex->hsolver);
2449   PetscStackCallStandard(HYPRE_StructPFMGSetup,ex->hsolver,mx->hmat,mx->hb,mx->hx);
2450   PetscStackCallStandard(HYPRE_StructPFMGSetZeroGuess,ex->hsolver);
2451   PetscFunctionReturn(0);
2452 }
2453 
2454 /*MC
2455      PCPFMG - the hypre PFMG multigrid solver
2456 
2457    Level: advanced
2458 
2459    Options Database:
2460 + -pc_pfmg_its <its> - number of iterations of PFMG to use as preconditioner
2461 . -pc_pfmg_num_pre_relax <steps> - number of smoothing steps before coarse grid solve
2462 . -pc_pfmg_num_post_relax <steps> - number of smoothing steps after coarse grid solve
2463 . -pc_pfmg_tol <tol> - tolerance of PFMG
2464 . -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
2465 - -pc_pfmg_rap_type - type of coarse matrix generation, one of Galerkin,non-Galerkin
2466 
2467    Notes:
2468     This is for CELL-centered descretizations
2469 
2470            This must be used with the MATHYPRESTRUCT matrix type.
2471            This is less general than in hypre, it supports only one block per process defined by a PETSc DMDA.
2472 
2473 .seealso:  PCMG, MATHYPRESTRUCT
2474 M*/
2475 
2476 PETSC_EXTERN PetscErrorCode PCCreate_PFMG(PC pc)
2477 {
2478   PC_PFMG        *ex;
2479 
2480   PetscFunctionBegin;
2481   PetscCall(PetscNew(&ex)); \
2482   pc->data = ex;
2483 
2484   ex->its            = 1;
2485   ex->tol            = 1.e-8;
2486   ex->relax_type     = 1;
2487   ex->rap_type       = 0;
2488   ex->num_pre_relax  = 1;
2489   ex->num_post_relax = 1;
2490   ex->max_levels     = 0;
2491 
2492   pc->ops->setfromoptions  = PCSetFromOptions_PFMG;
2493   pc->ops->view            = PCView_PFMG;
2494   pc->ops->destroy         = PCDestroy_PFMG;
2495   pc->ops->apply           = PCApply_PFMG;
2496   pc->ops->applyrichardson = PCApplyRichardson_PFMG;
2497   pc->ops->setup           = PCSetUp_PFMG;
2498 
2499   PetscCall(PetscCommGetComm(PetscObjectComm((PetscObject)pc),&ex->hcomm));
2500   PetscStackCallStandard(HYPRE_StructPFMGCreate,ex->hcomm,&ex->hsolver);
2501   PetscFunctionReturn(0);
2502 }
2503 
2504 /* ---------------------------------------------------------------------------------------------------------------------------------------------------*/
2505 
2506 /* we know we are working with a HYPRE_SStructMatrix */
2507 typedef struct {
2508   MPI_Comm            hcomm;       /* does not share comm with HYPRE_SStructMatrix because need to create solver before getting matrix */
2509   HYPRE_SStructSolver ss_solver;
2510 
2511   /* keep copy of SYSPFMG options used so may view them */
2512   PetscInt its;
2513   double   tol;
2514   PetscInt relax_type;
2515   PetscInt num_pre_relax,num_post_relax;
2516 } PC_SysPFMG;
2517 
2518 PetscErrorCode PCDestroy_SysPFMG(PC pc)
2519 {
2520   PC_SysPFMG     *ex = (PC_SysPFMG*) pc->data;
2521 
2522   PetscFunctionBegin;
2523   if (ex->ss_solver) PetscStackCallStandard(HYPRE_SStructSysPFMGDestroy,ex->ss_solver);
2524   PetscCall(PetscCommRestoreComm(PetscObjectComm((PetscObject)pc),&ex->hcomm));
2525   PetscCall(PetscFree(pc->data));
2526   PetscFunctionReturn(0);
2527 }
2528 
2529 static const char *SysPFMGRelaxType[] = {"Weighted-Jacobi","Red/Black-Gauss-Seidel"};
2530 
2531 PetscErrorCode PCView_SysPFMG(PC pc,PetscViewer viewer)
2532 {
2533   PetscBool      iascii;
2534   PC_SysPFMG     *ex = (PC_SysPFMG*) pc->data;
2535 
2536   PetscFunctionBegin;
2537   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
2538   if (iascii) {
2539     PetscCall(PetscViewerASCIIPrintf(viewer,"  HYPRE SysPFMG preconditioning\n"));
2540     PetscCall(PetscViewerASCIIPrintf(viewer,"  max iterations %d\n",ex->its));
2541     PetscCall(PetscViewerASCIIPrintf(viewer,"  tolerance %g\n",ex->tol));
2542     PetscCall(PetscViewerASCIIPrintf(viewer,"  relax type %s\n",PFMGRelaxType[ex->relax_type]));
2543     PetscCall(PetscViewerASCIIPrintf(viewer,"  number pre-relax %d post-relax %d\n",ex->num_pre_relax,ex->num_post_relax));
2544   }
2545   PetscFunctionReturn(0);
2546 }
2547 
2548 PetscErrorCode PCSetFromOptions_SysPFMG(PetscOptionItems *PetscOptionsObject,PC pc)
2549 {
2550   PC_SysPFMG     *ex = (PC_SysPFMG*) pc->data;
2551   PetscBool      flg = PETSC_FALSE;
2552 
2553   PetscFunctionBegin;
2554   PetscCall(PetscOptionsHead(PetscOptionsObject,"SysPFMG options"));
2555   PetscCall(PetscOptionsBool("-pc_syspfmg_print_statistics","Print statistics","HYPRE_SStructSysPFMGSetPrintLevel",flg,&flg,NULL));
2556   if (flg) {
2557     PetscStackCallStandard(HYPRE_SStructSysPFMGSetPrintLevel,ex->ss_solver,3);
2558   }
2559   PetscCall(PetscOptionsInt("-pc_syspfmg_its","Number of iterations of SysPFMG to use as preconditioner","HYPRE_SStructSysPFMGSetMaxIter",ex->its,&ex->its,NULL));
2560   PetscStackCallStandard(HYPRE_SStructSysPFMGSetMaxIter,ex->ss_solver,ex->its);
2561   PetscCall(PetscOptionsInt("-pc_syspfmg_num_pre_relax","Number of smoothing steps before coarse grid","HYPRE_SStructSysPFMGSetNumPreRelax",ex->num_pre_relax,&ex->num_pre_relax,NULL));
2562   PetscStackCallStandard(HYPRE_SStructSysPFMGSetNumPreRelax,ex->ss_solver,ex->num_pre_relax);
2563   PetscCall(PetscOptionsInt("-pc_syspfmg_num_post_relax","Number of smoothing steps after coarse grid","HYPRE_SStructSysPFMGSetNumPostRelax",ex->num_post_relax,&ex->num_post_relax,NULL));
2564   PetscStackCallStandard(HYPRE_SStructSysPFMGSetNumPostRelax,ex->ss_solver,ex->num_post_relax);
2565 
2566   PetscCall(PetscOptionsReal("-pc_syspfmg_tol","Tolerance of SysPFMG","HYPRE_SStructSysPFMGSetTol",ex->tol,&ex->tol,NULL));
2567   PetscStackCallStandard(HYPRE_SStructSysPFMGSetTol,ex->ss_solver,ex->tol);
2568   PetscCall(PetscOptionsEList("-pc_syspfmg_relax_type","Relax type for the up and down cycles","HYPRE_SStructSysPFMGSetRelaxType",SysPFMGRelaxType,ALEN(SysPFMGRelaxType),SysPFMGRelaxType[ex->relax_type],&ex->relax_type,NULL));
2569   PetscStackCallStandard(HYPRE_SStructSysPFMGSetRelaxType,ex->ss_solver, ex->relax_type);
2570   PetscCall(PetscOptionsTail());
2571   PetscFunctionReturn(0);
2572 }
2573 
2574 PetscErrorCode PCApply_SysPFMG(PC pc,Vec x,Vec y)
2575 {
2576   PC_SysPFMG        *ex = (PC_SysPFMG*) pc->data;
2577   PetscScalar       *yy;
2578   const PetscScalar *xx;
2579   PetscInt          ilower[3],iupper[3];
2580   HYPRE_Int         hlower[3],hupper[3];
2581   Mat_HYPRESStruct  *mx     = (Mat_HYPRESStruct*)(pc->pmat->data);
2582   PetscInt          ordering= mx->dofs_order;
2583   PetscInt          nvars   = mx->nvars;
2584   PetscInt          part    = 0;
2585   PetscInt          size;
2586   PetscInt          i;
2587 
2588   PetscFunctionBegin;
2589   PetscCall(PetscCitationsRegister(hypreCitation,&cite));
2590   PetscCall(DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]));
2591   /* when HYPRE_MIXEDINT is defined, sizeof(HYPRE_Int) == 32 */
2592   iupper[0] += ilower[0] - 1;
2593   iupper[1] += ilower[1] - 1;
2594   iupper[2] += ilower[2] - 1;
2595   hlower[0]  = (HYPRE_Int)ilower[0];
2596   hlower[1]  = (HYPRE_Int)ilower[1];
2597   hlower[2]  = (HYPRE_Int)ilower[2];
2598   hupper[0]  = (HYPRE_Int)iupper[0];
2599   hupper[1]  = (HYPRE_Int)iupper[1];
2600   hupper[2]  = (HYPRE_Int)iupper[2];
2601 
2602   size = 1;
2603   for (i= 0; i< 3; i++) size *= (iupper[i]-ilower[i]+1);
2604 
2605   /* copy x values over to hypre for variable ordering */
2606   if (ordering) {
2607     PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,mx->ss_b,0.0);
2608     PetscCall(VecGetArrayRead(x,&xx));
2609     for (i= 0; i< nvars; i++) PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,mx->ss_b,part,hlower,hupper,i,(HYPRE_Complex*)(xx+(size*i)));
2610     PetscCall(VecRestoreArrayRead(x,&xx));
2611     PetscStackCallStandard(HYPRE_SStructVectorAssemble,mx->ss_b);
2612     PetscStackCallStandard(HYPRE_SStructMatrixMatvec,1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x);
2613     PetscStackCallStandard(HYPRE_SStructSysPFMGSolve,ex->ss_solver,mx->ss_mat,mx->ss_b,mx->ss_x);
2614 
2615     /* copy solution values back to PETSc */
2616     PetscCall(VecGetArray(y,&yy));
2617     for (i= 0; i< nvars; i++) PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,mx->ss_x,part,hlower,hupper,i,(HYPRE_Complex*)(yy+(size*i)));
2618     PetscCall(VecRestoreArray(y,&yy));
2619   } else {      /* nodal ordering must be mapped to variable ordering for sys_pfmg */
2620     PetscScalar *z;
2621     PetscInt    j, k;
2622 
2623     PetscCall(PetscMalloc1(nvars*size,&z));
2624     PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,mx->ss_b,0.0);
2625     PetscCall(VecGetArrayRead(x,&xx));
2626 
2627     /* transform nodal to hypre's variable ordering for sys_pfmg */
2628     for (i= 0; i< size; i++) {
2629       k= i*nvars;
2630       for (j= 0; j< nvars; j++) z[j*size+i]= xx[k+j];
2631     }
2632     for (i= 0; i< nvars; i++) PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,mx->ss_b,part,hlower,hupper,i,(HYPRE_Complex*)(z+(size*i)));
2633     PetscCall(VecRestoreArrayRead(x,&xx));
2634     PetscStackCallStandard(HYPRE_SStructVectorAssemble,mx->ss_b);
2635     PetscStackCallStandard(HYPRE_SStructSysPFMGSolve,ex->ss_solver,mx->ss_mat,mx->ss_b,mx->ss_x);
2636 
2637     /* copy solution values back to PETSc */
2638     PetscCall(VecGetArray(y,&yy));
2639     for (i= 0; i< nvars; i++) PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,mx->ss_x,part,hlower,hupper,i,(HYPRE_Complex*)(z+(size*i)));
2640     /* transform hypre's variable ordering for sys_pfmg to nodal ordering */
2641     for (i= 0; i< size; i++) {
2642       k= i*nvars;
2643       for (j= 0; j< nvars; j++) yy[k+j]= z[j*size+i];
2644     }
2645     PetscCall(VecRestoreArray(y,&yy));
2646     PetscCall(PetscFree(z));
2647   }
2648   PetscFunctionReturn(0);
2649 }
2650 
2651 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)
2652 {
2653   PC_SysPFMG     *jac = (PC_SysPFMG*)pc->data;
2654   HYPRE_Int      oits;
2655 
2656   PetscFunctionBegin;
2657   PetscCall(PetscCitationsRegister(hypreCitation,&cite));
2658   PetscStackCallStandard(HYPRE_SStructSysPFMGSetMaxIter,jac->ss_solver,its*jac->its);
2659   PetscStackCallStandard(HYPRE_SStructSysPFMGSetTol,jac->ss_solver,rtol);
2660   PetscCall(PCApply_SysPFMG(pc,b,y));
2661   PetscStackCallStandard(HYPRE_SStructSysPFMGGetNumIterations,jac->ss_solver,&oits);
2662   *outits = oits;
2663   if (oits == its) *reason = PCRICHARDSON_CONVERGED_ITS;
2664   else             *reason = PCRICHARDSON_CONVERGED_RTOL;
2665   PetscStackCallStandard(HYPRE_SStructSysPFMGSetTol,jac->ss_solver,jac->tol);
2666   PetscStackCallStandard(HYPRE_SStructSysPFMGSetMaxIter,jac->ss_solver,jac->its);
2667   PetscFunctionReturn(0);
2668 }
2669 
2670 PetscErrorCode PCSetUp_SysPFMG(PC pc)
2671 {
2672   PC_SysPFMG       *ex = (PC_SysPFMG*) pc->data;
2673   Mat_HYPRESStruct *mx = (Mat_HYPRESStruct*)(pc->pmat->data);
2674   PetscBool        flg;
2675 
2676   PetscFunctionBegin;
2677   PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat,MATHYPRESSTRUCT,&flg));
2678   PetscCheck(flg,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Must use MATHYPRESSTRUCT with this preconditioner");
2679 
2680   /* create the hypre sstruct solver object and set its information */
2681   if (ex->ss_solver) PetscStackCallStandard(HYPRE_SStructSysPFMGDestroy,ex->ss_solver);
2682   PetscStackCallStandard(HYPRE_SStructSysPFMGCreate,ex->hcomm,&ex->ss_solver);
2683   PetscStackCallStandard(HYPRE_SStructSysPFMGSetZeroGuess,ex->ss_solver);
2684   PetscStackCallStandard(HYPRE_SStructSysPFMGSetup,ex->ss_solver,mx->ss_mat,mx->ss_b,mx->ss_x);
2685   PetscFunctionReturn(0);
2686 }
2687 
2688 /*MC
2689      PCSysPFMG - the hypre SysPFMG multigrid solver
2690 
2691    Level: advanced
2692 
2693    Options Database:
2694 + -pc_syspfmg_its <its> - number of iterations of SysPFMG to use as preconditioner
2695 . -pc_syspfmg_num_pre_relax <steps> - number of smoothing steps before coarse grid
2696 . -pc_syspfmg_num_post_relax <steps> - number of smoothing steps after coarse grid
2697 . -pc_syspfmg_tol <tol> - tolerance of SysPFMG
2698 - -pc_syspfmg_relax_type <Weighted-Jacobi,Red/Black-Gauss-Seidel> - relaxation type for the up and down cycles
2699 
2700    Notes:
2701     This is for CELL-centered descretizations
2702 
2703            This must be used with the MATHYPRESSTRUCT matrix type.
2704            This is less general than in hypre, it supports only one part, and one block per process defined by a PETSc DMDA.
2705            Also, only cell-centered variables.
2706 
2707 .seealso:  PCMG, MATHYPRESSTRUCT
2708 M*/
2709 
2710 PETSC_EXTERN PetscErrorCode PCCreate_SysPFMG(PC pc)
2711 {
2712   PC_SysPFMG     *ex;
2713 
2714   PetscFunctionBegin;
2715   PetscCall(PetscNew(&ex)); \
2716   pc->data = ex;
2717 
2718   ex->its            = 1;
2719   ex->tol            = 1.e-8;
2720   ex->relax_type     = 1;
2721   ex->num_pre_relax  = 1;
2722   ex->num_post_relax = 1;
2723 
2724   pc->ops->setfromoptions  = PCSetFromOptions_SysPFMG;
2725   pc->ops->view            = PCView_SysPFMG;
2726   pc->ops->destroy         = PCDestroy_SysPFMG;
2727   pc->ops->apply           = PCApply_SysPFMG;
2728   pc->ops->applyrichardson = PCApplyRichardson_SysPFMG;
2729   pc->ops->setup           = PCSetUp_SysPFMG;
2730 
2731   PetscCall(PetscCommGetComm(PetscObjectComm((PetscObject)pc),&ex->hcomm));
2732   PetscStackCallStandard(HYPRE_SStructSysPFMGCreate,ex->hcomm,&ex->ss_solver);
2733   PetscFunctionReturn(0);
2734 }
2735