SUBROUTINE SUJBWAVALLO (YD_PVC, KSCALE, KCUTOFF, KLEVS, &
                      & YD_IOSTREAM,YD_IOREQUEST)

!      SUJBWAVALLO - Allocate, read and distribute the square-root and
!                    inverse square-root vertical correlation matrices
!                    for wavelet Jb.

!     Purpose: Allocate, read and distribute the vertical correlation
!     -------  matrices for wavelet Jb.

!     Interface: called from SUJBWAVELET
!     ---------

!     Author: Mike Fisher 2000-09-18
!     ------

!     Modifications:
!     -------------
!     2001-10-09 M.Fisher: Separated allocation for the case LJBWSTATS=T
!        M.Hamrud      01-Oct-2003 CY28 Cleaning
!        M.Hamrud      01-Dec-2003 CY28R1 Cleaning
!        M.Fisher      17-Mar-2004 Matrix skylines
!        M.Fisher      01-Aug-2007 Skylined file format
!        M.Fisher      07-Aug-2007 Use IOSTREAM_MIX
!        M.Hamrud      05-Oct-2009 Improve message passsing using threads

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

USE PARKIND1  ,ONLY : JPIM     ,JPRB
USE YOMHOOK   ,ONLY : LHOOK,   DR_HOOK
USE YOMLUN,     ONLY : NULOUT,NULERR
USE YOMCST,     ONLY : RPI
USE YOMMP,      ONLY : MYPROC
USE YOMCT0,     ONLY : NPROC
USE YOMWAVELET, ONLY :  WAVELET_VCOR_STRUCT, &
 & GRID_DEFINITION  
USE IOSTREAM_MIX, ONLY : IO_GET, TYPE_IOSTREAM , TYPE_IOREQUEST
USE MPL_MODULE
USE OML_MOD, ONLY :  OML_OMP, OML_WAIT_EVENT, OML_SET_EVENT

IMPLICIT NONE

TYPE(WAVELET_VCOR_STRUCT),INTENT(OUT)   :: YD_PVC 
INTEGER(KIND=JPIM),INTENT(IN)    :: KSCALE 
INTEGER(KIND=JPIM),INTENT(IN)    :: KCUTOFF 
INTEGER(KIND=JPIM),INTENT(IN)    :: KLEVS 
TYPE(TYPE_IOSTREAM), INTENT(INOUT)  :: YD_IOSTREAM
TYPE(TYPE_IOREQUEST), INTENT(INOUT) :: YD_IOREQUEST

INTEGER(KIND=JPIM) :: INPTOT(NPROC), J, ILATS, ILEVS, ICUTOFF, JLAT, JLON, ILSUM, &
 & I, JK, INLATG, ISLATG, ILON, IM1, ILAT_OFFSET,ITAG
INTEGER(KIND=JPIM), ALLOCATABLE :: INDXL2G(:,:), INLONS(:), &
 & ILON_OFFSET(:), IBUF(:)
INTEGER(KIND=JPIM), PARAMETER :: JPIOMASTER=1
LOGICAL, ALLOCATABLE  :: LLWANTED(:)
REAL(KIND=JPRB)    :: ZDLON,  ZEPS, &
 & ZMSG1D((KLEVS*KLEVS*2+4*KLEVS)*500),zlong
INTEGER(KIND=JPIM) :: JJ
INTEGER(KIND=JPIM) :: INUMSENT, JS,INUMT,IMYTHREAD
INTEGER(KIND=JPIM) :: IPROC
INTEGER(KIND=JPIM), ALLOCATABLE :: ISENDREQ(:),ILOCK(:),IOFFIO(:),ICOUNT(:)
LOGICAL :: LLMINE

REAL(KIND=JPRB), ALLOCATABLE :: ZZDLON(:)
REAL(KIND=JPRB) :: ZHOOK_HANDLE

#include "abor1.intfb.h"

9990 FORMAT (' VERTICAL CORRELATION MATRIX ALLOCATED',8(1X,I8))

IF (LHOOK) CALL DR_HOOK('SUJBWAVALLO',0,ZHOOK_HANDLE)

ALLOCATE(IBUF(3))
CALL IO_GET(YD_IOSTREAM,YD_IOREQUEST,KR1=IBUF)
ITAG=6667
CALL GSTATS_BARRIER(723)
CALL GSTATS(639,0)
CALL MPL_BROADCAST(IBUF,KROOT=JPIOMASTER,KTAG=ITAG, &
 & CDSTRING='SUJBWAVALLO')
CALL GSTATS(639,1)
CALL GSTATS_BARRIER2(723)
ITAG=ITAG+1

ICUTOFF = IBUF(1)
ILATS   = IBUF(2)
ILEVS   = IBUF(3)
DEALLOCATE(IBUF)

IF (ILEVS/=KLEVS .OR. ICUTOFF/=KCUTOFF) THEN
  WRITE (NULOUT,*) 'ILEVS=',ILEVS,' KLEVS=',KLEVS,&
   & ' ICUTOFF=',ICUTOFF,' KCUTOFF=',KCUTOFF  
  CALL ABOR1 ('sujbwavelet: matrix mismatch')
ENDIF

YD_PVC%NLATSG = ILATS
YD_PVC%NLEVS = KLEVS

ALLOCATE (YD_PVC%LATSG(ILATS))
ALLOCATE (YD_PVC%NLONSG(ILATS))
ALLOCATE (YD_PVC%LON0G(ILATS))

CALL IO_GET(YD_IOSTREAM,YD_IOREQUEST,PR1=YD_PVC%LATSG)
CALL IO_GET(YD_IOSTREAM,YD_IOREQUEST,KR1=YD_PVC%NLONSG)
CALL IO_GET(YD_IOSTREAM,YD_IOREQUEST,PR1=YD_PVC%LON0G)

IF (NPROC>1) THEN
  CALL GSTATS_BARRIER(723)
  CALL GSTATS(639,0)
  CALL MPL_BROADCAST(YD_PVC%LATSG,KROOT=JPIOMASTER,KTAG=ITAG, &
   & CDSTRING='SUJBWAVALLO')
  ITAG=ITAG+1
  CALL MPL_BROADCAST(YD_PVC%NLONSG,KROOT=JPIOMASTER,KTAG=ITAG, &
   & CDSTRING='SUJBWAVALLO')
  ITAG=ITAG+1
  CALL MPL_BROADCAST(YD_PVC%LON0G,KROOT=JPIOMASTER,KTAG=ITAG, &
   & CDSTRING='SUJBWAVALLO')
  ITAG=ITAG+1
  CALL GSTATS(639,1)
  CALL GSTATS_BARRIER2(723)
ENDIF

YD_PVC%NPTOTG = SUM(YD_PVC%NLONSG(:))

!         Find which matrices are needed locally on this PE

ALLOCATE(INDXL2G(0:YD_PVC%NPTOTG,NPROC))
ALLOCATE(INLONS(YD_PVC%NLATSG))
ALLOCATE(ILON_OFFSET(YD_PVC%NLATSG))
ALLOCATE(ZZDLON(YD_PVC%NLATSG))

ALLOCATE(LLWANTED(YD_PVC%NPTOTG))

ZEPS=SQRT(EPSILON(ZEPS))

IF (YD_PVC%NPTOTG == 1) THEN
  LLWANTED(:)=.TRUE.
ELSE
  LLWANTED(:)=.FALSE.

  DO J=1,GRID_DEFINITION(KSCALE)%NGPTOT
    IF (GRID_DEFINITION(KSCALE)%GELAT(J) <= YD_PVC%LATSG(YD_PVC%NLATSG)) THEN
      ISLATG = YD_PVC%NLATSG
      INLATG = YD_PVC%NLATSG
    ELSE
      ISLATG=1
      DO WHILE (GRID_DEFINITION(KSCALE)%GELAT(J) < YD_PVC%LATSG(ISLATG))
        ISLATG = ISLATG+1
      ENDDO
      INLATG = MAX(1,ISLATG-1)
    ENDIF
 
    ZLONG = GRID_DEFINITION(KSCALE)%GELAM(J)
    DO WHILE (ZLONG < YD_PVC%LON0G(ISLATG))
      ZLONG = ZLONG + 2.0_JPRB*RPI
    ENDDO
    ZDLON = 2.0_JPRB*RPI/YD_PVC%NLONSG(ISLATG)
    ILON = 1 + INT( (ZLONG+ZEPS-YD_PVC%LON0G(ISLATG))/ZDLON )

    LLWANTED(ILON+SUM(YD_PVC%NLONSG(1:ISLATG-1))) = .TRUE.
    LLWANTED(1+MOD(ILON,YD_PVC%NLONSG(ISLATG))+ &
     & SUM(YD_PVC%NLONSG(1:ISLATG-1))    ) = .TRUE.  

    ZLONG = GRID_DEFINITION(KSCALE)%GELAM(J)
    DO WHILE (ZLONG < YD_PVC%LON0G(INLATG))
      ZLONG = ZLONG + 2.0_JPRB*RPI
    ENDDO
    ZDLON = 2.0_JPRB*RPI/YD_PVC%NLONSG(INLATG)
    ILON = 1 + INT( (ZLONG+ZEPS-YD_PVC%LON0G(INLATG))/ZDLON )

    LLWANTED(ILON+SUM(YD_PVC%NLONSG(1:INLATG-1))) = .TRUE.
    LLWANTED(1+MOD(ILON,YD_PVC%NLONSG(INLATG))+ &
     & SUM(YD_PVC%NLONSG(1:INLATG-1))     ) = .TRUE.  
  ENDDO
ENDIF

INPTOT=0
ILATS=0
INLONS(:)=0

ILSUM=0
DO JLAT=1,YD_PVC%NLATSG
  IF (JLAT>1) ILSUM=ILSUM+YD_PVC%NLONSG(JLAT-1)
  ZDLON  = 2.0_JPRB*RPI/YD_PVC%NLONSG(JLAT)

!--- find the start of the contiguous block of wanted matrices

  IF (ALL(LLWANTED(ILSUM+1:ILSUM+YD_PVC%NLONSG(JLAT)))) THEN
    I=1
  ELSEIF (ALL(.NOT.LLWANTED(ILSUM+1:ILSUM+YD_PVC%NLONSG(JLAT)))) THEN
    CYCLE
  ELSE 
    IM1=YD_PVC%NLONSG(JLAT)
    I=1
    DO WHILE (LLWANTED(ILSUM+IM1).OR..NOT.LLWANTED(ILSUM+I))
      IM1=I
      I=I+1
    ENDDO
  ENDIF

  ILON_OFFSET(ILATS+1)=I-1
  ZZDLON(ILATS+1)=ZDLON

!--- update the local tables

  DO JLON=1,YD_PVC%NLONSG(JLAT)
    IF (LLWANTED(I+ILSUM)) THEN
      INPTOT(MYPROC)=INPTOT(MYPROC)+1
      INLONS(ILATS+1)=INLONS(ILATS+1)+1
      INDXL2G(INPTOT(MYPROC),MYPROC) = I+ILSUM
    ENDIF
    I=1+MOD(I,YD_PVC%NLONSG(JLAT))
  ENDDO
  IF (INLONS(ILATS+1)>0) THEN
    ILATS=ILATS+1
  ENDIF
  IF (ILATS==1) ILAT_OFFSET = JLAT-1
ENDDO

INDXL2G(0,MYPROC)=INPTOT(MYPROC)

CALL GSTATS_BARRIER(723)
CALL GSTATS(640,0)
JS=0
ALLOCATE(ISENDREQ(NPROC))
DO IPROC=1,NPROC
  IF(IPROC == MYPROC)CYCLE
  JS=JS+1
  CALL MPL_SEND(INDXL2G(0:INPTOT(MYPROC),MYPROC),KDEST=IPROC,KTAG=ITAG,&
   & KMP_TYPE=JP_NON_BLOCKING_STANDARD,KREQUEST=ISENDREQ(JS), &
   & CDSTRING='SUJBWAVALLO')
ENDDO
INUMSENT=JS
DO IPROC=1,NPROC
  IF(IPROC == MYPROC)CYCLE
  CALL MPL_RECV(INDXL2G(0:YD_PVC%NPTOTG,IPROC),KSOURCE=IPROC,KTAG=ITAG,&
   & CDSTRING='SUJBWAVALLO')
  INPTOT(IPROC)=INDXL2G(0,IPROC)
ENDDO
IF(INUMSENT > 0) THEN
  CALL MPL_WAIT(INDXL2G,KREQUEST=ISENDREQ(1:INUMSENT), &
   & CDSTRING='SUJBWAVALLO: ERROR IN MPL_WAIT FOR SENDS')
ENDIF
DEALLOCATE(ISENDREQ)

CALL GSTATS(640,1)
CALL GSTATS_BARRIER2(723)

!         Allocate local arrays

YD_PVC%NPTOT = INPTOT(MYPROC)

YD_PVC%NLATS = ILATS
YD_PVC%NLAT_OFFSET    = ILAT_OFFSET

ALLOCATE (YD_PVC%NLONS(ILATS))
ALLOCATE (YD_PVC%NLON_OFFSET(ILATS))
ALLOCATE (YD_PVC%DLON(ILATS))

YD_PVC%NLONS(:)       = INLONS(1:ILATS)
YD_PVC%NLON_OFFSET(:) = ILON_OFFSET(1:ILATS)
YD_PVC%DLON(:)        = ZZDLON(1:ILATS)

DEALLOCATE(LLWANTED)
DEALLOCATE(INLONS)
DEALLOCATE(ILON_OFFSET)
DEALLOCATE(ZZDLON)

ALLOCATE (YD_PVC%MATS   (KLEVS,KLEVS,INPTOT(MYPROC)))
WRITE (NULOUT,9990) SIZE(YD_PVC%MATS),    SHAPE(YD_PVC%MATS)

ALLOCATE (YD_PVC%MATINVS(KLEVS,KLEVS,INPTOT(MYPROC)))
WRITE (NULOUT,9990) SIZE(YD_PVC%MATINVS), SHAPE(YD_PVC%MATINVS)

ALLOCATE (YD_PVC%MATS_SKYLINE_LEFT (KLEVS,INPTOT(MYPROC)))
ALLOCATE (YD_PVC%MATS_SKYLINE_RIGHT(KLEVS,INPTOT(MYPROC)))
ALLOCATE (YD_PVC%MATINVS_SKYLINE_LEFT (KLEVS,INPTOT(MYPROC)))
ALLOCATE (YD_PVC%MATINVS_SKYLINE_RIGHT(KLEVS,INPTOT(MYPROC)))

!         Read and distribute the big arrays

CALL GSTATS_BARRIER(742)
ALLOCATE(IOFFIO(YD_PVC%NPTOTG+1))
ALLOCATE(ICOUNT(YD_PVC%NPTOTG))

IOFFIO(1)=0
IOFFIO(2:)=-99
ICOUNT(:)=-99999999
ALLOCATE(ILOCK(YD_PVC%NPTOTG))
IF(OML_OMP()) THEN
  DO J=1,YD_PVC%NPTOTG
    CALL OML_SET_EVENT(0,ILOCK(J))
  ENDDO
ENDIF
ITAG=ITAG+1
IF(MYPROC > 1)CALL GSTATS(636,0)

! Thread 1 is doing the reading, the other threads are sharing the distribution of matrices 
! Note that MPI is called in threaded region
!$OMP PARALLEL PRIVATE(IMYTHREAD,INUMT,J,LLMINE)

IMYTHREAD=OML_MY_THREAD()
INUMT = 1
IF (OML_OMP()) INUMT = OML_MAX_THREADS() ! To disable multi-threading comment out this line
DO J=1,YD_PVC%NPTOTG
  IF(IMYTHREAD == 1) THEN
    CALL READ_MAT(J,KLEVS,YD_IOSTREAM,YD_IOREQUEST,ZMSG1D,ILOCK,ICOUNT,IOFFIO)
  ENDIF
  LLMINE = .FALSE.
  IF(INUMT == 1) THEN
    LLMINE = .TRUE.
  ELSE
    IF(MOD(J-1,INUMT-1)+2 == IMYTHREAD) LLMINE=.TRUE. 
  ENDIF
  IF(LLMINE) THEN
    CALL DIST_MAT(J,KLEVS,INDXL2G,INPTOT,ZMSG1D,ILOCK,ICOUNT,IOFFIO,YD_PVC)
  ENDIF
ENDDO

IF (MYPROC==JPIOMASTER .AND. IMYTHREAD == 1)  CALL GSTATS(636,0)
!$OMP BARRIER
IF (MYPROC==JPIOMASTER .AND. IMYTHREAD == 1)  CALL GSTATS(636,1)

!$OMP END PARALLEL
IF(MYPROC > 1) CALL GSTATS(636,1)

CALL GSTATS_BARRIER2(742)

DEALLOCATE(INDXL2G)
DEALLOCATE(IOFFIO)
DEALLOCATE(ICOUNT)
!           Nullify unused pointers

NULLIFY (YD_PVC%SAMPAV)
NULLIFY (YD_PVC%NSAMPS)
NULLIFY (YD_PVC%LPELIST)
NULLIFY (YD_PVC%MASTERPE)
NULLIFY (YD_PVC%INDEXG2L)
NULLIFY (YD_PVC%EVALS)

IF (LHOOK) CALL DR_HOOK('SUJBWAVALLO',1,ZHOOK_HANDLE)
CONTAINS

!==================================================================================================

SUBROUTINE READ_MAT(KJ,KLEVS,YD_IOSTREAM,YD_IOREQUEST,PMSG1D,KLOCK,KCOUNT,KOFFIO)
! Read matrix
INTEGER(KIND=JPIM),  INTENT(IN)    :: KJ
INTEGER(KIND=JPIM),  INTENT(IN)    :: KLEVS 
TYPE(TYPE_IOSTREAM), INTENT(INOUT) :: YD_IOSTREAM
TYPE(TYPE_IOREQUEST),INTENT(INOUT) :: YD_IOREQUEST
REAL(KIND=JPRB),     INTENT(INOUT) :: PMSG1D(:)
INTEGER(KIND=JPIM),  INTENT(INOUT) :: KLOCK(:)
INTEGER(KIND=JPIM),  INTENT(INOUT) :: KCOUNT(:)
INTEGER(KIND=JPIM),  INTENT(INOUT) :: KOFFIO(:)

INTEGER(KIND=JPIM) :: I_MAT_SKYLINE_LEFT(KLEVS), I_MAT_SKYLINE_RIGHT(KLEVS), &
 & I_MATINV_SKYLINE_LEFT (KLEVS), I_MATINV_SKYLINE_RIGHT(KLEVS),IELEM(KLEVS),&
 & ITOTELEM,ITOTELEMINV,II,JK,J1,JJ,IELEMINV(KLEVS)
REAL(KIND=JPRB)    :: ZZMAT(KLEVS*KLEVS),ZZMATINV(KLEVS*KLEVS)
REAL(KIND=JPRB) :: ZHOOK_HANDLE

!------------------------------------------------------------------------------------
IF (LHOOK) CALL DR_HOOK('SUJBWAVALLO:READ_MAT',0,ZHOOK_HANDLE)

CALL IO_GET(YD_IOSTREAM,YD_IOREQUEST,KR1=I_MAT_SKYLINE_LEFT)
CALL IO_GET(YD_IOSTREAM,YD_IOREQUEST,KR1=I_MAT_SKYLINE_RIGHT)
IF (MYPROC==JPIOMASTER)  THEN
  IELEM(:) = I_MAT_SKYLINE_RIGHT(:)-I_MAT_SKYLINE_LEFT(:)+1
  ITOTELEM = SUM(IELEM(:))
ELSE
  ITOTELEM = 1
ENDIF
CALL IO_GET(YD_IOSTREAM,YD_IOREQUEST,PR1=ZZMAT(1:ITOTELEM))

CALL IO_GET(YD_IOSTREAM,YD_IOREQUEST,KR1=I_MATINV_SKYLINE_LEFT)
CALL IO_GET(YD_IOSTREAM,YD_IOREQUEST,KR1=I_MATINV_SKYLINE_RIGHT)
IF (MYPROC==JPIOMASTER)  THEN
  IELEMINV(:) = I_MATINV_SKYLINE_RIGHT(:)-I_MATINV_SKYLINE_LEFT(:)+1
  ITOTELEMINV = SUM(IELEMINV(:))
ELSE
  ITOTELEMINV = 1
ENDIF

CALL IO_GET(YD_IOSTREAM,YD_IOREQUEST,PR1=ZZMATINV(1:ITOTELEMINV))

IF (MYPROC==JPIOMASTER) THEN
  IF( SIZE(PMSG1D)-KOFFIO(KJ) < KLEVS*KLEVS*2+4*KLEVS ) THEN
    CALL GSTATS(636,0)
    IF (OML_OMP()) THEN
      DO JJ=1,KJ-1
        CALL OML_WAIT_EVENT(2,KLOCK(JJ))
      ENDDO
    ENDIF
    CALL GSTATS(636,1)
    KOFFIO(KJ)=0
  ENDIF
  CALL GSTATS(306,0)
  II=1
  PMSG1D(KOFFIO(KJ)+II)=KJ
  II=II+1
  DO JK=1,KLEVS
    PMSG1D(KOFFIO(KJ)+II)=I_MAT_SKYLINE_LEFT(JK)
    II=II+1
    PMSG1D(KOFFIO(KJ)+II)=I_MAT_SKYLINE_RIGHT(JK)
    II=II+1
    PMSG1D(KOFFIO(KJ)+II)=I_MATINV_SKYLINE_LEFT(JK)
    II=II+1
    PMSG1D(KOFFIO(KJ)+II)=I_MATINV_SKYLINE_RIGHT(JK)
    II=II+1
  ENDDO
  
  DO J1=1,ITOTELEM
    PMSG1D(KOFFIO(KJ)+II)=ZZMAT(J1)
    II=II+1
  ENDDO
  DO J1=1,ITOTELEMINV
    PMSG1D(KOFFIO(KJ)+II)=ZZMATINV(J1)
    II=II+1
  ENDDO
  
  KCOUNT(KJ)=II-1
  KOFFIO(KJ+1)=KOFFIO(KJ)+KCOUNT(KJ)
!$OMP FLUSH(PMSG1D,KCOUNT,KOFFIO,KLOCK)
  CALL OML_SET_EVENT(1,KLOCK(KJ))
!$OMP FLUSH(KLOCK)
  CALL GSTATS(306,1)
ENDIF
IF (LHOOK) CALL DR_HOOK('SUJBWAVALLO:READ_MAT',1,ZHOOK_HANDLE)
END SUBROUTINE READ_MAT
!======================================================================================================
SUBROUTINE DIST_MAT(KJ,KLEVS,KINDXL2G,KINPTOT,PMSG1D,KLOCK,KCOUNT,KOFFIO,YD_PVC)
!Distribute matrix
INTEGER(KIND=JPIM),  INTENT(IN)    :: KJ
INTEGER(KIND=JPIM),  INTENT(IN)    :: KLEVS 
INTEGER(KIND=JPIM),  INTENT(IN)    :: KINDXL2G(0:,:)
INTEGER(KIND=JPIM),  INTENT(IN)    :: KINPTOT(:)
REAL(KIND=JPRB),     INTENT(INOUT) :: PMSG1D(:)
INTEGER(KIND=JPIM),  INTENT(INOUT) :: KLOCK(:)
INTEGER(KIND=JPIM),  INTENT(INOUT) :: KCOUNT(:)
INTEGER(KIND=JPIM),  INTENT(INOUT) :: KOFFIO(:)
TYPE(WAVELET_VCOR_STRUCT),INTENT(OUT)   :: YD_PVC 

LOGICAL :: LLWANTS_MATRIX(NPROC)
INTEGER(KIND=JPIM) :: IWANTS_MATRIX(0:NPROC),INWANTS_MATRIX,IWANTNUM
INTEGER(KIND=JPIM) :: J1,IPROC,JK,IJ
INTEGER(KIND=JPIM) :: IP2,JSTAGE,II2,IHALF,IRECV,ISEND,ISENDREQ1
INTEGER(KIND=JPIM) :: II,ITAG,ISOURCE
INTEGER(KIND=JPIM) :: I_MAT_SKYLINE_LEFT(KLEVS), I_MAT_SKYLINE_RIGHT(KLEVS), &
 & I_MATINV_SKYLINE_LEFT (KLEVS), I_MATINV_SKYLINE_RIGHT(KLEVS)
REAL(KIND=JPRB)    :: ZMSGRECV(KLEVS*KLEVS*2+4*KLEVS+1) 
REAL(KIND=JPRB)    :: ZMAT(KLEVS,KLEVS), ZMATINV(KLEVS,KLEVS)
REAL(KIND=JPRB)    :: ZHOOK_HANDLE

!---------------------------------------------------------------------------------------------
IF (LHOOK) CALL DR_HOOK('SUJBWAVALLO:DIST_MAT',0,ZHOOK_HANDLE)

ITAG=1278
IWANTS_MATRIX(0)=JPIOMASTER
LLWANTS_MATRIX(:)=.FALSE.
INWANTS_MATRIX=0
DO IPROC=1,NPROC
  DO J1=1,KINPTOT(IPROC)
    IF (KINDXL2G(J1,IPROC)==KJ) THEN
      LLWANTS_MATRIX(IPROC)=.TRUE.
      IF(IPROC == JPIOMASTER) CYCLE
      INWANTS_MATRIX=INWANTS_MATRIX+1
      IWANTS_MATRIX(INWANTS_MATRIX)=IPROC
      IF(MYPROC == IPROC) IWANTNUM=INWANTS_MATRIX
      EXIT
    ENDIF
  ENDDO
ENDDO

IP2=0
DO
  IP2=IP2+1
  IF(2**IP2 >= INWANTS_MATRIX ) EXIT
ENDDO

IF (MYPROC==JPIOMASTER) THEN
  IF (OML_OMP()) CALL OML_WAIT_EVENT(1,KLOCK(KJ))
!$OMP FLUSH(KCOUNT,KOFFIO,ZMSGRECV)
  IF(KCOUNT(KJ) < 0 .OR. KCOUNT(KJ) > SIZE(ZMSGRECV)) THEN
    WRITE(NULERR,*) 'J,KCOUNT(KJ),SIZE(ZMSGRECV) ',KJ,KCOUNT(KJ),SIZE(ZMSGRECV)
    CALL ABOR1('sujbwavelet: KCOUNT WRONG')
  ENDIF
  IF(KOFFIO(KJ) /= 0) THEN
    IF(KOFFIO(KJ-1)+KCOUNT(KJ-1) /= KOFFIO(KJ)) THEN
      WRITE(NULERR,*) 'J,KOFFIO(KJ-1),KCOUNT(KJ-1),KOFFIO(KJ) ',KJ,KOFFIO(KJ-1),KCOUNT(KJ-1),KOFFIO(KJ)
      CALL ABOR1('sujbwavelet: KOFFIO WRONG')
    ENDIF
  ENDIF
      
        
  IF(INWANTS_MATRIX > 0) THEN
    IPROC=IWANTS_MATRIX(1)
    CALL MPL_SEND(PMSG1D(KOFFIO(KJ)+1:KOFFIO(KJ)+KCOUNT(KJ)),KDEST=IPROC,KTAG=ITAG, &
     & KMP_TYPE=JP_NON_BLOCKING_STANDARD,KREQUEST=ISENDREQ1, &
     & CDSTRING='SUJBWAVALLO:DIST_MAT SEND ' )
    CALL MPL_WAIT(PMSG1D,KREQUEST=ISENDREQ1, &
     & CDSTRING='SUJBWAVALLO:DIST_MAT ERROR IN MPL_WAIT FOR SENDS')
  ENDIF
  IF(LLWANTS_MATRIX(MYPROC))THEN
    ZMSGRECV(1:KCOUNT(KJ)) = PMSG1D(KOFFIO(KJ)+1:KOFFIO(KJ)+KCOUNT(KJ)) 
  ENDIF
ELSE

  IF(LLWANTS_MATRIX(MYPROC))THEN
    DO JSTAGE=1,IP2
      II2=2**JSTAGE
      IHALF=II2/2
      IF(IWANTNUM == 1 .AND. JSTAGE == 1) THEN
        ISOURCE=JPIOMASTER
        CALL MPL_RECV(ZMSGRECV, &
         & KSOURCE=ISOURCE, &
         & KTAG=ITAG,&
         & KMP_TYPE=JP_BLOCKING_STANDARD,KOUNT=KCOUNT(KJ),&
         & CDSTRING='SUJBWAVALLO:DIST_MAT RECV' )
      ELSE
        IRECV=IWANTNUM-IHALF
        IF(IRECV > 0 .AND. IWANTNUM <= II2) THEN
          ISOURCE=IWANTS_MATRIX(IRECV)
          CALL MPL_RECV(ZMSGRECV, &
           & KSOURCE=ISOURCE, &
           & KTAG=ITAG,&
           & KMP_TYPE=JP_BLOCKING_STANDARD,KOUNT=KCOUNT(KJ),&
           & CDSTRING='SUJBWAVALLO:DIST_MAT RECV' )
        ENDIF
      ENDIF
      ISEND = IWANTNUM + IHALF
      IF(ISEND <= INWANTS_MATRIX .AND. IWANTNUM <= IHALF) THEN
        IPROC=IWANTS_MATRIX(ISEND)
        CALL MPL_SEND(ZMSGRECV(1:KCOUNT(KJ)),KDEST=IPROC,KTAG=ITAG, &
         & KMP_TYPE=JP_NON_BLOCKING_STANDARD,KREQUEST=ISENDREQ1, &
         & CDSTRING='SUJBWAVALLO:DIST_MAT SEND ' )
        CALL MPL_WAIT(ZMSGRECV,KREQUEST=ISENDREQ1, &
         & CDSTRING='SUJBWAVALLO:DIST_MAT ERROR IN MPL_WAIT FOR SENDS')
      ENDIF
    ENDDO
  ENDIF
ENDIF

IF(LLWANTS_MATRIX(MYPROC))THEN
  II=1
  IJ=ZMSGRECV(II)+0.1_JPRB
  IF(IJ /= KJ)THEN
    WRITE(NULERR,*) 'sujbwavelet: IJ =/ KJ ',IJ,KJ
    CALL ABOR1 ('sujbwavelet: IJ =/ KJ')
  ENDIF
  II=II+1
  DO JK=1,KLEVS
    I_MAT_SKYLINE_LEFT(JK)=ZMSGRECV(II)+0.1_JPRB
    II=II+1
    I_MAT_SKYLINE_RIGHT(JK)=ZMSGRECV(II)+0.1_JPRB
    II=II+1
    I_MATINV_SKYLINE_LEFT(JK)=ZMSGRECV(II)+0.1_JPRB
    II=II+1
    I_MATINV_SKYLINE_RIGHT(JK)=ZMSGRECV(II)+0.1_JPRB
    II=II+1
  ENDDO
  
  DO JK=1,KLEVS
    ZMAT(1:I_MAT_SKYLINE_LEFT(JK)-1,JK)=0.0_JPRB
    DO J1=I_MAT_SKYLINE_LEFT(JK),I_MAT_SKYLINE_RIGHT(JK)
      ZMAT(J1,JK) =ZMSGRECV(II)
      II=II+1
    ENDDO
    ZMAT(I_MAT_SKYLINE_RIGHT(JK)+1:KLEVS,JK)=0.0_JPRB
  ENDDO
  DO JK=1,KLEVS
    ZMATINV(1:I_MATINV_SKYLINE_LEFT(JK)-1,JK)=0.0_JPRB
    DO J1=I_MATINV_SKYLINE_LEFT(JK),I_MATINV_SKYLINE_RIGHT(JK)
      ZMATINV(J1,JK) =ZMSGRECV(II)
      II=II+1
    ENDDO
    ZMATINV(I_MATINV_SKYLINE_RIGHT(JK)+1:KLEVS,JK)=0.0_JPRB
  ENDDO
        
  IF(KCOUNT(KJ) /= II-1)THEN
    CALL ABOR1 ('sujbwavelet: send/recv mismatch')
  ENDIF

  DO J1=1,YD_PVC%NPTOT
    IF (KINDXL2G(J1,MYPROC)==KJ) THEN
      YD_PVC%MATS   (:,:,J1) = ZMAT(:,:)
      YD_PVC%MATINVS(:,:,J1) = ZMATINV(:,:)
      YD_PVC%MATS_SKYLINE_LEFT    (:,J1) = I_MAT_SKYLINE_LEFT
      YD_PVC%MATS_SKYLINE_RIGHT   (:,J1) = I_MAT_SKYLINE_RIGHT
      YD_PVC%MATINVS_SKYLINE_LEFT (:,J1) = I_MATINV_SKYLINE_LEFT
      YD_PVC%MATINVS_SKYLINE_RIGHT(:,J1) = I_MATINV_SKYLINE_RIGHT
    ENDIF
  ENDDO
ENDIF
IF(MYPROC==JPIOMASTER) THEN
  CALL OML_SET_EVENT(2,KLOCK(KJ))
!$OMP FLUSH(KLOCK)
ENDIF

IF (LHOOK) CALL DR_HOOK('SUJBWAVALLO:DIST_MAT',1,ZHOOK_HANDLE)
END SUBROUTINE DIST_MAT

END SUBROUTINE SUJBWAVALLO

