xref: /petsc/src/mat/utils/zerodiag.c (revision e090d5668ba2b2ea997ebb925e3a05be0dc5d9ab)
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