10367cb8aSBarry Smith 20367cb8aSBarry Smith 30367cb8aSBarry Smith 4a5eb4965SSatish Balay #ifdef PETSC_RCS_HEADER 5*814823dcSBarry Smith static char vcid[] = "$Id: zerodiag.c,v 1.27 1998/11/04 19:45:13 bsmith Exp bsmith $"; 6ad608de0SBarry Smith #endif 7ad608de0SBarry Smith 8ad608de0SBarry Smith /* 9ad608de0SBarry Smith This file contains routines to reorder a matrix so that the diagonal 1048b35521SBarry Smith elements are nonzero. 11ad608de0SBarry Smith */ 12ad608de0SBarry Smith 1370f55243SBarry Smith #include "src/mat/matimpl.h" /*I "mat.h" I*/ 14ad608de0SBarry Smith #include <math.h> 15ad608de0SBarry Smith 1648b35521SBarry Smith #define SWAP(a,b) {int _t; _t = a; a = b; b = _t; } 1748b35521SBarry Smith 185615d1e5SSatish Balay #undef __FUNC__ 195615d1e5SSatish Balay #define __FUNC__ "MatZeroFindPre_Private" 20d4bb536fSBarry Smith /* 21d4bb536fSBarry Smith Given a current row and current permutation, find a column permutation 22d4bb536fSBarry Smith that removes a zero diagonal. 23d4bb536fSBarry Smith */ 2433f51a72SBarry Smith int MatZeroFindPre_Private(Mat mat,int prow,int* row,int* col,int *icol,double repla, 25ec201a9bSBarry Smith double atol,int* rc,double* rcv,int nz, int *j, Scalar *v) 2648b35521SBarry Smith { 27ec201a9bSBarry Smith int k, repl, kk, nnz, *jj,ierr; 28ec201a9bSBarry Smith Scalar *vv; 2948b35521SBarry Smith 303a40ed3dSBarry Smith PetscFunctionBegin; 31d4bb536fSBarry Smith /* 32d4bb536fSBarry Smith Here one could sort the col[j[k]] to try to select the column closest 33d4bb536fSBarry Smith to the diagonal (in the new ordering) that satisfies the criteria 34d4bb536fSBarry Smith */ 3548b35521SBarry Smith for (k=0; k<nz; k++) { 3633f51a72SBarry Smith if (icol[j[k]] < prow && PetscAbsScalar(v[k]) > repla) { 3748b35521SBarry Smith /* See if this one will work */ 3833f51a72SBarry Smith repl = icol[j[k]]; 390367cb8aSBarry Smith ierr = MatGetRow( mat, row[repl], &nnz, &jj, &vv ); CHKERRQ(ierr); 4048b35521SBarry Smith for (kk=0; kk<nnz; kk++) { 4133f51a72SBarry Smith if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > atol) { 42cddf8d76SBarry Smith *rcv = PetscAbsScalar(v[k]); 4348b35521SBarry Smith *rc = repl; 440367cb8aSBarry Smith ierr = MatRestoreRow( mat, row[repl], &nnz, &jj, &vv ); CHKERRQ(ierr); 453a40ed3dSBarry Smith PetscFunctionReturn(1); 4648b35521SBarry Smith } 4748b35521SBarry Smith } 480367cb8aSBarry Smith ierr = MatRestoreRow( mat, row[repl], &nnz, &jj, &vv ); CHKERRQ(ierr); 4948b35521SBarry Smith } 5048b35521SBarry Smith } 510367cb8aSBarry Smith 520367cb8aSBarry Smith SETERRQ(1,1," "); 533a40ed3dSBarry Smith PetscFunctionReturn(0); 5448b35521SBarry Smith } 55ad608de0SBarry Smith 565615d1e5SSatish Balay #undef __FUNC__ 575615d1e5SSatish Balay #define __FUNC__ "MatReorderForNonzeroDiagonal" 58ad608de0SBarry Smith /*@ 5948b35521SBarry Smith MatReorderForNonzeroDiagonal - Changes matrix ordering to remove 6048b35521SBarry Smith zeros from diagonal. This may help in the LU factorization to 6148b35521SBarry Smith prevent a zero pivot. 62ad608de0SBarry Smith 63fee21e36SBarry Smith Collective on Mat 64fee21e36SBarry Smith 6598a79cdbSBarry Smith Input Parameters: 6698a79cdbSBarry Smith + mat - matrix to reorder 6798a79cdbSBarry Smith - rmap,cmap - row and column permutations. Usually obtained from 6898a79cdbSBarry Smith MatGetReordering(). 6998a79cdbSBarry Smith 70ad608de0SBarry Smith Notes: 71ad608de0SBarry Smith This is not intended as a replacement for pivoting for matrices that 72d252947aSBarry Smith have ``bad'' structure. It is only a stop-gap measure. Should be called 73d252947aSBarry Smith after a call to MatGetReordering(), this routine changes the column 74d252947aSBarry Smith ordering defined in cis. 75d252947aSBarry Smith 76b259b22eSLois Curfman McInnes Options Database Keys (When using SLES): 7798a79cdbSBarry Smith + -pc_ilu_nonzeros_along_diagonal 7898a79cdbSBarry Smith - -pc_lu_nonzeros_along_diagonal 79ad608de0SBarry Smith 8033f51a72SBarry Smith Algorithm Notes: 8133f51a72SBarry Smith Column pivoting is used. 8233f51a72SBarry Smith 8333f51a72SBarry Smith 1) Choice of column is made by looking at the 8433f51a72SBarry Smith non-zero elements in the troublesome row for columns that are not yet 8533f51a72SBarry Smith included (moving from left to right). 8633f51a72SBarry Smith 8733f51a72SBarry Smith 2) If (1) fails we check all the columns to the left of the current row 88*814823dcSBarry Smith and see if one of them has could be swapped. It can be swapped if 89*814823dcSBarry Smith its corresponding row has a non-zero in the column it is being 90*814823dcSBarry Smith swapped with; to make sure the previous nonzero diagonal remains 91*814823dcSBarry Smith nonzero 9233f51a72SBarry Smith 9398a79cdbSBarry Smith 94ad608de0SBarry Smith @*/ 9548b35521SBarry Smith int MatReorderForNonzeroDiagonal(Mat mat,double atol,IS ris,IS cis ) 96ad608de0SBarry Smith { 9733f51a72SBarry Smith int ierr, prow, k, nz, n, repl, *j, *col, *row, m, *irow, *icol; 98d93a2b8dSBarry Smith Scalar *v; 99d93a2b8dSBarry Smith double repla; 10033f51a72SBarry Smith IS icis,iris; 101ad608de0SBarry Smith 1023a40ed3dSBarry Smith PetscFunctionBegin; 10390f02eecSBarry Smith PetscValidHeaderSpecific(mat,MAT_COOKIE); 10490f02eecSBarry Smith PetscValidHeaderSpecific(ris,IS_COOKIE); 10590f02eecSBarry Smith PetscValidHeaderSpecific(cis,IS_COOKIE); 10690f02eecSBarry Smith 10748b35521SBarry Smith ierr = ISGetIndices(ris,&row); CHKERRQ(ierr); 10848b35521SBarry Smith ierr = ISGetIndices(cis,&col); CHKERRQ(ierr); 10933f51a72SBarry Smith ierr = ISInvertPermutation(cis,&icis);CHKERRQ(ierr); 11033f51a72SBarry Smith ierr = ISInvertPermutation(ris,&iris);CHKERRQ(ierr); 11133f51a72SBarry Smith ierr = ISGetIndices(icis,&icol); CHKERRQ(ierr); 11248b35521SBarry Smith ierr = MatGetSize(mat,&m,&n); CHKERRQ(ierr); 113ad608de0SBarry Smith 114ad608de0SBarry Smith for (prow=0; prow<n; prow++) { 11590f02eecSBarry Smith ierr = MatGetRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr); 11633f51a72SBarry Smith for (k=0; k<nz; k++) {if (icol[j[k]] == prow) break;} 117cddf8d76SBarry Smith if (k >= nz || PetscAbsScalar(v[k]) <= atol) { 118ad608de0SBarry Smith /* Element too small or zero; find the best candidate */ 119ad608de0SBarry Smith repl = prow; 120cddf8d76SBarry Smith repla = (k >= nz) ? 0.0 : PetscAbsScalar(v[k]); 121d4bb536fSBarry Smith /* 12233f51a72SBarry Smith Here one could sort the icol[j[k]] list to try to select the 123d4bb536fSBarry Smith column closest to the diagonal in the new ordering. (Note have 124d4bb536fSBarry Smith to permute the v[k] values as well, and use a fixed bound on the 125d4bb536fSBarry Smith quality of repla rather then looking for the absolute largest. 126d4bb536fSBarry Smith */ 12748b35521SBarry Smith for (k=0; k<nz; k++) { 12833f51a72SBarry Smith if (icol[j[k]] > prow && PetscAbsScalar(v[k]) > repla) { 12933f51a72SBarry Smith repl = icol[j[k]]; 130cddf8d76SBarry Smith repla = PetscAbsScalar(v[k]); 131ad608de0SBarry Smith } 13248b35521SBarry Smith } 133ad608de0SBarry Smith if (prow == repl) { 1345f944b44SBarry Smith /* 1355f944b44SBarry Smith Look for an element that allows us 136ad608de0SBarry Smith to pivot with a previous column. To do this, we need 137ad608de0SBarry Smith to be sure that we don't introduce a zero in a previous 1385f944b44SBarry Smith diagonal 1395f944b44SBarry Smith */ 14033f51a72SBarry Smith if (!MatZeroFindPre_Private(mat,prow,row,col,icol,repla,atol,&repl,&repla,nz,j,v)){ 1415f051944SBarry Smith (*PetscErrorPrintf)("Permuted row number %d\n",prow); 142a8c6a408SBarry Smith SETERRQ(PETSC_ERR_MAT_LU_ZRPVT,0,"Cannot reorder matrix to eliminate zero diagonal entry"); 143ad608de0SBarry Smith } 144ad608de0SBarry Smith } 14533f51a72SBarry Smith SWAP(icol[col[prow]],icol[col[repl]]); 146ad608de0SBarry Smith SWAP(col[prow],col[repl]); 147ad608de0SBarry Smith } 14890f02eecSBarry Smith ierr = MatRestoreRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr); 149ad608de0SBarry Smith } 15048b35521SBarry Smith ierr = ISRestoreIndices(ris,&row); CHKERRQ(ierr); 15148b35521SBarry Smith ierr = ISRestoreIndices(cis,&col); CHKERRQ(ierr); 15233f51a72SBarry Smith ierr = ISRestoreIndices(icis,&icol); CHKERRQ(ierr); 15333f51a72SBarry Smith ierr = ISDestroy(icis); CHKERRQ(ierr); 1543a40ed3dSBarry Smith PetscFunctionReturn(0); 155ad608de0SBarry Smith } 15648b35521SBarry Smith 15748b35521SBarry Smith 15848b35521SBarry Smith 159