! (C) Copyright 2005- ECMWF.
! (C) Copyright 2013- Meteo-France.
! 
! This software is licensed under the terms of the Apache Licence Version 2.0
! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
! In applying this licence, ECMWF does not waive the privileges and immunities
! granted to it by virtue of its status as an intergovernmental organisation
! nor does it submit to any jurisdiction.
!

MODULE MPL_GATHERV_MOD

!**** MPL_GATHERV Gather data to specific processor

!     Purpose.
!     --------
!     Gather data to specific processor
!     The data may be REAL*4, REAL*8,or INTEGER, one dimensional array
!                     REAL*4,or REAL*8, two dimensional array
!                  or INTEGER scalar

!**   Interface.
!     ----------
!        CALL MPL_GATHERV

!        Input required arguments :
!        -------------------------
!           PSENDBUF -  buffer containing message
!                       (can be type REAL*4, REAL*8 or INTEGER)
!           PRECVBUF -  buffer containing message (required from kroot)
!                       (can be type REAL*4, REAL*8 or INTEGER)
!           KRECVCOUNTS-number of elements received from each process
!                       (required from kroot processor)

!        Input optional arguments :
!        -------------------------
!           KROOT    -  rank of receiveing processor (default 1) 
!           KMP_TYPE -  buffering type (see MPL_BUFFER_METHOD)
!                       overrides value provided to MPL_BUFFER_METHOD
!           KCOMM    -  Communicator number if different from MPI_COMM_WORLD 
!                       or from that established as the default 
!                       by an MPL communicator routine
!           KRECVDISPL -displacements in PRECVBUF at which to place 
!                       the incoming data
!           CDSTRING -  Character string for ABORT messages
!                       used when KERROR is not provided

!        Output required arguments :
!        -------------------------
!           none

!        Output optional arguments :
!        -------------------------
!           KREQUEST -  Communication request
!                       required when buffering type is non-blocking
!           KERROR   -  return error code.     If not supplied, 
!                       MPL_GATHERV aborts when an error is detected.
!     Author.
!     -------
!        D.Dent, M.Hamrud     ECMWF

!     Modifications.
!     --------------
!        Original:  2000-11-23
!        M.Hamrud:  2014-10-22 : Add nonblocking option
!        F.Vana:    2015-03-05 : Support for single precision
!        P.Gillies: 2018-06-25 : Add SENDCOUNT argument, needed for zero-length sends
! --- *NOT* THREAD SAFE YET ---

!     ------------------------------------------------------------------

USE EC_PARKIND , ONLY : JPRD, JPIM, JPIB, JPRM
USE OML_MOD   ,ONLY : OML_MY_THREAD

USE MPL_MPIF
USE MPL_DATA_MODULE
USE MPL_STATS_MOD
USE YOMMPLSTATS
USE MPL_MESSAGE_MOD
USE MPL_SEND_MOD
USE MPL_RECV_MOD
USE MPL_MYRANK_MOD
IMPLICIT NONE

PRIVATE


LOGICAL   :: LLABORT=.TRUE.
REAL(KIND=JPRD)    :: ZDUM_JPRD
REAL(KIND=JPRM)    :: ZDUM_JPRM
INTEGER(KIND=JPIM)    :: ZDUM_INT

INTERFACE MPL_GATHERV
MODULE PROCEDURE MPL_GATHERV_REAL8,MPL_GATHERV_REAL4,MPL_GATHERV_CHAR_SCALAR,&
               & MPL_GATHERV_INT,MPL_GATHERV_INT_SCALAR
END INTERFACE

PUBLIC MPL_GATHERV

CONTAINS

SUBROUTINE MPL_GATHERV_PREAMB1(IERROR,IPL_NUMPROC,IPL_MYRANK,ICOMM,IROOT,IMP_TYPE, &
     & KCOMM,KROOT,KMP_TYPE,KREQUEST)


#ifdef USE_8_BYTE_WORDS
  USE MPI4TO8, ONLY : &
    MPI_COMM_SIZE => MPI_COMM_SIZE8
#endif


INTEGER(KIND=JPIM),INTENT(OUT) :: IERROR,IPL_NUMPROC,IPL_MYRANK,ICOMM,IROOT,IMP_TYPE
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KROOT
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KCOMM,KMP_TYPE,KREQUEST
INTEGER(KIND=JPIM) :: ITID
ITID = OML_MY_THREAD()
IERROR = 0

IF(MPL_NUMPROC < 1) CALL MPL_MESSAGE( &
  & CDMESSAGE='MPL_GATHERV: MPL NOT INITIALISED ',LDABORT=LLABORT) 

IF(PRESENT(KCOMM)) THEN
  ICOMM=KCOMM
ELSE
  ICOMM=MPL_COMM_OML(ITID)
ENDIF

IF(ICOMM == MPL_COMM_OML(ITID)) THEN
  IPL_NUMPROC = MPL_NUMPROC
  IPL_MYRANK  = MPL_RANK
ELSE
  CALL MPI_COMM_SIZE(ICOMM,IPL_NUMPROC,IERROR)
  IPL_MYRANK  = MPL_MYRANK(ICOMM)
ENDIF

IF(PRESENT(KROOT)) THEN
  IROOT=KROOT
ELSE
  IROOT=1
ENDIF

IF(PRESENT(KMP_TYPE)) THEN
  IMP_TYPE=KMP_TYPE
ELSE
  IMP_TYPE=MPL_METHOD
ENDIF
IF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
  IF(.NOT.PRESENT(KREQUEST)) CALL MPL_MESSAGE(CDMESSAGE='MPL_GATHERV:  KREQUEST MISSING',LDABORT=LLABORT)
ENDIF


END SUBROUTINE MPL_GATHERV_PREAMB1

SUBROUTINE MPL_GATHERV_PREAMB2(IPL_NUMPROC,IPL_MYRANK,IRECVBUFSIZE,ISENDCOUNT,&
     & KRECVCOUNTS,KIRECVDISPL,KRECVDISPL,CDSTRING)

INTEGER(KIND=JPIM),INTENT(IN) :: IPL_NUMPROC,IPL_MYRANK,IRECVBUFSIZE,ISENDCOUNT
INTEGER(KIND=JPIM),INTENT(IN)  :: KRECVCOUNTS(:)
INTEGER(KIND=JPIM),INTENT(OUT) :: KIRECVDISPL(:) 
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KRECVDISPL(:)
CHARACTER(LEN=*),INTENT(IN),OPTIONAL :: CDSTRING
INTEGER(KIND=JPIM) :: IR


IF(SIZE(KRECVCOUNTS)  < IPL_NUMPROC) THEN
  WRITE(MPL_ERRUNIT,*)'MPL_GATHERV: ERROR KRECVCOUNTS DIMENSION=',&
   & SIZE(KRECVCOUNTS)
  CALL MPL_MESSAGE(CDMESSAGE=&
   & 'MPL_GATHERV: ERROR KRECVCOUNTS DIMENSION IS WRONG',LDABORT=LLABORT)
ENDIF
IF(ISENDCOUNT /= KRECVCOUNTS(IPL_MYRANK)) THEN
  WRITE(MPL_ERRUNIT,*)'MPL_GATHERV: ERROR KRECVCOUNTS INCONSISTENCY ',&
   & ISENDCOUNT,KRECVCOUNTS(IPL_MYRANK)
  CALL MPL_MESSAGE(CDMESSAGE=&
   & 'MPL_GATHERV: ERROR ISENDCOUNT /= KRECVCOUNTS(MPL_RANK) ',LDABORT=LLABORT)
ENDIF

IF(PRESENT(KRECVDISPL)) THEN
  KIRECVDISPL(1:IPL_NUMPROC) = KRECVDISPL(1:IPL_NUMPROC)
ELSE
  KIRECVDISPL(1:IPL_NUMPROC) = 0
  DO IR=2, IPL_NUMPROC
    KIRECVDISPL(IR) = KIRECVDISPL(IR-1) + KRECVCOUNTS(IR-1)
  ENDDO
ENDIF
DO IR=1, IPL_NUMPROC
  IF(KIRECVDISPL(IR)+KRECVCOUNTS(IR) > IRECVBUFSIZE) THEN
    WRITE(MPL_ERRUNIT,'(A,4I10)')'MPL_GATHERV:RECV BUFFER TOO SMALL  ', &
     & IR,KIRECVDISPL(IR),KRECVCOUNTS(IR),IRECVBUFSIZE
    CALL MPL_MESSAGE(CDMESSAGE='MPL_GATHERV',CDSTRING=CDSTRING,LDABORT=LLABORT)
  ENDIF
ENDDO

END SUBROUTINE MPL_GATHERV_PREAMB2

SUBROUTINE MPL_GATHERV_REAL4(PSENDBUF,KROOT,PRECVBUF,KRECVCOUNTS,KSENDCOUNT,KRECVDISPL, &
                            & KMP_TYPE,KCOMM,KERROR,KREQUEST,CDSTRING)


#ifdef USE_8_BYTE_WORDS
  USE MPI4TO8, ONLY : &
    MPI_GATHERV => MPI_GATHERV8
#endif



REAL(KIND=JPRM),INTENT(IN) :: PSENDBUF(:)
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KROOT
REAL(KIND=JPRM),INTENT(OUT),OPTIONAL  :: PRECVBUF(:)
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KRECVCOUNTS(:),KSENDCOUNT
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KRECVDISPL(:),KCOMM,KMP_TYPE
INTEGER(KIND=JPIM),INTENT(OUT),OPTIONAL :: KERROR,KREQUEST
CHARACTER(LEN=*),INTENT(IN),OPTIONAL :: CDSTRING

INTEGER(KIND=JPIM) :: IRECVDISPL(MPL_NUMPROC)
INTEGER(KIND=JPIM) :: IERROR,IPL_NUMPROC,IPL_MYRANK,ICOMM,IROOT,IMP_TYPE
INTEGER(KIND=JPIM) :: IRECVBUFSIZE,ISENDCOUNT

IF(PRESENT(KSENDCOUNT)) THEN
  ISENDCOUNT=KSENDCOUNT
ELSE
  ISENDCOUNT = SIZE(PSENDBUF)
ENDIF
#ifndef NAG
IF( (LOC(PSENDBUF(UBOUND(PSENDBUF,1))) - LOC(PSENDBUF(LBOUND(PSENDBUF,1)))) /= 4_JPIB*(ISENDCOUNT - 1) .AND. &
  & ISENDCOUNT > 0 ) THEN
  CALL MPL_MESSAGE(CDMESSAGE='MPL_GATHERV: SENDBUF NOT CONTIGUOUS ',LDABORT=LLABORT)
ENDIF
#endif

CALL MPL_GATHERV_PREAMB1(IERROR,IPL_NUMPROC,IPL_MYRANK,ICOMM,IROOT,IMP_TYPE,KCOMM,KROOT,KMP_TYPE,KREQUEST)

IF(IPL_MYRANK == IROOT) THEN
  IF( .NOT. PRESENT(PRECVBUF)) CALL MPL_MESSAGE(&
   & CDMESSAGE='MPL_GATHERV:RECVBUF MISSING',CDSTRING=CDSTRING,LDABORT=LLABORT)

  IRECVBUFSIZE = SIZE(PRECVBUF)
#ifndef NAG
  IF( (LOC(PRECVBUF(UBOUND(PRECVBUF,1))) - LOC(PRECVBUF(LBOUND(PRECVBUF,1)))) /= 4_JPIB*(IRECVBUFSIZE - 1) .AND. &
    & IRECVBUFSIZE > 0 ) THEN
    CALL MPL_MESSAGE(CDMESSAGE='MPL_GATHERV: RECVBUF NOT CONTIGUOUS ',LDABORT=LLABORT)
  ENDIF
#endif

  CALL MPL_GATHERV_PREAMB2(IPL_NUMPROC,IPL_MYRANK,IRECVBUFSIZE,ISENDCOUNT,&
       & KRECVCOUNTS,IRECVDISPL,KRECVDISPL,CDSTRING)
  IF(IMP_TYPE == JP_BLOCKING_STANDARD .OR. IMP_TYPE == JP_BLOCKING_BUFFERED) THEN
    CALL MPI_GATHERV(PSENDBUF(1),ISENDCOUNT,INT(MPI_REAL4),PRECVBUF(1),KRECVCOUNTS, &
     &  IRECVDISPL,INT(MPI_REAL4),IROOT-1,ICOMM,IERROR)
  ELSEIF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
    CALL MPI_IGATHERV(PSENDBUF(1),ISENDCOUNT,INT(MPI_REAL4),PRECVBUF(1),KRECVCOUNTS, &
     &  IRECVDISPL,INT(MPI_REAL4),IROOT-1,ICOMM,KREQUEST,IERROR)
  ENDIF
  IF(LMPLSTATS) THEN
    CALL MPL_SENDSTATS(ISENDCOUNT,INT(MPI_REAL4))
    CALL MPL_RECVSTATS(SUM(KRECVCOUNTS),INT(MPI_REAL4))
  ENDIF
ELSE
  IF(IMP_TYPE == JP_BLOCKING_STANDARD .OR. IMP_TYPE == JP_BLOCKING_BUFFERED) THEN
    CALL MPI_GATHERV(PSENDBUF(1),ISENDCOUNT,INT(MPI_REAL4),ZDUM_JPRM,1, &
     &  1,INT(MPI_REAL4),IROOT-1,ICOMM,IERROR)
  ELSEIF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
    CALL MPI_IGATHERV(PSENDBUF(1),ISENDCOUNT,INT(MPI_REAL4),ZDUM_JPRM,1, &
     &  1,INT(MPI_REAL4),IROOT-1,ICOMM,KREQUEST,IERROR)
  ENDIF
  IF(LMPLSTATS) THEN
    CALL MPL_SENDSTATS(ISENDCOUNT,INT(MPI_REAL4))
  ENDIF
ENDIF

IF(PRESENT(KERROR)) THEN
  KERROR=IERROR
ELSE
  IF(IERROR /= 0 ) CALL MPL_MESSAGE(IERROR,'MPL_GATHERV',&
   & CDSTRING,LDABORT=LLABORT)
ENDIF

END SUBROUTINE MPL_GATHERV_REAL4

SUBROUTINE MPL_GATHERV_REAL8(PSENDBUF,KROOT,PRECVBUF,KRECVCOUNTS,KSENDCOUNT,KRECVDISPL, &
                            & KMP_TYPE,KCOMM,KERROR,KREQUEST,CDSTRING)


#ifdef USE_8_BYTE_WORDS
  USE MPI4TO8, ONLY : &
    MPI_GATHERV => MPI_GATHERV8
#endif



REAL(KIND=JPRD)            :: PSENDBUF(:)
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KRECVCOUNTS(:),KSENDCOUNT
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KROOT
REAL(KIND=JPRD),OPTIONAL   :: PRECVBUF(:)
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KRECVDISPL(:),KCOMM,KMP_TYPE
INTEGER(KIND=JPIM),INTENT(OUT),OPTIONAL :: KERROR,KREQUEST
CHARACTER(LEN=*),INTENT(IN),OPTIONAL :: CDSTRING

INTEGER(KIND=JPIM) :: IRECVDISPL(MPL_NUMPROC)
INTEGER(KIND=JPIM) :: IERROR,IPL_NUMPROC,IPL_MYRANK,ICOMM,IROOT,IMP_TYPE
INTEGER(KIND=JPIM) :: IRECVBUFSIZE,ISENDCOUNT
INTEGER(KIND=JPIM) :: IDUM,IST,IEND,JK


IF(PRESENT(KSENDCOUNT)) THEN
  ISENDCOUNT=KSENDCOUNT
ELSE
  ISENDCOUNT = SIZE(PSENDBUF)
ENDIF
#ifndef NAG
IF( (LOC(PSENDBUF(UBOUND(PSENDBUF,1))) - LOC(PSENDBUF(LBOUND(PSENDBUF,1)))) /= 8_JPIB*(ISENDCOUNT - 1) .AND. &
  & ISENDCOUNT > 0 ) THEN
  CALL MPL_MESSAGE(CDMESSAGE='MPL_GATHERV: SENDBUF NOT CONTIGUOUS ',LDABORT=LLABORT)
ENDIF
#endif

CALL MPL_GATHERV_PREAMB1(IERROR,IPL_NUMPROC,IPL_MYRANK,ICOMM,IROOT,IMP_TYPE,KCOMM,KROOT,KMP_TYPE,KREQUEST)

IF(IPL_MYRANK == IROOT) THEN
  IF( .NOT. PRESENT(PRECVBUF)) CALL MPL_MESSAGE(&
   & CDMESSAGE='MPL_GATHERV:RECVBUF MISSING',CDSTRING=CDSTRING,LDABORT=LLABORT)
  IRECVBUFSIZE = SIZE(PRECVBUF)
#ifndef NAG
  IF( (LOC(PRECVBUF(UBOUND(PRECVBUF,1))) - LOC(PRECVBUF(LBOUND(PRECVBUF,1)))) /= 8_JPIB*(IRECVBUFSIZE - 1) .AND. &
    & IRECVBUFSIZE > 0 ) THEN
    CALL MPL_MESSAGE(CDMESSAGE='MPL_GATHERV: RECVBUF NOT CONTIGUOUS ',LDABORT=LLABORT)
  ENDIF
#endif
  CALL MPL_GATHERV_PREAMB2(IPL_NUMPROC,IPL_MYRANK,IRECVBUFSIZE,ISENDCOUNT,&
       & KRECVCOUNTS,IRECVDISPL,KRECVDISPL,CDSTRING)

  IF(IMP_TYPE == JP_BLOCKING_STANDARD .OR. IMP_TYPE == JP_BLOCKING_BUFFERED) THEN
    CALL MPI_GATHERV(PSENDBUF(1),ISENDCOUNT,INT(MPI_REAL8),PRECVBUF(1),KRECVCOUNTS,&
     &  IRECVDISPL,INT(MPI_REAL8),IROOT-1,ICOMM,IERROR)
  ELSEIF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
    CALL MPI_IGATHERV(PSENDBUF(1),ISENDCOUNT,INT(MPI_REAL8),PRECVBUF(1),KRECVCOUNTS,&
     &  IRECVDISPL,INT(MPI_REAL8),IROOT-1,ICOMM,KREQUEST,IERROR)
  ENDIF
  IF(LMPLSTATS) THEN
    CALL MPL_SENDSTATS(ISENDCOUNT,INT(MPI_REAL8))
    CALL MPL_RECVSTATS(SUM(KRECVCOUNTS),INT(MPI_REAL8))
  ENDIF
ELSE
  IF(IMP_TYPE == JP_BLOCKING_STANDARD .OR. IMP_TYPE == JP_BLOCKING_BUFFERED) THEN
    CALL MPI_GATHERV(PSENDBUF(1),ISENDCOUNT,INT(MPI_REAL8),ZDUM_JPRD,1, &
     &  1,INT(MPI_REAL8),IROOT-1,ICOMM,IERROR)
  ELSEIF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
    CALL MPI_IGATHERV(PSENDBUF(1),ISENDCOUNT,INT(MPI_REAL8),ZDUM_JPRD,1, &
     &  1,INT(MPI_REAL8),IROOT-1,ICOMM,KREQUEST,IERROR)
  ENDIF
  IF(LMPLSTATS) THEN
    CALL MPL_SENDSTATS(ISENDCOUNT,INT(MPI_REAL8))
  ENDIF
ENDIF

IF(PRESENT(KERROR)) THEN
  KERROR=IERROR
ELSE
  IF(IERROR /= 0 ) CALL MPL_MESSAGE(IERROR,'MPL_GATHERV',CDSTRING,&
   & LDABORT=LLABORT)
ENDIF

END SUBROUTINE MPL_GATHERV_REAL8

SUBROUTINE MPL_GATHERV_CHAR_SCALAR(CSENDBUF,KROOT,CRECVBUF,KRECVCOUNTS,KSENDCOUNT,KRECVDISPL, &
                            & KMP_TYPE,KCOMM,KERROR,KREQUEST,CDSTRING)


#ifdef USE_8_BYTE_WORDS
  USE MPI4TO8, ONLY : &
    MPI_GATHERV => MPI_GATHERV8
#endif


CHARACTER(LEN=*)                        :: CSENDBUF
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL  :: KRECVCOUNTS(:),KSENDCOUNT
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL  :: KROOT
CHARACTER(LEN=*),OPTIONAL               :: CRECVBUF(:)
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL  :: KRECVDISPL(:),KCOMM,KMP_TYPE
INTEGER(KIND=JPIM),INTENT(OUT),OPTIONAL :: KERROR,KREQUEST
CHARACTER(LEN=*),INTENT(IN),OPTIONAL    :: CDSTRING

INTEGER(KIND=JPIM) :: IRECVDISPL(MPL_NUMPROC)
INTEGER(KIND=JPIM) :: IERROR,IPL_NUMPROC,IPL_MYRANK,ICOMM,IROOT,IMP_TYPE
INTEGER(KIND=JPIM) :: IRECVBUFSIZE,ISENDCOUNT
INTEGER(KIND=JPIM) :: IDUM,IST,IEND,JK !,ICOUNT

IF(PRESENT(KSENDCOUNT)) THEN
  ISENDCOUNT=KSENDCOUNT
ELSE
  ISENDCOUNT = LEN(CSENDBUF)
ENDIF

CALL MPL_GATHERV_PREAMB1(IERROR,IPL_NUMPROC,IPL_MYRANK,ICOMM,IROOT,IMP_TYPE,KCOMM,KROOT,KMP_TYPE,KREQUEST)

IF(IPL_MYRANK == IROOT) THEN
  IF( .NOT. PRESENT(CRECVBUF)) CALL MPL_MESSAGE(&
   & CDMESSAGE='MPL_GATHERV:RECVBUF MISSING',CDSTRING=CDSTRING,LDABORT=LLABORT)
  IRECVBUFSIZE = LEN(CRECVBUF)*SIZE(CRECVBUF)
#ifndef NAG
  IF( (LOC(CRECVBUF(UBOUND(CRECVBUF,1))) - LOC(CRECVBUF(LBOUND(CRECVBUF,1)))) /= (IRECVBUFSIZE-LEN(CRECVBUF) ) .AND. &
    & IRECVBUFSIZE > 0 ) THEN
    CALL MPL_MESSAGE(CDMESSAGE='MPL_GATHERV: RECVBUF NOT CONTIGUOUS ',LDABORT=LLABORT)
  ENDIF
#endif
  CALL MPL_GATHERV_PREAMB2(IPL_NUMPROC,IPL_MYRANK,IRECVBUFSIZE,ISENDCOUNT,&
       & KRECVCOUNTS,IRECVDISPL,KRECVDISPL,CDSTRING)

  IF(IMP_TYPE == JP_BLOCKING_STANDARD .OR. IMP_TYPE == JP_BLOCKING_BUFFERED) THEN
    CALL MPI_GATHERV(CSENDBUF,ISENDCOUNT,INT(MPI_CHARACTER),CRECVBUF(1),KRECVCOUNTS,&
     &  IRECVDISPL,INT(MPI_CHARACTER),IROOT-1,ICOMM,IERROR)
  ELSEIF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
    CALL MPI_IGATHERV(CSENDBUF,ISENDCOUNT,INT(MPI_CHARACTER),CRECVBUF(1),KRECVCOUNTS,&
     &  IRECVDISPL,INT(MPI_CHARACTER),IROOT-1,ICOMM,KREQUEST,IERROR)
  ENDIF
  IF(LMPLSTATS) THEN
    CALL MPL_SENDSTATS(ISENDCOUNT,INT(MPI_CHARACTER))
    CALL MPL_RECVSTATS(SUM(KRECVCOUNTS),INT(MPI_CHARACTER))
  ENDIF
ELSE
  IF(IMP_TYPE == JP_BLOCKING_STANDARD .OR. IMP_TYPE == JP_BLOCKING_BUFFERED) THEN
    CALL MPI_GATHERV(CSENDBUF,ISENDCOUNT,INT(MPI_CHARACTER),ZDUM_JPRD,1, &
     &  1,INT(MPI_CHARACTER),IROOT-1,ICOMM,IERROR)
  ELSEIF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
    CALL MPI_IGATHERV(CSENDBUF,ISENDCOUNT,INT(MPI_CHARACTER),ZDUM_JPRD,1, &
     &  1,INT(MPI_CHARACTER),IROOT-1,ICOMM,KREQUEST,IERROR)
  ENDIF
  IF(LMPLSTATS) THEN
    CALL MPL_SENDSTATS(ISENDCOUNT,INT(MPI_CHARACTER))
  ENDIF
ENDIF

IF(PRESENT(KERROR)) THEN
  KERROR=IERROR
ELSE
  IF(IERROR /= 0 ) CALL MPL_MESSAGE(IERROR,'MPL_GATHERV',CDSTRING,&
   & LDABORT=LLABORT)
ENDIF

END SUBROUTINE MPL_GATHERV_CHAR_SCALAR

SUBROUTINE MPL_GATHERV_INT(KSENDBUF,KROOT,KRECVBUF,KRECVCOUNTS,KSENDCOUNT,KRECVDISPL, &
                            &  KMP_TYPE,KCOMM,KERROR,KREQUEST,CDSTRING)


#ifdef USE_8_BYTE_WORDS
  USE MPI4TO8, ONLY : &
    MPI_GATHERV => MPI_GATHERV8
#endif



INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KROOT
INTEGER(KIND=JPIM),INTENT(IN)         :: KSENDBUF(:)
INTEGER(KIND=JPIM),INTENT(OUT),OPTIONAL :: KRECVBUF(:)
INTEGER(KIND=JPIM),INTENT(IN) :: KRECVCOUNTS(:)
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KSENDCOUNT,KRECVDISPL(:),KCOMM,KMP_TYPE
INTEGER(KIND=JPIM),INTENT(OUT),OPTIONAL :: KERROR,KREQUEST
CHARACTER(LEN=*),INTENT(IN),OPTIONAL :: CDSTRING

INTEGER(KIND=JPIM) :: IRECVDISPL(MPL_NUMPROC)
INTEGER(KIND=JPIM) :: IERROR,IPL_NUMPROC,IPL_MYRANK,ICOMM,IROOT,IMP_TYPE
INTEGER(KIND=JPIM) :: IRECVBUFSIZE,ISENDCOUNT

IF(PRESENT(KSENDCOUNT)) THEN
  ISENDCOUNT=KSENDCOUNT
ELSE
  ISENDCOUNT = SIZE(KSENDBUF)
ENDIF
#ifndef NAG
IF( (LOC(KSENDBUF(UBOUND(KSENDBUF,1))) - LOC(KSENDBUF(LBOUND(KSENDBUF,1)))) /= 4_JPIB*(ISENDCOUNT - 1) .AND. &
  & ISENDCOUNT > 0 ) THEN
  CALL MPL_MESSAGE(CDMESSAGE='MPL_GATHERV: SENDBUF NOT CONTIGUOUS ',LDABORT=LLABORT)
ENDIF
#endif

CALL MPL_GATHERV_PREAMB1(IERROR,IPL_NUMPROC,IPL_MYRANK,ICOMM,IROOT,IMP_TYPE,KCOMM,KROOT,KMP_TYPE,KREQUEST)

IF(IPL_MYRANK == IROOT) THEN
  IF( .NOT. PRESENT(KRECVBUF)) CALL MPL_MESSAGE(&
   & CDMESSAGE='MPL_GATHERV:RECVBUF MISSING',CDSTRING=CDSTRING,LDABORT=LLABORT)

  IRECVBUFSIZE = SIZE(KRECVBUF)
#ifndef NAG
  IF( (LOC(KRECVBUF(UBOUND(KRECVBUF,1))) - LOC(KRECVBUF(LBOUND(KRECVBUF,1)))) /= 4_JPIB*(IRECVBUFSIZE - 1) .AND. &
    & IRECVBUFSIZE > 0 ) THEN
    CALL MPL_MESSAGE(CDMESSAGE='MPL_GATHERV: RECVBUF NOT CONTIGUOUS ',LDABORT=LLABORT)
  ENDIF
#endif

  CALL MPL_GATHERV_PREAMB2(IPL_NUMPROC,IPL_MYRANK,IRECVBUFSIZE,ISENDCOUNT,&
       & KRECVCOUNTS,IRECVDISPL,KRECVDISPL,CDSTRING)
  IF(IMP_TYPE == JP_BLOCKING_STANDARD .OR. IMP_TYPE == JP_BLOCKING_BUFFERED) THEN
    CALL MPI_GATHERV(KSENDBUF(1),ISENDCOUNT,INT(MPI_INTEGER),KRECVBUF(1),&
     & KRECVCOUNTS,IRECVDISPL,INT(MPI_INTEGER),IROOT-1,ICOMM,IERROR)
  ELSEIF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
    CALL MPI_IGATHERV(KSENDBUF(1),ISENDCOUNT,INT(MPI_INTEGER),KRECVBUF(1),&
     & KRECVCOUNTS,IRECVDISPL,INT(MPI_INTEGER),IROOT-1,ICOMM,KREQUEST,IERROR)
  ENDIF
  IF(LMPLSTATS) THEN
    CALL MPL_SENDSTATS(ISENDCOUNT,INT(MPI_INTEGER))
    CALL MPL_RECVSTATS(SUM(KRECVCOUNTS),INT(MPI_INTEGER))
  ENDIF
ELSE
  IF(IMP_TYPE == JP_BLOCKING_STANDARD .OR. IMP_TYPE == JP_BLOCKING_BUFFERED) THEN
    CALL MPI_GATHERV(KSENDBUF(1),ISENDCOUNT,INT(MPI_INTEGER),ZDUM_INT,1, &
     &  1,INT(MPI_INTEGER),IROOT-1,ICOMM,IERROR)
  ELSEIF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
    CALL MPI_IGATHERV(KSENDBUF(1),ISENDCOUNT,INT(MPI_INTEGER),ZDUM_INT,1, &
     &  1,INT(MPI_INTEGER),IROOT-1,ICOMM,KREQUEST,IERROR)
  ENDIF
  IF(LMPLSTATS) THEN
    CALL MPL_SENDSTATS(ISENDCOUNT,INT(MPI_INTEGER))
  ENDIF
ENDIF

IF(PRESENT(KERROR)) THEN
  KERROR=IERROR
ELSE
  IF(IERROR /= 0 ) CALL MPL_MESSAGE(IERROR,'MPL_GATHERV',CDSTRING,LDABORT=LLABORT)
ENDIF

END SUBROUTINE MPL_GATHERV_INT

SUBROUTINE MPL_GATHERV_INT_SCALAR(KSENDBUF,KROOT,KRECVBUF,KRECVCOUNTS,KSENDCOUNT,&
 & KMP_TYPE,KRECVDISPL,KCOMM,KERROR,KREQUEST,CDSTRING)


#ifdef USE_8_BYTE_WORDS
  USE MPI4TO8, ONLY : &
    MPI_GATHERV => MPI_GATHERV8, MPI_GATHER => MPI_GATHER8
#endif



INTEGER(KIND=JPIM),INTENT(IN) :: KSENDBUF
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KROOT
INTEGER(KIND=JPIM),INTENT(OUT),OPTIONAL :: KRECVBUF(:)
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KRECVCOUNTS(:),KSENDCOUNT
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KRECVDISPL(:),KCOMM,KMP_TYPE
INTEGER(KIND=JPIM),INTENT(OUT),OPTIONAL :: KERROR,KREQUEST
CHARACTER(LEN=*),INTENT(IN),OPTIONAL :: CDSTRING

INTEGER(KIND=JPIM) :: IRECVDISPL(MPL_NUMPROC),IRECVCOUNTS(MPL_NUMPROC)
INTEGER(KIND=JPIM) :: IERROR,IPL_NUMPROC,IPL_MYRANK,ICOMM,IROOT,IMP_TYPE
INTEGER(KIND=JPIM) :: IRECVBUFSIZE,ISENDCOUNT

IF(PRESENT(KSENDCOUNT)) THEN
  ISENDCOUNT=KSENDCOUNT
ELSE
  ISENDCOUNT = 1
ENDIF
IF(PRESENT(KRECVCOUNTS)) THEN
  IRECVCOUNTS=KRECVCOUNTS
ELSE
  IRECVCOUNTS(:) = 1
ENDIF
CALL MPL_GATHERV_PREAMB1(IERROR,IPL_NUMPROC,IPL_MYRANK,ICOMM,IROOT,IMP_TYPE,KCOMM,KROOT,KMP_TYPE,KREQUEST)

IF(IPL_MYRANK == IROOT) THEN
  IF( .NOT. PRESENT(KRECVBUF)) CALL MPL_MESSAGE(&
   & CDMESSAGE='MPL_GATHERV:RECVBUF MISSING',CDSTRING=CDSTRING,LDABORT=LLABORT)
  IRECVBUFSIZE = SIZE(KRECVBUF)
  IF(PRESENT(KRECVDISPL).OR.PRESENT(KSENDCOUNT)) THEN
    IF(.NOT.PRESENT(KSENDCOUNT)) THEN
      IRECVCOUNTS(:) = 1
    ENDIF
    CALL MPL_GATHERV_PREAMB2(IPL_NUMPROC,IPL_MYRANK,IRECVBUFSIZE,ISENDCOUNT,&
         & IRECVCOUNTS,IRECVDISPL,KRECVDISPL,CDSTRING)
    IF(IMP_TYPE == JP_BLOCKING_STANDARD .OR. IMP_TYPE == JP_BLOCKING_BUFFERED) THEN
      CALL MPI_GATHERV(KSENDBUF,ISENDCOUNT,INT(MPI_INTEGER),KRECVBUF(1),&
       & IRECVCOUNTS,IRECVDISPL,INT(MPI_INTEGER),IROOT-1,ICOMM,IERROR)
    ELSEIF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
      CALL MPI_IGATHERV(KSENDBUF,ISENDCOUNT,INT(MPI_INTEGER),KRECVBUF(1),&
       & IRECVCOUNTS,IRECVDISPL,INT(MPI_INTEGER),IROOT-1,ICOMM,KREQUEST,IERROR)
    ENDIF
    IF(LMPLSTATS) THEN
      CALL MPL_SENDSTATS(ISENDCOUNT,INT(MPI_INTEGER))
      CALL MPL_RECVSTATS(SUM(IRECVCOUNTS),INT(MPI_INTEGER))
    ENDIF
  ELSE
    IF(IRECVBUFSIZE < IPL_NUMPROC) THEN
      CALL MPL_MESSAGE(CDMESSAGE='MPL_GATHERV:IRECVBUFSIZE < IPL_NUMPROC',&
       & CDSTRING=CDSTRING,LDABORT=LLABORT)
    ENDIF
    IF(IMP_TYPE == JP_BLOCKING_STANDARD .OR. IMP_TYPE == JP_BLOCKING_BUFFERED) THEN
      CALL MPI_GATHER(KSENDBUF,ISENDCOUNT,INT(MPI_INTEGER),KRECVBUF(1),&
       & ISENDCOUNT,INT(MPI_INTEGER),IROOT-1,ICOMM,IERROR)
    ELSEIF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
      CALL MPI_IGATHER(KSENDBUF,ISENDCOUNT,INT(MPI_INTEGER),KRECVBUF(1),&
       & ISENDCOUNT,INT(MPI_INTEGER),IROOT-1,ICOMM,KREQUEST,IERROR)
    ENDIF
    IF(LMPLSTATS) THEN
      CALL MPL_SENDSTATS(ISENDCOUNT,INT(MPI_INTEGER))
      CALL MPL_RECVSTATS(ISENDCOUNT,INT(MPI_INTEGER))
    ENDIF
  ENDIF
ELSE
  IF(PRESENT(KRECVDISPL).OR.PRESENT(KSENDCOUNT)) THEN
    IF(.NOT.PRESENT(KSENDCOUNT)) THEN
      IRECVCOUNTS(:)=1
    ENDIF
    IF(IMP_TYPE == JP_BLOCKING_STANDARD .OR. IMP_TYPE == JP_BLOCKING_BUFFERED) THEN
      CALL MPI_GATHERV(KSENDBUF,ISENDCOUNT,INT(MPI_INTEGER),ZDUM_INT,KRECVBUF(1), &
       &  IRECVCOUNTS,INT(MPI_INTEGER),IROOT-1,ICOMM,IERROR)
    ELSEIF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
      CALL MPI_IGATHERV(KSENDBUF,ISENDCOUNT,INT(MPI_INTEGER),ZDUM_INT,1, &
       &  1,INT(MPI_INTEGER),IROOT-1,ICOMM,KREQUEST,IERROR)
    ENDIF
    IF(LMPLSTATS) THEN
      CALL MPL_SENDSTATS(ISENDCOUNT,INT(MPI_INTEGER))
    ENDIF
  ELSE
    IF(IMP_TYPE == JP_BLOCKING_STANDARD .OR. IMP_TYPE == JP_BLOCKING_BUFFERED) THEN
      CALL MPI_GATHER(KSENDBUF,ISENDCOUNT,INT(MPI_INTEGER),ZDUM_INT,&
       & 1,INT(MPI_INTEGER),IROOT-1,ICOMM,IERROR)
    ELSEIF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
      CALL MPI_IGATHER(KSENDBUF,ISENDCOUNT,INT(MPI_INTEGER),ZDUM_INT,&
       & 1,INT(MPI_INTEGER),IROOT-1,ICOMM,KREQUEST,IERROR)
    ENDIF
    IF(LMPLSTATS) THEN
      CALL MPL_SENDSTATS(ISENDCOUNT,INT(MPI_INTEGER))
    ENDIF
  ENDIF
ENDIF

IF(PRESENT(KERROR)) THEN
  KERROR=IERROR
ELSE
  IF(IERROR /= 0 ) CALL MPL_MESSAGE(IERROR,'MPL_GATHERV',CDSTRING,LDABORT=LLABORT)
ENDIF

END SUBROUTINE MPL_GATHERV_INT_SCALAR

SUBROUTINE MPL_GATHERV_REAL8_SCALAR(PSENDBUF,KROOT,PRECVBUF,KRECVCOUNTS,&
 &  KRECVDISPL,KMP_TYPE,KCOMM,KERROR,KREQUEST,CDSTRING)


#ifdef USE_8_BYTE_WORDS
  USE MPI4TO8, ONLY : &
    MPI_GATHERV => MPI_GATHERV8, MPI_GATHER => MPI_GATHER8
#endif



REAL(KIND=JPRD),INTENT(IN) :: PSENDBUF
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KROOT
REAL(KIND=JPRD),INTENT(OUT),OPTIONAL :: PRECVBUF(:)
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KRECVCOUNTS(:) ! Not used; for compatibility only
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KRECVDISPL(:),KCOMM,KMP_TYPE
INTEGER(KIND=JPIM),INTENT(OUT),OPTIONAL :: KERROR,KREQUEST
CHARACTER(LEN=*),INTENT(IN),OPTIONAL :: CDSTRING

INTEGER(KIND=JPIM) :: IRECVDISPL(MPL_NUMPROC),IRECVCOUNTS(MPL_NUMPROC)
INTEGER(KIND=JPIM) :: IERROR,IPL_NUMPROC,IPL_MYRANK,ICOMM,IROOT,IMP_TYPE
INTEGER(KIND=JPIM) :: IRECVBUFSIZE,ISENDCOUNT

ISENDCOUNT = 1
CALL MPL_GATHERV_PREAMB1(IERROR,IPL_NUMPROC,IPL_MYRANK,ICOMM,IROOT,IMP_TYPE,KCOMM,KROOT,KMP_TYPE,KREQUEST)

IF(IPL_MYRANK == IROOT) THEN
  IF( .NOT. PRESENT(PRECVBUF)) CALL MPL_MESSAGE(&
   & CDMESSAGE='MPL_GATHERV:RECVBUF MISSING',CDSTRING=CDSTRING,LDABORT=LLABORT)
  IRECVBUFSIZE = SIZE(PRECVBUF)
  IF(PRESENT(KRECVDISPL)) THEN
    IRECVCOUNTS(:) = 1
    CALL MPL_GATHERV_PREAMB2(IPL_NUMPROC,IPL_MYRANK,IRECVBUFSIZE,ISENDCOUNT,&
         & IRECVCOUNTS,IRECVDISPL,KRECVDISPL,CDSTRING)
    IF(IMP_TYPE == JP_BLOCKING_STANDARD .OR. IMP_TYPE == JP_BLOCKING_BUFFERED) THEN
      CALL MPI_GATHERV(PSENDBUF,ISENDCOUNT,INT(MPI_REAL8),PRECVBUF(1),&
       & IRECVCOUNTS,IRECVDISPL,INT(MPI_REAL8),IROOT-1,ICOMM,IERROR)
    ELSEIF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
      CALL MPI_IGATHERV(PSENDBUF,ISENDCOUNT,INT(MPI_REAL8),PRECVBUF(1),&
       & IRECVCOUNTS,IRECVDISPL,INT(MPI_REAL8),IROOT-1,ICOMM,KREQUEST,IERROR)
    ENDIF
    IF(LMPLSTATS) THEN
      CALL MPL_SENDSTATS(ISENDCOUNT,INT(MPI_REAL8))
      CALL MPL_RECVSTATS(SUM(IRECVCOUNTS),INT(MPI_REAL8))
    ENDIF
  ELSE
    IF(IRECVBUFSIZE < IPL_NUMPROC) THEN
      CALL MPL_MESSAGE(CDMESSAGE='MPL_GATHERV:IRECVBUFSIZE < IPL_NUMPROC',&
       & CDSTRING=CDSTRING,LDABORT=LLABORT)
    ENDIF
    IF(IMP_TYPE == JP_BLOCKING_STANDARD .OR. IMP_TYPE == JP_BLOCKING_BUFFERED) THEN
      CALL MPI_GATHER(PSENDBUF,ISENDCOUNT,INT(MPI_REAL8),PRECVBUF(1),&
       & ISENDCOUNT,INT(MPI_REAL8),IROOT-1,ICOMM,IERROR)
    ELSEIF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
      CALL MPI_IGATHER(PSENDBUF,ISENDCOUNT,INT(MPI_REAL8),PRECVBUF(1),&
       & ISENDCOUNT,INT(MPI_REAL8),IROOT-1,ICOMM,KREQUEST,IERROR)
    ENDIF
    IF(LMPLSTATS) THEN
      CALL MPL_SENDSTATS(ISENDCOUNT,INT(MPI_REAL8))
      CALL MPL_RECVSTATS(ISENDCOUNT,INT(MPI_REAL8))
    ENDIF
  ENDIF
ELSE
  IF(PRESENT(KRECVDISPL)) THEN
    IF(IMP_TYPE == JP_BLOCKING_STANDARD .OR. IMP_TYPE == JP_BLOCKING_BUFFERED) THEN
      CALL MPI_GATHERV(PSENDBUF,ISENDCOUNT,INT(MPI_REAL8),ZDUM_JPRD,1, &
       &  1,INT(MPI_REAL8),IROOT-1,ICOMM,IERROR)
    ELSEIF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
      CALL MPI_IGATHERV(PSENDBUF,ISENDCOUNT,INT(MPI_REAL8),ZDUM_JPRD,1, &
       &  1,INT(MPI_REAL8),IROOT-1,ICOMM,KREQUEST,IERROR)
    ENDIF
    IF(LMPLSTATS) THEN
      CALL MPL_SENDSTATS(ISENDCOUNT,INT(MPI_REAL8))
    ENDIF
  ELSE
    IF(IMP_TYPE == JP_BLOCKING_STANDARD .OR. IMP_TYPE == JP_BLOCKING_BUFFERED) THEN
      CALL MPI_GATHER(PSENDBUF,ISENDCOUNT,INT(MPI_REAL8),ZDUM_JPRD,&
       & 1,INT(MPI_REAL8),IROOT-1,ICOMM,IERROR)
    ELSEIF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
      CALL MPI_IGATHER(PSENDBUF,ISENDCOUNT,INT(MPI_REAL8),ZDUM_JPRD,&
       & 1,INT(MPI_REAL8),IROOT-1,ICOMM,KREQUEST,IERROR)
    ENDIF
   IF(LMPLSTATS) THEN
      CALL MPL_SENDSTATS(ISENDCOUNT,INT(MPI_REAL8))
    ENDIF
  ENDIF
ENDIF

IF(PRESENT(KERROR)) THEN
  KERROR=IERROR
ELSE
  IF(IERROR /= 0 ) CALL MPL_MESSAGE(IERROR,'MPL_GATHERV',CDSTRING,LDABORT=LLABORT)
ENDIF

END SUBROUTINE MPL_GATHERV_REAL8_SCALAR

END MODULE MPL_GATHERV_MOD


