SUBROUTINE RANDOM_CTLVEC(YDCV,LDINIT,LDMERR,LDTOVS,LDLAM,LDPARA,LDTS,KSEED)

!     Purpose.
!     --------
!       Generate random control vector with independent elements drawn from a zero-mean,
!       unit-variance Gaussian distribution.

!     Inputs.
!     -------
!               LDINIT  :  Generate random values for initial state
!               LDMERR  :  Generate random values for model error components
!               LDTOVS  :  Generate random values for TOVS control vector
!               LDLAM   :  Generate random values for LAM
!               LDPARA  :  Generate random values for parameters
!               LDTS    :  Generate random values for Ts control vector
!               KSEED   :  Random number seed

!     Output.
!     -------

!               YDCV    :  Random control vector
!               KSEED   :  The next available random number seed

!     NB:       RANDOM_CTLVEC uses a sequence of seeds, starting from KSEED.
!     ---       On return, KSEED is set to the next available seed.
!               It is recommended not to reset KSEED between calls to
!               RANDOM_CTLVEC. Do not just increment KSEED from call to call!

!     Author.
!     -------
!       Y.Tremolet

!     Modifications.
!     --------------
!        Original : 18-Mar-2004
!        M.Fisher : 19-Aug-2004 Parallelize
!        C.Fischer: 30-May-2005 Add Ts control vector
! ------------------------------------------------------------------

USE PARKIND1, ONLY: JPIM, JPRB
USE YOMHOOK , ONLY: LHOOK, DR_HOOK
USE YOMMP   , ONLY: MYLEVS, MY_REGION_NS, MY_REGION_EW, MYPROC
USE YOMDIM  , ONLY: NPROMA, NSMAX, NFLEVL, NFLEVG
USE YOMCVA  , ONLY: NVATOVV, NGRBVAR
USE YOMTVRAD, ONLY: NVATOVOFF,NVATOVLEN,NVATOVLENG
USE YOMDIMO , ONLY: NOBNTV, NOBNTVG
USE YOMWAVELET, ONLY: GRID_DEFINITION
USE YOMMODEL_ERROR, ONLY: NGRBMERRCTL
USE RANDOM_NUMBERS_MIX
USE CONTROL_VECTORS
USE CONTROL_VECTORS_DATA_MIX, ONLY: MYTSOFF
USE SPECTRAL_FIELDS_MOD

IMPLICIT NONE

TYPE(CONTROL_VECTOR), INTENT(INOUT) :: YDCV 
LOGICAL, INTENT(IN) :: LDINIT 
LOGICAL, INTENT(IN) :: LDMERR 
LOGICAL, INTENT(IN) :: LDTOVS 
LOGICAL, INTENT(IN) :: LDLAM 
LOGICAL, INTENT(IN) :: LDPARA 
LOGICAL, INTENT(IN) :: LDTS 
INTEGER (KIND=JPIM),  INTENT(INOUT) :: KSEED

TYPE(randomNumberStream) :: YL_RANDOM_STREAM
TYPE(randomNumberStream), ALLOCATABLE :: YL_RANSTREAM_OMP(:)
TYPE(spectral_field)     :: ylsp

REAL(KIND=JPRB), ALLOCATABLE :: ZTMP(:)
REAL(KIND=JPRB) :: ZHOOK_HANDLE
INTEGER (KIND=JPIM) :: ILENCOL, JSCALE, IL, IGPTOTG, ii, jc, &
                     & IBGN, IOFFL, JF,JL,JJ, ISEED, ICEND, JKGLO, IBL, JFLD, &
                     & JGLAT, IOFF, ILAT, JLON, INDLON, ISTLON, INDLAT, IFSTLAT
INTEGER(KIND=JPIM), ALLOCATABLE :: ILSEED(:)

#include "setimzero.intfb.h"
#include "spec_imzero.intfb.h"
#include "abor1.intfb.h"

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

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

!--- Generate random numbers for model error, tovscv, etc.

IF (YDCV%nmoderr>0) THEN
  IF (LDMERR) THEN
    CALL allocate_spec(ylsp,ydcv%nserr,ydcv%nmsmax, &
                     & ydcv%nve3d,ydcv%nve2d,0,NGRBMERRCTL)
    ii=0
    il=ylsp%nspsizel
    DO jc=1,YDCV%nmoderr
      CALL random_spectral_field(ylsp,KSEED)
      CALL SPEC_IMZERO(ylsp)
      ydcv%moderr(ii+1:ii+il)=ylsp
      ii=ii+il
    ENDDO
    CALL deallocate_spec(ylsp)
    IF (ii/=SIZE(YDCV%MODERR)) CALL ABOR1('RANDOM_CTLVEC: Error model error')
  ELSE
    YDCV%moderr(:) = 0.0_JPRB
    KSEED=KSEED+NSMAX
  ENDIF
ENDIF

IF (YDCV%ltovscv) THEN
  IF (LDTOVS) THEN
    ALLOCATE(ZTMP(NVATOVLENG*NVATOVV))
    CALL INITIALIZE_RANDOM_NUMBERS (KSEED,YL_RANDOM_STREAM)
    CALL GAUSSIAN_DISTRIBUTION (ZTMP,YL_RANDOM_STREAM)
    ioffl=0
    jl=0
    DO jf=1,NVATOVV
      DO jj=1,NVATOVLEN
        jl=jl+1
        ydcv%tovscv(jl)=ztmp(ioffl+NVATOVOFF(MYPROC)+jj)
      ENDDO
      ioffl=ioffl+NVATOVLENG
    ENDDO
    DEALLOCATE(ZTMP)
  ELSE
    YDCV%tovscv(:) = 0.0_JPRB
  ENDIF
ENDIF
KSEED=KSEED+1

IF (YDCV%ltscv) THEN
  IF (LDTS) THEN
    ALLOCATE(ZTMP(NOBNTVG))
    CALL INITIALIZE_RANDOM_NUMBERS (KSEED,YL_RANDOM_STREAM)
    CALL GAUSSIAN_DISTRIBUTION (ZTMP,YL_RANDOM_STREAM)
    jl=0
    DO jj=1,NOBNTV
      jl=jl+1
      ydcv%tscv(jl)=ztmp(MYTSOFF+jj)
    ENDDO
    DEALLOCATE(ZTMP)
  ELSE
    YDCV%tscv(:) = 0.0_JPRB
  ENDIF
ENDIF
KSEED=KSEED+1

IF (YDCV%lam1d) THEN
  IF (LDLAM) THEN
    CALL INITIALIZE_RANDOM_NUMBERS (KSEED,YL_RANDOM_STREAM)
    ALLOCATE(ZTMP(NFLEVG*YDCV%NS1D))
    CALL GAUSSIAN_DISTRIBUTION (ZTMP,YL_RANDOM_STREAM)
    jj=0
    DO jf=1,ydcv%ns1d
      DO jl=1,NFLEVL
        il=MYLEVS(jl)
        jj=jj+1
        ydcv%lamcv(jj)=ZTMP(il+NFLEVG*ydcv%ns1d)
      ENDDO
    ENDDO
    DEALLOCATE(ZTMP)
  ELSE
    YDCV%lamcv(:)  = 0.0_JPRB
  ENDIF
ENDIF
KSEED=KSEED+1

IF (YDCV%npara>0) THEN
  IF (LDPARA) THEN
    CALL INITIALIZE_RANDOM_NUMBERS (KSEED,YL_RANDOM_STREAM)
    ALLOCATE(ZTMP(ydcv%npara))
    CALL GAUSSIAN_DISTRIBUTION (ZTMP,YL_RANDOM_STREAM)
    YDCV%params(:) = ZTMP
    DEALLOCATE(ZTMP)
  ELSE
    YDCV%params(:) = 0.0_JPRB
  ENDIF
ENDIF
KSEED=KSEED+1

!--- Generate random numbers for initcv

IF (YDCV%linitcv) THEN
  IF (LDINIT) THEN
    IF (.not.ydcv%lwaveletjb) THEN
      CALL allocate_spec(ylsp,ydcv%nsmax,ydcv%nmsmax,ydcv%ns3d,ydcv%ns2d,ydcv%ns1d,NGRBVAR)
      CALL random_spectral_field (ylsp,KSEED)
      CALL SPEC_IMZERO(ylsp)
      ydcv%initcv(:)=ylsp
      CALL deallocate_spec(ylsp)
    ELSE
      DO jscale=1,ydcv%nscales

!--- generate unique seeds for each grid column

        ALLOCATE(ILSEED(GRID_DEFINITION(jscale)%NGPTOT))
        ISEED=KSEED+SUM(GRID_DEFINITION(1:jscale-1)%ngptotg)-1
        ILAT=GRID_DEFINITION(jscale)%NPTRFLOFF
        IOFF=0
        IFSTLAT=GRID_DEFINITION(jscale)%NFRSTLAT(MY_REGION_NS)
        INDLAT=GRID_DEFINITION(jscale)%NLSTLAT(MY_REGION_NS) 
        IGPTOTG=SUM(GRID_DEFINITION(jscale)%NLOENG(1:IFSTLAT-1))

        DO JGLAT=IFSTLAT,INDLAT
          ILAT=ILAT+1
          ISTLON=GRID_DEFINITION(jscale)%NSTA(ILAT,MY_REGION_EW)
          INDLON=ISTLON-1+ GRID_DEFINITION(jscale)%NONL(ILAT,MY_REGION_EW)
          IGPTOTG=IGPTOTG+ISTLON-1

          DO JLON=ISTLON,INDLON
            IOFF=IOFF+1
            IGPTOTG=IGPTOTG+1
            ILSEED(IOFF)=ISEED+IGPTOTG
          ENDDO

          IGPTOTG=IGPTOTG+GRID_DEFINITION(jscale)%NLOENG(JGLAT)-INDLON
        ENDDO

        ALLOCATE(YL_RANSTREAM_OMP((GRID_DEFINITION(jscale)%NGPTOT-1)/NPROMA+1))
        ILENCOL=NFLEVG*YDCV%NS3D+YDCV%NS2D
!$OMP PARALLEL DO SCHEDULE(DYNAMIC) PRIVATE(JKGLO,ICEND,IBL,IBGN,JLON,JFLD,ZTMP)
        DO JKGLO=1,GRID_DEFINITION(jscale)%NGPTOT,NPROMA
          ICEND=MIN(NPROMA,GRID_DEFINITION(jscale)%NGPTOT-JKGLO+1)
          IBL=(JKGLO-1)/NPROMA+1
          IBGN=YDCV%ibgn_scale(jscale)+(JKGLO-1)*ILENCOL
          ALLOCATE (ZTMP(ILENCOL))
          DO JLON=1,ICEND
            CALL INITIALIZE_RANDOM_NUMBERS (ILSEED(JLON+JKGLO-1),YL_RANSTREAM_OMP(IBL))
            CALL GAUSSIAN_DISTRIBUTION(ZTMP,YL_RANSTREAM_OMP(IBL))
            DO JFLD=1,ILENCOL
              YDCV%initcv(IBGN+JLON-1+(JFLD-1)*NPROMA)=ZTMP(JFLD)
            ENDDO
          ENDDO
          DEALLOCATE(ZTMP)
          DO JFLD=1,ILENCOL
            DO JLON=ICEND+1,NPROMA
              YDCV%initcv(IBGN+JLON-1+(JFLD-1)*NPROMA)=0.0_JPRB
            ENDDO
          ENDDO
        ENDDO
!OMP END PARALLEL DO
        DEALLOCATE(YL_RANSTREAM_OMP)
        DEALLOCATE(ILSEED)
      ENDDO
      KSEED=KSEED+SUM(GRID_DEFINITION(:)%ngptotg)
    ENDIF
  ELSE
    YDCV%initcv(:) = 0.0_JPRB
  ENDIF
ENDIF

CALL SETIMZERO(YDCV)

IF (LHOOK) CALL DR_HOOK('RANDOM_CTLVEC',1,ZHOOK_HANDLE)
END SUBROUTINE RANDOM_CTLVEC
