Actual source code: zerodiag.c
petsc-3.7.1 2016-05-15
Report Typos and Errors

      2: /*
      3:     This file contains routines to reorder a matrix so that the diagonal
      4:     elements are nonzero.
      5:  */

      7: #include <petsc/private/matimpl.h>       /*I  "petscmat.h"  I*/

      9: #define SWAP(a,b) {PetscInt _t; _t = a; a = b; b = _t; }

     13: /*@
     14:     MatReorderForNonzeroDiagonal - Changes matrix ordering to remove
     15:     zeros from diagonal. This may help in the LU factorization to
     16:     prevent a zero pivot.

     18:     Collective on Mat

     20:     Input Parameters:
     21: +   mat  - matrix to reorder
     22: -   rmap,cmap - row and column permutations.  Usually obtained from
     23:                MatGetOrdering().

     25:     Level: intermediate

     27:     Notes:
     28:     This is not intended as a replacement for pivoting for matrices that
     29:     have ``bad'' structure. It is only a stop-gap measure. Should be called
     30:     after a call to MatGetOrdering(), this routine changes the column
     31:     ordering defined in cis.

     33:     Only works for SeqAIJ matrices

     35:     Options Database Keys (When using KSP):
     36: .      -pc_factor_nonzeros_along_diagonal

     38:     Algorithm Notes:
     39:     Column pivoting is used.

     41:     1) Choice of column is made by looking at the
     42:        non-zero elements in the troublesome row for columns that are not yet
     43:        included (moving from left to right).

     45:     2) If (1) fails we check all the columns to the left of the current row
     46:        and see if one of them has could be swapped. It can be swapped if
     47:        its corresponding row has a non-zero in the column it is being
     48:        swapped with; to make sure the previous nonzero diagonal remains
     49:        nonzero

     52: @*/
     53: PetscErrorCode  MatReorderForNonzeroDiagonal(Mat mat,PetscReal abstol,IS ris,IS cis)
     54: {

     58:   PetscTryMethod(mat,"MatReorderForNonzeroDiagonal_C",(Mat,PetscReal,IS,IS),(mat,abstol,ris,cis));
     59:   return(0);
     60: }

     62: PETSC_INTERN PetscErrorCode MatGetRow_SeqAIJ(Mat,PetscInt,PetscInt*,PetscInt**,PetscScalar**);
     63: PETSC_INTERN PetscErrorCode MatRestoreRow_SeqAIJ(Mat,PetscInt,PetscInt*,PetscInt**,PetscScalar**);

     65: #include <../src/vec/is/is/impls/general/general.h>

     69: PETSC_INTERN PetscErrorCode  MatReorderForNonzeroDiagonal_SeqAIJ(Mat mat,PetscReal abstol,IS ris,IS cis)
     70: {
     72:   PetscInt       prow,k,nz,n,repl,*j,*col,*row,m,*icol,nnz,*jj,kk;
     73:   PetscScalar    *v,*vv;
     74:   PetscReal      repla;
     75:   IS             icis;

     78:   /* access the indices of the IS directly, because it changes them */
     79:   row  = ((IS_General*)ris->data)->idx;
     80:   col  = ((IS_General*)cis->data)->idx;
     81:   ISInvertPermutation(cis,PETSC_DECIDE,&icis);
     82:   icol = ((IS_General*)icis->data)->idx;
     83:   MatGetSize(mat,&m,&n);

     85:   for (prow=0; prow<n; prow++) {
     86:     MatGetRow_SeqAIJ(mat,row[prow],&nz,&j,&v);
     87:     for (k=0; k<nz; k++) {
     88:       if (icol[j[k]] == prow) break;
     89:     }
     90:     if (k >= nz || PetscAbsScalar(v[k]) <= abstol) {
     91:       /* Element too small or zero; find the best candidate */
     92:       repla = (k >= nz) ? 0.0 : PetscAbsScalar(v[k]);
     93:       /*
     94:           Look for a later column we can swap with this one
     95:       */
     96:       for (k=0; k<nz; k++) {
     97:         if (icol[j[k]] > prow && PetscAbsScalar(v[k]) > repla) {
     98:           /* found a suitable later column */
     99:           repl = icol[j[k]];
    100:           SWAP(icol[col[prow]],icol[col[repl]]);
    101:           SWAP(col[prow],col[repl]);
    102:           goto found;
    103:         }
    104:       }
    105:       /*
    106:            Did not find a suitable later column so look for an earlier column
    107:            We need to be sure that we don't introduce a zero in a previous
    108:            diagonal
    109:       */
    110:       for (k=0; k<nz; k++) {
    111:         if (icol[j[k]] < prow && PetscAbsScalar(v[k]) > repla) {
    112:           /* See if this one will work */
    113:           repl = icol[j[k]];
    114:           MatGetRow_SeqAIJ(mat,row[repl],&nnz,&jj,&vv);
    115:           for (kk=0; kk<nnz; kk++) {
    116:             if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > abstol) {
    117:               MatRestoreRow_SeqAIJ(mat,row[repl],&nnz,&jj,&vv);
    118:               SWAP(icol[col[prow]],icol[col[repl]]);
    119:               SWAP(col[prow],col[repl]);
    120:               goto found;
    121:             }
    122:           }
    123:           MatRestoreRow_SeqAIJ(mat,row[repl],&nnz,&jj,&vv);
    124:         }
    125:       }
    126:       /*
    127:           No column  suitable; instead check all future rows
    128:           Note: this will be very slow
    129:       */
    130:       for (k=prow+1; k<n; k++) {
    131:         MatGetRow_SeqAIJ(mat,row[k],&nnz,&jj,&vv);
    132:         for (kk=0; kk<nnz; kk++) {
    133:           if (icol[jj[kk]] == prow && PetscAbsScalar(vv[kk]) > abstol) {
    134:             /* found a row */
    135:             SWAP(row[prow],row[k]);
    136:             goto found;
    137:           }
    138:         }
    139:         MatRestoreRow_SeqAIJ(mat,row[k],&nnz,&jj,&vv);
    140:       }

    142: found:;
    143:     }
    144:     MatRestoreRow_SeqAIJ(mat,row[prow],&nz,&j,&v);
    145:   }
    146:   ISDestroy(&icis);
    147:   return(0);
    148: }