MODULE SPECTRAL_FIELDS_MOD

!   Author.
!   -------
!     Yannick Tremolet
!
!   Modifications.
!   -------------- 
!     Original    02-03-05  
!     Y.Tremolet  02-07-25 Added operators.
!     C.Fischer   03-03-03 Aladin spectral treatment added.
!      N.B.1: the mean wind spec%sp1d is treated in assign_sp_sp and in
!             assign_scalar_sp but not in assign_ar_sp and assign_sp_ar.
!             therefore, whenever a fortran array is copied to a spectral_field
!             type in Aladin, one should take care of the mean wind externally.
!             see for example get_cv_init and set_cv_init in control_vectors.F90.
!     Y.Tremolet  11-Mar-2004 Type definition moved to SPECTRAL_FIELDS_DATA.
!     Y.Tremolet  11-Mar-2004 SPECTRAL_FIELDS_PARA_MOD for distributed operators.
!     Y.Tremolet  22-Jul-2004 SPECTRAL_FIELDS_OPER_MOD for basic operators.
!     M.Fisher    23-Aug-2004 Added RANDOM_SPECTRAL_FIELD
!     C. Fischer  20-May-2005 RANDOM_SPECTRAL_FIELD updated for Aladin
! ------------------------------------------------------------------

USE PARKIND1, ONLY: JPIM, JPRB
USE SPECTRAL_FIELDS_DATA, ONLY: SPECTRAL_FIELD, &
                              & NPRTRV, NPRTRW, MYSETV, MYSETW, NFLEVL, &
                              & NFLEVG, NALLMS, NPTRMS, NUMLL, NPTRLL, &
                              & LELAM, NPSURF, MYMS, MYLEVS, NULOUT, &
                              & NGRBVO,NGRBD,NGRBT,NGRBQ,NGRBO3,NGRBLNSP
USE SPECTRAL_FIELDS_OPER_MOD, ONLY: ASSIGNMENT(=), OPERATOR(.EQV.), OPERATOR(.NEQV.), &
                              & SELF_ADD, SELF_SUB, SELF_MUL
USE SPECTRAL_FIELDS_PARA_MOD, ONLY: DOT_PRODUCT, SPECTRAL_NORM, &
                              & SPECTRAL_NORM_LEVS, SPECTRAL_MAX_LEVS

IMPLICIT NONE
PRIVATE
PUBLIC SPECTRAL_FIELD, SETUP_SPEC, ALLOCATE_SPEC, DEALLOCATE_SPEC, &
     & ASSIGNMENT(=), OPERATOR(.EQV.), OPERATOR(.NEQV.), &
     & SELF_ADD, SELF_SUB, SELF_MUL, INQ_SPEC,  RANDOM_SPECTRAL_FIELD, &
     & DOT_PRODUCT, SPECTRAL_NORM, SPECTRAL_NORM_LEVS, SPECTRAL_MAX_LEVS


! ------------------------------------------------------------------
CONTAINS
! ------------------------------------------------------------------

SUBROUTINE setup_spec(kprtrv,kprtrw,ksetv,ksetw,kflevl,kflevg,knms,kmyms, &
                    & ksmax,kmsmax,kallms,kptrms,knmull,kptrll,kpsurf,ldlam, &
                    & kulout,kgrbvo,kgrbd,kgrbt,kgrbq,kgrbo3,kgrblnsp)

! This is a way to get values from ifs to ifsaux

INTEGER(KIND=JPIM), INTENT(IN) :: kprtrv,kprtrw,ksetv,ksetw,kflevl,kflevg,knms, &
              & kmyms(knms),ksmax, kmsmax, kallms(max(ksmax,kmsmax)+1),kptrms(kprtrw),&
              & knmull(kprtrv),kptrll(kprtrv),kpsurf(kprtrv), &
              & kulout,kgrbvo,kgrbd,kgrbt,kgrbq,kgrbo3,kgrblnsp
LOGICAL, INTENT(IN) :: ldlam

INTEGER(KIND=JPIM) :: jl, iiismax

LELAM=ldlam

if (ldlam) then
  iiismax=kmsmax
else
  iiismax=ksmax
endif

NPRTRV=kprtrv
NPRTRW=kprtrw
MYSETV=ksetv
MYSETW=ksetw
NFLEVL=kflevl
NFLEVG=kflevg
IF (ALLOCATED(MYMS)) DEALLOCATE(MYMS)
ALLOCATE(MYMS(knms))
MYMS(:)=kmyms(:)
IF (ALLOCATED(NALLMS)) DEALLOCATE(NALLMS)
ALLOCATE(NALLMS(iiismax+1))
NALLMS(1:iiismax+1)=KALLMS(1:iiismax+1)
IF (.NOT.ALLOCATED(NPTRMS)) ALLOCATE(NPTRMS(kprtrw))
NPTRMS(:)=kptrms(:)
IF (.NOT.ALLOCATED(NUMLL))  ALLOCATE(NUMLL(kprtrv))
NUMLL(:)=knmull(:)
IF (.NOT.ALLOCATED(NPTRLL)) ALLOCATE(NPTRLL(kprtrv))
NPTRLL(:)=kptrll(:)
IF (.NOT.ALLOCATED(NPSURF)) ALLOCATE(NPSURF(kprtrv))
NPSURF(:)=kpsurf(:)
IF (.NOT.ALLOCATED(MYLEVS)) ALLOCATE(MYLEVS(NFLEVL))
DO jl=1,NFLEVL
  MYLEVS(jl) = NPTRLL(MYSETV)+jl-1
ENDDO
NULOUT=kulout
NGRBVO=kgrbvo
NGRBD =kgrbd
NGRBT =kgrbt
NGRBQ =kgrbq
NGRBO3=kgrbo3
NGRBLNSP=kgrblnsp

write(NULOUT,*)'SETUP_SPEC: SPECTRAL_FIELD type has been setup.'

END SUBROUTINE setup_spec

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

SUBROUTINE allocate_spec(ydsp,ksmax,kmsmax,ks3d,ks2d,ks1d,kgrib,kparamid)

TYPE (SPECTRAL_FIELD), INTENT(OUT) :: ydsp
INTEGER(KIND=JPIM), INTENT(IN) :: ksmax, kmsmax, ks3d, ks2d, ks1d, kgrib(ks3d+ks2d)
INTEGER(KIND=JPIM),OPTIONAL,INTENT(IN) :: kparamid(ks3d+ks2d)

INTEGER(KIND=JPIM) :: idum1,idum2(0:ksmax),idum3,idum4, &
           & idum5(NPRTRW+1),idum6(0:ksmax),jp,jm,imaxms, &
           & imdim,il,ik,ind,ipos,ikm,isc3
INTEGER(KIND=JPIM) :: indd, indv, indt, indq, indo, inds
INTEGER(KIND=JPIM) :: IKNTMP(0:kmsmax),IKMTMP(0:ksmax),icpl4m(0:kmsmax)

INTERFACE
#include "ini_spec_dist.h"
END INTERFACE

IF (LELAM) THEN
  CALL ELLIPS(ksmax,kmsmax,IKNTMP,IKMTMP)
  imaxms=kmsmax/NPRTRW+1
  ALLOCATE(ydsp%nesm0 (0:kmsmax))
  ALLOCATE(ydsp%nesm0g(0:kmsmax))
  ALLOCATE(ydsp%ncpl4m(0:kmsmax))
  IF (ASSOCIATED(ydsp%nasm0 )) NULLIFY(ydsp%nasm0 )
  IF (ASSOCIATED(ydsp%nasm0g)) NULLIFY(ydsp%nasm0g)
ELSE
  imaxms=ksmax/NPRTRW+1
  ALLOCATE(ydsp%nasm0 (0:ksmax))
  ALLOCATE(ydsp%nasm0g(0:ksmax))
  NULLIFY(ydsp%nesm0 )
  NULLIFY(ydsp%nesm0g)
  NULLIFY(ydsp%ncpl4m)
ENDIF

ALLOCATE(ydsp%numpp(NPRTRW))
ALLOCATE(ydsp%ms_proc(imaxms,NPRTRW))
ALLOCATE(ydsp%numll(NPRTRV))
ALLOCATE(ydsp%nptrll(NPRTRV))
ALLOCATE(ydsp%ns2l(NPRTRV))
ALLOCATE(ydsp%ngrib(ks3d+ks2d))
ALLOCATE(ydsp%nparamid(ks3d+ks2d))

ydsp%nsmax=ksmax
ydsp%ns2g=ks2d
ydsp%ns2l(:)=ks2d*NPSURF(:)
ydsp%ns2d=ydsp%ns2l(MYSETV)
ydsp%ns3d=ks3d

ydsp%nflevl=nflevl
ydsp%nflevg=nflevg

IF (LELAM) THEN
  ydsp%ns1d=ks1d
  ydsp%nmsmax=kmsmax
  ydsp%nspec2g=0
  do jm=0,kmsmax
    icpl4m(jm) = 4*(IKNTMP(jm)+1)
    ydsp%nspec2g = ydsp%nspec2g + 4*(IKNTMP(jm)+1)
  enddo
  ydsp%ncpl4m(:)=icpl4m(:)
  ydsp%nesm0g(0)=1
  do jm=1,kmsmax
    ydsp%nesm0g(jm) = ydsp%nesm0g(jm-1) + icpl4m(jm-1)
  enddo

  ydsp%numpp(:) = 0
  ydsp%nesm0(:) = -99

  imdim = 0
  il = 1
  ind = 1
  ik  = 0
  ipos = 1
  do jm=0,kmsmax
    ik = ik + ind
    if (ik > NPRTRW) then
      ik = NPRTRW
      ind = -1
    elseif (ik < 1) THEN
      ik = 1
      ind = 1
    endif

    ikm = icpl4m(jm)/4 -1
    ydsp%numpp(ik) = ydsp%numpp(ik) +1
    if (ik == MYSETW) THEN
      imdim = imdim + ikm +1
      ydsp%nesm0(jm) = ipos
      ipos = ipos + (ikm+1)*4
      il = il +1
    endif
  enddo

  ydsp%nspec2 = 4*imdim
ELSE
  ydsp%ns1d=0
  ydsp%nmsmax=0
  ydsp%nspec2g=(ksmax+1)*(ksmax+2)
  ydsp%nasm0g(0)=1
  DO jm=0,ksmax-1
    ydsp%nasm0g(jm+1) = ydsp%nasm0g(jm) + 2*(ksmax-jm+1)
  ENDDO

  CALL INI_SPEC_DIST(KSMAX,KSMAX,&
   & NPRTRW,MYSETW,KASM0=ydsp%nasm0,KUMPP=ydsp%numpp,&
   & KSPEC2=ydsp%nspec2)
ENDIF

ydsp%nump = ydsp%numpp(MYSETW)
DO jp=1,NPRTRW
  DO jm=1,ydsp%numpp(jp)
    ydsp%ms_proc(jm,jp)=NALLMS(NPTRMS(jp)-1+jm)
  ENDDO
ENDDO

ydsp%numll(:) =NUMLL(:)
ydsp%nptrll(:)=NPTRLL(:)

ydsp%ngrib(:)=kgrib(:)
ydsp%ngrib3 => ydsp%ngrib(1:ks3d)
ydsp%ngrib2 => ydsp%ngrib(ks3d+1:ks3d+ks2d)
IF(PRESENT(kparamid)) THEN
  ydsp%nparamid(:)=kparamid
ELSE
  ydsp%nparamid(:)=ydsp%ngrib(:)
ENDIF
ydsp%nparamid3 => ydsp%nparamid(1:ks3d)
ydsp%nparamid2 => ydsp%nparamid(ks3d+1:ks3d+ks2d)

ALLOCATE(ydsp%sp2d(ydsp%nspec2,ydsp%ns2d))
ALLOCATE(ydsp%sp3d(ydsp%nflevl,ydsp%nspec2,ydsp%ns3d))
IF (LELAM) THEN
  ALLOCATE(ydsp%sp1d(ydsp%nflevl,ydsp%ns1d))
ELSE
  NULLIFY(ydsp%sp1d)
ENDIF

!cf nspsizeg and nspsizel contain only the horizontal spectral fields
! (eg. not the mean wind profiles for aladin case)

ydsp%nspsizel = (ydsp%nflevl*ydsp%ns3d+ydsp%ns2d)*ydsp%nspec2
ydsp%nspsizeg = (ydsp%nflevg*ydsp%ns3d+ydsp%ns2g)*ydsp%nspec2g

NULLIFY(ydsp%DIV)
NULLIFY(ydsp%VOR)
NULLIFY(ydsp%TEM)
NULLIFY(ydsp%HUM)
NULLIFY(ydsp%OZN)
indd=INTLOC(ydsp%ngrib3,NGRBD)
indv=INTLOC(ydsp%ngrib3,NGRBVO)
indt=INTLOC(ydsp%ngrib3,NGRBT)
indq=INTLOC(ydsp%ngrib3,NGRBQ)
indo=INTLOC(ydsp%ngrib3,NGRBO3)
IF (indd>0) ydsp%DIV => ydsp%sp3d(:,:,indd)
IF (indv>0) ydsp%VOR => ydsp%sp3d(:,:,indv)
IF (indt>0) ydsp%TEM => ydsp%sp3d(:,:,indt)
IF (indq>0) ydsp%HUM => ydsp%sp3d(:,:,indq)
IF (indo>0) ydsp%OZN => ydsp%sp3d(:,:,indo)

NULLIFY(ydsp%SPR)
inds=INTLOC(ydsp%ngrib2,NGRBLNSP)
IF (inds>0.and.SIZE(ydsp%sp2d,2)>0) ydsp%SPR => ydsp%sp2d(:,inds)

isc3=1
IF (indd>0 .AND. indv>0) isc3=3
IF (indd>isc3 .OR. indv>isc3) THEN  ! Div and Vor not first in array...
  CALL ABOR1('ALLOCATE_SPEC: DIV and VOR not first in array')
ENDIF
IF (ydsp%ns3d>=isc3) THEN
  ydsp%SCAL => ydsp%sp3d(:,:,isc3:ydsp%ns3d)
ELSE
  NULLIFY(ydsp%SCAL)
ENDIF

CONTAINS
  INTEGER(KIND=JPIM) FUNCTION INTLOC(kindx,kval)
  INTEGER(KIND=JPIM), INTENT(IN) :: kindx(:),kval
  INTEGER(KIND=JPIM) :: ii,jj
  jj=0
  ii=1
  DO WHILE (ii<=SIZE(kindx) .AND. jj==0)
    IF (kindx(ii)==kval) jj=ii
    ii=ii+1
  ENDDO
  INTLOC=jj
  END FUNCTION INTLOC
END SUBROUTINE allocate_spec

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

SUBROUTINE deallocate_spec(ydsp)

TYPE (SPECTRAL_FIELD), INTENT(INOUT) :: ydsp

NULLIFY(ydsp%div)
NULLIFY(ydsp%vor)
NULLIFY(ydsp%tem)
NULLIFY(ydsp%hum)
NULLIFY(ydsp%ozn)
NULLIFY(ydsp%spr)
NULLIFY(ydsp%scal)
NULLIFY(ydsp%ngrib2)
NULLIFY(ydsp%ngrib3)

IF (ASSOCIATED(ydsp%sp2d   )) DEALLOCATE(ydsp%sp2d)
IF (ASSOCIATED(ydsp%sp3d   )) DEALLOCATE(ydsp%sp3d)
IF (ASSOCIATED(ydsp%sp1d   )) DEALLOCATE(ydsp%sp1d)
IF (ASSOCIATED(ydsp%nasm0  )) DEALLOCATE(ydsp%nasm0)
IF (ASSOCIATED(ydsp%nasm0g )) DEALLOCATE(ydsp%nasm0g)
IF (ASSOCIATED(ydsp%nesm0  )) DEALLOCATE(ydsp%nesm0)
IF (ASSOCIATED(ydsp%nesm0g )) DEALLOCATE(ydsp%nesm0g)
IF (ASSOCIATED(ydsp%ncpl4m )) DEALLOCATE(ydsp%ncpl4m)
IF (ASSOCIATED(ydsp%numpp  )) DEALLOCATE(ydsp%numpp)
IF (ASSOCIATED(ydsp%ms_proc)) DEALLOCATE(ydsp%ms_proc)
IF (ASSOCIATED(ydsp%numll  )) DEALLOCATE(ydsp%numll)
IF (ASSOCIATED(ydsp%nptrll )) DEALLOCATE(ydsp%nptrll)
IF (ASSOCIATED(ydsp%ns2l   )) DEALLOCATE(ydsp%ns2l)
IF (ASSOCIATED(ydsp%ngrib  )) DEALLOCATE(ydsp%ngrib)

END SUBROUTINE deallocate_spec

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

SUBROUTINE inq_spec(ydsp,ksmax,kmsmax,ks3d,ks2d,ks1d)

! Sets all indices as allocate_spec without allocating
! space for data.

TYPE (SPECTRAL_FIELD), INTENT(OUT) :: ydsp
INTEGER(KIND=JPIM), INTENT(IN) :: ksmax, kmsmax, ks3d, ks2d, ks1d

INTEGER(KIND=JPIM) :: idum1,idum2(0:ksmax),idum3,idum4, &
           & idum5(NPRTRW+1),idum6(0:ksmax),jp,jm,imaxms, &
           & imdim,il,ik,ind,ipos,ikm
INTEGER(KIND=JPIM) :: IKNTMP(0:kmsmax),IKMTMP(0:ksmax),icpl4m(0:kmsmax)

INTERFACE
#include "ini_spec_dist.h"
END INTERFACE

IF (LELAM) THEN
  CALL ELLIPS(ksmax,kmsmax,IKNTMP,IKMTMP)
  imaxms=kmsmax/NPRTRW+1
  ALLOCATE(ydsp%nesm0 (0:kmsmax))
  ALLOCATE(ydsp%nesm0g(0:kmsmax))
  ALLOCATE(ydsp%ncpl4m(0:kmsmax))
  IF (ASSOCIATED(ydsp%nasm0 )) NULLIFY(ydsp%nasm0 )
  IF (ASSOCIATED(ydsp%nasm0g)) NULLIFY(ydsp%nasm0g)
ELSE
  imaxms=ksmax/NPRTRW+1
  ALLOCATE(ydsp%nasm0 (0:ksmax))
  ALLOCATE(ydsp%nasm0g(0:ksmax))
  NULLIFY(ydsp%nesm0 )
  NULLIFY(ydsp%nesm0g)
  NULLIFY(ydsp%ncpl4m)
ENDIF

ALLOCATE(ydsp%numpp(NPRTRW))
ALLOCATE(ydsp%ms_proc(imaxms,NPRTRW))
ALLOCATE(ydsp%numll(NPRTRV))
ALLOCATE(ydsp%nptrll(NPRTRV))
ALLOCATE(ydsp%ns2l(NPRTRV))

ydsp%nsmax=ksmax
ydsp%ns2g=ks2d
ydsp%ns2l(:)=ks2d*NPSURF(:)
ydsp%ns2d=ydsp%ns2l(MYSETV)
ydsp%ns3d=ks3d

ydsp%nflevl=nflevl
ydsp%nflevg=nflevg

IF (LELAM) THEN
  ydsp%ns1d=ks1d
  ydsp%nmsmax=kmsmax
  ydsp%nspec2g=0
  do jm=0,kmsmax
    icpl4m(jm) = 4*(IKNTMP(jm)+1)
    ydsp%nspec2g = ydsp%nspec2g + 4*(IKNTMP(jm)+1)
  enddo
  ydsp%ncpl4m(:)=icpl4m(:)
  ydsp%nesm0g(0)=1
  do jm=1,kmsmax
    ydsp%nesm0g(jm) = ydsp%nesm0g(jm-1) + icpl4m(jm-1)
  enddo

  ydsp%numpp(:) = 0
  ydsp%nesm0(:) = -99

  imdim = 0
  il = 1
  ind = 1
  ik  = 0
  ipos = 1
  do jm=0,kmsmax
    ik = ik + ind
    if (ik > NPRTRW) then
      ik = NPRTRW
      ind = -1
    elseif (ik < 1) THEN
      ik = 1
      ind = 1
    endif

    ikm = icpl4m(jm)/4 -1
    ydsp%numpp(ik) = ydsp%numpp(ik) +1
    if (ik == MYSETW) THEN
      imdim = imdim + ikm +1
      ydsp%nesm0(jm) = ipos
      ipos = ipos + (ikm+1)*4
      il = il +1
    endif
  enddo

  ydsp%nspec2 = 4*imdim
ELSE
  ydsp%ns1d=0
  ydsp%nmsmax=0
  ydsp%nspec2g=(ksmax+1)*(ksmax+2)
  ydsp%nasm0g(0)=1
  DO jm=0,ksmax-1
    ydsp%nasm0g(jm+1) = ydsp%nasm0g(jm) + 2*(ksmax-jm+1)
  ENDDO

  CALL INI_SPEC_DIST(KSMAX,KSMAX,&
   & NPRTRW,MYSETW,KASM0=ydsp%nasm0,KUMPP=ydsp%numpp,&
   & KSPEC2=ydsp%nspec2)
ENDIF

ydsp%nump = ydsp%numpp(MYSETW)
DO jp=1,NPRTRW
  DO jm=1,ydsp%numpp(jp)
    ydsp%ms_proc(jm,jp)=NALLMS(NPTRMS(jp)-1+jm)
  ENDDO
ENDDO

ydsp%numll(:) =NUMLL(:)
ydsp%nptrll(:)=NPTRLL(:)

!cf nspsizeg and nspsizel contain only the horizontal spectral fields
! (eg. not the mean wind profiles for aladin case)

ydsp%nspsizel = (ydsp%nflevl*ydsp%ns3d+ydsp%ns2d)*ydsp%nspec2
ydsp%nspsizeg = (ydsp%nflevg*ydsp%ns3d+ydsp%ns2g)*ydsp%nspec2g

ALLOCATE(ydsp%ngrib(1))
ALLOCATE(ydsp%sp2d(1,1))
ALLOCATE(ydsp%sp3d(1,1,1))
IF (LELAM) THEN
  ALLOCATE(ydsp%sp1d(1,1))
ELSE
  NULLIFY(ydsp%sp1d )
ENDIF

END SUBROUTINE inq_spec
! ------------------------------------------------------------------

SUBROUTINE random_spectral_field (spec,kseed)

!--- Sets the elements of 'spec' to random, unit gaussian values.

!--- NB: There is no normalization by the square-root of the spectral norm.

!--- NB: All seeds in the range kseed to kseed+spec%nsmax are used. On return,
!---     KSEED is incremented by (spec%nsmax+1), so that a subsequent call to
!---     random_spectral_field will use a new set of seeds.

USE RANDOM_NUMBERS_MIX

TYPE (SPECTRAL_FIELD), INTENT(INOUT) :: spec
INTEGER(KIND=JPIM), INTENT(INOUT) :: kseed

INTEGER(KIND=JPIM) :: ii,im,ioff,il,jf,jm,js,jn,jir,jl,len,iseed
REAL(KIND=JPRB), ALLOCATABLE :: ZTMP(:)
TYPE(randomNumberStream), ALLOCATABLE :: yl_random_stream(:)


ALLOCATE(yl_random_stream(spec%NUMP))

!$OMP PARALLEL DO SCHEDULE(DYNAMIC) PRIVATE(jm,im,js,len,iseed,jf,jn,jir,jl,il,ioff,ztmp)
DO jm=1,spec%NUMP
  im=MYMS(jm)

  IF (.NOT.LELAM) THEN
    js =spec%NASM0 (im)-1
    len=2*(spec%nsmax-im+1)
  ELSE
    js =spec%NESM0 (im)-1
    len=spec%ncpl4m(im)
  ENDIF

  allocate (ztmp(len*(spec%ns3d*spec%nflevg+spec%ns2d)))
  iseed=kseed+im
  CALL initialize_random_numbers (iseed,yl_random_stream(jm))
  CALL gaussian_distribution (ztmp,yl_random_stream(jm))

  DO jf=1,spec%ns2d
    ioff=spec%ns3d*spec%nflevg+jf-1
    spec%sp2d(js+1:js+len,jf)=ztmp(ioff+1:ioff+len)
  ENDDO

  IF (.NOT.LELAM) THEN
    DO jn=im,spec%nsmax
      DO jir=0,1
        js =spec%NASM0 (im)+(jn-im)*2+jir
        DO jf=1,spec%ns3d
          DO jl=1,spec%nflevl
            il=MYLEVS(jl)
            spec%sp3d(jl,js,jf)=ztmp(js-spec%NASM0(im)+1+len*(il+spec%nflevg*(jf-1)))
          ENDDO
        ENDDO
      ENDDO
    ENDDO
  ELSE
    js =spec%NESM0 (im)-1  ! repeated for LAM since "js" is recomputed for IFS
    DO jf=1,spec%ns3d
      DO jl=1,spec%nflevl
        il=MYLEVS(jl)
        spec%sp3d(jl,js+1:js+len,jf)=ztmp(js+1+len*(il+spec%nflevg*(jf-1)):js+len+len*(il+spec%nflevg*(jf-1)))
      ENDDO
    ENDDO
  ENDIF
  deallocate(ztmp)
ENDDO
!OMP END PARALLEL DO

DEALLOCATE(yl_random_stream)

kseed=kseed+(1+spec%nsmax)

IF (LELAM) THEN

!cf DO YOU WANT A RANDOM MEAN WIND COMPONENT, OR ZERO? -> I want it, thanks for asking !

  ALLOCATE(yl_random_stream(1))
  allocate (ztmp(spec%ns1d*spec%nflevg))

  CALL initialize_random_numbers (kseed,yl_random_stream(1))
  CALL gaussian_distribution (ztmp,yl_random_stream(1))
  kseed=kseed+1

  DO jf=1,spec%ns1d
    DO jl=1,spec%nflevl
      il=MYLEVS(jl)
      spec%sp1d(jl,jf)=ztmp(il+nflevg*(jf-1))
    ENDDO
  ENDDO
  deallocate(ztmp)
ENDIF


RETURN
END SUBROUTINE random_spectral_field

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

END MODULE SPECTRAL_FIELDS_MOD
