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