From a0fa36af7a73e26dc1b1e01c965178f17665021d Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 12 Aug 2024 23:47:22 -0400 Subject: [PATCH 01/31] Setup Test SDF, copy existing tropopause.F90 --- test/test_sdfs/suite_tropopause_find.xml | 12 + tropopause_find/tropopause_find.F90 | 1512 ++++++++++++++++++++++ 2 files changed, 1524 insertions(+) create mode 100644 test/test_sdfs/suite_tropopause_find.xml create mode 100644 tropopause_find/tropopause_find.F90 diff --git a/test/test_sdfs/suite_tropopause_find.xml b/test/test_sdfs/suite_tropopause_find.xml new file mode 100644 index 00000000..6d1c5876 --- /dev/null +++ b/test/test_sdfs/suite_tropopause_find.xml @@ -0,0 +1,12 @@ + + + + + + qneg + geopotential_temp + + + tropopause_find + + diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 new file mode 100644 index 00000000..a2fd8308 --- /dev/null +++ b/tropopause_find/tropopause_find.F90 @@ -0,0 +1,1512 @@ +! This module is used to diagnose the location of the tropopause. Multiple +! algorithms are provided, some of which may not be able to identify a +! tropopause in all situations. To handle these cases, an analytic +! definition and a climatology are provided that can be used to fill in +! when the original algorithm fails. The tropopause temperature and +! pressure are determined and can be output to the history file. +! +! These routines are based upon code in the WACCM chemistry module +! including mo_tropoause.F90 and llnl_set_chem_trop.F90. The code +! for the Reichler et al. [2003] algorithm is from: +! +! http://www.gfdl.noaa.gov/~tjr/TROPO/tropocode.htm +! +! Author: Charles Bardeen +! Created: April, 2009 + +module tropopause + !--------------------------------------------------------------- + ! ... variables for the tropopause module + !--------------------------------------------------------------- + + use shr_kind_mod, only : r8 => shr_kind_r8 + use shr_const_mod, only : pi => shr_const_pi + use ppgrid, only : pcols, pver, begchunk, endchunk + use cam_abortutils, only : endrun + use cam_logfile, only : iulog + use cam_history_support, only : fillvalue + use physics_types, only : physics_state + use physconst, only : cappa, rair, gravit + use spmd_utils, only : masterproc + + implicit none + + private + + public :: tropopause_readnl, tropopause_init, tropopause_find, tropopause_output + public :: tropopause_findChemTrop + public :: TROP_ALG_NONE, TROP_ALG_ANALYTIC, TROP_ALG_CLIMATE + public :: TROP_ALG_STOBIE, TROP_ALG_HYBSTOB, TROP_ALG_TWMO, TROP_ALG_WMO + public :: TROP_ALG_CPP + public :: NOTFOUND + + save + + ! These parameters define and enumeration to be used to define the primary + ! and backup algorithms to be used with the tropopause_find() method. The + ! backup algorithm is meant to provide a solution when the primary algorithm + ! fail. The algorithms that can't fail are: TROP_ALG_ANALYTIC, TROP_ALG_CLIMATE + ! and TROP_ALG_STOBIE. + integer, parameter :: TROP_ALG_NONE = 1 ! Don't evaluate + integer, parameter :: TROP_ALG_ANALYTIC = 2 ! Analytic Expression + integer, parameter :: TROP_ALG_CLIMATE = 3 ! Climatology + integer, parameter :: TROP_ALG_STOBIE = 4 ! Stobie Algorithm + integer, parameter :: TROP_ALG_TWMO = 5 ! WMO Definition, Reichler et al. [2003] + integer, parameter :: TROP_ALG_WMO = 6 ! WMO Definition + integer, parameter :: TROP_ALG_HYBSTOB = 7 ! Hybrid Stobie Algorithm + integer, parameter :: TROP_ALG_CPP = 8 ! Cold Point Parabolic + + integer, parameter :: TROP_NALG = 8 ! Number of Algorithms + character,parameter :: TROP_LETTER(TROP_NALG) = (/ ' ', 'A', 'C', 'S', 'T', 'W', 'H', 'F' /) + ! unique identifier for output, don't use P + + ! These variables should probably be controlled by namelist entries. + logical ,parameter :: output_all = .False. ! output tropopause info from all algorithms + integer ,parameter :: default_primary = TROP_ALG_TWMO ! default primary algorithm + integer ,parameter :: default_backup = TROP_ALG_CLIMATE ! default backup algorithm + + ! Namelist variables + character(len=256) :: tropopause_climo_file = 'trop_climo' ! absolute filepath of climatology file + + ! These variables are used to store the climatology data. + real(r8) :: days(12) ! days in the climatology + real(r8), pointer :: tropp_p_loc(:,:,:) ! climatological tropopause pressures + + integer, parameter :: NOTFOUND = -1 + + real(r8),parameter :: ALPHA = 0.03_r8 + + ! physical constants + ! These constants are set in module variables rather than as parameters + ! to support the aquaplanet mode in which the constants have values determined + ! by the experiment protocol + real(r8) :: cnst_kap ! = cappa + real(r8) :: cnst_faktor ! = -gravit/rair + real(r8) :: cnst_ka1 ! = cnst_kap - 1._r8 + +!================================================================================================ +contains +!================================================================================================ + + ! Read namelist variables. + subroutine tropopause_readnl(nlfile) + + use namelist_utils, only: find_group_name + use units, only: getunit, freeunit + use mpishorthand + + character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input + + ! Local variables + integer :: unitn, ierr + character(len=*), parameter :: subname = 'tropopause_readnl' + + namelist /tropopause_nl/ tropopause_climo_file + !----------------------------------------------------------------------------- + + if (masterproc) then + unitn = getunit() + open( unitn, file=trim(nlfile), status='old' ) + call find_group_name(unitn, 'tropopause_nl', status=ierr) + if (ierr == 0) then + read(unitn, tropopause_nl, iostat=ierr) + if (ierr /= 0) then + call endrun(subname // ':: ERROR reading namelist') + end if + end if + close(unitn) + call freeunit(unitn) + end if + +#ifdef SPMD + ! Broadcast namelist variables + call mpibcast(tropopause_climo_file, len(tropopause_climo_file), mpichar, 0, mpicom) +#endif + + end subroutine tropopause_readnl + + + ! This routine is called during intialization and must be called before the + ! other methods in this module can be used. Its main tasks are to read in the + ! climatology from a file and to define the output fields. Much of this code + ! is taken from mo_tropopause. + subroutine tropopause_init() + + use cam_history, only: addfld, horiz_only + + + implicit none + + ! define physical constants + cnst_kap = cappa + cnst_faktor = -gravit/rair + cnst_ka1 = cnst_kap - 1._r8 + + ! Define the output fields. + call addfld('TROP_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure', flag_xyfill=.True.) + call addfld('TROP_T', horiz_only, 'A', 'K', 'Tropopause Temperature', flag_xyfill=.True.) + call addfld('TROP_Z', horiz_only, 'A', 'm', 'Tropopause Height', flag_xyfill=.True.) + call addfld('TROP_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height') + call addfld('TROP_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Probabilty') + call addfld('TROP_FD', horiz_only, 'A', 'probability', 'Tropopause Found') + + call addfld('TROPP_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (primary)', flag_xyfill=.True.) + call addfld('TROPP_T', horiz_only, 'A', 'K', 'Tropopause Temperature (primary)', flag_xyfill=.True.) + call addfld('TROPP_Z', horiz_only, 'A', 'm', 'Tropopause Height (primary)', flag_xyfill=.True.) + call addfld('TROPP_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height (primary)') + call addfld('TROPP_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (primary)') + call addfld('TROPP_FD', horiz_only, 'A', 'probability', 'Tropopause Found (primary)') + + call addfld('TROPF_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (cold point)', flag_xyfill=.True.) + call addfld('TROPF_T', horiz_only, 'A', 'K', 'Tropopause Temperature (cold point)', flag_xyfill=.True.) + call addfld('TROPF_Z', horiz_only, 'A', 'm', 'Tropopause Height (cold point)', flag_xyfill=.True.) + call addfld('TROPF_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height (cold point)', flag_xyfill=.True.) + call addfld('TROPF_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (cold point)') + call addfld('TROPF_FD', horiz_only, 'A', 'probability', 'Tropopause Found (cold point)') + + call addfld( 'hstobie_trop', (/ 'lev' /), 'I', 'fraction of model time', 'Lowest level with stratospheric chemsitry') + call addfld( 'hstobie_linoz', (/ 'lev' /), 'I', 'fraction of model time', 'Lowest possible Linoz level') + call addfld( 'hstobie_tropop', (/ 'lev' /), 'I', 'fraction of model time', & + 'Troposphere boundary calculated in chemistry' ) + + ! If requested, be prepared to output results from all of the methods. + if (output_all) then + call addfld('TROPA_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (analytic)', flag_xyfill=.True.) + call addfld('TROPA_T', horiz_only, 'A', 'K', 'Tropopause Temperature (analytic)', flag_xyfill=.True.) + call addfld('TROPA_Z', horiz_only, 'A', 'm', 'Tropopause Height (analytic)', flag_xyfill=.True.) + call addfld('TROPA_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (analytic)') + call addfld('TROPA_FD', horiz_only, 'A', 'probability', 'Tropopause Found (analytic)') + + call addfld('TROPC_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (climatology)', flag_xyfill=.True.) + call addfld('TROPC_T', horiz_only, 'A', 'K', 'Tropopause Temperature (climatology)', flag_xyfill=.True.) + call addfld('TROPC_Z', horiz_only, 'A', 'm', 'Tropopause Height (climatology)', flag_xyfill=.True.) + call addfld('TROPC_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (climatology)') + call addfld('TROPC_FD', horiz_only, 'A', 'probability', 'Tropopause Found (climatology)') + + call addfld('TROPS_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (stobie)', flag_xyfill=.True.) + call addfld('TROPS_T', horiz_only, 'A', 'K', 'Tropopause Temperature (stobie)', flag_xyfill=.True.) + call addfld('TROPS_Z', horiz_only, 'A', 'm', 'Tropopause Height (stobie)', flag_xyfill=.True.) + call addfld('TROPS_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (stobie)') + call addfld('TROPS_FD', horiz_only, 'A', 'probability', 'Tropopause Found (stobie)') + + call addfld('TROPT_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (twmo)', flag_xyfill=.True.) + call addfld('TROPT_T', horiz_only, 'A', 'K', 'Tropopause Temperature (twmo)', flag_xyfill=.True.) + call addfld('TROPT_Z', horiz_only, 'A', 'm', 'Tropopause Height (twmo)', flag_xyfill=.True.) + call addfld('TROPT_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (twmo)') + call addfld('TROPT_FD', horiz_only, 'A', 'probability', 'Tropopause Found (twmo)') + + call addfld('TROPW_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (WMO)', flag_xyfill=.True.) + call addfld('TROPW_T', horiz_only, 'A', 'K', 'Tropopause Temperature (WMO)', flag_xyfill=.True.) + call addfld('TROPW_Z', horiz_only, 'A', 'm', 'Tropopause Height (WMO)', flag_xyfill=.True.) + call addfld('TROPW_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (WMO)') + call addfld('TROPW_FD', horiz_only, 'A', 'probability', 'Tropopause Found (WMO)') + + call addfld('TROPH_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (Hybrid Stobie)', flag_xyfill=.True.) + call addfld('TROPH_T', horiz_only, 'A', 'K', 'Tropopause Temperature (Hybrid Stobie)', flag_xyfill=.True.) + call addfld('TROPH_Z', horiz_only, 'A', 'm', 'Tropopause Height (Hybrid Stobie)', flag_xyfill=.True.) + call addfld('TROPH_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (Hybrid Stobie)') + call addfld('TROPH_FD', horiz_only, 'A', 'probability', 'Tropopause Found (Hybrid Stobie)') + end if + + + call tropopause_read_file() + + + end subroutine tropopause_init + + + subroutine tropopause_read_file + !------------------------------------------------------------------ + ! ... initialize upper boundary values + !------------------------------------------------------------------ + use interpolate_data, only : lininterp_init, lininterp, interp_type, lininterp_finish + use dyn_grid, only : get_dyn_grid_parm + use phys_grid, only : get_ncols_p, get_rlat_all_p, get_rlon_all_p + use ioFileMod, only : getfil + use time_manager, only : get_calday + use physconst, only : pi + use cam_pio_utils, only: cam_pio_openfile + use pio, only : file_desc_t, var_desc_t, pio_inq_dimid, pio_inq_dimlen, & + pio_inq_varid, pio_get_var, pio_closefile, pio_nowrite + + !------------------------------------------------------------------ + ! ... local variables + !------------------------------------------------------------------ + integer :: i, j, n + integer :: ierr + type(file_desc_t) :: pio_id + integer :: dimid + type(var_desc_t) :: vid + integer :: nlon, nlat, ntimes + integer :: start(3) + integer :: count(3) + integer, parameter :: dates(12) = (/ 116, 214, 316, 415, 516, 615, & + 716, 816, 915, 1016, 1115, 1216 /) + integer :: plon, plat + type(interp_type) :: lon_wgts, lat_wgts + real(r8), allocatable :: tropp_p_in(:,:,:) + real(r8), allocatable :: lat(:) + real(r8), allocatable :: lon(:) + real(r8) :: to_lats(pcols), to_lons(pcols) + real(r8), parameter :: d2r=pi/180._r8, zero=0._r8, twopi=pi*2._r8 + character(len=256) :: locfn + integer :: c, ncols + + + plon = get_dyn_grid_parm('plon') + plat = get_dyn_grid_parm('plat') + + + !----------------------------------------------------------------------- + ! ... open netcdf file + !----------------------------------------------------------------------- + call getfil (tropopause_climo_file, locfn, 0) + call cam_pio_openfile(pio_id, trim(locfn), PIO_NOWRITE) + + !----------------------------------------------------------------------- + ! ... get time dimension + !----------------------------------------------------------------------- + ierr = pio_inq_dimid( pio_id, 'time', dimid ) + ierr = pio_inq_dimlen( pio_id, dimid, ntimes ) + if( ntimes /= 12 )then + write(iulog,*) 'tropopause_init: number of months = ',ntimes,'; expecting 12' + call endrun + end if + !----------------------------------------------------------------------- + ! ... get latitudes + !----------------------------------------------------------------------- + ierr = pio_inq_dimid( pio_id, 'lat', dimid ) + ierr = pio_inq_dimlen( pio_id, dimid, nlat ) + allocate( lat(nlat), stat=ierr ) + if( ierr /= 0 ) then + write(iulog,*) 'tropopause_init: lat allocation error = ',ierr + call endrun + end if + ierr = pio_inq_varid( pio_id, 'lat', vid ) + ierr = pio_get_var( pio_id, vid, lat ) + lat(:nlat) = lat(:nlat) * d2r + !----------------------------------------------------------------------- + ! ... get longitudes + !----------------------------------------------------------------------- + ierr = pio_inq_dimid( pio_id, 'lon', dimid ) + ierr = pio_inq_dimlen( pio_id, dimid, nlon ) + allocate( lon(nlon), stat=ierr ) + if( ierr /= 0 ) then + write(iulog,*) 'tropopause_init: lon allocation error = ',ierr + call endrun + end if + ierr = pio_inq_varid( pio_id, 'lon', vid ) + ierr = pio_get_var( pio_id, vid, lon ) + lon(:nlon) = lon(:nlon) * d2r + + !------------------------------------------------------------------ + ! ... allocate arrays + !------------------------------------------------------------------ + allocate( tropp_p_in(nlon,nlat,ntimes), stat=ierr ) + if( ierr /= 0 ) then + write(iulog,*) 'tropopause_init: tropp_p_in allocation error = ',ierr + call endrun + end if + !------------------------------------------------------------------ + ! ... read in the tropopause pressure + !------------------------------------------------------------------ + ierr = pio_inq_varid( pio_id, 'trop_p', vid ) + start = (/ 1, 1, 1 /) + count = (/ nlon, nlat, ntimes /) + ierr = pio_get_var( pio_id, vid, start, count, tropp_p_in ) + + !------------------------------------------------------------------ + ! ... close the netcdf file + !------------------------------------------------------------------ + call pio_closefile( pio_id ) + + !-------------------------------------------------------------------- + ! ... regrid + !-------------------------------------------------------------------- + + allocate( tropp_p_loc(pcols,begchunk:endchunk,ntimes), stat=ierr ) + + if( ierr /= 0 ) then + write(iulog,*) 'tropopause_init: tropp_p_loc allocation error = ',ierr + call endrun + end if + + do c=begchunk,endchunk + ncols = get_ncols_p(c) + call get_rlat_all_p(c, pcols, to_lats) + call get_rlon_all_p(c, pcols, to_lons) + call lininterp_init(lon, nlon, to_lons, ncols, 2, lon_wgts, zero, twopi) + call lininterp_init(lat, nlat, to_lats, ncols, 1, lat_wgts) + do n=1,ntimes + call lininterp(tropp_p_in(:,:,n), nlon, nlat, tropp_p_loc(1:ncols,c,n), ncols, lon_wgts, lat_wgts) + end do + call lininterp_finish(lon_wgts) + call lininterp_finish(lat_wgts) + end do + deallocate(lon) + deallocate(lat) + deallocate(tropp_p_in) + + !-------------------------------------------------------- + ! ... initialize the monthly day of year times + !-------------------------------------------------------- + + do n = 1,12 + days(n) = get_calday( dates(n), 0 ) + end do + if (masterproc) then + write(iulog,*) 'tropopause_init : days' + write(iulog,'(1p,5g15.8)') days(:) + endif + + end subroutine tropopause_read_file + + + ! This analytic expression closely matches the mean tropopause determined + ! by the NCEP reanalysis and has been used by the radiation code. + subroutine tropopause_analytic(pstate, tropLev, tropP, tropT, tropZ) + + implicit none + + type(physics_state), intent(in) :: pstate + integer, intent(inout) :: tropLev(pcols) ! tropopause level index + real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) + real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) + real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) + + ! Local Variables + integer :: i + integer :: k + integer :: ncol ! number of columns in the chunk + integer :: lchnk ! chunk identifier + real(r8) :: tP ! tropopause pressure (Pa) + + ! Information about the chunk. + lchnk = pstate%lchnk + ncol = pstate%ncol + + ! Iterate over all of the columns. + do i = 1, ncol + + ! Skip column in which the tropopause has already been found. + if (tropLev(i) == NOTFOUND) then + + ! Calculate the pressure of the tropopause. + tP = (25000.0_r8 - 15000.0_r8 * (cos(pstate%lat(i)))**2) + + ! Find the level that contains the tropopause. + do k = pver, 2, -1 + if (tP >= pstate%pint(i, k)) then + tropLev(i) = k + exit + end if + end do + + ! Return the optional outputs + if (present(tropP)) tropP(i) = tP + + if (present(tropT)) then + tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP) + end if + + if (present(tropZ)) then + tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP) + end if + end if + end do + end subroutine tropopause_analytic + + + ! Read the tropopause pressure in from a file containging a climatology. The + ! data is interpolated to the current dat of year and latitude. + ! + ! NOTE: The data is read in during tropopause_init and stored in the module + ! variable trop + subroutine tropopause_climate(pstate, tropLev, tropP, tropT, tropZ) + use time_manager, only : get_curr_calday + + implicit none + + type(physics_state), intent(in) :: pstate + integer, intent(inout) :: tropLev(pcols) ! tropopause level index + real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) + real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) + real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) + + ! Local Variables + integer :: i + integer :: k + integer :: m + integer :: ncol ! number of columns in the chunk + integer :: lchnk ! chunk identifier + real(r8) :: tP ! tropopause pressure (Pa) + real(r8) :: calday ! day of year including fraction + real(r8) :: dels + integer :: last + integer :: next + + ! Information about the chunk. + lchnk = pstate%lchnk + ncol = pstate%ncol + + ! If any columns remain to be indentified, the nget the current + ! day from the calendar. + + if (any(tropLev == NOTFOUND)) then + + ! Determine the calendar day. + calday = get_curr_calday() + + !-------------------------------------------------------- + ! ... setup the time interpolation + !-------------------------------------------------------- + if( calday < days(1) ) then + next = 1 + last = 12 + dels = (365._r8 + calday - days(12)) / (365._r8 + days(1) - days(12)) + else if( calday >= days(12) ) then + next = 1 + last = 12 + dels = (calday - days(12)) / (365._r8 + days(1) - days(12)) + else + do m = 11,1,-1 + if( calday >= days(m) ) then + exit + end if + end do + last = m + next = m + 1 + dels = (calday - days(m)) / (days(m+1) - days(m)) + end if + + dels = max( min( 1._r8,dels ),0._r8 ) + + + ! Iterate over all of the columns. + do i = 1, ncol + + ! Skip column in which the tropopause has already been found. + if (tropLev(i) == NOTFOUND) then + + !-------------------------------------------------------- + ! ... get tropopause level from climatology + !-------------------------------------------------------- + ! Interpolate the tropopause pressure. + tP = tropp_p_loc(i,lchnk,last) & + + dels * (tropp_p_loc(i,lchnk,next) - tropp_p_loc(i,lchnk,last)) + + ! Find the associated level. + do k = pver, 2, -1 + if (tP >= pstate%pint(i, k)) then + tropLev(i) = k + exit + end if + end do + + ! Return the optional outputs + if (present(tropP)) tropP(i) = tP + + if (present(tropT)) then + tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP) + end if + + if (present(tropZ)) then + tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP) + end if + end if + end do + end if + + return + end subroutine tropopause_climate + + !----------------------------------------------------------------------- + !----------------------------------------------------------------------- + subroutine tropopause_hybridstobie(pstate, tropLev, tropP, tropT, tropZ) + use cam_history, only : outfld + + !----------------------------------------------------------------------- + ! Originally written by Philip Cameron-Smith, LLNL + ! + ! Stobie-Linoz hybrid: the highest altitude of + ! a) Stobie algorithm, or + ! b) minimum Linoz pressure. + ! + ! NOTE: the ltrop(i) gridbox itself is assumed to be a STRATOSPHERIC gridbox. + !----------------------------------------------------------------------- + !----------------------------------------------------------------------- + ! ... Local variables + !----------------------------------------------------------------------- + + implicit none + + type(physics_state), intent(in) :: pstate + integer, intent(inout) :: tropLev(pcols) ! tropopause level index + real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) + real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) + real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) + + real(r8),parameter :: min_Stobie_Pressure= 40.E2_r8 !For case 2 & 4. [Pa] + real(r8),parameter :: max_Linoz_Pressure =208.E2_r8 !For case 4. [Pa] + + integer :: i, k, ncol + real(r8) :: stobie_min, shybrid_temp !temporary variable for case 2 & 3. + integer :: ltrop_linoz(pcols) !Lowest possible Linoz vertical level + integer :: ltrop_trop(pcols) !Tropopause level for hybrid case. + logical :: ltrop_linoz_set !Flag that lowest linoz level already found. + real(r8) :: trop_output(pcols,pver) !For output purposes only. + real(r8) :: trop_linoz_output(pcols,pver) !For output purposes only. + real(r8) :: trop_trop_output(pcols,pver) !For output purposes only. + + ! write(iulog,*) 'In set_chem_trop, o3_ndx =',o3_ndx + ltrop_linoz(:) = 1 ! Initialize to default value. + ltrop_trop(:) = 1 ! Initialize to default value. + ncol = pstate%ncol + + LOOP_COL4: do i=1,ncol + + ! Skip column in which the tropopause has already been found. + not_found: if (tropLev(i) == NOTFOUND) then + + stobie_min = 1.e10_r8 ! An impossibly large number + ltrop_linoz_set = .FALSE. + LOOP_LEV: do k=pver,1,-1 + IF (pstate%pmid(i,k) < min_stobie_pressure) cycle + shybrid_temp = ALPHA * pstate%t(i,k) - Log10(pstate%pmid(i,k)) + !PJC_NOTE: the units of pmid won't matter, because it is just an additive offset. + IF (shybrid_temp0) then + trop_output(i,tropLev(i))=1._r8 + trop_linoz_output(i,ltrop_linoz(i))=1._r8 + trop_trop_output(i,ltrop_trop(i))=1._r8 + endif + enddo + + call outfld( 'hstobie_trop', trop_output(:ncol,:), ncol, pstate%lchnk ) + call outfld( 'hstobie_linoz', trop_linoz_output(:ncol,:), ncol, pstate%lchnk ) + call outfld( 'hstobie_tropop', trop_trop_output(:ncol,:), ncol, pstate%lchnk ) + + endsubroutine tropopause_hybridstobie + + ! This routine originates with Stobie at NASA Goddard, but does not have a + ! known reference. It was supplied by Philip Cameron-Smith of LLNL. + ! + subroutine tropopause_stobie(pstate, tropLev, tropP, tropT, tropZ) + + implicit none + + type(physics_state), intent(in) :: pstate + integer, intent(inout) :: tropLev(pcols) ! tropopause level index + real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) + real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) + real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) + + ! Local Variables + integer :: i + integer :: k + integer :: ncol ! number of columns in the chunk + integer :: lchnk ! chunk identifier + integer :: tLev ! tropopause level + real(r8) :: tP ! tropopause pressure (Pa) + real(r8) :: stobie(pver) ! stobie weighted temperature + real(r8) :: sTrop ! stobie value at the tropopause + + ! Information about the chunk. + lchnk = pstate%lchnk + ncol = pstate%ncol + + ! Iterate over all of the columns. + do i = 1, ncol + + ! Skip column in which the tropopause has already been found. + if (tropLev(i) == NOTFOUND) then + + ! Caclulate a pressure weighted temperature. + stobie(:) = ALPHA * pstate%t(i,:) - log10(pstate%pmid(i, :)) + + ! Search from the bottom up, looking for the first minimum. + tLev = -1 + + do k = pver-1, 1, -1 + + if (pstate%pmid(i, k) <= 4000._r8) then + exit + end if + + if (pstate%pmid(i, k) >= 55000._r8) then + cycle + end if + + if ((tLev == -1) .or. (stobie(k) < sTrop)) then + tLev = k + tP = pstate%pmid(i, k) + sTrop = stobie(k) + end if + end do + + if (tLev /= -1) then + tropLev(i) = tLev + + ! Return the optional outputs + if (present(tropP)) tropP(i) = tP + + if (present(tropT)) then + tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP) + end if + + if (present(tropZ)) then + tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP) + end if + end if + end if + end do + + return + end subroutine tropopause_stobie + + + ! This routine is an implementation of Reichler et al. [2003] done by + ! Reichler and downloaded from his web site. Minimal modifications were + ! made to have the routine work within the CAM framework (i.e. using + ! CAM constants and types). + ! + ! NOTE: I am not a big fan of the goto's and multiple returns in this + ! code, but for the moment I have left them to preserve as much of the + ! original and presumably well tested code as possible. + ! UPDATE: The most "obvious" substitutions have been made to replace + ! goto/return statements with cycle/exit. The structure is still + ! somewhat tangled. + ! UPDATE 2: "gamma" renamed to "gam" in order to avoid confusion + ! with the Fortran 2008 intrinsic. "level" argument removed because + ! a physics column is not contiguous, so using explicit dimensions + ! will cause the data to be needlessly copied. + ! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ! + ! determination of tropopause height from gridded temperature data + ! + ! reference: Reichler, T., M. Dameris, and R. Sausen (2003) + ! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + subroutine twmo(t, p, plimu, pliml, gam, trp) + + real(r8), intent(in), dimension(:) :: t, p + real(r8), intent(in) :: plimu, pliml, gam + real(r8), intent(out) :: trp + + real(r8), parameter :: deltaz = 2000.0_r8 + + real(r8) :: pmk, pm, a, b, tm, dtdp, dtdz + real(r8) :: ag, bg, ptph + real(r8) :: pm0, pmk0, dtdz0 + real(r8) :: p2km, asum, aquer + real(r8) :: pmk2, pm2, a2, b2, tm2, dtdp2, dtdz2 + integer :: level + integer :: icount, jj + integer :: j + + + trp=-99.0_r8 ! negative means not valid + + ! initialize start level + ! dt/dz + level = size(t) + pmk= .5_r8 * (p(level-1)**cnst_kap+p(level)**cnst_kap) + pm = pmk**(1/cnst_kap) + a = (t(level-1)-t(level))/(p(level-1)**cnst_kap-p(level)**cnst_kap) + b = t(level)-(a*p(level)**cnst_kap) + tm = a * pmk + b + dtdp = a * cnst_kap * (pm**cnst_ka1) + dtdz = cnst_faktor*dtdp*pm/tm + + main_loop: do j=level-1,2,-1 + pm0 = pm + pmk0 = pmk + dtdz0 = dtdz + + ! dt/dz + pmk= .5_r8 * (p(j-1)**cnst_kap+p(j)**cnst_kap) + pm = pmk**(1/cnst_kap) + a = (t(j-1)-t(j))/(p(j-1)**cnst_kap-p(j)**cnst_kap) + b = t(j)-(a*p(j)**cnst_kap) + tm = a * pmk + b + dtdp = a * cnst_kap * (pm**cnst_ka1) + dtdz = cnst_faktor*dtdp*pm/tm + ! dt/dz valid? + if (dtdz.le.gam) cycle main_loop ! no, dt/dz < -2 K/km + if (pm.gt.plimu) cycle main_loop ! no, too low + + ! dtdz is valid, calculate tropopause pressure + if (dtdz0.lt.gam) then + ag = (dtdz-dtdz0) / (pmk-pmk0) + bg = dtdz0 - (ag * pmk0) + ptph = exp(log((gam-bg)/ag)/cnst_kap) + else + ptph = pm + endif + + if (ptph.lt.pliml) cycle main_loop + if (ptph.gt.plimu) cycle main_loop + + ! 2nd test: dtdz above 2 km must not exceed gam + p2km = ptph + deltaz*(pm/tm)*cnst_faktor ! p at ptph + 2km + asum = 0.0_r8 ! dtdz above + icount = 0 ! number of levels above + + ! test until apm < p2km + in_loop: do jj=j,2,-1 + + pmk2 = .5_r8 * (p(jj-1)**cnst_kap+p(jj)**cnst_kap) ! p mean ^kappa + pm2 = pmk2**(1/cnst_kap) ! p mean + if(pm2.gt.ptph) cycle in_loop ! doesn't happen + if(pm2.lt.p2km) exit in_loop ! ptropo is valid + + a2 = (t(jj-1)-t(jj)) ! a + a2 = a2/(p(jj-1)**cnst_kap-p(jj)**cnst_kap) + b2 = t(jj)-(a2*p(jj)**cnst_kap) ! b + tm2 = a2 * pmk2 + b2 ! T mean + dtdp2 = a2 * cnst_kap * (pm2**(cnst_kap-1)) ! dt/dp + dtdz2 = cnst_faktor*dtdp2*pm2/tm2 + asum = asum+dtdz2 + icount = icount+1 + aquer = asum/float(icount) ! dt/dz mean + + ! discard ptropo ? + if (aquer.le.gam) cycle main_loop ! dt/dz above < gam + + enddo in_loop ! test next level + + trp = ptph + exit main_loop + enddo main_loop + + end subroutine twmo + + + ! This routine uses an implementation of Reichler et al. [2003] done by + ! Reichler and downloaded from his web site. This is similar to the WMO + ! routines, but is designed for GCMs with a coarse vertical grid. + subroutine tropopause_twmo(pstate, tropLev, tropP, tropT, tropZ) + + implicit none + + type(physics_state), intent(in) :: pstate + integer, intent(inout) :: tropLev(pcols) ! tropopause level index + real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) + real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) + real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) + + ! Local Variables + real(r8), parameter :: gam = -0.002_r8 ! K/m + real(r8), parameter :: plimu = 45000._r8 ! Pa + real(r8), parameter :: pliml = 7500._r8 ! Pa + + integer :: i + integer :: k + integer :: ncol ! number of columns in the chunk + integer :: lchnk ! chunk identifier + real(r8) :: tP ! tropopause pressure (Pa) + + ! Information about the chunk. + lchnk = pstate%lchnk + ncol = pstate%ncol + + ! Iterate over all of the columns. + do i = 1, ncol + + ! Skip column in which the tropopause has already been found. + if (tropLev(i) == NOTFOUND) then + + ! Use the routine from Reichler. + call twmo(pstate%t(i, :), pstate%pmid(i, :), plimu, pliml, gam, tP) + + ! if successful, store of the results and find the level and temperature. + if (tP > 0) then + + ! Find the associated level. + do k = pver, 2, -1 + if (tP >= pstate%pint(i, k)) then + tropLev(i) = k + exit + end if + end do + + ! Return the optional outputs + if (present(tropP)) tropP(i) = tP + + if (present(tropT)) then + tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP) + end if + + if (present(tropZ)) then + tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP) + end if + end if + end if + end do + + return + end subroutine tropopause_twmo + + ! This routine implements the WMO definition of the tropopause (WMO, 1957; Seidel and Randel, 2006). + ! This requires that the lapse rate be less than 2 K/km for an altitude range + ! of 2 km. The search starts at the surface and stops the first time this + ! criteria is met. + ! + ! NOTE: This code was modeled after the code in mo_tropopause; however, the + ! requirement that dt be greater than 0 was removed and the check to make + ! sure that the lapse rate is maintained for 2 km was added. + subroutine tropopause_wmo(pstate, tropLev, tropP, tropT, tropZ) + + implicit none + + type(physics_state), intent(in) :: pstate + integer, intent(inout) :: tropLev(pcols) ! tropopause level index + real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) + real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) + real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) + + ! Local Variables + real(r8), parameter :: ztrop_low = 5000._r8 ! lowest tropopause level allowed (m) + real(r8), parameter :: ztrop_high = 20000._r8 ! highest tropopause level allowed (m) + real(r8), parameter :: max_dtdz = 0.002_r8 ! max dt/dz for tropopause level (K/m) + real(r8), parameter :: min_trop_dz = 2000._r8 ! min tropopause thickness (m) + + integer :: i + integer :: k + integer :: k2 + integer :: ncol ! number of columns in the chunk + integer :: lchnk ! chunk identifier + real(r8) :: tP ! tropopause pressure (Pa) + real(r8) :: dt + + ! Information about the chunk. + lchnk = pstate%lchnk + ncol = pstate%ncol + + ! Iterate over all of the columns. + do i = 1, ncol + + ! Skip column in which the tropopause has already been found. + if (tropLev(i) == NOTFOUND) then + + kloop: do k = pver-1, 2, -1 + + ! Skip levels below the minimum and stop if nothing is found + ! before the maximum. + if (pstate%zm(i, k) < ztrop_low) then + cycle kloop + else if (pstate%zm(i, k) > ztrop_high) then + exit kloop + end if + + ! Compare the actual lapse rate to the threshold + dt = pstate%t(i, k) - pstate%t(i, k-1) + + if (dt <= (max_dtdz * (pstate%zm(i, k-1) - pstate%zm(i, k)))) then + + ! Make sure that the lapse rate stays below the threshold for the + ! specified range. + k2loop: do k2 = k-1, 2, -1 + if ((pstate%zm(i, k2) - pstate%zm(i, k)) >= min_trop_dz) then + tP = pstate%pmid(i, k) + tropLev(i) = k + exit k2loop + end if + + dt = pstate%t(i, k) - pstate%t(i, k2) + if (dt > (max_dtdz * (pstate%zm(i, k2) - pstate%zm(i, k)))) then + exit k2loop + end if + end do k2loop + + if (tropLev(i) == NOTFOUND) then + cycle kloop + else + + ! Return the optional outputs + if (present(tropP)) tropP(i) = tP + + if (present(tropT)) then + tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP) + end if + + if (present(tropZ)) then + tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP) + end if + + exit kloop + end if + end if + end do kloop + end if + end do + + return + end subroutine tropopause_wmo + + + ! This routine searches for the cold point tropopause, and uses a parabolic + ! fit of the coldest point and two adjacent points to interpolate the cold point + ! between model levels. + subroutine tropopause_cpp(pstate, tropLev, tropP, tropT, tropZ) + + implicit none + + type(physics_state), intent(in) :: pstate + integer, intent(inout) :: tropLev(pcols) ! tropopause level index + real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) + real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) + real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) + + ! Local Variables + real(r8), parameter :: ztrop_low = 5000._r8 ! lowest tropopause level allowed (m) + real(r8), parameter :: ztrop_high = 25000._r8 ! highest tropopause level allowed (m) + + integer :: i + integer :: k, firstk, lastk + integer :: k2 + integer :: ncol ! number of columns in the chunk + integer :: lchnk ! chunk identifier + real(r8) :: tZ ! tropopause height (m) + real(r8) :: tmin + real(r8) :: f0, f1, f2 + real(r8) :: x0, x1, x2 + real(r8) :: c0, c1, c2 + real(r8) :: a, b, c + + ! Information about the chunk. + lchnk = pstate%lchnk + ncol = pstate%ncol + + ! Iterate over all of the columns. + do i = 1, ncol + + firstk = 0 + lastk = pver+1 + + ! Skip column in which the tropopause has already been found. + if (tropLev(i) == NOTFOUND) then + tmin = 1e6_r8 + + kloop: do k = pver-1, 2, -1 + + ! Skip levels below the minimum and stop if nothing is found + ! before the maximum. + if (pstate%zm(i, k) < ztrop_low) then + firstk = k + cycle kloop + else if (pstate%zm(i, k) > ztrop_high) then + lastk = k + exit kloop + end if + + ! Find the coldest point + if (pstate%t(i, k) < tmin) then + tropLev(i) = k + tmin = pstate%t(i,k) + end if + end do kloop + + + ! If the minimum is at the edge of the search range, then don't + ! consider this to be a minima + if ((tropLev(i) >= (firstk-1)) .or. (tropLev(i) <= (lastk+1))) then + tropLev(i) = NOTFOUND + else + + ! If returning P, Z, or T, then do a parabolic fit using the + ! cold point and it its 2 surrounding points to interpolate + ! between model levels. + if (present(tropP) .or. present(tropZ) .or. present(tropT)) then + f0 = pstate%t(i, tropLev(i)-1) + f1 = pstate%t(i, tropLev(i)) + f2 = pstate%t(i, tropLev(i)+1) + + x0 = pstate%zm(i, tropLev(i)-1) + x1 = pstate%zm(i, tropLev(i)) + x2 = pstate%zm(i, tropLev(i)+1) + + c0 = (x0-x1)*(x0-x2) + c1 = (x1-x0)*(x1-x2) + c2 = (x2-x0)*(x2-x1) + + ! Determine the quadratic coefficients of: + ! T = a * z^2 - b*z + c + a = (f0/c0 + f1/c1 + f2/c2) + b = (f0/c0*(x1+x2) + f1/c1*(x0+x2) + f2/c2*(x0+x1)) + c = f0/c0*x1*x2 + f1/c1*x0*x2 + f2/c2*x0*x1 + + ! Find the altitude of the minimum temperature + tZ = 0.5_r8 * b / a + + ! The fit should be between the upper and lower points, + ! so skip the point if the fit fails. + if ((tZ >= x0) .or. (tZ <= x2)) then + tropLev(i) = NOTFOUND + else + + ! Return the optional outputs + if (present(tropP)) then + tropP(i) = tropopause_interpolateP(pstate, i, tropLev(i), tZ) + end if + + if (present(tropT)) then + tropT(i) = a * tZ*tZ - b*tZ + c + end if + + if (present(tropZ)) then + tropZ(i) = tZ + end if + end if + end if + end if + end if + end do + + return + end subroutine tropopause_cpp + + + ! Searches all the columns in the chunk and attempts to identify the tropopause. + ! Two routines can be specifed, a primary routine which is tried first and a + ! backup routine which will be tried only if the first routine fails. If the + ! tropopause can not be identified by either routine, then a NOTFOUND is returned + ! for the tropopause level, temperature and pressure. + subroutine tropopause_find(pstate, tropLev, tropP, tropT, tropZ, primary, backup) + + implicit none + + type(physics_state), intent(in) :: pstate + integer, optional, intent(in) :: primary ! primary detection algorithm + integer, optional, intent(in) :: backup ! backup detection algorithm + integer, intent(out) :: tropLev(pcols) ! tropopause level index + real(r8), optional, intent(out) :: tropP(pcols) ! tropopause pressure (Pa) + real(r8), optional, intent(out) :: tropT(pcols) ! tropopause temperature (K) + real(r8), optional, intent(out) :: tropZ(pcols) ! tropopause height (m) + + ! Local Variable + integer :: primAlg ! Primary algorithm + integer :: backAlg ! Backup algorithm + + ! Initialize the results to a missing value, so that the algorithms will + ! attempt to find the tropopause for all of them. + tropLev(:) = NOTFOUND + if (present(tropP)) tropP(:) = fillvalue + if (present(tropT)) tropT(:) = fillvalue + if (present(tropZ)) tropZ(:) = fillvalue + + ! Set the algorithms to be used, either the ones provided or the defaults. + if (present(primary)) then + primAlg = primary + else + primAlg = default_primary + end if + + if (present(backup)) then + backAlg = backup + else + backAlg = default_backup + end if + + ! Try to find the tropopause using the primary algorithm. + if (primAlg /= TROP_ALG_NONE) then + call tropopause_findUsing(pstate, primAlg, tropLev, tropP, tropT, tropZ) + end if + + if ((backAlg /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then + call tropopause_findUsing(pstate, backAlg, tropLev, tropP, tropT, tropZ) + end if + + return + end subroutine tropopause_find + + ! Searches all the columns in the chunk and attempts to identify the "chemical" + ! tropopause. This is the lapse rate tropopause, backed up by the climatology + ! if the lapse rate fails to find the tropopause at pressures higher than a certain + ! threshold. This pressure threshold depends on latitude. Between 50S and 50N, + ! the climatology is used if the lapse rate tropopause is not found at P > 75 hPa. + ! At high latitude (poleward of 50), the threshold is increased to 125 hPa to + ! eliminate false events that are sometimes detected in the cold polar stratosphere. + ! + ! NOTE: This routine was adapted from code in chemistry.F90 and mo_gasphase_chemdr.F90. + subroutine tropopause_findChemTrop(pstate, tropLev, primary, backup) + + implicit none + + type(physics_state), intent(in) :: pstate + integer, optional, intent(in) :: primary ! primary detection algorithm + integer, optional, intent(in) :: backup ! backup detection algorithm + integer, intent(out) :: tropLev(pcols) ! tropopause level index + + ! Local Variable + real(r8), parameter :: rad2deg = 180._r8/pi ! radians to degrees conversion factor + real(r8) :: dlats(pcols) + integer :: i + integer :: ncol + integer :: backAlg + + ! First use the lapse rate tropopause. + ncol = pstate%ncol + call tropopause_find(pstate, tropLev, primary=primary, backup=TROP_ALG_NONE) + + ! Now check high latitudes (poleward of 50) and set the level to the + ! climatology if the level was not found or is at P <= 125 hPa. + dlats(:ncol) = pstate%lat(:ncol) * rad2deg ! convert to degrees + + if (present(backup)) then + backAlg = backup + else + backAlg = default_backup + end if + + do i = 1, ncol + if (abs(dlats(i)) > 50._r8) then + if (tropLev(i) .ne. NOTFOUND) then + if (pstate%pmid(i, tropLev(i)) <= 12500._r8) then + tropLev(i) = NOTFOUND + end if + end if + end if + end do + + ! Now use the backup algorithm + if ((backAlg /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then + call tropopause_findUsing(pstate, backAlg, tropLev) + end if + + return + end subroutine tropopause_findChemTrop + + + ! Call the appropriate tropopause detection routine based upon the algorithm + ! specifed. + ! + ! NOTE: It is assumed that the output fields have been initialized by the + ! caller, and only output values set to fillvalue will be detected. + subroutine tropopause_findUsing(pstate, algorithm, tropLev, tropP, tropT, tropZ) + + implicit none + + type(physics_state), intent(in) :: pstate + integer, intent(in) :: algorithm ! detection algorithm + integer, intent(inout) :: tropLev(pcols) ! tropopause level index + real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) + real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) + real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) + + ! Dispatch the request to the appropriate routine. + select case(algorithm) + case(TROP_ALG_ANALYTIC) + call tropopause_analytic(pstate, tropLev, tropP, tropT, tropZ) + + case(TROP_ALG_CLIMATE) + call tropopause_climate(pstate, tropLev, tropP, tropT, tropZ) + + case(TROP_ALG_STOBIE) + call tropopause_stobie(pstate, tropLev, tropP, tropT, tropZ) + + case(TROP_ALG_HYBSTOB) + call tropopause_hybridstobie(pstate, tropLev, tropP, tropT, tropZ) + + case(TROP_ALG_TWMO) + call tropopause_twmo(pstate, tropLev, tropP, tropT, tropZ) + + case(TROP_ALG_WMO) + call tropopause_wmo(pstate, tropLev, tropP, tropT, tropZ) + + case(TROP_ALG_CPP) + call tropopause_cpp(pstate, tropLev, tropP, tropT, tropZ) + + case default + write(iulog, *) 'tropopause: Invalid detection algorithm (', algorithm, ') specified.' + call endrun + end select + + return + end subroutine tropopause_findUsing + + + ! This routine interpolates the pressures in the physics state to + ! find the pressure at the specified tropopause altitude. + function tropopause_interpolateP(pstate, icol, tropLev, tropZ) + + implicit none + + type(physics_state), intent(in) :: pstate + integer, intent(in) :: icol ! column being processed + integer, intent(in) :: tropLev ! tropopause level index + real(r8), optional, intent(in) :: tropZ ! tropopause pressure (m) + real(r8) :: tropopause_interpolateP + + ! Local Variables + real(r8) :: tropP ! tropopause pressure (Pa) + real(r8) :: dlogPdZ ! dlog(p)/dZ + + ! Interpolate the temperature linearly against log(P) + + ! Is the tropopause at the midpoint? + if (tropZ == pstate%zm(icol, tropLev)) then + tropP = pstate%pmid(icol, tropLev) + + else if (tropZ > pstate%zm(icol, tropLev)) then + + ! It is above the midpoint? Make sure we aren't at the top. + if (tropLev > 1) then + dlogPdZ = (log(pstate%pmid(icol, tropLev)) - log(pstate%pmid(icol, tropLev - 1))) / & + (pstate%zm(icol, tropLev) - pstate%zm(icol, tropLev - 1)) + tropP = pstate%pmid(icol, tropLev) + exp((tropZ - pstate%zm(icol, tropLev)) * dlogPdZ) + end if + else + + ! It is below the midpoint. Make sure we aren't at the bottom. + if (tropLev < pver) then + dlogPdZ = (log(pstate%pmid(icol, tropLev + 1)) - log(pstate%pmid(icol, tropLev))) / & + (pstate%zm(icol, tropLev + 1) - pstate%zm(icol, tropLev)) + tropP = pstate%pmid(icol, tropLev) + exp((tropZ - pstate%zm(icol, tropLev)) * dlogPdZ) + end if + end if + + tropopause_interpolateP = tropP + end function tropopause_interpolateP + + + ! This routine interpolates the temperatures in the physics state to + ! find the temperature at the specified tropopause pressure. + function tropopause_interpolateT(pstate, icol, tropLev, tropP) + + implicit none + + type(physics_state), intent(in) :: pstate + integer, intent(in) :: icol ! column being processed + integer, intent(in) :: tropLev ! tropopause level index + real(r8), optional, intent(in) :: tropP ! tropopause pressure (Pa) + real(r8) :: tropopause_interpolateT + + ! Local Variables + real(r8) :: tropT ! tropopause temperature (K) + real(r8) :: dTdlogP ! dT/dlog(P) + + ! Interpolate the temperature linearly against log(P) + + ! Is the tropopause at the midpoint? + if (tropP == pstate%pmid(icol, tropLev)) then + tropT = pstate%t(icol, tropLev) + + else if (tropP < pstate%pmid(icol, tropLev)) then + + ! It is above the midpoint? Make sure we aren't at the top. + if (tropLev > 1) then + dTdlogP = (pstate%t(icol, tropLev) - pstate%t(icol, tropLev - 1)) / & + (log(pstate%pmid(icol, tropLev)) - log(pstate%pmid(icol, tropLev - 1))) + tropT = pstate%t(icol, tropLev) + (log(tropP) - log(pstate%pmid(icol, tropLev))) * dTdlogP + end if + else + + ! It is below the midpoint. Make sure we aren't at the bottom. + if (tropLev < pver) then + dTdlogP = (pstate%t(icol, tropLev + 1) - pstate%t(icol, tropLev)) / & + (log(pstate%pmid(icol, tropLev + 1)) - log(pstate%pmid(icol, tropLev))) + tropT = pstate%t(icol, tropLev) + (log(tropP) - log(pstate%pmid(icol, tropLev))) * dTdlogP + end if + end if + + tropopause_interpolateT = tropT + end function tropopause_interpolateT + + + ! This routine interpolates the geopotential height in the physics state to + ! find the geopotential height at the specified tropopause pressure. + function tropopause_interpolateZ(pstate, icol, tropLev, tropP) + use physconst, only: rga + + implicit none + + type(physics_state), intent(in) :: pstate + integer, intent(in) :: icol ! column being processed + integer, intent(in) :: tropLev ! tropopause level index + real(r8), optional, intent(in) :: tropP ! tropopause pressure (Pa) + real(r8) :: tropopause_interpolateZ + + ! Local Variables + real(r8) :: tropZ ! tropopause geopotential height (m) + real(r8) :: dZdlogP ! dZ/dlog(P) + + ! Interpolate the geopotential height linearly against log(P) + + ! Is the tropoause at the midpoint? + if (tropP == pstate%pmid(icol, tropLev)) then + tropZ = pstate%zm(icol, tropLev) + + else if (tropP < pstate%pmid(icol, tropLev)) then + + ! It is above the midpoint? Make sure we aren't at the top. + dZdlogP = (pstate%zm(icol, tropLev) - pstate%zi(icol, tropLev)) / & + (log(pstate%pmid(icol, tropLev)) - log(pstate%pint(icol, tropLev))) + tropZ = pstate%zm(icol, tropLev) + (log(tropP) - log(pstate%pmid(icol, tropLev))) * dZdlogP + else + + ! It is below the midpoint. Make sure we aren't at the bottom. + dZdlogP = (pstate%zm(icol, tropLev) - pstate%zi(icol, tropLev+1)) / & + (log(pstate%pmid(icol, tropLev)) - log(pstate%pint(icol, tropLev+1))) + tropZ = pstate%zm(icol, tropLev) + (log(tropP) - log(pstate%pmid(icol, tropLev))) * dZdlogP + end if + + tropopause_interpolateZ = tropZ + pstate%phis(icol)*rga + end function tropopause_interpolateZ + + + ! Output the tropopause pressure and temperature to the history files. Two sets + ! of output will be generated, one for the default algorithm and another one + ! using the default routine, but backed by a climatology when the default + ! algorithm fails. + subroutine tropopause_output(pstate) + use cam_history, only : outfld + + implicit none + + type(physics_state), intent(in) :: pstate + + ! Local Variables + integer :: i + integer :: alg + integer :: ncol ! number of cloumns in the chunk + integer :: lchnk ! chunk identifier + integer :: tropLev(pcols) ! tropopause level index + real(r8) :: tropP(pcols) ! tropopause pressure (Pa) + real(r8) :: tropT(pcols) ! tropopause temperature (K) + real(r8) :: tropZ(pcols) ! tropopause height (m) + real(r8) :: tropFound(pcols) ! tropopause found + real(r8) :: tropDZ(pcols, pver) ! relative tropopause height (m) + real(r8) :: tropPdf(pcols, pver) ! tropopause probability distribution + + ! Information about the chunk. + lchnk = pstate%lchnk + ncol = pstate%ncol + + ! Find the tropopause using the default algorithm backed by the climatology. + call tropopause_find(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ) + + tropPdf(:,:) = 0._r8 + tropFound(:) = 0._r8 + tropDZ(:,:) = fillvalue + do i = 1, ncol + if (tropLev(i) /= NOTFOUND) then + tropPdf(i, tropLev(i)) = 1._r8 + tropFound(i) = 1._r8 + tropDZ(i,:) = pstate%zm(i,:) - tropZ(i) + end if + end do + + call outfld('TROP_P', tropP(:ncol), ncol, lchnk) + call outfld('TROP_T', tropT(:ncol), ncol, lchnk) + call outfld('TROP_Z', tropZ(:ncol), ncol, lchnk) + call outfld('TROP_DZ', tropDZ(:ncol, :), ncol, lchnk) + call outfld('TROP_PD', tropPdf(:ncol, :), ncol, lchnk) + call outfld('TROP_FD', tropFound(:ncol), ncol, lchnk) + + + ! Find the tropopause using just the primary algorithm. + call tropopause_find(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, backup=TROP_ALG_NONE) + + tropPdf(:,:) = 0._r8 + tropFound(:) = 0._r8 + tropDZ(:,:) = fillvalue + + do i = 1, ncol + if (tropLev(i) /= NOTFOUND) then + tropPdf(i, tropLev(i)) = 1._r8 + tropFound(i) = 1._r8 + tropDZ(i,:) = pstate%zm(i,:) - tropZ(i) + end if + end do + + call outfld('TROPP_P', tropP(:ncol), ncol, lchnk) + call outfld('TROPP_T', tropT(:ncol), ncol, lchnk) + call outfld('TROPP_Z', tropZ(:ncol), ncol, lchnk) + call outfld('TROPP_DZ', tropDZ(:ncol, :), ncol, lchnk) + call outfld('TROPP_PD', tropPdf(:ncol, :), ncol, lchnk) + call outfld('TROPP_FD', tropFound(:ncol), ncol, lchnk) + + + ! Find the tropopause using just the cold point algorithm. + call tropopause_find(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=TROP_ALG_CPP, backup=TROP_ALG_NONE) + + tropPdf(:,:) = 0._r8 + tropFound(:) = 0._r8 + tropDZ(:,:) = fillvalue + + do i = 1, ncol + if (tropLev(i) /= NOTFOUND) then + tropPdf(i, tropLev(i)) = 1._r8 + tropFound(i) = 1._r8 + tropDZ(i,:) = pstate%zm(i,:) - tropZ(i) + end if + end do + + call outfld('TROPF_P', tropP(:ncol), ncol, lchnk) + call outfld('TROPF_T', tropT(:ncol), ncol, lchnk) + call outfld('TROPF_Z', tropZ(:ncol), ncol, lchnk) + call outfld('TROPF_DZ', tropDZ(:ncol, :), ncol, lchnk) + call outfld('TROPF_PD', tropPdf(:ncol, :), ncol, lchnk) + call outfld('TROPF_FD', tropFound(:ncol), ncol, lchnk) + + + ! If requested, do all of the algorithms. + if (output_all) then + + do alg = 2, TROP_NALG + + ! Find the tropopause using just the analytic algorithm. + call tropopause_find(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=alg, backup=TROP_ALG_NONE) + + tropPdf(:,:) = 0._r8 + tropFound(:) = 0._r8 + + do i = 1, ncol + if (tropLev(i) /= NOTFOUND) then + tropPdf(i, tropLev(i)) = 1._r8 + tropFound(i) = 1._r8 + end if + end do + + call outfld('TROP' // TROP_LETTER(alg) // '_P', tropP(:ncol), ncol, lchnk) + call outfld('TROP' // TROP_LETTER(alg) // '_T', tropT(:ncol), ncol, lchnk) + call outfld('TROP' // TROP_LETTER(alg) // '_Z', tropZ(:ncol), ncol, lchnk) + call outfld('TROP' // TROP_LETTER(alg) // '_PD', tropPdf(:ncol, :), ncol, lchnk) + call outfld('TROP' // TROP_LETTER(alg) // '_FD', tropFound(:ncol), ncol, lchnk) + end do + end if + + return + end subroutine tropopause_output +end module tropopause From bf224a534d0d709b6ef5ffb1f663c1fa8c23e7d5 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 12 Aug 2024 23:48:04 -0400 Subject: [PATCH 02/31] Initial updates for CCPP-ization: - Rename to tropopause_find, _init, _run routines - Remove most uses of physics_state and clean argument lists - Remove use statements for physconst - Comment out history addfld/outfld calls for CAM-SIMA --- tropopause_find/tropopause_find.F90 | 1018 ++++++++++++++------------- 1 file changed, 542 insertions(+), 476 deletions(-) diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index a2fd8308..d70c8ad7 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -14,26 +14,29 @@ ! Author: Charles Bardeen ! Created: April, 2009 -module tropopause +module tropopause_find !--------------------------------------------------------------- ! ... variables for the tropopause module !--------------------------------------------------------------- - use shr_kind_mod, only : r8 => shr_kind_r8 + use ccpp_kinds, only : kind_phys use shr_const_mod, only : pi => shr_const_pi use ppgrid, only : pcols, pver, begchunk, endchunk use cam_abortutils, only : endrun use cam_logfile, only : iulog use cam_history_support, only : fillvalue use physics_types, only : physics_state - use physconst, only : cappa, rair, gravit use spmd_utils, only : masterproc implicit none private + + ! CCPP-compliant subroutines + public :: tropopause_find_init + public :: tropopause_find_run - public :: tropopause_readnl, tropopause_init, tropopause_find, tropopause_output + public :: tropopause_readnl, tropopause_output public :: tropopause_findChemTrop public :: TROP_ALG_NONE, TROP_ALG_ANALYTIC, TROP_ALG_CLIMATE public :: TROP_ALG_STOBIE, TROP_ALG_HYBSTOB, TROP_ALG_TWMO, TROP_ALG_WMO @@ -69,20 +72,21 @@ module tropopause character(len=256) :: tropopause_climo_file = 'trop_climo' ! absolute filepath of climatology file ! These variables are used to store the climatology data. - real(r8) :: days(12) ! days in the climatology - real(r8), pointer :: tropp_p_loc(:,:,:) ! climatological tropopause pressures + real(kind_phys) :: days(12) ! days in the climatology + real(kind_phys), pointer :: tropp_p_loc(:,:,:) ! climatological tropopause pressures integer, parameter :: NOTFOUND = -1 - real(r8),parameter :: ALPHA = 0.03_r8 + real(kind_phys),parameter :: ALPHA = 0.03_kind_phys ! physical constants ! These constants are set in module variables rather than as parameters ! to support the aquaplanet mode in which the constants have values determined ! by the experiment protocol - real(r8) :: cnst_kap ! = cappa - real(r8) :: cnst_faktor ! = -gravit/rair - real(r8) :: cnst_ka1 ! = cnst_kap - 1._r8 + real(kind_phys) :: cnst_kap ! = cappa + real(kind_phys) :: cnst_faktor ! = -gravit/rair + real(kind_phys) :: cnst_rga ! = 1/gravit + real(kind_phys) :: cnst_ka1 ! = cnst_kap - 1._kind_phys !================================================================================================ contains @@ -130,90 +134,173 @@ end subroutine tropopause_readnl ! other methods in this module can be used. Its main tasks are to read in the ! climatology from a file and to define the output fields. Much of this code ! is taken from mo_tropopause. - subroutine tropopause_init() + !> \section arg_table_tropopause_find_init Argument Table + !! \htmlinclude tropopause_find_init.html + subroutine tropopause_find_init(cappa, rair, gravit, errmsg, errflg) - use cam_history, only: addfld, horiz_only + !use cam_history, only: addfld, horiz_only + real(kind_phys), intent(in) :: cappa ! R/Cp + real(kind_phys), intent(in) :: rair ! Dry air gas constant (J K-1 kg-1) + real(kind_phys), intent(in) :: gravit ! Gravitational acceleration (m s-2) + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg - implicit none + errmsg = ' ' + errflg = 0 ! define physical constants cnst_kap = cappa cnst_faktor = -gravit/rair - cnst_ka1 = cnst_kap - 1._r8 + cnst_rga = 1._kind_phys/gravit ! Reciprocal of gravit (s2 m-1) + cnst_ka1 = cnst_kap - 1._kind_phys ! Define the output fields. - call addfld('TROP_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure', flag_xyfill=.True.) - call addfld('TROP_T', horiz_only, 'A', 'K', 'Tropopause Temperature', flag_xyfill=.True.) - call addfld('TROP_Z', horiz_only, 'A', 'm', 'Tropopause Height', flag_xyfill=.True.) - call addfld('TROP_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height') - call addfld('TROP_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Probabilty') - call addfld('TROP_FD', horiz_only, 'A', 'probability', 'Tropopause Found') + ! call addfld('TROP_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure', flag_xyfill=.True.) + ! call addfld('TROP_T', horiz_only, 'A', 'K', 'Tropopause Temperature', flag_xyfill=.True.) + ! call addfld('TROP_Z', horiz_only, 'A', 'm', 'Tropopause Height', flag_xyfill=.True.) + ! call addfld('TROP_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height') + ! call addfld('TROP_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Probabilty') + ! call addfld('TROP_FD', horiz_only, 'A', 'probability', 'Tropopause Found') - call addfld('TROPP_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (primary)', flag_xyfill=.True.) - call addfld('TROPP_T', horiz_only, 'A', 'K', 'Tropopause Temperature (primary)', flag_xyfill=.True.) - call addfld('TROPP_Z', horiz_only, 'A', 'm', 'Tropopause Height (primary)', flag_xyfill=.True.) - call addfld('TROPP_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height (primary)') - call addfld('TROPP_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (primary)') - call addfld('TROPP_FD', horiz_only, 'A', 'probability', 'Tropopause Found (primary)') + ! call addfld('TROPP_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (primary)', flag_xyfill=.True.) + ! call addfld('TROPP_T', horiz_only, 'A', 'K', 'Tropopause Temperature (primary)', flag_xyfill=.True.) + ! call addfld('TROPP_Z', horiz_only, 'A', 'm', 'Tropopause Height (primary)', flag_xyfill=.True.) + ! call addfld('TROPP_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height (primary)') + ! call addfld('TROPP_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (primary)') + ! call addfld('TROPP_FD', horiz_only, 'A', 'probability', 'Tropopause Found (primary)') - call addfld('TROPF_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (cold point)', flag_xyfill=.True.) - call addfld('TROPF_T', horiz_only, 'A', 'K', 'Tropopause Temperature (cold point)', flag_xyfill=.True.) - call addfld('TROPF_Z', horiz_only, 'A', 'm', 'Tropopause Height (cold point)', flag_xyfill=.True.) - call addfld('TROPF_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height (cold point)', flag_xyfill=.True.) - call addfld('TROPF_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (cold point)') - call addfld('TROPF_FD', horiz_only, 'A', 'probability', 'Tropopause Found (cold point)') - - call addfld( 'hstobie_trop', (/ 'lev' /), 'I', 'fraction of model time', 'Lowest level with stratospheric chemsitry') - call addfld( 'hstobie_linoz', (/ 'lev' /), 'I', 'fraction of model time', 'Lowest possible Linoz level') - call addfld( 'hstobie_tropop', (/ 'lev' /), 'I', 'fraction of model time', & - 'Troposphere boundary calculated in chemistry' ) - - ! If requested, be prepared to output results from all of the methods. - if (output_all) then - call addfld('TROPA_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (analytic)', flag_xyfill=.True.) - call addfld('TROPA_T', horiz_only, 'A', 'K', 'Tropopause Temperature (analytic)', flag_xyfill=.True.) - call addfld('TROPA_Z', horiz_only, 'A', 'm', 'Tropopause Height (analytic)', flag_xyfill=.True.) - call addfld('TROPA_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (analytic)') - call addfld('TROPA_FD', horiz_only, 'A', 'probability', 'Tropopause Found (analytic)') - - call addfld('TROPC_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (climatology)', flag_xyfill=.True.) - call addfld('TROPC_T', horiz_only, 'A', 'K', 'Tropopause Temperature (climatology)', flag_xyfill=.True.) - call addfld('TROPC_Z', horiz_only, 'A', 'm', 'Tropopause Height (climatology)', flag_xyfill=.True.) - call addfld('TROPC_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (climatology)') - call addfld('TROPC_FD', horiz_only, 'A', 'probability', 'Tropopause Found (climatology)') - - call addfld('TROPS_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (stobie)', flag_xyfill=.True.) - call addfld('TROPS_T', horiz_only, 'A', 'K', 'Tropopause Temperature (stobie)', flag_xyfill=.True.) - call addfld('TROPS_Z', horiz_only, 'A', 'm', 'Tropopause Height (stobie)', flag_xyfill=.True.) - call addfld('TROPS_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (stobie)') - call addfld('TROPS_FD', horiz_only, 'A', 'probability', 'Tropopause Found (stobie)') - - call addfld('TROPT_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (twmo)', flag_xyfill=.True.) - call addfld('TROPT_T', horiz_only, 'A', 'K', 'Tropopause Temperature (twmo)', flag_xyfill=.True.) - call addfld('TROPT_Z', horiz_only, 'A', 'm', 'Tropopause Height (twmo)', flag_xyfill=.True.) - call addfld('TROPT_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (twmo)') - call addfld('TROPT_FD', horiz_only, 'A', 'probability', 'Tropopause Found (twmo)') - - call addfld('TROPW_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (WMO)', flag_xyfill=.True.) - call addfld('TROPW_T', horiz_only, 'A', 'K', 'Tropopause Temperature (WMO)', flag_xyfill=.True.) - call addfld('TROPW_Z', horiz_only, 'A', 'm', 'Tropopause Height (WMO)', flag_xyfill=.True.) - call addfld('TROPW_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (WMO)') - call addfld('TROPW_FD', horiz_only, 'A', 'probability', 'Tropopause Found (WMO)') - - call addfld('TROPH_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (Hybrid Stobie)', flag_xyfill=.True.) - call addfld('TROPH_T', horiz_only, 'A', 'K', 'Tropopause Temperature (Hybrid Stobie)', flag_xyfill=.True.) - call addfld('TROPH_Z', horiz_only, 'A', 'm', 'Tropopause Height (Hybrid Stobie)', flag_xyfill=.True.) - call addfld('TROPH_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (Hybrid Stobie)') - call addfld('TROPH_FD', horiz_only, 'A', 'probability', 'Tropopause Found (Hybrid Stobie)') - end if + ! call addfld('TROPF_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (cold point)', flag_xyfill=.True.) + ! call addfld('TROPF_T', horiz_only, 'A', 'K', 'Tropopause Temperature (cold point)', flag_xyfill=.True.) + ! call addfld('TROPF_Z', horiz_only, 'A', 'm', 'Tropopause Height (cold point)', flag_xyfill=.True.) + ! call addfld('TROPF_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height (cold point)', flag_xyfill=.True.) + ! call addfld('TROPF_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (cold point)') + ! call addfld('TROPF_FD', horiz_only, 'A', 'probability', 'Tropopause Found (cold point)') + + ! call addfld( 'hstobie_trop', (/ 'lev' /), 'I', 'fraction of model time', 'Lowest level with stratospheric chemsitry') + ! call addfld( 'hstobie_linoz', (/ 'lev' /), 'I', 'fraction of model time', 'Lowest possible Linoz level') + ! call addfld( 'hstobie_tropop', (/ 'lev' /), 'I', 'fraction of model time', & + ! 'Troposphere boundary calculated in chemistry' ) + + ! ! If requested, be prepared to output results from all of the methods. + ! if (output_all) then + ! call addfld('TROPA_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (analytic)', flag_xyfill=.True.) + ! call addfld('TROPA_T', horiz_only, 'A', 'K', 'Tropopause Temperature (analytic)', flag_xyfill=.True.) + ! call addfld('TROPA_Z', horiz_only, 'A', 'm', 'Tropopause Height (analytic)', flag_xyfill=.True.) + ! call addfld('TROPA_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (analytic)') + ! call addfld('TROPA_FD', horiz_only, 'A', 'probability', 'Tropopause Found (analytic)') + + ! call addfld('TROPC_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (climatology)', flag_xyfill=.True.) + ! call addfld('TROPC_T', horiz_only, 'A', 'K', 'Tropopause Temperature (climatology)', flag_xyfill=.True.) + ! call addfld('TROPC_Z', horiz_only, 'A', 'm', 'Tropopause Height (climatology)', flag_xyfill=.True.) + ! call addfld('TROPC_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (climatology)') + ! call addfld('TROPC_FD', horiz_only, 'A', 'probability', 'Tropopause Found (climatology)') + + ! call addfld('TROPS_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (stobie)', flag_xyfill=.True.) + ! call addfld('TROPS_T', horiz_only, 'A', 'K', 'Tropopause Temperature (stobie)', flag_xyfill=.True.) + ! call addfld('TROPS_Z', horiz_only, 'A', 'm', 'Tropopause Height (stobie)', flag_xyfill=.True.) + ! call addfld('TROPS_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (stobie)') + ! call addfld('TROPS_FD', horiz_only, 'A', 'probability', 'Tropopause Found (stobie)') + + ! call addfld('TROPT_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (twmo)', flag_xyfill=.True.) + ! call addfld('TROPT_T', horiz_only, 'A', 'K', 'Tropopause Temperature (twmo)', flag_xyfill=.True.) + ! call addfld('TROPT_Z', horiz_only, 'A', 'm', 'Tropopause Height (twmo)', flag_xyfill=.True.) + ! call addfld('TROPT_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (twmo)') + ! call addfld('TROPT_FD', horiz_only, 'A', 'probability', 'Tropopause Found (twmo)') + + ! call addfld('TROPW_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (WMO)', flag_xyfill=.True.) + ! call addfld('TROPW_T', horiz_only, 'A', 'K', 'Tropopause Temperature (WMO)', flag_xyfill=.True.) + ! call addfld('TROPW_Z', horiz_only, 'A', 'm', 'Tropopause Height (WMO)', flag_xyfill=.True.) + ! call addfld('TROPW_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (WMO)') + ! call addfld('TROPW_FD', horiz_only, 'A', 'probability', 'Tropopause Found (WMO)') + + ! call addfld('TROPH_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (Hybrid Stobie)', flag_xyfill=.True.) + ! call addfld('TROPH_T', horiz_only, 'A', 'K', 'Tropopause Temperature (Hybrid Stobie)', flag_xyfill=.True.) + ! call addfld('TROPH_Z', horiz_only, 'A', 'm', 'Tropopause Height (Hybrid Stobie)', flag_xyfill=.True.) + ! call addfld('TROPH_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (Hybrid Stobie)') + ! call addfld('TROPH_FD', horiz_only, 'A', 'probability', 'Tropopause Found (Hybrid Stobie)') + ! end if call tropopause_read_file() - end subroutine tropopause_init - + end subroutine tropopause_find_init + + + ! Searches all the columns in the chunk and attempts to identify the tropopause. + ! Two routines can be specifed, a primary routine which is tried first and a + ! backup routine which will be tried only if the first routine fails. If the + ! tropopause can not be identified by either routine, then a NOTFOUND is returned + ! for the tropopause level, temperature and pressure. + !> \section arg_table_tropopause_find_run Argument Table + !! \htmlinclude tropopause_find_run.html + subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + tropLev, tropP, tropT, tropZ, primary, backup, & + errmsg, errflg) + + implicit none + + real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns + real(kind_phys), intent(in) :: pver ! Number of vertical levels + real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) + real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) + + integer, optional, intent(in) :: primary ! primary detection algorithm + integer, optional, intent(in) :: backup ! backup detection algorithm + integer, intent(out) :: tropLev(:) ! tropopause level index + real(kind_phys), optional, intent(out) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), optional, intent(out) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), optional, intent(out) :: tropZ(:) ! tropopause height (m) + + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + + errmsg = ' ' + errflg = 0 + + ! Local Variable + integer :: primAlg ! Primary algorithm + integer :: backAlg ! Backup algorithm + + ! Initialize the results to a missing value, so that the algorithms will + ! attempt to find the tropopause for all of them. + tropLev(:) = NOTFOUND + if (present(tropP)) tropP(:) = fillvalue + if (present(tropT)) tropT(:) = fillvalue + if (present(tropZ)) tropZ(:) = fillvalue + + ! Set the algorithms to be used, either the ones provided or the defaults. + if (present(primary)) then + primAlg = primary + else + primAlg = default_primary + end if + + if (present(backup)) then + backAlg = backup + else + backAlg = default_backup + end if + + ! Try to find the tropopause using the primary algorithm. + if (primAlg /= TROP_ALG_NONE) then + call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + primAlg, tropLev, tropP, tropT, tropZ) + end if + + if ((backAlg /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then + call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + backAlg, tropLev, tropP, tropT, tropZ) + end if + + return + end subroutine tropopause_find_run subroutine tropopause_read_file !------------------------------------------------------------------ @@ -244,11 +331,11 @@ subroutine tropopause_read_file 716, 816, 915, 1016, 1115, 1216 /) integer :: plon, plat type(interp_type) :: lon_wgts, lat_wgts - real(r8), allocatable :: tropp_p_in(:,:,:) - real(r8), allocatable :: lat(:) - real(r8), allocatable :: lon(:) - real(r8) :: to_lats(pcols), to_lons(pcols) - real(r8), parameter :: d2r=pi/180._r8, zero=0._r8, twopi=pi*2._r8 + real(kind_phys), allocatable :: tropp_p_in(:,:,:) + real(kind_phys), allocatable :: lat(:) + real(kind_phys), allocatable :: lon(:) + real(kind_phys) :: to_lats(pcols), to_lons(pcols) + real(kind_phys), parameter :: d2r=pi/180._kind_phys, zero=0._kind_phys, twopi=pi*2._kind_phys character(len=256) :: locfn integer :: c, ncols @@ -269,7 +356,7 @@ subroutine tropopause_read_file ierr = pio_inq_dimid( pio_id, 'time', dimid ) ierr = pio_inq_dimlen( pio_id, dimid, ntimes ) if( ntimes /= 12 )then - write(iulog,*) 'tropopause_init: number of months = ',ntimes,'; expecting 12' + write(iulog,*) 'tropopause_find_init: number of months = ',ntimes,'; expecting 12' call endrun end if !----------------------------------------------------------------------- @@ -279,7 +366,7 @@ subroutine tropopause_read_file ierr = pio_inq_dimlen( pio_id, dimid, nlat ) allocate( lat(nlat), stat=ierr ) if( ierr /= 0 ) then - write(iulog,*) 'tropopause_init: lat allocation error = ',ierr + write(iulog,*) 'tropopause_find_init: lat allocation error = ',ierr call endrun end if ierr = pio_inq_varid( pio_id, 'lat', vid ) @@ -292,7 +379,7 @@ subroutine tropopause_read_file ierr = pio_inq_dimlen( pio_id, dimid, nlon ) allocate( lon(nlon), stat=ierr ) if( ierr /= 0 ) then - write(iulog,*) 'tropopause_init: lon allocation error = ',ierr + write(iulog,*) 'tropopause_find_init: lon allocation error = ',ierr call endrun end if ierr = pio_inq_varid( pio_id, 'lon', vid ) @@ -304,7 +391,7 @@ subroutine tropopause_read_file !------------------------------------------------------------------ allocate( tropp_p_in(nlon,nlat,ntimes), stat=ierr ) if( ierr /= 0 ) then - write(iulog,*) 'tropopause_init: tropp_p_in allocation error = ',ierr + write(iulog,*) 'tropopause_find_init: tropp_p_in allocation error = ',ierr call endrun end if !------------------------------------------------------------------ @@ -327,7 +414,7 @@ subroutine tropopause_read_file allocate( tropp_p_loc(pcols,begchunk:endchunk,ntimes), stat=ierr ) if( ierr /= 0 ) then - write(iulog,*) 'tropopause_init: tropp_p_loc allocation error = ',ierr + write(iulog,*) 'tropopause_find_init: tropp_p_loc allocation error = ',ierr call endrun end if @@ -355,7 +442,7 @@ subroutine tropopause_read_file days(n) = get_calday( dates(n), 0 ) end do if (masterproc) then - write(iulog,*) 'tropopause_init : days' + write(iulog,*) 'tropopause_find_init : days' write(iulog,'(1p,5g15.8)') days(:) endif @@ -364,26 +451,27 @@ end subroutine tropopause_read_file ! This analytic expression closely matches the mean tropopause determined ! by the NCEP reanalysis and has been used by the radiation code. - subroutine tropopause_analytic(pstate, tropLev, tropP, tropT, tropZ) - - implicit none - - type(physics_state), intent(in) :: pstate - integer, intent(inout) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) + subroutine tropopause_analytic(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + tropLev, tropP, tropT, tropZ) + + real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns + real(kind_phys), intent(in) :: pver ! Number of vertical levels + real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) + real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) + integer, intent(inout) :: tropLev(:) ! tropopause level index + real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) ! Local Variables integer :: i integer :: k - integer :: ncol ! number of columns in the chunk - integer :: lchnk ! chunk identifier - real(r8) :: tP ! tropopause pressure (Pa) - - ! Information about the chunk. - lchnk = pstate%lchnk - ncol = pstate%ncol + real(kind_phys) :: tP ! tropopause pressure (Pa) ! Iterate over all of the columns. do i = 1, ncol @@ -392,11 +480,11 @@ subroutine tropopause_analytic(pstate, tropLev, tropP, tropT, tropZ) if (tropLev(i) == NOTFOUND) then ! Calculate the pressure of the tropopause. - tP = (25000.0_r8 - 15000.0_r8 * (cos(pstate%lat(i)))**2) + tP = (25000.0_kind_phys - 15000.0_kind_phys * (cos(lat(i)))**2) ! Find the level that contains the tropopause. do k = pver, 2, -1 - if (tP >= pstate%pint(i, k)) then + if (tP >= pint(i, k)) then tropLev(i) = k exit end if @@ -406,11 +494,11 @@ subroutine tropopause_analytic(pstate, tropLev, tropP, tropT, tropZ) if (present(tropP)) tropP(i) = tP if (present(tropT)) then - tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP) + tropT(i) = tropopause_interpolateT(pmid, t, i, tropLev(i), tP) end if if (present(tropZ)) then - tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP) + tropZ(i) = tropopause_interpolateZ(pint, pmid, zi, zm, phis, i, tropLev(i), tP) end if end if end do @@ -422,32 +510,37 @@ end subroutine tropopause_analytic ! ! NOTE: The data is read in during tropopause_init and stored in the module ! variable trop - subroutine tropopause_climate(pstate, tropLev, tropP, tropT, tropZ) + subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + tropLev, tropP, tropT, tropZ) use time_manager, only : get_curr_calday - implicit none - - type(physics_state), intent(in) :: pstate - integer, intent(inout) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) + real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns + real(kind_phys), intent(in) :: pver ! Number of vertical levels + real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) + real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) + integer, intent(inout) :: tropLev(:) ! tropopause level index + real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) ! Local Variables integer :: i integer :: k integer :: m - integer :: ncol ! number of columns in the chunk integer :: lchnk ! chunk identifier - real(r8) :: tP ! tropopause pressure (Pa) - real(r8) :: calday ! day of year including fraction - real(r8) :: dels + real(kind_phys) :: tP ! tropopause pressure (Pa) + real(kind_phys) :: calday ! day of year including fraction + real(kind_phys) :: dels integer :: last integer :: next ! Information about the chunk. lchnk = pstate%lchnk - ncol = pstate%ncol ! If any columns remain to be indentified, the nget the current ! day from the calendar. @@ -463,11 +556,11 @@ subroutine tropopause_climate(pstate, tropLev, tropP, tropT, tropZ) if( calday < days(1) ) then next = 1 last = 12 - dels = (365._r8 + calday - days(12)) / (365._r8 + days(1) - days(12)) + dels = (365._kind_phys + calday - days(12)) / (365._kind_phys + days(1) - days(12)) else if( calday >= days(12) ) then next = 1 last = 12 - dels = (calday - days(12)) / (365._r8 + days(1) - days(12)) + dels = (calday - days(12)) / (365._kind_phys + days(1) - days(12)) else do m = 11,1,-1 if( calday >= days(m) ) then @@ -479,7 +572,7 @@ subroutine tropopause_climate(pstate, tropLev, tropP, tropT, tropZ) dels = (calday - days(m)) / (days(m+1) - days(m)) end if - dels = max( min( 1._r8,dels ),0._r8 ) + dels = max( min( 1._kind_phys,dels ),0._kind_phys ) ! Iterate over all of the columns. @@ -497,7 +590,7 @@ subroutine tropopause_climate(pstate, tropLev, tropP, tropT, tropZ) ! Find the associated level. do k = pver, 2, -1 - if (tP >= pstate%pint(i, k)) then + if (tP >= pint(i, k)) then tropLev(i) = k exit end if @@ -507,11 +600,11 @@ subroutine tropopause_climate(pstate, tropLev, tropP, tropT, tropZ) if (present(tropP)) tropP(i) = tP if (present(tropT)) then - tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP) + tropT(i) = tropopause_interpolateT(pmid, t, i, tropLev(i), tP) end if if (present(tropZ)) then - tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP) + tropZ(i) = tropopause_interpolateZ(pint, pmid, zi, zm, phis, i, tropLev(i), tP) end if end if end do @@ -522,8 +615,9 @@ end subroutine tropopause_climate !----------------------------------------------------------------------- !----------------------------------------------------------------------- - subroutine tropopause_hybridstobie(pstate, tropLev, tropP, tropT, tropZ) - use cam_history, only : outfld + subroutine tropopause_hybridstobie(ncol, pver, pmid, t, zm, & + tropLev, tropP, tropT, tropZ) + !use cam_history, only : outfld !----------------------------------------------------------------------- ! Originally written by Philip Cameron-Smith, LLNL @@ -537,48 +631,49 @@ subroutine tropopause_hybridstobie(pstate, tropLev, tropP, tropT, tropZ) !----------------------------------------------------------------------- ! ... Local variables !----------------------------------------------------------------------- + real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns + real(kind_phys), intent(in) :: pver ! Number of vertical levelserp + real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) + real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + + integer, intent(inout) :: tropLev(:) ! tropopause level index + real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) - implicit none - - type(physics_state), intent(in) :: pstate - integer, intent(inout) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) - - real(r8),parameter :: min_Stobie_Pressure= 40.E2_r8 !For case 2 & 4. [Pa] - real(r8),parameter :: max_Linoz_Pressure =208.E2_r8 !For case 4. [Pa] + real(kind_phys),parameter :: min_Stobie_Pressure= 40.E2_kind_phys !For case 2 & 4. [Pa] + real(kind_phys),parameter :: max_Linoz_Pressure =208.E2_kind_phys !For case 4. [Pa] integer :: i, k, ncol - real(r8) :: stobie_min, shybrid_temp !temporary variable for case 2 & 3. + real(kind_phys) :: stobie_min, shybrid_temp !temporary variable for case 2 & 3. integer :: ltrop_linoz(pcols) !Lowest possible Linoz vertical level integer :: ltrop_trop(pcols) !Tropopause level for hybrid case. logical :: ltrop_linoz_set !Flag that lowest linoz level already found. - real(r8) :: trop_output(pcols,pver) !For output purposes only. - real(r8) :: trop_linoz_output(pcols,pver) !For output purposes only. - real(r8) :: trop_trop_output(pcols,pver) !For output purposes only. + real(kind_phys) :: trop_output(pcols,pver) !For output purposes only. + real(kind_phys) :: trop_linoz_output(pcols,pver) !For output purposes only. + real(kind_phys) :: trop_trop_output(pcols,pver) !For output purposes only. ! write(iulog,*) 'In set_chem_trop, o3_ndx =',o3_ndx ltrop_linoz(:) = 1 ! Initialize to default value. ltrop_trop(:) = 1 ! Initialize to default value. - ncol = pstate%ncol LOOP_COL4: do i=1,ncol ! Skip column in which the tropopause has already been found. not_found: if (tropLev(i) == NOTFOUND) then - stobie_min = 1.e10_r8 ! An impossibly large number + stobie_min = 1.e10_kind_phys ! An impossibly large number ltrop_linoz_set = .FALSE. LOOP_LEV: do k=pver,1,-1 - IF (pstate%pmid(i,k) < min_stobie_pressure) cycle - shybrid_temp = ALPHA * pstate%t(i,k) - Log10(pstate%pmid(i,k)) + IF (pmid(i,k) < min_stobie_pressure) cycle + shybrid_temp = ALPHA * t(i,k) - Log10(pmid(i,k)) !PJC_NOTE: the units of pmid won't matter, because it is just an additive offset. IF (shybrid_temp0) then - trop_output(i,tropLev(i))=1._r8 - trop_linoz_output(i,ltrop_linoz(i))=1._r8 - trop_trop_output(i,ltrop_trop(i))=1._r8 + trop_output(i,tropLev(i))=1._kind_phys + trop_linoz_output(i,ltrop_linoz(i))=1._kind_phys + trop_trop_output(i,ltrop_trop(i))=1._kind_phys endif enddo - call outfld( 'hstobie_trop', trop_output(:ncol,:), ncol, pstate%lchnk ) - call outfld( 'hstobie_linoz', trop_linoz_output(:ncol,:), ncol, pstate%lchnk ) - call outfld( 'hstobie_tropop', trop_trop_output(:ncol,:), ncol, pstate%lchnk ) + !call outfld( 'hstobie_trop', trop_output(:ncol,:), ncol, pstate%lchnk ) + !call outfld( 'hstobie_linoz', trop_linoz_output(:ncol,:), ncol, pstate%lchnk ) + !call outfld( 'hstobie_tropop', trop_trop_output(:ncol,:), ncol, pstate%lchnk ) - endsubroutine tropopause_hybridstobie + end subroutine tropopause_hybridstobie ! This routine originates with Stobie at NASA Goddard, but does not have a ! known reference. It was supplied by Philip Cameron-Smith of LLNL. ! - subroutine tropopause_stobie(pstate, tropLev, tropP, tropT, tropZ) - - implicit none - - type(physics_state), intent(in) :: pstate - integer, intent(inout) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) + subroutine tropopause_stobie(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + tropLev, tropP, tropT, tropZ) + + real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns + real(kind_phys), intent(in) :: pver ! Number of vertical levels + real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) + real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) + + integer, intent(inout) :: tropLev(:) ! tropopause level index + real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) ! Local Variables integer :: i integer :: k - integer :: ncol ! number of columns in the chunk - integer :: lchnk ! chunk identifier integer :: tLev ! tropopause level - real(r8) :: tP ! tropopause pressure (Pa) - real(r8) :: stobie(pver) ! stobie weighted temperature - real(r8) :: sTrop ! stobie value at the tropopause - - ! Information about the chunk. - lchnk = pstate%lchnk - ncol = pstate%ncol + real(kind_phys) :: tP ! tropopause pressure (Pa) + real(kind_phys) :: stobie(pver) ! stobie weighted temperature + real(kind_phys) :: sTrop ! stobie value at the tropopause ! Iterate over all of the columns. do i = 1, ncol @@ -651,24 +748,24 @@ subroutine tropopause_stobie(pstate, tropLev, tropP, tropT, tropZ) if (tropLev(i) == NOTFOUND) then ! Caclulate a pressure weighted temperature. - stobie(:) = ALPHA * pstate%t(i,:) - log10(pstate%pmid(i, :)) + stobie(:) = ALPHA * t(i,:) - log10(pmid(i, :)) ! Search from the bottom up, looking for the first minimum. tLev = -1 do k = pver-1, 1, -1 - if (pstate%pmid(i, k) <= 4000._r8) then + if (pmid(i, k) <= 4000._kind_phys) then exit end if - if (pstate%pmid(i, k) >= 55000._r8) then + if (pmid(i, k) >= 55000._kind_phys) then cycle end if if ((tLev == -1) .or. (stobie(k) < sTrop)) then tLev = k - tP = pstate%pmid(i, k) + tP = pmid(i, k) sTrop = stobie(k) end if end do @@ -680,11 +777,11 @@ subroutine tropopause_stobie(pstate, tropLev, tropP, tropT, tropZ) if (present(tropP)) tropP(i) = tP if (present(tropT)) then - tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP) + tropT(i) = tropopause_interpolateT(pmid, t, i, tropLev(i), tP) end if if (present(tropZ)) then - tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP) + tropZ(i) = tropopause_interpolateZ(pint, pmid, zi, zm, phis, i, tropLev(i), tP) end if end if end if @@ -719,28 +816,28 @@ end subroutine tropopause_stobie !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine twmo(t, p, plimu, pliml, gam, trp) - real(r8), intent(in), dimension(:) :: t, p - real(r8), intent(in) :: plimu, pliml, gam - real(r8), intent(out) :: trp + real(kind_phys), intent(in), dimension(:) :: t, p + real(kind_phys), intent(in) :: plimu, pliml, gam + real(kind_phys), intent(out) :: trp - real(r8), parameter :: deltaz = 2000.0_r8 + real(kind_phys), parameter :: deltaz = 2000.0_kind_phys - real(r8) :: pmk, pm, a, b, tm, dtdp, dtdz - real(r8) :: ag, bg, ptph - real(r8) :: pm0, pmk0, dtdz0 - real(r8) :: p2km, asum, aquer - real(r8) :: pmk2, pm2, a2, b2, tm2, dtdp2, dtdz2 + real(kind_phys) :: pmk, pm, a, b, tm, dtdp, dtdz + real(kind_phys) :: ag, bg, ptph + real(kind_phys) :: pm0, pmk0, dtdz0 + real(kind_phys) :: p2km, asum, aquer + real(kind_phys) :: pmk2, pm2, a2, b2, tm2, dtdp2, dtdz2 integer :: level integer :: icount, jj integer :: j - trp=-99.0_r8 ! negative means not valid + trp=-99.0_kind_phys ! negative means not valid ! initialize start level ! dt/dz level = size(t) - pmk= .5_r8 * (p(level-1)**cnst_kap+p(level)**cnst_kap) + pmk= .5_kind_phys * (p(level-1)**cnst_kap+p(level)**cnst_kap) pm = pmk**(1/cnst_kap) a = (t(level-1)-t(level))/(p(level-1)**cnst_kap-p(level)**cnst_kap) b = t(level)-(a*p(level)**cnst_kap) @@ -754,7 +851,7 @@ subroutine twmo(t, p, plimu, pliml, gam, trp) dtdz0 = dtdz ! dt/dz - pmk= .5_r8 * (p(j-1)**cnst_kap+p(j)**cnst_kap) + pmk= .5_kind_phys * (p(j-1)**cnst_kap+p(j)**cnst_kap) pm = pmk**(1/cnst_kap) a = (t(j-1)-t(j))/(p(j-1)**cnst_kap-p(j)**cnst_kap) b = t(j)-(a*p(j)**cnst_kap) @@ -779,13 +876,13 @@ subroutine twmo(t, p, plimu, pliml, gam, trp) ! 2nd test: dtdz above 2 km must not exceed gam p2km = ptph + deltaz*(pm/tm)*cnst_faktor ! p at ptph + 2km - asum = 0.0_r8 ! dtdz above + asum = 0.0_kind_phys ! dtdz above icount = 0 ! number of levels above ! test until apm < p2km in_loop: do jj=j,2,-1 - pmk2 = .5_r8 * (p(jj-1)**cnst_kap+p(jj)**cnst_kap) ! p mean ^kappa + pmk2 = .5_kind_phys * (p(jj-1)**cnst_kap+p(jj)**cnst_kap) ! p mean ^kappa pm2 = pmk2**(1/cnst_kap) ! p mean if(pm2.gt.ptph) cycle in_loop ! doesn't happen if(pm2.lt.p2km) exit in_loop ! ptropo is valid @@ -815,30 +912,31 @@ end subroutine twmo ! This routine uses an implementation of Reichler et al. [2003] done by ! Reichler and downloaded from his web site. This is similar to the WMO ! routines, but is designed for GCMs with a coarse vertical grid. - subroutine tropopause_twmo(pstate, tropLev, tropP, tropT, tropZ) - - implicit none - - type(physics_state), intent(in) :: pstate - integer, intent(inout) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) + subroutine tropopause_twmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + tropLev, tropP, tropT, tropZ) + + real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns + real(kind_phys), intent(in) :: pver ! Number of vertical levels + real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) + real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) + integer, intent(inout) :: tropLev(:) ! tropopause level index + real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) ! Local Variables - real(r8), parameter :: gam = -0.002_r8 ! K/m - real(r8), parameter :: plimu = 45000._r8 ! Pa - real(r8), parameter :: pliml = 7500._r8 ! Pa + real(kind_phys), parameter :: gam = -0.002_kind_phys ! K/m + real(kind_phys), parameter :: plimu = 45000._kind_phys ! Pa + real(kind_phys), parameter :: pliml = 7500._kind_phys ! Pa integer :: i integer :: k - integer :: ncol ! number of columns in the chunk - integer :: lchnk ! chunk identifier - real(r8) :: tP ! tropopause pressure (Pa) - - ! Information about the chunk. - lchnk = pstate%lchnk - ncol = pstate%ncol + real(kind_phys) :: tP ! tropopause pressure (Pa) ! Iterate over all of the columns. do i = 1, ncol @@ -847,14 +945,14 @@ subroutine tropopause_twmo(pstate, tropLev, tropP, tropT, tropZ) if (tropLev(i) == NOTFOUND) then ! Use the routine from Reichler. - call twmo(pstate%t(i, :), pstate%pmid(i, :), plimu, pliml, gam, tP) + call twmo(t(i, :), pmid(i, :), plimu, pliml, gam, tP) ! if successful, store of the results and find the level and temperature. if (tP > 0) then ! Find the associated level. do k = pver, 2, -1 - if (tP >= pstate%pint(i, k)) then + if (tP >= pint(i, k)) then tropLev(i) = k exit end if @@ -864,11 +962,11 @@ subroutine tropopause_twmo(pstate, tropLev, tropP, tropT, tropZ) if (present(tropP)) tropP(i) = tP if (present(tropT)) then - tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP) + tropT(i) = tropopause_interpolateT(pmid, t, i, tropLev(i), tP) end if if (present(tropZ)) then - tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP) + tropZ(i) = tropopause_interpolateZ(pint, pmid, zi, zm, phis, i, tropLev(i), tP) end if end if end if @@ -885,33 +983,27 @@ end subroutine tropopause_twmo ! NOTE: This code was modeled after the code in mo_tropopause; however, the ! requirement that dt be greater than 0 was removed and the check to make ! sure that the lapse rate is maintained for 2 km was added. - subroutine tropopause_wmo(pstate, tropLev, tropP, tropT, tropZ) - - implicit none + subroutine tropopause_wmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + tropLev, tropP, tropT, tropZ) type(physics_state), intent(in) :: pstate - integer, intent(inout) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) + integer, intent(inout) :: tropLev(:) ! tropopause level index + real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) ! Local Variables - real(r8), parameter :: ztrop_low = 5000._r8 ! lowest tropopause level allowed (m) - real(r8), parameter :: ztrop_high = 20000._r8 ! highest tropopause level allowed (m) - real(r8), parameter :: max_dtdz = 0.002_r8 ! max dt/dz for tropopause level (K/m) - real(r8), parameter :: min_trop_dz = 2000._r8 ! min tropopause thickness (m) + real(kind_phys), parameter :: ztrop_low = 5000._kind_phys ! lowest tropopause level allowed (m) + real(kind_phys), parameter :: ztrop_high = 20000._kind_phys ! highest tropopause level allowed (m) + real(kind_phys), parameter :: max_dtdz = 0.002_kind_phys ! max dt/dz for tropopause level (K/m) + real(kind_phys), parameter :: min_trop_dz = 2000._kind_phys ! min tropopause thickness (m) integer :: i integer :: k integer :: k2 integer :: ncol ! number of columns in the chunk - integer :: lchnk ! chunk identifier - real(r8) :: tP ! tropopause pressure (Pa) - real(r8) :: dt - - ! Information about the chunk. - lchnk = pstate%lchnk - ncol = pstate%ncol + real(kind_phys) :: tP ! tropopause pressure (Pa) + real(kind_phys) :: dt ! Iterate over all of the columns. do i = 1, ncol @@ -923,28 +1015,28 @@ subroutine tropopause_wmo(pstate, tropLev, tropP, tropT, tropZ) ! Skip levels below the minimum and stop if nothing is found ! before the maximum. - if (pstate%zm(i, k) < ztrop_low) then + if (zm(i, k) < ztrop_low) then cycle kloop - else if (pstate%zm(i, k) > ztrop_high) then + else if (zm(i, k) > ztrop_high) then exit kloop end if ! Compare the actual lapse rate to the threshold - dt = pstate%t(i, k) - pstate%t(i, k-1) + dt = t(i, k) - t(i, k-1) - if (dt <= (max_dtdz * (pstate%zm(i, k-1) - pstate%zm(i, k)))) then + if (dt <= (max_dtdz * (zm(i, k-1) - zm(i, k)))) then ! Make sure that the lapse rate stays below the threshold for the ! specified range. k2loop: do k2 = k-1, 2, -1 - if ((pstate%zm(i, k2) - pstate%zm(i, k)) >= min_trop_dz) then - tP = pstate%pmid(i, k) + if ((zm(i, k2) - zm(i, k)) >= min_trop_dz) then + tP = pmid(i, k) tropLev(i) = k exit k2loop end if - dt = pstate%t(i, k) - pstate%t(i, k2) - if (dt > (max_dtdz * (pstate%zm(i, k2) - pstate%zm(i, k)))) then + dt = t(i, k) - t(i, k2) + if (dt > (max_dtdz * (zm(i, k2) - zm(i, k)))) then exit k2loop end if end do k2loop @@ -957,11 +1049,11 @@ subroutine tropopause_wmo(pstate, tropLev, tropP, tropT, tropZ) if (present(tropP)) tropP(i) = tP if (present(tropT)) then - tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP) + tropT(i) = tropopause_interpolateT(pmid, t, i, tropLev(i), tP) end if if (present(tropZ)) then - tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP) + tropZ(i) = tropopause_interpolateZ(pint, pmid, zi, zm, phis, i, tropLev(i), tP) end if exit kloop @@ -978,35 +1070,37 @@ end subroutine tropopause_wmo ! This routine searches for the cold point tropopause, and uses a parabolic ! fit of the coldest point and two adjacent points to interpolate the cold point ! between model levels. - subroutine tropopause_cpp(pstate, tropLev, tropP, tropT, tropZ) - - implicit none - - type(physics_state), intent(in) :: pstate - integer, intent(inout) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) + subroutine tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + tropLev, tropP, tropT, tropZ) + + real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns + real(kind_phys), intent(in) :: pver ! Number of vertical levels + real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) + real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) + integer, intent(inout) :: tropLev(:) ! tropopause level index + real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) ! Local Variables - real(r8), parameter :: ztrop_low = 5000._r8 ! lowest tropopause level allowed (m) - real(r8), parameter :: ztrop_high = 25000._r8 ! highest tropopause level allowed (m) + real(kind_phys), parameter :: ztrop_low = 5000._kind_phys ! lowest tropopause level allowed (m) + real(kind_phys), parameter :: ztrop_high = 25000._kind_phys ! highest tropopause level allowed (m) integer :: i integer :: k, firstk, lastk integer :: k2 integer :: ncol ! number of columns in the chunk - integer :: lchnk ! chunk identifier - real(r8) :: tZ ! tropopause height (m) - real(r8) :: tmin - real(r8) :: f0, f1, f2 - real(r8) :: x0, x1, x2 - real(r8) :: c0, c1, c2 - real(r8) :: a, b, c - - ! Information about the chunk. - lchnk = pstate%lchnk - ncol = pstate%ncol + real(kind_phys) :: tZ ! tropopause height (m) + real(kind_phys) :: tmin + real(kind_phys) :: f0, f1, f2 + real(kind_phys) :: x0, x1, x2 + real(kind_phys) :: c0, c1, c2 + real(kind_phys) :: a, b, c ! Iterate over all of the columns. do i = 1, ncol @@ -1016,24 +1110,24 @@ subroutine tropopause_cpp(pstate, tropLev, tropP, tropT, tropZ) ! Skip column in which the tropopause has already been found. if (tropLev(i) == NOTFOUND) then - tmin = 1e6_r8 + tmin = 1e6_kind_phys kloop: do k = pver-1, 2, -1 ! Skip levels below the minimum and stop if nothing is found ! before the maximum. - if (pstate%zm(i, k) < ztrop_low) then + if (zm(i, k) < ztrop_low) then firstk = k cycle kloop - else if (pstate%zm(i, k) > ztrop_high) then + else if (zm(i, k) > ztrop_high) then lastk = k exit kloop end if ! Find the coldest point - if (pstate%t(i, k) < tmin) then + if (t(i, k) < tmin) then tropLev(i) = k - tmin = pstate%t(i,k) + tmin = t(i,k) end if end do kloop @@ -1048,13 +1142,13 @@ subroutine tropopause_cpp(pstate, tropLev, tropP, tropT, tropZ) ! cold point and it its 2 surrounding points to interpolate ! between model levels. if (present(tropP) .or. present(tropZ) .or. present(tropT)) then - f0 = pstate%t(i, tropLev(i)-1) - f1 = pstate%t(i, tropLev(i)) - f2 = pstate%t(i, tropLev(i)+1) + f0 = t(i, tropLev(i)-1) + f1 = t(i, tropLev(i)) + f2 = t(i, tropLev(i)+1) - x0 = pstate%zm(i, tropLev(i)-1) - x1 = pstate%zm(i, tropLev(i)) - x2 = pstate%zm(i, tropLev(i)+1) + x0 = zm(i, tropLev(i)-1) + x1 = zm(i, tropLev(i)) + x2 = zm(i, tropLev(i)+1) c0 = (x0-x1)*(x0-x2) c1 = (x1-x0)*(x1-x2) @@ -1067,7 +1161,7 @@ subroutine tropopause_cpp(pstate, tropLev, tropP, tropT, tropZ) c = f0/c0*x1*x2 + f1/c1*x0*x2 + f2/c2*x0*x1 ! Find the altitude of the minimum temperature - tZ = 0.5_r8 * b / a + tZ = 0.5_kind_phys * b / a ! The fit should be between the upper and lower points, ! so skip the point if the fit fails. @@ -1077,7 +1171,7 @@ subroutine tropopause_cpp(pstate, tropLev, tropP, tropT, tropZ) ! Return the optional outputs if (present(tropP)) then - tropP(i) = tropopause_interpolateP(pstate, i, tropLev(i), tZ) + tropP(i) = tropopause_interpolateP(pmid, zm, i, tropLev(i), tZ) end if if (present(tropT)) then @@ -1095,60 +1189,6 @@ subroutine tropopause_cpp(pstate, tropLev, tropP, tropT, tropZ) return end subroutine tropopause_cpp - - - ! Searches all the columns in the chunk and attempts to identify the tropopause. - ! Two routines can be specifed, a primary routine which is tried first and a - ! backup routine which will be tried only if the first routine fails. If the - ! tropopause can not be identified by either routine, then a NOTFOUND is returned - ! for the tropopause level, temperature and pressure. - subroutine tropopause_find(pstate, tropLev, tropP, tropT, tropZ, primary, backup) - - implicit none - - type(physics_state), intent(in) :: pstate - integer, optional, intent(in) :: primary ! primary detection algorithm - integer, optional, intent(in) :: backup ! backup detection algorithm - integer, intent(out) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(out) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(out) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(out) :: tropZ(pcols) ! tropopause height (m) - - ! Local Variable - integer :: primAlg ! Primary algorithm - integer :: backAlg ! Backup algorithm - - ! Initialize the results to a missing value, so that the algorithms will - ! attempt to find the tropopause for all of them. - tropLev(:) = NOTFOUND - if (present(tropP)) tropP(:) = fillvalue - if (present(tropT)) tropT(:) = fillvalue - if (present(tropZ)) tropZ(:) = fillvalue - - ! Set the algorithms to be used, either the ones provided or the defaults. - if (present(primary)) then - primAlg = primary - else - primAlg = default_primary - end if - - if (present(backup)) then - backAlg = backup - else - backAlg = default_backup - end if - - ! Try to find the tropopause using the primary algorithm. - if (primAlg /= TROP_ALG_NONE) then - call tropopause_findUsing(pstate, primAlg, tropLev, tropP, tropT, tropZ) - end if - - if ((backAlg /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then - call tropopause_findUsing(pstate, backAlg, tropLev, tropP, tropT, tropZ) - end if - - return - end subroutine tropopause_find ! Searches all the columns in the chunk and attempts to identify the "chemical" ! tropopause. This is the lapse rate tropopause, backed up by the climatology @@ -1159,29 +1199,36 @@ end subroutine tropopause_find ! eliminate false events that are sometimes detected in the cold polar stratosphere. ! ! NOTE: This routine was adapted from code in chemistry.F90 and mo_gasphase_chemdr.F90. - subroutine tropopause_findChemTrop(pstate, tropLev, primary, backup) + subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zm, phis, & + tropLev, primary, backup) implicit none - type(physics_state), intent(in) :: pstate + real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns + real(kind_phys), intent(in) :: pver ! Number of vertical levels + real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) + real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) + integer, optional, intent(in) :: primary ! primary detection algorithm integer, optional, intent(in) :: backup ! backup detection algorithm - integer, intent(out) :: tropLev(pcols) ! tropopause level index + integer, intent(out) :: tropLev(:) ! tropopause level index ! Local Variable - real(r8), parameter :: rad2deg = 180._r8/pi ! radians to degrees conversion factor - real(r8) :: dlats(pcols) + real(kind_phys), parameter :: rad2deg = 180._kind_phys/pi ! radians to degrees conversion factor + real(kind_phys) :: dlats(pcols) integer :: i - integer :: ncol integer :: backAlg ! First use the lapse rate tropopause. - ncol = pstate%ncol - call tropopause_find(pstate, tropLev, primary=primary, backup=TROP_ALG_NONE) + call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zm, phis, tropLev, primary=primary, backup=TROP_ALG_NONE) ! Now check high latitudes (poleward of 50) and set the level to the ! climatology if the level was not found or is at P <= 125 hPa. - dlats(:ncol) = pstate%lat(:ncol) * rad2deg ! convert to degrees + dlats(:ncol) = lat(:ncol) * rad2deg ! convert to degrees if (present(backup)) then backAlg = backup @@ -1190,9 +1237,9 @@ subroutine tropopause_findChemTrop(pstate, tropLev, primary, backup) end if do i = 1, ncol - if (abs(dlats(i)) > 50._r8) then + if (abs(dlats(i)) > 50._kind_phys) then if (tropLev(i) .ne. NOTFOUND) then - if (pstate%pmid(i, tropLev(i)) <= 12500._r8) then + if (pmid(i, tropLev(i)) <= 12500._kind_phys) then tropLev(i) = NOTFOUND end if end if @@ -1201,7 +1248,7 @@ subroutine tropopause_findChemTrop(pstate, tropLev, primary, backup) ! Now use the backup algorithm if ((backAlg /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then - call tropopause_findUsing(pstate, backAlg, tropLev) + call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zm, phis, backAlg, tropLev) end if return @@ -1213,39 +1260,49 @@ end subroutine tropopause_findChemTrop ! ! NOTE: It is assumed that the output fields have been initialized by the ! caller, and only output values set to fillvalue will be detected. - subroutine tropopause_findUsing(pstate, algorithm, tropLev, tropP, tropT, tropZ) + subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + algorithm, tropLev, tropP, tropT, tropZ) implicit none - type(physics_state), intent(in) :: pstate + real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns + real(kind_phys), intent(in) :: pver ! Number of vertical levels + real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) + real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) + integer, intent(in) :: algorithm ! detection algorithm - integer, intent(inout) :: tropLev(pcols) ! tropopause level index - real(r8), optional, intent(inout) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8), optional, intent(inout) :: tropT(pcols) ! tropopause temperature (K) - real(r8), optional, intent(inout) :: tropZ(pcols) ! tropopause height (m) + integer, intent(inout) :: tropLev(:) ! tropopause level index + real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) ! Dispatch the request to the appropriate routine. select case(algorithm) case(TROP_ALG_ANALYTIC) - call tropopause_analytic(pstate, tropLev, tropP, tropT, tropZ) + call tropopause_analytic(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) case(TROP_ALG_CLIMATE) - call tropopause_climate(pstate, tropLev, tropP, tropT, tropZ) + call tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) case(TROP_ALG_STOBIE) - call tropopause_stobie(pstate, tropLev, tropP, tropT, tropZ) + call tropopause_stobie(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) case(TROP_ALG_HYBSTOB) - call tropopause_hybridstobie(pstate, tropLev, tropP, tropT, tropZ) + call tropopause_hybridstobie(ncol, pver, pmid, t, zm, tropLev, tropP, tropT, tropZ) case(TROP_ALG_TWMO) - call tropopause_twmo(pstate, tropLev, tropP, tropT, tropZ) + call tropopause_twmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) case(TROP_ALG_WMO) - call tropopause_wmo(pstate, tropLev, tropP, tropT, tropZ) + call tropopause_wmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) case(TROP_ALG_CPP) - call tropopause_cpp(pstate, tropLev, tropP, tropT, tropZ) + call tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) case default write(iulog, *) 'tropopause: Invalid detection algorithm (', algorithm, ') specified.' @@ -1258,41 +1315,42 @@ end subroutine tropopause_findUsing ! This routine interpolates the pressures in the physics state to ! find the pressure at the specified tropopause altitude. - function tropopause_interpolateP(pstate, icol, tropLev, tropZ) + function tropopause_interpolateP(pmid, zm, icol, tropLev, tropZ) implicit none - type(physics_state), intent(in) :: pstate + real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver integer, intent(in) :: icol ! column being processed integer, intent(in) :: tropLev ! tropopause level index - real(r8), optional, intent(in) :: tropZ ! tropopause pressure (m) - real(r8) :: tropopause_interpolateP + real(kind_phys), optional, intent(in) :: tropZ ! tropopause pressure (m) + real(kind_phys) :: tropopause_interpolateP ! Local Variables - real(r8) :: tropP ! tropopause pressure (Pa) - real(r8) :: dlogPdZ ! dlog(p)/dZ + real(kind_phys) :: tropP ! tropopause pressure (Pa) + real(kind_phys) :: dlogPdZ ! dlog(p)/dZ ! Interpolate the temperature linearly against log(P) ! Is the tropopause at the midpoint? - if (tropZ == pstate%zm(icol, tropLev)) then - tropP = pstate%pmid(icol, tropLev) + if (tropZ == zm(icol, tropLev)) then + tropP = pmid(icol, tropLev) - else if (tropZ > pstate%zm(icol, tropLev)) then + else if (tropZ > zm(icol, tropLev)) then ! It is above the midpoint? Make sure we aren't at the top. if (tropLev > 1) then - dlogPdZ = (log(pstate%pmid(icol, tropLev)) - log(pstate%pmid(icol, tropLev - 1))) / & - (pstate%zm(icol, tropLev) - pstate%zm(icol, tropLev - 1)) - tropP = pstate%pmid(icol, tropLev) + exp((tropZ - pstate%zm(icol, tropLev)) * dlogPdZ) + dlogPdZ = (log(pmid(icol, tropLev)) - log(pmid(icol, tropLev - 1))) / & + (zm(icol, tropLev) - zm(icol, tropLev - 1)) + tropP = pmid(icol, tropLev) + exp((tropZ - zm(icol, tropLev)) * dlogPdZ) end if else ! It is below the midpoint. Make sure we aren't at the bottom. if (tropLev < pver) then - dlogPdZ = (log(pstate%pmid(icol, tropLev + 1)) - log(pstate%pmid(icol, tropLev))) / & - (pstate%zm(icol, tropLev + 1) - pstate%zm(icol, tropLev)) - tropP = pstate%pmid(icol, tropLev) + exp((tropZ - pstate%zm(icol, tropLev)) * dlogPdZ) + dlogPdZ = (log(pmid(icol, tropLev + 1)) - log(pmid(icol, tropLev))) / & + (zm(icol, tropLev + 1) - zm(icol, tropLev)) + tropP = pmid(icol, tropLev) + exp((tropZ - zm(icol, tropLev)) * dlogPdZ) end if end if @@ -1302,41 +1360,42 @@ end function tropopause_interpolateP ! This routine interpolates the temperatures in the physics state to ! find the temperature at the specified tropopause pressure. - function tropopause_interpolateT(pstate, icol, tropLev, tropP) + function tropopause_interpolateT(pmid, t, icol, tropLev, tropP) implicit none - type(physics_state), intent(in) :: pstate + real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) + real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) integer, intent(in) :: icol ! column being processed integer, intent(in) :: tropLev ! tropopause level index - real(r8), optional, intent(in) :: tropP ! tropopause pressure (Pa) - real(r8) :: tropopause_interpolateT + real(kind_phys), optional, intent(in) :: tropP ! tropopause pressure (Pa) + real(kind_phys) :: tropopause_interpolateT ! Local Variables - real(r8) :: tropT ! tropopause temperature (K) - real(r8) :: dTdlogP ! dT/dlog(P) + real(kind_phys) :: tropT ! tropopause temperature (K) + real(kind_phys) :: dTdlogP ! dT/dlog(P) ! Interpolate the temperature linearly against log(P) ! Is the tropopause at the midpoint? - if (tropP == pstate%pmid(icol, tropLev)) then - tropT = pstate%t(icol, tropLev) + if (tropP == pmid(icol, tropLev)) then + tropT = t(icol, tropLev) - else if (tropP < pstate%pmid(icol, tropLev)) then + else if (tropP < pmid(icol, tropLev)) then ! It is above the midpoint? Make sure we aren't at the top. if (tropLev > 1) then - dTdlogP = (pstate%t(icol, tropLev) - pstate%t(icol, tropLev - 1)) / & - (log(pstate%pmid(icol, tropLev)) - log(pstate%pmid(icol, tropLev - 1))) - tropT = pstate%t(icol, tropLev) + (log(tropP) - log(pstate%pmid(icol, tropLev))) * dTdlogP + dTdlogP = (t(icol, tropLev) - t(icol, tropLev - 1)) / & + (log(pmid(icol, tropLev)) - log(pmid(icol, tropLev - 1))) + tropT = t(icol, tropLev) + (log(tropP) - log(pmid(icol, tropLev))) * dTdlogP end if else ! It is below the midpoint. Make sure we aren't at the bottom. if (tropLev < pver) then - dTdlogP = (pstate%t(icol, tropLev + 1) - pstate%t(icol, tropLev)) / & - (log(pstate%pmid(icol, tropLev + 1)) - log(pstate%pmid(icol, tropLev))) - tropT = pstate%t(icol, tropLev) + (log(tropP) - log(pstate%pmid(icol, tropLev))) * dTdlogP + dTdlogP = (t(icol, tropLev + 1) - t(icol, tropLev)) / & + (log(pmid(icol, tropLev + 1)) - log(pmid(icol, tropLev))) + tropT = t(icol, tropLev) + (log(tropP) - log(pmid(icol, tropLev))) * dTdlogP end if end if @@ -1346,42 +1405,44 @@ end function tropopause_interpolateT ! This routine interpolates the geopotential height in the physics state to ! find the geopotential height at the specified tropopause pressure. - function tropopause_interpolateZ(pstate, icol, tropLev, tropP) - use physconst, only: rga - - implicit none - - type(physics_state), intent(in) :: pstate + function tropopause_interpolateZ(pint, pmid, zi, zm, phis, icol, tropLev, tropP) + + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) + real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) integer, intent(in) :: icol ! column being processed integer, intent(in) :: tropLev ! tropopause level index - real(r8), optional, intent(in) :: tropP ! tropopause pressure (Pa) - real(r8) :: tropopause_interpolateZ + real(kind_phys), optional, intent(in) :: tropP ! tropopause pressure (Pa) + real(kind_phys) :: tropopause_interpolateZ ! Local Variables - real(r8) :: tropZ ! tropopause geopotential height (m) - real(r8) :: dZdlogP ! dZ/dlog(P) + real(kind_phys) :: tropZ ! tropopause geopotential height (m) + real(kind_phys) :: dZdlogP ! dZ/dlog(P) ! Interpolate the geopotential height linearly against log(P) ! Is the tropoause at the midpoint? - if (tropP == pstate%pmid(icol, tropLev)) then - tropZ = pstate%zm(icol, tropLev) + if (tropP == pmid(icol, tropLev)) then + tropZ = zm(icol, tropLev) - else if (tropP < pstate%pmid(icol, tropLev)) then + else if (tropP < pmid(icol, tropLev)) then ! It is above the midpoint? Make sure we aren't at the top. - dZdlogP = (pstate%zm(icol, tropLev) - pstate%zi(icol, tropLev)) / & - (log(pstate%pmid(icol, tropLev)) - log(pstate%pint(icol, tropLev))) - tropZ = pstate%zm(icol, tropLev) + (log(tropP) - log(pstate%pmid(icol, tropLev))) * dZdlogP + dZdlogP = (zm(icol, tropLev) - zi(icol, tropLev)) / & + (log(pmid(icol, tropLev)) - log(pint(icol, tropLev))) + tropZ = zm(icol, tropLev) + (log(tropP) - log(pmid(icol, tropLev))) * dZdlogP else ! It is below the midpoint. Make sure we aren't at the bottom. - dZdlogP = (pstate%zm(icol, tropLev) - pstate%zi(icol, tropLev+1)) / & - (log(pstate%pmid(icol, tropLev)) - log(pstate%pint(icol, tropLev+1))) - tropZ = pstate%zm(icol, tropLev) + (log(tropP) - log(pstate%pmid(icol, tropLev))) * dZdlogP + dZdlogP = (zm(icol, tropLev) - zi(icol, tropLev+1)) / & + (log(pmid(icol, tropLev)) - log(pint(icol, tropLev+1))) + tropZ = zm(icol, tropLev) + (log(tropP) - log(pmid(icol, tropLev))) * dZdlogP end if - tropopause_interpolateZ = tropZ + pstate%phis(icol)*rga + tropopause_interpolateZ = tropZ + phis(icol)*cnst_rga end function tropopause_interpolateZ @@ -1389,96 +1450,101 @@ end function tropopause_interpolateZ ! of output will be generated, one for the default algorithm and another one ! using the default routine, but backed by a climatology when the default ! algorithm fails. - subroutine tropopause_output(pstate) - use cam_history, only : outfld + subroutine tropopause_output(ncol, pver, lat, pint, pmid, t, zi, zm, phis) + !use cam_history, only : outfld - implicit none - - type(physics_state), intent(in) :: pstate + real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns + real(kind_phys), intent(in) :: pver ! Number of vertical levels + real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) + real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) ! Local Variables integer :: i integer :: alg integer :: ncol ! number of cloumns in the chunk - integer :: lchnk ! chunk identifier + !integer :: lchnk ! chunk identifier integer :: tropLev(pcols) ! tropopause level index - real(r8) :: tropP(pcols) ! tropopause pressure (Pa) - real(r8) :: tropT(pcols) ! tropopause temperature (K) - real(r8) :: tropZ(pcols) ! tropopause height (m) - real(r8) :: tropFound(pcols) ! tropopause found - real(r8) :: tropDZ(pcols, pver) ! relative tropopause height (m) - real(r8) :: tropPdf(pcols, pver) ! tropopause probability distribution + real(kind_phys) :: tropP(pcols) ! tropopause pressure (Pa) + real(kind_phys) :: tropT(pcols) ! tropopause temperature (K) + real(kind_phys) :: tropZ(pcols) ! tropopause height (m) + real(kind_phys) :: tropFound(pcols) ! tropopause found + real(kind_phys) :: tropDZ(pcols, pver) ! relative tropopause height (m) + real(kind_phys) :: tropPdf(pcols, pver) ! tropopause probability distribution ! Information about the chunk. - lchnk = pstate%lchnk - ncol = pstate%ncol + !lchnk = pstate%lchnk ! Find the tropopause using the default algorithm backed by the climatology. - call tropopause_find(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ) + call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ) - tropPdf(:,:) = 0._r8 - tropFound(:) = 0._r8 + tropPdf(:,:) = 0._kind_phys + tropFound(:) = 0._kind_phys tropDZ(:,:) = fillvalue do i = 1, ncol if (tropLev(i) /= NOTFOUND) then - tropPdf(i, tropLev(i)) = 1._r8 - tropFound(i) = 1._r8 - tropDZ(i,:) = pstate%zm(i,:) - tropZ(i) + tropPdf(i, tropLev(i)) = 1._kind_phys + tropFound(i) = 1._kind_phys + tropDZ(i,:) = zm(i,:) - tropZ(i) end if end do - call outfld('TROP_P', tropP(:ncol), ncol, lchnk) - call outfld('TROP_T', tropT(:ncol), ncol, lchnk) - call outfld('TROP_Z', tropZ(:ncol), ncol, lchnk) - call outfld('TROP_DZ', tropDZ(:ncol, :), ncol, lchnk) - call outfld('TROP_PD', tropPdf(:ncol, :), ncol, lchnk) - call outfld('TROP_FD', tropFound(:ncol), ncol, lchnk) + ! call outfld('TROP_P', tropP(:ncol), ncol, lchnk) + ! call outfld('TROP_T', tropT(:ncol), ncol, lchnk) + ! call outfld('TROP_Z', tropZ(:ncol), ncol, lchnk) + ! call outfld('TROP_DZ', tropDZ(:ncol, :), ncol, lchnk) + ! call outfld('TROP_PD', tropPdf(:ncol, :), ncol, lchnk) + ! call outfld('TROP_FD', tropFound(:ncol), ncol, lchnk) ! Find the tropopause using just the primary algorithm. - call tropopause_find(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, backup=TROP_ALG_NONE) + call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, backup=TROP_ALG_NONE) - tropPdf(:,:) = 0._r8 - tropFound(:) = 0._r8 + tropPdf(:,:) = 0._kind_phys + tropFound(:) = 0._kind_phys tropDZ(:,:) = fillvalue do i = 1, ncol if (tropLev(i) /= NOTFOUND) then - tropPdf(i, tropLev(i)) = 1._r8 - tropFound(i) = 1._r8 - tropDZ(i,:) = pstate%zm(i,:) - tropZ(i) + tropPdf(i, tropLev(i)) = 1._kind_phys + tropFound(i) = 1._kind_phys + tropDZ(i,:) = zm(i,:) - tropZ(i) end if end do - call outfld('TROPP_P', tropP(:ncol), ncol, lchnk) - call outfld('TROPP_T', tropT(:ncol), ncol, lchnk) - call outfld('TROPP_Z', tropZ(:ncol), ncol, lchnk) - call outfld('TROPP_DZ', tropDZ(:ncol, :), ncol, lchnk) - call outfld('TROPP_PD', tropPdf(:ncol, :), ncol, lchnk) - call outfld('TROPP_FD', tropFound(:ncol), ncol, lchnk) + ! call outfld('TROPP_P', tropP(:ncol), ncol, lchnk) + ! call outfld('TROPP_T', tropT(:ncol), ncol, lchnk) + ! call outfld('TROPP_Z', tropZ(:ncol), ncol, lchnk) + ! call outfld('TROPP_DZ', tropDZ(:ncol, :), ncol, lchnk) + ! call outfld('TROPP_PD', tropPdf(:ncol, :), ncol, lchnk) + ! call outfld('TROPP_FD', tropFound(:ncol), ncol, lchnk) ! Find the tropopause using just the cold point algorithm. - call tropopause_find(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=TROP_ALG_CPP, backup=TROP_ALG_NONE) + call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=TROP_ALG_CPP, backup=TROP_ALG_NONE) - tropPdf(:,:) = 0._r8 - tropFound(:) = 0._r8 + tropPdf(:,:) = 0._kind_phys + tropFound(:) = 0._kind_phys tropDZ(:,:) = fillvalue do i = 1, ncol if (tropLev(i) /= NOTFOUND) then - tropPdf(i, tropLev(i)) = 1._r8 - tropFound(i) = 1._r8 - tropDZ(i,:) = pstate%zm(i,:) - tropZ(i) + tropPdf(i, tropLev(i)) = 1._kind_phys + tropFound(i) = 1._kind_phys + tropDZ(i,:) = zm(i,:) - tropZ(i) end if end do - call outfld('TROPF_P', tropP(:ncol), ncol, lchnk) - call outfld('TROPF_T', tropT(:ncol), ncol, lchnk) - call outfld('TROPF_Z', tropZ(:ncol), ncol, lchnk) - call outfld('TROPF_DZ', tropDZ(:ncol, :), ncol, lchnk) - call outfld('TROPF_PD', tropPdf(:ncol, :), ncol, lchnk) - call outfld('TROPF_FD', tropFound(:ncol), ncol, lchnk) + ! call outfld('TROPF_P', tropP(:ncol), ncol, lchnk) + ! call outfld('TROPF_T', tropT(:ncol), ncol, lchnk) + ! call outfld('TROPF_Z', tropZ(:ncol), ncol, lchnk) + ! call outfld('TROPF_DZ', tropDZ(:ncol, :), ncol, lchnk) + ! call outfld('TROPF_PD', tropPdf(:ncol, :), ncol, lchnk) + ! call outfld('TROPF_FD', tropFound(:ncol), ncol, lchnk) ! If requested, do all of the algorithms. @@ -1487,26 +1553,26 @@ subroutine tropopause_output(pstate) do alg = 2, TROP_NALG ! Find the tropopause using just the analytic algorithm. - call tropopause_find(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=alg, backup=TROP_ALG_NONE) + call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=alg, backup=TROP_ALG_NONE) - tropPdf(:,:) = 0._r8 - tropFound(:) = 0._r8 + tropPdf(:,:) = 0._kind_phys + tropFound(:) = 0._kind_phys do i = 1, ncol if (tropLev(i) /= NOTFOUND) then - tropPdf(i, tropLev(i)) = 1._r8 - tropFound(i) = 1._r8 + tropPdf(i, tropLev(i)) = 1._kind_phys + tropFound(i) = 1._kind_phys end if end do - call outfld('TROP' // TROP_LETTER(alg) // '_P', tropP(:ncol), ncol, lchnk) - call outfld('TROP' // TROP_LETTER(alg) // '_T', tropT(:ncol), ncol, lchnk) - call outfld('TROP' // TROP_LETTER(alg) // '_Z', tropZ(:ncol), ncol, lchnk) - call outfld('TROP' // TROP_LETTER(alg) // '_PD', tropPdf(:ncol, :), ncol, lchnk) - call outfld('TROP' // TROP_LETTER(alg) // '_FD', tropFound(:ncol), ncol, lchnk) + ! call outfld('TROP' // TROP_LETTER(alg) // '_P', tropP(:ncol), ncol, lchnk) + ! call outfld('TROP' // TROP_LETTER(alg) // '_T', tropT(:ncol), ncol, lchnk) + ! call outfld('TROP' // TROP_LETTER(alg) // '_Z', tropZ(:ncol), ncol, lchnk) + ! call outfld('TROP' // TROP_LETTER(alg) // '_PD', tropPdf(:ncol, :), ncol, lchnk) + ! call outfld('TROP' // TROP_LETTER(alg) // '_FD', tropFound(:ncol), ncol, lchnk) end do end if return end subroutine tropopause_output -end module tropopause +end module tropopause_find From 6e11a3b175e265b57ca44103b14eccafc8b9370d Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Wed, 14 Aug 2024 19:05:22 -0400 Subject: [PATCH 03/31] Continue CCPP-ization of fields; split into diagnostics; read_file split to utilities module in CAM --- tropopause_find/tropopause_diagnostics.F90 | 224 ++++++++ tropopause_find/tropopause_find.F90 | 562 ++++----------------- tropopause_find/tropopause_find.meta | 155 ++++++ 3 files changed, 476 insertions(+), 465 deletions(-) create mode 100644 tropopause_find/tropopause_diagnostics.F90 create mode 100644 tropopause_find/tropopause_find.meta diff --git a/tropopause_find/tropopause_diagnostics.F90 b/tropopause_find/tropopause_diagnostics.F90 new file mode 100644 index 00000000..c110451c --- /dev/null +++ b/tropopause_find/tropopause_diagnostics.F90 @@ -0,0 +1,224 @@ +module tropopause_output + ! ... output tropopause diagnostics + ! this will be moved to cam_diagnostics when History is available. (hplin, 8/14/24) + use ccpp_kinds, only : kind_phys + + implicit none + private + + ! CCPP-compliant subroutines + public :: tropopause_diagnostics_init + public :: tropopause_diagnostics_run + +contains + ! Initialize the output history fields. + subroutine tropopause_diagnostics_init(errmsg, errflg) + + !use cam_history, only: history_add_field + !use cam_history_support, only: horiz_only + + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + + errmsg = ' ' + errflg = 0 + + ! Define the output fields. + ! call addfld('TROP_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure', flag_xyfill=.True.) + ! call addfld('TROP_T', horiz_only, 'A', 'K', 'Tropopause Temperature', flag_xyfill=.True.) + ! call addfld('TROP_Z', horiz_only, 'A', 'm', 'Tropopause Height', flag_xyfill=.True.) + ! call addfld('TROP_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height') + ! call addfld('TROP_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Probabilty') + ! call addfld('TROP_FD', horiz_only, 'A', 'probability', 'Tropopause Found') + + ! call addfld('TROPP_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (primary)', flag_xyfill=.True.) + ! call addfld('TROPP_T', horiz_only, 'A', 'K', 'Tropopause Temperature (primary)', flag_xyfill=.True.) + ! call addfld('TROPP_Z', horiz_only, 'A', 'm', 'Tropopause Height (primary)', flag_xyfill=.True.) + ! call addfld('TROPP_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height (primary)') + ! call addfld('TROPP_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (primary)') + ! call addfld('TROPP_FD', horiz_only, 'A', 'probability', 'Tropopause Found (primary)') + + ! call addfld('TROPF_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (cold point)', flag_xyfill=.True.) + ! call addfld('TROPF_T', horiz_only, 'A', 'K', 'Tropopause Temperature (cold point)', flag_xyfill=.True.) + ! call addfld('TROPF_Z', horiz_only, 'A', 'm', 'Tropopause Height (cold point)', flag_xyfill=.True.) + ! call addfld('TROPF_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height (cold point)', flag_xyfill=.True.) + ! call addfld('TROPF_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (cold point)') + ! call addfld('TROPF_FD', horiz_only, 'A', 'probability', 'Tropopause Found (cold point)') + + ! call addfld( 'hstobie_trop', (/ 'lev' /), 'I', 'fraction of model time', 'Lowest level with stratospheric chemsitry') + ! call addfld( 'hstobie_linoz', (/ 'lev' /), 'I', 'fraction of model time', 'Lowest possible Linoz level') + ! call addfld( 'hstobie_tropop', (/ 'lev' /), 'I', 'fraction of model time', & + ! 'Troposphere boundary calculated in chemistry' ) + + ! ! If requested, be prepared to output results from all of the methods. + ! if (output_all) then + ! call addfld('TROPA_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (analytic)', flag_xyfill=.True.) + ! call addfld('TROPA_T', horiz_only, 'A', 'K', 'Tropopause Temperature (analytic)', flag_xyfill=.True.) + ! call addfld('TROPA_Z', horiz_only, 'A', 'm', 'Tropopause Height (analytic)', flag_xyfill=.True.) + ! call addfld('TROPA_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (analytic)') + ! call addfld('TROPA_FD', horiz_only, 'A', 'probability', 'Tropopause Found (analytic)') + + ! call addfld('TROPC_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (climatology)', flag_xyfill=.True.) + ! call addfld('TROPC_T', horiz_only, 'A', 'K', 'Tropopause Temperature (climatology)', flag_xyfill=.True.) + ! call addfld('TROPC_Z', horiz_only, 'A', 'm', 'Tropopause Height (climatology)', flag_xyfill=.True.) + ! call addfld('TROPC_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (climatology)') + ! call addfld('TROPC_FD', horiz_only, 'A', 'probability', 'Tropopause Found (climatology)') + + ! call addfld('TROPS_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (stobie)', flag_xyfill=.True.) + ! call addfld('TROPS_T', horiz_only, 'A', 'K', 'Tropopause Temperature (stobie)', flag_xyfill=.True.) + ! call addfld('TROPS_Z', horiz_only, 'A', 'm', 'Tropopause Height (stobie)', flag_xyfill=.True.) + ! call addfld('TROPS_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (stobie)') + ! call addfld('TROPS_FD', horiz_only, 'A', 'probability', 'Tropopause Found (stobie)') + + ! call addfld('TROPT_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (twmo)', flag_xyfill=.True.) + ! call addfld('TROPT_T', horiz_only, 'A', 'K', 'Tropopause Temperature (twmo)', flag_xyfill=.True.) + ! call addfld('TROPT_Z', horiz_only, 'A', 'm', 'Tropopause Height (twmo)', flag_xyfill=.True.) + ! call addfld('TROPT_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (twmo)') + ! call addfld('TROPT_FD', horiz_only, 'A', 'probability', 'Tropopause Found (twmo)') + + ! call addfld('TROPW_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (WMO)', flag_xyfill=.True.) + ! call addfld('TROPW_T', horiz_only, 'A', 'K', 'Tropopause Temperature (WMO)', flag_xyfill=.True.) + ! call addfld('TROPW_Z', horiz_only, 'A', 'm', 'Tropopause Height (WMO)', flag_xyfill=.True.) + ! call addfld('TROPW_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (WMO)') + ! call addfld('TROPW_FD', horiz_only, 'A', 'probability', 'Tropopause Found (WMO)') + + ! call addfld('TROPH_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (Hybrid Stobie)', flag_xyfill=.True.) + ! call addfld('TROPH_T', horiz_only, 'A', 'K', 'Tropopause Temperature (Hybrid Stobie)', flag_xyfill=.True.) + ! call addfld('TROPH_Z', horiz_only, 'A', 'm', 'Tropopause Height (Hybrid Stobie)', flag_xyfill=.True.) + ! call addfld('TROPH_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (Hybrid Stobie)') + ! call addfld('TROPH_FD', horiz_only, 'A', 'probability', 'Tropopause Found (Hybrid Stobie)') + ! end if + end subroutine tropopause_diagnostics_init + + ! Output the tropopause pressure and temperature to the history files. Two sets + ! of output will be generated, one for the default algorithm and another one + ! using the default routine, but backed by a climatology when the default + ! algorithm fails. + !> \section arg_table_tropopause_diagnostics_run Argument Table + !! \htmlinclude tropopause_diagnostics_run.html + subroutine tropopause_diagnostics_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis) + !use cam_history, only : outfld + + real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns + real(kind_phys), intent(in) :: pver ! Number of vertical levels + real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) + real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) + + ! Local Variables + integer :: i + integer :: alg + integer :: ncol ! number of cloumns in the chunk + !integer :: lchnk ! chunk identifier + integer :: tropLev(pcols) ! tropopause level index + real(kind_phys) :: tropP(pcols) ! tropopause pressure (Pa) + real(kind_phys) :: tropT(pcols) ! tropopause temperature (K) + real(kind_phys) :: tropZ(pcols) ! tropopause height (m) + real(kind_phys) :: tropFound(pcols) ! tropopause found + real(kind_phys) :: tropDZ(pcols, pver) ! relative tropopause height (m) + real(kind_phys) :: tropPdf(pcols, pver) ! tropopause probability distribution + + ! Information about the chunk. + !lchnk = pstate%lchnk + + ! Find the tropopause using the default algorithm backed by the climatology. + call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ) + + tropPdf(:,:) = 0._kind_phys + tropFound(:) = 0._kind_phys + tropDZ(:,:) = fillvalue + do i = 1, ncol + if (tropLev(i) /= NOTFOUND) then + tropPdf(i, tropLev(i)) = 1._kind_phys + tropFound(i) = 1._kind_phys + tropDZ(i,:) = zm(i,:) - tropZ(i) + end if + end do + + ! call outfld('TROP_P', tropP(:ncol), ncol, lchnk) + ! call outfld('TROP_T', tropT(:ncol), ncol, lchnk) + ! call outfld('TROP_Z', tropZ(:ncol), ncol, lchnk) + ! call outfld('TROP_DZ', tropDZ(:ncol, :), ncol, lchnk) + ! call outfld('TROP_PD', tropPdf(:ncol, :), ncol, lchnk) + ! call outfld('TROP_FD', tropFound(:ncol), ncol, lchnk) + + + ! Find the tropopause using just the primary algorithm. + call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, backup=TROP_ALG_NONE) + + tropPdf(:,:) = 0._kind_phys + tropFound(:) = 0._kind_phys + tropDZ(:,:) = fillvalue + + do i = 1, ncol + if (tropLev(i) /= NOTFOUND) then + tropPdf(i, tropLev(i)) = 1._kind_phys + tropFound(i) = 1._kind_phys + tropDZ(i,:) = zm(i,:) - tropZ(i) + end if + end do + + ! call outfld('TROPP_P', tropP(:ncol), ncol, lchnk) + ! call outfld('TROPP_T', tropT(:ncol), ncol, lchnk) + ! call outfld('TROPP_Z', tropZ(:ncol), ncol, lchnk) + ! call outfld('TROPP_DZ', tropDZ(:ncol, :), ncol, lchnk) + ! call outfld('TROPP_PD', tropPdf(:ncol, :), ncol, lchnk) + ! call outfld('TROPP_FD', tropFound(:ncol), ncol, lchnk) + + + ! Find the tropopause using just the cold point algorithm. + call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=TROP_ALG_CPP, backup=TROP_ALG_NONE) + + tropPdf(:,:) = 0._kind_phys + tropFound(:) = 0._kind_phys + tropDZ(:,:) = fillvalue + + do i = 1, ncol + if (tropLev(i) /= NOTFOUND) then + tropPdf(i, tropLev(i)) = 1._kind_phys + tropFound(i) = 1._kind_phys + tropDZ(i,:) = zm(i,:) - tropZ(i) + end if + end do + + ! call outfld('TROPF_P', tropP(:ncol), ncol, lchnk) + ! call outfld('TROPF_T', tropT(:ncol), ncol, lchnk) + ! call outfld('TROPF_Z', tropZ(:ncol), ncol, lchnk) + ! call outfld('TROPF_DZ', tropDZ(:ncol, :), ncol, lchnk) + ! call outfld('TROPF_PD', tropPdf(:ncol, :), ncol, lchnk) + ! call outfld('TROPF_FD', tropFound(:ncol), ncol, lchnk) + + + ! If requested, do all of the algorithms. + if (output_all) then + + do alg = 2, TROP_NALG + + ! Find the tropopause using just the analytic algorithm. + call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=alg, backup=TROP_ALG_NONE) + + tropPdf(:,:) = 0._kind_phys + tropFound(:) = 0._kind_phys + + do i = 1, ncol + if (tropLev(i) /= NOTFOUND) then + tropPdf(i, tropLev(i)) = 1._kind_phys + tropFound(i) = 1._kind_phys + end if + end do + + ! call outfld('TROP' // TROP_LETTER(alg) // '_P', tropP(:ncol), ncol, lchnk) + ! call outfld('TROP' // TROP_LETTER(alg) // '_T', tropT(:ncol), ncol, lchnk) + ! call outfld('TROP' // TROP_LETTER(alg) // '_Z', tropZ(:ncol), ncol, lchnk) + ! call outfld('TROP' // TROP_LETTER(alg) // '_PD', tropPdf(:ncol, :), ncol, lchnk) + ! call outfld('TROP' // TROP_LETTER(alg) // '_FD', tropFound(:ncol), ncol, lchnk) + end do + end if + + return + end subroutine tropopause_output +end module tropopause_output \ No newline at end of file diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index d70c8ad7..66d61ec8 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -13,35 +13,31 @@ ! ! Author: Charles Bardeen ! Created: April, 2009 - +! +! CCPP-ized: Haipeng Lin, August 2024 module tropopause_find !--------------------------------------------------------------- ! ... variables for the tropopause module !--------------------------------------------------------------- use ccpp_kinds, only : kind_phys - use shr_const_mod, only : pi => shr_const_pi - use ppgrid, only : pcols, pver, begchunk, endchunk use cam_abortutils, only : endrun use cam_logfile, only : iulog use cam_history_support, only : fillvalue - use physics_types, only : physics_state - use spmd_utils, only : masterproc implicit none private ! CCPP-compliant subroutines - public :: tropopause_find_init - public :: tropopause_find_run - - public :: tropopause_readnl, tropopause_output - public :: tropopause_findChemTrop - public :: TROP_ALG_NONE, TROP_ALG_ANALYTIC, TROP_ALG_CLIMATE - public :: TROP_ALG_STOBIE, TROP_ALG_HYBSTOB, TROP_ALG_TWMO, TROP_ALG_WMO - public :: TROP_ALG_CPP - public :: NOTFOUND + public :: tropopause_find_init + public :: tropopause_find_run + + public :: tropopause_findChemTrop + public :: TROP_ALG_NONE, TROP_ALG_ANALYTIC, TROP_ALG_CLIMATE + public :: TROP_ALG_STOBIE, TROP_ALG_HYBSTOB, TROP_ALG_TWMO, TROP_ALG_WMO + public :: TROP_ALG_CPP + public :: NOTFOUND save @@ -58,6 +54,7 @@ module tropopause_find integer, parameter :: TROP_ALG_WMO = 6 ! WMO Definition integer, parameter :: TROP_ALG_HYBSTOB = 7 ! Hybrid Stobie Algorithm integer, parameter :: TROP_ALG_CPP = 8 ! Cold Point Parabolic + integer, parameter :: TROP_ALG_CHEMTROP = 9 ! Chemical tropopause integer, parameter :: TROP_NALG = 8 ! Number of Algorithms character,parameter :: TROP_LETTER(TROP_NALG) = (/ ' ', 'A', 'C', 'S', 'T', 'W', 'H', 'F' /) @@ -71,10 +68,6 @@ module tropopause_find ! Namelist variables character(len=256) :: tropopause_climo_file = 'trop_climo' ! absolute filepath of climatology file - ! These variables are used to store the climatology data. - real(kind_phys) :: days(12) ! days in the climatology - real(kind_phys), pointer :: tropp_p_loc(:,:,:) ! climatological tropopause pressures - integer, parameter :: NOTFOUND = -1 real(kind_phys),parameter :: ALPHA = 0.03_kind_phys @@ -92,56 +85,20 @@ module tropopause_find contains !================================================================================================ - ! Read namelist variables. - subroutine tropopause_readnl(nlfile) - - use namelist_utils, only: find_group_name - use units, only: getunit, freeunit - use mpishorthand - - character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input - - ! Local variables - integer :: unitn, ierr - character(len=*), parameter :: subname = 'tropopause_readnl' - - namelist /tropopause_nl/ tropopause_climo_file - !----------------------------------------------------------------------------- - - if (masterproc) then - unitn = getunit() - open( unitn, file=trim(nlfile), status='old' ) - call find_group_name(unitn, 'tropopause_nl', status=ierr) - if (ierr == 0) then - read(unitn, tropopause_nl, iostat=ierr) - if (ierr /= 0) then - call endrun(subname // ':: ERROR reading namelist') - end if - end if - close(unitn) - call freeunit(unitn) - end if - -#ifdef SPMD - ! Broadcast namelist variables - call mpibcast(tropopause_climo_file, len(tropopause_climo_file), mpichar, 0, mpicom) -#endif - - end subroutine tropopause_readnl - - ! This routine is called during intialization and must be called before the ! other methods in this module can be used. Its main tasks are to read in the ! climatology from a file and to define the output fields. Much of this code ! is taken from mo_tropopause. - !> \section arg_table_tropopause_find_init Argument Table - !! \htmlinclude tropopause_find_init.html - subroutine tropopause_find_init(cappa, rair, gravit, errmsg, errflg) +!> \section arg_table_tropopause_find_init Argument Table +!! \htmlinclude tropopause_find_init.html + subroutine tropopause_find_init(cappa, rair, gravit, pi, tropopause_climo_file, errmsg, errflg) - !use cam_history, only: addfld, horiz_only real(kind_phys), intent(in) :: cappa ! R/Cp real(kind_phys), intent(in) :: rair ! Dry air gas constant (J K-1 kg-1) real(kind_phys), intent(in) :: gravit ! Gravitational acceleration (m s-2) + real(kind_phys), intent(in) :: pi ! Pi + + character(len=256), intent(in) :: tropopause_climo_file ! absolute path of climatology file character(len=512), intent(out) :: errmsg integer, intent(out) :: errflg @@ -154,76 +111,10 @@ subroutine tropopause_find_init(cappa, rair, gravit, errmsg, errflg) cnst_faktor = -gravit/rair cnst_rga = 1._kind_phys/gravit ! Reciprocal of gravit (s2 m-1) cnst_ka1 = cnst_kap - 1._kind_phys + cnst_pi = pi - ! Define the output fields. - ! call addfld('TROP_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure', flag_xyfill=.True.) - ! call addfld('TROP_T', horiz_only, 'A', 'K', 'Tropopause Temperature', flag_xyfill=.True.) - ! call addfld('TROP_Z', horiz_only, 'A', 'm', 'Tropopause Height', flag_xyfill=.True.) - ! call addfld('TROP_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height') - ! call addfld('TROP_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Probabilty') - ! call addfld('TROP_FD', horiz_only, 'A', 'probability', 'Tropopause Found') - - ! call addfld('TROPP_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (primary)', flag_xyfill=.True.) - ! call addfld('TROPP_T', horiz_only, 'A', 'K', 'Tropopause Temperature (primary)', flag_xyfill=.True.) - ! call addfld('TROPP_Z', horiz_only, 'A', 'm', 'Tropopause Height (primary)', flag_xyfill=.True.) - ! call addfld('TROPP_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height (primary)') - ! call addfld('TROPP_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (primary)') - ! call addfld('TROPP_FD', horiz_only, 'A', 'probability', 'Tropopause Found (primary)') - - ! call addfld('TROPF_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (cold point)', flag_xyfill=.True.) - ! call addfld('TROPF_T', horiz_only, 'A', 'K', 'Tropopause Temperature (cold point)', flag_xyfill=.True.) - ! call addfld('TROPF_Z', horiz_only, 'A', 'm', 'Tropopause Height (cold point)', flag_xyfill=.True.) - ! call addfld('TROPF_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height (cold point)', flag_xyfill=.True.) - ! call addfld('TROPF_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (cold point)') - ! call addfld('TROPF_FD', horiz_only, 'A', 'probability', 'Tropopause Found (cold point)') - - ! call addfld( 'hstobie_trop', (/ 'lev' /), 'I', 'fraction of model time', 'Lowest level with stratospheric chemsitry') - ! call addfld( 'hstobie_linoz', (/ 'lev' /), 'I', 'fraction of model time', 'Lowest possible Linoz level') - ! call addfld( 'hstobie_tropop', (/ 'lev' /), 'I', 'fraction of model time', & - ! 'Troposphere boundary calculated in chemistry' ) - - ! ! If requested, be prepared to output results from all of the methods. - ! if (output_all) then - ! call addfld('TROPA_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (analytic)', flag_xyfill=.True.) - ! call addfld('TROPA_T', horiz_only, 'A', 'K', 'Tropopause Temperature (analytic)', flag_xyfill=.True.) - ! call addfld('TROPA_Z', horiz_only, 'A', 'm', 'Tropopause Height (analytic)', flag_xyfill=.True.) - ! call addfld('TROPA_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (analytic)') - ! call addfld('TROPA_FD', horiz_only, 'A', 'probability', 'Tropopause Found (analytic)') - - ! call addfld('TROPC_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (climatology)', flag_xyfill=.True.) - ! call addfld('TROPC_T', horiz_only, 'A', 'K', 'Tropopause Temperature (climatology)', flag_xyfill=.True.) - ! call addfld('TROPC_Z', horiz_only, 'A', 'm', 'Tropopause Height (climatology)', flag_xyfill=.True.) - ! call addfld('TROPC_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (climatology)') - ! call addfld('TROPC_FD', horiz_only, 'A', 'probability', 'Tropopause Found (climatology)') - - ! call addfld('TROPS_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (stobie)', flag_xyfill=.True.) - ! call addfld('TROPS_T', horiz_only, 'A', 'K', 'Tropopause Temperature (stobie)', flag_xyfill=.True.) - ! call addfld('TROPS_Z', horiz_only, 'A', 'm', 'Tropopause Height (stobie)', flag_xyfill=.True.) - ! call addfld('TROPS_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (stobie)') - ! call addfld('TROPS_FD', horiz_only, 'A', 'probability', 'Tropopause Found (stobie)') - - ! call addfld('TROPT_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (twmo)', flag_xyfill=.True.) - ! call addfld('TROPT_T', horiz_only, 'A', 'K', 'Tropopause Temperature (twmo)', flag_xyfill=.True.) - ! call addfld('TROPT_Z', horiz_only, 'A', 'm', 'Tropopause Height (twmo)', flag_xyfill=.True.) - ! call addfld('TROPT_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (twmo)') - ! call addfld('TROPT_FD', horiz_only, 'A', 'probability', 'Tropopause Found (twmo)') - - ! call addfld('TROPW_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (WMO)', flag_xyfill=.True.) - ! call addfld('TROPW_T', horiz_only, 'A', 'K', 'Tropopause Temperature (WMO)', flag_xyfill=.True.) - ! call addfld('TROPW_Z', horiz_only, 'A', 'm', 'Tropopause Height (WMO)', flag_xyfill=.True.) - ! call addfld('TROPW_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (WMO)') - ! call addfld('TROPW_FD', horiz_only, 'A', 'probability', 'Tropopause Found (WMO)') - - ! call addfld('TROPH_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (Hybrid Stobie)', flag_xyfill=.True.) - ! call addfld('TROPH_T', horiz_only, 'A', 'K', 'Tropopause Temperature (Hybrid Stobie)', flag_xyfill=.True.) - ! call addfld('TROPH_Z', horiz_only, 'A', 'm', 'Tropopause Height (Hybrid Stobie)', flag_xyfill=.True.) - ! call addfld('TROPH_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (Hybrid Stobie)') - ! call addfld('TROPH_FD', horiz_only, 'A', 'probability', 'Tropopause Found (Hybrid Stobie)') - ! end if - - - call tropopause_read_file() - + ! read tropopause climatological data from file + call tropopause_read_file(tropopause_climo_file) end subroutine tropopause_find_init @@ -233,17 +124,16 @@ end subroutine tropopause_find_init ! backup routine which will be tried only if the first routine fails. If the ! tropopause can not be identified by either routine, then a NOTFOUND is returned ! for the tropopause level, temperature and pressure. - !> \section arg_table_tropopause_find_run Argument Table - !! \htmlinclude tropopause_find_run.html +!> \section arg_table_tropopause_find_run Argument Table +!! \htmlinclude tropopause_find_run.html subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - tropLev, tropP, tropT, tropZ, primary, backup, & - errmsg, errflg) - - implicit none + calday, tropp_p_loc, & + tropLev, tropP, tropT, tropZ, primary, backup, & + errmsg, errflg) real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns real(kind_phys), intent(in) :: pver ! Number of vertical levels - real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) @@ -251,12 +141,19 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) + real(kind_phys), intent(in) :: calday ! Day of year including fraction from get_curr_calday + + ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). + ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM + real(kind_phys), intent(in), pointer:: tropp_p_loc(:,:) + + integer, intent(out) :: tropLev(:) ! tropopause level index + real(kind_phys), optional, intent(out) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), optional, intent(out) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), optional, intent(out) :: tropZ(:) ! tropopause height (m) + integer, optional, intent(in) :: primary ! primary detection algorithm integer, optional, intent(in) :: backup ! backup detection algorithm - integer, intent(out) :: tropLev(:) ! tropopause level index - real(kind_phys), optional, intent(out) :: tropP(:) ! tropopause pressure (Pa) - real(kind_phys), optional, intent(out) :: tropT(:) ! tropopause temperature (K) - real(kind_phys), optional, intent(out) :: tropZ(:) ! tropopause height (m) character(len=512), intent(out) :: errmsg integer, intent(out) :: errflg @@ -302,153 +199,6 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & return end subroutine tropopause_find_run - subroutine tropopause_read_file - !------------------------------------------------------------------ - ! ... initialize upper boundary values - !------------------------------------------------------------------ - use interpolate_data, only : lininterp_init, lininterp, interp_type, lininterp_finish - use dyn_grid, only : get_dyn_grid_parm - use phys_grid, only : get_ncols_p, get_rlat_all_p, get_rlon_all_p - use ioFileMod, only : getfil - use time_manager, only : get_calday - use physconst, only : pi - use cam_pio_utils, only: cam_pio_openfile - use pio, only : file_desc_t, var_desc_t, pio_inq_dimid, pio_inq_dimlen, & - pio_inq_varid, pio_get_var, pio_closefile, pio_nowrite - - !------------------------------------------------------------------ - ! ... local variables - !------------------------------------------------------------------ - integer :: i, j, n - integer :: ierr - type(file_desc_t) :: pio_id - integer :: dimid - type(var_desc_t) :: vid - integer :: nlon, nlat, ntimes - integer :: start(3) - integer :: count(3) - integer, parameter :: dates(12) = (/ 116, 214, 316, 415, 516, 615, & - 716, 816, 915, 1016, 1115, 1216 /) - integer :: plon, plat - type(interp_type) :: lon_wgts, lat_wgts - real(kind_phys), allocatable :: tropp_p_in(:,:,:) - real(kind_phys), allocatable :: lat(:) - real(kind_phys), allocatable :: lon(:) - real(kind_phys) :: to_lats(pcols), to_lons(pcols) - real(kind_phys), parameter :: d2r=pi/180._kind_phys, zero=0._kind_phys, twopi=pi*2._kind_phys - character(len=256) :: locfn - integer :: c, ncols - - - plon = get_dyn_grid_parm('plon') - plat = get_dyn_grid_parm('plat') - - - !----------------------------------------------------------------------- - ! ... open netcdf file - !----------------------------------------------------------------------- - call getfil (tropopause_climo_file, locfn, 0) - call cam_pio_openfile(pio_id, trim(locfn), PIO_NOWRITE) - - !----------------------------------------------------------------------- - ! ... get time dimension - !----------------------------------------------------------------------- - ierr = pio_inq_dimid( pio_id, 'time', dimid ) - ierr = pio_inq_dimlen( pio_id, dimid, ntimes ) - if( ntimes /= 12 )then - write(iulog,*) 'tropopause_find_init: number of months = ',ntimes,'; expecting 12' - call endrun - end if - !----------------------------------------------------------------------- - ! ... get latitudes - !----------------------------------------------------------------------- - ierr = pio_inq_dimid( pio_id, 'lat', dimid ) - ierr = pio_inq_dimlen( pio_id, dimid, nlat ) - allocate( lat(nlat), stat=ierr ) - if( ierr /= 0 ) then - write(iulog,*) 'tropopause_find_init: lat allocation error = ',ierr - call endrun - end if - ierr = pio_inq_varid( pio_id, 'lat', vid ) - ierr = pio_get_var( pio_id, vid, lat ) - lat(:nlat) = lat(:nlat) * d2r - !----------------------------------------------------------------------- - ! ... get longitudes - !----------------------------------------------------------------------- - ierr = pio_inq_dimid( pio_id, 'lon', dimid ) - ierr = pio_inq_dimlen( pio_id, dimid, nlon ) - allocate( lon(nlon), stat=ierr ) - if( ierr /= 0 ) then - write(iulog,*) 'tropopause_find_init: lon allocation error = ',ierr - call endrun - end if - ierr = pio_inq_varid( pio_id, 'lon', vid ) - ierr = pio_get_var( pio_id, vid, lon ) - lon(:nlon) = lon(:nlon) * d2r - - !------------------------------------------------------------------ - ! ... allocate arrays - !------------------------------------------------------------------ - allocate( tropp_p_in(nlon,nlat,ntimes), stat=ierr ) - if( ierr /= 0 ) then - write(iulog,*) 'tropopause_find_init: tropp_p_in allocation error = ',ierr - call endrun - end if - !------------------------------------------------------------------ - ! ... read in the tropopause pressure - !------------------------------------------------------------------ - ierr = pio_inq_varid( pio_id, 'trop_p', vid ) - start = (/ 1, 1, 1 /) - count = (/ nlon, nlat, ntimes /) - ierr = pio_get_var( pio_id, vid, start, count, tropp_p_in ) - - !------------------------------------------------------------------ - ! ... close the netcdf file - !------------------------------------------------------------------ - call pio_closefile( pio_id ) - - !-------------------------------------------------------------------- - ! ... regrid - !-------------------------------------------------------------------- - - allocate( tropp_p_loc(pcols,begchunk:endchunk,ntimes), stat=ierr ) - - if( ierr /= 0 ) then - write(iulog,*) 'tropopause_find_init: tropp_p_loc allocation error = ',ierr - call endrun - end if - - do c=begchunk,endchunk - ncols = get_ncols_p(c) - call get_rlat_all_p(c, pcols, to_lats) - call get_rlon_all_p(c, pcols, to_lons) - call lininterp_init(lon, nlon, to_lons, ncols, 2, lon_wgts, zero, twopi) - call lininterp_init(lat, nlat, to_lats, ncols, 1, lat_wgts) - do n=1,ntimes - call lininterp(tropp_p_in(:,:,n), nlon, nlat, tropp_p_loc(1:ncols,c,n), ncols, lon_wgts, lat_wgts) - end do - call lininterp_finish(lon_wgts) - call lininterp_finish(lat_wgts) - end do - deallocate(lon) - deallocate(lat) - deallocate(tropp_p_in) - - !-------------------------------------------------------- - ! ... initialize the monthly day of year times - !-------------------------------------------------------- - - do n = 1,12 - days(n) = get_calday( dates(n), 0 ) - end do - if (masterproc) then - write(iulog,*) 'tropopause_find_init : days' - write(iulog,'(1p,5g15.8)') days(:) - endif - - end subroutine tropopause_read_file - - ! This analytic expression closely matches the mean tropopause determined ! by the NCEP reanalysis and has been used by the radiation code. subroutine tropopause_analytic(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & @@ -456,14 +206,14 @@ subroutine tropopause_analytic(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns real(kind_phys), intent(in) :: pver ! Number of vertical levels - real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) - integer, intent(inout) :: tropLev(:) ! tropopause level index + integer, intent(inout) :: tropLev(:) ! tropopause level index real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) @@ -504,26 +254,31 @@ subroutine tropopause_analytic(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & end do end subroutine tropopause_analytic - ! Read the tropopause pressure in from a file containging a climatology. The ! data is interpolated to the current dat of year and latitude. ! ! NOTE: The data is read in during tropopause_init and stored in the module ! variable trop subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - tropLev, tropP, tropT, tropZ) - use time_manager, only : get_curr_calday + calday, tropp_p_loc, tropLev, tropP, tropT, tropZ) real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns real(kind_phys), intent(in) :: pver ! Number of vertical levels - real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) - integer, intent(inout) :: tropLev(:) ! tropopause level index + + real(kind_phys), intent(in) :: calday ! Day of year including fraction from get_curr_calday + + ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). + ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM + real(kind_phys), intent(in), pointer:: tropp_p_loc(:,:) + + integer, intent(inout) :: tropLev(:) ! tropopause level index real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) @@ -532,23 +287,16 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & integer :: i integer :: k integer :: m - integer :: lchnk ! chunk identifier real(kind_phys) :: tP ! tropopause pressure (Pa) real(kind_phys) :: calday ! day of year including fraction real(kind_phys) :: dels integer :: last integer :: next - - ! Information about the chunk. - lchnk = pstate%lchnk ! If any columns remain to be indentified, the nget the current ! day from the calendar. if (any(tropLev == NOTFOUND)) then - - ! Determine the calendar day. - calday = get_curr_calday() !-------------------------------------------------------- ! ... setup the time interpolation @@ -585,8 +333,8 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & ! ... get tropopause level from climatology !-------------------------------------------------------- ! Interpolate the tropopause pressure. - tP = tropp_p_loc(i,lchnk,last) & - + dels * (tropp_p_loc(i,lchnk,next) - tropp_p_loc(i,lchnk,last)) + tP = tropp_p_loc(i,last) & + + dels * (tropp_p_loc(i,next) - tropp_p_loc(i,last)) ! Find the associated level. do k = pver, 2, -1 @@ -647,12 +395,12 @@ subroutine tropopause_hybridstobie(ncol, pver, pmid, t, zm, & integer :: i, k, ncol real(kind_phys) :: stobie_min, shybrid_temp !temporary variable for case 2 & 3. - integer :: ltrop_linoz(pcols) !Lowest possible Linoz vertical level - integer :: ltrop_trop(pcols) !Tropopause level for hybrid case. + integer :: ltrop_linoz(ncol) !Lowest possible Linoz vertical level + integer :: ltrop_trop(ncol) !Tropopause level for hybrid case. logical :: ltrop_linoz_set !Flag that lowest linoz level already found. - real(kind_phys) :: trop_output(pcols,pver) !For output purposes only. - real(kind_phys) :: trop_linoz_output(pcols,pver) !For output purposes only. - real(kind_phys) :: trop_trop_output(pcols,pver) !For output purposes only. + real(kind_phys) :: trop_output(ncol,pver) !For output purposes only. + real(kind_phys) :: trop_linoz_output(ncol,pver) !For output purposes only. + real(kind_phys) :: trop_trop_output(ncol,pver) !For output purposes only. ! write(iulog,*) 'In set_chem_trop, o3_ndx =',o3_ndx ltrop_linoz(:) = 1 ! Initialize to default value. @@ -720,7 +468,7 @@ subroutine tropopause_stobie(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns real(kind_phys), intent(in) :: pver ! Number of vertical levels - real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) @@ -917,7 +665,7 @@ subroutine tropopause_twmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns real(kind_phys), intent(in) :: pver ! Number of vertical levels - real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) @@ -986,7 +734,16 @@ end subroutine tropopause_twmo subroutine tropopause_wmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & tropLev, tropP, tropT, tropZ) - type(physics_state), intent(in) :: pstate + real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns + real(kind_phys), intent(in) :: pver ! Number of vertical levels + real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) + real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) + integer, intent(inout) :: tropLev(:) ! tropopause level index real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) @@ -1075,7 +832,7 @@ subroutine tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns real(kind_phys), intent(in) :: pver ! Number of vertical levels - real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) @@ -1199,42 +956,39 @@ end subroutine tropopause_cpp ! eliminate false events that are sometimes detected in the cold polar stratosphere. ! ! NOTE: This routine was adapted from code in chemistry.F90 and mo_gasphase_chemdr.F90. + ! During the CCPP-ization, findChemTrop is now called from tropopause_find_run using method CHEMTROP + ! and now also returns the standard tropLev, tropP, tropT, tropZ outputs (optional). + ! The "backup" option is dropped as it is not used anywhere in current CAM. subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zm, phis, & - tropLev, primary, backup) - - implicit none + tropLev, tropP, tropT, tropZ) real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns real(kind_phys), intent(in) :: pver ! Number of vertical levels - real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) - integer, optional, intent(in) :: primary ! primary detection algorithm - integer, optional, intent(in) :: backup ! backup detection algorithm - integer, intent(out) :: tropLev(:) ! tropopause level index + integer, intent(out) :: tropLev(:) ! tropopause level index + real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) ! Local Variable real(kind_phys), parameter :: rad2deg = 180._kind_phys/pi ! radians to degrees conversion factor - real(kind_phys) :: dlats(pcols) + real(kind_phys) :: dlats(ncol) integer :: i integer :: backAlg ! First use the lapse rate tropopause. - call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zm, phis, tropLev, primary=primary, backup=TROP_ALG_NONE) + ! (Not specifying primary will use the lapse rate) + call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zm, phis, tropLev, backup=TROP_ALG_NONE) ! Now check high latitudes (poleward of 50) and set the level to the ! climatology if the level was not found or is at P <= 125 hPa. dlats(:ncol) = lat(:ncol) * rad2deg ! convert to degrees - - if (present(backup)) then - backAlg = backup - else - backAlg = default_backup - end if do i = 1, ncol if (abs(dlats(i)) > 50._kind_phys) then @@ -1248,7 +1002,7 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zm, phis, & ! Now use the backup algorithm if ((backAlg /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then - call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zm, phis, backAlg, tropLev) + call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zm, phis, default_backup, tropLev) end if return @@ -1261,13 +1015,12 @@ end subroutine tropopause_findChemTrop ! NOTE: It is assumed that the output fields have been initialized by the ! caller, and only output values set to fillvalue will be detected. subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + calday, tropp_p_loc, & algorithm, tropLev, tropP, tropT, tropZ) - implicit none - real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns real(kind_phys), intent(in) :: pver ! Number of vertical levels - real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) + real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) @@ -1275,8 +1028,14 @@ subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) - integer, intent(in) :: algorithm ! detection algorithm - integer, intent(inout) :: tropLev(:) ! tropopause level index + real(kind_phys), intent(in) :: calday ! Day of year including fraction from get_curr_calday + + ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). + ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM + real(kind_phys), intent(in), pointer:: tropp_p_loc(:,:) + + integer, intent(in) :: algorithm ! detection algorithm + integer, intent(inout) :: tropLev(:) ! tropopause level index real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) @@ -1287,7 +1046,8 @@ subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & call tropopause_analytic(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) case(TROP_ALG_CLIMATE) - call tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) + call tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + calday, tropp_p_loc, tropLev, tropP, tropT, tropZ) case(TROP_ALG_STOBIE) call tropopause_stobie(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) @@ -1304,6 +1064,9 @@ subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & case(TROP_ALG_CPP) call tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) + case(TROP_ALG_CHEMTROP) + call tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zm, phis, tropLev, tropP, tropT, tropZ) + case default write(iulog, *) 'tropopause: Invalid detection algorithm (', algorithm, ') specified.' call endrun @@ -1444,135 +1207,4 @@ function tropopause_interpolateZ(pint, pmid, zi, zm, phis, icol, tropLev, tropP) tropopause_interpolateZ = tropZ + phis(icol)*cnst_rga end function tropopause_interpolateZ - - - ! Output the tropopause pressure and temperature to the history files. Two sets - ! of output will be generated, one for the default algorithm and another one - ! using the default routine, but backed by a climatology when the default - ! algorithm fails. - subroutine tropopause_output(ncol, pver, lat, pint, pmid, t, zi, zm, phis) - !use cam_history, only : outfld - - real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns - real(kind_phys), intent(in) :: pver ! Number of vertical levels - real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) - real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp - real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) - real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) - real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp - real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver - real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) - - ! Local Variables - integer :: i - integer :: alg - integer :: ncol ! number of cloumns in the chunk - !integer :: lchnk ! chunk identifier - integer :: tropLev(pcols) ! tropopause level index - real(kind_phys) :: tropP(pcols) ! tropopause pressure (Pa) - real(kind_phys) :: tropT(pcols) ! tropopause temperature (K) - real(kind_phys) :: tropZ(pcols) ! tropopause height (m) - real(kind_phys) :: tropFound(pcols) ! tropopause found - real(kind_phys) :: tropDZ(pcols, pver) ! relative tropopause height (m) - real(kind_phys) :: tropPdf(pcols, pver) ! tropopause probability distribution - - ! Information about the chunk. - !lchnk = pstate%lchnk - - ! Find the tropopause using the default algorithm backed by the climatology. - call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ) - - tropPdf(:,:) = 0._kind_phys - tropFound(:) = 0._kind_phys - tropDZ(:,:) = fillvalue - do i = 1, ncol - if (tropLev(i) /= NOTFOUND) then - tropPdf(i, tropLev(i)) = 1._kind_phys - tropFound(i) = 1._kind_phys - tropDZ(i,:) = zm(i,:) - tropZ(i) - end if - end do - - ! call outfld('TROP_P', tropP(:ncol), ncol, lchnk) - ! call outfld('TROP_T', tropT(:ncol), ncol, lchnk) - ! call outfld('TROP_Z', tropZ(:ncol), ncol, lchnk) - ! call outfld('TROP_DZ', tropDZ(:ncol, :), ncol, lchnk) - ! call outfld('TROP_PD', tropPdf(:ncol, :), ncol, lchnk) - ! call outfld('TROP_FD', tropFound(:ncol), ncol, lchnk) - - - ! Find the tropopause using just the primary algorithm. - call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, backup=TROP_ALG_NONE) - - tropPdf(:,:) = 0._kind_phys - tropFound(:) = 0._kind_phys - tropDZ(:,:) = fillvalue - - do i = 1, ncol - if (tropLev(i) /= NOTFOUND) then - tropPdf(i, tropLev(i)) = 1._kind_phys - tropFound(i) = 1._kind_phys - tropDZ(i,:) = zm(i,:) - tropZ(i) - end if - end do - - ! call outfld('TROPP_P', tropP(:ncol), ncol, lchnk) - ! call outfld('TROPP_T', tropT(:ncol), ncol, lchnk) - ! call outfld('TROPP_Z', tropZ(:ncol), ncol, lchnk) - ! call outfld('TROPP_DZ', tropDZ(:ncol, :), ncol, lchnk) - ! call outfld('TROPP_PD', tropPdf(:ncol, :), ncol, lchnk) - ! call outfld('TROPP_FD', tropFound(:ncol), ncol, lchnk) - - - ! Find the tropopause using just the cold point algorithm. - call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=TROP_ALG_CPP, backup=TROP_ALG_NONE) - - tropPdf(:,:) = 0._kind_phys - tropFound(:) = 0._kind_phys - tropDZ(:,:) = fillvalue - - do i = 1, ncol - if (tropLev(i) /= NOTFOUND) then - tropPdf(i, tropLev(i)) = 1._kind_phys - tropFound(i) = 1._kind_phys - tropDZ(i,:) = zm(i,:) - tropZ(i) - end if - end do - - ! call outfld('TROPF_P', tropP(:ncol), ncol, lchnk) - ! call outfld('TROPF_T', tropT(:ncol), ncol, lchnk) - ! call outfld('TROPF_Z', tropZ(:ncol), ncol, lchnk) - ! call outfld('TROPF_DZ', tropDZ(:ncol, :), ncol, lchnk) - ! call outfld('TROPF_PD', tropPdf(:ncol, :), ncol, lchnk) - ! call outfld('TROPF_FD', tropFound(:ncol), ncol, lchnk) - - - ! If requested, do all of the algorithms. - if (output_all) then - - do alg = 2, TROP_NALG - - ! Find the tropopause using just the analytic algorithm. - call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=alg, backup=TROP_ALG_NONE) - - tropPdf(:,:) = 0._kind_phys - tropFound(:) = 0._kind_phys - - do i = 1, ncol - if (tropLev(i) /= NOTFOUND) then - tropPdf(i, tropLev(i)) = 1._kind_phys - tropFound(i) = 1._kind_phys - end if - end do - - ! call outfld('TROP' // TROP_LETTER(alg) // '_P', tropP(:ncol), ncol, lchnk) - ! call outfld('TROP' // TROP_LETTER(alg) // '_T', tropT(:ncol), ncol, lchnk) - ! call outfld('TROP' // TROP_LETTER(alg) // '_Z', tropZ(:ncol), ncol, lchnk) - ! call outfld('TROP' // TROP_LETTER(alg) // '_PD', tropPdf(:ncol, :), ncol, lchnk) - ! call outfld('TROP' // TROP_LETTER(alg) // '_FD', tropFound(:ncol), ncol, lchnk) - end do - end if - - return - end subroutine tropopause_output end module tropopause_find diff --git a/tropopause_find/tropopause_find.meta b/tropopause_find/tropopause_find.meta new file mode 100644 index 00000000..7d52802c --- /dev/null +++ b/tropopause_find/tropopause_find.meta @@ -0,0 +1,155 @@ +[ccpp-table-properties] + name = tropopause_find + type = scheme + +[ccpp-arg-table] + name = tropopause_find_init + type = scheme +[ cappa ] + standard_name = ratio_of_dry_air_gas_constant_to_specific_heat_of_dry_air_at_constant_pressure + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ rair ] + standard_name = gas_constant_of_dry_air + units = J kg-1 K-1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ gravit ] + standard_name = standard_gravitational_acceleration + units = m s-2 + type = real | kind = kind_phys + dimensions = () + intent = in +[ pi ] + standard_name = pi_constant + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ tropopause_climo_file ] + standard_name = enter_standard_name_5 + units = enter_units + type = character | kind = len=256 + dimensions = () + intent = in +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out + +[ccpp-arg-table] + name = tropopause_find_run + type = scheme +[ ncol ] + standard_name = horizontal_loop_extent + units = count + type = integer + dimensions = () + intent = in +[ pver ] + standard_name = vertical_layer_dimension + units = count + type = integer + dimensions = () + intent = in +[ lat ] + standard_name = latitude + units = radians + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ pint ] + standard_name = air_pressure_at_interface + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_interface_dimension) + intent = in +[ pmid ] + standard_name = air_pressure + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ t ] + standard_name = air_temperature + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ zi ] + standard_name = geopotential_height_wrt_surface_at_interface + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_interface_dimension) + intent = out +[ zm ] + standard_name = geopotential_height_wrt_surface + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ phis ] + standard_name = surface_geopotential + units = m2 s-2 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ tropLev ] + standard_name = enter_standard_name_19 + units = 1 + type = integer + dimensions = (horizontal_loop_extent) + intent = out +[ tropP ] + standard_name = tropopause_air_pressure + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropT ] + standard_name = tropopause_air_temperature + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropZ ] + standard_name = tropopause_altitude + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ primary ] + standard_name = enter_standard_name_17 + units = enter_units + type = integer + dimensions = () + intent = in +[ backup ] + standard_name = enter_standard_name_18 + units = enter_units + type = integer + dimensions = () + intent = in +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out \ No newline at end of file From d37246af1838e3a693f590b19f985f130368f3da Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Thu, 15 Aug 2024 14:22:28 -0400 Subject: [PATCH 04/31] Add metadata and namelist for test build --- tropopause_find/tropopause_diagnostics.F90 | 249 +++++++++---------- tropopause_find/tropopause_diagnostics.meta | 35 +++ tropopause_find/tropopause_find.F90 | 96 +++---- tropopause_find/tropopause_find.meta | 34 ++- tropopause_find/tropopause_find_namelist.xml | 24 ++ 5 files changed, 254 insertions(+), 184 deletions(-) create mode 100644 tropopause_find/tropopause_diagnostics.meta create mode 100644 tropopause_find/tropopause_find_namelist.xml diff --git a/tropopause_find/tropopause_diagnostics.F90 b/tropopause_find/tropopause_diagnostics.F90 index c110451c..35673adf 100644 --- a/tropopause_find/tropopause_diagnostics.F90 +++ b/tropopause_find/tropopause_diagnostics.F90 @@ -1,6 +1,7 @@ -module tropopause_output +module tropopause_diagnostics ! ... output tropopause diagnostics ! this will be moved to cam_diagnostics when History is available. (hplin, 8/14/24) + ! Currently stubbed out use ccpp_kinds, only : kind_phys implicit none @@ -12,6 +13,8 @@ module tropopause_output contains ! Initialize the output history fields. +!> \section arg_table_tropopause_diagnostics_init Argument Table +!! \htmlinclude tropopause_diagnostics_init.html subroutine tropopause_diagnostics_init(errmsg, errflg) !use cam_history, only: history_add_field @@ -94,131 +97,127 @@ end subroutine tropopause_diagnostics_init ! of output will be generated, one for the default algorithm and another one ! using the default routine, but backed by a climatology when the default ! algorithm fails. - !> \section arg_table_tropopause_diagnostics_run Argument Table - !! \htmlinclude tropopause_diagnostics_run.html - subroutine tropopause_diagnostics_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis) +!> \section arg_table_tropopause_diagnostics_run Argument Table +!! \htmlinclude tropopause_diagnostics_run.html + subroutine tropopause_diagnostics_run(errmsg, errflg) !use cam_history, only : outfld - real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns - real(kind_phys), intent(in) :: pver ! Number of vertical levels - real(kind_phys), intent(in) :: lat(:,:) ! Latitudes (radians) - real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp - real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) - real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) - real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp - real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver - real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) - - ! Local Variables - integer :: i - integer :: alg - integer :: ncol ! number of cloumns in the chunk - !integer :: lchnk ! chunk identifier - integer :: tropLev(pcols) ! tropopause level index - real(kind_phys) :: tropP(pcols) ! tropopause pressure (Pa) - real(kind_phys) :: tropT(pcols) ! tropopause temperature (K) - real(kind_phys) :: tropZ(pcols) ! tropopause height (m) - real(kind_phys) :: tropFound(pcols) ! tropopause found - real(kind_phys) :: tropDZ(pcols, pver) ! relative tropopause height (m) - real(kind_phys) :: tropPdf(pcols, pver) ! tropopause probability distribution - - ! Information about the chunk. - !lchnk = pstate%lchnk - - ! Find the tropopause using the default algorithm backed by the climatology. - call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ) - - tropPdf(:,:) = 0._kind_phys - tropFound(:) = 0._kind_phys - tropDZ(:,:) = fillvalue - do i = 1, ncol - if (tropLev(i) /= NOTFOUND) then - tropPdf(i, tropLev(i)) = 1._kind_phys - tropFound(i) = 1._kind_phys - tropDZ(i,:) = zm(i,:) - tropZ(i) - end if - end do - - ! call outfld('TROP_P', tropP(:ncol), ncol, lchnk) - ! call outfld('TROP_T', tropT(:ncol), ncol, lchnk) - ! call outfld('TROP_Z', tropZ(:ncol), ncol, lchnk) - ! call outfld('TROP_DZ', tropDZ(:ncol, :), ncol, lchnk) - ! call outfld('TROP_PD', tropPdf(:ncol, :), ncol, lchnk) - ! call outfld('TROP_FD', tropFound(:ncol), ncol, lchnk) - - - ! Find the tropopause using just the primary algorithm. - call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, backup=TROP_ALG_NONE) - - tropPdf(:,:) = 0._kind_phys - tropFound(:) = 0._kind_phys - tropDZ(:,:) = fillvalue - - do i = 1, ncol - if (tropLev(i) /= NOTFOUND) then - tropPdf(i, tropLev(i)) = 1._kind_phys - tropFound(i) = 1._kind_phys - tropDZ(i,:) = zm(i,:) - tropZ(i) - end if - end do - - ! call outfld('TROPP_P', tropP(:ncol), ncol, lchnk) - ! call outfld('TROPP_T', tropT(:ncol), ncol, lchnk) - ! call outfld('TROPP_Z', tropZ(:ncol), ncol, lchnk) - ! call outfld('TROPP_DZ', tropDZ(:ncol, :), ncol, lchnk) - ! call outfld('TROPP_PD', tropPdf(:ncol, :), ncol, lchnk) - ! call outfld('TROPP_FD', tropFound(:ncol), ncol, lchnk) - - - ! Find the tropopause using just the cold point algorithm. - call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=TROP_ALG_CPP, backup=TROP_ALG_NONE) - - tropPdf(:,:) = 0._kind_phys - tropFound(:) = 0._kind_phys - tropDZ(:,:) = fillvalue - - do i = 1, ncol - if (tropLev(i) /= NOTFOUND) then - tropPdf(i, tropLev(i)) = 1._kind_phys - tropFound(i) = 1._kind_phys - tropDZ(i,:) = zm(i,:) - tropZ(i) - end if - end do - - ! call outfld('TROPF_P', tropP(:ncol), ncol, lchnk) - ! call outfld('TROPF_T', tropT(:ncol), ncol, lchnk) - ! call outfld('TROPF_Z', tropZ(:ncol), ncol, lchnk) - ! call outfld('TROPF_DZ', tropDZ(:ncol, :), ncol, lchnk) - ! call outfld('TROPF_PD', tropPdf(:ncol, :), ncol, lchnk) - ! call outfld('TROPF_FD', tropFound(:ncol), ncol, lchnk) - - - ! If requested, do all of the algorithms. - if (output_all) then - - do alg = 2, TROP_NALG - - ! Find the tropopause using just the analytic algorithm. - call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=alg, backup=TROP_ALG_NONE) - - tropPdf(:,:) = 0._kind_phys - tropFound(:) = 0._kind_phys - - do i = 1, ncol - if (tropLev(i) /= NOTFOUND) then - tropPdf(i, tropLev(i)) = 1._kind_phys - tropFound(i) = 1._kind_phys - end if - end do - - ! call outfld('TROP' // TROP_LETTER(alg) // '_P', tropP(:ncol), ncol, lchnk) - ! call outfld('TROP' // TROP_LETTER(alg) // '_T', tropT(:ncol), ncol, lchnk) - ! call outfld('TROP' // TROP_LETTER(alg) // '_Z', tropZ(:ncol), ncol, lchnk) - ! call outfld('TROP' // TROP_LETTER(alg) // '_PD', tropPdf(:ncol, :), ncol, lchnk) - ! call outfld('TROP' // TROP_LETTER(alg) // '_FD', tropFound(:ncol), ncol, lchnk) - end do - end if + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + + errmsg = ' ' + errflg = 0 + + ! ! Local Variables + ! integer :: i + ! integer :: alg + ! integer :: ncol ! number of cloumns in the chunk + ! !integer :: lchnk ! chunk identifier + ! integer :: tropLev(pcols) ! tropopause level index + ! real(kind_phys) :: tropP(pcols) ! tropopause pressure (Pa) + ! real(kind_phys) :: tropT(pcols) ! tropopause temperature (K) + ! real(kind_phys) :: tropZ(pcols) ! tropopause height (m) + ! real(kind_phys) :: tropFound(pcols) ! tropopause found + ! real(kind_phys) :: tropDZ(pcols, pver) ! relative tropopause height (m) + ! real(kind_phys) :: tropPdf(pcols, pver) ! tropopause probability distribution + + ! ! Information about the chunk. + ! !lchnk = pstate%lchnk + + ! ! Find the tropopause using the default algorithm backed by the climatology. + ! call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ) + + ! tropPdf(:,:) = 0._kind_phys + ! tropFound(:) = 0._kind_phys + ! tropDZ(:,:) = fillvalue + ! do i = 1, ncol + ! if (tropLev(i) /= NOTFOUND) then + ! tropPdf(i, tropLev(i)) = 1._kind_phys + ! tropFound(i) = 1._kind_phys + ! tropDZ(i,:) = zm(i,:) - tropZ(i) + ! end if + ! end do + + ! ! call outfld('TROP_P', tropP(:ncol), ncol, lchnk) + ! ! call outfld('TROP_T', tropT(:ncol), ncol, lchnk) + ! ! call outfld('TROP_Z', tropZ(:ncol), ncol, lchnk) + ! ! call outfld('TROP_DZ', tropDZ(:ncol, :), ncol, lchnk) + ! ! call outfld('TROP_PD', tropPdf(:ncol, :), ncol, lchnk) + ! ! call outfld('TROP_FD', tropFound(:ncol), ncol, lchnk) + + + ! ! Find the tropopause using just the primary algorithm. + ! call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, backup=TROP_ALG_NONE) + + ! tropPdf(:,:) = 0._kind_phys + ! tropFound(:) = 0._kind_phys + ! tropDZ(:,:) = fillvalue + + ! do i = 1, ncol + ! if (tropLev(i) /= NOTFOUND) then + ! tropPdf(i, tropLev(i)) = 1._kind_phys + ! tropFound(i) = 1._kind_phys + ! tropDZ(i,:) = zm(i,:) - tropZ(i) + ! end if + ! end do + + ! ! call outfld('TROPP_P', tropP(:ncol), ncol, lchnk) + ! ! call outfld('TROPP_T', tropT(:ncol), ncol, lchnk) + ! ! call outfld('TROPP_Z', tropZ(:ncol), ncol, lchnk) + ! ! call outfld('TROPP_DZ', tropDZ(:ncol, :), ncol, lchnk) + ! ! call outfld('TROPP_PD', tropPdf(:ncol, :), ncol, lchnk) + ! ! call outfld('TROPP_FD', tropFound(:ncol), ncol, lchnk) + + + ! ! Find the tropopause using just the cold point algorithm. + ! call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=TROP_ALG_CPP, backup=TROP_ALG_NONE) + + ! tropPdf(:,:) = 0._kind_phys + ! tropFound(:) = 0._kind_phys + ! tropDZ(:,:) = fillvalue + + ! do i = 1, ncol + ! if (tropLev(i) /= NOTFOUND) then + ! tropPdf(i, tropLev(i)) = 1._kind_phys + ! tropFound(i) = 1._kind_phys + ! tropDZ(i,:) = zm(i,:) - tropZ(i) + ! end if + ! end do + + ! ! call outfld('TROPF_P', tropP(:ncol), ncol, lchnk) + ! ! call outfld('TROPF_T', tropT(:ncol), ncol, lchnk) + ! ! call outfld('TROPF_Z', tropZ(:ncol), ncol, lchnk) + ! ! call outfld('TROPF_DZ', tropDZ(:ncol, :), ncol, lchnk) + ! ! call outfld('TROPF_PD', tropPdf(:ncol, :), ncol, lchnk) + ! ! call outfld('TROPF_FD', tropFound(:ncol), ncol, lchnk) + + + ! ! If requested, do all of the algorithms. + ! if (output_all) then + + ! do alg = 2, TROP_NALG + + ! ! Find the tropopause using just the analytic algorithm. + ! call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=alg, backup=TROP_ALG_NONE) + + ! tropPdf(:,:) = 0._kind_phys + ! tropFound(:) = 0._kind_phys + + ! do i = 1, ncol + ! if (tropLev(i) /= NOTFOUND) then + ! tropPdf(i, tropLev(i)) = 1._kind_phys + ! tropFound(i) = 1._kind_phys + ! end if + ! end do + + ! ! call outfld('TROP' // TROP_LETTER(alg) // '_P', tropP(:ncol), ncol, lchnk) + ! ! call outfld('TROP' // TROP_LETTER(alg) // '_T', tropT(:ncol), ncol, lchnk) + ! ! call outfld('TROP' // TROP_LETTER(alg) // '_Z', tropZ(:ncol), ncol, lchnk) + ! ! call outfld('TROP' // TROP_LETTER(alg) // '_PD', tropPdf(:ncol, :), ncol, lchnk) + ! ! call outfld('TROP' // TROP_LETTER(alg) // '_FD', tropFound(:ncol), ncol, lchnk) + ! end do + ! end if return - end subroutine tropopause_output -end module tropopause_output \ No newline at end of file + end subroutine tropopause_diagnostics_run +end module tropopause_diagnostics \ No newline at end of file diff --git a/tropopause_find/tropopause_diagnostics.meta b/tropopause_find/tropopause_diagnostics.meta new file mode 100644 index 00000000..621501f1 --- /dev/null +++ b/tropopause_find/tropopause_diagnostics.meta @@ -0,0 +1,35 @@ +[ccpp-table-properties] + name = tropopause_diagnostics + type = scheme + +[ccpp-arg-table] + name = tropopause_diagnostics_init + type = scheme +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out + +[ccpp-arg-table] + name = tropopause_diagnostics_run + type = scheme +[ errmsg ] + standard_name = ccpp_error_message + units = none + type = character | kind = len=512 + dimensions = () + intent = out +[ errflg ] + standard_name = ccpp_error_code + units = 1 + type = integer + dimensions = () + intent = out diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index 66d61ec8..94d4676c 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -21,6 +21,8 @@ module tropopause_find !--------------------------------------------------------------- use ccpp_kinds, only : kind_phys + + ! FIXME: hplin remove use statements here. use cam_abortutils, only : endrun use cam_logfile, only : iulog use cam_history_support, only : fillvalue @@ -33,7 +35,6 @@ module tropopause_find public :: tropopause_find_init public :: tropopause_find_run - public :: tropopause_findChemTrop public :: TROP_ALG_NONE, TROP_ALG_ANALYTIC, TROP_ALG_CLIMATE public :: TROP_ALG_STOBIE, TROP_ALG_HYBSTOB, TROP_ALG_TWMO, TROP_ALG_WMO public :: TROP_ALG_CPP @@ -56,8 +57,8 @@ module tropopause_find integer, parameter :: TROP_ALG_CPP = 8 ! Cold Point Parabolic integer, parameter :: TROP_ALG_CHEMTROP = 9 ! Chemical tropopause - integer, parameter :: TROP_NALG = 8 ! Number of Algorithms - character,parameter :: TROP_LETTER(TROP_NALG) = (/ ' ', 'A', 'C', 'S', 'T', 'W', 'H', 'F' /) + integer, parameter :: TROP_NALG = 9 ! Number of Algorithms + character,parameter :: TROP_LETTER(TROP_NALG) = (/ ' ', 'A', 'C', 'S', 'T', 'W', 'H', 'F', 'M' /) ! unique identifier for output, don't use P ! These variables should probably be controlled by namelist entries. @@ -70,7 +71,7 @@ module tropopause_find integer, parameter :: NOTFOUND = -1 - real(kind_phys),parameter :: ALPHA = 0.03_kind_phys + real(kind_phys), parameter :: ALPHA = 0.03_kind_phys ! physical constants ! These constants are set in module variables rather than as parameters @@ -91,15 +92,13 @@ module tropopause_find ! is taken from mo_tropopause. !> \section arg_table_tropopause_find_init Argument Table !! \htmlinclude tropopause_find_init.html - subroutine tropopause_find_init(cappa, rair, gravit, pi, tropopause_climo_file, errmsg, errflg) + subroutine tropopause_find_init(cappa, rair, gravit, pi, errmsg, errflg) real(kind_phys), intent(in) :: cappa ! R/Cp real(kind_phys), intent(in) :: rair ! Dry air gas constant (J K-1 kg-1) real(kind_phys), intent(in) :: gravit ! Gravitational acceleration (m s-2) real(kind_phys), intent(in) :: pi ! Pi - character(len=256), intent(in) :: tropopause_climo_file ! absolute path of climatology file - character(len=512), intent(out) :: errmsg integer, intent(out) :: errflg @@ -113,9 +112,6 @@ subroutine tropopause_find_init(cappa, rair, gravit, pi, tropopause_climo_file, cnst_ka1 = cnst_kap - 1._kind_phys cnst_pi = pi - ! read tropopause climatological data from file - call tropopause_read_file(tropopause_climo_file) - end subroutine tropopause_find_init @@ -127,7 +123,7 @@ end subroutine tropopause_find_init !> \section arg_table_tropopause_find_run Argument Table !! \htmlinclude tropopause_find_run.html subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - calday, tropp_p_loc, & + calday, tropp_p_loc, tropp_days, & tropLev, tropP, tropT, tropZ, primary, backup, & errmsg, errflg) @@ -146,14 +142,17 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM real(kind_phys), intent(in), pointer:: tropp_p_loc(:,:) + integer, intent(in), pointer:: tropp_days(:) ! Day-of-year for climo data, 12 - integer, intent(out) :: tropLev(:) ! tropopause level index - real(kind_phys), optional, intent(out) :: tropP(:) ! tropopause pressure (Pa) - real(kind_phys), optional, intent(out) :: tropT(:) ! tropopause temperature (K) - real(kind_phys), optional, intent(out) :: tropZ(:) ! tropopause height (m) + integer, intent(out) :: tropLev(:) ! tropopause level index + real(kind_phys), intent(out) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), intent(out) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), intent(out) :: tropZ(:) ! tropopause height (m) - integer, optional, intent(in) :: primary ! primary detection algorithm - integer, optional, intent(in) :: backup ! backup detection algorithm + ! primary and backup are no longer optional arguments for CCPP-compliance. + ! specify defaults when calling (TWMO, CLIMO) + integer, intent(in) :: primary ! primary detection algorithm + integer, intent(in) :: backup ! backup detection algorithm character(len=512), intent(out) :: errmsg integer, intent(out) :: errflg @@ -161,39 +160,24 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & errmsg = ' ' errflg = 0 - ! Local Variable - integer :: primAlg ! Primary algorithm - integer :: backAlg ! Backup algorithm - ! Initialize the results to a missing value, so that the algorithms will ! attempt to find the tropopause for all of them. tropLev(:) = NOTFOUND - if (present(tropP)) tropP(:) = fillvalue - if (present(tropT)) tropT(:) = fillvalue - if (present(tropZ)) tropZ(:) = fillvalue - - ! Set the algorithms to be used, either the ones provided or the defaults. - if (present(primary)) then - primAlg = primary - else - primAlg = default_primary - end if - - if (present(backup)) then - backAlg = backup - else - backAlg = default_backup - end if + tropP(:) = fillvalue + tropT(:) = fillvalue + tropZ(:) = fillvalue ! Try to find the tropopause using the primary algorithm. - if (primAlg /= TROP_ALG_NONE) then + if (primary /= TROP_ALG_NONE) then call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - primAlg, tropLev, tropP, tropT, tropZ) + calday, tropp_p_loc, tropp_days, & + primary, tropLev, tropP, tropT, tropZ) end if - if ((backAlg /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then + if ((backup /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - backAlg, tropLev, tropP, tropT, tropZ) + calday, tropp_p_loc, tropp_days, & + backup, tropLev, tropP, tropT, tropZ) end if return @@ -260,7 +244,7 @@ end subroutine tropopause_analytic ! NOTE: The data is read in during tropopause_init and stored in the module ! variable trop subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - calday, tropp_p_loc, tropLev, tropP, tropT, tropZ) + calday, tropp_p_loc, tropp_days, tropLev, tropP, tropT, tropZ) real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns real(kind_phys), intent(in) :: pver ! Number of vertical levels @@ -277,6 +261,7 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM real(kind_phys), intent(in), pointer:: tropp_p_loc(:,:) + integer, intent(in), pointer:: tropp_days(:) ! Day-of-year for climo data, 12 integer, intent(inout) :: tropLev(:) ! tropopause level index real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) @@ -293,7 +278,7 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & integer :: last integer :: next - ! If any columns remain to be indentified, the nget the current + ! If any columns remain to be indentified, then get the current ! day from the calendar. if (any(tropLev == NOTFOUND)) then @@ -960,6 +945,7 @@ end subroutine tropopause_cpp ! and now also returns the standard tropLev, tropP, tropT, tropZ outputs (optional). ! The "backup" option is dropped as it is not used anywhere in current CAM. subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zm, phis, & + calday, tropp_p_loc, tropp_days, & tropLev, tropP, tropT, tropZ) real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns @@ -971,6 +957,13 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zm, phis, & real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) + real(kind_phys), intent(in) :: calday ! Day of year including fraction from get_curr_calday + + ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). + ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM + real(kind_phys), intent(in), pointer:: tropp_p_loc(:,:) + integer, intent(in), pointer:: tropp_days(:) ! Day-of-year for climo data, 12 + integer, intent(out) :: tropLev(:) ! tropopause level index real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) @@ -984,7 +977,8 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zm, phis, & ! First use the lapse rate tropopause. ! (Not specifying primary will use the lapse rate) - call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zm, phis, tropLev, backup=TROP_ALG_NONE) + call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zm, phis, & + calday, tropp_p_loc, tropp_days, TROP_ALG_TWMO, tropLev) ! Now check high latitudes (poleward of 50) and set the level to the ! climatology if the level was not found or is at P <= 125 hPa. @@ -1002,7 +996,8 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zm, phis, & ! Now use the backup algorithm if ((backAlg /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then - call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zm, phis, default_backup, tropLev) + call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zm, phis, & + calday, tropp_p_loc, tropp_days, default_backup, tropLev) end if return @@ -1015,7 +1010,7 @@ end subroutine tropopause_findChemTrop ! NOTE: It is assumed that the output fields have been initialized by the ! caller, and only output values set to fillvalue will be detected. subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - calday, tropp_p_loc, & + calday, tropp_p_loc, tropp_days, & algorithm, tropLev, tropP, tropT, tropZ) real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns @@ -1033,6 +1028,7 @@ subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM real(kind_phys), intent(in), pointer:: tropp_p_loc(:,:) + integer, intent(in), pointer:: tropp_days(:) ! Day-of-year for climo data, 12 integer, intent(in) :: algorithm ! detection algorithm integer, intent(inout) :: tropLev(:) ! tropopause level index @@ -1047,7 +1043,8 @@ subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & case(TROP_ALG_CLIMATE) call tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - calday, tropp_p_loc, tropLev, tropP, tropT, tropZ) + calday, tropp_p_loc, tropp_days, & + tropLev, tropP, tropT, tropZ) case(TROP_ALG_STOBIE) call tropopause_stobie(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) @@ -1065,7 +1062,10 @@ subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & call tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) case(TROP_ALG_CHEMTROP) - call tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zm, phis, tropLev, tropP, tropT, tropZ) + ! hplin: needs climatological arguments as calling tropopause_findUsing from within findChemTrop + call tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + calday, tropp_p_loc, tropp_days, & + tropLev, tropP, tropT, tropZ) case default write(iulog, *) 'tropopause: Invalid detection algorithm (', algorithm, ') specified.' diff --git a/tropopause_find/tropopause_find.meta b/tropopause_find/tropopause_find.meta index 7d52802c..6fcb45c0 100644 --- a/tropopause_find/tropopause_find.meta +++ b/tropopause_find/tropopause_find.meta @@ -29,12 +29,6 @@ type = real | kind = kind_phys dimensions = () intent = in -[ tropopause_climo_file ] - standard_name = enter_standard_name_5 - units = enter_units - type = character | kind = len=256 - dimensions = () - intent = in [ errmsg ] standard_name = ccpp_error_message units = none @@ -105,8 +99,26 @@ type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in +[ calday ] + standard_name = fractional_calendar_days_on_end_of_current_timestep + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in +[ tropp_p_loc ] + standard_name = tropopause_air_pressure_from_climatology + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent,12) + intent = in +[ tropp_days ] + standard_name = tropopause_calendar_days_from_climatology + units = 1 + type = integer + dimensions = (12) + intent = in [ tropLev ] - standard_name = enter_standard_name_19 + standard_name = model_level_number_at_tropopause units = 1 type = integer dimensions = (horizontal_loop_extent) @@ -130,14 +142,14 @@ dimensions = (horizontal_loop_extent) intent = out [ primary ] - standard_name = enter_standard_name_17 - units = enter_units + standard_name = control_for_tropopause_find_method + units = 1 type = integer dimensions = () intent = in [ backup ] - standard_name = enter_standard_name_18 - units = enter_units + standard_name = control_for_tropopause_find_method_secondary + units = 1 type = integer dimensions = () intent = in diff --git a/tropopause_find/tropopause_find_namelist.xml b/tropopause_find/tropopause_find_namelist.xml new file mode 100644 index 00000000..6c6513b8 --- /dev/null +++ b/tropopause_find/tropopause_find_namelist.xml @@ -0,0 +1,24 @@ + + + + + + + + + + char*256 + abs + tropo + tropopause_nl + filename_of_tropopause_air_pressure_from_climatology + none + + + Full pathname of boundary dataset for tropopause climatology. Default: set by build-namelist. + + + trop_climo + + + From 72ed07db32388f7ee5af8039ea1cee5f40de655a Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Thu, 15 Aug 2024 15:39:50 -0400 Subject: [PATCH 05/31] Remove incompatible hardcoded dimension; fix dimension for tropp_p_loc to pcols (not ncol) --- tropopause_find/tropopause_find.meta | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tropopause_find/tropopause_find.meta b/tropopause_find/tropopause_find.meta index 6fcb45c0..40410655 100644 --- a/tropopause_find/tropopause_find.meta +++ b/tropopause_find/tropopause_find.meta @@ -109,13 +109,13 @@ standard_name = tropopause_air_pressure_from_climatology units = Pa type = real | kind = kind_phys - dimensions = (horizontal_loop_extent,12) + dimensions = (horizontal_dimension, number_of_months_in_year) intent = in [ tropp_days ] standard_name = tropopause_calendar_days_from_climatology units = 1 type = integer - dimensions = (12) + dimensions = (number_of_months_in_year) intent = in [ tropLev ] standard_name = model_level_number_at_tropopause From bbf785b7f8344370aa961f0f30dfd4d028e7f868 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Thu, 15 Aug 2024 15:52:54 -0400 Subject: [PATCH 06/31] Fix wrong intents and types --- tropopause_find/tropopause_find.F90 | 40 ++++++++++---------- tropopause_find/tropopause_find.meta | 4 +- tropopause_find/tropopause_find_namelist.xml | 2 +- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index 94d4676c..a69e3600 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -127,8 +127,8 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & tropLev, tropP, tropT, tropZ, primary, backup, & errmsg, errflg) - real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns - real(kind_phys), intent(in) :: pver ! Number of vertical levels + integer, intent(in) :: ncol ! Number of atmospheric columns + integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) @@ -188,8 +188,8 @@ end subroutine tropopause_find_run subroutine tropopause_analytic(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & tropLev, tropP, tropT, tropZ) - real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns - real(kind_phys), intent(in) :: pver ! Number of vertical levels + integer, intent(in) :: ncol ! Number of atmospheric columns + integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) @@ -246,8 +246,8 @@ end subroutine tropopause_analytic subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, tropLev, tropP, tropT, tropZ) - real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns - real(kind_phys), intent(in) :: pver ! Number of vertical levels + integer, intent(in) :: ncol ! Number of atmospheric columns + integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) @@ -364,8 +364,8 @@ subroutine tropopause_hybridstobie(ncol, pver, pmid, t, zm, & !----------------------------------------------------------------------- ! ... Local variables !----------------------------------------------------------------------- - real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns - real(kind_phys), intent(in) :: pver ! Number of vertical levelserp + integer, intent(in) :: ncol ! Number of atmospheric columns + integer, intent(in) :: pver ! Number of vertical levelserp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver @@ -451,8 +451,8 @@ end subroutine tropopause_hybridstobie subroutine tropopause_stobie(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & tropLev, tropP, tropT, tropZ) - real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns - real(kind_phys), intent(in) :: pver ! Number of vertical levels + integer, intent(in) :: ncol ! Number of atmospheric columns + integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) @@ -648,8 +648,8 @@ end subroutine twmo subroutine tropopause_twmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & tropLev, tropP, tropT, tropZ) - real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns - real(kind_phys), intent(in) :: pver ! Number of vertical levels + integer, intent(in) :: ncol ! Number of atmospheric columns + integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) @@ -719,8 +719,8 @@ end subroutine tropopause_twmo subroutine tropopause_wmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & tropLev, tropP, tropT, tropZ) - real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns - real(kind_phys), intent(in) :: pver ! Number of vertical levels + integer, intent(in) :: ncol ! Number of atmospheric columns + integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) @@ -815,8 +815,8 @@ end subroutine tropopause_wmo subroutine tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & tropLev, tropP, tropT, tropZ) - real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns - real(kind_phys), intent(in) :: pver ! Number of vertical levels + integer, intent(in) :: ncol ! Number of atmospheric columns + integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) @@ -948,8 +948,8 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zm, phis, & calday, tropp_p_loc, tropp_days, & tropLev, tropP, tropT, tropZ) - real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns - real(kind_phys), intent(in) :: pver ! Number of vertical levels + integer, intent(in) :: ncol ! Number of atmospheric columns + integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) @@ -1013,8 +1013,8 @@ subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, & algorithm, tropLev, tropP, tropT, tropZ) - real(kind_phys), intent(in) :: ncol ! Number of atmospheric columns - real(kind_phys), intent(in) :: pver ! Number of vertical levels + integer, intent(in) :: ncol ! Number of atmospheric columns + integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) diff --git a/tropopause_find/tropopause_find.meta b/tropopause_find/tropopause_find.meta index 40410655..9d6816dd 100644 --- a/tropopause_find/tropopause_find.meta +++ b/tropopause_find/tropopause_find.meta @@ -86,13 +86,13 @@ units = m type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_interface_dimension) - intent = out + intent = in [ zm ] standard_name = geopotential_height_wrt_surface units = m type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) - intent = out + intent = in [ phis ] standard_name = surface_geopotential units = m2 s-2 diff --git a/tropopause_find/tropopause_find_namelist.xml b/tropopause_find/tropopause_find_namelist.xml index 6c6513b8..c9881e0d 100644 --- a/tropopause_find/tropopause_find_namelist.xml +++ b/tropopause_find/tropopause_find_namelist.xml @@ -8,7 +8,7 @@ char*256 - abs + tropo tropopause_nl filename_of_tropopause_air_pressure_from_climatology From cd7650469615ff6249a74eaaefd4cf52fec9aa9b Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Thu, 15 Aug 2024 16:10:39 -0400 Subject: [PATCH 07/31] Add scheme_name for tropopause_find_run --- test/test_sdfs/suite_tropopause_find.xml | 2 +- tropopause_find/tropopause_find.F90 | 4 +++- tropopause_find/tropopause_find.meta | 6 ++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/test/test_sdfs/suite_tropopause_find.xml b/test/test_sdfs/suite_tropopause_find.xml index 6d1c5876..13042cdc 100644 --- a/test/test_sdfs/suite_tropopause_find.xml +++ b/test/test_sdfs/suite_tropopause_find.xml @@ -3,10 +3,10 @@ - qneg geopotential_temp tropopause_find + qneg diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index a69e3600..3c2080c5 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -125,7 +125,7 @@ end subroutine tropopause_find_init subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, & tropLev, tropP, tropT, tropZ, primary, backup, & - errmsg, errflg) + scheme_name, errmsg, errflg) integer, intent(in) :: ncol ! Number of atmospheric columns integer, intent(in) :: pver ! Number of vertical levels @@ -154,9 +154,11 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & integer, intent(in) :: primary ! primary detection algorithm integer, intent(in) :: backup ! backup detection algorithm + character(len=64), intent(out) :: scheme_name character(len=512), intent(out) :: errmsg integer, intent(out) :: errflg + scheme_name = 'tropopause_find' errmsg = ' ' errflg = 0 diff --git a/tropopause_find/tropopause_find.meta b/tropopause_find/tropopause_find.meta index 9d6816dd..38396d2f 100644 --- a/tropopause_find/tropopause_find.meta +++ b/tropopause_find/tropopause_find.meta @@ -153,6 +153,12 @@ type = integer dimensions = () intent = in +[ scheme_name ] + standard_name = scheme_name + units = none + type = character | kind = len=64 + dimensions = () + intent = out [ errmsg ] standard_name = ccpp_error_message units = none From fd91d53e54546b0cb8c171c427c0402342b3b2e7 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Thu, 15 Aug 2024 16:16:53 -0400 Subject: [PATCH 08/31] Delete tropopause_nl from scheme and move to CAM --- tropopause_find/tropopause_find_namelist.xml | 24 -------------------- 1 file changed, 24 deletions(-) delete mode 100644 tropopause_find/tropopause_find_namelist.xml diff --git a/tropopause_find/tropopause_find_namelist.xml b/tropopause_find/tropopause_find_namelist.xml deleted file mode 100644 index c9881e0d..00000000 --- a/tropopause_find/tropopause_find_namelist.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - char*256 - - tropo - tropopause_nl - filename_of_tropopause_air_pressure_from_climatology - none - - - Full pathname of boundary dataset for tropopause climatology. Default: set by build-namelist. - - - trop_climo - - - From 1d4f92aa138a7939cafaaa34c4e74abc9621d9bb Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Thu, 15 Aug 2024 16:27:01 -0400 Subject: [PATCH 09/31] Remove USE statements and replace with CCPP-ized error handling --- tropopause_find/tropopause_find.F90 | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index 3c2080c5..ae8e5e71 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -22,11 +22,6 @@ module tropopause_find use ccpp_kinds, only : kind_phys - ! FIXME: hplin remove use statements here. - use cam_abortutils, only : endrun - use cam_logfile, only : iulog - use cam_history_support, only : fillvalue - implicit none private @@ -72,6 +67,10 @@ module tropopause_find integer, parameter :: NOTFOUND = -1 real(kind_phys), parameter :: ALPHA = 0.03_kind_phys + + ! FIXME hplin 8/15/24: fillvalue from cam_history_support. To check how it is used + ! and if we can remove it with a generic (NOTFOUND?) value + real(kind_phys), parameter :: fillvalue = 1.e36_kind_phys ! physical constants ! These constants are set in module variables rather than as parameters @@ -389,7 +388,6 @@ subroutine tropopause_hybridstobie(ncol, pver, pmid, t, zm, & real(kind_phys) :: trop_linoz_output(ncol,pver) !For output purposes only. real(kind_phys) :: trop_trop_output(ncol,pver) !For output purposes only. - ! write(iulog,*) 'In set_chem_trop, o3_ndx =',o3_ndx ltrop_linoz(:) = 1 ! Initialize to default value. ltrop_trop(:) = 1 ! Initialize to default value. @@ -1070,8 +1068,8 @@ subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & tropLev, tropP, tropT, tropZ) case default - write(iulog, *) 'tropopause: Invalid detection algorithm (', algorithm, ') specified.' - call endrun + errflg = 1 + write(errmsg,*) 'tropopause: Invalid detection algorithm (', algorithm, ') specified.' end select return From 2a1b626c743b49b780c4b0359a9c0a2946fb27ba Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Thu, 15 Aug 2024 16:41:35 -0400 Subject: [PATCH 10/31] Fix compile type mismatches, duplicate local variable decls from physics_state removal --- tropopause_find/tropopause_find.F90 | 98 +++++++++++++++++------------ 1 file changed, 57 insertions(+), 41 deletions(-) diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index ae8e5e71..d77913f7 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -80,6 +80,7 @@ module tropopause_find real(kind_phys) :: cnst_faktor ! = -gravit/rair real(kind_phys) :: cnst_rga ! = 1/gravit real(kind_phys) :: cnst_ka1 ! = cnst_kap - 1._kind_phys + real(kind_phys) :: cnst_rad2deg ! = 180/pi !================================================================================================ contains @@ -105,11 +106,11 @@ subroutine tropopause_find_init(cappa, rair, gravit, pi, errmsg, errflg) errflg = 0 ! define physical constants - cnst_kap = cappa - cnst_faktor = -gravit/rair - cnst_rga = 1._kind_phys/gravit ! Reciprocal of gravit (s2 m-1) - cnst_ka1 = cnst_kap - 1._kind_phys - cnst_pi = pi + cnst_kap = cappa + cnst_faktor = -gravit/rair + cnst_rga = 1._kind_phys/gravit ! Reciprocal of gravit (s2 m-1) + cnst_ka1 = cnst_kap - 1._kind_phys + cnst_rad2deg = 180._kind_phys/pi ! radians to degrees conversion factor end subroutine tropopause_find_init @@ -172,13 +173,13 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & if (primary /= TROP_ALG_NONE) then call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, & - primary, tropLev, tropP, tropT, tropZ) + primary, tropLev, tropP, tropT, tropZ, errmsg, errflg) end if if ((backup /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, & - backup, tropLev, tropP, tropT, tropZ) + backup, tropLev, tropP, tropT, tropZ, errmsg, errflg) end if return @@ -229,7 +230,7 @@ subroutine tropopause_analytic(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & if (present(tropP)) tropP(i) = tP if (present(tropT)) then - tropT(i) = tropopause_interpolateT(pmid, t, i, tropLev(i), tP) + tropT(i) = tropopause_interpolateT(pver, pmid, t, i, tropLev(i), tP) end if if (present(tropZ)) then @@ -274,7 +275,6 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & integer :: k integer :: m real(kind_phys) :: tP ! tropopause pressure (Pa) - real(kind_phys) :: calday ! day of year including fraction real(kind_phys) :: dels integer :: last integer :: next @@ -287,23 +287,23 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & !-------------------------------------------------------- ! ... setup the time interpolation !-------------------------------------------------------- - if( calday < days(1) ) then + if( calday < tropp_days(1) ) then next = 1 last = 12 - dels = (365._kind_phys + calday - days(12)) / (365._kind_phys + days(1) - days(12)) - else if( calday >= days(12) ) then + dels = (365._kind_phys + calday - tropp_days(12)) / (365._kind_phys + tropp_days(1) - tropp_days(12)) + else if( calday >= tropp_days(12) ) then next = 1 last = 12 - dels = (calday - days(12)) / (365._kind_phys + days(1) - days(12)) + dels = (calday - tropp_days(12)) / (365._kind_phys + tropp_days(1) - tropp_days(12)) else do m = 11,1,-1 - if( calday >= days(m) ) then + if( calday >= tropp_days(m) ) then exit end if end do last = m next = m + 1 - dels = (calday - days(m)) / (days(m+1) - days(m)) + dels = (calday - tropp_days(m)) / (tropp_days(m+1) - tropp_days(m)) end if dels = max( min( 1._kind_phys,dels ),0._kind_phys ) @@ -334,7 +334,7 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & if (present(tropP)) tropP(i) = tP if (present(tropT)) then - tropT(i) = tropopause_interpolateT(pmid, t, i, tropLev(i), tP) + tropT(i) = tropopause_interpolateT(pver, pmid, t, i, tropLev(i), tP) end if if (present(tropZ)) then @@ -379,7 +379,7 @@ subroutine tropopause_hybridstobie(ncol, pver, pmid, t, zm, & real(kind_phys),parameter :: min_Stobie_Pressure= 40.E2_kind_phys !For case 2 & 4. [Pa] real(kind_phys),parameter :: max_Linoz_Pressure =208.E2_kind_phys !For case 4. [Pa] - integer :: i, k, ncol + integer :: i, k real(kind_phys) :: stobie_min, shybrid_temp !temporary variable for case 2 & 3. integer :: ltrop_linoz(ncol) !Lowest possible Linoz vertical level integer :: ltrop_trop(ncol) !Tropopause level for hybrid case. @@ -510,7 +510,7 @@ subroutine tropopause_stobie(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & if (present(tropP)) tropP(i) = tP if (present(tropT)) then - tropT(i) = tropopause_interpolateT(pmid, t, i, tropLev(i), tP) + tropT(i) = tropopause_interpolateT(pver, pmid, t, i, tropLev(i), tP) end if if (present(tropZ)) then @@ -695,7 +695,7 @@ subroutine tropopause_twmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & if (present(tropP)) tropP(i) = tP if (present(tropT)) then - tropT(i) = tropopause_interpolateT(pmid, t, i, tropLev(i), tP) + tropT(i) = tropopause_interpolateT(pver, pmid, t, i, tropLev(i), tP) end if if (present(tropZ)) then @@ -743,7 +743,6 @@ subroutine tropopause_wmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & integer :: i integer :: k integer :: k2 - integer :: ncol ! number of columns in the chunk real(kind_phys) :: tP ! tropopause pressure (Pa) real(kind_phys) :: dt @@ -791,7 +790,7 @@ subroutine tropopause_wmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & if (present(tropP)) tropP(i) = tP if (present(tropT)) then - tropT(i) = tropopause_interpolateT(pmid, t, i, tropLev(i), tP) + tropT(i) = tropopause_interpolateT(pver, pmid, t, i, tropLev(i), tP) end if if (present(tropZ)) then @@ -836,7 +835,6 @@ subroutine tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & integer :: i integer :: k, firstk, lastk integer :: k2 - integer :: ncol ! number of columns in the chunk real(kind_phys) :: tZ ! tropopause height (m) real(kind_phys) :: tmin real(kind_phys) :: f0, f1, f2 @@ -913,7 +911,7 @@ subroutine tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & ! Return the optional outputs if (present(tropP)) then - tropP(i) = tropopause_interpolateP(pmid, zm, i, tropLev(i), tZ) + tropP(i) = tropopause_interpolateP(pver, pmid, zm, i, tropLev(i), tZ) end if if (present(tropT)) then @@ -944,9 +942,9 @@ end subroutine tropopause_cpp ! During the CCPP-ization, findChemTrop is now called from tropopause_find_run using method CHEMTROP ! and now also returns the standard tropLev, tropP, tropT, tropZ outputs (optional). ! The "backup" option is dropped as it is not used anywhere in current CAM. - subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zm, phis, & + subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, & - tropLev, tropP, tropT, tropZ) + tropLev, tropP, tropT, tropZ, errmsg, errflg) integer, intent(in) :: ncol ! Number of atmospheric columns integer, intent(in) :: pver ! Number of vertical levels @@ -954,6 +952,7 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zm, phis, & real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) @@ -964,25 +963,32 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zm, phis, & real(kind_phys), intent(in), pointer:: tropp_p_loc(:,:) integer, intent(in), pointer:: tropp_days(:) ! Day-of-year for climo data, 12 - integer, intent(out) :: tropLev(:) ! tropopause level index - real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) - real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) - real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) + integer, intent(out) :: tropLev(:) ! tropopause level index + real(kind_phys), intent(inout) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), intent(inout) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), intent(inout) :: tropZ(:) ! tropopause height (m) + + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg ! Local Variable - real(kind_phys), parameter :: rad2deg = 180._kind_phys/pi ! radians to degrees conversion factor - real(kind_phys) :: dlats(ncol) + real(kind_phys) :: dlats(ncol) integer :: i integer :: backAlg + errmsg = ' ' + errflg = 0 + ! First use the lapse rate tropopause. ! (Not specifying primary will use the lapse rate) - call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zm, phis, & - calday, tropp_p_loc, tropp_days, TROP_ALG_TWMO, tropLev) + call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + calday, tropp_p_loc, tropp_days, & + TROP_ALG_TWMO, tropLev, tropP, tropT, tropZ, & + errmsg, errflg) ! Now check high latitudes (poleward of 50) and set the level to the ! climatology if the level was not found or is at P <= 125 hPa. - dlats(:ncol) = lat(:ncol) * rad2deg ! convert to degrees + dlats(:ncol) = lat(:ncol) * cnst_rad2deg ! convert to degrees do i = 1, ncol if (abs(dlats(i)) > 50._kind_phys) then @@ -996,8 +1002,10 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zm, phis, & ! Now use the backup algorithm if ((backAlg /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then - call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zm, phis, & - calday, tropp_p_loc, tropp_days, default_backup, tropLev) + call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + calday, tropp_p_loc, tropp_days, & + default_backup, tropLev, tropP, tropT, tropZ, & + errmsg, errflg) end if return @@ -1011,7 +1019,7 @@ end subroutine tropopause_findChemTrop ! caller, and only output values set to fillvalue will be detected. subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, & - algorithm, tropLev, tropP, tropT, tropZ) + algorithm, tropLev, tropP, tropT, tropZ, errmsg, errflg) integer, intent(in) :: ncol ! Number of atmospheric columns integer, intent(in) :: pver ! Number of vertical levels @@ -1036,6 +1044,12 @@ subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + + errmsg = ' ' + errflg = 0 + ! Dispatch the request to the appropriate routine. select case(algorithm) case(TROP_ALG_ANALYTIC) @@ -1065,7 +1079,8 @@ subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & ! hplin: needs climatological arguments as calling tropopause_findUsing from within findChemTrop call tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, & - tropLev, tropP, tropT, tropZ) + tropLev, tropP, tropT, tropZ, & + errmsg, errflg) case default errflg = 1 @@ -1078,10 +1093,11 @@ end subroutine tropopause_findUsing ! This routine interpolates the pressures in the physics state to ! find the pressure at the specified tropopause altitude. - function tropopause_interpolateP(pmid, zm, icol, tropLev, tropZ) + function tropopause_interpolateP(pver, pmid, zm, icol, tropLev, tropZ) implicit none + integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver integer, intent(in) :: icol ! column being processed @@ -1123,10 +1139,11 @@ end function tropopause_interpolateP ! This routine interpolates the temperatures in the physics state to ! find the temperature at the specified tropopause pressure. - function tropopause_interpolateT(pmid, t, icol, tropLev, tropP) + function tropopause_interpolateT(pver, pmid, t, icol, tropLev, tropP) implicit none + integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) integer, intent(in) :: icol ! column being processed @@ -1172,7 +1189,6 @@ function tropopause_interpolateZ(pint, pmid, zi, zm, phis, icol, tropLev, tropP) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) - real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) From a6d9967d0864abf9b138f9e5677a63fe4708eba5 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Thu, 15 Aug 2024 17:26:30 -0400 Subject: [PATCH 11/31] Removal of POINTERs per CCPP-convention --- tropopause_find/tropopause_find.F90 | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index d77913f7..f1dd7dc5 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -141,8 +141,8 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM - real(kind_phys), intent(in), pointer:: tropp_p_loc(:,:) - integer, intent(in), pointer:: tropp_days(:) ! Day-of-year for climo data, 12 + real(kind_phys), intent(in) :: tropp_p_loc(:,:) + integer, intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 integer, intent(out) :: tropLev(:) ! tropopause level index real(kind_phys), intent(out) :: tropP(:) ! tropopause pressure (Pa) @@ -262,8 +262,8 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM - real(kind_phys), intent(in), pointer:: tropp_p_loc(:,:) - integer, intent(in), pointer:: tropp_days(:) ! Day-of-year for climo data, 12 + real(kind_phys), intent(in) :: tropp_p_loc(:,:) + integer, intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 integer, intent(inout) :: tropLev(:) ! tropopause level index real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) @@ -960,8 +960,8 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM - real(kind_phys), intent(in), pointer:: tropp_p_loc(:,:) - integer, intent(in), pointer:: tropp_days(:) ! Day-of-year for climo data, 12 + real(kind_phys), intent(in) :: tropp_p_loc(:,:) + integer, intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 integer, intent(out) :: tropLev(:) ! tropopause level index real(kind_phys), intent(inout) :: tropP(:) ! tropopause pressure (Pa) @@ -1035,8 +1035,8 @@ subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM - real(kind_phys), intent(in), pointer:: tropp_p_loc(:,:) - integer, intent(in), pointer:: tropp_days(:) ! Day-of-year for climo data, 12 + real(kind_phys), intent(in) :: tropp_p_loc(:,:) + integer, intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 integer, intent(in) :: algorithm ! detection algorithm integer, intent(inout) :: tropLev(:) ! tropopause level index From b38715bd269c661b353afa9c2fe8a8e19f5a46b1 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 19 Aug 2024 12:13:31 -0400 Subject: [PATCH 12/31] Prepare for multiple scheme calculation; setup for History diagnostics --- .../tropopause_diagnostics.F90 | 0 .../tropopause_diagnostics.meta | 0 tropopause_find/tropopause_find.F90 | 330 +++++++++++++----- tropopause_find/tropopause_find.meta | 94 ++++- 4 files changed, 320 insertions(+), 104 deletions(-) rename {tropopause_find => cam_diagnostics}/tropopause_diagnostics.F90 (100%) rename {tropopause_find => cam_diagnostics}/tropopause_diagnostics.meta (100%) diff --git a/tropopause_find/tropopause_diagnostics.F90 b/cam_diagnostics/tropopause_diagnostics.F90 similarity index 100% rename from tropopause_find/tropopause_diagnostics.F90 rename to cam_diagnostics/tropopause_diagnostics.F90 diff --git a/tropopause_find/tropopause_diagnostics.meta b/cam_diagnostics/tropopause_diagnostics.meta similarity index 100% rename from tropopause_find/tropopause_diagnostics.meta rename to cam_diagnostics/tropopause_diagnostics.meta diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index f1dd7dc5..e2f06826 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -30,6 +30,11 @@ module tropopause_find public :: tropopause_find_init public :: tropopause_find_run + ! "Wrapped" routine for use in old CAM for backward compatibility. + ! Also called by tropopause_find_run driver routine. + public :: tropopause_findWithBackup + + ! Switches for tropopause method public :: TROP_ALG_NONE, TROP_ALG_ANALYTIC, TROP_ALG_CLIMATE public :: TROP_ALG_STOBIE, TROP_ALG_HYBSTOB, TROP_ALG_TWMO, TROP_ALG_WMO public :: TROP_ALG_CPP @@ -114,18 +119,115 @@ subroutine tropopause_find_init(cappa, rair, gravit, pi, errmsg, errflg) end subroutine tropopause_find_init + ! "Driver" routine for tropopause_find. Identifies the tropopause using several methods + ! and populates them into the model state. + ! Most methods use climatological tropopause as a backup, and as such is guaranteed to + ! find a tropopause in all columns. Others are explicitly single-method and used by + ! other parameterizations as-is with NOTFOUND values being intentional. +!> \section arg_table_tropopause_find_run Argument Table +!! \htmlinclude tropopause_find_run.html + subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + calday, tropp_p_loc, tropp_days, & + tropLev, tropP, tropT, tropZ, & ! Default primary+backup ( twmo+climate) + tropLev_clim, tropP_clim, tropT_clim, tropZ_clim, & ! Climate-only + tropLev_hybstob, tropP_hybstob, tropT_hybstob, tropZ_hybstob, & ! Hybridstobie + climate backup + tropLev_cpp, tropP_cpp, tropT_cpp, tropZ_cpp, & ! Cold point only + hstobie_trop, hstobie_linoz, hstobie_tropop, & ! Hybridstobie only for chemistry diagnostics + scheme_name, errmsg, errflg) + + integer, intent(in) :: ncol ! Number of atmospheric columns + integer, intent(in) :: pver ! Number of vertical levels + real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) + real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) + + real(kind_phys), intent(in) :: calday ! Day of year including fraction from get_curr_calday + + ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). + ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM + real(kind_phys), intent(in) :: tropp_p_loc(:,:) + integer, intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 + + integer, intent(out) :: tropLev(:) ! tropopause level index + real(kind_phys), intent(out) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), intent(out) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), intent(out) :: tropZ(:) ! tropopause height (m) + + integer, intent(out) :: tropLev_clim(:) ! climatology-backed tropopause level index + real(kind_phys), intent(out) :: tropP_clim(:) ! climatology-backed tropopause pressure (Pa) + real(kind_phys), intent(out) :: tropT_clim(:) ! climatology-backed tropopause temperature (K) + real(kind_phys), intent(out) :: tropZ_clim(:) ! climatology-backed tropopause height (m) + + integer, intent(out) :: tropLev_hybstob(:) ! hybridstobie climatology-backed tropopause level index + real(kind_phys), intent(out) :: tropP_hybstob(:) ! hybridstobie climatology-backed tropopause pressure (Pa) + real(kind_phys), intent(out) :: tropT_hybstob(:) ! hybridstobie climatology-backed tropopause temperature (K) + real(kind_phys), intent(out) :: tropZ_hybstob(:) ! hybridstobie climatology-backed tropopause height (m) + + integer, intent(out) :: tropLev_cpp(:) ! cold point tropopause level index + real(kind_phys), intent(out) :: tropP_cpp(:) ! cold point tropopause pressure (Pa) + real(kind_phys), intent(out) :: tropT_cpp(:) ! cold point tropopause temperature (K) + real(kind_phys), intent(out) :: tropZ_cpp(:) ! cold point tropopause height (m) + + ! Optional output arguments for hybridstobie with chemistry + real(kind_phys), intent(out) :: hstobie_trop(:,:) ! Lowest level with strat. chem + real(kind_phys), intent(out) :: hstobie_linoz(:,:) ! Lowest possible Linoz level + real(kind_phys), intent(out) :: hstobie_tropop(:,:) ! Troposphere boundary calculated in chem. + + character(len=64), intent(out) :: scheme_name + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + + scheme_name = 'tropopause_find' + errmsg = ' ' + errflg = 0 + + ! Obtain the primary output, which is TWMO + climate + call tropopause_findWithBackup(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + calday, tropp_p_loc, tropp_days, & + tropLev, tropP, tropT, tropZ, & + primary=default_primary, backup=default_backup, & + errmsg=errmsg, errflg=errflg) + + ! Any other intended outputs + ! Climatology only + call tropopause_findWithBackup(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + calday, tropp_p_loc, tropp_days, & + tropLev_clim, tropP_clim, tropT_clim, tropZ_clim, & + primary=TROP_ALG_CLIMATE, backup=TROP_ALG_NONE, & + errmsg=errmsg, errflg=errflg) + + ! Cold point (CPP) only + call tropopause_findWithBackup(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + calday, tropp_p_loc, tropp_days, & + tropLev_cpp, tropP_cpp, tropT_cpp, tropZ_cpp, & + primary=TROP_ALG_CPP, backup=TROP_ALG_NONE, & + errmsg=errmsg, errflg=errflg) + + ! Hybridstobie with climatology-backed + call tropopause_findWithBackup(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + calday, tropp_p_loc, tropp_days, & + tropLev_hybstob, tropP_hybstob, tropT_hybstob, tropZ_hybstob, & + hstobie_trop, hstobie_linoz, hstobie_tropop, & + primary=TROP_ALG_HYBSTOB, backup=TROP_ALG_CLIMATE, & + errmsg=errmsg, errflg=errflg) + + end subroutine tropopause_find_run ! Searches all the columns in the chunk and attempts to identify the tropopause. ! Two routines can be specifed, a primary routine which is tried first and a ! backup routine which will be tried only if the first routine fails. If the ! tropopause can not be identified by either routine, then a NOTFOUND is returned ! for the tropopause level, temperature and pressure. -!> \section arg_table_tropopause_find_run Argument Table -!! \htmlinclude tropopause_find_run.html - subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - calday, tropp_p_loc, tropp_days, & - tropLev, tropP, tropT, tropZ, primary, backup, & - scheme_name, errmsg, errflg) + subroutine tropopause_findWithBackup(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + calday, tropp_p_loc, tropp_days, & + tropLev, tropP, tropT, tropZ, & + hstobie_trop, hstobie_linoz, hstobie_tropop, & + primary, backup, & + errmsg, errflg) integer, intent(in) :: ncol ! Number of atmospheric columns integer, intent(in) :: pver ! Number of vertical levels @@ -149,16 +251,19 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), intent(out) :: tropT(:) ! tropopause temperature (K) real(kind_phys), intent(out) :: tropZ(:) ! tropopause height (m) + ! Optional output arguments for hybridstobie with chemistry + real(kind_phys), optional, intent(inout) :: hstobie_trop(:,:) ! Lowest level with strat. chem + real(kind_phys), optional, intent(inout) :: hstobie_linoz(:,:) ! Lowest possible Linoz level + real(kind_phys), optional, intent(inout) :: hstobie_tropop(:,:) ! Troposphere boundary calculated in chem. + ! primary and backup are no longer optional arguments for CCPP-compliance. ! specify defaults when calling (TWMO, CLIMO) integer, intent(in) :: primary ! primary detection algorithm integer, intent(in) :: backup ! backup detection algorithm - character(len=64), intent(out) :: scheme_name character(len=512), intent(out) :: errmsg integer, intent(out) :: errflg - scheme_name = 'tropopause_find' errmsg = ' ' errflg = 0 @@ -173,17 +278,112 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & if (primary /= TROP_ALG_NONE) then call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, & - primary, tropLev, tropP, tropT, tropZ, errmsg, errflg) + primary, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, & + hstobie_trop=hstobie_trop, hstobie_linoz=hstobie_linoz, hstobie_tropop=hstobie_tropop, & ! only for HYBSTOB + errmsg=errmsg, errflg=errflg) end if if ((backup /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, & - backup, tropLev, tropP, tropT, tropZ, errmsg, errflg) + backup, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, & + errmsg=errmsg, errflg=errflg) end if return - end subroutine tropopause_find_run + end subroutine tropopause_findWithBackup + + ! Call the appropriate tropopause detection routine based upon the algorithm + ! specifed. + ! + ! NOTE: It is assumed that the output fields have been initialized by the + ! caller, and only output values set to fillvalue will be detected. + subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + calday, tropp_p_loc, tropp_days, & + algorithm, tropLev, tropP, tropT, tropZ, & + hstobie_trop, hstobie_linoz, hstobie_tropop, & + errmsg, errflg) + + integer, intent(in) :: ncol ! Number of atmospheric columns + integer, intent(in) :: pver ! Number of vertical levels + real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) + real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) + + real(kind_phys), intent(in) :: calday ! Day of year including fraction from get_curr_calday + + ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). + ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM + real(kind_phys), intent(in) :: tropp_p_loc(:,:) + integer, intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 + + integer, intent(in) :: algorithm ! detection algorithm + integer, intent(inout) :: tropLev(:) ! tropopause level index + real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) + + ! Optional output arguments for hybridstobie with chemistry + real(kind_phys), optional, intent(inout) :: hstobie_trop(:,:) ! Lowest level with strat. chem + real(kind_phys), optional, intent(inout) :: hstobie_linoz(:,:) ! Lowest possible Linoz level + real(kind_phys), optional, intent(inout) :: hstobie_tropop(:,:) ! Troposphere boundary calculated in chem. + + character(len=512), intent(out) :: errmsg + integer, intent(out) :: errflg + + errmsg = ' ' + errflg = 0 + + ! Dispatch the request to the appropriate routine. + select case(algorithm) + case(TROP_ALG_ANALYTIC) + call tropopause_analytic(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) + + case(TROP_ALG_CLIMATE) + call tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + calday, tropp_p_loc, tropp_days, & + tropLev, tropP, tropT, tropZ) + + case(TROP_ALG_STOBIE) + call tropopause_stobie(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) + + case(TROP_ALG_HYBSTOB) + if(present(hstobie_trop) .and. present(hstobie_linoz) .and. present(hstobie_tropop)) then + call tropopause_hybridstobie(ncol, pver, pmid, t, zm, & + tropLev, tropP, tropT, tropZ, & + hstobie_trop, hstobie_linoz, hstobie_tropop) + else + call tropopause_hybridstobie(ncol, pver, pmid, t, zm, & + tropLev, tropP, tropT, tropZ) + endif + + case(TROP_ALG_TWMO) + call tropopause_twmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) + + case(TROP_ALG_WMO) + call tropopause_wmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) + + case(TROP_ALG_CPP) + call tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) + + case(TROP_ALG_CHEMTROP) + ! hplin: needs climatological arguments as calling tropopause_findUsing from within findChemTrop + call tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + calday, tropp_p_loc, tropp_days, & + tropLev, tropP, tropT, tropZ, & + errmsg, errflg) + + case default + errflg = 1 + write(errmsg,*) 'tropopause: Invalid detection algorithm (', algorithm, ') specified.' + end select + + return + end subroutine tropopause_findUsing ! This analytic expression closely matches the mean tropopause determined ! by the NCEP reanalysis and has been used by the radiation code. @@ -350,7 +550,8 @@ end subroutine tropopause_climate !----------------------------------------------------------------------- !----------------------------------------------------------------------- subroutine tropopause_hybridstobie(ncol, pver, pmid, t, zm, & - tropLev, tropP, tropT, tropZ) + tropLev, tropP, tropT, tropZ, & + hstobie_trop, hstobie_linoz, hstobie_tropop) !use cam_history, only : outfld !----------------------------------------------------------------------- @@ -375,6 +576,11 @@ subroutine tropopause_hybridstobie(ncol, pver, pmid, t, zm, & real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) + + ! Optional output arguments for hybridstobie with chemistry + real(kind_phys), optional, intent(inout) :: hstobie_trop(:,:) ! Lowest level with strat. chem + real(kind_phys), optional, intent(inout) :: hstobie_linoz(:,:) ! Lowest possible Linoz level + real(kind_phys), optional, intent(inout) :: hstobie_tropop(:,:) ! Troposphere boundary calculated in chem. real(kind_phys),parameter :: min_Stobie_Pressure= 40.E2_kind_phys !For case 2 & 4. [Pa] real(kind_phys),parameter :: max_Linoz_Pressure =208.E2_kind_phys !For case 4. [Pa] @@ -439,6 +645,18 @@ subroutine tropopause_hybridstobie(ncol, pver, pmid, t, zm, & endif enddo + if(present(hstobie_trop)) then + hstobie_trop(:,:) = trop_output(:,:) + endif + + if(present(hstobie_linoz)) then + hstobie_linoz(:,:) = trop_linoz_output(:,:) + endif + + if(present(hstobie_tropop)) then + hstobie_tropop(:,:) = trop_trop_output(:,:) + endif + !call outfld( 'hstobie_trop', trop_output(:ncol,:), ncol, pstate%lchnk ) !call outfld( 'hstobie_linoz', trop_linoz_output(:ncol,:), ncol, pstate%lchnk ) !call outfld( 'hstobie_tropop', trop_trop_output(:ncol,:), ncol, pstate%lchnk ) @@ -983,8 +1201,8 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, ! (Not specifying primary will use the lapse rate) call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, & - TROP_ALG_TWMO, tropLev, tropP, tropT, tropZ, & - errmsg, errflg) + TROP_ALG_TWMO, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, & + errmsg=errmsg, errflg=errflg) ! Now check high latitudes (poleward of 50) and set the level to the ! climatology if the level was not found or is at P <= 125 hPa. @@ -1004,92 +1222,12 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, if ((backAlg /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, & - default_backup, tropLev, tropP, tropT, tropZ, & - errmsg, errflg) + default_backup, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, & + errmsg=errmsg, errflg=errflg) end if return end subroutine tropopause_findChemTrop - - - ! Call the appropriate tropopause detection routine based upon the algorithm - ! specifed. - ! - ! NOTE: It is assumed that the output fields have been initialized by the - ! caller, and only output values set to fillvalue will be detected. - subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - calday, tropp_p_loc, tropp_days, & - algorithm, tropLev, tropP, tropT, tropZ, errmsg, errflg) - - integer, intent(in) :: ncol ! Number of atmospheric columns - integer, intent(in) :: pver ! Number of vertical levels - real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) - real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp - real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) - real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) - real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp - real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver - real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) - - real(kind_phys), intent(in) :: calday ! Day of year including fraction from get_curr_calday - - ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). - ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM - real(kind_phys), intent(in) :: tropp_p_loc(:,:) - integer, intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 - - integer, intent(in) :: algorithm ! detection algorithm - integer, intent(inout) :: tropLev(:) ! tropopause level index - real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) - real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) - real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) - - character(len=512), intent(out) :: errmsg - integer, intent(out) :: errflg - - errmsg = ' ' - errflg = 0 - - ! Dispatch the request to the appropriate routine. - select case(algorithm) - case(TROP_ALG_ANALYTIC) - call tropopause_analytic(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) - - case(TROP_ALG_CLIMATE) - call tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - calday, tropp_p_loc, tropp_days, & - tropLev, tropP, tropT, tropZ) - - case(TROP_ALG_STOBIE) - call tropopause_stobie(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) - - case(TROP_ALG_HYBSTOB) - call tropopause_hybridstobie(ncol, pver, pmid, t, zm, tropLev, tropP, tropT, tropZ) - - case(TROP_ALG_TWMO) - call tropopause_twmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) - - case(TROP_ALG_WMO) - call tropopause_wmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) - - case(TROP_ALG_CPP) - call tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) - - case(TROP_ALG_CHEMTROP) - ! hplin: needs climatological arguments as calling tropopause_findUsing from within findChemTrop - call tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - calday, tropp_p_loc, tropp_days, & - tropLev, tropP, tropT, tropZ, & - errmsg, errflg) - - case default - errflg = 1 - write(errmsg,*) 'tropopause: Invalid detection algorithm (', algorithm, ') specified.' - end select - - return - end subroutine tropopause_findUsing - ! This routine interpolates the pressures in the physics state to ! find the pressure at the specified tropopause altitude. diff --git a/tropopause_find/tropopause_find.meta b/tropopause_find/tropopause_find.meta index 38396d2f..f01d2a49 100644 --- a/tropopause_find/tropopause_find.meta +++ b/tropopause_find/tropopause_find.meta @@ -141,18 +141,96 @@ type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out -[ primary ] - standard_name = control_for_tropopause_find_method +[ tropLev_clim ] + standard_name = model_level_number_at_tropopause_assuming_climatology units = 1 type = integer - dimensions = () - intent = in -[ backup ] - standard_name = control_for_tropopause_find_method_secondary + dimensions = (horizontal_loop_extent) + intent = out +[ tropP_clim ] + standard_name = tropopause_air_pressure_assuming_climatology + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropT_clim ] + standard_name = tropopause_air_temperature_assuming_climatology + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropZ_clim ] + standard_name = tropopause_altitude_assuming_climatology + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropLev_hybstob ] + standard_name = model_level_number_at_tropopause_assuming_hybridstobie_and_climatology units = 1 type = integer - dimensions = () - intent = in + dimensions = (horizontal_loop_extent) + intent = out +[ tropP_hybstob ] + standard_name = tropopause_air_pressure_assuming_hybridstobie_and_climatology + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropT_hybstob ] + standard_name = tropopause_air_temperature_assuming_hybridstobie_and_climatology + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropZ_hybstob ] + standard_name = tropopause_altitude_assuming_hybridstobie_and_climatology + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropLev_cpp ] + standard_name = model_level_number_at_tropopause_assuming_cold_point + units = 1 + type = integer + dimensions = (horizontal_loop_extent) + intent = out +[ tropP_cpp ] + standard_name = tropopause_air_pressure_assuming_cold_point + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropT_cpp ] + standard_name = tropopause_air_temperature_assuming_cold_point + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropZ_cpp ] + standard_name = tropopause_altitude_assuming_cold_point + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ hstobie_trop ] + standard_name = lower_bound_of_model_level_number_for_stratospheric_chemistry + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ hstobie_linoz ] + standard_name = lower_bound_of_model_level_number_for_linoz_chemistry + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ hstobie_tropop ] + standard_name = model_level_number_at_tropopause_for_chemistry + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out [ scheme_name ] standard_name = scheme_name units = none From 1cc3e24848bbc1fd7e6866f07f1f43a757d74510 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 19 Aug 2024 13:33:24 -0400 Subject: [PATCH 13/31] Add history diagnostics for tropopause_find (initial) --- cam_diagnostics/tropopause_diagnostics.F90 | 316 +++++++++------------ 1 file changed, 139 insertions(+), 177 deletions(-) diff --git a/cam_diagnostics/tropopause_diagnostics.F90 b/cam_diagnostics/tropopause_diagnostics.F90 index 35673adf..e4a527a5 100644 --- a/cam_diagnostics/tropopause_diagnostics.F90 +++ b/cam_diagnostics/tropopause_diagnostics.F90 @@ -17,8 +17,8 @@ module tropopause_diagnostics !! \htmlinclude tropopause_diagnostics_init.html subroutine tropopause_diagnostics_init(errmsg, errflg) - !use cam_history, only: history_add_field - !use cam_history_support, only: horiz_only + use cam_history, only: history_add_field + use cam_history_support, only: horiz_only character(len=512), intent(out) :: errmsg integer, intent(out) :: errflg @@ -27,70 +27,32 @@ subroutine tropopause_diagnostics_init(errmsg, errflg) errflg = 0 ! Define the output fields. - ! call addfld('TROP_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure', flag_xyfill=.True.) - ! call addfld('TROP_T', horiz_only, 'A', 'K', 'Tropopause Temperature', flag_xyfill=.True.) - ! call addfld('TROP_Z', horiz_only, 'A', 'm', 'Tropopause Height', flag_xyfill=.True.) - ! call addfld('TROP_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height') - ! call addfld('TROP_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Probabilty') - ! call addfld('TROP_FD', horiz_only, 'A', 'probability', 'Tropopause Found') - - ! call addfld('TROPP_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (primary)', flag_xyfill=.True.) - ! call addfld('TROPP_T', horiz_only, 'A', 'K', 'Tropopause Temperature (primary)', flag_xyfill=.True.) - ! call addfld('TROPP_Z', horiz_only, 'A', 'm', 'Tropopause Height (primary)', flag_xyfill=.True.) - ! call addfld('TROPP_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height (primary)') - ! call addfld('TROPP_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (primary)') - ! call addfld('TROPP_FD', horiz_only, 'A', 'probability', 'Tropopause Found (primary)') - - ! call addfld('TROPF_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (cold point)', flag_xyfill=.True.) - ! call addfld('TROPF_T', horiz_only, 'A', 'K', 'Tropopause Temperature (cold point)', flag_xyfill=.True.) - ! call addfld('TROPF_Z', horiz_only, 'A', 'm', 'Tropopause Height (cold point)', flag_xyfill=.True.) - ! call addfld('TROPF_DZ', (/ 'lev' /), 'A', 'm', 'Relative Tropopause Height (cold point)', flag_xyfill=.True.) - ! call addfld('TROPF_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (cold point)') - ! call addfld('TROPF_FD', horiz_only, 'A', 'probability', 'Tropopause Found (cold point)') - - ! call addfld( 'hstobie_trop', (/ 'lev' /), 'I', 'fraction of model time', 'Lowest level with stratospheric chemsitry') - ! call addfld( 'hstobie_linoz', (/ 'lev' /), 'I', 'fraction of model time', 'Lowest possible Linoz level') - ! call addfld( 'hstobie_tropop', (/ 'lev' /), 'I', 'fraction of model time', & - ! 'Troposphere boundary calculated in chemistry' ) - - ! ! If requested, be prepared to output results from all of the methods. - ! if (output_all) then - ! call addfld('TROPA_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (analytic)', flag_xyfill=.True.) - ! call addfld('TROPA_T', horiz_only, 'A', 'K', 'Tropopause Temperature (analytic)', flag_xyfill=.True.) - ! call addfld('TROPA_Z', horiz_only, 'A', 'm', 'Tropopause Height (analytic)', flag_xyfill=.True.) - ! call addfld('TROPA_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (analytic)') - ! call addfld('TROPA_FD', horiz_only, 'A', 'probability', 'Tropopause Found (analytic)') - - ! call addfld('TROPC_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (climatology)', flag_xyfill=.True.) - ! call addfld('TROPC_T', horiz_only, 'A', 'K', 'Tropopause Temperature (climatology)', flag_xyfill=.True.) - ! call addfld('TROPC_Z', horiz_only, 'A', 'm', 'Tropopause Height (climatology)', flag_xyfill=.True.) - ! call addfld('TROPC_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (climatology)') - ! call addfld('TROPC_FD', horiz_only, 'A', 'probability', 'Tropopause Found (climatology)') - - ! call addfld('TROPS_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (stobie)', flag_xyfill=.True.) - ! call addfld('TROPS_T', horiz_only, 'A', 'K', 'Tropopause Temperature (stobie)', flag_xyfill=.True.) - ! call addfld('TROPS_Z', horiz_only, 'A', 'm', 'Tropopause Height (stobie)', flag_xyfill=.True.) - ! call addfld('TROPS_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (stobie)') - ! call addfld('TROPS_FD', horiz_only, 'A', 'probability', 'Tropopause Found (stobie)') - - ! call addfld('TROPT_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (twmo)', flag_xyfill=.True.) - ! call addfld('TROPT_T', horiz_only, 'A', 'K', 'Tropopause Temperature (twmo)', flag_xyfill=.True.) - ! call addfld('TROPT_Z', horiz_only, 'A', 'm', 'Tropopause Height (twmo)', flag_xyfill=.True.) - ! call addfld('TROPT_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (twmo)') - ! call addfld('TROPT_FD', horiz_only, 'A', 'probability', 'Tropopause Found (twmo)') - - ! call addfld('TROPW_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (WMO)', flag_xyfill=.True.) - ! call addfld('TROPW_T', horiz_only, 'A', 'K', 'Tropopause Temperature (WMO)', flag_xyfill=.True.) - ! call addfld('TROPW_Z', horiz_only, 'A', 'm', 'Tropopause Height (WMO)', flag_xyfill=.True.) - ! call addfld('TROPW_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (WMO)') - ! call addfld('TROPW_FD', horiz_only, 'A', 'probability', 'Tropopause Found (WMO)') - - ! call addfld('TROPH_P', horiz_only, 'A', 'Pa', 'Tropopause Pressure (Hybrid Stobie)', flag_xyfill=.True.) - ! call addfld('TROPH_T', horiz_only, 'A', 'K', 'Tropopause Temperature (Hybrid Stobie)', flag_xyfill=.True.) - ! call addfld('TROPH_Z', horiz_only, 'A', 'm', 'Tropopause Height (Hybrid Stobie)', flag_xyfill=.True.) - ! call addfld('TROPH_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (Hybrid Stobie)') - ! call addfld('TROPH_FD', horiz_only, 'A', 'probability', 'Tropopause Found (Hybrid Stobie)') - ! end if + call history_add_field('TROP_P', 'tropopause_air_pressure', horiz_only, 'avg', 'Pa') + call history_add_field('TROP_T', 'tropopause_air_temperature', horiz_only, 'avg', 'K' ) + call history_add_field('TROP_Z', 'tropopause_altitude', horiz_only, 'avg', 'm' ) + call history_add_field('TROP_DZ', 'tropopause_altitude_relative', 'lev', 'avg', 'm') + call history_add_field('TROP_PD', 'probability_distribution_of_model_level_number_at_tropopause', 'lev', 'avg', 'probability') + call history_add_field('TROP_FD', 'tropopause_found', horiz_only, 'avg', 'probability') + + call history_add_field('TROPF_P', 'tropopause_air_pressure_assuming_cold_point', horiz_only, 'avg', 'Pa') + call history_add_field('TROPF_T', 'tropopause_air_temperature_assuming_cold_point', horiz_only, 'avg', 'K' ) + call history_add_field('TROPF_Z', 'tropopause_altitude_assuming_cold_point', horiz_only, 'avg', 'm' ) + call history_add_field('TROPF_DZ', 'tropopause_altitude_relative_assuming_cold_point', 'lev', 'avg', 'm') + call history_add_field('TROPF_PD', 'probability_distribution_of_model_level_number_at_tropopause_assuming_cold_point', 'lev', 'avg', 'probability') + call history_add_field('TROPF_FD', 'tropopause_found_assuming_cold_point', horiz_only, 'avg', 'probability') + + call history_add_field('TROPC_P', 'tropopause_air_pressure_assuming_climatology', horiz_only, 'avg', 'Pa') + call history_add_field('TROPC_T', 'tropopause_air_temperature_assuming_climatology', horiz_only, 'avg', 'K' ) + call history_add_field('TROPC_Z', 'tropopause_altitude_assuming_climatology', horiz_only, 'avg', 'm' ) + call history_add_field('TROPC_DZ', 'tropopause_altitude_relative_assuming_climatology', 'lev', 'avg', 'm') + call history_add_field('TROPC_PD', 'probability_distribution_of_model_level_number_at_tropopause_assuming_climatology', 'lev', 'avg', 'probability') + call history_add_field('TROPC_FD', 'tropopause_found_assuming_cold_point', horiz_only, 'avg', 'probability') + + ! Hybridstobie output fields + call history_add_field('hstobie_trop', 'lower_bound_of_model_level_number_for_stratospheric_chemistry', 'lev', 'inst', 'fraction of model time') + call history_add_field('hstobie_linoz', 'lower_bound_of_model_level_number_for_linoz_chemistry', 'lev', 'inst', 'fraction of model time') + call history_add_field('hstobie_tropop', 'model_level_number_at_tropopause_for_chemistry', 'lev', 'inst', 'fraction of model time') + end subroutine tropopause_diagnostics_init ! Output the tropopause pressure and temperature to the history files. Two sets @@ -99,8 +61,45 @@ end subroutine tropopause_diagnostics_init ! algorithm fails. !> \section arg_table_tropopause_diagnostics_run Argument Table !! \htmlinclude tropopause_diagnostics_run.html - subroutine tropopause_diagnostics_run(errmsg, errflg) - !use cam_history, only : outfld + subroutine tropopause_diagnostics_run(ncol, pver, & + zm, & + tropLev, tropP, tropT, tropZ, & ! Default primary+backup ( twmo+climate) + tropLev_clim, tropP_clim, tropT_clim, tropZ_clim, & ! Climate-only + tropLev_hybstob, tropP_hybstob, tropT_hybstob, tropZ_hybstob, & ! Hybridstobie + climate backup + tropLev_cpp, tropP_cpp, tropT_cpp, tropZ_cpp, & ! Cold point only + hstobie_trop, hstobie_linoz, hstobie_tropop, & ! Hybridstobie only for chemistry diagnostics + errmsg, errflg) + use cam_history, only: history_out_field + + integer, intent(in) :: ncol ! Number of atmospheric columns + integer, intent(in) :: pver ! Number of vertical levels + + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + + integer, intent(out) :: tropLev(:) ! tropopause level index + real(kind_phys), intent(out) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), intent(out) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), intent(out) :: tropZ(:) ! tropopause height (m) + + integer, intent(out) :: tropLev_clim(:) ! climatology-backed tropopause level index + real(kind_phys), intent(out) :: tropP_clim(:) ! climatology-backed tropopause pressure (Pa) + real(kind_phys), intent(out) :: tropT_clim(:) ! climatology-backed tropopause temperature (K) + real(kind_phys), intent(out) :: tropZ_clim(:) ! climatology-backed tropopause height (m) + + integer, intent(out) :: tropLev_hybstob(:) ! hybridstobie climatology-backed tropopause level index + real(kind_phys), intent(out) :: tropP_hybstob(:) ! hybridstobie climatology-backed tropopause pressure (Pa) + real(kind_phys), intent(out) :: tropT_hybstob(:) ! hybridstobie climatology-backed tropopause temperature (K) + real(kind_phys), intent(out) :: tropZ_hybstob(:) ! hybridstobie climatology-backed tropopause height (m) + + integer, intent(out) :: tropLev_cpp(:) ! cold point tropopause level index + real(kind_phys), intent(out) :: tropP_cpp(:) ! cold point tropopause pressure (Pa) + real(kind_phys), intent(out) :: tropT_cpp(:) ! cold point tropopause temperature (K) + real(kind_phys), intent(out) :: tropZ_cpp(:) ! cold point tropopause height (m) + + ! Optional output arguments for hybridstobie with chemistry + real(kind_phys), intent(out) :: hstobie_trop(:,:) ! Lowest level with strat. chem + real(kind_phys), intent(out) :: hstobie_linoz(:,:) ! Lowest possible Linoz level + real(kind_phys), intent(out) :: hstobie_tropop(:,:) ! Troposphere boundary calculated in chem. character(len=512), intent(out) :: errmsg integer, intent(out) :: errflg @@ -108,115 +107,78 @@ subroutine tropopause_diagnostics_run(errmsg, errflg) errmsg = ' ' errflg = 0 - ! ! Local Variables - ! integer :: i - ! integer :: alg - ! integer :: ncol ! number of cloumns in the chunk - ! !integer :: lchnk ! chunk identifier - ! integer :: tropLev(pcols) ! tropopause level index - ! real(kind_phys) :: tropP(pcols) ! tropopause pressure (Pa) - ! real(kind_phys) :: tropT(pcols) ! tropopause temperature (K) - ! real(kind_phys) :: tropZ(pcols) ! tropopause height (m) - ! real(kind_phys) :: tropFound(pcols) ! tropopause found - ! real(kind_phys) :: tropDZ(pcols, pver) ! relative tropopause height (m) - ! real(kind_phys) :: tropPdf(pcols, pver) ! tropopause probability distribution - - ! ! Information about the chunk. - ! !lchnk = pstate%lchnk - - ! ! Find the tropopause using the default algorithm backed by the climatology. - ! call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ) - - ! tropPdf(:,:) = 0._kind_phys - ! tropFound(:) = 0._kind_phys - ! tropDZ(:,:) = fillvalue - ! do i = 1, ncol - ! if (tropLev(i) /= NOTFOUND) then - ! tropPdf(i, tropLev(i)) = 1._kind_phys - ! tropFound(i) = 1._kind_phys - ! tropDZ(i,:) = zm(i,:) - tropZ(i) - ! end if - ! end do - - ! ! call outfld('TROP_P', tropP(:ncol), ncol, lchnk) - ! ! call outfld('TROP_T', tropT(:ncol), ncol, lchnk) - ! ! call outfld('TROP_Z', tropZ(:ncol), ncol, lchnk) - ! ! call outfld('TROP_DZ', tropDZ(:ncol, :), ncol, lchnk) - ! ! call outfld('TROP_PD', tropPdf(:ncol, :), ncol, lchnk) - ! ! call outfld('TROP_FD', tropFound(:ncol), ncol, lchnk) - - - ! ! Find the tropopause using just the primary algorithm. - ! call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, backup=TROP_ALG_NONE) - - ! tropPdf(:,:) = 0._kind_phys - ! tropFound(:) = 0._kind_phys - ! tropDZ(:,:) = fillvalue - - ! do i = 1, ncol - ! if (tropLev(i) /= NOTFOUND) then - ! tropPdf(i, tropLev(i)) = 1._kind_phys - ! tropFound(i) = 1._kind_phys - ! tropDZ(i,:) = zm(i,:) - tropZ(i) - ! end if - ! end do - - ! ! call outfld('TROPP_P', tropP(:ncol), ncol, lchnk) - ! ! call outfld('TROPP_T', tropT(:ncol), ncol, lchnk) - ! ! call outfld('TROPP_Z', tropZ(:ncol), ncol, lchnk) - ! ! call outfld('TROPP_DZ', tropDZ(:ncol, :), ncol, lchnk) - ! ! call outfld('TROPP_PD', tropPdf(:ncol, :), ncol, lchnk) - ! ! call outfld('TROPP_FD', tropFound(:ncol), ncol, lchnk) - - - ! ! Find the tropopause using just the cold point algorithm. - ! call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=TROP_ALG_CPP, backup=TROP_ALG_NONE) - - ! tropPdf(:,:) = 0._kind_phys - ! tropFound(:) = 0._kind_phys - ! tropDZ(:,:) = fillvalue - - ! do i = 1, ncol - ! if (tropLev(i) /= NOTFOUND) then - ! tropPdf(i, tropLev(i)) = 1._kind_phys - ! tropFound(i) = 1._kind_phys - ! tropDZ(i,:) = zm(i,:) - tropZ(i) - ! end if - ! end do - - ! ! call outfld('TROPF_P', tropP(:ncol), ncol, lchnk) - ! ! call outfld('TROPF_T', tropT(:ncol), ncol, lchnk) - ! ! call outfld('TROPF_Z', tropZ(:ncol), ncol, lchnk) - ! ! call outfld('TROPF_DZ', tropDZ(:ncol, :), ncol, lchnk) - ! ! call outfld('TROPF_PD', tropPdf(:ncol, :), ncol, lchnk) - ! ! call outfld('TROPF_FD', tropFound(:ncol), ncol, lchnk) - - - ! ! If requested, do all of the algorithms. - ! if (output_all) then - - ! do alg = 2, TROP_NALG - - ! ! Find the tropopause using just the analytic algorithm. - ! call tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=alg, backup=TROP_ALG_NONE) - - ! tropPdf(:,:) = 0._kind_phys - ! tropFound(:) = 0._kind_phys - - ! do i = 1, ncol - ! if (tropLev(i) /= NOTFOUND) then - ! tropPdf(i, tropLev(i)) = 1._kind_phys - ! tropFound(i) = 1._kind_phys - ! end if - ! end do - - ! ! call outfld('TROP' // TROP_LETTER(alg) // '_P', tropP(:ncol), ncol, lchnk) - ! ! call outfld('TROP' // TROP_LETTER(alg) // '_T', tropT(:ncol), ncol, lchnk) - ! ! call outfld('TROP' // TROP_LETTER(alg) // '_Z', tropZ(:ncol), ncol, lchnk) - ! ! call outfld('TROP' // TROP_LETTER(alg) // '_PD', tropPdf(:ncol, :), ncol, lchnk) - ! ! call outfld('TROP' // TROP_LETTER(alg) // '_FD', tropFound(:ncol), ncol, lchnk) - ! end do - ! end if + ! Local Variables + integer :: i + integer :: alg + integer :: tropLev(ncol) ! tropopause level index + real(kind_phys) :: tropP(ncol) ! tropopause pressure (Pa) + real(kind_phys) :: tropT(ncol) ! tropopause temperature (K) + real(kind_phys) :: tropZ(ncol) ! tropopause height (m) + real(kind_phys) :: tropFound(ncol) ! tropopause found + real(kind_phys) :: tropDZ(ncol, pver) ! relative tropopause height (m) + real(kind_phys) :: tropPdf(ncol, pver) ! tropopause probability distribution + + ! Default algorithm output + tropPdf(:,:) = 0._kind_phys + tropFound(:) = 0._kind_phys + tropDZ(:,:) = fillvalue + do i = 1, ncol + if (tropLev(i) /= NOTFOUND) then + tropPdf(i, tropLev(i)) = 1._kind_phys + tropFound(i) = 1._kind_phys + tropDZ(i,:) = zm(i,:) - tropZ(i) + end if + end do + + call history_out_field('TROP_P', tropP) + call history_out_field('TROP_T', tropT) + call history_out_field('TROP_Z', tropZ) + call history_out_field('TROP_DZ', tropDZ) + call history_out_field('TROP_PD', tropPdf) + call history_out_field('TROP_FD', tropFound) + + ! Cold point output + tropPdf(:,:) = 0._kind_phys + tropFound(:) = 0._kind_phys + tropDZ(:,:) = fillvalue + do i = 1, ncol + if (tropLev_cpp(i) /= NOTFOUND) then + tropPdf(i, tropLev_cpp(i)) = 1._kind_phys + tropFound(i) = 1._kind_phys + tropDZ(i,:) = zm(i,:) - tropZ_cpp(i) + end if + end do + + call history_out_field('TROPF_P', tropP_cpp) + call history_out_field('TROPF_T', tropT_cpp) + call history_out_field('TROPF_Z', tropZ_cpp) + call history_out_field('TROPF_DZ', tropDZ) + call history_out_field('TROPF_PD', tropPdf) + call history_out_field('TROPF_FD', tropFound) + + ! Climatology output + tropPdf(:,:) = 0._kind_phys + tropFound(:) = 0._kind_phys + tropDZ(:,:) = fillvalue + do i = 1, ncol + if (tropLev_clim(i) /= NOTFOUND) then + tropPdf(i, tropLev_clim(i)) = 1._kind_phys + tropFound(i) = 1._kind_phys + tropDZ(i,:) = zm(i,:) - tropZ_clim(i) + end if + end do + + call history_out_field('TROPC_P', tropP_clim) + call history_out_field('TROPC_T', tropT_clim) + call history_out_field('TROPC_Z', tropZ_clim) + call history_out_field('TROPC_DZ', tropDZ) + call history_out_field('TROPC_PD', tropPdf) + call history_out_field('TROPC_FD', tropFound) + + ! Hybridstobie outputs for chemistry + call history_out_field('hstobie_trop', hstobie_trop) + call history_out_field('hstobie_linoz', hstobie_linoz) + call history_out_field('hstobie_tropop', hstobie_tropop) return end subroutine tropopause_diagnostics_run From 470ad755d1707459da7b2853fa4b1c7106a828ce Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 19 Aug 2024 13:59:31 -0400 Subject: [PATCH 14/31] Add metadata to tropopause_diagnostics --- cam_diagnostics/tropopause_diagnostics.meta | 132 ++++++++++++++++++++ test/test_sdfs/suite_tropopause_find.xml | 1 + 2 files changed, 133 insertions(+) diff --git a/cam_diagnostics/tropopause_diagnostics.meta b/cam_diagnostics/tropopause_diagnostics.meta index 621501f1..8751fc2f 100644 --- a/cam_diagnostics/tropopause_diagnostics.meta +++ b/cam_diagnostics/tropopause_diagnostics.meta @@ -21,6 +21,138 @@ [ccpp-arg-table] name = tropopause_diagnostics_run type = scheme +[ ncol ] + standard_name = horizontal_loop_extent + units = count + type = integer + dimensions = () + intent = in +[ pver ] + standard_name = vertical_layer_dimension + units = count + type = integer + dimensions = () + intent = in +[ zm ] + standard_name = geopotential_height_wrt_surface + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = in +[ tropLev ] + standard_name = model_level_number_at_tropopause + units = 1 + type = integer + dimensions = (horizontal_loop_extent) + intent = out +[ tropP ] + standard_name = tropopause_air_pressure + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropT ] + standard_name = tropopause_air_temperature + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropZ ] + standard_name = tropopause_altitude + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropLev_clim ] + standard_name = model_level_number_at_tropopause_assuming_climatology + units = 1 + type = integer + dimensions = (horizontal_loop_extent) + intent = out +[ tropP_clim ] + standard_name = tropopause_air_pressure_assuming_climatology + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropT_clim ] + standard_name = tropopause_air_temperature_assuming_climatology + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropZ_clim ] + standard_name = tropopause_altitude_assuming_climatology + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropLev_hybstob ] + standard_name = model_level_number_at_tropopause_assuming_hybridstobie_and_climatology + units = 1 + type = integer + dimensions = (horizontal_loop_extent) + intent = out +[ tropP_hybstob ] + standard_name = tropopause_air_pressure_assuming_hybridstobie_and_climatology + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropT_hybstob ] + standard_name = tropopause_air_temperature_assuming_hybridstobie_and_climatology + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropZ_hybstob ] + standard_name = tropopause_altitude_assuming_hybridstobie_and_climatology + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropLev_cpp ] + standard_name = model_level_number_at_tropopause_assuming_cold_point + units = 1 + type = integer + dimensions = (horizontal_loop_extent) + intent = out +[ tropP_cpp ] + standard_name = tropopause_air_pressure_assuming_cold_point + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropT_cpp ] + standard_name = tropopause_air_temperature_assuming_cold_point + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropZ_cpp ] + standard_name = tropopause_altitude_assuming_cold_point + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ hstobie_trop ] + standard_name = lower_bound_of_model_level_number_for_stratospheric_chemistry + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ hstobie_linoz ] + standard_name = lower_bound_of_model_level_number_for_linoz_chemistry + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out +[ hstobie_tropop ] + standard_name = model_level_number_at_tropopause_for_chemistry + units = 1 + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent, vertical_layer_dimension) + intent = out [ errmsg ] standard_name = ccpp_error_message units = none diff --git a/test/test_sdfs/suite_tropopause_find.xml b/test/test_sdfs/suite_tropopause_find.xml index 13042cdc..c3696499 100644 --- a/test/test_sdfs/suite_tropopause_find.xml +++ b/test/test_sdfs/suite_tropopause_find.xml @@ -7,6 +7,7 @@ tropopause_find + tropopause_diagnostics qneg From b37c251af30a3f498c3efbae6d3e8c7e5cd855ea Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 20 Aug 2024 00:00:37 -0400 Subject: [PATCH 15/31] Fixes for building tropopause_diagnostics --- cam_diagnostics/tropopause_diagnostics.F90 | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/cam_diagnostics/tropopause_diagnostics.F90 b/cam_diagnostics/tropopause_diagnostics.F90 index e4a527a5..a0570fb7 100644 --- a/cam_diagnostics/tropopause_diagnostics.F90 +++ b/cam_diagnostics/tropopause_diagnostics.F90 @@ -1,8 +1,6 @@ module tropopause_diagnostics - ! ... output tropopause diagnostics - ! this will be moved to cam_diagnostics when History is available. (hplin, 8/14/24) - ! Currently stubbed out - use ccpp_kinds, only : kind_phys + ! ... output tropopause diagnostics within CAM-SIMA + use ccpp_kinds, only: kind_phys implicit none private @@ -11,6 +9,9 @@ module tropopause_diagnostics public :: tropopause_diagnostics_init public :: tropopause_diagnostics_run + ! Parameters consistent with tropopause_find - can they be imported? + integer, parameter :: NOTFOUND = -1 + contains ! Initialize the output history fields. !> \section arg_table_tropopause_diagnostics_init Argument Table @@ -69,7 +70,8 @@ subroutine tropopause_diagnostics_run(ncol, pver, & tropLev_cpp, tropP_cpp, tropT_cpp, tropZ_cpp, & ! Cold point only hstobie_trop, hstobie_linoz, hstobie_tropop, & ! Hybridstobie only for chemistry diagnostics errmsg, errflg) - use cam_history, only: history_out_field + use cam_history, only: history_out_field + use cam_history_support, only: fillvalue integer, intent(in) :: ncol ! Number of atmospheric columns integer, intent(in) :: pver ! Number of vertical levels @@ -104,20 +106,16 @@ subroutine tropopause_diagnostics_run(ncol, pver, & character(len=512), intent(out) :: errmsg integer, intent(out) :: errflg - errmsg = ' ' - errflg = 0 - ! Local Variables integer :: i integer :: alg - integer :: tropLev(ncol) ! tropopause level index - real(kind_phys) :: tropP(ncol) ! tropopause pressure (Pa) - real(kind_phys) :: tropT(ncol) ! tropopause temperature (K) - real(kind_phys) :: tropZ(ncol) ! tropopause height (m) real(kind_phys) :: tropFound(ncol) ! tropopause found real(kind_phys) :: tropDZ(ncol, pver) ! relative tropopause height (m) real(kind_phys) :: tropPdf(ncol, pver) ! tropopause probability distribution + errmsg = ' ' + errflg = 0 + ! Default algorithm output tropPdf(:,:) = 0._kind_phys tropFound(:) = 0._kind_phys From 177b6e503bbe7c985281b5fd95928a8d2e6f9d95 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 20 Aug 2024 18:08:34 -0400 Subject: [PATCH 16/31] Correctly support findChemTrop using the new CHEMTROP option --- tropopause_find/tropopause_find.F90 | 17 +++++++++++++++-- tropopause_find/tropopause_find.meta | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index e2f06826..a6973787 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -132,6 +132,7 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & tropLev_clim, tropP_clim, tropT_clim, tropZ_clim, & ! Climate-only tropLev_hybstob, tropP_hybstob, tropT_hybstob, tropZ_hybstob, & ! Hybridstobie + climate backup tropLev_cpp, tropP_cpp, tropT_cpp, tropZ_cpp, & ! Cold point only + tropLev_chem, tropP_chem, tropT_chem, tropZ_chem, & ! Chemical tropopause only hstobie_trop, hstobie_linoz, hstobie_tropop, & ! Hybridstobie only for chemistry diagnostics scheme_name, errmsg, errflg) @@ -172,6 +173,11 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), intent(out) :: tropT_cpp(:) ! cold point tropopause temperature (K) real(kind_phys), intent(out) :: tropZ_cpp(:) ! cold point tropopause height (m) + integer, intent(out) :: tropLev_chem(:) ! chemical tropopause level index + real(kind_phys), intent(out) :: tropP_chem(:) ! chemical tropopause pressure (Pa) + real(kind_phys), intent(out) :: tropT_chem(:) ! chemical tropopause temperature (K) + real(kind_phys), intent(out) :: tropZ_chem(:) ! chemical tropopause height (m) + ! Optional output arguments for hybridstobie with chemistry real(kind_phys), intent(out) :: hstobie_trop(:,:) ! Lowest level with strat. chem real(kind_phys), intent(out) :: hstobie_linoz(:,:) ! Lowest possible Linoz level @@ -215,6 +221,14 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & primary=TROP_ALG_HYBSTOB, backup=TROP_ALG_CLIMATE, & errmsg=errmsg, errflg=errflg) + ! Chemical tropopause (used for chemistry) + call tropopause_findWithBackup(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + calday, tropp_p_loc, tropp_days, & + tropLev_chem, tropP_chem, tropT_chem, tropZ_chem, & + hstobie_trop, hstobie_linoz, hstobie_tropop, & + primary=TROP_ALG_CHEMTROP, backup=TROP_ALG_CLIMATE, & + errmsg=errmsg, errflg=errflg) + end subroutine tropopause_find_run ! Searches all the columns in the chunk and attempts to identify the tropopause. @@ -1192,7 +1206,6 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, ! Local Variable real(kind_phys) :: dlats(ncol) integer :: i - integer :: backAlg errmsg = ' ' errflg = 0 @@ -1219,7 +1232,7 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, end do ! Now use the backup algorithm - if ((backAlg /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then + if (any(tropLev(:) == NOTFOUND)) then call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, & default_backup, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, & diff --git a/tropopause_find/tropopause_find.meta b/tropopause_find/tropopause_find.meta index f01d2a49..b2e47e62 100644 --- a/tropopause_find/tropopause_find.meta +++ b/tropopause_find/tropopause_find.meta @@ -213,6 +213,30 @@ type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out +[ tropLev_chem ] + standard_name = model_level_number_at_tropopause_assuming_chemical + units = 1 + type = integer + dimensions = (horizontal_loop_extent) + intent = out +[ tropP_chem ] + standard_name = tropopause_air_pressure_assuming_chemical + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropT_chem ] + standard_name = tropopause_air_temperature_assuming_chemical + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropZ_chem ] + standard_name = tropopause_altitude_assuming_chemical + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out [ hstobie_trop ] standard_name = lower_bound_of_model_level_number_for_stratospheric_chemistry units = 1 From 948d4da817b3ddf9bb7c42e8ecea0f5a509e2d07 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 20 Aug 2024 18:21:28 -0400 Subject: [PATCH 17/31] Fix tropp_days is fraction day-of-year --- tropopause_find/tropopause_find.F90 | 10 +++++----- tropopause_find/tropopause_find.meta | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index a6973787..2ce1b7e4 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -151,7 +151,7 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM real(kind_phys), intent(in) :: tropp_p_loc(:,:) - integer, intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 + real(kind_phys), intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 integer, intent(out) :: tropLev(:) ! tropopause level index real(kind_phys), intent(out) :: tropP(:) ! tropopause pressure (Pa) @@ -258,7 +258,7 @@ subroutine tropopause_findWithBackup(ncol, pver, lat, pint, pmid, t, zi, zm, phi ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM real(kind_phys), intent(in) :: tropp_p_loc(:,:) - integer, intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 + real(kind_phys), intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 integer, intent(out) :: tropLev(:) ! tropopause level index real(kind_phys), intent(out) :: tropP(:) ! tropopause pressure (Pa) @@ -333,7 +333,7 @@ subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM real(kind_phys), intent(in) :: tropp_p_loc(:,:) - integer, intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 + real(kind_phys), intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 integer, intent(in) :: algorithm ! detection algorithm integer, intent(inout) :: tropLev(:) ! tropopause level index @@ -477,7 +477,7 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM real(kind_phys), intent(in) :: tropp_p_loc(:,:) - integer, intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 + real(kind_phys), intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 integer, intent(inout) :: tropLev(:) ! tropopause level index real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) @@ -1193,7 +1193,7 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM real(kind_phys), intent(in) :: tropp_p_loc(:,:) - integer, intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 + real(kind_phys), intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 integer, intent(out) :: tropLev(:) ! tropopause level index real(kind_phys), intent(inout) :: tropP(:) ! tropopause pressure (Pa) diff --git a/tropopause_find/tropopause_find.meta b/tropopause_find/tropopause_find.meta index b2e47e62..9ee26e8e 100644 --- a/tropopause_find/tropopause_find.meta +++ b/tropopause_find/tropopause_find.meta @@ -114,7 +114,7 @@ [ tropp_days ] standard_name = tropopause_calendar_days_from_climatology units = 1 - type = integer + type = real | kind = kind_phys dimensions = (number_of_months_in_year) intent = in [ tropLev ] From 8498efc82afe5847519312aebcdcb896d63b76dc Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Thu, 22 Aug 2024 16:35:39 -0400 Subject: [PATCH 18/31] Update with metadata in preparation for pull request --- doc/ChangeLog | 41 +++++++ doc/NamesNotInDictionary.txt | 214 ++++++++++++++++++++++------------- 2 files changed, 177 insertions(+), 78 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 47d4b3ef..5ad154a9 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,44 @@ +=============================================================== + +Tag name: +Originator(s): jimmielin +Date: August 22, 2024 +One-line Summary: tropopause_find CCPP-ization +Github PR URL: + +This PR fixes the following NCAR/atmospheric_physics Github issues: + - Creates the CCPP interface for the tropopause_find routine + + Several (extensive) changes were made to tropopause_find.F90 for CCPP-compatibility: + - tropopause_read_file, which provides tropp_p_loc and tropp_days climatological data used as the default fall-back method, has been moved to a utility module in CAM-SIMA to read, regrid, and provide this climatology to the CCPP-ized physics; it also removes lchnk indexing since they're no longer used in CAM-SIMA. + - tropopause_find used to accept (optional) arguments for returning tropT, tropZ, tropP (tropopause temperature, height, and pressure) which are no longer optional; + - tropopause_find accepted "primary" and "backup" methods for finding the tropopause. All the methods known to be used in CAM are now calculated at the same time in the tropopause_find_run main driver routine; it calls the underlying logic as appropriate with and populates the appropriate standard name physics fields. Because the same physical quantities for tropopause level, height, pressure, temperature, etc. using different methods are used throughout the CAM physics and simultaneously output in the diagnostics, the same standard names with a suffix are used to differentiate between these quantities computed by different methods. + - Standard CCPP-ization procedures, metadata, explicit use of fields instead of physics state, only passing active :ncol fields, ... + + A "shim" that will completely replicate existing behavior, bit-for-bit in current CAM, will be included in current CAM as tropopause.F90. + +Code reviewed by: + +List all existing files that have been added (A), modified (M), or deleted (D), +and describe the changes: +- Implementation of tropopause_find using CCPP and test SDF: +A test/test_sdfs/suite_tropopause_find.xml +A tropopause_find/tropopause_find.F90 +A tropopause_find/tropopause_find.meta + +- Implementation of diagnostics (history) output within CAM-SIMA: +A cam_diagnostics/tropopause_diagnostics.F90 +A cam_diagnostics/tropopause_diagnostics.meta + +- Metadata for changes made in this PR: +M doc/ChangeLog +M doc/NamesNotInDictionary.txt + + +List and Describe any test failures: N/A + +Summarize any changes to answers: +Difference in =============================================================== diff --git a/doc/NamesNotInDictionary.txt b/doc/NamesNotInDictionary.txt index bcb6f51d..d6c18dcf 100644 --- a/doc/NamesNotInDictionary.txt +++ b/doc/NamesNotInDictionary.txt @@ -1,70 +1,66 @@ ####################### Date/time of when script was run: -2024-07-12 11:08:18.467654 +2024-08-22 16:28:19.167822 ####################### Non-dictionary standard names found in the following metadata files: -------------------------- -atmospheric_physics.jt.062024/utilities/geopotential_temp.meta +./atmospheric_physics/dry_adiabatic_adjust/dadadj.meta - air_pressure_at_interface - - ln_air_pressure_at_interface + - binary_indicator_for_dry_adiabatic_adjusted_grid_cell + - number_of_iterations_for_dry_adiabatic_adjustment_algorithm_convergence + - number_of_vertical_levels_from_model_top_where_dry_adiabatic_adjustment_occurs + - tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water -------------------------- -atmospheric_physics.jt.062024/zhang_mcfarlane/zm_conv_convtran.meta +./atmospheric_physics/dry_adiabatic_adjust/dadadj_apply_qv_tendency.meta - - atmosphere_detrainment_convective_mass_flux_for_deep_convection_for_convective_columns - - atmosphere_downdraft_convective_mass_flux_for_deep_convection_for_convective_columns - - atmosphere_downdraft_entrainment_convective_mass_flux_for_deep_convection_for_convective_columns - - atmosphere_updraft_convective_mass_flux_for_deep_convection_for_convective_columns - - atmosphere_updraft_entrainment_convective_mass_flux_for_deep_convection_for_convective_columns - - current_timestep_number - - flag_for_zhang_mcfarlane_deep_convective_transport? - - fraction_of_water_insoluble_convectively_transported_species - - horizontal_index_of_convective_columns_for_deep_convection_for_convective_columns - - maximum_number_of_grid_cells_with_deep_convection? - - minimum_number_of_grid_cells_with_deep_convection? - - pressure_thickness_for_deep_convection_for_convective_columns - - pressure_thickness_for_subcloud_layer_for_deep_convection_for_convective_columns - - pressure_thickness_of_dry_air_for_deep_convection_for_convective_columns? - - tendency_of_ccpp_constituents? - - vertical_index_at_top_of_deep_convection_for_convective_columns - - vertical_index_of_deep_conveciton_launch_level_for_convective_columns + - tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water -------------------------- -atmospheric_physics.jt.062024/zhang_mcfarlane/zm_conv_momtran.meta +./atmospheric_physics/tj2016/tj2016_precip.meta - - atmosphere_detrainment_convective_mass_flux_for_deep_convection_for_convective_columns - - atmosphere_downdraft_convective_mass_flux_for_deep_convection_for_convective_columns - - atmosphere_downdraft_entrainment_convective_mass_flux_for_deep_convection_for_convective_columns - - atmosphere_updraft_convective_mass_flux_for_deep_convection_for_convective_columns - - atmosphere_updraft_entrainment_convective_mass_flux_for_deep_convection_for_convective_columns - - current_timestep_number - - eastward_and_northward_winds_in_deep_convective_downdrafts? - - enter_name - - flag_for_zhang_mcfarlane_deep_momentum_transport? - - horizontal_index_of_convective_columns_for_deep_convection_for_convective_columns - - maximum_number_of_grid_cells_with_deep_convection? - - minimum_number_of_grid_cells_with_deep_convection? - - momentum_downward_transport_parameter_for_zhang_mcfarlane? - - momentum_upward_transport_parameter_for_zhang_mcfarlane? - - pressure_thickness_for_deep_convection_for_convective_columns - - pressure_thickness_for_subcloud_layer_for_deep_convection_for_convective_columns - - tendency_of_eastward_wind_due_to_zhang_mcfarlane_deep_convective_downdraft_pressure_gradient_term - - tendency_of_eastward_wind_due_to_zhang_mcfarlane_deep_convective_updraft_pressure_gradient_term - - tendency_of_northward_wind_due_to_zhang_mcfarlane_deep_convective_downdraft_pressure_gradient_term - - tendency_of_northward_wind_due_to_zhang_mcfarlane_deep_convective_updraft_pressure_gradient_term - - vertical_index_at_top_of_deep_convection_for_convective_columns - - vertical_index_of_deep_conveciton_launch_level_for_convective_columns + - gas_constant_of_water_vapor + - lwe_large_scale_precipitation_rate_at_surface + - ratio_of_water_vapor_to_dry_air_molecular_weights + - sum_of_sigma_pressure_hybrid_coordinate_a_coefficient_and_sigma_pressure_hybrid_coordinate_b_coefficient + +-------------------------- + +./atmospheric_physics/tj2016/tj2016_sfc_pbl_hs.meta + + - air_pressure_at_interface + - eddy_heat_diffusivity + - eddy_momentum_diffusivity + - gas_constant_of_water_vapor + - ln_air_pressure_at_interface + - pi_constant + - ratio_of_water_vapor_to_dry_air_molecular_weights + - sum_of_sigma_pressure_hybrid_coordinate_a_coefficient_and_sigma_pressure_hybrid_coordinate_b_coefficient + - surface_eastward_wind_stress + - surface_evaporation_rate + - surface_northward_wind_stress + - surface_upward_sensible_heat_flux + - tendency_of_air_temperature_due_to_diabatic_heating + - tendency_of_air_temperature_due_to_vertical_diffusion + - tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water_due_to_vertical_diffusion -------------------------- -atmospheric_physics.jt.062024/zhang_mcfarlane/zm_conv_evap.meta +./atmospheric_physics/utilities/geopotential_temp.meta + + - air_pressure_at_interface + - ln_air_pressure_at_interface + +-------------------------- + +./atmospheric_physics/zhang_mcfarlane/zm_conv_evap.meta - - cloud_area_fraction @@ -90,7 +86,34 @@ atmospheric_physics.jt.062024/zhang_mcfarlane/zm_conv_evap.meta -------------------------- -atmospheric_physics.jt.062024/zhang_mcfarlane/zm_convr.meta +./atmospheric_physics/zhang_mcfarlane/zm_conv_momtran.meta + + - atmosphere_detrainment_convective_mass_flux_for_deep_convection_for_convective_columns + - atmosphere_downdraft_convective_mass_flux_for_deep_convection_for_convective_columns + - atmosphere_downdraft_entrainment_convective_mass_flux_for_deep_convection_for_convective_columns + - atmosphere_updraft_convective_mass_flux_for_deep_convection_for_convective_columns + - atmosphere_updraft_entrainment_convective_mass_flux_for_deep_convection_for_convective_columns + - current_timestep_number + - eastward_and_northward_winds_in_deep_convective_downdrafts? + - enter_name + - flag_for_zhang_mcfarlane_deep_momentum_transport? + - horizontal_index_of_convective_columns_for_deep_convection_for_convective_columns + - maximum_number_of_grid_cells_with_deep_convection? + - minimum_number_of_grid_cells_with_deep_convection? + - momentum_downward_transport_parameter_for_zhang_mcfarlane? + - momentum_upward_transport_parameter_for_zhang_mcfarlane? + - pressure_thickness_for_deep_convection_for_convective_columns + - pressure_thickness_for_subcloud_layer_for_deep_convection_for_convective_columns + - tendency_of_eastward_wind_due_to_zhang_mcfarlane_deep_convective_downdraft_pressure_gradient_term + - tendency_of_eastward_wind_due_to_zhang_mcfarlane_deep_convective_updraft_pressure_gradient_term + - tendency_of_northward_wind_due_to_zhang_mcfarlane_deep_convective_downdraft_pressure_gradient_term + - tendency_of_northward_wind_due_to_zhang_mcfarlane_deep_convective_updraft_pressure_gradient_term + - vertical_index_at_top_of_deep_convection_for_convective_columns + - vertical_index_of_deep_conveciton_launch_level_for_convective_columns + +-------------------------- + +./atmospheric_physics/zhang_mcfarlane/zm_convr.meta - air_pressure_at_interface - atmosphere_convective_mass_flux_due_to all_convection? @@ -146,47 +169,82 @@ atmospheric_physics.jt.062024/zhang_mcfarlane/zm_convr.meta -------------------------- -atmospheric_physics.jt.062024/dry_adiabatic_adjust/dadadj.meta - - - air_pressure_at_interface - - binary_indicator_for_dry_adiabatic_adjusted_grid_cell - - number_of_iterations_for_dry_adiabatic_adjustment_algorithm_convergence - - number_of_vertical_levels_from_model_top_where_dry_adiabatic_adjustment_occurs - - tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water - --------------------------- - -atmospheric_physics.jt.062024/dry_adiabatic_adjust/dadadj_apply_qv_tendency.meta +./atmospheric_physics/zhang_mcfarlane/zm_conv_convtran.meta - - tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water + - atmosphere_detrainment_convective_mass_flux_for_deep_convection_for_convective_columns + - atmosphere_downdraft_convective_mass_flux_for_deep_convection_for_convective_columns + - atmosphere_downdraft_entrainment_convective_mass_flux_for_deep_convection_for_convective_columns + - atmosphere_updraft_convective_mass_flux_for_deep_convection_for_convective_columns + - atmosphere_updraft_entrainment_convective_mass_flux_for_deep_convection_for_convective_columns + - current_timestep_number + - flag_for_zhang_mcfarlane_deep_convective_transport? + - fraction_of_water_insoluble_convectively_transported_species + - horizontal_index_of_convective_columns_for_deep_convection_for_convective_columns + - maximum_number_of_grid_cells_with_deep_convection? + - minimum_number_of_grid_cells_with_deep_convection? + - pressure_thickness_for_deep_convection_for_convective_columns + - pressure_thickness_for_subcloud_layer_for_deep_convection_for_convective_columns + - pressure_thickness_of_dry_air_for_deep_convection_for_convective_columns? + - tendency_of_ccpp_constituents? + - vertical_index_at_top_of_deep_convection_for_convective_columns + - vertical_index_of_deep_conveciton_launch_level_for_convective_columns -------------------------- -atmospheric_physics.jt.062024/tj2016/tj2016_precip.meta - - - gas_constant_of_water_vapor - - lwe_large_scale_precipitation_rate_at_surface - - ratio_of_water_vapor_to_dry_air_molecular_weights - - sum_of_sigma_pressure_hybrid_coordinate_a_coefficient_and_sigma_pressure_hybrid_coordinate_b_coefficient +./atmospheric_physics/cam_diagnostics/tropopause_diagnostics.meta + + - lower_bound_of_model_level_number_for_linoz_chemistry + - lower_bound_of_model_level_number_for_stratospheric_chemistry + - model_level_number_at_tropopause + - model_level_number_at_tropopause_assuming_climatology + - model_level_number_at_tropopause_assuming_cold_point + - model_level_number_at_tropopause_assuming_hybridstobie_and_climatology + - model_level_number_at_tropopause_for_chemistry + - tropopause_air_pressure + - tropopause_air_pressure_assuming_climatology + - tropopause_air_pressure_assuming_cold_point + - tropopause_air_pressure_assuming_hybridstobie_and_climatology + - tropopause_air_temperature + - tropopause_air_temperature_assuming_climatology + - tropopause_air_temperature_assuming_cold_point + - tropopause_air_temperature_assuming_hybridstobie_and_climatology + - tropopause_altitude + - tropopause_altitude_assuming_climatology + - tropopause_altitude_assuming_cold_point + - tropopause_altitude_assuming_hybridstobie_and_climatology -------------------------- -atmospheric_physics.jt.062024/tj2016/tj2016_sfc_pbl_hs.meta +./atmospheric_physics/tropopause_find/tropopause_find.meta - air_pressure_at_interface - - eddy_heat_diffusivity - - eddy_momentum_diffusivity - - gas_constant_of_water_vapor - - ln_air_pressure_at_interface + - fractional_calendar_days_on_end_of_current_timestep + - lower_bound_of_model_level_number_for_linoz_chemistry + - lower_bound_of_model_level_number_for_stratospheric_chemistry + - model_level_number_at_tropopause + - model_level_number_at_tropopause_assuming_chemical + - model_level_number_at_tropopause_assuming_climatology + - model_level_number_at_tropopause_assuming_cold_point + - model_level_number_at_tropopause_assuming_hybridstobie_and_climatology + - model_level_number_at_tropopause_for_chemistry - pi_constant - - ratio_of_water_vapor_to_dry_air_molecular_weights - - sum_of_sigma_pressure_hybrid_coordinate_a_coefficient_and_sigma_pressure_hybrid_coordinate_b_coefficient - - surface_eastward_wind_stress - - surface_evaporation_rate - - surface_northward_wind_stress - - surface_upward_sensible_heat_flux - - tendency_of_air_temperature_due_to_diabatic_heating - - tendency_of_air_temperature_due_to_vertical_diffusion - - tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water_due_to_vertical_diffusion + - ratio_of_dry_air_gas_constant_to_specific_heat_of_dry_air_at_constant_pressure + - tropopause_air_pressure + - tropopause_air_pressure_assuming_chemical + - tropopause_air_pressure_assuming_climatology + - tropopause_air_pressure_assuming_cold_point + - tropopause_air_pressure_assuming_hybridstobie_and_climatology + - tropopause_air_pressure_from_climatology + - tropopause_air_temperature + - tropopause_air_temperature_assuming_chemical + - tropopause_air_temperature_assuming_climatology + - tropopause_air_temperature_assuming_cold_point + - tropopause_air_temperature_assuming_hybridstobie_and_climatology + - tropopause_altitude + - tropopause_altitude_assuming_chemical + - tropopause_altitude_assuming_climatology + - tropopause_altitude_assuming_cold_point + - tropopause_altitude_assuming_hybridstobie_and_climatology + - tropopause_calendar_days_from_climatology ####################### From 56415e872effc3b9ea7829ed8808401db287669f Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Fri, 23 Aug 2024 02:07:31 -0400 Subject: [PATCH 19/31] Add TROPP (primary only) output; fix intents in tropopause_diagnostics; clarify arguments in driver routine --- cam_diagnostics/tropopause_diagnostics.F90 | 65 +++++--- cam_diagnostics/tropopause_diagnostics.meta | 62 ++++--- doc/NamesNotInDictionary.txt | 6 +- tropopause_find/tropopause_find.F90 | 172 ++++++++++++++++---- tropopause_find/tropopause_find.meta | 24 +++ 5 files changed, 261 insertions(+), 68 deletions(-) diff --git a/cam_diagnostics/tropopause_diagnostics.F90 b/cam_diagnostics/tropopause_diagnostics.F90 index a0570fb7..c6ad00f7 100644 --- a/cam_diagnostics/tropopause_diagnostics.F90 +++ b/cam_diagnostics/tropopause_diagnostics.F90 @@ -64,7 +64,8 @@ end subroutine tropopause_diagnostics_init !! \htmlinclude tropopause_diagnostics_run.html subroutine tropopause_diagnostics_run(ncol, pver, & zm, & - tropLev, tropP, tropT, tropZ, & ! Default primary+backup ( twmo+climate) + tropLev, tropP, tropT, tropZ, & ! Default primary+backup (twmo+climate) + tropLev_twmo, tropP_twmo, tropT_twmo, tropZ_twmo, & ! Primary only (twmo) tropLev_clim, tropP_clim, tropT_clim, tropZ_clim, & ! Climate-only tropLev_hybstob, tropP_hybstob, tropT_hybstob, tropZ_hybstob, & ! Hybridstobie + climate backup tropLev_cpp, tropP_cpp, tropT_cpp, tropZ_cpp, & ! Cold point only @@ -78,30 +79,35 @@ subroutine tropopause_diagnostics_run(ncol, pver, & real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver - integer, intent(out) :: tropLev(:) ! tropopause level index - real(kind_phys), intent(out) :: tropP(:) ! tropopause pressure (Pa) - real(kind_phys), intent(out) :: tropT(:) ! tropopause temperature (K) - real(kind_phys), intent(out) :: tropZ(:) ! tropopause height (m) + integer, intent(in) :: tropLev(:) ! tropopause level index + real(kind_phys), intent(in) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), intent(in) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), intent(in) :: tropZ(:) ! tropopause height (m) - integer, intent(out) :: tropLev_clim(:) ! climatology-backed tropopause level index - real(kind_phys), intent(out) :: tropP_clim(:) ! climatology-backed tropopause pressure (Pa) - real(kind_phys), intent(out) :: tropT_clim(:) ! climatology-backed tropopause temperature (K) - real(kind_phys), intent(out) :: tropZ_clim(:) ! climatology-backed tropopause height (m) + integer, intent(in) :: tropLev_twmo(:) ! lapse-rate tropopause level index + real(kind_phys), intent(in) :: tropP_twmo(:) ! lapse-rate tropopause pressure (Pa) + real(kind_phys), intent(in) :: tropT_twmo(:) ! lapse-rate tropopause temperature (K) + real(kind_phys), intent(in) :: tropZ_twmo(:) ! lapse-rate tropopause height (m) - integer, intent(out) :: tropLev_hybstob(:) ! hybridstobie climatology-backed tropopause level index - real(kind_phys), intent(out) :: tropP_hybstob(:) ! hybridstobie climatology-backed tropopause pressure (Pa) - real(kind_phys), intent(out) :: tropT_hybstob(:) ! hybridstobie climatology-backed tropopause temperature (K) - real(kind_phys), intent(out) :: tropZ_hybstob(:) ! hybridstobie climatology-backed tropopause height (m) + integer, intent(in) :: tropLev_clim(:) ! climatology-backed tropopause level index + real(kind_phys), intent(in) :: tropP_clim(:) ! climatology-backed tropopause pressure (Pa) + real(kind_phys), intent(in) :: tropT_clim(:) ! climatology-backed tropopause temperature (K) + real(kind_phys), intent(in) :: tropZ_clim(:) ! climatology-backed tropopause height (m) - integer, intent(out) :: tropLev_cpp(:) ! cold point tropopause level index - real(kind_phys), intent(out) :: tropP_cpp(:) ! cold point tropopause pressure (Pa) - real(kind_phys), intent(out) :: tropT_cpp(:) ! cold point tropopause temperature (K) - real(kind_phys), intent(out) :: tropZ_cpp(:) ! cold point tropopause height (m) + integer, intent(in) :: tropLev_hybstob(:) ! hybridstobie climatology-backed tropopause level index + real(kind_phys), intent(in) :: tropP_hybstob(:) ! hybridstobie climatology-backed tropopause pressure (Pa) + real(kind_phys), intent(in) :: tropT_hybstob(:) ! hybridstobie climatology-backed tropopause temperature (K) + real(kind_phys), intent(in) :: tropZ_hybstob(:) ! hybridstobie climatology-backed tropopause height (m) + + integer, intent(in) :: tropLev_cpp(:) ! cold point tropopause level index + real(kind_phys), intent(in) :: tropP_cpp(:) ! cold point tropopause pressure (Pa) + real(kind_phys), intent(in) :: tropT_cpp(:) ! cold point tropopause temperature (K) + real(kind_phys), intent(in) :: tropZ_cpp(:) ! cold point tropopause height (m) ! Optional output arguments for hybridstobie with chemistry - real(kind_phys), intent(out) :: hstobie_trop(:,:) ! Lowest level with strat. chem - real(kind_phys), intent(out) :: hstobie_linoz(:,:) ! Lowest possible Linoz level - real(kind_phys), intent(out) :: hstobie_tropop(:,:) ! Troposphere boundary calculated in chem. + real(kind_phys), intent(in) :: hstobie_trop(:,:) ! Lowest level with strat. chem + real(kind_phys), intent(in) :: hstobie_linoz(:,:) ! Lowest possible Linoz level + real(kind_phys), intent(in) :: hstobie_tropop(:,:) ! Troposphere boundary calculated in chem. character(len=512), intent(out) :: errmsg integer, intent(out) :: errflg @@ -135,6 +141,25 @@ subroutine tropopause_diagnostics_run(ncol, pver, & call history_out_field('TROP_PD', tropPdf) call history_out_field('TROP_FD', tropFound) + ! Primary-only (currently TWMO) algorithm output + tropPdf(:,:) = 0._kind_phys + tropFound(:) = 0._kind_phys + tropDZ(:,:) = fillvalue + do i = 1, ncol + if (tropLev_twmo(i) /= NOTFOUND) then + tropPdf(i, tropLev_twmo(i)) = 1._kind_phys + tropFound(i) = 1._kind_phys + tropDZ(i,:) = zm(i,:) - tropZ(i) + end if + end do + + call history_out_field('TROPP_P', tropP_twmo) + call history_out_field('TROPP_T', tropT_twmo) + call history_out_field('TROPP_Z', tropZ_twmo) + call history_out_field('TROPP_DZ', tropDZ) + call history_out_field('TROPP_PD', tropPdf) + call history_out_field('TROPP_FD', tropFound) + ! Cold point output tropPdf(:,:) = 0._kind_phys tropFound(:) = 0._kind_phys diff --git a/cam_diagnostics/tropopause_diagnostics.meta b/cam_diagnostics/tropopause_diagnostics.meta index 8751fc2f..a400f51c 100644 --- a/cam_diagnostics/tropopause_diagnostics.meta +++ b/cam_diagnostics/tropopause_diagnostics.meta @@ -44,115 +44,139 @@ units = 1 type = integer dimensions = (horizontal_loop_extent) - intent = out + intent = in [ tropP ] standard_name = tropopause_air_pressure units = Pa type = real | kind = kind_phys dimensions = (horizontal_loop_extent) - intent = out + intent = in [ tropT ] standard_name = tropopause_air_temperature units = K type = real | kind = kind_phys dimensions = (horizontal_loop_extent) - intent = out + intent = in [ tropZ ] standard_name = tropopause_altitude units = m type = real | kind = kind_phys dimensions = (horizontal_loop_extent) - intent = out + intent = in +[ tropLev_twmo ] + standard_name = model_level_number_at_tropopause_assuming_lapse_rate + units = 1 + type = integer + dimensions = (horizontal_loop_extent) + intent = in +[ tropP_twmo ] + standard_name = tropopause_air_pressure_assuming_lapse_rate + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ tropT_twmo ] + standard_name = tropopause_air_temperature_assuming_lapse_rate + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in +[ tropZ_twmo ] + standard_name = tropopause_altitude_assuming_lapse_rate + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = in [ tropLev_clim ] standard_name = model_level_number_at_tropopause_assuming_climatology units = 1 type = integer dimensions = (horizontal_loop_extent) - intent = out + intent = in [ tropP_clim ] standard_name = tropopause_air_pressure_assuming_climatology units = Pa type = real | kind = kind_phys dimensions = (horizontal_loop_extent) - intent = out + intent = in [ tropT_clim ] standard_name = tropopause_air_temperature_assuming_climatology units = K type = real | kind = kind_phys dimensions = (horizontal_loop_extent) - intent = out + intent = in [ tropZ_clim ] standard_name = tropopause_altitude_assuming_climatology units = m type = real | kind = kind_phys dimensions = (horizontal_loop_extent) - intent = out + intent = in [ tropLev_hybstob ] standard_name = model_level_number_at_tropopause_assuming_hybridstobie_and_climatology units = 1 type = integer dimensions = (horizontal_loop_extent) - intent = out + intent = in [ tropP_hybstob ] standard_name = tropopause_air_pressure_assuming_hybridstobie_and_climatology units = Pa type = real | kind = kind_phys dimensions = (horizontal_loop_extent) - intent = out + intent = in [ tropT_hybstob ] standard_name = tropopause_air_temperature_assuming_hybridstobie_and_climatology units = K type = real | kind = kind_phys dimensions = (horizontal_loop_extent) - intent = out + intent = in [ tropZ_hybstob ] standard_name = tropopause_altitude_assuming_hybridstobie_and_climatology units = m type = real | kind = kind_phys dimensions = (horizontal_loop_extent) - intent = out + intent = in [ tropLev_cpp ] standard_name = model_level_number_at_tropopause_assuming_cold_point units = 1 type = integer dimensions = (horizontal_loop_extent) - intent = out + intent = in [ tropP_cpp ] standard_name = tropopause_air_pressure_assuming_cold_point units = Pa type = real | kind = kind_phys dimensions = (horizontal_loop_extent) - intent = out + intent = in [ tropT_cpp ] standard_name = tropopause_air_temperature_assuming_cold_point units = K type = real | kind = kind_phys dimensions = (horizontal_loop_extent) - intent = out + intent = in [ tropZ_cpp ] standard_name = tropopause_altitude_assuming_cold_point units = m type = real | kind = kind_phys dimensions = (horizontal_loop_extent) - intent = out + intent = in [ hstobie_trop ] standard_name = lower_bound_of_model_level_number_for_stratospheric_chemistry units = 1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) - intent = out + intent = in [ hstobie_linoz ] standard_name = lower_bound_of_model_level_number_for_linoz_chemistry units = 1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) - intent = out + intent = in [ hstobie_tropop ] standard_name = model_level_number_at_tropopause_for_chemistry units = 1 type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) - intent = out + intent = in [ errmsg ] standard_name = ccpp_error_message units = none diff --git a/doc/NamesNotInDictionary.txt b/doc/NamesNotInDictionary.txt index d6c18dcf..eb75e631 100644 --- a/doc/NamesNotInDictionary.txt +++ b/doc/NamesNotInDictionary.txt @@ -1,7 +1,7 @@ ####################### Date/time of when script was run: -2024-08-22 16:28:19.167822 +2024-08-23 02:03:20.542270 ####################### Non-dictionary standard names found in the following metadata files: @@ -226,6 +226,7 @@ Non-dictionary standard names found in the following metadata files: - model_level_number_at_tropopause_assuming_climatology - model_level_number_at_tropopause_assuming_cold_point - model_level_number_at_tropopause_assuming_hybridstobie_and_climatology + - model_level_number_at_tropopause_assuming_lapse_rate - model_level_number_at_tropopause_for_chemistry - pi_constant - ratio_of_dry_air_gas_constant_to_specific_heat_of_dry_air_at_constant_pressure @@ -234,17 +235,20 @@ Non-dictionary standard names found in the following metadata files: - tropopause_air_pressure_assuming_climatology - tropopause_air_pressure_assuming_cold_point - tropopause_air_pressure_assuming_hybridstobie_and_climatology + - tropopause_air_pressure_assuming_lapse_rate - tropopause_air_pressure_from_climatology - tropopause_air_temperature - tropopause_air_temperature_assuming_chemical - tropopause_air_temperature_assuming_climatology - tropopause_air_temperature_assuming_cold_point - tropopause_air_temperature_assuming_hybridstobie_and_climatology + - tropopause_air_temperature_assuming_lapse_rate - tropopause_altitude - tropopause_altitude_assuming_chemical - tropopause_altitude_assuming_climatology - tropopause_altitude_assuming_cold_point - tropopause_altitude_assuming_hybridstobie_and_climatology + - tropopause_altitude_assuming_lapse_rate - tropopause_calendar_days_from_climatology ####################### diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index 2ce1b7e4..3a7189f7 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -128,7 +128,8 @@ end subroutine tropopause_find_init !! \htmlinclude tropopause_find_run.html subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, & - tropLev, tropP, tropT, tropZ, & ! Default primary+backup ( twmo+climate) + tropLev, tropP, tropT, tropZ, & ! Default primary+backup (twmo+climate) + tropLev_twmo, tropP_twmo, tropT_twmo, tropZ_twmo, & ! Primary only (twmo) tropLev_clim, tropP_clim, tropT_clim, tropZ_clim, & ! Climate-only tropLev_hybstob, tropP_hybstob, tropT_hybstob, tropZ_hybstob, & ! Hybridstobie + climate backup tropLev_cpp, tropP_cpp, tropT_cpp, tropZ_cpp, & ! Cold point only @@ -158,6 +159,11 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), intent(out) :: tropT(:) ! tropopause temperature (K) real(kind_phys), intent(out) :: tropZ(:) ! tropopause height (m) + integer, intent(out) :: tropLev_twmo(:) ! lapse-rate tropopause level index + real(kind_phys), intent(out) :: tropP_twmo(:) ! lapse-rate tropopause pressure (Pa) + real(kind_phys), intent(out) :: tropT_twmo(:) ! lapse-rate tropopause temperature (K) + real(kind_phys), intent(out) :: tropZ_twmo(:) ! lapse-rate tropopause height (m) + integer, intent(out) :: tropLev_clim(:) ! climatology-backed tropopause level index real(kind_phys), intent(out) :: tropP_clim(:) ! climatology-backed tropopause pressure (Pa) real(kind_phys), intent(out) :: tropT_clim(:) ! climatology-backed tropopause temperature (K) @@ -192,42 +198,152 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & errflg = 0 ! Obtain the primary output, which is TWMO + climate - call tropopause_findWithBackup(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - calday, tropp_p_loc, tropp_days, & - tropLev, tropP, tropT, tropZ, & - primary=default_primary, backup=default_backup, & - errmsg=errmsg, errflg=errflg) + call tropopause_findWithBackup( & + ncol = ncol, & + pver = pver, & + lat = lat, & + pint = pint, & + pmid = pmid, & + t = t, & + zi = zi, & + zm = zm, & + phis = phis, & + calday = calday, & + tropp_p_loc = tropp_p_loc, & + tropp_days = tropp_days, & + tropLev = tropLev, & + tropP = tropP, & + tropT = tropT, & + tropZ = tropZ, & + primary = default_primary, & + backup = default_backup, & + errmsg = errmsg, & + errflg = errflg & + ) ! Any other intended outputs + ! Primary (TWMO) only + call tropopause_findWithBackup( & + ncol = ncol, & + pver = pver, & + lat = lat, & + pint = pint, & + pmid = pmid, & + t = t, & + zi = zi, & + zm = zm, & + phis = phis, & + calday = calday, & + tropp_p_loc = tropp_p_loc, & + tropp_days = tropp_days, & + tropLev = tropLev_twmo, & + tropP = tropP_twmo, & + tropT = tropT_twmo, & + tropZ = tropZ_twmo, & + primary = default_primary, & + backup = TROP_ALG_NONE, & + errmsg = errmsg, & + errflg = errflg & + ) + ! Climatology only - call tropopause_findWithBackup(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - calday, tropp_p_loc, tropp_days, & - tropLev_clim, tropP_clim, tropT_clim, tropZ_clim, & - primary=TROP_ALG_CLIMATE, backup=TROP_ALG_NONE, & - errmsg=errmsg, errflg=errflg) + call tropopause_findWithBackup( & + ncol = ncol, & + pver = pver, & + lat = lat, & + pint = pint, & + pmid = pmid, & + t = t, & + zi = zi, & + zm = zm, & + phis = phis, & + calday = calday, & + tropp_p_loc = tropp_p_loc, & + tropp_days = tropp_days, & + tropLev = tropLev_clim, & + tropP = tropP_clim, & + tropT = tropT_clim, & + tropZ = tropZ_clim, & + primary = TROP_ALG_CLIMATE, & + backup = TROP_ALG_NONE, & + errmsg = errmsg, & + errflg = errflg & + ) ! Cold point (CPP) only - call tropopause_findWithBackup(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - calday, tropp_p_loc, tropp_days, & - tropLev_cpp, tropP_cpp, tropT_cpp, tropZ_cpp, & - primary=TROP_ALG_CPP, backup=TROP_ALG_NONE, & - errmsg=errmsg, errflg=errflg) + call tropopause_findWithBackup( & + ncol = ncol, & + pver = pver, & + lat = lat, & + pint = pint, & + pmid = pmid, & + t = t, & + zi = zi, & + zm = zm, & + phis = phis, & + calday = calday, & + tropp_p_loc = tropp_p_loc, & + tropp_days = tropp_days, & + tropLev = tropLev_cpp, & + tropP = tropP_cpp, & + tropT = tropT_cpp, & + tropZ = tropZ_cpp, & + primary = TROP_ALG_CPP, & + backup = TROP_ALG_NONE, & + errmsg = errmsg, & + errflg = errflg & + ) ! Hybridstobie with climatology-backed - call tropopause_findWithBackup(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - calday, tropp_p_loc, tropp_days, & - tropLev_hybstob, tropP_hybstob, tropT_hybstob, tropZ_hybstob, & - hstobie_trop, hstobie_linoz, hstobie_tropop, & - primary=TROP_ALG_HYBSTOB, backup=TROP_ALG_CLIMATE, & - errmsg=errmsg, errflg=errflg) + call tropopause_findWithBackup( & + ncol = ncol, & + pver = pver, & + lat = lat, & + pint = pint, & + pmid = pmid, & + t = t, & + zi = zi, & + zm = zm, & + phis = phis, & + calday = calday, & + tropp_p_loc = tropp_p_loc, & + tropp_days = tropp_days, & + tropLev = tropLev_hybstob, & + tropP = tropP_hybstob, & + tropT = tropT_hybstob, & + tropZ = tropZ_hybstob, & + primary = TROP_ALG_HYBSTOB, & + backup = TROP_ALG_CLIMATE, & + hstobie_trop = hstobie_trop, & ! Only used if TROP_ALG_HYBSTOB + hstobie_linoz = hstobie_linoz, & ! Only used if TROP_ALG_HYBSTOB + hstobie_tropop = hstobie_tropop, & ! Only used if TROP_ALG_HYBSTOB + errmsg = errmsg, & + errflg = errflg & + ) ! Chemical tropopause (used for chemistry) - call tropopause_findWithBackup(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - calday, tropp_p_loc, tropp_days, & - tropLev_chem, tropP_chem, tropT_chem, tropZ_chem, & - hstobie_trop, hstobie_linoz, hstobie_tropop, & - primary=TROP_ALG_CHEMTROP, backup=TROP_ALG_CLIMATE, & - errmsg=errmsg, errflg=errflg) + call tropopause_findWithBackup( & + ncol = ncol, & + pver = pver, & + lat = lat, & + pint = pint, & + pmid = pmid, & + t = t, & + zi = zi, & + zm = zm, & + phis = phis, & + calday = calday, & + tropp_p_loc = tropp_p_loc, & + tropp_days = tropp_days, & + tropLev = tropLev_chem, & + tropP = tropP_chem, & + tropT = tropT_chem, & + tropZ = tropZ_chem, & + primary = TROP_ALG_CHEMTROP, & + backup = TROP_ALG_CLIMATE, & + errmsg = errmsg, & + errflg = errflg & + ) end subroutine tropopause_find_run diff --git a/tropopause_find/tropopause_find.meta b/tropopause_find/tropopause_find.meta index 9ee26e8e..09342c86 100644 --- a/tropopause_find/tropopause_find.meta +++ b/tropopause_find/tropopause_find.meta @@ -141,6 +141,30 @@ type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out +[ tropLev_twmo ] + standard_name = model_level_number_at_tropopause_assuming_lapse_rate + units = 1 + type = integer + dimensions = (horizontal_loop_extent) + intent = out +[ tropP_twmo ] + standard_name = tropopause_air_pressure_assuming_lapse_rate + units = Pa + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropT_twmo ] + standard_name = tropopause_air_temperature_assuming_lapse_rate + units = K + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out +[ tropZ_twmo ] + standard_name = tropopause_altitude_assuming_lapse_rate + units = m + type = real | kind = kind_phys + dimensions = (horizontal_loop_extent) + intent = out [ tropLev_clim ] standard_name = model_level_number_at_tropopause_assuming_climatology units = 1 From f3838c40285348ae11f965987c4dd6491f6f52d2 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Fri, 23 Aug 2024 10:44:29 -0400 Subject: [PATCH 20/31] Add TROPP (primary only) history field definition --- cam_diagnostics/tropopause_diagnostics.F90 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cam_diagnostics/tropopause_diagnostics.F90 b/cam_diagnostics/tropopause_diagnostics.F90 index c6ad00f7..5c750e6c 100644 --- a/cam_diagnostics/tropopause_diagnostics.F90 +++ b/cam_diagnostics/tropopause_diagnostics.F90 @@ -35,6 +35,13 @@ subroutine tropopause_diagnostics_init(errmsg, errflg) call history_add_field('TROP_PD', 'probability_distribution_of_model_level_number_at_tropopause', 'lev', 'avg', 'probability') call history_add_field('TROP_FD', 'tropopause_found', horiz_only, 'avg', 'probability') + call history_add_field('TROPP_P', 'tropopause_air_pressure_assuming_lapse_rate', horiz_only, 'avg', 'Pa') + call history_add_field('TROPP_T', 'tropopause_air_temperature_assuming_lapse_rate', horiz_only, 'avg', 'K' ) + call history_add_field('TROPP_Z', 'tropopause_altitude_assuming_lapse_rate', horiz_only, 'avg', 'm' ) + call history_add_field('TROPP_DZ', 'tropopause_altitude_relative_assuming_lapse_rate', 'lev', 'avg', 'm') + call history_add_field('TROPP_PD', 'probability_distribution_of_model_level_number_at_tropopause_assuming_lapse_rate', 'lev', 'avg', 'probability') + call history_add_field('TROPP_FD', 'tropopause_found_assuming_lapse_rate', horiz_only, 'avg', 'probability') + call history_add_field('TROPF_P', 'tropopause_air_pressure_assuming_cold_point', horiz_only, 'avg', 'Pa') call history_add_field('TROPF_T', 'tropopause_air_temperature_assuming_cold_point', horiz_only, 'avg', 'K' ) call history_add_field('TROPF_Z', 'tropopause_altitude_assuming_cold_point', horiz_only, 'avg', 'm' ) From 2b1d98ef54403e41310f9f49d82f4ef04d8bbe24 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Fri, 23 Aug 2024 11:07:39 -0400 Subject: [PATCH 21/31] Remove geopotential_temp from test SDF for tropopause_find --- test/test_sdfs/suite_tropopause_find.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_sdfs/suite_tropopause_find.xml b/test/test_sdfs/suite_tropopause_find.xml index c3696499..98faf1d6 100644 --- a/test/test_sdfs/suite_tropopause_find.xml +++ b/test/test_sdfs/suite_tropopause_find.xml @@ -3,7 +3,6 @@ - geopotential_temp tropopause_find From 4ea57ffbadf97abf6ca91129b33d244e0396cf9a Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 3 Sep 2024 12:22:47 -0400 Subject: [PATCH 22/31] First batch of updates for review comments, including standard name updates and revised code comments, cleanup --- cam_diagnostics/tropopause_diagnostics.F90 | 57 +++++---- cam_diagnostics/tropopause_diagnostics.meta | 58 ++++----- doc/ChangeLog | 5 +- suite_cam7.xml | 7 ++ tropopause_find/tropopause_find.F90 | 126 ++++++++------------ tropopause_find/tropopause_find.meta | 68 +++++------ 6 files changed, 154 insertions(+), 167 deletions(-) diff --git a/cam_diagnostics/tropopause_diagnostics.F90 b/cam_diagnostics/tropopause_diagnostics.F90 index 5c750e6c..39a428b7 100644 --- a/cam_diagnostics/tropopause_diagnostics.F90 +++ b/cam_diagnostics/tropopause_diagnostics.F90 @@ -28,38 +28,43 @@ subroutine tropopause_diagnostics_init(errmsg, errflg) errflg = 0 ! Define the output fields. + + ! Primary (Lapse rate) + backup (climatology) method call history_add_field('TROP_P', 'tropopause_air_pressure', horiz_only, 'avg', 'Pa') call history_add_field('TROP_T', 'tropopause_air_temperature', horiz_only, 'avg', 'K' ) - call history_add_field('TROP_Z', 'tropopause_altitude', horiz_only, 'avg', 'm' ) - call history_add_field('TROP_DZ', 'tropopause_altitude_relative', 'lev', 'avg', 'm') - call history_add_field('TROP_PD', 'probability_distribution_of_model_level_number_at_tropopause', 'lev', 'avg', 'probability') + call history_add_field('TROP_Z', 'tropopause_geopotential_height_wrt_surface', horiz_only, 'avg', 'm' ) + call history_add_field('TROP_DZ', 'geopotential_height_difference_between_atmosphere_layer_and_tropopause', 'lev', 'avg', 'm') + call history_add_field('TROP_PD', 'probability_distribution_of_tropopause_vertical_layer_index', 'lev', 'avg', 'probability') call history_add_field('TROP_FD', 'tropopause_found', horiz_only, 'avg', 'probability') - call history_add_field('TROPP_P', 'tropopause_air_pressure_assuming_lapse_rate', horiz_only, 'avg', 'Pa') - call history_add_field('TROPP_T', 'tropopause_air_temperature_assuming_lapse_rate', horiz_only, 'avg', 'K' ) - call history_add_field('TROPP_Z', 'tropopause_altitude_assuming_lapse_rate', horiz_only, 'avg', 'm' ) - call history_add_field('TROPP_DZ', 'tropopause_altitude_relative_assuming_lapse_rate', 'lev', 'avg', 'm') - call history_add_field('TROPP_PD', 'probability_distribution_of_model_level_number_at_tropopause_assuming_lapse_rate', 'lev', 'avg', 'probability') - call history_add_field('TROPP_FD', 'tropopause_found_assuming_lapse_rate', horiz_only, 'avg', 'probability') - - call history_add_field('TROPF_P', 'tropopause_air_pressure_assuming_cold_point', horiz_only, 'avg', 'Pa') - call history_add_field('TROPF_T', 'tropopause_air_temperature_assuming_cold_point', horiz_only, 'avg', 'K' ) - call history_add_field('TROPF_Z', 'tropopause_altitude_assuming_cold_point', horiz_only, 'avg', 'm' ) - call history_add_field('TROPF_DZ', 'tropopause_altitude_relative_assuming_cold_point', 'lev', 'avg', 'm') - call history_add_field('TROPF_PD', 'probability_distribution_of_model_level_number_at_tropopause_assuming_cold_point', 'lev', 'avg', 'probability') - call history_add_field('TROPF_FD', 'tropopause_found_assuming_cold_point', horiz_only, 'avg', 'probability') - - call history_add_field('TROPC_P', 'tropopause_air_pressure_assuming_climatology', horiz_only, 'avg', 'Pa') - call history_add_field('TROPC_T', 'tropopause_air_temperature_assuming_climatology', horiz_only, 'avg', 'K' ) - call history_add_field('TROPC_Z', 'tropopause_altitude_assuming_climatology', horiz_only, 'avg', 'm' ) - call history_add_field('TROPC_DZ', 'tropopause_altitude_relative_assuming_climatology', 'lev', 'avg', 'm') - call history_add_field('TROPC_PD', 'probability_distribution_of_model_level_number_at_tropopause_assuming_climatology', 'lev', 'avg', 'probability') - call history_add_field('TROPC_FD', 'tropopause_found_assuming_cold_point', horiz_only, 'avg', 'probability') + ! Primary (Lapse rate) only + call history_add_field('TROPP_P', 'tropopause_air_pressure_from_lapse_rate_method', horiz_only, 'avg', 'Pa') + call history_add_field('TROPP_T', 'tropopause_air_temperature_from_lapse_rate_method', horiz_only, 'avg', 'K' ) + call history_add_field('TROPP_Z', 'tropopause_geopotential_height_wrt_surface_from_lapse_rate_method', horiz_only, 'avg', 'm' ) + call history_add_field('TROPP_DZ', 'geopotential_height_difference_between_atmosphere_layer_and_tropopause_from_lapse_rate_method', 'lev', 'avg', 'm') + call history_add_field('TROPP_PD', 'probability_distribution_of_tropopause_vertical_layer_index_from_lapse_rate_method', 'lev', 'avg', 'probability') + call history_add_field('TROPP_FD', 'tropopause_found_from_lapse_rate_method', horiz_only, 'avg', 'probability') + + ! Cold point (CPP) only + call history_add_field('TROPF_P', 'tropopause_air_pressure_from_cold_point_method', horiz_only, 'avg', 'Pa') + call history_add_field('TROPF_T', 'tropopause_air_temperature_from_cold_point_method', horiz_only, 'avg', 'K' ) + call history_add_field('TROPF_Z', 'tropopause_geopotential_height_wrt_surface_from_cold_point_method', horiz_only, 'avg', 'm' ) + call history_add_field('TROPF_DZ', 'geopotential_height_difference_between_atmosphere_layer_and_tropopause_from_cold_point_method', 'lev', 'avg', 'm') + call history_add_field('TROPF_PD', 'probability_distribution_of_tropopause_vertical_layer_index_from_cold_point_method', 'lev', 'avg', 'probability') + call history_add_field('TROPF_FD', 'tropopause_found_from_cold_point_method', horiz_only, 'avg', 'probability') + + ! Climatology only - will never fail + call history_add_field('TROPC_P', 'tropopause_air_pressure_from_climatological_method', horiz_only, 'avg', 'Pa') + call history_add_field('TROPC_T', 'tropopause_air_temperature_from_climatological_method', horiz_only, 'avg', 'K' ) + call history_add_field('TROPC_Z', 'tropopause_geopotential_height_wrt_surface_from_climatological_method', horiz_only, 'avg', 'm' ) + call history_add_field('TROPC_DZ', 'geopotential_height_difference_between_atmosphere_layer_and_tropopause_from_climatological_method', 'lev', 'avg', 'm') + call history_add_field('TROPC_PD', 'probability_distribution_of_tropopause_vertical_layer_index_from_climatological_method', 'lev', 'avg', 'probability') + call history_add_field('TROPC_FD', 'tropopause_found_from_climatological_method', horiz_only, 'avg', 'probability') ! Hybridstobie output fields - call history_add_field('hstobie_trop', 'lower_bound_of_model_level_number_for_stratospheric_chemistry', 'lev', 'inst', 'fraction of model time') - call history_add_field('hstobie_linoz', 'lower_bound_of_model_level_number_for_linoz_chemistry', 'lev', 'inst', 'fraction of model time') - call history_add_field('hstobie_tropop', 'model_level_number_at_tropopause_for_chemistry', 'lev', 'inst', 'fraction of model time') + call history_add_field('hstobie_trop', 'vertical_layer_index_lower_bound_from_hybrid_stobie_linoz_with_climatological_backup_method_for_stratospheric_chemistry', 'lev', 'inst', 'fraction of model time') + call history_add_field('hstobie_linoz', 'vertical_layer_index_lower_bound_from_hybrid_stobie_linoz_with_climatological_backup_method_for_linearized_ozone_chemistry', 'lev', 'inst', 'fraction of model time') + call history_add_field('hstobie_tropop', 'tropopause_vertical_layer_index_from_hybrid_stobie_linoz_with_climatological_backup_method_for_chemistry', 'lev', 'inst', 'fraction of model time') end subroutine tropopause_diagnostics_init diff --git a/cam_diagnostics/tropopause_diagnostics.meta b/cam_diagnostics/tropopause_diagnostics.meta index a400f51c..1472bcca 100644 --- a/cam_diagnostics/tropopause_diagnostics.meta +++ b/cam_diagnostics/tropopause_diagnostics.meta @@ -40,8 +40,8 @@ dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in [ tropLev ] - standard_name = model_level_number_at_tropopause - units = 1 + standard_name = tropopause_vertical_layer_index + units = index type = integer dimensions = (horizontal_loop_extent) intent = in @@ -58,122 +58,122 @@ dimensions = (horizontal_loop_extent) intent = in [ tropZ ] - standard_name = tropopause_altitude + standard_name = tropopause_geopotential_height_wrt_surface units = m type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in [ tropLev_twmo ] - standard_name = model_level_number_at_tropopause_assuming_lapse_rate - units = 1 + standard_name = tropopause_vertical_layer_index_from_lapse_rate_method + units = index type = integer dimensions = (horizontal_loop_extent) intent = in [ tropP_twmo ] - standard_name = tropopause_air_pressure_assuming_lapse_rate + standard_name = tropopause_air_pressure_from_lapse_rate_method units = Pa type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in [ tropT_twmo ] - standard_name = tropopause_air_temperature_assuming_lapse_rate + standard_name = tropopause_air_temperature_from_lapse_rate_method units = K type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in [ tropZ_twmo ] - standard_name = tropopause_altitude_assuming_lapse_rate + standard_name = tropopause_geopotential_height_wrt_surface_from_lapse_rate_method units = m type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in [ tropLev_clim ] - standard_name = model_level_number_at_tropopause_assuming_climatology - units = 1 + standard_name = tropopause_vertical_layer_index_from_climatological_method + units = index type = integer dimensions = (horizontal_loop_extent) intent = in [ tropP_clim ] - standard_name = tropopause_air_pressure_assuming_climatology + standard_name = tropopause_air_pressure_from_climatological_method units = Pa type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in [ tropT_clim ] - standard_name = tropopause_air_temperature_assuming_climatology + standard_name = tropopause_air_temperature_from_climatological_method units = K type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in [ tropZ_clim ] - standard_name = tropopause_altitude_assuming_climatology + standard_name = tropopause_geopotential_height_wrt_surface_from_climatological_method units = m type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in [ tropLev_hybstob ] - standard_name = model_level_number_at_tropopause_assuming_hybridstobie_and_climatology - units = 1 + standard_name = tropopause_vertical_layer_index_from_hybrid_stobie_linoz_with_climatological_backup_method + units = index type = integer dimensions = (horizontal_loop_extent) intent = in [ tropP_hybstob ] - standard_name = tropopause_air_pressure_assuming_hybridstobie_and_climatology + standard_name = tropopause_air_pressure_from_hybrid_stobie_linoz_with_climatological_backup_method units = Pa type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in [ tropT_hybstob ] - standard_name = tropopause_air_temperature_assuming_hybridstobie_and_climatology + standard_name = tropopause_air_temperature_from_hybrid_stobie_linoz_with_climatological_backup_method units = K type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in [ tropZ_hybstob ] - standard_name = tropopause_altitude_assuming_hybridstobie_and_climatology + standard_name = tropopause_geopotential_height_wrt_surface_from_hybrid_stobie_linoz_with_climatological_backup_method units = m type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in [ tropLev_cpp ] - standard_name = model_level_number_at_tropopause_assuming_cold_point - units = 1 + standard_name = tropopause_vertical_layer_index_from_cold_point_method + units = index type = integer dimensions = (horizontal_loop_extent) intent = in [ tropP_cpp ] - standard_name = tropopause_air_pressure_assuming_cold_point + standard_name = tropopause_air_pressure_from_cold_point_method units = Pa type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in [ tropT_cpp ] - standard_name = tropopause_air_temperature_assuming_cold_point + standard_name = tropopause_air_temperature_from_cold_point_method units = K type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in [ tropZ_cpp ] - standard_name = tropopause_altitude_assuming_cold_point + standard_name = tropopause_geopotential_height_wrt_surface_from_cold_point_method units = m type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = in [ hstobie_trop ] - standard_name = lower_bound_of_model_level_number_for_stratospheric_chemistry - units = 1 + standard_name = vertical_layer_index_lower_bound_from_hybrid_stobie_linoz_with_climatological_backup_method_for_stratospheric_chemistry + units = index type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in [ hstobie_linoz ] - standard_name = lower_bound_of_model_level_number_for_linoz_chemistry - units = 1 + standard_name = vertical_layer_index_lower_bound_from_hybrid_stobie_linoz_with_climatological_backup_method_for_linearized_ozone_chemistry + units = index type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in [ hstobie_tropop ] - standard_name = model_level_number_at_tropopause_for_chemistry - units = 1 + standard_name = tropopause_vertical_layer_index_from_hybrid_stobie_linoz_with_climatological_backup_method_for_chemistry + units = index type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = in diff --git a/doc/ChangeLog b/doc/ChangeLog index 5ad154a9..b5219f3f 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -4,7 +4,7 @@ Tag name: Originator(s): jimmielin Date: August 22, 2024 One-line Summary: tropopause_find CCPP-ization -Github PR URL: +Github PR URL: https://github.com/ESCOMP/atmospheric_physics/pull/112 This PR fixes the following NCAR/atmospheric_physics Github issues: - Creates the CCPP interface for the tropopause_find routine @@ -37,8 +37,7 @@ M doc/NamesNotInDictionary.txt List and Describe any test failures: N/A -Summarize any changes to answers: -Difference in +Summarize any changes to answers: none =============================================================== diff --git a/suite_cam7.xml b/suite_cam7.xml index 1cb64eb3..5fea991f 100644 --- a/suite_cam7.xml +++ b/suite_cam7.xml @@ -9,4 +9,11 @@ qneg geopotential_temp + + + + + tropopause_find + tropopause_diagnostics + diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index 3a7189f7..aa0a32da 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -5,12 +5,6 @@ ! when the original algorithm fails. The tropopause temperature and ! pressure are determined and can be output to the history file. ! -! These routines are based upon code in the WACCM chemistry module -! including mo_tropoause.F90 and llnl_set_chem_trop.F90. The code -! for the Reichler et al. [2003] algorithm is from: -! -! http://www.gfdl.noaa.gov/~tjr/TROPO/tropocode.htm -! ! Author: Charles Bardeen ! Created: April, 2009 ! @@ -42,10 +36,10 @@ module tropopause_find save - ! These parameters define and enumeration to be used to define the primary + ! These parameters define an enumeration to be used to define the primary ! and backup algorithms to be used with the tropopause_find() method. The ! backup algorithm is meant to provide a solution when the primary algorithm - ! fail. The algorithms that can't fail are: TROP_ALG_ANALYTIC, TROP_ALG_CLIMATE + ! fails. The algorithms that can't fail are: TROP_ALG_ANALYTIC, TROP_ALG_CLIMATE ! and TROP_ALG_STOBIE. integer, parameter :: TROP_ALG_NONE = 1 ! Don't evaluate integer, parameter :: TROP_ALG_ANALYTIC = 2 ! Analytic Expression @@ -91,10 +85,6 @@ module tropopause_find contains !================================================================================================ - ! This routine is called during intialization and must be called before the - ! other methods in this module can be used. Its main tasks are to read in the - ! climatology from a file and to define the output fields. Much of this code - ! is taken from mo_tropopause. !> \section arg_table_tropopause_find_init Argument Table !! \htmlinclude tropopause_find_init.html subroutine tropopause_find_init(cappa, rair, gravit, pi, errmsg, errflg) @@ -131,7 +121,7 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & tropLev, tropP, tropT, tropZ, & ! Default primary+backup (twmo+climate) tropLev_twmo, tropP_twmo, tropT_twmo, tropZ_twmo, & ! Primary only (twmo) tropLev_clim, tropP_clim, tropT_clim, tropZ_clim, & ! Climate-only - tropLev_hybstob, tropP_hybstob, tropT_hybstob, tropZ_hybstob, & ! Hybridstobie + climate backup + tropLev_hybstob, tropP_hybstob, tropT_hybstob, tropZ_hybstob, & ! Hybridstobie + climate backup tropLev_cpp, tropP_cpp, tropT_cpp, tropZ_cpp, & ! Cold point only tropLev_chem, tropP_chem, tropT_chem, tropZ_chem, & ! Chemical tropopause only hstobie_trop, hstobie_linoz, hstobie_tropop, & ! Hybridstobie only for chemistry diagnostics @@ -140,14 +130,14 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & integer, intent(in) :: ncol ! Number of atmospheric columns integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) - real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa) real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) - real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp - real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m) + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m) real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) - real(kind_phys), intent(in) :: calday ! Day of year including fraction from get_curr_calday + real(kind_phys), intent(in) :: calday ! Day of year including fraction of day ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM @@ -362,14 +352,14 @@ subroutine tropopause_findWithBackup(ncol, pver, lat, pint, pmid, t, zi, zm, phi integer, intent(in) :: ncol ! Number of atmospheric columns integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) - real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa) real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) - real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp - real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m) + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m) real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) - real(kind_phys), intent(in) :: calday ! Day of year including fraction from get_curr_calday + real(kind_phys), intent(in) :: calday ! Day of year including fraction of day ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM @@ -420,7 +410,6 @@ subroutine tropopause_findWithBackup(ncol, pver, lat, pint, pmid, t, zi, zm, phi errmsg=errmsg, errflg=errflg) end if - return end subroutine tropopause_findWithBackup ! Call the appropriate tropopause detection routine based upon the algorithm @@ -437,14 +426,14 @@ subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & integer, intent(in) :: ncol ! Number of atmospheric columns integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) - real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa) real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) - real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp - real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m) + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m) real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) - real(kind_phys), intent(in) :: calday ! Day of year including fraction from get_curr_calday + real(kind_phys), intent(in) :: calday ! Day of year including fraction of day ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM @@ -512,7 +501,6 @@ subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & write(errmsg,*) 'tropopause: Invalid detection algorithm (', algorithm, ') specified.' end select - return end subroutine tropopause_findUsing ! This analytic expression closely matches the mean tropopause determined @@ -523,11 +511,11 @@ subroutine tropopause_analytic(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & integer, intent(in) :: ncol ! Number of atmospheric columns integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) - real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa) real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) - real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp - real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m) + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m) real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) integer, intent(inout) :: tropLev(:) ! tropopause level index real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) @@ -568,13 +556,11 @@ subroutine tropopause_analytic(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & end if end if end do + end subroutine tropopause_analytic ! Read the tropopause pressure in from a file containging a climatology. The ! data is interpolated to the current dat of year and latitude. - ! - ! NOTE: The data is read in during tropopause_init and stored in the module - ! variable trop subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, tropLev, tropP, tropT, tropZ) @@ -584,11 +570,11 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) - real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp - real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m) + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m) real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) - real(kind_phys), intent(in) :: calday ! Day of year including fraction from get_curr_calday + real(kind_phys), intent(in) :: calday ! Day of year including fraction of day ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM @@ -674,7 +660,6 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & end do end if - return end subroutine tropopause_climate !----------------------------------------------------------------------- @@ -682,7 +667,6 @@ end subroutine tropopause_climate subroutine tropopause_hybridstobie(ncol, pver, pmid, t, zm, & tropLev, tropP, tropT, tropZ, & hstobie_trop, hstobie_linoz, hstobie_tropop) - !use cam_history, only : outfld !----------------------------------------------------------------------- ! Originally written by Philip Cameron-Smith, LLNL @@ -700,7 +684,7 @@ subroutine tropopause_hybridstobie(ncol, pver, pmid, t, zm, & integer, intent(in) :: pver ! Number of vertical levelserp real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) - real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m) integer, intent(inout) :: tropLev(:) ! tropopause level index real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) @@ -787,10 +771,6 @@ subroutine tropopause_hybridstobie(ncol, pver, pmid, t, zm, & hstobie_tropop(:,:) = trop_trop_output(:,:) endif - !call outfld( 'hstobie_trop', trop_output(:ncol,:), ncol, pstate%lchnk ) - !call outfld( 'hstobie_linoz', trop_linoz_output(:ncol,:), ncol, pstate%lchnk ) - !call outfld( 'hstobie_tropop', trop_trop_output(:ncol,:), ncol, pstate%lchnk ) - end subroutine tropopause_hybridstobie ! This routine originates with Stobie at NASA Goddard, but does not have a @@ -802,11 +782,11 @@ subroutine tropopause_stobie(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & integer, intent(in) :: ncol ! Number of atmospheric columns integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) - real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa) real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) - real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp - real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m) + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m) real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) integer, intent(inout) :: tropLev(:) ! tropopause level index @@ -867,8 +847,7 @@ subroutine tropopause_stobie(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & end if end if end do - - return + end subroutine tropopause_stobie @@ -892,7 +871,9 @@ end subroutine tropopause_stobie ! ! determination of tropopause height from gridded temperature data ! - ! reference: Reichler, T., M. Dameris, and R. Sausen (2003) + ! Reichler, T., M. Dameris, and R. Sausen (2003), + ! Determining the tropopause height from gridded data, + ! Geophys. Res. Lett., 30, 2042, doi:10.1029/2003GL018240, 20. ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine twmo(t, p, plimu, pliml, gam, trp) @@ -999,11 +980,11 @@ subroutine tropopause_twmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & integer, intent(in) :: ncol ! Number of atmospheric columns integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) - real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa) real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) - real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp - real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m) + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m) real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) integer, intent(inout) :: tropLev(:) ! tropopause level index real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) @@ -1053,28 +1034,27 @@ subroutine tropopause_twmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & end if end do - return end subroutine tropopause_twmo ! This routine implements the WMO definition of the tropopause (WMO, 1957; Seidel and Randel, 2006). + ! Seidel, D. J., and W. J. Randel (2006), + ! Variability and trends in the global tropopause estimated from radiosonde data, + ! J. Geophys. Res., 111, D21101, doi:10.1029/2006JD007363. + ! ! This requires that the lapse rate be less than 2 K/km for an altitude range ! of 2 km. The search starts at the surface and stops the first time this ! criteria is met. - ! - ! NOTE: This code was modeled after the code in mo_tropopause; however, the - ! requirement that dt be greater than 0 was removed and the check to make - ! sure that the lapse rate is maintained for 2 km was added. subroutine tropopause_wmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & tropLev, tropP, tropT, tropZ) integer, intent(in) :: ncol ! Number of atmospheric columns integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) - real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa) real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) - real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp - real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m) + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m) real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) integer, intent(inout) :: tropLev(:) ! tropopause level index @@ -1152,7 +1132,6 @@ subroutine tropopause_wmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & end if end do - return end subroutine tropopause_wmo @@ -1165,11 +1144,11 @@ subroutine tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & integer, intent(in) :: ncol ! Number of atmospheric columns integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) - real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa) real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) - real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp - real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m) + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m) real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) integer, intent(inout) :: tropLev(:) ! tropopause level index real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) @@ -1275,7 +1254,6 @@ subroutine tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & end if end do - return end subroutine tropopause_cpp ! Searches all the columns in the chunk and attempts to identify the "chemical" @@ -1297,17 +1275,16 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, integer, intent(in) :: ncol ! Number of atmospheric columns integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) - real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa) real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) - real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp - real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m) + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m) real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) - real(kind_phys), intent(in) :: calday ! Day of year including fraction from get_curr_calday + real(kind_phys), intent(in) :: calday ! Day of year including fraction of day ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). - ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM real(kind_phys), intent(in) :: tropp_p_loc(:,:) real(kind_phys), intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 @@ -1355,7 +1332,6 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, errmsg=errmsg, errflg=errflg) end if - return end subroutine tropopause_findChemTrop ! This routine interpolates the pressures in the physics state to @@ -1366,7 +1342,7 @@ function tropopause_interpolateP(pver, pmid, zm, icol, tropLev, tropZ) integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) - real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m) integer, intent(in) :: icol ! column being processed integer, intent(in) :: tropLev ! tropopause level index real(kind_phys), optional, intent(in) :: tropZ ! tropopause pressure (m) @@ -1454,10 +1430,10 @@ end function tropopause_interpolateT ! find the geopotential height at the specified tropopause pressure. function tropopause_interpolateZ(pint, pmid, zi, zm, phis, icol, tropLev, tropP) - real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa), pverp + real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa) real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) - real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m), pverp - real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m), pver + real(kind_phys), intent(in) :: zi(:,:) ! Geopotential height above surface at interfaces (m) + real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m) real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) integer, intent(in) :: icol ! column being processed integer, intent(in) :: tropLev ! tropopause level index diff --git a/tropopause_find/tropopause_find.meta b/tropopause_find/tropopause_find.meta index 09342c86..91fb2dea 100644 --- a/tropopause_find/tropopause_find.meta +++ b/tropopause_find/tropopause_find.meta @@ -118,8 +118,8 @@ dimensions = (number_of_months_in_year) intent = in [ tropLev ] - standard_name = model_level_number_at_tropopause - units = 1 + standard_name = tropopause_vertical_layer_index + units = index type = integer dimensions = (horizontal_loop_extent) intent = out @@ -136,146 +136,146 @@ dimensions = (horizontal_loop_extent) intent = out [ tropZ ] - standard_name = tropopause_altitude + standard_name = tropopause_geopotential_height_wrt_surface units = m type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out [ tropLev_twmo ] - standard_name = model_level_number_at_tropopause_assuming_lapse_rate - units = 1 + standard_name = tropopause_vertical_layer_index_from_lapse_rate_method + units = index type = integer dimensions = (horizontal_loop_extent) intent = out [ tropP_twmo ] - standard_name = tropopause_air_pressure_assuming_lapse_rate + standard_name = tropopause_air_pressure_from_lapse_rate_method units = Pa type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out [ tropT_twmo ] - standard_name = tropopause_air_temperature_assuming_lapse_rate + standard_name = tropopause_air_temperature_from_lapse_rate_method units = K type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out [ tropZ_twmo ] - standard_name = tropopause_altitude_assuming_lapse_rate + standard_name = tropopause_geopotential_height_wrt_surface_from_lapse_rate_method units = m type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out [ tropLev_clim ] - standard_name = model_level_number_at_tropopause_assuming_climatology - units = 1 + standard_name = tropopause_vertical_layer_index_from_climatological_method + units = index type = integer dimensions = (horizontal_loop_extent) intent = out [ tropP_clim ] - standard_name = tropopause_air_pressure_assuming_climatology + standard_name = tropopause_air_pressure_from_climatological_method units = Pa type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out [ tropT_clim ] - standard_name = tropopause_air_temperature_assuming_climatology + standard_name = tropopause_air_temperature_from_climatological_method units = K type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out [ tropZ_clim ] - standard_name = tropopause_altitude_assuming_climatology + standard_name = tropopause_geopotential_height_wrt_surface_from_climatological_method units = m type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out [ tropLev_hybstob ] - standard_name = model_level_number_at_tropopause_assuming_hybridstobie_and_climatology - units = 1 + standard_name = tropopause_vertical_layer_index_from_hybrid_stobie_linoz_with_climatological_backup_method + units = index type = integer dimensions = (horizontal_loop_extent) intent = out [ tropP_hybstob ] - standard_name = tropopause_air_pressure_assuming_hybridstobie_and_climatology + standard_name = tropopause_air_pressure_from_hybrid_stobie_linoz_with_climatological_backup_method units = Pa type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out [ tropT_hybstob ] - standard_name = tropopause_air_temperature_assuming_hybridstobie_and_climatology + standard_name = tropopause_air_temperature_from_hybrid_stobie_linoz_with_climatological_backup_method units = K type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out [ tropZ_hybstob ] - standard_name = tropopause_altitude_assuming_hybridstobie_and_climatology + standard_name = tropopause_geopotential_height_wrt_surface_from_hybrid_stobie_linoz_with_climatological_backup_method units = m type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out [ tropLev_cpp ] - standard_name = model_level_number_at_tropopause_assuming_cold_point - units = 1 + standard_name = tropopause_vertical_layer_index_from_cold_point_method + units = index type = integer dimensions = (horizontal_loop_extent) intent = out [ tropP_cpp ] - standard_name = tropopause_air_pressure_assuming_cold_point + standard_name = tropopause_air_pressure_from_cold_point_method units = Pa type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out [ tropT_cpp ] - standard_name = tropopause_air_temperature_assuming_cold_point + standard_name = tropopause_air_temperature_from_cold_point_method units = K type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out [ tropZ_cpp ] - standard_name = tropopause_altitude_assuming_cold_point + standard_name = tropopause_geopotential_height_wrt_surface_from_cold_point_method units = m type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out [ tropLev_chem ] - standard_name = model_level_number_at_tropopause_assuming_chemical - units = 1 + standard_name = tropopause_vertical_layer_index_from_chemical_method + units = index type = integer dimensions = (horizontal_loop_extent) intent = out [ tropP_chem ] - standard_name = tropopause_air_pressure_assuming_chemical + standard_name = tropopause_air_pressure_from_chemical_method units = Pa type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out [ tropT_chem ] - standard_name = tropopause_air_temperature_assuming_chemical + standard_name = tropopause_air_temperature_from_chemical_method units = K type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out [ tropZ_chem ] - standard_name = tropopause_altitude_assuming_chemical + standard_name = tropopause_geopotential_height_wrt_surface_from_chemical_method units = m type = real | kind = kind_phys dimensions = (horizontal_loop_extent) intent = out [ hstobie_trop ] - standard_name = lower_bound_of_model_level_number_for_stratospheric_chemistry - units = 1 + standard_name = vertical_layer_index_lower_bound_from_hybrid_stobie_linoz_with_climatological_backup_method_for_stratospheric_chemistry + units = index type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ hstobie_linoz ] - standard_name = lower_bound_of_model_level_number_for_linoz_chemistry - units = 1 + standard_name = vertical_layer_index_lower_bound_from_hybrid_stobie_linoz_with_climatological_backup_method_for_linearized_ozone_chemistry + units = index type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out [ hstobie_tropop ] - standard_name = model_level_number_at_tropopause_for_chemistry - units = 1 + standard_name = tropopause_vertical_layer_index_from_hybrid_stobie_linoz_with_climatological_backup_method_for_chemistry + units = index type = real | kind = kind_phys dimensions = (horizontal_loop_extent, vertical_layer_dimension) intent = out From 113d041b5ce04dfcc908169a70b5804732d83cc3 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 3 Sep 2024 17:38:20 -0400 Subject: [PATCH 23/31] Update CCPP standard names --- doc/NamesNotInDictionary.txt | 184 ++++++++++++++++++----------------- 1 file changed, 94 insertions(+), 90 deletions(-) diff --git a/doc/NamesNotInDictionary.txt b/doc/NamesNotInDictionary.txt index eb75e631..061c4a11 100644 --- a/doc/NamesNotInDictionary.txt +++ b/doc/NamesNotInDictionary.txt @@ -1,30 +1,14 @@ ####################### Date/time of when script was run: -2024-08-23 02:03:20.542270 +2024-09-03 17:37:38.967474 ####################### Non-dictionary standard names found in the following metadata files: -------------------------- -./atmospheric_physics/dry_adiabatic_adjust/dadadj.meta - - - air_pressure_at_interface - - binary_indicator_for_dry_adiabatic_adjusted_grid_cell - - number_of_iterations_for_dry_adiabatic_adjustment_algorithm_convergence - - number_of_vertical_levels_from_model_top_where_dry_adiabatic_adjustment_occurs - - tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water - --------------------------- - -./atmospheric_physics/dry_adiabatic_adjust/dadadj_apply_qv_tendency.meta - - - tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water - --------------------------- - -./atmospheric_physics/tj2016/tj2016_precip.meta +atmospheric_physics/tj2016/tj2016_precip.meta - gas_constant_of_water_vapor - lwe_large_scale_precipitation_rate_at_surface @@ -33,7 +17,7 @@ Non-dictionary standard names found in the following metadata files: -------------------------- -./atmospheric_physics/tj2016/tj2016_sfc_pbl_hs.meta +atmospheric_physics/tj2016/tj2016_sfc_pbl_hs.meta - air_pressure_at_interface - eddy_heat_diffusivity @@ -53,40 +37,23 @@ Non-dictionary standard names found in the following metadata files: -------------------------- -./atmospheric_physics/utilities/geopotential_temp.meta +atmospheric_physics/dry_adiabatic_adjust/dadadj.meta - air_pressure_at_interface - - ln_air_pressure_at_interface + - binary_indicator_for_dry_adiabatic_adjusted_grid_cell + - number_of_iterations_for_dry_adiabatic_adjustment_algorithm_convergence + - number_of_vertical_levels_from_model_top_where_dry_adiabatic_adjustment_occurs + - tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water -------------------------- -./atmospheric_physics/zhang_mcfarlane/zm_conv_evap.meta +atmospheric_physics/dry_adiabatic_adjust/dadadj_apply_qv_tendency.meta - - - - cloud_area_fraction - - flag_for_zhang_mcfarlane_convective_organization_parameterization? - - freezing_point_of_water? - - frozen_precipitation_mass_flux_at_interface_due_to_deep_convection? - - heating_rate - - latent_heat_of_fusion_of_water_at_0c? - - latent_heat_of_vaporization_of_water_at_0c? - - lwe_frozen_precipitation_rate_at_surface_due_to_deep_convection - - lwe_precipitation_rate_at_surface_due_to_deep_convection - - precipitation_mass_flux_at_interface_due_to_deep_convection? - - pressure_thickness - - specific_heat_of_dry_air_at_constant_pressure? - - tendency_of_dry_air_enthalpy_at_constant_pressure_due_to_frozen_precipitation_melt? - - tendency_of_dry_air_enthalpy_at_constant_pressure_due_to_frozen_precipitation_production_in_deep_convection? - - tendency_of_frozen_precipitation_wrt_moist_air_and_condensed_water_due_to_deep_convection? - - tendency_of_precipitation_wrt_moist_air_and_condensed_water_due_to_deep_convection? - - tendency_of_precipitation_wrt_moist_air_and_condensed_water_due_to_deep_convection_excluding_subcloud_evaporation - - tendency_of_water_vapor_mixing_ratio_wrt_moist_air and_condensed_water? - - tunable_evaporation_efficiency_for_land_in_zhang_mcfarlane_deep_convection_scheme? - - tunable_evaporation_efficiency_in_zhang_mcfarlane_deep_convection_scheme? + - tendency_of_water_vapor_mixing_ratio_wrt_moist_air_and_condensed_water -------------------------- -./atmospheric_physics/zhang_mcfarlane/zm_conv_momtran.meta +atmospheric_physics/zhang_mcfarlane/zm_conv_momtran.meta - atmosphere_detrainment_convective_mass_flux_for_deep_convection_for_convective_columns - atmosphere_downdraft_convective_mass_flux_for_deep_convection_for_convective_columns @@ -113,7 +80,33 @@ Non-dictionary standard names found in the following metadata files: -------------------------- -./atmospheric_physics/zhang_mcfarlane/zm_convr.meta +atmospheric_physics/zhang_mcfarlane/zm_conv_evap.meta + + - + - cloud_area_fraction + - flag_for_zhang_mcfarlane_convective_organization_parameterization? + - freezing_point_of_water? + - frozen_precipitation_mass_flux_at_interface_due_to_deep_convection? + - heating_rate + - latent_heat_of_fusion_of_water_at_0c? + - latent_heat_of_vaporization_of_water_at_0c? + - lwe_frozen_precipitation_rate_at_surface_due_to_deep_convection + - lwe_precipitation_rate_at_surface_due_to_deep_convection + - precipitation_mass_flux_at_interface_due_to_deep_convection? + - pressure_thickness + - specific_heat_of_dry_air_at_constant_pressure? + - tendency_of_dry_air_enthalpy_at_constant_pressure_due_to_frozen_precipitation_melt? + - tendency_of_dry_air_enthalpy_at_constant_pressure_due_to_frozen_precipitation_production_in_deep_convection? + - tendency_of_frozen_precipitation_wrt_moist_air_and_condensed_water_due_to_deep_convection? + - tendency_of_precipitation_wrt_moist_air_and_condensed_water_due_to_deep_convection? + - tendency_of_precipitation_wrt_moist_air_and_condensed_water_due_to_deep_convection_excluding_subcloud_evaporation + - tendency_of_water_vapor_mixing_ratio_wrt_moist_air and_condensed_water? + - tunable_evaporation_efficiency_for_land_in_zhang_mcfarlane_deep_convection_scheme? + - tunable_evaporation_efficiency_in_zhang_mcfarlane_deep_convection_scheme? + +-------------------------- + +atmospheric_physics/zhang_mcfarlane/zm_convr.meta - air_pressure_at_interface - atmosphere_convective_mass_flux_due_to all_convection? @@ -169,7 +162,7 @@ Non-dictionary standard names found in the following metadata files: -------------------------- -./atmospheric_physics/zhang_mcfarlane/zm_conv_convtran.meta +atmospheric_physics/zhang_mcfarlane/zm_conv_convtran.meta - atmosphere_detrainment_convective_mass_flux_for_deep_convection_for_convective_columns - atmosphere_downdraft_convective_mass_flux_for_deep_convection_for_convective_columns @@ -191,64 +184,75 @@ Non-dictionary standard names found in the following metadata files: -------------------------- -./atmospheric_physics/cam_diagnostics/tropopause_diagnostics.meta +atmospheric_physics/utilities/geopotential_temp.meta + + - air_pressure_at_interface + - ln_air_pressure_at_interface + +-------------------------- + +atmospheric_physics/cam_diagnostics/tropopause_diagnostics.meta - - lower_bound_of_model_level_number_for_linoz_chemistry - - lower_bound_of_model_level_number_for_stratospheric_chemistry - - model_level_number_at_tropopause - - model_level_number_at_tropopause_assuming_climatology - - model_level_number_at_tropopause_assuming_cold_point - - model_level_number_at_tropopause_assuming_hybridstobie_and_climatology - - model_level_number_at_tropopause_for_chemistry - tropopause_air_pressure - - tropopause_air_pressure_assuming_climatology - - tropopause_air_pressure_assuming_cold_point - - tropopause_air_pressure_assuming_hybridstobie_and_climatology + - tropopause_air_pressure_from_climatological_method + - tropopause_air_pressure_from_cold_point_method + - tropopause_air_pressure_from_hybrid_stobie_linoz_with_climatological_backup_method + - tropopause_air_pressure_from_lapse_rate_method - tropopause_air_temperature - - tropopause_air_temperature_assuming_climatology - - tropopause_air_temperature_assuming_cold_point - - tropopause_air_temperature_assuming_hybridstobie_and_climatology - - tropopause_altitude - - tropopause_altitude_assuming_climatology - - tropopause_altitude_assuming_cold_point - - tropopause_altitude_assuming_hybridstobie_and_climatology + - tropopause_air_temperature_from_climatological_method + - tropopause_air_temperature_from_cold_point_method + - tropopause_air_temperature_from_hybrid_stobie_linoz_with_climatological_backup_method + - tropopause_air_temperature_from_lapse_rate_method + - tropopause_geopotential_height_wrt_surface + - tropopause_geopotential_height_wrt_surface_from_climatological_method + - tropopause_geopotential_height_wrt_surface_from_cold_point_method + - tropopause_geopotential_height_wrt_surface_from_hybrid_stobie_linoz_with_climatological_backup_method + - tropopause_geopotential_height_wrt_surface_from_lapse_rate_method + - tropopause_vertical_layer_index + - tropopause_vertical_layer_index_from_climatological_method + - tropopause_vertical_layer_index_from_cold_point_method + - tropopause_vertical_layer_index_from_hybrid_stobie_linoz_with_climatological_backup_method + - tropopause_vertical_layer_index_from_hybrid_stobie_linoz_with_climatological_backup_method_for_chemistry + - tropopause_vertical_layer_index_from_lapse_rate_method + - vertical_layer_index_lower_bound_from_hybrid_stobie_linoz_with_climatological_backup_method_for_linearized_ozone_chemistry + - vertical_layer_index_lower_bound_from_hybrid_stobie_linoz_with_climatological_backup_method_for_stratospheric_chemistry -------------------------- -./atmospheric_physics/tropopause_find/tropopause_find.meta +atmospheric_physics/tropopause_find/tropopause_find.meta - air_pressure_at_interface - fractional_calendar_days_on_end_of_current_timestep - - lower_bound_of_model_level_number_for_linoz_chemistry - - lower_bound_of_model_level_number_for_stratospheric_chemistry - - model_level_number_at_tropopause - - model_level_number_at_tropopause_assuming_chemical - - model_level_number_at_tropopause_assuming_climatology - - model_level_number_at_tropopause_assuming_cold_point - - model_level_number_at_tropopause_assuming_hybridstobie_and_climatology - - model_level_number_at_tropopause_assuming_lapse_rate - - model_level_number_at_tropopause_for_chemistry - pi_constant - ratio_of_dry_air_gas_constant_to_specific_heat_of_dry_air_at_constant_pressure - tropopause_air_pressure - - tropopause_air_pressure_assuming_chemical - - tropopause_air_pressure_assuming_climatology - - tropopause_air_pressure_assuming_cold_point - - tropopause_air_pressure_assuming_hybridstobie_and_climatology - - tropopause_air_pressure_assuming_lapse_rate + - tropopause_air_pressure_from_chemical_method + - tropopause_air_pressure_from_climatological_method - tropopause_air_pressure_from_climatology + - tropopause_air_pressure_from_cold_point_method + - tropopause_air_pressure_from_hybrid_stobie_linoz_with_climatological_backup_method + - tropopause_air_pressure_from_lapse_rate_method - tropopause_air_temperature - - tropopause_air_temperature_assuming_chemical - - tropopause_air_temperature_assuming_climatology - - tropopause_air_temperature_assuming_cold_point - - tropopause_air_temperature_assuming_hybridstobie_and_climatology - - tropopause_air_temperature_assuming_lapse_rate - - tropopause_altitude - - tropopause_altitude_assuming_chemical - - tropopause_altitude_assuming_climatology - - tropopause_altitude_assuming_cold_point - - tropopause_altitude_assuming_hybridstobie_and_climatology - - tropopause_altitude_assuming_lapse_rate + - tropopause_air_temperature_from_chemical_method + - tropopause_air_temperature_from_climatological_method + - tropopause_air_temperature_from_cold_point_method + - tropopause_air_temperature_from_hybrid_stobie_linoz_with_climatological_backup_method + - tropopause_air_temperature_from_lapse_rate_method - tropopause_calendar_days_from_climatology + - tropopause_geopotential_height_wrt_surface + - tropopause_geopotential_height_wrt_surface_from_chemical_method + - tropopause_geopotential_height_wrt_surface_from_climatological_method + - tropopause_geopotential_height_wrt_surface_from_cold_point_method + - tropopause_geopotential_height_wrt_surface_from_hybrid_stobie_linoz_with_climatological_backup_method + - tropopause_geopotential_height_wrt_surface_from_lapse_rate_method + - tropopause_vertical_layer_index + - tropopause_vertical_layer_index_from_chemical_method + - tropopause_vertical_layer_index_from_climatological_method + - tropopause_vertical_layer_index_from_cold_point_method + - tropopause_vertical_layer_index_from_hybrid_stobie_linoz_with_climatological_backup_method + - tropopause_vertical_layer_index_from_hybrid_stobie_linoz_with_climatological_backup_method_for_chemistry + - tropopause_vertical_layer_index_from_lapse_rate_method + - vertical_layer_index_lower_bound_from_hybrid_stobie_linoz_with_climatological_backup_method_for_linearized_ozone_chemistry + - vertical_layer_index_lower_bound_from_hybrid_stobie_linoz_with_climatological_backup_method_for_stratospheric_chemistry ####################### From 5355723a1291906da65633272d2aeeb6f59810a3 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 3 Sep 2024 17:41:41 -0400 Subject: [PATCH 24/31] Cleanup: Remove unused variables in tropopause_find --- tropopause_find/tropopause_find.F90 | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index aa0a32da..e6c5875b 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -50,25 +50,17 @@ module tropopause_find integer, parameter :: TROP_ALG_HYBSTOB = 7 ! Hybrid Stobie Algorithm integer, parameter :: TROP_ALG_CPP = 8 ! Cold Point Parabolic integer, parameter :: TROP_ALG_CHEMTROP = 9 ! Chemical tropopause - - integer, parameter :: TROP_NALG = 9 ! Number of Algorithms - character,parameter :: TROP_LETTER(TROP_NALG) = (/ ' ', 'A', 'C', 'S', 'T', 'W', 'H', 'F', 'M' /) - ! unique identifier for output, don't use P - - ! These variables should probably be controlled by namelist entries. - logical ,parameter :: output_all = .False. ! output tropopause info from all algorithms - integer ,parameter :: default_primary = TROP_ALG_TWMO ! default primary algorithm - integer ,parameter :: default_backup = TROP_ALG_CLIMATE ! default backup algorithm - ! Namelist variables - character(len=256) :: tropopause_climo_file = 'trop_climo' ! absolute filepath of climatology file + integer, parameter :: default_primary = TROP_ALG_TWMO ! default primary algorithm + integer, parameter :: default_backup = TROP_ALG_CLIMATE ! default backup algorithm - integer, parameter :: NOTFOUND = -1 + integer, parameter :: NOTFOUND = -1 real(kind_phys), parameter :: ALPHA = 0.03_kind_phys - ! FIXME hplin 8/15/24: fillvalue from cam_history_support. To check how it is used - ! and if we can remove it with a generic (NOTFOUND?) value + ! FIXME hplin 8/15/24 9/3/24: fillvalue from cam_history_support. + ! Used to fill arrays that are eventually output from tropopause_diagnostics and thus + ! needs to use the same value as the underlying History component. real(kind_phys), parameter :: fillvalue = 1.e36_kind_phys ! physical constants From 5d4a18d658b494f8d473fd3bc1780c16b4b3942a Mon Sep 17 00:00:00 2001 From: Jesse Nusbaumer Date: Fri, 6 Sep 2024 15:43:45 -0600 Subject: [PATCH 25/31] Make 'fillvalue' an input argument instead of a local parameter. --- tropopause_find/tropopause_find.F90 | 265 ++++++++++++++------------- tropopause_find/tropopause_find.meta | 8 +- 2 files changed, 141 insertions(+), 132 deletions(-) diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index e6c5875b..3bd743b5 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -58,13 +58,8 @@ module tropopause_find real(kind_phys), parameter :: ALPHA = 0.03_kind_phys - ! FIXME hplin 8/15/24 9/3/24: fillvalue from cam_history_support. - ! Used to fill arrays that are eventually output from tropopause_diagnostics and thus - ! needs to use the same value as the underlying History component. - real(kind_phys), parameter :: fillvalue = 1.e36_kind_phys - ! physical constants - ! These constants are set in module variables rather than as parameters + ! These constants are set in module variables rather than as parameters ! to support the aquaplanet mode in which the constants have values determined ! by the experiment protocol real(kind_phys) :: cnst_kap ! = cappa @@ -80,7 +75,7 @@ module tropopause_find !> \section arg_table_tropopause_find_init Argument Table !! \htmlinclude tropopause_find_init.html subroutine tropopause_find_init(cappa, rair, gravit, pi, errmsg, errflg) - + real(kind_phys), intent(in) :: cappa ! R/Cp real(kind_phys), intent(in) :: rair ! Dry air gas constant (J K-1 kg-1) real(kind_phys), intent(in) :: gravit ! Gravitational acceleration (m s-2) @@ -108,7 +103,7 @@ end subroutine tropopause_find_init ! other parameterizations as-is with NOTFOUND values being intentional. !> \section arg_table_tropopause_find_run Argument Table !! \htmlinclude tropopause_find_run.html - subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + subroutine tropopause_find_run(ncol, pver, fillvalue, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, & tropLev, tropP, tropT, tropZ, & ! Default primary+backup (twmo+climate) tropLev_twmo, tropP_twmo, tropT_twmo, tropZ_twmo, & ! Primary only (twmo) @@ -121,6 +116,7 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & integer, intent(in) :: ncol ! Number of atmospheric columns integer, intent(in) :: pver ! Number of vertical levels + real(kind_phys), intent(in) :: fillvalue ! Fill value for diagnostic outputs real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa) real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) @@ -183,6 +179,7 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & call tropopause_findWithBackup( & ncol = ncol, & pver = pver, & + fillvalue = fillvalue, & lat = lat, & pint = pint, & pmid = pmid, & @@ -208,6 +205,7 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & call tropopause_findWithBackup( & ncol = ncol, & pver = pver, & + fillvalue = fillvalue, & lat = lat, & pint = pint, & pmid = pmid, & @@ -232,6 +230,7 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & call tropopause_findWithBackup( & ncol = ncol, & pver = pver, & + fillvalue = fillvalue, & lat = lat, & pint = pint, & pmid = pmid, & @@ -256,6 +255,7 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & call tropopause_findWithBackup( & ncol = ncol, & pver = pver, & + fillvalue = fillvalue, & lat = lat, & pint = pint, & pmid = pmid, & @@ -280,6 +280,7 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & call tropopause_findWithBackup( & ncol = ncol, & pver = pver, & + fillvalue = fillvalue, & lat = lat, & pint = pint, & pmid = pmid, & @@ -307,6 +308,7 @@ subroutine tropopause_find_run(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & call tropopause_findWithBackup( & ncol = ncol, & pver = pver, & + fillvalue = fillvalue, & lat = lat, & pint = pint, & pmid = pmid, & @@ -334,7 +336,7 @@ end subroutine tropopause_find_run ! backup routine which will be tried only if the first routine fails. If the ! tropopause can not be identified by either routine, then a NOTFOUND is returned ! for the tropopause level, temperature and pressure. - subroutine tropopause_findWithBackup(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + subroutine tropopause_findWithBackup(ncol, pver, fillvalue, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, & tropLev, tropP, tropT, tropZ, & hstobie_trop, hstobie_linoz, hstobie_tropop, & @@ -343,6 +345,7 @@ subroutine tropopause_findWithBackup(ncol, pver, lat, pint, pmid, t, zi, zm, phi integer, intent(in) :: ncol ! Number of atmospheric columns integer, intent(in) :: pver ! Number of vertical levels + real(kind_phys), intent(in) :: fillvalue ! Fill value for diagnostic outputs real(kind_phys), intent(in) :: lat(:) ! Latitudes (radians) real(kind_phys), intent(in) :: pint(:,:) ! Interface pressures (Pa) real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) @@ -513,7 +516,7 @@ subroutine tropopause_analytic(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) - + ! Local Variables integer :: i integer :: k @@ -521,13 +524,13 @@ subroutine tropopause_analytic(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & ! Iterate over all of the columns. do i = 1, ncol - + ! Skip column in which the tropopause has already been found. if (tropLev(i) == NOTFOUND) then - + ! Calculate the pressure of the tropopause. tP = (25000.0_kind_phys - 15000.0_kind_phys * (cos(lat(i)))**2) - + ! Find the level that contains the tropopause. do k = pver, 2, -1 if (tP >= pint(i, k)) then @@ -535,10 +538,10 @@ subroutine tropopause_analytic(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & exit end if end do - + ! Return the optional outputs if (present(tropP)) tropP(i) = tP - + if (present(tropT)) then tropT(i) = tropopause_interpolateT(pver, pmid, t, i, tropLev(i), tP) end if @@ -577,7 +580,7 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) - + ! Local Variables integer :: i integer :: k @@ -586,12 +589,12 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys) :: dels integer :: last integer :: next - + ! If any columns remain to be indentified, then get the current ! day from the calendar. - + if (any(tropLev == NOTFOUND)) then - + !-------------------------------------------------------- ! ... setup the time interpolation !-------------------------------------------------------- @@ -613,23 +616,23 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & next = m + 1 dels = (calday - tropp_days(m)) / (tropp_days(m+1) - tropp_days(m)) end if - + dels = max( min( 1._kind_phys,dels ),0._kind_phys ) - + ! Iterate over all of the columns. do i = 1, ncol - + ! Skip column in which the tropopause has already been found. if (tropLev(i) == NOTFOUND) then - + !-------------------------------------------------------- ! ... get tropopause level from climatology !-------------------------------------------------------- ! Interpolate the tropopause pressure. tP = tropp_p_loc(i,last) & + dels * (tropp_p_loc(i,next) - tropp_p_loc(i,last)) - + ! Find the associated level. do k = pver, 2, -1 if (tP >= pint(i, k)) then @@ -637,10 +640,10 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & exit end if end do - + ! Return the optional outputs if (present(tropP)) tropP(i) = tP - + if (present(tropT)) then tropT(i) = tropopause_interpolateT(pver, pmid, t, i, tropLev(i), tP) end if @@ -650,21 +653,21 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & end if end if end do - end if + end if end subroutine tropopause_climate - + !----------------------------------------------------------------------- !----------------------------------------------------------------------- subroutine tropopause_hybridstobie(ncol, pver, pmid, t, zm, & tropLev, tropP, tropT, tropZ, & hstobie_trop, hstobie_linoz, hstobie_tropop) - + !----------------------------------------------------------------------- ! Originally written by Philip Cameron-Smith, LLNL ! - ! Stobie-Linoz hybrid: the highest altitude of - ! a) Stobie algorithm, or + ! Stobie-Linoz hybrid: the highest altitude of + ! a) Stobie algorithm, or ! b) minimum Linoz pressure. ! ! NOTE: the ltrop(i) gridbox itself is assumed to be a STRATOSPHERIC gridbox. @@ -687,7 +690,7 @@ subroutine tropopause_hybridstobie(ncol, pver, pmid, t, zm, & real(kind_phys), optional, intent(inout) :: hstobie_trop(:,:) ! Lowest level with strat. chem real(kind_phys), optional, intent(inout) :: hstobie_linoz(:,:) ! Lowest possible Linoz level real(kind_phys), optional, intent(inout) :: hstobie_tropop(:,:) ! Troposphere boundary calculated in chem. - + real(kind_phys),parameter :: min_Stobie_Pressure= 40.E2_kind_phys !For case 2 & 4. [Pa] real(kind_phys),parameter :: max_Linoz_Pressure =208.E2_kind_phys !For case 4. [Pa] @@ -714,8 +717,8 @@ subroutine tropopause_hybridstobie(ncol, pver, pmid, t, zm, & IF (pmid(i,k) < min_stobie_pressure) cycle shybrid_temp = ALPHA * t(i,k) - Log10(pmid(i,k)) !PJC_NOTE: the units of pmid won't matter, because it is just an additive offset. - IF (shybrid_temp= 55000._kind_phys) then cycle end if - + if ((tLev == -1) .or. (stobie(k) < sTrop)) then tLev = k tP = pmid(i, k) sTrop = stobie(k) end if end do - + if (tLev /= -1) then tropLev(i) = tLev - + ! Return the optional outputs if (present(tropP)) tropP(i) = tP - + if (present(tropT)) then tropT(i) = tropopause_interpolateT(pver, pmid, t, i, tropLev(i), tP) end if @@ -873,7 +876,7 @@ subroutine twmo(t, p, plimu, pliml, gam, trp) real(kind_phys), intent(in), dimension(:) :: t, p real(kind_phys), intent(in) :: plimu, pliml, gam real(kind_phys), intent(out) :: trp - + real(kind_phys), parameter :: deltaz = 2000.0_kind_phys real(kind_phys) :: pmk, pm, a, b, tm, dtdp, dtdz @@ -884,18 +887,18 @@ subroutine twmo(t, p, plimu, pliml, gam, trp) integer :: level integer :: icount, jj integer :: j - + trp=-99.0_kind_phys ! negative means not valid - + ! initialize start level ! dt/dz level = size(t) pmk= .5_kind_phys * (p(level-1)**cnst_kap+p(level)**cnst_kap) - pm = pmk**(1/cnst_kap) + pm = pmk**(1/cnst_kap) a = (t(level-1)-t(level))/(p(level-1)**cnst_kap-p(level)**cnst_kap) b = t(level)-(a*p(level)**cnst_kap) - tm = a * pmk + b + tm = a * pmk + b dtdp = a * cnst_kap * (pm**cnst_ka1) dtdz = cnst_faktor*dtdp*pm/tm @@ -903,39 +906,39 @@ subroutine twmo(t, p, plimu, pliml, gam, trp) pm0 = pm pmk0 = pmk dtdz0 = dtdz - + ! dt/dz pmk= .5_kind_phys * (p(j-1)**cnst_kap+p(j)**cnst_kap) - pm = pmk**(1/cnst_kap) + pm = pmk**(1/cnst_kap) a = (t(j-1)-t(j))/(p(j-1)**cnst_kap-p(j)**cnst_kap) b = t(j)-(a*p(j)**cnst_kap) - tm = a * pmk + b + tm = a * pmk + b dtdp = a * cnst_kap * (pm**cnst_ka1) dtdz = cnst_faktor*dtdp*pm/tm ! dt/dz valid? if (dtdz.le.gam) cycle main_loop ! no, dt/dz < -2 K/km if (pm.gt.plimu) cycle main_loop ! no, too low - + ! dtdz is valid, calculate tropopause pressure if (dtdz0.lt.gam) then - ag = (dtdz-dtdz0) / (pmk-pmk0) - bg = dtdz0 - (ag * pmk0) + ag = (dtdz-dtdz0) / (pmk-pmk0) + bg = dtdz0 - (ag * pmk0) ptph = exp(log((gam-bg)/ag)/cnst_kap) else ptph = pm endif - + if (ptph.lt.pliml) cycle main_loop if (ptph.gt.plimu) cycle main_loop - + ! 2nd test: dtdz above 2 km must not exceed gam p2km = ptph + deltaz*(pm/tm)*cnst_faktor ! p at ptph + 2km asum = 0.0_kind_phys ! dtdz above icount = 0 ! number of levels above - + ! test until apm < p2km in_loop: do jj=j,2,-1 - + pmk2 = .5_kind_phys * (p(jj-1)**cnst_kap+p(jj)**cnst_kap) ! p mean ^kappa pm2 = pmk2**(1/cnst_kap) ! p mean if(pm2.gt.ptph) cycle in_loop ! doesn't happen @@ -950,18 +953,18 @@ subroutine twmo(t, p, plimu, pliml, gam, trp) asum = asum+dtdz2 icount = icount+1 aquer = asum/float(icount) ! dt/dz mean - + ! discard ptropo ? if (aquer.le.gam) cycle main_loop ! dt/dz above < gam - + enddo in_loop ! test next level - + trp = ptph exit main_loop enddo main_loop - + end subroutine twmo - + ! This routine uses an implementation of Reichler et al. [2003] done by ! Reichler and downloaded from his web site. This is similar to the WMO @@ -983,27 +986,27 @@ subroutine tropopause_twmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) - ! Local Variables + ! Local Variables real(kind_phys), parameter :: gam = -0.002_kind_phys ! K/m real(kind_phys), parameter :: plimu = 45000._kind_phys ! Pa real(kind_phys), parameter :: pliml = 7500._kind_phys ! Pa - + integer :: i integer :: k real(kind_phys) :: tP ! tropopause pressure (Pa) ! Iterate over all of the columns. do i = 1, ncol - + ! Skip column in which the tropopause has already been found. if (tropLev(i) == NOTFOUND) then ! Use the routine from Reichler. call twmo(t(i, :), pmid(i, :), plimu, pliml, gam, tP) - + ! if successful, store of the results and find the level and temperature. if (tP > 0) then - + ! Find the associated level. do k = pver, 2, -1 if (tP >= pint(i, k)) then @@ -1011,10 +1014,10 @@ subroutine tropopause_twmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & exit end if end do - + ! Return the optional outputs if (present(tropP)) tropP(i) = tP - + if (present(tropT)) then tropT(i) = tropopause_interpolateT(pver, pmid, t, i, tropLev(i), tP) end if @@ -1025,9 +1028,9 @@ subroutine tropopause_twmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & end if end if end do - + end subroutine tropopause_twmo - + ! This routine implements the WMO definition of the tropopause (WMO, 1957; Seidel and Randel, 2006). ! Seidel, D. J., and W. J. Randel (2006), ! Variability and trends in the global tropopause estimated from radiosonde data, @@ -1054,7 +1057,7 @@ subroutine tropopause_wmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) - ! Local Variables + ! Local Variables real(kind_phys), parameter :: ztrop_low = 5000._kind_phys ! lowest tropopause level allowed (m) real(kind_phys), parameter :: ztrop_high = 20000._kind_phys ! highest tropopause level allowed (m) real(kind_phys), parameter :: max_dtdz = 0.002_kind_phys ! max dt/dz for tropopause level (K/m) @@ -1068,12 +1071,12 @@ subroutine tropopause_wmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & ! Iterate over all of the columns. do i = 1, ncol - + ! Skip column in which the tropopause has already been found. if (tropLev(i) == NOTFOUND) then kloop: do k = pver-1, 2, -1 - + ! Skip levels below the minimum and stop if nothing is found ! before the maximum. if (zm(i, k) < ztrop_low) then @@ -1081,12 +1084,12 @@ subroutine tropopause_wmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & else if (zm(i, k) > ztrop_high) then exit kloop end if - + ! Compare the actual lapse rate to the threshold dt = t(i, k) - t(i, k-1) - + if (dt <= (max_dtdz * (zm(i, k-1) - zm(i, k)))) then - + ! Make sure that the lapse rate stays below the threshold for the ! specified range. k2loop: do k2 = k-1, 2, -1 @@ -1095,7 +1098,7 @@ subroutine tropopause_wmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & tropLev(i) = k exit k2loop end if - + dt = t(i, k) - t(i, k2) if (dt > (max_dtdz * (zm(i, k2) - zm(i, k)))) then exit k2loop @@ -1104,15 +1107,15 @@ subroutine tropopause_wmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & if (tropLev(i) == NOTFOUND) then cycle kloop - else + else ! Return the optional outputs if (present(tropP)) tropP(i) = tP - + if (present(tropT)) then tropT(i) = tropopause_interpolateT(pver, pmid, t, i, tropLev(i), tP) end if - + if (present(tropZ)) then tropZ(i) = tropopause_interpolateZ(pint, pmid, zi, zm, phis, i, tropLev(i), tP) end if @@ -1123,10 +1126,10 @@ subroutine tropopause_wmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & end do kloop end if end do - + end subroutine tropopause_wmo - - + + ! This routine searches for the cold point tropopause, and uses a parabolic ! fit of the coldest point and two adjacent points to interpolate the cold point ! between model levels. @@ -1147,7 +1150,7 @@ subroutine tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) - ! Local Variables + ! Local Variables real(kind_phys), parameter :: ztrop_low = 5000._kind_phys ! lowest tropopause level allowed (m) real(kind_phys), parameter :: ztrop_high = 25000._kind_phys ! highest tropopause level allowed (m) @@ -1163,7 +1166,7 @@ subroutine tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & ! Iterate over all of the columns. do i = 1, ncol - + firstk = 0 lastk = pver+1 @@ -1172,7 +1175,7 @@ subroutine tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & tmin = 1e6_kind_phys kloop: do k = pver-1, 2, -1 - + ! Skip levels below the minimum and stop if nothing is found ! before the maximum. if (zm(i, k) < ztrop_low) then @@ -1182,7 +1185,7 @@ subroutine tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & lastk = k exit kloop end if - + ! Find the coldest point if (t(i, k) < tmin) then tropLev(i) = k @@ -1190,7 +1193,7 @@ subroutine tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & end if end do kloop - + ! If the minimum is at the edge of the search range, then don't ! consider this to be a minima if ((tropLev(i) >= (firstk-1)) .or. (tropLev(i) <= (lastk+1))) then @@ -1221,7 +1224,7 @@ subroutine tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & ! Find the altitude of the minimum temperature tZ = 0.5_kind_phys * b / a - + ! The fit should be between the upper and lower points, ! so skip the point if the fit fails. if ((tZ >= x0) .or. (tZ <= x2)) then @@ -1232,7 +1235,7 @@ subroutine tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & if (present(tropP)) then tropP(i) = tropopause_interpolateP(pver, pmid, zm, i, tropLev(i), tZ) end if - + if (present(tropT)) then tropT(i) = a * tZ*tZ - b*tZ + c end if @@ -1245,15 +1248,15 @@ subroutine tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & end if end if end do - + end subroutine tropopause_cpp - + ! Searches all the columns in the chunk and attempts to identify the "chemical" ! tropopause. This is the lapse rate tropopause, backed up by the climatology ! if the lapse rate fails to find the tropopause at pressures higher than a certain - ! threshold. This pressure threshold depends on latitude. Between 50S and 50N, - ! the climatology is used if the lapse rate tropopause is not found at P > 75 hPa. - ! At high latitude (poleward of 50), the threshold is increased to 125 hPa to + ! threshold. This pressure threshold depends on latitude. Between 50S and 50N, + ! the climatology is used if the lapse rate tropopause is not found at P > 75 hPa. + ! At high latitude (poleward of 50), the threshold is increased to 125 hPa to ! eliminate false events that are sometimes detected in the cold polar stratosphere. ! ! NOTE: This routine was adapted from code in chemistry.F90 and mo_gasphase_chemdr.F90. @@ -1301,11 +1304,11 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, calday, tropp_p_loc, tropp_days, & TROP_ALG_TWMO, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, & errmsg=errmsg, errflg=errflg) - + ! Now check high latitudes (poleward of 50) and set the level to the ! climatology if the level was not found or is at P <= 125 hPa. dlats(:ncol) = lat(:ncol) * cnst_rad2deg ! convert to degrees - + do i = 1, ncol if (abs(dlats(i)) > 50._kind_phys) then if (tropLev(i) .ne. NOTFOUND) then @@ -1315,7 +1318,7 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, end if end if end do - + ! Now use the backup algorithm if (any(tropLev(:) == NOTFOUND)) then call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & @@ -1323,35 +1326,35 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, default_backup, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, & errmsg=errmsg, errflg=errflg) end if - + end subroutine tropopause_findChemTrop ! This routine interpolates the pressures in the physics state to ! find the pressure at the specified tropopause altitude. function tropopause_interpolateP(pver, pmid, zm, icol, tropLev, tropZ) - + implicit none integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m) integer, intent(in) :: icol ! column being processed - integer, intent(in) :: tropLev ! tropopause level index + integer, intent(in) :: tropLev ! tropopause level index real(kind_phys), optional, intent(in) :: tropZ ! tropopause pressure (m) real(kind_phys) :: tropopause_interpolateP - + ! Local Variables real(kind_phys) :: tropP ! tropopause pressure (Pa) real(kind_phys) :: dlogPdZ ! dlog(p)/dZ - + ! Interpolate the temperature linearly against log(P) - + ! Is the tropopause at the midpoint? if (tropZ == zm(icol, tropLev)) then tropP = pmid(icol, tropLev) - + else if (tropZ > zm(icol, tropLev)) then - + ! It is above the midpoint? Make sure we aren't at the top. if (tropLev > 1) then dlogPdZ = (log(pmid(icol, tropLev)) - log(pmid(icol, tropLev - 1))) / & @@ -1359,7 +1362,7 @@ function tropopause_interpolateP(pver, pmid, zm, icol, tropLev, tropZ) tropP = pmid(icol, tropLev) + exp((tropZ - zm(icol, tropLev)) * dlogPdZ) end if else - + ! It is below the midpoint. Make sure we aren't at the bottom. if (tropLev < pver) then dlogPdZ = (log(pmid(icol, tropLev + 1)) - log(pmid(icol, tropLev))) / & @@ -1367,37 +1370,37 @@ function tropopause_interpolateP(pver, pmid, zm, icol, tropLev, tropZ) tropP = pmid(icol, tropLev) + exp((tropZ - zm(icol, tropLev)) * dlogPdZ) end if end if - + tropopause_interpolateP = tropP end function tropopause_interpolateP - + ! This routine interpolates the temperatures in the physics state to ! find the temperature at the specified tropopause pressure. function tropopause_interpolateT(pver, pmid, t, icol, tropLev, tropP) - + implicit none integer, intent(in) :: pver ! Number of vertical levels real(kind_phys), intent(in) :: pmid(:,:) ! Midpoint pressures (Pa) real(kind_phys), intent(in) :: t(:,:) ! Temperature (K) integer, intent(in) :: icol ! column being processed - integer, intent(in) :: tropLev ! tropopause level index + integer, intent(in) :: tropLev ! tropopause level index real(kind_phys), optional, intent(in) :: tropP ! tropopause pressure (Pa) real(kind_phys) :: tropopause_interpolateT - + ! Local Variables real(kind_phys) :: tropT ! tropopause temperature (K) real(kind_phys) :: dTdlogP ! dT/dlog(P) - + ! Interpolate the temperature linearly against log(P) - + ! Is the tropopause at the midpoint? if (tropP == pmid(icol, tropLev)) then tropT = t(icol, tropLev) - + else if (tropP < pmid(icol, tropLev)) then - + ! It is above the midpoint? Make sure we aren't at the top. if (tropLev > 1) then dTdlogP = (t(icol, tropLev) - t(icol, tropLev - 1)) / & @@ -1405,7 +1408,7 @@ function tropopause_interpolateT(pver, pmid, t, icol, tropLev, tropP) tropT = t(icol, tropLev) + (log(tropP) - log(pmid(icol, tropLev))) * dTdlogP end if else - + ! It is below the midpoint. Make sure we aren't at the bottom. if (tropLev < pver) then dTdlogP = (t(icol, tropLev + 1) - t(icol, tropLev)) / & @@ -1413,11 +1416,11 @@ function tropopause_interpolateT(pver, pmid, t, icol, tropLev, tropP) tropT = t(icol, tropLev) + (log(tropP) - log(pmid(icol, tropLev))) * dTdlogP end if end if - + tropopause_interpolateT = tropT end function tropopause_interpolateT - + ! This routine interpolates the geopotential height in the physics state to ! find the geopotential height at the specified tropopause pressure. function tropopause_interpolateZ(pint, pmid, zi, zm, phis, icol, tropLev, tropP) @@ -1428,34 +1431,34 @@ function tropopause_interpolateZ(pint, pmid, zi, zm, phis, icol, tropLev, tropP) real(kind_phys), intent(in) :: zm(:,:) ! Geopotential height above surface at midpoints (m) real(kind_phys), intent(in) :: phis(:) ! Surface geopotential (m2 s-2) integer, intent(in) :: icol ! column being processed - integer, intent(in) :: tropLev ! tropopause level index + integer, intent(in) :: tropLev ! tropopause level index real(kind_phys), optional, intent(in) :: tropP ! tropopause pressure (Pa) real(kind_phys) :: tropopause_interpolateZ - + ! Local Variables real(kind_phys) :: tropZ ! tropopause geopotential height (m) real(kind_phys) :: dZdlogP ! dZ/dlog(P) - + ! Interpolate the geopotential height linearly against log(P) - + ! Is the tropoause at the midpoint? if (tropP == pmid(icol, tropLev)) then tropZ = zm(icol, tropLev) - + else if (tropP < pmid(icol, tropLev)) then - + ! It is above the midpoint? Make sure we aren't at the top. dZdlogP = (zm(icol, tropLev) - zi(icol, tropLev)) / & (log(pmid(icol, tropLev)) - log(pint(icol, tropLev))) tropZ = zm(icol, tropLev) + (log(tropP) - log(pmid(icol, tropLev))) * dZdlogP else - + ! It is below the midpoint. Make sure we aren't at the bottom. dZdlogP = (zm(icol, tropLev) - zi(icol, tropLev+1)) / & (log(pmid(icol, tropLev)) - log(pint(icol, tropLev+1))) tropZ = zm(icol, tropLev) + (log(tropP) - log(pmid(icol, tropLev))) * dZdlogP end if - + tropopause_interpolateZ = tropZ + phis(icol)*cnst_rga end function tropopause_interpolateZ end module tropopause_find diff --git a/tropopause_find/tropopause_find.meta b/tropopause_find/tropopause_find.meta index 91fb2dea..6daeb6a1 100644 --- a/tropopause_find/tropopause_find.meta +++ b/tropopause_find/tropopause_find.meta @@ -57,6 +57,12 @@ type = integer dimensions = () intent = in +[ fillvalue ] + standard_name = fill_value_for_diagnostic_output + units = 1 + type = real | kind = kind_phys + dimensions = () + intent = in [ lat ] standard_name = latitude units = radians @@ -296,4 +302,4 @@ units = 1 type = integer dimensions = () - intent = out \ No newline at end of file + intent = out From d400fb2014745053b21972564639bff82d5efcac Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 10 Sep 2024 14:06:25 -0400 Subject: [PATCH 26/31] Update tropopause_find/tropopause_find.F90 Co-authored-by: Jesse Nusbaumer --- tropopause_find/tropopause_find.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index 3bd743b5..a2cd5041 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -554,8 +554,8 @@ subroutine tropopause_analytic(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & end subroutine tropopause_analytic - ! Read the tropopause pressure in from a file containging a climatology. The - ! data is interpolated to the current dat of year and latitude. + ! Determine the tropopause pressure from a climatology, + ! interpolated to the current day of year and latitude. subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, tropLev, tropP, tropT, tropZ) From d9a568684a52d1da344f461a10fccacc8ea990f3 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Wed, 11 Sep 2024 22:40:30 -0400 Subject: [PATCH 27/31] Update in response to code review comments --- cam_diagnostics/tropopause_diagnostics.F90 | 8 +++----- doc/ChangeLog | 2 +- tropopause_find/tropopause_find.F90 | 12 ++++-------- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/cam_diagnostics/tropopause_diagnostics.F90 b/cam_diagnostics/tropopause_diagnostics.F90 index 39a428b7..529ad0a0 100644 --- a/cam_diagnostics/tropopause_diagnostics.F90 +++ b/cam_diagnostics/tropopause_diagnostics.F90 @@ -9,7 +9,6 @@ module tropopause_diagnostics public :: tropopause_diagnostics_init public :: tropopause_diagnostics_run - ! Parameters consistent with tropopause_find - can they be imported? integer, parameter :: NOTFOUND = -1 contains @@ -29,7 +28,7 @@ subroutine tropopause_diagnostics_init(errmsg, errflg) ! Define the output fields. - ! Primary (Lapse rate) + backup (climatology) method + ! Primary (Lapse rate) + backup (climatology) method - will always find a tropopause call history_add_field('TROP_P', 'tropopause_air_pressure', horiz_only, 'avg', 'Pa') call history_add_field('TROP_T', 'tropopause_air_temperature', horiz_only, 'avg', 'K' ) call history_add_field('TROP_Z', 'tropopause_geopotential_height_wrt_surface', horiz_only, 'avg', 'm' ) @@ -53,7 +52,7 @@ subroutine tropopause_diagnostics_init(errmsg, errflg) call history_add_field('TROPF_PD', 'probability_distribution_of_tropopause_vertical_layer_index_from_cold_point_method', 'lev', 'avg', 'probability') call history_add_field('TROPF_FD', 'tropopause_found_from_cold_point_method', horiz_only, 'avg', 'probability') - ! Climatology only - will never fail + ! Climatology only - will always find a tropopause call history_add_field('TROPC_P', 'tropopause_air_pressure_from_climatological_method', horiz_only, 'avg', 'Pa') call history_add_field('TROPC_T', 'tropopause_air_temperature_from_climatological_method', horiz_only, 'avg', 'K' ) call history_add_field('TROPC_Z', 'tropopause_geopotential_height_wrt_surface_from_climatological_method', horiz_only, 'avg', 'm' ) @@ -215,6 +214,5 @@ subroutine tropopause_diagnostics_run(ncol, pver, & call history_out_field('hstobie_linoz', hstobie_linoz) call history_out_field('hstobie_tropop', hstobie_tropop) - return end subroutine tropopause_diagnostics_run -end module tropopause_diagnostics \ No newline at end of file +end module tropopause_diagnostics diff --git a/doc/ChangeLog b/doc/ChangeLog index b5219f3f..c44469bf 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -15,7 +15,7 @@ This PR fixes the following NCAR/atmospheric_physics Github issues: - tropopause_find accepted "primary" and "backup" methods for finding the tropopause. All the methods known to be used in CAM are now calculated at the same time in the tropopause_find_run main driver routine; it calls the underlying logic as appropriate with and populates the appropriate standard name physics fields. Because the same physical quantities for tropopause level, height, pressure, temperature, etc. using different methods are used throughout the CAM physics and simultaneously output in the diagnostics, the same standard names with a suffix are used to differentiate between these quantities computed by different methods. - Standard CCPP-ization procedures, metadata, explicit use of fields instead of physics state, only passing active :ncol fields, ... - A "shim" that will completely replicate existing behavior, bit-for-bit in current CAM, will be included in current CAM as tropopause.F90. + CAM interface code that will completely replicate existing behavior, bit-for-bit in current CAM, will be included in current CAM as tropopause.F90. Code reviewed by: diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index a2cd5041..add9fa12 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -39,8 +39,8 @@ module tropopause_find ! These parameters define an enumeration to be used to define the primary ! and backup algorithms to be used with the tropopause_find() method. The ! backup algorithm is meant to provide a solution when the primary algorithm - ! fails. The algorithms that can't fail are: TROP_ALG_ANALYTIC, TROP_ALG_CLIMATE - ! and TROP_ALG_STOBIE. + ! fails. The algorithms that can't fail (i.e., always find a tropopause) are: + ! TROP_ALG_ANALYTIC, TROP_ALG_CLIMATE, and TROP_ALG_STOBIE. integer, parameter :: TROP_ALG_NONE = 1 ! Don't evaluate integer, parameter :: TROP_ALG_ANALYTIC = 2 ! Analytic Expression integer, parameter :: TROP_ALG_CLIMATE = 3 ! Climatology @@ -128,7 +128,6 @@ subroutine tropopause_find_run(ncol, pver, fillvalue, lat, pint, pmid, t, zi, zm real(kind_phys), intent(in) :: calday ! Day of year including fraction of day ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). - ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM real(kind_phys), intent(in) :: tropp_p_loc(:,:) real(kind_phys), intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 @@ -331,7 +330,7 @@ subroutine tropopause_find_run(ncol, pver, fillvalue, lat, pint, pmid, t, zi, zm end subroutine tropopause_find_run - ! Searches all the columns in the chunk and attempts to identify the tropopause. + ! Searches all the columns and attempts to identify the tropopause. ! Two routines can be specifed, a primary routine which is tried first and a ! backup routine which will be tried only if the first routine fails. If the ! tropopause can not be identified by either routine, then a NOTFOUND is returned @@ -357,7 +356,6 @@ subroutine tropopause_findWithBackup(ncol, pver, fillvalue, lat, pint, pmid, t, real(kind_phys), intent(in) :: calday ! Day of year including fraction of day ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). - ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM real(kind_phys), intent(in) :: tropp_p_loc(:,:) real(kind_phys), intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 @@ -431,7 +429,6 @@ subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), intent(in) :: calday ! Day of year including fraction of day ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). - ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM real(kind_phys), intent(in) :: tropp_p_loc(:,:) real(kind_phys), intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 @@ -572,7 +569,6 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), intent(in) :: calday ! Day of year including fraction of day ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). - ! Remark: Not chunkized, subsetted to chunk for backwards compatibility with CAM real(kind_phys), intent(in) :: tropp_p_loc(:,:) real(kind_phys), intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 @@ -1251,7 +1247,7 @@ subroutine tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & end subroutine tropopause_cpp - ! Searches all the columns in the chunk and attempts to identify the "chemical" + ! Searches all the columns and attempts to identify the "chemical" ! tropopause. This is the lapse rate tropopause, backed up by the climatology ! if the lapse rate fails to find the tropopause at pressures higher than a certain ! threshold. This pressure threshold depends on latitude. Between 50S and 50N, From b9e485bcab57719278810b409637a3072ee81fbd Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Wed, 18 Sep 2024 19:09:33 -0400 Subject: [PATCH 28/31] Update standard name to tropopause_air_pressure_from_climatology_dataset; address review comments --- doc/NamesNotInDictionary.txt | 5 +++-- tropopause_find/tropopause_find.F90 | 10 +++++----- tropopause_find/tropopause_find.meta | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/doc/NamesNotInDictionary.txt b/doc/NamesNotInDictionary.txt index 061c4a11..496c6413 100644 --- a/doc/NamesNotInDictionary.txt +++ b/doc/NamesNotInDictionary.txt @@ -1,7 +1,7 @@ ####################### Date/time of when script was run: -2024-09-03 17:37:38.967474 +2024-09-18 19:06:50.047235 ####################### Non-dictionary standard names found in the following metadata files: @@ -222,13 +222,14 @@ atmospheric_physics/cam_diagnostics/tropopause_diagnostics.meta atmospheric_physics/tropopause_find/tropopause_find.meta - air_pressure_at_interface + - fill_value_for_diagnostic_output - fractional_calendar_days_on_end_of_current_timestep - pi_constant - ratio_of_dry_air_gas_constant_to_specific_heat_of_dry_air_at_constant_pressure - tropopause_air_pressure - tropopause_air_pressure_from_chemical_method - tropopause_air_pressure_from_climatological_method - - tropopause_air_pressure_from_climatology + - tropopause_air_pressure_from_climatology_dataset - tropopause_air_pressure_from_cold_point_method - tropopause_air_pressure_from_hybrid_stobie_linoz_with_climatological_backup_method - tropopause_air_pressure_from_lapse_rate_method diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index add9fa12..77097170 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -127,7 +127,7 @@ subroutine tropopause_find_run(ncol, pver, fillvalue, lat, pint, pmid, t, zi, zm real(kind_phys), intent(in) :: calday ! Day of year including fraction of day - ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). + ! Climatological tropopause pressures (Pa), (ncol,ntimes=12). real(kind_phys), intent(in) :: tropp_p_loc(:,:) real(kind_phys), intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 @@ -355,7 +355,7 @@ subroutine tropopause_findWithBackup(ncol, pver, fillvalue, lat, pint, pmid, t, real(kind_phys), intent(in) :: calday ! Day of year including fraction of day - ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). + ! Climatological tropopause pressures (Pa), (ncol,ntimes=12). real(kind_phys), intent(in) :: tropp_p_loc(:,:) real(kind_phys), intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 @@ -428,7 +428,7 @@ subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), intent(in) :: calday ! Day of year including fraction of day - ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). + ! Climatological tropopause pressures (Pa), (ncol,ntimes=12). real(kind_phys), intent(in) :: tropp_p_loc(:,:) real(kind_phys), intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 @@ -568,7 +568,7 @@ subroutine tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & real(kind_phys), intent(in) :: calday ! Day of year including fraction of day - ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). + ! Climatological tropopause pressures (Pa), (ncol,ntimes=12). real(kind_phys), intent(in) :: tropp_p_loc(:,:) real(kind_phys), intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 @@ -1275,7 +1275,7 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, real(kind_phys), intent(in) :: calday ! Day of year including fraction of day - ! Climatological tropopause pressures (Pa), (pcols,ntimes=12). + ! Climatological tropopause pressures (Pa), (ncol,ntimes=12). real(kind_phys), intent(in) :: tropp_p_loc(:,:) real(kind_phys), intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 diff --git a/tropopause_find/tropopause_find.meta b/tropopause_find/tropopause_find.meta index 6daeb6a1..bc218575 100644 --- a/tropopause_find/tropopause_find.meta +++ b/tropopause_find/tropopause_find.meta @@ -112,7 +112,7 @@ dimensions = () intent = in [ tropp_p_loc ] - standard_name = tropopause_air_pressure_from_climatology + standard_name = tropopause_air_pressure_from_climatology_dataset units = Pa type = real | kind = kind_phys dimensions = (horizontal_dimension, number_of_months_in_year) From 391c1140463382872ed388b9e1df6ee523488214 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Mon, 23 Sep 2024 13:12:26 -0400 Subject: [PATCH 29/31] Remove recursive call to findUsing from findChemTrop --- tropopause_find/tropopause_find.F90 | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index 77097170..5b43239a 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -1295,11 +1295,7 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, errflg = 0 ! First use the lapse rate tropopause. - ! (Not specifying primary will use the lapse rate) - call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - calday, tropp_p_loc, tropp_days, & - TROP_ALG_TWMO, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, & - errmsg=errmsg, errflg=errflg) + call tropopause_twmo(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) ! Now check high latitudes (poleward of 50) and set the level to the ! climatology if the level was not found or is at P <= 125 hPa. @@ -1315,12 +1311,11 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, end if end do - ! Now use the backup algorithm + ! Now use the climatology backup if (any(tropLev(:) == NOTFOUND)) then - call tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & - calday, tropp_p_loc, tropp_days, & - default_backup, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, & - errmsg=errmsg, errflg=errflg) + call tropopause_climate(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & + calday, tropp_p_loc, tropp_days, & + tropLev, tropP, tropT, tropZ) end if end subroutine tropopause_findChemTrop From 7e73d8a8978083cd05da1a30d4f33a97d10a3bf8 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 24 Sep 2024 12:23:10 -0400 Subject: [PATCH 30/31] Make findWithBackup (not CCPP-run routine) optional arguments again This avoids a regression in CAM where tropZ is attempted to be interpolated when geopotential height is unavailable. This would not be an issue in CCPP as the framework would check for the fields. --- tropopause_find/tropopause_find.F90 | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index 5b43239a..f2d57f8a 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -359,10 +359,10 @@ subroutine tropopause_findWithBackup(ncol, pver, fillvalue, lat, pint, pmid, t, real(kind_phys), intent(in) :: tropp_p_loc(:,:) real(kind_phys), intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 - integer, intent(out) :: tropLev(:) ! tropopause level index - real(kind_phys), intent(out) :: tropP(:) ! tropopause pressure (Pa) - real(kind_phys), intent(out) :: tropT(:) ! tropopause temperature (K) - real(kind_phys), intent(out) :: tropZ(:) ! tropopause height (m) + integer, intent(out) :: tropLev(:) ! tropopause level index + real(kind_phys), optional, intent(out) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), optional, intent(out) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), optional, intent(out) :: tropZ(:) ! tropopause height (m) ! Optional output arguments for hybridstobie with chemistry real(kind_phys), optional, intent(inout) :: hstobie_trop(:,:) ! Lowest level with strat. chem @@ -383,9 +383,9 @@ subroutine tropopause_findWithBackup(ncol, pver, fillvalue, lat, pint, pmid, t, ! Initialize the results to a missing value, so that the algorithms will ! attempt to find the tropopause for all of them. tropLev(:) = NOTFOUND - tropP(:) = fillvalue - tropT(:) = fillvalue - tropZ(:) = fillvalue + if(present(tropP)) tropP(:) = fillvalue + if(present(tropT)) tropT(:) = fillvalue + if(present(tropZ)) tropZ(:) = fillvalue ! Try to find the tropopause using the primary algorithm. if (primary /= TROP_ALG_NONE) then @@ -1432,7 +1432,7 @@ function tropopause_interpolateZ(pint, pmid, zi, zm, phis, icol, tropLev, tropP) ! Interpolate the geopotential height linearly against log(P) - ! Is the tropoause at the midpoint? + ! Is the tropopause at the midpoint? if (tropP == pmid(icol, tropLev)) then tropZ = zm(icol, tropLev) From 886c8952eb296c4eea3107f2498a242d1321c490 Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Tue, 24 Sep 2024 19:06:02 -0400 Subject: [PATCH 31/31] Changes to findChemTrop to propagate OPTIONAL arguments --- tropopause_find/tropopause_find.F90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tropopause_find/tropopause_find.F90 b/tropopause_find/tropopause_find.F90 index f2d57f8a..fd1683d7 100644 --- a/tropopause_find/tropopause_find.F90 +++ b/tropopause_find/tropopause_find.F90 @@ -482,7 +482,7 @@ subroutine tropopause_findUsing(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & call tropopause_cpp(ncol, pver, lat, pint, pmid, t, zi, zm, phis, tropLev, tropP, tropT, tropZ) case(TROP_ALG_CHEMTROP) - ! hplin: needs climatological arguments as calling tropopause_findUsing from within findChemTrop + ! hplin: needs climatological arguments as calling tropopause_climate from within findChemTrop call tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, & calday, tropp_p_loc, tropp_days, & tropLev, tropP, tropT, tropZ, & @@ -1279,10 +1279,10 @@ subroutine tropopause_findChemTrop(ncol, pver, lat, pint, pmid, t, zi, zm, phis, real(kind_phys), intent(in) :: tropp_p_loc(:,:) real(kind_phys), intent(in) :: tropp_days(:) ! Day-of-year for climo data, 12 - integer, intent(out) :: tropLev(:) ! tropopause level index - real(kind_phys), intent(inout) :: tropP(:) ! tropopause pressure (Pa) - real(kind_phys), intent(inout) :: tropT(:) ! tropopause temperature (K) - real(kind_phys), intent(inout) :: tropZ(:) ! tropopause height (m) + integer, intent(out) :: tropLev(:) ! tropopause level index + real(kind_phys), optional, intent(inout) :: tropP(:) ! tropopause pressure (Pa) + real(kind_phys), optional, intent(inout) :: tropT(:) ! tropopause temperature (K) + real(kind_phys), optional, intent(inout) :: tropZ(:) ! tropopause height (m) character(len=512), intent(out) :: errmsg integer, intent(out) :: errflg