13bf14a46SMatthew Knepley /* 23bf14a46SMatthew Knepley Provides an interface to the PaStiX sparse solver 33bf14a46SMatthew Knepley */ 4c6db04a5SJed Brown #include <../src/mat/impls/aij/seq/aij.h> 5c6db04a5SJed Brown #include <../src/mat/impls/aij/mpi/mpiaij.h> 6c6db04a5SJed Brown #include <../src/mat/impls/sbaij/seq/sbaij.h> 7c6db04a5SJed Brown #include <../src/mat/impls/sbaij/mpi/mpisbaij.h> 83bf14a46SMatthew Knepley 9dbbbd53dSSatish Balay #if defined(PETSC_USE_COMPLEX) 105ec454cfSSatish Balay #define _H_COMPLEX 115ec454cfSSatish Balay #endif 125ec454cfSSatish Balay 13c6db04a5SJed Brown #include <pastix.h> 143bf14a46SMatthew Knepley 15519f805aSKarl Rupp #if defined(PETSC_USE_COMPLEX) 16519f805aSKarl Rupp #if defined(PETSC_USE_REAL_SINGLE) 17*688c8ee7SFlorent Pruvost #define SPM_FLTTYPE SpmComplex32 185ec454cfSSatish Balay #else 19*688c8ee7SFlorent Pruvost #define SPM_FLTTYPE SpmComplex64 205ec454cfSSatish Balay #endif 21d41469e0Sxavier lacoste #else /* PETSC_USE_COMPLEX */ 22d41469e0Sxavier lacoste 23519f805aSKarl Rupp #if defined(PETSC_USE_REAL_SINGLE) 24*688c8ee7SFlorent Pruvost #define SPM_FLTTYPE SpmFloat 255ec454cfSSatish Balay #else 26*688c8ee7SFlorent Pruvost #define SPM_FLTTYPE SpmDouble 275ec454cfSSatish Balay #endif 28d41469e0Sxavier lacoste 29d41469e0Sxavier lacoste #endif /* PETSC_USE_COMPLEX */ 30d41469e0Sxavier lacoste 31dbbbd53dSSatish Balay typedef PetscScalar PastixScalar; 32dbbbd53dSSatish Balay 333bf14a46SMatthew Knepley typedef struct Mat_Pastix_ { 343bf14a46SMatthew Knepley pastix_data_t *pastix_data; /* Pastix data storage structure */ 35*688c8ee7SFlorent Pruvost MPI_Comm comm; /* MPI Communicator used to initialize pastix */ 36*688c8ee7SFlorent Pruvost spmatrix_t *spm; /* SPM matrix structure */ 37*688c8ee7SFlorent Pruvost MatStructure matstruc; /* DIFFERENT_NONZERO_PATTERN if uninitilized, SAME otherwise */ 38*688c8ee7SFlorent Pruvost PetscScalar *rhs; /* Right-hand-side member */ 39*688c8ee7SFlorent Pruvost PetscInt rhsnbr; /* Right-hand-side number */ 40*688c8ee7SFlorent Pruvost pastix_int_t iparm[IPARM_SIZE]; /* Integer parameters */ 41baed9decSBarry Smith double dparm[DPARM_SIZE]; /* Floating point parameters */ 423bf14a46SMatthew Knepley } Mat_Pastix; 433bf14a46SMatthew Knepley 443bf14a46SMatthew Knepley /* 45*688c8ee7SFlorent Pruvost convert PETSc matrix to SPM structure 463bf14a46SMatthew Knepley 473bf14a46SMatthew Knepley input: 48*688c8ee7SFlorent Pruvost A - matrix in aij, baij or sbaij format 49*688c8ee7SFlorent Pruvost reuse - MAT_INITIAL_MATRIX: spaces are allocated and values are set for the triple 50*688c8ee7SFlorent Pruvost MAT_REUSE_MATRIX: only the values in v array are updated 513bf14a46SMatthew Knepley output: 52*688c8ee7SFlorent Pruvost spm - The SPM built from A 533bf14a46SMatthew Knepley */ 54*688c8ee7SFlorent Pruvost static PetscErrorCode MatConvertToSPM(Mat A, MatReuse reuse, Mat_Pastix *pastix) 55d71ae5a4SJacob Faibussowitsch { 56*688c8ee7SFlorent Pruvost Mat A_loc, A_aij; 57*688c8ee7SFlorent Pruvost const PetscInt *row, *col; 58*688c8ee7SFlorent Pruvost PetscInt n, i; 59*688c8ee7SFlorent Pruvost const PetscScalar *val; 60*688c8ee7SFlorent Pruvost PetscBool ismpiaij, isseqaij, ismpisbaij, isseqsbaij; 61*688c8ee7SFlorent Pruvost PetscBool flag; 62*688c8ee7SFlorent Pruvost spmatrix_t spm2, *spm = NULL; 63*688c8ee7SFlorent Pruvost int spm_err; 643bf14a46SMatthew Knepley 653bf14a46SMatthew Knepley PetscFunctionBegin; 66*688c8ee7SFlorent Pruvost /* Get A datas */ 67*688c8ee7SFlorent Pruvost PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATSEQAIJ, &isseqaij)); 68*688c8ee7SFlorent Pruvost PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIAIJ, &ismpiaij)); 69*688c8ee7SFlorent Pruvost /* TODO: Block Aij should be handled with dof in spm */ 70*688c8ee7SFlorent Pruvost PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATSEQSBAIJ, &isseqsbaij)); 71*688c8ee7SFlorent Pruvost PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPISBAIJ, &ismpisbaij)); 723bf14a46SMatthew Knepley 73*688c8ee7SFlorent Pruvost if (isseqsbaij || ismpisbaij) PetscCall(MatConvert(A, MATAIJ, reuse, &A_aij)); 74*688c8ee7SFlorent Pruvost else A_aij = A; 75745c78f7SBarry Smith 76*688c8ee7SFlorent Pruvost if (ismpiaij || ismpisbaij) PetscCall(MatMPIAIJGetLocalMat(A_aij, MAT_INITIAL_MATRIX, &A_loc)); 77*688c8ee7SFlorent Pruvost else if (isseqaij || isseqsbaij) A_loc = A_aij; 78*688c8ee7SFlorent Pruvost else SETERRQ(PetscObjectComm((PetscObject)A_aij), PETSC_ERR_SUP, "Not for type %s", ((PetscObject)A)->type_name); 79*688c8ee7SFlorent Pruvost 80*688c8ee7SFlorent Pruvost /* Use getRowIJ and the trick CSC/CSR instead of GetColumnIJ for performance */ 81*688c8ee7SFlorent Pruvost PetscCall(MatGetRowIJ(A_loc, 0, PETSC_FALSE, PETSC_FALSE, &n, &row, &col, &flag)); 82*688c8ee7SFlorent Pruvost PetscCheck(flag, PETSC_COMM_SELF, PETSC_ERR_SUP, "GetRowIJ failed"); 83*688c8ee7SFlorent Pruvost PetscCall(MatSeqAIJGetArrayRead(A_loc, &val)); 84*688c8ee7SFlorent Pruvost 85*688c8ee7SFlorent Pruvost PetscCall(PetscMalloc1(1, &spm)); 86*688c8ee7SFlorent Pruvost PetscStackCallExternalVoid("spmInitDist", spmInitDist(spm, pastix->comm)); 87*688c8ee7SFlorent Pruvost 88*688c8ee7SFlorent Pruvost spm->n = n; 89*688c8ee7SFlorent Pruvost spm->nnz = row[n]; 90*688c8ee7SFlorent Pruvost spm->fmttype = SpmCSR; 91*688c8ee7SFlorent Pruvost spm->flttype = SPM_FLTTYPE; 92*688c8ee7SFlorent Pruvost spm->replicated = !(A->rmap->n != A->rmap->N); 93*688c8ee7SFlorent Pruvost 94*688c8ee7SFlorent Pruvost PetscStackCallExternalVoid("spmUpdateComputedFields", spmUpdateComputedFields(spm)); 95*688c8ee7SFlorent Pruvost PetscStackCallExternalVoid("spmAlloc", spmAlloc(spm)); 96*688c8ee7SFlorent Pruvost 97*688c8ee7SFlorent Pruvost /* Get data distribution */ 98*688c8ee7SFlorent Pruvost if (!spm->replicated) { 99*688c8ee7SFlorent Pruvost for (i = A->rmap->rstart; i < A->rmap->rend; i++) spm->loc2glob[i - A->rmap->rstart] = i; 100*688c8ee7SFlorent Pruvost } 101*688c8ee7SFlorent Pruvost 102*688c8ee7SFlorent Pruvost /* Copy arrays */ 103*688c8ee7SFlorent Pruvost PetscCall(PetscArraycpy(spm->colptr, col, spm->nnz)); 104*688c8ee7SFlorent Pruvost PetscCall(PetscArraycpy(spm->rowptr, row, spm->n + 1)); 105*688c8ee7SFlorent Pruvost PetscCall(PetscArraycpy((PetscScalar *)spm->values, val, spm->nnzexp)); 106*688c8ee7SFlorent Pruvost PetscCall(MatRestoreRowIJ(A_loc, 0, PETSC_FALSE, PETSC_FALSE, &n, &row, &col, &flag)); 107*688c8ee7SFlorent Pruvost PetscCheck(flag, PETSC_COMM_SELF, PETSC_ERR_SUP, "RestoreRowIJ failed"); 108*688c8ee7SFlorent Pruvost PetscCall(MatSeqAIJRestoreArrayRead(A_loc, &val)); 109*688c8ee7SFlorent Pruvost if (ismpiaij || ismpisbaij) PetscCall(MatDestroy(&A_loc)); 110*688c8ee7SFlorent Pruvost 111*688c8ee7SFlorent Pruvost /* 112*688c8ee7SFlorent Pruvost PaStiX works only with CSC matrices for now, so let's lure him by telling him 113*688c8ee7SFlorent Pruvost that the PETSc CSR matrix is a CSC matrix. 114*688c8ee7SFlorent Pruvost Note that this is not available yet for Hermitian matrices and LL^h/LDL^h factorizations. 115745c78f7SBarry Smith */ 116*688c8ee7SFlorent Pruvost { 117*688c8ee7SFlorent Pruvost spm_int_t *tmp; 118*688c8ee7SFlorent Pruvost spm->fmttype = SpmCSC; 119*688c8ee7SFlorent Pruvost tmp = spm->colptr; 120*688c8ee7SFlorent Pruvost spm->colptr = spm->rowptr; 121*688c8ee7SFlorent Pruvost spm->rowptr = tmp; 122*688c8ee7SFlorent Pruvost pastix->iparm[IPARM_TRANSPOSE_SOLVE] = PastixTrans; 123f31ce8a6SBarry Smith } 124745c78f7SBarry Smith 125*688c8ee7SFlorent Pruvost /* Update matrix to be in PaStiX format */ 126*688c8ee7SFlorent Pruvost PetscStackCallExternalVoid("spmCheckAndCorrect", spm_err = spmCheckAndCorrect(spm, &spm2)); 127*688c8ee7SFlorent Pruvost if (spm_err != 0) { 128*688c8ee7SFlorent Pruvost PetscStackCallExternalVoid("spmExit", spmExit(spm)); 129*688c8ee7SFlorent Pruvost *spm = spm2; 1303bf14a46SMatthew Knepley } 1313bf14a46SMatthew Knepley 132*688c8ee7SFlorent Pruvost if (isseqsbaij || ismpisbaij) PetscCall(MatDestroy(&A_aij)); 133*688c8ee7SFlorent Pruvost 134*688c8ee7SFlorent Pruvost pastix->spm = spm; 1353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1363bf14a46SMatthew Knepley } 1373bf14a46SMatthew Knepley 1383bf14a46SMatthew Knepley /* 139*688c8ee7SFlorent Pruvost Call clean step of PaStiX if initialized 140*688c8ee7SFlorent Pruvost Free the SpM matrix and the PaStiX instance. 1413bf14a46SMatthew Knepley */ 142*688c8ee7SFlorent Pruvost static PetscErrorCode MatDestroy_PaStiX(Mat A) 143d71ae5a4SJacob Faibussowitsch { 144*688c8ee7SFlorent Pruvost Mat_Pastix *pastix = (Mat_Pastix *)A->data; 145745c78f7SBarry Smith 1463bf14a46SMatthew Knepley PetscFunctionBegin; 147*688c8ee7SFlorent Pruvost /* Finalize SPM (matrix handler of PaStiX) */ 148*688c8ee7SFlorent Pruvost if (pastix->spm) { 149*688c8ee7SFlorent Pruvost PetscStackCallExternalVoid("spmExit", spmExit(pastix->spm)); 150*688c8ee7SFlorent Pruvost PetscCall(PetscFree(pastix->spm)); 1513bf14a46SMatthew Knepley } 152*688c8ee7SFlorent Pruvost 153*688c8ee7SFlorent Pruvost /* clear composed functions */ 1542e956fe4SStefano Zampini PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatFactorGetSolverType_C", NULL)); 155*688c8ee7SFlorent Pruvost 156*688c8ee7SFlorent Pruvost /* Finalize PaStiX */ 157*688c8ee7SFlorent Pruvost if (pastix->pastix_data) pastixFinalize(&pastix->pastix_data); 158*688c8ee7SFlorent Pruvost 159*688c8ee7SFlorent Pruvost /* Deallocate PaStiX structure */ 1609566063dSJacob Faibussowitsch PetscCall(PetscFree(A->data)); 1613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1623bf14a46SMatthew Knepley } 1633bf14a46SMatthew Knepley 1643bf14a46SMatthew Knepley /* 165dd8e379bSPierre Jolivet Gather right-hand side. 1663bf14a46SMatthew Knepley Call for Solve step. 1673bf14a46SMatthew Knepley Scatter solution. 1683bf14a46SMatthew Knepley */ 16966976f2fSJacob Faibussowitsch static PetscErrorCode MatSolve_PaStiX(Mat A, Vec b, Vec x) 170d71ae5a4SJacob Faibussowitsch { 171*688c8ee7SFlorent Pruvost Mat_Pastix *pastix = (Mat_Pastix *)A->data; 172*688c8ee7SFlorent Pruvost const PetscScalar *bptr; 173*688c8ee7SFlorent Pruvost PetscInt ldrhs; 1743bf14a46SMatthew Knepley 1753bf14a46SMatthew Knepley PetscFunctionBegin; 176*688c8ee7SFlorent Pruvost pastix->rhsnbr = 1; 177*688c8ee7SFlorent Pruvost ldrhs = pastix->spm->n; 178*688c8ee7SFlorent Pruvost 1799566063dSJacob Faibussowitsch PetscCall(VecCopy(b, x)); 180*688c8ee7SFlorent Pruvost PetscCall(VecGetArray(x, &pastix->rhs)); 181*688c8ee7SFlorent Pruvost PetscCall(VecGetArrayRead(b, &bptr)); 1823bf14a46SMatthew Knepley 1833bf14a46SMatthew Knepley /* solve phase */ 184*688c8ee7SFlorent Pruvost /*-------------*/ 185*688c8ee7SFlorent Pruvost PetscCheck(pastix->pastix_data, PETSC_COMM_SELF, PETSC_ERR_SUP, "PaStiX hasn't been initialized"); 186*688c8ee7SFlorent Pruvost PetscCallExternal(pastix_task_solve, pastix->pastix_data, ldrhs, pastix->rhsnbr, pastix->rhs, ldrhs); 187*688c8ee7SFlorent Pruvost PetscCallExternal(pastix_task_refine, pastix->pastix_data, ldrhs, pastix->rhsnbr, (PetscScalar *)bptr, ldrhs, pastix->rhs, ldrhs); 1883bf14a46SMatthew Knepley 189*688c8ee7SFlorent Pruvost PetscCall(VecRestoreArray(x, &pastix->rhs)); 190*688c8ee7SFlorent Pruvost PetscCall(VecRestoreArrayRead(b, &bptr)); 1913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1923bf14a46SMatthew Knepley } 1933bf14a46SMatthew Knepley 1943bf14a46SMatthew Knepley /* 1953bf14a46SMatthew Knepley Numeric factorisation using PaStiX solver. 1963bf14a46SMatthew Knepley 197*688c8ee7SFlorent Pruvost input: 198*688c8ee7SFlorent Pruvost F - PETSc matrix that contains PaStiX interface. 199*688c8ee7SFlorent Pruvost A - PETSC matrix in aij, bail or sbaij format 2003bf14a46SMatthew Knepley */ 20166976f2fSJacob Faibussowitsch static PetscErrorCode MatFactorNumeric_PaStiX(Mat F, Mat A, const MatFactorInfo *info) 202d71ae5a4SJacob Faibussowitsch { 203*688c8ee7SFlorent Pruvost Mat_Pastix *pastix = (Mat_Pastix *)F->data; 2043bf14a46SMatthew Knepley 2053bf14a46SMatthew Knepley PetscFunctionBegin; 20657508eceSPierre Jolivet F->ops->solve = MatSolve_PaStiX; 2073bf14a46SMatthew Knepley 208*688c8ee7SFlorent Pruvost /* Perform Numerical Factorization */ 209*688c8ee7SFlorent Pruvost PetscCheck(pastix->pastix_data, PETSC_COMM_SELF, PETSC_ERR_SUP, "PaStiX hasn't been initialized"); 210*688c8ee7SFlorent Pruvost PetscCallExternal(pastix_task_numfact, pastix->pastix_data, pastix->spm); 2113bf14a46SMatthew Knepley 21257508eceSPierre Jolivet F->assembled = PETSC_TRUE; 2133ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2143bf14a46SMatthew Knepley } 2153bf14a46SMatthew Knepley 216*688c8ee7SFlorent Pruvost static PetscErrorCode MatLUFactorNumeric_PaStiX(Mat F, Mat A, const MatFactorInfo *info) 217d71ae5a4SJacob Faibussowitsch { 218*688c8ee7SFlorent Pruvost Mat_Pastix *pastix = (Mat_Pastix *)F->data; 2193bf14a46SMatthew Knepley 2203bf14a46SMatthew Knepley PetscFunctionBegin; 221*688c8ee7SFlorent Pruvost PetscCheck(pastix->iparm[IPARM_FACTORIZATION] == PastixFactGETRF, PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Incorrect factorization type for symbolic and numerical factorization by PaStiX"); 222*688c8ee7SFlorent Pruvost pastix->iparm[IPARM_FACTORIZATION] = PastixFactGETRF; 223*688c8ee7SFlorent Pruvost PetscCall(MatFactorNumeric_PaStiX(F, A, info)); 2243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2253bf14a46SMatthew Knepley } 2263bf14a46SMatthew Knepley 227*688c8ee7SFlorent Pruvost static PetscErrorCode MatCholeskyFactorNumeric_PaStiX(Mat F, Mat A, const MatFactorInfo *info) 228d71ae5a4SJacob Faibussowitsch { 229*688c8ee7SFlorent Pruvost Mat_Pastix *pastix = (Mat_Pastix *)F->data; 2303bf14a46SMatthew Knepley 2313bf14a46SMatthew Knepley PetscFunctionBegin; 232*688c8ee7SFlorent Pruvost PetscCheck(pastix->iparm[IPARM_FACTORIZATION] == PastixFactSYTRF, PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Incorrect factorization type for symbolic and numerical factorization by PaStiX"); 233*688c8ee7SFlorent Pruvost pastix->iparm[IPARM_FACTORIZATION] = PastixFactSYTRF; 234*688c8ee7SFlorent Pruvost PetscCall(MatFactorNumeric_PaStiX(F, A, info)); 235*688c8ee7SFlorent Pruvost PetscFunctionReturn(PETSC_SUCCESS); 236*688c8ee7SFlorent Pruvost } 237*688c8ee7SFlorent Pruvost 238*688c8ee7SFlorent Pruvost /* 239*688c8ee7SFlorent Pruvost Perform Ordering step and Symbolic Factorization step 240*688c8ee7SFlorent Pruvost 241*688c8ee7SFlorent Pruvost Note the Petsc r and c permutations are ignored 242*688c8ee7SFlorent Pruvost input: 243*688c8ee7SFlorent Pruvost F - PETSc matrix that contains PaStiX interface. 244*688c8ee7SFlorent Pruvost A - matrix in aij, bail or sbaij format 245*688c8ee7SFlorent Pruvost r - permutation ? 246*688c8ee7SFlorent Pruvost c - TODO 247*688c8ee7SFlorent Pruvost info - Informations about the factorization to perform. 248*688c8ee7SFlorent Pruvost output: 249*688c8ee7SFlorent Pruvost pastix_data - This instance will be updated with the SolverMatrix allocated. 250*688c8ee7SFlorent Pruvost */ 251*688c8ee7SFlorent Pruvost static PetscErrorCode MatFactorSymbolic_PaStiX(Mat F, Mat A, IS r, IS c, const MatFactorInfo *info) 252*688c8ee7SFlorent Pruvost { 253*688c8ee7SFlorent Pruvost Mat_Pastix *pastix = (Mat_Pastix *)F->data; 254*688c8ee7SFlorent Pruvost 255*688c8ee7SFlorent Pruvost PetscFunctionBegin; 256*688c8ee7SFlorent Pruvost pastix->matstruc = DIFFERENT_NONZERO_PATTERN; 257*688c8ee7SFlorent Pruvost 258*688c8ee7SFlorent Pruvost /* Initialise SPM structure */ 259*688c8ee7SFlorent Pruvost PetscCall(MatConvertToSPM(A, MAT_INITIAL_MATRIX, pastix)); 260*688c8ee7SFlorent Pruvost 261*688c8ee7SFlorent Pruvost /* Ordering - Symbolic factorization - Build SolverMatrix */ 262*688c8ee7SFlorent Pruvost PetscCheck(pastix->pastix_data, PETSC_COMM_SELF, PETSC_ERR_SUP, "PaStiX hasn't been initialized"); 263*688c8ee7SFlorent Pruvost PetscCallExternal(pastix_task_analyze, pastix->pastix_data, pastix->spm); 264*688c8ee7SFlorent Pruvost PetscFunctionReturn(PETSC_SUCCESS); 265*688c8ee7SFlorent Pruvost } 266*688c8ee7SFlorent Pruvost 267*688c8ee7SFlorent Pruvost static PetscErrorCode MatLUFactorSymbolic_PaStiX(Mat F, Mat A, IS r, IS c, const MatFactorInfo *info) 268*688c8ee7SFlorent Pruvost { 269*688c8ee7SFlorent Pruvost Mat_Pastix *pastix = (Mat_Pastix *)F->data; 270*688c8ee7SFlorent Pruvost 271*688c8ee7SFlorent Pruvost PetscFunctionBegin; 272*688c8ee7SFlorent Pruvost pastix->iparm[IPARM_FACTORIZATION] = PastixFactGETRF; 273*688c8ee7SFlorent Pruvost PetscCall(MatFactorSymbolic_PaStiX(F, A, r, c, info)); 274*688c8ee7SFlorent Pruvost PetscFunctionReturn(PETSC_SUCCESS); 275*688c8ee7SFlorent Pruvost } 276*688c8ee7SFlorent Pruvost 277*688c8ee7SFlorent Pruvost /* Note the Petsc r permutation is ignored */ 278*688c8ee7SFlorent Pruvost static PetscErrorCode MatCholeskyFactorSymbolic_PaStiX(Mat F, Mat A, IS r, const MatFactorInfo *info) 279*688c8ee7SFlorent Pruvost { 280*688c8ee7SFlorent Pruvost Mat_Pastix *pastix = (Mat_Pastix *)F->data; 281*688c8ee7SFlorent Pruvost 282*688c8ee7SFlorent Pruvost PetscFunctionBegin; 283*688c8ee7SFlorent Pruvost /* Warning: Cholesky in Petsc wrapper does not handle (complex) Hermitian matrices. 284*688c8ee7SFlorent Pruvost The factorization type can be forced using the parameter 285*688c8ee7SFlorent Pruvost mat_pastix_factorization (see enum pastix_factotype_e in 286*688c8ee7SFlorent Pruvost https://solverstack.gitlabpages.inria.fr/pastix/group__pastix__api.html). */ 287*688c8ee7SFlorent Pruvost pastix->iparm[IPARM_FACTORIZATION] = PastixFactSYTRF; 288*688c8ee7SFlorent Pruvost PetscCall(MatFactorSymbolic_PaStiX(F, A, r, NULL, info)); 2893ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2903bf14a46SMatthew Knepley } 2913bf14a46SMatthew Knepley 29266976f2fSJacob Faibussowitsch static PetscErrorCode MatView_PaStiX(Mat A, PetscViewer viewer) 293d71ae5a4SJacob Faibussowitsch { 294ace3abfcSBarry Smith PetscBool iascii; 2953bf14a46SMatthew Knepley PetscViewerFormat format; 2963bf14a46SMatthew Knepley 2973bf14a46SMatthew Knepley PetscFunctionBegin; 2989566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 2993bf14a46SMatthew Knepley if (iascii) { 3009566063dSJacob Faibussowitsch PetscCall(PetscViewerGetFormat(viewer, &format)); 3013bf14a46SMatthew Knepley if (format == PETSC_VIEWER_ASCII_INFO) { 302*688c8ee7SFlorent Pruvost Mat_Pastix *pastix = (Mat_Pastix *)A->data; 303*688c8ee7SFlorent Pruvost spmatrix_t *spm = pastix->spm; 304*688c8ee7SFlorent Pruvost PetscCheck(!spm, PETSC_COMM_SELF, PETSC_ERR_SUP, "Sparse matrix isn't initialized"); 305b5e56a35SBarry Smith 3069566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "PaStiX run parameters:\n")); 307*688c8ee7SFlorent Pruvost PetscCall(PetscViewerASCIIPrintf(viewer, " Matrix type : %s \n", ((spm->mtxtype == SpmSymmetric) ? "Symmetric" : "Unsymmetric"))); 308*688c8ee7SFlorent Pruvost PetscCall(PetscViewerASCIIPrintf(viewer, " Level of printing (0,1,2): %ld \n", (long)pastix->iparm[IPARM_VERBOSE])); 309*688c8ee7SFlorent Pruvost PetscCall(PetscViewerASCIIPrintf(viewer, " Number of refinements iterations : %ld \n", (long)pastix->iparm[IPARM_NBITER])); 310*688c8ee7SFlorent Pruvost PetscCall(PetscPrintf(PETSC_COMM_SELF, " Error : %e \n", pastix->dparm[DPARM_RELATIVE_ERROR])); 311*688c8ee7SFlorent Pruvost if (pastix->iparm[IPARM_VERBOSE] > 0) spmPrintInfo(spm, stdout); 3123bf14a46SMatthew Knepley } 3133bf14a46SMatthew Knepley } 3143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3153bf14a46SMatthew Knepley } 3163bf14a46SMatthew Knepley 3173bf14a46SMatthew Knepley /*MC 3182692d6eeSBarry Smith MATSOLVERPASTIX - A solver package providing direct solvers (LU) for distributed 3193bf14a46SMatthew Knepley and sequential matrices via the external package PaStiX. 3203bf14a46SMatthew Knepley 321*688c8ee7SFlorent Pruvost Use `./configure --download-hwloc --download-metis --download-ptscotch --download-pastix --download-netlib-lapack [or MKL for ex. --with-blaslapack-dir=${MKLROOT}]` 322*688c8ee7SFlorent Pruvost to have PETSc installed with PasTiX. 323c2b89b5dSBarry Smith 324*688c8ee7SFlorent Pruvost Use `-pc_type lu` `-pc_factor_mat_solver_type pastix` to use this direct solver. 3253bf14a46SMatthew Knepley 3263bf14a46SMatthew Knepley Options Database Keys: 327*688c8ee7SFlorent Pruvost -mat_pastix_verbose <0,1,2> - print level of information messages from PaStiX 328*688c8ee7SFlorent Pruvost -mat_pastix_factorization <0,1,2,3,4> - Factorization algorithm (Cholesky, LDL^t, LU, LL^t, LDL^h) 329*688c8ee7SFlorent Pruvost -mat_pastix_itermax <integer> - Maximum number of iterations during refinement 330*688c8ee7SFlorent Pruvost -mat_pastix_epsilon_refinement <double> - Epsilon for refinement 331*688c8ee7SFlorent Pruvost -mat_pastix_epsilon_magn_ctrl <double> - Epsilon for magnitude control 332*688c8ee7SFlorent Pruvost -mat_pastix_ordering <0,1> - Ordering (Scotch or Metis) 333*688c8ee7SFlorent Pruvost -mat_pastix_thread_nbr <integer> - Set the numbers of threads for each MPI process 334*688c8ee7SFlorent Pruvost -mat_pastix_scheduler <0,1,2,3,4> - Scheduler (sequential, static, parsec, starpu, dynamic) 335*688c8ee7SFlorent Pruvost -mat_pastix_compress_when <0,1,2,3> - When to compress (never, minimal-theory, just-in-time, supernodes) 336*688c8ee7SFlorent Pruvost -mat_pastix_compress_tolerance <double> - Tolerance for low-rank kernels. 3373bf14a46SMatthew Knepley 33895452b02SPatrick Sanan Notes: 33995452b02SPatrick Sanan This only works for matrices with symmetric nonzero structure, if you pass it a matrix with 3402ef1f0ffSBarry Smith nonsymmetric structure PasTiX, and hence, PETSc return with an error. 341baed9decSBarry Smith 3423bf14a46SMatthew Knepley Level: beginner 3433bf14a46SMatthew Knepley 3441cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `PCFactorSetMatSolverType()`, `MatSolverType`, `MatGetFactor()` 3453bf14a46SMatthew Knepley M*/ 3463bf14a46SMatthew Knepley 34766976f2fSJacob Faibussowitsch static PetscErrorCode MatGetInfo_PaStiX(Mat A, MatInfoType flag, MatInfo *info) 348d71ae5a4SJacob Faibussowitsch { 349*688c8ee7SFlorent Pruvost Mat_Pastix *pastix = (Mat_Pastix *)A->data; 3503bf14a46SMatthew Knepley 3513bf14a46SMatthew Knepley PetscFunctionBegin; 3523bf14a46SMatthew Knepley info->block_size = 1.0; 353*688c8ee7SFlorent Pruvost info->nz_allocated = pastix->iparm[IPARM_ALLOCATED_TERMS]; 354*688c8ee7SFlorent Pruvost info->nz_used = pastix->iparm[IPARM_NNZEROS]; 3553bf14a46SMatthew Knepley info->nz_unneeded = 0.0; 3563bf14a46SMatthew Knepley info->assemblies = 0.0; 3573bf14a46SMatthew Knepley info->mallocs = 0.0; 3583bf14a46SMatthew Knepley info->memory = 0.0; 3593bf14a46SMatthew Knepley info->fill_ratio_given = 0; 3603bf14a46SMatthew Knepley info->fill_ratio_needed = 0; 3613bf14a46SMatthew Knepley info->factor_mallocs = 0; 3623ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3633bf14a46SMatthew Knepley } 3643bf14a46SMatthew Knepley 365*688c8ee7SFlorent Pruvost static PetscErrorCode MatFactorGetSolverType_PaStiX(Mat A, MatSolverType *type) 366d71ae5a4SJacob Faibussowitsch { 3673bf14a46SMatthew Knepley PetscFunctionBegin; 3682692d6eeSBarry Smith *type = MATSOLVERPASTIX; 3693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3703bf14a46SMatthew Knepley } 3713bf14a46SMatthew Knepley 372*688c8ee7SFlorent Pruvost /* Sets PaStiX options from the options database */ 373*688c8ee7SFlorent Pruvost static PetscErrorCode MatSetFromOptions_PaStiX(Mat A) 374*688c8ee7SFlorent Pruvost { 375*688c8ee7SFlorent Pruvost Mat_Pastix *pastix = (Mat_Pastix *)A->data; 376*688c8ee7SFlorent Pruvost pastix_int_t *iparm = pastix->iparm; 377*688c8ee7SFlorent Pruvost double *dparm = pastix->dparm; 378*688c8ee7SFlorent Pruvost PetscInt icntl; 379*688c8ee7SFlorent Pruvost PetscReal dcntl; 380*688c8ee7SFlorent Pruvost PetscBool set; 381*688c8ee7SFlorent Pruvost 382*688c8ee7SFlorent Pruvost PetscFunctionBegin; 383*688c8ee7SFlorent Pruvost PetscOptionsBegin(PetscObjectComm((PetscObject)A), ((PetscObject)A)->prefix, "PaStiX Options", "Mat"); 384*688c8ee7SFlorent Pruvost 385*688c8ee7SFlorent Pruvost iparm[IPARM_VERBOSE] = 0; 386*688c8ee7SFlorent Pruvost iparm[IPARM_ITERMAX] = 20; 387*688c8ee7SFlorent Pruvost 388*688c8ee7SFlorent Pruvost PetscCall(PetscOptionsRangeInt("-mat_pastix_verbose", "iparm[IPARM_VERBOSE] : level of printing (0 to 2)", "None", iparm[IPARM_VERBOSE], &icntl, &set, 0, 2)); 389*688c8ee7SFlorent Pruvost if (set) iparm[IPARM_VERBOSE] = (pastix_int_t)icntl; 390*688c8ee7SFlorent Pruvost 391*688c8ee7SFlorent Pruvost PetscCall(PetscOptionsRangeInt("-mat_pastix_factorization", "iparm[IPARM_FACTORIZATION]: Factorization algorithm", "None", iparm[IPARM_FACTORIZATION], &icntl, &set, 0, 4)); 392*688c8ee7SFlorent Pruvost if (set) iparm[IPARM_FACTORIZATION] = (pastix_int_t)icntl; 393*688c8ee7SFlorent Pruvost 394*688c8ee7SFlorent Pruvost PetscCall(PetscOptionsBoundedInt("-mat_pastix_itermax", "iparm[IPARM_ITERMAX]: Max iterations", "None", iparm[IPARM_ITERMAX], &icntl, &set, 1)); 395*688c8ee7SFlorent Pruvost if (set) iparm[IPARM_ITERMAX] = (pastix_int_t)icntl; 396*688c8ee7SFlorent Pruvost 397*688c8ee7SFlorent Pruvost PetscCall(PetscOptionsBoundedReal("-mat_pastix_epsilon_refinement", "dparm[DPARM_EPSILON_REFINEMENT]: Epsilon refinement", "None", dparm[DPARM_EPSILON_REFINEMENT], &dcntl, &set, -1.)); 398*688c8ee7SFlorent Pruvost if (set) dparm[DPARM_EPSILON_REFINEMENT] = (double)dcntl; 399*688c8ee7SFlorent Pruvost 400*688c8ee7SFlorent Pruvost PetscCall(PetscOptionsReal("-mat_pastix_epsilon_magn_ctrl", "dparm[DPARM_EPSILON_MAGN_CTRL]: Epsilon magnitude control", "None", dparm[DPARM_EPSILON_MAGN_CTRL], &dcntl, &set)); 401*688c8ee7SFlorent Pruvost if (set) dparm[DPARM_EPSILON_MAGN_CTRL] = (double)dcntl; 402*688c8ee7SFlorent Pruvost 403*688c8ee7SFlorent Pruvost PetscCall(PetscOptionsRangeInt("-mat_pastix_ordering", "iparm[IPARM_ORDERING]: Ordering algorithm", "None", iparm[IPARM_ORDERING], &icntl, &set, 0, 2)); 404*688c8ee7SFlorent Pruvost if (set) iparm[IPARM_ORDERING] = (pastix_int_t)icntl; 405*688c8ee7SFlorent Pruvost 406*688c8ee7SFlorent Pruvost PetscCall(PetscOptionsBoundedInt("-mat_pastix_thread_nbr", "iparm[IPARM_THREAD_NBR]: Number of thread by MPI node", "None", iparm[IPARM_THREAD_NBR], &icntl, &set, -1)); 407*688c8ee7SFlorent Pruvost if (set) iparm[IPARM_THREAD_NBR] = (pastix_int_t)icntl; 408*688c8ee7SFlorent Pruvost 409*688c8ee7SFlorent Pruvost PetscCall(PetscOptionsRangeInt("-mat_pastix_scheduler", "iparm[IPARM_SCHEDULER]: Scheduler", "None", iparm[IPARM_SCHEDULER], &icntl, &set, 0, 4)); 410*688c8ee7SFlorent Pruvost if (set) iparm[IPARM_SCHEDULER] = (pastix_int_t)icntl; 411*688c8ee7SFlorent Pruvost 412*688c8ee7SFlorent Pruvost PetscCall(PetscOptionsRangeInt("-mat_pastix_compress_when", "iparm[IPARM_COMPRESS_WHEN]: When to compress", "None", iparm[IPARM_COMPRESS_WHEN], &icntl, &set, 0, 3)); 413*688c8ee7SFlorent Pruvost if (set) iparm[IPARM_COMPRESS_WHEN] = (pastix_int_t)icntl; 414*688c8ee7SFlorent Pruvost 415*688c8ee7SFlorent Pruvost PetscCall(PetscOptionsBoundedReal("-mat_pastix_compress_tolerance", "dparm[DPARM_COMPRESS_TOLERANCE]: Tolerance for low-rank kernels", "None", dparm[DPARM_COMPRESS_TOLERANCE], &dcntl, &set, 0.)); 416*688c8ee7SFlorent Pruvost if (set) dparm[DPARM_COMPRESS_TOLERANCE] = (double)dcntl; 417*688c8ee7SFlorent Pruvost 418*688c8ee7SFlorent Pruvost PetscOptionsEnd(); 419*688c8ee7SFlorent Pruvost PetscFunctionReturn(PETSC_SUCCESS); 420*688c8ee7SFlorent Pruvost } 421*688c8ee7SFlorent Pruvost 422*688c8ee7SFlorent Pruvost static PetscErrorCode MatGetFactor_pastix(Mat A, MatFactorType ftype, Mat *F, const char *mattype) 423d71ae5a4SJacob Faibussowitsch { 4243bf14a46SMatthew Knepley Mat B; 4253bf14a46SMatthew Knepley Mat_Pastix *pastix; 4263bf14a46SMatthew Knepley 4273bf14a46SMatthew Knepley PetscFunctionBegin; 4283bf14a46SMatthew Knepley /* Create the factorization matrix */ 4299566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B)); 4309566063dSJacob Faibussowitsch PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N)); 431*688c8ee7SFlorent Pruvost PetscCall(PetscStrallocpy(MATSOLVERPASTIX, &((PetscObject)B)->type_name)); 4329566063dSJacob Faibussowitsch PetscCall(MatSetUp(B)); 4333bf14a46SMatthew Knepley 434*688c8ee7SFlorent Pruvost PetscCheck(ftype == MAT_FACTOR_LU || ftype == MAT_FACTOR_CHOLESKY, PETSC_COMM_SELF, PETSC_ERR_SUP, "Factor type not supported by PaStiX"); 4353bf14a46SMatthew Knepley 43600c67f3bSHong Zhang /* set solvertype */ 4379566063dSJacob Faibussowitsch PetscCall(PetscFree(B->solvertype)); 4389566063dSJacob Faibussowitsch PetscCall(PetscStrallocpy(MATSOLVERPASTIX, &B->solvertype)); 43900c67f3bSHong Zhang 440*688c8ee7SFlorent Pruvost B->ops->lufactorsymbolic = MatLUFactorSymbolic_PaStiX; 441*688c8ee7SFlorent Pruvost B->ops->lufactornumeric = MatLUFactorNumeric_PaStiX; 442*688c8ee7SFlorent Pruvost B->ops->choleskyfactorsymbolic = MatCholeskyFactorSymbolic_PaStiX; 443*688c8ee7SFlorent Pruvost B->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_PaStiX; 444*688c8ee7SFlorent Pruvost B->ops->view = MatView_PaStiX; 445*688c8ee7SFlorent Pruvost B->ops->getinfo = MatGetInfo_PaStiX; 446*688c8ee7SFlorent Pruvost B->ops->destroy = MatDestroy_PaStiX; 4472205254eSKarl Rupp 448*688c8ee7SFlorent Pruvost PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatFactorGetSolverType_C", MatFactorGetSolverType_PaStiX)); 449*688c8ee7SFlorent Pruvost 450*688c8ee7SFlorent Pruvost B->factortype = ftype; 451*688c8ee7SFlorent Pruvost 452*688c8ee7SFlorent Pruvost /* Create the pastix structure */ 453*688c8ee7SFlorent Pruvost PetscCall(PetscNew(&pastix)); 45458c95f1bSBarry Smith B->data = (void *)pastix; 4553bf14a46SMatthew Knepley 456*688c8ee7SFlorent Pruvost /* Call to set default pastix options */ 457*688c8ee7SFlorent Pruvost PetscStackCallExternalVoid("pastixInitParam", pastixInitParam(pastix->iparm, pastix->dparm)); 458*688c8ee7SFlorent Pruvost PetscCall(MatSetFromOptions_PaStiX(B)); 459*688c8ee7SFlorent Pruvost 460*688c8ee7SFlorent Pruvost /* Get PETSc communicator */ 461*688c8ee7SFlorent Pruvost PetscCall(PetscObjectGetComm((PetscObject)A, &pastix->comm)); 462*688c8ee7SFlorent Pruvost 463*688c8ee7SFlorent Pruvost /* Initialise PaStiX structure */ 464*688c8ee7SFlorent Pruvost pastix->iparm[IPARM_SCOTCH_MT] = 0; 465*688c8ee7SFlorent Pruvost PetscStackCallExternalVoid("pastixInit", pastixInit(&pastix->pastix_data, pastix->comm, pastix->iparm, pastix->dparm)); 466*688c8ee7SFlorent Pruvost 467*688c8ee7SFlorent Pruvost /* Warning: Cholesky in Petsc wrapper does not handle (complex) Hermitian matrices. 468*688c8ee7SFlorent Pruvost The factorization type can be forced using the parameter 469*688c8ee7SFlorent Pruvost mat_pastix_factorization (see enum pastix_factotype_e in 470*688c8ee7SFlorent Pruvost https://solverstack.gitlabpages.inria.fr/pastix/group__pastix__api.html). */ 471*688c8ee7SFlorent Pruvost pastix->iparm[IPARM_FACTORIZATION] = ftype == MAT_FACTOR_CHOLESKY ? PastixFactSYTRF : PastixFactGETRF; 472*688c8ee7SFlorent Pruvost 4733bf14a46SMatthew Knepley *F = B; 4743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4753bf14a46SMatthew Knepley } 4763bf14a46SMatthew Knepley 477d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetFactor_mpiaij_pastix(Mat A, MatFactorType ftype, Mat *F) 478d71ae5a4SJacob Faibussowitsch { 4793bf14a46SMatthew Knepley PetscFunctionBegin; 4805f80ce2aSJacob Faibussowitsch PetscCheck(ftype == MAT_FACTOR_LU, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot use PETSc AIJ matrices with PaStiX Cholesky, use SBAIJ matrix"); 481*688c8ee7SFlorent Pruvost PetscCall(MatGetFactor_pastix(A, ftype, F, MATMPIAIJ)); 4823ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4833bf14a46SMatthew Knepley } 4843bf14a46SMatthew Knepley 485*688c8ee7SFlorent Pruvost static PetscErrorCode MatGetFactor_seqaij_pastix(Mat A, MatFactorType ftype, Mat *F) 486d71ae5a4SJacob Faibussowitsch { 4873bf14a46SMatthew Knepley PetscFunctionBegin; 488*688c8ee7SFlorent Pruvost PetscCheck(ftype == MAT_FACTOR_LU, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot use PETSc AIJ matrices with PaStiX Cholesky, use SBAIJ matrix"); 489*688c8ee7SFlorent Pruvost PetscCall(MatGetFactor_pastix(A, ftype, F, MATSEQAIJ)); 4903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4913bf14a46SMatthew Knepley } 4923bf14a46SMatthew Knepley 493d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetFactor_mpisbaij_pastix(Mat A, MatFactorType ftype, Mat *F) 494d71ae5a4SJacob Faibussowitsch { 4953bf14a46SMatthew Knepley PetscFunctionBegin; 4965f80ce2aSJacob Faibussowitsch PetscCheck(ftype == MAT_FACTOR_CHOLESKY, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot use PETSc SBAIJ matrices with PaStiX LU, use AIJ matrix"); 497*688c8ee7SFlorent Pruvost PetscCall(MatGetFactor_pastix(A, ftype, F, MATMPISBAIJ)); 498*688c8ee7SFlorent Pruvost PetscFunctionReturn(PETSC_SUCCESS); 499*688c8ee7SFlorent Pruvost } 50041c8de11SBarry Smith 501*688c8ee7SFlorent Pruvost static PetscErrorCode MatGetFactor_seqsbaij_pastix(Mat A, MatFactorType ftype, Mat *F) 502*688c8ee7SFlorent Pruvost { 503*688c8ee7SFlorent Pruvost PetscFunctionBegin; 504*688c8ee7SFlorent Pruvost PetscCheck(ftype == MAT_FACTOR_CHOLESKY, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot use PETSc SBAIJ matrices with PaStiX LU, use AIJ matrix"); 505*688c8ee7SFlorent Pruvost PetscCall(MatGetFactor_pastix(A, ftype, F, MATSEQSBAIJ)); 5063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 5073bf14a46SMatthew Knepley } 508f7a08781SBarry Smith 509d1f0640dSPierre Jolivet PETSC_INTERN PetscErrorCode MatSolverTypeRegister_Pastix(void) 510d71ae5a4SJacob Faibussowitsch { 51142c9c57cSBarry Smith PetscFunctionBegin; 5129566063dSJacob Faibussowitsch PetscCall(MatSolverTypeRegister(MATSOLVERPASTIX, MATMPIAIJ, MAT_FACTOR_LU, MatGetFactor_mpiaij_pastix)); 5139566063dSJacob Faibussowitsch PetscCall(MatSolverTypeRegister(MATSOLVERPASTIX, MATSEQAIJ, MAT_FACTOR_LU, MatGetFactor_seqaij_pastix)); 5149566063dSJacob Faibussowitsch PetscCall(MatSolverTypeRegister(MATSOLVERPASTIX, MATMPISBAIJ, MAT_FACTOR_CHOLESKY, MatGetFactor_mpisbaij_pastix)); 5159566063dSJacob Faibussowitsch PetscCall(MatSolverTypeRegister(MATSOLVERPASTIX, MATSEQSBAIJ, MAT_FACTOR_CHOLESKY, MatGetFactor_seqsbaij_pastix)); 5163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 51742c9c57cSBarry Smith } 518