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

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

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

trunk/libf/phylmd/coefkz.f90 revision 47 by guez, Fri Jul 1 15:00:48 2011 UTC trunk/phylmd/Interface_surf/coefkz.f revision 288 by guez, Tue Jul 24 16:27:12 2018 UTC
# Line 4  module coefkz_m Line 4  module coefkz_m
4    
5  contains  contains
6    
7    SUBROUTINE coefkz(nsrf, knon, paprs, pplay, ksta, ksta_ter, ts, rugos, u, v, &    SUBROUTINE coefkz(nsrf, paprs, pplay, ts, u, v, t, q, zgeop, coefm, coefh)
        t, q, qsurf, pcfm, pcfh)  
8    
9      ! Authors: F. Hourdin, M. Forichon, Z.X. Li (LMD/CNRS)      ! Authors: F. Hourdin, M. Forichon, Z. X. Li (LMD/CNRS)
10      ! date: 1993/09/22      ! Date: September 22nd, 1993
     ! Objet : calculer le coefficient de frottement du sol ("Cdrag") et les  
     ! coefficients d'échange turbulent dans l'atmosphère.  
   
     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  
11    
12      ! Arguments:      ! Objet : calculer les coefficients d'échange turbulent dans
13        ! l'atmosphère.
14    
15        USE clesphys, ONLY: ksta, ksta_ter
16        USE conf_phys_m, ONLY: iflag_pbl
17        USE dimphy, ONLY: klev
18        USE fcttre, ONLY: foede, foeew
19        USE indicesol, ONLY: is_oce
20        USE suphec_m, ONLY: rcpd, rd, retv, rg, rkappa, rlstt, rlvtt, rtt
21        USE yoethf_m, ONLY: r2es, r5ies, r5les, rvtmp2
22    
23      integer, intent(in):: nsrf ! indicateur de la nature du sol      integer, intent(in):: nsrf ! indicateur de la nature du sol
     INTEGER, intent(in):: knon ! nombre de points a traiter  
24    
25      REAL, intent(in):: paprs(klon, klev+1)      REAL, intent(in):: paprs(:, :) ! (knon, klev + 1)
26      ! pression a chaque intercouche (en Pa)      ! pression a chaque intercouche (en Pa)
27    
28      real, intent(in):: pplay(klon, klev)      real, intent(in):: pplay(:, :) ! (knon, klev)
29      ! pression au milieu de chaque couche (en Pa)      ! pression au milieu de chaque couche (en Pa)
30    
31      REAL, intent(in):: ksta, ksta_ter      REAL, intent(in):: ts(:) ! (knon) temperature du sol (en Kelvin)
32      REAL, intent(in):: ts(klon) ! temperature du sol (en Kelvin)      REAL, intent(in):: u(:, :), v(:, :) ! (knon, klev) wind
33      REAL, intent(in):: rugos(klon) ! longeur de rugosite (en m)      REAL, intent(in):: t(:, :) ! (knon, klev) temperature (K)
34      REAL, intent(in):: u(klon, klev), v(klon, klev) ! wind      real, intent(in):: q(:, :) ! (knon, klev) vapeur d'eau (kg/kg)
35      REAL, intent(in):: t(klon, klev) ! temperature (K)      REAL, intent(in):: zgeop(:, :) ! (knon, klev)
36      real, intent(in):: q(klon, klev) ! vapeur d'eau (kg/kg)      REAL, intent(out):: coefm(:, 2:) ! (knon, 2:klev) coefficient, vitesse
37      real, intent(in):: qsurf(klon)  
38      REAL, intent(inout):: pcfm(klon, klev) ! coefficient, vitesse      real, intent(out):: coefh(:, 2:) ! (knon, 2:klev)
39      real, intent(inout):: pcfh(klon, klev) ! coefficient, chaleur et humidité      ! coefficient, chaleur et humidité
40    
41      ! Local:      ! Local:
42    
43      INTEGER itop(klon) ! numero de couche du sommet de la couche limite      INTEGER knon ! nombre de points a traiter
44    
45        INTEGER itop(size(ts)) ! (knon)
46        ! numero de couche du sommet de la couche limite
47    
48      ! Quelques constantes et options:      ! Quelques constantes et options:
49    
50      REAL, PARAMETER:: cepdu2 =0.1**2      REAL, PARAMETER:: cepdu2 =0.1**2
51      REAL, PARAMETER:: CKAP = 0.4      REAL, PARAMETER:: ratqs = 0.05 ! largeur de distribution de vapeur d'eau
     REAL, PARAMETER:: cb = 5.  
     REAL, PARAMETER:: cc = 5.  
     REAL, PARAMETER:: cd = 5.  
     REAL, PARAMETER:: clam = 160.  
     REAL, PARAMETER:: ratqs = 0.05 ! ! largeur de distribution de vapeur d'eau  
     LOGICAL, PARAMETER:: richum = .TRUE. ! utilise le nombre de Richardson humide  
52      REAL, PARAMETER:: ric = 0.4 ! nombre de Richardson critique      REAL, PARAMETER:: ric = 0.4 ! nombre de Richardson critique
53      REAL, PARAMETER:: prandtl = 0.4      REAL, PARAMETER:: prandtl = 0.4
54    
55      REAL kstable ! diffusion minimale (situation stable)      REAL kstable ! diffusion minimale (situation stable)
56      REAL, PARAMETER:: mixlen = 35. ! constante controlant longueur de melange      REAL, PARAMETER:: mixlen = 35. ! constante contrôlant longueur de mélange
57      INTEGER, PARAMETER:: isommet = klev ! le sommet de la couche limite      INTEGER, PARAMETER:: isommet = klev ! sommet de la couche limite
58        INTEGER i, k
59      LOGICAL, PARAMETER:: tvirtu = .TRUE.      REAL zmgeom(size(ts))
60      ! calculer Ri d'une maniere plus performante      REAL ri(size(ts))
61        REAL l2(size(ts))
62      LOGICAL, PARAMETER:: opt_ec = .FALSE.      REAL zdphi, zdu2, ztvd, ztvu, cdn
63      ! formule du Centre Europeen dans l'atmosphere      REAL zt, zq, zcvm5, zcor, zqs, zfr, zdqs
64        logical zdelta
     INTEGER i, k, kk  
     REAL zgeop(klon, klev)  
     REAL zmgeom(klon)  
     REAL zri(klon)  
     REAL zl2(klon)  
   
     REAL u1(klon), v1(klon), t1(klon), q1(klon), z1(klon)  
     REAL pcfm1(klon), pcfh1(klon)  
   
     REAL zdphi, zdu2, ztvd, ztvu, zcdn  
     REAL zscf  
     REAL zt, zq, zdelta, zcvm5, zcor, zqs, zfr, zdqs  
     REAL z2geomf, zalh2, zalm2, zscfh, zscfm  
     REAL, PARAMETER:: t_coup = 273.15  
65      REAL gamt(2:klev) ! contre-gradient pour la chaleur sensible: Kelvin/metre      REAL gamt(2:klev) ! contre-gradient pour la chaleur sensible: Kelvin/metre
66    
67      !--------------------------------------------------------------------      !--------------------------------------------------------------------
68    
69      ! Initialiser les sorties      knon = size(ts)
     DO k = 1, klev  
        DO i = 1, knon  
           pcfm(i, k) = 0.  
           pcfh(i, k) = 0.  
        ENDDO  
     ENDDO  
     DO i = 1, knon  
        itop(i) = 0  
     ENDDO  
70    
71      ! Prescrire la valeur de contre-gradient      ! Prescrire la valeur de contre-gradient
72      if (iflag_pbl.eq.1) then      if (iflag_pbl == 1) then
73         DO k = 3, klev         DO k = 3, klev
74            gamt(k) = -1.0E-03            gamt(k) = - 1E-3
75         ENDDO         ENDDO
76         gamt(2) = -2.5E-03         gamt(2) = - 2.5E-3
77      else      else
78         DO k = 2, klev         DO k = 2, klev
79            gamt(k) = 0.0            gamt(k) = 0.0
80         ENDDO         ENDDO
81      ENDIF      ENDIF
82    
83      IF ( nsrf .NE. is_oce ) THEN      kstable = merge(ksta, ksta_ter, nsrf == is_oce)
        kstable = ksta_ter  
     ELSE  
        kstable = ksta  
     ENDIF  
   
     ! Calculer les géopotentiels de chaque couche  
     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  
   
     ! Calculer le frottement au sol (Cdrag)  
   
     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  
   
     CALL clcdrag(klon, knon, nsrf, .false., u1, v1, t1, q1, z1, ts, qsurf, &  
          rugos, pcfm1, pcfh1)  
   
     DO i = 1, knon  
        pcfm(i, 1) = pcfm1(i)  
        pcfh(i, 1) = pcfh1(i)  
     ENDDO  
84    
85      ! Calculer les coefficients turbulents dans l'atmosphere      ! Calculer les coefficients turbulents dans l'atmosphere
86    
87      DO i = 1, knon      itop = isommet
        itop(i) = isommet  
     ENDDO  
88    
89      loop_vertical: DO k = 2, isommet      DO k = 2, isommet
90         loop_horiz: DO i = 1, knon         DO i = 1, knon
91            zdu2 = MAX(cepdu2, (u(i, k)-u(i, k-1))**2 &            zdu2 = MAX(cepdu2, (u(i, k) - u(i, k - 1))**2 &
92                 +(v(i, k)-v(i, k-1))**2)                 + (v(i, k) - v(i, k - 1))**2)
93            zmgeom(i) = zgeop(i, k)-zgeop(i, k-1)            zmgeom(i) = zgeop(i, k) - zgeop(i, k - 1)
94            zdphi =zmgeom(i) / 2.0            zdphi = zmgeom(i) / 2.0
95            zt = (t(i, k)+t(i, k-1)) * 0.5            zt = (t(i, k) + t(i, k - 1)) * 0.5
96            zq = (q(i, k)+q(i, k-1)) * 0.5            zq = (q(i, k) + q(i, k - 1)) * 0.5
97    
98            ! calculer Qs et dQs/dT:            ! calculer Qs et dQs/dT:
99              zdelta = RTT >=zt
100            IF (thermcep) THEN            zcvm5 = merge(R5IES * RLSTT, R5LES * RLVTT, zdelta) / RCPD &
101               zdelta = MAX(0., SIGN(1., RTT-zt))                 / (1. + RVTMP2 * zq)
102               zcvm5 = R5LES*RLVTT/RCPD/(1.0+RVTMP2*zq)*(1.-zdelta)  &            zqs = R2ES * FOEEW(zt, zdelta) / pplay(i, k)
103                    + R5IES*RLSTT/RCPD/(1.0+RVTMP2*zq)*zdelta            zqs = MIN(0.5, zqs)
104               zqs = R2ES * FOEEW(zt, zdelta) / pplay(i, k)            zcor = 1./(1. - RETV * zqs)
105               zqs = MIN(0.5, zqs)            zqs = zqs * zcor
106               zcor = 1./(1.-RETV*zqs)            zdqs = FOEDE(zt, zdelta, zcvm5, zqs, zcor)
              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  
107    
108            ! calculer la fraction nuageuse (processus humide):            ! calculer la fraction nuageuse (processus humide):
109              zfr = (zq + ratqs * zq - zqs) / (2.0 * ratqs * zq)
           zfr = (zq+ratqs*zq-zqs) / (2.0*ratqs*zq)  
110            zfr = MAX(0.0, MIN(1.0, zfr))            zfr = MAX(0.0, MIN(1.0, zfr))
           IF (.NOT.richum) zfr = 0.0  
111    
112            !  calculer le nombre de Richardson:            ! calculer le nombre de Richardson:
113              ztvd = (t(i, k) &
114            IF (tvirtu) THEN                 + zdphi/RCPD/(1. + RVTMP2 * zq) &
115               ztvd =( t(i, k) &                 * ((1. - zfr) + zfr * (1. + RLVTT * zqs/RD/zt)/(1. + zdqs)) &
116                    + zdphi/RCPD/(1.+RVTMP2*zq) &                 ) * (1. + RETV * q(i, k))
117                    *( (1.-zfr) + zfr*(1.+RLVTT*zqs/RD/zt)/(1.+zdqs) ) &            ztvu = (t(i, k - 1) &
118                    )*(1.+RETV*q(i, k))                 - zdphi/RCPD/(1. + RVTMP2 * zq) &
119               ztvu =( t(i, k-1) &                 * ((1. - zfr) + zfr * (1. + RLVTT * zqs/RD/zt)/(1. + zdqs)) &
120                    - zdphi/RCPD/(1.+RVTMP2*zq) &                 ) * (1. + RETV * q(i, k - 1))
121                    *( (1.-zfr) + zfr*(1.+RLVTT*zqs/RD/zt)/(1.+zdqs) ) &            ri(i) = zmgeom(i) * (ztvd - ztvu)/(zdu2 * 0.5 * (ztvd + ztvu))
122                    )*(1.+RETV*q(i, k-1))            ri(i) = ri(i) &
123               zri(i) =zmgeom(i)*(ztvd-ztvu)/(zdu2*0.5*(ztvd+ztvu))                 + zmgeom(i) * zmgeom(i)/RG * gamt(k) &
124               zri(i) = zri(i) &                 * (paprs(i, k)/101325.0)**RKAPPA &
125                    + zmgeom(i)*zmgeom(i)/RG*gamt(k) &                 /(zdu2 * 0.5 * (ztvd + ztvu))
                   *(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  
126    
127            ! finalement, les coefficients d'echange sont obtenus:            ! finalement, les coefficients d'echange sont obtenus:
128    
129            zcdn = SQRT(zdu2) / zmgeom(i) * RG            cdn = SQRT(zdu2) / zmgeom(i) * RG
130    
131            IF (opt_ec) THEN            l2(i) = (mixlen * MAX(0.0, (paprs(i, k) - paprs(i, itop(i) + 1)) &
132               z2geomf = zgeop(i, k-1)+zgeop(i, k)                 /(paprs(i, 2) - paprs(i, itop(i) + 1))))**2
133               zalm2 = (0.5*ckap/RG*z2geomf &            coefm(i, k) = sqrt(max(cdn**2 * (ric - ri(i)) / ric, kstable))
134                    /(1.+0.5*ckap/rg/clam*z2geomf))**2            coefm(i, k) = l2(i) * coefm(i, k)
135               zalh2 = (0.5*ckap/rg*z2geomf &            coefh(i, k) = coefm(i, k) / prandtl ! h et m different
136                    /(1.+0.5*ckap/RG/(clam*SQRT(1.5*cd))*z2geomf))**2         ENDDO
              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 loop_horiz  
     ENDDO loop_vertical  
   
     ! 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.  
              pcfm(i, k) = 0.  
           ENDDO  
        ENDIF  
137      ENDDO      ENDDO
138    
139        ! Au-delà du sommet, pas de diffusion turbulente :
140        forall (i = 1: knon)
141           coefh(i, itop(i) + 1:) = 0.
142           coefm(i, itop(i) + 1:) = 0.
143        END forall
144    
145    END SUBROUTINE coefkz    END SUBROUTINE coefkz
146    
147  end module coefkz_m  end module coefkz_m

Legend:
Removed from v.47  
changed lines
  Added in v.288

  ViewVC Help
Powered by ViewVC 1.1.21