1 /*$Id: superlu.c,v 1.10 2001/08/15 15:56:50 bsmith Exp $*/ 2 3 /* 4 Provides an interface to the SuperLU sparse solver 5 Modified for SuperLU 2.0 by Matthew Knepley 6 */ 7 8 #include "src/mat/impls/aij/seq/aij.h" 9 10 EXTERN_C_BEGIN 11 #if defined(PETSC_USE_COMPLEX) 12 #include "zsp_defs.h" 13 #else 14 #include "dsp_defs.h" 15 #endif 16 #include "util.h" 17 EXTERN_C_END 18 19 typedef struct { 20 SuperMatrix A,B,AC,L,U; 21 int *perm_r,*perm_c,ispec,relax,panel_size; 22 double pivot_threshold; 23 NCformat *store; 24 MatStructure flg; 25 PetscTruth SuperluMatOdering; 26 27 /* A few function pointers for inheritance */ 28 int (*MatDuplicate)(Mat,MatDuplicateOption,Mat*); 29 int (*MatView)(Mat,PetscViewer); 30 int (*MatAssemblyEnd)(Mat,MatAssemblyType); 31 int (*MatLUFactorSymbolic)(Mat,IS,IS,MatFactorInfo*,Mat*); 32 int (*MatDestroy)(Mat); 33 34 /* Flag to clean up (non-global) SuperLU objects during Destroy */ 35 PetscTruth CleanUpSuperLU; 36 } Mat_SuperLU; 37 38 39 EXTERN int MatFactorInfo_SuperLU(Mat,PetscViewer); 40 EXTERN int MatLUFactorSymbolic_SuperLU(Mat,IS,IS,MatFactorInfo*,Mat*); 41 42 EXTERN_C_BEGIN 43 EXTERN int MatConvert_SuperLU_SeqAIJ(Mat,MatType,Mat*); 44 EXTERN int MatConvert_SeqAIJ_SuperLU(Mat,MatType,Mat*); 45 EXTERN_C_END 46 47 #undef __FUNCT__ 48 #define __FUNCT__ "MatDestroy_SuperLU" 49 int MatDestroy_SuperLU(Mat A) 50 { 51 int ierr; 52 Mat_SuperLU *lu = (Mat_SuperLU*)A->spptr; 53 54 PetscFunctionBegin; 55 if (lu->CleanUpSuperLU) { 56 /* We have to free the global data or SuperLU crashes (sucky design)*/ 57 /* Since we don't know if more solves on other matrices may be done 58 we cannot free the yucky SuperLU global data 59 StatFree(); 60 */ 61 62 /* Free the SuperLU datastructures */ 63 Destroy_CompCol_Permuted(&lu->AC); 64 Destroy_SuperNode_Matrix(&lu->L); 65 Destroy_CompCol_Matrix(&lu->U); 66 ierr = PetscFree(lu->B.Store);CHKERRQ(ierr); 67 ierr = PetscFree(lu->A.Store);CHKERRQ(ierr); 68 ierr = PetscFree(lu->perm_r);CHKERRQ(ierr); 69 ierr = PetscFree(lu->perm_c);CHKERRQ(ierr); 70 } 71 ierr = MatConvert_SuperLU_SeqAIJ(A,MATSEQAIJ,&A);CHKERRQ(ierr); 72 ierr = (*A->ops->destroy)(A);CHKERRQ(ierr); 73 PetscFunctionReturn(0); 74 } 75 76 #undef __FUNCT__ 77 #define __FUNCT__ "MatView_SuperLU" 78 int MatView_SuperLU(Mat A,PetscViewer viewer) 79 { 80 int ierr; 81 PetscTruth isascii; 82 PetscViewerFormat format; 83 Mat_SuperLU *lu=(Mat_SuperLU*)(A->spptr); 84 85 PetscFunctionBegin; 86 ierr = (*lu->MatView)(A,viewer);CHKERRQ(ierr); 87 88 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);CHKERRQ(ierr); 89 if (isascii) { 90 ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr); 91 if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) { 92 ierr = MatFactorInfo_SuperLU(A,viewer);CHKERRQ(ierr); 93 } 94 } 95 PetscFunctionReturn(0); 96 } 97 98 #undef __FUNCT__ 99 #define __FUNCT__ "MatAssemblyEnd_SuperLU" 100 int MatAssemblyEnd_SuperLU(Mat A,MatAssemblyType mode) { 101 int ierr; 102 Mat_SuperLU *lu=(Mat_SuperLU*)(A->spptr); 103 104 PetscFunctionBegin; 105 ierr = (*lu->MatAssemblyEnd)(A,mode);CHKERRQ(ierr); 106 107 lu->MatLUFactorSymbolic = A->ops->lufactorsymbolic; 108 A->ops->lufactorsymbolic = MatLUFactorSymbolic_SuperLU; 109 PetscFunctionReturn(0); 110 } 111 112 #include "src/mat/impls/dense/seq/dense.h" 113 #undef __FUNCT__ 114 #define __FUNCT__ "MatCreateNull_SuperLU" 115 int MatCreateNull_SuperLU(Mat A,Mat *nullMat) 116 { 117 Mat_SuperLU *lu = (Mat_SuperLU*)A->spptr; 118 int numRows = A->m,numCols = A->n; 119 SCformat *Lstore; 120 int numNullCols,size; 121 #if defined(PETSC_USE_COMPLEX) 122 doublecomplex *nullVals,*workVals; 123 #else 124 PetscScalar *nullVals,*workVals; 125 #endif 126 int row,newRow,col,newCol,block,b,ierr; 127 128 PetscFunctionBegin; 129 PetscValidHeaderSpecific(A,MAT_COOKIE); 130 PetscValidPointer(nullMat); 131 if (!A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Unfactored matrix"); 132 numNullCols = numCols - numRows; 133 if (numNullCols < 0) SETERRQ(PETSC_ERR_ARG_WRONG,"Function only applies to underdetermined problems"); 134 /* Create the null matrix */ 135 ierr = MatCreateSeqDense(A->comm,numRows,numNullCols,PETSC_NULL,nullMat);CHKERRQ(ierr); 136 if (numNullCols == 0) { 137 ierr = MatAssemblyBegin(*nullMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 138 ierr = MatAssemblyEnd(*nullMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 139 PetscFunctionReturn(0); 140 } 141 #if defined(PETSC_USE_COMPLEX) 142 nullVals = (doublecomplex*)((Mat_SeqDense*)(*nullMat)->data)->v; 143 #else 144 nullVals = ((Mat_SeqDense*)(*nullMat)->data)->v; 145 #endif 146 /* Copy in the columns */ 147 Lstore = (SCformat*)lu->L.Store; 148 for(block = 0; block <= Lstore->nsuper; block++) { 149 newRow = Lstore->sup_to_col[block]; 150 size = Lstore->sup_to_col[block+1] - Lstore->sup_to_col[block]; 151 for(col = Lstore->rowind_colptr[newRow]; col < Lstore->rowind_colptr[newRow+1]; col++) { 152 newCol = Lstore->rowind[col]; 153 if (newCol >= numRows) { 154 for(b = 0; b < size; b++) 155 #if defined(PETSC_USE_COMPLEX) 156 nullVals[(newCol-numRows)*numRows+newRow+b] = ((doublecomplex*)Lstore->nzval)[Lstore->nzval_colptr[newRow+b]+col]; 157 #else 158 nullVals[(newCol-numRows)*numRows+newRow+b] = ((double*)Lstore->nzval)[Lstore->nzval_colptr[newRow+b]+col]; 159 #endif 160 } 161 } 162 } 163 /* Permute rhs to form P^T_c B */ 164 ierr = PetscMalloc(numRows*sizeof(double),&workVals);CHKERRQ(ierr); 165 for(b = 0; b < numNullCols; b++) { 166 for(row = 0; row < numRows; row++) workVals[lu->perm_c[row]] = nullVals[b*numRows+row]; 167 for(row = 0; row < numRows; row++) nullVals[b*numRows+row] = workVals[row]; 168 } 169 /* Backward solve the upper triangle A x = b */ 170 for(b = 0; b < numNullCols; b++) { 171 #if defined(PETSC_USE_COMPLEX) 172 sp_ztrsv("L","T","U",&lu->L,&lu->U,&nullVals[b*numRows],&ierr); 173 #else 174 sp_dtrsv("L","T","U",&lu->L,&lu->U,&nullVals[b*numRows],&ierr); 175 #endif 176 if (ierr < 0) 177 SETERRQ1(PETSC_ERR_ARG_WRONG,"The argument %d was invalid",-ierr); 178 } 179 ierr = PetscFree(workVals);CHKERRQ(ierr); 180 181 ierr = MatAssemblyBegin(*nullMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 182 ierr = MatAssemblyEnd(*nullMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 183 PetscFunctionReturn(0); 184 } 185 186 #undef __FUNCT__ 187 #define __FUNCT__ "MatSolve_SuperLU" 188 int MatSolve_SuperLU(Mat A,Vec b,Vec x) 189 { 190 Mat_SuperLU *lu = (Mat_SuperLU*)A->spptr; 191 PetscScalar *array; 192 int m,ierr; 193 194 PetscFunctionBegin; 195 ierr = VecGetLocalSize(b,&m);CHKERRQ(ierr); 196 ierr = VecCopy(b,x);CHKERRQ(ierr); 197 ierr = VecGetArray(x,&array);CHKERRQ(ierr); 198 /* Create the Rhs */ 199 lu->B.Stype = SLU_DN; 200 lu->B.Mtype = SLU_GE; 201 lu->B.nrow = m; 202 lu->B.ncol = 1; 203 ((DNformat*)lu->B.Store)->lda = m; 204 ((DNformat*)lu->B.Store)->nzval = array; 205 #if defined(PETSC_USE_COMPLEX) 206 lu->B.Dtype = SLU_Z; 207 zgstrs("T",&lu->L,&lu->U,lu->perm_r,lu->perm_c,&lu->B,&ierr); 208 #else 209 lu->B.Dtype = SLU_D; 210 dgstrs("T",&lu->L,&lu->U,lu->perm_r,lu->perm_c,&lu->B,&ierr); 211 #endif 212 if (ierr < 0) SETERRQ1(PETSC_ERR_ARG_WRONG,"The diagonal element of row %d was invalid",-ierr); 213 ierr = VecRestoreArray(x,&array);CHKERRQ(ierr); 214 PetscFunctionReturn(0); 215 } 216 217 static int StatInitCalled = 0; 218 219 #undef __FUNCT__ 220 #define __FUNCT__ "MatLUFactorNumeric_SuperLU" 221 int MatLUFactorNumeric_SuperLU(Mat A,Mat *F) 222 { 223 Mat_SeqAIJ *aa = (Mat_SeqAIJ*)(A)->data; 224 Mat_SuperLU *lu = (Mat_SuperLU*)(*F)->spptr; 225 int *etree,ierr; 226 PetscTruth flag; 227 228 PetscFunctionBegin; 229 /* Create the SuperMatrix for A^T: 230 Since SuperLU only likes column-oriented matrices,we pass it the transpose, 231 and then solve A^T X = B in MatSolve(). 232 */ 233 234 if ( lu->flg == DIFFERENT_NONZERO_PATTERN){ /* first numerical factorization */ 235 lu->A.Stype = SLU_NC; 236 #if defined(PETSC_USE_COMPLEX) 237 lu->A.Dtype = SLU_Z; 238 #else 239 lu->A.Dtype = SLU_D; 240 #endif 241 lu->A.Mtype = SLU_GE; 242 lu->A.nrow = A->n; 243 lu->A.ncol = A->m; 244 245 ierr = PetscMalloc(sizeof(NCformat),&lu->store);CHKERRQ(ierr); 246 ierr = PetscMalloc(sizeof(DNformat),&lu->B.Store);CHKERRQ(ierr); 247 } 248 lu->store->nnz = aa->nz; 249 lu->store->colptr = aa->i; 250 lu->store->rowind = aa->j; 251 lu->store->nzval = aa->a; 252 lu->A.Store = lu->store; 253 254 /* Set SuperLU options */ 255 lu->relax = sp_ienv(2); 256 lu->panel_size = sp_ienv(1); 257 /* We have to initialize global data or SuperLU crashes (sucky design) */ 258 if (!StatInitCalled) { 259 StatInit(lu->panel_size,lu->relax); 260 } 261 StatInitCalled++; 262 263 ierr = PetscOptionsBegin(A->comm,A->prefix,"SuperLU Options","Mat");CHKERRQ(ierr); 264 /* use SuperLU mat ordeing */ 265 ierr = PetscOptionsInt("-mat_superlu_ordering","SuperLU ordering type (one of 0, 1, 2, 3)\n 0: natural ordering;\n 1: MMD applied to A'*A;\n 2: MMD applied to A'+A;\n 3: COLAMD, approximate minimum degree column ordering","None",lu->ispec,&lu->ispec,&flag);CHKERRQ(ierr); 266 if (flag) { 267 get_perm_c(lu->ispec, &lu->A, lu->perm_c); 268 lu->SuperluMatOdering = PETSC_TRUE; 269 } 270 PetscOptionsEnd(); 271 272 /* Create the elimination tree */ 273 ierr = PetscMalloc(A->n*sizeof(int),&etree);CHKERRQ(ierr); 274 sp_preorder("N",&lu->A,lu->perm_c,etree,&lu->AC); 275 /* Factor the matrix */ 276 #if defined(PETSC_USE_COMPLEX) 277 zgstrf("N",&lu->AC,lu->pivot_threshold,0.0,lu->relax,lu->panel_size,etree,PETSC_NULL,0,lu->perm_r,lu->perm_c,&lu->L,&lu->U,&ierr); 278 #else 279 dgstrf("N",&lu->AC,lu->pivot_threshold,0.0,lu->relax,lu->panel_size,etree,PETSC_NULL,0,lu->perm_r,lu->perm_c,&lu->L,&lu->U,&ierr); 280 #endif 281 if (ierr < 0) { 282 SETERRQ1(PETSC_ERR_ARG_WRONG,"The diagonal element of row %d was invalid",-ierr); 283 } else if (ierr > 0) { 284 if (ierr <= A->m) { 285 SETERRQ1(PETSC_ERR_ARG_WRONG,"The diagonal element %d of U is exactly zero",ierr); 286 } else { 287 SETERRQ1(PETSC_ERR_ARG_WRONG,"Memory allocation failure after %d bytes were allocated",ierr-A->m); 288 } 289 } 290 291 /* Cleanup */ 292 ierr = PetscFree(etree);CHKERRQ(ierr); 293 294 lu->flg = SAME_NONZERO_PATTERN; 295 PetscFunctionReturn(0); 296 } 297 298 /* 299 Note the r permutation is ignored 300 */ 301 #undef __FUNCT__ 302 #define __FUNCT__ "MatLUFactorSymbolic_SuperLU" 303 int MatLUFactorSymbolic_SuperLU(Mat A,IS r,IS c,MatFactorInfo *info,Mat *F) 304 { 305 Mat B; 306 Mat_SuperLU *lu; 307 int ierr,*ca; 308 309 PetscFunctionBegin; 310 311 ierr = MatCreate(A->comm,A->m,A->n,PETSC_DETERMINE,PETSC_DETERMINE,&B);CHKERRQ(ierr); 312 ierr = MatSetType(B,MATSUPERLU);CHKERRQ(ierr); 313 ierr = MatSeqAIJSetPreallocation(B,0,PETSC_NULL);CHKERRQ(ierr); 314 315 B->ops->lufactornumeric = MatLUFactorNumeric_SuperLU; 316 B->ops->solve = MatSolve_SuperLU; 317 B->factor = FACTOR_LU; 318 B->assembled = PETSC_TRUE; /* required by -sles_view */ 319 320 lu = (Mat_SuperLU*)(B->spptr); 321 ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatCreateNull","MatCreateNull_SuperLU", 322 (void(*)(void))MatCreateNull_SuperLU);CHKERRQ(ierr); 323 324 /* Allocate the work arrays required by SuperLU (notice sizes are for the transpose) */ 325 ierr = PetscMalloc(A->n*sizeof(int),&lu->perm_r);CHKERRQ(ierr); 326 ierr = PetscMalloc(A->m*sizeof(int),&lu->perm_c);CHKERRQ(ierr); 327 328 /* use PETSc mat ordering */ 329 ierr = ISGetIndices(c,&ca);CHKERRQ(ierr); 330 ierr = PetscMemcpy(lu->perm_c,ca,A->m*sizeof(int));CHKERRQ(ierr); 331 ierr = ISRestoreIndices(c,&ca);CHKERRQ(ierr); 332 lu->SuperluMatOdering = PETSC_FALSE; 333 334 lu->pivot_threshold = info->dtcol; 335 PetscLogObjectMemory(B,(A->m+A->n)*sizeof(int)+sizeof(Mat_SuperLU)); 336 337 lu->flg = DIFFERENT_NONZERO_PATTERN; 338 lu->CleanUpSuperLU = PETSC_TRUE; 339 340 *F = B; 341 PetscFunctionReturn(0); 342 } 343 344 /* used by -sles_view */ 345 #undef __FUNCT__ 346 #define __FUNCT__ "MatFactorInfo_SuperLU" 347 int MatFactorInfo_SuperLU(Mat A,PetscViewer viewer) 348 { 349 Mat_SuperLU *lu= (Mat_SuperLU*)A->spptr; 350 int ierr; 351 352 PetscFunctionBegin; 353 ierr = PetscViewerASCIIPrintf(viewer,"SuperLU run parameters:\n");CHKERRQ(ierr); 354 if(lu->SuperluMatOdering) { 355 ierr = PetscViewerASCIIPrintf(viewer," SuperLU mat ordering: %d\n",lu->ispec);CHKERRQ(ierr); 356 } 357 PetscFunctionReturn(0); 358 } 359 360 #undef __FUNCT__ 361 #define __FUNCT__ "MatDuplicate_SuperLU" 362 int MatDuplicate_SuperLU(Mat A, MatDuplicateOption op, Mat *M) { 363 int ierr; 364 Mat_SuperLU *lu=(Mat_SuperLU *)A->spptr; 365 366 PetscFunctionBegin; 367 ierr = (*lu->MatDuplicate)(A,op,M);CHKERRQ(ierr); 368 ierr = MatConvert_SeqAIJ_SuperLU(*M,MATSUPERLU,M);CHKERRQ(ierr); 369 ierr = PetscMemcpy((*M)->spptr,lu,sizeof(Mat_SuperLU));CHKERRQ(ierr); 370 PetscFunctionReturn(0); 371 } 372 373 EXTERN_C_BEGIN 374 #undef __FUNCT__ 375 #define __FUNCT__ "MatConvert_SuperLU_SeqAIJ" 376 int MatConvert_SuperLU_SeqAIJ(Mat A,MatType type,Mat *newmat) { 377 /* This routine is only called to convert an unfactored PETSc-SuperLU matrix */ 378 /* to its base PETSc type, so we will ignore 'MatType type'. */ 379 int ierr; 380 Mat B=*newmat; 381 Mat_SuperLU *lu=(Mat_SuperLU *)A->spptr; 382 383 PetscFunctionBegin; 384 if (B != A) { 385 ierr = MatDuplicate(A,MAT_COPY_VALUES,&B);CHKERRQ(ierr); 386 } 387 /* Reset the original function pointers */ 388 B->ops->duplicate = lu->MatDuplicate; 389 B->ops->view = lu->MatView; 390 B->ops->assemblyend = lu->MatAssemblyEnd; 391 B->ops->lufactorsymbolic = lu->MatLUFactorSymbolic; 392 B->ops->destroy = lu->MatDestroy; 393 /* lu is only a function pointer stash unless we've factored the matrix, which we haven't! */ 394 ierr = PetscFree(lu);CHKERRQ(ierr); 395 ierr = PetscObjectChangeTypeName((PetscObject)B,MATSEQAIJ);CHKERRQ(ierr); 396 *newmat = B; 397 PetscFunctionReturn(0); 398 } 399 EXTERN_C_END 400 401 EXTERN_C_BEGIN 402 #undef __FUNCT__ 403 #define __FUNCT__ "MatConvert_SeqAIJ_SuperLU" 404 int MatConvert_SeqAIJ_SuperLU(Mat A,MatType type,Mat *newmat) { 405 /* This routine is only called to convert to MATSUPERLU */ 406 /* from MATSEQAIJ, so we will ignore 'MatType type'. */ 407 int ierr; 408 Mat B=*newmat; 409 Mat_SuperLU *lu; 410 411 PetscFunctionBegin; 412 if (B != A) { 413 ierr = MatDuplicate(A,MAT_COPY_VALUES,&B);CHKERRQ(ierr); 414 } 415 416 ierr = PetscNew(Mat_SuperLU,&lu);CHKERRQ(ierr); 417 lu->MatDuplicate = A->ops->duplicate; 418 lu->MatView = A->ops->view; 419 lu->MatAssemblyEnd = A->ops->assemblyend; 420 lu->MatLUFactorSymbolic = A->ops->lufactorsymbolic; 421 lu->MatDestroy = A->ops->destroy; 422 lu->CleanUpSuperLU = PETSC_FALSE; 423 424 B->spptr = (void*)lu; 425 B->ops->duplicate = MatDuplicate_SuperLU; 426 B->ops->view = MatView_SuperLU; 427 B->ops->assemblyend = MatAssemblyEnd_SuperLU; 428 B->ops->lufactorsymbolic = MatLUFactorSymbolic_SuperLU; 429 B->ops->destroy = MatDestroy_SuperLU; 430 431 ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_seqaij_superlu_C", 432 "MatConvert_SeqAIJ_SuperLU",MatConvert_SeqAIJ_SuperLU);CHKERRQ(ierr); 433 ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_superlu_seqaij_C", 434 "MatConvert_SuperLU_SeqAIJ",MatConvert_SuperLU_SeqAIJ);CHKERRQ(ierr); 435 PetscLogInfo(0,"Using SuperLU for SeqAIJ LU factorization and solves."); 436 ierr = PetscObjectChangeTypeName((PetscObject)B,MATSUPERLU);CHKERRQ(ierr); 437 *newmat = B; 438 PetscFunctionReturn(0); 439 } 440 EXTERN_C_END 441 442 /*MC 443 MATSUPERLU - MATSUPERLU = "superlu" - A matrix type providing direct solvers (LU) for sequential matrices 444 via the external package SuperLU. 445 446 If SuperLU is installed (see the manual for 447 instructions on how to declare the existence of external packages), 448 a matrix type can be constructed which invokes SuperLU solvers. 449 After calling MatCreate(...,A), simply call MatSetType(A,MATSUPERLU). 450 This matrix type is only supported for double precision real. 451 452 This matrix inherits from MATSEQAIJ. As a result, MatSeqAIJSetPreallocation is 453 supported for this matrix type. One can also call MatConvert for an inplace conversion to or from 454 the MATSEQAIJ type without data copy. 455 456 Options Database Keys: 457 + -mat_type superlu - sets the matrix type to "superlu" during a call to MatSetFromOptions() 458 - -mat_superlu_ordering <0,1,2,3> - 0: natural ordering, 459 1: MMD applied to A'*A, 460 2: MMD applied to A'+A, 461 3: COLAMD, approximate minimum degree column ordering 462 463 Level: beginner 464 465 .seealso: PCLU 466 M*/ 467 468 EXTERN_C_BEGIN 469 #undef __FUNCT__ 470 #define __FUNCT__ "MatCreate_SuperLU" 471 int MatCreate_SuperLU(Mat A) { 472 int ierr; 473 474 PetscFunctionBegin; 475 /* Change type name before calling MatSetType to force proper construction of SeqAIJ and SUPERLU types */ 476 ierr = PetscObjectChangeTypeName((PetscObject)A,MATSUPERLU);CHKERRQ(ierr); 477 ierr = MatSetType(A,MATSEQAIJ);CHKERRQ(ierr); 478 ierr = MatConvert_SeqAIJ_SuperLU(A,MATSUPERLU,&A);CHKERRQ(ierr); 479 PetscFunctionReturn(0); 480 } 481 EXTERN_C_END 482