1 /*$Id: zerodiag.c,v 1.44 2001/08/06 21:16:10 bsmith Exp $*/ 2 3 /* 4 This file contains routines to reorder a matrix so that the diagonal 5 elements are nonzero. 6 */ 7 8 #include "src/mat/matimpl.h" /*I "petscmat.h" I*/ 9 10 #define SWAP(a,b) {int _t; _t = a; a = b; b = _t; } 11 12 #undef __FUNCT__ 13 #define __FUNCT__ "MatReorderForNonzeroDiagonal" 14 /*@ 15 MatReorderForNonzeroDiagonal - Changes matrix ordering to remove 16 zeros from diagonal. This may help in the LU factorization to 17 prevent a zero pivot. 18 19 Collective on Mat 20 21 Input Parameters: 22 + mat - matrix to reorder 23 - rmap,cmap - row and column permutations. Usually obtained from 24 MatGetOrdering(). 25 26 Level: intermediate 27 28 Notes: 29 This is not intended as a replacement for pivoting for matrices that 30 have ``bad'' structure. It is only a stop-gap measure. Should be called 31 after a call to MatGetOrdering(), this routine changes the column 32 ordering defined in cis. 33 34 Only works for SeqAIJ matrices 35 36 Options Database Keys (When using KSP): 37 + -pc_ilu_nonzeros_along_diagonal 38 - -pc_lu_nonzeros_along_diagonal 39 40 Algorithm Notes: 41 Column pivoting is used. 42 43 1) Choice of column is made by looking at the 44 non-zero elements in the troublesome row for columns that are not yet 45 included (moving from left to right). 46 47 2) If (1) fails we check all the columns to the left of the current row 48 and see if one of them has could be swapped. It can be swapped if 49 its corresponding row has a non-zero in the column it is being 50 swapped with; to make sure the previous nonzero diagonal remains 51 nonzero 52 53 54 @*/ 55 int MatReorderForNonzeroDiagonal(Mat mat,PetscReal atol,IS ris,IS cis) 56 { 57 int ierr,(*f)(Mat,PetscReal,IS,IS); 58 59 PetscFunctionBegin; 60 ierr = PetscObjectQueryFunction((PetscObject)mat,"MatReorderForNonzeroDiagonal_C",(void (**)(void))&f);CHKERRQ(ierr); 61 if (f) { 62 ierr = (*f)(mat,atol,ris,cis);CHKERRQ(ierr); 63 } 64 PetscFunctionReturn(0); 65 } 66 67 EXTERN_C_BEGIN 68 #undef __FUNCT__ 69 #define __FUNCT__ "MatReorderForNonzeroDiagonal_SeqAIJ" 70 int MatReorderForNonzeroDiagonal_SeqAIJ(Mat mat,PetscReal atol,IS ris,IS cis) 71 { 72 int ierr,prow,k,nz,n,repl,*j,*col,*row,m,*icol,nnz,*jj,kk; 73 PetscScalar *v,*vv; 74 PetscReal repla; 75 IS icis; 76 77 PetscFunctionBegin; 78 ierr = ISGetIndices(ris,&row);CHKERRQ(ierr); 79 ierr = ISGetIndices(cis,&col);CHKERRQ(ierr); 80 ierr = ISInvertPermutation(cis,PETSC_DECIDE,&icis);CHKERRQ(ierr); 81 ierr = ISGetIndices(icis,&icol);CHKERRQ(ierr); 82 ierr = MatGetSize(mat,&m,&n);CHKERRQ(ierr); 83 84 for (prow=0; prow<n; prow++) { 85 ierr = MatGetRow(mat,row[prow],&nz,&j,&v);CHKERRQ(ierr); 86 for (k=0; k<nz; k++) {if (icol[j[k]] == prow) break;} 87 if (k >= nz || PetscAbsScalar(v[k]) <= atol) { 88 /* Element too small or zero; find the best candidate */ 89 repla = (k >= nz) ? 0.0 : PetscAbsScalar(v[k]); 90 /* 91 Look for a later column we can swap with this one 92 */ 93 for (k=0; k<nz; k++) { 94 if (icol[j[k]] > prow && PetscAbsScalar(v[k]) > repla) { 95 /* found a suitable later column */ 96 repl = icol[j[k]]; 97 SWAP(icol[col[prow]],icol[col[repl]]); 98 SWAP(col[prow],col[repl]); 99 goto found; 100 } 101 } 102 /* 103 Did not find a suitable later column so look for an earlier column 104 We need to be sure that we don't introduce a zero in a previous 105 diagonal 106 */ 107 for (k=0; k<nz; k++) { 108 if (icol[j[k]] < prow && PetscAbsScalar(v[k]) > repla) { 109 /* See if this one will work */ 110 repl = icol[j[k]]; 111 ierr = MatGetRow(mat,row[repl],&nnz,&jj,&vv);CHKERRQ(ierr); 112 for (kk=0; kk<nnz; kk++) { 113 if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > atol) { 114 ierr = MatRestoreRow(mat,row[repl],&nnz,&jj,&vv);CHKERRQ(ierr); 115 SWAP(icol[col[prow]],icol[col[repl]]); 116 SWAP(col[prow],col[repl]); 117 goto found; 118 } 119 } 120 ierr = MatRestoreRow(mat,row[repl],&nnz,&jj,&vv);CHKERRQ(ierr); 121 } 122 } 123 /* 124 No column suitable; instead check all future rows 125 Note: this will be very slow 126 */ 127 for (k=prow+1; k<n; k++) { 128 ierr = MatGetRow(mat,row[k],&nnz,&jj,&vv);CHKERRQ(ierr); 129 for (kk=0; kk<nnz; kk++) { 130 if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > atol) { 131 /* found a row */ 132 SWAP(row[prow],row[k]); 133 goto found; 134 } 135 } 136 ierr = MatRestoreRow(mat,row[k],&nnz,&jj,&vv);CHKERRQ(ierr); 137 } 138 139 found:; 140 } 141 ierr = MatRestoreRow(mat,row[prow],&nz,&j,&v);CHKERRQ(ierr); 142 } 143 ierr = ISRestoreIndices(ris,&row);CHKERRQ(ierr); 144 ierr = ISRestoreIndices(cis,&col);CHKERRQ(ierr); 145 ierr = ISRestoreIndices(icis,&icol);CHKERRQ(ierr); 146 ierr = ISDestroy(icis);CHKERRQ(ierr); 147 PetscFunctionReturn(0); 148 } 149 EXTERN_C_END 150 151 152