xref: /petsc/src/ksp/pc/impls/hypre/hypre.c (revision 4ffacfe27a72f4cdf51b68a3bbb6aed96040fb2f)
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,"PCHYPRESetDiscreteGradient_C",NULL));
504   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetDiscreteCurl_C",NULL));
505   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetInterpolations_C",NULL));
506   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetConstantEdgeVectors_C",NULL));
507   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetPoissonMatrix_C",NULL));
508   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetEdgeConstantVectors_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   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSetCoordinates_C",NULL));
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   PetscOptionsHeadBegin(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   PetscOptionsHeadEnd();
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 %" PetscInt_FMT "\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 %" PetscInt_FMT "\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   PetscOptionsHeadBegin(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   PetscOptionsHeadEnd();
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 %" PetscInt_FMT "\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? %" PetscInt_FMT "\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 PetscErrorCode PCMGGalerkinSetMatProductAlgorithm_HYPRE_BoomerAMG(PC pc,const char name[])
646 {
647   PC_HYPRE *jac  = (PC_HYPRE*)pc->data;
648   PetscBool      flag;
649 
650 #if PETSC_PKG_HYPRE_VERSION_GE(2,23,0)
651   PetscFunctionBegin;
652   if (jac->spgemm_type) {
653     PetscCall(PetscStrcmp(jac->spgemm_type,name,&flag));
654     PetscCheck(flag,PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Cannot reset the HYPRE SpGEMM (really we can)");
655     PetscFunctionReturn(0);
656   } else {
657     PetscCall(PetscStrallocpy(name, &jac->spgemm_type));
658   }
659   PetscCall(PetscStrcmp("cusparse",jac->spgemm_type,&flag));
660   if (flag) {
661     PetscStackCallStandard(HYPRE_SetSpGemmUseCusparse,1);
662     PetscFunctionReturn(0);
663   }
664   PetscCall(PetscStrcmp("hypre",jac->spgemm_type,&flag));
665   if (flag) {
666     PetscStackCallStandard(HYPRE_SetSpGemmUseCusparse,0);
667     PetscFunctionReturn(0);
668   }
669   jac->spgemm_type = NULL;
670   SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown HYPRE SpGEM type %s; Choices are cusparse, hypre",name);
671 #endif
672 }
673 
674 static PetscErrorCode PCMGGalerkinGetMatProductAlgorithm_HYPRE_BoomerAMG(PC pc, const char *spgemm[])
675 {
676   PC_HYPRE *jac  = (PC_HYPRE*)pc->data;
677 
678   PetscFunctionBegin;
679   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
680 #if PETSC_PKG_HYPRE_VERSION_GE(2,23,0)
681   *spgemm = jac->spgemm_type;
682 #endif
683   PetscFunctionReturn(0);
684 }
685 
686 static const char *HYPREBoomerAMGCycleType[]   = {"","V","W"};
687 static const char *HYPREBoomerAMGCoarsenType[] = {"CLJP","Ruge-Stueben","","modifiedRuge-Stueben","","","Falgout", "", "PMIS", "", "HMIS"};
688 static const char *HYPREBoomerAMGMeasureType[] = {"local","global"};
689 /* The following corresponds to HYPRE_BoomerAMGSetRelaxType which has many missing numbers in the enum */
690 static const char *HYPREBoomerAMGSmoothType[]  = {"Schwarz-smoothers","Pilut","ParaSails","Euclid"};
691 static const char *HYPREBoomerAMGRelaxType[]   = {"Jacobi","sequential-Gauss-Seidel","seqboundary-Gauss-Seidel","SOR/Jacobi","backward-SOR/Jacobi",
692                                                   "" /* [5] hybrid chaotic Gauss-Seidel (works only with OpenMP) */,"symmetric-SOR/Jacobi",
693                                                   "" /* 7 */,"l1scaled-SOR/Jacobi","Gaussian-elimination",
694                                                   "" /* 10 */, "" /* 11 */, "" /* 12 */, "l1-Gauss-Seidel" /* nonsymmetric */, "backward-l1-Gauss-Seidel" /* nonsymmetric */,
695                                                   "CG" /* non-stationary */,"Chebyshev","FCF-Jacobi","l1scaled-Jacobi"};
696 static const char *HYPREBoomerAMGInterpType[]  = {"classical", "", "", "direct", "multipass", "multipass-wts", "ext+i",
697                                                   "ext+i-cc", "standard", "standard-wts", "block", "block-wtd", "FF", "FF1",
698                                                   "ext", "ad-wts", "ext-mm", "ext+i-mm", "ext+e-mm"};
699 static PetscErrorCode PCSetFromOptions_HYPRE_BoomerAMG(PetscOptionItems *PetscOptionsObject,PC pc)
700 {
701   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
702   PetscInt       bs,n,indx,level;
703   PetscBool      flg, tmp_truth;
704   double         tmpdbl, twodbl[2];
705   const char     *symtlist[] = {"nonsymmetric","SPD","nonsymmetric,SPD"};
706   const char     *PCHYPRESpgemmTypes[] = {"cusparse","hypre"};
707 
708   PetscFunctionBegin;
709   PetscOptionsHeadBegin(PetscOptionsObject,"HYPRE BoomerAMG Options");
710   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_cycle_type","Cycle type","None",HYPREBoomerAMGCycleType+1,2,HYPREBoomerAMGCycleType[jac->cycletype],&indx,&flg));
711   if (flg) {
712     jac->cycletype = indx+1;
713     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleType,jac->hsolver,jac->cycletype);
714   }
715   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_max_levels","Number of levels (of grids) allowed","None",jac->maxlevels,&jac->maxlevels,&flg));
716   if (flg) {
717     PetscCheck(jac->maxlevels >= 2,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Number of levels %" PetscInt_FMT " must be at least two",jac->maxlevels);
718     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxLevels,jac->hsolver,jac->maxlevels);
719   }
720   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_max_iter","Maximum iterations used PER hypre call","None",jac->maxiter,&jac->maxiter,&flg));
721   if (flg) {
722     PetscCheck(jac->maxiter >= 1,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Number of iterations %" PetscInt_FMT " must be at least one",jac->maxiter);
723     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxIter,jac->hsolver,jac->maxiter);
724   }
725   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));
726   if (flg) {
727     PetscCheck(jac->tol >= 0.0,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Tolerance %g must be greater than or equal to zero",(double)jac->tol);
728     PetscStackCallStandard(HYPRE_BoomerAMGSetTol,jac->hsolver,jac->tol);
729   }
730   bs = 1;
731   if (pc->pmat) {
732     PetscCall(MatGetBlockSize(pc->pmat,&bs));
733   }
734   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_numfunctions","Number of functions","HYPRE_BoomerAMGSetNumFunctions",bs,&bs,&flg));
735   if (flg) {
736     PetscStackCallStandard(HYPRE_BoomerAMGSetNumFunctions,jac->hsolver,bs);
737   }
738 
739   PetscCall(PetscOptionsReal("-pc_hypre_boomeramg_truncfactor","Truncation factor for interpolation (0=no truncation)","None",jac->truncfactor,&jac->truncfactor,&flg));
740   if (flg) {
741     PetscCheck(jac->truncfactor >= 0.0,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Truncation factor %g must be great than or equal zero",(double)jac->truncfactor);
742     PetscStackCallStandard(HYPRE_BoomerAMGSetTruncFactor,jac->hsolver,jac->truncfactor);
743   }
744 
745   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_P_max","Max elements per row for interpolation operator (0=unlimited)","None",jac->pmax,&jac->pmax,&flg));
746   if (flg) {
747     PetscCheck(jac->pmax >= 0,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"P_max %" PetscInt_FMT " must be greater than or equal to zero",jac->pmax);
748     PetscStackCallStandard(HYPRE_BoomerAMGSetPMaxElmts,jac->hsolver,jac->pmax);
749   }
750 
751   PetscCall(PetscOptionsRangeInt("-pc_hypre_boomeramg_agg_nl","Number of levels of aggressive coarsening","None",jac->agg_nl,&jac->agg_nl,&flg,0,jac->maxlevels));
752   if (flg) PetscStackCallStandard(HYPRE_BoomerAMGSetAggNumLevels,jac->hsolver,jac->agg_nl);
753 
754   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_agg_num_paths","Number of paths for aggressive coarsening","None",jac->agg_num_paths,&jac->agg_num_paths,&flg));
755   if (flg) {
756     PetscCheck(jac->agg_num_paths >= 1,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Number of paths %" PetscInt_FMT " must be greater than or equal to 1",jac->agg_num_paths);
757     PetscStackCallStandard(HYPRE_BoomerAMGSetNumPaths,jac->hsolver,jac->agg_num_paths);
758   }
759 
760   PetscCall(PetscOptionsReal("-pc_hypre_boomeramg_strong_threshold","Threshold for being strongly connected","None",jac->strongthreshold,&jac->strongthreshold,&flg));
761   if (flg) {
762     PetscCheck(jac->strongthreshold >= 0.0,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Strong threshold %g must be great than or equal zero",(double)jac->strongthreshold);
763     PetscStackCallStandard(HYPRE_BoomerAMGSetStrongThreshold,jac->hsolver,jac->strongthreshold);
764   }
765   PetscCall(PetscOptionsReal("-pc_hypre_boomeramg_max_row_sum","Maximum row sum","None",jac->maxrowsum,&jac->maxrowsum,&flg));
766   if (flg) {
767     PetscCheck(jac->maxrowsum >= 0.0,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Maximum row sum %g must be greater than zero",(double)jac->maxrowsum);
768     PetscCheck(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);
769     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxRowSum,jac->hsolver,jac->maxrowsum);
770   }
771 
772   /* Grid sweeps */
773   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_grid_sweeps_all","Number of sweeps for the up and down grid levels","None",jac->gridsweeps[0],&indx,&flg));
774   if (flg) {
775     PetscStackCallStandard(HYPRE_BoomerAMGSetNumSweeps,jac->hsolver,indx);
776     /* modify the jac structure so we can view the updated options with PC_View */
777     jac->gridsweeps[0] = indx;
778     jac->gridsweeps[1] = indx;
779     /*defaults coarse to 1 */
780     jac->gridsweeps[2] = 1;
781   }
782   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_nodal_coarsen","Use a nodal based coarsening 1-6","HYPRE_BoomerAMGSetNodal",jac->nodal_coarsening,&jac->nodal_coarsening,&flg));
783   if (flg) {
784     PetscStackCallStandard(HYPRE_BoomerAMGSetNodal,jac->hsolver,jac->nodal_coarsening);
785   }
786   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));
787   if (flg) {
788     PetscStackCallStandard(HYPRE_BoomerAMGSetNodalDiag,jac->hsolver,jac->nodal_coarsening_diag);
789   }
790   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_vec_interp_variant","Variant of algorithm 1-3","HYPRE_BoomerAMGSetInterpVecVariant",jac->vec_interp_variant, &jac->vec_interp_variant,&flg));
791   if (flg) {
792     PetscStackCallStandard(HYPRE_BoomerAMGSetInterpVecVariant,jac->hsolver,jac->vec_interp_variant);
793   }
794   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));
795   if (flg) {
796     PetscStackCallStandard(HYPRE_BoomerAMGSetInterpVecQMax,jac->hsolver,jac->vec_interp_qmax);
797   }
798   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));
799   if (flg) {
800     PetscStackCallStandard(HYPRE_BoomerAMGSetSmoothInterpVectors,jac->hsolver,jac->vec_interp_smooth);
801   }
802   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_interp_refine","Preprocess the interpolation matrix through iterative weight refinement","HYPRE_BoomerAMGSetInterpRefine",jac->interp_refine, &jac->interp_refine,&flg));
803   if (flg) {
804     PetscStackCallStandard(HYPRE_BoomerAMGSetInterpRefine,jac->hsolver,jac->interp_refine);
805   }
806   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_grid_sweeps_down","Number of sweeps for the down cycles","None",jac->gridsweeps[0], &indx,&flg));
807   if (flg) {
808     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleNumSweeps,jac->hsolver,indx, 1);
809     jac->gridsweeps[0] = indx;
810   }
811   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_grid_sweeps_up","Number of sweeps for the up cycles","None",jac->gridsweeps[1],&indx,&flg));
812   if (flg) {
813     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleNumSweeps,jac->hsolver,indx, 2);
814     jac->gridsweeps[1] = indx;
815   }
816   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_grid_sweeps_coarse","Number of sweeps for the coarse level","None",jac->gridsweeps[2],&indx,&flg));
817   if (flg) {
818     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleNumSweeps,jac->hsolver,indx, 3);
819     jac->gridsweeps[2] = indx;
820   }
821 
822   /* Smooth type */
823   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_smooth_type","Enable more complex smoothers","None",HYPREBoomerAMGSmoothType,PETSC_STATIC_ARRAY_LENGTH(HYPREBoomerAMGSmoothType),HYPREBoomerAMGSmoothType[0],&indx,&flg));
824   if (flg) {
825     jac->smoothtype = indx;
826     PetscStackCallStandard(HYPRE_BoomerAMGSetSmoothType,jac->hsolver,indx+6);
827     jac->smoothnumlevels = 25;
828     PetscStackCallStandard(HYPRE_BoomerAMGSetSmoothNumLevels,jac->hsolver,25);
829   }
830 
831   /* Number of smoothing levels */
832   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_smooth_num_levels","Number of levels on which more complex smoothers are used","None",25,&indx,&flg));
833   if (flg && (jac->smoothtype != -1)) {
834     jac->smoothnumlevels = indx;
835     PetscStackCallStandard(HYPRE_BoomerAMGSetSmoothNumLevels,jac->hsolver,indx);
836   }
837 
838   /* Number of levels for ILU(k) for Euclid */
839   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_eu_level","Number of levels for ILU(k) in Euclid smoother","None",0,&indx,&flg));
840   if (flg && (jac->smoothtype == 3)) {
841     jac->eu_level = indx;
842     PetscStackCallStandard(HYPRE_BoomerAMGSetEuLevel,jac->hsolver,indx);
843   }
844 
845   /* Filter for ILU(k) for Euclid */
846   double droptolerance;
847   PetscCall(PetscOptionsReal("-pc_hypre_boomeramg_eu_droptolerance","Drop tolerance for ILU(k) in Euclid smoother","None",0,&droptolerance,&flg));
848   if (flg && (jac->smoothtype == 3)) {
849     jac->eu_droptolerance = droptolerance;
850     PetscStackCallStandard(HYPRE_BoomerAMGSetEuLevel,jac->hsolver,droptolerance);
851   }
852 
853   /* Use Block Jacobi ILUT for Euclid */
854   PetscCall(PetscOptionsBool("-pc_hypre_boomeramg_eu_bj", "Use Block Jacobi for ILU in Euclid smoother?", "None", PETSC_FALSE, &tmp_truth, &flg));
855   if (flg && (jac->smoothtype == 3)) {
856     jac->eu_bj = tmp_truth;
857     PetscStackCallStandard(HYPRE_BoomerAMGSetEuBJ,jac->hsolver,jac->eu_bj);
858   }
859 
860   /* Relax type */
861   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_relax_type_all","Relax type for the up and down cycles","None",HYPREBoomerAMGRelaxType,PETSC_STATIC_ARRAY_LENGTH(HYPREBoomerAMGRelaxType),HYPREBoomerAMGRelaxType[6],&indx,&flg));
862   if (flg) {
863     jac->relaxtype[0] = jac->relaxtype[1]  = indx;
864     PetscStackCallStandard(HYPRE_BoomerAMGSetRelaxType,jac->hsolver, indx);
865     /* by default, coarse type set to 9 */
866     jac->relaxtype[2] = 9;
867     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleRelaxType,jac->hsolver, 9, 3);
868   }
869   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_relax_type_down","Relax type for the down cycles","None",HYPREBoomerAMGRelaxType,PETSC_STATIC_ARRAY_LENGTH(HYPREBoomerAMGRelaxType),HYPREBoomerAMGRelaxType[6],&indx,&flg));
870   if (flg) {
871     jac->relaxtype[0] = indx;
872     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleRelaxType,jac->hsolver, indx, 1);
873   }
874   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_relax_type_up","Relax type for the up cycles","None",HYPREBoomerAMGRelaxType,PETSC_STATIC_ARRAY_LENGTH(HYPREBoomerAMGRelaxType),HYPREBoomerAMGRelaxType[6],&indx,&flg));
875   if (flg) {
876     jac->relaxtype[1] = indx;
877     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleRelaxType,jac->hsolver, indx, 2);
878   }
879   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_relax_type_coarse","Relax type on coarse grid","None",HYPREBoomerAMGRelaxType,PETSC_STATIC_ARRAY_LENGTH(HYPREBoomerAMGRelaxType),HYPREBoomerAMGRelaxType[9],&indx,&flg));
880   if (flg) {
881     jac->relaxtype[2] = indx;
882     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleRelaxType,jac->hsolver, indx, 3);
883   }
884 
885   /* Relaxation Weight */
886   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));
887   if (flg) {
888     PetscStackCallStandard(HYPRE_BoomerAMGSetRelaxWt,jac->hsolver,tmpdbl);
889     jac->relaxweight = tmpdbl;
890   }
891 
892   n         = 2;
893   twodbl[0] = twodbl[1] = 1.0;
894   PetscCall(PetscOptionsRealArray("-pc_hypre_boomeramg_relax_weight_level","Set the relaxation weight for a particular level (weight,level)","None",twodbl, &n, &flg));
895   if (flg) {
896     if (n == 2) {
897       indx =  (int)PetscAbsReal(twodbl[1]);
898       PetscStackCallStandard(HYPRE_BoomerAMGSetLevelRelaxWt,jac->hsolver,twodbl[0],indx);
899     } 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 %" PetscInt_FMT,n);
900   }
901 
902   /* Outer relaxation Weight */
903   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));
904   if (flg) {
905     PetscStackCallStandard(HYPRE_BoomerAMGSetOuterWt,jac->hsolver, tmpdbl);
906     jac->outerrelaxweight = tmpdbl;
907   }
908 
909   n         = 2;
910   twodbl[0] = twodbl[1] = 1.0;
911   PetscCall(PetscOptionsRealArray("-pc_hypre_boomeramg_outer_relax_weight_level","Set the outer relaxation weight for a particular level (weight,level)","None",twodbl, &n, &flg));
912   if (flg) {
913     if (n == 2) {
914       indx =  (int)PetscAbsReal(twodbl[1]);
915       PetscStackCallStandard(HYPRE_BoomerAMGSetLevelOuterWt,jac->hsolver, twodbl[0], indx);
916     } 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 %" PetscInt_FMT,n);
917   }
918 
919   /* the Relax Order */
920   PetscCall(PetscOptionsBool("-pc_hypre_boomeramg_no_CF", "Do not use CF-relaxation", "None", PETSC_FALSE, &tmp_truth, &flg));
921 
922   if (flg && tmp_truth) {
923     jac->relaxorder = 0;
924     PetscStackCallStandard(HYPRE_BoomerAMGSetRelaxOrder,jac->hsolver, jac->relaxorder);
925   }
926   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_measure_type","Measure type","None",HYPREBoomerAMGMeasureType,PETSC_STATIC_ARRAY_LENGTH(HYPREBoomerAMGMeasureType),HYPREBoomerAMGMeasureType[0],&indx,&flg));
927   if (flg) {
928     jac->measuretype = indx;
929     PetscStackCallStandard(HYPRE_BoomerAMGSetMeasureType,jac->hsolver,jac->measuretype);
930   }
931   /* update list length 3/07 */
932   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_coarsen_type","Coarsen type","None",HYPREBoomerAMGCoarsenType,PETSC_STATIC_ARRAY_LENGTH(HYPREBoomerAMGCoarsenType),HYPREBoomerAMGCoarsenType[6],&indx,&flg));
933   if (flg) {
934     jac->coarsentype = indx;
935     PetscStackCallStandard(HYPRE_BoomerAMGSetCoarsenType,jac->hsolver,jac->coarsentype);
936   }
937 
938   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_max_coarse_size", "Maximum size of coarsest grid", "None", jac->maxc, &jac->maxc, &flg));
939   if (flg) {
940     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxCoarseSize,jac->hsolver, jac->maxc);
941   }
942   PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_min_coarse_size", "Minimum size of coarsest grid", "None", jac->minc, &jac->minc, &flg));
943   if (flg) {
944     PetscStackCallStandard(HYPRE_BoomerAMGSetMinCoarseSize,jac->hsolver, jac->minc);
945   }
946 #if PETSC_PKG_HYPRE_VERSION_GE(2,23,0)
947   // global parameter but is closely associated with BoomerAMG
948   PetscCall(PetscOptionsEList("-pc_mg_galerkin_mat_product_algorithm","Type of SpGEMM to use in hypre (only for now)","PCMGGalerkinSetMatProductAlgorithm",PCHYPRESpgemmTypes,PETSC_STATIC_ARRAY_LENGTH(PCHYPRESpgemmTypes),PCHYPRESpgemmTypes[0],&indx,&flg));
949   if (!flg) indx = 0;
950   PetscCall(PCMGGalerkinSetMatProductAlgorithm_HYPRE_BoomerAMG(pc,PCHYPRESpgemmTypes[indx]));
951 #endif
952   /* AIR */
953 #if PETSC_PKG_HYPRE_VERSION_GE(2,18,0)
954   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));
955   PetscStackCallStandard(HYPRE_BoomerAMGSetRestriction,jac->hsolver,jac->Rtype);
956   if (jac->Rtype) {
957     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 */
958 
959     PetscCall(PetscOptionsReal("-pc_hypre_boomeramg_strongthresholdR","Threshold for R","None",jac->Rstrongthreshold,&jac->Rstrongthreshold,NULL));
960     PetscStackCallStandard(HYPRE_BoomerAMGSetStrongThresholdR,jac->hsolver,jac->Rstrongthreshold);
961 
962     PetscCall(PetscOptionsReal("-pc_hypre_boomeramg_filterthresholdR","Filter threshold for R","None",jac->Rfilterthreshold,&jac->Rfilterthreshold,NULL));
963     PetscStackCallStandard(HYPRE_BoomerAMGSetFilterThresholdR,jac->hsolver,jac->Rfilterthreshold);
964 
965     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));
966     PetscStackCallStandard(HYPRE_BoomerAMGSetADropTol,jac->hsolver,jac->Adroptol);
967 
968     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));
969     PetscStackCallStandard(HYPRE_BoomerAMGSetADropType,jac->hsolver,jac->Adroptype);
970   }
971 #endif
972 
973 #if PETSC_PKG_HYPRE_VERSION_LE(9,9,9)
974   PetscCheck(!jac->Rtype || !jac->agg_nl,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"-pc_hypre_boomeramg_restriction_type (%" PetscInt_FMT ") and -pc_hypre_boomeramg_agg_nl (%" PetscInt_FMT ")",jac->Rtype,jac->agg_nl);
975 #endif
976 
977   /* new 3/07 */
978   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_interp_type","Interpolation type","None",HYPREBoomerAMGInterpType,PETSC_STATIC_ARRAY_LENGTH(HYPREBoomerAMGInterpType),HYPREBoomerAMGInterpType[0],&indx,&flg));
979   if (flg || jac->Rtype) {
980     if (flg) jac->interptype = indx;
981     PetscStackCallStandard(HYPRE_BoomerAMGSetInterpType,jac->hsolver,jac->interptype);
982   }
983 
984   PetscCall(PetscOptionsName("-pc_hypre_boomeramg_print_statistics","Print statistics","None",&flg));
985   if (flg) {
986     level = 3;
987     PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_print_statistics","Print statistics","None",level,&level,NULL));
988 
989     jac->printstatistics = PETSC_TRUE;
990     PetscStackCallStandard(HYPRE_BoomerAMGSetPrintLevel,jac->hsolver,level);
991   }
992 
993   PetscCall(PetscOptionsName("-pc_hypre_boomeramg_print_debug","Print debug information","None",&flg));
994   if (flg) {
995     level = 3;
996     PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_print_debug","Print debug information","None",level,&level,NULL));
997 
998     jac->printstatistics = PETSC_TRUE;
999     PetscStackCallStandard(HYPRE_BoomerAMGSetDebugFlag,jac->hsolver,level);
1000   }
1001 
1002   PetscCall(PetscOptionsBool("-pc_hypre_boomeramg_nodal_relaxation", "Nodal relaxation via Schwarz", "None", PETSC_FALSE, &tmp_truth, &flg));
1003   if (flg && tmp_truth) {
1004     PetscInt tmp_int;
1005     PetscCall(PetscOptionsInt("-pc_hypre_boomeramg_nodal_relaxation", "Nodal relaxation via Schwarz", "None",jac->nodal_relax_levels,&tmp_int,&flg));
1006     if (flg) jac->nodal_relax_levels = tmp_int;
1007     PetscStackCallStandard(HYPRE_BoomerAMGSetSmoothType,jac->hsolver,6);
1008     PetscStackCallStandard(HYPRE_BoomerAMGSetDomainType,jac->hsolver,1);
1009     PetscStackCallStandard(HYPRE_BoomerAMGSetOverlap,jac->hsolver,0);
1010     PetscStackCallStandard(HYPRE_BoomerAMGSetSmoothNumLevels,jac->hsolver,jac->nodal_relax_levels);
1011   }
1012 
1013   PetscCall(PetscOptionsBool("-pc_hypre_boomeramg_keeptranspose", "Avoid transpose matvecs in preconditioner application", "None", jac->keeptranspose, &jac->keeptranspose, NULL));
1014   PetscStackCallStandard(HYPRE_BoomerAMGSetKeepTranspose,jac->hsolver,jac->keeptranspose ? 1 : 0);
1015 
1016   /* options for ParaSails solvers */
1017   PetscCall(PetscOptionsEList("-pc_hypre_boomeramg_parasails_sym","Symmetry of matrix and preconditioner","None",symtlist,PETSC_STATIC_ARRAY_LENGTH(symtlist),symtlist[0],&indx,&flg));
1018   if (flg) {
1019     jac->symt = indx;
1020     PetscStackCallStandard(HYPRE_BoomerAMGSetSym,jac->hsolver,jac->symt);
1021   }
1022 
1023   PetscOptionsHeadEnd();
1024   PetscFunctionReturn(0);
1025 }
1026 
1027 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)
1028 {
1029   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1030   HYPRE_Int      oits;
1031 
1032   PetscFunctionBegin;
1033   PetscCall(PetscCitationsRegister(hypreCitation,&cite));
1034   PetscStackCallStandard(HYPRE_BoomerAMGSetMaxIter,jac->hsolver,its*jac->maxiter);
1035   PetscStackCallStandard(HYPRE_BoomerAMGSetTol,jac->hsolver,rtol);
1036   jac->applyrichardson = PETSC_TRUE;
1037   PetscCall(PCApply_HYPRE(pc,b,y));
1038   jac->applyrichardson = PETSC_FALSE;
1039   PetscStackCallStandard(HYPRE_BoomerAMGGetNumIterations,jac->hsolver,&oits);
1040   *outits = oits;
1041   if (oits == its) *reason = PCRICHARDSON_CONVERGED_ITS;
1042   else             *reason = PCRICHARDSON_CONVERGED_RTOL;
1043   PetscStackCallStandard(HYPRE_BoomerAMGSetTol,jac->hsolver,jac->tol);
1044   PetscStackCallStandard(HYPRE_BoomerAMGSetMaxIter,jac->hsolver,jac->maxiter);
1045   PetscFunctionReturn(0);
1046 }
1047 
1048 static PetscErrorCode PCView_HYPRE_BoomerAMG(PC pc,PetscViewer viewer)
1049 {
1050   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1051   PetscBool      iascii;
1052 
1053   PetscFunctionBegin;
1054   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
1055   if (iascii) {
1056     PetscCall(PetscViewerASCIIPrintf(viewer,"  HYPRE BoomerAMG preconditioning\n"));
1057     PetscCall(PetscViewerASCIIPrintf(viewer,"    Cycle type %s\n",HYPREBoomerAMGCycleType[jac->cycletype]));
1058     PetscCall(PetscViewerASCIIPrintf(viewer,"    Maximum number of levels %" PetscInt_FMT "\n",jac->maxlevels));
1059     PetscCall(PetscViewerASCIIPrintf(viewer,"    Maximum number of iterations PER hypre call %" PetscInt_FMT "\n",jac->maxiter));
1060     PetscCall(PetscViewerASCIIPrintf(viewer,"    Convergence tolerance PER hypre call %g\n",(double)jac->tol));
1061     PetscCall(PetscViewerASCIIPrintf(viewer,"    Threshold for strong coupling %g\n",(double)jac->strongthreshold));
1062     PetscCall(PetscViewerASCIIPrintf(viewer,"    Interpolation truncation factor %g\n",(double)jac->truncfactor));
1063     PetscCall(PetscViewerASCIIPrintf(viewer,"    Interpolation: max elements per row %" PetscInt_FMT "\n",jac->pmax));
1064     if (jac->interp_refine) {
1065       PetscCall(PetscViewerASCIIPrintf(viewer,"    Interpolation: number of steps of weighted refinement %" PetscInt_FMT "\n",jac->interp_refine));
1066     }
1067     PetscCall(PetscViewerASCIIPrintf(viewer,"    Number of levels of aggressive coarsening %" PetscInt_FMT "\n",jac->agg_nl));
1068     PetscCall(PetscViewerASCIIPrintf(viewer,"    Number of paths for aggressive coarsening %" PetscInt_FMT "\n",jac->agg_num_paths));
1069 
1070     PetscCall(PetscViewerASCIIPrintf(viewer,"    Maximum row sums %g\n",(double)jac->maxrowsum));
1071 
1072     PetscCall(PetscViewerASCIIPrintf(viewer,"    Sweeps down         %" PetscInt_FMT "\n",jac->gridsweeps[0]));
1073     PetscCall(PetscViewerASCIIPrintf(viewer,"    Sweeps up           %" PetscInt_FMT "\n",jac->gridsweeps[1]));
1074     PetscCall(PetscViewerASCIIPrintf(viewer,"    Sweeps on coarse    %" PetscInt_FMT "\n",jac->gridsweeps[2]));
1075 
1076     PetscCall(PetscViewerASCIIPrintf(viewer,"    Relax down          %s\n",HYPREBoomerAMGRelaxType[jac->relaxtype[0]]));
1077     PetscCall(PetscViewerASCIIPrintf(viewer,"    Relax up            %s\n",HYPREBoomerAMGRelaxType[jac->relaxtype[1]]));
1078     PetscCall(PetscViewerASCIIPrintf(viewer,"    Relax on coarse     %s\n",HYPREBoomerAMGRelaxType[jac->relaxtype[2]]));
1079 
1080     PetscCall(PetscViewerASCIIPrintf(viewer,"    Relax weight  (all)      %g\n",(double)jac->relaxweight));
1081     PetscCall(PetscViewerASCIIPrintf(viewer,"    Outer relax weight (all) %g\n",(double)jac->outerrelaxweight));
1082 
1083     if (jac->relaxorder) {
1084       PetscCall(PetscViewerASCIIPrintf(viewer,"    Using CF-relaxation\n"));
1085     } else {
1086       PetscCall(PetscViewerASCIIPrintf(viewer,"    Not using CF-relaxation\n"));
1087     }
1088     if (jac->smoothtype!=-1) {
1089       PetscCall(PetscViewerASCIIPrintf(viewer,"    Smooth type          %s\n",HYPREBoomerAMGSmoothType[jac->smoothtype]));
1090       PetscCall(PetscViewerASCIIPrintf(viewer,"    Smooth num levels    %" PetscInt_FMT "\n",jac->smoothnumlevels));
1091     } else {
1092       PetscCall(PetscViewerASCIIPrintf(viewer,"    Not using more complex smoothers.\n"));
1093     }
1094     if (jac->smoothtype==3) {
1095       PetscCall(PetscViewerASCIIPrintf(viewer,"    Euclid ILU(k) levels %" PetscInt_FMT "\n",jac->eu_level));
1096       PetscCall(PetscViewerASCIIPrintf(viewer,"    Euclid ILU(k) drop tolerance %g\n",(double)jac->eu_droptolerance));
1097       PetscCall(PetscViewerASCIIPrintf(viewer,"    Euclid ILU use Block-Jacobi? %" PetscInt_FMT "\n",jac->eu_bj));
1098     }
1099     PetscCall(PetscViewerASCIIPrintf(viewer,"    Measure type        %s\n",HYPREBoomerAMGMeasureType[jac->measuretype]));
1100     PetscCall(PetscViewerASCIIPrintf(viewer,"    Coarsen type        %s\n",HYPREBoomerAMGCoarsenType[jac->coarsentype]));
1101     PetscCall(PetscViewerASCIIPrintf(viewer,"    Interpolation type  %s\n",jac->interptype != 100 ? HYPREBoomerAMGInterpType[jac->interptype] : "1pt"));
1102     if (jac->nodal_coarsening) {
1103       PetscCall(PetscViewerASCIIPrintf(viewer,"    Using nodal coarsening with HYPRE_BOOMERAMGSetNodal() %" PetscInt_FMT "\n",jac->nodal_coarsening));
1104     }
1105     if (jac->vec_interp_variant) {
1106       PetscCall(PetscViewerASCIIPrintf(viewer,"    HYPRE_BoomerAMGSetInterpVecVariant() %" PetscInt_FMT "\n",jac->vec_interp_variant));
1107       PetscCall(PetscViewerASCIIPrintf(viewer,"    HYPRE_BoomerAMGSetInterpVecQMax() %" PetscInt_FMT "\n",jac->vec_interp_qmax));
1108       PetscCall(PetscViewerASCIIPrintf(viewer,"    HYPRE_BoomerAMGSetSmoothInterpVectors() %d\n",jac->vec_interp_smooth));
1109     }
1110     if (jac->nodal_relax) {
1111       PetscCall(PetscViewerASCIIPrintf(viewer,"    Using nodal relaxation via Schwarz smoothing on levels %" PetscInt_FMT "\n",jac->nodal_relax_levels));
1112     }
1113 #if PETSC_PKG_HYPRE_VERSION_GE(2,23,0)
1114     PetscCall(PetscViewerASCIIPrintf(viewer,"    SpGEMM type         %s\n",jac->spgemm_type));
1115 #endif
1116     /* AIR */
1117     if (jac->Rtype) {
1118       PetscCall(PetscViewerASCIIPrintf(viewer,"    Using approximate ideal restriction type %" PetscInt_FMT "\n",jac->Rtype));
1119       PetscCall(PetscViewerASCIIPrintf(viewer,"      Threshold for R %g\n",(double)jac->Rstrongthreshold));
1120       PetscCall(PetscViewerASCIIPrintf(viewer,"      Filter for R %g\n",(double)jac->Rfilterthreshold));
1121       PetscCall(PetscViewerASCIIPrintf(viewer,"      A drop tolerance %g\n",(double)jac->Adroptol));
1122       PetscCall(PetscViewerASCIIPrintf(viewer,"      A drop type %" PetscInt_FMT "\n",jac->Adroptype));
1123     }
1124   }
1125   PetscFunctionReturn(0);
1126 }
1127 
1128 /* --------------------------------------------------------------------------------------------*/
1129 static PetscErrorCode PCSetFromOptions_HYPRE_ParaSails(PetscOptionItems *PetscOptionsObject,PC pc)
1130 {
1131   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1132   PetscInt       indx;
1133   PetscBool      flag;
1134   const char     *symtlist[] = {"nonsymmetric","SPD","nonsymmetric,SPD"};
1135 
1136   PetscFunctionBegin;
1137   PetscOptionsHeadBegin(PetscOptionsObject,"HYPRE ParaSails Options");
1138   PetscCall(PetscOptionsInt("-pc_hypre_parasails_nlevels","Number of number of levels","None",jac->nlevels,&jac->nlevels,0));
1139   PetscCall(PetscOptionsReal("-pc_hypre_parasails_thresh","Threshold","None",jac->threshold,&jac->threshold,&flag));
1140   if (flag) PetscStackCallStandard(HYPRE_ParaSailsSetParams,jac->hsolver,jac->threshold,jac->nlevels);
1141 
1142   PetscCall(PetscOptionsReal("-pc_hypre_parasails_filter","filter","None",jac->filter,&jac->filter,&flag));
1143   if (flag) PetscStackCallStandard(HYPRE_ParaSailsSetFilter,jac->hsolver,jac->filter);
1144 
1145   PetscCall(PetscOptionsReal("-pc_hypre_parasails_loadbal","Load balance","None",jac->loadbal,&jac->loadbal,&flag));
1146   if (flag) PetscStackCallStandard(HYPRE_ParaSailsSetLoadbal,jac->hsolver,jac->loadbal);
1147 
1148   PetscCall(PetscOptionsBool("-pc_hypre_parasails_logging","Print info to screen","None",(PetscBool)jac->logging,(PetscBool*)&jac->logging,&flag));
1149   if (flag) PetscStackCallStandard(HYPRE_ParaSailsSetLogging,jac->hsolver,jac->logging);
1150 
1151   PetscCall(PetscOptionsBool("-pc_hypre_parasails_reuse","Reuse nonzero pattern in preconditioner","None",(PetscBool)jac->ruse,(PetscBool*)&jac->ruse,&flag));
1152   if (flag) PetscStackCallStandard(HYPRE_ParaSailsSetReuse,jac->hsolver,jac->ruse);
1153 
1154   PetscCall(PetscOptionsEList("-pc_hypre_parasails_sym","Symmetry of matrix and preconditioner","None",symtlist,PETSC_STATIC_ARRAY_LENGTH(symtlist),symtlist[0],&indx,&flag));
1155   if (flag) {
1156     jac->symt = indx;
1157     PetscStackCallStandard(HYPRE_ParaSailsSetSym,jac->hsolver,jac->symt);
1158   }
1159 
1160   PetscOptionsHeadEnd();
1161   PetscFunctionReturn(0);
1162 }
1163 
1164 static PetscErrorCode PCView_HYPRE_ParaSails(PC pc,PetscViewer viewer)
1165 {
1166   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1167   PetscBool      iascii;
1168   const char     *symt = 0;
1169 
1170   PetscFunctionBegin;
1171   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
1172   if (iascii) {
1173     PetscCall(PetscViewerASCIIPrintf(viewer,"  HYPRE ParaSails preconditioning\n"));
1174     PetscCall(PetscViewerASCIIPrintf(viewer,"    nlevels %" PetscInt_FMT "\n",jac->nlevels));
1175     PetscCall(PetscViewerASCIIPrintf(viewer,"    threshold %g\n",(double)jac->threshold));
1176     PetscCall(PetscViewerASCIIPrintf(viewer,"    filter %g\n",(double)jac->filter));
1177     PetscCall(PetscViewerASCIIPrintf(viewer,"    load balance %g\n",(double)jac->loadbal));
1178     PetscCall(PetscViewerASCIIPrintf(viewer,"    reuse nonzero structure %s\n",PetscBools[jac->ruse]));
1179     PetscCall(PetscViewerASCIIPrintf(viewer,"    print info to screen %s\n",PetscBools[jac->logging]));
1180     if (!jac->symt) symt = "nonsymmetric matrix and preconditioner";
1181     else if (jac->symt == 1) symt = "SPD matrix and preconditioner";
1182     else if (jac->symt == 2) symt = "nonsymmetric matrix but SPD preconditioner";
1183     else SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONG,"Unknown HYPRE ParaSails symmetric option %" PetscInt_FMT,jac->symt);
1184     PetscCall(PetscViewerASCIIPrintf(viewer,"    %s\n",symt));
1185   }
1186   PetscFunctionReturn(0);
1187 }
1188 /* --------------------------------------------------------------------------------------------*/
1189 static PetscErrorCode PCSetFromOptions_HYPRE_AMS(PetscOptionItems *PetscOptionsObject,PC pc)
1190 {
1191   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1192   PetscInt       n;
1193   PetscBool      flag,flag2,flag3,flag4;
1194 
1195   PetscFunctionBegin;
1196   PetscOptionsHeadBegin(PetscOptionsObject,"HYPRE AMS Options");
1197   PetscCall(PetscOptionsInt("-pc_hypre_ams_print_level","Debugging output level for AMS","None",jac->as_print,&jac->as_print,&flag));
1198   if (flag) PetscStackCallStandard(HYPRE_AMSSetPrintLevel,jac->hsolver,jac->as_print);
1199   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));
1200   if (flag) PetscStackCallStandard(HYPRE_AMSSetMaxIter,jac->hsolver,jac->as_max_iter);
1201   PetscCall(PetscOptionsInt("-pc_hypre_ams_cycle_type","Cycle type for AMS multigrid","None",jac->ams_cycle_type,&jac->ams_cycle_type,&flag));
1202   if (flag) PetscStackCallStandard(HYPRE_AMSSetCycleType,jac->hsolver,jac->ams_cycle_type);
1203   PetscCall(PetscOptionsReal("-pc_hypre_ams_tol","Error tolerance for AMS multigrid","None",jac->as_tol,&jac->as_tol,&flag));
1204   if (flag) PetscStackCallStandard(HYPRE_AMSSetTol,jac->hsolver,jac->as_tol);
1205   PetscCall(PetscOptionsInt("-pc_hypre_ams_relax_type","Relaxation type for AMS smoother","None",jac->as_relax_type,&jac->as_relax_type,&flag));
1206   PetscCall(PetscOptionsInt("-pc_hypre_ams_relax_times","Number of relaxation steps for AMS smoother","None",jac->as_relax_times,&jac->as_relax_times,&flag2));
1207   PetscCall(PetscOptionsReal("-pc_hypre_ams_relax_weight","Relaxation weight for AMS smoother","None",jac->as_relax_weight,&jac->as_relax_weight,&flag3));
1208   PetscCall(PetscOptionsReal("-pc_hypre_ams_omega","SSOR coefficient for AMS smoother","None",jac->as_omega,&jac->as_omega,&flag4));
1209   if (flag || flag2 || flag3 || flag4) {
1210     PetscStackCallStandard(HYPRE_AMSSetSmoothingOptions,jac->hsolver,jac->as_relax_type,
1211                                                                       jac->as_relax_times,
1212                                                                       jac->as_relax_weight,
1213                                                                       jac->as_omega);
1214   }
1215   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));
1216   n = 5;
1217   PetscCall(PetscOptionsIntArray("-pc_hypre_ams_amg_alpha_options","AMG options for vector Poisson","None",jac->as_amg_alpha_opts,&n,&flag2));
1218   if (flag || flag2) {
1219     PetscStackCallStandard(HYPRE_AMSSetAlphaAMGOptions,jac->hsolver,jac->as_amg_alpha_opts[0],       /* AMG coarsen type */
1220                                                                      jac->as_amg_alpha_opts[1],       /* AMG agg_levels */
1221                                                                      jac->as_amg_alpha_opts[2],       /* AMG relax_type */
1222                                                                      jac->as_amg_alpha_theta,
1223                                                                      jac->as_amg_alpha_opts[3],       /* AMG interp_type */
1224                                                                      jac->as_amg_alpha_opts[4]);     /* AMG Pmax */
1225   }
1226   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));
1227   n = 5;
1228   PetscCall(PetscOptionsIntArray("-pc_hypre_ams_amg_beta_options","AMG options for scalar Poisson solver","None",jac->as_amg_beta_opts,&n,&flag2));
1229   if (flag || flag2) {
1230     PetscStackCallStandard(HYPRE_AMSSetBetaAMGOptions,jac->hsolver,jac->as_amg_beta_opts[0],       /* AMG coarsen type */
1231                                                                     jac->as_amg_beta_opts[1],       /* AMG agg_levels */
1232                                                                     jac->as_amg_beta_opts[2],       /* AMG relax_type */
1233                                                                     jac->as_amg_beta_theta,
1234                                                                     jac->as_amg_beta_opts[3],       /* AMG interp_type */
1235                                                                     jac->as_amg_beta_opts[4]);     /* AMG Pmax */
1236   }
1237   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));
1238   if (flag) { /* override HYPRE's default only if the options is used */
1239     PetscStackCallStandard(HYPRE_AMSSetProjectionFrequency,jac->hsolver,jac->ams_proj_freq);
1240   }
1241   PetscOptionsHeadEnd();
1242   PetscFunctionReturn(0);
1243 }
1244 
1245 static PetscErrorCode PCView_HYPRE_AMS(PC pc,PetscViewer viewer)
1246 {
1247   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1248   PetscBool      iascii;
1249 
1250   PetscFunctionBegin;
1251   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
1252   if (iascii) {
1253     PetscCall(PetscViewerASCIIPrintf(viewer,"  HYPRE AMS preconditioning\n"));
1254     PetscCall(PetscViewerASCIIPrintf(viewer,"    subspace iterations per application %" PetscInt_FMT "\n",jac->as_max_iter));
1255     PetscCall(PetscViewerASCIIPrintf(viewer,"    subspace cycle type %" PetscInt_FMT "\n",jac->ams_cycle_type));
1256     PetscCall(PetscViewerASCIIPrintf(viewer,"    subspace iteration tolerance %g\n",(double)jac->as_tol));
1257     PetscCall(PetscViewerASCIIPrintf(viewer,"    smoother type %" PetscInt_FMT "\n",jac->as_relax_type));
1258     PetscCall(PetscViewerASCIIPrintf(viewer,"    number of smoothing steps %" PetscInt_FMT "\n",jac->as_relax_times));
1259     PetscCall(PetscViewerASCIIPrintf(viewer,"    smoother weight %g\n",(double)jac->as_relax_weight));
1260     PetscCall(PetscViewerASCIIPrintf(viewer,"    smoother omega %g\n",(double)jac->as_omega));
1261     if (jac->alpha_Poisson) {
1262       PetscCall(PetscViewerASCIIPrintf(viewer,"    vector Poisson solver (passed in by user)\n"));
1263     } else {
1264       PetscCall(PetscViewerASCIIPrintf(viewer,"    vector Poisson solver (computed) \n"));
1265     }
1266     PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG coarsening type %" PetscInt_FMT "\n",jac->as_amg_alpha_opts[0]));
1267     PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG levels of aggressive coarsening %" PetscInt_FMT "\n",jac->as_amg_alpha_opts[1]));
1268     PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG relaxation type %" PetscInt_FMT "\n",jac->as_amg_alpha_opts[2]));
1269     PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG interpolation type %" PetscInt_FMT "\n",jac->as_amg_alpha_opts[3]));
1270     PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG max nonzero elements in interpolation rows %" PetscInt_FMT "\n",jac->as_amg_alpha_opts[4]));
1271     PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG strength threshold %g\n",(double)jac->as_amg_alpha_theta));
1272     if (!jac->ams_beta_is_zero) {
1273       if (jac->beta_Poisson) {
1274         PetscCall(PetscViewerASCIIPrintf(viewer,"    scalar Poisson solver (passed in by user)\n"));
1275       } else {
1276         PetscCall(PetscViewerASCIIPrintf(viewer,"    scalar Poisson solver (computed) \n"));
1277       }
1278       PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG coarsening type %" PetscInt_FMT "\n",jac->as_amg_beta_opts[0]));
1279       PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG levels of aggressive coarsening %" PetscInt_FMT "\n",jac->as_amg_beta_opts[1]));
1280       PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG relaxation type %" PetscInt_FMT "\n",jac->as_amg_beta_opts[2]));
1281       PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG interpolation type %" PetscInt_FMT "\n",jac->as_amg_beta_opts[3]));
1282       PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG max nonzero elements in interpolation rows %" PetscInt_FMT "\n",jac->as_amg_beta_opts[4]));
1283       PetscCall(PetscViewerASCIIPrintf(viewer,"        boomerAMG strength threshold %g\n",(double)jac->as_amg_beta_theta));
1284       if (jac->ams_beta_is_zero_part) {
1285         PetscCall(PetscViewerASCIIPrintf(viewer,"        compatible subspace projection frequency %" PetscInt_FMT " (-1 HYPRE uses default)\n",jac->ams_proj_freq));
1286       }
1287     } else {
1288       PetscCall(PetscViewerASCIIPrintf(viewer,"    scalar Poisson solver not used (zero-conductivity everywhere) \n"));
1289     }
1290   }
1291   PetscFunctionReturn(0);
1292 }
1293 
1294 static PetscErrorCode PCSetFromOptions_HYPRE_ADS(PetscOptionItems *PetscOptionsObject,PC pc)
1295 {
1296   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1297   PetscInt       n;
1298   PetscBool      flag,flag2,flag3,flag4;
1299 
1300   PetscFunctionBegin;
1301   PetscOptionsHeadBegin(PetscOptionsObject,"HYPRE ADS Options");
1302   PetscCall(PetscOptionsInt("-pc_hypre_ads_print_level","Debugging output level for ADS","None",jac->as_print,&jac->as_print,&flag));
1303   if (flag) PetscStackCallStandard(HYPRE_ADSSetPrintLevel,jac->hsolver,jac->as_print);
1304   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));
1305   if (flag) PetscStackCallStandard(HYPRE_ADSSetMaxIter,jac->hsolver,jac->as_max_iter);
1306   PetscCall(PetscOptionsInt("-pc_hypre_ads_cycle_type","Cycle type for ADS multigrid","None",jac->ads_cycle_type,&jac->ads_cycle_type,&flag));
1307   if (flag) PetscStackCallStandard(HYPRE_ADSSetCycleType,jac->hsolver,jac->ads_cycle_type);
1308   PetscCall(PetscOptionsReal("-pc_hypre_ads_tol","Error tolerance for ADS multigrid","None",jac->as_tol,&jac->as_tol,&flag));
1309   if (flag) PetscStackCallStandard(HYPRE_ADSSetTol,jac->hsolver,jac->as_tol);
1310   PetscCall(PetscOptionsInt("-pc_hypre_ads_relax_type","Relaxation type for ADS smoother","None",jac->as_relax_type,&jac->as_relax_type,&flag));
1311   PetscCall(PetscOptionsInt("-pc_hypre_ads_relax_times","Number of relaxation steps for ADS smoother","None",jac->as_relax_times,&jac->as_relax_times,&flag2));
1312   PetscCall(PetscOptionsReal("-pc_hypre_ads_relax_weight","Relaxation weight for ADS smoother","None",jac->as_relax_weight,&jac->as_relax_weight,&flag3));
1313   PetscCall(PetscOptionsReal("-pc_hypre_ads_omega","SSOR coefficient for ADS smoother","None",jac->as_omega,&jac->as_omega,&flag4));
1314   if (flag || flag2 || flag3 || flag4) {
1315     PetscStackCallStandard(HYPRE_ADSSetSmoothingOptions,jac->hsolver,jac->as_relax_type,
1316                                                                       jac->as_relax_times,
1317                                                                       jac->as_relax_weight,
1318                                                                       jac->as_omega);
1319   }
1320   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));
1321   n = 5;
1322   PetscCall(PetscOptionsIntArray("-pc_hypre_ads_ams_options","AMG options for AMS solver inside ADS","None",jac->as_amg_alpha_opts,&n,&flag2));
1323   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));
1324   if (flag || flag2 || flag3) {
1325     PetscStackCallStandard(HYPRE_ADSSetAMSOptions,jac->hsolver,jac->ams_cycle_type,             /* AMS cycle type */
1326                                                                 jac->as_amg_alpha_opts[0],       /* AMG coarsen type */
1327                                                                 jac->as_amg_alpha_opts[1],       /* AMG agg_levels */
1328                                                                 jac->as_amg_alpha_opts[2],       /* AMG relax_type */
1329                                                                 jac->as_amg_alpha_theta,
1330                                                                 jac->as_amg_alpha_opts[3],       /* AMG interp_type */
1331                                                                 jac->as_amg_alpha_opts[4]);     /* AMG Pmax */
1332   }
1333   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));
1334   n = 5;
1335   PetscCall(PetscOptionsIntArray("-pc_hypre_ads_amg_options","AMG options for vector AMG solver inside ADS","None",jac->as_amg_beta_opts,&n,&flag2));
1336   if (flag || flag2) {
1337     PetscStackCallStandard(HYPRE_ADSSetAMGOptions,jac->hsolver,jac->as_amg_beta_opts[0],       /* AMG coarsen type */
1338                                                                 jac->as_amg_beta_opts[1],       /* AMG agg_levels */
1339                                                                 jac->as_amg_beta_opts[2],       /* AMG relax_type */
1340                                                                 jac->as_amg_beta_theta,
1341                                                                 jac->as_amg_beta_opts[3],       /* AMG interp_type */
1342                                                                 jac->as_amg_beta_opts[4]);     /* AMG Pmax */
1343   }
1344   PetscOptionsHeadEnd();
1345   PetscFunctionReturn(0);
1346 }
1347 
1348 static PetscErrorCode PCView_HYPRE_ADS(PC pc,PetscViewer viewer)
1349 {
1350   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1351   PetscBool      iascii;
1352 
1353   PetscFunctionBegin;
1354   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
1355   if (iascii) {
1356     PetscCall(PetscViewerASCIIPrintf(viewer,"  HYPRE ADS preconditioning\n"));
1357     PetscCall(PetscViewerASCIIPrintf(viewer,"    subspace iterations per application %" PetscInt_FMT "\n",jac->as_max_iter));
1358     PetscCall(PetscViewerASCIIPrintf(viewer,"    subspace cycle type %" PetscInt_FMT "\n",jac->ads_cycle_type));
1359     PetscCall(PetscViewerASCIIPrintf(viewer,"    subspace iteration tolerance %g\n",(double)jac->as_tol));
1360     PetscCall(PetscViewerASCIIPrintf(viewer,"    smoother type %" PetscInt_FMT "\n",jac->as_relax_type));
1361     PetscCall(PetscViewerASCIIPrintf(viewer,"    number of smoothing steps %" PetscInt_FMT "\n",jac->as_relax_times));
1362     PetscCall(PetscViewerASCIIPrintf(viewer,"    smoother weight %g\n",(double)jac->as_relax_weight));
1363     PetscCall(PetscViewerASCIIPrintf(viewer,"    smoother omega %g\n",(double)jac->as_omega));
1364     PetscCall(PetscViewerASCIIPrintf(viewer,"    AMS solver using boomerAMG\n"));
1365     PetscCall(PetscViewerASCIIPrintf(viewer,"        subspace cycle type %" PetscInt_FMT "\n",jac->ams_cycle_type));
1366     PetscCall(PetscViewerASCIIPrintf(viewer,"        coarsening type %" PetscInt_FMT "\n",jac->as_amg_alpha_opts[0]));
1367     PetscCall(PetscViewerASCIIPrintf(viewer,"        levels of aggressive coarsening %" PetscInt_FMT "\n",jac->as_amg_alpha_opts[1]));
1368     PetscCall(PetscViewerASCIIPrintf(viewer,"        relaxation type %" PetscInt_FMT "\n",jac->as_amg_alpha_opts[2]));
1369     PetscCall(PetscViewerASCIIPrintf(viewer,"        interpolation type %" PetscInt_FMT "\n",jac->as_amg_alpha_opts[3]));
1370     PetscCall(PetscViewerASCIIPrintf(viewer,"        max nonzero elements in interpolation rows %" PetscInt_FMT "\n",jac->as_amg_alpha_opts[4]));
1371     PetscCall(PetscViewerASCIIPrintf(viewer,"        strength threshold %g\n",(double)jac->as_amg_alpha_theta));
1372     PetscCall(PetscViewerASCIIPrintf(viewer,"    vector Poisson solver using boomerAMG\n"));
1373     PetscCall(PetscViewerASCIIPrintf(viewer,"        coarsening type %" PetscInt_FMT "\n",jac->as_amg_beta_opts[0]));
1374     PetscCall(PetscViewerASCIIPrintf(viewer,"        levels of aggressive coarsening %" PetscInt_FMT "\n",jac->as_amg_beta_opts[1]));
1375     PetscCall(PetscViewerASCIIPrintf(viewer,"        relaxation type %" PetscInt_FMT "\n",jac->as_amg_beta_opts[2]));
1376     PetscCall(PetscViewerASCIIPrintf(viewer,"        interpolation type %" PetscInt_FMT "\n",jac->as_amg_beta_opts[3]));
1377     PetscCall(PetscViewerASCIIPrintf(viewer,"        max nonzero elements in interpolation rows %" PetscInt_FMT "\n",jac->as_amg_beta_opts[4]));
1378     PetscCall(PetscViewerASCIIPrintf(viewer,"        strength threshold %g\n",(double)jac->as_amg_beta_theta));
1379   }
1380   PetscFunctionReturn(0);
1381 }
1382 
1383 static PetscErrorCode PCHYPRESetDiscreteGradient_HYPRE(PC pc, Mat G)
1384 {
1385   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1386   PetscBool      ishypre;
1387 
1388   PetscFunctionBegin;
1389   PetscCall(PetscObjectTypeCompare((PetscObject)G,MATHYPRE,&ishypre));
1390   if (ishypre) {
1391     PetscCall(PetscObjectReference((PetscObject)G));
1392     PetscCall(MatDestroy(&jac->G));
1393     jac->G = G;
1394   } else {
1395     PetscCall(MatDestroy(&jac->G));
1396     PetscCall(MatConvert(G,MATHYPRE,MAT_INITIAL_MATRIX,&jac->G));
1397   }
1398   PetscFunctionReturn(0);
1399 }
1400 
1401 /*@
1402  PCHYPRESetDiscreteGradient - Set discrete gradient matrix
1403 
1404    Collective on PC
1405 
1406    Input Parameters:
1407 +  pc - the preconditioning context
1408 -  G - the discrete gradient
1409 
1410    Level: intermediate
1411 
1412    Notes:
1413     G should have as many rows as the number of edges and as many columns as the number of vertices in the mesh
1414 
1415     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
1416 
1417 .seealso: `PCHYPRESetDiscreteCurl()`
1418 @*/
1419 PetscErrorCode PCHYPRESetDiscreteGradient(PC pc, Mat G)
1420 {
1421   PetscFunctionBegin;
1422   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1423   PetscValidHeaderSpecific(G,MAT_CLASSID,2);
1424   PetscCheckSameComm(pc,1,G,2);
1425   PetscTryMethod(pc,"PCHYPRESetDiscreteGradient_C",(PC,Mat),(pc,G));
1426   PetscFunctionReturn(0);
1427 }
1428 
1429 static PetscErrorCode PCHYPRESetDiscreteCurl_HYPRE(PC pc, Mat C)
1430 {
1431   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1432   PetscBool      ishypre;
1433 
1434   PetscFunctionBegin;
1435   PetscCall(PetscObjectTypeCompare((PetscObject)C,MATHYPRE,&ishypre));
1436   if (ishypre) {
1437     PetscCall(PetscObjectReference((PetscObject)C));
1438     PetscCall(MatDestroy(&jac->C));
1439     jac->C = C;
1440   } else {
1441     PetscCall(MatDestroy(&jac->C));
1442     PetscCall(MatConvert(C,MATHYPRE,MAT_INITIAL_MATRIX,&jac->C));
1443   }
1444   PetscFunctionReturn(0);
1445 }
1446 
1447 /*@
1448  PCHYPRESetDiscreteCurl - Set discrete curl matrix
1449 
1450    Collective on PC
1451 
1452    Input Parameters:
1453 +  pc - the preconditioning context
1454 -  C - the discrete curl
1455 
1456    Level: intermediate
1457 
1458    Notes:
1459     C should have as many rows as the number of faces and as many columns as the number of edges in the mesh
1460 
1461     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
1462 
1463 .seealso: `PCHYPRESetDiscreteGradient()`
1464 @*/
1465 PetscErrorCode PCHYPRESetDiscreteCurl(PC pc, Mat C)
1466 {
1467   PetscFunctionBegin;
1468   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1469   PetscValidHeaderSpecific(C,MAT_CLASSID,2);
1470   PetscCheckSameComm(pc,1,C,2);
1471   PetscTryMethod(pc,"PCHYPRESetDiscreteCurl_C",(PC,Mat),(pc,C));
1472   PetscFunctionReturn(0);
1473 }
1474 
1475 static PetscErrorCode PCHYPRESetInterpolations_HYPRE(PC pc, PetscInt dim, Mat RT_PiFull, Mat RT_Pi[], Mat ND_PiFull, Mat ND_Pi[])
1476 {
1477   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1478   PetscBool      ishypre;
1479   PetscInt       i;
1480   PetscFunctionBegin;
1481 
1482   PetscCall(MatDestroy(&jac->RT_PiFull));
1483   PetscCall(MatDestroy(&jac->ND_PiFull));
1484   for (i=0;i<3;++i) {
1485     PetscCall(MatDestroy(&jac->RT_Pi[i]));
1486     PetscCall(MatDestroy(&jac->ND_Pi[i]));
1487   }
1488 
1489   jac->dim = dim;
1490   if (RT_PiFull) {
1491     PetscCall(PetscObjectTypeCompare((PetscObject)RT_PiFull,MATHYPRE,&ishypre));
1492     if (ishypre) {
1493       PetscCall(PetscObjectReference((PetscObject)RT_PiFull));
1494       jac->RT_PiFull = RT_PiFull;
1495     } else {
1496       PetscCall(MatConvert(RT_PiFull,MATHYPRE,MAT_INITIAL_MATRIX,&jac->RT_PiFull));
1497     }
1498   }
1499   if (RT_Pi) {
1500     for (i=0;i<dim;++i) {
1501       if (RT_Pi[i]) {
1502         PetscCall(PetscObjectTypeCompare((PetscObject)RT_Pi[i],MATHYPRE,&ishypre));
1503         if (ishypre) {
1504           PetscCall(PetscObjectReference((PetscObject)RT_Pi[i]));
1505           jac->RT_Pi[i] = RT_Pi[i];
1506         } else {
1507           PetscCall(MatConvert(RT_Pi[i],MATHYPRE,MAT_INITIAL_MATRIX,&jac->RT_Pi[i]));
1508         }
1509       }
1510     }
1511   }
1512   if (ND_PiFull) {
1513     PetscCall(PetscObjectTypeCompare((PetscObject)ND_PiFull,MATHYPRE,&ishypre));
1514     if (ishypre) {
1515       PetscCall(PetscObjectReference((PetscObject)ND_PiFull));
1516       jac->ND_PiFull = ND_PiFull;
1517     } else {
1518       PetscCall(MatConvert(ND_PiFull,MATHYPRE,MAT_INITIAL_MATRIX,&jac->ND_PiFull));
1519     }
1520   }
1521   if (ND_Pi) {
1522     for (i=0;i<dim;++i) {
1523       if (ND_Pi[i]) {
1524         PetscCall(PetscObjectTypeCompare((PetscObject)ND_Pi[i],MATHYPRE,&ishypre));
1525         if (ishypre) {
1526           PetscCall(PetscObjectReference((PetscObject)ND_Pi[i]));
1527           jac->ND_Pi[i] = ND_Pi[i];
1528         } else {
1529           PetscCall(MatConvert(ND_Pi[i],MATHYPRE,MAT_INITIAL_MATRIX,&jac->ND_Pi[i]));
1530         }
1531       }
1532     }
1533   }
1534 
1535   PetscFunctionReturn(0);
1536 }
1537 
1538 /*@
1539  PCHYPRESetInterpolations - Set interpolation matrices for AMS/ADS preconditioner
1540 
1541    Collective on PC
1542 
1543    Input Parameters:
1544 +  pc - the preconditioning context
1545 -  dim - the dimension of the problem, only used in AMS
1546 -  RT_PiFull - Raviart-Thomas interpolation matrix
1547 -  RT_Pi - x/y/z component of Raviart-Thomas interpolation matrix
1548 -  ND_PiFull - Nedelec interpolation matrix
1549 -  ND_Pi - x/y/z component of Nedelec interpolation matrix
1550 
1551    Notes:
1552     For AMS, only Nedelec interpolation matrices are needed, the Raviart-Thomas interpolation matrices can be set to NULL.
1553 
1554     For ADS, both type of interpolation matrices are needed.
1555 
1556    Level: intermediate
1557 
1558 @*/
1559 PetscErrorCode PCHYPRESetInterpolations(PC pc, PetscInt dim, Mat RT_PiFull, Mat RT_Pi[], Mat ND_PiFull, Mat ND_Pi[])
1560 {
1561   PetscInt       i;
1562 
1563   PetscFunctionBegin;
1564   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1565   if (RT_PiFull) {
1566     PetscValidHeaderSpecific(RT_PiFull,MAT_CLASSID,3);
1567     PetscCheckSameComm(pc,1,RT_PiFull,3);
1568   }
1569   if (RT_Pi) {
1570     PetscValidPointer(RT_Pi,4);
1571     for (i=0;i<dim;++i) {
1572       if (RT_Pi[i]) {
1573         PetscValidHeaderSpecific(RT_Pi[i],MAT_CLASSID,4);
1574         PetscCheckSameComm(pc,1,RT_Pi[i],4);
1575       }
1576     }
1577   }
1578   if (ND_PiFull) {
1579     PetscValidHeaderSpecific(ND_PiFull,MAT_CLASSID,5);
1580     PetscCheckSameComm(pc,1,ND_PiFull,5);
1581   }
1582   if (ND_Pi) {
1583     PetscValidPointer(ND_Pi,6);
1584     for (i=0;i<dim;++i) {
1585       if (ND_Pi[i]) {
1586         PetscValidHeaderSpecific(ND_Pi[i],MAT_CLASSID,6);
1587         PetscCheckSameComm(pc,1,ND_Pi[i],6);
1588       }
1589     }
1590   }
1591   PetscTryMethod(pc,"PCHYPRESetInterpolations_C",(PC,PetscInt,Mat,Mat[],Mat,Mat[]),(pc,dim,RT_PiFull,RT_Pi,ND_PiFull,ND_Pi));
1592   PetscFunctionReturn(0);
1593 }
1594 
1595 static PetscErrorCode PCHYPRESetPoissonMatrix_HYPRE(PC pc, Mat A, PetscBool isalpha)
1596 {
1597   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1598   PetscBool      ishypre;
1599 
1600   PetscFunctionBegin;
1601   PetscCall(PetscObjectTypeCompare((PetscObject)A,MATHYPRE,&ishypre));
1602   if (ishypre) {
1603     if (isalpha) {
1604       PetscCall(PetscObjectReference((PetscObject)A));
1605       PetscCall(MatDestroy(&jac->alpha_Poisson));
1606       jac->alpha_Poisson = A;
1607     } else {
1608       if (A) {
1609         PetscCall(PetscObjectReference((PetscObject)A));
1610       } else {
1611         jac->ams_beta_is_zero = PETSC_TRUE;
1612       }
1613       PetscCall(MatDestroy(&jac->beta_Poisson));
1614       jac->beta_Poisson = A;
1615     }
1616   } else {
1617     if (isalpha) {
1618       PetscCall(MatDestroy(&jac->alpha_Poisson));
1619       PetscCall(MatConvert(A,MATHYPRE,MAT_INITIAL_MATRIX,&jac->alpha_Poisson));
1620     } else {
1621       if (A) {
1622         PetscCall(MatDestroy(&jac->beta_Poisson));
1623         PetscCall(MatConvert(A,MATHYPRE,MAT_INITIAL_MATRIX,&jac->beta_Poisson));
1624       } else {
1625         PetscCall(MatDestroy(&jac->beta_Poisson));
1626         jac->ams_beta_is_zero = PETSC_TRUE;
1627       }
1628     }
1629   }
1630   PetscFunctionReturn(0);
1631 }
1632 
1633 /*@
1634  PCHYPRESetAlphaPoissonMatrix - Set vector Poisson matrix
1635 
1636    Collective on PC
1637 
1638    Input Parameters:
1639 +  pc - the preconditioning context
1640 -  A - the matrix
1641 
1642    Level: intermediate
1643 
1644    Notes:
1645     A should be obtained by discretizing the vector valued Poisson problem with linear finite elements
1646 
1647 .seealso: `PCHYPRESetDiscreteGradient()`, `PCHYPRESetDiscreteCurl()`, `PCHYPRESetBetaPoissonMatrix()`
1648 @*/
1649 PetscErrorCode PCHYPRESetAlphaPoissonMatrix(PC pc, Mat A)
1650 {
1651   PetscFunctionBegin;
1652   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1653   PetscValidHeaderSpecific(A,MAT_CLASSID,2);
1654   PetscCheckSameComm(pc,1,A,2);
1655   PetscTryMethod(pc,"PCHYPRESetPoissonMatrix_C",(PC,Mat,PetscBool),(pc,A,PETSC_TRUE));
1656   PetscFunctionReturn(0);
1657 }
1658 
1659 /*@
1660  PCHYPRESetBetaPoissonMatrix - Set Poisson matrix
1661 
1662    Collective on PC
1663 
1664    Input Parameters:
1665 +  pc - the preconditioning context
1666 -  A - the matrix
1667 
1668    Level: intermediate
1669 
1670    Notes:
1671     A should be obtained by discretizing the Poisson problem with linear finite elements.
1672           Following HYPRE convention, the scalar Poisson solver of AMS can be turned off by passing NULL.
1673 
1674 .seealso: `PCHYPRESetDiscreteGradient()`, `PCHYPRESetDiscreteCurl()`, `PCHYPRESetAlphaPoissonMatrix()`
1675 @*/
1676 PetscErrorCode PCHYPRESetBetaPoissonMatrix(PC pc, Mat A)
1677 {
1678   PetscFunctionBegin;
1679   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1680   if (A) {
1681     PetscValidHeaderSpecific(A,MAT_CLASSID,2);
1682     PetscCheckSameComm(pc,1,A,2);
1683   }
1684   PetscTryMethod(pc,"PCHYPRESetPoissonMatrix_C",(PC,Mat,PetscBool),(pc,A,PETSC_FALSE));
1685   PetscFunctionReturn(0);
1686 }
1687 
1688 static PetscErrorCode PCHYPRESetEdgeConstantVectors_HYPRE(PC pc,Vec ozz, Vec zoz, Vec zzo)
1689 {
1690   PC_HYPRE           *jac = (PC_HYPRE*)pc->data;
1691 
1692   PetscFunctionBegin;
1693   /* throw away any vector if already set */
1694   PetscCall(VecHYPRE_IJVectorDestroy(&jac->constants[0]));
1695   PetscCall(VecHYPRE_IJVectorDestroy(&jac->constants[1]));
1696   PetscCall(VecHYPRE_IJVectorDestroy(&jac->constants[2]));
1697   PetscCall(VecHYPRE_IJVectorCreate(ozz->map,&jac->constants[0]));
1698   PetscCall(VecHYPRE_IJVectorCopy(ozz,jac->constants[0]));
1699   PetscCall(VecHYPRE_IJVectorCreate(zoz->map,&jac->constants[1]));
1700   PetscCall(VecHYPRE_IJVectorCopy(zoz,jac->constants[1]));
1701   jac->dim = 2;
1702   if (zzo) {
1703     PetscCall(VecHYPRE_IJVectorCreate(zzo->map,&jac->constants[2]));
1704     PetscCall(VecHYPRE_IJVectorCopy(zzo,jac->constants[2]));
1705     jac->dim++;
1706   }
1707   PetscFunctionReturn(0);
1708 }
1709 
1710 /*@
1711  PCHYPRESetEdgeConstantVectors - Set the representation of the constant vector fields in the edge element basis
1712 
1713    Collective on PC
1714 
1715    Input Parameters:
1716 +  pc - the preconditioning context
1717 -  ozz - vector representing (1,0,0) (or (1,0) in 2D)
1718 -  zoz - vector representing (0,1,0) (or (0,1) in 2D)
1719 -  zzo - vector representing (0,0,1) (use NULL in 2D)
1720 
1721    Level: intermediate
1722 
1723 @*/
1724 PetscErrorCode PCHYPRESetEdgeConstantVectors(PC pc, Vec ozz, Vec zoz, Vec zzo)
1725 {
1726   PetscFunctionBegin;
1727   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1728   PetscValidHeaderSpecific(ozz,VEC_CLASSID,2);
1729   PetscValidHeaderSpecific(zoz,VEC_CLASSID,3);
1730   if (zzo) PetscValidHeaderSpecific(zzo,VEC_CLASSID,4);
1731   PetscCheckSameComm(pc,1,ozz,2);
1732   PetscCheckSameComm(pc,1,zoz,3);
1733   if (zzo) PetscCheckSameComm(pc,1,zzo,4);
1734   PetscTryMethod(pc,"PCHYPRESetEdgeConstantVectors_C",(PC,Vec,Vec,Vec),(pc,ozz,zoz,zzo));
1735   PetscFunctionReturn(0);
1736 }
1737 
1738 static PetscErrorCode PCSetCoordinates_HYPRE(PC pc, PetscInt dim, PetscInt nloc, PetscReal *coords)
1739 {
1740   PC_HYPRE        *jac = (PC_HYPRE*)pc->data;
1741   Vec             tv;
1742   PetscInt        i;
1743 
1744   PetscFunctionBegin;
1745   /* throw away any coordinate vector if already set */
1746   PetscCall(VecHYPRE_IJVectorDestroy(&jac->coords[0]));
1747   PetscCall(VecHYPRE_IJVectorDestroy(&jac->coords[1]));
1748   PetscCall(VecHYPRE_IJVectorDestroy(&jac->coords[2]));
1749   jac->dim = dim;
1750 
1751   /* compute IJ vector for coordinates */
1752   PetscCall(VecCreate(PetscObjectComm((PetscObject)pc),&tv));
1753   PetscCall(VecSetType(tv,VECSTANDARD));
1754   PetscCall(VecSetSizes(tv,nloc,PETSC_DECIDE));
1755   for (i=0;i<dim;i++) {
1756     PetscScalar *array;
1757     PetscInt    j;
1758 
1759     PetscCall(VecHYPRE_IJVectorCreate(tv->map,&jac->coords[i]));
1760     PetscCall(VecGetArrayWrite(tv,&array));
1761     for (j=0;j<nloc;j++) array[j] = coords[j*dim+i];
1762     PetscCall(VecRestoreArrayWrite(tv,&array));
1763     PetscCall(VecHYPRE_IJVectorCopy(tv,jac->coords[i]));
1764   }
1765   PetscCall(VecDestroy(&tv));
1766   PetscFunctionReturn(0);
1767 }
1768 
1769 /* ---------------------------------------------------------------------------------*/
1770 
1771 static PetscErrorCode  PCHYPREGetType_HYPRE(PC pc,const char *name[])
1772 {
1773   PC_HYPRE *jac = (PC_HYPRE*)pc->data;
1774 
1775   PetscFunctionBegin;
1776   *name = jac->hypre_type;
1777   PetscFunctionReturn(0);
1778 }
1779 
1780 static PetscErrorCode  PCHYPRESetType_HYPRE(PC pc,const char name[])
1781 {
1782   PC_HYPRE       *jac = (PC_HYPRE*)pc->data;
1783   PetscBool      flag;
1784 
1785   PetscFunctionBegin;
1786   if (jac->hypre_type) {
1787     PetscCall(PetscStrcmp(jac->hypre_type,name,&flag));
1788     PetscCheck(flag,PetscObjectComm((PetscObject)pc),PETSC_ERR_ORDER,"Cannot reset the HYPRE preconditioner type once it has been set");
1789     PetscFunctionReturn(0);
1790   } else {
1791     PetscCall(PetscStrallocpy(name, &jac->hypre_type));
1792   }
1793 
1794   jac->maxiter         = PETSC_DEFAULT;
1795   jac->tol             = PETSC_DEFAULT;
1796   jac->printstatistics = PetscLogPrintInfo;
1797 
1798   PetscCall(PetscStrcmp("pilut",jac->hypre_type,&flag));
1799   if (flag) {
1800     PetscCall(PetscCommGetComm(PetscObjectComm((PetscObject)pc),&jac->comm_hypre));
1801     PetscStackCallStandard(HYPRE_ParCSRPilutCreate,jac->comm_hypre,&jac->hsolver);
1802     pc->ops->setfromoptions = PCSetFromOptions_HYPRE_Pilut;
1803     pc->ops->view           = PCView_HYPRE_Pilut;
1804     jac->destroy            = HYPRE_ParCSRPilutDestroy;
1805     jac->setup              = HYPRE_ParCSRPilutSetup;
1806     jac->solve              = HYPRE_ParCSRPilutSolve;
1807     jac->factorrowsize      = PETSC_DEFAULT;
1808     PetscFunctionReturn(0);
1809   }
1810   PetscCall(PetscStrcmp("euclid",jac->hypre_type,&flag));
1811   if (flag) {
1812 #if defined(PETSC_USE_64BIT_INDICES)
1813     SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Hypre Euclid does not support 64 bit indices");
1814 #endif
1815     PetscCall(PetscCommGetComm(PetscObjectComm((PetscObject)pc),&jac->comm_hypre));
1816     PetscStackCallStandard(HYPRE_EuclidCreate,jac->comm_hypre,&jac->hsolver);
1817     pc->ops->setfromoptions = PCSetFromOptions_HYPRE_Euclid;
1818     pc->ops->view           = PCView_HYPRE_Euclid;
1819     jac->destroy            = HYPRE_EuclidDestroy;
1820     jac->setup              = HYPRE_EuclidSetup;
1821     jac->solve              = HYPRE_EuclidSolve;
1822     jac->factorrowsize      = PETSC_DEFAULT;
1823     jac->eu_level           = PETSC_DEFAULT; /* default */
1824     PetscFunctionReturn(0);
1825   }
1826   PetscCall(PetscStrcmp("parasails",jac->hypre_type,&flag));
1827   if (flag) {
1828     PetscCall(PetscCommGetComm(PetscObjectComm((PetscObject)pc),&jac->comm_hypre));
1829     PetscStackCallStandard(HYPRE_ParaSailsCreate,jac->comm_hypre,&jac->hsolver);
1830     pc->ops->setfromoptions = PCSetFromOptions_HYPRE_ParaSails;
1831     pc->ops->view           = PCView_HYPRE_ParaSails;
1832     jac->destroy            = HYPRE_ParaSailsDestroy;
1833     jac->setup              = HYPRE_ParaSailsSetup;
1834     jac->solve              = HYPRE_ParaSailsSolve;
1835     /* initialize */
1836     jac->nlevels   = 1;
1837     jac->threshold = .1;
1838     jac->filter    = .1;
1839     jac->loadbal   = 0;
1840     if (PetscLogPrintInfo) jac->logging = (int) PETSC_TRUE;
1841     else jac->logging = (int) PETSC_FALSE;
1842 
1843     jac->ruse = (int) PETSC_FALSE;
1844     jac->symt = 0;
1845     PetscStackCallStandard(HYPRE_ParaSailsSetParams,jac->hsolver,jac->threshold,jac->nlevels);
1846     PetscStackCallStandard(HYPRE_ParaSailsSetFilter,jac->hsolver,jac->filter);
1847     PetscStackCallStandard(HYPRE_ParaSailsSetLoadbal,jac->hsolver,jac->loadbal);
1848     PetscStackCallStandard(HYPRE_ParaSailsSetLogging,jac->hsolver,jac->logging);
1849     PetscStackCallStandard(HYPRE_ParaSailsSetReuse,jac->hsolver,jac->ruse);
1850     PetscStackCallStandard(HYPRE_ParaSailsSetSym,jac->hsolver,jac->symt);
1851     PetscFunctionReturn(0);
1852   }
1853   PetscCall(PetscStrcmp("boomeramg",jac->hypre_type,&flag));
1854   if (flag) {
1855     PetscStackCallStandard(HYPRE_BoomerAMGCreate,&jac->hsolver);
1856     pc->ops->setfromoptions  = PCSetFromOptions_HYPRE_BoomerAMG;
1857     pc->ops->view            = PCView_HYPRE_BoomerAMG;
1858     pc->ops->applytranspose  = PCApplyTranspose_HYPRE_BoomerAMG;
1859     pc->ops->applyrichardson = PCApplyRichardson_HYPRE_BoomerAMG;
1860     PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCGetInterpolations_C",PCGetInterpolations_BoomerAMG));
1861     PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCGetCoarseOperators_C",PCGetCoarseOperators_BoomerAMG));
1862     jac->destroy             = HYPRE_BoomerAMGDestroy;
1863     jac->setup               = HYPRE_BoomerAMGSetup;
1864     jac->solve               = HYPRE_BoomerAMGSolve;
1865     jac->applyrichardson     = PETSC_FALSE;
1866     /* these defaults match the hypre defaults */
1867     jac->cycletype        = 1;
1868     jac->maxlevels        = 25;
1869     jac->maxiter          = 1;
1870     jac->tol              = 0.0; /* tolerance of zero indicates use as preconditioner (suppresses convergence errors) */
1871     jac->truncfactor      = 0.0;
1872     jac->strongthreshold  = .25;
1873     jac->maxrowsum        = .9;
1874     jac->coarsentype      = 6;
1875     jac->measuretype      = 0;
1876     jac->gridsweeps[0]    = jac->gridsweeps[1] = jac->gridsweeps[2] = 1;
1877     jac->smoothtype       = -1; /* Not set by default */
1878     jac->smoothnumlevels  = 25;
1879     jac->eu_level         = 0;
1880     jac->eu_droptolerance = 0;
1881     jac->eu_bj            = 0;
1882     jac->relaxtype[0]     = jac->relaxtype[1] = 6; /* Defaults to SYMMETRIC since in PETSc we are using a PC - most likely with CG */
1883     jac->relaxtype[2]     = 9; /*G.E. */
1884     jac->relaxweight      = 1.0;
1885     jac->outerrelaxweight = 1.0;
1886     jac->relaxorder       = 1;
1887     jac->interptype       = 0;
1888     jac->Rtype            = 0;
1889     jac->Rstrongthreshold = 0.25;
1890     jac->Rfilterthreshold = 0.0;
1891     jac->Adroptype        = -1;
1892     jac->Adroptol         = 0.0;
1893     jac->agg_nl           = 0;
1894     jac->agg_interptype   = 4;
1895     jac->pmax             = 0;
1896     jac->truncfactor      = 0.0;
1897     jac->agg_num_paths    = 1;
1898     jac->maxc             = 9;
1899     jac->minc             = 1;
1900     jac->nodal_coarsening      = 0;
1901     jac->nodal_coarsening_diag = 0;
1902     jac->vec_interp_variant    = 0;
1903     jac->vec_interp_qmax       = 0;
1904     jac->vec_interp_smooth     = PETSC_FALSE;
1905     jac->interp_refine         = 0;
1906     jac->nodal_relax           = PETSC_FALSE;
1907     jac->nodal_relax_levels    = 1;
1908     jac->rap2                  = 0;
1909 
1910     /* GPU defaults
1911          from https://hypre.readthedocs.io/en/latest/solvers-boomeramg.html#gpu-supported-options
1912          and /src/parcsr_ls/par_amg.c */
1913 #if defined(PETSC_HAVE_HYPRE_DEVICE)
1914     jac->keeptranspose         = PETSC_TRUE;
1915     jac->mod_rap2              = 1;
1916     jac->coarsentype           = 8;
1917     jac->relaxorder            = 0;
1918     jac->interptype            = 6;
1919     jac->relaxtype[0]          = 18;
1920     jac->relaxtype[1]          = 18;
1921     jac->agg_interptype        = 7;
1922 #else
1923     jac->keeptranspose         = PETSC_FALSE;
1924     jac->mod_rap2              = 0;
1925 #endif
1926     PetscStackCallStandard(HYPRE_BoomerAMGSetCycleType,jac->hsolver,jac->cycletype);
1927     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxLevels,jac->hsolver,jac->maxlevels);
1928     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxIter,jac->hsolver,jac->maxiter);
1929     PetscStackCallStandard(HYPRE_BoomerAMGSetTol,jac->hsolver,jac->tol);
1930     PetscStackCallStandard(HYPRE_BoomerAMGSetTruncFactor,jac->hsolver,jac->truncfactor);
1931     PetscStackCallStandard(HYPRE_BoomerAMGSetStrongThreshold,jac->hsolver,jac->strongthreshold);
1932     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxRowSum,jac->hsolver,jac->maxrowsum);
1933     PetscStackCallStandard(HYPRE_BoomerAMGSetCoarsenType,jac->hsolver,jac->coarsentype);
1934     PetscStackCallStandard(HYPRE_BoomerAMGSetMeasureType,jac->hsolver,jac->measuretype);
1935     PetscStackCallStandard(HYPRE_BoomerAMGSetRelaxOrder,jac->hsolver, jac->relaxorder);
1936     PetscStackCallStandard(HYPRE_BoomerAMGSetInterpType,jac->hsolver,jac->interptype);
1937     PetscStackCallStandard(HYPRE_BoomerAMGSetAggNumLevels,jac->hsolver,jac->agg_nl);
1938     PetscStackCallStandard(HYPRE_BoomerAMGSetAggInterpType,jac->hsolver,jac->agg_interptype);
1939     PetscStackCallStandard(HYPRE_BoomerAMGSetPMaxElmts,jac->hsolver,jac->pmax);
1940     PetscStackCallStandard(HYPRE_BoomerAMGSetNumPaths,jac->hsolver,jac->agg_num_paths);
1941     PetscStackCallStandard(HYPRE_BoomerAMGSetRelaxType,jac->hsolver, jac->relaxtype[0]);  /* defaults coarse to 9 */
1942     PetscStackCallStandard(HYPRE_BoomerAMGSetNumSweeps,jac->hsolver, jac->gridsweeps[0]); /* defaults coarse to 1 */
1943     PetscStackCallStandard(HYPRE_BoomerAMGSetMaxCoarseSize,jac->hsolver, jac->maxc);
1944     PetscStackCallStandard(HYPRE_BoomerAMGSetMinCoarseSize,jac->hsolver, jac->minc);
1945     /* GPU */
1946 #if PETSC_PKG_HYPRE_VERSION_GE(2,18,0)
1947     PetscStackCallStandard(HYPRE_BoomerAMGSetKeepTranspose,jac->hsolver,jac->keeptranspose ? 1 : 0);
1948     PetscStackCallStandard(HYPRE_BoomerAMGSetRAP2,jac->hsolver, jac->rap2);
1949     PetscStackCallStandard(HYPRE_BoomerAMGSetModuleRAP2,jac->hsolver, jac->mod_rap2);
1950 #endif
1951 
1952     /* AIR */
1953 #if PETSC_PKG_HYPRE_VERSION_GE(2,18,0)
1954     PetscStackCallStandard(HYPRE_BoomerAMGSetRestriction,jac->hsolver,jac->Rtype);
1955     PetscStackCallStandard(HYPRE_BoomerAMGSetStrongThresholdR,jac->hsolver,jac->Rstrongthreshold);
1956     PetscStackCallStandard(HYPRE_BoomerAMGSetFilterThresholdR,jac->hsolver,jac->Rfilterthreshold);
1957     PetscStackCallStandard(HYPRE_BoomerAMGSetADropTol,jac->hsolver,jac->Adroptol);
1958     PetscStackCallStandard(HYPRE_BoomerAMGSetADropType,jac->hsolver,jac->Adroptype);
1959 #endif
1960     PetscFunctionReturn(0);
1961   }
1962   PetscCall(PetscStrcmp("ams",jac->hypre_type,&flag));
1963   if (flag) {
1964     PetscCall(HYPRE_AMSCreate(&jac->hsolver));
1965     pc->ops->setfromoptions  = PCSetFromOptions_HYPRE_AMS;
1966     pc->ops->view            = PCView_HYPRE_AMS;
1967     jac->destroy             = HYPRE_AMSDestroy;
1968     jac->setup               = HYPRE_AMSSetup;
1969     jac->solve               = HYPRE_AMSSolve;
1970     jac->coords[0]           = NULL;
1971     jac->coords[1]           = NULL;
1972     jac->coords[2]           = NULL;
1973     /* solver parameters: these are borrowed from mfem package, and they are not the default values from HYPRE AMS */
1974     jac->as_print           = 0;
1975     jac->as_max_iter        = 1; /* used as a preconditioner */
1976     jac->as_tol             = 0.; /* used as a preconditioner */
1977     jac->ams_cycle_type     = 13;
1978     /* Smoothing options */
1979     jac->as_relax_type      = 2;
1980     jac->as_relax_times     = 1;
1981     jac->as_relax_weight    = 1.0;
1982     jac->as_omega           = 1.0;
1983     /* Vector valued Poisson AMG solver parameters: coarsen type, agg_levels, relax_type, interp_type, Pmax */
1984     jac->as_amg_alpha_opts[0] = 10;
1985     jac->as_amg_alpha_opts[1] = 1;
1986     jac->as_amg_alpha_opts[2] = 6;
1987     jac->as_amg_alpha_opts[3] = 6;
1988     jac->as_amg_alpha_opts[4] = 4;
1989     jac->as_amg_alpha_theta   = 0.25;
1990     /* Scalar Poisson AMG solver parameters: coarsen type, agg_levels, relax_type, interp_type, Pmax */
1991     jac->as_amg_beta_opts[0] = 10;
1992     jac->as_amg_beta_opts[1] = 1;
1993     jac->as_amg_beta_opts[2] = 6;
1994     jac->as_amg_beta_opts[3] = 6;
1995     jac->as_amg_beta_opts[4] = 4;
1996     jac->as_amg_beta_theta   = 0.25;
1997     PetscStackCallStandard(HYPRE_AMSSetPrintLevel,jac->hsolver,jac->as_print);
1998     PetscStackCallStandard(HYPRE_AMSSetMaxIter,jac->hsolver,jac->as_max_iter);
1999     PetscStackCallStandard(HYPRE_AMSSetCycleType,jac->hsolver,jac->ams_cycle_type);
2000     PetscStackCallStandard(HYPRE_AMSSetTol,jac->hsolver,jac->as_tol);
2001     PetscStackCallStandard(HYPRE_AMSSetSmoothingOptions,jac->hsolver,jac->as_relax_type,
2002                                                                       jac->as_relax_times,
2003                                                                       jac->as_relax_weight,
2004                                                                       jac->as_omega);
2005     PetscStackCallStandard(HYPRE_AMSSetAlphaAMGOptions,jac->hsolver,jac->as_amg_alpha_opts[0],       /* AMG coarsen type */
2006                                                                      jac->as_amg_alpha_opts[1],       /* AMG agg_levels */
2007                                                                      jac->as_amg_alpha_opts[2],       /* AMG relax_type */
2008                                                                      jac->as_amg_alpha_theta,
2009                                                                      jac->as_amg_alpha_opts[3],       /* AMG interp_type */
2010                                                                      jac->as_amg_alpha_opts[4]);     /* AMG Pmax */
2011     PetscStackCallStandard(HYPRE_AMSSetBetaAMGOptions,jac->hsolver,jac->as_amg_beta_opts[0],       /* AMG coarsen type */
2012                                                                     jac->as_amg_beta_opts[1],       /* AMG agg_levels */
2013                                                                     jac->as_amg_beta_opts[2],       /* AMG relax_type */
2014                                                                     jac->as_amg_beta_theta,
2015                                                                     jac->as_amg_beta_opts[3],       /* AMG interp_type */
2016                                                                     jac->as_amg_beta_opts[4]);     /* AMG Pmax */
2017     /* Zero conductivity */
2018     jac->ams_beta_is_zero      = PETSC_FALSE;
2019     jac->ams_beta_is_zero_part = PETSC_FALSE;
2020     PetscFunctionReturn(0);
2021   }
2022   PetscCall(PetscStrcmp("ads",jac->hypre_type,&flag));
2023   if (flag) {
2024     PetscCall(HYPRE_ADSCreate(&jac->hsolver));
2025     pc->ops->setfromoptions  = PCSetFromOptions_HYPRE_ADS;
2026     pc->ops->view            = PCView_HYPRE_ADS;
2027     jac->destroy             = HYPRE_ADSDestroy;
2028     jac->setup               = HYPRE_ADSSetup;
2029     jac->solve               = HYPRE_ADSSolve;
2030     jac->coords[0]           = NULL;
2031     jac->coords[1]           = NULL;
2032     jac->coords[2]           = NULL;
2033     /* solver parameters: these are borrowed from mfem package, and they are not the default values from HYPRE ADS */
2034     jac->as_print           = 0;
2035     jac->as_max_iter        = 1; /* used as a preconditioner */
2036     jac->as_tol             = 0.; /* used as a preconditioner */
2037     jac->ads_cycle_type     = 13;
2038     /* Smoothing options */
2039     jac->as_relax_type      = 2;
2040     jac->as_relax_times     = 1;
2041     jac->as_relax_weight    = 1.0;
2042     jac->as_omega           = 1.0;
2043     /* AMS solver parameters: cycle_type, coarsen type, agg_levels, relax_type, interp_type, Pmax */
2044     jac->ams_cycle_type       = 14;
2045     jac->as_amg_alpha_opts[0] = 10;
2046     jac->as_amg_alpha_opts[1] = 1;
2047     jac->as_amg_alpha_opts[2] = 6;
2048     jac->as_amg_alpha_opts[3] = 6;
2049     jac->as_amg_alpha_opts[4] = 4;
2050     jac->as_amg_alpha_theta   = 0.25;
2051     /* Vector Poisson AMG solver parameters: coarsen type, agg_levels, relax_type, interp_type, Pmax */
2052     jac->as_amg_beta_opts[0] = 10;
2053     jac->as_amg_beta_opts[1] = 1;
2054     jac->as_amg_beta_opts[2] = 6;
2055     jac->as_amg_beta_opts[3] = 6;
2056     jac->as_amg_beta_opts[4] = 4;
2057     jac->as_amg_beta_theta   = 0.25;
2058     PetscStackCallStandard(HYPRE_ADSSetPrintLevel,jac->hsolver,jac->as_print);
2059     PetscStackCallStandard(HYPRE_ADSSetMaxIter,jac->hsolver,jac->as_max_iter);
2060     PetscStackCallStandard(HYPRE_ADSSetCycleType,jac->hsolver,jac->ams_cycle_type);
2061     PetscStackCallStandard(HYPRE_ADSSetTol,jac->hsolver,jac->as_tol);
2062     PetscStackCallStandard(HYPRE_ADSSetSmoothingOptions,jac->hsolver,jac->as_relax_type,
2063                                                                       jac->as_relax_times,
2064                                                                       jac->as_relax_weight,
2065                                                                       jac->as_omega);
2066     PetscStackCallStandard(HYPRE_ADSSetAMSOptions,jac->hsolver,jac->ams_cycle_type,             /* AMG coarsen type */
2067                                                                 jac->as_amg_alpha_opts[0],       /* AMG coarsen type */
2068                                                                 jac->as_amg_alpha_opts[1],       /* AMG agg_levels */
2069                                                                 jac->as_amg_alpha_opts[2],       /* AMG relax_type */
2070                                                                 jac->as_amg_alpha_theta,
2071                                                                 jac->as_amg_alpha_opts[3],       /* AMG interp_type */
2072                                                                 jac->as_amg_alpha_opts[4]);     /* AMG Pmax */
2073     PetscStackCallStandard(HYPRE_ADSSetAMGOptions,jac->hsolver,jac->as_amg_beta_opts[0],       /* AMG coarsen type */
2074                                                                 jac->as_amg_beta_opts[1],       /* AMG agg_levels */
2075                                                                 jac->as_amg_beta_opts[2],       /* AMG relax_type */
2076                                                                 jac->as_amg_beta_theta,
2077                                                                 jac->as_amg_beta_opts[3],       /* AMG interp_type */
2078                                                                 jac->as_amg_beta_opts[4]);     /* AMG Pmax */
2079     PetscFunctionReturn(0);
2080   }
2081   PetscCall(PetscFree(jac->hypre_type));
2082 
2083   jac->hypre_type = NULL;
2084   SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown HYPRE preconditioner %s; Choices are euclid, pilut, parasails, boomeramg, ams",name);
2085 }
2086 
2087 /*
2088     It only gets here if the HYPRE type has not been set before the call to
2089    ...SetFromOptions() which actually is most of the time
2090 */
2091 PetscErrorCode PCSetFromOptions_HYPRE(PetscOptionItems *PetscOptionsObject,PC pc)
2092 {
2093   PetscInt       indx;
2094   const char     *type[] = {"euclid","pilut","parasails","boomeramg","ams","ads"};
2095   PetscBool      flg;
2096 
2097   PetscFunctionBegin;
2098   PetscOptionsHeadBegin(PetscOptionsObject,"HYPRE preconditioner options");
2099   PetscCall(PetscOptionsEList("-pc_hypre_type","HYPRE preconditioner type","PCHYPRESetType",type,PETSC_STATIC_ARRAY_LENGTH(type),"boomeramg",&indx,&flg));
2100   if (flg) {
2101     PetscCall(PCHYPRESetType_HYPRE(pc,type[indx]));
2102   } else {
2103     PetscCall(PCHYPRESetType_HYPRE(pc,"boomeramg"));
2104   }
2105   if (pc->ops->setfromoptions) PetscCall(pc->ops->setfromoptions(PetscOptionsObject,pc));
2106   PetscOptionsHeadEnd();
2107   PetscFunctionReturn(0);
2108 }
2109 
2110 /*@C
2111      PCHYPRESetType - Sets which hypre preconditioner you wish to use
2112 
2113    Input Parameters:
2114 +     pc - the preconditioner context
2115 -     name - either  euclid, pilut, parasails, boomeramg, ams, ads
2116 
2117    Options Database Keys:
2118    -pc_hypre_type - One of euclid, pilut, parasails, boomeramg, ams, ads
2119 
2120    Level: intermediate
2121 
2122 .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`,
2123           `PCHYPRE`
2124 
2125 @*/
2126 PetscErrorCode  PCHYPRESetType(PC pc,const char name[])
2127 {
2128   PetscFunctionBegin;
2129   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
2130   PetscValidCharPointer(name,2);
2131   PetscTryMethod(pc,"PCHYPRESetType_C",(PC,const char[]),(pc,name));
2132   PetscFunctionReturn(0);
2133 }
2134 
2135 /*@C
2136      PCHYPREGetType - Gets which hypre preconditioner you are using
2137 
2138    Input Parameter:
2139 .     pc - the preconditioner context
2140 
2141    Output Parameter:
2142 .     name - either  euclid, pilut, parasails, boomeramg, ams, ads
2143 
2144    Level: intermediate
2145 
2146 .seealso: `PCCreate()`, `PCHYPRESetType()`, `PCType`, `PC`,
2147           `PCHYPRE`
2148 
2149 @*/
2150 PetscErrorCode  PCHYPREGetType(PC pc,const char *name[])
2151 {
2152   PetscFunctionBegin;
2153   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
2154   PetscValidPointer(name,2);
2155   PetscTryMethod(pc,"PCHYPREGetType_C",(PC,const char*[]),(pc,name));
2156   PetscFunctionReturn(0);
2157 }
2158 
2159 /*@C
2160    PCMGGalerkinSetMatProductAlgorithm - Set type of SpGEMM for hypre to use
2161 
2162    Logically Collective on PC
2163 
2164    Input Parameters:
2165 +  pc - the hypre context
2166 -  type - one of 'cusparse', 'hypre'
2167 
2168    Options Database Key:
2169 .  -pc_mg_galerkin_mat_product_algorithm <cusparse,hypre> - Type of SpGEMM to use in hypre
2170 
2171    Level: intermediate
2172 
2173 .seealso: `PCMGGalerkinGetMatProductAlgorithm()`
2174 
2175 @*/
2176 PetscErrorCode PCMGGalerkinSetMatProductAlgorithm(PC pc,const char name[])
2177 {
2178   PetscFunctionBegin;
2179   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
2180   PetscTryMethod(pc,"PCMGGalerkinSetMatProductAlgorithm_C",(PC,const char[]),(pc,name));
2181   PetscFunctionReturn(0);
2182 }
2183 
2184 /*@C
2185    PCMGGalerkinGetMatProductAlgorithm - Get type of SpGEMM for hypre
2186 
2187    Not Collective
2188 
2189    Input Parameter:
2190 .  pc - the multigrid context
2191 
2192    Output Parameter:
2193 .  name - one of 'cusparse', 'hypre'
2194 
2195    Level: intermediate
2196 
2197 .seealso: `PCMGGalerkinSetMatProductAlgorithm()`
2198 
2199 @*/
2200 PetscErrorCode PCMGGalerkinGetMatProductAlgorithm(PC pc,const char *name[])
2201 {
2202   PetscFunctionBegin;
2203   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
2204   PetscTryMethod(pc,"PCMGGalerkinGetMatProductAlgorithm_C",(PC,const char*[]),(pc,name));
2205   PetscFunctionReturn(0);
2206 }
2207 
2208 /*MC
2209      PCHYPRE - Allows you to use the matrix element based preconditioners in the LLNL package hypre
2210 
2211    Options Database Keys:
2212 +   -pc_hypre_type - One of euclid, pilut, parasails, boomeramg, ams, ads
2213 .   -pc_hypre_boomeramg_nodal_coarsen <n> - where n is from 1 to 6 (see HYPRE_BOOMERAMGSetNodal())
2214 .   -pc_hypre_boomeramg_vec_interp_variant <v> - where v is from 1 to 3 (see HYPRE_BoomerAMGSetInterpVecVariant())
2215 -   Many others, run with -pc_type hypre -pc_hypre_type XXX -help to see options for the XXX preconditioner
2216 
2217    Level: intermediate
2218 
2219    Notes:
2220     Apart from pc_hypre_type (for which there is PCHYPRESetType()),
2221           the many hypre options can ONLY be set via the options database (e.g. the command line
2222           or with PetscOptionsSetValue(), there are no functions to set them)
2223 
2224           The options -pc_hypre_boomeramg_max_iter and -pc_hypre_boomeramg_tol refer to the number of iterations
2225           (V-cycles) and tolerance that boomeramg does EACH time it is called. So for example, if
2226           -pc_hypre_boomeramg_max_iter is set to 2 then 2-V-cycles are being used to define the preconditioner
2227           (-pc_hypre_boomeramg_tol should be set to 0.0 - the default - to strictly use a fixed number of
2228           iterations per hypre call). -ksp_max_it and -ksp_rtol STILL determine the total number of iterations
2229           and tolerance for the Krylov solver. For example, if -pc_hypre_boomeramg_max_iter is 2 and -ksp_max_it is 10
2230           then AT MOST twenty V-cycles of boomeramg will be called.
2231 
2232            Note that the option -pc_hypre_boomeramg_relax_type_all defaults to symmetric relaxation
2233            (symmetric-SOR/Jacobi), which is required for Krylov solvers like CG that expect symmetry.
2234            Otherwise, you may want to use -pc_hypre_boomeramg_relax_type_all SOR/Jacobi.
2235           If you wish to use BoomerAMG WITHOUT a Krylov method use -ksp_type richardson NOT -ksp_type preonly
2236           and use -ksp_max_it to control the number of V-cycles.
2237           (see the PETSc FAQ.html at the PETSc website under the Documentation tab).
2238 
2239           2007-02-03 Using HYPRE-1.11.1b, the routine HYPRE_BoomerAMGSolveT and the option
2240           -pc_hypre_parasails_reuse were failing with SIGSEGV. Dalcin L.
2241 
2242           MatSetNearNullSpace() - if you provide a near null space to your matrix it is ignored by hypre UNLESS you also use
2243           the following two options:
2244 
2245           See PCPFMG for access to the hypre Struct PFMG solver
2246 
2247    GPU Notes:
2248      To configure hypre BoomerAMG so that it can utilize NVIDIA GPUs run ./configure --download-hypre --with-cuda
2249      Then pass VECCUDA vectors and MATAIJCUSPARSE matrices to the solvers and PETSc will automatically utilize hypre's GPU solvers.
2250 
2251      To configure hypre BoomerAMG so that it can utilize AMD GPUs run ./configure --download-hypre --with-hip
2252      Then pass VECHIP vectors to the solvers and PETSc will automatically utilize hypre's GPU solvers.
2253 
2254 .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`,
2255           `PCHYPRESetType()`, `PCPFMG`
2256 
2257 M*/
2258 
2259 PETSC_EXTERN PetscErrorCode PCCreate_HYPRE(PC pc)
2260 {
2261   PC_HYPRE       *jac;
2262 
2263   PetscFunctionBegin;
2264   PetscCall(PetscNewLog(pc,&jac));
2265 
2266   pc->data                = jac;
2267   pc->ops->reset          = PCReset_HYPRE;
2268   pc->ops->destroy        = PCDestroy_HYPRE;
2269   pc->ops->setfromoptions = PCSetFromOptions_HYPRE;
2270   pc->ops->setup          = PCSetUp_HYPRE;
2271   pc->ops->apply          = PCApply_HYPRE;
2272   jac->comm_hypre         = MPI_COMM_NULL;
2273   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetType_C",PCHYPRESetType_HYPRE));
2274   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPREGetType_C",PCHYPREGetType_HYPRE));
2275   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCSetCoordinates_C",PCSetCoordinates_HYPRE));
2276   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetDiscreteGradient_C",PCHYPRESetDiscreteGradient_HYPRE));
2277   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetDiscreteCurl_C",PCHYPRESetDiscreteCurl_HYPRE));
2278   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetInterpolations_C",PCHYPRESetInterpolations_HYPRE));
2279   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetEdgeConstantVectors_C",PCHYPRESetEdgeConstantVectors_HYPRE));
2280   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCHYPRESetPoissonMatrix_C",PCHYPRESetPoissonMatrix_HYPRE));
2281   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGGalerkinSetMatProductAlgorithm_C",PCMGGalerkinSetMatProductAlgorithm_HYPRE_BoomerAMG));
2282   PetscCall(PetscObjectComposeFunction((PetscObject)pc,"PCMGGalerkinGetMatProductAlgorithm_C",PCMGGalerkinGetMatProductAlgorithm_HYPRE_BoomerAMG));
2283 #if defined(PETSC_HAVE_HYPRE_DEVICE)
2284 #if defined(HYPRE_USING_HIP)
2285   PetscCall(PetscDeviceInitialize(PETSC_DEVICE_HIP));
2286 #endif
2287 #if defined(HYPRE_USING_CUDA)
2288   PetscCall(PetscDeviceInitialize(PETSC_DEVICE_CUDA));
2289 #endif
2290 #endif
2291   PetscFunctionReturn(0);
2292 }
2293 
2294 /* ---------------------------------------------------------------------------------------------------------------------------------*/
2295 
2296 typedef struct {
2297   MPI_Comm           hcomm;        /* does not share comm with HYPRE_StructMatrix because need to create solver before getting matrix */
2298   HYPRE_StructSolver hsolver;
2299 
2300   /* keep copy of PFMG options used so may view them */
2301   PetscInt its;
2302   double   tol;
2303   PetscInt relax_type;
2304   PetscInt rap_type;
2305   PetscInt num_pre_relax,num_post_relax;
2306   PetscInt max_levels;
2307 } PC_PFMG;
2308 
2309 PetscErrorCode PCDestroy_PFMG(PC pc)
2310 {
2311   PC_PFMG        *ex = (PC_PFMG*) pc->data;
2312 
2313   PetscFunctionBegin;
2314   if (ex->hsolver) PetscStackCallStandard(HYPRE_StructPFMGDestroy,ex->hsolver);
2315   PetscCall(PetscCommRestoreComm(PetscObjectComm((PetscObject)pc),&ex->hcomm));
2316   PetscCall(PetscFree(pc->data));
2317   PetscFunctionReturn(0);
2318 }
2319 
2320 static const char *PFMGRelaxType[] = {"Jacobi","Weighted-Jacobi","symmetric-Red/Black-Gauss-Seidel","Red/Black-Gauss-Seidel"};
2321 static const char *PFMGRAPType[] = {"Galerkin","non-Galerkin"};
2322 
2323 PetscErrorCode PCView_PFMG(PC pc,PetscViewer viewer)
2324 {
2325   PetscBool      iascii;
2326   PC_PFMG        *ex = (PC_PFMG*) pc->data;
2327 
2328   PetscFunctionBegin;
2329   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
2330   if (iascii) {
2331     PetscCall(PetscViewerASCIIPrintf(viewer,"  HYPRE PFMG preconditioning\n"));
2332     PetscCall(PetscViewerASCIIPrintf(viewer,"    max iterations %" PetscInt_FMT "\n",ex->its));
2333     PetscCall(PetscViewerASCIIPrintf(viewer,"    tolerance %g\n",ex->tol));
2334     PetscCall(PetscViewerASCIIPrintf(viewer,"    relax type %s\n",PFMGRelaxType[ex->relax_type]));
2335     PetscCall(PetscViewerASCIIPrintf(viewer,"    RAP type %s\n",PFMGRAPType[ex->rap_type]));
2336     PetscCall(PetscViewerASCIIPrintf(viewer,"    number pre-relax %" PetscInt_FMT " post-relax %" PetscInt_FMT "\n",ex->num_pre_relax,ex->num_post_relax));
2337     PetscCall(PetscViewerASCIIPrintf(viewer,"    max levels %" PetscInt_FMT "\n",ex->max_levels));
2338   }
2339   PetscFunctionReturn(0);
2340 }
2341 
2342 PetscErrorCode PCSetFromOptions_PFMG(PetscOptionItems *PetscOptionsObject,PC pc)
2343 {
2344   PC_PFMG        *ex = (PC_PFMG*) pc->data;
2345   PetscBool      flg = PETSC_FALSE;
2346 
2347   PetscFunctionBegin;
2348   PetscOptionsHeadBegin(PetscOptionsObject,"PFMG options");
2349   PetscCall(PetscOptionsBool("-pc_pfmg_print_statistics","Print statistics","HYPRE_StructPFMGSetPrintLevel",flg,&flg,NULL));
2350   if (flg) {
2351     PetscStackCallStandard(HYPRE_StructPFMGSetPrintLevel,ex->hsolver,3);
2352   }
2353   PetscCall(PetscOptionsInt("-pc_pfmg_its","Number of iterations of PFMG to use as preconditioner","HYPRE_StructPFMGSetMaxIter",ex->its,&ex->its,NULL));
2354   PetscStackCallStandard(HYPRE_StructPFMGSetMaxIter,ex->hsolver,ex->its);
2355   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));
2356   PetscStackCallStandard(HYPRE_StructPFMGSetNumPreRelax,ex->hsolver,ex->num_pre_relax);
2357   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));
2358   PetscStackCallStandard(HYPRE_StructPFMGSetNumPostRelax,ex->hsolver,ex->num_post_relax);
2359 
2360   PetscCall(PetscOptionsInt("-pc_pfmg_max_levels","Max Levels for MG hierarchy","HYPRE_StructPFMGSetMaxLevels",ex->max_levels,&ex->max_levels,NULL));
2361   PetscStackCallStandard(HYPRE_StructPFMGSetMaxLevels,ex->hsolver,ex->max_levels);
2362 
2363   PetscCall(PetscOptionsReal("-pc_pfmg_tol","Tolerance of PFMG","HYPRE_StructPFMGSetTol",ex->tol,&ex->tol,NULL));
2364   PetscStackCallStandard(HYPRE_StructPFMGSetTol,ex->hsolver,ex->tol);
2365   PetscCall(PetscOptionsEList("-pc_pfmg_relax_type","Relax type for the up and down cycles","HYPRE_StructPFMGSetRelaxType",PFMGRelaxType,PETSC_STATIC_ARRAY_LENGTH(PFMGRelaxType),PFMGRelaxType[ex->relax_type],&ex->relax_type,NULL));
2366   PetscStackCallStandard(HYPRE_StructPFMGSetRelaxType,ex->hsolver, ex->relax_type);
2367   PetscCall(PetscOptionsEList("-pc_pfmg_rap_type","RAP type","HYPRE_StructPFMGSetRAPType",PFMGRAPType,PETSC_STATIC_ARRAY_LENGTH(PFMGRAPType),PFMGRAPType[ex->rap_type],&ex->rap_type,NULL));
2368   PetscStackCallStandard(HYPRE_StructPFMGSetRAPType,ex->hsolver, ex->rap_type);
2369   PetscOptionsHeadEnd();
2370   PetscFunctionReturn(0);
2371 }
2372 
2373 PetscErrorCode PCApply_PFMG(PC pc,Vec x,Vec y)
2374 {
2375   PC_PFMG           *ex = (PC_PFMG*) pc->data;
2376   PetscScalar       *yy;
2377   const PetscScalar *xx;
2378   PetscInt          ilower[3],iupper[3];
2379   HYPRE_Int         hlower[3],hupper[3];
2380   Mat_HYPREStruct   *mx = (Mat_HYPREStruct*)(pc->pmat->data);
2381 
2382   PetscFunctionBegin;
2383   PetscCall(PetscCitationsRegister(hypreCitation,&cite));
2384   PetscCall(DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]));
2385   /* when HYPRE_MIXEDINT is defined, sizeof(HYPRE_Int) == 32 */
2386   iupper[0] += ilower[0] - 1;
2387   iupper[1] += ilower[1] - 1;
2388   iupper[2] += ilower[2] - 1;
2389   hlower[0]  = (HYPRE_Int)ilower[0];
2390   hlower[1]  = (HYPRE_Int)ilower[1];
2391   hlower[2]  = (HYPRE_Int)ilower[2];
2392   hupper[0]  = (HYPRE_Int)iupper[0];
2393   hupper[1]  = (HYPRE_Int)iupper[1];
2394   hupper[2]  = (HYPRE_Int)iupper[2];
2395 
2396   /* copy x values over to hypre */
2397   PetscStackCallStandard(HYPRE_StructVectorSetConstantValues,mx->hb,0.0);
2398   PetscCall(VecGetArrayRead(x,&xx));
2399   PetscStackCallStandard(HYPRE_StructVectorSetBoxValues,mx->hb,hlower,hupper,(HYPRE_Complex*)xx);
2400   PetscCall(VecRestoreArrayRead(x,&xx));
2401   PetscStackCallStandard(HYPRE_StructVectorAssemble,mx->hb);
2402   PetscStackCallStandard(HYPRE_StructPFMGSolve,ex->hsolver,mx->hmat,mx->hb,mx->hx);
2403 
2404   /* copy solution values back to PETSc */
2405   PetscCall(VecGetArray(y,&yy));
2406   PetscStackCallStandard(HYPRE_StructVectorGetBoxValues,mx->hx,hlower,hupper,(HYPRE_Complex*)yy);
2407   PetscCall(VecRestoreArray(y,&yy));
2408   PetscFunctionReturn(0);
2409 }
2410 
2411 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)
2412 {
2413   PC_PFMG        *jac = (PC_PFMG*)pc->data;
2414   HYPRE_Int      oits;
2415 
2416   PetscFunctionBegin;
2417   PetscCall(PetscCitationsRegister(hypreCitation,&cite));
2418   PetscStackCallStandard(HYPRE_StructPFMGSetMaxIter,jac->hsolver,its*jac->its);
2419   PetscStackCallStandard(HYPRE_StructPFMGSetTol,jac->hsolver,rtol);
2420 
2421   PetscCall(PCApply_PFMG(pc,b,y));
2422   PetscStackCallStandard(HYPRE_StructPFMGGetNumIterations,jac->hsolver,&oits);
2423   *outits = oits;
2424   if (oits == its) *reason = PCRICHARDSON_CONVERGED_ITS;
2425   else             *reason = PCRICHARDSON_CONVERGED_RTOL;
2426   PetscStackCallStandard(HYPRE_StructPFMGSetTol,jac->hsolver,jac->tol);
2427   PetscStackCallStandard(HYPRE_StructPFMGSetMaxIter,jac->hsolver,jac->its);
2428   PetscFunctionReturn(0);
2429 }
2430 
2431 PetscErrorCode PCSetUp_PFMG(PC pc)
2432 {
2433   PC_PFMG         *ex = (PC_PFMG*) pc->data;
2434   Mat_HYPREStruct *mx = (Mat_HYPREStruct*)(pc->pmat->data);
2435   PetscBool       flg;
2436 
2437   PetscFunctionBegin;
2438   PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat,MATHYPRESTRUCT,&flg));
2439   PetscCheck(flg,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Must use MATHYPRESTRUCT with this preconditioner");
2440 
2441   /* create the hypre solver object and set its information */
2442   if (ex->hsolver) PetscStackCallStandard(HYPRE_StructPFMGDestroy,ex->hsolver);
2443   PetscStackCallStandard(HYPRE_StructPFMGCreate,ex->hcomm,&ex->hsolver);
2444   PetscStackCallStandard(HYPRE_StructPFMGSetup,ex->hsolver,mx->hmat,mx->hb,mx->hx);
2445   PetscStackCallStandard(HYPRE_StructPFMGSetZeroGuess,ex->hsolver);
2446   PetscFunctionReturn(0);
2447 }
2448 
2449 /*MC
2450      PCPFMG - the hypre PFMG multigrid solver
2451 
2452    Level: advanced
2453 
2454    Options Database:
2455 + -pc_pfmg_its <its> - number of iterations of PFMG to use as preconditioner
2456 . -pc_pfmg_num_pre_relax <steps> - number of smoothing steps before coarse grid solve
2457 . -pc_pfmg_num_post_relax <steps> - number of smoothing steps after coarse grid solve
2458 . -pc_pfmg_tol <tol> - tolerance of PFMG
2459 . -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
2460 - -pc_pfmg_rap_type - type of coarse matrix generation, one of Galerkin,non-Galerkin
2461 
2462    Notes:
2463     This is for CELL-centered descretizations
2464 
2465            This must be used with the MATHYPRESTRUCT matrix type.
2466            This is less general than in hypre, it supports only one block per process defined by a PETSc DMDA.
2467 
2468 .seealso: `PCMG`, `MATHYPRESTRUCT`
2469 M*/
2470 
2471 PETSC_EXTERN PetscErrorCode PCCreate_PFMG(PC pc)
2472 {
2473   PC_PFMG        *ex;
2474 
2475   PetscFunctionBegin;
2476   PetscCall(PetscNew(&ex)); \
2477   pc->data = ex;
2478 
2479   ex->its            = 1;
2480   ex->tol            = 1.e-8;
2481   ex->relax_type     = 1;
2482   ex->rap_type       = 0;
2483   ex->num_pre_relax  = 1;
2484   ex->num_post_relax = 1;
2485   ex->max_levels     = 0;
2486 
2487   pc->ops->setfromoptions  = PCSetFromOptions_PFMG;
2488   pc->ops->view            = PCView_PFMG;
2489   pc->ops->destroy         = PCDestroy_PFMG;
2490   pc->ops->apply           = PCApply_PFMG;
2491   pc->ops->applyrichardson = PCApplyRichardson_PFMG;
2492   pc->ops->setup           = PCSetUp_PFMG;
2493 
2494   PetscCall(PetscCommGetComm(PetscObjectComm((PetscObject)pc),&ex->hcomm));
2495   PetscStackCallStandard(HYPRE_StructPFMGCreate,ex->hcomm,&ex->hsolver);
2496   PetscFunctionReturn(0);
2497 }
2498 
2499 /* ---------------------------------------------------------------------------------------------------------------------------------------------------*/
2500 
2501 /* we know we are working with a HYPRE_SStructMatrix */
2502 typedef struct {
2503   MPI_Comm            hcomm;       /* does not share comm with HYPRE_SStructMatrix because need to create solver before getting matrix */
2504   HYPRE_SStructSolver ss_solver;
2505 
2506   /* keep copy of SYSPFMG options used so may view them */
2507   PetscInt its;
2508   double   tol;
2509   PetscInt relax_type;
2510   PetscInt num_pre_relax,num_post_relax;
2511 } PC_SysPFMG;
2512 
2513 PetscErrorCode PCDestroy_SysPFMG(PC pc)
2514 {
2515   PC_SysPFMG     *ex = (PC_SysPFMG*) pc->data;
2516 
2517   PetscFunctionBegin;
2518   if (ex->ss_solver) PetscStackCallStandard(HYPRE_SStructSysPFMGDestroy,ex->ss_solver);
2519   PetscCall(PetscCommRestoreComm(PetscObjectComm((PetscObject)pc),&ex->hcomm));
2520   PetscCall(PetscFree(pc->data));
2521   PetscFunctionReturn(0);
2522 }
2523 
2524 static const char *SysPFMGRelaxType[] = {"Weighted-Jacobi","Red/Black-Gauss-Seidel"};
2525 
2526 PetscErrorCode PCView_SysPFMG(PC pc,PetscViewer viewer)
2527 {
2528   PetscBool      iascii;
2529   PC_SysPFMG     *ex = (PC_SysPFMG*) pc->data;
2530 
2531   PetscFunctionBegin;
2532   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
2533   if (iascii) {
2534     PetscCall(PetscViewerASCIIPrintf(viewer,"  HYPRE SysPFMG preconditioning\n"));
2535     PetscCall(PetscViewerASCIIPrintf(viewer,"  max iterations %" PetscInt_FMT "\n",ex->its));
2536     PetscCall(PetscViewerASCIIPrintf(viewer,"  tolerance %g\n",ex->tol));
2537     PetscCall(PetscViewerASCIIPrintf(viewer,"  relax type %s\n",PFMGRelaxType[ex->relax_type]));
2538     PetscCall(PetscViewerASCIIPrintf(viewer,"  number pre-relax %" PetscInt_FMT " post-relax %" PetscInt_FMT "\n",ex->num_pre_relax,ex->num_post_relax));
2539   }
2540   PetscFunctionReturn(0);
2541 }
2542 
2543 PetscErrorCode PCSetFromOptions_SysPFMG(PetscOptionItems *PetscOptionsObject,PC pc)
2544 {
2545   PC_SysPFMG     *ex = (PC_SysPFMG*) pc->data;
2546   PetscBool      flg = PETSC_FALSE;
2547 
2548   PetscFunctionBegin;
2549   PetscOptionsHeadBegin(PetscOptionsObject,"SysPFMG options");
2550   PetscCall(PetscOptionsBool("-pc_syspfmg_print_statistics","Print statistics","HYPRE_SStructSysPFMGSetPrintLevel",flg,&flg,NULL));
2551   if (flg) {
2552     PetscStackCallStandard(HYPRE_SStructSysPFMGSetPrintLevel,ex->ss_solver,3);
2553   }
2554   PetscCall(PetscOptionsInt("-pc_syspfmg_its","Number of iterations of SysPFMG to use as preconditioner","HYPRE_SStructSysPFMGSetMaxIter",ex->its,&ex->its,NULL));
2555   PetscStackCallStandard(HYPRE_SStructSysPFMGSetMaxIter,ex->ss_solver,ex->its);
2556   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));
2557   PetscStackCallStandard(HYPRE_SStructSysPFMGSetNumPreRelax,ex->ss_solver,ex->num_pre_relax);
2558   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));
2559   PetscStackCallStandard(HYPRE_SStructSysPFMGSetNumPostRelax,ex->ss_solver,ex->num_post_relax);
2560 
2561   PetscCall(PetscOptionsReal("-pc_syspfmg_tol","Tolerance of SysPFMG","HYPRE_SStructSysPFMGSetTol",ex->tol,&ex->tol,NULL));
2562   PetscStackCallStandard(HYPRE_SStructSysPFMGSetTol,ex->ss_solver,ex->tol);
2563   PetscCall(PetscOptionsEList("-pc_syspfmg_relax_type","Relax type for the up and down cycles","HYPRE_SStructSysPFMGSetRelaxType",SysPFMGRelaxType,PETSC_STATIC_ARRAY_LENGTH(SysPFMGRelaxType),SysPFMGRelaxType[ex->relax_type],&ex->relax_type,NULL));
2564   PetscStackCallStandard(HYPRE_SStructSysPFMGSetRelaxType,ex->ss_solver, ex->relax_type);
2565   PetscOptionsHeadEnd();
2566   PetscFunctionReturn(0);
2567 }
2568 
2569 PetscErrorCode PCApply_SysPFMG(PC pc,Vec x,Vec y)
2570 {
2571   PC_SysPFMG        *ex = (PC_SysPFMG*) pc->data;
2572   PetscScalar       *yy;
2573   const PetscScalar *xx;
2574   PetscInt          ilower[3],iupper[3];
2575   HYPRE_Int         hlower[3],hupper[3];
2576   Mat_HYPRESStruct  *mx     = (Mat_HYPRESStruct*)(pc->pmat->data);
2577   PetscInt          ordering= mx->dofs_order;
2578   PetscInt          nvars   = mx->nvars;
2579   PetscInt          part    = 0;
2580   PetscInt          size;
2581   PetscInt          i;
2582 
2583   PetscFunctionBegin;
2584   PetscCall(PetscCitationsRegister(hypreCitation,&cite));
2585   PetscCall(DMDAGetCorners(mx->da,&ilower[0],&ilower[1],&ilower[2],&iupper[0],&iupper[1],&iupper[2]));
2586   /* when HYPRE_MIXEDINT is defined, sizeof(HYPRE_Int) == 32 */
2587   iupper[0] += ilower[0] - 1;
2588   iupper[1] += ilower[1] - 1;
2589   iupper[2] += ilower[2] - 1;
2590   hlower[0]  = (HYPRE_Int)ilower[0];
2591   hlower[1]  = (HYPRE_Int)ilower[1];
2592   hlower[2]  = (HYPRE_Int)ilower[2];
2593   hupper[0]  = (HYPRE_Int)iupper[0];
2594   hupper[1]  = (HYPRE_Int)iupper[1];
2595   hupper[2]  = (HYPRE_Int)iupper[2];
2596 
2597   size = 1;
2598   for (i= 0; i< 3; i++) size *= (iupper[i]-ilower[i]+1);
2599 
2600   /* copy x values over to hypre for variable ordering */
2601   if (ordering) {
2602     PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,mx->ss_b,0.0);
2603     PetscCall(VecGetArrayRead(x,&xx));
2604     for (i= 0; i< nvars; i++) PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,mx->ss_b,part,hlower,hupper,i,(HYPRE_Complex*)(xx+(size*i)));
2605     PetscCall(VecRestoreArrayRead(x,&xx));
2606     PetscStackCallStandard(HYPRE_SStructVectorAssemble,mx->ss_b);
2607     PetscStackCallStandard(HYPRE_SStructMatrixMatvec,1.0,mx->ss_mat,mx->ss_b,0.0,mx->ss_x);
2608     PetscStackCallStandard(HYPRE_SStructSysPFMGSolve,ex->ss_solver,mx->ss_mat,mx->ss_b,mx->ss_x);
2609 
2610     /* copy solution values back to PETSc */
2611     PetscCall(VecGetArray(y,&yy));
2612     for (i= 0; i< nvars; i++) PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,mx->ss_x,part,hlower,hupper,i,(HYPRE_Complex*)(yy+(size*i)));
2613     PetscCall(VecRestoreArray(y,&yy));
2614   } else {      /* nodal ordering must be mapped to variable ordering for sys_pfmg */
2615     PetscScalar *z;
2616     PetscInt    j, k;
2617 
2618     PetscCall(PetscMalloc1(nvars*size,&z));
2619     PetscStackCallStandard(HYPRE_SStructVectorSetConstantValues,mx->ss_b,0.0);
2620     PetscCall(VecGetArrayRead(x,&xx));
2621 
2622     /* transform nodal to hypre's variable ordering for sys_pfmg */
2623     for (i= 0; i< size; i++) {
2624       k= i*nvars;
2625       for (j= 0; j< nvars; j++) z[j*size+i]= xx[k+j];
2626     }
2627     for (i= 0; i< nvars; i++) PetscStackCallStandard(HYPRE_SStructVectorSetBoxValues,mx->ss_b,part,hlower,hupper,i,(HYPRE_Complex*)(z+(size*i)));
2628     PetscCall(VecRestoreArrayRead(x,&xx));
2629     PetscStackCallStandard(HYPRE_SStructVectorAssemble,mx->ss_b);
2630     PetscStackCallStandard(HYPRE_SStructSysPFMGSolve,ex->ss_solver,mx->ss_mat,mx->ss_b,mx->ss_x);
2631 
2632     /* copy solution values back to PETSc */
2633     PetscCall(VecGetArray(y,&yy));
2634     for (i= 0; i< nvars; i++) PetscStackCallStandard(HYPRE_SStructVectorGetBoxValues,mx->ss_x,part,hlower,hupper,i,(HYPRE_Complex*)(z+(size*i)));
2635     /* transform hypre's variable ordering for sys_pfmg to nodal ordering */
2636     for (i= 0; i< size; i++) {
2637       k= i*nvars;
2638       for (j= 0; j< nvars; j++) yy[k+j]= z[j*size+i];
2639     }
2640     PetscCall(VecRestoreArray(y,&yy));
2641     PetscCall(PetscFree(z));
2642   }
2643   PetscFunctionReturn(0);
2644 }
2645 
2646 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)
2647 {
2648   PC_SysPFMG     *jac = (PC_SysPFMG*)pc->data;
2649   HYPRE_Int      oits;
2650 
2651   PetscFunctionBegin;
2652   PetscCall(PetscCitationsRegister(hypreCitation,&cite));
2653   PetscStackCallStandard(HYPRE_SStructSysPFMGSetMaxIter,jac->ss_solver,its*jac->its);
2654   PetscStackCallStandard(HYPRE_SStructSysPFMGSetTol,jac->ss_solver,rtol);
2655   PetscCall(PCApply_SysPFMG(pc,b,y));
2656   PetscStackCallStandard(HYPRE_SStructSysPFMGGetNumIterations,jac->ss_solver,&oits);
2657   *outits = oits;
2658   if (oits == its) *reason = PCRICHARDSON_CONVERGED_ITS;
2659   else             *reason = PCRICHARDSON_CONVERGED_RTOL;
2660   PetscStackCallStandard(HYPRE_SStructSysPFMGSetTol,jac->ss_solver,jac->tol);
2661   PetscStackCallStandard(HYPRE_SStructSysPFMGSetMaxIter,jac->ss_solver,jac->its);
2662   PetscFunctionReturn(0);
2663 }
2664 
2665 PetscErrorCode PCSetUp_SysPFMG(PC pc)
2666 {
2667   PC_SysPFMG       *ex = (PC_SysPFMG*) pc->data;
2668   Mat_HYPRESStruct *mx = (Mat_HYPRESStruct*)(pc->pmat->data);
2669   PetscBool        flg;
2670 
2671   PetscFunctionBegin;
2672   PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat,MATHYPRESSTRUCT,&flg));
2673   PetscCheck(flg,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"Must use MATHYPRESSTRUCT with this preconditioner");
2674 
2675   /* create the hypre sstruct solver object and set its information */
2676   if (ex->ss_solver) PetscStackCallStandard(HYPRE_SStructSysPFMGDestroy,ex->ss_solver);
2677   PetscStackCallStandard(HYPRE_SStructSysPFMGCreate,ex->hcomm,&ex->ss_solver);
2678   PetscStackCallStandard(HYPRE_SStructSysPFMGSetZeroGuess,ex->ss_solver);
2679   PetscStackCallStandard(HYPRE_SStructSysPFMGSetup,ex->ss_solver,mx->ss_mat,mx->ss_b,mx->ss_x);
2680   PetscFunctionReturn(0);
2681 }
2682 
2683 /*MC
2684      PCSysPFMG - the hypre SysPFMG multigrid solver
2685 
2686    Level: advanced
2687 
2688    Options Database:
2689 + -pc_syspfmg_its <its> - number of iterations of SysPFMG to use as preconditioner
2690 . -pc_syspfmg_num_pre_relax <steps> - number of smoothing steps before coarse grid
2691 . -pc_syspfmg_num_post_relax <steps> - number of smoothing steps after coarse grid
2692 . -pc_syspfmg_tol <tol> - tolerance of SysPFMG
2693 - -pc_syspfmg_relax_type <Weighted-Jacobi,Red/Black-Gauss-Seidel> - relaxation type for the up and down cycles
2694 
2695    Notes:
2696     This is for CELL-centered descretizations
2697 
2698            This must be used with the MATHYPRESSTRUCT matrix type.
2699            This is less general than in hypre, it supports only one part, and one block per process defined by a PETSc DMDA.
2700            Also, only cell-centered variables.
2701 
2702 .seealso: `PCMG`, `MATHYPRESSTRUCT`
2703 M*/
2704 
2705 PETSC_EXTERN PetscErrorCode PCCreate_SysPFMG(PC pc)
2706 {
2707   PC_SysPFMG     *ex;
2708 
2709   PetscFunctionBegin;
2710   PetscCall(PetscNew(&ex)); \
2711   pc->data = ex;
2712 
2713   ex->its            = 1;
2714   ex->tol            = 1.e-8;
2715   ex->relax_type     = 1;
2716   ex->num_pre_relax  = 1;
2717   ex->num_post_relax = 1;
2718 
2719   pc->ops->setfromoptions  = PCSetFromOptions_SysPFMG;
2720   pc->ops->view            = PCView_SysPFMG;
2721   pc->ops->destroy         = PCDestroy_SysPFMG;
2722   pc->ops->apply           = PCApply_SysPFMG;
2723   pc->ops->applyrichardson = PCApplyRichardson_SysPFMG;
2724   pc->ops->setup           = PCSetUp_SysPFMG;
2725 
2726   PetscCall(PetscCommGetComm(PetscObjectComm((PetscObject)pc),&ex->hcomm));
2727   PetscStackCallStandard(HYPRE_SStructSysPFMGCreate,ex->hcomm,&ex->ss_solver);
2728   PetscFunctionReturn(0);
2729 }
2730