1 #define PETSCMAT_DLL 2 3 #include "src/mat/impls/aij/seq/aij.h" 4 #include "src/inline/dot.h" 5 #include "src/inline/spops.h" 6 #include "petscbt.h" 7 #include "src/mat/utils/freespace.h" 8 9 #undef __FUNCT__ 10 #define __FUNCT__ "MatOrdering_Flow_SeqAIJ" 11 PetscErrorCode MatOrdering_Flow_SeqAIJ(Mat mat,const MatOrderingType type,IS *irow,IS *icol) 12 { 13 PetscFunctionBegin; 14 15 SETERRQ(PETSC_ERR_SUP,"Code not written"); 16 #if !defined(PETSC_USE_DEBUG) 17 PetscFunctionReturn(0); 18 #endif 19 } 20 21 22 #if !defined(PETSC_AVOID_GNUCOPYRIGHT_CODE) 23 EXTERN PetscErrorCode SPARSEKIT2dperm(PetscInt*,MatScalar*,PetscInt*,PetscInt*,MatScalar*,PetscInt*,PetscInt*,PetscInt*,PetscInt*,PetscInt*); 24 EXTERN PetscErrorCode SPARSEKIT2ilutp(PetscInt*,MatScalar*,PetscInt*,PetscInt*,PetscInt*,PetscReal,PetscReal*,PetscInt*,MatScalar*,PetscInt*,PetscInt*,PetscInt*,MatScalar*,PetscInt*,PetscInt*,PetscErrorCode*); 25 EXTERN PetscErrorCode SPARSEKIT2msrcsr(PetscInt*,MatScalar*,PetscInt*,MatScalar*,PetscInt*,PetscInt*,MatScalar*,PetscInt*); 26 #endif 27 28 #undef __FUNCT__ 29 #define __FUNCT__ "MatILUDTFactor_SeqAIJ" 30 /* ------------------------------------------------------------ 31 32 This interface was contribed by Tony Caola 33 34 This routine is an interface to the pivoting drop-tolerance 35 ILU routine written by Yousef Saad (saad@cs.umn.edu) as part of 36 SPARSEKIT2. 37 38 The SPARSEKIT2 routines used here are covered by the GNU 39 copyright; see the file gnu in this directory. 40 41 Thanks to Prof. Saad, Dr. Hysom, and Dr. Smith for their 42 help in getting this routine ironed out. 43 44 The major drawback to this routine is that if info->fill is 45 not large enough it fails rather than allocating more space; 46 this can be fixed by hacking/improving the f2c version of 47 Yousef Saad's code. 48 49 ------------------------------------------------------------ 50 */ 51 PetscErrorCode MatILUDTFactor_SeqAIJ(Mat A,IS isrow,IS iscol,MatFactorInfo *info,Mat *fact) 52 { 53 #if defined(PETSC_AVOID_GNUCOPYRIGHT_CODE) 54 PetscFunctionBegin; 55 SETERRQ(PETSC_ERR_SUP_SYS,"This distribution does not include GNU Copyright code\n\ 56 You can obtain the drop tolerance routines by installing PETSc from\n\ 57 www.mcs.anl.gov/petsc\n"); 58 #else 59 Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data,*b; 60 IS iscolf,isicol,isirow; 61 PetscTruth reorder; 62 PetscErrorCode ierr,sierr; 63 PetscInt *c,*r,*ic,i,n = A->rmap.n; 64 PetscInt *old_i = a->i,*old_j = a->j,*new_i,*old_i2 = 0,*old_j2 = 0,*new_j; 65 PetscInt *ordcol,*iwk,*iperm,*jw; 66 PetscInt jmax,lfill,job,*o_i,*o_j; 67 MatScalar *old_a = a->a,*w,*new_a,*old_a2 = 0,*wk,*o_a; 68 PetscReal af; 69 70 PetscFunctionBegin; 71 72 if (info->dt == PETSC_DEFAULT) info->dt = .005; 73 if (info->dtcount == PETSC_DEFAULT) info->dtcount = (PetscInt)(1.5*a->rmax); 74 if (info->dtcol == PETSC_DEFAULT) info->dtcol = .01; 75 if (info->fill == PETSC_DEFAULT) info->fill = ((double)(n*(info->dtcount+1)))/a->nz; 76 lfill = (PetscInt)(info->dtcount/2.0); 77 jmax = (PetscInt)(info->fill*a->nz); 78 79 80 /* ------------------------------------------------------------ 81 If reorder=.TRUE., then the original matrix has to be 82 reordered to reflect the user selected ordering scheme, and 83 then de-reordered so it is in it's original format. 84 Because Saad's dperm() is NOT in place, we have to copy 85 the original matrix and allocate more storage. . . 86 ------------------------------------------------------------ 87 */ 88 89 /* set reorder to true if either isrow or iscol is not identity */ 90 ierr = ISIdentity(isrow,&reorder);CHKERRQ(ierr); 91 if (reorder) {ierr = ISIdentity(iscol,&reorder);CHKERRQ(ierr);} 92 reorder = PetscNot(reorder); 93 94 95 /* storage for ilu factor */ 96 ierr = PetscMalloc((n+1)*sizeof(PetscInt),&new_i);CHKERRQ(ierr); 97 ierr = PetscMalloc(jmax*sizeof(PetscInt),&new_j);CHKERRQ(ierr); 98 ierr = PetscMalloc(jmax*sizeof(MatScalar),&new_a);CHKERRQ(ierr); 99 ierr = PetscMalloc(n*sizeof(PetscInt),&ordcol);CHKERRQ(ierr); 100 101 /* ------------------------------------------------------------ 102 Make sure that everything is Fortran formatted (1-Based) 103 ------------------------------------------------------------ 104 */ 105 for (i=old_i[0];i<old_i[n];i++) { 106 old_j[i]++; 107 } 108 for(i=0;i<n+1;i++) { 109 old_i[i]++; 110 }; 111 112 113 if (reorder) { 114 ierr = ISGetIndices(iscol,&c);CHKERRQ(ierr); 115 ierr = ISGetIndices(isrow,&r);CHKERRQ(ierr); 116 for(i=0;i<n;i++) { 117 r[i] = r[i]+1; 118 c[i] = c[i]+1; 119 } 120 ierr = PetscMalloc((n+1)*sizeof(PetscInt),&old_i2);CHKERRQ(ierr); 121 ierr = PetscMalloc((old_i[n]-old_i[0]+1)*sizeof(PetscInt),&old_j2);CHKERRQ(ierr); 122 ierr = PetscMalloc((old_i[n]-old_i[0]+1)*sizeof(MatScalar),&old_a2);CHKERRQ(ierr); 123 job = 3; SPARSEKIT2dperm(&n,old_a,old_j,old_i,old_a2,old_j2,old_i2,r,c,&job); 124 for (i=0;i<n;i++) { 125 r[i] = r[i]-1; 126 c[i] = c[i]-1; 127 } 128 ierr = ISRestoreIndices(iscol,&c);CHKERRQ(ierr); 129 ierr = ISRestoreIndices(isrow,&r);CHKERRQ(ierr); 130 o_a = old_a2; 131 o_j = old_j2; 132 o_i = old_i2; 133 } else { 134 o_a = old_a; 135 o_j = old_j; 136 o_i = old_i; 137 } 138 139 /* ------------------------------------------------------------ 140 Call Saad's ilutp() routine to generate the factorization 141 ------------------------------------------------------------ 142 */ 143 144 ierr = PetscMalloc(2*n*sizeof(PetscInt),&iperm);CHKERRQ(ierr); 145 ierr = PetscMalloc(2*n*sizeof(PetscInt),&jw);CHKERRQ(ierr); 146 ierr = PetscMalloc(n*sizeof(PetscScalar),&w);CHKERRQ(ierr); 147 148 SPARSEKIT2ilutp(&n,o_a,o_j,o_i,&lfill,(PetscReal)info->dt,&info->dtcol,&n,new_a,new_j,new_i,&jmax,w,jw,iperm,&sierr); 149 if (sierr) { 150 switch (sierr) { 151 case -3: SETERRQ2(PETSC_ERR_LIB,"ilutp(), matrix U overflows, need larger info->fill current fill %G space allocated %D",info->fill,jmax); 152 case -2: SETERRQ2(PETSC_ERR_LIB,"ilutp(), matrix L overflows, need larger info->fill current fill %G space allocated %D",info->fill,jmax); 153 case -5: SETERRQ(PETSC_ERR_LIB,"ilutp(), zero row encountered"); 154 case -1: SETERRQ(PETSC_ERR_LIB,"ilutp(), input matrix may be wrong"); 155 case -4: SETERRQ1(PETSC_ERR_LIB,"ilutp(), illegal info->fill value %D",jmax); 156 default: SETERRQ1(PETSC_ERR_LIB,"ilutp(), zero pivot detected on row %D",sierr); 157 } 158 } 159 160 ierr = PetscFree(w);CHKERRQ(ierr); 161 ierr = PetscFree(jw);CHKERRQ(ierr); 162 163 /* ------------------------------------------------------------ 164 Saad's routine gives the result in Modified Sparse Row (msr) 165 Convert to Compressed Sparse Row format (csr) 166 ------------------------------------------------------------ 167 */ 168 169 ierr = PetscMalloc(n*sizeof(PetscScalar),&wk);CHKERRQ(ierr); 170 ierr = PetscMalloc((n+1)*sizeof(PetscInt),&iwk);CHKERRQ(ierr); 171 172 SPARSEKIT2msrcsr(&n,new_a,new_j,new_a,new_j,new_i,wk,iwk); 173 174 ierr = PetscFree(iwk);CHKERRQ(ierr); 175 ierr = PetscFree(wk);CHKERRQ(ierr); 176 177 if (reorder) { 178 ierr = PetscFree(old_a2);CHKERRQ(ierr); 179 ierr = PetscFree(old_j2);CHKERRQ(ierr); 180 ierr = PetscFree(old_i2);CHKERRQ(ierr); 181 } else { 182 /* fix permutation of old_j that the factorization introduced */ 183 for (i=old_i[0]; i<old_i[n]; i++) { 184 old_j[i-1] = iperm[old_j[i-1]-1]; 185 } 186 } 187 188 /* get rid of the shift to indices starting at 1 */ 189 for (i=0; i<n+1; i++) { 190 old_i[i]--; 191 } 192 for (i=old_i[0];i<old_i[n];i++) { 193 old_j[i]--; 194 } 195 196 /* Make the factored matrix 0-based */ 197 for (i=0; i<n+1; i++) { 198 new_i[i]--; 199 } 200 for (i=new_i[0];i<new_i[n];i++) { 201 new_j[i]--; 202 } 203 204 /*-- due to the pivoting, we need to reorder iscol to correctly --*/ 205 /*-- permute the right-hand-side and solution vectors --*/ 206 ierr = ISInvertPermutation(iscol,PETSC_DECIDE,&isicol);CHKERRQ(ierr); 207 ierr = ISInvertPermutation(isrow,PETSC_DECIDE,&isirow);CHKERRQ(ierr); 208 ierr = ISGetIndices(isicol,&ic);CHKERRQ(ierr); 209 for(i=0; i<n; i++) { 210 ordcol[i] = ic[iperm[i]-1]; 211 }; 212 ierr = ISRestoreIndices(isicol,&ic);CHKERRQ(ierr); 213 ierr = ISDestroy(isicol);CHKERRQ(ierr); 214 215 ierr = PetscFree(iperm);CHKERRQ(ierr); 216 217 ierr = ISCreateGeneral(PETSC_COMM_SELF,n,ordcol,&iscolf);CHKERRQ(ierr); 218 ierr = PetscFree(ordcol);CHKERRQ(ierr); 219 220 /*----- put together the new matrix -----*/ 221 222 ierr = MatCreate(((PetscObject)A)->comm,fact);CHKERRQ(ierr); 223 ierr = MatSetSizes(*fact,n,n,n,n);CHKERRQ(ierr); 224 ierr = MatSetType(*fact,((PetscObject)A)->type_name);CHKERRQ(ierr); 225 ierr = MatSeqAIJSetPreallocation_SeqAIJ(*fact,MAT_SKIP_ALLOCATION,PETSC_NULL);CHKERRQ(ierr); 226 (*fact)->factor = MAT_FACTOR_LU; 227 (*fact)->assembled = PETSC_TRUE; 228 229 b = (Mat_SeqAIJ*)(*fact)->data; 230 b->free_a = PETSC_TRUE; 231 b->free_ij = PETSC_TRUE; 232 b->singlemalloc = PETSC_FALSE; 233 b->a = new_a; 234 b->j = new_j; 235 b->i = new_i; 236 b->ilen = 0; 237 b->imax = 0; 238 /* I am not sure why these are the inverses of the row and column permutations; but the other way is NO GOOD */ 239 b->row = isirow; 240 b->col = iscolf; 241 ierr = PetscMalloc((n+1)*sizeof(PetscScalar),&b->solve_work);CHKERRQ(ierr); 242 b->maxnz = b->nz = new_i[n]; 243 ierr = MatMarkDiagonal_SeqAIJ(*fact);CHKERRQ(ierr); 244 (*fact)->info.factor_mallocs = 0; 245 246 af = ((double)b->nz)/((double)a->nz) + .001; 247 ierr = PetscInfo2(A,"Fill ratio:given %G needed %G\n",info->fill,af);CHKERRQ(ierr); 248 ierr = PetscInfo1(A,"Run with -pc_factor_fill %G or use \n",af);CHKERRQ(ierr); 249 ierr = PetscInfo1(A,"PCFactorSetFill(pc,%G);\n",af);CHKERRQ(ierr); 250 ierr = PetscInfo(A,"for best performance.\n");CHKERRQ(ierr); 251 252 ierr = MatILUDTFactor_Inode(A,isrow,iscol,info,fact);CHKERRQ(ierr); 253 254 PetscFunctionReturn(0); 255 #endif 256 } 257 258 EXTERN_C_BEGIN 259 #undef __FUNCT__ 260 #define __FUNCT__ "MatGetFactor_seqaij_petsc" 261 PetscErrorCode MatGetFactor_seqaij_petsc(Mat A,MatFactorType ftype,Mat *B) 262 { 263 PetscInt n = A->rmap.n; 264 PetscErrorCode ierr; 265 266 PetscFunctionBegin; 267 ierr = MatCreate(((PetscObject)A)->comm,B);CHKERRQ(ierr); 268 ierr = MatSetSizes(*B,n,n,n,n);CHKERRQ(ierr); 269 if (ftype == MAT_FACTOR_LU || ftype == MAT_FACTOR_ILU) { 270 ierr = MatSetType(*B,MATSEQAIJ);CHKERRQ(ierr); 271 } else if (ftype == MAT_FACTOR_CHOLESKY || ftype == MAT_FACTOR_ICC) { 272 ierr = MatSetType(*B,MATSEQSBAIJ);CHKERRQ(ierr); 273 ierr = MatSeqSBAIJSetPreallocation(*B,1,MAT_SKIP_ALLOCATION,PETSC_NULL);CHKERRQ(ierr); 274 (*B)->ops->iccfactorsymbolic = MatICCFactorSymbolic_SeqAIJ; 275 (*B)->ops->choleskyfactorsymbolic = MatCholeskyFactorSymbolic_SeqAIJ; 276 (*B)->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqAIJ; 277 } else SETERRQ(PETSC_ERR_SUP,"Factor type not supported"); 278 PetscFunctionReturn(0); 279 } 280 EXTERN_C_END 281 282 #undef __FUNCT__ 283 #define __FUNCT__ "MatLUFactorSymbolic_SeqAIJ" 284 PetscErrorCode MatLUFactorSymbolic_SeqAIJ(Mat A,IS isrow,IS iscol,MatFactorInfo *info,Mat *B) 285 { 286 Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data,*b; 287 IS isicol; 288 PetscErrorCode ierr; 289 PetscInt *r,*ic,i,n=A->rmap.n,*ai=a->i,*aj=a->j; 290 PetscInt *bi,*bj,*ajtmp; 291 PetscInt *bdiag,row,nnz,nzi,reallocs=0,nzbd,*im; 292 PetscReal f; 293 PetscInt nlnk,*lnk,k,**bi_ptr; 294 PetscFreeSpaceList free_space=PETSC_NULL,current_space=PETSC_NULL; 295 PetscBT lnkbt; 296 297 PetscFunctionBegin; 298 if (A->rmap.N != A->cmap.N) SETERRQ(PETSC_ERR_ARG_WRONG,"matrix must be square"); 299 ierr = ISInvertPermutation(iscol,PETSC_DECIDE,&isicol);CHKERRQ(ierr); 300 ierr = ISGetIndices(isrow,&r);CHKERRQ(ierr); 301 ierr = ISGetIndices(isicol,&ic);CHKERRQ(ierr); 302 303 /* get new row pointers */ 304 ierr = PetscMalloc((n+1)*sizeof(PetscInt),&bi);CHKERRQ(ierr); 305 bi[0] = 0; 306 307 /* bdiag is location of diagonal in factor */ 308 ierr = PetscMalloc((n+1)*sizeof(PetscInt),&bdiag);CHKERRQ(ierr); 309 bdiag[0] = 0; 310 311 /* linked list for storing column indices of the active row */ 312 nlnk = n + 1; 313 ierr = PetscLLCreate(n,n,nlnk,lnk,lnkbt);CHKERRQ(ierr); 314 315 ierr = PetscMalloc2(n+1,PetscInt**,&bi_ptr,n+1,PetscInt,&im);CHKERRQ(ierr); 316 317 /* initial FreeSpace size is f*(ai[n]+1) */ 318 f = info->fill; 319 ierr = PetscFreeSpaceGet((PetscInt)(f*(ai[n]+1)),&free_space);CHKERRQ(ierr); 320 current_space = free_space; 321 322 for (i=0; i<n; i++) { 323 /* copy previous fill into linked list */ 324 nzi = 0; 325 nnz = ai[r[i]+1] - ai[r[i]]; 326 if (!nnz) SETERRQ(PETSC_ERR_MAT_LU_ZRPVT,"Empty row in matrix"); 327 ajtmp = aj + ai[r[i]]; 328 ierr = PetscLLAddPerm(nnz,ajtmp,ic,n,nlnk,lnk,lnkbt);CHKERRQ(ierr); 329 nzi += nlnk; 330 331 /* add pivot rows into linked list */ 332 row = lnk[n]; 333 while (row < i) { 334 nzbd = bdiag[row] - bi[row] + 1; /* num of entries in the row with column index <= row */ 335 ajtmp = bi_ptr[row] + nzbd; /* points to the entry next to the diagonal */ 336 ierr = PetscLLAddSortedLU(ajtmp,row,nlnk,lnk,lnkbt,i,nzbd,im);CHKERRQ(ierr); 337 nzi += nlnk; 338 row = lnk[row]; 339 } 340 bi[i+1] = bi[i] + nzi; 341 im[i] = nzi; 342 343 /* mark bdiag */ 344 nzbd = 0; 345 nnz = nzi; 346 k = lnk[n]; 347 while (nnz-- && k < i){ 348 nzbd++; 349 k = lnk[k]; 350 } 351 bdiag[i] = bi[i] + nzbd; 352 353 /* if free space is not available, make more free space */ 354 if (current_space->local_remaining<nzi) { 355 nnz = (n - i)*nzi; /* estimated and max additional space needed */ 356 ierr = PetscFreeSpaceGet(nnz,¤t_space);CHKERRQ(ierr); 357 reallocs++; 358 } 359 360 /* copy data into free space, then initialize lnk */ 361 ierr = PetscLLClean(n,n,nzi,lnk,current_space->array,lnkbt);CHKERRQ(ierr); 362 bi_ptr[i] = current_space->array; 363 current_space->array += nzi; 364 current_space->local_used += nzi; 365 current_space->local_remaining -= nzi; 366 } 367 #if defined(PETSC_USE_INFO) 368 if (ai[n] != 0) { 369 PetscReal af = ((PetscReal)bi[n])/((PetscReal)ai[n]); 370 ierr = PetscInfo3(A,"Reallocs %D Fill ratio:given %G needed %G\n",reallocs,f,af);CHKERRQ(ierr); 371 ierr = PetscInfo1(A,"Run with -pc_factor_fill %G or use \n",af);CHKERRQ(ierr); 372 ierr = PetscInfo1(A,"PCFactorSetFill(pc,%G);\n",af);CHKERRQ(ierr); 373 ierr = PetscInfo(A,"for best performance.\n");CHKERRQ(ierr); 374 } else { 375 ierr = PetscInfo(A,"Empty matrix\n");CHKERRQ(ierr); 376 } 377 #endif 378 379 ierr = ISRestoreIndices(isrow,&r);CHKERRQ(ierr); 380 ierr = ISRestoreIndices(isicol,&ic);CHKERRQ(ierr); 381 382 /* destroy list of free space and other temporary array(s) */ 383 ierr = PetscMalloc((bi[n]+1)*sizeof(PetscInt),&bj);CHKERRQ(ierr); 384 ierr = PetscFreeSpaceContiguous(&free_space,bj);CHKERRQ(ierr); 385 ierr = PetscLLDestroy(lnk,lnkbt);CHKERRQ(ierr); 386 ierr = PetscFree2(bi_ptr,im);CHKERRQ(ierr); 387 388 /* put together the new matrix */ 389 ierr = MatSeqAIJSetPreallocation_SeqAIJ(*B,MAT_SKIP_ALLOCATION,PETSC_NULL);CHKERRQ(ierr); 390 ierr = PetscLogObjectParent(*B,isicol);CHKERRQ(ierr); 391 b = (Mat_SeqAIJ*)(*B)->data; 392 b->free_a = PETSC_TRUE; 393 b->free_ij = PETSC_TRUE; 394 b->singlemalloc = PETSC_FALSE; 395 ierr = PetscMalloc((bi[n]+1)*sizeof(PetscScalar),&b->a);CHKERRQ(ierr); 396 b->j = bj; 397 b->i = bi; 398 b->diag = bdiag; 399 b->ilen = 0; 400 b->imax = 0; 401 b->row = isrow; 402 b->col = iscol; 403 ierr = PetscObjectReference((PetscObject)isrow);CHKERRQ(ierr); 404 ierr = PetscObjectReference((PetscObject)iscol);CHKERRQ(ierr); 405 b->icol = isicol; 406 ierr = PetscMalloc((n+1)*sizeof(PetscScalar),&b->solve_work);CHKERRQ(ierr); 407 408 /* In b structure: Free imax, ilen, old a, old j. Allocate solve_work, new a, new j */ 409 ierr = PetscLogObjectMemory(*B,(bi[n]-n)*(sizeof(PetscInt)+sizeof(PetscScalar)));CHKERRQ(ierr); 410 b->maxnz = b->nz = bi[n] ; 411 412 (*B)->factor = MAT_FACTOR_LU; 413 (*B)->info.factor_mallocs = reallocs; 414 (*B)->info.fill_ratio_given = f; 415 416 if (ai[n] != 0) { 417 (*B)->info.fill_ratio_needed = ((PetscReal)bi[n])/((PetscReal)ai[n]); 418 } else { 419 (*B)->info.fill_ratio_needed = 0.0; 420 } 421 ierr = MatLUFactorSymbolic_Inode(A,isrow,iscol,info,B);CHKERRQ(ierr); 422 (*B)->ops->lufactornumeric = A->ops->lufactornumeric; /* Use Inode variant ONLY if A has inodes */ 423 PetscFunctionReturn(0); 424 } 425 426 /* 427 Trouble in factorization, should we dump the original matrix? 428 */ 429 #undef __FUNCT__ 430 #define __FUNCT__ "MatFactorDumpMatrix" 431 PetscErrorCode MatFactorDumpMatrix(Mat A) 432 { 433 PetscErrorCode ierr; 434 PetscTruth flg; 435 436 PetscFunctionBegin; 437 ierr = PetscOptionsHasName(PETSC_NULL,"-mat_factor_dump_on_error",&flg);CHKERRQ(ierr); 438 if (flg) { 439 PetscViewer viewer; 440 char filename[PETSC_MAX_PATH_LEN]; 441 442 ierr = PetscSNPrintf(filename,PETSC_MAX_PATH_LEN,"matrix_factor_error.%d",PetscGlobalRank);CHKERRQ(ierr); 443 ierr = PetscViewerBinaryOpen(((PetscObject)A)->comm,filename,FILE_MODE_WRITE,&viewer);CHKERRQ(ierr); 444 ierr = MatView(A,viewer);CHKERRQ(ierr); 445 ierr = PetscViewerDestroy(viewer);CHKERRQ(ierr); 446 } 447 PetscFunctionReturn(0); 448 } 449 450 /* ----------------------------------------------------------- */ 451 #undef __FUNCT__ 452 #define __FUNCT__ "MatLUFactorNumeric_SeqAIJ" 453 PetscErrorCode MatLUFactorNumeric_SeqAIJ(Mat A,MatFactorInfo *info,Mat *B) 454 { 455 Mat C=*B; 456 Mat_SeqAIJ *a=(Mat_SeqAIJ*)A->data,*b=(Mat_SeqAIJ *)C->data; 457 IS isrow = b->row,isicol = b->icol; 458 PetscErrorCode ierr; 459 PetscInt *r,*ic,i,j,n=A->rmap.n,*bi=b->i,*bj=b->j; 460 PetscInt *ajtmp,*bjtmp,nz,row,*ics; 461 PetscInt *diag_offset = b->diag,diag,*pj; 462 PetscScalar *rtmp,*pc,multiplier,*rtmps; 463 MatScalar *v,*pv; 464 PetscScalar d; 465 PetscReal rs; 466 LUShift_Ctx sctx; 467 PetscInt newshift,*ddiag; 468 469 PetscFunctionBegin; 470 ierr = ISGetIndices(isrow,&r);CHKERRQ(ierr); 471 ierr = ISGetIndices(isicol,&ic);CHKERRQ(ierr); 472 ierr = PetscMalloc((n+1)*sizeof(PetscScalar),&rtmp);CHKERRQ(ierr); 473 ierr = PetscMemzero(rtmp,(n+1)*sizeof(PetscScalar));CHKERRQ(ierr); 474 rtmps = rtmp; ics = ic; 475 476 sctx.shift_top = 0; 477 sctx.nshift_max = 0; 478 sctx.shift_lo = 0; 479 sctx.shift_hi = 0; 480 481 /* if both shift schemes are chosen by user, only use info->shiftpd */ 482 if (info->shiftpd && info->shiftnz) info->shiftnz = 0.0; 483 if (info->shiftpd) { /* set sctx.shift_top=max{rs} */ 484 PetscInt *aai = a->i; 485 ddiag = a->diag; 486 sctx.shift_top = 0; 487 for (i=0; i<n; i++) { 488 /* calculate sum(|aij|)-RealPart(aii), amt of shift needed for this row */ 489 d = (a->a)[ddiag[i]]; 490 rs = -PetscAbsScalar(d) - PetscRealPart(d); 491 v = a->a+aai[i]; 492 nz = aai[i+1] - aai[i]; 493 for (j=0; j<nz; j++) 494 rs += PetscAbsScalar(v[j]); 495 if (rs>sctx.shift_top) sctx.shift_top = rs; 496 } 497 if (sctx.shift_top < info->zeropivot) sctx.shift_top = info->zeropivot; 498 sctx.shift_top *= 1.1; 499 sctx.nshift_max = 5; 500 sctx.shift_lo = 0.; 501 sctx.shift_hi = 1.; 502 } 503 504 sctx.shift_amount = 0; 505 sctx.nshift = 0; 506 do { 507 sctx.lushift = PETSC_FALSE; 508 for (i=0; i<n; i++){ 509 nz = bi[i+1] - bi[i]; 510 bjtmp = bj + bi[i]; 511 for (j=0; j<nz; j++) rtmps[bjtmp[j]] = 0.0; 512 513 /* load in initial (unfactored row) */ 514 nz = a->i[r[i]+1] - a->i[r[i]]; 515 ajtmp = a->j + a->i[r[i]]; 516 v = a->a + a->i[r[i]]; 517 for (j=0; j<nz; j++) { 518 rtmp[ics[ajtmp[j]]] = v[j]; 519 } 520 rtmp[ics[r[i]]] += sctx.shift_amount; /* shift the diagonal of the matrix */ 521 522 row = *bjtmp++; 523 while (row < i) { 524 pc = rtmp + row; 525 if (*pc != 0.0) { 526 pv = b->a + diag_offset[row]; 527 pj = b->j + diag_offset[row] + 1; 528 multiplier = *pc / *pv++; 529 *pc = multiplier; 530 nz = bi[row+1] - diag_offset[row] - 1; 531 for (j=0; j<nz; j++) rtmps[pj[j]] -= multiplier * pv[j]; 532 ierr = PetscLogFlops(2*nz);CHKERRQ(ierr); 533 } 534 row = *bjtmp++; 535 } 536 /* finished row so stick it into b->a */ 537 pv = b->a + bi[i] ; 538 pj = b->j + bi[i] ; 539 nz = bi[i+1] - bi[i]; 540 diag = diag_offset[i] - bi[i]; 541 rs = 0.0; 542 for (j=0; j<nz; j++) { 543 pv[j] = rtmps[pj[j]]; 544 if (j != diag) rs += PetscAbsScalar(pv[j]); 545 } 546 547 /* 9/13/02 Victor Eijkhout suggested scaling zeropivot by rs for matrices with funny scalings */ 548 sctx.rs = rs; 549 sctx.pv = pv[diag]; 550 ierr = MatLUCheckShift_inline(info,sctx,i,newshift);CHKERRQ(ierr); 551 if (newshift == 1) break; 552 } 553 554 if (info->shiftpd && !sctx.lushift && info->shift_fraction>0 && sctx.nshift<sctx.nshift_max) { 555 /* 556 * if no shift in this attempt & shifting & started shifting & can refine, 557 * then try lower shift 558 */ 559 sctx.shift_hi = info->shift_fraction; 560 info->shift_fraction = (sctx.shift_hi+sctx.shift_lo)/2.; 561 sctx.shift_amount = info->shift_fraction * sctx.shift_top; 562 sctx.lushift = PETSC_TRUE; 563 sctx.nshift++; 564 } 565 } while (sctx.lushift); 566 567 /* invert diagonal entries for simplier triangular solves */ 568 for (i=0; i<n; i++) { 569 b->a[diag_offset[i]] = 1.0/b->a[diag_offset[i]]; 570 } 571 ierr = PetscFree(rtmp);CHKERRQ(ierr); 572 ierr = ISRestoreIndices(isicol,&ic);CHKERRQ(ierr); 573 ierr = ISRestoreIndices(isrow,&r);CHKERRQ(ierr); 574 C->factor = MAT_FACTOR_LU; 575 C->assembled = PETSC_TRUE; 576 C->preallocated = PETSC_TRUE; 577 ierr = PetscLogFlops(C->cmap.n);CHKERRQ(ierr); 578 if (sctx.nshift){ 579 if (info->shiftnz) { 580 ierr = PetscInfo2(A,"number of shift_nz tries %D, shift_amount %G\n",sctx.nshift,sctx.shift_amount);CHKERRQ(ierr); 581 } else if (info->shiftpd) { 582 ierr = PetscInfo4(A,"number of shift_pd tries %D, shift_amount %G, diagonal shifted up by %e fraction top_value %e\n",sctx.nshift,sctx.shift_amount,info->shift_fraction,sctx.shift_top);CHKERRQ(ierr); 583 } 584 } 585 PetscFunctionReturn(0); 586 } 587 588 /* 589 This routine implements inplace ILU(0) with row or/and column permutations. 590 Input: 591 A - original matrix 592 Output; 593 A - a->i (rowptr) is same as original rowptr, but factored i-the row is stored in rowperm[i] 594 a->j (col index) is permuted by the inverse of colperm, then sorted 595 a->a reordered accordingly with a->j 596 a->diag (ptr to diagonal elements) is updated. 597 */ 598 #undef __FUNCT__ 599 #define __FUNCT__ "MatLUFactorNumeric_SeqAIJ_InplaceWithPerm" 600 PetscErrorCode MatLUFactorNumeric_SeqAIJ_InplaceWithPerm(Mat A,MatFactorInfo *info,Mat *B) 601 { 602 Mat_SeqAIJ *a=(Mat_SeqAIJ*)A->data; 603 IS isrow = a->row,isicol = a->icol; 604 PetscErrorCode ierr; 605 PetscInt *r,*ic,i,j,n=A->rmap.n,*ai=a->i,*aj=a->j; 606 PetscInt *ajtmp,nz,row,*ics; 607 PetscInt *diag = a->diag,nbdiag,*pj; 608 PetscScalar *rtmp,*pc,multiplier,d; 609 MatScalar *v,*pv; 610 PetscReal rs; 611 LUShift_Ctx sctx; 612 PetscInt newshift; 613 614 PetscFunctionBegin; 615 if (A != *B) SETERRQ(PETSC_ERR_ARG_INCOMP,"input and output matrix must have same address"); 616 ierr = ISGetIndices(isrow,&r);CHKERRQ(ierr); 617 ierr = ISGetIndices(isicol,&ic);CHKERRQ(ierr); 618 ierr = PetscMalloc((n+1)*sizeof(PetscScalar),&rtmp);CHKERRQ(ierr); 619 ierr = PetscMemzero(rtmp,(n+1)*sizeof(PetscScalar));CHKERRQ(ierr); 620 ics = ic; 621 622 sctx.shift_top = 0; 623 sctx.nshift_max = 0; 624 sctx.shift_lo = 0; 625 sctx.shift_hi = 0; 626 627 /* if both shift schemes are chosen by user, only use info->shiftpd */ 628 if (info->shiftpd && info->shiftnz) info->shiftnz = 0.0; 629 if (info->shiftpd) { /* set sctx.shift_top=max{rs} */ 630 sctx.shift_top = 0; 631 for (i=0; i<n; i++) { 632 /* calculate sum(|aij|)-RealPart(aii), amt of shift needed for this row */ 633 d = (a->a)[diag[i]]; 634 rs = -PetscAbsScalar(d) - PetscRealPart(d); 635 v = a->a+ai[i]; 636 nz = ai[i+1] - ai[i]; 637 for (j=0; j<nz; j++) 638 rs += PetscAbsScalar(v[j]); 639 if (rs>sctx.shift_top) sctx.shift_top = rs; 640 } 641 if (sctx.shift_top < info->zeropivot) sctx.shift_top = info->zeropivot; 642 sctx.shift_top *= 1.1; 643 sctx.nshift_max = 5; 644 sctx.shift_lo = 0.; 645 sctx.shift_hi = 1.; 646 } 647 648 sctx.shift_amount = 0; 649 sctx.nshift = 0; 650 do { 651 sctx.lushift = PETSC_FALSE; 652 for (i=0; i<n; i++){ 653 /* load in initial unfactored row */ 654 nz = ai[r[i]+1] - ai[r[i]]; 655 ajtmp = aj + ai[r[i]]; 656 v = a->a + ai[r[i]]; 657 /* sort permuted ajtmp and values v accordingly */ 658 for (j=0; j<nz; j++) ajtmp[j] = ics[ajtmp[j]]; 659 ierr = PetscSortIntWithScalarArray(nz,ajtmp,v);CHKERRQ(ierr); 660 661 diag[r[i]] = ai[r[i]]; 662 for (j=0; j<nz; j++) { 663 rtmp[ajtmp[j]] = v[j]; 664 if (ajtmp[j] < i) diag[r[i]]++; /* update a->diag */ 665 } 666 rtmp[r[i]] += sctx.shift_amount; /* shift the diagonal of the matrix */ 667 668 row = *ajtmp++; 669 while (row < i) { 670 pc = rtmp + row; 671 if (*pc != 0.0) { 672 pv = a->a + diag[r[row]]; 673 pj = aj + diag[r[row]] + 1; 674 675 multiplier = *pc / *pv++; 676 *pc = multiplier; 677 nz = ai[r[row]+1] - diag[r[row]] - 1; 678 for (j=0; j<nz; j++) rtmp[pj[j]] -= multiplier * pv[j]; 679 ierr = PetscLogFlops(2*nz);CHKERRQ(ierr); 680 } 681 row = *ajtmp++; 682 } 683 /* finished row so overwrite it onto a->a */ 684 pv = a->a + ai[r[i]] ; 685 pj = aj + ai[r[i]] ; 686 nz = ai[r[i]+1] - ai[r[i]]; 687 nbdiag = diag[r[i]] - ai[r[i]]; /* num of entries before the diagonal */ 688 689 rs = 0.0; 690 for (j=0; j<nz; j++) { 691 pv[j] = rtmp[pj[j]]; 692 if (j != nbdiag) rs += PetscAbsScalar(pv[j]); 693 } 694 695 /* 9/13/02 Victor Eijkhout suggested scaling zeropivot by rs for matrices with funny scalings */ 696 sctx.rs = rs; 697 sctx.pv = pv[nbdiag]; 698 ierr = MatLUCheckShift_inline(info,sctx,i,newshift);CHKERRQ(ierr); 699 if (newshift == 1) break; 700 } 701 702 if (info->shiftpd && !sctx.lushift && info->shift_fraction>0 && sctx.nshift<sctx.nshift_max) { 703 /* 704 * if no shift in this attempt & shifting & started shifting & can refine, 705 * then try lower shift 706 */ 707 sctx.shift_hi = info->shift_fraction; 708 info->shift_fraction = (sctx.shift_hi+sctx.shift_lo)/2.; 709 sctx.shift_amount = info->shift_fraction * sctx.shift_top; 710 sctx.lushift = PETSC_TRUE; 711 sctx.nshift++; 712 } 713 } while (sctx.lushift); 714 715 /* invert diagonal entries for simplier triangular solves */ 716 for (i=0; i<n; i++) { 717 a->a[diag[r[i]]] = 1.0/a->a[diag[r[i]]]; 718 } 719 720 ierr = PetscFree(rtmp);CHKERRQ(ierr); 721 ierr = ISRestoreIndices(isicol,&ic);CHKERRQ(ierr); 722 ierr = ISRestoreIndices(isrow,&r);CHKERRQ(ierr); 723 A->factor = MAT_FACTOR_LU; 724 A->ops->solve = MatSolve_SeqAIJ_InplaceWithPerm; 725 A->assembled = PETSC_TRUE; 726 A->preallocated = PETSC_TRUE; 727 ierr = PetscLogFlops(A->cmap.n);CHKERRQ(ierr); 728 if (sctx.nshift){ 729 if (info->shiftnz) { 730 ierr = PetscInfo2(A,"number of shift_nz tries %D, shift_amount %G\n",sctx.nshift,sctx.shift_amount);CHKERRQ(ierr); 731 } else if (info->shiftpd) { 732 ierr = PetscInfo4(A,"number of shift_pd tries %D, shift_amount %G, diagonal shifted up by %e fraction top_value %e\n",sctx.nshift,sctx.shift_amount,info->shift_fraction,sctx.shift_top);CHKERRQ(ierr); 733 } 734 } 735 PetscFunctionReturn(0); 736 } 737 738 /* ----------------------------------------------------------- */ 739 #undef __FUNCT__ 740 #define __FUNCT__ "MatLUFactor_SeqAIJ" 741 PetscErrorCode MatLUFactor_SeqAIJ(Mat A,IS row,IS col,MatFactorInfo *info) 742 { 743 PetscErrorCode ierr; 744 Mat C; 745 746 PetscFunctionBegin; 747 ierr = MatGetFactor(A,MAT_SOLVER_PETSC,MAT_FACTOR_LU,&C);CHKERRQ(ierr); 748 ierr = MatLUFactorSymbolic(A,row,col,info,&C);CHKERRQ(ierr); 749 ierr = MatLUFactorNumeric(A,info,&C);CHKERRQ(ierr); 750 ierr = MatHeaderCopy(A,C);CHKERRQ(ierr); 751 ierr = PetscLogObjectParent(A,((Mat_SeqAIJ*)(A->data))->icol);CHKERRQ(ierr); 752 PetscFunctionReturn(0); 753 } 754 /* ----------------------------------------------------------- */ 755 #undef __FUNCT__ 756 #define __FUNCT__ "MatSolve_SeqAIJ" 757 PetscErrorCode MatSolve_SeqAIJ(Mat A,Vec bb,Vec xx) 758 { 759 Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data; 760 IS iscol = a->col,isrow = a->row; 761 PetscErrorCode ierr; 762 PetscInt *r,*c,i, n = A->rmap.n,*vi,*ai = a->i,*aj = a->j; 763 PetscInt nz,*rout,*cout; 764 PetscScalar *x,*tmp,*tmps,sum; 765 const PetscScalar *b; 766 const MatScalar *aa = a->a,*v; 767 768 PetscFunctionBegin; 769 if (!n) PetscFunctionReturn(0); 770 771 ierr = VecGetArray(bb,(PetscScalar**)&b);CHKERRQ(ierr); 772 ierr = VecGetArray(xx,&x);CHKERRQ(ierr); 773 tmp = a->solve_work; 774 775 ierr = ISGetIndices(isrow,&rout);CHKERRQ(ierr); r = rout; 776 ierr = ISGetIndices(iscol,&cout);CHKERRQ(ierr); c = cout + (n-1); 777 778 /* forward solve the lower triangular */ 779 tmp[0] = b[*r++]; 780 tmps = tmp; 781 for (i=1; i<n; i++) { 782 v = aa + ai[i] ; 783 vi = aj + ai[i] ; 784 nz = a->diag[i] - ai[i]; 785 sum = b[*r++]; 786 SPARSEDENSEMDOT(sum,tmps,v,vi,nz); 787 tmp[i] = sum; 788 } 789 790 /* backward solve the upper triangular */ 791 for (i=n-1; i>=0; i--){ 792 v = aa + a->diag[i] + 1; 793 vi = aj + a->diag[i] + 1; 794 nz = ai[i+1] - a->diag[i] - 1; 795 sum = tmp[i]; 796 SPARSEDENSEMDOT(sum,tmps,v,vi,nz); 797 x[*c--] = tmp[i] = sum*aa[a->diag[i]]; 798 } 799 800 ierr = ISRestoreIndices(isrow,&rout);CHKERRQ(ierr); 801 ierr = ISRestoreIndices(iscol,&cout);CHKERRQ(ierr); 802 ierr = VecRestoreArray(bb,(PetscScalar**)&b);CHKERRQ(ierr); 803 ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr); 804 ierr = PetscLogFlops(2*a->nz - A->cmap.n);CHKERRQ(ierr); 805 PetscFunctionReturn(0); 806 } 807 808 #undef __FUNCT__ 809 #define __FUNCT__ "MatMatSolve_SeqAIJ" 810 PetscErrorCode MatMatSolve_SeqAIJ(Mat A,Mat B,Mat X) 811 { 812 Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data; 813 IS iscol = a->col,isrow = a->row; 814 PetscErrorCode ierr; 815 PetscInt *r,*c,i, n = A->rmap.n,*vi,*ai = a->i,*aj = a->j; 816 PetscInt nz,*rout,*cout,neq; 817 PetscScalar *x,*b,*tmp,*tmps,sum; 818 const MatScalar *aa = a->a,*v; 819 820 PetscFunctionBegin; 821 if (!n) PetscFunctionReturn(0); 822 823 ierr = MatGetArray(B,&b);CHKERRQ(ierr); 824 ierr = MatGetArray(X,&x);CHKERRQ(ierr); 825 826 tmp = a->solve_work; 827 ierr = ISGetIndices(isrow,&rout);CHKERRQ(ierr); r = rout; 828 ierr = ISGetIndices(iscol,&cout);CHKERRQ(ierr); c = cout; 829 830 for (neq=0; neq<n; neq++){ 831 /* forward solve the lower triangular */ 832 tmp[0] = b[r[0]]; 833 tmps = tmp; 834 for (i=1; i<n; i++) { 835 v = aa + ai[i] ; 836 vi = aj + ai[i] ; 837 nz = a->diag[i] - ai[i]; 838 sum = b[r[i]]; 839 SPARSEDENSEMDOT(sum,tmps,v,vi,nz); 840 tmp[i] = sum; 841 } 842 /* backward solve the upper triangular */ 843 for (i=n-1; i>=0; i--){ 844 v = aa + a->diag[i] + 1; 845 vi = aj + a->diag[i] + 1; 846 nz = ai[i+1] - a->diag[i] - 1; 847 sum = tmp[i]; 848 SPARSEDENSEMDOT(sum,tmps,v,vi,nz); 849 x[c[i]] = tmp[i] = sum*aa[a->diag[i]]; 850 } 851 852 b += n; 853 x += n; 854 } 855 ierr = ISRestoreIndices(isrow,&rout);CHKERRQ(ierr); 856 ierr = ISRestoreIndices(iscol,&cout);CHKERRQ(ierr); 857 ierr = MatRestoreArray(B,&b);CHKERRQ(ierr); 858 ierr = MatRestoreArray(X,&x);CHKERRQ(ierr); 859 ierr = PetscLogFlops(n*(2*a->nz - n));CHKERRQ(ierr); 860 PetscFunctionReturn(0); 861 } 862 863 #undef __FUNCT__ 864 #define __FUNCT__ "MatSolve_SeqAIJ_InplaceWithPerm" 865 PetscErrorCode MatSolve_SeqAIJ_InplaceWithPerm(Mat A,Vec bb,Vec xx) 866 { 867 Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data; 868 IS iscol = a->col,isrow = a->row; 869 PetscErrorCode ierr; 870 PetscInt *r,*c,i, n = A->rmap.n,*vi,*ai = a->i,*aj = a->j; 871 PetscInt nz,*rout,*cout,row; 872 PetscScalar *x,*b,*tmp,*tmps,sum; 873 const MatScalar *aa = a->a,*v; 874 875 PetscFunctionBegin; 876 if (!n) PetscFunctionReturn(0); 877 878 ierr = VecGetArray(bb,&b);CHKERRQ(ierr); 879 ierr = VecGetArray(xx,&x);CHKERRQ(ierr); 880 tmp = a->solve_work; 881 882 ierr = ISGetIndices(isrow,&rout);CHKERRQ(ierr); r = rout; 883 ierr = ISGetIndices(iscol,&cout);CHKERRQ(ierr); c = cout + (n-1); 884 885 /* forward solve the lower triangular */ 886 tmp[0] = b[*r++]; 887 tmps = tmp; 888 for (row=1; row<n; row++) { 889 i = rout[row]; /* permuted row */ 890 v = aa + ai[i] ; 891 vi = aj + ai[i] ; 892 nz = a->diag[i] - ai[i]; 893 sum = b[*r++]; 894 SPARSEDENSEMDOT(sum,tmps,v,vi,nz); 895 tmp[row] = sum; 896 } 897 898 /* backward solve the upper triangular */ 899 for (row=n-1; row>=0; row--){ 900 i = rout[row]; /* permuted row */ 901 v = aa + a->diag[i] + 1; 902 vi = aj + a->diag[i] + 1; 903 nz = ai[i+1] - a->diag[i] - 1; 904 sum = tmp[row]; 905 SPARSEDENSEMDOT(sum,tmps,v,vi,nz); 906 x[*c--] = tmp[row] = sum*aa[a->diag[i]]; 907 } 908 909 ierr = ISRestoreIndices(isrow,&rout);CHKERRQ(ierr); 910 ierr = ISRestoreIndices(iscol,&cout);CHKERRQ(ierr); 911 ierr = VecRestoreArray(bb,&b);CHKERRQ(ierr); 912 ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr); 913 ierr = PetscLogFlops(2*a->nz - A->cmap.n);CHKERRQ(ierr); 914 PetscFunctionReturn(0); 915 } 916 917 /* ----------------------------------------------------------- */ 918 #undef __FUNCT__ 919 #define __FUNCT__ "MatSolve_SeqAIJ_NaturalOrdering" 920 PetscErrorCode MatSolve_SeqAIJ_NaturalOrdering(Mat A,Vec bb,Vec xx) 921 { 922 Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data; 923 PetscErrorCode ierr; 924 PetscInt n = A->rmap.n; 925 const PetscInt *ai = a->i,*aj = a->j,*adiag = a->diag,*vi; 926 PetscScalar *x; 927 const PetscScalar *b; 928 const MatScalar *aa = a->a; 929 #if !defined(PETSC_USE_FORTRAN_KERNEL_SOLVEAIJ) 930 PetscInt adiag_i,i,nz,ai_i; 931 const MatScalar *v; 932 PetscScalar sum; 933 #endif 934 935 PetscFunctionBegin; 936 if (!n) PetscFunctionReturn(0); 937 938 ierr = VecGetArray(bb,(PetscScalar**)&b);CHKERRQ(ierr); 939 ierr = VecGetArray(xx,&x);CHKERRQ(ierr); 940 941 #if defined(PETSC_USE_FORTRAN_KERNEL_SOLVEAIJ) 942 fortransolveaij_(&n,x,ai,aj,adiag,aa,b); 943 #else 944 /* forward solve the lower triangular */ 945 x[0] = b[0]; 946 for (i=1; i<n; i++) { 947 ai_i = ai[i]; 948 v = aa + ai_i; 949 vi = aj + ai_i; 950 nz = adiag[i] - ai_i; 951 sum = b[i]; 952 while (nz--) sum -= *v++ * x[*vi++]; 953 x[i] = sum; 954 } 955 956 /* backward solve the upper triangular */ 957 for (i=n-1; i>=0; i--){ 958 adiag_i = adiag[i]; 959 v = aa + adiag_i + 1; 960 vi = aj + adiag_i + 1; 961 nz = ai[i+1] - adiag_i - 1; 962 sum = x[i]; 963 while (nz--) sum -= *v++ * x[*vi++]; 964 x[i] = sum*aa[adiag_i]; 965 } 966 #endif 967 ierr = PetscLogFlops(2*a->nz - A->cmap.n);CHKERRQ(ierr); 968 ierr = VecRestoreArray(bb,(PetscScalar**)&b);CHKERRQ(ierr); 969 ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr); 970 PetscFunctionReturn(0); 971 } 972 973 #undef __FUNCT__ 974 #define __FUNCT__ "MatSolveAdd_SeqAIJ" 975 PetscErrorCode MatSolveAdd_SeqAIJ(Mat A,Vec bb,Vec yy,Vec xx) 976 { 977 Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data; 978 IS iscol = a->col,isrow = a->row; 979 PetscErrorCode ierr; 980 PetscInt *r,*c,i, n = A->rmap.n,*vi,*ai = a->i,*aj = a->j; 981 PetscInt nz,*rout,*cout; 982 PetscScalar *x,*b,*tmp,sum; 983 const MatScalar *aa = a->a,*v; 984 985 PetscFunctionBegin; 986 if (yy != xx) {ierr = VecCopy(yy,xx);CHKERRQ(ierr);} 987 988 ierr = VecGetArray(bb,&b);CHKERRQ(ierr); 989 ierr = VecGetArray(xx,&x);CHKERRQ(ierr); 990 tmp = a->solve_work; 991 992 ierr = ISGetIndices(isrow,&rout);CHKERRQ(ierr); r = rout; 993 ierr = ISGetIndices(iscol,&cout);CHKERRQ(ierr); c = cout + (n-1); 994 995 /* forward solve the lower triangular */ 996 tmp[0] = b[*r++]; 997 for (i=1; i<n; i++) { 998 v = aa + ai[i] ; 999 vi = aj + ai[i] ; 1000 nz = a->diag[i] - ai[i]; 1001 sum = b[*r++]; 1002 while (nz--) sum -= *v++ * tmp[*vi++ ]; 1003 tmp[i] = sum; 1004 } 1005 1006 /* backward solve the upper triangular */ 1007 for (i=n-1; i>=0; i--){ 1008 v = aa + a->diag[i] + 1; 1009 vi = aj + a->diag[i] + 1; 1010 nz = ai[i+1] - a->diag[i] - 1; 1011 sum = tmp[i]; 1012 while (nz--) sum -= *v++ * tmp[*vi++ ]; 1013 tmp[i] = sum*aa[a->diag[i]]; 1014 x[*c--] += tmp[i]; 1015 } 1016 1017 ierr = ISRestoreIndices(isrow,&rout);CHKERRQ(ierr); 1018 ierr = ISRestoreIndices(iscol,&cout);CHKERRQ(ierr); 1019 ierr = VecRestoreArray(bb,&b);CHKERRQ(ierr); 1020 ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr); 1021 ierr = PetscLogFlops(2*a->nz);CHKERRQ(ierr); 1022 1023 PetscFunctionReturn(0); 1024 } 1025 /* -------------------------------------------------------------------*/ 1026 #undef __FUNCT__ 1027 #define __FUNCT__ "MatSolveTranspose_SeqAIJ" 1028 PetscErrorCode MatSolveTranspose_SeqAIJ(Mat A,Vec bb,Vec xx) 1029 { 1030 Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data; 1031 IS iscol = a->col,isrow = a->row; 1032 PetscErrorCode ierr; 1033 PetscInt *r,*c,i,n = A->rmap.n,*vi,*ai = a->i,*aj = a->j; 1034 PetscInt nz,*rout,*cout,*diag = a->diag; 1035 PetscScalar *x,*b,*tmp,s1; 1036 const MatScalar *aa = a->a,*v; 1037 1038 PetscFunctionBegin; 1039 ierr = VecGetArray(bb,&b);CHKERRQ(ierr); 1040 ierr = VecGetArray(xx,&x);CHKERRQ(ierr); 1041 tmp = a->solve_work; 1042 1043 ierr = ISGetIndices(isrow,&rout);CHKERRQ(ierr); r = rout; 1044 ierr = ISGetIndices(iscol,&cout);CHKERRQ(ierr); c = cout; 1045 1046 /* copy the b into temp work space according to permutation */ 1047 for (i=0; i<n; i++) tmp[i] = b[c[i]]; 1048 1049 /* forward solve the U^T */ 1050 for (i=0; i<n; i++) { 1051 v = aa + diag[i] ; 1052 vi = aj + diag[i] + 1; 1053 nz = ai[i+1] - diag[i] - 1; 1054 s1 = tmp[i]; 1055 s1 *= (*v++); /* multiply by inverse of diagonal entry */ 1056 while (nz--) { 1057 tmp[*vi++ ] -= (*v++)*s1; 1058 } 1059 tmp[i] = s1; 1060 } 1061 1062 /* backward solve the L^T */ 1063 for (i=n-1; i>=0; i--){ 1064 v = aa + diag[i] - 1 ; 1065 vi = aj + diag[i] - 1 ; 1066 nz = diag[i] - ai[i]; 1067 s1 = tmp[i]; 1068 while (nz--) { 1069 tmp[*vi-- ] -= (*v--)*s1; 1070 } 1071 } 1072 1073 /* copy tmp into x according to permutation */ 1074 for (i=0; i<n; i++) x[r[i]] = tmp[i]; 1075 1076 ierr = ISRestoreIndices(isrow,&rout);CHKERRQ(ierr); 1077 ierr = ISRestoreIndices(iscol,&cout);CHKERRQ(ierr); 1078 ierr = VecRestoreArray(bb,&b);CHKERRQ(ierr); 1079 ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr); 1080 1081 ierr = PetscLogFlops(2*a->nz-A->cmap.n);CHKERRQ(ierr); 1082 PetscFunctionReturn(0); 1083 } 1084 1085 #undef __FUNCT__ 1086 #define __FUNCT__ "MatSolveTransposeAdd_SeqAIJ" 1087 PetscErrorCode MatSolveTransposeAdd_SeqAIJ(Mat A,Vec bb,Vec zz,Vec xx) 1088 { 1089 Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data; 1090 IS iscol = a->col,isrow = a->row; 1091 PetscErrorCode ierr; 1092 PetscInt *r,*c,i,n = A->rmap.n,*vi,*ai = a->i,*aj = a->j; 1093 PetscInt nz,*rout,*cout,*diag = a->diag; 1094 PetscScalar *x,*b,*tmp; 1095 const MatScalar *aa = a->a,*v; 1096 1097 PetscFunctionBegin; 1098 if (zz != xx) {ierr = VecCopy(zz,xx);CHKERRQ(ierr);} 1099 1100 ierr = VecGetArray(bb,&b);CHKERRQ(ierr); 1101 ierr = VecGetArray(xx,&x);CHKERRQ(ierr); 1102 tmp = a->solve_work; 1103 1104 ierr = ISGetIndices(isrow,&rout);CHKERRQ(ierr); r = rout; 1105 ierr = ISGetIndices(iscol,&cout);CHKERRQ(ierr); c = cout; 1106 1107 /* copy the b into temp work space according to permutation */ 1108 for (i=0; i<n; i++) tmp[i] = b[c[i]]; 1109 1110 /* forward solve the U^T */ 1111 for (i=0; i<n; i++) { 1112 v = aa + diag[i] ; 1113 vi = aj + diag[i] + 1; 1114 nz = ai[i+1] - diag[i] - 1; 1115 tmp[i] *= *v++; 1116 while (nz--) { 1117 tmp[*vi++ ] -= (*v++)*tmp[i]; 1118 } 1119 } 1120 1121 /* backward solve the L^T */ 1122 for (i=n-1; i>=0; i--){ 1123 v = aa + diag[i] - 1 ; 1124 vi = aj + diag[i] - 1 ; 1125 nz = diag[i] - ai[i]; 1126 while (nz--) { 1127 tmp[*vi-- ] -= (*v--)*tmp[i]; 1128 } 1129 } 1130 1131 /* copy tmp into x according to permutation */ 1132 for (i=0; i<n; i++) x[r[i]] += tmp[i]; 1133 1134 ierr = ISRestoreIndices(isrow,&rout);CHKERRQ(ierr); 1135 ierr = ISRestoreIndices(iscol,&cout);CHKERRQ(ierr); 1136 ierr = VecRestoreArray(bb,&b);CHKERRQ(ierr); 1137 ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr); 1138 1139 ierr = PetscLogFlops(2*a->nz);CHKERRQ(ierr); 1140 PetscFunctionReturn(0); 1141 } 1142 /* ----------------------------------------------------------------*/ 1143 EXTERN PetscErrorCode Mat_CheckInode(Mat,PetscTruth); 1144 EXTERN PetscErrorCode MatDuplicateNoCreate_SeqAIJ(Mat,MatDuplicateOption,Mat*); 1145 1146 #undef __FUNCT__ 1147 #define __FUNCT__ "MatILUFactorSymbolic_SeqAIJ" 1148 PetscErrorCode MatILUFactorSymbolic_SeqAIJ(Mat A,IS isrow,IS iscol,MatFactorInfo *info,Mat *fact) 1149 { 1150 Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data,*b; 1151 IS isicol; 1152 PetscErrorCode ierr; 1153 PetscInt *r,*ic,n=A->rmap.n,*ai=a->i,*aj=a->j,d; 1154 PetscInt *bi,*cols,nnz,*cols_lvl; 1155 PetscInt *bdiag,prow,fm,nzbd,len, reallocs=0,dcount=0; 1156 PetscInt i,levels,diagonal_fill; 1157 PetscTruth col_identity,row_identity; 1158 PetscReal f; 1159 PetscInt nlnk,*lnk,*lnk_lvl=PETSC_NULL; 1160 PetscBT lnkbt; 1161 PetscInt nzi,*bj,**bj_ptr,**bjlvl_ptr; 1162 PetscFreeSpaceList free_space=PETSC_NULL,current_space=PETSC_NULL; 1163 PetscFreeSpaceList free_space_lvl=PETSC_NULL,current_space_lvl=PETSC_NULL; 1164 PetscTruth missing; 1165 1166 PetscFunctionBegin; 1167 if (A->rmap.n != A->cmap.n) SETERRQ2(PETSC_ERR_ARG_WRONG,"Must be square matrix, rows %D columns %D",A->rmap.n,A->cmap.n); 1168 f = info->fill; 1169 levels = (PetscInt)info->levels; 1170 diagonal_fill = (PetscInt)info->diagonal_fill; 1171 ierr = ISInvertPermutation(iscol,PETSC_DECIDE,&isicol);CHKERRQ(ierr); 1172 1173 /* special case that simply copies fill pattern */ 1174 ierr = ISIdentity(isrow,&row_identity);CHKERRQ(ierr); 1175 ierr = ISIdentity(iscol,&col_identity);CHKERRQ(ierr); 1176 if (!levels && row_identity && col_identity) { 1177 ierr = MatDuplicateNoCreate_SeqAIJ(A,MAT_DO_NOT_COPY_VALUES,fact);CHKERRQ(ierr); 1178 (*fact)->factor = MAT_FACTOR_LU; 1179 (*fact)->info.factor_mallocs = 0; 1180 (*fact)->info.fill_ratio_given = info->fill; 1181 (*fact)->info.fill_ratio_needed = 1.0; 1182 b = (Mat_SeqAIJ*)(*fact)->data; 1183 ierr = MatMissingDiagonal(A,&missing,&d);CHKERRQ(ierr); 1184 if (missing) SETERRQ1(PETSC_ERR_ARG_WRONGSTATE,"Matrix is missing diagonal entry %D",d); 1185 b->row = isrow; 1186 b->col = iscol; 1187 b->icol = isicol; 1188 ierr = PetscMalloc(((*fact)->rmap.n+1)*sizeof(PetscScalar),&b->solve_work);CHKERRQ(ierr); 1189 (*fact)->ops->solve = MatSolve_SeqAIJ_NaturalOrdering; 1190 ierr = PetscObjectReference((PetscObject)isrow);CHKERRQ(ierr); 1191 ierr = PetscObjectReference((PetscObject)iscol);CHKERRQ(ierr); 1192 ierr = Mat_CheckInode(*fact,PETSC_FALSE);CHKERRQ(ierr); 1193 PetscFunctionReturn(0); 1194 } 1195 1196 ierr = ISGetIndices(isrow,&r);CHKERRQ(ierr); 1197 ierr = ISGetIndices(isicol,&ic);CHKERRQ(ierr); 1198 1199 /* get new row pointers */ 1200 ierr = PetscMalloc((n+1)*sizeof(PetscInt),&bi);CHKERRQ(ierr); 1201 bi[0] = 0; 1202 /* bdiag is location of diagonal in factor */ 1203 ierr = PetscMalloc((n+1)*sizeof(PetscInt),&bdiag);CHKERRQ(ierr); 1204 bdiag[0] = 0; 1205 1206 ierr = PetscMalloc((2*n+1)*sizeof(PetscInt**),&bj_ptr);CHKERRQ(ierr); 1207 bjlvl_ptr = (PetscInt**)(bj_ptr + n); 1208 1209 /* create a linked list for storing column indices of the active row */ 1210 nlnk = n + 1; 1211 ierr = PetscIncompleteLLCreate(n,n,nlnk,lnk,lnk_lvl,lnkbt);CHKERRQ(ierr); 1212 1213 /* initial FreeSpace size is f*(ai[n]+1) */ 1214 ierr = PetscFreeSpaceGet((PetscInt)(f*(ai[n]+1)),&free_space);CHKERRQ(ierr); 1215 current_space = free_space; 1216 ierr = PetscFreeSpaceGet((PetscInt)(f*(ai[n]+1)),&free_space_lvl);CHKERRQ(ierr); 1217 current_space_lvl = free_space_lvl; 1218 1219 for (i=0; i<n; i++) { 1220 nzi = 0; 1221 /* copy current row into linked list */ 1222 nnz = ai[r[i]+1] - ai[r[i]]; 1223 if (!nnz) SETERRQ(PETSC_ERR_MAT_LU_ZRPVT,"Empty row in matrix"); 1224 cols = aj + ai[r[i]]; 1225 lnk[i] = -1; /* marker to indicate if diagonal exists */ 1226 ierr = PetscIncompleteLLInit(nnz,cols,n,ic,nlnk,lnk,lnk_lvl,lnkbt);CHKERRQ(ierr); 1227 nzi += nlnk; 1228 1229 /* make sure diagonal entry is included */ 1230 if (diagonal_fill && lnk[i] == -1) { 1231 fm = n; 1232 while (lnk[fm] < i) fm = lnk[fm]; 1233 lnk[i] = lnk[fm]; /* insert diagonal into linked list */ 1234 lnk[fm] = i; 1235 lnk_lvl[i] = 0; 1236 nzi++; dcount++; 1237 } 1238 1239 /* add pivot rows into the active row */ 1240 nzbd = 0; 1241 prow = lnk[n]; 1242 while (prow < i) { 1243 nnz = bdiag[prow]; 1244 cols = bj_ptr[prow] + nnz + 1; 1245 cols_lvl = bjlvl_ptr[prow] + nnz + 1; 1246 nnz = bi[prow+1] - bi[prow] - nnz - 1; 1247 ierr = PetscILULLAddSorted(nnz,cols,levels,cols_lvl,prow,nlnk,lnk,lnk_lvl,lnkbt,prow);CHKERRQ(ierr); 1248 nzi += nlnk; 1249 prow = lnk[prow]; 1250 nzbd++; 1251 } 1252 bdiag[i] = nzbd; 1253 bi[i+1] = bi[i] + nzi; 1254 1255 /* if free space is not available, make more free space */ 1256 if (current_space->local_remaining<nzi) { 1257 nnz = nzi*(n - i); /* estimated and max additional space needed */ 1258 ierr = PetscFreeSpaceGet(nnz,¤t_space);CHKERRQ(ierr); 1259 ierr = PetscFreeSpaceGet(nnz,¤t_space_lvl);CHKERRQ(ierr); 1260 reallocs++; 1261 } 1262 1263 /* copy data into free_space and free_space_lvl, then initialize lnk */ 1264 ierr = PetscIncompleteLLClean(n,n,nzi,lnk,lnk_lvl,current_space->array,current_space_lvl->array,lnkbt);CHKERRQ(ierr); 1265 bj_ptr[i] = current_space->array; 1266 bjlvl_ptr[i] = current_space_lvl->array; 1267 1268 /* make sure the active row i has diagonal entry */ 1269 if (*(bj_ptr[i]+bdiag[i]) != i) { 1270 SETERRQ1(PETSC_ERR_MAT_LU_ZRPVT,"Row %D has missing diagonal in factored matrix\n\ 1271 try running with -pc_factor_nonzeros_along_diagonal or -pc_factor_diagonal_fill",i); 1272 } 1273 1274 current_space->array += nzi; 1275 current_space->local_used += nzi; 1276 current_space->local_remaining -= nzi; 1277 current_space_lvl->array += nzi; 1278 current_space_lvl->local_used += nzi; 1279 current_space_lvl->local_remaining -= nzi; 1280 } 1281 1282 ierr = ISRestoreIndices(isrow,&r);CHKERRQ(ierr); 1283 ierr = ISRestoreIndices(isicol,&ic);CHKERRQ(ierr); 1284 1285 /* destroy list of free space and other temporary arrays */ 1286 ierr = PetscMalloc((bi[n]+1)*sizeof(PetscInt),&bj);CHKERRQ(ierr); 1287 ierr = PetscFreeSpaceContiguous(&free_space,bj);CHKERRQ(ierr); 1288 ierr = PetscIncompleteLLDestroy(lnk,lnkbt);CHKERRQ(ierr); 1289 ierr = PetscFreeSpaceDestroy(free_space_lvl);CHKERRQ(ierr); 1290 ierr = PetscFree(bj_ptr);CHKERRQ(ierr); 1291 1292 #if defined(PETSC_USE_INFO) 1293 { 1294 PetscReal af = ((PetscReal)bi[n])/((PetscReal)ai[n]); 1295 ierr = PetscInfo3(A,"Reallocs %D Fill ratio:given %G needed %G\n",reallocs,f,af);CHKERRQ(ierr); 1296 ierr = PetscInfo1(A,"Run with -[sub_]pc_factor_fill %G or use \n",af);CHKERRQ(ierr); 1297 ierr = PetscInfo1(A,"PCFactorSetFill([sub]pc,%G);\n",af);CHKERRQ(ierr); 1298 ierr = PetscInfo(A,"for best performance.\n");CHKERRQ(ierr); 1299 if (diagonal_fill) { 1300 ierr = PetscInfo1(A,"Detected and replaced %D missing diagonals",dcount);CHKERRQ(ierr); 1301 } 1302 } 1303 #endif 1304 1305 /* put together the new matrix */ 1306 ierr = PetscLogObjectParent(*fact,isicol);CHKERRQ(ierr); 1307 b = (Mat_SeqAIJ*)(*fact)->data; 1308 b->free_a = PETSC_TRUE; 1309 b->free_ij = PETSC_TRUE; 1310 b->singlemalloc = PETSC_FALSE; 1311 len = (bi[n] )*sizeof(PetscScalar); 1312 ierr = PetscMalloc(len+1,&b->a);CHKERRQ(ierr); 1313 b->j = bj; 1314 b->i = bi; 1315 for (i=0; i<n; i++) bdiag[i] += bi[i]; 1316 b->diag = bdiag; 1317 b->ilen = 0; 1318 b->imax = 0; 1319 b->row = isrow; 1320 b->col = iscol; 1321 ierr = PetscObjectReference((PetscObject)isrow);CHKERRQ(ierr); 1322 ierr = PetscObjectReference((PetscObject)iscol);CHKERRQ(ierr); 1323 b->icol = isicol; 1324 ierr = PetscMalloc((n+1)*sizeof(PetscScalar),&b->solve_work);CHKERRQ(ierr); 1325 /* In b structure: Free imax, ilen, old a, old j. 1326 Allocate bdiag, solve_work, new a, new j */ 1327 ierr = PetscLogObjectMemory(*fact,(bi[n]-n) * (sizeof(PetscInt)+sizeof(PetscScalar)));CHKERRQ(ierr); 1328 b->maxnz = b->nz = bi[n] ; 1329 (*fact)->factor = MAT_FACTOR_LU; 1330 (*fact)->info.factor_mallocs = reallocs; 1331 (*fact)->info.fill_ratio_given = f; 1332 (*fact)->info.fill_ratio_needed = ((PetscReal)bi[n])/((PetscReal)ai[n]); 1333 1334 ierr = MatILUFactorSymbolic_Inode(A,isrow,iscol,info,fact);CHKERRQ(ierr); 1335 (*fact)->ops->lufactornumeric = A->ops->lufactornumeric; /* Use Inode variant ONLY if A has inodes */ 1336 1337 PetscFunctionReturn(0); 1338 } 1339 1340 #include "src/mat/impls/sbaij/seq/sbaij.h" 1341 #undef __FUNCT__ 1342 #define __FUNCT__ "MatCholeskyFactorNumeric_SeqAIJ" 1343 PetscErrorCode MatCholeskyFactorNumeric_SeqAIJ(Mat A,MatFactorInfo *info,Mat *B) 1344 { 1345 Mat C = *B; 1346 Mat_SeqAIJ *a=(Mat_SeqAIJ*)A->data; 1347 Mat_SeqSBAIJ *b=(Mat_SeqSBAIJ*)C->data; 1348 IS ip=b->row,iip = b->icol; 1349 PetscErrorCode ierr; 1350 PetscInt *rip,*riip,i,j,mbs=A->rmap.n,*bi=b->i,*bj=b->j,*bcol; 1351 PetscInt *ai=a->i,*aj=a->j; 1352 PetscInt k,jmin,jmax,*jl,*il,col,nexti,ili,nz; 1353 MatScalar *rtmp,*ba=b->a,*bval,*aa=a->a,dk,uikdi; 1354 PetscReal zeropivot,rs,shiftnz; 1355 PetscReal shiftpd; 1356 ChShift_Ctx sctx; 1357 PetscInt newshift; 1358 1359 PetscFunctionBegin; 1360 1361 shiftnz = info->shiftnz; 1362 shiftpd = info->shiftpd; 1363 zeropivot = info->zeropivot; 1364 1365 ierr = ISGetIndices(ip,&rip);CHKERRQ(ierr); 1366 ierr = ISGetIndices(iip,&riip);CHKERRQ(ierr); 1367 1368 /* initialization */ 1369 nz = (2*mbs+1)*sizeof(PetscInt)+mbs*sizeof(MatScalar); 1370 ierr = PetscMalloc(nz,&il);CHKERRQ(ierr); 1371 jl = il + mbs; 1372 rtmp = (MatScalar*)(jl + mbs); 1373 1374 sctx.shift_amount = 0; 1375 sctx.nshift = 0; 1376 do { 1377 sctx.chshift = PETSC_FALSE; 1378 for (i=0; i<mbs; i++) { 1379 rtmp[i] = 0.0; jl[i] = mbs; il[0] = 0; 1380 } 1381 1382 for (k = 0; k<mbs; k++){ 1383 bval = ba + bi[k]; 1384 /* initialize k-th row by the perm[k]-th row of A */ 1385 jmin = ai[rip[k]]; jmax = ai[rip[k]+1]; 1386 for (j = jmin; j < jmax; j++){ 1387 col = riip[aj[j]]; 1388 if (col >= k){ /* only take upper triangular entry */ 1389 rtmp[col] = aa[j]; 1390 *bval++ = 0.0; /* for in-place factorization */ 1391 } 1392 } 1393 /* shift the diagonal of the matrix */ 1394 if (sctx.nshift) rtmp[k] += sctx.shift_amount; 1395 1396 /* modify k-th row by adding in those rows i with U(i,k)!=0 */ 1397 dk = rtmp[k]; 1398 i = jl[k]; /* first row to be added to k_th row */ 1399 1400 while (i < k){ 1401 nexti = jl[i]; /* next row to be added to k_th row */ 1402 1403 /* compute multiplier, update diag(k) and U(i,k) */ 1404 ili = il[i]; /* index of first nonzero element in U(i,k:bms-1) */ 1405 uikdi = - ba[ili]*ba[bi[i]]; /* diagonal(k) */ 1406 dk += uikdi*ba[ili]; 1407 ba[ili] = uikdi; /* -U(i,k) */ 1408 1409 /* add multiple of row i to k-th row */ 1410 jmin = ili + 1; jmax = bi[i+1]; 1411 if (jmin < jmax){ 1412 for (j=jmin; j<jmax; j++) rtmp[bj[j]] += uikdi*ba[j]; 1413 /* update il and jl for row i */ 1414 il[i] = jmin; 1415 j = bj[jmin]; jl[i] = jl[j]; jl[j] = i; 1416 } 1417 i = nexti; 1418 } 1419 1420 /* shift the diagonals when zero pivot is detected */ 1421 /* compute rs=sum of abs(off-diagonal) */ 1422 rs = 0.0; 1423 jmin = bi[k]+1; 1424 nz = bi[k+1] - jmin; 1425 bcol = bj + jmin; 1426 while (nz--){ 1427 rs += PetscAbsScalar(rtmp[*bcol]); 1428 bcol++; 1429 } 1430 1431 sctx.rs = rs; 1432 sctx.pv = dk; 1433 ierr = MatCholeskyCheckShift_inline(info,sctx,k,newshift);CHKERRQ(ierr); 1434 1435 if (newshift == 1) { 1436 if (!sctx.shift_amount) { 1437 sctx.shift_amount = 1e-5; 1438 } 1439 break; 1440 } 1441 1442 /* copy data into U(k,:) */ 1443 ba[bi[k]] = 1.0/dk; /* U(k,k) */ 1444 jmin = bi[k]+1; jmax = bi[k+1]; 1445 if (jmin < jmax) { 1446 for (j=jmin; j<jmax; j++){ 1447 col = bj[j]; ba[j] = rtmp[col]; rtmp[col] = 0.0; 1448 } 1449 /* add the k-th row into il and jl */ 1450 il[k] = jmin; 1451 i = bj[jmin]; jl[k] = jl[i]; jl[i] = k; 1452 } 1453 } 1454 } while (sctx.chshift); 1455 ierr = PetscFree(il);CHKERRQ(ierr); 1456 1457 ierr = ISRestoreIndices(ip,&rip);CHKERRQ(ierr); 1458 ierr = ISRestoreIndices(iip,&riip);CHKERRQ(ierr); 1459 C->factor = MAT_FACTOR_CHOLESKY; 1460 C->assembled = PETSC_TRUE; 1461 C->preallocated = PETSC_TRUE; 1462 ierr = PetscLogFlops(C->rmap.n);CHKERRQ(ierr); 1463 if (sctx.nshift){ 1464 if (shiftnz) { 1465 ierr = PetscInfo2(A,"number of shiftnz tries %D, shift_amount %G\n",sctx.nshift,sctx.shift_amount);CHKERRQ(ierr); 1466 } else if (shiftpd) { 1467 ierr = PetscInfo2(A,"number of shiftpd tries %D, shift_amount %G\n",sctx.nshift,sctx.shift_amount);CHKERRQ(ierr); 1468 } 1469 } 1470 PetscFunctionReturn(0); 1471 } 1472 1473 #undef __FUNCT__ 1474 #define __FUNCT__ "MatICCFactorSymbolic_SeqAIJ" 1475 PetscErrorCode MatICCFactorSymbolic_SeqAIJ(Mat A,IS perm,MatFactorInfo *info,Mat *fact) 1476 { 1477 Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data; 1478 Mat_SeqSBAIJ *b; 1479 PetscErrorCode ierr; 1480 PetscTruth perm_identity,missing; 1481 PetscInt reallocs=0,*rip,*riip,i,*ai=a->i,*aj=a->j,am=A->rmap.n,*ui; 1482 PetscInt jmin,jmax,nzk,k,j,*jl,prow,*il,nextprow; 1483 PetscInt nlnk,*lnk,*lnk_lvl=PETSC_NULL,d; 1484 PetscInt ncols,ncols_upper,*cols,*ajtmp,*uj,**uj_ptr,**uj_lvl_ptr; 1485 PetscReal fill=info->fill,levels=info->levels; 1486 PetscFreeSpaceList free_space=PETSC_NULL,current_space=PETSC_NULL; 1487 PetscFreeSpaceList free_space_lvl=PETSC_NULL,current_space_lvl=PETSC_NULL; 1488 PetscBT lnkbt; 1489 IS iperm; 1490 1491 PetscFunctionBegin; 1492 if (A->rmap.n != A->cmap.n) SETERRQ2(PETSC_ERR_ARG_WRONG,"Must be square matrix, rows %D columns %D",A->rmap.n,A->cmap.n); 1493 ierr = MatMissingDiagonal(A,&missing,&d);CHKERRQ(ierr); 1494 if (missing) SETERRQ1(PETSC_ERR_ARG_WRONGSTATE,"Matrix is missing diagonal entry %D",d); 1495 ierr = ISIdentity(perm,&perm_identity);CHKERRQ(ierr); 1496 ierr = ISInvertPermutation(perm,PETSC_DECIDE,&iperm);CHKERRQ(ierr); 1497 1498 ierr = PetscMalloc((am+1)*sizeof(PetscInt),&ui);CHKERRQ(ierr); 1499 ui[0] = 0; 1500 1501 /* ICC(0) without matrix ordering: simply copies fill pattern */ 1502 if (!levels && perm_identity) { 1503 1504 for (i=0; i<am; i++) { 1505 ui[i+1] = ui[i] + ai[i+1] - a->diag[i]; 1506 } 1507 ierr = PetscMalloc((ui[am]+1)*sizeof(PetscInt),&uj);CHKERRQ(ierr); 1508 cols = uj; 1509 for (i=0; i<am; i++) { 1510 aj = a->j + a->diag[i]; 1511 ncols = ui[i+1] - ui[i]; 1512 for (j=0; j<ncols; j++) *cols++ = *aj++; 1513 } 1514 } else { /* case: levels>0 || (levels=0 && !perm_identity) */ 1515 ierr = ISGetIndices(iperm,&riip);CHKERRQ(ierr); 1516 ierr = ISGetIndices(perm,&rip);CHKERRQ(ierr); 1517 1518 /* initialization */ 1519 ierr = PetscMalloc((am+1)*sizeof(PetscInt),&ajtmp);CHKERRQ(ierr); 1520 1521 /* jl: linked list for storing indices of the pivot rows 1522 il: il[i] points to the 1st nonzero entry of U(i,k:am-1) */ 1523 ierr = PetscMalloc((2*am+1)*sizeof(PetscInt)+2*am*sizeof(PetscInt**),&jl);CHKERRQ(ierr); 1524 il = jl + am; 1525 uj_ptr = (PetscInt**)(il + am); 1526 uj_lvl_ptr = (PetscInt**)(uj_ptr + am); 1527 for (i=0; i<am; i++){ 1528 jl[i] = am; il[i] = 0; 1529 } 1530 1531 /* create and initialize a linked list for storing column indices of the active row k */ 1532 nlnk = am + 1; 1533 ierr = PetscIncompleteLLCreate(am,am,nlnk,lnk,lnk_lvl,lnkbt);CHKERRQ(ierr); 1534 1535 /* initial FreeSpace size is fill*(ai[am]+1) */ 1536 ierr = PetscFreeSpaceGet((PetscInt)(fill*(ai[am]+1)),&free_space);CHKERRQ(ierr); 1537 current_space = free_space; 1538 ierr = PetscFreeSpaceGet((PetscInt)(fill*(ai[am]+1)),&free_space_lvl);CHKERRQ(ierr); 1539 current_space_lvl = free_space_lvl; 1540 1541 for (k=0; k<am; k++){ /* for each active row k */ 1542 /* initialize lnk by the column indices of row rip[k] of A */ 1543 nzk = 0; 1544 ncols = ai[rip[k]+1] - ai[rip[k]]; 1545 if (!ncols) SETERRQ(PETSC_ERR_MAT_CH_ZRPVT,"Empty row in matrix"); 1546 ncols_upper = 0; 1547 for (j=0; j<ncols; j++){ 1548 i = *(aj + ai[rip[k]] + j); /* unpermuted column index */ 1549 if (riip[i] >= k){ /* only take upper triangular entry */ 1550 ajtmp[ncols_upper] = i; 1551 ncols_upper++; 1552 } 1553 } 1554 ierr = PetscIncompleteLLInit(ncols_upper,ajtmp,am,riip,nlnk,lnk,lnk_lvl,lnkbt);CHKERRQ(ierr); 1555 nzk += nlnk; 1556 1557 /* update lnk by computing fill-in for each pivot row to be merged in */ 1558 prow = jl[k]; /* 1st pivot row */ 1559 1560 while (prow < k){ 1561 nextprow = jl[prow]; 1562 1563 /* merge prow into k-th row */ 1564 jmin = il[prow] + 1; /* index of the 2nd nzero entry in U(prow,k:am-1) */ 1565 jmax = ui[prow+1]; 1566 ncols = jmax-jmin; 1567 i = jmin - ui[prow]; 1568 cols = uj_ptr[prow] + i; /* points to the 2nd nzero entry in U(prow,k:am-1) */ 1569 uj = uj_lvl_ptr[prow] + i; /* levels of cols */ 1570 j = *(uj - 1); 1571 ierr = PetscICCLLAddSorted(ncols,cols,levels,uj,am,nlnk,lnk,lnk_lvl,lnkbt,j);CHKERRQ(ierr); 1572 nzk += nlnk; 1573 1574 /* update il and jl for prow */ 1575 if (jmin < jmax){ 1576 il[prow] = jmin; 1577 j = *cols; jl[prow] = jl[j]; jl[j] = prow; 1578 } 1579 prow = nextprow; 1580 } 1581 1582 /* if free space is not available, make more free space */ 1583 if (current_space->local_remaining<nzk) { 1584 i = am - k + 1; /* num of unfactored rows */ 1585 i = PetscMin(i*nzk, i*(i-1)); /* i*nzk, i*(i-1): estimated and max additional space needed */ 1586 ierr = PetscFreeSpaceGet(i,¤t_space);CHKERRQ(ierr); 1587 ierr = PetscFreeSpaceGet(i,¤t_space_lvl);CHKERRQ(ierr); 1588 reallocs++; 1589 } 1590 1591 /* copy data into free_space and free_space_lvl, then initialize lnk */ 1592 if (nzk == 0) SETERRQ1(PETSC_ERR_ARG_WRONG,"Empty row %D in ICC matrix factor",k); 1593 ierr = PetscIncompleteLLClean(am,am,nzk,lnk,lnk_lvl,current_space->array,current_space_lvl->array,lnkbt);CHKERRQ(ierr); 1594 1595 /* add the k-th row into il and jl */ 1596 if (nzk > 1){ 1597 i = current_space->array[1]; /* col value of the first nonzero element in U(k, k+1:am-1) */ 1598 jl[k] = jl[i]; jl[i] = k; 1599 il[k] = ui[k] + 1; 1600 } 1601 uj_ptr[k] = current_space->array; 1602 uj_lvl_ptr[k] = current_space_lvl->array; 1603 1604 current_space->array += nzk; 1605 current_space->local_used += nzk; 1606 current_space->local_remaining -= nzk; 1607 1608 current_space_lvl->array += nzk; 1609 current_space_lvl->local_used += nzk; 1610 current_space_lvl->local_remaining -= nzk; 1611 1612 ui[k+1] = ui[k] + nzk; 1613 } 1614 1615 #if defined(PETSC_USE_INFO) 1616 if (ai[am] != 0) { 1617 PetscReal af = (PetscReal)ui[am]/((PetscReal)ai[am]); 1618 ierr = PetscInfo3(A,"Reallocs %D Fill ratio:given %G needed %G\n",reallocs,fill,af);CHKERRQ(ierr); 1619 ierr = PetscInfo1(A,"Run with -pc_factor_fill %G or use \n",af);CHKERRQ(ierr); 1620 ierr = PetscInfo1(A,"PCFactorSetFill(pc,%G) for best performance.\n",af);CHKERRQ(ierr); 1621 } else { 1622 ierr = PetscInfo(A,"Empty matrix.\n");CHKERRQ(ierr); 1623 } 1624 #endif 1625 1626 ierr = ISRestoreIndices(perm,&rip);CHKERRQ(ierr); 1627 ierr = ISRestoreIndices(iperm,&riip);CHKERRQ(ierr); 1628 ierr = PetscFree(jl);CHKERRQ(ierr); 1629 ierr = PetscFree(ajtmp);CHKERRQ(ierr); 1630 1631 /* destroy list of free space and other temporary array(s) */ 1632 ierr = PetscMalloc((ui[am]+1)*sizeof(PetscInt),&uj);CHKERRQ(ierr); 1633 ierr = PetscFreeSpaceContiguous(&free_space,uj);CHKERRQ(ierr); 1634 ierr = PetscIncompleteLLDestroy(lnk,lnkbt);CHKERRQ(ierr); 1635 ierr = PetscFreeSpaceDestroy(free_space_lvl);CHKERRQ(ierr); 1636 1637 } /* end of case: levels>0 || (levels=0 && !perm_identity) */ 1638 1639 /* put together the new matrix in MATSEQSBAIJ format */ 1640 1641 b = (Mat_SeqSBAIJ*)(*fact)->data; 1642 b->singlemalloc = PETSC_FALSE; 1643 ierr = PetscMalloc((ui[am]+1)*sizeof(MatScalar),&b->a);CHKERRQ(ierr); 1644 b->j = uj; 1645 b->i = ui; 1646 b->diag = 0; 1647 b->ilen = 0; 1648 b->imax = 0; 1649 b->row = perm; 1650 b->col = perm; 1651 ierr = PetscObjectReference((PetscObject)perm);CHKERRQ(ierr); 1652 ierr = PetscObjectReference((PetscObject)perm);CHKERRQ(ierr); 1653 b->icol = iperm; 1654 b->pivotinblocks = PETSC_FALSE; /* need to get from MatFactorInfo */ 1655 ierr = PetscMalloc((am+1)*sizeof(PetscScalar),&b->solve_work);CHKERRQ(ierr); 1656 ierr = PetscLogObjectMemory((*fact),(ui[am]-am)*(sizeof(PetscInt)+sizeof(MatScalar)));CHKERRQ(ierr); 1657 b->maxnz = b->nz = ui[am]; 1658 b->free_a = PETSC_TRUE; 1659 b->free_ij = PETSC_TRUE; 1660 1661 (*fact)->factor = MAT_FACTOR_CHOLESKY; 1662 (*fact)->info.factor_mallocs = reallocs; 1663 (*fact)->info.fill_ratio_given = fill; 1664 if (ai[am] != 0) { 1665 (*fact)->info.fill_ratio_needed = ((PetscReal)ui[am])/((PetscReal)ai[am]); 1666 } else { 1667 (*fact)->info.fill_ratio_needed = 0.0; 1668 } 1669 (*fact)->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqAIJ; 1670 if (perm_identity){ 1671 (*fact)->ops->solve = MatSolve_SeqSBAIJ_1_NaturalOrdering; 1672 (*fact)->ops->solvetranspose = MatSolve_SeqSBAIJ_1_NaturalOrdering; 1673 } 1674 PetscFunctionReturn(0); 1675 } 1676 1677 #undef __FUNCT__ 1678 #define __FUNCT__ "MatCholeskyFactorSymbolic_SeqAIJ" 1679 PetscErrorCode MatCholeskyFactorSymbolic_SeqAIJ(Mat A,IS perm,MatFactorInfo *info,Mat *fact) 1680 { 1681 Mat_SeqAIJ *a = (Mat_SeqAIJ*)A->data; 1682 Mat_SeqSBAIJ *b; 1683 PetscErrorCode ierr; 1684 PetscTruth perm_identity; 1685 PetscReal fill = info->fill; 1686 PetscInt *rip,*riip,i,am=A->rmap.n,*ai=a->i,*aj=a->j,reallocs=0,prow; 1687 PetscInt *jl,jmin,jmax,nzk,*ui,k,j,*il,nextprow; 1688 PetscInt nlnk,*lnk,ncols,ncols_upper,*cols,*uj,**ui_ptr,*uj_ptr; 1689 PetscFreeSpaceList free_space=PETSC_NULL,current_space=PETSC_NULL; 1690 PetscBT lnkbt; 1691 IS iperm; 1692 1693 PetscFunctionBegin; 1694 if (A->rmap.n != A->cmap.n) SETERRQ2(PETSC_ERR_ARG_WRONG,"Must be square matrix, rows %D columns %D",A->rmap.n,A->cmap.n); 1695 /* check whether perm is the identity mapping */ 1696 ierr = ISIdentity(perm,&perm_identity);CHKERRQ(ierr); 1697 ierr = ISInvertPermutation(perm,PETSC_DECIDE,&iperm);CHKERRQ(ierr); 1698 ierr = ISGetIndices(iperm,&riip);CHKERRQ(ierr); 1699 ierr = ISGetIndices(perm,&rip);CHKERRQ(ierr); 1700 1701 /* initialization */ 1702 ierr = PetscMalloc((am+1)*sizeof(PetscInt),&ui);CHKERRQ(ierr); 1703 ui[0] = 0; 1704 1705 /* jl: linked list for storing indices of the pivot rows 1706 il: il[i] points to the 1st nonzero entry of U(i,k:am-1) */ 1707 ierr = PetscMalloc((3*am+1)*sizeof(PetscInt)+am*sizeof(PetscInt**),&jl);CHKERRQ(ierr); 1708 il = jl + am; 1709 cols = il + am; 1710 ui_ptr = (PetscInt**)(cols + am); 1711 for (i=0; i<am; i++){ 1712 jl[i] = am; il[i] = 0; 1713 } 1714 1715 /* create and initialize a linked list for storing column indices of the active row k */ 1716 nlnk = am + 1; 1717 ierr = PetscLLCreate(am,am,nlnk,lnk,lnkbt);CHKERRQ(ierr); 1718 1719 /* initial FreeSpace size is fill*(ai[am]+1) */ 1720 ierr = PetscFreeSpaceGet((PetscInt)(fill*(ai[am]+1)),&free_space);CHKERRQ(ierr); 1721 current_space = free_space; 1722 1723 for (k=0; k<am; k++){ /* for each active row k */ 1724 /* initialize lnk by the column indices of row rip[k] of A */ 1725 nzk = 0; 1726 ncols = ai[rip[k]+1] - ai[rip[k]]; 1727 if (!ncols) SETERRQ(PETSC_ERR_MAT_CH_ZRPVT,"Empty row in matrix"); 1728 ncols_upper = 0; 1729 for (j=0; j<ncols; j++){ 1730 i = riip[*(aj + ai[rip[k]] + j)]; 1731 if (i >= k){ /* only take upper triangular entry */ 1732 cols[ncols_upper] = i; 1733 ncols_upper++; 1734 } 1735 } 1736 ierr = PetscLLAdd(ncols_upper,cols,am,nlnk,lnk,lnkbt);CHKERRQ(ierr); 1737 nzk += nlnk; 1738 1739 /* update lnk by computing fill-in for each pivot row to be merged in */ 1740 prow = jl[k]; /* 1st pivot row */ 1741 1742 while (prow < k){ 1743 nextprow = jl[prow]; 1744 /* merge prow into k-th row */ 1745 jmin = il[prow] + 1; /* index of the 2nd nzero entry in U(prow,k:am-1) */ 1746 jmax = ui[prow+1]; 1747 ncols = jmax-jmin; 1748 uj_ptr = ui_ptr[prow] + jmin - ui[prow]; /* points to the 2nd nzero entry in U(prow,k:am-1) */ 1749 ierr = PetscLLAddSorted(ncols,uj_ptr,am,nlnk,lnk,lnkbt);CHKERRQ(ierr); 1750 nzk += nlnk; 1751 1752 /* update il and jl for prow */ 1753 if (jmin < jmax){ 1754 il[prow] = jmin; 1755 j = *uj_ptr; jl[prow] = jl[j]; jl[j] = prow; 1756 } 1757 prow = nextprow; 1758 } 1759 1760 /* if free space is not available, make more free space */ 1761 if (current_space->local_remaining<nzk) { 1762 i = am - k + 1; /* num of unfactored rows */ 1763 i = PetscMin(i*nzk, i*(i-1)); /* i*nzk, i*(i-1): estimated and max additional space needed */ 1764 ierr = PetscFreeSpaceGet(i,¤t_space);CHKERRQ(ierr); 1765 reallocs++; 1766 } 1767 1768 /* copy data into free space, then initialize lnk */ 1769 ierr = PetscLLClean(am,am,nzk,lnk,current_space->array,lnkbt);CHKERRQ(ierr); 1770 1771 /* add the k-th row into il and jl */ 1772 if (nzk-1 > 0){ 1773 i = current_space->array[1]; /* col value of the first nonzero element in U(k, k+1:am-1) */ 1774 jl[k] = jl[i]; jl[i] = k; 1775 il[k] = ui[k] + 1; 1776 } 1777 ui_ptr[k] = current_space->array; 1778 current_space->array += nzk; 1779 current_space->local_used += nzk; 1780 current_space->local_remaining -= nzk; 1781 1782 ui[k+1] = ui[k] + nzk; 1783 } 1784 1785 #if defined(PETSC_USE_INFO) 1786 if (ai[am] != 0) { 1787 PetscReal af = (PetscReal)(ui[am])/((PetscReal)ai[am]); 1788 ierr = PetscInfo3(A,"Reallocs %D Fill ratio:given %G needed %G\n",reallocs,fill,af);CHKERRQ(ierr); 1789 ierr = PetscInfo1(A,"Run with -pc_factor_fill %G or use \n",af);CHKERRQ(ierr); 1790 ierr = PetscInfo1(A,"PCFactorSetFill(pc,%G) for best performance.\n",af);CHKERRQ(ierr); 1791 } else { 1792 ierr = PetscInfo(A,"Empty matrix.\n");CHKERRQ(ierr); 1793 } 1794 #endif 1795 1796 ierr = ISRestoreIndices(perm,&rip);CHKERRQ(ierr); 1797 ierr = ISRestoreIndices(iperm,&riip);CHKERRQ(ierr); 1798 ierr = PetscFree(jl);CHKERRQ(ierr); 1799 1800 /* destroy list of free space and other temporary array(s) */ 1801 ierr = PetscMalloc((ui[am]+1)*sizeof(PetscInt),&uj);CHKERRQ(ierr); 1802 ierr = PetscFreeSpaceContiguous(&free_space,uj);CHKERRQ(ierr); 1803 ierr = PetscLLDestroy(lnk,lnkbt);CHKERRQ(ierr); 1804 1805 /* put together the new matrix in MATSEQSBAIJ format */ 1806 1807 b = (Mat_SeqSBAIJ*)(*fact)->data; 1808 b->singlemalloc = PETSC_FALSE; 1809 b->free_a = PETSC_TRUE; 1810 b->free_ij = PETSC_TRUE; 1811 ierr = PetscMalloc((ui[am]+1)*sizeof(MatScalar),&b->a);CHKERRQ(ierr); 1812 b->j = uj; 1813 b->i = ui; 1814 b->diag = 0; 1815 b->ilen = 0; 1816 b->imax = 0; 1817 b->row = perm; 1818 b->col = perm; 1819 ierr = PetscObjectReference((PetscObject)perm);CHKERRQ(ierr); 1820 ierr = PetscObjectReference((PetscObject)perm);CHKERRQ(ierr); 1821 b->icol = iperm; 1822 b->pivotinblocks = PETSC_FALSE; /* need to get from MatFactorInfo */ 1823 ierr = PetscMalloc((am+1)*sizeof(PetscScalar),&b->solve_work);CHKERRQ(ierr); 1824 ierr = PetscLogObjectMemory(*fact,(ui[am]-am)*(sizeof(PetscInt)+sizeof(MatScalar)));CHKERRQ(ierr); 1825 b->maxnz = b->nz = ui[am]; 1826 1827 (*fact)->factor = MAT_FACTOR_CHOLESKY; 1828 (*fact)->info.factor_mallocs = reallocs; 1829 (*fact)->info.fill_ratio_given = fill; 1830 if (ai[am] != 0) { 1831 (*fact)->info.fill_ratio_needed = ((PetscReal)ui[am])/((PetscReal)ai[am]); 1832 } else { 1833 (*fact)->info.fill_ratio_needed = 0.0; 1834 } 1835 (*fact)->ops->choleskyfactornumeric = MatCholeskyFactorNumeric_SeqAIJ; 1836 if (perm_identity){ 1837 (*fact)->ops->solve = MatSolve_SeqSBAIJ_1_NaturalOrdering; 1838 (*fact)->ops->solvetranspose = MatSolve_SeqSBAIJ_1_NaturalOrdering; 1839 (*fact)->ops->forwardsolve = MatForwardSolve_SeqSBAIJ_1_NaturalOrdering; 1840 (*fact)->ops->backwardsolve = MatBackwardSolve_SeqSBAIJ_1_NaturalOrdering; 1841 } else { 1842 (*fact)->ops->solve = MatSolve_SeqSBAIJ_1; 1843 (*fact)->ops->solvetranspose = MatSolve_SeqSBAIJ_1; 1844 (*fact)->ops->forwardsolve = MatForwardSolve_SeqSBAIJ_1; 1845 (*fact)->ops->backwardsolve = MatBackwardSolve_SeqSBAIJ_1; 1846 } 1847 PetscFunctionReturn(0); 1848 } 1849