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

Legend:
Removed from v.40  
changed lines
  Added in v.250

  ViewVC Help
Powered by ViewVC 1.1.21