source: trunk/MESOSCALE_DEV/SRC/ARWpost/src/module_calc_cape.f90 @ 207

Last change on this file since 207 was 207, checked in by aslmd, 13 years ago

MESOSCALE: A GENERAL CLEAN-UP FOLLOWING UPDATING THE USER MANUAL. EVERYTHING ESSENTIAL IS IN MESOSCALE (much lighter than before). EVERYTHING FOR DEVELOPPERS OR EXPERTS IS IN MESOSCALE_DEV.

File size: 15.3 KB
Line 
1!! Diagnostics: CAPE / CIN / LCL / LFC
2!! Depend on 2D/3D flag send in
3!! Code originally from RIP4
4
5MODULE module_calc_cape
6
7  real, dimension(150)                                           :: buoy, zrel, benaccum
8  real, dimension(150)                                           :: psadithte, psadiprs
9  real, dimension(150,150)                                       :: psaditmk
10
11  CONTAINS
12  SUBROUTINE calc_cape(SCR4, cname, cdesc, cunits, i3dflag)
13
14!   If i3dflag=1, this routine calculates CAPE and CIN (in m**2/s**2,
15!   or J/kg) for every grid point in the entire 3D domain (treating
16!   each grid point as a parcel).  If i3dflag=0, then it
17!   calculates CAPE and CIN only for the parcel with max theta-e in
18!   the column, (i.e. something akin to Colman's MCAPE).  By "parcel",
19!   we mean a 500-m deep parcel, with actual temperature and moisture
20!   averaged over that depth.
21!
22!   In the case of i3dflag=0,
23!   MCAPE, MCIN, LCL and LFC (2D fields are calculated)
24
25
26  USE constants_module
27  USE module_model_basics
28
29  IMPLICIT NONE
30
31  !Arguments
32  real, allocatable, dimension(:,:,:,:)                          :: SCR4
33  character (len=128)                                            :: cname, cdesc, cunits
34  integer                                                        :: i3dflag
35
36  ! Local variables
37  integer                                                        :: i, j, k, kk, jt, ip, iustnlist
38  integer                                                        :: kpar, kpar1, kpar2, kmax, klev, kel
39  integer                                                        :: ilcl, klcl, klfc
40  integer                                                        :: nprs, nthte
41  real, dimension(west_east_dim,south_north_dim)                 :: ter
42  real, dimension(west_east_dim,south_north_dim,bottom_top_dim)  :: prs, tmk, ght, qvp
43  real, dimension(west_east_dim,south_north_dim,bottom_top_dim)  :: prsf, cape, cin
44  real                                                           :: ethpari, zlcl, tvenv
45  real                                                           :: p1, p2, pp1, pp2, pup, pdn
46  real                                                           :: totprs, totqvp, totthe
47  real                                                           :: eslift, ghtlift, qvplift, tmklift, tvlift
48  real                                                           :: ghtpari, prspari, qvppari, tmkpari
49  real                                                           :: tmkenv, qvpenv, tlcl
50  real                                                           :: fac1, fac2, facden, th, deltap
51  real                                                           :: benamin, davg, pavg, pressure, temp
52  real                                                           :: e, eth, ethmax, q, dz, cpm
53  character (len=20)                                             :: fname
54  logical                                                        :: is_used
55
56 
57  SCR4 = 0.0
58
59
60     ! Open psadilookup.dat     
61     DO iustnlist = 10,100
62        INQUIRE(unit=iustnlist, opened=is_used)
63        if (.not. is_used) exit
64     END DO
65     fname = 'src/psadilookup.dat'
66     OPEN (unit=iustnlist,file=fname,form='formatted',status='old')
67
68     DO i = 1,14
69       READ (iustnlist,*)
70     ENDDO
71     READ (iustnlist,*) nthte,nprs
72     IF ( nthte.ne.150 .OR. nprs.ne.150 ) then
73       PRINT*, 'Number of pressure or theta_e levels in lookup table'
74       PRINT*, '     file not = 150.  Check lookup table file.'
75       STOP
76     ENDIF
77     READ (iustnlist,173) (psadithte(jt),jt=1,nthte)
78     READ (iustnlist,173) (psadiprs(ip),ip=1,nprs)
79     READ (iustnlist,173) ((psaditmk(ip,jt),ip=1,nprs),jt=1,nthte)
80 173 FORMAT (5e15.7)
81     CLOSE (iustnlist) 
82
83
84  !! Get fields we want from the ones we have
85     ter      = HGT
86     qvp      = QV
87     prs      = PRES * 0.01                   ! pressure in hPa
88     tmk      = TK                            ! temperature in K
89     ght      = (PH+PHB) / G                  ! height in m
90
91
92  !! First calculate a pressure array on FULL SIGMA levels
93  !! Similar to the pfcalc.f routine from RIP4
94  !! Top full sigma level is ommitted
95     prsf(:,:,1) = PSFC(:,:)             !! Lowest full sigma set to surface pressure
96     DO k = 2, bottom_top_dim
97       prsf(:,:,k)=.5*(prs(:,:,k-1)+prs(:,:,k))
98     END DO
99
100     
101     cape = 0.0
102     cin  = 0.0
103
104     DO j = 1,south_north_dim          !! BIG i/j loop
105     DO i = 1,west_east_dim
106
107       IF ( i3dflag == 1 ) THEN       !! 3D case
108
109         kpar1=bottom_top_dim-1
110         kpar2=1
111
112       ELSE                           !! 2D case
113 
114!      Find parcel with max theta-e in lowest 3 km AGL.
115         ethmax = -1.
116         DO k = 1, bottom_top_dim
117           IF ( ght(i,j,k)-ter(i,j) .lt. 3000. ) THEN
118             q        = max(qvp(i,j,k),1.e-15)
119             temp     = tmk(i,j,k)
120             pressure = prs(i,j,k)
121             e        = (q*pressure)/(EPS+q)
122             tlcl     = TLCLC1/(log(temp**TLCLC2/e)-TLCLC3)+TLCLC4
123             eth  =     temp*(1000./pressure)**( GAMMA_RIP*(1.+GAMMAMD*q) )*     &
124                        exp( (THTECON1/tlcl-THTECON2)*q*(1.+THTECON3*q) )
125             IF ( eth .gt. ethmax ) THEN
126               klev=k
127               ethmax=eth
128             END IF
129           END IF
130         END DO
131         kpar1=klev
132         kpar2=klev
133 
134!      Establish average properties of that parcel
135!      (over depth of approximately davg meters)
136         davg = 500.
137         pavg = davg*prs(i,j,kpar1)*G /                        &
138                ( Rd*virtual(tmk(i,j,kpar1),qvp(i,j,kpar1)) )
139         p2 = min(prs(i,j,kpar1)+.5*pavg,prsf(i,j,1))
140         p1 = p2-pavg
141         totthe = 0.
142         totqvp = 0.
143         totprs = 0.
144         DO k = 1,bottom_top_dim-1
145           IF ( prsf(i,j,k)   .le. p1 ) GOTO 35
146           IF ( prsf(i,j,k+1) .ge. p2 ) GOTO 34
147           pressure = prs(i,j,k)
148           pup      = prsf(i,j,k)
149           pdn      = prsf(i,j,k+1)
150           q        = max(qvp(i,j,k),1.e-15)
151           th       = tmk(i,j,k)*(1000./pressure)**(GAMMA_RIP*(1.+GAMMAMD*q))
152           pp1      = max(p1,pdn)
153           pp2      = min(p2,pup)
154           IF ( pp2 .gt. pp1 ) THEN
155             deltap = pp2-pp1
156             totqvp = totqvp+q*deltap
157             totthe = totthe+th*deltap
158             totprs = totprs+deltap
159           END IF
160 34        CONTINUE
161         END DO
162 35      CONTINUE
163         qvppari = totqvp/totprs
164         tmkpari = (totthe/totprs)*(prs(i,j,kpar1)/1000.)**    &
165                   (GAMMA_RIP*(1.+GAMMAMD*qvp(i,j,kpar1)))
166       ENDIF
167
168       !!!   END of 2D / 3D specific bits
169
170
171       DO kpar = kpar1,kpar2,-1                      !! This loop is done for both 2D / 3D
172 
173!   Calculate temperature and moisture properties of parcel
174
175         IF ( i3dflag == 1 ) THEN    ! (Note, qvppari and tmkpari already calculated above for 2D case.)
176           qvppari = qvp(i,j,kpar)
177           tmkpari = tmk(i,j,kpar)
178         END IF
179         prspari = prs(i,j,kpar)
180         ghtpari = ght(i,j,kpar)
181         cpm     = cp*(1.+CPMD*qvppari)
182 
183         e       = max(1.e-20,qvppari*prspari/(EPS+qvppari))
184         tlcl    = TLCLC1/(log(tmkpari**TLCLC2/e)-TLCLC3)+TLCLC4
185         ethpari = tmkpari*(1000./prspari)**(GAMMA_RIP*(1.+GAMMAMD*qvppari))*   &
186                   exp((THTECON1/tlcl-THTECON2)*qvppari*                    &
187                   (1.+THTECON3*qvppari))
188         zlcl    = ghtpari+(tmkpari-tlcl)/(G/cpm)
189
190!   Calculate buoyancy and relative height of lifted parcel at
191!   all levels, and store in bottom up arrays.  Add a level at the LCL,
192!   and at all points where buoyancy is zero.
193 
194         kk = 0                    ! for arrays that go bottom to top
195         ilcl = 0
196         IF ( ghtpari .ge. zlcl ) THEN
197           !! initial parcel already saturated or supersaturated.
198           ilcl = 2
199           klcl = 1
200         END IF
201
202         DO k = kpar,bottom_top_dim
203 33        kk=kk+1                ! for arrays that go bottom to top
204
205           IF ( ght(i,j,k) .lt. zlcl ) THEN ! model level is below LCL
206             qvplift = qvppari
207             tmklift = tmkpari-G/cpm*(ght(i,j,k)-ghtpari)
208             tvenv   = virtual(tmk(i,j,k),qvp(i,j,k))
209             tvlift  = virtual(tmklift,qvplift)
210             ghtlift = ght(i,j,k)
211           ELSE IF ( ght(i,j,k) .ge. zlcl .AND. ilcl .eq. 0 ) THEN
212             !! This model level and previous model level straddle the LCL,
213             !! so first create a new level in the bottom-up array, at the LCL.
214             tmklift = tlcl
215             qvplift = qvppari
216             facden  = ght(i,j,k)-ght(i,j,k-1)
217             fac1    = (zlcl-ght(i,j,k-1))/facden
218             fac2    = (ght(i,j,k)-zlcl)/facden
219             tmkenv  = tmk(i,j,k-1)*fac2+tmk(i,j,k)*fac1
220             qvpenv  = qvp(i,j,k-1)*fac2+qvp(i,j,k)*fac1
221             tvenv   = virtual(tmkenv,qvpenv)
222             tvlift  = virtual(tmklift,qvplift)
223             ghtlift = zlcl
224             ilcl    = 1
225           ELSE
226             tmklift = tonpsadiabat(ethpari,prs(i,j,k))                               
227             eslift  = EZERO*exp(eslcon1*(tmklift-CELKEL)/    &
228                       (tmklift-eslcon2))
229             qvplift = EPS*eslift/(prs(i,j,k)-eslift)
230             tvenv   = virtual(tmk(i,j,k),qvp(i,j,k))
231             tvlift  = virtual(tmklift,qvplift)
232             ghtlift = ght(i,j,k)
233           END IF
234
235           buoy(kk) = G*(tvlift-tvenv)/tvenv  ! buoyancy
236           zrel(kk) = ghtlift-ghtpari
237
238           IF ( (buoy(kk)*buoy(kk-1).lt.0.0) .AND. (kk.gt.1) ) THEN
239             !! Parcel ascent curve crosses sounding curve, so create a new level
240             !! in the bottom-up array at the crossing.
241             kk = kk+1
242             buoy(kk)   = buoy(kk-1)
243             zrel(kk)   = zrel(kk-1)
244             buoy(kk-1) = 0.
245             zrel(kk-1) = zrel(kk-2) + buoy(kk-2)/(buoy(kk-2)-buoy(kk))*  &
246                          (zrel(kk)-zrel(kk-2))
247           END IF
248
249           IF (ilcl == 1) THEN
250             klcl = kk
251             ilcl = 2
252             GOTO 33
253           END IF
254
255         END DO         !! END DO k = kpar,bottom_top_dim
256
257         kmax = kk
258         IF (kmax .gt. 150) THEN
259           PRINT*, 'in calc_cape: kmax got too big. kmax=',kmax
260           STOP
261         ENDIF
262
263 
264!        Get the accumulated buoyant energy from the parcel's starting
265!        point, at all levels up to the top level.
266
267         benaccum(1) = 0.0
268         benamin     = 9e9
269         DO k = 2,kmax
270           dz          = zrel(k)-zrel(k-1)
271           benaccum(k) = benaccum(k-1)+.5*dz*(buoy(k-1)+buoy(k))
272             IF ( benaccum(k) .lt. benamin ) THEN
273               benamin = benaccum(k)
274             END IF
275         END DO
276
277
278!        Determine equilibrium level (EL), which we define as the highest
279!        level of non-negative buoyancy above the LCL. Note, this may be
280!        the top level if the parcel is still buoyant there.
281
282         DO k = kmax,klcl,-1
283           IF ( buoy(k) .ge. 0. ) THEN
284             kel = k   ! k of equilibrium level
285             GOTO 50
286           END IF
287         END DO
288
289
290!        If we got through that loop, then there is no non-negative
291!        buoyancy above the LCL in the sounding.  In these situations,
292!        both CAPE and CIN will be set to -0.1 J/kg.  Also, where CAPE is
293!        non-zero, CAPE and CIN will be set to a minimum of +0.1 J/kg, so
294!        that the zero contour in either the CIN or CAPE fields will
295!        circumscribe regions of non-zero CAPE.
296 
297         cape(i,j,kpar) = -0.1
298         cin(i,j,kpar)  = -0.1
299         klfc = kmax
300 
301         GOTO 102
302 
303 50      CONTINUE
304
305 
306
307!        If there is an equilibrium level, then CAPE is positive.  We'll
308!        define the level of free convection (LFC) as the point below the
309!        EL, but at or above the LCL, where accumulated buoyant energy is a
310!        minimum.  The net positive area (accumulated buoyant energy) from
311!        the LFC up to the EL will be defined as the CAPE, and the net
312!        negative area (negative of accumulated buoyant energy) from the
313!        parcel starting point to the LFC will be defined as the convective
314!        inhibition (CIN).
315 
316!        First get the LFC according to the above definition.
317 
318         benamin = 9e9
319         klfc = kmax
320         DO k = klcl,kel
321           IF ( benaccum(k) .lt. benamin ) THEN
322             benamin = benaccum(k)
323             klfc = k
324           END IF
325         END DO
326 
327!        Now we can assign values to cape and cin
328 
329         cape(i,j,kpar) = max(benaccum(kel)-benamin,0.1)
330         cin(i,j,kpar)  = max(-benamin,0.1)
331 
332!        CIN is uninteresting when CAPE is small (< 100 J/kg), so set
333!        CIN to -.1 in that case.
334 
335         IF ( cape(i,j,kpar) .lt. 100. ) cin(i,j,kpar) = -0.1
336
337 102     CONTINUE
338
339       ENDDO          !! END of BIG 2D/3D loop
340
341
342       IF ( i3dflag == 0 ) THEN
343         SCR4(i,j,1,1) = cape(i,j,kpar1)
344         SCR4(i,j,1,2) = cin(i,j,kpar1)
345         SCR4(i,j,1,3) = zrel(klcl)+ghtpari-ter(i,j)   ! meters AGL (LCL)
346         SCR4(i,j,1,4) = zrel(klfc)+ghtpari-ter(i,j)   ! meters AGL (LFC)
347       ENDIF
348
349 
350     END DO
351     END DO                !! END BIG i/j loop
352 
353
354  !! These will be set by module_diagnostics as we have more than 1 field
355
356  IF ( i3dflag == 1 ) THEN
357    SCR4(:,:,:,1) = cape(:,:,:)
358    SCR4(:,:,:,2) = cin(:,:,:)
359  ENDIF
360
361  cname    = " "
362  cdesc    = " "
363  cunits   = " "
364 
365
366  END SUBROUTINE calc_cape
367
368
369!*********************************************************************c
370!*********************************************************************c
371  FUNCTION tonpsadiabat (thte,prs)
372 
373!   This function gives the temperature (in K) on a moist adiabat
374!   (specified by thte in K) given pressure in hPa.  It uses a
375!   lookup table, with data that was generated by the Bolton (1980)
376!   formula for theta_e.
377
378 
379!     First check if pressure is less than min pressure in lookup table.
380!     If it is, assume parcel is so dry that the given theta-e value can
381!     be interpretted as theta, and get temperature from the simple dry
382!     theta formula.
383 
384      IF ( prs .lt. psadiprs(150) ) THEN
385        tonpsadiabat = thte*(prs/1000.)**GAMMA_RIP
386        RETURN
387      ENDIF
388 
389
390!     Otherwise, look for the given thte/prs point in the lookup table.
391 
392      DO jtch = 1,150-1
393        IF ( thte.ge.psadithte(jtch) .AND. thte.lt.psadithte(jtch+1) ) THEN
394          jt = jtch
395          GOTO 213
396        END IF
397      END DO
398      jt = -1
399 213  CONTINUE
400
401      DO ipch = 1,150-1
402        if ( prs.le.psadiprs(ipch) .AND. prs.gt.psadiprs(ipch+1) ) THEN
403          ip = ipch
404          GOTO 215
405        END IF
406      ENDDO
407      ip = -1
408 215  CONTINUE
409
410
411      IF ( jt.eq.-1 .OR. ip.eq.-1 ) THEN
412        PRINT*, 'Outside of lookup table bounds. prs,thte=',prs,thte
413        STOP
414      ENDIF
415
416
417      fracjt  = (thte-psadithte(jt))/(psadithte(jt+1)-psadithte(jt))
418      fracjt2 = 1.-fracjt
419      fracip  = (psadiprs(ip)-prs)/(psadiprs(ip)-psadiprs(ip+1))
420      fracip2 = 1.-fracip
421
422      IF ( psaditmk(ip,jt  ).gt.1e9 .OR. psaditmk(ip+1,jt  ).gt.1e9 .OR.   &
423           psaditmk(ip,jt+1).gt.1e9 .OR. psaditmk(ip+1,jt+1).gt.1e9 ) THEN
424        PRINT*, 'Tried to access missing tmperature in lookup table.'
425        PRINT*, 'Prs and Thte probably unreasonable. prs,thte=',prs,thte
426        STOP
427      ENDIF
428
429      tonpsadiabat = fracip2*fracjt2*psaditmk(ip  ,jt  )+   &
430                     fracip *fracjt2*psaditmk(ip+1,jt  )+   &
431                     fracip2*fracjt *psaditmk(ip  ,jt+1)+   &
432                     fracip *fracjt *psaditmk(ip+1,jt+1)
433     
434
435  END FUNCTION tonpsadiabat
436
437
438END MODULE module_calc_cape
Note: See TracBrowser for help on using the repository browser.