1*e090d566SSatish Balay /*$Id: zerodiag.c,v 1.38 2000/04/12 04:24:13 bsmith Exp balay $*/ 2ad608de0SBarry Smith 3ad608de0SBarry Smith /* 4ad608de0SBarry Smith This file contains routines to reorder a matrix so that the diagonal 548b35521SBarry Smith elements are nonzero. 6ad608de0SBarry Smith */ 7ad608de0SBarry Smith 8*e090d566SSatish Balay #include "src/mat/matimpl.h" /*I "petscmat.h" I*/ 9ad608de0SBarry Smith 1048b35521SBarry Smith #define SWAP(a,b) {int _t; _t = a; a = b; b = _t; } 1148b35521SBarry Smith 125615d1e5SSatish Balay #undef __FUNC__ 13b2863d3aSBarry Smith #define __FUNC__ /*<a name=""></a>*/"MatReorderForNonzeroDiagonal" 14ad608de0SBarry Smith /*@ 1548b35521SBarry Smith MatReorderForNonzeroDiagonal - Changes matrix ordering to remove 1648b35521SBarry Smith zeros from diagonal. This may help in the LU factorization to 1748b35521SBarry Smith prevent a zero pivot. 18ad608de0SBarry Smith 19fee21e36SBarry Smith Collective on Mat 20fee21e36SBarry Smith 2198a79cdbSBarry Smith Input Parameters: 2298a79cdbSBarry Smith + mat - matrix to reorder 2398a79cdbSBarry Smith - rmap,cmap - row and column permutations. Usually obtained from 2491e9ee9fSBarry Smith MatGetOrdering(). 2598a79cdbSBarry Smith 2615091d37SBarry Smith Level: intermediate 2715091d37SBarry Smith 28ad608de0SBarry Smith Notes: 29ad608de0SBarry Smith This is not intended as a replacement for pivoting for matrices that 30d252947aSBarry Smith have ``bad'' structure. It is only a stop-gap measure. Should be called 3191e9ee9fSBarry Smith after a call to MatGetOrdering(), this routine changes the column 32d252947aSBarry Smith ordering defined in cis. 33d252947aSBarry Smith 34b259b22eSLois Curfman McInnes Options Database Keys (When using SLES): 3598a79cdbSBarry Smith + -pc_ilu_nonzeros_along_diagonal 3698a79cdbSBarry Smith - -pc_lu_nonzeros_along_diagonal 37ad608de0SBarry Smith 3833f51a72SBarry Smith Algorithm Notes: 3933f51a72SBarry Smith Column pivoting is used. 4033f51a72SBarry Smith 4133f51a72SBarry Smith 1) Choice of column is made by looking at the 4233f51a72SBarry Smith non-zero elements in the troublesome row for columns that are not yet 4333f51a72SBarry Smith included (moving from left to right). 4433f51a72SBarry Smith 4533f51a72SBarry Smith 2) If (1) fails we check all the columns to the left of the current row 46814823dcSBarry Smith and see if one of them has could be swapped. It can be swapped if 47814823dcSBarry Smith its corresponding row has a non-zero in the column it is being 48814823dcSBarry Smith swapped with; to make sure the previous nonzero diagonal remains 49814823dcSBarry Smith nonzero 5033f51a72SBarry Smith 5198a79cdbSBarry Smith 52ad608de0SBarry Smith @*/ 53329f5518SBarry Smith int MatReorderForNonzeroDiagonal(Mat mat,PetscReal atol,IS ris,IS cis) 54ad608de0SBarry Smith { 5572af6520SSatish Balay int ierr,prow,k,nz,n,repl,*j,*col,*row,m,*icol,nnz,*jj,kk; 56fd61f322SBarry Smith Scalar *v,*vv; 57329f5518SBarry Smith PetscReal repla; 58fd61f322SBarry Smith IS icis; 59ad608de0SBarry Smith 603a40ed3dSBarry Smith PetscFunctionBegin; 6190f02eecSBarry Smith PetscValidHeaderSpecific(mat,MAT_COOKIE); 6290f02eecSBarry Smith PetscValidHeaderSpecific(ris,IS_COOKIE); 6390f02eecSBarry Smith PetscValidHeaderSpecific(cis,IS_COOKIE); 6490f02eecSBarry Smith 6548b35521SBarry Smith ierr = ISGetIndices(ris,&row);CHKERRQ(ierr); 6648b35521SBarry Smith ierr = ISGetIndices(cis,&col);CHKERRQ(ierr); 674c49b128SBarry Smith ierr = ISInvertPermutation(cis,PETSC_DECIDE,&icis);CHKERRQ(ierr); 6833f51a72SBarry Smith ierr = ISGetIndices(icis,&icol);CHKERRQ(ierr); 6948b35521SBarry Smith ierr = MatGetSize(mat,&m,&n);CHKERRQ(ierr); 70ad608de0SBarry Smith 71ad608de0SBarry Smith for (prow=0; prow<n; prow++) { 7290f02eecSBarry Smith ierr = MatGetRow(mat,row[prow],&nz,&j,&v);CHKERRQ(ierr); 7333f51a72SBarry Smith for (k=0; k<nz; k++) {if (icol[j[k]] == prow) break;} 74cddf8d76SBarry Smith if (k >= nz || PetscAbsScalar(v[k]) <= atol) { 75ad608de0SBarry Smith /* Element too small or zero; find the best candidate */ 76ad608de0SBarry Smith repl = prow; 77cddf8d76SBarry Smith repla = (k >= nz) ? 0.0 : PetscAbsScalar(v[k]); 78d4bb536fSBarry Smith /* 79fd61f322SBarry Smith Look for a later column we can swap with this one 80d4bb536fSBarry Smith */ 8148b35521SBarry Smith for (k=0; k<nz; k++) { 8233f51a72SBarry Smith if (icol[j[k]] > prow && PetscAbsScalar(v[k]) > repla) { 83fd61f322SBarry Smith /* found a suitable later column */ 8433f51a72SBarry Smith repl = icol[j[k]]; 85cddf8d76SBarry Smith repla = PetscAbsScalar(v[k]); 8633f51a72SBarry Smith SWAP(icol[col[prow]],icol[col[repl]]); 87ad608de0SBarry Smith SWAP(col[prow],col[repl]); 88fd61f322SBarry Smith goto found; 89fd61f322SBarry Smith } 90fd61f322SBarry Smith } 91fd61f322SBarry Smith /* 92fd61f322SBarry Smith Did not find a suitable later column so look for an earlier column 93fd61f322SBarry Smith We need to be sure that we don't introduce a zero in a previous 94fd61f322SBarry Smith diagonal 95fd61f322SBarry Smith */ 96fd61f322SBarry Smith for (k=0; k<nz; k++) { 97fd61f322SBarry Smith if (icol[j[k]] < prow && PetscAbsScalar(v[k]) > repla) { 98fd61f322SBarry Smith /* See if this one will work */ 99fd61f322SBarry Smith repl = icol[j[k]]; 100fd61f322SBarry Smith ierr = MatGetRow(mat,row[repl],&nnz,&jj,&vv);CHKERRQ(ierr); 101fd61f322SBarry Smith for (kk=0; kk<nnz; kk++) { 102fd61f322SBarry Smith if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > atol) { 103fd61f322SBarry Smith repla = PetscAbsScalar(v[k]); 104fd61f322SBarry Smith ierr = MatRestoreRow(mat,row[repl],&nnz,&jj,&vv);CHKERRQ(ierr); 105fd61f322SBarry Smith SWAP(icol[col[prow]],icol[col[repl]]); 106fd61f322SBarry Smith SWAP(col[prow],col[repl]); 107fd61f322SBarry Smith goto found; 108fd61f322SBarry Smith } 109fd61f322SBarry Smith } 110fd61f322SBarry Smith ierr = MatRestoreRow(mat,row[repl],&nnz,&jj,&vv);CHKERRQ(ierr); 111fd61f322SBarry Smith } 112fd61f322SBarry Smith } 113fd61f322SBarry Smith /* 114fd61f322SBarry Smith No column suitable; instead check all future rows 115fd61f322SBarry Smith Note: this will be very slow 116fd61f322SBarry Smith */ 117fd61f322SBarry Smith for (k=prow+1; k<n; k++) { 118fd61f322SBarry Smith ierr = MatGetRow(mat,row[k],&nnz,&jj,&vv);CHKERRQ(ierr); 119fd61f322SBarry Smith for (kk=0; kk<nnz; kk++) { 120fd61f322SBarry Smith if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > atol) { 121fd61f322SBarry Smith /* found a row */ 122fd61f322SBarry Smith SWAP(row[prow],row[k]); 123fd61f322SBarry Smith goto found; 124fd61f322SBarry Smith } 125fd61f322SBarry Smith } 126fd61f322SBarry Smith ierr = MatRestoreRow(mat,row[k],&nnz,&jj,&vv);CHKERRQ(ierr); 127fd61f322SBarry Smith } 128fd61f322SBarry Smith 129fd61f322SBarry Smith found:; 130ad608de0SBarry Smith } 13190f02eecSBarry Smith ierr = MatRestoreRow(mat,row[prow],&nz,&j,&v);CHKERRQ(ierr); 132ad608de0SBarry Smith } 13348b35521SBarry Smith ierr = ISRestoreIndices(ris,&row);CHKERRQ(ierr); 13448b35521SBarry Smith ierr = ISRestoreIndices(cis,&col);CHKERRQ(ierr); 13533f51a72SBarry Smith ierr = ISRestoreIndices(icis,&icol);CHKERRQ(ierr); 13633f51a72SBarry Smith ierr = ISDestroy(icis);CHKERRQ(ierr); 1373a40ed3dSBarry Smith PetscFunctionReturn(0); 138ad608de0SBarry Smith } 13948b35521SBarry Smith 14048b35521SBarry Smith 14148b35521SBarry Smith 142