  module mpi_wrapper

    use dc_types

#ifdef LIB_MPI
    ! MPI
    !
    use mpi
#endif

    implicit none

    private

    integer, save, public :: nprocs
    integer, save, public :: myrank


    public ::                &
      & MPIWrapperInit     , &
      & MPIWrapperFinalize , &
      & MPIWrapperISend    , &
      & MPIWrapperIRecv    , &
      & MPIWrapperWait


    interface MPIWrapperISend
       module procedure &
            MPIWrapperISend_dble_1d, &
            MPIWrapperISend_dble_2d, &
            MPIWrapperISend_dble_3d, &
            MPIWrapperISend_dble_4d
    end interface

    interface MPIWrapperIRecv
       module procedure &
            MPIWrapperIRecv_dble_1d, &
            MPIWrapperIRecv_dble_2d, &
            MPIWrapperIRecv_dble_3d, &
            MPIWrapperIRecv_dble_4d
    end interface

    interface MPIWrapperAbort
       module procedure &
            MPIWrapperStop
    end interface


    !**************************************************************************

  contains

    !**************************************************************************

    subroutine MPIWrapperInit


#ifdef LIB_MPI

      !
      ! local variables
      !
      integer :: ierr

#endif

      nprocs = 1
      myrank = 0

#ifdef LIB_MPI

      call mpi_init( ierr )
      call mpi_comm_size( mpi_comm_world, nprocs, ierr )
      call mpi_comm_rank( mpi_comm_world, myrank, ierr )

#endif

    end subroutine MPIWrapperInit

    !**************************************************************************

    subroutine MPIWrapperFinalize


#ifdef LIB_MPI

      !
      ! local variables
      !
      integer :: ierr


      call mpi_finalize( ierr )

#endif

    end subroutine MPIWrapperFinalize

    !**************************************************************************

    subroutine MPIWrapperStop

#ifdef LIB_MPI

      !
      ! local variables
      !
      integer :: errorcode = 9
      integer :: ierr


      call mpi_abort( mpi_comm_world, errorcode, ierr )
      call MPIWrapperFinalize
      stop

#endif

    end subroutine MPIWrapperstop

    !**************************************************************************

    !**************************************************************************

    subroutine MPIWrapperWait( ireq )


      integer, intent(inout) :: ireq


#ifdef LIB_MPI

      !
      ! local variables
      !
      integer :: ierr
      integer :: istatus( MPI_STATUS_SIZE )


      call mpi_wait( ireq, istatus, ierr )

#endif

    end subroutine MPIWrapperWait

    !**************************************************************************

    subroutine MPIWrapperISend_dble_1d( idest, im, buf, ireq )


      integer , intent(in ) :: idest
      integer , intent(in ) :: im
      real(DP), intent(in ) :: buf( im )
      integer , intent(out) :: ireq


#ifdef LIB_MPI

      !
      ! local variables
      !
      integer :: ierr
      integer :: isize


      isize = size( buf )

      call mpi_isend( buf, isize, &
           mpi_double_precision, idest, 1, mpi_comm_world, &
           ireq, ierr )

#endif

    end subroutine MPIWrapperISend_dble_1d

    !**************************************************************************

    subroutine MPIWrapperIRecv_dble_1d( idep, im, buf, ireq )


      integer , intent(in ) :: idep
      integer , intent(in ) :: im
      real(DP), intent(out) :: buf( im )
      integer , intent(out) :: ireq


#ifdef LIB_MPI

      !
      ! local variables
      !
      integer :: ierr
      integer :: isize


      isize = size( buf )

      call mpi_irecv( buf, isize, &
           mpi_double_precision, idep, 1, mpi_comm_world, &
           ireq, ierr )

#endif

    end subroutine MPIWrapperIRecv_dble_1d

    !**************************************************************************

    subroutine MPIWrapperISend_dble_2d( idest, im, jm, buf, ireq )


      integer , intent(in ) :: idest
      integer , intent(in ) :: im, jm
      real(DP), intent(in ) :: buf( im, jm )
      integer , intent(out) :: ireq


#ifdef LIB_MPI

      !
      ! local variables
      !
      integer :: ierr
      integer :: isize


      isize = size( buf )

      call mpi_isend( buf, isize, &
           mpi_double_precision, idest, 1, mpi_comm_world, &
           ireq, ierr )

#endif

    end subroutine MPIWrapperISend_dble_2d

    !**************************************************************************

    subroutine MPIWrapperIRecv_dble_2d( idep, im, jm, buf, ireq )


      integer , intent(in ) :: idep
      integer , intent(in ) :: im, jm
      real(DP), intent(out) :: buf( im, jm )
      integer , intent(out) :: ireq


#ifdef LIB_MPI

      !
      ! local variables
      !
      integer :: ierr
      integer :: isize


      isize = size( buf )

      call mpi_irecv( buf, isize, &
           mpi_double_precision, idep, 1, mpi_comm_world, &
           ireq, ierr )

#endif

    end subroutine MPIWrapperIRecv_dble_2d

    !**************************************************************************

    subroutine MPIWrapperISend_dble_3d( idest, im, jm, km, buf, ireq )


      integer , intent(in ) :: idest
      integer , intent(in ) :: im, jm, km
      real(DP), intent(in ) :: buf( im, jm, km )
      integer , intent(out) :: ireq


#ifdef LIB_MPI

      !
      ! local variables
      !
      integer :: ierr
      integer :: isize


      isize = size( buf )

      call mpi_isend( buf, isize, &
           mpi_double_precision, idest, 1, mpi_comm_world, &
           ireq, ierr )

#endif

    end subroutine MPIWrapperISend_dble_3d

    !**************************************************************************

    subroutine MPIWrapperIRecv_dble_3d( idep, im, jm, km, buf, ireq )


      integer , intent(in ) :: idep
      integer , intent(in ) :: im, jm, km
      real(DP), intent(out) :: buf( im, jm, km )
      integer , intent(out) :: ireq


#ifdef LIB_MPI

      !
      ! local variables
      !
      integer :: ierr
      integer :: isize


      isize = size( buf )

      call mpi_irecv( buf, isize, &
           mpi_double_precision, idep, 1, mpi_comm_world, &
           ireq, ierr )

#endif

    end subroutine MPIWrapperIRecv_dble_3d

    !**************************************************************************

    subroutine MPIWrapperISend_dble_4d( idest, im, jm, km, lm, buf, ireq )


      integer , intent(in ) :: idest
      integer , intent(in ) :: im, jm, km, lm
      real(DP), intent(in ) :: buf( im, jm, km, lm )
      integer , intent(out) :: ireq


#ifdef LIB_MPI

      !
      ! local variables
      !
      integer :: ierr
      integer :: isize


      isize = size( buf )

      call mpi_isend( buf, isize, &
           mpi_double_precision, idest, 1, mpi_comm_world, &
           ireq, ierr )

#endif

    end subroutine MPIWrapperISend_dble_4d

    !**************************************************************************

    subroutine MPIWrapperIRecv_dble_4d( idep, im, jm, km, lm, buf, ireq )


      integer , intent(in ) :: idep
      integer , intent(in ) :: im, jm, km, lm
      real(DP), intent(out) :: buf( im, jm, km, lm )
      integer , intent(out) :: ireq


#ifdef LIB_MPI

      !
      ! local variables
      !
      integer :: ierr
      integer :: isize


      isize = size( buf )

      call mpi_irecv( buf, isize, &
           mpi_double_precision, idep, 1, mpi_comm_world, &
           ireq, ierr )

#endif


    end subroutine MPIWrapperIRecv_dble_4d

    !**************************************************************************


  end module mpi_wrapper
