!copyright (C) 2001 MSC-RPN COMM %%%RPNPHY%%%
***S/P TURBUL
*
#include "phy_macros_f.h"
SUBROUTINE TURBUL(D, DSIZ, F, FSIZ, V, VSIZ, 1,9
$ WORK, ESPWORK,
$ TKE, QE, SE,
$ KOUNT, TRNCH, N, M, NK, IT)
#include "impnone.cdk"
INTEGER DSIZ, FSIZ, VSIZ, ESPWORK
INTEGER IT,KOUNT,TRNCH,N,M,NK
REAL D(DSIZ), F(FSIZ), V(VSIZ), WORK(ESPWORK)
REAL TKE(M,NK), QE(M,NK)
REAL SE(M,NK)
*
REAL TFILT
SAVE TFILT
DATA TFILT / 0.1 /
REAL HEURSER
INTEGER IERGET
EXTERNAL MZONXST, SERGET
*
*Author
* J. Mailhot and B. Bilodeau (Jan 1999)
*
*Revision
* 001 B. Bilodeau (Nov 2000) - New comdeck phybus.cdk
* 002 J. Mailhot (May 2000) - Add MOISTKE option (ifluvert=3)
* 003 A-M.Leduc (Dec 2002) - Add argument qc and remove
* ISHLCVT to call eturbl4--->eturbl5
* 004 J. Mailhot (Feb 2003) - Restore ADVECTKE option
* 005 A. Plante (May 2003) - IBM conversion
* - calls to exponen4 (to calculate power function '**')
* - calls to vexp routine (from massvp4 library)
* 006 B. Bilodeau (Aug 2003) - exponen4 replaced by vspown1
* 007 F. Lemay (Spring 2003) - Add implicit boundary condition
* option for vert. diff.
* 008 Y. Delage (Aug 2003) - Fill extra levels near sfc for
* TKE, ZN, KM and KT
* 009 S.Belair (Mar 2003)- Add F(ZD) in call...>eturbl6
*
*Object
* interface for turbulent kinetic energy calculations
*
*Arguments
*
* - Input/Output -
* D dynamic bus
* F permanent variables bus
* V volatile (output) bus
* WORK physics work space
* TKE turbulent energy
*
* - Input -
* DSIZ dimension of D
* FSIZ dimension of F
* VSIZ dimension of V
* ESPWORK dimension of WORK
* QE specific humidity on 'E' levels
* SE sigma level for turbulent energy
* KOUNT index of timestep
* TRNCH number of the slice
* N horizontal dimension
* M 1st dimension of T, Q, U, V
* NK vertical dimension
* IT task number in multi-tasking
*
*
*IMPLICITES
*
#include "indx_sfc.cdk"
*
#include "stk.cdk"
*
#include "phy_macros_f.h"
#include "phybus.cdk"
*
#include "options.cdk"
*
#include "clefcon.cdk"
*
#include "surfcon.cdk"
#include "consphy.cdk"
#include "dintern.cdk"
#include "fintern.cdk"
*
*MODULES
*
*
**********************************************************
* AUTOMATIC ARRAYS
**********************************************************
*
AUTOMATIC ( WORK2 , REAL , (N) )
*
EXTERNAL ETURBL6
EXTERNAL MOISTKE2
EXTERNAL SERXST
EXTERNAL SFLTR
*
*
**
*
*
REAL CF1,CF2, ETURBTAU, ZNTEM
INTEGER I,K,NNK
REAL AA
SAVE AA
DATA AA/0.516/
real uet,ilmot,fhz,fim,fit
*
*
* pointeurs des champs de travail
real b, c, dsgdz, x, x1, xb, xh, wk, wk2d, enold
pointer (b_ , b (n,nk*4))
pointer (c_ , c (n,nk ))
pointer (dsgdz_ , dsgdz(n,nk ))
pointer (x_ , x (n,nk ))
pointer (x1_ , x1 (n,nk ))
pointer (xb_ , xb (n ))
pointer (xh_ , xh (n ))
pointer (wk_ , wk (n*2 ))
pointer (wk2d_ , wk2d (n,nk ))
pointer (enold_ , enold(n,nk ))
*
*
* fonction-formule
integer ik
ik(i,k) = (k-1)*n + i -1
*
*
STK_INITA(work, espwork)
*
NNK = N*NK
*
STK_ALLOC(b_ , nnk*4)
STK_ALLOC(c_ , nnk )
STK_ALLOC(dsgdz_ , nnk )
STK_ALLOC(x_ , nnk )
STK_ALLOC(x1_ , nnk )
STK_ALLOC(xb_ , n )
STK_ALLOC(xh_ , n )
STK_ALLOC(wk_ , n*2 )
STK_ALLOC(wk2d_ , nnk )
STK_ALLOC(enold_ , nnk )
*
eturbtau=delt
if (advectke) then
if (kount.gt.1) then
eturbtau=factdt*delt
endif
endif
*
* FILTRE TEMPOREL
*
CF1=1.0-TFILT
CF2=TFILT
*
CALL SERGET ('HEURE', HEURSER, 1, IERGET)
*
* INITIALISER E AVEC EA,Z ET H
*
IF (KOUNT.EQ.0) THEN
DO K=1,NK
*VDIR NODEP
DO I=1,N
TKE(I,K)= MAX (ETRMIN, F(Z0+(indx_agrege-1)*N+I-1)/
X (V(ZA+I-1)+F(Z0+(indx_agrege-1)*N+I-1))*
X EXP(-(V(ZE+ik(I,K))- V(ZE+ik(I,NK)))/F(H+I-1)) )
END DO
END DO
if (advectke) then
DO K=1,NK
*VDIR NODEP
DO I=1,N
d(enmoins +ik(i,k)) = tke(i,k)
END DO
END DO
endif
ENDIF
*
*
IF (KOUNT.GT.0) THEN
CALL SERXST
( F(ZN) , 'LM' , TRNCH , N , 0.0 , 1.0 , -1 )
CALL MZONXST ( F(ZN) , 'LM' , TRNCH , N, HEURSER, 1.0, -1, IT)
CALL SERXST
( TKE , 'EN' , TRNCH , N , 0.0 , 1.0 , -1 )
CALL MZONXST ( TKE , 'EN' , TRNCH , N, HEURSER, 1.0, -1, IT)
ENDIF
*
DO K=1,NK
*VDIR NODEP
DO I=1,N
if (advectke) then
enold(i,k) = d(enmoins +ik(i,k))
tke(i,k) = max(tke(i,k),etrmin)
else
enold(i,k) = tke(i,k)
endif
END DO
END DO
*
if (advectke .and. kount.gt.1) then
do K=1,NK
*VDIR NODEP
do I=1,N
zntem = f(zn +ik(i,k))
f(zn +ik(I,K)) = f(znm1+ik(I,K))
f(znm1+ik(I,K)) = zntem
end do
end do
endif
*
IF(IFLUVERT.EQ.3) THEN
*
*
* convective velocity scale w*
* (passed to MOISTKE2 through XH)
DO I=1,N
XB(I)=1.0+DELTA*QE(I,NK)
XH(I)=(GRAV/(XB(I)*V(TVE+ik(I,NK))))*
1 ( XB(I)*F(FTEMP+(indx_agrege-1)*N+I-1)
1 + DELTA*V(TVE+ik(I,NK))*F(FVAP+(indx_agrege-1)*N+I-1) )
XH(I)=MAX(0.0,XH(I))
WORK2(I)=F(H+I-1)*XH(I)
END DO
CALL VSPOWN1 (XH,WORK2,1./3.,N)
*
CALL MOISTKE2
( TKE,ENOLD,F(ZN),F(ZD),V(KT),F(QCBL),F(FN),F(FNN),
$ V(GTE),V(GQ),V(GQL),F(H),
$ D(UMOINS), D(VMOINS), D(TMOINS),
$ V(TVE), D(HUMOINS), D(PMOINS), D(SIGM),
$ SE, wk2d, C, B, X, 4*NK, ETURBTAU, KOUNT,
$ V(ZE), V(KCL),F(UE2),X1,XB,XH,TRNCH,N,M,NK,IT)
*
ELSE
*
CALL ETURBL6
( TKE,ENOLD,F(ZN),F(ZD),V(GTE),
$ F(ILMO+(indx_agrege-1)*n),F(FN),
$ wk2d, V(GQL), F(LWC), C, B,
$ X , D(UMOINS), D(VMOINS), D(TMOINS),
$ V(TVE), D(HUMOINS), D(QCMOINS), QE, F(H), D(PMOINS),
$ F(TSURF),
$ D(SIGM), SE, 4*NK,
$ DSGDZ, ETURBTAU, KOUNT, V(GQ), F(CCN),
$ V(KT), V(ZE), V(KCL),X1,XB,XH,TRNCH,N,M,NK,
$ F(Z0+(indx_agrege-1)*N), WK, IT)
*
* Implicit diffusion scheme: the diffusion interprets the coefficients of the
* surface boundary fluxe condition as those in the ALFAT+BT*TA expression.
* Since the diffusion is made on potential temperature, there is a correction
* term that must be included in the non-homogeneous part of the expression -
* the alpha coefficient. The correction is of the form za*g/cp. It is
* relevant only for the CLEF option (as opposed to the MOISTKE option) since
* in this case, although the diffusion is made on potential temperature,
* the diffusion calculation takes an ordinary temperature as the argument.
*
IF (IMPFLX) THEN
DO I=1,N
V(ALFAT+I-1) = V(ALFAT+I-1) + V(BT+(indx_agrege-1)*N+I-1)*V(ZA+I-1)*GRAV/CPD
END DO
ENDIF
*
ENDIF
*
* -------------------------------------
* FILTRE TEMPOREL (TKE,ZN)
* -------------------------------------
*
IF (KOUNT.EQ.0) THEN
*VDIR NODEP
DO K=1,NK
*VDIR NODEP
DO I=1,N
F(ZNM1+ik(I,K)) = F(ZN+ik(I,K))
END DO
END DO
if (advectke) then
DO K=1,NK
*VDIR NODEP
DO I=1,N
F(ZN0+ik(I,K)) = F(ZN+ik(I,K))
END DO
END DO
endif
*
ELSE
*
if (.not.advectke) then
DO K=1,NK
*VDIR NODEP
DO I=1,N
ZNTEM = F(ZN+ik(I,K))
F(ZN +ik(I,K)) = CF1*F(ZN+ik(I,K))+CF2*F(ZNM1+ik(I,K))
F(ZNM1+ik(I,K)) = ZNTEM
END DO
END DO
else
DO K=1,NK
*VDIR NODEP
DO I=1,N
ZNTEM = F(ZN+ik(I,K))
F(ZN +ik(I,K)) = CF1*F(ZN+ik(I,K))+CF2*F(ZN0+ik(I,K))
F(ZN0+ik(I,K)) = ZNTEM
END DO
END DO
endif
*
ENDIF
*
*
* FILTRE VERTICAL SUR EN
*
CALL SFLTR
( TKE, TKE, C, 0.1, N, NK-1 )
*
IF (KOUNT.EQ.0) THEN
CALL SERXST
( F(ZN) , 'LM' , TRNCH , N , 0.0 , 1.0 , -1 )
CALL MZONXST ( F(ZN) , 'LM' , TRNCH , N, HEURSER, 1.0, -1, IT)
CALL SERXST
( TKE , 'EN' , TRNCH , N , 0.0 , 1.0 , -1 )
CALL MZONXST ( TKE , 'EN' , TRNCH , N, HEURSER, 1.0, -1, IT)
ENDIF
*
*
* ------------------------------------------------------
* HAUTEUR DE LA COUCHE LIMITE STABLE OU INSTABLE
* ------------------------------------------------------
*
* Ici HST est la hauteur calculee dans la routine FLXSURF1.
*
* KCL contient le K que l'on a diagnostique dans RIGRAD
* et passe a ETURBL3; il pointe vers le premier niveau
* de la couche limite.
*
* SCL est utilise comme champ de travail dans la boucle 100;
* il est mis a jour dans la boucle 200, et donne la hauteur
* de la couche limite en sigma.
*
*
*VDIR NODEP
DO 100 I=0,N-1
*
if(f(ilmo+(indx_agrege-1)*n+i).gt.0.0) then
* Cas stable
f(scl+i) = f(hst+(indx_agrege-1)*n+i)
else
* Cas instable: max(cas neutre, diagnostic)
* Z contient les hauteurs des niveaux intermediaires
f(scl+i) = max( f(hst+(indx_agrege-1)*n+i) ,
$ v(ze +ik(i+1,nint(v(kcl+i)))))
endif
*
* Si H est en train de chuter, on fait une relaxation pour
* ralentir la chute.
*
if(f(h+i) .gt. f(scl+i)) then
f(h+i) = f(scl+i) + (f(h+i)-f(scl+i))*exp(-delt/5400.)
else
f(h+i) = f(scl+i)
endif
*
100 CONTINUE
*
* On calcule SCL avec une approximation hydrostatique
do 200 i=0,n-1
f(scl+i)=-grav*f(h+i)/(rgasd*d(tmoins+ik(i+1,nk)))
200 continue
call vsexp(f(scl),f(scl),n)
*
CALL SERXST
( f(H) , 'F2' , TRNCH , N , 0.0 , 1.0, -1 )
CALL MZONXST ( f(H) , 'F2' , TRNCH , N , HEURSER, 1.0, -1, IT)
CALL SERXST
( F(SCL) , 'SE' , TRNCH , N , 0.0 , 1.0, -1 )
CALL MZONXST ( F(SCL) , 'SE' , TRNCH , N , HEURSER, 1.0, -1, IT)
*
*
DO K=1,NK-1
*VDIR NODEP
DO I=1,N
* KM
C IBM CONV. ; PAS D'AVANTAGE A PRECALCULER SQRT CI-DESSOUS
V(KM+ik(I,K))=AA*F(ZN+ik(i,k))*SQRT(TKE(i,k))
*
* KT
V(KT+ik(I,K))=V(KM+ik(I,K))*V(KT+ik(I,K))
*
END DO
END DO
*
do i=1,n
IF(IFLUVERT.LT.3) tke(i,nk)=tke(i,nk-1)
tke(i,nk+1)=tke(i,nk)
uet=sqrt(f(ue2+i-1))
ilmot=f(ilmo+ik(i,indx_agrege))
if(ilmot.gt.0.) then
fhz=1-v(za+i-1)/f(hst+ik(i,indx_agrege))
fim=0.5*(1+sqrt(1+4*as*v(za+i-1)*ilmot*beta/fhz))
fit=beta*fim
else
fim=(1-ci*v(za+i-1)*ilmot)**(-.16666666)
fit=beta*fim**2
fhz=1
endif
F(ZN+ik(i,nk))=karman*(v(za+i-1)+f(z0+ik(i,indx_agrege)))/fim
V(KM+ik(I,NK))=uet*F(ZN+ik(i,nk))*fhz
V(KT+ik(I,NK))=V(KM+ik(I,NK))*fim/fit
F(ZN+ik(i,nk+1))=karman*f(z0+ik(i,indx_agrege))
V(KM+ik(I,NK+1))=uet*F(ZN+ik(i,nk+1))
V(KT+ik(I,NK+1))=V(KM+ik(I,NK+1))/beta
enddo
STK_FREE
*
RETURN
END