10367cb8aSBarry Smith 2a5eb4965SSatish Balay #ifdef PETSC_RCS_HEADER 3*fd61f322SBarry Smith static char vcid[] = "$Id: zerodiag.c,v 1.28 1998/11/04 20:02:55 bsmith Exp bsmith $"; 4ad608de0SBarry Smith #endif 5ad608de0SBarry Smith 6ad608de0SBarry Smith /* 7ad608de0SBarry Smith This file contains routines to reorder a matrix so that the diagonal 848b35521SBarry Smith elements are nonzero. 9ad608de0SBarry Smith */ 10ad608de0SBarry Smith 1170f55243SBarry Smith #include "src/mat/matimpl.h" /*I "mat.h" I*/ 12ad608de0SBarry Smith 1348b35521SBarry Smith #define SWAP(a,b) {int _t; _t = a; a = b; b = _t; } 1448b35521SBarry Smith 155615d1e5SSatish Balay #undef __FUNC__ 165615d1e5SSatish Balay #define __FUNC__ "MatReorderForNonzeroDiagonal" 17ad608de0SBarry Smith /*@ 1848b35521SBarry Smith MatReorderForNonzeroDiagonal - Changes matrix ordering to remove 1948b35521SBarry Smith zeros from diagonal. This may help in the LU factorization to 2048b35521SBarry Smith prevent a zero pivot. 21ad608de0SBarry Smith 22fee21e36SBarry Smith Collective on Mat 23fee21e36SBarry Smith 2498a79cdbSBarry Smith Input Parameters: 2598a79cdbSBarry Smith + mat - matrix to reorder 2698a79cdbSBarry Smith - rmap,cmap - row and column permutations. Usually obtained from 2798a79cdbSBarry Smith MatGetReordering(). 2898a79cdbSBarry Smith 29ad608de0SBarry Smith Notes: 30ad608de0SBarry Smith This is not intended as a replacement for pivoting for matrices that 31d252947aSBarry Smith have ``bad'' structure. It is only a stop-gap measure. Should be called 32d252947aSBarry Smith after a call to MatGetReordering(), this routine changes the column 33d252947aSBarry Smith ordering defined in cis. 34d252947aSBarry Smith 35b259b22eSLois Curfman McInnes Options Database Keys (When using SLES): 3698a79cdbSBarry Smith + -pc_ilu_nonzeros_along_diagonal 3798a79cdbSBarry Smith - -pc_lu_nonzeros_along_diagonal 38ad608de0SBarry Smith 3933f51a72SBarry Smith Algorithm Notes: 4033f51a72SBarry Smith Column pivoting is used. 4133f51a72SBarry Smith 4233f51a72SBarry Smith 1) Choice of column is made by looking at the 4333f51a72SBarry Smith non-zero elements in the troublesome row for columns that are not yet 4433f51a72SBarry Smith included (moving from left to right). 4533f51a72SBarry Smith 4633f51a72SBarry Smith 2) If (1) fails we check all the columns to the left of the current row 47814823dcSBarry Smith and see if one of them has could be swapped. It can be swapped if 48814823dcSBarry Smith its corresponding row has a non-zero in the column it is being 49814823dcSBarry Smith swapped with; to make sure the previous nonzero diagonal remains 50814823dcSBarry Smith nonzero 5133f51a72SBarry Smith 5298a79cdbSBarry Smith 53ad608de0SBarry Smith @*/ 5448b35521SBarry Smith int MatReorderForNonzeroDiagonal(Mat mat,double atol,IS ris,IS cis ) 55ad608de0SBarry Smith { 56*fd61f322SBarry Smith int ierr, prow, k, nz, n, repl, *j, *col, *row, m, *irow, *icol,nnz,*jj,kk; 57*fd61f322SBarry Smith Scalar *v,*vv; 58d93a2b8dSBarry Smith double repla; 59*fd61f322SBarry Smith IS icis; 60ad608de0SBarry Smith 613a40ed3dSBarry Smith PetscFunctionBegin; 6290f02eecSBarry Smith PetscValidHeaderSpecific(mat,MAT_COOKIE); 6390f02eecSBarry Smith PetscValidHeaderSpecific(ris,IS_COOKIE); 6490f02eecSBarry Smith PetscValidHeaderSpecific(cis,IS_COOKIE); 6590f02eecSBarry Smith 6648b35521SBarry Smith ierr = ISGetIndices(ris,&row); CHKERRQ(ierr); 6748b35521SBarry Smith ierr = ISGetIndices(cis,&col); CHKERRQ(ierr); 6833f51a72SBarry Smith ierr = ISInvertPermutation(cis,&icis);CHKERRQ(ierr); 6933f51a72SBarry Smith ierr = ISGetIndices(icis,&icol); CHKERRQ(ierr); 7048b35521SBarry Smith ierr = MatGetSize(mat,&m,&n); CHKERRQ(ierr); 71ad608de0SBarry Smith 72ad608de0SBarry Smith for (prow=0; prow<n; prow++) { 7390f02eecSBarry Smith ierr = MatGetRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr); 7433f51a72SBarry Smith for (k=0; k<nz; k++) {if (icol[j[k]] == prow) break;} 75cddf8d76SBarry Smith if (k >= nz || PetscAbsScalar(v[k]) <= atol) { 76ad608de0SBarry Smith /* Element too small or zero; find the best candidate */ 77ad608de0SBarry Smith repl = prow; 78cddf8d76SBarry Smith repla = (k >= nz) ? 0.0 : PetscAbsScalar(v[k]); 79d4bb536fSBarry Smith /* 80*fd61f322SBarry Smith Look for a later column we can swap with this one 81d4bb536fSBarry Smith */ 8248b35521SBarry Smith for (k=0; k<nz; k++) { 8333f51a72SBarry Smith if (icol[j[k]] > prow && PetscAbsScalar(v[k]) > repla) { 84*fd61f322SBarry Smith /* found a suitable later column */ 8533f51a72SBarry Smith repl = icol[j[k]]; 86cddf8d76SBarry Smith repla = PetscAbsScalar(v[k]); 8733f51a72SBarry Smith SWAP(icol[col[prow]],icol[col[repl]]); 88ad608de0SBarry Smith SWAP(col[prow],col[repl]); 89*fd61f322SBarry Smith goto found; 90*fd61f322SBarry Smith } 91*fd61f322SBarry Smith } 92*fd61f322SBarry Smith /* 93*fd61f322SBarry Smith Did not find a suitable later column so look for an earlier column 94*fd61f322SBarry Smith We need to be sure that we don't introduce a zero in a previous 95*fd61f322SBarry Smith diagonal 96*fd61f322SBarry Smith */ 97*fd61f322SBarry Smith for (k=0; k<nz; k++) { 98*fd61f322SBarry Smith if (icol[j[k]] < prow && PetscAbsScalar(v[k]) > repla) { 99*fd61f322SBarry Smith /* See if this one will work */ 100*fd61f322SBarry Smith repl = icol[j[k]]; 101*fd61f322SBarry Smith ierr = MatGetRow( mat, row[repl], &nnz, &jj, &vv ); CHKERRQ(ierr); 102*fd61f322SBarry Smith for (kk=0; kk<nnz; kk++) { 103*fd61f322SBarry Smith if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > atol) { 104*fd61f322SBarry Smith repla = PetscAbsScalar(v[k]); 105*fd61f322SBarry Smith ierr = MatRestoreRow( mat, row[repl], &nnz, &jj, &vv ); CHKERRQ(ierr); 106*fd61f322SBarry Smith SWAP(icol[col[prow]],icol[col[repl]]); 107*fd61f322SBarry Smith SWAP(col[prow],col[repl]); 108*fd61f322SBarry Smith goto found; 109*fd61f322SBarry Smith } 110*fd61f322SBarry Smith } 111*fd61f322SBarry Smith ierr = MatRestoreRow( mat, row[repl], &nnz, &jj, &vv ); CHKERRQ(ierr); 112*fd61f322SBarry Smith } 113*fd61f322SBarry Smith } 114*fd61f322SBarry Smith /* 115*fd61f322SBarry Smith No column suitable; instead check all future rows 116*fd61f322SBarry Smith Note: this will be very slow 117*fd61f322SBarry Smith */ 118*fd61f322SBarry Smith for (k=prow+1; k<n; k++) { 119*fd61f322SBarry Smith ierr = MatGetRow( mat, row[k], &nnz, &jj, &vv ); CHKERRQ(ierr); 120*fd61f322SBarry Smith for (kk=0; kk<nnz; kk++) { 121*fd61f322SBarry Smith if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > atol) { 122*fd61f322SBarry Smith /* found a row */ 123*fd61f322SBarry Smith SWAP(row[prow],row[k]); 124*fd61f322SBarry Smith goto found; 125*fd61f322SBarry Smith } 126*fd61f322SBarry Smith } 127*fd61f322SBarry Smith ierr = MatRestoreRow( mat, row[k], &nnz, &jj, &vv ); CHKERRQ(ierr); 128*fd61f322SBarry Smith } 129*fd61f322SBarry Smith 130*fd61f322SBarry Smith found:; 131ad608de0SBarry Smith } 13290f02eecSBarry Smith ierr = MatRestoreRow( mat, row[prow], &nz, &j, &v ); CHKERRQ(ierr); 133ad608de0SBarry Smith } 13448b35521SBarry Smith ierr = ISRestoreIndices(ris,&row); CHKERRQ(ierr); 13548b35521SBarry Smith ierr = ISRestoreIndices(cis,&col); CHKERRQ(ierr); 13633f51a72SBarry Smith ierr = ISRestoreIndices(icis,&icol); CHKERRQ(ierr); 13733f51a72SBarry Smith ierr = ISDestroy(icis); CHKERRQ(ierr); 1383a40ed3dSBarry Smith PetscFunctionReturn(0); 139ad608de0SBarry Smith } 14048b35521SBarry Smith 14148b35521SBarry Smith 14248b35521SBarry Smith 143