      SUBROUTINE PSGEI2( M, N, A, IA, JA, DESCA, IPIV, WORK, INFO )
*
*  -- ... --
*
*     .. Scalar Arguments ..
      INTEGER            IA, INFO, JA, M, N
*     ..
*     .. Array Arguments ..
      INTEGER            DESCA( * ), IPIV( * )
      REAL   A( * ), WORK( * )
*     ..
*
*  Purpose
*  =======
*
*  PSGEI2 computes the inverse of a general M-by-N
*  distributed matrix sub( A ) = A(IA:IA+M-1,JA:JA+N-1) using...
*  partial pivoting with row interchanges.
*
*  This is the right-looking Parallel Level 2 BLAS version of the
*  algorithm.
*
*  Arguments
*  =========
*
*  M       (global input) INTEGER
*          The number of rows to be operated on, i.e. the number of rows
*          of the distributed submatrix sub( A ). M >= 0.
*
*  N       (global input) INTEGER
*          The number of columns to be operated on, i.e. the number of
*          columns of the distributed submatrix sub( A ).
*          NB_A-MOD(JA-1, NB_A) >= N >= 0.
*
*  A       (local input/local output) REAL pointer into the
*          local memory to an array of dimension (LLD_A, LOCq(JA+N-1)).
*          On entry, this array contains the local pieces of the M-by-N
*          distributed matrix sub( A ). On exit, this array contains
*          the local pieces of the factors L and U from the factoriza-
*          tion sub( A ) = P*L*U; the unit diagonal elements of L are
*          not stored.
*
*  IA      (global input) INTEGER
*          The row index in the global array A indicating the first
*          row of sub( A ).
*
*  JA      (global input) INTEGER
*          The column index in the global array A indicating the
*          first column of sub( A ).
*
*  DESCA   (global and local input) INTEGER array of dimension DLEN_.
*          The array descriptor for the distributed matrix A.
*
*  IPIV    (local output) INTEGER array, dimension ( LOCp(M_A)+MB_A )
*          This array contains the pivoting information.
*          IPIV(i) -> The global row local row i was swapped with.
*          This array is tied to the distributed matrix A.
*
*  INFO    (local output) INTEGER
*          = 0:  successful exit
*          < 0:  If the i-th argument is an array and the j-entry had
*                an illegal value, then INFO = -(i*100+j), if the i-th
*                argument is a scalar and had an illegal value, then
*                INFO = -i.
*          > 0:  If INFO = K, U(IA+K-1,JA+K-1) is exactly zero.
*                The factorization has been completed, but the factor U
*                is exactly singular, and division by zero will occur if
*                it is used to solve a system of equations.
*
*  =====================================================================
*
*     .. Parameters ..
      INTEGER            BLOCK_CYCLIC_2D, CSRC_, CTXT_, DLEN_, DTYPE_,
     $                   LLD_, MB_, M_, NB_, N_, RSRC_
      PARAMETER          ( BLOCK_CYCLIC_2D = 1, DLEN_ = 9, DTYPE_ = 1,
     $                     CTXT_ = 2, M_ = 3, N_ = 4, MB_ = 5, NB_ = 6,
     $                     RSRC_ = 7, CSRC_ = 8, LLD_ = 9 )
      REAL   ONE, ZERO
      PARAMETER          ( ONE = 1.0E+0, ZERO = 0.0E+0 )
*     ..
*     .. Local Scalars ..
      CHARACTER          ROWBTOP, COLBTOP
      INTEGER            I, IACOL, ICOFF, ICTXT, IIA, IROFF, J,
     $                   JJA, MN, MYCOL, MYROW, NPCOL, NPROW, 
     $                   ITEMP, IIAROW, MP, LI, LJ
      REAL   GMAX
*     ..
*     .. External Functions ..
      INTEGER            NUMROC
      EXTERNAL           NUMROC
*     ..
*     .. External Subroutines ..
      EXTERNAL           BLACS_ABORT, BLACS_GRIDINFO, CHK1MAT, IGEBR2D,
     $                   IGEBS2D, INFOG1L, INFOG2L, PSAMAX,
     $                   PSSCAL, PSSWAP, PTOPGET, PXERBLA,
     $                   SGEBS2D, SGEBR2D, SCOPY, SLASET, SGER, PSLACPY
*     ..
*     .. Intrinsic Functions ..
      INTRINSIC          MAX, MIN, MOD
*     ..
*     .. Executable Statements ..
*
*     Get grid parameters.
*
      ICTXT = DESCA( CTXT_ )
      CALL BLACS_GRIDINFO( ICTXT, NPROW, NPCOL, MYROW, MYCOL )
*
*     Test the input parameters.
*
      INFO = 0
      IF( NPROW.EQ.-1 ) THEN
         INFO = -(600+CTXT_)
      ELSE
         CALL CHK1MAT( M, 1, N, 2, IA, JA, DESCA, 6, INFO )
         IF( INFO.EQ.0 ) THEN
            IROFF = MOD( IA-1, DESCA( MB_ ) )
            ICOFF = MOD( JA-1, DESCA( NB_ ) )
            IF( N+ICOFF.GT.DESCA( NB_ ) ) THEN
               INFO = -2
            ELSE IF( IROFF.NE.0 ) THEN
               INFO = -4
            ELSE IF( ICOFF.NE.0 ) THEN
               INFO = -5
            ELSE IF( DESCA( MB_ ).NE.DESCA( NB_ ) ) THEN
               INFO = -(600+NB_)
            END IF
         END IF
      END IF
*
      IF( INFO.NE.0 ) THEN
         CALL PXERBLA( ICTXT, 'PSGEI2 ', -INFO )
         CALL BLACS_ABORT( ICTXT, 1 )
         RETURN
      END IF
*
*     Quick return if possible
*
      IF( M.EQ.0 .OR. N.EQ.0 )
     $   RETURN
*
      CALL PTOPGET( ICTXT, 'Broadcast', 'Rowwise', ROWBTOP )
      CALL PTOPGET( ICTXT, 'Broadcast', 'Columnwise', COLBTOP )
*
      MN = MIN( M, N )
      CALL INFOG2L( IA, JA, DESCA, NPROW, NPCOL, MYROW, MYCOL, IIA, JJA,
     $              ITEMP, IACOL )
      MP = NUMROC( IA-1+M, DESCA( MB_ ), MYROW, DESCA( RSRC_ ), NPROW )
*
      IF( MYCOL.EQ.IACOL ) THEN

        DO J = JA, JA+MN-1
          I = IA + J - JA
*
*         Get local indices for I and J, as well as the row number of
*         processors that contain the I-th row.
*
          LJ = JJA+J-JA
          CALL INFOG1L( I, DESCA( MB_ ), NPROW, MYROW, DESCA( RSRC_ ),
     $                  LI, IIAROW )
*
*         Find pivot and test for singularity.
*
          CALL PSAMAX( M-J+JA, GMAX, IPIV( IIA+J-JA ), A, I, J,
     $                 DESCA, 1 )
          IF( GMAX.NE.ZERO ) THEN
*
*           Apply the row interchanges to columns JA:JA+N-1
*
            CALL PSSWAP( N, A, I, JA, DESCA, DESCA( M_ ),
     $                   A, IPIV( IIA+J-JA ), JA, DESCA, DESCA( M_ ) )
*
*           Scale J-th column.
*
            CALL PSSCAL( IA-1+M, -ONE/GMAX, A, 1, J, DESCA, 1 )

          ELSE IF( INFO.EQ.0 ) THEN
            INFO = J - JA + 1
          END IF
*
*         Broadcast I-th row columnwise.
*
          IF( MYROW.EQ.IIAROW ) THEN
*
            CALL SCOPY( N, A( LI+( JJA -1 )*DESCA( LLD_ ) ),
     $                  DESCA( LLD_ ), WORK( 1 ), 1 )
            CALL SGEBS2D( ICTXT, 'Columnwise', COLBTOP, N, 1, 
     $                    WORK( 1 ), N )
*
          ELSE
*
            CALL SGEBR2D( ICTXT, 'Columnwise', COLBTOP, N, 1, 
     $                    WORK( 1 ), N, IIAROW, IACOL )
*
          END IF
*
*         Set I-th row.
*
          IF( MYROW.EQ.IIAROW ) THEN

            CALL SLASET( 'All', 1, N, ZERO, ZERO,
     $                   A( LI+( JJA -1 )*DESCA( LLD_ ) ), 
     $                   DESCA( LLD_ ) )

            IF( INFO.EQ.0 )
     $        A( LI+( LJ -1 )*DESCA( LLD_ ) ) = ONE/GMAX

          END IF
*
*         Apply the transformations to A to obtain the inverse of A.
*
          IF( J.GT.JA ) THEN
            CALL SGER( MP, J-JA, ONE, 
     $                 A( 1+( LJ -1 )*DESCA( LLD_ ) ), 1,
     $                 WORK( 1 ), 1,
     $                 A( 1+( JJA -1 )*DESCA( LLD_ ) ), DESCA( LLD_ ) )
          END IF
*
          IF( J-JA+1.LT.MN ) THEN
            CALL SGER( MP, N-J+JA-1, ONE, 
     $                 A( 1+( LJ -1 )*DESCA( LLD_ ) ), 1,
     $                 WORK( J-JA+2 ), 1,
     $                 A( 1+( LJ )*DESCA( LLD_ ) ), 
     $                 DESCA( LLD_ ) )
          END IF
*
        END DO
*
        CALL IGEBS2D( ICTXT, 'Rowwise', ROWBTOP, MN, 1, IPIV( IIA ),
     $                MN )
*
      ELSE
*
        CALL IGEBR2D( ICTXT, 'Rowwise', ROWBTOP, MN, 1, IPIV( IIA ),
     $                MN, MYROW, IACOL )
*
      END IF
*
      RETURN
*
*     End of PSGEI2
*
      END
