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