1 #include <../src/mat/impls/aij/seq/aij.h> 2 #include <../src/mat/impls/aij/mpi/mpiaij.h> 3 #include <StrumpackSparseSolver.h> 4 5 /* 6 GLOBAL - The sparse matrix and right hand side are all stored initially on process 0. Should be called centralized 7 DISTRIBUTED - The sparse matrix and right hand size are initially stored across the entire MPI communicator. 8 */ 9 typedef enum {GLOBAL, DISTRIBUTED} STRUMPACK_MatInputMode; 10 const char *STRUMPACK_MatInputModes[] = {"GLOBAL","DISTRIBUTED","STRUMPACK_MatInputMode","PETSC_",0}; 11 12 typedef struct { 13 STRUMPACK_SparseSolver S; 14 STRUMPACK_MatInputMode MatInputMode; 15 } STRUMPACK_data; 16 17 extern PetscErrorCode MatFactorInfo_STRUMPACK_MPI(Mat,PetscViewer); 18 extern PetscErrorCode MatLUFactorNumeric_STRUMPACK_MPI(Mat,Mat,const MatFactorInfo*); 19 extern PetscErrorCode MatDestroy_STRUMPACK_MPI(Mat); 20 extern PetscErrorCode MatView_STRUMPACK_MPI(Mat,PetscViewer); 21 extern PetscErrorCode MatSolve_STRUMPACK_MPI(Mat,Vec,Vec); 22 extern PetscErrorCode MatLUFactorSymbolic_STRUMPACK_MPI(Mat,Mat,IS,IS,const MatFactorInfo*); 23 extern PetscErrorCode MatDestroy_MPIAIJ(Mat); 24 25 #undef __FUNCT__ 26 #define __FUNCT__ "MatGetDiagonal_STRUMPACK_MPI" 27 PetscErrorCode MatGetDiagonal_STRUMPACK_MPI(Mat A,Vec v) 28 { 29 PetscFunctionBegin; 30 SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Mat type: STRUMPACK_MPI factor"); 31 PetscFunctionReturn(0); 32 } 33 34 #undef __FUNCT__ 35 #define __FUNCT__ "MatDestroy_STRUMPACK_MPI" 36 PetscErrorCode MatDestroy_STRUMPACK_MPI(Mat A) 37 { 38 STRUMPACK_data *sp = (STRUMPACK_data*)A->spptr; 39 PetscErrorCode ierr; 40 PetscBool flg; 41 42 PetscFunctionBegin; 43 /* Deallocate STRUMPACK_MPI storage */ 44 PetscStackCall("STRUMPACK_destroy",STRUMPACK_destroy(&(sp->S))); 45 ierr = PetscFree(A->spptr);CHKERRQ(ierr); 46 ierr = PetscObjectTypeCompare((PetscObject)A,MATSEQAIJ,&flg);CHKERRQ(ierr); 47 if (flg) { 48 ierr = MatDestroy_SeqAIJ(A);CHKERRQ(ierr); 49 } else { 50 ierr = MatDestroy_MPIAIJ(A);CHKERRQ(ierr); 51 } 52 PetscFunctionReturn(0); 53 } 54 55 #undef __FUNCT__ 56 #define __FUNCT__ "MatSolve_STRUMPACK_MPI" 57 PetscErrorCode MatSolve_STRUMPACK_MPI(Mat A,Vec b_mpi,Vec x) 58 { 59 STRUMPACK_data *sp = (STRUMPACK_data*)A->spptr; 60 STRUMPACK_RETURN_CODE sp_err; 61 PetscErrorCode ierr; 62 PetscMPIInt size; 63 PetscInt N=A->cmap->N; 64 const PetscScalar *bptr; 65 PetscScalar *xptr; 66 Vec x_seq,b_seq; 67 IS iden; 68 VecScatter scat; 69 70 PetscFunctionBegin; 71 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRQ(ierr); 72 if (size > 1 && sp->MatInputMode == GLOBAL) { 73 ierr = VecCreateSeq(PETSC_COMM_SELF,N,&x_seq);CHKERRQ(ierr); 74 ierr = VecGetArray(x_seq,&xptr);CHKERRQ(ierr); 75 /* global mat input, convert b to b_seq */ 76 ierr = VecCreateSeq(PETSC_COMM_SELF,N,&b_seq);CHKERRQ(ierr); 77 ierr = ISCreateStride(PETSC_COMM_SELF,N,0,1,&iden);CHKERRQ(ierr); 78 ierr = VecScatterCreate(b_mpi,iden,b_seq,iden,&scat);CHKERRQ(ierr); 79 ierr = ISDestroy(&iden);CHKERRQ(ierr); 80 ierr = VecScatterBegin(scat,b_mpi,b_seq,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 81 ierr = VecScatterEnd(scat,b_mpi,b_seq,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 82 ierr = VecGetArrayRead(b_seq,&bptr);CHKERRQ(ierr); 83 } else { /* size==1 || distributed mat input */ 84 ierr = VecGetArray(x,&xptr);CHKERRQ(ierr); 85 ierr = VecGetArrayRead(b_mpi,&bptr);CHKERRQ(ierr); 86 } 87 88 PetscStackCall("STRUMPACK_solve",sp_err = STRUMPACK_solve(sp->S,(PetscScalar*)bptr,xptr,0)); 89 90 if (sp_err != STRUMPACK_SUCCESS) { 91 if (sp_err == STRUMPACK_MATRIX_NOT_SET) { 92 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"STRUMPACK error: matrix was not set"); 93 } else if (sp_err == STRUMPACK_REORDERING_ERROR) { 94 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"STRUMPACK error: matrix reordering failed"); 95 } else { 96 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"STRUMPACK error: solve failed"); 97 } 98 } 99 100 if (size > 1 && sp->MatInputMode == GLOBAL) { 101 ierr = VecRestoreArrayRead(b_seq,&bptr);CHKERRQ(ierr); 102 ierr = VecDestroy(&b_seq);CHKERRQ(ierr); 103 /* convert seq x to mpi x */ 104 ierr = VecRestoreArray(x_seq,&xptr);CHKERRQ(ierr); 105 ierr = VecScatterBegin(scat,x_seq,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 106 ierr = VecScatterEnd(scat,x_seq,x,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 107 ierr = VecScatterDestroy(&scat);CHKERRQ(ierr); 108 ierr = VecDestroy(&x_seq);CHKERRQ(ierr); 109 } else { 110 ierr = VecRestoreArray(x,&xptr);CHKERRQ(ierr); 111 ierr = VecRestoreArrayRead(b_mpi,&bptr);CHKERRQ(ierr); 112 } 113 114 PetscFunctionReturn(0); 115 } 116 117 #undef __FUNCT__ 118 #define __FUNCT__ "MatMatSolve_STRUMPACK_MPI" 119 PetscErrorCode MatMatSolve_STRUMPACK_MPI(Mat A,Mat B_mpi,Mat X) 120 { 121 PetscErrorCode ierr; 122 PetscBool flg; 123 124 PetscFunctionBegin; 125 ierr = PetscObjectTypeCompareAny((PetscObject)B_mpi,&flg,MATSEQDENSE,MATMPIDENSE,NULL);CHKERRQ(ierr); 126 if (!flg) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"Matrix B must be MATDENSE matrix"); 127 ierr = PetscObjectTypeCompareAny((PetscObject)X,&flg,MATSEQDENSE,MATMPIDENSE,NULL);CHKERRQ(ierr); 128 if (!flg) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"Matrix X must be MATDENSE matrix"); 129 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"MatMatSolve_STRUMPACK_MPI() is not implemented yet"); 130 PetscFunctionReturn(0); 131 } 132 133 134 #undef __FUNCT__ 135 #define __FUNCT__ "MatLUFactorNumeric_STRUMPACK_MPI" 136 PetscErrorCode MatLUFactorNumeric_STRUMPACK_MPI(Mat F,Mat A,const MatFactorInfo *info) 137 { 138 STRUMPACK_data *sp = (STRUMPACK_data*)F->spptr; 139 STRUMPACK_RETURN_CODE sp_err; 140 Mat *tseq,A_seq = NULL; 141 Mat_SeqAIJ *A_d,*A_o; 142 PetscErrorCode ierr; 143 PetscInt M=A->rmap->N,m=A->rmap->n,N=A->cmap->N; 144 PetscMPIInt size; 145 IS isrow; 146 147 PetscFunctionBegin; 148 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRQ(ierr); 149 150 if (sp->MatInputMode == GLOBAL) { /* global mat input */ 151 if (size > 1) { /* convert mpi A to seq mat A */ 152 ierr = ISCreateStride(PETSC_COMM_SELF,M,0,1,&isrow);CHKERRQ(ierr); 153 ierr = MatGetSubMatrices(A,1,&isrow,&isrow,MAT_INITIAL_MATRIX,&tseq);CHKERRQ(ierr); 154 ierr = ISDestroy(&isrow);CHKERRQ(ierr); 155 A_seq = *tseq; 156 ierr = PetscFree(tseq);CHKERRQ(ierr); 157 A_d = (Mat_SeqAIJ*)A_seq->data; 158 } else { 159 PetscBool flg; 160 ierr = PetscObjectTypeCompare((PetscObject)A,MATMPIAIJ,&flg);CHKERRQ(ierr); 161 if (flg) { 162 Mat_MPIAIJ *At = (Mat_MPIAIJ*)A->data; 163 A = At->A; 164 } 165 A_d = (Mat_SeqAIJ*)A->data; 166 } 167 PetscStackCall("STRUMPACK_set_csr_matrix",STRUMPACK_set_csr_matrix(sp->S,&N,A_d->i,A_d->j,A_d->a,0)); 168 } else { /* distributed mat input */ 169 Mat_MPIAIJ *mat = (Mat_MPIAIJ*)A->data; 170 A_d = (Mat_SeqAIJ*)(mat->A)->data; 171 A_o = (Mat_SeqAIJ*)(mat->B)->data; 172 PetscStackCall("STRUMPACK_set_MPIAIJ_matrix",STRUMPACK_set_MPIAIJ_matrix( 173 sp->S,&m,A_d->i,A_d->j,A_d->a,A_o->i,A_o->j,A_o->a,mat->garray)); 174 } 175 176 /* Reorder and Factor the matrix. */ 177 /* TODO figure out how to avoid reorder if the matrix values changed, but the pattern remains the same. */ 178 PetscStackCall("STRUMPACK_reorder",sp_err = STRUMPACK_reorder(sp->S)); 179 PetscStackCall("STRUMPACK_factor",sp_err = STRUMPACK_factor(sp->S)); 180 if (sp_err != STRUMPACK_SUCCESS) { 181 if (sp_err == STRUMPACK_MATRIX_NOT_SET) { 182 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"STRUMPACK error: matrix was not set"); 183 } else if (sp_err == STRUMPACK_REORDERING_ERROR) { 184 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"STRUMPACK error: matrix reordering failed"); 185 } else { 186 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"STRUMPACK error: factorization failed"); 187 } 188 } 189 190 if (sp->MatInputMode == GLOBAL && size > 1) { 191 ierr = MatDestroy(&A_seq);CHKERRQ(ierr); 192 } 193 194 PetscFunctionReturn(0); 195 } 196 197 #undef __FUNCT__ 198 #define __FUNCT__ "MatLUFactorSymbolic_STRUMPACK_MPI" 199 PetscErrorCode MatLUFactorSymbolic_STRUMPACK_MPI(Mat F,Mat A,IS r,IS c,const MatFactorInfo *info) 200 { 201 PetscFunctionBegin; 202 F->ops->lufactornumeric = MatLUFactorNumeric_STRUMPACK_MPI; 203 F->ops->solve = MatSolve_STRUMPACK_MPI; 204 F->ops->matsolve = MatMatSolve_STRUMPACK_MPI; 205 PetscFunctionReturn(0); 206 } 207 208 #undef __FUNCT__ 209 #define __FUNCT__ "MatFactorGetSolverPackage_aij_strumpack_mpi" 210 PetscErrorCode MatFactorGetSolverPackage_aij_strumpack_mpi(Mat A,const MatSolverPackage *type) 211 { 212 PetscFunctionBegin; 213 *type = MATSOLVERSTRUMPACK_MPI; 214 PetscFunctionReturn(0); 215 } 216 217 #undef __FUNCT__ 218 #define __FUNCT__ "MatGetFactor_aij_strumpack_mpi" 219 PETSC_EXTERN PetscErrorCode MatGetFactor_aij_strumpack_mpi(Mat A,MatFactorType ftype,Mat *F) 220 { 221 Mat B; 222 STRUMPACK_data *sp; 223 PetscErrorCode ierr; 224 PetscInt M=A->rmap->N,N=A->cmap->N; 225 PetscMPIInt size; 226 STRUMPACK_INTERFACE iface; 227 PetscBool verb; 228 PetscInt argc; 229 char **args; 230 231 PetscFunctionBegin; 232 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRQ(ierr); 233 234 /* Create the factorization matrix */ 235 ierr = MatCreate(PetscObjectComm((PetscObject)A),&B);CHKERRQ(ierr); 236 ierr = MatSetSizes(B,A->rmap->n,A->cmap->n,M,N);CHKERRQ(ierr); 237 ierr = MatSetType(B,((PetscObject)A)->type_name);CHKERRQ(ierr); 238 ierr = MatSeqAIJSetPreallocation(B,0,NULL); 239 ierr = MatMPIAIJSetPreallocation(B,0,NULL,0,NULL);CHKERRQ(ierr); 240 241 B->ops->lufactorsymbolic = MatLUFactorSymbolic_STRUMPACK_MPI; 242 B->ops->view = MatView_STRUMPACK_MPI; 243 B->ops->destroy = MatDestroy_STRUMPACK_MPI; 244 B->ops->getdiagonal = MatGetDiagonal_STRUMPACK_MPI; 245 246 ierr = PetscObjectComposeFunction((PetscObject)B,"MatFactorGetSolverPackage_C",MatFactorGetSolverPackage_aij_strumpack_mpi);CHKERRQ(ierr); 247 248 B->factortype = MAT_FACTOR_LU; 249 250 ierr = PetscNewLog(B,&sp);CHKERRQ(ierr); 251 B->spptr = sp; 252 253 ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)A),((PetscObject)A)->prefix,"STRUMPACK_MPI Options","Mat");CHKERRQ(ierr); 254 255 sp->MatInputMode = DISTRIBUTED; 256 iface = STRUMPACK_MPI_DIST; 257 258 ierr = PetscOptionsEnum("-mat_strumpack_mpi_matinput","Matrix input mode (global or distributed)","None",STRUMPACK_MatInputModes, 259 (PetscEnum)sp->MatInputMode,(PetscEnum*)&sp->MatInputMode,NULL);CHKERRQ(ierr); 260 if (sp->MatInputMode == DISTRIBUTED && size == 1) sp->MatInputMode = GLOBAL; 261 if (sp->MatInputMode == DISTRIBUTED) { 262 iface = STRUMPACK_MPI_DIST; 263 } else if (sp->MatInputMode == GLOBAL) { 264 iface = STRUMPACK_MPI; 265 } 266 if (PetscLogPrintInfo) verb = PETSC_TRUE; 267 else verb = PETSC_FALSE; 268 ierr = PetscOptionsBool("-mat_strumpack_verbose","Print STRUMPACK information","None",verb,&verb,NULL);CHKERRQ(ierr); 269 270 PetscOptionsEnd(); 271 272 PetscGetArgs(&argc,&args); 273 274 #if defined(PETSC_USE_64BIT_INDICES) 275 #if defined(PETSC_USE_COMPLEX) 276 #if defined(PETSC_USE_REAL_SINGLE) 277 PetscStackCall("STRUMPACK_init",STRUMPACK_init(&(sp->S),PetscObjectComm((PetscObject)A),STRUMPACK_FLOATCOMPLEX_64,iface,argc,args,verb)); 278 #else 279 PetscStackCall("STRUMPACK_init",STRUMPACK_init(&(sp->S),PetscObjectComm((PetscObject)A),STRUMPACK_DOUBLECOMPLEX_64,iface,argc,args,verb)); 280 #endif 281 #else 282 #if defined(PETSC_USE_REAL_SINGLE) 283 PetscStackCall("STRUMPACK_init",STRUMPACK_init(&(sp->S),PetscObjectComm((PetscObject)A),STRUMPACK_FLOAT_64,iface,argc,args,verb)); 284 #else 285 PetscStackCall("STRUMPACK_init",STRUMPACK_init(&(sp->S),PetscObjectComm((PetscObject)A),STRUMPACK_DOUBLE_64,iface,argc,args,verb)); 286 #endif 287 #endif 288 #else 289 #if defined(PETSC_USE_COMPLEX) 290 #if defined(PETSC_USE_REAL_SINGLE) 291 PetscStackCall("STRUMPACK_init",STRUMPACK_init(&(sp->S),PetscObjectComm((PetscObject)A),STRUMPACK_FLOATCOMPLEX,iface,argc,args,verb)); 292 #else 293 PetscStackCall("STRUMPACK_init",STRUMPACK_init(&(sp->S),PetscObjectComm((PetscObject)A),STRUMPACK_DOUBLECOMPLEX,iface,argc,args,verb)); 294 #endif 295 #else 296 #if defined(PETSC_USE_REAL_SINGLE) 297 PetscStackCall("STRUMPACK_init",STRUMPACK_init(&(sp->S),PetscObjectComm((PetscObject)A),STRUMPACK_FLOAT,iface,argc,args,verb)); 298 #else 299 PetscStackCall("STRUMPACK_init",STRUMPACK_init(&(sp->S),PetscObjectComm((PetscObject)A),STRUMPACK_DOUBLE,iface,argc,args,verb)); 300 #endif 301 #endif 302 #endif 303 PetscStackCall("STRUMPACK_set_from_options",STRUMPACK_set_from_options(sp->S)); 304 305 *F = B; 306 PetscFunctionReturn(0); 307 } 308 309 #undef __FUNCT__ 310 #define __FUNCT__ "MatSolverPackageRegister_STRUMPACK_MPI" 311 PETSC_EXTERN PetscErrorCode MatSolverPackageRegister_STRUMPACK_MPI(void) 312 { 313 PetscErrorCode ierr; 314 315 PetscFunctionBegin; 316 ierr = MatSolverPackageRegister(MATSOLVERSTRUMPACK_MPI,MATMPIAIJ,MAT_FACTOR_LU,MatGetFactor_aij_strumpack_mpi);CHKERRQ(ierr); 317 ierr = MatSolverPackageRegister(MATSOLVERSTRUMPACK_MPI,MATSEQAIJ,MAT_FACTOR_LU,MatGetFactor_aij_strumpack_mpi);CHKERRQ(ierr); 318 PetscFunctionReturn(0); 319 } 320 321 #undef __FUNCT__ 322 #define __FUNCT__ "MatFactorInfo_STRUMPACK_MPI" 323 PetscErrorCode MatFactorInfo_STRUMPACK_MPI(Mat A,PetscViewer viewer) 324 { 325 PetscErrorCode ierr; 326 327 PetscFunctionBegin; 328 /* check if matrix is strumpack type */ 329 if (A->ops->solve != MatSolve_STRUMPACK_MPI) PetscFunctionReturn(0); 330 ierr = PetscViewerASCIIPrintf(viewer,"STRUMPACK_MPI sparse solver!\n");CHKERRQ(ierr); 331 PetscFunctionReturn(0); 332 } 333 334 #undef __FUNCT__ 335 #define __FUNCT__ "MatView_STRUMPACK_MPI" 336 PetscErrorCode MatView_STRUMPACK_MPI(Mat A,PetscViewer viewer) 337 { 338 PetscErrorCode ierr; 339 PetscBool iascii; 340 PetscViewerFormat format; 341 342 PetscFunctionBegin; 343 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 344 if (iascii) { 345 ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr); 346 if (format == PETSC_VIEWER_ASCII_INFO) { 347 ierr = MatFactorInfo_STRUMPACK_MPI(A,viewer);CHKERRQ(ierr); 348 } 349 } 350 PetscFunctionReturn(0); 351 } 352 353 354 /*MC 355 MATSOLVERSSTRUMPACK_MPI - Parallel direct solver package for LU factorization 356 357 Use ./configure --download-strumpack --download-parmetis --download-metis --download-ptscotch (and ScaLAPACK?/BLACS?) to have PETSc installed with SuperLU_DIST 358 359 Use -pc_type lu -pc_factor_mat_solver_package strumpack to us this direct solver 360 361 Works with AIJ matrices 362 363 .seealso: PCLU 364 365 .seealso: PCFactorSetMatSolverPackage(), MatSolverPackage 366 367 M*/ 368 369