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

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

  ViewVC Help
Powered by ViewVC 1.1.21