1 ! This module is used to diagnose the location of the tropopause.
2 ! Two routines are specifed, a primary routine (twmo) which is tried first
3 ! and a backup routine (climate) which will be tried only if the first routine fails.
4 ! If the tropopause can not be identified by either routine, then a NOTFOUND is returned.
6 ! These routines are based upon code in the WACCM chemistry module
7 ! including mo_tropoause.F90 and llnl_set_chem_trop.F90. The code
8 ! for the Reichler et al. [2003] algorithm is from:
10 ! http://www.gfdl.noaa.gov/~tjr/TROPO/tropocode.htm
15 module module_tropopause
21 public :: tropopause_init
22 public :: tropopause_driver
26 integer, parameter :: r8 = selected_real_kind(12)
28 real(r8), parameter :: pi =3.14159265358979323846_r8
29 real(r8), parameter :: mb2Pa = 100._r8
30 real(r8), parameter :: d2r = pi/180._r8
31 real(r8), parameter :: zero = 0._r8
32 real(r8), parameter :: twopi = pi*2._r8
34 integer, parameter :: NOTFOUND = -1
39 integer :: tropo_month_n ! # of month in tropopause file
40 integer :: tropo_lon_n ! # of lon in tropopause file
41 integer :: tropo_lat_n ! # of lat in tropopause file
44 real(r8), pointer :: tropo_p_loc(:,:,:) ! climatological tropopause pressures(Pa)
46 logical :: is_allocated
49 type(tropo_type), allocatable :: tropo_bc(:)
52 ! These constants are set in module variables rather than as parameters
53 ! to support the aquaplanet mode in which the constants have values determined
54 ! by the experiment protocol
56 real(r8),parameter :: CONST_BOLTZ = 1.38065e-23_r8 ! Boltzmann's constant ~ J/K/molecule
57 real(r8),parameter :: CONST_AVOGAD = 6.02214e26_r8 ! Avogadro's number ~ molecules/kmole
58 real(r8),parameter :: CONST_RGAS = CONST_AVOGAD*CONST_BOLTZ ! Universal gas constant ~ J/K/kmole
59 real(r8),parameter :: CONST_MWDAIR = 28.966_r8 ! molecular weight dry air ~ kg/kmole
60 real(r8),parameter :: CONST_RDAIR = CONST_RGAS/CONST_MWDAIR ! Dry air gas constant ~ J/K/kg
61 real(r8),parameter :: CONST_CPDAIR = 1.00464e3_r8 ! specific heat of dry air ~ J/kg/K
63 real(r8),parameter :: gravit = 9.80616_r8
64 real(r8),parameter :: rair = CONST_RDAIR
65 real(r8),parameter :: cappa = CONST_RDAIR/CONST_CPDAIR !R/CP
67 real(r8),parameter :: cnst_kap = cappa
68 real(r8),parameter :: cnst_faktor = -gravit/rair
69 real(r8),parameter :: cnst_ka1 = cnst_kap - 1._r8
73 subroutine tropopause_driver( id, dtstep, current_date_char, &
74 t_phy, p_phy, p8w, zmid, z8w, &
75 tropo_lev, tropo_p, tropo_z, &
76 ids, ide, jds, jde, kds, kde, &
77 ims, ime, jms, jme, kms, kme, &
78 its, ite, jts, jte, kts, kte )
82 !----------------------------------------------------
84 !----------------------------------------------------
85 integer, intent(in ) :: id, &
86 ids,ide, jds,jde, kds,kde, &
87 ims,ime, jms,jme, kms,kme, &
88 its,ite, jts,jte, kts,kte
90 real, intent(in ) :: dtstep
92 real, dimension( ims:ime, kms:kme, jms:jme ), &
93 intent(in ) :: t_phy, & ! t at mid-level
94 p_phy, & ! p at mid_level (Pa)
95 zmid, & ! z at mid_level (meters)
96 z8w, & ! z at interface (meters)
97 p8w ! p at interface (Pa)
99 real, dimension( ims:ime, jms:jme ), &
100 intent(inout) :: tropo_p, & ! tropopause pressure (Pa)
101 tropo_z ! tropopause height (meters)
102 integer, dimension( ims:ime, jms:jme ), &
103 intent(inout) :: tropo_lev ! tropopause level
105 CHARACTER (LEN=256),intent(in) :: current_date_char
106 !----------------------------------------------------
108 !----------------------------------------------------
112 !----------------------------------------------------
113 !----------------------------------------------------
114 ! ... tile dimensions, needed for nest domains
115 !----------------------------------------------------
116 iend = min(ite,ide-1)
117 jend = min(jte,jde-1)
119 tropo_lev(its:iend,jts:jend) = NOTFOUND
121 ! -- This is the primary routine
123 call tropopause_twmo (id, t_phy, p_phy, p8w, zmid, z8w, &
124 tropo_lev, tropo_p, tropo_z, &
125 ids,ide, jds,jde, kds,kde, &
126 ims,ime, jms,jme, kms,kme, &
127 its,ite, jts,jte, kts,kte )
129 ! -- This is the backup routine
131 if ( any(tropo_lev(its:iend,jts:jend) == NOTFOUND) ) then
133 call tropopause_climate (id, current_date_char, &
134 p_phy, p8w, zmid, z8w, &
135 tropo_lev, tropo_p, tropo_z, &
136 ids,ide, jds,jde, kds,kde, &
137 ims,ime, jms,jme, kms,kme, &
138 its,ite, jts,jte, kts,kte )
141 end subroutine tropopause_driver
143 !===========================================================================
145 subroutine tropopause_init (id, xlat, xlon, config_flags, &
146 ids,ide, jds,jde, kds,kde, &
147 ims,ime, jms,jme, kms,kme, &
148 its,ite, jts,jte, kts,kte )
149 !---------------------------------------------------------------------
150 ! ... new initialization routine for tropopause
151 !---------------------------------------------------------------------
152 use module_interpolate, only : lininterp_init, lininterp, interp_type, lininterp_finish
153 use module_configure, only : grid_config_rec_type
157 !---------------------------------------------------------------------
158 ! ... dummy arguments
159 !---------------------------------------------------------------------
160 integer, intent(in) :: id, &
161 ids,ide, jds,jde, kds,kde, &
162 ims,ime, jms,jme, kms,kme, &
163 its,ite, jts,jte, kts,kte
165 real, intent(in) :: xlat(ims:ime, jms:jme)
166 real, intent(in) :: xlon(ims:ime, jms:jme)
167 type(grid_config_rec_type), intent(in) :: config_flags
169 !---------------------------------------------------------------------
170 ! ... local variables
171 !---------------------------------------------------------------------
173 type(interp_type) :: lon_wgts, lat_wgts
184 integer :: dimid_month
187 character(len=128) :: err_msg
188 character(len=64) :: filename
189 character(len=3) :: id_num
191 character(len=80) :: attribute
193 real(r8), allocatable :: tropo_p_in(:,:,:) ! values of pressure levels (Pa) in tropopause file
194 real(r8), allocatable :: tropo_lat(:) ! values of lat (-90~90)in tropopause file
195 real(r8), allocatable :: tropo_lon(:) ! values of lon (0~360) in tropopause file
197 real(r8) :: wrf_lon(1) ! to match kind, values of lon (0~360)
198 real(r8) :: wrf_lat(1) ! input to lininterp_init needs to be an array, not scalar
199 real(r8) :: tmp_out(1)
202 CHARACTER(LEN=132) :: message
204 LOGICAL , EXTERNAL :: wrf_dm_on_monitor
207 !---------------------------------------------------------------------
208 ! ... tile dimensions
209 !---------------------------------------------------------------------
210 iend = min(ite,ide-1)
211 jend = min(jte,jde-1)
213 !---------------------------------------------------------------------
214 ! ... allocate tropo_bc
215 !---------------------------------------------------------------------
216 if( id == 1 .and. .not. allocated(tropo_bc) ) then
217 CALL nl_get_max_dom( 1,max_dom )
219 allocate(tropo_bc(max_dom),stat=astat )
220 if( astat /= 0 ) then
221 CALL wrf_message( 'tropopause_init: failed to allocate tropo_bc' )
225 tropo_bc(:)%is_allocated = .false.
228 tropo_bc_allocated : &
229 if( .not. tropo_bc(id)%is_allocated ) then
231 !---------------------------------------------------------------------
232 !... allocate tropo_bc type
233 !--------------------------------------------------------------------
236 IF( wrf_dm_on_monitor() ) THEN
237 write(id_num,'(i3)') 100+id
238 write(message,*) 'tropopause_init: intializing domain ' // id_num(2:3)
239 call wrf_message( trim(message) )
241 !---------------------------------------------------------------------
242 ! ... open climate tropopause netcdf file
243 !---------------------------------------------------------------------
244 ! filename = 'clim_p_trop.nc'
245 filename = config_flags%trop_lev_inname
246 if( filename == ' ' ) then
247 call wrf_message( 'tropopause_init: input filename not specified in namelist' )
251 err_msg = 'tropopause_init: failed to open file ' // trim(filename)
252 call handle_ncerr( nf_open( trim(filename), nf_noclobber, ncid ), trim(err_msg) )
253 write(message,*) 'tropopause_init: open filename= ',filename
254 call wrf_message( trim(message) )
255 !---------------------------------------------------------------------
257 !---------------------------------------------------------------------
258 err_msg = 'tropopause_init: failed to get time id'
259 call handle_ncerr( nf_inq_dimid( ncid, 'time', dimid_month ), trim(err_msg) )
260 err_msg = 'tropopause_init: failed to get time'
261 call handle_ncerr( nf_inq_dimlen( ncid, dimid_month, tropo_month_n ), trim(err_msg) )
262 if( tropo_month_n /= 12 )then
263 write(message,*) 'tropopause_init: number of months = ',tropo_month_n,'; expecting 12'
264 call wrf_message( trim(message) )
268 err_msg = 'tropopause_init: failed to get lat id'
269 call handle_ncerr( nf_inq_dimid( ncid, 'lat', dimid_lat ), trim(err_msg) )
270 err_msg = 'tropopause_init: failed to get lat'
271 call handle_ncerr( nf_inq_dimlen( ncid, dimid_lat, tropo_lat_n ), trim(err_msg) )
273 err_msg = 'tropopause_init: failed to get lon id'
274 call handle_ncerr( nf_inq_dimid( ncid, 'lon', dimid_lon ), trim(err_msg) )
275 err_msg = 'tropopause_init: failed to get lon'
276 call handle_ncerr( nf_inq_dimlen( ncid, dimid_lon, tropo_lon_n ), trim(err_msg) )
279 !---------------------------------------------------------------------
280 ! ... bcast the dimensions
281 !---------------------------------------------------------------------
283 CALL wrf_dm_bcast_integer ( tropo_month_n , 1 )
284 CALL wrf_dm_bcast_integer ( tropo_lat_n , 1 )
285 CALL wrf_dm_bcast_integer ( tropo_lon_n , 1 )
288 !---------------------------------------------------------------------
289 ! ... allocate local arrays
290 !---------------------------------------------------------------------
292 allocate( tropo_lat(tropo_lat_n), stat=astat )
293 if( astat /= 0 ) then
294 call wrf_message( 'tropopause_init: failed to allocate tropo_lat' )
298 allocate( tropo_lon(tropo_lon_n), stat=astat )
299 if( astat /= 0 ) then
300 call wrf_message( 'tropopause_init: failed to allocate tropo_lon' )
304 allocate( tropo_p_in(tropo_lon_n,tropo_lat_n,tropo_month_n), stat=astat )
305 if( astat /= 0 ) then
306 call wrf_message( 'tropopause_init: failed to allocate tropo_p_in' )
310 !---------------------------------------------------------------------
311 ! ... allocate tropo_bc(id) component arrays
312 !---------------------------------------------------------------------
314 allocate( tropo_bc(id)%tropo_p_loc(its:iend,jts:jend,tropo_month_n), stat=astat )
315 if( astat /= 0 ) then
316 call wrf_message( 'tropopause_init: failed to allocate tropo_bc(id)%tropo_p_loc' )
320 tropo_bc(id)%is_allocated = .true.
322 !---------------------------------------------------------------------
324 !---------------------------------------------------------------------
326 IF ( wrf_dm_on_monitor() ) THEN
327 !---------------------------
329 err_msg = 'tropopause_init: failed to get lat variable id'
330 call handle_ncerr( nf_inq_varid( ncid, 'lat', varid ), trim(err_msg) )
331 err_msg = 'tropopause_init: failed to read lat variable'
332 call handle_ncerr( nf_get_var_double( ncid, varid, tropo_lat ), trim(err_msg) )
335 tropo_lat(:) = tropo_lat(:) * d2r
337 !---------------------------
339 err_msg = 'tropopause_init: failed to get lon variable id'
340 call handle_ncerr( nf_inq_varid( ncid, 'lon', varid ), trim(err_msg) )
341 err_msg = 'tropopause_init: failed to read lon variable'
342 call handle_ncerr( nf_get_var_double( ncid, varid, tropo_lon ), trim(err_msg) )
344 !-------- check unit and note: 0-360 degree
345 tropo_lon(:) = tropo_lon(:) * d2r
346 !---------------------------
348 err_msg = 'tropopause_init: failed to get trop_p variable id'
349 call handle_ncerr( nf_inq_varid( ncid, 'trop_p', varid ), trim(err_msg) )
353 err_msg = 'tropopause_init: failed to get ndims of trop_p variable'
354 call handle_ncerr( nf_inq_varndims( ncid, varid, ndims ), trim(err_msg) )
356 if( ndims /= 3 ) then
357 write(message,*) 'tropopause_init: error! variable trop_p has ndims = ',ndims,', expecting 3'
358 call wrf_message( trim(message) )
362 err_msg = 'tropopause_init: failed to get dimid of vmr variable'
363 call handle_ncerr( nf_inq_vardimid( ncid, varid, dimid ), trim(err_msg) )
365 if( dimid(1) /= dimid_lon .or. dimid(2) /= dimid_lat .or. &
366 dimid(3) /= dimid_month )then
367 write(message,*) 'tropopause_init: error! dimensions in wrong order for variable trop_p,'// &
368 'expecting (lon,lat,month)'
369 call wrf_message( trim(message) )
373 !------------------------------------------------------------------
374 ! ... read in the tropo_p_in values
375 !------------------------------------------------------------------
376 err_msg = 'tropopause_init: failed to read trop_p variable'
377 call handle_ncerr( nf_get_var_double( ncid, varid, tropo_p_in ), trim(err_msg) )
379 !---------------------------------------------------------------------
380 !... close input netcdf file
381 !---------------------------------------------------------------------
382 err_msg = 'tropopause_init: failed to close file ' // trim(filename)
383 call handle_ncerr( nf_close( ncid ), trim(err_msg) )
387 !---------------------------------------------------------------------
388 ! ... bcast the variables
389 !---------------------------------------------------------------------
391 CALL wrf_dm_bcast_double ( tropo_lat, size(tropo_lat) )
392 CALL wrf_dm_bcast_double ( tropo_lon, size(tropo_lon) )
393 CALL wrf_dm_bcast_double ( tropo_p_in, size(tropo_p_in) )
396 !------------------------------------------------------------------
397 ! ... linear interpolation from tropo_p_in to tropo_p_loc
398 !------------------------------------------------------------------
399 !-------------------------------------
400 !... get wrf_lat_1d and wrf_lon_1d
401 !... note: grid%XLAT(ide,:) =0.
402 !... note: grid%XLONG(:,jde) =0.
403 !... => iend = min(ite,ide-1)
404 ! jend = min(jte,jde-1)
405 !-------------------------------------
407 !-------------------------------------------
408 !... for every point in the tile
409 !-------------------------------------------
411 do j = jts,jend ! input to lininterp_init needs to be an array, not scalar
412 !-------------------------------------------
413 !... from degrees to radians
414 !-------------------------------------------
415 wrf_lat(1) = xlat(i,j)*d2r
417 wrf_lon(1) = xlon(i,j)
418 if( wrf_lon(1) < 0.0_r8 ) wrf_lon(1) = wrf_lon(1) + 360.0_r8
419 wrf_lon(1) = wrf_lon(1)*d2r
421 !-------------------------------------
422 !...initialization interp routine
423 !-------------------------------------
424 call lininterp_init( tropo_lon, tropo_lon_n, wrf_lon, 1, 2, lon_wgts, zero, twopi )
425 call lininterp_init( tropo_lat, tropo_lat_n, wrf_lat, 1, 1, lat_wgts )
427 !-------------------------------------
428 !... linear interpolation
429 !-------------------------------------
430 do m = 1,tropo_month_n
431 call lininterp( tropo_p_in(:,:,m), tropo_lon_n, tropo_lat_n, &
432 tmp_out, 1 , lon_wgts, lat_wgts)
433 tropo_bc(id)%tropo_p_loc(i,j,m) = tmp_out(1)
439 call lininterp_finish( lon_wgts )
440 call lininterp_finish( lat_wgts )
442 deallocate(tropo_lon)
443 deallocate(tropo_lat)
444 deallocate(tropo_p_in)
446 call wrf_message( ' ' )
447 write(message,*) 'tropopause_init: DONE intialized domain ',id
448 call wrf_message( trim(message) )
449 call wrf_message( ' ' )
451 endif tropo_bc_allocated
453 end subroutine tropopause_init
455 !===========================================================================
457 subroutine handle_ncerr( ret, mes )
458 !---------------------------------------------------------------------
459 ! ... netcdf error handling routine
460 !---------------------------------------------------------------------
464 !---------------------------------------------------------------------
465 ! ... dummy arguments
466 !---------------------------------------------------------------------
467 integer, intent(in) :: ret
468 character(len=*), intent(in) :: mes
472 if( ret /= nf_noerr ) then
473 call wrf_message( trim(mes) )
474 call wrf_message( trim(nf_strerror(ret)) )
478 end subroutine handle_ncerr
480 !===========================================================================
482 ! This routine uses an implementation of Reichler et al. [2003] done by
483 ! Reichler and downloaded from his web site. This is similar to the WMO
484 ! routines, but is designed for GCMs with a coarse vertical grid.
486 subroutine tropopause_twmo (id, t_phy, p_phy, p8w, zmid, z8w, &
487 tropo_lev, tropo_p,tropo_z, &
488 ids,ide, jds,jde, kds,kde, &
489 ims,ime, jms,jme, kms,kme, &
490 its,ite, jts,jte, kts,kte )
493 !----------------------------------------------------
495 !----------------------------------------------------
496 integer, intent(in) :: id, &
497 ids,ide, jds,jde, kds,kde, &
498 ims,ime, jms,jme, kms,kme, &
499 its,ite, jts,jte, kts,kte
501 real, dimension( ims:ime , kms:kme , jms:jme ), &
502 intent(in) :: t_phy, & ! t at mid-level
503 p_phy, & ! p at mid_level (Pa)
504 zmid, & ! z at mid_level (meters)
505 z8w, & ! z at interface (meters)
506 p8w ! p at interface (Pa)
508 real, dimension( ims:ime, jms:jme ), &
509 intent(inout) :: tropo_p, & ! tropopause pressure (Pa)
510 tropo_z ! tropopause height (meters)
511 integer, dimension( ims:ime, jms:jme ), &
512 intent(inout) :: tropo_lev ! tropopause level
513 !----------------------------------------------------
515 !----------------------------------------------------
516 real, dimension( kts:kte) :: t_temp ! store t from top to bottom
517 real, dimension( kts:kte) :: p_temp ! store p from top to bottom
519 real(r8), parameter :: gamma = -0.002_r8 ! K/m
520 real(r8), parameter :: plimu = 45000._r8 ! Pa
521 real(r8), parameter :: pliml = 7500._r8 ! Pa
529 real(r8) :: tP ! tropopause pressure (Pa)
531 !----------------------------------------------------
535 ! Iterate over all of the grids.
539 ! subroutine twmo expects variables from top to bottom
540 ! t_phy and p_phy are from bottom to top
544 t_temp(kk) = t_phy(i,k,j)
545 p_temp(kk) = p_phy(i,k,j)
548 ! Use the routine from Reichler.
550 call twmo(pLev, t_temp, p_temp, plimu, pliml, gamma, tP)
552 ! if successful, store the results and find the level and temperature.
554 ! Find the associated level, from bottom to top
556 if (tP >= p8w(i,k,j)) then
557 tropo_lev(i,j) = k - 1 ! needed for wrf, from bottom to top
562 !----------------------------------------------------------
563 ! get tropopause height
564 ! Intrepolate the geopotential height linearly against log(P)
566 k = k - 1 ! needed for wrf, from bottom to top
568 ! Is the tropoause at the midpoint?
569 if (tropo_p(i,j) == p_phy(i,k,j)) then
570 tropo_z(i,j)= zmid(i,k,j)
571 else if (tropo_p(i,j) < p_phy(i,k,j)) then
572 ! It is below the midpoint. Make sure we aren't at the bottom.
574 dZdlogP = (zmid(i,k,j) - z8w(i,k-1,j)) / &
575 (log(p_phy(i,k,j)) - log(p8w(i,k-1,j)) )
576 tropo_z(i,j)= zmid(i,k,j) + (log(tropo_p(i,j)) - log(p_phy(i,k,j))) * dZdlogP
579 ! It is above the midpoint? Make sure we aren't at the top.
581 dZdlogP = (zmid(i,k,j) - z8w(i,k,j)) / &
582 (log(p_phy(i,k,j)) - log(p8w(i,k,j)) )
583 tropo_z(i,j)= zmid(i,k,j) + (log(tropo_p(i,j)) - log(p_phy(i,k,j))) * dZdlogP
586 !----------------------------------------------------------
589 ! if ( tropo_lev(i,j) == NOTFOUND ) then
590 ! write (*,*) 'tropopause_twmo: NOTFOUND at id, i, j = ', id, i, j
596 end subroutine tropopause_twmo
598 !===========================================================================
600 ! This routine is an implementation of Reichler et al. [2003] done by
601 ! Reichler and downloaded from his web site. Minimal modifications were
602 ! made to have the routine work within the CAM framework (i.e. using
603 ! CAM constants and types).
605 ! NOTE: I am not a big fan of the goto's and multiple returns in this
606 ! code, but for the moment I have left them to preserve as much of the
607 ! original and presumably well tested code as possible.
609 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
611 ! determination of tropopause height from gridded temperature data
613 ! reference: Reichler, T., M. Dameris, and R. Sausen (2003)
615 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
617 subroutine twmo(level, t, p, plimu, pliml, gamma, trp)
619 integer, intent(in) :: level
621 ! real(r8), intent(in), dimension(level) :: t, p
622 real, intent(in), dimension(level) :: t, p
624 real(r8), intent(in) :: plimu, pliml, gamma
625 real(r8), intent(out) :: trp
627 real(r8), parameter :: deltaz = 2000.0_r8
629 real(r8) :: pmk, pm, a, b, tm, dtdp, dtdz
630 real(r8) :: ag, bg, ptph
631 real(r8) :: pm0, pmk0, dtdz0
632 real(r8) :: p2km, asum, aquer
633 real(r8) :: pmk2, pm2, a2, b2, tm2, dtdp2, dtdz2
634 integer :: icount, jj
638 trp=-99.0_r8 ! negative means not valid
644 pmk= .5_r8 * (p(j-1)**cnst_kap+p(j)**cnst_kap)
645 pm = pmk**(1/cnst_kap)
646 a = (t(j-1)-t(j))/(p(j-1)**cnst_kap-p(j)**cnst_kap)
647 b = t(j)-(a*p(j)**cnst_kap)
649 dtdp = a * cnst_kap * (pm**cnst_ka1)
650 dtdz = cnst_faktor*dtdp*pm/tm
652 ! if (j.eq.level) go to 999 ! no, start level, initialize first
653 ! if (dtdz.le.gamma) go to 999 ! no, dt/dz < -2 K/km
654 ! if (pm.gt.plimu) go to 999 ! no, too low
655 if( j == level .or. dtdz <= gamma .or. pm > plimu ) then
662 ! dtdz is valid, calculate tropopause pressure
663 if (dtdz0 < gamma) then
664 ag = (dtdz-dtdz0) / (pmk-pmk0)
665 bg = dtdz0 - (ag * pmk0)
666 ptph = exp(log((gamma-bg)/ag)/cnst_kap)
671 ! if (ptph.lt.pliml) go to 999
672 ! if (ptph.gt.plimu) go to 999
673 if( ptph < pliml .or. ptph > plimu ) then
680 ! 2nd test: dtdz above 2 km must not exceed gamma
681 p2km = ptph + deltaz*(pm/tm)*cnst_faktor ! p at ptph + 2km
682 asum = 0.0_r8 ! dtdz above
683 icount = 0 ! number of levels above
685 ! test until apm < p2km
689 pmk2 = .5_r8 * (p(jj-1)**cnst_kap+p(jj)**cnst_kap) ! p mean ^kappa
690 pm2 = pmk2**(1/cnst_kap) ! p mean
691 if( pm2 > ptph ) then ! doesn't happen
694 if( pm2 < p2km ) then ! ptropo is valid
699 a2 = (t(jj-1)-t(jj)) ! a
700 a2 = a2/(p(jj-1)**cnst_kap-p(jj)**cnst_kap)
701 b2 = t(jj)-(a2*p(jj)**cnst_kap) ! b
702 tm2 = a2 * pmk2 + b2 ! T mean
703 dtdp2 = a2 * cnst_kap * (pm2**(cnst_kap-1)) ! dt/dp
704 dtdz2 = cnst_faktor*dtdp2*pm2/tm2
707 aquer = asum/float(icount) ! dt/dz mean
710 if( aquer <= gamma ) then ! dt/dz above < gamma
723 !===========================================================================
725 ! Read the tropopause pressure in from a file containging a climatology. The
726 ! data is interpolated to the current dat of year and latitude.
728 ! NOTE: The data is read in during tropopause_init and stored in the module
729 ! variable tropo_bc(id)%tropo_p_loc
731 subroutine tropopause_climate (id, current_date_char, &
732 p_phy, p8w, zmid, z8w, &
733 tropo_lev, tropo_p, tropo_z, &
734 ids,ide, jds,jde, kds,kde, &
735 ims,ime, jms,jme, kms,kme, &
736 its,ite, jts,jte, kts,kte )
739 !----------------------------------------------------
741 !----------------------------------------------------
742 integer, intent(in) :: id, &
743 ids,ide, jds,jde, kds,kde, &
744 ims,ime, jms,jme, kms,kme, &
745 its,ite, jts,jte, kts,kte
747 real, dimension( ims:ime , kms:kme , jms:jme ), &
748 intent(in) :: p_phy, & ! p at mid-level (Pa)
749 zmid, & ! z at mid_level (meters)
750 z8w, & ! z at interface (meters)
751 p8w ! p at interface (Pa)
753 real, dimension( ims:ime, jms:jme ), &
754 intent(inout) :: tropo_p, & ! tropopause pressure (Pa)
755 tropo_z ! tropopause height (meters)
756 integer, dimension( ims:ime, jms:jme ), &
757 intent(inout) :: tropo_lev ! tropopause level
759 CHARACTER (LEN=256),intent(in) :: current_date_char
760 !----------------------------------------------------
768 real(r8) :: tP ! tropopause pressure (Pa)
774 CHARACTER(LEN=132) :: message
775 !-----------------------------------------------------------------------
777 if (any(tropo_lev(its:iend,jts:jend) == NOTFOUND)) then
779 !------------------------------------------------------------------------
780 ! setup time interpolation
781 !------------------------------------------------------------------------
783 call get_time_interp_factors( current_date_char, last, next, del_time )
785 ! Iterate over all of the grids.
790 ! Skip grids in which the tropopause has already been found.
792 if (tropo_lev(i,j) == NOTFOUND) then
794 !--------------------------------------------------------
795 ! ... get tropopause level from climatology
796 !--------------------------------------------------------
797 ! Interpolate the tropopause pressure.
798 tP = tropo_bc(id)%tropo_p_loc(i,j,last) &
799 + (tropo_bc(id)%tropo_p_loc(i,j,next) &
800 - tropo_bc(id)%tropo_p_loc(i,j,last))*del_time
803 ! Find the associated level, from bottom to top
805 if (tP >= p8w(i,k,j)) then
806 tropo_lev(i,j) = k - 1 ! needed for wrf, from bottom to top
812 !----------------------------------------------------------
813 ! get tropopause height
814 ! Intrepolate the geopotential height linearly against log(P)
816 k = k - 1 ! needed for wrf
818 ! Is the tropoause at the midpoint?
819 if (tropo_p(i,j) == p_phy(i,k,j)) then
820 tropo_z(i,j)= zmid(i,k,j)
822 else if (tropo_p(i,j) < p_phy(i,k,j)) then
823 ! It is below the midpoint. Make sure we aren't at the bottom.
825 dZdlogP = (zmid(i,k,j) - z8w(i,k-1,j)) / &
826 (log(p_phy(i,k,j)) - log(p8w(i,k-1,j)) )
827 tropo_z(i,j)= zmid(i,k,j) + (log(tropo_p(i,j)) - log(p_phy(i,k,j))) * dZdlogP
830 ! It is above the midpoint? Make sure we aren't at the top.
832 dZdlogP = (zmid(i,k,j) - z8w(i,k,j)) / &
833 (log(p_phy(i,k,j)) - log(p8w(i,k,j)) )
834 tropo_z(i,j)= zmid(i,k,j) + (log(tropo_p(i,j)) - log(p_phy(i,k,j))) * dZdlogP
837 !----------------------------------------------------------
844 if (any(tropo_lev(its:iend,jts:jend) == NOTFOUND)) then
845 write(message,*) 'tropopause_climate: Warning: some tropopause levels still NOTFOUND'
847 write(message,*) 'tropopause_climate: Warning: Done finding tropopause'
849 call wrf_message( trim(message) )
851 end subroutine tropopause_climate
853 !===========================================================================
855 subroutine get_time_interp_factors(current_date_char , last, next, del_time )
856 !-----------------------------------------------------------------------------
857 ! ... setup the time interpolation
858 !-----------------------------------------------------------------------------
860 use module_date_time, only : get_julgmt
864 !-----------------------------------------------------------------------------
865 ! ... dummy arguments
866 !-----------------------------------------------------------------------------
867 CHARACTER (LEN=256),intent(in) :: current_date_char
869 integer, intent(out) :: next, last
870 real, intent(out) :: del_time
871 !-----------------------------------------------------------------------------
872 ! ... local variables
873 !-----------------------------------------------------------------------------
875 integer, parameter :: day_of_year(12) = (/ 16, 45, 75, 105, 136, 166, 197, &
876 228, 258, 289, 319, 350 /)
877 integer :: julyr , julday
882 !---------------------------------------------------------------------------------
884 call get_julgmt ( current_date_char, julyr, julday, gmt )
886 calday = real(julday) + gmt
888 if( calday < day_of_year(1) ) then
891 del_time = (365. + calday - day_of_year(12)) &
892 / (365. + day_of_year(1) - day_of_year(12))
893 else if( calday >= day_of_year(12) ) then
896 del_time = (calday - day_of_year(12)) &
897 / (365. + day_of_year(1) - day_of_year(12))
900 if( calday >= day_of_year(m) ) then
906 del_time = (calday - day_of_year(m)) / (day_of_year(m+1) - day_of_year(m))
909 del_time = max( min( 1.,del_time ),0. )
911 end subroutine get_time_interp_factors
913 !===========================================================================
914 end module module_tropopause