1 #ifdef PETSC_RCS_HEADER 2 static char vcid[] = "$Id: zerodiag.c,v 1.20 1998/04/13 17:43:46 bsmith Exp curfman $"; 3 #endif 4 5 /* 6 This file contains routines to reorder a matrix so that the diagonal 7 elements are nonzero. 8 */ 9 10 #include "src/mat/matimpl.h" /*I "mat.h" I*/ 11 #include <math.h> 12 13 #define SWAP(a,b) {int _t; _t = a; a = b; b = _t; } 14 15 #undef __FUNC__ 16 #define __FUNC__ "MatZeroFindPre_Private" 17 /* 18 Given a current row and current permutation, find a column permutation 19 that removes a zero diagonal. 20 */ 21 int MatZeroFindPre_Private(Mat mat,int prow,int* row,int* col,double repla, 22 double atol,int* rc,double* rcv ) 23 { 24 int k, nz, repl, *j, kk, nnz, *jj,ierr; 25 Scalar *v, *vv; 26 27 PetscFunctionBegin; 28 ierr = MatGetRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr); 29 /* 30 Here one could sort the col[j[k]] to try to select the column closest 31 to the diagonal (in the new ordering) that satisfies the criteria 32 */ 33 for (k=0; k<nz; k++) { 34 if (col[j[k]] < prow && PetscAbsScalar(v[k]) > repla) { 35 /* See if this one will work */ 36 repl = col[j[k]]; 37 ierr = MatGetRow( mat, row[repl], &nnz, &jj, &vv ); CHKERRQ(ierr); 38 for (kk=0; kk<nnz; kk++) { 39 if (col[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > atol) { 40 *rcv = PetscAbsScalar(v[k]); 41 *rc = repl; 42 ierr = MatRestoreRow( mat, row[repl], &nnz, &jj, &vv ); CHKERRQ(ierr); 43 ierr = MatRestoreRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr); 44 PetscFunctionReturn(1); 45 } 46 } 47 ierr = MatRestoreRow( mat, row[repl], &nnz, &jj, &vv ); CHKERRQ(ierr); 48 } 49 } 50 ierr = MatRestoreRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr); 51 PetscFunctionReturn(0); 52 } 53 54 #undef __FUNC__ 55 #define __FUNC__ "MatReorderForNonzeroDiagonal" 56 /*@ 57 MatReorderForNonzeroDiagonal - Changes matrix ordering to remove 58 zeros from diagonal. This may help in the LU factorization to 59 prevent a zero pivot. 60 61 Input Parameters: 62 . mat - matrix to reorder 63 . rmap,cmap - row and column permutations. Usually obtained from 64 . MatGetReordering(). 65 66 Collective on Mat 67 68 Notes: 69 This is not intended as a replacement for pivoting for matrices that 70 have ``bad'' structure. It is only a stop-gap measure. Should be called 71 after a call to MatGetReordering(), this routine changes the column 72 ordering defined in cis. 73 74 Options Database Keys (When using SLES): 75 $ -pc_ilu_nonzeros_along_diagonal 76 $ -pc_lu_nonzeros_along_diagonal 77 78 Algorithm: 79 Column pivoting is used. Choice of column is made by looking at the 80 non-zero elements in the row. This algorithm is simple and fast but 81 does NOT guarantee that a non-singular or well conditioned 82 principle submatrix will be produced. 83 @*/ 84 int MatReorderForNonzeroDiagonal(Mat mat,double atol,IS ris,IS cis ) 85 { 86 int ierr, prow, k, nz, n, repl, *j, *col, *row, m; 87 Scalar *v; 88 double repla; 89 90 PetscFunctionBegin; 91 PetscValidHeaderSpecific(mat,MAT_COOKIE); 92 PetscValidHeaderSpecific(ris,IS_COOKIE); 93 PetscValidHeaderSpecific(cis,IS_COOKIE); 94 95 ierr = ISGetIndices(ris,&row); CHKERRQ(ierr); 96 ierr = ISGetIndices(cis,&col); CHKERRQ(ierr); 97 ierr = MatGetSize(mat,&m,&n); CHKERRQ(ierr); 98 99 for (prow=0; prow<n; prow++) { 100 ierr = MatGetRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr); 101 for (k=0; k<nz; k++) {if (col[j[k]] == prow) break;} 102 if (k >= nz || PetscAbsScalar(v[k]) <= atol) { 103 /* Element too small or zero; find the best candidate */ 104 repl = prow; 105 repla = (k >= nz) ? 0.0 : PetscAbsScalar(v[k]); 106 /* 107 Here one could sort the col[j[k]] list to try to select the 108 column closest to the diagonal in the new ordering. (Note have 109 to permute the v[k] values as well, and use a fixed bound on the 110 quality of repla rather then looking for the absolute largest. 111 */ 112 for (k=0; k<nz; k++) { 113 if (col[j[k]] > prow && PetscAbsScalar(v[k]) > repla) { 114 repl = col[j[k]]; 115 repla = PetscAbsScalar(v[k]); 116 } 117 } 118 if (prow == repl) { 119 /* Look for an element that allows us 120 to pivot with a previous column. To do this, we need 121 to be sure that we don't introduce a zero in a previous 122 diagonal */ 123 if (!MatZeroFindPre_Private(mat,prow,row,col,repla,atol,&repl,&repla)){ 124 SETERRQ(PETSC_ERR_MAT_LU_ZRPVT,0,"Cannot reorder matrix to eliminate zero diagonal entry"); 125 } 126 } 127 SWAP(col[prow],col[repl]); 128 } 129 ierr = MatRestoreRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr); 130 } 131 ierr = ISRestoreIndices(ris,&row); CHKERRQ(ierr); 132 ierr = ISRestoreIndices(cis,&col); CHKERRQ(ierr); 133 PetscFunctionReturn(0); 134 } 135 136 137 138