SUBROUTINE stratosphere_mask(t_seri, pplay, xlat) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! ! determination of tropopause height and temperature from gridded temperature data ! ! reference: Reichler, T., M. Dameris, and R. Sausen (2003): ! modified: 6/28/06 tjr ! adapted to LMDZ by C. Kleinschmitt (2016-02-15) ! ! input: temp(nlon,nlat,nlev) 3D-temperature field ! ps(nlon,nlat) 2D-surface pressure field ! zs(nlon,nlat) 2D-surface height ! nlon grid points in x ! nlat grid points in y ! pfull(nlon,nlat,nlev) full pressure levels in Pa ! plimu upper limit for tropopause pressure ! pliml lower limit for tropopause pressure ! gamma tropopause criterion, e.g. -0.002 K/m ! ! output: tp(nlon, nlat) tropopause pressure in Pa, -999. if undefined ! ttp(nlon, nlat) tropopause temperature in K, -999. if undefined ! ztp(nlon, nlat) tropopause height in m, -999. if undefined ! tperr # of undetermined values ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! USE dimphy USE phys_local_var_mod, ONLY: stratomask #ifdef CPP_StratAer USE phys_local_var_mod, ONLY: p_tropopause #endif IMPLICIT NONE REAL,DIMENSION(klon,klev),INTENT(IN) :: t_seri ! Temperature REAL,DIMENSION(klon,klev),INTENT(IN) :: pplay ! pression pour le mileu de chaque couche (en Pa) REAL,DIMENSION(klon),INTENT(IN) :: xlat ! latitudes pour chaque point REAL, PARAMETER :: plimu=45000. REAL, PARAMETER :: pliml=7500. REAL, PARAMETER :: gamma=-0.002 LOGICAL, PARAMETER :: dofill=.true. REAL,DIMENSION(klon) :: tp, ttp, ztp REAL,DIMENSION(klev) :: t, p INTEGER :: tperr, i, k, invert, ifil REAL :: ptrp, ttrp, ztrp, psrf, zsrf, pi pi = 4.*ATAN(1.) tperr = 0 DO i=1,klon DO k=1,klev t(k)=t_seri(i,klev+1-k) p(k)=pplay(i,klev+1-k) ENDDO psrf=pplay(i,1) zsrf=0.0 call twmo(klev, t, p, psrf, zsrf, plimu, pliml, gamma, ptrp, ttrp, ztrp) tp(i)=ptrp ttp(i)=ttrp ztp(i)=ztrp IF (ptrp.lt.0.0) THEN tperr = tperr+1 ENDIF ENDDO ! fill holes IF (dofill) THEN ifil=0 DO i=1,klon IF (tp(i).lt.-990.) THEN !set missing values to very simple profile (neighbour averaging too expensive in LMDZ) tp(i)=50000.-20000.*cos(xlat(i)/360.*2.*pi) ifil=ifil+1 ENDIF ENDDO ! IF (ifil.ne.tperr) THEN CALL abort_physic('stratosphere_mask', 'inconsistency',1) ENDIF ENDIF ! DO i=1, klon DO k=1, klev IF (pplay(i,k).LT.tp(i)) THEN stratomask(i,k)=1.0 ELSE stratomask(i,k)=0.0 ENDIF ENDDO ENDDO !--this is only diagnosedd in the case of StratAer !--but it could be useful to LMDz #ifdef CPP_StratAer p_tropopause(:)=tp(:) #endif IF (ifil.gt.0) THEN print *,'Tropopause: number of undetermined values =', ifil ENDIF RETURN END SUBROUTINE stratosphere_mask !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! twmo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine twmo(level, t, p, ps, zs, plimu, pliml, gamma, ptrp, ttrp, ztrp) implicit none include "YOMCST.h" integer,intent(in) :: level real,intent(in),dimension(level):: t, p real,intent(in) :: plimu, pliml, gamma, ps, zs real,intent(out) :: ptrp, ttrp, ztrp real,parameter :: deltaz = 2000.0 real :: faktor real :: pmk, pm, a, b, tm, dtdp, dtdz, dlnp, tdlnp real :: ag, bg, ptph, ttph, a0, b0 real :: pm0, tm0, pmk0, dtdz0 real :: p2km, asum, aquer real :: pmk2, pm2, a2, b2, tm2, dtdp2, dtdz2 integer :: icount, jj, j ptrp=-999.0 ttrp=-999.0 ztrp=-999.0 faktor = -RG/R do j=level,2,-1 ! dt/dz pmk= 0.5 * (p(j-1)**rkappa+p(j)**rkappa) ! p**k at half level pm = pmk**(1./rkappa) ! p at half level a = (t(j-1)-t(j))/(p(j-1)**rkappa-p(j)**rkappa) ! dT/dp^k b = t(j)-(a*p(j)**rkappa) tm = a * pmk + b ! T at half level dtdp = a * rkappa * pm**(rkappa-1.) ! dT/dp at half level dtdz = faktor*dtdp*pm/tm ! dT/dz at half level ! dt/dz valid? if (j.eq.level) go to 999 ! no, start level, initialize first if (dtdz.le.gamma) go to 999 ! no, dt/dz < -2 K/km if (dtdz0.gt.gamma) go to 999 ! no, dt/dz below > -2 K/km if (pm.gt.plimu) go to 999 ! no, pm too low ! dtdz is valid, calculate tropopause pressure ptph ag = (dtdz-dtdz0) / (pmk-pmk0) bg = dtdz0 - (ag * pmk0) ptph = exp(log((gamma-bg)/ag)/rkappa) ! calculate temperature at this ptph assuming linear gamma ! interpolation ttph = tm0 ttph = ttph - (bg * log(pm0) + ag * (pm0**rkappa) /rkappa) / faktor*t(j) ttph = ttph + (bg * log(ptph) + ag * (ptph**rkappa)/rkappa) / faktor*t(j) if (ptph.lt.pliml) go to 999 if (ptph.gt.plimu) go to 999 ! 2nd test: dtdz above 2 km must not exceed gamma p2km = ptph + deltaz*(pm/tm)*faktor ! p at ptph + 2km asum = 0.0 ! dtdz above icount = 0 ! number of levels above ! test until apm < p2km do jj=j,2,-1 pmk2 = .5 * (p(jj-1)**rkappa+p(jj)**rkappa) ! p mean ^kappa pm2 = pmk2**(1/rkappa) ! p mean if(pm2.gt.ptph) go to 110 ! doesn't happen if(pm2.lt.p2km) go to 888 ! ptropo is valid a2 = (t(jj-1)-t(jj)) ! a a2 = a2/(p(jj-1)**rkappa-p(jj)**rkappa) b2 = t(jj)-(a2*p(jj)**rkappa) ! b tm2 = a2 * pmk2 + b2 ! T mean dtdp2 = a2 * rkappa * (pm2**(rkappa-1)) ! dt/dp dtdz2 = faktor*dtdp2*pm2/tm2 asum = asum+dtdz2 icount = icount+1 aquer = asum/float(icount) ! dt/dz mean ! discard ptropo ? if (aquer.le.gamma) go to 999 ! dt/dz above < gamma 110 continue enddo ! test next level 888 continue ! ptph is valid ptrp = ptph ttrp = ttph ! now calculate height of tropopause by integrating hypsometric equation ! from ps to ptrp ! linearly interpolate in p (results are identical to p^kappa) jj = LEVEL ! bottom do while ((P(jj).gt.PS) .or. (T(jj).lt.100)) ! T must be valid too jj=jj-1 enddo DLNP = log(PS/P(jj)) ! from surface pressure TM = T(jj) ! take TM of lowest level (better: extrapolate) TDLNP = TM*DLNP do while ( (JJ.ge.2) .and. (PTRP.lt.P(jj-1)) ) DLNP = log(P(jj)/P(jj-1)) TM = 0.5 * (T(jj) + T(jj-1)) TDLNP = TDLNP + TM*DLNP JJ=JJ-1 enddo DLNP = log(P(jj)/PTRP) ! up to tropopause pressure TM = 0.5 * (T(jj) + TTRP) ! use TTRP to get TM of this level TDLNP = TDLNP + TM*DLNP ZTRP = ZS + TDLNP*R/RG if (ZTRP .lt. 0) then print*,ZTRP print*,PS print*,P print*,T print*,ZS stop endif return 999 continue ! continue search at next higher level tm0 = tm pm0 = pm pmk0 = pmk dtdz0 = dtdz a0 = a b0 = b enddo ! no tropopouse found return end subroutine twmo