/[lmdze]/trunk/Sources/phylmd/coefkz.f
ViewVC logotype

Diff of /trunk/Sources/phylmd/coefkz.f

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

trunk/libf/phylmd/coefkz.f revision 38 by guez, Thu Jan 6 17:52:19 2011 UTC trunk/Sources/phylmd/coefkz.f revision 249 by guez, Fri Jan 5 17:15:05 2018 UTC
# Line 1  Line 1 
1        SUBROUTINE coefkz(nsrf, knon, paprs, pplay,  module coefkz_m
2  cIM 261103  
3       .                  ksta, ksta_ter,    IMPLICIT none
4  cIM 261103  
5       .                  ts, rugos,  contains
6       .                  u,v,t,q,  
7       .                  qsurf,    SUBROUTINE coefkz(nsrf, paprs, pplay, ksta, ksta_ter, ts, u, v, t, q, zgeop, &
8       .                  pcfm, pcfh)         coefm, coefh)
9        use dimens_m  
10        use indicesol      ! Authors: F. Hourdin, M. Forichon, Z. X. Li (LMD/CNRS)
11        use dimphy      ! Date: September 22nd, 1993
12        use iniprint  
13        use SUPHEC_M      ! Objet : calculer les coefficients d'échange turbulent dans
14        use yoethf_m      ! l'atmosphère.
15        use fcttre  
16        use conf_phys_m      USE conf_phys_m, ONLY: iflag_pbl
17        IMPLICIT none      USE dimphy, ONLY: klev
18  c======================================================================      USE fcttre, ONLY: foede, foeew
19  c Auteur(s) F. Hourdin, M. Forichon, Z.X. Li (LMD/CNRS) date: 19930922      USE indicesol, ONLY: is_oce
20  c           (une version strictement identique a l'ancien modele)      USE suphec_m, ONLY: rcpd, rd, retv, rg, rkappa, rlstt, rlvtt, rtt
21  c Objet: calculer le coefficient du frottement du sol (Cdrag) et les      USE yoethf_m, ONLY: r2es, r5ies, r5les, rvtmp2
22  c        coefficients d'echange turbulent dans l'atmosphere.  
23  c Arguments:      integer, intent(in):: nsrf ! indicateur de la nature du sol
24  c nsrf-----input-I- indicateur de la nature du sol  
25  c knon-----input-I- nombre de points a traiter      REAL, intent(in):: paprs(:, :) ! (knon, klev + 1)
26  c paprs----input-R- pression a chaque intercouche (en Pa)      ! pression a chaque intercouche (en Pa)
27  c pplay----input-R- pression au milieu de chaque couche (en Pa)  
28  c ts-------input-R- temperature du sol (en Kelvin)      real, intent(in):: pplay(:, :) ! (knon, klev)
29  c rugos----input-R- longeur de rugosite (en m)      ! pression au milieu de chaque couche (en Pa)
30  c u--------input-R- vitesse u  
31  c v--------input-R- vitesse v      REAL, intent(in):: ksta, ksta_ter
32  c t--------input-R- temperature (K)      REAL, intent(in):: ts(:) ! (knon) temperature du sol (en Kelvin)
33  c q--------input-R- vapeur d'eau (kg/kg)      REAL, intent(in):: u(:, :), v(:, :) ! (knon, klev) wind
34  c      REAL, intent(in):: t(:, :) ! (knon, klev) temperature (K)
35  c itop-----output-I- numero de couche du sommet de la couche limite      real, intent(in):: q(:, :) ! (knon, klev) vapeur d'eau (kg/kg)
36  c pcfm-----output-R- coefficients a calculer (vitesse)      REAL, intent(in):: zgeop(:, :) ! (knon, klev)
37  c pcfh-----output-R- coefficients a calculer (chaleur et humidite)      REAL, intent(out):: coefm(:, 2:) ! (knon, 2:klev) coefficient, vitesse
38  c======================================================================  
39  c      real, intent(out):: coefh(:, 2:) ! (knon, 2:klev)
40  c Arguments:      ! coefficient, chaleur et humidité
41  c  
42        INTEGER knon, nsrf      ! Local:
43        REAL ts(klon)  
44        REAL paprs(klon,klev+1), pplay(klon,klev)      INTEGER knon ! nombre de points a traiter
45        REAL u(klon,klev), v(klon,klev), t(klon,klev), q(klon,klev)  
46        REAL rugos(klon)      INTEGER itop(size(ts)) ! (knon)
47  c      ! numero de couche du sommet de la couche limite
48        REAL pcfm(klon,klev), pcfh(klon,klev)  
49        INTEGER itop(klon)      ! Quelques constantes et options:
50  c  
51  c Quelques constantes et options:      REAL, PARAMETER:: cepdu2 =0.1**2
52  c      REAL, PARAMETER:: CKAP = 0.4
53        REAL cepdu2, ckap, cb, cc, cd, clam      REAL, PARAMETER:: cb = 5.
54        PARAMETER (cepdu2 =(0.1)**2)      REAL, PARAMETER:: cc = 5.
55        PARAMETER (CKAP=0.4)      REAL, PARAMETER:: cd = 5.
56        PARAMETER (cb=5.0)      REAL, PARAMETER:: clam = 160.
57        PARAMETER (cc=5.0)      REAL, PARAMETER:: ratqs = 0.05 ! largeur de distribution de vapeur d'eau
58        PARAMETER (cd=5.0)  
59        PARAMETER (clam=160.0)      LOGICAL, PARAMETER:: richum = .TRUE.
60        REAL ratqs ! largeur de distribution de vapeur d'eau      ! utilise le nombre de Richardson humide
61        PARAMETER (ratqs=0.05)  
62        LOGICAL richum ! utilise le nombre de Richardson humide      REAL, PARAMETER:: ric = 0.4 ! nombre de Richardson critique
63        PARAMETER (richum=.TRUE.)      REAL, PARAMETER:: prandtl = 0.4
64        REAL ric ! nombre de Richardson critique  
65        PARAMETER(ric=0.4)      REAL kstable ! diffusion minimale (situation stable)
66        REAL prandtl      REAL, PARAMETER:: mixlen = 35. ! constante contrôlant longueur de mélange
67        PARAMETER (prandtl=0.4)      INTEGER, PARAMETER:: isommet = klev ! sommet de la couche limite
68        REAL kstable ! diffusion minimale (situation stable)  
69        ! GKtest      LOGICAL, PARAMETER:: tvirtu = .TRUE.
70        ! PARAMETER (kstable=1.0e-10)      ! calculer Ri d'une maniere plus performante
71        REAL ksta, ksta_ter  
72  cIM: 261103     REAL kstable_ter, kstable_sinon      LOGICAL, PARAMETER:: opt_ec = .FALSE.
73  cIM: 211003 cf GK   PARAMETER (kstable_ter = 1.0e-6)      ! formule du Centre Europeen dans l'atmosphere
74  cIM: 261103     PARAMETER (kstable_ter = 1.0e-8)  
75  cIM: 261103   PARAMETER (kstable_ter = 1.0e-10)      INTEGER i, k
76  cIM: 261103   PARAMETER (kstable_sinon = 1.0e-10)      REAL zmgeom(size(ts))
77        ! fin GKtest      REAL ri(size(ts))
78        REAL mixlen ! constante controlant longueur de melange      REAL l2(size(ts))
79        PARAMETER (mixlen=35.0)      REAL zdphi, zdu2, ztvd, ztvu, cdn
80        INTEGER isommet ! le sommet de la couche limite      REAL scf
81        PARAMETER (isommet=klev)      REAL zt, zq, zcvm5, zcor, zqs, zfr, zdqs
82        LOGICAL tvirtu ! calculer Ri d'une maniere plus performante      logical zdelta
83        PARAMETER (tvirtu=.TRUE.)      REAL z2geomf, zalh2, alm2, zscfh, scfm
84        LOGICAL opt_ec ! formule du Centre Europeen dans l'atmosphere      REAL gamt(2:klev) ! contre-gradient pour la chaleur sensible: Kelvin/metre
85        PARAMETER (opt_ec=.FALSE.)  
86        !--------------------------------------------------------------------
87  c  
88  c Variables locales:      knon = size(ts)
89  c  
90        INTEGER i, k, kk !IM 120704      ! Prescrire la valeur de contre-gradient
91        REAL zgeop(klon,klev)      if (iflag_pbl.eq.1) then
92        REAL zmgeom(klon)         DO k = 3, klev
93        REAL zri(klon)            gamt(k) = - 1E-3
94        REAL zl2(klon)         ENDDO
95           gamt(2) = - 2.5E-3
96        REAL u1(klon), v1(klon), t1(klon), q1(klon), z1(klon)      else
97        REAL pcfm1(klon), pcfh1(klon)         DO k = 2, klev
98  c            gamt(k) = 0.0
99        REAL zdphi, zdu2, ztvd, ztvu, zcdn         ENDDO
100        REAL zscf      ENDIF
101        REAL zt, zq, zdelta, zcvm5, zcor, zqs, zfr, zdqs  
102        REAL z2geomf, zalh2, zalm2, zscfh, zscfm      IF (nsrf .NE. is_oce ) THEN
103        REAL t_coup         kstable = ksta_ter
104        PARAMETER (t_coup=273.15)      ELSE
105  cIM         kstable = ksta
106        LOGICAL check      ENDIF
107        PARAMETER (check=.false.)  
108  c      ! Calculer les coefficients turbulents dans l'atmosphere
109  c contre-gradient pour la chaleur sensible: Kelvin/metre  
110        REAL gamt(2:klev)      itop = isommet
111        real qsurf(klon)  
112  c      loop_vertical: DO k = 2, isommet
113        LOGICAL appel1er         loop_horiz: DO i = 1, knon
114        SAVE appel1er            zdu2 = MAX(cepdu2, (u(i, k) - u(i, k - 1))**2 &
115  c                 + (v(i, k) - v(i, k - 1))**2)
116  c Fonctions thermodynamiques et fonctions d'instabilite            zmgeom(i) = zgeop(i, k) - zgeop(i, k - 1)
117        REAL fsta, fins, x            zdphi = zmgeom(i) / 2.0
118        LOGICAL zxli ! utiliser un jeu de fonctions simples            zt = (t(i, k) + t(i, k - 1)) * 0.5
119        PARAMETER (zxli=.FALSE.)            zq = (q(i, k) + q(i, k - 1)) * 0.5
120  c  
121        fsta(x) = 1.0 / (1.0+10.0*x*(1+8.0*x))            ! calculer Qs et dQs/dT:
122        fins(x) = SQRT(1.0-18.0*x)  
123  c            zdelta = RTT >=zt
124        DATA appel1er /.TRUE./            zcvm5 = merge(R5IES * RLSTT, R5LES * RLVTT, zdelta) / RCPD &
125  c                 / (1. + RVTMP2 * zq)
126        IF (appel1er) THEN            zqs = R2ES * FOEEW(zt, zdelta) / pplay(i, k)
127          if (prt_level > 9) THEN            zqs = MIN(0.5, zqs)
128            print *,'coefkz, opt_ec:', opt_ec            zcor = 1./(1. - RETV * zqs)
129            print *,'coefkz, richum:', richum            zqs = zqs * zcor
130            IF (richum) print *,'coefkz, ratqs:', ratqs            zdqs = FOEDE(zt, zdelta, zcvm5, zqs, zcor)
131            print *,'coefkz, isommet:', isommet  
132            print *,'coefkz, tvirtu:', tvirtu            ! calculer la fraction nuageuse (processus humide):
133            appel1er = .FALSE.  
134          endif            zfr = (zq + ratqs * zq - zqs) / (2.0 * ratqs * zq)
135        ENDIF            zfr = MAX(0.0, MIN(1.0, zfr))
136  c            IF (.NOT.richum) zfr = 0.0
137  c Initialiser les sorties  
138  c            !  calculer le nombre de Richardson:
139        DO k = 1, klev  
140        DO i = 1, knon            IF (tvirtu) THEN
141           pcfm(i,k) = 0.0               ztvd = (t(i, k) &
142           pcfh(i,k) = 0.0                    + zdphi/RCPD/(1. + RVTMP2 * zq) &
143        ENDDO                    * ((1. - zfr) + zfr * (1. + RLVTT * zqs/RD/zt)/(1. + zdqs) ) &
144        ENDDO                    ) * (1. + RETV * q(i, k))
145        DO i = 1, knon               ztvu = (t(i, k - 1) &
146           itop(i) = 0                    - zdphi/RCPD/(1. + RVTMP2 * zq) &
147        ENDDO                    * ((1. - zfr) + zfr * (1. + RLVTT * zqs/RD/zt)/(1. + zdqs) ) &
148                      ) * (1. + RETV * q(i, k - 1))
149  c               ri(i) = zmgeom(i) * (ztvd - ztvu)/(zdu2 * 0.5 * (ztvd + ztvu))
150  c Prescrire la valeur de contre-gradient               ri(i) = ri(i) &
151  c                    + zmgeom(i) * zmgeom(i)/RG * gamt(k) &
152        if (iflag_pbl.eq.1) then                    * (paprs(i, k)/101325.0)**RKAPPA &
153           DO k = 3, klev                    /(zdu2 * 0.5 * (ztvd + ztvu))
154              gamt(k) = -1.0E-03            ELSE
155           ENDDO               ! calcul de Ridchardson compatible LMD5
156           gamt(2) = -2.5E-03               ri(i) = (RCPD * (t(i, k) - t(i, k - 1)) &
157        else                    - RD * 0.5 * (t(i, k) + t(i, k - 1))/paprs(i, k) &
158           DO k = 2, klev                    * (pplay(i, k) - pplay(i, k - 1)) &
159              gamt(k) = 0.0                    ) * zmgeom(i)/(zdu2 * 0.5 * RCPD * (t(i, k - 1) + t(i, k)))
160           ENDDO               ri(i) = ri(i) + &
161        ENDIF                    zmgeom(i) * zmgeom(i) * gamt(k)/RG &
162  cIM cf JLD/ GKtest                    * (paprs(i, k)/101325.0)**RKAPPA &
163        IF ( nsrf .NE. is_oce ) THEN                    /(zdu2 * 0.5 * (t(i, k - 1) + t(i, k)))
164  cIM 261103     kstable = kstable_ter            ENDIF
165          kstable = ksta_ter  
166        ELSE            ! finalement, les coefficients d'echange sont obtenus:
167  cIM 261103     kstable = kstable_sinon  
168          kstable = ksta            cdn = SQRT(zdu2) / zmgeom(i) * RG
169        ENDIF  
 cIM cf JLD/ GKtest fin  
 c  
 c Calculer les geopotentiels de chaque couche  
 c  
       DO i = 1, knon  
          zgeop(i,1) = RD * t(i,1) / (0.5*(paprs(i,1)+pplay(i,1)))  
      .                   * (paprs(i,1)-pplay(i,1))  
       ENDDO  
       DO k = 2, klev  
       DO i = 1, knon  
          zgeop(i,k) = zgeop(i,k-1)  
      .              + RD * 0.5*(t(i,k-1)+t(i,k)) / paprs(i,k)  
      .                   * (pplay(i,k-1)-pplay(i,k))  
       ENDDO  
       ENDDO  
 c  
 c Calculer le frottement au sol (Cdrag)  
 c  
       DO i = 1, knon  
        u1(i) = u(i,1)  
        v1(i) = v(i,1)  
        t1(i) = t(i,1)  
        q1(i) = q(i,1)  
        z1(i) = zgeop(i,1)  
       ENDDO  
 c  
       CALL clcdrag(klon, knon, nsrf, zxli,  
      $             u1, v1, t1, q1, z1,  
      $             ts, qsurf, rugos,  
      $             pcfm1, pcfh1)  
 cIM  $             ts, qsurf, rugos,  
 C  
       DO i = 1, knon  
        pcfm(i,1)=pcfm1(i)  
        pcfh(i,1)=pcfh1(i)  
       ENDDO  
 c  
 c Calculer les coefficients turbulents dans l'atmosphere  
 c  
       DO i = 1, knon  
          itop(i) = isommet  
       ENDDO  
   
   
       DO k = 2, isommet  
       DO i = 1, knon  
             zdu2=MAX(cepdu2,(u(i,k)-u(i,k-1))**2  
      .                     +(v(i,k)-v(i,k-1))**2)  
             zmgeom(i)=zgeop(i,k)-zgeop(i,k-1)  
             zdphi =zmgeom(i) / 2.0  
             zt = (t(i,k)+t(i,k-1)) * 0.5  
             zq = (q(i,k)+q(i,k-1)) * 0.5  
 c  
 c           calculer Qs et dQs/dT:  
 c  
             IF (thermcep) THEN  
               zdelta = MAX(0.,SIGN(1.,RTT-zt))  
               zcvm5 = R5LES*RLVTT/RCPD/(1.0+RVTMP2*zq)*(1.-zdelta)  
      .            + R5IES*RLSTT/RCPD/(1.0+RVTMP2*zq)*zdelta  
               zqs = R2ES * FOEEW(zt,zdelta) / pplay(i,k)  
               zqs = MIN(0.5,zqs)  
               zcor = 1./(1.-RETV*zqs)  
               zqs = zqs*zcor  
               zdqs = FOEDE(zt,zdelta,zcvm5,zqs,zcor)  
             ELSE  
               IF (zt .LT. t_coup) THEN  
                  zqs = qsats(zt) / pplay(i,k)  
                  zdqs = dqsats(zt,zqs)  
               ELSE  
                  zqs = qsatl(zt) / pplay(i,k)  
                  zdqs = dqsatl(zt,zqs)  
               ENDIF  
             ENDIF  
 c  
 c           calculer la fraction nuageuse (processus humide):  
 c  
             zfr = (zq+ratqs*zq-zqs) / (2.0*ratqs*zq)  
             zfr = MAX(0.0,MIN(1.0,zfr))  
             IF (.NOT.richum) zfr = 0.0  
 c  
 c           calculer le nombre de Richardson:  
 c  
             IF (tvirtu) THEN  
             ztvd =( t(i,k)  
      .             + zdphi/RCPD/(1.+RVTMP2*zq)  
      .              *( (1.-zfr) + zfr*(1.+RLVTT*zqs/RD/zt)/(1.+zdqs) )  
      .            )*(1.+RETV*q(i,k))  
             ztvu =( t(i,k-1)  
      .             - zdphi/RCPD/(1.+RVTMP2*zq)  
      .              *( (1.-zfr) + zfr*(1.+RLVTT*zqs/RD/zt)/(1.+zdqs) )  
      .            )*(1.+RETV*q(i,k-1))  
             zri(i) =zmgeom(i)*(ztvd-ztvu)/(zdu2*0.5*(ztvd+ztvu))  
             zri(i) = zri(i)  
      .             + zmgeom(i)*zmgeom(i)/RG*gamt(k)  
      .               *(paprs(i,k)/101325.0)**RKAPPA  
      .               /(zdu2*0.5*(ztvd+ztvu))  
 c  
             ELSE ! calcul de Ridchardson compatible LMD5  
 c  
             zri(i) =(RCPD*(t(i,k)-t(i,k-1))  
      .              -RD*0.5*(t(i,k)+t(i,k-1))/paprs(i,k)  
      .               *(pplay(i,k)-pplay(i,k-1))  
      .              )*zmgeom(i)/(zdu2*0.5*RCPD*(t(i,k-1)+t(i,k)))  
             zri(i) = zri(i) +  
      .             zmgeom(i)*zmgeom(i)*gamt(k)/RG  
 cSB     .             /(paprs(i,k)/101325.0)**RKAPPA  
      .             *(paprs(i,k)/101325.0)**RKAPPA  
      .             /(zdu2*0.5*(t(i,k-1)+t(i,k)))  
             ENDIF  
 c  
 c           finalement, les coefficients d'echange sont obtenus:  
 c  
             zcdn=SQRT(zdu2) / zmgeom(i) * RG  
 c  
170            IF (opt_ec) THEN            IF (opt_ec) THEN
171              z2geomf=zgeop(i,k-1)+zgeop(i,k)               z2geomf = zgeop(i, k - 1) + zgeop(i, k)
172              zalm2=(0.5*ckap/RG*z2geomf               alm2 = (0.5 * ckap/RG * z2geomf &
173       .             /(1.+0.5*ckap/rg/clam*z2geomf))**2                    /(1. + 0.5 * ckap/rg/clam * z2geomf))**2
174              zalh2=(0.5*ckap/rg*z2geomf               zalh2 = (0.5 * ckap/rg * z2geomf &
175       .             /(1.+0.5*ckap/RG/(clam*SQRT(1.5*cd))*z2geomf))**2                    /(1. + 0.5 * ckap/RG/(clam * SQRT(1.5 * cd)) * z2geomf))**2
176              IF (zri(i).LT.0.0) THEN  ! situation instable               IF (ri(i) < 0.) THEN
177                 zscf = ((zgeop(i,k)/zgeop(i,k-1))**(1./3.)-1.)**3                  ! situation instable
178       .                / (zmgeom(i)/RG)**3 / (zgeop(i,k-1)/RG)                  scf = ((zgeop(i, k)/zgeop(i, k - 1))**(1./3.) - 1.)**3 &
179                 zscf = SQRT(-zri(i)*zscf)                       / (zmgeom(i)/RG)**3 / (zgeop(i, k - 1)/RG)
180                 zscfm = 1.0 / (1.0+3.0*cb*cc*zalm2*zscf)                  scf = SQRT(- ri(i) * scf)
181                 zscfh = 1.0 / (1.0+3.0*cb*cc*zalh2*zscf)                  scfm = 1.0 / (1.0 + 3.0 * cb * cc * alm2 * scf)
182                 pcfm(i,k)=zcdn*zalm2*(1.-2.0*cb*zri(i)*zscfm)                  zscfh = 1.0 / (1.0 + 3.0 * cb * cc * zalh2 * scf)
183                 pcfh(i,k)=zcdn*zalh2*(1.-3.0*cb*zri(i)*zscfh)                  coefm(i, k) = cdn * alm2 * (1. - 2. * cb * ri(i) * scfm)
184              ELSE ! situation stable                  coefh(i, k) = cdn * zalh2 * (1. - 3.0 * cb * ri(i) * zscfh)
185                 zscf=SQRT(1.+cd*zri(i))               ELSE
186                 pcfm(i,k)=zcdn*zalm2/(1.+2.0*cb*zri(i)/zscf)                  ! situation stable
187                 pcfh(i,k)=zcdn*zalh2/(1.+3.0*cb*zri(i)*zscf)                  scf = SQRT(1. + cd * ri(i))
188              ENDIF                  coefm(i, k) = cdn * alm2 / (1. + 2. * cb * ri(i) / scf)
189                    coefh(i, k) = cdn * zalh2/(1. + 3.0 * cb * ri(i) * scf)
190                 ENDIF
191            ELSE            ELSE
192              zl2(i)=(mixlen*MAX(0.0,(paprs(i,k)-paprs(i,itop(i)+1))               l2(i) = (mixlen * MAX(0.0, (paprs(i, k) - paprs(i, itop(i) + 1)) &
193       .                          /(paprs(i,2)-paprs(i,itop(i)+1)) ))**2                    /(paprs(i, 2) - paprs(i, itop(i) + 1)) ))**2
194              pcfm(i,k)=sqrt(max(zcdn*zcdn*(ric-zri(i))/ric, kstable))               coefm(i, k) = sqrt(max(cdn**2 * (ric - ri(i)) / ric, kstable))
195              pcfm(i,k)= zl2(i)* pcfm(i,k)               coefm(i, k) = l2(i) * coefm(i, k)
196              pcfh(i,k) = pcfm(i,k) /prandtl ! h et m different               coefh(i, k) = coefm(i, k) / prandtl ! h et m different
197            ENDIF            ENDIF
198        ENDDO         ENDDO loop_horiz
199        ENDDO      ENDDO loop_vertical
200  c  
201  c Au-dela du sommet, pas de diffusion turbulente:      ! Au-delà du sommet, pas de diffusion turbulente :
202  c      forall (i = 1: knon)
203        DO i = 1, knon         coefh(i, itop(i) + 1:) = 0.
204           IF (itop(i)+1 .LE. klev) THEN         coefm(i, itop(i) + 1:) = 0.
205              DO k = itop(i)+1, klev      END forall
206                 pcfh(i,k) = 0.0  
207                 pcfm(i,k) = 0.0    END SUBROUTINE coefkz
208              ENDDO  
209           ENDIF  end module coefkz_m
       ENDDO  
 c  
       RETURN  
       END  

Legend:
Removed from v.38  
changed lines
  Added in v.249

  ViewVC Help
Powered by ViewVC 1.1.21