LCOV - code coverage report
Current view: top level - physics/cam - tropopause.F90 (source / functions) Hit Total Coverage
Test: coverage.info Lines: 341 469 72.7 %
Date: 2025-03-13 18:42:46 Functions: 14 18 77.8 %

          Line data    Source code
       1             : ! This module is used to diagnose the location of the tropopause. Multiple
       2             : ! algorithms are provided, some of which may not be able to identify a
       3             : ! tropopause in all situations. To handle these cases, an analytic
       4             : ! definition and a climatology are provided that can be used to fill in
       5             : ! when the original algorithm fails. The tropopause temperature and
       6             : ! pressure are determined and can be output to the history file.
       7             : !
       8             : ! These routines are based upon code in the WACCM chemistry module
       9             : ! including mo_tropoause.F90 and llnl_set_chem_trop.F90. The code
      10             : ! for the Reichler et al. [2003] algorithm is from:
      11             : !
      12             : !   http://www.gfdl.noaa.gov/~tjr/TROPO/tropocode.htm
      13             : !
      14             : ! Author: Charles Bardeen
      15             : ! Created: April, 2009
      16             : 
      17             : module tropopause
      18             :   !---------------------------------------------------------------
      19             :   ! ... variables for the tropopause module
      20             :   !---------------------------------------------------------------
      21             : 
      22             :   use shr_kind_mod,         only : r8 => shr_kind_r8
      23             :   use shr_const_mod,        only : pi => shr_const_pi
      24             :   use ppgrid,               only : pcols, pver, begchunk, endchunk
      25             :   use cam_abortutils,       only : endrun
      26             :   use cam_logfile,          only : iulog
      27             :   use cam_history_support,  only : fillvalue
      28             :   use physics_types,        only : physics_state
      29             :   use physconst,            only : cappa, rair, gravit
      30             :   use spmd_utils,           only : masterproc
      31             : 
      32             :   implicit none
      33             : 
      34             :   private
      35             :   
      36             :   public  :: tropopause_readnl, tropopause_init, tropopause_find, tropopause_output
      37             :   public  :: tropopause_findChemTrop
      38             :   public  :: TROP_ALG_NONE, TROP_ALG_ANALYTIC, TROP_ALG_CLIMATE
      39             :   public  :: TROP_ALG_STOBIE, TROP_ALG_HYBSTOB, TROP_ALG_TWMO, TROP_ALG_WMO
      40             :   public  :: TROP_ALG_CPP
      41             :   public  :: NOTFOUND
      42             : 
      43             :   save
      44             : 
      45             :   ! These parameters define and enumeration to be used to define the primary
      46             :   ! and backup algorithms to be used with the tropopause_find() method. The
      47             :   ! backup algorithm is meant to provide a solution when the primary algorithm
      48             :   ! fail. The algorithms that can't fail are: TROP_ALG_ANALYTIC, TROP_ALG_CLIMATE
      49             :   ! and TROP_ALG_STOBIE.
      50             :   integer, parameter    :: TROP_ALG_NONE      = 1    ! Don't evaluate
      51             :   integer, parameter    :: TROP_ALG_ANALYTIC  = 2    ! Analytic Expression
      52             :   integer, parameter    :: TROP_ALG_CLIMATE   = 3    ! Climatology
      53             :   integer, parameter    :: TROP_ALG_STOBIE    = 4    ! Stobie Algorithm
      54             :   integer, parameter    :: TROP_ALG_TWMO      = 5    ! WMO Definition, Reichler et al. [2003]
      55             :   integer, parameter    :: TROP_ALG_WMO       = 6    ! WMO Definition
      56             :   integer, parameter    :: TROP_ALG_HYBSTOB   = 7    ! Hybrid Stobie Algorithm
      57             :   integer, parameter    :: TROP_ALG_CPP       = 8    ! Cold Point Parabolic
      58             :   
      59             :   integer, parameter    :: TROP_NALG          = 8    ! Number of Algorithms  
      60             :   character,parameter   :: TROP_LETTER(TROP_NALG) = (/ ' ', 'A', 'C', 'S', 'T', 'W', 'H', 'F' /)
      61             :                                                      ! unique identifier for output, don't use P
      62             : 
      63             :   ! These variables should probably be controlled by namelist entries.
      64             :   logical ,parameter    :: output_all         = .False.              ! output tropopause info from all algorithms
      65             :   integer ,parameter    :: default_primary    = TROP_ALG_TWMO        ! default primary algorithm
      66             :   integer ,parameter    :: default_backup     = TROP_ALG_CLIMATE     ! default backup algorithm
      67             : 
      68             :   ! Namelist variables
      69             :   character(len=256)    :: tropopause_climo_file = 'trop_climo'      ! absolute filepath of climatology file
      70             : 
      71             :   ! These variables are used to store the climatology data.
      72             :   real(r8)              :: days(12)                                  ! days in the climatology
      73             :   real(r8), pointer     :: tropp_p_loc(:,:,:)                        ! climatological tropopause pressures
      74             : 
      75             :   integer, parameter :: NOTFOUND = -1
      76             : 
      77             :   real(r8),parameter :: ALPHA  = 0.03_r8
      78             :     
      79             :   ! physical constants
      80             :   ! These constants are set in module variables rather than as parameters 
      81             :   ! to support the aquaplanet mode in which the constants have values determined
      82             :   ! by the experiment protocol
      83             :   real(r8) :: cnst_kap     ! = cappa
      84             :   real(r8) :: cnst_faktor  ! = -gravit/rair
      85             :   real(r8) :: cnst_ka1     ! = cnst_kap - 1._r8
      86             : 
      87             : !================================================================================================
      88             : contains
      89             : !================================================================================================
      90             : 
      91             :    ! Read namelist variables.
      92       60360 :    subroutine tropopause_readnl(nlfile)
      93             : 
      94             :       use namelist_utils,  only: find_group_name
      95             :       use units,           only: getunit, freeunit
      96             :       use mpishorthand
      97             : 
      98             :       character(len=*), intent(in) :: nlfile  ! filepath for file containing namelist input
      99             : 
     100             :       ! Local variables
     101             :       integer :: unitn, ierr
     102             :       character(len=*), parameter :: subname = 'tropopause_readnl'
     103             : 
     104             :       namelist /tropopause_nl/ tropopause_climo_file
     105             :       !-----------------------------------------------------------------------------
     106             : 
     107        1536 :       if (masterproc) then
     108           2 :          unitn = getunit()
     109           2 :          open( unitn, file=trim(nlfile), status='old' )
     110           2 :          call find_group_name(unitn, 'tropopause_nl', status=ierr)
     111           2 :          if (ierr == 0) then
     112           2 :             read(unitn, tropopause_nl, iostat=ierr)
     113           2 :             if (ierr /= 0) then
     114           0 :                call endrun(subname // ':: ERROR reading namelist')
     115             :             end if
     116             :          end if
     117           2 :          close(unitn)
     118           2 :          call freeunit(unitn)
     119             :       end if
     120             : 
     121             : #ifdef SPMD
     122             :       ! Broadcast namelist variables
     123        1536 :       call mpibcast(tropopause_climo_file, len(tropopause_climo_file), mpichar, 0, mpicom)
     124             : #endif
     125             : 
     126        1536 :    end subroutine tropopause_readnl
     127             : 
     128             : 
     129             :   ! This routine is called during intialization and must be called before the
     130             :   ! other methods in this module can be used. Its main tasks are to read in the
     131             :   ! climatology from a file and to define the output fields. Much of this code
     132             :   ! is taken from mo_tropopause.
     133        1536 :   subroutine tropopause_init()
     134             :   
     135             :     use cam_history,   only: addfld, horiz_only
     136             : 
     137             : 
     138             :     implicit none
     139             : 
     140             :     ! define physical constants
     141        1536 :     cnst_kap    = cappa
     142        1536 :     cnst_faktor = -gravit/rair
     143        1536 :     cnst_ka1    = cnst_kap - 1._r8
     144             : 
     145             :     ! Define the output fields.
     146        1536 :     call addfld('TROP_P',          horiz_only,  'A', 'Pa',          'Tropopause Pressure',              flag_xyfill=.True.)
     147        1536 :     call addfld('TROP_T',          horiz_only,  'A', 'K',           'Tropopause Temperature',           flag_xyfill=.True.)
     148        1536 :     call addfld('TROP_Z',          horiz_only,  'A', 'm',           'Tropopause Height',                flag_xyfill=.True.)
     149        3072 :     call addfld('TROP_DZ',         (/ 'lev' /), 'A', 'm',           'Relative Tropopause Height')
     150        3072 :     call addfld('TROP_PD',         (/ 'lev' /), 'A', 'probability', 'Tropopause Probabilty')
     151        1536 :     call addfld('TROP_FD',         horiz_only,  'A', 'probability', 'Tropopause Found')
     152             :     
     153        1536 :     call addfld('TROPP_P',         horiz_only,  'A', 'Pa',          'Tropopause Pressure (primary)',    flag_xyfill=.True.)
     154        1536 :     call addfld('TROPP_T',         horiz_only,  'A', 'K',           'Tropopause Temperature (primary)', flag_xyfill=.True.)
     155        1536 :     call addfld('TROPP_Z',         horiz_only,  'A', 'm',           'Tropopause Height (primary)',      flag_xyfill=.True.)
     156        3072 :     call addfld('TROPP_DZ',        (/ 'lev' /), 'A', 'm',           'Relative Tropopause Height (primary)')
     157        3072 :     call addfld('TROPP_PD',        (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (primary)')
     158        1536 :     call addfld('TROPP_FD',        horiz_only,  'A', 'probability', 'Tropopause Found (primary)')
     159             :     
     160        1536 :     call addfld('TROPF_P',         horiz_only,  'A',  'Pa',         'Tropopause Pressure (cold point)',    flag_xyfill=.True.)
     161        1536 :     call addfld('TROPF_T',         horiz_only,  'A',  'K',          'Tropopause Temperature (cold point)', flag_xyfill=.True.)
     162        1536 :     call addfld('TROPF_Z',         horiz_only,  'A',  'm',          'Tropopause Height (cold point)',      flag_xyfill=.True.)
     163        3072 :     call addfld('TROPF_DZ',        (/ 'lev' /),  'A', 'm',          'Relative Tropopause Height (cold point)', flag_xyfill=.True.)
     164        3072 :     call addfld('TROPF_PD',        (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (cold point)')
     165        1536 :     call addfld('TROPF_FD',        horiz_only,  'A', 'probability', 'Tropopause Found (cold point)')
     166             : 
     167        3072 :     call addfld( 'hstobie_trop',   (/ 'lev' /), 'I',  'fraction of model time', 'Lowest level with stratospheric chemsitry')
     168        3072 :     call addfld( 'hstobie_linoz',  (/ 'lev' /), 'I',  'fraction of model time', 'Lowest possible Linoz level')
     169             :     call addfld( 'hstobie_tropop', (/ 'lev' /), 'I', 'fraction of model time', &
     170        3072 :          'Troposphere boundary calculated in chemistry' )
     171             : 
     172             :     ! If requested, be prepared to output results from all of the methods.
     173             :     if (output_all) then
     174             :       call addfld('TROPA_P',  horiz_only,  'A',  'Pa',          'Tropopause Pressure (analytic)',        flag_xyfill=.True.)
     175             :       call addfld('TROPA_T',  horiz_only,  'A',  'K',          'Tropopause Temperature (analytic)',      flag_xyfill=.True.)
     176             :       call addfld('TROPA_Z',  horiz_only,  'A',  'm',          'Tropopause Height (analytic)',           flag_xyfill=.True.)
     177             :       call addfld('TROPA_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (analytic)')
     178             :       call addfld('TROPA_FD', horiz_only,  'A', 'probability', 'Tropopause Found (analytic)')
     179             : 
     180             :       call addfld('TROPC_P',  horiz_only,  'A',  'Pa',         'Tropopause Pressure (climatology)',      flag_xyfill=.True.)
     181             :       call addfld('TROPC_T',  horiz_only,  'A',  'K',          'Tropopause Temperature (climatology)',   flag_xyfill=.True.)
     182             :       call addfld('TROPC_Z',  horiz_only,  'A',  'm',          'Tropopause Height (climatology)',        flag_xyfill=.True.)
     183             :       call addfld('TROPC_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (climatology)')
     184             :       call addfld('TROPC_FD', horiz_only,  'A', 'probability', 'Tropopause Found (climatology)')
     185             : 
     186             :       call addfld('TROPS_P',  horiz_only,  'A',  'Pa',         'Tropopause Pressure (stobie)',           flag_xyfill=.True.)
     187             :       call addfld('TROPS_T',  horiz_only,  'A',  'K',          'Tropopause Temperature (stobie)',        flag_xyfill=.True.)
     188             :       call addfld('TROPS_Z',  horiz_only,  'A',  'm',          'Tropopause Height (stobie)',             flag_xyfill=.True.)
     189             :       call addfld('TROPS_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (stobie)')
     190             :       call addfld('TROPS_FD', horiz_only,  'A', 'probability', 'Tropopause Found (stobie)')
     191             : 
     192             :       call addfld('TROPT_P',  horiz_only,  'A',  'Pa',         'Tropopause Pressure (twmo)',             flag_xyfill=.True.)
     193             :       call addfld('TROPT_T',  horiz_only,  'A',  'K',          'Tropopause Temperature (twmo)',          flag_xyfill=.True.)
     194             :       call addfld('TROPT_Z',  horiz_only,  'A',  'm',          'Tropopause Height (twmo)',               flag_xyfill=.True.)
     195             :       call addfld('TROPT_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (twmo)')
     196             :       call addfld('TROPT_FD', horiz_only,  'A', 'probability', 'Tropopause Found (twmo)')
     197             : 
     198             :       call addfld('TROPW_P',  horiz_only,  'A',  'Pa',         'Tropopause Pressure (WMO)',              flag_xyfill=.True.)
     199             :       call addfld('TROPW_T',  horiz_only,  'A',  'K',          'Tropopause Temperature (WMO)',           flag_xyfill=.True.)
     200             :       call addfld('TROPW_Z',  horiz_only,  'A',  'm',          'Tropopause Height (WMO)',                flag_xyfill=.True.)
     201             :       call addfld('TROPW_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (WMO)')
     202             :       call addfld('TROPW_FD', horiz_only,  'A', 'probability', 'Tropopause Found (WMO)')
     203             : 
     204             :       call addfld('TROPH_P',  horiz_only,  'A',  'Pa',         'Tropopause Pressure (Hybrid Stobie)',    flag_xyfill=.True.)
     205             :       call addfld('TROPH_T',  horiz_only,  'A',  'K',          'Tropopause Temperature (Hybrid Stobie)', flag_xyfill=.True.)
     206             :       call addfld('TROPH_Z',  horiz_only,  'A',  'm',          'Tropopause Height (Hybrid Stobie)',      flag_xyfill=.True.)
     207             :       call addfld('TROPH_PD', (/ 'lev' /), 'A', 'probability', 'Tropopause Distribution (Hybrid Stobie)')
     208             :       call addfld('TROPH_FD', horiz_only,  'A', 'probability', 'Tropopause Found (Hybrid Stobie)')
     209             :     end if
     210             : 
     211             : 
     212        1536 :     call tropopause_read_file()
     213             : 
     214             : 
     215        1536 :   end subroutine tropopause_init
     216             :   
     217             : 
     218        1536 :   subroutine tropopause_read_file
     219             :     !------------------------------------------------------------------
     220             :     ! ... initialize upper boundary values
     221             :     !------------------------------------------------------------------
     222        1536 :     use interpolate_data,  only : lininterp_init, lininterp, interp_type, lininterp_finish
     223             :     use dyn_grid,     only : get_dyn_grid_parm
     224             :     use phys_grid,    only : get_ncols_p, get_rlat_all_p, get_rlon_all_p        
     225             :     use ioFileMod,    only : getfil
     226             :     use time_manager, only : get_calday
     227             :     use physconst,    only : pi
     228             :     use cam_pio_utils, only: cam_pio_openfile
     229             :     use pio,          only : file_desc_t, var_desc_t, pio_inq_dimid, pio_inq_dimlen, &
     230             :          pio_inq_varid, pio_get_var, pio_closefile, pio_nowrite
     231             : 
     232             :     !------------------------------------------------------------------
     233             :     ! ... local variables
     234             :     !------------------------------------------------------------------
     235             :     integer :: i, j, n
     236             :     integer :: ierr
     237             :     type(file_desc_t) :: pio_id
     238             :     integer :: dimid
     239             :     type(var_desc_t) :: vid
     240             :     integer :: nlon, nlat, ntimes
     241             :     integer :: start(3)
     242             :     integer :: count(3)
     243             :     integer, parameter :: dates(12) = (/ 116, 214, 316, 415,  516,  615, &
     244             :          716, 816, 915, 1016, 1115, 1216 /)
     245             :     integer :: plon, plat
     246             :     type(interp_type) :: lon_wgts, lat_wgts
     247        1536 :     real(r8), allocatable :: tropp_p_in(:,:,:)
     248        1536 :     real(r8), allocatable :: lat(:)
     249        1536 :     real(r8), allocatable :: lon(:)
     250             :     real(r8) :: to_lats(pcols), to_lons(pcols)
     251             :     real(r8), parameter :: d2r=pi/180._r8, zero=0._r8, twopi=pi*2._r8
     252             :     character(len=256) :: locfn
     253             :     integer  :: c, ncols
     254             : 
     255             : 
     256             :     plon = get_dyn_grid_parm('plon')
     257             :     plat = get_dyn_grid_parm('plat')
     258             : 
     259             : 
     260             :     !-----------------------------------------------------------------------
     261             :     !       ... open netcdf file
     262             :     !-----------------------------------------------------------------------
     263        1536 :     call getfil (tropopause_climo_file, locfn, 0)
     264        1536 :     call cam_pio_openfile(pio_id, trim(locfn), PIO_NOWRITE)
     265             : 
     266             :     !-----------------------------------------------------------------------
     267             :     !       ... get time dimension
     268             :     !-----------------------------------------------------------------------
     269        1536 :     ierr = pio_inq_dimid( pio_id, 'time', dimid )
     270        1536 :     ierr = pio_inq_dimlen( pio_id, dimid, ntimes )
     271        1536 :     if( ntimes /= 12 )then
     272           0 :        write(iulog,*) 'tropopause_init: number of months = ',ntimes,'; expecting 12'
     273           0 :        call endrun
     274             :     end if
     275             :     !-----------------------------------------------------------------------
     276             :     !       ... get latitudes
     277             :     !-----------------------------------------------------------------------
     278        1536 :     ierr = pio_inq_dimid( pio_id, 'lat', dimid )
     279        1536 :     ierr = pio_inq_dimlen( pio_id, dimid, nlat )
     280        4608 :     allocate( lat(nlat), stat=ierr )
     281        1536 :     if( ierr /= 0 ) then
     282           0 :        write(iulog,*) 'tropopause_init: lat allocation error = ',ierr
     283           0 :        call endrun
     284             :     end if
     285        1536 :     ierr = pio_inq_varid( pio_id, 'lat', vid )
     286        1536 :     ierr = pio_get_var( pio_id, vid, lat )
     287      115200 :     lat(:nlat) = lat(:nlat) * d2r
     288             :     !-----------------------------------------------------------------------
     289             :     !       ... get longitudes
     290             :     !-----------------------------------------------------------------------
     291        1536 :     ierr = pio_inq_dimid( pio_id, 'lon', dimid )
     292        1536 :     ierr = pio_inq_dimlen( pio_id, dimid, nlon )
     293        4608 :     allocate( lon(nlon), stat=ierr )
     294        1536 :     if( ierr /= 0 ) then
     295           0 :        write(iulog,*) 'tropopause_init: lon allocation error = ',ierr
     296           0 :        call endrun
     297             :     end if
     298        1536 :     ierr = pio_inq_varid( pio_id, 'lon', vid )
     299        1536 :     ierr = pio_get_var( pio_id, vid, lon )
     300      224256 :     lon(:nlon) = lon(:nlon) * d2r
     301             : 
     302             :     !------------------------------------------------------------------
     303             :     !  ... allocate arrays
     304             :     !------------------------------------------------------------------
     305        7680 :     allocate( tropp_p_in(nlon,nlat,ntimes), stat=ierr )
     306        1536 :     if( ierr /= 0 ) then
     307           0 :        write(iulog,*) 'tropopause_init: tropp_p_in allocation error = ',ierr
     308           0 :        call endrun
     309             :     end if
     310             :     !------------------------------------------------------------------
     311             :     !  ... read in the tropopause pressure
     312             :     !------------------------------------------------------------------
     313        1536 :     ierr = pio_inq_varid( pio_id, 'trop_p', vid )
     314        1536 :     start = (/ 1, 1, 1 /)
     315        6144 :     count = (/ nlon, nlat, ntimes /)
     316        1536 :     ierr = pio_get_var( pio_id, vid, start, count, tropp_p_in )
     317             : 
     318             :     !------------------------------------------------------------------
     319             :     !  ... close the netcdf file
     320             :     !------------------------------------------------------------------
     321        1536 :     call pio_closefile( pio_id )
     322             : 
     323             :     !--------------------------------------------------------------------
     324             :     !  ... regrid
     325             :     !--------------------------------------------------------------------
     326             : 
     327        6144 :     allocate( tropp_p_loc(pcols,begchunk:endchunk,ntimes), stat=ierr )
     328             : 
     329        1536 :     if( ierr /= 0 ) then
     330           0 :       write(iulog,*) 'tropopause_init: tropp_p_loc allocation error = ',ierr
     331           0 :       call endrun
     332             :     end if
     333             : 
     334        7728 :     do c=begchunk,endchunk
     335        6192 :        ncols = get_ncols_p(c)
     336        6192 :        call get_rlat_all_p(c, pcols, to_lats)
     337        6192 :        call get_rlon_all_p(c, pcols, to_lons)
     338        6192 :        call lininterp_init(lon, nlon, to_lons, ncols, 2, lon_wgts, zero, twopi)
     339        6192 :        call lininterp_init(lat, nlat, to_lats, ncols, 1, lat_wgts)
     340       80496 :        do n=1,ntimes
     341       80496 :           call lininterp(tropp_p_in(:,:,n), nlon, nlat, tropp_p_loc(1:ncols,c,n), ncols, lon_wgts, lat_wgts)    
     342             :        end do
     343        6192 :        call lininterp_finish(lon_wgts)
     344        7728 :        call lininterp_finish(lat_wgts)
     345             :     end do
     346        1536 :     deallocate(lon)
     347        1536 :     deallocate(lat)
     348        1536 :     deallocate(tropp_p_in)
     349             : 
     350             :     !--------------------------------------------------------
     351             :     ! ... initialize the monthly day of year times
     352             :     !--------------------------------------------------------
     353             : 
     354       19968 :     do n = 1,12
     355       19968 :        days(n) = get_calday( dates(n), 0 )
     356             :     end do
     357        1536 :     if (masterproc) then
     358           2 :        write(iulog,*) 'tropopause_init : days'
     359           2 :        write(iulog,'(1p,5g15.8)') days(:)
     360             :     endif
     361             : 
     362        3072 :   end subroutine tropopause_read_file
     363             :   
     364             : 
     365             :   ! This analytic expression closely matches the mean tropopause determined
     366             :   ! by the NCEP reanalysis and has been used by the radiation code.
     367           0 :   subroutine tropopause_analytic(pstate, tropLev, tropP, tropT, tropZ)
     368             : 
     369             :     implicit none
     370             : 
     371             :     type(physics_state), intent(in)     :: pstate
     372             :     integer,            intent(inout)   :: tropLev(pcols)             ! tropopause level index   
     373             :     real(r8), optional, intent(inout)   :: tropP(pcols)               ! tropopause pressure (Pa)  
     374             :     real(r8), optional, intent(inout)   :: tropT(pcols)               ! tropopause temperature (K)
     375             :     real(r8), optional, intent(inout)   :: tropZ(pcols)               ! tropopause height (m)
     376             :     
     377             :     ! Local Variables
     378             :     integer       :: i
     379             :     integer       :: k
     380             :     integer       :: ncol                     ! number of columns in the chunk
     381             :     integer       :: lchnk                    ! chunk identifier
     382             :     real(r8)      :: tP                       ! tropopause pressure (Pa)
     383             :  
     384             :     ! Information about the chunk.  
     385           0 :     lchnk = pstate%lchnk
     386           0 :     ncol  = pstate%ncol
     387             : 
     388             :     ! Iterate over all of the columns.
     389           0 :     do i = 1, ncol
     390             :      
     391             :       ! Skip column in which the tropopause has already been found.
     392           0 :       if (tropLev(i) == NOTFOUND) then
     393             :       
     394             :         ! Calculate the pressure of the tropopause.
     395           0 :         tP = (25000.0_r8 - 15000.0_r8 * (cos(pstate%lat(i)))**2)
     396             :       
     397             :         ! Find the level that contains the tropopause.
     398           0 :         do k = pver, 2, -1
     399           0 :           if (tP >= pstate%pint(i, k)) then
     400           0 :             tropLev(i) = k
     401           0 :             exit
     402             :           end if
     403             :         end do
     404             :         
     405             :         ! Return the optional outputs
     406           0 :         if (present(tropP)) tropP(i) = tP
     407             :         
     408           0 :         if (present(tropT)) then
     409           0 :           tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP)
     410             :         end if
     411             : 
     412           0 :         if (present(tropZ)) then
     413           0 :           tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP)
     414             :         end if
     415             :       end if
     416             :     end do
     417        1536 :   end subroutine tropopause_analytic
     418             : 
     419             : 
     420             :   ! Read the tropopause pressure in from a file containging a climatology. The
     421             :   ! data is interpolated to the current dat of year and latitude.
     422             :   !
     423             :   ! NOTE: The data is read in during tropopause_init and stored in the module
     424             :   ! variable trop
     425      171983 :   subroutine tropopause_climate(pstate, tropLev, tropP, tropT, tropZ)
     426             :      use time_manager, only : get_curr_calday
     427             : 
     428             :     implicit none
     429             : 
     430             :     type(physics_state), intent(in)    :: pstate 
     431             :     integer,            intent(inout)  :: tropLev(pcols)            ! tropopause level index   
     432             :     real(r8), optional, intent(inout)  :: tropP(pcols)              ! tropopause pressure (Pa)   
     433             :     real(r8), optional, intent(inout)  :: tropT(pcols)              ! tropopause temperature (K)
     434             :     real(r8), optional, intent(inout)  :: tropZ(pcols)              ! tropopause height (m)
     435             :  
     436             :     ! Local Variables
     437             :     integer       :: i
     438             :     integer       :: k
     439             :     integer       :: m
     440             :     integer       :: ncol                     ! number of columns in the chunk
     441             :     integer       :: lchnk                    ! chunk identifier
     442             :     real(r8)      :: tP                       ! tropopause pressure (Pa)
     443             :     real(r8)      :: calday                   ! day of year including fraction
     444             :     real(r8)      :: dels
     445             :     integer       :: last
     446             :     integer       :: next
     447             : 
     448             :     ! Information about the chunk.  
     449      171983 :     lchnk = pstate%lchnk
     450      171983 :     ncol  = pstate%ncol
     451             :     
     452             :     ! If any columns remain to be indentified, the nget the current
     453             :     ! day from the calendar.
     454             :     
     455     2598827 :     if (any(tropLev == NOTFOUND)) then
     456             :     
     457             :       ! Determine the calendar day.
     458      171983 :       calday = get_curr_calday()
     459             :       
     460             :       !--------------------------------------------------------
     461             :       ! ... setup the time interpolation
     462             :       !--------------------------------------------------------
     463      171983 :       if( calday < days(1) ) then
     464      171983 :         next = 1
     465      171983 :         last = 12
     466      171983 :         dels = (365._r8 + calday - days(12)) / (365._r8 + days(1) - days(12))
     467           0 :       else if( calday >= days(12) ) then
     468           0 :         next = 1
     469           0 :         last = 12
     470           0 :         dels = (calday - days(12)) / (365._r8 + days(1) - days(12))
     471             :       else
     472           0 :         do m = 11,1,-1
     473           0 :            if( calday >= days(m) ) then
     474             :               exit
     475             :            end if
     476             :         end do
     477           0 :         last = m
     478           0 :         next = m + 1
     479           0 :         dels = (calday - days(m)) / (days(m+1) - days(m))
     480             :       end if
     481             :       
     482      171983 :       dels = max( min( 1._r8,dels ),0._r8 )
     483             :         
     484             : 
     485             :       ! Iterate over all of the columns.
     486     2725279 :       do i = 1, ncol
     487             :        
     488             :         ! Skip column in which the tropopause has already been found.
     489     2725279 :         if (tropLev(i) == NOTFOUND) then
     490             :         
     491             :         !--------------------------------------------------------
     492             :         ! ... get tropopause level from climatology
     493             :         !--------------------------------------------------------
     494             :           ! Interpolate the tropopause pressure.
     495           0 :           tP = tropp_p_loc(i,lchnk,last) &
     496       56617 :             + dels * (tropp_p_loc(i,lchnk,next) - tropp_p_loc(i,lchnk,last))
     497             :                 
     498             :           ! Find the associated level.
     499     2668505 :           do k = pver, 2, -1
     500     2668505 :             if (tP >= pstate%pint(i, k)) then
     501       56617 :               tropLev(i) = k
     502       56617 :               exit
     503             :             end if
     504             :           end do
     505             :       
     506             :           ! Return the optional outputs
     507       56617 :           if (present(tropP)) tropP(i) = tP
     508             :           
     509       56617 :           if (present(tropT)) then
     510        5049 :             tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP)
     511             :           end if
     512             : 
     513       56617 :           if (present(tropZ)) then
     514        5049 :             tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP)
     515             :           end if
     516             :         end if
     517             :       end do
     518             :     end if        
     519             : 
     520      171983 :     return    
     521      171983 :   end subroutine tropopause_climate
     522             :   
     523             :   !-----------------------------------------------------------------------
     524             :   !-----------------------------------------------------------------------
     525           0 :   subroutine tropopause_hybridstobie(pstate, tropLev, tropP, tropT, tropZ)
     526      171983 :     use cam_history,  only : outfld
     527             :   
     528             :     !-----------------------------------------------------------------------
     529             :     ! Originally written by Philip Cameron-Smith, LLNL
     530             :     !
     531             :     !   Stobie-Linoz hybrid: the highest altitude of 
     532             :     !          a) Stobie algorithm, or 
     533             :     !          b) minimum Linoz pressure.
     534             :     !
     535             :     ! NOTE: the ltrop(i) gridbox itself is assumed to be a STRATOSPHERIC gridbox.
     536             :     !-----------------------------------------------------------------------
     537             :     !-----------------------------------------------------------------------
     538             :     !        ... Local variables
     539             :     !-----------------------------------------------------------------------
     540             :     
     541             :     implicit none
     542             : 
     543             :     type(physics_state), intent(in)     :: pstate 
     544             :     integer,            intent(inout)   :: tropLev(pcols)             ! tropopause level index   
     545             :     real(r8), optional, intent(inout)   :: tropP(pcols)               ! tropopause pressure (Pa)  
     546             :     real(r8), optional, intent(inout)   :: tropT(pcols)               ! tropopause temperature (K)
     547             :     real(r8), optional, intent(inout)   :: tropZ(pcols)               ! tropopause height (m)
     548             :     
     549             :     real(r8),parameter  ::  min_Stobie_Pressure= 40.E2_r8 !For case 2 & 4.  [Pa]
     550             :     real(r8),parameter  ::  max_Linoz_Pressure =208.E2_r8 !For case     4.  [Pa]
     551             : 
     552             :     integer      :: i, k, ncol
     553             :     real(r8)     :: stobie_min, shybrid_temp      !temporary variable for case 2 & 3.
     554             :     integer      :: ltrop_linoz(pcols)            !Lowest possible Linoz vertical level
     555             :     integer      :: ltrop_trop(pcols)             !Tropopause level for hybrid case.
     556             :     logical      :: ltrop_linoz_set               !Flag that lowest linoz level already found.
     557             :     real(r8)     :: trop_output(pcols,pver)        !For output purposes only.
     558             :     real(r8)     :: trop_linoz_output(pcols,pver)  !For output purposes only.
     559             :     real(r8)     :: trop_trop_output(pcols,pver)   !For output purposes only.
     560             : 
     561             :     !    write(iulog,*) 'In set_chem_trop, o3_ndx =',o3_ndx
     562           0 :     ltrop_linoz(:) = 1  ! Initialize to default value.
     563           0 :     ltrop_trop(:) = 1   ! Initialize to default value.
     564           0 :     ncol = pstate%ncol
     565             : 
     566           0 :     LOOP_COL4: do i=1,ncol
     567             : 
     568             :        ! Skip column in which the tropopause has already been found.
     569           0 :        not_found: if (tropLev(i) == NOTFOUND) then
     570             : 
     571             :           stobie_min = 1.e10_r8    ! An impossibly large number
     572             :           ltrop_linoz_set = .FALSE.
     573           0 :           LOOP_LEV: do k=pver,1,-1
     574           0 :              IF (pstate%pmid(i,k) < min_stobie_pressure) cycle
     575           0 :              shybrid_temp = ALPHA * pstate%t(i,k) - Log10(pstate%pmid(i,k))
     576             :              !PJC_NOTE: the units of pmid won't matter, because it is just an additive offset.
     577           0 :              IF (shybrid_temp<stobie_min) then 
     578           0 :                 ltrop_trop(i)=k     
     579           0 :                 stobie_min = shybrid_temp
     580             :              ENDIF
     581           0 :              IF (pstate%pmid(i,k) < max_Linoz_pressure .AND. .NOT. ltrop_linoz_set) THEN
     582           0 :                 ltrop_linoz(i) = k
     583           0 :                 ltrop_linoz_set = .TRUE.
     584             :              ENDIF
     585             :           enddo LOOP_LEV
     586             : 
     587           0 :           tropLev(i) = MIN(ltrop_trop(i),ltrop_linoz(i))
     588             : 
     589           0 :           if (present(tropP)) then
     590           0 :              tropP(i) = pstate%pmid(i,tropLev(i))
     591             :           endif
     592           0 :           if (present(tropT)) then
     593           0 :              tropT(i) = pstate%   t(i,tropLev(i))
     594             :           endif
     595           0 :           if (present(tropZ)) then
     596           0 :              tropZ(i) = pstate%  zm(i,tropLev(i))
     597             :           endif
     598             : 
     599             :        endif not_found
     600             : 
     601             :     enddo LOOP_COL4
     602             : 
     603           0 :     trop_output(:,:)=0._r8
     604           0 :     trop_linoz_output(:,:)=0._r8
     605           0 :     trop_trop_output(:,:)=0._r8
     606           0 :     do i=1,ncol
     607           0 :        if (tropLev(i)>0) then
     608           0 :           trop_output(i,tropLev(i))=1._r8
     609           0 :           trop_linoz_output(i,ltrop_linoz(i))=1._r8
     610           0 :           trop_trop_output(i,ltrop_trop(i))=1._r8
     611             :        endif
     612             :     enddo
     613             : 
     614           0 :     call outfld( 'hstobie_trop',   trop_output(:ncol,:),       ncol, pstate%lchnk )
     615           0 :     call outfld( 'hstobie_linoz',  trop_linoz_output(:ncol,:), ncol, pstate%lchnk )
     616           0 :     call outfld( 'hstobie_tropop', trop_trop_output(:ncol,:),  ncol, pstate%lchnk )
     617             : 
     618           0 :   endsubroutine tropopause_hybridstobie
     619             :   
     620             :   ! This routine originates with Stobie at NASA Goddard, but does not have a
     621             :   ! known reference. It was supplied by Philip Cameron-Smith of LLNL.
     622             :   !
     623           0 :   subroutine tropopause_stobie(pstate, tropLev, tropP, tropT, tropZ)
     624             : 
     625             :     implicit none
     626             : 
     627             :     type(physics_state), intent(in)     :: pstate 
     628             :     integer,            intent(inout)   :: tropLev(pcols)             ! tropopause level index   
     629             :     real(r8), optional, intent(inout)   :: tropP(pcols)               ! tropopause pressure (Pa)  
     630             :     real(r8), optional, intent(inout)   :: tropT(pcols)               ! tropopause temperature (K)
     631             :     real(r8), optional, intent(inout)   :: tropZ(pcols)               ! tropopause height (m)
     632             :     
     633             :     ! Local Variables
     634             :     integer       :: i
     635             :     integer       :: k
     636             :     integer       :: ncol                     ! number of columns in the chunk
     637             :     integer       :: lchnk                    ! chunk identifier
     638             :     integer       :: tLev                     ! tropopause level
     639             :     real(r8)      :: tP                       ! tropopause pressure (Pa)
     640             :     real(r8)      :: stobie(pver)             ! stobie weighted temperature
     641             :     real(r8)      :: sTrop                    ! stobie value at the tropopause
     642             :  
     643             :     ! Information about the chunk.  
     644           0 :     lchnk = pstate%lchnk
     645           0 :     ncol  = pstate%ncol
     646             : 
     647             :     ! Iterate over all of the columns.
     648           0 :     do i = 1, ncol
     649             :      
     650             :       ! Skip column in which the tropopause has already been found.
     651           0 :       if (tropLev(i) == NOTFOUND) then
     652             :       
     653             :         ! Caclulate a pressure weighted temperature.
     654           0 :         stobie(:) = ALPHA * pstate%t(i,:) - log10(pstate%pmid(i, :))
     655             : 
     656             :         ! Search from the bottom up, looking for the first minimum.
     657             :         tLev  = -1
     658             :   
     659           0 :         do k = pver-1, 1, -1
     660             :     
     661           0 :           if (pstate%pmid(i, k) <= 4000._r8) then
     662             :             exit
     663             :           end if
     664             :     
     665           0 :           if (pstate%pmid(i, k) >= 55000._r8) then
     666             :             cycle
     667             :           end if
     668             :           
     669           0 :           if ((tLev == -1) .or. (stobie(k) < sTrop)) then
     670           0 :             tLev  = k
     671           0 :             tP    = pstate%pmid(i, k)
     672             :             sTrop = stobie(k)
     673             :           end if
     674             :         end do
     675             :         
     676           0 :         if (tLev /= -1) then
     677           0 :           tropLev(i) = tLev
     678             :         
     679             :           ! Return the optional outputs
     680           0 :           if (present(tropP)) tropP(i) = tP
     681             :           
     682           0 :           if (present(tropT)) then
     683           0 :             tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP)
     684             :           end if
     685             : 
     686           0 :           if (present(tropZ)) then
     687           0 :             tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP)
     688             :           end if
     689             :         end if
     690             :       end if
     691             :     end do
     692             :     
     693           0 :     return
     694           0 :   end subroutine tropopause_stobie
     695             : 
     696             : 
     697             :   ! This routine is an implementation of Reichler et al. [2003] done by
     698             :   ! Reichler and downloaded from his web site. Minimal modifications were
     699             :   ! made to have the routine work within the CAM framework (i.e. using
     700             :   ! CAM constants and types).
     701             :   !
     702             :   ! NOTE: I am not a big fan of the goto's and multiple returns in this
     703             :   ! code, but for the moment I have left them to preserve as much of the
     704             :   ! original and presumably well tested code as possible.
     705             :   ! UPDATE: The most "obvious" substitutions have been made to replace
     706             :   ! goto/return statements with cycle/exit. The structure is still
     707             :   ! somewhat tangled.
     708             :   ! UPDATE 2: "gamma" renamed to "gam" in order to avoid confusion
     709             :   ! with the Fortran 2008 intrinsic. "level" argument removed because
     710             :   ! a physics column is not contiguous, so using explicit dimensions
     711             :   ! will cause the data to be needlessly copied.
     712             :   !
     713             :   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     714             :   !
     715             :   ! determination of tropopause height from gridded temperature data
     716             :   !
     717             :   ! reference: Reichler, T., M. Dameris, and R. Sausen (2003)
     718             :   !
     719             :   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
     720    11226600 :   subroutine twmo(t, p, plimu, pliml, gam, trp)
     721             : 
     722             :     real(r8), intent(in), dimension(:)      :: t, p
     723             :     real(r8), intent(in)                    :: plimu, pliml, gam
     724             :     real(r8), intent(out)                   :: trp
     725             :     
     726             :     real(r8), parameter                     :: deltaz = 2000.0_r8
     727             : 
     728             :     real(r8)                                :: pmk, pm, a, b, tm, dtdp, dtdz
     729             :     real(r8)                                :: ag, bg, ptph
     730             :     real(r8)                                :: pm0, pmk0, dtdz0
     731             :     real(r8)                                :: p2km, asum, aquer
     732             :     real(r8)                                :: pmk2, pm2, a2, b2, tm2, dtdp2, dtdz2
     733             :     integer                                 :: level
     734             :     integer                                 :: icount, jj
     735             :     integer                                 :: j
     736             :     
     737             : 
     738    11226600 :     trp=-99.0_r8                           ! negative means not valid
     739             :     
     740             :     ! initialize start level
     741             :     ! dt/dz
     742    11226600 :     level = size(t)
     743    11226600 :     pmk= .5_r8 * (p(level-1)**cnst_kap+p(level)**cnst_kap)
     744    11226600 :     pm = pmk**(1/cnst_kap)               
     745    11226600 :     a = (t(level-1)-t(level))/(p(level-1)**cnst_kap-p(level)**cnst_kap)
     746    11226600 :     b = t(level)-(a*p(level)**cnst_kap)
     747    11226600 :     tm = a * pmk + b               
     748    11226600 :     dtdp = a * cnst_kap * (pm**cnst_ka1)
     749    11226600 :     dtdz = cnst_faktor*dtdp*pm/tm
     750             : 
     751   462415622 :     main_loop: do j=level-1,2,-1
     752             :       pm0 = pm
     753   462353956 :       pmk0 = pmk
     754   462353956 :       dtdz0  = dtdz
     755             :     
     756             :       ! dt/dz
     757   462353956 :       pmk= .5_r8 * (p(j-1)**cnst_kap+p(j)**cnst_kap)
     758   462353956 :       pm = pmk**(1/cnst_kap)               
     759   462353956 :       a = (t(j-1)-t(j))/(p(j-1)**cnst_kap-p(j)**cnst_kap)
     760   462353956 :       b = t(j)-(a*p(j)**cnst_kap)
     761   462353956 :       tm = a * pmk + b               
     762   462353956 :       dtdp = a * cnst_kap * (pm**cnst_ka1)
     763   462353956 :       dtdz = cnst_faktor*dtdp*pm/tm
     764             :       ! dt/dz valid?
     765   462353956 :       if (dtdz.le.gam) cycle main_loop    ! no, dt/dz < -2 K/km
     766    51920171 :       if (pm.gt.plimu)   cycle main_loop    ! no, too low
     767             :   
     768             :       ! dtdz is valid, calculate tropopause pressure
     769    17023674 :       if (dtdz0.lt.gam) then
     770    13733505 :         ag = (dtdz-dtdz0) / (pmk-pmk0)     
     771    13733505 :         bg = dtdz0 - (ag * pmk0)          
     772    13733505 :         ptph = exp(log((gam-bg)/ag)/cnst_kap)
     773             :       else
     774             :         ptph = pm
     775             :       endif
     776             :   
     777    17023674 :       if (ptph.lt.pliml) cycle main_loop
     778    14661857 :       if (ptph.gt.plimu) cycle main_loop
     779             :   
     780             :       ! 2nd test: dtdz above 2 km must not exceed gam
     781    14656366 :       p2km = ptph + deltaz*(pm/tm)*cnst_faktor     ! p at ptph + 2km
     782    14656366 :       asum = 0.0_r8                                ! dtdz above
     783    14656366 :       icount = 0                                   ! number of levels above
     784             :   
     785             :       ! test until apm < p2km
     786    82324859 :       in_loop: do jj=j,2,-1
     787             :     
     788    82324859 :         pmk2 = .5_r8 * (p(jj-1)**cnst_kap+p(jj)**cnst_kap) ! p mean ^kappa
     789    82324859 :         pm2 = pmk2**(1/cnst_kap)                           ! p mean
     790    82324859 :         if(pm2.gt.ptph) cycle in_loop            ! doesn't happen
     791    82324859 :         if(pm2.lt.p2km) exit in_loop             ! ptropo is valid
     792             : 
     793    71159925 :         a2 = (t(jj-1)-t(jj))                     ! a
     794    71159925 :         a2 = a2/(p(jj-1)**cnst_kap-p(jj)**cnst_kap)
     795    71159925 :         b2 = t(jj)-(a2*p(jj)**cnst_kap)          ! b
     796    71159925 :         tm2 = a2 * pmk2 + b2                     ! T mean
     797    71159925 :         dtdp2 = a2 * cnst_kap * (pm2**(cnst_kap-1))  ! dt/dp
     798    71159925 :         dtdz2 = cnst_faktor*dtdp2*pm2/tm2
     799    71159925 :         asum = asum+dtdz2
     800    71159925 :         icount = icount+1
     801    71159925 :         aquer = asum/float(icount)               ! dt/dz mean
     802             :    
     803             :         ! discard ptropo ?
     804    82324859 :         if (aquer.le.gam) cycle main_loop      ! dt/dz above < gam
     805             :     
     806             :       enddo in_loop  ! test next level
     807             :     
     808    11164934 :       trp = ptph
     809   462415622 :       exit main_loop
     810             :     enddo main_loop
     811             :     
     812    11226600 :   end subroutine twmo
     813             :   
     814             : 
     815             :   ! This routine uses an implementation of Reichler et al. [2003] done by
     816             :   ! Reichler and downloaded from his web site. This is similar to the WMO
     817             :   ! routines, but is designed for GCMs with a coarse vertical grid.
     818      715176 :   subroutine tropopause_twmo(pstate, tropLev, tropP, tropT, tropZ)
     819             : 
     820             :     implicit none
     821             : 
     822             :     type(physics_state), intent(in)    :: pstate 
     823             :     integer,            intent(inout)  :: tropLev(pcols)            ! tropopause level index   
     824             :     real(r8), optional, intent(inout)  :: tropP(pcols)              ! tropopause pressure (Pa)   
     825             :     real(r8), optional, intent(inout)  :: tropT(pcols)              ! tropopause temperature (K)
     826             :     real(r8), optional, intent(inout)  :: tropZ(pcols)              ! tropopause height (m)
     827             : 
     828             :     ! Local Variables 
     829             :     real(r8), parameter     :: gam    = -0.002_r8         ! K/m
     830             :     real(r8), parameter     :: plimu    = 45000._r8         ! Pa
     831             :     real(r8), parameter     :: pliml    = 7500._r8          ! Pa
     832             :      
     833             :     integer                 :: i
     834             :     integer                 :: k
     835             :     integer                 :: ncol                         ! number of columns in the chunk
     836             :     integer                 :: lchnk                        ! chunk identifier
     837             :     real(r8)                :: tP                       ! tropopause pressure (Pa)
     838             : 
     839             :     ! Information about the chunk.  
     840      715176 :     lchnk = pstate%lchnk
     841      715176 :     ncol  = pstate%ncol
     842             : 
     843             :     ! Iterate over all of the columns.
     844    11941776 :     do i = 1, ncol
     845             :      
     846             :       ! Skip column in which the tropopause has already been found.
     847    11941776 :       if (tropLev(i) == NOTFOUND) then
     848             : 
     849             :         ! Use the routine from Reichler.
     850    11226600 :         call twmo(pstate%t(i, :), pstate%pmid(i, :), plimu, pliml, gam, tP)
     851             :      
     852             :         ! if successful, store of the results and find the level and temperature.
     853    11226600 :         if (tP > 0) then
     854             :         
     855             :           ! Find the associated level.
     856   467788385 :           do k = pver, 2, -1
     857   467788385 :             if (tP >= pstate%pint(i, k)) then
     858    11164934 :               tropLev(i) = k
     859    11164934 :               exit
     860             :             end if
     861             :           end do
     862             :           
     863             :           ! Return the optional outputs
     864    11164934 :           if (present(tropP)) tropP(i) = tP
     865             :           
     866    11164934 :           if (present(tropT)) then
     867     1836702 :             tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP)
     868             :           end if
     869             : 
     870    11164934 :           if (present(tropZ)) then
     871     1836702 :             tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP)
     872             :           end if
     873             :         end if
     874             :       end if
     875             :     end do
     876             :     
     877      715176 :     return
     878             :   end subroutine tropopause_twmo
     879             :   
     880             :   ! This routine implements the WMO definition of the tropopause (WMO, 1957; Seidel and Randel, 2006).
     881             :   ! This requires that the lapse rate be less than 2 K/km for an altitude range
     882             :   ! of 2 km. The search starts at the surface and stops the first time this
     883             :   ! criteria is met.
     884             :   !
     885             :   ! NOTE: This code was modeled after the code in mo_tropopause; however, the
     886             :   ! requirement that dt be greater than 0 was removed and the check to make
     887             :   ! sure that the lapse rate is maintained for 2 km was added.
     888           0 :   subroutine tropopause_wmo(pstate, tropLev, tropP, tropT, tropZ)
     889             : 
     890             :     implicit none
     891             : 
     892             :     type(physics_state), intent(in)    :: pstate 
     893             :     integer,            intent(inout)  :: tropLev(pcols)            ! tropopause level index   
     894             :     real(r8), optional, intent(inout)  :: tropP(pcols)              ! tropopause pressure (Pa)   
     895             :     real(r8), optional, intent(inout)  :: tropT(pcols)              ! tropopause temperature (K)
     896             :     real(r8), optional, intent(inout)  :: tropZ(pcols)              ! tropopause height (m)
     897             : 
     898             :     ! Local Variables 
     899             :     real(r8), parameter    :: ztrop_low   = 5000._r8        ! lowest tropopause level allowed (m)
     900             :     real(r8), parameter    :: ztrop_high  = 20000._r8       ! highest tropopause level allowed (m)
     901             :     real(r8), parameter    :: max_dtdz    = 0.002_r8        ! max dt/dz for tropopause level (K/m)
     902             :     real(r8), parameter    :: min_trop_dz = 2000._r8        ! min tropopause thickness (m)
     903             : 
     904             :     integer                 :: i
     905             :     integer                 :: k
     906             :     integer                 :: k2
     907             :     integer                 :: ncol                         ! number of columns in the chunk
     908             :     integer                 :: lchnk                        ! chunk identifier
     909             :     real(r8)                :: tP                           ! tropopause pressure (Pa)
     910             :     real(r8)                :: dt
     911             : 
     912             :     ! Information about the chunk.  
     913           0 :     lchnk = pstate%lchnk
     914           0 :     ncol  = pstate%ncol
     915             : 
     916             :     ! Iterate over all of the columns.
     917           0 :     do i = 1, ncol
     918             :      
     919             :       ! Skip column in which the tropopause has already been found.
     920           0 :       if (tropLev(i) == NOTFOUND) then
     921             : 
     922           0 :         kloop: do k = pver-1, 2, -1
     923             :          
     924             :           ! Skip levels below the minimum and stop if nothing is found
     925             :           ! before the maximum.
     926           0 :           if (pstate%zm(i, k) < ztrop_low) then
     927             :             cycle kloop
     928           0 :           else if (pstate%zm(i, k) > ztrop_high) then
     929             :             exit kloop
     930             :           end if
     931             :           
     932             :           ! Compare the actual lapse rate to the threshold
     933           0 :           dt = pstate%t(i, k) - pstate%t(i, k-1)
     934             :             
     935           0 :           if (dt <= (max_dtdz * (pstate%zm(i, k-1) - pstate%zm(i, k)))) then
     936             :             
     937             :             ! Make sure that the lapse rate stays below the threshold for the
     938             :             ! specified range.
     939           0 :             k2loop: do k2 = k-1, 2, -1
     940           0 :               if ((pstate%zm(i, k2) - pstate%zm(i, k)) >= min_trop_dz) then
     941           0 :                 tP = pstate%pmid(i, k)
     942           0 :                 tropLev(i) = k
     943           0 :                 exit k2loop
     944             :               end if
     945             :               
     946           0 :               dt = pstate%t(i, k) - pstate%t(i, k2)
     947           0 :               if (dt > (max_dtdz * (pstate%zm(i, k2) - pstate%zm(i, k)))) then
     948             :                 exit k2loop
     949             :               end if
     950             :            end do k2loop
     951             : 
     952           0 :            if (tropLev(i) == NOTFOUND) then
     953             :               cycle kloop
     954             :            else 
     955             : 
     956             :               ! Return the optional outputs
     957           0 :               if (present(tropP)) tropP(i) = tP
     958             :               
     959           0 :               if (present(tropT)) then
     960           0 :                 tropT(i) = tropopause_interpolateT(pstate, i, tropLev(i), tP)
     961             :               end if
     962             :   
     963           0 :               if (present(tropZ)) then
     964           0 :                 tropZ(i) = tropopause_interpolateZ(pstate, i, tropLev(i), tP)
     965             :               end if
     966             : 
     967             :               exit kloop
     968             :             end if
     969             :           end if
     970             :         end do kloop
     971             :       end if
     972             :     end do
     973             :     
     974           0 :     return
     975             :   end subroutine tropopause_wmo
     976             :   
     977             :   
     978             :   ! This routine searches for the cold point tropopause, and uses a parabolic
     979             :   ! fit of the coldest point and two adjacent points to interpolate the cold point
     980             :   ! between model levels.
     981       58824 :   subroutine tropopause_cpp(pstate, tropLev, tropP, tropT, tropZ)
     982             : 
     983             :     implicit none
     984             : 
     985             :     type(physics_state), intent(in)    :: pstate 
     986             :     integer,            intent(inout)  :: tropLev(pcols)            ! tropopause level index   
     987             :     real(r8), optional, intent(inout)  :: tropP(pcols)              ! tropopause pressure (Pa)   
     988             :     real(r8), optional, intent(inout)  :: tropT(pcols)              ! tropopause temperature (K)
     989             :     real(r8), optional, intent(inout)  :: tropZ(pcols)              ! tropopause height (m)
     990             : 
     991             :     ! Local Variables 
     992             :     real(r8), parameter    :: ztrop_low   = 5000._r8        ! lowest tropopause level allowed (m)
     993             :     real(r8), parameter    :: ztrop_high  = 25000._r8       ! highest tropopause level allowed (m)
     994             : 
     995             :     integer                 :: i
     996             :     integer                 :: k, firstk, lastk
     997             :     integer                 :: k2
     998             :     integer                 :: ncol                         ! number of columns in the chunk
     999             :     integer                 :: lchnk                        ! chunk identifier
    1000             :     real(r8)                :: tZ                           ! tropopause height (m)
    1001             :     real(r8)                :: tmin
    1002             :     real(r8)                :: f0, f1, f2
    1003             :     real(r8)                :: x0, x1, x2
    1004             :     real(r8)                :: c0, c1, c2
    1005             :     real(r8)                :: a, b, c
    1006             : 
    1007             :     ! Information about the chunk.  
    1008       58824 :     lchnk = pstate%lchnk
    1009       58824 :     ncol  = pstate%ncol
    1010             : 
    1011             :     ! Iterate over all of the columns.
    1012      982224 :     do i = 1, ncol
    1013             :      
    1014      923400 :       firstk = 0
    1015      923400 :       lastk  = pver+1
    1016             : 
    1017             :       ! Skip column in which the tropopause has already been found.
    1018      982224 :       if (tropLev(i) == NOTFOUND) then
    1019             :         tmin = 1e6_r8
    1020             : 
    1021    62137872 :         kloop: do k = pver-1, 2, -1
    1022             :          
    1023             :           ! Skip levels below the minimum and stop if nothing is found
    1024             :           ! before the maximum.
    1025    62137872 :           if (pstate%zm(i, k) < ztrop_low) then
    1026             :             firstk = k
    1027             :             cycle kloop
    1028    41419936 :           else if (pstate%zm(i, k) > ztrop_high) then
    1029             :             lastk = k
    1030             :             exit kloop
    1031             :           end if
    1032             :           
    1033             :           ! Find the coldest point
    1034    40496536 :           if (pstate%t(i, k) < tmin) then
    1035    20927322 :             tropLev(i) = k
    1036    20927322 :             tmin = pstate%t(i,k)
    1037             :           end if
    1038             :         end do kloop
    1039             : 
    1040             :         
    1041             :         ! If the minimum is at the edge of the search range, then don't
    1042             :         ! consider this to be a minima
    1043      923400 :         if ((tropLev(i) >= (firstk-1)) .or. (tropLev(i) <= (lastk+1))) then
    1044        7766 :           tropLev(i) = NOTFOUND
    1045             :         else
    1046             : 
    1047             :           ! If returning P, Z, or T, then do a parabolic fit using the
    1048             :           ! cold point and it its 2 surrounding points to interpolate
    1049             :           ! between model levels.
    1050      915634 :           if (present(tropP) .or. present(tropZ) .or. present(tropT)) then
    1051      915634 :             f0 = pstate%t(i, tropLev(i)-1)
    1052      915634 :             f1 = pstate%t(i, tropLev(i))
    1053      915634 :             f2 = pstate%t(i, tropLev(i)+1)
    1054             : 
    1055      915634 :             x0 = pstate%zm(i, tropLev(i)-1)
    1056      915634 :             x1 = pstate%zm(i, tropLev(i))
    1057      915634 :             x2 = pstate%zm(i, tropLev(i)+1)
    1058             : 
    1059      915634 :             c0 = (x0-x1)*(x0-x2)
    1060      915634 :             c1 = (x1-x0)*(x1-x2)
    1061      915634 :             c2 = (x2-x0)*(x2-x1)
    1062             : 
    1063             :             ! Determine the quadratic coefficients of:
    1064             :             !   T = a * z^2 - b*z + c
    1065      915634 :             a = (f0/c0 + f1/c1 + f2/c2)
    1066      915634 :             b = (f0/c0*(x1+x2) + f1/c1*(x0+x2) + f2/c2*(x0+x1))
    1067      915634 :             c = f0/c0*x1*x2 + f1/c1*x0*x2 + f2/c2*x0*x1
    1068             : 
    1069             :             ! Find the altitude of the minimum temperature
    1070      915634 :             tZ = 0.5_r8 * b / a
    1071             :             
    1072             :             ! The fit should be between the upper and lower points,
    1073             :             ! so skip the point if the fit fails.
    1074      915634 :             if ((tZ >= x0) .or. (tZ <= x2)) then
    1075           0 :               tropLev(i) = NOTFOUND
    1076             :             else
    1077             : 
    1078             :               ! Return the optional outputs
    1079      915634 :               if (present(tropP)) then
    1080      915634 :                 tropP(i) = tropopause_interpolateP(pstate, i, tropLev(i), tZ)
    1081             :               end if
    1082             :             
    1083      915634 :               if (present(tropT)) then
    1084      915634 :                 tropT(i) = a * tZ*tZ - b*tZ + c
    1085             :               end if
    1086             : 
    1087      915634 :               if (present(tropZ)) then
    1088      915634 :                 tropZ(i) = tZ
    1089             :               end if
    1090             :             end if
    1091             :           end if
    1092             :         end if
    1093             :       end if
    1094             :     end do
    1095             :     
    1096       58824 :     return
    1097             :   end subroutine tropopause_cpp
    1098             : 
    1099             : 
    1100             :   ! Searches all the columns in the chunk and attempts to identify the tropopause.
    1101             :   ! Two routines can be specifed, a primary routine which is tried first and a
    1102             :   ! backup routine which will be tried only if the first routine fails. If the
    1103             :   ! tropopause can not be identified by either routine, then a NOTFOUND is returned
    1104             :   ! for the tropopause level, temperature and pressure.
    1105      774000 :   subroutine tropopause_find(pstate, tropLev, tropP, tropT, tropZ, primary, backup)
    1106             : 
    1107             :     implicit none
    1108             : 
    1109             :     type(physics_state), intent(in)     :: pstate 
    1110             :     integer, optional, intent(in)       :: primary                   ! primary detection algorithm
    1111             :     integer, optional, intent(in)       :: backup                    ! backup detection algorithm
    1112             :     integer,            intent(out)     :: tropLev(pcols)            ! tropopause level index   
    1113             :     real(r8), optional, intent(out)     :: tropP(pcols)              ! tropopause pressure (Pa)  
    1114             :     real(r8), optional, intent(out)     :: tropT(pcols)              ! tropopause temperature (K)
    1115             :     real(r8), optional, intent(out)     :: tropZ(pcols)              ! tropopause height (m)
    1116             :     
    1117             :     ! Local Variable
    1118             :     integer       :: primAlg            ! Primary algorithm  
    1119             :     integer       :: backAlg            ! Backup algorithm  
    1120             :   
    1121             :     ! Initialize the results to a missing value, so that the algorithms will
    1122             :     ! attempt to find the tropopause for all of them.
    1123    13158000 :     tropLev(:) = NOTFOUND
    1124     3774024 :     if (present(tropP)) tropP(:) = fillvalue
    1125     3774024 :     if (present(tropT)) tropT(:) = fillvalue
    1126     3774024 :     if (present(tropZ)) tropZ(:) = fillvalue
    1127             :     
    1128             :     ! Set the algorithms to be used, either the ones provided or the defaults.
    1129      774000 :     if (present(primary)) then
    1130       58824 :       primAlg = primary
    1131             :     else
    1132      715176 :       primAlg = default_primary
    1133             :     end if
    1134             :     
    1135      774000 :     if (present(backup)) then
    1136      625392 :       backAlg = backup
    1137             :     else
    1138      148608 :       backAlg = default_backup
    1139             :     end if
    1140             :     
    1141             :     ! Try to find the tropopause using the primary algorithm.
    1142      774000 :     if (primAlg /= TROP_ALG_NONE) then
    1143      774000 :       call tropopause_findUsing(pstate, primAlg, tropLev, tropP, tropT, tropZ)
    1144             :     end if
    1145             :  
    1146    12772805 :     if ((backAlg /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then
    1147       38922 :       call tropopause_findUsing(pstate, backAlg, tropLev, tropP, tropT, tropZ)
    1148             :     end if
    1149             :     
    1150      774000 :     return
    1151             :   end subroutine tropopause_find
    1152             :   
    1153             :   ! Searches all the columns in the chunk and attempts to identify the "chemical"
    1154             :   ! tropopause. This is the lapse rate tropopause, backed up by the climatology
    1155             :   ! if the lapse rate fails to find the tropopause at pressures higher than a certain
    1156             :   ! threshold. This pressure threshold depends on latitude. Between 50S and 50N, 
    1157             :   ! the climatology is used if the lapse rate tropopause is not found at P > 75 hPa. 
    1158             :   ! At high latitude (poleward of 50), the threshold is increased to 125 hPa to 
    1159             :   ! eliminate false events that are sometimes detected in the cold polar stratosphere.
    1160             :   !
    1161             :   ! NOTE: This routine was adapted from code in chemistry.F90 and mo_gasphase_chemdr.F90.
    1162      507744 :   subroutine tropopause_findChemTrop(pstate, tropLev, primary, backup)
    1163             : 
    1164             :     implicit none
    1165             : 
    1166             :     type(physics_state), intent(in)     :: pstate 
    1167             :     integer, optional, intent(in)       :: primary                   ! primary detection algorithm
    1168             :     integer, optional, intent(in)       :: backup                    ! backup detection algorithm
    1169             :     integer,            intent(out)     :: tropLev(pcols)            ! tropopause level index   
    1170             : 
    1171             :     ! Local Variable
    1172             :     real(r8), parameter :: rad2deg = 180._r8/pi                      ! radians to degrees conversion factor
    1173             :     real(r8)            :: dlats(pcols)
    1174             :     integer             :: i
    1175             :     integer             :: ncol
    1176             :     integer             :: backAlg
    1177             : 
    1178             :     ! First use the lapse rate tropopause.
    1179      507744 :     ncol = pstate%ncol
    1180      507744 :     call tropopause_find(pstate, tropLev, primary=primary, backup=TROP_ALG_NONE)
    1181             :    
    1182             :     ! Now check high latitudes (poleward of 50) and set the level to the
    1183             :     ! climatology if the level was not found or is at P <= 125 hPa.
    1184     8478144 :     dlats(:ncol) = pstate%lat(:ncol) * rad2deg ! convert to degrees
    1185             : 
    1186      507744 :     if (present(backup)) then
    1187           0 :       backAlg = backup
    1188             :     else
    1189      507744 :       backAlg = default_backup
    1190             :     end if
    1191             :     
    1192     8478144 :     do i = 1, ncol
    1193     8478144 :       if (abs(dlats(i)) > 50._r8) then
    1194     1788256 :         if (tropLev(i) .ne. NOTFOUND) then
    1195     1788256 :           if (pstate%pmid(i, tropLev(i)) <= 12500._r8) then
    1196           0 :             tropLev(i) = NOTFOUND
    1197             :           end if
    1198             :         end if
    1199             :       end if
    1200             :     end do
    1201             :         
    1202             :     ! Now use the backup algorithm
    1203     8380036 :     if ((backAlg /= TROP_ALG_NONE) .and. any(tropLev(:) == NOTFOUND)) then
    1204      133061 :       call tropopause_findUsing(pstate, backAlg, tropLev)
    1205             :     end if
    1206             :     
    1207      507744 :     return
    1208             :   end subroutine tropopause_findChemTrop
    1209             :   
    1210             :   
    1211             :   ! Call the appropriate tropopause detection routine based upon the algorithm
    1212             :   ! specifed.
    1213             :   !
    1214             :   ! NOTE: It is assumed that the output fields have been initialized by the
    1215             :   ! caller, and only output values set to fillvalue will be detected.
    1216      945983 :   subroutine tropopause_findUsing(pstate, algorithm, tropLev, tropP, tropT, tropZ)
    1217             : 
    1218             :     implicit none
    1219             : 
    1220             :     type(physics_state), intent(in)     :: pstate 
    1221             :     integer,            intent(in)      :: algorithm                 ! detection algorithm
    1222             :     integer,            intent(inout)   :: tropLev(pcols)            ! tropopause level index   
    1223             :     real(r8), optional, intent(inout)   :: tropP(pcols)              ! tropopause pressure (Pa)  
    1224             :     real(r8), optional, intent(inout)   :: tropT(pcols)              ! tropopause temperature (K)
    1225             :     real(r8), optional, intent(inout)   :: tropZ(pcols)              ! tropopause height (m)
    1226             : 
    1227             :     ! Dispatch the request to the appropriate routine.
    1228      945983 :     select case(algorithm)
    1229             :       case(TROP_ALG_ANALYTIC)
    1230           0 :         call tropopause_analytic(pstate, tropLev, tropP, tropT, tropZ)
    1231             : 
    1232             :       case(TROP_ALG_CLIMATE)
    1233      171983 :         call tropopause_climate(pstate, tropLev, tropP, tropT, tropZ)
    1234             : 
    1235             :       case(TROP_ALG_STOBIE)
    1236           0 :         call tropopause_stobie(pstate, tropLev, tropP, tropT, tropZ)
    1237             : 
    1238             :       case(TROP_ALG_HYBSTOB)
    1239           0 :         call tropopause_hybridstobie(pstate, tropLev, tropP, tropT, tropZ)
    1240             : 
    1241             :       case(TROP_ALG_TWMO)
    1242      715176 :         call tropopause_twmo(pstate, tropLev, tropP, tropT, tropZ)
    1243             : 
    1244             :       case(TROP_ALG_WMO)
    1245           0 :         call tropopause_wmo(pstate, tropLev, tropP, tropT, tropZ)
    1246             : 
    1247             :       case(TROP_ALG_CPP)
    1248       58824 :         call tropopause_cpp(pstate, tropLev, tropP, tropT, tropZ)
    1249             : 
    1250             :       case default
    1251           0 :         write(iulog, *) 'tropopause: Invalid detection algorithm (',  algorithm, ') specified.'
    1252      945983 :         call endrun
    1253             :     end select
    1254             :     
    1255      945983 :     return
    1256             :   end subroutine tropopause_findUsing
    1257             : 
    1258             : 
    1259             :   ! This routine interpolates the pressures in the physics state to
    1260             :   ! find the pressure at the specified tropopause altitude.
    1261      915634 :   function tropopause_interpolateP(pstate, icol, tropLev, tropZ)
    1262             :  
    1263             :     implicit none
    1264             : 
    1265             :     type(physics_state), intent(in)     :: pstate 
    1266             :     integer, intent(in)                 :: icol               ! column being processed
    1267             :     integer, intent(in)                 :: tropLev            ! tropopause level index   
    1268             :     real(r8), optional, intent(in)      :: tropZ              ! tropopause pressure (m)
    1269             :     real(r8)                            :: tropopause_interpolateP
    1270             :     
    1271             :     ! Local Variables
    1272             :     real(r8)   :: tropP              ! tropopause pressure (Pa)
    1273             :     real(r8)   :: dlogPdZ            ! dlog(p)/dZ
    1274             :     
    1275             :     ! Interpolate the temperature linearly against log(P)
    1276             :     
    1277             :     ! Is the tropopause at the midpoint?
    1278      915634 :     if (tropZ == pstate%zm(icol, tropLev)) then
    1279           0 :       tropP = pstate%pmid(icol, tropLev)
    1280             :     
    1281      915634 :     else if (tropZ > pstate%zm(icol, tropLev)) then
    1282             :     
    1283             :       ! It is above the midpoint? Make sure we aren't at the top.
    1284      446662 :       if (tropLev > 1) then
    1285      446662 :         dlogPdZ = (log(pstate%pmid(icol, tropLev)) - log(pstate%pmid(icol, tropLev - 1))) / &
    1286      893324 :           (pstate%zm(icol, tropLev) - pstate%zm(icol, tropLev - 1)) 
    1287      446662 :         tropP = pstate%pmid(icol, tropLev) + exp((tropZ - pstate%zm(icol, tropLev)) * dlogPdZ)
    1288             :       end if
    1289             :     else
    1290             :       
    1291             :       ! It is below the midpoint. Make sure we aren't at the bottom.
    1292      468972 :       if (tropLev < pver) then
    1293      468972 :         dlogPdZ =  (log(pstate%pmid(icol, tropLev + 1)) - log(pstate%pmid(icol, tropLev))) / &
    1294      937944 :           (pstate%zm(icol, tropLev + 1) - pstate%zm(icol, tropLev))
    1295      468972 :         tropP = pstate%pmid(icol, tropLev) + exp((tropZ - pstate%zm(icol, tropLev)) * dlogPdZ)
    1296             :       end if
    1297             :     end if
    1298             :     
    1299      915634 :     tropopause_interpolateP = tropP
    1300      915634 :   end function tropopause_interpolateP
    1301             : 
    1302             :   
    1303             :   ! This routine interpolates the temperatures in the physics state to
    1304             :   ! find the temperature at the specified tropopause pressure.
    1305     1841751 :   function tropopause_interpolateT(pstate, icol, tropLev, tropP)
    1306             :  
    1307             :     implicit none
    1308             : 
    1309             :     type(physics_state), intent(in)     :: pstate 
    1310             :     integer, intent(in)                 :: icol               ! column being processed
    1311             :     integer, intent(in)                 :: tropLev            ! tropopause level index   
    1312             :     real(r8), optional, intent(in)      :: tropP              ! tropopause pressure (Pa)
    1313             :     real(r8)                            :: tropopause_interpolateT
    1314             :     
    1315             :     ! Local Variables
    1316             :     real(r8)   :: tropT              ! tropopause temperature (K)
    1317             :     real(r8)   :: dTdlogP            ! dT/dlog(P)
    1318             :     
    1319             :     ! Interpolate the temperature linearly against log(P)
    1320             :     
    1321             :     ! Is the tropopause at the midpoint?
    1322     1841751 :     if (tropP == pstate%pmid(icol, tropLev)) then
    1323           0 :       tropT = pstate%t(icol, tropLev)
    1324             :     
    1325     1841751 :     else if (tropP < pstate%pmid(icol, tropLev)) then
    1326             :     
    1327             :       ! It is above the midpoint? Make sure we aren't at the top.
    1328      887910 :       if (tropLev > 1) then
    1329      887910 :         dTdlogP = (pstate%t(icol, tropLev) - pstate%t(icol, tropLev - 1)) / & 
    1330     1775820 :           (log(pstate%pmid(icol, tropLev)) - log(pstate%pmid(icol, tropLev - 1)))
    1331      887910 :         tropT = pstate%t(icol, tropLev) + (log(tropP) - log(pstate%pmid(icol, tropLev))) * dTdlogP
    1332             :       end if
    1333             :     else
    1334             :       
    1335             :       ! It is below the midpoint. Make sure we aren't at the bottom.
    1336      953841 :       if (tropLev < pver) then
    1337      953841 :         dTdlogP = (pstate%t(icol, tropLev + 1) - pstate%t(icol, tropLev)) / &
    1338     1907682 :           (log(pstate%pmid(icol, tropLev + 1)) - log(pstate%pmid(icol, tropLev)))
    1339      953841 :         tropT = pstate%t(icol, tropLev) + (log(tropP) - log(pstate%pmid(icol, tropLev))) * dTdlogP
    1340             :       end if
    1341             :     end if
    1342             :     
    1343     1841751 :     tropopause_interpolateT = tropT
    1344     1841751 :   end function tropopause_interpolateT
    1345             : 
    1346             :   
    1347             :   ! This routine interpolates the geopotential height in the physics state to
    1348             :   ! find the geopotential height at the specified tropopause pressure.
    1349     1841751 :   function tropopause_interpolateZ(pstate, icol, tropLev, tropP)
    1350             :     use physconst, only: rga
    1351             : 
    1352             :     implicit none
    1353             : 
    1354             :     type(physics_state), intent(in)     :: pstate 
    1355             :     integer, intent(in)                 :: icol               ! column being processed
    1356             :     integer, intent(in)                 :: tropLev            ! tropopause level index   
    1357             :     real(r8), optional, intent(in)      :: tropP              ! tropopause pressure (Pa)
    1358             :     real(r8)                            :: tropopause_interpolateZ
    1359             :     
    1360             :     ! Local Variables
    1361             :     real(r8)   :: tropZ              ! tropopause geopotential height (m)
    1362             :     real(r8)   :: dZdlogP            ! dZ/dlog(P)
    1363             :     
    1364             :     ! Interpolate the geopotential height linearly against log(P)
    1365             :     
    1366             :     ! Is the tropoause at the midpoint?
    1367     1841751 :     if (tropP == pstate%pmid(icol, tropLev)) then
    1368           0 :       tropZ = pstate%zm(icol, tropLev)
    1369             :     
    1370     1841751 :     else if (tropP < pstate%pmid(icol, tropLev)) then
    1371             :     
    1372             :       ! It is above the midpoint? Make sure we aren't at the top.
    1373           0 :       dZdlogP = (pstate%zm(icol, tropLev) - pstate%zi(icol, tropLev)) / &
    1374      887910 :         (log(pstate%pmid(icol, tropLev)) - log(pstate%pint(icol, tropLev)))
    1375      887910 :       tropZ = pstate%zm(icol, tropLev) + (log(tropP) - log(pstate%pmid(icol, tropLev))) * dZdlogP
    1376             :     else
    1377             :       
    1378             :       ! It is below the midpoint. Make sure we aren't at the bottom.
    1379           0 :       dZdlogP = (pstate%zm(icol, tropLev) - pstate%zi(icol, tropLev+1)) / &
    1380      953841 :         (log(pstate%pmid(icol, tropLev)) - log(pstate%pint(icol, tropLev+1)))
    1381      953841 :       tropZ = pstate%zm(icol, tropLev) + (log(tropP) - log(pstate%pmid(icol, tropLev))) * dZdlogP
    1382             :     end if
    1383             :     
    1384     1841751 :     tropopause_interpolateZ = tropZ + pstate%phis(icol)*rga
    1385     1841751 :   end function tropopause_interpolateZ
    1386             : 
    1387             :   
    1388             :   ! Output the tropopause pressure and temperature to the history files. Two sets
    1389             :   ! of output will be generated, one for the default algorithm and another one
    1390             :   ! using the default routine, but backed by a climatology when the default
    1391             :   ! algorithm fails.
    1392       58824 :   subroutine tropopause_output(pstate)
    1393             :     use cam_history,  only : outfld
    1394             :     
    1395             :     implicit none
    1396             : 
    1397             :     type(physics_state), intent(in)     :: pstate
    1398             :   
    1399             :     ! Local Variables
    1400             :     integer       :: i
    1401             :     integer       :: alg
    1402             :     integer       :: ncol                     ! number of cloumns in the chunk
    1403             :     integer       :: lchnk                    ! chunk identifier
    1404             :     integer       :: tropLev(pcols)           ! tropopause level index   
    1405             :     real(r8)      :: tropP(pcols)             ! tropopause pressure (Pa)  
    1406             :     real(r8)      :: tropT(pcols)             ! tropopause temperature (K) 
    1407             :     real(r8)      :: tropZ(pcols)             ! tropopause height (m) 
    1408             :     real(r8)      :: tropFound(pcols)         ! tropopause found  
    1409             :     real(r8)      :: tropDZ(pcols, pver)      ! relative tropopause height (m) 
    1410             :     real(r8)      :: tropPdf(pcols, pver)     ! tropopause probability distribution  
    1411             : 
    1412             :     ! Information about the chunk.  
    1413       58824 :     lchnk = pstate%lchnk
    1414       58824 :     ncol  = pstate%ncol
    1415             : 
    1416             :     ! Find the tropopause using the default algorithm backed by the climatology.
    1417       58824 :     call tropopause_find(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ)
    1418             :     
    1419       58824 :     tropPdf(:,:) = 0._r8
    1420       58824 :     tropFound(:) = 0._r8
    1421    93059568 :     tropDZ(:,:) = fillvalue 
    1422      982224 :     do i = 1, ncol
    1423      982224 :       if (tropLev(i) /= NOTFOUND) then
    1424      923400 :         tropPdf(i, tropLev(i)) = 1._r8
    1425      923400 :         tropFound(i) = 1._r8
    1426    86799600 :         tropDZ(i,:) = pstate%zm(i,:) - tropZ(i) 
    1427             :       end if
    1428             :     end do
    1429             : 
    1430       58824 :     call outfld('TROP_P',   tropP(:ncol),      ncol, lchnk)
    1431       58824 :     call outfld('TROP_T',   tropT(:ncol),      ncol, lchnk)
    1432       58824 :     call outfld('TROP_Z',   tropZ(:ncol),      ncol, lchnk)
    1433    21474864 :     call outfld('TROP_DZ',  tropDZ(:ncol, :), ncol, lchnk)
    1434    21474864 :     call outfld('TROP_PD',  tropPdf(:ncol, :), ncol, lchnk)
    1435       58824 :     call outfld('TROP_FD',  tropFound(:ncol),  ncol, lchnk)
    1436             :     
    1437             :     
    1438             :     ! Find the tropopause using just the primary algorithm.
    1439       58824 :     call tropopause_find(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, backup=TROP_ALG_NONE)
    1440             : 
    1441       58824 :     tropPdf(:,:) = 0._r8
    1442       58824 :     tropFound(:) = 0._r8
    1443    93059568 :     tropDZ(:,:) = fillvalue 
    1444             :     
    1445      982224 :     do i = 1, ncol
    1446      982224 :       if (tropLev(i) /= NOTFOUND) then
    1447      918351 :         tropPdf(i, tropLev(i)) = 1._r8
    1448      918351 :         tropFound(i) = 1._r8
    1449    86324994 :         tropDZ(i,:) = pstate%zm(i,:) - tropZ(i) 
    1450             :       end if
    1451             :     end do
    1452             : 
    1453       58824 :     call outfld('TROPP_P',   tropP(:ncol),      ncol, lchnk)
    1454       58824 :     call outfld('TROPP_T',   tropT(:ncol),      ncol, lchnk)
    1455       58824 :     call outfld('TROPP_Z',   tropZ(:ncol),      ncol, lchnk)
    1456    21474864 :     call outfld('TROPP_DZ',  tropDZ(:ncol, :), ncol, lchnk)
    1457    21474864 :     call outfld('TROPP_PD',  tropPdf(:ncol, :), ncol, lchnk)
    1458       58824 :     call outfld('TROPP_FD',  tropFound(:ncol),  ncol, lchnk)
    1459             : 
    1460             : 
    1461             :     ! Find the tropopause using just the cold point algorithm.
    1462       58824 :     call tropopause_find(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=TROP_ALG_CPP, backup=TROP_ALG_NONE)
    1463             : 
    1464       58824 :     tropPdf(:,:) = 0._r8
    1465       58824 :     tropFound(:) = 0._r8
    1466    93059568 :     tropDZ(:,:) = fillvalue 
    1467             :     
    1468      982224 :     do i = 1, ncol
    1469      982224 :       if (tropLev(i) /= NOTFOUND) then
    1470      915634 :         tropPdf(i, tropLev(i)) = 1._r8
    1471      915634 :         tropFound(i) = 1._r8
    1472    86069596 :         tropDZ(i,:) = pstate%zm(i,:) - tropZ(i) 
    1473             :       end if
    1474             :     end do
    1475             : 
    1476       58824 :     call outfld('TROPF_P',   tropP(:ncol),      ncol, lchnk)
    1477       58824 :     call outfld('TROPF_T',   tropT(:ncol),      ncol, lchnk)
    1478       58824 :     call outfld('TROPF_Z',   tropZ(:ncol),      ncol, lchnk)
    1479    21474864 :     call outfld('TROPF_DZ',  tropDZ(:ncol, :), ncol, lchnk)
    1480    21474864 :     call outfld('TROPF_PD',  tropPdf(:ncol, :), ncol, lchnk)
    1481       58824 :     call outfld('TROPF_FD',  tropFound(:ncol),  ncol, lchnk)
    1482             :     
    1483             :     
    1484             :     ! If requested, do all of the algorithms.
    1485             :     if (output_all) then
    1486             :     
    1487             :       do alg = 2, TROP_NALG
    1488             :     
    1489             :         ! Find the tropopause using just the analytic algorithm.
    1490             :         call tropopause_find(pstate, tropLev, tropP=tropP, tropT=tropT, tropZ=tropZ, primary=alg, backup=TROP_ALG_NONE)
    1491             :   
    1492             :         tropPdf(:,:) = 0._r8
    1493             :         tropFound(:) = 0._r8
    1494             :       
    1495             :         do i = 1, ncol
    1496             :           if (tropLev(i) /= NOTFOUND) then
    1497             :             tropPdf(i, tropLev(i)) = 1._r8
    1498             :             tropFound(i) = 1._r8
    1499             :           end if
    1500             :         end do
    1501             :   
    1502             :         call outfld('TROP' // TROP_LETTER(alg) // '_P',   tropP(:ncol),      ncol, lchnk)
    1503             :         call outfld('TROP' // TROP_LETTER(alg) // '_T',   tropT(:ncol),      ncol, lchnk)
    1504             :         call outfld('TROP' // TROP_LETTER(alg) // '_Z',   tropZ(:ncol),      ncol, lchnk)
    1505             :         call outfld('TROP' // TROP_LETTER(alg) // '_PD',  tropPdf(:ncol, :), ncol, lchnk)
    1506             :         call outfld('TROP' // TROP_LETTER(alg) // '_FD',  tropFound(:ncol),  ncol, lchnk)
    1507             :       end do
    1508             :     end if
    1509             :     
    1510       58824 :     return
    1511       58824 :   end subroutine tropopause_output
    1512             : end module tropopause

Generated by: LCOV version 1.14