! (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,                 ONLY : MPI_CHARACTER, MPI_INTEGER, MPI_REAL4, MPI_REAL8
USE MPL_DATA_MODULE,          ONLY : MPL_COMM_OML, MPL_ERRUNIT, MPL_METHOD, MPL_NUMPROC, MPL_RANK, &
 &                                   JP_BLOCKING_STANDARD, JP_BLOCKING_BUFFERED, &
 &                                   JP_NON_BLOCKING_STANDARD, JP_NON_BLOCKING_BUFFERED
USE MPL_STATS_MOD,            ONLY : MPL_RECVSTATS, MPL_SENDSTATS
USE YOMMPLSTATS,              ONLY : LMPLSTATS
USE MPL_MESSAGE_MOD,          ONLY : MPL_MESSAGE
USE MPL_MYRANK_MOD,           ONLY : MPL_MYRANK
USE MPL_WAIT_MOD,             ONLY : MPL_WAIT
USE MPL_DISPLS_CONTAINER_MOD, ONLY : YDDISPLS_LIST
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,KIRECVDISPL_PT,IMP_TYPE,KRECVDISPL,KREQUEST,CDSTRING)

INTEGER(KIND=JPIM),INTENT(IN) :: IPL_NUMPROC,IPL_MYRANK,IRECVBUFSIZE,ISENDCOUNT
INTEGER(KIND=JPIM),INTENT(IN)  :: KRECVCOUNTS(:)
INTEGER(KIND=JPIM),ALLOCATABLE,TARGET,INTENT(OUT) :: KIRECVDISPL(:)
INTEGER(KIND=JPIM), POINTER, INTENT(OUT) :: KIRECVDISPL_PT(:)
INTEGER(KIND=JPIM),INTENT(IN) :: IMP_TYPE
INTEGER(KIND=JPIM),INTENT(IN),TARGET,OPTIONAL :: KRECVDISPL(:)
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KREQUEST
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_PT => KRECVDISPL
ELSE
  IF(IMP_TYPE == JP_NON_BLOCKING_STANDARD .OR. IMP_TYPE == JP_NON_BLOCKING_BUFFERED) THEN
    CALL YDDISPLS_LIST%APPEND(KNPROC=IPL_NUMPROC, KRECV_PT=KIRECVDISPL_PT)
  ELSE
    ALLOCATE(KIRECVDISPL(IPL_NUMPROC))
    KIRECVDISPL_PT => KIRECVDISPL
  END IF
  KIRECVDISPL_PT(1) = 0
  DO IR=2, IPL_NUMPROC
    KIRECVDISPL_PT(IR) = KIRECVDISPL_PT(IR-1) + KRECVCOUNTS(IR-1)
  ENDDO
ENDIF
DO IR=1, IPL_NUMPROC
  IF(KIRECVDISPL_PT(IR)+KRECVCOUNTS(IR) > IRECVBUFSIZE) THEN
    WRITE(MPL_ERRUNIT,'(A,4I10)')'MPL_GATHERV:RECV BUFFER TOO SMALL  ', &
      & IR,KIRECVDISPL_PT(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),ALLOCATABLE :: IRECVDISPL(:)
INTEGER(KIND=JPIM),POINTER :: IRECVDISPL_PT(:)
INTEGER(KIND=JPIM) :: IERROR,IPL_NUMPROC,IPL_MYRANK,ICOMM,IROOT,IMP_TYPE
INTEGER(KIND=JPIM) :: IRECVBUFSIZE,ISENDCOUNT,IDATA_TYPE
LOGICAL LLPRESENT_RECVBUF

IDATA_TYPE=INT(MPI_REAL4)
LLPRESENT_RECVBUF=PRESENT(PRECVBUF)

#include "mpl_gatherv_array_tmpl.i90"

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),ALLOCATABLE :: IRECVDISPL(:)
INTEGER(KIND=JPIM),POINTER :: IRECVDISPL_PT(:)
INTEGER(KIND=JPIM) :: IERROR,IPL_NUMPROC,IPL_MYRANK,ICOMM,IROOT,IMP_TYPE
INTEGER(KIND=JPIM) :: IRECVBUFSIZE,ISENDCOUNT
INTEGER(KIND=JPIM) :: IDUM,IST,IEND,JK, IDATA_TYPE
LOGICAL            :: LLPRESENT_RECVBUF

IDATA_TYPE = INT(MPI_REAL8)
LLPRESENT_RECVBUF=PRESENT(PRECVBUF)

#include "mpl_gatherv_array_tmpl.i90"

END SUBROUTINE MPL_GATHERV_REAL8

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),TARGET,INTENT(IN)         :: KSENDBUF(:)
INTEGER(KIND=JPIM),TARGET,INTENT(OUT),OPTIONAL :: KRECVBUF(:)
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KRECVCOUNTS(:)
INTEGER(KIND=JPIM),INTENT(IN),OPTIONAL :: KSENDCOUNT,KCOMM,KMP_TYPE
INTEGER(KIND=JPIM),TARGET,INTENT(IN),OPTIONAL :: KRECVDISPL(:)
INTEGER(KIND=JPIM),INTENT(OUT),OPTIONAL :: KERROR,KREQUEST
CHARACTER(LEN=*),INTENT(IN),OPTIONAL :: CDSTRING

INTEGER(KIND=JPIM),ALLOCATABLE :: IRECVDISPL(:)
INTEGER(KIND=JPIM),POINTER :: IRECVDISPL_PT(:)
INTEGER(KIND=JPIM) :: IERROR,IPL_NUMPROC,IPL_MYRANK,ICOMM,IROOT,IMP_TYPE
INTEGER(KIND=JPIM) :: IRECVBUFSIZE,ISENDCOUNT,IDATA_TYPE

LOGICAL LLPRESENT_RECVBUF

IDATA_TYPE=INT(MPI_INTEGER)
LLPRESENT_RECVBUF=PRESENT(KRECVBUF)

IF (PRESENT(KRECVBUF)) THEN
ASSOCIATE(PSENDBUF=>KSENDBUF,PRECVBUF=>KRECVBUF)
#include "mpl_gatherv_array_tmpl.i90"
END ASSOCIATE
ELSE
ASSOCIATE(PSENDBUF=>KSENDBUF,PRECVBUF=>KSENDBUF)
#include "mpl_gatherv_array_tmpl.i90"
END ASSOCIATE
END IF

END SUBROUTINE MPL_GATHERV_INT

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),ALLOCATABLE :: IRECVDISPL(:)
INTEGER(KIND=JPIM),POINTER :: IRECVDISPL_PT(:)
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 NAGFOR
  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,IRECVDISPL_PT,IMP_TYPE,KRECVDISPL,KREQUEST,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_PT,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_PT,INT(MPI_CHARACTER),IROOT-1,ICOMM,KREQUEST,IERROR)
    IF(.NOT. PRESENT(KRECVDISPL)) THEN
      CALL YDDISPLS_LIST%APPEND(KREQ=KREQUEST,NO_NEW_NODE=.TRUE.)
    ENDIF
  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_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) :: IRECVCOUNTS(MPL_NUMPROC)
INTEGER(KIND=JPIM),ALLOCATABLE :: IRECVDISPL(:)
INTEGER(KIND=JPIM),POINTER :: IRECVDISPL_PT(:)
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,IRECVDISPL_PT,IMP_TYPE,KRECVDISPL,KREQUEST,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_PT,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_PT,INT(MPI_INTEGER),IROOT-1,ICOMM,KREQUEST,IERROR)
      IF(.NOT. PRESENT(KRECVDISPL)) THEN
        CALL YDDISPLS_LIST%APPEND(KREQ=KREQUEST,NO_NEW_NODE=.TRUE.)
      ENDIF
    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)
      CALL MPL_WAIT(KREQUEST)
    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)
      CALL MPL_WAIT(KREQUEST)
    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)
      IF(.NOT. PRESENT(KRECVDISPL)) THEN
        CALL YDDISPLS_LIST%APPEND(KREQ=KREQUEST,NO_NEW_NODE=.TRUE.)
      ENDIF
    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) :: IRECVCOUNTS(MPL_NUMPROC)
INTEGER(KIND=JPIM),ALLOCATABLE :: IRECVDISPL(:)
INTEGER(KIND=JPIM),POINTER :: IRECVDISPL_PT(:)
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,IRECVDISPL_PT,IMP_TYPE,KRECVDISPL,KREQUEST,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_PT,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_PT,INT(MPI_REAL8),IROOT-1,ICOMM,KREQUEST,IERROR)
      IF(.NOT. PRESENT(KRECVDISPL)) THEN
        CALL YDDISPLS_LIST%APPEND(KREQ=KREQUEST,NO_NEW_NODE=.TRUE.)
      ENDIF
    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)
      CALL MPL_WAIT(KREQUEST)
    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)
      CALL MPL_WAIT(KREQUEST)
    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)
      CALL MPL_WAIT(KREQUEST)
    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


