1e6f8f311SMark Adams /* 2e6f8f311SMark Adams This file implements an AmgX preconditioner in PETSc as part of PC. 3e6f8f311SMark Adams */ 4e6f8f311SMark Adams 5e6f8f311SMark Adams /* 6e6f8f311SMark Adams Include files needed for the AmgX preconditioner: 7e6f8f311SMark Adams pcimpl.h - private include file intended for use by all preconditioners 8e6f8f311SMark Adams */ 9e6f8f311SMark Adams 10e6f8f311SMark Adams #include <petsc/private/pcimpl.h> /*I "petscpc.h" I*/ 110e6b6b59SJacob Faibussowitsch #include <petscdevice_cuda.h> 12e6f8f311SMark Adams #include <amgx_c.h> 13e6f8f311SMark Adams #include <limits> 14e6f8f311SMark Adams #include <vector> 15e6f8f311SMark Adams #include <algorithm> 16e6f8f311SMark Adams #include <map> 17e6f8f311SMark Adams #include <numeric> 18e6f8f311SMark Adams #include "cuda_runtime.h" 19e6f8f311SMark Adams 209371c9d4SSatish Balay enum class AmgXSmoother { 219371c9d4SSatish Balay PCG, 229371c9d4SSatish Balay PCGF, 239371c9d4SSatish Balay PBiCGStab, 249371c9d4SSatish Balay GMRES, 259371c9d4SSatish Balay FGMRES, 269371c9d4SSatish Balay JacobiL1, 279371c9d4SSatish Balay BlockJacobi, 289371c9d4SSatish Balay GS, 299371c9d4SSatish Balay MulticolorGS, 309371c9d4SSatish Balay MulticolorILU, 319371c9d4SSatish Balay MulticolorDILU, 329371c9d4SSatish Balay ChebyshevPoly, 339371c9d4SSatish Balay NoSolver 349371c9d4SSatish Balay }; 359371c9d4SSatish Balay enum class AmgXAMGMethod { 369371c9d4SSatish Balay Classical, 379371c9d4SSatish Balay Aggregation 389371c9d4SSatish Balay }; 399371c9d4SSatish Balay enum class AmgXSelector { 409371c9d4SSatish Balay Size2, 419371c9d4SSatish Balay Size4, 429371c9d4SSatish Balay Size8, 439371c9d4SSatish Balay MultiPairwise, 449371c9d4SSatish Balay PMIS, 459371c9d4SSatish Balay HMIS 469371c9d4SSatish Balay }; 479371c9d4SSatish Balay enum class AmgXCoarseSolver { 489371c9d4SSatish Balay DenseLU, 499371c9d4SSatish Balay NoSolver 509371c9d4SSatish Balay }; 519371c9d4SSatish Balay enum class AmgXAMGCycle { 529371c9d4SSatish Balay V, 539371c9d4SSatish Balay W, 549371c9d4SSatish Balay F, 559371c9d4SSatish Balay CG, 569371c9d4SSatish Balay CGF 579371c9d4SSatish Balay }; 58e6f8f311SMark Adams 599371c9d4SSatish Balay struct AmgXControlMap { 60e6f8f311SMark Adams static const std::map<std::string, AmgXAMGMethod> AMGMethods; 61e6f8f311SMark Adams static const std::map<std::string, AmgXSmoother> Smoothers; 62e6f8f311SMark Adams static const std::map<std::string, AmgXSelector> Selectors; 63e6f8f311SMark Adams static const std::map<std::string, AmgXCoarseSolver> CoarseSolvers; 64e6f8f311SMark Adams static const std::map<std::string, AmgXAMGCycle> AMGCycles; 65e6f8f311SMark Adams }; 66e6f8f311SMark Adams 67e6f8f311SMark Adams const std::map<std::string, AmgXAMGMethod> AmgXControlMap::AMGMethods = { 68e6f8f311SMark Adams {"CLASSICAL", AmgXAMGMethod::Classical }, 69e6f8f311SMark Adams {"AGGREGATION", AmgXAMGMethod::Aggregation} 70e6f8f311SMark Adams }; 71e6f8f311SMark Adams 72e6f8f311SMark Adams const std::map<std::string, AmgXSmoother> AmgXControlMap::Smoothers = { 73e6f8f311SMark Adams {"PCG", AmgXSmoother::PCG }, 74e6f8f311SMark Adams {"PCGF", AmgXSmoother::PCGF }, 75e6f8f311SMark Adams {"PBICGSTAB", AmgXSmoother::PBiCGStab }, 76e6f8f311SMark Adams {"GMRES", AmgXSmoother::GMRES }, 77e6f8f311SMark Adams {"FGMRES", AmgXSmoother::FGMRES }, 78e6f8f311SMark Adams {"JACOBI_L1", AmgXSmoother::JacobiL1 }, 79e6f8f311SMark Adams {"BLOCK_JACOBI", AmgXSmoother::BlockJacobi }, 80e6f8f311SMark Adams {"GS", AmgXSmoother::GS }, 81e6f8f311SMark Adams {"MULTICOLOR_GS", AmgXSmoother::MulticolorGS }, 82e6f8f311SMark Adams {"MULTICOLOR_ILU", AmgXSmoother::MulticolorILU }, 83e6f8f311SMark Adams {"MULTICOLOR_DILU", AmgXSmoother::MulticolorDILU}, 84e6f8f311SMark Adams {"CHEBYSHEV_POLY", AmgXSmoother::ChebyshevPoly }, 85e6f8f311SMark Adams {"NOSOLVER", AmgXSmoother::NoSolver } 86e6f8f311SMark Adams }; 87e6f8f311SMark Adams 88e6f8f311SMark Adams const std::map<std::string, AmgXSelector> AmgXControlMap::Selectors = { 89e6f8f311SMark Adams {"SIZE_2", AmgXSelector::Size2 }, 90e6f8f311SMark Adams {"SIZE_4", AmgXSelector::Size4 }, 91e6f8f311SMark Adams {"SIZE_8", AmgXSelector::Size8 }, 92e6f8f311SMark Adams {"MULTI_PAIRWISE", AmgXSelector::MultiPairwise}, 93e6f8f311SMark Adams {"PMIS", AmgXSelector::PMIS }, 94e6f8f311SMark Adams {"HMIS", AmgXSelector::HMIS } 95e6f8f311SMark Adams }; 96e6f8f311SMark Adams 97e6f8f311SMark Adams const std::map<std::string, AmgXCoarseSolver> AmgXControlMap::CoarseSolvers = { 98e6f8f311SMark Adams {"DENSE_LU_SOLVER", AmgXCoarseSolver::DenseLU }, 99e6f8f311SMark Adams {"NOSOLVER", AmgXCoarseSolver::NoSolver} 100e6f8f311SMark Adams }; 101e6f8f311SMark Adams 102e6f8f311SMark Adams const std::map<std::string, AmgXAMGCycle> AmgXControlMap::AMGCycles = { 103e6f8f311SMark Adams {"V", AmgXAMGCycle::V }, 104e6f8f311SMark Adams {"W", AmgXAMGCycle::W }, 105e6f8f311SMark Adams {"F", AmgXAMGCycle::F }, 106e6f8f311SMark Adams {"CG", AmgXAMGCycle::CG }, 107e6f8f311SMark Adams {"CGF", AmgXAMGCycle::CGF} 108e6f8f311SMark Adams }; 109e6f8f311SMark Adams 110e6f8f311SMark Adams /* 111e6f8f311SMark Adams Private context (data structure) for the AMGX preconditioner. 112e6f8f311SMark Adams */ 113e6f8f311SMark Adams struct PC_AMGX { 114e6f8f311SMark Adams AMGX_solver_handle solver; 115e6f8f311SMark Adams AMGX_config_handle cfg; 116e6f8f311SMark Adams AMGX_resources_handle rsrc; 117e6f8f311SMark Adams bool solve_state_init; 118e6f8f311SMark Adams bool rsrc_init; 119e6f8f311SMark Adams PetscBool verbose; 120e6f8f311SMark Adams 121e6f8f311SMark Adams AMGX_matrix_handle A; 122e6f8f311SMark Adams AMGX_vector_handle sol; 123e6f8f311SMark Adams AMGX_vector_handle rhs; 124e6f8f311SMark Adams 125e6f8f311SMark Adams MPI_Comm comm; 126e6f8f311SMark Adams PetscMPIInt rank = 0; 127e6f8f311SMark Adams PetscMPIInt nranks = 0; 128e6f8f311SMark Adams int devID = 0; 129e6f8f311SMark Adams 130e6f8f311SMark Adams void *lib_handle = 0; 131e6f8f311SMark Adams std::string cfg_contents; 132e6f8f311SMark Adams 133e6f8f311SMark Adams // Cached state for re-setup 134e6f8f311SMark Adams PetscInt nnz; 135e6f8f311SMark Adams PetscInt nLocalRows; 136e6f8f311SMark Adams PetscInt nGlobalRows; 137e6f8f311SMark Adams PetscInt bSize; 138e6f8f311SMark Adams Mat localA; 139e6f8f311SMark Adams const PetscScalar *values; 140e6f8f311SMark Adams 141e6f8f311SMark Adams // AMG Control parameters 142e6f8f311SMark Adams AmgXSmoother smoother; 143e6f8f311SMark Adams AmgXAMGMethod amg_method; 144e6f8f311SMark Adams AmgXSelector selector; 145e6f8f311SMark Adams AmgXCoarseSolver coarse_solver; 146e6f8f311SMark Adams AmgXAMGCycle amg_cycle; 147e6f8f311SMark Adams PetscInt presweeps; 148e6f8f311SMark Adams PetscInt postsweeps; 149e6f8f311SMark Adams PetscInt max_levels; 150e6f8f311SMark Adams PetscInt aggressive_levels; 151e6f8f311SMark Adams PetscInt dense_lu_num_rows; 152e6f8f311SMark Adams PetscScalar strength_threshold; 153e6f8f311SMark Adams PetscBool print_grid_stats; 154e6f8f311SMark Adams PetscBool exact_coarse_solve; 155e6f8f311SMark Adams 156e6f8f311SMark Adams // Smoother control parameters 157e6f8f311SMark Adams PetscScalar jacobi_relaxation_factor; 158e6f8f311SMark Adams PetscScalar gs_symmetric; 159e6f8f311SMark Adams }; 160e6f8f311SMark Adams 161e6f8f311SMark Adams static PetscInt s_count = 0; 162e6f8f311SMark Adams 163e6f8f311SMark Adams // Buffer of messages from AmgX 164e6f8f311SMark Adams // Currently necessary hack before we adapt AmgX to print from single rank only 165e6f8f311SMark Adams static std::string amgx_output{}; 166e6f8f311SMark Adams 167e6f8f311SMark Adams // A print callback that allows AmgX to return status messages 1689371c9d4SSatish Balay static void print_callback(const char *msg, int length) { 169e6f8f311SMark Adams amgx_output.append(msg); 170e6f8f311SMark Adams } 171e6f8f311SMark Adams 172e6f8f311SMark Adams // Outputs messages from the AmgX message buffer and clears it 1739371c9d4SSatish Balay PetscErrorCode amgx_output_messages(PC_AMGX *amgx) { 174e6f8f311SMark Adams PetscFunctionBegin; 175e6f8f311SMark Adams 176e6f8f311SMark Adams // If AmgX output is enabled and we have a message, output it 177e6f8f311SMark Adams if (amgx->verbose && !amgx_output.empty()) { 178e6f8f311SMark Adams // Only a single rank to output the AmgX messages 179e6f8f311SMark Adams PetscCall(PetscPrintf(amgx->comm, "AMGX: %s", amgx_output.c_str())); 180e6f8f311SMark Adams 181e6f8f311SMark Adams // Note that all ranks clear their received output 182e6f8f311SMark Adams amgx_output.clear(); 183e6f8f311SMark Adams } 184e6f8f311SMark Adams 185e6f8f311SMark Adams PetscFunctionReturn(0); 186e6f8f311SMark Adams } 187e6f8f311SMark Adams 188e6f8f311SMark Adams // XXX Need to add call in AmgX API that gracefully destroys everything 189e6f8f311SMark Adams // without abort etc. 1909371c9d4SSatish Balay #define PetscCallAmgX(rc) \ 1919371c9d4SSatish Balay do { \ 192e6f8f311SMark Adams AMGX_RC err = (rc); \ 193e6f8f311SMark Adams char msg[4096]; \ 194e6f8f311SMark Adams switch (err) { \ 1959371c9d4SSatish Balay case AMGX_RC_OK: break; \ 1969371c9d4SSatish Balay default: AMGX_get_error_string(err, msg, 4096); SETERRQ(amgx->comm, PETSC_ERR_LIB, "%s", msg); \ 197e6f8f311SMark Adams } \ 198e6f8f311SMark Adams } while (0) 199e6f8f311SMark Adams 200e6f8f311SMark Adams /* 201e6f8f311SMark Adams PCSetUp_AMGX - Prepares for the use of the AmgX preconditioner 202e6f8f311SMark Adams by setting data structures and options. 203e6f8f311SMark Adams 204e6f8f311SMark Adams Input Parameter: 205e6f8f311SMark Adams . pc - the preconditioner context 206e6f8f311SMark Adams 207e6f8f311SMark Adams Application Interface Routine: PCSetUp() 208e6f8f311SMark Adams 209*f1580f4eSBarry Smith Note: 210e6f8f311SMark Adams The interface routine PCSetUp() is not usually called directly by 211e6f8f311SMark Adams the user, but instead is called by PCApply() if necessary. 212e6f8f311SMark Adams */ 2139371c9d4SSatish Balay static PetscErrorCode PCSetUp_AMGX(PC pc) { 214e6f8f311SMark Adams PC_AMGX *amgx = (PC_AMGX *)pc->data; 215e6f8f311SMark Adams Mat Pmat = pc->pmat; 216e6f8f311SMark Adams PetscBool is_dev_ptrs; 217e6f8f311SMark Adams 218e6f8f311SMark Adams PetscFunctionBegin; 219e6f8f311SMark Adams PetscCall(PetscObjectTypeCompareAny((PetscObject)Pmat, &is_dev_ptrs, MATAIJCUSPARSE, MATSEQAIJCUSPARSE, MATMPIAIJCUSPARSE, "")); 220e6f8f311SMark Adams 221e6f8f311SMark Adams // At the present time, an AmgX matrix is a sequential matrix 222e6f8f311SMark Adams // Non-sequential/MPI matrices must be adapted to extract the local matrix 223e6f8f311SMark Adams bool partial_setup_allowed = (pc->setupcalled && pc->flag != DIFFERENT_NONZERO_PATTERN); 224e6f8f311SMark Adams if (amgx->nranks > 1) { 225e6f8f311SMark Adams if (partial_setup_allowed) { 226e6f8f311SMark Adams PetscCall(MatMPIAIJGetLocalMat(Pmat, MAT_REUSE_MATRIX, &amgx->localA)); 227e6f8f311SMark Adams } else { 228e6f8f311SMark Adams PetscCall(MatMPIAIJGetLocalMat(Pmat, MAT_INITIAL_MATRIX, &amgx->localA)); 229e6f8f311SMark Adams } 230e6f8f311SMark Adams 23148a46eb9SPierre Jolivet if (is_dev_ptrs) PetscCall(MatConvert(amgx->localA, MATSEQAIJCUSPARSE, MAT_INPLACE_MATRIX, &amgx->localA)); 232e6f8f311SMark Adams } else { 233e6f8f311SMark Adams amgx->localA = Pmat; 234e6f8f311SMark Adams } 235e6f8f311SMark Adams 236e6f8f311SMark Adams if (is_dev_ptrs) { 237e6f8f311SMark Adams PetscCall(MatSeqAIJCUSPARSEGetArrayRead(amgx->localA, &amgx->values)); 238e6f8f311SMark Adams } else { 239e6f8f311SMark Adams PetscCall(MatSeqAIJGetArrayRead(amgx->localA, &amgx->values)); 240e6f8f311SMark Adams } 241e6f8f311SMark Adams 242e6f8f311SMark Adams if (!partial_setup_allowed) { 243e6f8f311SMark Adams // Initialise resources and matrices 244e6f8f311SMark Adams if (!amgx->rsrc_init) { 245e6f8f311SMark Adams // Read configuration file 246e6f8f311SMark Adams PetscCallAmgX(AMGX_config_create(&amgx->cfg, amgx->cfg_contents.c_str())); 247e6f8f311SMark Adams PetscCallAmgX(AMGX_resources_create(&amgx->rsrc, amgx->cfg, &amgx->comm, 1, &amgx->devID)); 248e6f8f311SMark Adams amgx->rsrc_init = true; 249e6f8f311SMark Adams } 250e6f8f311SMark Adams 251e6f8f311SMark Adams PetscCheck(!amgx->solve_state_init, amgx->comm, PETSC_ERR_PLIB, "AmgX solve state initialisation already called."); 252e6f8f311SMark Adams PetscCallAmgX(AMGX_matrix_create(&amgx->A, amgx->rsrc, AMGX_mode_dDDI)); 253e6f8f311SMark Adams PetscCallAmgX(AMGX_vector_create(&amgx->sol, amgx->rsrc, AMGX_mode_dDDI)); 254e6f8f311SMark Adams PetscCallAmgX(AMGX_vector_create(&amgx->rhs, amgx->rsrc, AMGX_mode_dDDI)); 255e6f8f311SMark Adams PetscCallAmgX(AMGX_solver_create(&amgx->solver, amgx->rsrc, AMGX_mode_dDDI, amgx->cfg)); 256e6f8f311SMark Adams amgx->solve_state_init = true; 257e6f8f311SMark Adams 258e6f8f311SMark Adams // Extract the CSR data 259e6f8f311SMark Adams PetscBool done; 260e6f8f311SMark Adams const PetscInt *colIndices; 261e6f8f311SMark Adams const PetscInt *rowOffsets; 262e6f8f311SMark Adams PetscCall(MatGetRowIJ(amgx->localA, 0, PETSC_FALSE, PETSC_FALSE, &amgx->nLocalRows, &rowOffsets, &colIndices, &done)); 263e6f8f311SMark Adams PetscCheck(done, amgx->comm, PETSC_ERR_PLIB, "MatGetRowIJ was not successful"); 264e6f8f311SMark Adams PetscCheck(amgx->nLocalRows < std::numeric_limits<int>::max(), PETSC_COMM_SELF, PETSC_ERR_PLIB, "AmgX restricted to int local rows but nLocalRows = %" PetscInt_FMT " > max<int>", amgx->nLocalRows); 265e6f8f311SMark Adams 266e6f8f311SMark Adams if (is_dev_ptrs) { 267e6f8f311SMark Adams PetscCallCUDA(cudaMemcpy(&amgx->nnz, &rowOffsets[amgx->nLocalRows], sizeof(int), cudaMemcpyDefault)); 268e6f8f311SMark Adams } else { 269e6f8f311SMark Adams amgx->nnz = rowOffsets[amgx->nLocalRows]; 270e6f8f311SMark Adams } 271e6f8f311SMark Adams 272e6f8f311SMark Adams PetscCheck(amgx->nnz < std::numeric_limits<int>::max(), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Support for 64-bit integer nnz not yet implemented, nnz = %" PetscInt_FMT ".", amgx->nnz); 273e6f8f311SMark Adams 274e6f8f311SMark Adams // Allocate space for some partition offsets 275e6f8f311SMark Adams std::vector<PetscInt> partitionOffsets(amgx->nranks + 1); 276e6f8f311SMark Adams 277e6f8f311SMark Adams // Fetch the number of local rows per rank 278e6f8f311SMark Adams partitionOffsets[0] = 0; /* could use PetscLayoutGetRanges */ 279e6f8f311SMark Adams PetscCallMPI(MPI_Allgather(&amgx->nLocalRows, 1, MPIU_INT, partitionOffsets.data() + 1, 1, MPIU_INT, amgx->comm)); 280e6f8f311SMark Adams std::partial_sum(partitionOffsets.begin(), partitionOffsets.end(), partitionOffsets.begin()); 281e6f8f311SMark Adams 282e6f8f311SMark Adams // Fetch the number of global rows 283e6f8f311SMark Adams amgx->nGlobalRows = partitionOffsets[amgx->nranks]; 284e6f8f311SMark Adams 285e6f8f311SMark Adams PetscCall(MatGetBlockSize(Pmat, &amgx->bSize)); 286e6f8f311SMark Adams 287e6f8f311SMark Adams // XXX Currently constrained to 32-bit indices, to be changed in the future 288e6f8f311SMark Adams // Create the distribution and upload the matrix data 289e6f8f311SMark Adams AMGX_distribution_handle dist; 290e6f8f311SMark Adams PetscCallAmgX(AMGX_distribution_create(&dist, amgx->cfg)); 291e6f8f311SMark Adams PetscCallAmgX(AMGX_distribution_set_32bit_colindices(dist, true)); 292e6f8f311SMark Adams PetscCallAmgX(AMGX_distribution_set_partition_data(dist, AMGX_DIST_PARTITION_OFFSETS, partitionOffsets.data())); 293e6f8f311SMark Adams PetscCallAmgX(AMGX_matrix_upload_distributed(amgx->A, amgx->nGlobalRows, (int)amgx->nLocalRows, (int)amgx->nnz, amgx->bSize, amgx->bSize, rowOffsets, colIndices, amgx->values, NULL, dist)); 294e6f8f311SMark Adams PetscCallAmgX(AMGX_solver_setup(amgx->solver, amgx->A)); 295e6f8f311SMark Adams PetscCallAmgX(AMGX_vector_bind(amgx->sol, amgx->A)); 296e6f8f311SMark Adams PetscCallAmgX(AMGX_vector_bind(amgx->rhs, amgx->A)); 297e6f8f311SMark Adams 298e6f8f311SMark Adams PetscInt nlr = 0; 299e6f8f311SMark Adams PetscCall(MatRestoreRowIJ(amgx->localA, 0, PETSC_FALSE, PETSC_FALSE, &nlr, &rowOffsets, &colIndices, &done)); 300e6f8f311SMark Adams } else { 301e6f8f311SMark Adams // The fast path for if the sparsity pattern persists 302e6f8f311SMark Adams PetscCallAmgX(AMGX_matrix_replace_coefficients(amgx->A, amgx->nLocalRows, amgx->nnz, amgx->values, NULL)); 303e6f8f311SMark Adams PetscCallAmgX(AMGX_solver_resetup(amgx->solver, amgx->A)); 304e6f8f311SMark Adams } 305e6f8f311SMark Adams 306e6f8f311SMark Adams if (is_dev_ptrs) { 307e6f8f311SMark Adams PetscCall(MatSeqAIJCUSPARSERestoreArrayRead(amgx->localA, &amgx->values)); 308e6f8f311SMark Adams } else { 309e6f8f311SMark Adams PetscCall(MatSeqAIJRestoreArrayRead(amgx->localA, &amgx->values)); 310e6f8f311SMark Adams } 311e6f8f311SMark Adams amgx_output_messages(amgx); 312e6f8f311SMark Adams PetscFunctionReturn(0); 313e6f8f311SMark Adams } 314e6f8f311SMark Adams 315e6f8f311SMark Adams /* 316e6f8f311SMark Adams PCApply_AMGX - Applies the AmgX preconditioner to a vector. 317e6f8f311SMark Adams 318e6f8f311SMark Adams Input Parameters: 319e6f8f311SMark Adams . pc - the preconditioner context 320e6f8f311SMark Adams . b - rhs vector 321e6f8f311SMark Adams 322e6f8f311SMark Adams Output Parameter: 323e6f8f311SMark Adams . x - solution vector 324e6f8f311SMark Adams 325e6f8f311SMark Adams Application Interface Routine: PCApply() 326e6f8f311SMark Adams */ 3279371c9d4SSatish Balay static PetscErrorCode PCApply_AMGX(PC pc, Vec b, Vec x) { 328e6f8f311SMark Adams PC_AMGX *amgx = (PC_AMGX *)pc->data; 329e6f8f311SMark Adams PetscScalar *x_; 330e6f8f311SMark Adams const PetscScalar *b_; 331e6f8f311SMark Adams PetscBool is_dev_ptrs; 332e6f8f311SMark Adams 333e6f8f311SMark Adams PetscFunctionBegin; 334e6f8f311SMark Adams PetscCall(PetscObjectTypeCompareAny((PetscObject)x, &is_dev_ptrs, VECCUDA, VECMPICUDA, VECSEQCUDA, "")); 335e6f8f311SMark Adams 336e6f8f311SMark Adams if (is_dev_ptrs) { 337e6f8f311SMark Adams PetscCall(VecCUDAGetArrayWrite(x, &x_)); 338e6f8f311SMark Adams PetscCall(VecCUDAGetArrayRead(b, &b_)); 339e6f8f311SMark Adams } else { 340e6f8f311SMark Adams PetscCall(VecGetArrayWrite(x, &x_)); 341e6f8f311SMark Adams PetscCall(VecGetArrayRead(b, &b_)); 342e6f8f311SMark Adams } 343e6f8f311SMark Adams 344e6f8f311SMark Adams PetscCallAmgX(AMGX_vector_upload(amgx->sol, amgx->nLocalRows, 1, x_)); 345e6f8f311SMark Adams PetscCallAmgX(AMGX_vector_upload(amgx->rhs, amgx->nLocalRows, 1, b_)); 346e6f8f311SMark Adams PetscCallAmgX(AMGX_solver_solve_with_0_initial_guess(amgx->solver, amgx->rhs, amgx->sol)); 347e6f8f311SMark Adams 348e6f8f311SMark Adams AMGX_SOLVE_STATUS status; 349e6f8f311SMark Adams PetscCallAmgX(AMGX_solver_get_status(amgx->solver, &status)); 350e6f8f311SMark Adams PetscCall(PCSetErrorIfFailure(pc, static_cast<PetscBool>(status == AMGX_SOLVE_FAILED))); 351e6f8f311SMark Adams PetscCheck(status != AMGX_SOLVE_FAILED, amgx->comm, PETSC_ERR_CONV_FAILED, "AmgX solver failed to solve the system! The error code is %d.", status); 352e6f8f311SMark Adams PetscCallAmgX(AMGX_vector_download(amgx->sol, x_)); 353e6f8f311SMark Adams 354e6f8f311SMark Adams if (is_dev_ptrs) { 355e6f8f311SMark Adams PetscCall(VecCUDARestoreArrayWrite(x, &x_)); 356e6f8f311SMark Adams PetscCall(VecCUDARestoreArrayRead(b, &b_)); 357e6f8f311SMark Adams } else { 358e6f8f311SMark Adams PetscCall(VecRestoreArrayWrite(x, &x_)); 359e6f8f311SMark Adams PetscCall(VecRestoreArrayRead(b, &b_)); 360e6f8f311SMark Adams } 361e6f8f311SMark Adams amgx_output_messages(amgx); 362e6f8f311SMark Adams PetscFunctionReturn(0); 363e6f8f311SMark Adams } 364e6f8f311SMark Adams 3659371c9d4SSatish Balay static PetscErrorCode PCReset_AMGX(PC pc) { 366e6f8f311SMark Adams PC_AMGX *amgx = (PC_AMGX *)pc->data; 367e6f8f311SMark Adams 368e6f8f311SMark Adams PetscFunctionBegin; 369e6f8f311SMark Adams if (amgx->solve_state_init) { 370e6f8f311SMark Adams PetscCallAmgX(AMGX_solver_destroy(amgx->solver)); 371e6f8f311SMark Adams PetscCallAmgX(AMGX_matrix_destroy(amgx->A)); 372e6f8f311SMark Adams PetscCallAmgX(AMGX_vector_destroy(amgx->sol)); 373e6f8f311SMark Adams PetscCallAmgX(AMGX_vector_destroy(amgx->rhs)); 374e6f8f311SMark Adams if (amgx->nranks > 1) PetscCall(MatDestroy(&amgx->localA)); 375e6f8f311SMark Adams amgx_output_messages(amgx); 376e6f8f311SMark Adams amgx->solve_state_init = false; 377e6f8f311SMark Adams } 378e6f8f311SMark Adams PetscFunctionReturn(0); 379e6f8f311SMark Adams } 380e6f8f311SMark Adams 381e6f8f311SMark Adams /* 382e6f8f311SMark Adams PCDestroy_AMGX - Destroys the private context for the AmgX preconditioner 383e6f8f311SMark Adams that was created with PCCreate_AMGX(). 384e6f8f311SMark Adams 385e6f8f311SMark Adams Input Parameter: 386e6f8f311SMark Adams . pc - the preconditioner context 387e6f8f311SMark Adams 388e6f8f311SMark Adams Application Interface Routine: PCDestroy() 389e6f8f311SMark Adams */ 3909371c9d4SSatish Balay static PetscErrorCode PCDestroy_AMGX(PC pc) { 391e6f8f311SMark Adams PC_AMGX *amgx = (PC_AMGX *)pc->data; 392e6f8f311SMark Adams 393e6f8f311SMark Adams PetscFunctionBegin; 394e6f8f311SMark Adams /* decrease the number of instances, only the last instance need to destroy resource and finalizing AmgX */ 395e6f8f311SMark Adams if (s_count == 1) { 396e6f8f311SMark Adams /* can put this in a PCAMGXInitializePackage method */ 397e6f8f311SMark Adams PetscCheck(amgx->rsrc != nullptr, PETSC_COMM_SELF, PETSC_ERR_PLIB, "s_rsrc == NULL"); 398e6f8f311SMark Adams PetscCallAmgX(AMGX_resources_destroy(amgx->rsrc)); 399e6f8f311SMark Adams /* destroy config (need to use AMGX_SAFE_CALL after this point) */ 400e6f8f311SMark Adams PetscCallAmgX(AMGX_config_destroy(amgx->cfg)); 401e6f8f311SMark Adams PetscCallAmgX(AMGX_finalize_plugins()); 402e6f8f311SMark Adams PetscCallAmgX(AMGX_finalize()); 403e6f8f311SMark Adams PetscCallMPI(MPI_Comm_free(&amgx->comm)); 404e6f8f311SMark Adams } else { 405e6f8f311SMark Adams PetscCallAmgX(AMGX_config_destroy(amgx->cfg)); 406e6f8f311SMark Adams } 407e6f8f311SMark Adams s_count -= 1; 408e6f8f311SMark Adams PetscCall(PetscFree(amgx)); 409e6f8f311SMark Adams PetscFunctionReturn(0); 410e6f8f311SMark Adams } 411e6f8f311SMark Adams 412e6f8f311SMark Adams template <class T> 4139371c9d4SSatish Balay std::string map_reverse_lookup(const std::map<std::string, T> &map, const T &key) { 414e6f8f311SMark Adams for (auto const &m : map) { 415ad540459SPierre Jolivet if (m.second == key) return m.first; 416e6f8f311SMark Adams } 417e6f8f311SMark Adams return ""; 418e6f8f311SMark Adams } 419e6f8f311SMark Adams 420a22370e2Smarkadams4 static PetscErrorCode PCSetFromOptions_AMGX(PC pc, PetscOptionItems *PetscOptionsObject) { 421e6f8f311SMark Adams PC_AMGX *amgx = (PC_AMGX *)pc->data; 422e6f8f311SMark Adams constexpr int MAX_PARAM_LEN = 128; 423e6f8f311SMark Adams char option[MAX_PARAM_LEN]; 424e6f8f311SMark Adams 425e6f8f311SMark Adams PetscFunctionBegin; 426e6f8f311SMark Adams PetscOptionsHeadBegin(PetscOptionsObject, "AmgX options"); 427e6f8f311SMark Adams amgx->cfg_contents = "config_version=2,"; 428e6f8f311SMark Adams amgx->cfg_contents += "determinism_flag=1,"; 429e6f8f311SMark Adams 430e6f8f311SMark Adams // Set exact coarse solve 431e6f8f311SMark Adams PetscCall(PetscOptionsBool("-pc_amgx_exact_coarse_solve", "AmgX AMG Exact Coarse Solve", "", amgx->exact_coarse_solve, &amgx->exact_coarse_solve, NULL)); 432ad540459SPierre Jolivet if (amgx->exact_coarse_solve) amgx->cfg_contents += "exact_coarse_solve=1,"; 433e6f8f311SMark Adams 434e6f8f311SMark Adams amgx->cfg_contents += "solver(amg)=AMG,"; 435e6f8f311SMark Adams 436e6f8f311SMark Adams // Set method 437e6f8f311SMark Adams std::string def_amg_method = map_reverse_lookup(AmgXControlMap::AMGMethods, amgx->amg_method); 438e6f8f311SMark Adams PetscCall(PetscStrcpy(option, def_amg_method.c_str())); 439e6f8f311SMark Adams PetscCall(PetscOptionsString("-pc_amgx_amg_method", "AmgX AMG Method", "", option, option, MAX_PARAM_LEN, NULL)); 440e6f8f311SMark Adams PetscCheck(AmgXControlMap::AMGMethods.count(option) == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "AMG Method %s not registered for AmgX.", option); 441e6f8f311SMark Adams amgx->amg_method = AmgXControlMap::AMGMethods.at(option); 442e6f8f311SMark Adams amgx->cfg_contents += "amg:algorithm=" + std::string(option) + ","; 443e6f8f311SMark Adams 444e6f8f311SMark Adams // Set cycle 445e6f8f311SMark Adams std::string def_amg_cycle = map_reverse_lookup(AmgXControlMap::AMGCycles, amgx->amg_cycle); 446e6f8f311SMark Adams PetscCall(PetscStrcpy(option, def_amg_cycle.c_str())); 447e6f8f311SMark Adams PetscCall(PetscOptionsString("-pc_amgx_amg_cycle", "AmgX AMG Cycle", "", option, option, MAX_PARAM_LEN, NULL)); 448e6f8f311SMark Adams PetscCheck(AmgXControlMap::AMGCycles.count(option) == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "AMG Cycle %s not registered for AmgX.", option); 449e6f8f311SMark Adams amgx->amg_cycle = AmgXControlMap::AMGCycles.at(option); 450e6f8f311SMark Adams amgx->cfg_contents += "amg:cycle=" + std::string(option) + ","; 451e6f8f311SMark Adams 452e6f8f311SMark Adams // Set smoother 453e6f8f311SMark Adams std::string def_smoother = map_reverse_lookup(AmgXControlMap::Smoothers, amgx->smoother); 454e6f8f311SMark Adams PetscCall(PetscStrcpy(option, def_smoother.c_str())); 455e6f8f311SMark Adams PetscCall(PetscOptionsString("-pc_amgx_smoother", "AmgX Smoother", "", option, option, MAX_PARAM_LEN, NULL)); 456e6f8f311SMark Adams PetscCheck(AmgXControlMap::Smoothers.count(option) == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Smoother %s not registered for AmgX.", option); 457e6f8f311SMark Adams amgx->smoother = AmgXControlMap::Smoothers.at(option); 458e6f8f311SMark Adams amgx->cfg_contents += "amg:smoother(smooth)=" + std::string(option) + ","; 459e6f8f311SMark Adams 460e6f8f311SMark Adams if (amgx->smoother == AmgXSmoother::JacobiL1 || amgx->smoother == AmgXSmoother::BlockJacobi) { 461e6f8f311SMark Adams PetscCall(PetscOptionsScalar("-pc_amgx_jacobi_relaxation_factor", "AmgX AMG Jacobi Relaxation Factor", "", amgx->jacobi_relaxation_factor, &amgx->jacobi_relaxation_factor, NULL)); 462e6f8f311SMark Adams amgx->cfg_contents += "smooth:relaxation_factor=" + std::to_string(amgx->jacobi_relaxation_factor) + ","; 463e6f8f311SMark Adams } else if (amgx->smoother == AmgXSmoother::GS || amgx->smoother == AmgXSmoother::MulticolorGS) { 464e6f8f311SMark Adams PetscCall(PetscOptionsScalar("-pc_amgx_gs_symmetric", "AmgX AMG Gauss Seidel Symmetric", "", amgx->gs_symmetric, &amgx->gs_symmetric, NULL)); 465e6f8f311SMark Adams amgx->cfg_contents += "smooth:symmetric_GS=" + std::to_string(amgx->gs_symmetric) + ","; 466e6f8f311SMark Adams } 467e6f8f311SMark Adams 468e6f8f311SMark Adams // Set selector 469e6f8f311SMark Adams std::string def_selector = map_reverse_lookup(AmgXControlMap::Selectors, amgx->selector); 470e6f8f311SMark Adams PetscCall(PetscStrcpy(option, def_selector.c_str())); 471e6f8f311SMark Adams PetscCall(PetscOptionsString("-pc_amgx_selector", "AmgX Selector", "", option, option, MAX_PARAM_LEN, NULL)); 472e6f8f311SMark Adams PetscCheck(AmgXControlMap::Selectors.count(option) == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Selector %s not registered for AmgX.", option); 473e6f8f311SMark Adams 474e6f8f311SMark Adams // Double check that the user has selected an appropriate selector for the AMG method 475e6f8f311SMark Adams if (amgx->amg_method == AmgXAMGMethod::Classical) { 476e6f8f311SMark Adams PetscCheck(amgx->selector == AmgXSelector::PMIS || amgx->selector == AmgXSelector::HMIS, amgx->comm, PETSC_ERR_PLIB, "Chosen selector is not used for AmgX Classical AMG: selector=%s", option); 477e6f8f311SMark Adams amgx->cfg_contents += "amg:interpolator=D2,"; 478e6f8f311SMark Adams } else if (amgx->amg_method == AmgXAMGMethod::Aggregation) { 479e6f8f311SMark Adams PetscCheck(amgx->selector == AmgXSelector::Size2 || amgx->selector == AmgXSelector::Size4 || amgx->selector == AmgXSelector::Size8 || amgx->selector == AmgXSelector::MultiPairwise, amgx->comm, PETSC_ERR_PLIB, "Chosen selector is not used for AmgX Aggregation AMG"); 480e6f8f311SMark Adams } 481e6f8f311SMark Adams amgx->selector = AmgXControlMap::Selectors.at(option); 482e6f8f311SMark Adams amgx->cfg_contents += "amg:selector=" + std::string(option) + ","; 483e6f8f311SMark Adams 484e6f8f311SMark Adams // Set presweeps 485e6f8f311SMark Adams PetscCall(PetscOptionsInt("-pc_amgx_presweeps", "AmgX AMG Presweep Count", "", amgx->presweeps, &amgx->presweeps, NULL)); 486e6f8f311SMark Adams amgx->cfg_contents += "amg:presweeps=" + std::to_string(amgx->presweeps) + ","; 487e6f8f311SMark Adams 488e6f8f311SMark Adams // Set postsweeps 489e6f8f311SMark Adams PetscCall(PetscOptionsInt("-pc_amgx_postsweeps", "AmgX AMG Postsweep Count", "", amgx->postsweeps, &amgx->postsweeps, NULL)); 490e6f8f311SMark Adams amgx->cfg_contents += "amg:postsweeps=" + std::to_string(amgx->postsweeps) + ","; 491e6f8f311SMark Adams 492e6f8f311SMark Adams // Set max levels 493e6f8f311SMark Adams PetscCall(PetscOptionsInt("-pc_amgx_max_levels", "AmgX AMG Max Level Count", "", amgx->max_levels, &amgx->max_levels, NULL)); 494e6f8f311SMark Adams amgx->cfg_contents += "amg:max_levels=100,"; 495e6f8f311SMark Adams 496e6f8f311SMark Adams // Set dense LU num rows 497e6f8f311SMark Adams PetscCall(PetscOptionsInt("-pc_amgx_dense_lu_num_rows", "AmgX Dense LU Number of Rows", "", amgx->dense_lu_num_rows, &amgx->dense_lu_num_rows, NULL)); 498e6f8f311SMark Adams amgx->cfg_contents += "amg:dense_lu_num_rows=" + std::to_string(amgx->dense_lu_num_rows) + ","; 499e6f8f311SMark Adams 500e6f8f311SMark Adams // Set strength threshold 501e6f8f311SMark Adams PetscCall(PetscOptionsScalar("-pc_amgx_strength_threshold", "AmgX AMG Strength Threshold", "", amgx->strength_threshold, &amgx->strength_threshold, NULL)); 502e6f8f311SMark Adams amgx->cfg_contents += "amg:strength_threshold=" + std::to_string(amgx->strength_threshold) + ","; 503e6f8f311SMark Adams 504e6f8f311SMark Adams // Set aggressive_levels 505e6f8f311SMark Adams PetscCall(PetscOptionsInt("-pc_amgx_aggressive_levels", "AmgX AMG Presweep Count", "", amgx->aggressive_levels, &amgx->aggressive_levels, NULL)); 506ad540459SPierre Jolivet if (amgx->aggressive_levels > 0) amgx->cfg_contents += "amg:aggressive_levels=" + std::to_string(amgx->aggressive_levels) + ","; 507e6f8f311SMark Adams 508e6f8f311SMark Adams // Set coarse solver 509e6f8f311SMark Adams std::string def_coarse_solver = map_reverse_lookup(AmgXControlMap::CoarseSolvers, amgx->coarse_solver); 510e6f8f311SMark Adams PetscCall(PetscStrcpy(option, def_coarse_solver.c_str())); 511e6f8f311SMark Adams PetscCall(PetscOptionsString("-pc_amgx_coarse_solver", "AmgX CoarseSolver", "", option, option, MAX_PARAM_LEN, NULL)); 512e6f8f311SMark Adams PetscCheck(AmgXControlMap::CoarseSolvers.count(option) == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "CoarseSolver %s not registered for AmgX.", option); 513e6f8f311SMark Adams amgx->coarse_solver = AmgXControlMap::CoarseSolvers.at(option); 514e6f8f311SMark Adams amgx->cfg_contents += "amg:coarse_solver=" + std::string(option) + ","; 515e6f8f311SMark Adams 516e6f8f311SMark Adams // Set max iterations 517e6f8f311SMark Adams amgx->cfg_contents += "amg:max_iters=1,"; 518e6f8f311SMark Adams 519e6f8f311SMark Adams // Set output control parameters 520e6f8f311SMark Adams PetscCall(PetscOptionsBool("-pc_amgx_print_grid_stats", "AmgX Print Grid Stats", "", amgx->print_grid_stats, &amgx->print_grid_stats, NULL)); 521e6f8f311SMark Adams 522ad540459SPierre Jolivet if (amgx->print_grid_stats) amgx->cfg_contents += "amg:print_grid_stats=1,"; 523e6f8f311SMark Adams amgx->cfg_contents += "amg:monitor_residual=0"; 524e6f8f311SMark Adams 525e6f8f311SMark Adams // Set whether AmgX output will be seen 526e6f8f311SMark Adams PetscCall(PetscOptionsBool("-pc_amgx_verbose", "Enable output from AmgX", "", amgx->verbose, &amgx->verbose, NULL)); 527e6f8f311SMark Adams PetscOptionsHeadEnd(); 528e6f8f311SMark Adams PetscFunctionReturn(0); 529e6f8f311SMark Adams } 530e6f8f311SMark Adams 5319371c9d4SSatish Balay static PetscErrorCode PCView_AMGX(PC pc, PetscViewer viewer) { 532e6f8f311SMark Adams PC_AMGX *amgx = (PC_AMGX *)pc->data; 533e6f8f311SMark Adams PetscBool iascii; 534e6f8f311SMark Adams 535e6f8f311SMark Adams PetscFunctionBegin; 536e6f8f311SMark Adams PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 537e6f8f311SMark Adams if (iascii) { 538e6f8f311SMark Adams std::string output_cfg(amgx->cfg_contents); 539e6f8f311SMark Adams std::replace(output_cfg.begin(), output_cfg.end(), ',', '\n'); 540e6f8f311SMark Adams PetscCall(PetscViewerASCIIPrintf(viewer, "\n%s\n", output_cfg.c_str())); 541e6f8f311SMark Adams } 542e6f8f311SMark Adams PetscFunctionReturn(0); 543e6f8f311SMark Adams } 544e6f8f311SMark Adams 545e6f8f311SMark Adams /*MC 546e6f8f311SMark Adams PCAMGX - Interface to NVIDIA's AmgX algebraic multigrid 547e6f8f311SMark Adams 548e6f8f311SMark Adams Options Database Keys: 549e6f8f311SMark Adams + -pc_amgx_amg_method <CLASSICAL,AGGREGATION> - set the AMG algorithm to use 550e6f8f311SMark Adams . -pc_amgx_amg_cycle <V,W,F,CG> - set the AMG cycle type 551e6f8f311SMark Adams . -pc_amgx_smoother <PCG,PCGF,PBICGSTAB,GMRES,FGMRES,JACOBI_L1,BLOCK_JACOBI,GS,MULTICOLOR_GS,MULTICOLOR_ILU,MULTICOLOR_DILU,CHEBYSHEV_POLY,NOSOLVER> - set the AMG pre/post smoother 552e6f8f311SMark Adams . -pc_amgx_jacobi_relaxation_factor - set the relaxation factor for Jacobi smoothing 553e6f8f311SMark Adams . -pc_amgx_gs_symmetric - enforce symmetric Gauss-Seidel smoothing (only applies if GS smoothing is selected) 554e6f8f311SMark Adams . -pc_amgx_selector <SIZE_2,SIZE_4,SIZE_8,MULTI_PAIRWISE,PMIS,HMIS> - set the AMG coarse selector 555e6f8f311SMark Adams . -pc_amgx_presweeps - set the number of AMG pre-sweeps 556e6f8f311SMark Adams . -pc_amgx_postsweeps - set the number of AMG post-sweeps 557e6f8f311SMark Adams . -pc_amgx_max_levels - set the maximum number of levels in the AMG level hierarchy 558e6f8f311SMark Adams . -pc_amgx_strength_threshold - set the strength threshold for the AMG coarsening 559e6f8f311SMark Adams . -pc_amgx_aggressive_levels - set the number of levels (from the finest) that should apply aggressive coarsening 560e6f8f311SMark Adams . -pc_amgx_coarse_solver <DENSE_LU_SOLVER,NOSOLVER> - set the coarse solve 561e6f8f311SMark Adams . -pc_amgx_print_grid_stats - output the AMG grid hierarchy to stdout 562e6f8f311SMark Adams - -pc_amgx_verbose - enable AmgX output 563e6f8f311SMark Adams 564e6f8f311SMark Adams Level: intermediate 565e6f8f311SMark Adams 566*f1580f4eSBarry Smith Note: 567*f1580f4eSBarry Smith Implementation will accept host or device pointers, but good performance will require that the `KSP` is also GPU accelerated so that data is not frequently transferred between host and device. 568e6f8f311SMark Adams 569e6f8f311SMark Adams .seealso: `PCGAMG`, `PCHYPRE`, `PCMG`, `PCAmgXGetResources()`, `PCCreate()`, `PCSetType()`, `PCType` (for list of available types), `PC` 570e6f8f311SMark Adams M*/ 571e6f8f311SMark Adams 5729371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PCCreate_AMGX(PC pc) { 573e6f8f311SMark Adams PC_AMGX *amgx; 574e6f8f311SMark Adams 575e6f8f311SMark Adams PetscFunctionBegin; 576e6f8f311SMark Adams PetscCall(PetscNewLog(pc, &amgx)); 577e6f8f311SMark Adams pc->ops->apply = PCApply_AMGX; 578e6f8f311SMark Adams pc->ops->setfromoptions = PCSetFromOptions_AMGX; 579e6f8f311SMark Adams pc->ops->setup = PCSetUp_AMGX; 580e6f8f311SMark Adams pc->ops->view = PCView_AMGX; 581e6f8f311SMark Adams pc->ops->destroy = PCDestroy_AMGX; 582e6f8f311SMark Adams pc->ops->reset = PCReset_AMGX; 583e6f8f311SMark Adams pc->data = (void *)amgx; 584e6f8f311SMark Adams 585e6f8f311SMark Adams // Set the defaults 586e6f8f311SMark Adams amgx->selector = AmgXSelector::PMIS; 587e6f8f311SMark Adams amgx->smoother = AmgXSmoother::BlockJacobi; 588e6f8f311SMark Adams amgx->amg_method = AmgXAMGMethod::Classical; 589e6f8f311SMark Adams amgx->coarse_solver = AmgXCoarseSolver::DenseLU; 590e6f8f311SMark Adams amgx->amg_cycle = AmgXAMGCycle::V; 591e6f8f311SMark Adams amgx->exact_coarse_solve = PETSC_TRUE; 592e6f8f311SMark Adams amgx->presweeps = 1; 593e6f8f311SMark Adams amgx->postsweeps = 1; 594e6f8f311SMark Adams amgx->max_levels = 100; 595e6f8f311SMark Adams amgx->strength_threshold = 0.5; 596e6f8f311SMark Adams amgx->aggressive_levels = 0; 597e6f8f311SMark Adams amgx->dense_lu_num_rows = 1; 598e6f8f311SMark Adams amgx->jacobi_relaxation_factor = 0.9; 599e6f8f311SMark Adams amgx->gs_symmetric = PETSC_FALSE; 600e6f8f311SMark Adams amgx->print_grid_stats = PETSC_FALSE; 601e6f8f311SMark Adams amgx->verbose = PETSC_FALSE; 602e6f8f311SMark Adams amgx->rsrc_init = false; 603e6f8f311SMark Adams amgx->solve_state_init = false; 604e6f8f311SMark Adams 605e6f8f311SMark Adams s_count++; 606e6f8f311SMark Adams 607e6f8f311SMark Adams PetscCallCUDA(cudaGetDevice(&amgx->devID)); 608e6f8f311SMark Adams if (s_count == 1) { 609e6f8f311SMark Adams PetscCallAmgX(AMGX_initialize()); 610e6f8f311SMark Adams PetscCallAmgX(AMGX_initialize_plugins()); 611e6f8f311SMark Adams PetscCallAmgX(AMGX_register_print_callback(&print_callback)); 612e6f8f311SMark Adams PetscCallAmgX(AMGX_install_signal_handler()); 613e6f8f311SMark Adams } 614e6f8f311SMark Adams /* This communicator is not yet known to this system, so we duplicate it and make an internal communicator */ 615e6f8f311SMark Adams PetscCallMPI(MPI_Comm_dup(PetscObjectComm((PetscObject)pc), &amgx->comm)); 616e6f8f311SMark Adams PetscCallMPI(MPI_Comm_size(amgx->comm, &amgx->nranks)); 617e6f8f311SMark Adams PetscCallMPI(MPI_Comm_rank(amgx->comm, &amgx->rank)); 618e6f8f311SMark Adams 619e6f8f311SMark Adams amgx_output_messages(amgx); 620e6f8f311SMark Adams PetscFunctionReturn(0); 621e6f8f311SMark Adams } 622e6f8f311SMark Adams 623a22370e2Smarkadams4 /*@C 624e6f8f311SMark Adams PCAmgXGetResources - get AMGx's internal resource object 625e6f8f311SMark Adams 626e6f8f311SMark Adams Not Collective 627e6f8f311SMark Adams 628*f1580f4eSBarry Smith Input Parameter: 629e6f8f311SMark Adams . pc - the PC 630e6f8f311SMark Adams 631e6f8f311SMark Adams Output Parameter: 632e6f8f311SMark Adams . rsrc_out - pointer to the AMGx resource object 633e6f8f311SMark Adams 634e6f8f311SMark Adams Level: advanced 635e6f8f311SMark Adams 636*f1580f4eSBarry Smith .seealso: `PCAMGX`, `PC`, `PCGAMG` 637e6f8f311SMark Adams @*/ 6389371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PCAmgXGetResources(PC pc, void *rsrc_out) { 639e6f8f311SMark Adams PC_AMGX *amgx = (PC_AMGX *)pc->data; 640e6f8f311SMark Adams 641e6f8f311SMark Adams PetscFunctionBegin; 642e6f8f311SMark Adams if (!amgx->rsrc_init) { 643e6f8f311SMark Adams // Read configuration file 644e6f8f311SMark Adams PetscCallAmgX(AMGX_config_create(&amgx->cfg, amgx->cfg_contents.c_str())); 645e6f8f311SMark Adams PetscCallAmgX(AMGX_resources_create(&amgx->rsrc, amgx->cfg, &amgx->comm, 1, &amgx->devID)); 646e6f8f311SMark Adams amgx->rsrc_init = true; 647e6f8f311SMark Adams } 648e6f8f311SMark Adams *static_cast<AMGX_resources_handle *>(rsrc_out) = amgx->rsrc; 649e6f8f311SMark Adams PetscFunctionReturn(0); 650e6f8f311SMark Adams } 651