1 /* 2 Provides an interface to the LUSOL package of .... 3 4 */ 5 #include "src/mat/impls/aij/seq/aij.h" 6 7 #if defined(PETSC_HAVE_FORTRAN_UNDERSCORE) 8 #define LU1FAC lu1fac_ 9 #define LU6SOL lu6sol_ 10 #define M1PAGE m1page_ 11 #define M5SETX m5setx_ 12 #define M6RDEL m6rdel_ 13 #elif !defined(PETSC_HAVE_FORTRAN_CAPS) 14 #define LU1FAC lu1fac 15 #define LU6SOL lu6sol 16 #define M1PAGE m1page 17 #define M5SETX m5setx 18 #define M6RDEL m6rdel 19 #endif 20 21 EXTERN_C_BEGIN 22 /* 23 Dummy symbols that the MINOS files mi25bfac.f and mi15blas.f may require 24 */ 25 void PETSC_STDCALL M1PAGE() { 26 ; 27 } 28 void PETSC_STDCALL M5SETX() { 29 ; 30 } 31 32 void PETSC_STDCALL M6RDEL() { 33 ; 34 } 35 36 extern void PETSC_STDCALL LU1FAC (int *m, int *n, int *nnz, int *size, int *luparm, 37 double *parmlu, double *data, int *indc, int *indr, 38 int *rowperm, int *colperm, int *collen, int *rowlen, 39 int *colstart, int *rowstart, int *rploc, int *cploc, 40 int *rpinv, int *cpinv, double *w, int *inform); 41 42 extern void PETSC_STDCALL LU6SOL (int *mode, int *m, int *n, double *rhs, double *x, 43 int *size, int *luparm, double *parmlu, double *data, 44 int *indc, int *indr, int *rowperm, int *colperm, 45 int *collen, int *rowlen, int *colstart, int *rowstart, 46 int *inform); 47 EXTERN_C_END 48 49 EXTERN PetscErrorCode MatDuplicate_LUSOL(Mat,MatDuplicateOption,Mat*); 50 51 typedef struct { 52 double *data; 53 int *indc; 54 int *indr; 55 56 int *ip; 57 int *iq; 58 int *lenc; 59 int *lenr; 60 int *locc; 61 int *locr; 62 int *iploc; 63 int *iqloc; 64 int *ipinv; 65 int *iqinv; 66 double *mnsw; 67 double *mnsv; 68 69 double elbowroom; 70 double luroom; /* Extra space allocated when factor fails */ 71 double parmlu[30]; /* Input/output to LUSOL */ 72 73 int n; /* Number of rows/columns in matrix */ 74 int nz; /* Number of nonzeros */ 75 int nnz; /* Number of nonzeros allocated for factors */ 76 int luparm[30]; /* Input/output to LUSOL */ 77 78 int (*MatDuplicate)(Mat,MatDuplicateOption,Mat*); 79 int (*MatLUFactorSymbolic)(Mat,IS,IS,MatFactorInfo*,Mat*); 80 int (*MatDestroy)(Mat); 81 PetscTruth CleanUpLUSOL; 82 83 } Mat_LUSOL; 84 85 /* LUSOL input/Output Parameters (Description uses C-style indexes 86 * 87 * Input parameters Typical value 88 * 89 * luparm(0) = nout File number for printed messages. 6 90 * luparm(1) = lprint Print level. 0 91 * < 0 suppresses output. 92 * = 0 gives error messages. 93 * = 1 gives debug output from some of the 94 * other routines in LUSOL. 95 * >= 2 gives the pivot row and column and the 96 * no. of rows and columns involved at 97 * each elimination step in lu1fac. 98 * luparm(2) = maxcol lu1fac: maximum number of columns 5 99 * searched allowed in a Markowitz-type 100 * search for the next pivot element. 101 * For some of the factorization, the 102 * number of rows searched is 103 * maxrow = maxcol - 1. 104 * 105 * 106 * Output parameters 107 * 108 * luparm(9) = inform Return code from last call to any LU routine. 109 * luparm(10) = nsing No. of singularities marked in the 110 * output array w(*). 111 * luparm(11) = jsing Column index of last singularity. 112 * luparm(12) = minlen Minimum recommended value for lena. 113 * luparm(13) = maxlen ? 114 * luparm(14) = nupdat No. of updates performed by the lu8 routines. 115 * luparm(15) = nrank No. of nonempty rows of U. 116 * luparm(16) = ndens1 No. of columns remaining when the density of 117 * the matrix being factorized reached dens1. 118 * luparm(17) = ndens2 No. of columns remaining when the density of 119 * the matrix being factorized reached dens2. 120 * luparm(18) = jumin The column index associated with dumin. 121 * luparm(19) = numl0 No. of columns in initial L. 122 * luparm(20) = lenl0 Size of initial L (no. of nonzeros). 123 * luparm(21) = lenu0 Size of initial U. 124 * luparm(22) = lenl Size of current L. 125 * luparm(23) = lenu Size of current U. 126 * luparm(24) = lrow Length of row file. 127 * luparm(25) = ncp No. of compressions of LU data structures. 128 * luparm(26) = mersum lu1fac: sum of Markowitz merit counts. 129 * luparm(27) = nutri lu1fac: triangular rows in U. 130 * luparm(28) = nltri lu1fac: triangular rows in L. 131 * luparm(29) = 132 * 133 * 134 * Input parameters Typical value 135 * 136 * parmlu(0) = elmax1 Max multiplier allowed in L 10.0 137 * during factor. 138 * parmlu(1) = elmax2 Max multiplier allowed in L 10.0 139 * during updates. 140 * parmlu(2) = small Absolute tolerance for eps**0.8 141 * treating reals as zero. IBM double: 3.0d-13 142 * parmlu(3) = utol1 Absolute tol for flagging eps**0.66667 143 * small diagonals of U. IBM double: 3.7d-11 144 * parmlu(4) = utol2 Relative tol for flagging eps**0.66667 145 * small diagonals of U. IBM double: 3.7d-11 146 * parmlu(5) = uspace Factor limiting waste space in U. 3.0 147 * In lu1fac, the row or column lists 148 * are compressed if their length 149 * exceeds uspace times the length of 150 * either file after the last compression. 151 * parmlu(6) = dens1 The density at which the Markowitz 0.3 152 * strategy should search maxcol columns 153 * and no rows. 154 * parmlu(7) = dens2 the density at which the Markowitz 0.6 155 * strategy should search only 1 column 156 * or (preferably) use a dense LU for 157 * all the remaining rows and columns. 158 * 159 * 160 * Output parameters 161 * 162 * parmlu(9) = amax Maximum element in A. 163 * parmlu(10) = elmax Maximum multiplier in current L. 164 * parmlu(11) = umax Maximum element in current U. 165 * parmlu(12) = dumax Maximum diagonal in U. 166 * parmlu(13) = dumin Minimum diagonal in U. 167 * parmlu(14) = 168 * parmlu(15) = 169 * parmlu(16) = 170 * parmlu(17) = 171 * parmlu(18) = 172 * parmlu(19) = resid lu6sol: residual after solve with U or U'. 173 * ... 174 * parmlu(29) = 175 */ 176 177 #define Factorization_Tolerance 1e-1 178 #define Factorization_Pivot_Tolerance pow(2.2204460492503131E-16, 2.0 / 3.0) 179 #define Factorization_Small_Tolerance 1e-15 /* pow(DBL_EPSILON, 0.8) */ 180 181 EXTERN_C_BEGIN 182 #undef __FUNCT__ 183 #define __FUNCT__ "MatConvert_LUSOL_SeqAIJ" 184 PetscErrorCode MatConvert_LUSOL_SeqAIJ(Mat A,const MatType type,Mat *newmat) { 185 /* This routine is only called to convert an unfactored PETSc-LUSOL matrix */ 186 /* to its base PETSc type, so we will ignore 'MatType type'. */ 187 PetscErrorCode ierr; 188 Mat B=*newmat; 189 Mat_LUSOL *lusol=(Mat_LUSOL *)A->spptr; 190 191 PetscFunctionBegin; 192 if (B != A) { 193 ierr = MatDuplicate(A,MAT_COPY_VALUES,&B);CHKERRQ(ierr); 194 } 195 B->ops->duplicate = lusol->MatDuplicate; 196 B->ops->lufactorsymbolic = lusol->MatLUFactorSymbolic; 197 B->ops->destroy = lusol->MatDestroy; 198 199 ierr = PetscFree(lusol);CHKERRQ(ierr); 200 ierr = PetscObjectChangeTypeName((PetscObject)B,MATSEQAIJ);CHKERRQ(ierr); 201 *newmat = B; 202 PetscFunctionReturn(0); 203 } 204 EXTERN_C_END 205 206 #undef __FUNCT__ 207 #define __FUNCT__ "MatDestroy_LUSOL" 208 PetscErrorCode MatDestroy_LUSOL(Mat A) 209 { 210 PetscErrorCode ierr; 211 Mat_LUSOL *lusol=(Mat_LUSOL *)A->spptr; 212 213 PetscFunctionBegin; 214 if (lusol->CleanUpLUSOL) { 215 ierr = PetscFree(lusol->ip);CHKERRQ(ierr); 216 ierr = PetscFree(lusol->iq);CHKERRQ(ierr); 217 ierr = PetscFree(lusol->lenc);CHKERRQ(ierr); 218 ierr = PetscFree(lusol->lenr);CHKERRQ(ierr); 219 ierr = PetscFree(lusol->locc);CHKERRQ(ierr); 220 ierr = PetscFree(lusol->locr);CHKERRQ(ierr); 221 ierr = PetscFree(lusol->iploc);CHKERRQ(ierr); 222 ierr = PetscFree(lusol->iqloc);CHKERRQ(ierr); 223 ierr = PetscFree(lusol->ipinv);CHKERRQ(ierr); 224 ierr = PetscFree(lusol->iqinv);CHKERRQ(ierr); 225 ierr = PetscFree(lusol->mnsw);CHKERRQ(ierr); 226 ierr = PetscFree(lusol->mnsv);CHKERRQ(ierr); 227 228 ierr = PetscFree(lusol->indc);CHKERRQ(ierr); 229 } 230 231 ierr = MatConvert_LUSOL_SeqAIJ(A,MATSEQAIJ,&A); 232 ierr = (*A->ops->destroy)(A);CHKERRQ(ierr); 233 PetscFunctionReturn(0); 234 } 235 236 #undef __FUNCT__ 237 #define __FUNCT__ "MatSolve_LUSOL" 238 PetscErrorCode MatSolve_LUSOL(Mat A,Vec b,Vec x) { 239 Mat_LUSOL *lusol=(Mat_LUSOL*)A->spptr; 240 double *bb,*xx; 241 int mode=5; 242 int i,m,n,nnz,status,ierr; 243 244 PetscFunctionBegin; 245 ierr = VecGetArray(x, &xx);CHKERRQ(ierr); 246 ierr = VecGetArray(b, &bb);CHKERRQ(ierr); 247 248 m = n = lusol->n; 249 nnz = lusol->nnz; 250 251 for (i = 0; i < m; i++) 252 { 253 lusol->mnsv[i] = bb[i]; 254 } 255 256 LU6SOL(&mode, &m, &n, lusol->mnsv, xx, &nnz, 257 lusol->luparm, lusol->parmlu, lusol->data, 258 lusol->indc, lusol->indr, lusol->ip, lusol->iq, 259 lusol->lenc, lusol->lenr, lusol->locc, lusol->locr, &status); 260 261 if (status != 0) 262 { 263 SETERRQ(PETSC_ERR_ARG_SIZ,"solve failed"); 264 } 265 266 ierr = VecRestoreArray(x, &xx);CHKERRQ(ierr); 267 ierr = VecRestoreArray(b, &bb);CHKERRQ(ierr); 268 PetscFunctionReturn(0); 269 } 270 271 #undef __FUNCT__ 272 #define __FUNCT__ "MatLUFactorNumeric_LUSOL" 273 PetscErrorCode MatLUFactorNumeric_LUSOL(Mat A, Mat *F) { 274 Mat_SeqAIJ *a; 275 Mat_LUSOL *lusol = (Mat_LUSOL*)(*F)->spptr; 276 int m, n, nz, nnz, status; 277 int i, rs, re,ierr; 278 int factorizations; 279 280 PetscFunctionBegin; 281 ierr = MatGetSize(A,&m,&n);CHKERRQ(ierr);CHKERRQ(ierr); 282 a = (Mat_SeqAIJ *)A->data; 283 284 if (m != lusol->n) { 285 SETERRQ(PETSC_ERR_ARG_SIZ,"factorization struct inconsistent"); 286 } 287 288 factorizations = 0; 289 do 290 { 291 /*******************************************************************/ 292 /* Check the workspace allocation. */ 293 /*******************************************************************/ 294 295 nz = a->nz; 296 nnz = PetscMax(lusol->nnz, (int)(lusol->elbowroom*nz)); 297 nnz = PetscMax(nnz, 5*n); 298 299 if (nnz < lusol->luparm[12]){ 300 nnz = (int)(lusol->luroom * lusol->luparm[12]); 301 } else if ((factorizations > 0) && (lusol->luroom < 6)){ 302 lusol->luroom += 0.1; 303 } 304 305 nnz = PetscMax(nnz, (int)(lusol->luroom*(lusol->luparm[22] + lusol->luparm[23]))); 306 307 if (nnz > lusol->nnz){ 308 ierr = PetscFree(lusol->indc);CHKERRQ(ierr); 309 ierr = PetscMalloc((sizeof(double)+2*sizeof(int))*nnz,&lusol->indc);CHKERRQ(ierr); 310 lusol->indr = lusol->indc + nnz; 311 lusol->data = (double *)(lusol->indr + nnz); 312 lusol->nnz = nnz; 313 } 314 315 /*******************************************************************/ 316 /* Fill in the data for the problem. (1-based Fortran style) */ 317 /*******************************************************************/ 318 319 nz = 0; 320 for (i = 0; i < n; i++) 321 { 322 rs = a->i[i]; 323 re = a->i[i+1]; 324 325 while (rs < re) 326 { 327 if (a->a[rs] != 0.0) 328 { 329 lusol->indc[nz] = i + 1; 330 lusol->indr[nz] = a->j[rs] + 1; 331 lusol->data[nz] = a->a[rs]; 332 nz++; 333 } 334 rs++; 335 } 336 } 337 338 /*******************************************************************/ 339 /* Do the factorization. */ 340 /*******************************************************************/ 341 342 LU1FAC(&m, &n, &nz, &nnz, 343 lusol->luparm, lusol->parmlu, lusol->data, 344 lusol->indc, lusol->indr, lusol->ip, lusol->iq, 345 lusol->lenc, lusol->lenr, lusol->locc, lusol->locr, 346 lusol->iploc, lusol->iqloc, lusol->ipinv, 347 lusol->iqinv, lusol->mnsw, &status); 348 349 switch(status) 350 { 351 case 0: /* factored */ 352 break; 353 354 case 7: /* insufficient memory */ 355 break; 356 357 case 1: 358 case -1: /* singular */ 359 SETERRQ(1,"Singular matrix"); 360 361 case 3: 362 case 4: /* error conditions */ 363 SETERRQ(1,"matrix error"); 364 365 default: /* unknown condition */ 366 SETERRQ(1,"matrix unknown return code"); 367 } 368 369 factorizations++; 370 } while (status == 7); 371 (*F)->assembled = PETSC_TRUE; 372 PetscFunctionReturn(0); 373 } 374 375 #undef __FUNCT__ 376 #define __FUNCT__ "MatLUFactorSymbolic_LUSOL" 377 PetscErrorCode MatLUFactorSymbolic_LUSOL(Mat A, IS r, IS c,MatFactorInfo *info, Mat *F) { 378 /************************************************************************/ 379 /* Input */ 380 /* A - matrix to factor */ 381 /* r - row permutation (ignored) */ 382 /* c - column permutation (ignored) */ 383 /* */ 384 /* Output */ 385 /* F - matrix storing the factorization; */ 386 /************************************************************************/ 387 Mat B; 388 Mat_LUSOL *lusol; 389 PetscErrorCode ierr; 390 int i, m, n, nz, nnz; 391 392 PetscFunctionBegin; 393 394 /************************************************************************/ 395 /* Check the arguments. */ 396 /************************************************************************/ 397 398 ierr = MatGetSize(A, &m, &n);CHKERRQ(ierr); 399 nz = ((Mat_SeqAIJ *)A->data)->nz; 400 401 /************************************************************************/ 402 /* Create the factorization. */ 403 /************************************************************************/ 404 405 ierr = MatCreate(A->comm,PETSC_DECIDE,PETSC_DECIDE,m,n,&B);CHKERRQ(ierr); 406 ierr = MatSetType(B,A->type_name);CHKERRQ(ierr); 407 ierr = MatSeqAIJSetPreallocation(B,0,PETSC_NULL);CHKERRQ(ierr); 408 409 B->ops->lufactornumeric = MatLUFactorNumeric_LUSOL; 410 B->ops->solve = MatSolve_LUSOL; 411 B->factor = FACTOR_LU; 412 lusol = (Mat_LUSOL*)(B->spptr); 413 414 /************************************************************************/ 415 /* Initialize parameters */ 416 /************************************************************************/ 417 418 for (i = 0; i < 30; i++) 419 { 420 lusol->luparm[i] = 0; 421 lusol->parmlu[i] = 0; 422 } 423 424 lusol->luparm[1] = -1; 425 lusol->luparm[2] = 5; 426 lusol->luparm[7] = 1; 427 428 lusol->parmlu[0] = 1 / Factorization_Tolerance; 429 lusol->parmlu[1] = 1 / Factorization_Tolerance; 430 lusol->parmlu[2] = Factorization_Small_Tolerance; 431 lusol->parmlu[3] = Factorization_Pivot_Tolerance; 432 lusol->parmlu[4] = Factorization_Pivot_Tolerance; 433 lusol->parmlu[5] = 3.0; 434 lusol->parmlu[6] = 0.3; 435 lusol->parmlu[7] = 0.6; 436 437 /************************************************************************/ 438 /* Allocate the workspace needed by LUSOL. */ 439 /************************************************************************/ 440 441 lusol->elbowroom = PetscMax(lusol->elbowroom, info->fill); 442 nnz = PetscMax((int)(lusol->elbowroom*nz), 5*n); 443 444 lusol->n = n; 445 lusol->nz = nz; 446 lusol->nnz = nnz; 447 lusol->luroom = 1.75; 448 449 ierr = PetscMalloc(sizeof(int)*n,&lusol->ip); 450 ierr = PetscMalloc(sizeof(int)*n,&lusol->iq); 451 ierr = PetscMalloc(sizeof(int)*n,&lusol->lenc); 452 ierr = PetscMalloc(sizeof(int)*n,&lusol->lenr); 453 ierr = PetscMalloc(sizeof(int)*n,&lusol->locc); 454 ierr = PetscMalloc(sizeof(int)*n,&lusol->locr); 455 ierr = PetscMalloc(sizeof(int)*n,&lusol->iploc); 456 ierr = PetscMalloc(sizeof(int)*n,&lusol->iqloc); 457 ierr = PetscMalloc(sizeof(int)*n,&lusol->ipinv); 458 ierr = PetscMalloc(sizeof(int)*n,&lusol->iqinv); 459 ierr = PetscMalloc(sizeof(double)*n,&lusol->mnsw); 460 ierr = PetscMalloc(sizeof(double)*n,&lusol->mnsv); 461 462 ierr = PetscMalloc((sizeof(double)+2*sizeof(int))*nnz,&lusol->indc); 463 lusol->indr = lusol->indc + nnz; 464 lusol->data = (double *)(lusol->indr + nnz); 465 lusol->CleanUpLUSOL = PETSC_TRUE; 466 *F = B; 467 PetscFunctionReturn(0); 468 } 469 470 EXTERN_C_BEGIN 471 #undef __FUNCT__ 472 #define __FUNCT__ "MatConvert_SeqAIJ_LUSOL" 473 PetscErrorCode MatConvert_SeqAIJ_LUSOL(Mat A,const MatType type,Mat *newmat) { 474 PetscErrorCode ierr; 475 int m, n; 476 Mat_LUSOL *lusol; 477 Mat B=*newmat; 478 479 PetscFunctionBegin; 480 ierr = MatGetSize(A, &m, &n);CHKERRQ(ierr); 481 if (m != n) { 482 SETERRQ(PETSC_ERR_ARG_SIZ,"matrix must be square"); 483 } 484 if (B != A) { 485 ierr = MatDuplicate(A,MAT_COPY_VALUES,&B);CHKERRQ(ierr); 486 } 487 488 ierr = PetscNew(Mat_LUSOL,&lusol);CHKERRQ(ierr); 489 lusol->MatDuplicate = A->ops->duplicate; 490 lusol->MatLUFactorSymbolic = A->ops->lufactorsymbolic; 491 lusol->MatDestroy = A->ops->destroy; 492 lusol->CleanUpLUSOL = PETSC_FALSE; 493 494 B->spptr = (void*)lusol; 495 B->ops->duplicate = MatDuplicate_LUSOL; 496 B->ops->lufactorsymbolic = MatLUFactorSymbolic_LUSOL; 497 B->ops->destroy = MatDestroy_LUSOL; 498 499 PetscLogInfo(0,"Using LUSOL for LU factorization and solves."); 500 ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_seqaij_lusol_C", 501 "MatConvert_SeqAIJ_LUSOL",MatConvert_SeqAIJ_LUSOL);CHKERRQ(ierr); 502 ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_lusol_seqaij_C", 503 "MatConvert_LUSOL_SeqAIJ",MatConvert_LUSOL_SeqAIJ);CHKERRQ(ierr); 504 ierr = PetscObjectChangeTypeName((PetscObject)B,type);CHKERRQ(ierr); 505 *newmat = B; 506 PetscFunctionReturn(0); 507 } 508 EXTERN_C_END 509 510 #undef __FUNCT__ 511 #define __FUNCT__ "MatDuplicate_LUSOL" 512 PetscErrorCode MatDuplicate_LUSOL(Mat A, MatDuplicateOption op, Mat *M) { 513 PetscErrorCode ierr; 514 Mat_LUSOL *lu=(Mat_LUSOL *)A->spptr; 515 PetscFunctionBegin; 516 ierr = (*lu->MatDuplicate)(A,op,M);CHKERRQ(ierr); 517 ierr = PetscMemcpy((*M)->spptr,lu,sizeof(Mat_LUSOL));CHKERRQ(ierr); 518 PetscFunctionReturn(0); 519 } 520 521 /*MC 522 MATLUSOL - MATLUSOL = "lusol" - A matrix type providing direct solvers (LU) for sequential matrices 523 via the external package LUSOL. 524 525 If LUSOL is installed (see the manual for 526 instructions on how to declare the existence of external packages), 527 a matrix type can be constructed which invokes LUSOL solvers. 528 After calling MatCreate(...,A), simply call MatSetType(A,MATLUSOL). 529 This matrix type is only supported for double precision real. 530 531 This matrix inherits from MATSEQAIJ. As a result, MatSeqAIJSetPreallocation is 532 supported for this matrix type. MatConvert can be called for a fast inplace conversion 533 to and from the MATSEQAIJ matrix type. 534 535 Options Database Keys: 536 . -mat_type lusol - sets the matrix type to "lusol" during a call to MatSetFromOptions() 537 538 Level: beginner 539 540 .seealso: PCLU 541 M*/ 542 543 EXTERN_C_BEGIN 544 #undef __FUNCT__ 545 #define __FUNCT__ "MatCreate_LUSOL" 546 PetscErrorCode MatCreate_LUSOL(Mat A) 547 { 548 PetscErrorCode ierr; 549 550 PetscFunctionBegin; 551 /* Change type name before calling MatSetType to force proper construction of SeqAIJ and LUSOL types */ 552 ierr = PetscObjectChangeTypeName((PetscObject)A,MATLUSOL);CHKERRQ(ierr); 553 ierr = MatSetType(A,MATSEQAIJ);CHKERRQ(ierr); 554 ierr = MatConvert_SeqAIJ_LUSOL(A,MATLUSOL,&A);CHKERRQ(ierr); 555 PetscFunctionReturn(0); 556 } 557 EXTERN_C_END 558