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