18#if CUDSS_VERSION >= 800
20#define CUDSS_REAL_T CUDSS_R_32F
22#define CUDSS_REAL_T CUDSS_R_64F
24#define CUDSS_INT_T CUDSS_R_32I
27#define CUDSS_REAL_T CUDA_R_32F
29#define CUDSS_REAL_T CUDA_R_64F
31#define CUDSS_INT_T CUDA_R_32I
37#define MFEM_CUDSS_CHECK(x) \
39 cudssStatus_t mfem_err_internal_var_name = (x); \
40 if (mfem_err_internal_var_name != CUDSS_STATUS_SUCCESS) { \
41 ::mfem::mfem_cudss_error(mfem_err_internal_var_name, #x, \
42 _MFEM_FUNC_NAME, __FILE__, __LINE__); \
50 const char *file,
int line)
52 mfem::err <<
"\n\nCUDSS error: (" << expr <<
") failed with error:\n --> "
53 <<
"CUDSS call ended unsuccessfully"
54 <<
" [code: " <<
static_cast<int>(status) <<
']'
55 <<
"\n ... in function: " << func <<
"\n ... in file: " << file
56 <<
':' << line <<
'\n';
69 const char* comm_lib =
GetEnv(
"CUDSS_COMM_LIB");
70#ifdef MFEM_CUDSS_COMM_LIB
71 if (comm_lib ==
nullptr)
73 comm_lib = MFEM_CUDSS_COMM_LIB;
76 MFEM_CUDSS_CHECK(cudssSetCommLayer(handle, comm_lib));
78#if CUDSS_VERSION >= 800
79 MFEM_CUDSS_CHECK(cudssDataSet(handle, solverData, CUDSS_DATA_COMM_HOST,
80 &mpi_comm,
sizeof(MPI_Comm *)));
82 MFEM_CUDSS_CHECK(cudssDataSet(handle, solverData, CUDSS_DATA_COMM,
83 &mpi_comm,
sizeof(MPI_Comm *)));
96 MFEM_CUDSS_CHECK(cudssMatrixDestroy(*Ac));
97 MFEM_CUDSS_CHECK(cudssMatrixDestroy(xc));
98 MFEM_CUDSS_CHECK(cudssMatrixDestroy(yc));
102 MFEM_CUDSS_CHECK(cudssDataDestroy(handle, solverData));
103 MFEM_CUDSS_CHECK(cudssConfigDestroy(solverConfig));
105 MFEM_CUDSS_CHECK(cudssDestroy(handle));
109 if (csr_offsets_d != NULL)
114 if (csr_columns_d != NULL)
119 if (csr_values_d != NULL)
125void CuDSSSolver::InitCuDSS()
128 MFEM_CUDSS_CHECK(cudssCreate(&handle));
131 MFEM_CUDSS_CHECK(cudssSetStream(handle, 0));
133#ifdef MFEM_USE_OPENMP
136 const char* threading_lib =
GetEnv(
"CUDSS_THREADING_LIB");
137#ifdef MFEM_CUDSS_THREADING_LIB
138 if (threading_lib ==
nullptr)
140 threading_lib = MFEM_CUDSS_THREADING_LIB;
143 MFEM_CUDSS_CHECK(cudssSetThreadingLayer(handle, threading_lib));
147 MFEM_CUDSS_CHECK(cudssConfigCreate(&solverConfig));
148 MFEM_CUDSS_CHECK(cudssDataCreate(handle, &solverData));
156 mat_type = CUDSS_MTYPE_SYMMETRIC;
159 mat_type = CUDSS_MTYPE_SPD;
162 mat_type = CUDSS_MTYPE_GENERAL;
170 if (mat_type == CUDSS_MTYPE_GENERAL)
172 mview = CUDSS_MVIEW_FULL;
180 mview = CUDSS_MVIEW_LOWER;
183 mview = CUDSS_MVIEW_UPPER;
186 mview = CUDSS_MVIEW_FULL;
193 MFEM_VERIFY(Ac ==
nullptr,
194 "Set reordering reuse before setting the operator!");
195 reorder_reuse = reuse;
201 bool cuDSSObjectInitialized = (Ac !=
nullptr);
203 hypre_ParCSRMatrix *parcsr_op = op;
205 hypre_CSRMatrix *csr_op = hypre_MergeDiagAndOffd(parcsr_op);
207#if MFEM_HYPRE_VERSION >= 21600
208 hypre_CSRMatrixBigJtoJ(csr_op);
213 n_global = internal::to_int(parcsr_op->global_num_rows);
214 row_start = parcsr_op->first_row_index;
215 row_end = row_start + n_loc - 1;
216 MFEM_VERIFY(!cuDSSObjectInitialized || !reorder_reuse ||
217 (reorder_reuse && (nnz == csr_op->num_nonzeros)),
218 "Inconsistent new matrix pattern!");
219 nnz = csr_op->num_nonzeros;
221 SetMatrixCuDSS(csr_op->i, csr_op->j, csr_op->data);
222 hypre_CSRMatrixDestroy(csr_op);
226void CuDSSSolver::SetMatrix(
const SparseMatrix &op)
228 bool cuDSSObjectInitialized = (Ac !=
nullptr);
231 MFEM_VERIFY(!cuDSSObjectInitialized || !reorder_reuse ||
232 (reorder_reuse && (nnz == op.NumNonZeroElems())),
233 "Inconsistent new matrix pattern!");
235 SparseMatrix *A =
const_cast<SparseMatrix *
>(&op);
237 nnz = A->NumNonZeroElems();
241 int *csr_offsets =
const_cast<int *
>(A->ReadI());
242 int *csr_columns =
const_cast<int *
>(A->ReadJ());
243 real_t *csr_values =
const_cast<real_t *
>(A->ReadData());
245 SetMatrixCuDSS(csr_offsets, csr_columns, csr_values);
248void CuDSSSolver::SetMatrixCuDSS(
int *csr_offsets,
int *csr_columns,
251 bool cuDSSObjectInitialized = (Ac !=
nullptr);
253 if (!cuDSSObjectInitialized)
256 Ac = std::make_unique<cudssMatrix_t>();
261 if (cuDSSObjectInitialized && !reorder_reuse)
264 MFEM_CUDSS_CHECK(cudssMatrixDestroy(*Ac));
269 if (csr_values_d == NULL || !reorder_reuse)
271 if (csr_values_d != NULL) {
CuMemFree(csr_values_d); }
279 if (!cuDSSObjectInitialized || !reorder_reuse)
281 if (csr_offsets_d != NULL) {
CuMemFree(csr_offsets_d); }
282 CuMemAlloc(&csr_offsets_d, (n_loc + 1) *
sizeof(
int));
283 if (csr_columns_d != NULL) {
CuMemFree(csr_columns_d); }
284 CuMemAlloc(&csr_columns_d, nnz *
sizeof(
int));
285 CuMemcpyDtoD(csr_offsets_d, csr_offsets, (n_loc + 1) *
sizeof(
int));
286 CuMemcpyDtoD(csr_columns_d, csr_columns, nnz *
sizeof(
int));
291 if (!cuDSSObjectInitialized || !reorder_reuse)
295#if CUDSS_VERSION >= 800
297 cudssMatrixCreateCsr(
298 Ac.get(), n_global, n_global, nnz, csr_offsets_d, NULL,
299 csr_columns_d, csr_values_d, CUDSS_INT_T, CUDSS_INT_T, CUDSS_REAL_T,
300 mat_type, mview, CUDSS_BASE_ZERO));
303 cudssMatrixCreateCsr(
304 Ac.get(), n_global, n_global, nnz, csr_offsets_d, NULL,
305 csr_columns_d, csr_values_d, CUDSS_INT_T, CUDSS_REAL_T,
306 mat_type, mview, CUDSS_BASE_ZERO));
311#if CUDSS_VERSION >= 800
313 cudssMatrixCreateCsr(
314 Ac.get(), n_global, n_global, nnz, csr_offsets_d, NULL,
315 csr_columns_d, csr_values_d, CUDSS_INT_T, CUDSS_INT_T, CUDSS_REAL_T,
316 mat_type, mview, CUDSS_BASE_ZERO));
319 cudssMatrixCreateCsr(
320 Ac.get(), n_global, n_global, nnz, csr_offsets_d, NULL,
321 csr_columns_d, csr_values_d, CUDSS_INT_T, CUDSS_REAL_T,
322 mat_type, mview, CUDSS_BASE_ZERO));
328 MFEM_CUDSS_CHECK(cudssMatrixSetDistributionRow1d(*Ac, row_start, row_end));
332 MFEM_CUDSS_CHECK(cudssExecute(handle, CUDSS_PHASE_ANALYSIS, solverConfig,
333 solverData, *Ac, yc, xc));
339 MFEM_CUDSS_CHECK(cudssMatrixSetValues(*Ac, csr_values_d));
343 MFEM_CUDSS_CHECK(cudssExecute(handle, CUDSS_PHASE_FACTORIZATION, solverConfig,
344 solverData, *Ac, yc, xc));
352 bool cuDSSObjectInitialized = (Ac !=
nullptr);
355 "Inconsistent new matrix size!");
371 MFEM_ABORT(
"Unsupported Operator Type \n");
375void CuDSSSolver::SetNumRHS(
int nrhs_)
const
383 MFEM_CUDSS_CHECK(cudssMatrixDestroy(xc));
384 MFEM_CUDSS_CHECK(cudssMatrixDestroy(yc));
387 MFEM_CUDSS_CHECK(cudssMatrixCreateDn(&xc, n_global, nrhs_, n_global, NULL,
388 CUDSS_REAL_T, CUDSS_LAYOUT_COL_MAJOR));
390 MFEM_CUDSS_CHECK(cudssMatrixCreateDn(&yc, n_global, nrhs_, n_global, NULL,
391 CUDSS_REAL_T, CUDSS_LAYOUT_COL_MAJOR));
394 MFEM_CUDSS_CHECK(cudssMatrixSetDistributionRow1d(xc, row_start, row_end));
395 MFEM_CUDSS_CHECK(cudssMatrixSetDistributionRow1d(yc, row_start, row_end));
420 SOL.
MakeRef(*Y[0], 0, Y[0]->Size());
425 RHS.
SetSize(nrhs * n_global, *X[0]);
426 for (
int i = 0; i < nrhs; i++)
428 Vector s(RHS, i * n_global, n_loc);
433 SOL.
SetSize(nrhs * n_global, *Y[0]);
436 MFEM_CUDSS_CHECK(cudssMatrixSetValues(xc,
const_cast<real_t *
>(RHS.
Read())));
437 MFEM_CUDSS_CHECK(cudssMatrixSetValues(yc, SOL.
Write()));
440 MFEM_CUDSS_CHECK(cudssExecute(handle, CUDSS_PHASE_SOLVE, solverConfig,
441 solverData, *Ac, yc, xc));
451 for (
int i = 0; i < nrhs; i++)
453 Vector s(SOL, i * n_global, n_loc);
int Size() const
Return the logical size of the array.
void Mult(const Vector &x, Vector &y) const override
Solve .
void SetOperator(const Operator &op) override
Set/update the solver for the given operator.
MatType
Specify the type of matrix we are applying the solver to.
@ SYMMETRIC_INDEFINITE
CUDSS_MTYPE_SYMMETRIC: Real symmetric matrix.
@ SYMMETRIC_POSITIVE_DEFINITE
CUDSS_MTYPE_SPD: Symmetric positive-definite matrix.
void SetReorderingReuse(bool reuse)
Set the flag controlling reuse of the symbolic factorization for multiple operators.
MatViewType
Specify the view type of matrix we are applying the solver to.
@ UPPER
CUDSS_MVIEW_UPPER: Upper-triangular matrix (including the diagonal).
@ LOWER
CUDSS_MVIEW_LOWER: Lower-triangular matrix (including the diagonal).
CuDSSSolver()
Constructor.
void SetMatrixViewType(MatViewType mvtype)
Set the matrix view type.
void SetMatrixSymType(MatType mtype_)
Set the matrix type.
void ArrayMult(const Array< const Vector * > &X, Array< Vector * > &Y) const override
Solve .
Wrapper for hypre's ParCSR matrix class.
void HypreRead() const
Update the internal hypre_ParCSRMatrix object, A, to be in hypre memory space.
static bool IsInitialized()
Return true if MPI has been initialized.
int width
Dimension of the input / number of columns in the matrix.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
int height
Dimension of the output / number of rows in the matrix.
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
virtual const real_t * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
void SyncAliasMemory(const Vector &v) const
Update the alias memory location of the vector to match v.
void SetSize(int s)
Resize the vector to size s.
virtual real_t * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
void MakeRef(Vector &base, int offset, int size)
Reset the Vector to be a reference to a sub-vector of base.
void * CuMemAlloc(void **dptr, size_t bytes)
Allocates device memory and returns destination ptr.
void * CuMemFree(void *dptr)
Frees device memory and returns destination ptr.
void mfem_error(const char *msg)
const char * GetEnv(const char *name)
Wrapper for std::getenv.
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
void * CuMemcpyDtoD(void *dst, const void *src, size_t bytes)
Copies memory from Device to Device.
void mfem_cudss_error(cudssStatus_t status, const char *expr, const char *func, const char *file, int line)