!***********************************************************************
!*                   GNU Lesser General Public License                 
!*
!* This file is part of the FV3 dynamical core.
!*
!* The FV3 dynamical core is free software: you can redistribute it 
!* and/or modify it under the terms of the
!* GNU Lesser General Public License as published by the
!* Free Software Foundation, either version 3 of the License, or 
!* (at your option) any later version.
!*
!* The FV3 dynamical core is distributed in the hope that it will be 
!* useful, but WITHOUT ANYWARRANTY; without even the implied warranty 
!* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
!* See the GNU General Public License for more details.
!*
!* You should have received a copy of the GNU Lesser General Public
!* License along with the FV3 dynamical core.  
!* If not, see <http://www.gnu.org/licenses/>.
!***********************************************************************

!>@ The module 'fv_diagnostics' contains routines to compute diagnosic fields.
module fv_diagnostics_mod

! <table>
! <tr>
!     <th>Module Name</th>
!     <th>Functions Included</th>
!   </tr>
!   <tr>
!     <td>a2b_edge_mod</td>
!     <td>a2b_ord2, a2b_ord4</td>
!   </tr>
!   <tr>
!     <td>constants_mod</td>
!     <td>grav, rdgas, rvgas, pi=>pi_8, radius, kappa, WTMAIR, WTMCO2,
!         omega, hlv, cp_air, cp_vapor</td>
!   </tr>
!   <tr>
!     <td>diag_manager_mod</td>
!     <td>diag_axis_init, register_diag_field,
!         register_static_field, send_data, diag_grid_init</td>
!   </tr>
!   <tr>
!     <td>field_manager_mod</td>
!     <td>MODEL_ATMOS</td>
!   </tr>
!   <tr>
!     <td>fms_mod</td>
!     <td>write_version_number</td>
!   </tr>
!   <tr>
!     <td>fms_io_mod</td>
!     <td>set_domain, nullify_domain, write_version_number</td>
!   </tr>
!   <tr>
!     <td>fv_arrays_mod</td>
!     <td>fv_atmos_type, fv_grid_type, fv_diag_type, fv_grid_bounds_type, 
!         R_GRIDmax_step</td>
!   </tr>
!   <tr>
!     <td>fv_eta_mod</td>
!     <td>get_eta_level, gw_1d</td>
!   </tr>
!   <tr>
!     <td>fv_grid_utils_mod</td>
!     <td> g_sum</td>
!   </tr>
!   <tr>
!     <td>fv_io_mod</td>
!     <td>fv_io_read_tracers</td>
!   </tr>
!   <tr>
!     <td>fv_mp_mod</td>
!     <td>mp_reduce_sum, mp_reduce_min, mp_reduce_max, is_master</td>
!   </tr>
!   <tr>
!     <td>fv_mapz_mod</td>
!     <td>E_Flux, moist_cv</td>
!   </tr>
!   <tr>
!     <td>fv_sg_mod</td>
!     <td>qsmith</td>
!   </tr>
!   <tr>
!     <td>fv_surf_map_mod</td>
!     <td>zs_g</td>
!   </tr>
!   <tr>
!     <td>fv_timing_mod</td>
!     <td>timing_on, timing_off</td>
!   </tr>
!   <tr>
!     <td>gfdl_cloud_microphys_mod</td>
!     <td>wqs1, qsmith_init</td>
!   </tr>
!   <tr>
!     <td>mpp_mod</td>
!     <td>mpp_error, FATAL, stdlog, mpp_pe, mpp_root_pe, mpp_sum, mpp_max, NOTE</td>
!   </tr>
!   <tr>
!     <td>mpp_domains_mod</td>
!     <td>domain2d, mpp_update_domains, DGRID_NE</td>
!   </tr>>
!   <tr>
!     <td>sat_vapor_pres_mod</td>
!     <td>compute_qs, lookup_es</td>
!   </tr>
!   <tr>
!     <td>time_manager_mod</td>
!     <td>time_type, get_date, get_time</td>
!   </tr>
!   <tr>
!     <td>tracer_manager_mod</td>
!     <td>get_tracer_names, get_number_tracers, get_tracer_index, set_tracer_profile</td>
!   </tr>
! </table>

 use constants_mod,      only: grav, rdgas, rvgas, pi=>pi_8, radius, kappa, WTMAIR, WTMCO2, &
                               omega, hlv, cp_air, cp_vapor
 use fms_mod,            only: write_version_number
 use fms_io_mod,         only: set_domain, nullify_domain, write_version_number
 use time_manager_mod,   only: time_type, get_date, get_time
 use mpp_domains_mod,    only: domain2d, mpp_update_domains, DGRID_NE
 use diag_manager_mod,   only: diag_axis_init, register_diag_field, &
                               register_static_field, send_data, diag_grid_init
 use fv_arrays_mod,      only: fv_atmos_type, fv_grid_type, fv_diag_type, fv_grid_bounds_type, & 
                               R_GRID
 !!! CLEANUP needs rem oval?
 use fv_mapz_mod,        only: E_Flux, moist_cv
 use fv_mp_mod,          only: mp_reduce_sum, mp_reduce_min, mp_reduce_max, is_master
 use fv_eta_mod,         only: get_eta_level, gw_1d
 use fv_grid_utils_mod,  only: g_sum
 use a2b_edge_mod,       only: a2b_ord2, a2b_ord4
 use fv_surf_map_mod,    only: zs_g
 use fv_sg_mod,          only: qsmith

 use tracer_manager_mod, only: get_tracer_names, get_number_tracers, get_tracer_index
 use field_manager_mod,  only: MODEL_ATMOS
 use mpp_mod,            only: mpp_error, FATAL, stdlog, mpp_pe, mpp_root_pe, mpp_sum, mpp_max, NOTE
 use sat_vapor_pres_mod, only: compute_qs, lookup_es

 use fv_arrays_mod, only: max_step 
#ifndef GFS_PHYS
 use gfdl_cloud_microphys_mod, only: wqs1, qsmith_init
#endif
#ifdef MULTI_GASES
 use multi_gases_mod,  only:  virq, virqd, vicpqd, vicvqd, num_gas
#endif

 implicit none
 private


 real, parameter:: missing_value = -1.e10
 real, parameter:: missing_value2 = -1.e3 !< for variables with many missing values
 real, parameter:: missing_value3 = 1.e10 !< for variables where we look for smallest values
 real :: ginv
 real :: pk0
 logical master
 character(len=3) :: gn = ''

! private (to this module) diag:

 type(time_type) :: fv_time
 type(fv_diag_type), pointer :: idiag

 logical :: module_is_initialized=.false.
 logical :: prt_minmax =.false.
 logical :: m_calendar
 integer  sphum, liq_wat, ice_wat, cld_amt    ! GFDL physics
 integer  rainwat, snowwat, graupel
 integer :: istep, mp_top
 real    :: ptop
 real, parameter    ::     rad2deg = 180./pi

! tracers
 character(len=128)   :: tname
 character(len=256)   :: tlongname, tunits
 real :: sphum_ll_fix = 0.
 real :: qcly0 ! initial value for terminator test

 public :: fv_diag_init, fv_time, fv_diag, prt_mxm, prt_maxmin, range_check!, id_divg, id_te
 public :: prt_mass, prt_minmax, ppme, fv_diag_init_gn, z_sum, sphum_ll_fix, eqv_pot, qcly0, gn
 public :: prt_height, prt_gb_nh_sh, interpolate_vertical, rh_calc, get_height_field, dbzcalc
 public :: max_vv,get_vorticity,max_uh 
 public :: max_vorticity,max_vorticity_hy1,bunkers_vector
 public :: helicity_relative_CAPS 

 integer, parameter :: nplev = 31
 integer :: levs(nplev)

! version number of this module
! Include variable "version" to be written to log file.
#include<file_version.h>

contains

 subroutine fv_diag_init(Atm, axes, Time, npx, npy, npz, p_ref)
    type(fv_atmos_type), intent(inout), target :: Atm(:)
    integer, intent(out) :: axes(4)
    type(time_type), intent(in) :: Time
    integer,         intent(in) :: npx, npy, npz
    real, intent(in):: p_ref

    real, allocatable :: grid_xt(:), grid_yt(:), grid_xe(:), grid_ye(:), grid_xn(:), grid_yn(:)
    real, allocatable :: grid_x(:),  grid_y(:)
    real              :: vrange(2), vsrange(2), wrange(2), trange(2), slprange(2), rhrange(2), skrange(2)
    real, allocatable :: a3(:,:,:)
    real              :: pfull(npz)
    real              :: hyam(npz), hybm(npz)

    !These id_* are not needed later since they are for static data which is not used elsewhere
    integer :: id_bk, id_pk, id_area, id_lon, id_lat, id_lont, id_latt, id_phalf, id_pfull
    integer :: id_hyam, id_hybm
    integer :: id_plev
    integer :: i, j, k, n, ntileMe, id_xt, id_yt, id_x, id_y, id_xe, id_ye, id_xn, id_yn
    integer :: isc, iec, jsc, jec
    logical :: used

    character(len=64) :: plev
    character(len=64) :: field
    integer              :: ntprog
    integer              :: unit

    integer :: ncnst
    integer :: axe2(3)


    call write_version_number ( 'FV_DIAGNOSTICS_MOD', version )
    idiag => Atm(1)%idiag

! For total energy diagnostics:
    idiag%steps = 0
    idiag%efx = 0.;       idiag%efx_sum = 0.
    idiag%mtq = 0.;       idiag%mtq_sum = 0.

    ncnst = Atm(1)%ncnst
    m_calendar = Atm(1)%flagstruct%moist_phys
    call set_domain(Atm(1)%domain)  ! Set domain so that diag_manager can access tile information

    sphum   = get_tracer_index (MODEL_ATMOS, 'sphum')
    liq_wat = get_tracer_index (MODEL_ATMOS, 'liq_wat')
    ice_wat = get_tracer_index (MODEL_ATMOS, 'ice_wat')

    rainwat = get_tracer_index (MODEL_ATMOS, 'rainwat')
    snowwat = get_tracer_index (MODEL_ATMOS, 'snowwat')
    graupel = get_tracer_index (MODEL_ATMOS, 'graupel')
    cld_amt = get_tracer_index (MODEL_ATMOS, 'cld_amt')

! valid range for some fields

!!!  This will need mods for more than 1 tile per pe  !!!

    vsrange = (/ -200.,  200. /)  ! surface (lowest layer) winds

    vrange = (/ -330.,  330. /)  ! winds
    wrange = (/ -100.,  100. /)  ! vertical wind
   rhrange = (/  -10.,  150. /)  ! RH
#ifdef HIWPP
    trange = (/    5.,  350. /)  ! temperature
#else
    trange = (/  100.,  350. /)  ! temperature
#endif
    slprange = (/800.,  1200./)  ! sea-level-pressure
    skrange  = (/ -10000000.0,  10000000.0 /)  ! dissipation estimate for SKEB

    ginv = 1./GRAV
     if (Atm(1)%grid_number == 1) fv_time = Time

    allocate ( idiag%phalf(npz+1) )
    call get_eta_level(Atm(1)%npz, p_ref, pfull, idiag%phalf, Atm(1)%ak, Atm(1)%bk, 0.01)

    mp_top = 1
    do k=1,npz
       if ( pfull(k) > 30.e2 ) then
            mp_top = k
            exit
       endif 
    enddo
    if ( is_master() ) write(*,*) 'mp_top=', mp_top, 'pfull=', pfull(mp_top)

!   allocate(grid_xt(npx-1), grid_yt(npy-1), grid_xe(npx), grid_ye(npy-1), grid_xn(npx-1), grid_yn(npy))
    allocate(grid_xt(npx-1), grid_yt(npy-1))
    grid_xt = (/ (i, i=1,npx-1) /)
    grid_yt = (/ (j, j=1,npy-1) /)
!   grid_xe = (/ (i, i=1,npx) /)
!   grid_ye = (/ (j, j=1,npy-1) /)
!   grid_xn = (/ (i, i=1,npx-1) /)
!   grid_yn = (/ (j, j=1,npy) /)

    allocate(grid_x(npx), grid_y(npy))
    grid_x = (/ (i, i=1,npx) /)
    grid_y = (/ (j, j=1,npy) /)

    n=1
    isc = Atm(n)%bd%isc; iec = Atm(n)%bd%iec
    jsc = Atm(n)%bd%jsc; jec = Atm(n)%bd%jec

    ! Send diag_manager the grid informtaion
    call diag_grid_init(DOMAIN=Atm(n)%domain, &
         &              GLO_LON=rad2deg*Atm(n)%gridstruct%grid(isc:iec+1,jsc:jec+1,1), &
         &              GLO_LAT=rad2deg*Atm(n)%gridstruct%grid(isc:iec+1,jsc:jec+1,2), &
         &              AGLO_LON=rad2deg*Atm(n)%gridstruct%agrid(isc-1:iec+1,jsc-1:jec+1,1), &
         &              AGLO_LAT=rad2deg*Atm(n)%gridstruct%agrid(isc-1:iec+1,jsc-1:jec+1,2))

    ntileMe = size(Atm(:))
    if (ntileMe > 1) call mpp_error(FATAL, "fv_diag_init can only be called with one grid at a time.")

!    do n = 1, ntileMe
    n = 1
       field = 'grid'

       id_xt = diag_axis_init('grid_xt',grid_xt,'degrees_E','x','T-cell longitude', &
                           set_name=trim(field),Domain2=Atm(n)%Domain, tile_count=n)
       id_yt = diag_axis_init('grid_yt',grid_yt,'degrees_N','y','T-cell latitude',  &
                           set_name=trim(field), Domain2=Atm(n)%Domain, tile_count=n)
!  Don't need these right now
!      id_xe = diag_axis_init ('grid_xe',grid_xe,'degrees_E','x','E-cell longitude', &
!                              set_name=trim(field),Domain2=Domain, tile_count=n)
!      id_ye = diag_axis_init ('grid_ye',grid_ye,'degrees_N','y','E-cell latitude',  &
!                              set_name=trim(field), Domain2=Domain, tile_count=n)
!      id_xn = diag_axis_init ('grid_xn',grid_xn,'degrees_E','x','N-cell longitude', &
!                              set_name=trim(field),Domain2=Domain, aux='geolon_n, geolat_n', tile_count=n)
!      id_yn = diag_axis_init ('grid_yn',grid_yn,'degrees_N','y','N-cell latitude',  &
!                              set_name=trim(field), Domain2=Domain, tile_count=n)

       id_x = diag_axis_init('grid_x',grid_x,'degrees_E','x','cell corner longitude', &
                           set_name=trim(field),Domain2=Atm(n)%Domain, tile_count=n)
       id_y = diag_axis_init('grid_y',grid_y,'degrees_N','y','cell corner latitude',  &
                           set_name=trim(field), Domain2=Atm(n)%Domain, tile_count=n)

!    end do
!   deallocate(grid_xt, grid_yt, grid_xe, grid_ye, grid_xn, grid_yn)
    deallocate(grid_xt, grid_yt)
    deallocate(grid_x,  grid_y )

    id_phalf = diag_axis_init('phalf', idiag%phalf, 'mb', 'z', &
            'ref half pressure level', direction=-1, set_name="dynamics")
    id_pfull = diag_axis_init('pfull', pfull, 'mb', 'z', &
            'ref full pressure level', direction=-1, set_name="dynamics", edges=id_phalf)

!---- register static fields -------

    id_bk    = register_static_field ( "dynamics", 'bk', (/id_phalf/), &
         'vertical coordinate sigma value', 'none' )

    id_pk    = register_static_field ( "dynamics", 'pk', (/id_phalf/), &
         'pressure part of the hybrid coordinate', 'pascal' )

    id_hyam    = register_static_field ( "dynamics", 'hyam', (/id_pfull/), &
         'vertical coordinate A value', '1E-5 Pa' )

    id_hybm    = register_static_field ( "dynamics", 'hybm', (/id_pfull/), &
         'vertical coordinate B value', 'none' )

!--- Send static data

    if ( id_bk > 0 )    used = send_data ( id_bk,Atm(1)%bk, Time )
    if ( id_pk > 0 )    used = send_data ( id_pk,Atm(1)%ak, Time )
    if ( id_hyam > 0 ) then
         do k=1,npz
            hyam(k) = 0.5 * ( Atm(1)%ak(k) + Atm(1)%ak(k+1) ) * 1.E-5
         enddo
         used = send_data ( id_hyam, hyam, Time )
    endif
    if ( id_hybm > 0 ) then
         do k=1,npz
            hybm(k) = 0.5 * ( Atm(1)%bk(k) + Atm(1)%bk(k+1) )
         enddo
         used = send_data ( id_hybm, hybm, Time )
    endif

!   Approach will need modification if we wish to write values on other than A grid.
    axes(1) = id_xt
    axes(2) = id_yt
    axes(3) = id_pfull
    axes(4) = id_phalf

! Selected pressure levels
! SJL note: 31 is enough here; if you need more levels you should do it OFF line
! do not add more to prevent the model from slowing down too much.
    levs = (/1,2,3,5,7,10,20,30,50,70,100,150,200,250,300,350,400,450,500,550,600,650,700,750,800,850,900,925,950,975,1000/)

    id_plev = diag_axis_init('plev', levs(:)*1.0, 'mb', 'z', &
            'actual pressure level', direction=-1, set_name="dynamics")

    axe2(1) = id_xt
    axe2(2) = id_yt
    axe2(3) = id_plev

!---- register time independent fields -------

!    do n = 1, ntileMe
    n = 1
       field= 'dynamics'
       id_lon  = register_static_field ( trim(field), 'grid_lon', (/id_x,id_y/),  &
                                         'longitude', 'degrees_E' )
       id_lat  = register_static_field ( trim(field), 'grid_lat', (/id_x,id_y/),  &
                                         'latitude', 'degrees_N' )
       id_lont = register_static_field ( trim(field), 'grid_lont', (/id_xt,id_yt/),  &
                                         'longitude', 'degrees_E' )
       id_latt = register_static_field ( trim(field), 'grid_latt', (/id_xt,id_yt/),  &
                                         'latitude', 'degrees_N' )
       id_area = register_static_field ( trim(field), 'area', axes(1:2),  &
                                         'cell area', 'm**2' )
#ifndef DYNAMICS_ZS
       idiag%id_zsurf = register_static_field ( trim(field), 'zsurf', axes(1:2),  &
                                         'surface height', 'm' )
#endif
       idiag%id_zs = register_static_field ( trim(field), 'zs', axes(1:2),  &
                                        'Original Mean Terrain', 'm' )
! 3D hybrid_z fields:
       idiag%id_ze = register_static_field ( trim(field), 'ze', axes(1:3),  &
                                        'Hybrid_Z_surface', 'm' )
       idiag%id_oro = register_static_field ( trim(field), 'oro', axes(1:2),  &
                                        'Land/Water Mask', 'none' )
       idiag%id_sgh = register_static_field ( trim(field), 'sgh', axes(1:2),  &
                                        'Terrain Standard deviation', 'm' )
!       idiag%id_ts = register_static_field ( trim(field), 'ts', axes(1:2),  &
!                                        'Skin temperature', 'K' )

!--------------------
! Initial conditions:
!--------------------
       idiag%ic_ps  = register_static_field ( trim(field), 'ps_ic', axes(1:2),  &
                                         'initial surface pressure', 'Pa' )
       idiag%ic_ua = register_static_field ( trim(field), 'ua_ic', axes(1:3),        &
            'zonal wind', 'm/sec' )
       idiag%ic_va = register_static_field ( trim(field), 'va_ic', axes(1:3),        &
            'meridional wind', 'm/sec' )
       idiag%ic_ppt= register_static_field ( trim(field), 'ppt_ic', axes(1:3),        &
            'potential temperature perturbation', 'K' )
       idiag%ic_sphum  = register_static_field ( trim(field), 'sphum_ic', axes(1:2),  &
                                         'initial surface pressure', 'Pa' )

!    end do

    master = (mpp_pe()==mpp_root_pe())

    n=1
    isc = Atm(n)%bd%isc; iec = Atm(n)%bd%iec
    jsc = Atm(n)%bd%jsc; jec = Atm(n)%bd%jec

    allocate ( idiag%zsurf(isc:iec,jsc:jec) )

    do j=jsc,jec
       do i=isc,iec
          idiag%zsurf(i,j) = ginv * Atm(n)%phis(i,j)
       enddo
    enddo

!--- Send time independent data

!    do n = 1, ntileMe
    n = 1
       isc = Atm(n)%bd%isc; iec = Atm(n)%bd%iec
       jsc = Atm(n)%bd%jsc; jec = Atm(n)%bd%jec
       if (id_lon  > 0) used = send_data(id_lon,  rad2deg*Atm(n)%gridstruct%grid(isc:iec+1,jsc:jec+1,1), Time)
       if (id_lat  > 0) used = send_data(id_lat,  rad2deg*Atm(n)%gridstruct%grid(isc:iec+1,jsc:jec+1,2), Time)
       if (id_lont > 0) used = send_data(id_lont, rad2deg*Atm(n)%gridstruct%agrid(isc:iec,jsc:jec,1), Time)
       if (id_latt > 0) used = send_data(id_latt, rad2deg*Atm(n)%gridstruct%agrid(isc:iec,jsc:jec,2), Time)
       if (id_area > 0) used = send_data(id_area, Atm(n)%gridstruct%area(isc:iec,jsc:jec), Time)
#ifndef DYNAMICS_ZS
       if (idiag%id_zsurf > 0) used = send_data(idiag%id_zsurf, idiag%zsurf, Time)
#endif
       if ( Atm(n)%flagstruct%fv_land ) then
         if (idiag%id_zs  > 0) used = send_data(idiag%id_zs , zs_g, Time)
         if (idiag%id_oro > 0) used = send_data(idiag%id_oro, Atm(n)%oro(isc:iec,jsc:jec), Time)
         if (idiag%id_sgh > 0) used = send_data(idiag%id_sgh, Atm(n)%sgh(isc:iec,jsc:jec), Time)
       endif

       if ( Atm(n)%flagstruct%ncep_ic ) then
         if (idiag%id_ts > 0) used = send_data(idiag%id_ts, Atm(n)%ts(isc:iec,jsc:jec), Time)
       endif

       if ( Atm(n)%flagstruct%hybrid_z .and. idiag%id_ze > 0 ) &
                      used = send_data(idiag%id_ze, Atm(n)%ze0(isc:iec,jsc:jec,1:npz), Time)

       if (idiag%ic_ps > 0) used = send_data(idiag%ic_ps, Atm(n)%ps(isc:iec,jsc:jec)*ginv, Time)

       if(idiag%ic_ua > 0) used=send_data(idiag%ic_ua, Atm(n)%ua(isc:iec,jsc:jec,:), Time)
       if(idiag%ic_va > 0) used=send_data(idiag%ic_va, Atm(n)%va(isc:iec,jsc:jec,:), Time)

       pk0 = 1000.E2 ** kappa
       if(idiag%ic_ppt> 0) then
! Potential temperature
          allocate ( idiag%pt1(npz) )
          allocate ( a3(isc:iec,jsc:jec,npz) )
#ifdef TEST_GWAVES
          call gw_1d(npz, 1000.E2, Atm(n)%ak, Atm(n)%ak, Atm(n)%ak(1), 10.E3, idiag%pt1)
#else
          idiag%pt1 = 0.
#endif
          do k=1,npz
          do j=jsc,jec
             do i=isc,iec
                a3(i,j,k) =  (Atm(n)%pt(i,j,k)/Atm(n)%pkz(i,j,k) - idiag%pt1(k)) * pk0
             enddo
          enddo
          enddo
          used=send_data(idiag%ic_ppt, a3, Time)
          deallocate ( a3 )
          deallocate ( idiag%pt1 )
       endif
!    end do

!--------------------------------------------------------------
! Register main prognostic fields: ps, (u,v), t, omega (dp/dt)
!--------------------------------------------------------------

    allocate(idiag%id_tracer(ncnst))
    allocate(idiag%id_tracer_dmmr(ncnst))
    allocate(idiag%id_tracer_dvmr(ncnst))
    allocate(idiag%w_mr(ncnst))
    idiag%id_tracer(:)      = 0
    idiag%id_tracer_dmmr(:) = 0 
    idiag%id_tracer_dvmr(:) = 0 
    idiag%w_mr(:) = 0.E0

    allocate(idiag%id_u(nplev))
    allocate(idiag%id_v(nplev))
    allocate(idiag%id_t(nplev))
    allocate(idiag%id_h(nplev))
    allocate(idiag%id_q(nplev))
    allocate(idiag%id_omg(nplev))
    idiag%id_u(:)   = 0
    idiag%id_v(:)   = 0
    idiag%id_t(:)   = 0
    idiag%id_h(:)   = 0
    idiag%id_q(:)   = 0
    idiag%id_omg(:) = 0

!    do n = 1, ntileMe
    n = 1
       field= 'dynamics'

#ifdef DYNAMICS_ZS
       idiag%id_zsurf = register_diag_field ( trim(field), 'zsurf', axes(1:2), Time,           &
                                       'surface height', 'm')
#endif
!-------------------
! Surface pressure
!-------------------
       idiag%id_ps = register_diag_field ( trim(field), 'ps', axes(1:2), Time,           &
            'surface pressure', 'Pa', missing_value=missing_value )

!-------------------
! Mountain torque
!-------------------
       idiag%id_mq = register_diag_field ( trim(field), 'mq', axes(1:2), Time,           &
            'mountain torque', 'Hadleys per unit area', missing_value=missing_value )
!-------------------
! Angular momentum
!-------------------
       idiag%id_aam = register_diag_field ( trim(field), 'aam', axes(1:2), Time,           &
            'angular momentum', 'kg*m^2/s', missing_value=missing_value )
       idiag%id_amdt = register_diag_field ( trim(field), 'amdt', axes(1:2), Time,           &
            'angular momentum error', 'kg*m^2/s^2', missing_value=missing_value )

!
      do i=1,nplev
        write(plev,'(I5)') levs(i)
! Height:
        idiag%id_h(i)   = register_diag_field(trim(field), 'z'//trim(adjustl(plev)), axes(1:2), Time, &
                                    trim(adjustl(plev))//'-mb height', 'm', missing_value=missing_value)
! u-wind:
        idiag%id_u(i)   = register_diag_field(trim(field), 'u'//trim(adjustl(plev)), axes(1:2), Time, &
                                    trim(adjustl(plev))//'-mb u', 'm/s', missing_value=missing_value)
! v-wind:
        idiag%id_v(i)   = register_diag_field(trim(field), 'v'//trim(adjustl(plev)), axes(1:2), Time, &
                                    trim(adjustl(plev))//'-mb v', 'm/s', missing_value=missing_value)
! Temperature (K):
        idiag%id_t(i)   = register_diag_field(trim(field), 't'//trim(adjustl(plev)), axes(1:2), Time, &
                                    trim(adjustl(plev))//'-mb temperature', 'K', missing_value=missing_value)
! specific humidity:
        idiag%id_q(i)   = register_diag_field(trim(field), 'q'//trim(adjustl(plev)), axes(1:2), Time, &
                                    trim(adjustl(plev))//'-mb specific humidity', 'kg/kg', missing_value=missing_value)
! Omega (Pa/sec)
        idiag%id_omg(i) = register_diag_field(trim(field), 'omg'//trim(adjustl(plev)), axes(1:2), Time, &
                                    trim(adjustl(plev))//'-mb omega', 'Pa/s', missing_value=missing_value)
      enddo

      idiag%id_u_plev = register_diag_field ( trim(field), 'u_plev', axe2(1:3), Time,        &
           'zonal wind', 'm/sec', missing_value=missing_value, range=vrange )
      idiag%id_v_plev = register_diag_field ( trim(field), 'v_plev', axe2(1:3), Time,        &
           'meridional wind', 'm/sec', missing_value=missing_value, range=vrange )
      idiag%id_t_plev = register_diag_field ( trim(field), 't_plev', axe2(1:3), Time,        &
           'temperature', 'K', missing_value=missing_value, range=trange )
      idiag%id_h_plev = register_diag_field ( trim(field), 'h_plev', axe2(1:3), Time,        &
           'height', 'm', missing_value=missing_value )
      idiag%id_q_plev = register_diag_field ( trim(field), 'q_plev', axe2(1:3), Time,        &
           'specific humidity', 'kg/kg', missing_value=missing_value )
      idiag%id_omg_plev = register_diag_field ( trim(field), 'omg_plev', axe2(1:3), Time,        &
           'omega', 'Pa/s', missing_value=missing_value )

      ! flag for calculation of geopotential
      if ( all(idiag%id_h(minloc(abs(levs-10)))>0)  .or. all(idiag%id_h(minloc(abs(levs-50)))>0)  .or. &
           all(idiag%id_h(minloc(abs(levs-100)))>0) .or. all(idiag%id_h(minloc(abs(levs-200)))>0) .or. &
           all(idiag%id_h(minloc(abs(levs-250)))>0) .or. all(idiag%id_h(minloc(abs(levs-300)))>0) .or. &
           all(idiag%id_h(minloc(abs(levs-500)))>0) .or. all(idiag%id_h(minloc(abs(levs-700)))>0) .or. &
           all(idiag%id_h(minloc(abs(levs-850)))>0) .or. all(idiag%id_h(minloc(abs(levs-1000)))>0) ) then
           idiag%id_hght = 1
      else
           idiag%id_hght = 0
      endif
!-----------------------------
! mean temp between 300-500 mb
!-----------------------------
      idiag%id_tm = register_diag_field (trim(field), 'tm', axes(1:2),  Time,   &
                                   'mean 300-500 mb temp', 'K', missing_value=missing_value )

!-------------------
! Sea-level-pressure
!-------------------
       idiag%id_slp = register_diag_field (trim(field), 'slp', axes(1:2),  Time,   &
                                     'sea-level pressure', 'mb', missing_value=missing_value,  &
                                      range=slprange )
!----------------------------------
! Bottom level pressure for masking
!----------------------------------
       idiag%id_pmask = register_diag_field (trim(field), 'pmask', axes(1:2),  Time,   &
                                     'masking pressure at lowest level', 'mb',   &
                                      missing_value=missing_value )
!------------------------------------------
! Fix for Bottom level pressure for masking
!------------------------------------------
       idiag%id_pmaskv2 = register_diag_field(TRIM(field), 'pmaskv2', axes(1:2), Time,&
            & 'masking pressure at lowest level', 'mb', missing_value=missing_value)
                                     
!-------------------
! Hurricane scales:
!-------------------
! Net effects: ~ intensity * freq
       idiag%id_c15 = register_diag_field (trim(field), 'cat15', axes(1:2),  Time,   &
                                     'de-pression < 1000', 'mb', missing_value=missing_value)
       idiag%id_c25 = register_diag_field (trim(field), 'cat25', axes(1:2),  Time,   &
                                     'de-pression < 980', 'mb', missing_value=missing_value)
       idiag%id_c35 = register_diag_field (trim(field), 'cat35', axes(1:2),  Time,   &
                                     'de-pression < 964', 'mb', missing_value=missing_value)
       idiag%id_c45 = register_diag_field (trim(field), 'cat45', axes(1:2),  Time,   &
                                     'de-pression < 944', 'mb', missing_value=missing_value)
! Frequency:
       idiag%id_f15 = register_diag_field (trim(field), 'f15', axes(1:2),  Time,   &
                                     'Cat15 frequency', 'none', missing_value=missing_value)
       idiag%id_f25 = register_diag_field (trim(field), 'f25', axes(1:2),  Time,   &
                                     'Cat25 frequency', 'none', missing_value=missing_value)
       idiag%id_f35 = register_diag_field (trim(field), 'f35', axes(1:2),  Time,   &
                                     'Cat35 frequency', 'none', missing_value=missing_value)
       idiag%id_f45 = register_diag_field (trim(field), 'f45', axes(1:2),  Time,   &
                                     'Cat45 frequency', 'none', missing_value=missing_value)
!-------------------
! A grid winds (lat-lon)
!-------------------
       if (Atm(n)%flagstruct%write_3d_diags) then
          idiag%id_ua = register_diag_field ( trim(field), 'ucomp', axes(1:3), Time,        &
               'zonal wind', 'm/sec', missing_value=missing_value, range=vrange )
          idiag%id_va = register_diag_field ( trim(field), 'vcomp', axes(1:3), Time,        &
               'meridional wind', 'm/sec', missing_value=missing_value, range=vrange)
          if ( .not. Atm(n)%flagstruct%hydrostatic )                                        &
               idiag%id_w = register_diag_field ( trim(field), 'w', axes(1:3), Time,        &
               'vertical wind', 'm/sec', missing_value=missing_value, range=wrange )

          idiag%id_pt   = register_diag_field ( trim(field), 'temp', axes(1:3), Time,       &
               'temperature', 'K', missing_value=missing_value, range=trange )
          idiag%id_ppt  = register_diag_field ( trim(field), 'ppt', axes(1:3), Time,       &
               'potential temperature perturbation', 'K', missing_value=missing_value )
          idiag%id_theta_e = register_diag_field ( trim(field), 'theta_e', axes(1:3), Time,       &
               'theta_e', 'K', missing_value=missing_value )
          idiag%id_omga = register_diag_field ( trim(field), 'omega', axes(1:3), Time,      &
               'omega', 'Pa/s', missing_value=missing_value )
          idiag%id_divg  = register_diag_field ( trim(field), 'divg', axes(1:3), Time,      &
               'mean divergence', '1/s', missing_value=missing_value )
          ! diagnotic output for skeb testing
          idiag%id_diss = register_diag_field ( trim(field), 'diss_est', axes(1:3), Time,    &
               'random', 'none', missing_value=missing_value, range=skrange )

          idiag%id_rh = register_diag_field ( trim(field), 'rh', axes(1:3), Time,        &
               'Relative Humidity', '%', missing_value=missing_value )
          !            'Relative Humidity', '%', missing_value=missing_value, range=rhrange )
          idiag%id_delp = register_diag_field ( trim(field), 'delp', axes(1:3), Time,        &
               'pressure thickness', 'pa', missing_value=missing_value )
          if ( .not. Atm(n)%flagstruct%hydrostatic )                                        &
               idiag%id_delz = register_diag_field ( trim(field), 'delz', axes(1:3), Time,        &
               'height thickness', 'm', missing_value=missing_value )
          if( Atm(n)%flagstruct%hydrostatic ) then 
             idiag%id_pfhy = register_diag_field ( trim(field), 'pfhy', axes(1:3), Time,        &
                  'hydrostatic pressure', 'pa', missing_value=missing_value )
          else
             idiag%id_pfnh = register_diag_field ( trim(field), 'pfnh', axes(1:3), Time,        &
                  'non-hydrostatic pressure', 'pa', missing_value=missing_value )
          endif
          idiag%id_zratio = register_diag_field ( trim(field), 'zratio', axes(1:3), Time,        &
               'nonhydro_ratio', 'n/a', missing_value=missing_value )
          !--------------------
          ! 3D Condensate
          !--------------------
          idiag%id_qn = register_diag_field ( trim(field), 'qn', axes(1:3), Time,       &
               'cloud condensate', 'kg/m/s^2', missing_value=missing_value )
          idiag%id_qp = register_diag_field ( trim(field), 'qp', axes(1:3), Time,       &
               'precip condensate', 'kg/m/s^2', missing_value=missing_value )
          ! fast moist phys tendencies:
          idiag%id_mdt = register_diag_field ( trim(field), 'mdt', axes(1:3), Time,       &
               'DT/Dt: fast moist phys', 'deg/sec', missing_value=missing_value )
          idiag%id_qdt = register_diag_field ( trim(field), 'qdt', axes(1:3), Time,       &
               'Dqv/Dt: fast moist phys', 'kg/kg/sec', missing_value=missing_value )
          idiag%id_dbz = register_diag_field ( trim(field), 'reflectivity', axes(1:3), time, &
               'Stoelinga simulated reflectivity', 'dBz', missing_value=missing_value)

          !--------------------
          ! Relative vorticity
          !--------------------
          idiag%id_vort = register_diag_field ( trim(field), 'vort', axes(1:3), Time,       &
               'vorticity', '1/s', missing_value=missing_value )
          !--------------------
          ! Potential vorticity
          !--------------------
          idiag%id_pv = register_diag_field ( trim(field), 'pv', axes(1:3), Time,       &
               'potential vorticity', '1/s', missing_value=missing_value )

       endif

! Total energy (only when moist_phys = .T.)
       idiag%id_te    = register_diag_field ( trim(field), 'te', axes(1:2), Time,      &
            'Total Energy', 'J/kg', missing_value=missing_value )
! Total Kinetic energy
       idiag%id_ke    = register_diag_field ( trim(field), 'ke', axes(1:2), Time,      &
            'Total KE', 'm^2/s^2', missing_value=missing_value )
       idiag%id_ws     = register_diag_field ( trim(field), 'ws', axes(1:2), Time,        &
            'Terrain W', 'm/s', missing_value=missing_value )
       idiag%id_maxdbz = register_diag_field ( trim(field), 'max_reflectivity', axes(1:2), time, &
                'Stoelinga simulated maximum (composite) reflectivity', 'dBz', missing_value=missing_value)
       idiag%id_basedbz = register_diag_field ( trim(field), 'base_reflectivity', axes(1:2), time, &
                'Stoelinga simulated base (1 km AGL) reflectivity', 'dBz', missing_value=missing_value)
       idiag%id_dbz4km = register_diag_field ( trim(field), '4km_reflectivity', axes(1:2), time, &
                'Stoelinga simulated base reflectivity', 'dBz', missing_value=missing_value)
       idiag%id_dbztop = register_diag_field ( trim(field), 'echo_top', axes(1:2), time, &
                'Echo top ( <= 18.5 dBz )', 'm', missing_value=missing_value2)
       idiag%id_dbz_m10C = register_diag_field ( trim(field), 'm10C_reflectivity', axes(1:2), time, &
                'Reflectivity at -10C level', 'm', missing_value=missing_value)

!--------------------------
! Extra surface diagnistics:
!--------------------------
! Surface (lowest layer) vorticity: for tropical cyclones diag.
       idiag%id_vorts = register_diag_field ( trim(field), 'vorts', axes(1:2), Time,       &
            'surface vorticity', '1/s', missing_value=missing_value )
       idiag%id_us = register_diag_field ( trim(field), 'us', axes(1:2), Time,        &
            'surface u-wind', 'm/sec', missing_value=missing_value, range=vsrange )
       idiag%id_vs = register_diag_field ( trim(field), 'vs', axes(1:2), Time,        &
            'surface v-wind', 'm/sec', missing_value=missing_value, range=vsrange )
       idiag%id_tq = register_diag_field ( trim(field), 'tq', axes(1:2), Time,        &
            'Total water path', 'kg/m**2', missing_value=missing_value )
       idiag%id_iw = register_diag_field ( trim(field), 'iw', axes(1:2), Time,        &
            'Ice water path', 'kg/m**2', missing_value=missing_value )
       idiag%id_lw = register_diag_field ( trim(field), 'lw', axes(1:2), Time,        &
            'Liquid water path', 'kg/m**2', missing_value=missing_value )
       idiag%id_ts = register_diag_field ( trim(field), 'ts', axes(1:2), Time,  &
                                        'Skin temperature', 'K' )
       idiag%id_tb = register_diag_field ( trim(field), 'tb', axes(1:2), Time,  &
                                        'lowest layer temperature', 'K' )
       idiag%id_ctt = register_diag_field( trim(field), 'ctt', axes(1:2), Time,  &
                                        'cloud_top temperature', 'K', missing_value=missing_value3 )
       idiag%id_ctp = register_diag_field( trim(field), 'ctp', axes(1:2), Time,  &
                                        'cloud_top pressure', 'hPa' , missing_value=missing_value3 )
       idiag%id_ctz = register_diag_field( trim(field), 'ctz', axes(1:2), Time,  &
                                        'cloud_top height', 'hPa' , missing_value=missing_value2 )
       idiag%id_cape = register_diag_field( trim(field), 'cape', axes(1:2), Time,  &
                                        'Convective available potential energy (surface-based)', 'J/kg' , missing_value=missing_value )
       idiag%id_cin = register_diag_field( trim(field), 'cin', axes(1:2), Time,  &
                                        'Convective inhibition (surface-based)', 'J/kg' , missing_value=missing_value )
#ifdef HIWPP
       idiag%id_acl = register_diag_field ( trim(field), 'acl', axes(1:2), Time,        &
            'Column-averaged Cl mixing ratio', 'kg/kg', missing_value=missing_value )
       idiag%id_acl2 = register_diag_field ( trim(field), 'acl2', axes(1:2), Time,        &
            'Column-averaged Cl2 mixing ratio', 'kg/kg', missing_value=missing_value )
       idiag%id_acly = register_diag_field ( trim(field), 'acly', axes(1:2), Time,        &
            'Column-averaged total chlorine mixing ratio', 'kg/kg', missing_value=missing_value )
#endif

!--------------------------
! 850-mb vorticity
!--------------------------
       idiag%id_vort850 = register_diag_field ( trim(field), 'vort850', axes(1:2), Time,       &
                           '850-mb vorticity', '1/s', missing_value=missing_value )

       idiag%id_vort200 = register_diag_field ( trim(field), 'vort200', axes(1:2), Time,       &
                           '200-mb vorticity', '1/s', missing_value=missing_value )

! Cubed_2_latlon interpolation is more accurate, particularly near the poles, using
! winds speed (a scalar), rather than wind vectors or kinetic energy directly.
       idiag%id_s200 = register_diag_field ( trim(field), 's200', axes(1:2), Time,       &
                           '200-mb wind_speed', 'm/s', missing_value=missing_value )
       idiag%id_sl12 = register_diag_field ( trim(field), 'sl12', axes(1:2), Time,       &
                           '12th L wind_speed', 'm/s', missing_value=missing_value )
       idiag%id_sl13 = register_diag_field ( trim(field), 'sl13', axes(1:2), Time,       &
                           '13th L wind_speed', 'm/s', missing_value=missing_value )
! Selceted (HIWPP) levels of non-precip condensates:
       idiag%id_qn200 = register_diag_field ( trim(field), 'qn200', axes(1:2), Time,       &
               '200mb condensate', 'kg/m/s^2', missing_value=missing_value )
       idiag%id_qn500 = register_diag_field ( trim(field), 'qn500', axes(1:2), Time,       &
               '500mb condensate', 'kg/m/s^2', missing_value=missing_value )
       idiag%id_qn850 = register_diag_field ( trim(field), 'qn850', axes(1:2), Time,       &
               '850mb condensate', 'kg/m/s^2', missing_value=missing_value )

       idiag%id_vort500 = register_diag_field ( trim(field), 'vort500', axes(1:2), Time,       &
                           '500-mb vorticity', '1/s', missing_value=missing_value )

       idiag%id_rain5km = register_diag_field ( trim(field), 'rain5km', axes(1:2), Time,       &
                           '5-km AGL liquid water', 'kg/kg', missing_value=missing_value )
!--------------------------
! w on height or pressure levels
!--------------------------
       if( .not. Atm(n)%flagstruct%hydrostatic ) then
          idiag%id_w200 = register_diag_field ( trim(field), 'w200', axes(1:2), Time,       &
                              '200-mb w-wind', 'm/s', missing_value=missing_value )
          idiag%id_w500 = register_diag_field ( trim(field), 'w500', axes(1:2), Time,       &
                              '500-mb w-wind', 'm/s', missing_value=missing_value )
          idiag%id_w700 = register_diag_field ( trim(field), 'w700', axes(1:2), Time,       &
                              '700-mb w-wind', 'm/s', missing_value=missing_value )

          idiag%id_w850 = register_diag_field ( trim(field), 'w850', axes(1:2), Time,       &
                           '850-mb w-wind', 'm/s', missing_value=missing_value )
          idiag%id_w5km = register_diag_field ( trim(field), 'w5km', axes(1:2), Time,       &
                           '5-km AGL w-wind', 'm/s', missing_value=missing_value )
          idiag%id_w2500m = register_diag_field ( trim(field), 'w2500m', axes(1:2), Time,       &
                           '2.5-km AGL w-wind', 'm/s', missing_value=missing_value )
          idiag%id_w1km = register_diag_field ( trim(field), 'w1km', axes(1:2), Time,       &
                           '1-km AGL w-wind', 'm/s', missing_value=missing_value )
          idiag%id_wmaxup = register_diag_field ( trim(field), 'wmaxup', axes(1:2), Time,       &
                           'column-maximum updraft', 'm/s', missing_value=missing_value )
          idiag%id_wmaxdn = register_diag_field ( trim(field), 'wmaxdn', axes(1:2), Time,       &
                           'column-maximum downdraft', 'm/s', missing_value=missing_value )

       endif

! helicity
       idiag%id_x850 = register_diag_field ( trim(field), 'x850', axes(1:2), Time,       &
                           '850-mb vertical comp. of helicity', 'm/s**2', missing_value=missing_value )
!       idiag%id_x03 = register_diag_field ( trim(field), 'x03', axes(1:2), Time,       &
!                           '0-3 km vertical comp. of helicity', 'm**2/s**2', missing_value=missing_value )
!       idiag%id_x25 = register_diag_field ( trim(field), 'x25', axes(1:2), Time,       &
!                           '2-5 km vertical comp. of helicity', 'm**2/s**2', missing_value=missing_value )

! Storm Relative Helicity
       idiag%id_srh1 = register_diag_field ( trim(field), 'srh01', axes(1:2), Time,       &
                           '0-1 km Storm Relative Helicity', 'm/s**2', missing_value=missing_value )
       idiag%id_srh3 = register_diag_field ( trim(field), 'srh03', axes(1:2), Time,       &
                           '0-3 km Storm Relative Helicity', 'm/s**2', missing_value=missing_value )
       idiag%id_ustm = register_diag_field ( trim(field), 'ustm', axes(1:2), Time,       &
                           'u Component of Storm Motion', 'm/s', missing_value=missing_value )
       idiag%id_vstm = register_diag_field ( trim(field), 'vstm', axes(1:2), Time,       &
                           'v Component of Storm Motion', 'm/s', missing_value=missing_value )

       idiag%id_srh25 = register_diag_field ( trim(field), 'srh25', axes(1:2), Time,       &
                           '2-5 km Storm Relative Helicity', 'm/s**2', missing_value=missing_value )
       
       if( .not. Atm(n)%flagstruct%hydrostatic ) then
          idiag%id_uh03 = register_diag_field ( trim(field), 'uh03', axes(1:2), Time,       &
                           '0-3 km Updraft Helicity', 'm/s**2', missing_value=missing_value )
          idiag%id_uh25 = register_diag_field ( trim(field), 'uh25', axes(1:2), Time,       &
                           '2-5 km Updraft Helicity', 'm/s**2', missing_value=missing_value )
       endif
! TC test winds at 100 m
       if( .not. Atm(n)%flagstruct%hydrostatic )                                          &
       idiag%id_w100m = register_diag_field ( trim(field), 'w100m', axes(1:2), Time,       &
                        '100-m AGL w-wind', 'm/s', missing_value=missing_value )
       idiag%id_u100m = register_diag_field ( trim(field), 'u100m', axes(1:2), Time,       &
                        '100-m AGL u-wind', 'm/s', missing_value=missing_value )
       idiag%id_v100m = register_diag_field ( trim(field), 'v100m', axes(1:2), Time,       &
                        '100-m AGL v-wind', 'm/s', missing_value=missing_value )
!--------------------------
! relative humidity (physics definition):
!--------------------------
       idiag%id_rh10 = register_diag_field ( trim(field), 'rh10', axes(1:2), Time,       &
                           '10-mb relative humidity', '%', missing_value=missing_value )
       idiag%id_rh50 = register_diag_field ( trim(field), 'rh50', axes(1:2), Time,       &
                           '50-mb relative humidity', '%', missing_value=missing_value )
       idiag%id_rh100 = register_diag_field ( trim(field), 'rh100', axes(1:2), Time,       &
                           '100-mb relative humidity', '%', missing_value=missing_value )
       idiag%id_rh200 = register_diag_field ( trim(field), 'rh200', axes(1:2), Time,       &
                           '200-mb relative humidity', '%', missing_value=missing_value )
       idiag%id_rh250 = register_diag_field ( trim(field), 'rh250', axes(1:2), Time,       &
                           '250-mb relative humidity', '%', missing_value=missing_value )
       idiag%id_rh300 = register_diag_field ( trim(field), 'rh300', axes(1:2), Time,       &
                           '300-mb relative humidity', '%', missing_value=missing_value )
       idiag%id_rh500 = register_diag_field ( trim(field), 'rh500', axes(1:2), Time,       &
                           '500-mb relative humidity', '%', missing_value=missing_value )
       idiag%id_rh700 = register_diag_field ( trim(field), 'rh700', axes(1:2), Time,       &
                           '700-mb relative humidity', '%', missing_value=missing_value )
       idiag%id_rh850 = register_diag_field ( trim(field), 'rh850', axes(1:2), Time,       &
                           '850-mb relative humidity', '%', missing_value=missing_value )
       idiag%id_rh925 = register_diag_field ( trim(field), 'rh925', axes(1:2), Time,       &
                           '925-mb relative humidity', '%', missing_value=missing_value )
       idiag%id_rh1000 = register_diag_field ( trim(field), 'rh1000', axes(1:2), Time,       &
                           '1000-mb relative humidity', '%', missing_value=missing_value )
!--------------------------
! Dew Point
!--------------------------
       idiag%id_dp10 = register_diag_field ( trim(field), 'dp10', axes(1:2), Time,       &
                           '10-mb dew point', 'K', missing_value=missing_value )
       idiag%id_dp50 = register_diag_field ( trim(field), 'dp50', axes(1:2), Time,       &
                           '50-mb dew point', 'K', missing_value=missing_value )
       idiag%id_dp100 = register_diag_field ( trim(field), 'dp100', axes(1:2), Time,       &
                           '100-mb dew point', 'K', missing_value=missing_value )
       idiag%id_dp200 = register_diag_field ( trim(field), 'dp200', axes(1:2), Time,       &
                           '200-mb dew point', 'K', missing_value=missing_value )
       idiag%id_dp250 = register_diag_field ( trim(field), 'dp250', axes(1:2), Time,       &
                           '250-mb dew point', 'K', missing_value=missing_value )
       idiag%id_dp300 = register_diag_field ( trim(field), 'dp300', axes(1:2), Time,       &
                           '300-mb dew point', 'K', missing_value=missing_value )
       idiag%id_dp500 = register_diag_field ( trim(field), 'dp500', axes(1:2), Time,       &
                           '500-mb dew point', 'K', missing_value=missing_value )
       idiag%id_dp700 = register_diag_field ( trim(field), 'dp700', axes(1:2), Time,       &
                           '700-mb dew point', 'K', missing_value=missing_value )
       idiag%id_dp850 = register_diag_field ( trim(field), 'dp850', axes(1:2), Time,       &
                           '850-mb dew point', 'K', missing_value=missing_value )
       idiag%id_dp925 = register_diag_field ( trim(field), 'dp925', axes(1:2), Time,       &
                           '925-mb dew point', 'K', missing_value=missing_value )
       idiag%id_dp1000 = register_diag_field ( trim(field), 'dp1000', axes(1:2), Time,       &
                           '1000-mb dew point', 'K', missing_value=missing_value )
!--------------------------
! relative humidity (CMIP definition):
!--------------------------
       idiag%id_rh10_cmip = register_diag_field ( trim(field), 'rh10_cmip', axes(1:2), Time,       &
                           '10-mb relative humidity (CMIP)', '%', missing_value=missing_value )
       idiag%id_rh50_cmip = register_diag_field ( trim(field), 'rh50_cmip', axes(1:2), Time,       &
                           '50-mb relative humidity (CMIP)', '%', missing_value=missing_value )
       idiag%id_rh100_cmip = register_diag_field ( trim(field), 'rh100_cmip', axes(1:2), Time,       &
                           '100-mb relative humidity (CMIP)', '%', missing_value=missing_value )
       idiag%id_rh250_cmip = register_diag_field ( trim(field), 'rh250_cmip', axes(1:2), Time,       &
                           '250-mb relative humidity (CMIP)', '%', missing_value=missing_value )
       idiag%id_rh300_cmip = register_diag_field ( trim(field), 'rh300_cmip', axes(1:2), Time,       &
                           '300-mb relative humidity (CMIP)', '%', missing_value=missing_value )
       idiag%id_rh500_cmip = register_diag_field ( trim(field), 'rh500_cmip', axes(1:2), Time,       &
                           '500-mb relative humidity (CMIP)', '%', missing_value=missing_value )
       idiag%id_rh700_cmip = register_diag_field ( trim(field), 'rh700_cmip', axes(1:2), Time,       &
                           '700-mb relative humidity (CMIP)', '%', missing_value=missing_value )
       idiag%id_rh850_cmip = register_diag_field ( trim(field), 'rh850_cmip', axes(1:2), Time,       &
                           '850-mb relative humidity (CMIP)', '%', missing_value=missing_value )
       idiag%id_rh925_cmip = register_diag_field ( trim(field), 'rh925_cmip', axes(1:2), Time,       &
                           '925-mb relative humidity (CMIP)', '%', missing_value=missing_value )
       idiag%id_rh1000_cmip = register_diag_field ( trim(field), 'rh1000_cmip', axes(1:2), Time,       &
                           '1000-mb relative humidity (CMIP)', '%', missing_value=missing_value )

       if (Atm(n)%flagstruct%write_3d_diags) then
          do i=1, ncnst
             !--------------------
             ! Tracer diagnostics:
             !--------------------
             call get_tracer_names ( MODEL_ATMOS, i, tname, tlongname, tunits )
             idiag%id_tracer(i) = register_diag_field ( field, trim(tname),  &
                  axes(1:3), Time, trim(tlongname), &
                  trim(tunits), missing_value=missing_value)
             if (master) then
                if (idiag%id_tracer(i) > 0) then
                   unit = stdlog()
                   write(unit,'(a,a,a,a)') &
                        & 'Diagnostics available for tracer ',trim(tname), &
                        ' in module ', trim(field)
                end if
             endif
             !----------------------------------
             ! ESM Tracer dmmr/dvmr diagnostics:
             !   for specific elements only
             !----------------------------------
             !---co2
             if (trim(tname).eq.'co2') then
                idiag%w_mr(:) = WTMCO2
                idiag%id_tracer_dmmr(i) = register_diag_field ( field, trim(tname)//'_dmmr',  &
                     axes(1:3), Time, trim(tlongname)//" (dry mmr)",           &
                     trim(tunits), missing_value=missing_value)
                idiag%id_tracer_dvmr(i) = register_diag_field ( field, trim(tname)//'_dvmr',  &
                     axes(1:3), Time, trim(tlongname)//" (dry vmr)",           &
                     'mol/mol', missing_value=missing_value)
                if (master) then
                   unit = stdlog()
                   if (idiag%id_tracer_dmmr(i) > 0) then
                      write(unit,'(a,a,a,a)') 'Diagnostics available for '//trim(tname)//' dry mmr ', &
                           trim(tname)//'_dmmr', ' in module ', trim(field)
                   end if
                   if (idiag%id_tracer_dvmr(i) > 0) then
                      write(unit,'(a,a,a,a)') 'Diagnostics available for '//trim(tname)//' dry vmr ', &
                           trim(tname)//'_dvmr', ' in module ', trim(field)
                   end if
                endif
             endif
             !---end co2

          enddo
       endif

       if ( Atm(1)%flagstruct%consv_am .or. idiag%id_mq > 0 .or. idiag%id_amdt > 0 )  then
          allocate ( idiag%zxg(isc:iec,jsc:jec) )
          ! Initialize gradient of terrain for mountain torque computation:
          call init_mq(Atm(n)%phis, Atm(n)%gridstruct, &
               npx, npy, isc, iec, jsc, jec, Atm(n)%ng)
       endif

!    end do


#ifdef TEST_TRACER
        call prt_mass(npz, Atm(n)%ncnst, isc, iec, jsc, jec, Atm(n)%ng, max(1,Atm(n)%flagstruct%nwat),    &
                      Atm(n)%ps, Atm(n)%delp, Atm(n)%q, Atm(n)%gridstruct%area_64, Atm(n)%domain)
#else
        call prt_mass(npz, Atm(n)%ncnst, isc, iec, jsc, jec, Atm(n)%ng, Atm(n)%flagstruct%nwat,    &
                      Atm(n)%ps, Atm(n)%delp, Atm(n)%q, Atm(n)%gridstruct%area_64, Atm(n)%domain)
#endif

    call nullify_domain()  ! Nullify  set_domain info

    module_is_initialized=.true.
    istep = 0
#ifndef GFS_PHYS
    if(idiag%id_theta_e >0 ) call qsmith_init
#endif
 end subroutine fv_diag_init


 subroutine init_mq(phis, gridstruct, npx, npy, is, ie, js, je, ng)
    integer, intent(in):: npx, npy, is, ie, js, je, ng
    real, intent(in):: phis(is-ng:ie+ng, js-ng:je+ng)
    type(fv_grid_type), intent(IN), target :: gridstruct

! local:
    real zs(is-ng:ie+ng, js-ng:je+ng)
    real zb(is-ng:ie+ng, js-ng:je+ng)
    real pdx(3,is:ie,js:je+1)
    real pdy(3,is:ie+1,js:je)
    integer i, j, n

    real, pointer :: rarea(:,:)
    real, pointer, dimension(:,:) :: dx, dy
    real(kind=R_GRID), pointer, dimension(:,:,:) :: en1, en2, vlon, vlat
    real, pointer, dimension(:,:,:) :: agrid

    rarea => gridstruct%rarea
    dx    => gridstruct%dx
    dy    => gridstruct%dy
    en1   => gridstruct%en1
    en2   => gridstruct%en2
    agrid => gridstruct%agrid
    vlon  => gridstruct%vlon
    vlat  => gridstruct%vlat

!   do j=js,je
!      do i=is,ie
    do j=js-ng,je+ng
       do i=is-ng,ie+ng
          zs(i,j) = phis(i,j) / grav
       enddo
    enddo
!   call mpp_update_domains( zs, domain )

!   call a2b_ord2(zs, zb, gridstruct, npx, npy, is, ie, js, je, ng)
    call a2b_ord4(zs, zb, gridstruct, npx, npy, is, ie, js, je, ng)

    do j=js,je+1
       do i=is,ie
          do n=1,3
             pdx(n,i,j) = 0.5*(zb(i,j)+zb(i+1,j))*dx(i,j)*en1(n,i,j)
          enddo
       enddo
    enddo
    do j=js,je
       do i=is,ie+1
          do n=1,3
             pdy(n,i,j) = 0.5*(zb(i,j)+zb(i,j+1))*dy(i,j)*en2(n,i,j)
          enddo
       enddo
    enddo

! Compute "volume-mean" gradient by Green's theorem
    do j=js,je
       do i=is,ie
          idiag%zxg(i,j) = vlon(i,j,1)*(pdx(1,i,j+1)-pdx(1,i,j)-pdy(1,i,j)+pdy(1,i+1,j))  &
                         + vlon(i,j,2)*(pdx(2,i,j+1)-pdx(2,i,j)-pdy(2,i,j)+pdy(2,i+1,j))  &
                         + vlon(i,j,3)*(pdx(3,i,j+1)-pdx(3,i,j)-pdy(3,i,j)+pdy(3,i+1,j))
! dF/d(lamda) = radius*cos(agrid(i,j,2)) * dF/dx, F is a scalar
!                                                       ________________________
          idiag%zxg(i,j) =  idiag%zxg(i,j)*rarea(i,j) * radius*cos(agrid(i,j,2))
!                                                       ^^^^^^^^^^^^^^^^^^^^^^^^
       enddo
    enddo

 end subroutine init_mq

 subroutine fv_diag(Atm, zvir, Time, print_freq)

    type(fv_atmos_type), intent(inout) :: Atm(:)
    type(time_type),     intent(in) :: Time
    real,                intent(in):: zvir
    integer,             intent(in):: print_freq

    integer :: isc, iec, jsc, jec, n, ntileMe
    integer :: isd, ied, jsd, jed, npz, itrac
    integer :: ngc, nwater

    real, allocatable :: a2(:,:),a3(:,:,:), wk(:,:,:), wz(:,:,:), ucoor(:,:,:), vcoor(:,:,:)
    real, allocatable :: ustm(:,:), vstm(:,:)
    real, allocatable :: slp(:,:), depress(:,:), ws_max(:,:), tc_count(:,:)
    real, allocatable :: u2(:,:), v2(:,:), x850(:,:), var1(:,:), var2(:,:), var3(:,:)
    real, allocatable :: dmmr(:,:,:), dvmr(:,:,:)
    real height(2)
    real:: plevs(nplev), pout(nplev)
    integer:: idg(nplev), id1(nplev)
    real    :: tot_mq, tmp, sar, slon, slat
    real    :: a1d(Atm(1)%npz)
!   real    :: t_gb, t_nh, t_sh, t_eq, area_gb, area_nh, area_sh, area_eq
    logical :: do_cs_intp
    logical :: used
    logical :: bad_range
    integer i,j,k, yr, mon, dd, hr, mn, days, seconds, nq, theta_d
    character(len=128)   :: tname
    real, parameter:: ws_0 = 16.   ! minimum max_wind_speed within the 7x7 search box
    real, parameter:: ws_1 = 20.
    real, parameter:: vort_c0= 2.2e-5 
    logical, allocatable :: storm(:,:), cat_crt(:,:)
    real :: tmp2, pvsum, e2, einf, qm, mm, maxdbz, allmax, rgrav
    integer :: Cl, Cl2
    !!! CLEANUP: does it really make sense to have this routine loop over Atm% anymore? We assume n=1 below anyway

! cat15: SLP<1000; srf_wnd>ws_0; vort>vort_c0
! cat25: SLP< 980; srf_wnd>ws_1; vort>vort_c0
! cat35: SLP< 964; srf_wnd>ws_1; vort>vort_c0
! cat45: SLP< 944; srf_wnd>ws_1; vort>vort_c0

    height(1) = 5.E3      ! for computing 5-km "pressure"
    height(2) = 0.        ! for sea-level pressure

    do i=1,nplev
       pout(i) = levs(i) * 1.e2
       plevs(i) = log( pout(i) )
    enddo

    ntileMe = size(Atm(:))
    n = 1
    isc = Atm(n)%bd%isc; iec = Atm(n)%bd%iec
    jsc = Atm(n)%bd%jsc; jec = Atm(n)%bd%jec
    ngc = Atm(n)%ng
    npz = Atm(n)%npz
    ptop = Atm(n)%ak(1)
    nq = size (Atm(n)%q,4)

    isd = Atm(n)%bd%isd; ied = Atm(n)%bd%ied
    jsd = Atm(n)%bd%jsd; jed = Atm(n)%bd%jed

    if( idiag%id_c15>0 ) then
        allocate (   storm(isc:iec,jsc:jec) )
        allocate ( depress(isc:iec,jsc:jec) )
        allocate (  ws_max(isc:iec,jsc:jec) )
        allocate ( cat_crt(isc:iec,jsc:jec) )
        allocate (tc_count(isc:iec,jsc:jec) )
    endif

    if( idiag%id_x850>0 ) then
        allocate ( x850(isc:iec,jsc:jec) )
    endif

    fv_time = Time
    call set_domain(Atm(1)%domain)

    if ( m_calendar ) then
         call get_date(fv_time, yr, mon, dd, hr, mn, seconds)
         if( print_freq == 0 ) then
                 prt_minmax = .false.
         elseif( print_freq < 0 ) then
                 istep = istep + 1
                 prt_minmax = mod(istep, -print_freq) == 0
         else
                 prt_minmax = mod(hr, print_freq) == 0 .and. mn==0 .and. seconds==0
         endif
     else
         call get_time (fv_time, seconds,  days)
         if( print_freq == 0 ) then
                 prt_minmax = .false.
         elseif( print_freq < 0 ) then
                 istep = istep + 1
                 prt_minmax = mod(istep, -print_freq) == 0
         else
                 prt_minmax = mod(seconds, 3600*print_freq) == 0
         endif
     endif

     if(prt_minmax) then
         if ( m_calendar ) then
              if(master) write(*,*) yr, mon, dd, hr, mn, seconds
         else
              if(master) write(*,*) Days, seconds
         endif
     endif

    allocate ( a2(isc:iec,jsc:jec) )

    if( prt_minmax ) then

        call prt_mxm('ZS', idiag%zsurf,     isc, iec, jsc, jec, 0,   1, 1.0, Atm(n)%gridstruct%area_64, Atm(n)%domain)
        call prt_maxmin('PS', Atm(n)%ps, isc, iec, jsc, jec, ngc, 1, 0.01)

#ifdef HIWPP
        allocate(var2(isc:iec,jsc:jec))
        !hemispheric max/min pressure
        do j=jsc,jec
        do i=isc,iec
           slat = rad2deg*Atm(n)%gridstruct%agrid(i,j,2)
           if (slat >= 0.) then
              a2(i,j) = Atm(n)%ps(i,j)
              var2(i,j) = 101300.
           else
              a2(i,j) = 101300.
              var2(i,j) = Atm(n)%ps(i,j)
           endif
        enddo
        enddo
        call prt_maxmin('NH PS', a2, isc, iec, jsc, jec, 0, 1, 0.01)
        call prt_maxmin('SH PS', var2, isc, iec, jsc, jec, 0, 1, 0.01)

        deallocate(var2)
#endif

#ifdef TEST_TRACER
        call prt_mass(npz, nq, isc, iec, jsc, jec, ngc, max(1,Atm(n)%flagstruct%nwat),    &
                      Atm(n)%ps, Atm(n)%delp, Atm(n)%q, Atm(n)%gridstruct%area_64, Atm(n)%domain)
#else
        call prt_mass(npz, nq, isc, iec, jsc, jec, ngc, Atm(n)%flagstruct%nwat,    &
                      Atm(n)%ps, Atm(n)%delp, Atm(n)%q, Atm(n)%gridstruct%area_64, Atm(n)%domain)
#endif

#ifndef SW_DYNAMICS
        if (Atm(n)%flagstruct%consv_te > 1.e-5) then
           idiag%steps = idiag%steps + 1
           idiag%efx_sum = idiag%efx_sum + E_Flux
           if ( idiag%steps <= max_step ) idiag%efx(idiag%steps) = E_Flux
           if (master)  then
              write(*,*) 'ENG Deficit (W/m**2)', trim(gn), '=', E_Flux
           endif


        endif
        if ( .not. Atm(n)%flagstruct%hydrostatic )   &
          call nh_total_energy(isc, iec, jsc, jec, isd, ied, jsd, jed, npz,  &
                               Atm(n)%w, Atm(n)%delz, Atm(n)%pt, Atm(n)%delp,  &
                               Atm(n)%q, Atm(n)%phis, Atm(n)%gridstruct%area, Atm(n)%domain, &
                               sphum, liq_wat, rainwat, ice_wat, snowwat, graupel, Atm(n)%flagstruct%nwat,     &
                               Atm(n)%ua, Atm(n)%va, Atm(n)%flagstruct%moist_phys, a2)
#endif
        call prt_maxmin('UA_top', Atm(n)%ua(isc:iec,jsc:jec,1),    &
                        isc, iec, jsc, jec, 0, 1, 1.)
        call prt_maxmin('UA', Atm(n)%ua, isc, iec, jsc, jec, ngc, npz, 1.)
        call prt_maxmin('VA', Atm(n)%va, isc, iec, jsc, jec, ngc, npz, 1.)

        if ( .not. Atm(n)%flagstruct%hydrostatic ) then
          call prt_maxmin('W ', Atm(n)%w , isc, iec, jsc, jec, ngc, npz, 1.)
          call prt_maxmin('Bottom w', Atm(n)%w(isc:iec,jsc:jec,npz), isc, iec, jsc, jec, 0, 1, 1.)
          do j=jsc,jec
             do i=isc,iec
                a2(i,j) = -Atm(n)%w(i,j,npz)/Atm(n)%delz(i,j,npz)
             enddo
          enddo
          call prt_maxmin('Bottom: w/dz', a2, isc, iec, jsc, jec, 0, 1, 1.)

          if ( Atm(n)%flagstruct%hybrid_z ) call prt_maxmin('Hybrid_ZTOP (km)', Atm(n)%ze0(isc:iec,jsc:jec,1), &
                                                 isc, iec, jsc, jec, 0, 1, 1.E-3)
          call prt_maxmin('DZ (m)', Atm(n)%delz(isc:iec,jsc:jec,1:npz),    &
                          isc, iec, jsc, jec, 0, npz, 1.)
          call prt_maxmin('Bottom DZ (m)', Atm(n)%delz(isc:iec,jsc:jec,npz),    &
                          isc, iec, jsc, jec, 0, 1, 1.)
!         call prt_maxmin('Top DZ (m)', Atm(n)%delz(isc:iec,jsc:jec,1),    &
!                         isc, iec, jsc, jec, 0, 1, 1.)
        endif

#ifndef SW_DYNAMICS
        call prt_maxmin('TA', Atm(n)%pt,   isc, iec, jsc, jec, ngc, npz, 1.)
!       call prt_maxmin('Top: TA', Atm(n)%pt(isc:iec,jsc:jec,  1), isc, iec, jsc, jec, 0, 1, 1.)
!       call prt_maxmin('Bot: TA', Atm(n)%pt(isc:iec,jsc:jec,npz), isc, iec, jsc, jec, 0, 1, 1.)
        call prt_maxmin('OM', Atm(n)%omga, isc, iec, jsc, jec, ngc, npz, 1.)
#endif

    elseif ( Atm(n)%flagstruct%range_warn ) then
         call range_check('DELP', Atm(n)%delp, isc, iec, jsc, jec, ngc, npz, Atm(n)%gridstruct%agrid,    &
                           0.01*ptop, 200.E2, bad_range)
         call range_check('UA', Atm(n)%ua, isc, iec, jsc, jec, ngc, npz, Atm(n)%gridstruct%agrid,   &
                           -250., 250., bad_range)
         call range_check('VA', Atm(n)%va, isc, iec, jsc, jec, ngc, npz, Atm(n)%gridstruct%agrid,   &
                           -250., 250., bad_range)
#ifndef SW_DYNAMICS
         call range_check('TA', Atm(n)%pt, isc, iec, jsc, jec, ngc, npz, Atm(n)%gridstruct%agrid,   &
#ifdef HIWPP
                           130., 350., bad_range) !DCMIP ICs have very low temperatures
#else
                           150., 350., bad_range)
#endif
#endif

      endif

    allocate ( u2(isc:iec,jsc:jec) )
    allocate ( v2(isc:iec,jsc:jec) )
    allocate ( wk(isc:iec,jsc:jec,npz) )
    if ( any(idiag%id_tracer_dmmr > 0) .or. any(idiag%id_tracer_dvmr > 0) ) then
        allocate ( dmmr(isc:iec,jsc:jec,1:npz) )
        allocate ( dvmr(isc:iec,jsc:jec,1:npz) )
    endif

!    do n = 1, ntileMe
    n = 1

#ifdef DYNAMICS_ZS
       if(idiag%id_zsurf > 0)  used=send_data(idiag%id_zsurf, idiag%zsurf, Time)
#endif
       if(idiag%id_ps > 0) used=send_data(idiag%id_ps, Atm(n)%ps(isc:iec,jsc:jec), Time)

       if(idiag%id_c15>0 .or. idiag%id_c25>0 .or. idiag%id_c35>0 .or. idiag%id_c45>0) then
          call wind_max(isc, iec, jsc, jec ,isd, ied, jsd, jed, Atm(n)%ua(isc:iec,jsc:jec,npz),   &
                        Atm(n)%va(isc:iec,jsc:jec,npz), ws_max, Atm(n)%domain)
          do j=jsc,jec
             do i=isc,iec
                if( abs(Atm(n)%gridstruct%agrid(i,j,2)*rad2deg)<45.0 .and.     &
                    Atm(n)%phis(i,j)*ginv<500.0 .and. ws_max(i,j)>ws_0 ) then
                    storm(i,j) = .true.
                else
                    storm(i,j) = .false.
                endif
             enddo
          enddo
       endif

       if ( idiag%id_vort200>0 .or. idiag%id_vort500>0 .or. idiag%id_vort850>0 .or. idiag%id_vorts>0   &
            .or. idiag%id_vort>0 .or. idiag%id_pv>0 .or. idiag%id_rh>0 .or. idiag%id_x850>0 .or.  &
            idiag%id_uh03>0 .or. idiag%id_uh25>0) then
          call get_vorticity(isc, iec, jsc, jec, isd, ied, jsd, jed, npz, Atm(n)%u, Atm(n)%v, wk, &
               Atm(n)%gridstruct%dx, Atm(n)%gridstruct%dy, Atm(n)%gridstruct%rarea)

          if(idiag%id_vort >0) used=send_data(idiag%id_vort,  wk, Time)
          if(idiag%id_vorts>0) used=send_data(idiag%id_vorts, wk(isc:iec,jsc:jec,npz), Time)

          if(idiag%id_c15>0) then
             do j=jsc,jec
                do i=isc,iec
                   if ( storm(i,j) )    &
                   storm(i,j) = (Atm(n)%gridstruct%agrid(i,j,2)>0. .and. wk(i,j,npz)> vort_c0) .or. &
                                (Atm(n)%gridstruct%agrid(i,j,2)<0. .and. wk(i,j,npz)<-vort_c0) 
                enddo
             enddo
          endif

          if( idiag%id_vort200>0 ) then
             call interpolate_vertical(isc, iec, jsc, jec, npz,   &
                                       200.e2, Atm(n)%peln, wk, a2)
             used=send_data(idiag%id_vort200, a2, Time)
          endif
          if( idiag%id_vort500>0 ) then
             call interpolate_vertical(isc, iec, jsc, jec, npz,   &
                                       500.e2, Atm(n)%peln, wk, a2)
             used=send_data(idiag%id_vort500, a2, Time)
          endif

          if(idiag%id_vort850>0 .or. idiag%id_c15>0 .or. idiag%id_x850>0) then
             call interpolate_vertical(isc, iec, jsc, jec, npz,   &
                                       850.e2, Atm(n)%peln, wk, a2)
             used=send_data(idiag%id_vort850, a2, Time)
             if ( idiag%id_x850>0 ) x850(:,:) = a2(:,:) 

             if(idiag%id_c15>0) then
             do j=jsc,jec
                do i=isc,iec
                   if ( storm(i,j) )    &
                     storm(i,j) = (Atm(n)%gridstruct%agrid(i,j,2)>0. .and. a2(i,j)> vort_c0) .or.     &
                                  (Atm(n)%gridstruct%agrid(i,j,2)<0. .and. a2(i,j)<-vort_c0) 
                enddo
             enddo
             endif

          endif

          if( .not. Atm(n)%flagstruct%hydrostatic ) then

             if ( idiag%id_uh03 > 0 ) then
                call updraft_helicity(isc, iec, jsc, jec, ngc, npz, zvir, sphum, a2, &
                     Atm(n)%w, wk, Atm(n)%delz, Atm(n)%q,   &
                     Atm(n)%flagstruct%hydrostatic, Atm(n)%pt, Atm(n)%peln, Atm(n)%phis, grav, 0., 3.e3)
                used = send_data ( idiag%id_uh03, a2, Time )
                if(prt_minmax) then
                   do j=jsc,jec
                      do i=isc,iec
                         tmp = rad2deg * Atm(n)%gridstruct%agrid(i,j,1)
                         tmp2 = rad2deg * Atm(n)%gridstruct%agrid(i,j,2)
                         if (  tmp2<25. .or. tmp2>50.    &
                              .or. tmp<235. .or. tmp>300. ) then
                            a2(i,j) = 0.
                         endif
                      enddo
                   enddo
                   call prt_maxmin('UH over CONUS', a2, isc, iec, jsc, jec, 0,   1, 1.)
                endif
             endif
             if ( idiag%id_uh25 > 0 ) then
                call updraft_helicity(isc, iec, jsc, jec, ngc, npz, zvir, sphum, a2, &
                     Atm(n)%w, wk, Atm(n)%delz, Atm(n)%q,   &
                     Atm(n)%flagstruct%hydrostatic, Atm(n)%pt, Atm(n)%peln, Atm(n)%phis, grav, 2.e3, 5.e3)
                used = send_data ( idiag%id_uh25, a2, Time )
             endif
          endif


          if ( idiag%id_srh1 > 0 .or. idiag%id_srh3 > 0 .or. idiag%id_srh25 > 0 .or. idiag%id_ustm > 0 .or. idiag%id_vstm > 0) then
              allocate(ustm(isc:iec,jsc:jec), vstm(isc:iec,jsc:jec))

              call bunkers_vector(isc, iec, jsc, jec, ngc, npz, zvir, sphum, ustm, vstm, &
                   Atm(n)%ua, Atm(n)%va, Atm(n)%delz, Atm(n)%q,   &
                   Atm(n)%flagstruct%hydrostatic, Atm(n)%pt, Atm(n)%peln, Atm(n)%phis, grav)

              if ( idiag%id_ustm > 0 ) then
                 used = send_data ( idiag%id_ustm, ustm, Time )
              endif
              if ( idiag%id_vstm > 0 ) then
                 used = send_data ( idiag%id_vstm, vstm, Time )
              endif

              if ( idiag%id_srh1 > 0 ) then
                 call helicity_relative_CAPS(isc, iec, jsc, jec, ngc, npz, zvir, sphum, a2, ustm, vstm, &
                      Atm(n)%ua, Atm(n)%va, Atm(n)%delz, Atm(n)%q,   &
                      Atm(n)%flagstruct%hydrostatic, Atm(n)%pt, Atm(n)%peln, Atm(n)%phis, grav, 0., 1.e3)
                 used = send_data ( idiag%id_srh1, a2, Time )
                 if(prt_minmax) then
                    do j=jsc,jec
                       do i=isc,iec
                          tmp = rad2deg * Atm(n)%gridstruct%agrid(i,j,1)
                          tmp2 = rad2deg * Atm(n)%gridstruct%agrid(i,j,2)
                          if (  tmp2<25. .or. tmp2>50.    &
                               .or. tmp<235. .or. tmp>300. ) then
                             a2(i,j) = 0.
                          endif
                       enddo
                    enddo
                    call prt_maxmin('SRH (0-1 km) over CONUS', a2, isc, iec, jsc, jec, 0,   1, 1.)
                 endif
              endif

              if ( idiag%id_srh3 > 0 ) then
                 call helicity_relative_CAPS(isc, iec, jsc, jec, ngc, npz, zvir, sphum, a2, ustm, vstm, &
                      Atm(n)%ua, Atm(n)%va, Atm(n)%delz, Atm(n)%q,   &
                      Atm(n)%flagstruct%hydrostatic, Atm(n)%pt, Atm(n)%peln, Atm(n)%phis, grav, 0., 3e3)
                 used = send_data ( idiag%id_srh3, a2, Time )
                 if(prt_minmax) then
                    do j=jsc,jec
                       do i=isc,iec
                          tmp = rad2deg * Atm(n)%gridstruct%agrid(i,j,1)
                          tmp2 = rad2deg * Atm(n)%gridstruct%agrid(i,j,2)
                          if (  tmp2<25. .or. tmp2>50.    &
                               .or. tmp<235. .or. tmp>300. ) then
                             a2(i,j) = 0.
                          endif
                       enddo
                    enddo
                    call prt_maxmin('SRH (0-3 km) over CONUS', a2, isc, iec, jsc, jec, 0,   1, 1.)
                 endif
              endif

              if ( idiag%id_srh25 > 0 ) then
                 call helicity_relative_CAPS(isc, iec, jsc, jec, ngc, npz, zvir, sphum, a2, ustm, vstm, &
                      Atm(n)%ua, Atm(n)%va, Atm(n)%delz, Atm(n)%q,   &
                      Atm(n)%flagstruct%hydrostatic, Atm(n)%pt, Atm(n)%peln, Atm(n)%phis, grav, 2.e3, 5e3)
                 used = send_data ( idiag%id_srh25, a2, Time )
                 if(prt_minmax) then
                    do j=jsc,jec
                       do i=isc,iec
                          tmp = rad2deg * Atm(n)%gridstruct%agrid(i,j,1)
                          tmp2 = rad2deg * Atm(n)%gridstruct%agrid(i,j,2)
                          if (  tmp2<25. .or. tmp2>50.    &
                               .or. tmp<235. .or. tmp>300. ) then
                             a2(i,j) = 0.
                          endif
                       enddo
                    enddo
                    call prt_maxmin('SRH (2-5 km) over CONUS', a2, isc, iec, jsc, jec, 0,   1, 1.)
                 endif
              endif

              deallocate(ustm, vstm)
          endif


          if ( idiag%id_pv > 0 ) then
! Note: this is expensive computation.
              call pv_entropy(isc, iec, jsc, jec, ngc, npz, wk,    &
                              Atm(n)%gridstruct%f0, Atm(n)%pt, Atm(n)%pkz, Atm(n)%delp, grav)
              used = send_data ( idiag%id_pv, wk, Time )
              if (prt_minmax) call prt_maxmin('PV', wk, isc, iec, jsc, jec, 0, 1, 1.)
          endif

       endif


       
!!$       if ( idiag%id_srh > 0 ) then
!!$          call helicity_relative(isc, iec, jsc, jec, ngc, npz, zvir, sphum, a2, &
!!$               Atm(n)%ua, Atm(n)%va, Atm(n)%delz, Atm(n)%q,   &
!!$               Atm(n)%flagstruct%hydrostatic, Atm(n)%pt, Atm(n)%peln, Atm(n)%phis, grav, 0., 3.e3)
!!$          used = send_data ( idiag%id_srh, a2, Time )
!!$          if(prt_minmax) then
!!$             do j=jsc,jec
!!$                do i=isc,iec
!!$                   tmp = rad2deg * Atm(n)%gridstruct%agrid(i,j,1)
!!$                   tmp2 = rad2deg * Atm(n)%gridstruct%agrid(i,j,2)
!!$                   if (  tmp2<25. .or. tmp2>50.    &
!!$                        .or. tmp<235. .or. tmp>300. ) then
!!$                      a2(i,j) = 0.
!!$                   endif
!!$                enddo
!!$             enddo
!!$             call prt_maxmin('SRH over CONUS', a2, isc, iec, jsc, jec, 0,   1, 1.)
!!$          endif
!!$       endif

!!$       if ( idiag%id_srh25 > 0 ) then
!!$          call helicity_relative(isc, iec, jsc, jec, ngc, npz, zvir, sphum, a2, &
!!$               Atm(n)%ua, Atm(n)%va, Atm(n)%delz, Atm(n)%q,   &
!!$               Atm(n)%flagstruct%hydrostatic, Atm(n)%pt, Atm(n)%peln, Atm(n)%phis, grav, 2.e3, 5.e3)
!!$          used = send_data ( idiag%id_srh25, a2, Time )
!!$       endif


       ! Relative Humidity
       if ( idiag%id_rh > 0 ) then
          ! Compute FV mean pressure
          do k=1,npz
             do j=jsc,jec
                do i=isc,iec
                   a2(i,j) = Atm(n)%delp(i,j,k)/(Atm(n)%peln(i,k+1,j)-Atm(n)%peln(i,k,j))
                enddo
             enddo
#ifdef MULTI_GASES
             call qsmith((iec-isc+1)*(jec-jsc+1), npz,                       &
                   (iec-isc+1)*(jec-jsc+1), 1, Atm(n)%pt(isc:iec,jsc:jec,k), &
                  a2, Atm(n)%q(isc:iec,jsc:jec,k,sphum), wk(isc,jsc,k))
#else
             call qsmith(iec-isc+1, jec-jsc+1, 1, Atm(n)%pt(isc:iec,jsc:jec,k),   &
                  a2, Atm(n)%q(isc:iec,jsc:jec,k,sphum), wk(isc,jsc,k))
#endif
             do j=jsc,jec
                do i=isc,iec
                   wk(i,j,k) = 100.*Atm(n)%q(i,j,k,sphum)/wk(i,j,k)
                enddo
             enddo
          enddo
          used = send_data ( idiag%id_rh, wk, Time )
          if(prt_minmax) then
             call prt_maxmin('RH_sf (%)', wk(isc:iec,jsc:jec,npz), isc, iec, jsc, jec, 0,   1, 1.)
             call prt_maxmin('RH_3D (%)', wk, isc, iec, jsc, jec, 0, npz, 1.)
          endif
       endif

       ! rel hum from physics at selected press levels (for IPCC)
       if (idiag%id_rh50>0  .or. idiag%id_rh100>0 .or. idiag%id_rh200>0 .or. idiag%id_rh250>0 .or. &
           idiag%id_rh300>0 .or. idiag%id_rh500>0 .or. idiag%id_rh700>0 .or. idiag%id_rh850>0 .or. &
           idiag%id_rh925>0 .or. idiag%id_rh1000>0 .or.                                            &
           idiag%id_dp50>0  .or. idiag%id_dp100>0 .or. idiag%id_dp200>0 .or. idiag%id_dp250>0 .or. &
           idiag%id_dp300>0 .or. idiag%id_dp500>0 .or. idiag%id_dp700>0 .or. idiag%id_dp850>0 .or. &
           idiag%id_dp925>0 .or. idiag%id_dp1000>0) then
           ! compute mean pressure
           do k=1,npz
               do j=jsc,jec
               do i=isc,iec
                   a2(i,j) = Atm(n)%delp(i,j,k)/(Atm(n)%peln(i,k+1,j)-Atm(n)%peln(i,k,j))
               enddo
               enddo
               call rh_calc (a2, Atm(n)%pt(isc:iec,jsc:jec,k), &
                             Atm(n)%q(isc:iec,jsc:jec,k,sphum), wk(isc:iec,jsc:jec,k))
           enddo
           if (idiag%id_rh50>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 50.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh50, a2, Time)
           endif
           if (idiag%id_rh100>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 100.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh100, a2, Time)
           endif
           if (idiag%id_rh200>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 200.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh200, a2, Time)
           endif
           if (idiag%id_rh250>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 250.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh250, a2, Time)
           endif
           if (idiag%id_rh300>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 300.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh300, a2, Time)
           endif
           if (idiag%id_rh500>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 500.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh500, a2, Time)
           endif
           if (idiag%id_rh700>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 700.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh700, a2, Time)
           endif
           if (idiag%id_rh850>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 850.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh850, a2, Time)
           endif
           if (idiag%id_rh925>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 925.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh925, a2, Time)
           endif
           if (idiag%id_rh1000>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 1000.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh1000, a2, Time)
           endif

           if (idiag%id_dp50>0  .or. idiag%id_dp100>0 .or. idiag%id_dp200>0 .or. idiag%id_dp250>0 .or. &
                idiag%id_dp300>0 .or. idiag%id_dp500>0 .or. idiag%id_dp700>0 .or. idiag%id_dp850>0 .or. &
                idiag%id_dp925>0 .or. idiag%id_dp1000>0 ) then

              if (allocated(a3)) deallocate(a3)
              allocate(a3(isc:iec,jsc:jec,1:npz))
              !compute dew point (K)
              !using formula at https://cals.arizona.edu/azmet/dewpoint.html
              do k=1,npz
              do j=jsc,jec
              do i=isc,iec
                 tmp = ( log(max(wk(i,j,k)*1.e-2,1.e-2)) + 17.27 * ( Atm(n)%pt(i,j,k) - 273.14 )/ ( -35.84 + Atm(n)%pt(i,j,k)) ) / 17.27 
                 a3(i,j,k) = 273.14 + 237.3*tmp/ ( 1. - tmp )
              enddo
              enddo
              enddo

              if (idiag%id_dp50>0) then
                 call interpolate_vertical(isc, iec, jsc, jec, npz, 50.e2, Atm(n)%peln, a3, a2)
                 used=send_data(idiag%id_dp50, a2, Time)
              endif
              if (idiag%id_dp100>0) then
                 call interpolate_vertical(isc, iec, jsc, jec, npz, 100.e2, Atm(n)%peln, a3, a2)
                 used=send_data(idiag%id_dp100, a2, Time)
              endif
              if (idiag%id_dp200>0) then
                 call interpolate_vertical(isc, iec, jsc, jec, npz, 200.e2, Atm(n)%peln, a3, a2)
                 used=send_data(idiag%id_dp200, a2, Time)
              endif
              if (idiag%id_dp250>0) then
                 call interpolate_vertical(isc, iec, jsc, jec, npz, 250.e2, Atm(n)%peln, a3, a2)
                 used=send_data(idiag%id_dp250, a2, Time)
              endif
              if (idiag%id_dp300>0) then
                 call interpolate_vertical(isc, iec, jsc, jec, npz, 300.e2, Atm(n)%peln, a3, a2)
                 used=send_data(idiag%id_dp300, a2, Time)
              endif
              if (idiag%id_dp500>0) then
                 call interpolate_vertical(isc, iec, jsc, jec, npz, 500.e2, Atm(n)%peln, a3, a2)
                 used=send_data(idiag%id_dp500, a2, Time)
              endif
              if (idiag%id_dp700>0) then
                 call interpolate_vertical(isc, iec, jsc, jec, npz, 700.e2, Atm(n)%peln, a3, a2)
                 used=send_data(idiag%id_dp700, a2, Time)
              endif
              if (idiag%id_dp850>0) then
                 call interpolate_vertical(isc, iec, jsc, jec, npz, 850.e2, Atm(n)%peln, a3, a2)
                 used=send_data(idiag%id_dp850, a2, Time)
              endif
              if (idiag%id_dp925>0) then
                 call interpolate_vertical(isc, iec, jsc, jec, npz, 925.e2, Atm(n)%peln, a3, a2)
                 used=send_data(idiag%id_dp925, a2, Time)
              endif
              if (idiag%id_dp1000>0) then
                 call interpolate_vertical(isc, iec, jsc, jec, npz, 1000.e2, Atm(n)%peln, a3, a2)
                 used=send_data(idiag%id_dp1000, a2, Time)
              endif
              deallocate(a3)

           endif

       endif

       ! rel hum (CMIP definition) at selected press levels  (for IPCC)
       if (idiag%id_rh10_cmip>0  .or. idiag%id_rh50_cmip>0  .or. idiag%id_rh100_cmip>0 .or. &
           idiag%id_rh250_cmip>0 .or. idiag%id_rh300_cmip>0 .or. idiag%id_rh500_cmip>0 .or. &
           idiag%id_rh700_cmip>0 .or. idiag%id_rh850_cmip>0 .or. idiag%id_rh925_cmip>0 .or. &
           idiag%id_rh1000_cmip>0) then
           ! compute mean pressure
           do k=1,npz
               do j=jsc,jec
               do i=isc,iec
                   a2(i,j) = Atm(n)%delp(i,j,k)/(Atm(n)%peln(i,k+1,j)-Atm(n)%peln(i,k,j))
               enddo
               enddo
               call rh_calc (a2, Atm(n)%pt(isc:iec,jsc:jec,k), &
                             Atm(n)%q(isc:iec,jsc:jec,k,sphum), wk(isc:iec,jsc:jec,k), do_cmip=.true.)
           enddo
           if (idiag%id_rh10_cmip>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 10.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh10_cmip, a2, Time)
           endif
           if (idiag%id_rh50_cmip>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 50.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh50_cmip, a2, Time)
           endif
           if (idiag%id_rh100_cmip>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 100.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh100_cmip, a2, Time)
           endif
           if (idiag%id_rh250_cmip>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 250.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh250_cmip, a2, Time)
           endif
           if (idiag%id_rh300_cmip>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 300.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh300_cmip, a2, Time)
           endif
           if (idiag%id_rh500_cmip>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 500.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh500_cmip, a2, Time)
           endif
           if (idiag%id_rh700_cmip>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 700.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh700_cmip, a2, Time)
           endif
           if (idiag%id_rh850_cmip>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 850.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh850_cmip, a2, Time)
           endif
           if (idiag%id_rh925_cmip>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 925.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh925_cmip, a2, Time)
           endif
           if (idiag%id_rh1000_cmip>0) then
               call interpolate_vertical(isc, iec, jsc, jec, npz, 1000.e2, Atm(n)%peln, wk(isc:iec,jsc:jec,:), a2)
               used=send_data(idiag%id_rh1000_cmip, a2, Time)
           endif
       endif

       if(idiag%id_c25>0 .or. idiag%id_c35>0 .or. idiag%id_c45>0) then
          do j=jsc,jec
             do i=isc,iec
                if ( storm(i,j) .and. ws_max(i,j)>ws_1 ) then
                     cat_crt(i,j) = .true.
                else
                     cat_crt(i,j) = .false.
                endif
             enddo
          enddo
       endif



       if( idiag%id_slp>0 .or. idiag%id_tm>0 .or. idiag%id_hght>0 .or. idiag%id_c15>0 .or. idiag%id_ctz>0 ) then

          allocate ( wz(isc:iec,jsc:jec,npz+1) )
          call get_height_field(isc, iec, jsc, jec, ngc, npz, Atm(n)%flagstruct%hydrostatic, Atm(n)%delz,  &
                                wz, Atm(n)%pt, Atm(n)%q, Atm(n)%peln, zvir)
          if( prt_minmax )   &
          call prt_mxm('ZTOP',wz(isc:iec,jsc:jec,1), isc, iec, jsc, jec, 0, 1, 1.E-3, Atm(n)%gridstruct%area_64, Atm(n)%domain)
!         call prt_maxmin('ZTOP', wz(isc:iec,jsc:jec,1), isc, iec, jsc, jec, 0, 1, 1.E-3)

          if(idiag%id_slp > 0) then
! Cumpute SLP (pressure at height=0)
          allocate ( slp(isc:iec,jsc:jec) )
          call get_pressure_given_height(isc, iec, jsc, jec, ngc, npz, wz, 1, height(2),   &
                                        Atm(n)%pt(:,:,npz), Atm(n)%peln, slp, 0.01)
          used = send_data (idiag%id_slp, slp, Time)
             if( prt_minmax ) then
             call prt_maxmin('SLP', slp, isc, iec, jsc, jec, 0, 1, 1.)
! US Potential Landfall TCs (PLT):
                 do j=jsc,jec
                    do i=isc,iec
                       a2(i,j) = 1015.
                       slon = rad2deg*Atm(n)%gridstruct%agrid(i,j,1)
                       slat = rad2deg*Atm(n)%gridstruct%agrid(i,j,2)
                       if ( slat>15. .and. slat<40. .and. slon>270. .and. slon<290. ) then
                            a2(i,j) = slp(i,j)
                       endif
                    enddo
                 enddo
                 call prt_maxmin('ATL SLP', a2, isc, iec, jsc, jec, 0,   1, 1.)
             endif
          endif

! Compute H3000 and/or H500
          if( idiag%id_tm>0 .or. idiag%id_hght>0 .or. idiag%id_ppt>0) then

             allocate( a3(isc:iec,jsc:jec,nplev) )

             idg(:) = idiag%id_h(:)

             if ( idiag%id_tm>0 ) then
                  idg(minloc(abs(levs-300))) = 1  ! 300-mb
                  idg(minloc(abs(levs-500))) = 1  ! 500-mb
             else
                  idg(minloc(abs(levs-300))) = idiag%id_h(minloc(abs(levs-300)))
                  idg(minloc(abs(levs-500))) = idiag%id_h(minloc(abs(levs-500)))
             endif

             call get_height_given_pressure(isc, iec, jsc, jec, npz, wz, nplev, idg, plevs, Atm(n)%peln, a3)
             ! reset 
             idg(minloc(abs(levs-300))) = idiag%id_h(minloc(abs(levs-300)))
             idg(minloc(abs(levs-500))) = idiag%id_h(minloc(abs(levs-500)))

             do i=1,nplev
                if (idg(i)>0) used=send_data(idg(i), a3(isc:iec,jsc:jec,i), Time)
             enddo

             if (idiag%id_h_plev>0)  then
               id1(:) = 1
               call get_height_given_pressure(isc, iec, jsc, jec, npz, wz, nplev, id1, plevs, Atm(n)%peln, a3)
               used=send_data(idiag%id_h_plev, a3(isc:iec,jsc:jec,:), Time)
             endif

             if( prt_minmax ) then
  
                if(all(idiag%id_h(minloc(abs(levs-100)))>0))  &
                call prt_mxm('Z100',a3(isc:iec,jsc:jec,11),isc,iec,jsc,jec,0,1,1.E-3,Atm(n)%gridstruct%area_64,Atm(n)%domain)

                if(all(idiag%id_h(minloc(abs(levs-500)))>0))  then
                   if (.not. Atm(n)%neststruct%nested) then
#ifdef TO_BE_DELETED
                   t_eq = 0.   ;    t_nh = 0.;    t_sh = 0.;    t_gb = 0.
                   area_eq = 0.; area_nh = 0.; area_sh = 0.; area_gb = 0.
                   do j=jsc,jec
                      do i=isc,iec
                         slat = Atm(n)%gridstruct%agrid(i,j,2)*rad2deg
                         area_gb = area_gb + Atm(n)%gridstruct%area(i,j)
                         t_gb = t_gb + a3(i,j,19)*Atm(n)%gridstruct%area(i,j)
                         if( (slat>-20. .and. slat<20.) ) then
! Tropics:
                              area_eq = area_eq + Atm(n)%gridstruct%area(i,j)
                                 t_eq =    t_eq + a3(i,j,19)*Atm(n)%gridstruct%area(i,j)
                         elseif( slat>=20. .and. slat<80. ) then
! NH
                              area_nh = area_nh + Atm(n)%gridstruct%area(i,j)
                                 t_nh =    t_nh + a3(i,j,19)*Atm(n)%gridstruct%area(i,j)
                         elseif( slat<=-20. .and. slat>-80. ) then
! SH
                              area_sh = area_sh + Atm(n)%gridstruct%area(i,j)
                                 t_sh =    t_sh + a3(i,j,19)*Atm(n)%gridstruct%area(i,j)
                         endif
                      enddo
                   enddo
                   call mp_reduce_sum(area_gb)
                   call mp_reduce_sum(   t_gb)
                   call mp_reduce_sum(area_nh)
                   call mp_reduce_sum(   t_nh)
                   call mp_reduce_sum(area_sh)
                   call mp_reduce_sum(   t_sh)
                   call mp_reduce_sum(area_eq)
                   call mp_reduce_sum(   t_eq)
                   if (master) write(*,*) 'Z500 GB_NH_SH_EQ=', t_gb/area_gb, t_nh/area_nh, t_sh/area_sh, t_eq/area_eq
#endif
!                  call prt_mxm('Z500',a3(isc:iec,jsc:jec,19),isc,iec,jsc,jec,0,1,1.,Atm(n)%gridstruct%area_64,Atm(n)%domain)
                   call prt_gb_nh_sh('fv_GFS Z500', isc,iec, jsc,jec, a3(isc,jsc,19), Atm(n)%gridstruct%area_64(isc:iec,jsc:jec),   &
                                     Atm(n)%gridstruct%agrid_64(isc:iec,jsc:jec,2))
                   endif
                endif

             endif

             ! mean virtual temp 300mb to 500mb
             if( idiag%id_tm>0 ) then
                 do j=jsc,jec
                    do i=isc,iec
                       a2(i,j) = grav*(a3(i,j,15)-a3(i,j,19))/(rdgas*(plevs(19)-plevs(15)))
                    enddo
                 enddo
                 used = send_data ( idiag%id_tm, a2, Time )
             endif

            if(idiag%id_c15>0 .or. idiag%id_c25>0 .or. idiag%id_c35>0 .or. idiag%id_c45>0) then
             do j=jsc,jec
                do i=isc,iec
! Minimum warm core:
                   if ( storm(i,j) ) then
                        if( a2(i,j)<254.0 .or. Atm(n)%pt(i,j,npz)<281.0 ) Then
                              storm(i,j) = .false.
                            cat_crt(i,j) = .false.
                        endif
                   endif
                enddo
             enddo
! Cat 1-5:
             do j=jsc,jec
                do i=isc,iec
                   if ( storm(i,j) .and. slp(i,j)<1000.0 ) then
                         depress(i,j) = 1000. - slp(i,j)
                        tc_count(i,j) = 1.
                   else
                         depress(i,j) = 0.
                        tc_count(i,j) = 0.
                   endif
                enddo
             enddo
             used = send_data(idiag%id_c15, depress, Time)
             if(idiag%id_f15>0) used = send_data(idiag%id_f15, tc_count, Time)
             if(prt_minmax) then
                do j=jsc,jec
                   do i=isc,iec
                      slon = rad2deg*Atm(n)%gridstruct%agrid(i,j,1)
                      slat = rad2deg*Atm(n)%gridstruct%agrid(i,j,2)
! Western Pac: negative; positive elsewhere
                      if ( slat>0. .and. slat<40. .and. slon>110. .and. slon<180. ) then
                           depress(i,j) = -depress(i,j)
                      endif
                   enddo
                enddo
                call prt_maxmin('Depress', depress, isc, iec, jsc, jec, 0,   1, 1.)
                do j=jsc,jec
                   do i=isc,iec
                      if ( Atm(n)%gridstruct%agrid(i,j,2)<0.) then
! Excluding the SH cyclones
                           depress(i,j) = 0.
                      endif
                   enddo
                enddo
                call prt_maxmin('NH Deps', depress, isc, iec, jsc, jec, 0,   1, 1.)

! ATL basin cyclones
                do j=jsc,jec
                   do i=isc,iec
                      tmp = rad2deg * Atm(n)%gridstruct%agrid(i,j,1)
                      if ( tmp<280. ) then
                           depress(i,j) = 0.
                      endif
                   enddo
                enddo
                call prt_maxmin('ATL Deps', depress, isc, iec, jsc, jec, 0,   1, 1.)
             endif
            endif

! Cat 2-5:
            if(idiag%id_c25>0) then
             do j=jsc,jec
                do i=isc,iec
                   if ( cat_crt(i,j) .and. slp(i,j)<980.0 ) then
                        depress(i,j) = 980. - slp(i,j)
                       tc_count(i,j) = 1.
                   else
                        depress(i,j) = 0.
                       tc_count(i,j) = 0.
                   endif
                enddo
             enddo
             used = send_data(idiag%id_c25, depress, Time)
             if(idiag%id_f25>0) used = send_data(idiag%id_f25, tc_count, Time)
            endif

! Cat 3-5:
            if(idiag%id_c35>0) then
             do j=jsc,jec
                do i=isc,iec
                   if ( cat_crt(i,j) .and. slp(i,j)<964.0 ) then
                        depress(i,j) = 964. - slp(i,j)
                       tc_count(i,j) = 1.
                   else
                        depress(i,j) = 0.
                       tc_count(i,j) = 0.
                   endif
                enddo
             enddo
             used = send_data(idiag%id_c35, depress, Time)
             if(idiag%id_f35>0) used = send_data(idiag%id_f35, tc_count, Time)
            endif

! Cat 4-5:
            if(idiag%id_c45>0) then
             do j=jsc,jec
                do i=isc,iec
                   if ( cat_crt(i,j) .and. slp(i,j)<944.0 ) then
                        depress(i,j) = 944. - slp(i,j)
                       tc_count(i,j) = 1.
                   else
                        depress(i,j) = 0.
                       tc_count(i,j) = 0.
                   endif
                enddo
             enddo
             used = send_data(idiag%id_c45, depress, Time)
             if(idiag%id_f45>0) used = send_data(idiag%id_f45, tc_count, Time)
            endif

            if (idiag%id_c15>0) then
                deallocate(depress)
                deallocate(cat_crt)
                deallocate(storm)
                deallocate(ws_max)
                deallocate(tc_count)
            endif

            if(idiag%id_slp>0 )  deallocate( slp )

!           deallocate( a3 )
          endif

!        deallocate ( wz )
      endif

! Temperature:
       idg(:) = idiag%id_t(:)

       do_cs_intp = .false.
       do i=1,nplev
          if ( idg(i)>0 ) then
               do_cs_intp = .true.
               exit
          endif
       enddo

       if ( do_cs_intp ) then  ! log(pe) as the coordinaite for temp re-construction
          if(.not. allocated (a3) ) allocate( a3(isc:iec,jsc:jec,nplev) )
          call cs3_interpolator(isc,iec,jsc,jec,npz, Atm(n)%pt(isc:iec,jsc:jec,:), nplev,    &
                                plevs, wz, Atm(n)%peln, idg, a3, 1)
          do i=1,nplev
             if (idg(i)>0) used=send_data(idg(i), a3(isc:iec,jsc:jec,i), Time)
          enddo
          if ( all(idiag%id_t(minloc(abs(levs-100)))>0) .and. prt_minmax ) then
             call prt_mxm('T100:', a3(isc:iec,jsc:jec,11), isc, iec, jsc, jec, 0, 1, 1.,   &
                          Atm(n)%gridstruct%area_64, Atm(n)%domain)
             if (.not. Atm(n)%neststruct%nested)  then
                tmp = 0.
                sar = 0.
                !            Compute mean temp at 100 mb near EQ
                do j=jsc,jec
                   do i=isc,iec
                      slat = Atm(n)%gridstruct%agrid(i,j,2)*rad2deg
                      if( (slat>-10.0 .and. slat<10.) ) then
                         sar = sar + Atm(n)%gridstruct%area(i,j)
                         tmp = tmp + a3(i,j,11)*Atm(n)%gridstruct%area(i,j)
                      endif
                   enddo
                enddo
                call mp_reduce_sum(sar)
                call mp_reduce_sum(tmp)
                if ( sar > 0. ) then
                   if (master) write(*,*) 'Tropical [10s,10n] mean T100 =', tmp/sar
                else
                   if (master) write(*,*) 'Warning: problem computing tropical mean T100'
                endif
             endif
          endif
          if ( all(idiag%id_t(minloc(abs(levs-200)))>0) .and. prt_minmax ) then
             call prt_mxm('T200:', a3(isc:iec,jsc:jec,13), isc, iec, jsc, jec, 0, 1, 1.,   &
                          Atm(n)%gridstruct%area_64, Atm(n)%domain)
             if (.not. Atm(n)%neststruct%nested) then
                tmp = 0.
                sar = 0.
                do j=jsc,jec
                   do i=isc,iec
                      slat = Atm(n)%gridstruct%agrid(i,j,2)*rad2deg
                      if( (slat>-20 .and. slat<20) ) then
                         sar = sar + Atm(n)%gridstruct%area(i,j)
                         tmp = tmp + a3(i,j,13)*Atm(n)%gridstruct%area(i,j)
                      endif
                   enddo
                enddo
                call mp_reduce_sum(sar)
                call mp_reduce_sum(tmp)
                if ( sar > 0. ) then
                   if (master) write(*,*) 'Tropical [-20.,20.] mean T200 =', tmp/sar
                endif
             endif
          endif
          deallocate( a3 )
       endif

       if (idiag%id_t_plev>0) then
         if(.not. allocated (a3) ) allocate( a3(isc:iec,jsc:jec,nplev) )
         id1(:) = 1
         call cs3_interpolator(isc,iec,jsc,jec,npz, Atm(n)%pt(isc:iec,jsc:jec,:), nplev,    &
                               plevs, wz, Atm(n)%peln, id1, a3, 1)
         used=send_data(idiag%id_t_plev, a3(isc:iec,jsc:jec,:), Time)
         deallocate( a3 )
       endif

       if(idiag%id_mq > 0)  then
          do j=jsc,jec
             do i=isc,iec
! zxg * surface pressure * 1.e-18--> Hadleys per unit area
! Unit Hadley = 1.E18 kg m**2 / s**2
                a2(i,j) = -1.e-18 * Atm(n)%ps(i,j)*idiag%zxg(i,j)
             enddo
          enddo
          used = send_data(idiag%id_mq, a2, Time)
          if( prt_minmax ) then
              tot_mq  = g_sum( Atm(n)%domain, a2, isc, iec, jsc, jec, ngc, Atm(n)%gridstruct%area_64, 0) 
              idiag%mtq_sum = idiag%mtq_sum + tot_mq
              if ( idiag%steps <= max_step ) idiag%mtq(idiag%steps) = tot_mq
              if(master) write(*,*) 'Total (global) mountain torque (Hadleys)=', tot_mq
          endif
       endif

       if (idiag%id_ts > 0) used = send_data(idiag%id_ts, Atm(n)%ts(isc:iec,jsc:jec), Time)

       if ( idiag%id_tq>0 ) then
          nwater = Atm(1)%flagstruct%nwat
          a2 = 0.
          do k=1,npz
          do j=jsc,jec
             do i=isc,iec
!               a2(i,j) = a2(i,j) + Atm(n)%q(i,j,k,1)*Atm(n)%delp(i,j,k)
                a2(i,j) = a2(i,j) + sum(Atm(n)%q(i,j,k,1:nwater))*Atm(n)%delp(i,j,k)
             enddo
          enddo
          enddo
          used = send_data(idiag%id_tq, a2*ginv, Time)
       endif
#ifdef HIWPP
       Cl  = get_tracer_index (MODEL_ATMOS, 'Cl')
       Cl2 = get_tracer_index (MODEL_ATMOS, 'Cl2')
       if (Cl > 0 .and. Cl2 > 0) then
        allocate(var2(isc:iec,jsc:jec))
          var2 = 0.
          do k=1,npz
          do j=jsc,jec
          do i=isc,iec
             var2(i,j) = var2(i,j) + Atm(n)%delp(i,j,k)
          enddo
          enddo
          enddo

          if ( idiag%id_acl > 0 ) then
             a2 = 0.
             einf = 0.
             qm = 0.
             do k=1,npz
                do j=jsc,jec
                   do i=isc,iec
                      a2(i,j) = a2(i,j) + Atm(n)%q(i,j,k,Cl)*Atm(n)%delp(i,j,k) ! moist mass
                   enddo
                enddo
             enddo
             !Convert to mean mixing ratio
             do j=jsc,jec
             do i=isc,iec
                a2(i,j) = a2(i,j) / var2(i,j)
             enddo
             enddo
             used = send_data(idiag%id_acl, a2, Time)
          endif
          if ( idiag%id_acl2 > 0 ) then
             a2 = 0.
             einf = 0.
             qm = 0.
             do k=1,npz
                do j=jsc,jec
                   do i=isc,iec
                      a2(i,j) = a2(i,j) + Atm(n)%q(i,j,k,Cl2)*Atm(n)%delp(i,j,k) ! moist mass
                   enddo
                enddo
             enddo
             !Convert to mean mixing ratio
             do j=jsc,jec
             do i=isc,iec
                a2(i,j) = a2(i,j) / var2(i,j)
             enddo
             enddo
             used = send_data(idiag%id_acl2, a2, Time)
          endif
          if ( idiag%id_acly > 0 ) then
             a2 = 0.
             einf = 0.
             qm = 0.
             e2 = 0.
             do k=1,npz
                do j=jsc,jec
                   do i=isc,iec
                      mm = (Atm(n)%q(i,j,k,Cl)+2.*Atm(n)%q(i,j,k,Cl2))*Atm(n)%delp(i,j,k) ! moist mass
                      a2(i,j) = a2(i,j) + mm
                      qm = qm + mm*Atm(n)%gridstruct%area_64(i,j)
                   enddo
                enddo
             enddo
             !Convert to mean mixing ratio
             do j=jsc,jec
             do i=isc,iec
                a2(i,j) = a2(i,j) / var2(i,j)
             enddo
             enddo
             used = send_data(idiag%id_acly, a2, Time)
             do j=jsc,jec
                do i=isc,iec
                   e2 = e2 + ((a2(i,j) - qcly0)**2)*Atm(n)%gridstruct%area_64(i,j)
                   einf = max(einf, abs(a2(i,j) - qcly0))
                enddo
             enddo
             if (prt_minmax .and. .not. Atm(n)%neststruct%nested) then
                call mp_reduce_sum(qm)
                call mp_reduce_max(einf)
                call mp_reduce_sum(e2)
                if (master) then
                   write(*,*) ' TERMINATOR TEST: '
                   write(*,*) '      chlorine mass: ', real(qm)/(4.*pi*RADIUS*RADIUS)
                   write(*,*) '             L2 err: ', sqrt(e2)/sqrt(4.*pi*RADIUS*RADIUS)/qcly0
                   write(*,*) '            max err: ', einf/qcly0
                endif
             endif
          endif

          deallocate(var2)

       endif
#endif
       if ( idiag%id_iw>0 ) then
          a2 = 0.
          if (ice_wat > 0) then
             do k=1,npz
             do j=jsc,jec
             do i=isc,iec
                a2(i,j) = a2(i,j) + Atm(n)%delp(i,j,k) *       &
                                    Atm(n)%q(i,j,k,ice_wat)
             enddo
             enddo
             enddo
          endif
          if (snowwat > 0) then
             do k=1,npz
             do j=jsc,jec
             do i=isc,iec
                a2(i,j) = a2(i,j) + Atm(n)%delp(i,j,k) *      &
                                    Atm(n)%q(i,j,k,snowwat)
             enddo
             enddo
             enddo
          endif
          if (graupel > 0) then
             do k=1,npz
             do j=jsc,jec
             do i=isc,iec
                a2(i,j) = a2(i,j) + Atm(n)%delp(i,j,k) *      &
                                    Atm(n)%q(i,j,k,graupel)
             enddo
             enddo
             enddo
          endif
          used = send_data(idiag%id_iw, a2*ginv, Time)
       endif
       if ( idiag%id_lw>0 ) then
          a2 = 0.
          if (liq_wat > 0) then
             do k=1,npz
             do j=jsc,jec
             do i=isc,iec
                a2(i,j) = a2(i,j) + Atm(n)%q(i,j,k,liq_wat)*Atm(n)%delp(i,j,k)
             enddo
             enddo
             enddo
          endif
          if (rainwat > 0) then
             do k=1,npz
             do j=jsc,jec
             do i=isc,iec
                a2(i,j) = a2(i,j) + Atm(n)%q(i,j,k,rainwat)*Atm(n)%delp(i,j,k)
             enddo
             enddo
             enddo
          endif
          used = send_data(idiag%id_lw, a2*ginv, Time)
       endif

! Cloud top temperature & cloud top press:
       if ( (idiag%id_ctt>0 .or. idiag%id_ctp>0 .or. idiag%id_ctz>0).and. Atm(n)%flagstruct%nwat==6) then
            allocate ( var1(isc:iec,jsc:jec) )
            allocate ( var2(isc:iec,jsc:jec) )
!$OMP parallel do default(shared) private(tmp)
            do j=jsc,jec
               do i=isc,iec
                  do k=2,npz
                     tmp = atm(n)%q(i,j,k,liq_wat)+atm(n)%q(i,j,k,rainwat)+atm(n)%q(i,j,k,ice_wat)+  &
                           atm(n)%q(i,j,k,snowwat)+atm(n)%q(i,j,k,graupel) 
                     if( tmp>5.e-6 ) then
                         a2(i,j) = Atm(n)%pt(i,j,k)
                         var1(i,j) = 0.01*Atm(n)%pe(i,k,j)
                         var2(i,j) = wz(i,j,k) - wz(i,j,npz+1) ! height AGL
                         exit
                     elseif( k==npz ) then
                        a2(i,j) = missing_value2
                        var1(i,j) = missing_value2
                        var2(i,j) = missing_value2
!!$                           a2(i,j) = Atm(n)%pt(i,j,k)
!!$                         var1(i,j) = 0.01*Atm(n)%pe(i,k+1,j)   ! surface pressure
                     endif
                  enddo
               enddo
            enddo
          if ( idiag%id_ctt>0 ) then
               used = send_data(idiag%id_ctt, a2, Time)
               if(prt_minmax) call prt_maxmin('Cloud_top_T (K)', a2, isc, iec, jsc, jec, 0, 1, 1.)
          endif
          if ( idiag%id_ctp>0 ) then
               used = send_data(idiag%id_ctp, var1, Time)
               if(prt_minmax) call prt_maxmin('Cloud_top_P (mb)', var1, isc, iec, jsc, jec, 0, 1, 1.)
          endif
          deallocate ( var1 )
          if ( idiag%id_ctz>0 ) then
               used = send_data(idiag%id_ctz, var2, Time)
               if(prt_minmax) call prt_maxmin('Cloud_top_z (m)', var2, isc, iec, jsc, jec, 0, 1, 1.)
          endif
          deallocate ( var2 )
       endif

! Condensates:
       if ( idiag%id_qn>0 .or. idiag%id_qn200>0 .or. idiag%id_qn500>0 .or. idiag%id_qn850>0 ) then
!$OMP parallel do default(shared)
          do k=1,npz
          do j=jsc,jec
          do i=isc,iec
             wk(i,j,k) = 0.
          enddo
          enddo
          enddo
          if (liq_wat > 0) then
!$OMP parallel do default(shared)
             do k=1,npz
             do j=jsc,jec
             do i=isc,iec
                wk(i,j,k) = wk(i,j,k) + Atm(n)%q(i,j,k,liq_wat)*Atm(n)%delp(i,j,k)
             enddo
             enddo
             enddo
          endif
          if (ice_wat > 0) then
!$OMP parallel do default(shared)
             do k=1,npz
             do j=jsc,jec
             do i=isc,iec
                wk(i,j,k) = wk(i,j,k) + Atm(n)%q(i,j,k,ice_wat)*Atm(n)%delp(i,j,k)
             enddo
             enddo
             enddo
          endif
          if ( idiag%id_qn>0 ) used = send_data(idiag%id_qn, wk, Time)
          if ( idiag%id_qn200>0 ) then
            call interpolate_vertical(isc, iec, jsc, jec, npz, 200.e2, Atm(n)%peln, wk, a2)
            used=send_data(idiag%id_qn200, a2, Time)
          endif
          if ( idiag%id_qn500>0 ) then
            call interpolate_vertical(isc, iec, jsc, jec, npz, 500.e2, Atm(n)%peln, wk, a2)
            used=send_data(idiag%id_qn500, a2, Time)
          endif
          if ( idiag%id_qn850>0 ) then
            call interpolate_vertical(isc, iec, jsc, jec, npz, 850.e2, Atm(n)%peln, wk, a2)
            used=send_data(idiag%id_qn850, a2, Time)
          endif
       endif
! Total 3D condensates
       if ( idiag%id_qp>0 ) then
!$OMP parallel do default(shared)
          do k=1,npz
          do j=jsc,jec
          do i=isc,iec
             wk(i,j,k) = 0.
          enddo
          enddo
          enddo
          if (rainwat > 0) then
!$OMP parallel do default(shared)
             do k=1,npz
             do j=jsc,jec
             do i=isc,iec
                wk(i,j,k) = wk(i,j,k) + Atm(n)%q(i,j,k,rainwat)*Atm(n)%delp(i,j,k)
             enddo
             enddo
             enddo
          endif
          if (snowwat > 0) then
!$OMP parallel do default(shared)
             do k=1,npz
             do j=jsc,jec
             do i=isc,iec
                wk(i,j,k) = wk(i,j,k) + Atm(n)%q(i,j,k,snowwat)*Atm(n)%delp(i,j,k)
             enddo
             enddo
             enddo
          endif
          if (graupel > 0) then
!$OMP parallel do default(shared)
             do k=1,npz
             do j=jsc,jec
             do i=isc,iec
                wk(i,j,k) = wk(i,j,k) + Atm(n)%q(i,j,k,graupel)*Atm(n)%delp(i,j,k)
             enddo
             enddo
             enddo
          endif
          used = send_data(idiag%id_qp, wk, Time)
       endif

       if(idiag%id_us > 0 .and. idiag%id_vs > 0) then
          u2(:,:) = Atm(n)%ua(isc:iec,jsc:jec,npz)
          v2(:,:) = Atm(n)%va(isc:iec,jsc:jec,npz)
          do j=jsc,jec
             do i=isc,iec
                a2(i,j) = sqrt(u2(i,j)**2 + v2(i,j)**2)
             enddo
          enddo
          used=send_data(idiag%id_us, u2, Time)
          used=send_data(idiag%id_vs, v2, Time)
          if(prt_minmax) call prt_maxmin('Surf_wind_speed', a2, isc, iec, jsc, jec, 0, 1, 1.)
       endif

       if(idiag%id_tb > 0) then
          a2(:,:) = Atm(n)%pt(isc:iec,jsc:jec,npz)
          used=send_data(idiag%id_tb, a2, Time)
          if( prt_minmax )   &
          call prt_mxm('T_bot:', a2, isc, iec, jsc, jec, 0, 1, 1., Atm(n)%gridstruct%area_64, Atm(n)%domain)
       endif

       if(idiag%id_ua > 0) used=send_data(idiag%id_ua, Atm(n)%ua(isc:iec,jsc:jec,:), Time)
       if(idiag%id_va > 0) used=send_data(idiag%id_va, Atm(n)%va(isc:iec,jsc:jec,:), Time)

       if(idiag%id_ke > 0) then
          a2(:,:) = 0.
          do k=1,npz
          do j=jsc,jec
             do i=isc,iec
                a2(i,j) = a2(i,j) + Atm(n)%delp(i,j,k)*(Atm(n)%ua(i,j,k)**2+Atm(n)%va(i,j,k)**2)
             enddo
          enddo
          enddo
! Mass weighted KE 
          do j=jsc,jec
             do i=isc,iec
                a2(i,j) = 0.5*a2(i,j)/(Atm(n)%ps(i,j)-ptop)
             enddo
          enddo
          used=send_data(idiag%id_ke, a2, Time)
          if(prt_minmax) then
             tot_mq  = g_sum( Atm(n)%domain, a2, isc, iec, jsc, jec, ngc, Atm(n)%gridstruct%area_64, 1) 
             if (master) write(*,*) 'SQRT(2.*KE; m/s)=', sqrt(2.*tot_mq)  
          endif
       endif


#ifdef GFS_PHYS
       if(idiag%id_delp > 0 .or. idiag%id_cape > 0 .or. idiag%id_cin > 0 .or. ((.not. Atm(n)%flagstruct%hydrostatic) .and. idiag%id_pfnh > 0)) then
          do k=1,npz
            do j=jsc,jec
            do i=isc,iec         
              wk(i,j,k) = Atm(n)%delp(i,j,k)*(1.-sum(Atm(n)%q(i,j,k,2:Atm(n)%flagstruct%nwat)))
            enddo
            enddo
          enddo
          if (idiag%id_delp > 0) used=send_data(idiag%id_delp, wk, Time)
       endif

       if( ( (.not. Atm(n)%flagstruct%hydrostatic) .and. idiag%id_pfnh > 0) .or. idiag%id_cape > 0 .or. idiag%id_cin > 0) then
           do k=1,npz
             do j=jsc,jec
             do i=isc,iec         
#ifdef MULTI_GASES
                 wk(i,j,k) = -wk(i,j,k)/(Atm(n)%delz(i,j,k)*grav)*rdgas*  &
                             Atm(n)%pt(i,j,k)*virq(Atm(n)%q(i,j,k,1:num_gas))
#else
                 wk(i,j,k) = -wk(i,j,k)/(Atm(n)%delz(i,j,k)*grav)*rdgas*  &
                             Atm(n)%pt(i,j,k)*(1.+zvir*Atm(n)%q(i,j,k,sphum))
#endif
             enddo
             enddo
           enddo
!           if (prt_minmax) then
!              call prt_maxmin(' PFNH (mb)', wk(isc:iec,jsc:jec,1), isc, iec, jsc, jec, 0, npz, 1.E-2)
!           endif
           used=send_data(idiag%id_pfnh, wk, Time)
       endif
#else
       if(idiag%id_delp > 0) used=send_data(idiag%id_delp, Atm(n)%delp(isc:iec,jsc:jec,:), Time)

       if( (.not. Atm(n)%flagstruct%hydrostatic) .and. (idiag%id_pfnh > 0 .or.  idiag%id_cape > 0 .or. idiag%id_cin > 0)) then
           do k=1,npz
             do j=jsc,jec
             do i=isc,iec
#ifdef MULTI_GASES
                 wk(i,j,k) = -Atm(n)%delp(i,j,k)/(Atm(n)%delz(i,j,k)*grav)*rdgas*          &
                              Atm(n)%pt(i,j,k)*virq(Atm(n)%q(i,j,k,1:num_gas))
#else
                 wk(i,j,k) = -Atm(n)%delp(i,j,k)/(Atm(n)%delz(i,j,k)*grav)*rdgas*          &
                              Atm(n)%pt(i,j,k)*(1.+zvir*Atm(n)%q(i,j,k,sphum))
#endif
             enddo
             enddo
           enddo
           used=send_data(idiag%id_pfnh, wk, Time)
       endif
#endif

      if( Atm(n)%flagstruct%hydrostatic .and. (idiag%id_pfhy > 0 .or. idiag%id_cape > 0 .or. idiag%id_cin > 0) ) then
          do k=1,npz
            do j=jsc,jec
            do i=isc,iec         
                wk(i,j,k) = 0.5 *(Atm(n)%pe(i,k,j)+Atm(n)%pe(i,k+1,j))
            enddo
            enddo
          enddo
          used=send_data(idiag%id_pfhy, wk, Time)
      endif

       if (idiag%id_cape > 0 .or. idiag%id_cin > 0) then
          !wk here contains layer-mean pressure

          allocate(var2(isc:iec,jsc:jec))
          allocate(a3(isc:iec,jsc:jec,npz))
          call eqv_pot(a3, Atm(n)%pt, Atm(n)%delp, Atm(n)%delz, Atm(n)%peln, Atm(n)%pkz, Atm(n)%q(isd:ied,jsd:jed,1:npz,sphum), &
                       isc, iec, jsc, jec, ngc, npz, Atm(n)%flagstruct%hydrostatic, Atm(n)%flagstruct%moist_phys)

!$OMP parallel do default(shared)
          do j=jsc,jec
          do i=isc,iec
             a2(i,j) = 0.
             var2(i,j) = 0.

             call getcape(npz, wk(i,j,:), Atm(n)%pt(i,j,:), -Atm(n)%delz(i,j,:), Atm(n)%q(i,j,:,sphum), a3(i,j,:), a2(i,j), var2(i,j), source_in=1)
          enddo
          enddo

          if (idiag%id_cape > 0) then
             if (prt_minmax) then
                call prt_maxmin(' CAPE (J/kg)', a2, isc,iec,jsc,jec, 0, 1, 1.)
             endif
             used=send_data(idiag%id_cape, a2, Time)
          endif
          if (idiag%id_cin > 0) then
             if (prt_minmax) then
                call prt_maxmin(' CIN (J/kg)', var2, isc,iec,jsc,jec, 0, 1, 1.)
             endif
             used=send_data(idiag%id_cin, var2, Time)
          endif

          deallocate(var2)
          deallocate(a3)

       endif


       if((.not. Atm(n)%flagstruct%hydrostatic) .and. idiag%id_delz > 0) then
          do k=1,npz
            do j=jsc,jec
            do i=isc,iec
               wk(i,j,k) = -Atm(n)%delz(i,j,k)
            enddo
            enddo
          enddo
          used=send_data(idiag%id_delz, wk, Time)
       endif
 

! pressure for masking p-level fields
! incorrectly defines a2 to be ps (in mb).
       if (idiag%id_pmask>0) then
            do j=jsc,jec
            do i=isc,iec
                a2(i,j) = exp((Atm(n)%peln(i,npz+1,j)+Atm(n)%peln(i,npz+1,j))*0.5)*0.01
               !a2(i,j) = Atm(n)%delp(i,j,k)/(Atm(n)%peln(i,k+1,j)-Atm(n)%peln(i,k,j))*0.01
            enddo
            enddo
            used=send_data(idiag%id_pmask, a2, Time)
       endif
! fix for pressure for masking p-level fields
! based on lowest-level pfull
! define pressure at lowest level the same as interpolate_vertical (in mb)
       if (idiag%id_pmaskv2>0) then
            do j=jsc,jec
            do i=isc,iec
                a2(i,j) = exp((Atm(n)%peln(i,npz,j)+Atm(n)%peln(i,npz+1,j))*0.5)*0.01
            enddo
            enddo
            used=send_data(idiag%id_pmaskv2, a2, Time)
       endif

       if ( idiag%id_u100m>0 .or. idiag%id_v100m>0 .or. idiag%id_w100m>0 .or. idiag%id_w5km>0 .or. idiag%id_w2500m>0 .or. idiag%id_w1km>0 .or. idiag%id_basedbz>0 .or. idiag%id_dbz4km>0) then
          if (.not.allocated(wz)) allocate ( wz(isc:iec,jsc:jec,npz+1) )
          if ( Atm(n)%flagstruct%hydrostatic) then
             rgrav = 1. / grav
!$OMP parallel do default(none) shared(isc,iec,jsc,jec,wz,npz,Atm,n,rgrav)
            do j=jsc,jec
               do i=isc,iec
                  wz(i,j,npz+1) = 0.
!                  wz(i,j,npz+1) = Atm(n)%phis(i,j)/grav
               enddo
               do k=npz,1,-1
                  do i=isc,iec
                     wz(i,j,k) = wz(i,j,k+1) - (rdgas*rgrav)*Atm(n)%pt(i,j,k)*(Atm(n)%peln(i,k,j) - Atm(n)%peln(i,k+1,j))
                  enddo
               enddo
            enddo
          else
!$OMP parallel do default(none) shared(isc,iec,jsc,jec,wz,npz,Atm,n)
            do j=jsc,jec
               do i=isc,iec
                  wz(i,j,npz+1) = 0.
!                  wz(i,j,npz+1) = Atm(n)%phis(i,j)/grav
               enddo
               do k=npz,1,-1
                  do i=isc,iec
                     wz(i,j,k) = wz(i,j,k+1) - Atm(n)%delz(i,j,k)
                  enddo
               enddo
            enddo
         endif
            if( prt_minmax )   &
                 call prt_maxmin('ZTOP', wz(isc:iec,jsc:jec,1)+Atm(n)%phis(isc:iec,jsc:jec)/grav, isc, iec, jsc, jec, 0, 1, 1.E-3)
       endif

       if ( idiag%id_rain5km>0 ) then
            rainwat = get_tracer_index (MODEL_ATMOS, 'rainwat')
            call interpolate_z(isc, iec, jsc, jec, npz, 5.e3, wz, Atm(n)%q(isc:iec,jsc:jec,:,rainwat), a2)
            used=send_data(idiag%id_rain5km, a2, Time)
            if(prt_minmax) call prt_maxmin('rain5km', a2, isc, iec, jsc, jec, 0, 1, 1.)
       endif
       if ( idiag%id_w5km>0 ) then
            call interpolate_z(isc, iec, jsc, jec, npz, 5.e3, wz, Atm(n)%w(isc:iec,jsc:jec,:), a2)
            used=send_data(idiag%id_w5km, a2, Time)
            if(prt_minmax) call prt_maxmin('W5km', a2, isc, iec, jsc, jec, 0, 1, 1.)
       endif
       if ( idiag%id_w2500m>0 ) then
            call interpolate_z(isc, iec, jsc, jec, npz, 2.5e3, wz, Atm(n)%w(isc:iec,jsc:jec,:), a2)
            used=send_data(idiag%id_w2500m, a2, Time)
            if(prt_minmax) call prt_maxmin('W2500m', a2, isc, iec, jsc, jec, 0, 1, 1.)
       endif
       if ( idiag%id_w1km>0 ) then
            call interpolate_z(isc, iec, jsc, jec, npz, 1.e3, wz, Atm(n)%w(isc:iec,jsc:jec,:), a2)
            used=send_data(idiag%id_w1km, a2, Time)
            if(prt_minmax) call prt_maxmin('W1km', a2, isc, iec, jsc, jec, 0, 1, 1.)
       endif
       if ( idiag%id_w100m>0 ) then
            call interpolate_z(isc, iec, jsc, jec, npz, 100., wz, Atm(n)%w(isc:iec,jsc:jec,:), a2)
            used=send_data(idiag%id_w100m, a2, Time)
            if(prt_minmax) call prt_maxmin('w100m', a2, isc, iec, jsc, jec, 0, 1, 1.)
       endif
       if ( idiag%id_u100m>0 ) then
            call interpolate_z(isc, iec, jsc, jec, npz, 100., wz, Atm(n)%ua(isc:iec,jsc:jec,:), a2)
            used=send_data(idiag%id_u100m, a2, Time)
            if(prt_minmax) call prt_maxmin('u100m', a2, isc, iec, jsc, jec, 0, 1, 1.)
       endif
       if ( idiag%id_v100m>0 ) then
            call interpolate_z(isc, iec, jsc, jec, npz, 100., wz, Atm(n)%va(isc:iec,jsc:jec,:), a2)
            used=send_data(idiag%id_v100m, a2, Time)
            if(prt_minmax) call prt_maxmin('v100m', a2, isc, iec, jsc, jec, 0, 1, 1.)
       endif

       if ( rainwat > 0 .and. (idiag%id_dbz>0 .or. idiag%id_maxdbz>0 .or. idiag%id_basedbz>0 .or. idiag%id_dbz4km>0 .or. idiag%id_dbztop>0 .or. idiag%id_dbz_m10C>0)) then

          if (.not. allocated(a3)) allocate(a3(isc:iec,jsc:jec,npz))

!          call dbzcalc_smithxue(Atm(n)%q, Atm(n)%pt, Atm(n)%delp, Atm(n)%peln, Atm(n)%delz, &
          call dbzcalc(Atm(n)%q, Atm(n)%pt, Atm(n)%delp, Atm(n)%peln, Atm(n)%delz, &
               a3, a2, allmax, Atm(n)%bd, npz, Atm(n)%ncnst, Atm(n)%flagstruct%hydrostatic, &
               zvir, .false., .false., .false., .true. ) ! GFDL MP has constant N_0 intercept

          if (idiag%id_dbz > 0) used=send_data(idiag%id_dbz, a3, time)
          if (idiag%id_maxdbz > 0) used=send_data(idiag%id_maxdbz, a2, time)

          if (idiag%id_basedbz > 0) then
             !interpolate to 1km dbz
             call cs_interpolator(isc, iec, jsc, jec, npz, a3, 1000., wz, a2, -20.)
             used=send_data(idiag%id_basedbz, a2, time)
             if(prt_minmax) call prt_maxmin('Base_dBz', a2, isc, iec, jsc, jec, 0, 1, 1.)
          endif

          if (idiag%id_dbz4km > 0) then
             !interpolate to 1km dbz
             call cs_interpolator(isc, iec, jsc, jec, npz, a3, 4000., wz, a2, -20.)
             used=send_data(idiag%id_dbz4km, a2, time)
          endif
          if (idiag%id_dbztop > 0) then
             do j=jsc,jec
             do i=isc,iec
                a2(i,j) = missing_value
             do k=2,npz
                if (wz(i,j,k) >= 25000. ) continue ! nothing above 25 km
                if (a3(i,j,k) >= 18.5 ) then
                   a2(i,j) = wz(i,j,k)
                   exit
                endif
             enddo
             enddo
             enddo
             used=send_data(idiag%id_dbztop, a2, time)
          endif
          if (idiag%id_dbz_m10C > 0) then
             do j=jsc,jec
             do i=isc,iec
                a2(i,j) = missing_value
             do k=npz,1,-1
                if (wz(i,j,k) >= 25000. ) exit ! nothing above 25 km
                if (Atm(n)%pt(i,j,k) <= 263.14 ) then
                   a2(i,j) = a3(i,j,k)
                   exit
                endif
             enddo
             enddo
             enddo
             used=send_data(idiag%id_dbz_m10C, a2, time)
          endif

          if (prt_minmax) then
             call mpp_max(allmax)
             if (master) write(*,*) 'max reflectivity = ', allmax, ' dBZ'
          endif

          deallocate(a3)
       endif
!-------------------------------------------------------
! Applying cubic-spline as the intepolator for (u,v,T,q)
!-------------------------------------------------------
       if(.not. allocated(a3)) allocate( a3(isc:iec,jsc:jec,nplev) )
! u-winds:
       idg(:) = idiag%id_u(:)

       do_cs_intp = .false.
       do i=1,nplev
          if ( idg(i)>0 ) then
               do_cs_intp = .true.
               exit
          endif
       enddo

       if ( do_cs_intp ) then
          call cs3_interpolator(isc,iec,jsc,jec,npz, Atm(n)%ua(isc:iec,jsc:jec,:), nplev,    &
                               pout, wz, Atm(n)%pe(isc:iec,1:npz+1,jsc:jec), idg, a3, -1)
!                              plevs, Atm(n)%peln, idg, a3, -1)
          do i=1,nplev
             if (idg(i)>0) used=send_data(idg(i), a3(isc:iec,jsc:jec,i), Time)
          enddo
       endif

       if (idiag%id_u_plev>0) then
         id1(:) = 1
         call cs3_interpolator(isc,iec,jsc,jec,npz, Atm(n)%ua(isc:iec,jsc:jec,:), nplev,    &
                              pout, wz, Atm(n)%pe(isc:iec,1:npz+1,jsc:jec), id1, a3, -1)
         used=send_data(idiag%id_u_plev, a3(isc:iec,jsc:jec,:), Time)
       endif

! v-winds:
       idg(:) = idiag%id_v(:)

       do_cs_intp = .false.
       do i=1,nplev
          if ( idg(i)>0 ) then
               do_cs_intp = .true.
               exit
          endif
       enddo

       if ( do_cs_intp ) then
          call cs3_interpolator(isc,iec,jsc,jec,npz, Atm(n)%va(isc:iec,jsc:jec,:), nplev,    &
                               pout, wz, Atm(n)%pe(isc:iec,1:npz+1,jsc:jec), idg, a3, -1)
!                              plevs, Atm(n)%peln, idg, a3, -1)
          do i=1,nplev
             if (idg(i)>0) used=send_data(idg(i), a3(isc:iec,jsc:jec,i), Time)
          enddo
       endif

       if (idiag%id_v_plev>0) then
         id1(:) = 1
         call cs3_interpolator(isc,iec,jsc,jec,npz, Atm(n)%va(isc:iec,jsc:jec,:), nplev,    &
                              pout, wz, Atm(n)%pe(isc:iec,1:npz+1,jsc:jec), id1, a3, -1)
         used=send_data(idiag%id_v_plev, a3(isc:iec,jsc:jec,:), Time)
       endif

! Specific humidity
       idg(:) = idiag%id_q(:)

       do_cs_intp = .false.
       do i=1,nplev
          if ( idg(i)>0 ) then
               do_cs_intp = .true.
               exit
          endif
       enddo

       if ( do_cs_intp ) then
          call cs3_interpolator(isc,iec,jsc,jec,npz, Atm(n)%q(isc:iec,jsc:jec,:,sphum), nplev, &
                               pout, wz, Atm(n)%pe(isc:iec,1:npz+1,jsc:jec), idg, a3, 0)
!                              plevs, Atm(n)%peln, idg, a3, 0)
          do i=1,nplev
             if (idg(i)>0) used=send_data(idg(i), a3(isc:iec,jsc:jec,i), Time)
          enddo
       endif

       if (idiag%id_q_plev>0) then
         id1(:) = 1
         call cs3_interpolator(isc,iec,jsc,jec,npz, Atm(n)%q(isc:iec,jsc:jec,:,sphum), nplev, &
                              pout, wz, Atm(n)%pe(isc:iec,1:npz+1,jsc:jec), id1, a3, 0)
         used=send_data(idiag%id_q_plev, a3(isc:iec,jsc:jec,:), Time)
       endif

! Omega
       idg(:) = idiag%id_omg(:)

       do_cs_intp = .false.
       do i=1,nplev
          if ( idg(i)>0 ) then
               do_cs_intp = .true.
               exit
          endif
       enddo
       if ( do_cs_intp ) then
          call cs3_interpolator(isc,iec,jsc,jec,npz, Atm(n)%omga(isc:iec,jsc:jec,:), nplev,    &
                               pout, wz, Atm(n)%pe(isc:iec,1:npz+1,jsc:jec), idg, a3, -1)
!                              plevs, Atm(n)%peln, idg, a3)
          do i=1,nplev
             if (idg(i)>0) used=send_data(idg(i), a3(isc:iec,jsc:jec,i), Time)
          enddo
       endif

       if (idiag%id_omg_plev>0) then
         id1(:) = 1
         call cs3_interpolator(isc,iec,jsc,jec,npz, Atm(n)%omga(isc:iec,jsc:jec,:), nplev,    &
                              pout, wz, Atm(n)%pe(isc:iec,1:npz+1,jsc:jec), id1, a3, -1)
         used=send_data(idiag%id_omg_plev, a3(isc:iec,jsc:jec,:), Time)
       endif

       if( allocated(a3) ) deallocate (a3)
! *** End cs_intp

       if ( idiag%id_sl12>0 ) then   ! 13th level wind speed (~ 222 mb for the 32L setup)
            do j=jsc,jec
               do i=isc,iec
                  a2(i,j) = sqrt(Atm(n)%ua(i,j,12)**2 + Atm(n)%va(i,j,12)**2)
               enddo
            enddo
            used=send_data(idiag%id_sl12, a2, Time)
       endif
       if ( idiag%id_sl13>0 ) then   ! 13th level wind speed (~ 222 mb for the 32L setup)
            do j=jsc,jec
               do i=isc,iec
                  a2(i,j) = sqrt(Atm(n)%ua(i,j,13)**2 + Atm(n)%va(i,j,13)**2)
               enddo
            enddo
            used=send_data(idiag%id_sl13, a2, Time)
       endif

       if ( (.not.Atm(n)%flagstruct%hydrostatic) .and. idiag%id_w200>0 ) then
            call interpolate_vertical(isc, iec, jsc, jec, npz,   &
                                      200.e2, Atm(n)%peln, Atm(n)%w(isc:iec,jsc:jec,:), a2)
            used=send_data(idiag%id_w200, a2, Time)
       endif
! 500-mb
       if ( (.not.Atm(n)%flagstruct%hydrostatic) .and. idiag%id_w500>0 ) then
            call interpolate_vertical(isc, iec, jsc, jec, npz,   &
                                      500.e2, Atm(n)%peln, Atm(n)%w(isc:iec,jsc:jec,:), a2)
            used=send_data(idiag%id_w500, a2, Time)
       endif
       if ( (.not.Atm(n)%flagstruct%hydrostatic) .and. idiag%id_w700>0 ) then
            call interpolate_vertical(isc, iec, jsc, jec, npz,   &
                                      700.e2, Atm(n)%peln, Atm(n)%w(isc:iec,jsc:jec,:), a2)
            used=send_data(idiag%id_w700, a2, Time)
       endif
       if ( (.not.Atm(n)%flagstruct%hydrostatic) .and. idiag%id_w850>0 .or. idiag%id_x850>0) then
            call interpolate_vertical(isc, iec, jsc, jec, npz,   &
                                      850.e2, Atm(n)%peln, Atm(n)%w(isc:iec,jsc:jec,:), a2)
            used=send_data(idiag%id_w850, a2, Time)

            if ( idiag%id_x850>0 .and. idiag%id_vort850>0 ) then
                 x850(:,:) = x850(:,:)*a2(:,:) 
                 used=send_data(idiag%id_x850, x850, Time)
                 deallocate ( x850 )
            endif
       endif


       if ( .not.Atm(n)%flagstruct%hydrostatic .and. idiag%id_w>0  ) then
          used=send_data(idiag%id_w, Atm(n)%w(isc:iec,jsc:jec,:), Time)
       endif
       if ( .not. Atm(n)%flagstruct%hydrostatic .and. (idiag%id_wmaxup>0 .or. idiag%id_wmaxdn>0) ) then
          allocate(var2(isc:iec,jsc:jec))
          do j=jsc,jec
          do i=isc,iec
             a2(i,j) = 0.
             var2(i,j) = 0.
             do k=3,npz
                if (Atm(n)%pe(i,k,j) <= 400.e2) continue
                a2(i,j) = max(a2(i,j),Atm(n)%w(i,j,k))
                var2(i,j) = min(var2(i,j),Atm(n)%w(i,j,k))
             enddo
          enddo
          enddo
          if (idiag%id_wmaxup > 0) then
             used=send_data(idiag%id_wmaxup, a2, Time)
          endif
          if (idiag%id_wmaxdn > 0) then
             used=send_data(idiag%id_wmaxdn, var2, Time)
          endif
          deallocate(var2)
       endif

       if(idiag%id_pt   > 0) used=send_data(idiag%id_pt  , Atm(n)%pt  (isc:iec,jsc:jec,:), Time)
       if(idiag%id_omga > 0) used=send_data(idiag%id_omga, Atm(n)%omga(isc:iec,jsc:jec,:), Time)
       if(idiag%id_diss > 0) used=send_data(idiag%id_diss, Atm(n)%diss_est(isc:iec,jsc:jec,:), Time)
       
       allocate( a3(isc:iec,jsc:jec,npz) )
       if(idiag%id_theta_e > 0 ) then

          if ( Atm(n)%flagstruct%adiabatic .and. Atm(n)%flagstruct%kord_tm>0 ) then
             do k=1,npz
                do j=jsc,jec
                   do i=isc,iec
                      a3(i,j,k) = Atm(n)%pt(i,j,k)
                   enddo
                enddo
             enddo
          else
             call eqv_pot(a3, Atm(n)%pt, Atm(n)%delp, Atm(n)%delz, Atm(n)%peln, Atm(n)%pkz, Atm(n)%q(isd:ied,jsd:jed,1:npz,sphum),    &
                  isc, iec, jsc, jec, ngc, npz, Atm(n)%flagstruct%hydrostatic, Atm(n)%flagstruct%moist_phys)
          endif

          if (idiag%id_theta_e > 0) then
             if( prt_minmax ) call prt_maxmin('Theta_E', a3, isc, iec, jsc, jec, 0, npz, 1.)
             used=send_data(idiag%id_theta_e, a3, Time)
          end if
          theta_d = get_tracer_index (MODEL_ATMOS, 'theta_d')
          if ( theta_d>0 ) then
             if( prt_minmax ) then
                ! Check level-34 ~ 300 mb
                a2(:,:) = 0.
                do k=1,npz
                do j=jsc,jec
                do i=isc,iec
                   a2(i,j) = a2(i,j) + Atm(n)%delp(i,j,k)*(Atm(n)%q(i,j,k,theta_d)-a3(i,j,k))**2
                enddo
                enddo
                enddo
                call prt_mxm('PT_SUM', a2, isc, iec, jsc, jec, 0, 1, 1.e-5, Atm(n)%gridstruct%area_64, Atm(n)%domain)

                do k=1,npz
                do j=jsc,jec
                do i=isc,iec
                   a3(i,j,k) =  Atm(n)%q(i,j,k,theta_d)/a3(i,j,k) - 1.
                enddo
                enddo
                enddo
                call prt_maxmin('Theta_Err (%)', a3, isc, iec, jsc, jec, 0, npz, 100.)
                !           if ( master ) write(*,*) 'PK0=', pk0, 'KAPPA=', kappa
             endif
          endif

       endif

       if(idiag%id_ppt> 0) then
! Potential temperature perturbation for gravity wave test_case
          allocate ( idiag%pt1(npz) )
          if( .not. allocated(a3) ) allocate ( a3(isc:iec,jsc:jec,npz) )
#ifdef TEST_GWAVES
          call gw_1d(npz, 1000.E2, Atm(n)%ak, Atm(n)%ak, Atm(n)%ak(1), 10.E3, idiag%pt1)
#else
          idiag%pt1 = 0. 
#endif
          do k=1,npz
          do j=jsc,jec
             do i=isc,iec
!               wk(i,j,k) =  (Atm(n)%pt(i,j,k)-300.)/Atm(n)%pkz(i,j,k) * pk0
                wk(i,j,k) =  (Atm(n)%pt(i,j,k)/Atm(n)%pkz(i,j,k) - idiag%pt1(k)) * pk0
             enddo
          enddo
          enddo
          used=send_data(idiag%id_ppt, wk, Time)

          if( prt_minmax ) then
              call prt_maxmin('PoTemp', wk, isc, iec, jsc, jec, 0, npz, 1.)
          endif

          if( allocated(a3) ) deallocate ( a3 )
          deallocate ( idiag%pt1 )
       endif


#ifndef SW_DYNAMICS
        do itrac=1, Atm(n)%ncnst
          call get_tracer_names (MODEL_ATMOS, itrac, tname)
          if (idiag%id_tracer(itrac) > 0 .and. itrac.gt.nq) then
            used = send_data (idiag%id_tracer(itrac), Atm(n)%qdiag(isc:iec,jsc:jec,:,itrac), Time )
          else
            used = send_data (idiag%id_tracer(itrac), Atm(n)%q(isc:iec,jsc:jec,:,itrac), Time )
          endif
          if (itrac .le. nq) then
            if( prt_minmax ) call prt_maxmin(trim(tname), Atm(n)%q(:,:,1,itrac),     &
                              isc, iec, jsc, jec, ngc, npz, 1.)
          else
            if( prt_minmax ) call prt_maxmin(trim(tname), Atm(n)%qdiag(:,:,1,itrac), &
                              isc, iec, jsc, jec, ngc, npz, 1.)
          endif
!-------------------------------
! ESM TRACER diagnostics output:
! jgj: per SJ email (jul 17 2008): q_dry = q_moist/(1-sphum)
! mass mixing ratio: q_dry = mass_tracer/mass_dryair = mass_tracer/(mass_air - mass_water) ~ q_moist/(1-sphum)
! co2_mmr = (wco2/wair) * co2_vmr
! Note: There is a check to ensure tracer number one is sphum

          if (idiag%id_tracer_dmmr(itrac) > 0 .or. idiag%id_tracer_dvmr(itrac) > 0) then
              if (itrac .gt. nq) then
                dmmr(:,:,:) = Atm(n)%qdiag(isc:iec,jsc:jec,1:npz,itrac)  &
                              /(1.0-Atm(n)%q(isc:iec,jsc:jec,1:npz,1))
              else
                dmmr(:,:,:) = Atm(n)%q(isc:iec,jsc:jec,1:npz,itrac)  &
                              /(1.0-Atm(n)%q(isc:iec,jsc:jec,1:npz,1))
              endif
              dvmr(:,:,:) = dmmr(isc:iec,jsc:jec,1:npz) * WTMAIR/idiag%w_mr(itrac)
              used = send_data (idiag%id_tracer_dmmr(itrac), dmmr, Time )
              used = send_data (idiag%id_tracer_dvmr(itrac), dvmr, Time )
              if( prt_minmax ) then
                 call prt_maxmin(trim(tname)//'_dmmr', dmmr, &
                    isc, iec, jsc, jec, 0, npz, 1.)
                 call prt_maxmin(trim(tname)//'_dvmr', dvmr, & 
                    isc, iec, jsc, jec, 0, npz, 1.)
            endif
          endif
        enddo

! Maximum overlap cloud fraction
      if ( .not. Atm(n)%neststruct%nested )  then
        if ( cld_amt > 0 .and. prt_minmax ) then
          a2(:,:) = 0.
          do k=1,npz
             do j=jsc,jec
             do i=isc,iec
                a2(i,j) =  max(a2(i,j), Atm(n)%q(i,j,k,cld_amt) )
             enddo
             enddo
          enddo
          call prt_gb_nh_sh('Max_cld GB_NH_SH_EQ',isc,iec, jsc,jec, a2, Atm(n)%gridstruct%area_64(isc:iec,jsc:jec),   &
                            Atm(n)%gridstruct%agrid_64(isc:iec,jsc:jec,2))
        endif
      endif

#endif

   ! enddo  ! end ntileMe do-loop

    deallocate ( a2 )
    deallocate ( u2 )
    deallocate ( v2 )
    deallocate ( wk )

    if (allocated(a3)) deallocate(a3)
    if (allocated(wz)) deallocate(wz)
    if (allocated(dmmr)) deallocate(dmmr)
    if (allocated(dvmr)) deallocate(dvmr)

    call nullify_domain()


 end subroutine fv_diag

 subroutine wind_max(isc, iec, jsc, jec ,isd, ied, jsd, jed, us, vs, ws_max, domain)
 integer isc, iec, jsc, jec
 integer isd, ied, jsd, jed
 real, intent(in), dimension(isc:iec,jsc:jec):: us, vs
 real, intent(out) :: ws_max(isc:iec,jsc:jec)
 type(domain2d), intent(INOUT) :: domain
! Local
 real :: wx(isc:iec,jsd:jed), ws(isd:ied,jsd:jed)
 integer:: i,j

 ws = 0.   ! fill corners with zeros
 do j=jsc,jec
    do i=isc,iec
       ws(i,j) = sqrt(us(i,j)**2 + vs(i,j)**2)
    enddo
 enddo

 call mpp_update_domains( ws, domain )

 do j=jsd,jed
    do i=isc,iec
       wx(i,j) = max(ws(i-3,j), ws(i-2,j), ws(i-1,j), ws(i,j), ws(i+1,j), ws(i+2,j), ws(i+3,j))
    enddo
 enddo

 do j=jsc,jec
    do i=isc,iec
       ws_max(i,j) = max(wx(i,j-3), wx(i,j-2), wx(i,j-1), wx(i,j), wx(i,j+1), wx(i,j+2), wx(i,j+3))
    enddo
 enddo

 end subroutine wind_max


 subroutine get_vorticity(isc, iec, jsc, jec ,isd, ied, jsd, jed, npz, u, v, vort, dx, dy, rarea)
 integer isd, ied, jsd, jed, npz
 integer isc, iec, jsc, jec
 real, intent(in)  :: u(isd:ied, jsd:jed+1, npz), v(isd:ied+1, jsd:jed, npz)
 real, intent(out) :: vort(isc:iec, jsc:jec, npz)
 real, intent(IN) :: dx(isd:ied,jsd:jed+1)
 real, intent(IN) :: dy(isd:ied+1,jsd:jed)
 real, intent(IN) :: rarea(isd:ied,jsd:jed)
! Local
 real :: utmp(isc:iec, jsc:jec+1), vtmp(isc:iec+1, jsc:jec)
 integer :: i,j,k

      do k=1,npz
         do j=jsc,jec+1
            do i=isc,iec
               utmp(i,j) = u(i,j,k)*dx(i,j)
            enddo
         enddo
         do j=jsc,jec
            do i=isc,iec+1
               vtmp(i,j) = v(i,j,k)*dy(i,j)
            enddo
         enddo

         do j=jsc,jec
            do i=isc,iec
               vort(i,j,k) = rarea(i,j)*(utmp(i,j)-utmp(i,j+1)-vtmp(i,j)+vtmp(i+1,j))
            enddo
         enddo
      enddo

 end subroutine get_vorticity


 subroutine get_height_field(is, ie, js, je, ng, km, hydrostatic, delz, wz, pt, q, peln, zvir)
  integer, intent(in):: is, ie, js, je, km, ng
  real, intent(in):: peln(is:ie,km+1,js:je)
  real, intent(in):: pt(is-ng:ie+ng,js-ng:je+ng,km)
  real, intent(in)::  q(is-ng:ie+ng,js-ng:je+ng,km,*) ! water vapor
  real, intent(in):: delz(is-ng:,js-ng:,1:)
  real, intent(in):: zvir
  logical, intent(in):: hydrostatic
  real, intent(out):: wz(is:ie,js:je,km+1)
!
  integer i,j,k
  real gg

      gg  = rdgas * ginv

      do j=js,je
         do i=is,ie
            wz(i,j,km+1) = idiag%zsurf(i,j)
         enddo
      if (hydrostatic ) then
         do k=km,1,-1
            do i=is,ie
#ifdef MULTI_GASES
               wz(i,j,k) = wz(i,j,k+1) + gg*pt(i,j,k)*virq(q(i,j,k,1:num_gas))  &
                          *(peln(i,k+1,j)-peln(i,k,j))
#else
               wz(i,j,k) = wz(i,j,k+1) + gg*pt(i,j,k)*(1.+zvir*q(i,j,k,sphum))  &
                          *(peln(i,k+1,j)-peln(i,k,j))
#endif
            enddo
         enddo
      else
         do k=km,1,-1
            do i=is,ie
               wz(i,j,k) = wz(i,j,k+1)  - delz(i,j,k)
            enddo
         enddo
      endif
      enddo

 end subroutine get_height_field

 subroutine range_check(qname, q, is, ie, js, je, n_g, km, pos, q_low, q_hi, bad_range)
      character(len=*), intent(in)::  qname
      integer, intent(in):: is, ie, js, je
      integer, intent(in):: n_g, km
      real, intent(in)::    q(is-n_g:ie+n_g, js-n_g:je+n_g, km)
      real, intent(in):: pos(is-n_g:ie+n_g, js-n_g:je+n_g,2)
      real, intent(in):: q_low, q_hi
      logical, optional, intent(out):: bad_range
!
      real qmin, qmax
      integer i,j,k

      if ( present(bad_range) ) bad_range = .false. 
      qmin = q(is,js,1)
      qmax = qmin

      do k=1,km
      do j=js,je
         do i=is,ie
            if( q(i,j,k) < qmin ) then
                qmin = q(i,j,k)
            elseif( q(i,j,k) > qmax ) then
                qmax = q(i,j,k)
            endif
          enddo
      enddo
      enddo

      call mp_reduce_min(qmin)
      call mp_reduce_max(qmax)

      if( qmin<q_low .or. qmax>q_hi ) then
          if(master) write(*,*) 'Range_check Warning:', qname, ' max = ', qmax, ' min = ', qmin
          if ( present(bad_range) ) then
               bad_range = .true. 
          endif
      endif

      if ( present(bad_range) ) then
! Print out where the bad value(s) is (are)
         if ( bad_range .EQV. .false. ) return
         do k=1,km
            do j=js,je
               do i=is,ie
                  if( q(i,j,k)<q_low .or. q(i,j,k)>q_hi ) then
                      write(*,*) 'Warn_K=',k,'(i,j)=',i,j, pos(i,j,1)*rad2deg, pos(i,j,2)*rad2deg, q(i,j,k)
                      if ( k/= 1 ) write(*,*) k-1, q(i,j,k-1)
                      if ( k/=km ) write(*,*) k+1, q(i,j,k+1)
                  endif
               enddo
            enddo
         enddo
         call mpp_error(NOTE,'==> Error from range_check: data out of bound')
      endif

 end subroutine range_check

 subroutine prt_maxmin(qname, q, is, ie, js, je, n_g, km, fac)
      character(len=*), intent(in)::  qname
      integer, intent(in):: is, ie, js, je
      integer, intent(in):: n_g, km
      real, intent(in)::    q(is-n_g:ie+n_g, js-n_g:je+n_g, km)
      real, intent(in)::    fac

      real qmin, qmax
      integer i,j,k
      !mpp_root_pe doesn't appear to recognize nested grid
      master = (mpp_pe()==mpp_root_pe()) .or. is_master()

      qmin = q(is,js,1)
      qmax = qmin

      do k=1,km
      do j=js,je
         do i=is,ie
!           qmin = min(qmin, q(i,j,k))
!           qmax = max(qmax, q(i,j,k))
            if( q(i,j,k) < qmin  ) then
                qmin = q(i,j,k)
            elseif( q(i,j,k) > qmax ) then
                qmax = q(i,j,k)
            endif
          enddo
      enddo
      enddo

      call mp_reduce_min(qmin)
      call mp_reduce_max(qmax)

      if(master) then
            write(*,*) qname//trim(gn), ' max = ', qmax*fac, ' min = ', qmin*fac
      endif

 end subroutine prt_maxmin

 subroutine prt_mxm(qname, q, is, ie, js, je, n_g, km, fac, area, domain)
      character(len=*), intent(in)::  qname
      integer, intent(in):: is, ie, js, je
      integer, intent(in):: n_g, km
      real, intent(in)::    q(is-n_g:ie+n_g, js-n_g:je+n_g, km)
      real, intent(in)::    fac
! BUG !!!
!     real, intent(IN)::    area(is-n_g:ie+n_g, js-n_g:je+n_g, km)
      real(kind=R_GRID), intent(IN)::    area(is-3:ie+3, js-3:je+3)
      type(domain2d), intent(INOUT) :: domain
!
      real qmin, qmax, gmean
      integer i,j,k

      !mpp_root_pe doesn't appear to recognize nested grid
      master = (mpp_pe()==mpp_root_pe()) .or. is_master()
      qmin = q(is,js,1)
      qmax = qmin
      gmean = 0.

      do k=1,km
      do j=js,je
         do i=is,ie
!           qmin = min(qmin, q(i,j,k))
!           qmax = max(qmax, q(i,j,k))
            if( q(i,j,k) < qmin ) then
                qmin = q(i,j,k)
            elseif( q(i,j,k) > qmax ) then
                qmax = q(i,j,k)
            endif
          enddo
      enddo
      enddo

      call mp_reduce_min(qmin)
      call mp_reduce_max(qmax)

! SJL: BUG!!!
!     gmean = g_sum(domain, q(is,js,km), is, ie, js, je, 3, area, 1) 
      gmean = g_sum(domain, q(is:ie,js:je,km), is, ie, js, je, 3, area, 1) 

      if(master) write(6,*) qname, gn, qmax*fac, qmin*fac, gmean*fac

 end subroutine prt_mxm

 !Added nwat == 1 case for water vapor diagnostics
 subroutine prt_mass(km, nq, is, ie, js, je, n_g, nwat, ps, delp, q, area, domain)

 integer, intent(in):: is, ie, js, je
 integer, intent(in):: nq, n_g, km, nwat
 real, intent(in)::   ps(is-n_g:ie+n_g, js-n_g:je+n_g)
 real, intent(in):: delp(is-n_g:ie+n_g, js-n_g:je+n_g, km)
 real, intent(in)::  q(is-n_g:ie+n_g, js-n_g:je+n_g, km, nq)
 real(kind=R_GRID), intent(IN):: area(is-n_g:ie+n_g,js-n_g:je+n_g)
 type(domain2d), intent(INOUT) :: domain
! Local:
 real psq(is:ie,js:je,nwat), psqv(is:ie,js:je)
 real q_strat(is:ie,js:je)
 real qtot(nwat), qwat
 real psmo, totw, psdry
 integer k, n, kstrat

!Needed when calling prt_mass in fv_restart?
    sphum   = get_tracer_index (MODEL_ATMOS, 'sphum')
    liq_wat = get_tracer_index (MODEL_ATMOS, 'liq_wat')
    ice_wat = get_tracer_index (MODEL_ATMOS, 'ice_wat')

    rainwat = get_tracer_index (MODEL_ATMOS, 'rainwat')
    snowwat = get_tracer_index (MODEL_ATMOS, 'snowwat')
    graupel = get_tracer_index (MODEL_ATMOS, 'graupel')

 if ( nwat==0 ) then
      psmo = g_sum(domain, ps(is:ie,js:je), is, ie, js, je, n_g, area, 1) 
      if( master ) write(*,*) 'Total surface pressure (mb)', trim(gn), ' = ',  0.01*psmo
      call z_sum(is, ie, js, je, km, n_g, delp, q(is-n_g,js-n_g,1,1  ), psqv(is,js)) 
      return
 endif

 psq(:,:,:) = 0.
 call z_sum(is, ie, js, je, km, n_g, delp, q(is-n_g,js-n_g,1,sphum  ), psq(is,js,sphum  )) 

 if (liq_wat > 0)  &
      call z_sum(is, ie, js, je, km, n_g, delp, q(is-n_g,js-n_g,1,liq_wat), psq(is,js,liq_wat))

 if (rainwat > 0)  &
      call z_sum(is, ie, js, je, km, n_g, delp, q(is-n_g,js-n_g,1,rainwat), psq(is,js,rainwat))

!nwat == 4 => KESSLER, ice is probably garbage...
 if (ice_wat > 0)  &
      call z_sum(is, ie, js, je, km, n_g, delp, q(is-n_g,js-n_g,1,ice_wat), psq(is,js,ice_wat))

 if (snowwat > 0) &
      call z_sum(is, ie, js, je, km, n_g, delp, q(is-n_g,js-n_g,1,snowwat), psq(is,js,snowwat))
 if (graupel > 0) &
      call z_sum(is, ie, js, je, km, n_g, delp, q(is-n_g,js-n_g,1,graupel), psq(is,js,graupel))


! Mean water vapor in the "stratosphere" (75 mb and above):
 if ( idiag%phalf(2)< 75. ) then
 kstrat = 1
 do k=1,km
    if ( idiag%phalf(k+1) > 75. ) exit
    kstrat = k
 enddo
 call z_sum(is, ie, js, je, kstrat, n_g, delp, q(is-n_g,js-n_g,1,sphum), q_strat(is,js)) 
 psmo = g_sum(domain, q_strat(is,js), is, ie, js, je, n_g, area, 1) * 1.e6           &
      / p_sum(is, ie, js, je, kstrat, n_g, delp, area, domain)
 if(master) write(*,*) 'Mean specific humidity (mg/kg) above 75 mb', trim(gn), '=', psmo
 endif


!-------------------
! Check global means
!-------------------
 psmo = g_sum(domain, ps(is:ie,js:je), is, ie, js, je, n_g, area, 1) 

 do n=1,nwat
    qtot(n) = g_sum(domain, psq(is,js,n), is, ie, js, je, n_g, area, 1) 
 enddo

 totw  = sum(qtot(1:nwat))
 psdry = psmo - totw

 if( master ) then
     write(*,*) 'Total surface pressure (mb)', trim(gn), ' = ',  0.01*psmo
     write(*,*) 'mean dry surface pressure', trim(gn), ' = ',    0.01*psdry
     write(*,*) 'Total Water Vapor (kg/m**2)', trim(gn), ' =',  qtot(sphum)*ginv
     if ( nwat> 2 ) then
          write(*,*) '--- Micro Phys water substances (kg/m**2) ---'
          write(*,*) 'Total cloud water', trim(gn), '=', qtot(liq_wat)*ginv
          if (rainwat > 0) &
               write(*,*) 'Total rain  water', trim(gn), '=', qtot(rainwat)*ginv
          if (ice_wat > 0) &
               write(*,*) 'Total cloud ice  ', trim(gn), '=', qtot(ice_wat)*ginv
          if (snowwat > 0) &
               write(*,*) 'Total snow       ', trim(gn), '=', qtot(snowwat)*ginv
          if (graupel > 0) &
               write(*,*) 'Total graupel    ', trim(gn), '=', qtot(graupel)*ginv
          write(*,*) '---------------------------------------------'
     elseif ( nwat==2 ) then
          write(*,*) 'GFS condensate (kg/m^2)', trim(gn), '=', qtot(liq_wat)*ginv
     endif
  endif

 end subroutine prt_mass


 subroutine z_sum(is, ie, js, je, km, n_g, delp, q, sum2)
 integer, intent(in):: is, ie, js, je,  n_g, km
 real, intent(in):: delp(is-n_g:ie+n_g, js-n_g:je+n_g, km)
 real, intent(in)::    q(is-n_g:ie+n_g, js-n_g:je+n_g, km)
 real, intent(out):: sum2(is:ie,js:je)

 integer i,j,k

 do j=js,je
    do i=is,ie
       sum2(i,j) = delp(i,j,1)*q(i,j,1)
    enddo
    do k=2,km
       do i=is,ie
          sum2(i,j) = sum2(i,j) + delp(i,j,k)*q(i,j,k)
       enddo
    enddo
 enddo

 end subroutine z_sum


 real function p_sum(is, ie, js, je, km, n_g, delp, area, domain)
 integer, intent(in):: is, ie, js, je,  n_g, km
 real, intent(in):: delp(is-n_g:ie+n_g, js-n_g:je+n_g, km)
 real(kind=R_GRID), intent(IN) :: area(is-n_g:ie+n_g, js-n_g:je+n_g)
 real :: sum2(is:ie,js:je)
 integer i,j,k
 type(domain2d), intent(INOUT) :: domain

!$OMP parallel do default(none) shared(is,ie,js,je,km,sum2,delp)
 do j=js,je
    do i=is,ie
       sum2(i,j) = delp(i,j,1)
    enddo
    do k=2,km
       do i=is,ie
          sum2(i,j) = sum2(i,j) + delp(i,j,k)
       enddo
    enddo
 enddo
 p_sum = g_sum(domain, sum2, is, ie, js, je, n_g, area, 1)

 end function p_sum



 subroutine get_pressure_given_height(is, ie, js, je, ng, km, wz, kd, height,   &
                                      ts, peln, a2, fac)

 integer,  intent(in):: is, ie, js, je, km, ng
 integer,  intent(in):: kd           !< vertical dimension of the ouput height
 real, intent(in):: wz(is:ie,js:je,km+1)
 real, intent(in):: ts(is-ng:ie+ng,js-ng:je+ng)
 real, intent(in):: peln(is:ie,km+1,js:je)
 real, intent(in):: height(kd)   !< must be monotonically decreasing with increasing k
 real, intent(out):: a2(is:ie,js:je,kd)      !< pressure (pa)
 real, optional, intent(in):: fac

! local:
 integer n, i,j,k
 real ptmp, tm


 do n=1,kd

!$OMP parallel do default(none) shared(is,ie,js,je,n,height,wz,km,peln,a2,ginv,ts,fac) &
!$OMP                          private(ptmp, tm)
    do j=js,je

       do 1000 i=is,ie

         if ( height(n) >= wz(i,j,km+1) ) then
!---------------------
! Search from top down
!---------------------
          do k=1,km
             if( height(n) < wz(i,j,k) .and. height(n) >= wz(i,j,k+1) ) then
! Found it!
                 ptmp = peln(i,k,j) + (peln(i,k+1,j)-peln(i,k,j)) *   &
                       (wz(i,j,k)-height(n)) / (wz(i,j,k)-wz(i,j,k+1))
                 a2(i,j,n) = exp(ptmp)
                 go to 500
             endif
          enddo

         else
!-----------------------------------------
! xtrapolation: mean laspe rate 6.5 deg/km
!-----------------------------------------
                tm = rdgas*ginv*(ts(i,j) + 3.25E-3*(wz(i,j,km)-height(n)))
          a2(i,j,n) = exp( peln(i,km+1,j) + (wz(i,j,km+1) - height(n))/tm )
         endif
500      if ( present(fac) ) a2(i,j,n) = fac * a2(i,j,n)
1000   continue
    enddo
 enddo

 end subroutine get_pressure_given_height


 subroutine get_height_given_pressure(is, ie, js, je, km, wz, kd, id, log_p, peln, a2)
 integer,  intent(in):: is, ie, js, je, km
 integer,  intent(in):: kd       !< vertical dimension of the ouput height
 integer,  intent(in):: id(kd)
 real, intent(in):: log_p(kd)    !< must be monotonically increasing  with increasing k
                                 !! log (p)
 real, intent(in):: wz(is:ie,js:je,km+1)
 real, intent(in):: peln(is:ie,km+1,js:je)
 real, intent(out):: a2(is:ie,js:je,kd)      !< height (m)
! local:
 real, dimension(2*km+1):: pn, gz
 integer n,i,j,k, k1, k2, l

 k2 = max(12, km/2+1)

!$OMP parallel do default(none) shared(k2,is,ie,js,je,km,kd,id,log_p,peln,a2,wz)   &
!$OMP             private(i,j,n,k,k1,l,pn,gz)
 do j=js,je
    do i=is,ie
!---------------
! Mirror method:
!---------------
       do k=1,km+1
          pn(k) = peln(i,k,j)
          gz(k) = wz(i,j,k)
       enddo
       do k=km+2, km+k2
          l = 2*(km+1) - k
          gz(k) = 2.*gz(km+1) - gz(l)
          pn(k) = 2.*pn(km+1) - pn(l)
       enddo
       k1 = 1
       do 1000 n=1,kd
          if( id(n)<0 ) goto 1000
          do k=k1,km+k2-1
             if( log_p(n) <= pn(k+1) .and. log_p(n) >= pn(k) ) then
                 a2(i,j,n) = gz(k) + (gz(k+1)-gz(k))*(log_p(n)-pn(k))/(pn(k+1)-pn(k))
                 k1 = k
                 go to 1000
             endif
          enddo
1000   continue
    enddo
 enddo

 end subroutine get_height_given_pressure

 subroutine prt_height(qname, is, ie, js, je, ng, km, press, phis, delz, peln, area, lat)
 character(len=*), intent(in)::  qname
 integer,  intent(in):: is, ie, js, je, ng, km
 real, intent(in):: press
 real, intent(in):: peln(is:ie,km+1,js:je)
 real, intent(in):: phis(is-ng:ie+ng,js-ng:je+ng)
 real, intent(in):: delz(is-ng:ie+ng,js-ng:je+ng,km)
 real(kind=R_GRID), intent(in), dimension(is:ie, js:je):: area, lat
! local:
 real:: a2(is:ie,js:je)      !< height (m)
 real(kind=R_GRID), dimension(2*km+1):: pn, gz
 real(kind=R_GRID):: log_p
 integer i,j,k, k2, l

 log_p = log(press)
 k2 = max(12, km/2+1)

!$OMP parallel do default(none) shared(k2,is,ie,js,je,km,log_p,peln,phis,delz,a2)   &
!$OMP             private(i,j,k,l,pn,gz)
 do j=js,je
    do 1000 i=is,ie
!---------------
! Mirror method:
!---------------
       do k=1,km+1
          pn(k) = peln(i,k,j)
       enddo
       gz(km+1) = phis(i,j)/grav
       do k=km,1,-1
          gz(k) = gz(k+1) - delz(i,j,k)
       enddo
       do k=km+2, km+k2
          l = 2*(km+1) - k
          gz(k) = 2.*gz(km+1) - gz(l)
          pn(k) = 2.*pn(km+1) - pn(l)
       enddo

       do k=1,km+k2-1
          if( log_p <= pn(k+1) .and. log_p >= pn(k) ) then
              a2(i,j) = gz(k) + (gz(k+1)-gz(k))*(log_p-pn(k))/(pn(k+1)-pn(k))
              go to 1000
          endif
       enddo
1000   continue
 enddo
 call prt_gb_nh_sh(qname, is,ie, js,je, a2, area, lat)

 end subroutine prt_height

 subroutine prt_gb_nh_sh(qname, is,ie, js,je, a2, area, lat)
  character(len=*), intent(in)::  qname
  integer, intent(in):: is, ie, js, je
  real, intent(in), dimension(is:ie, js:je):: a2
  real(kind=R_GRID), intent(in), dimension(is:ie, js:je):: area, lat
! Local:
  real(R_GRID), parameter:: rad2deg = 180./pi
  real(R_GRID):: slat
  real:: t_eq, t_nh, t_sh, t_gb
  real:: area_eq, area_nh, area_sh, area_gb
  integer:: i,j

     t_eq = 0.   ;    t_nh = 0.;    t_sh = 0.;    t_gb = 0.
     area_eq = 0.; area_nh = 0.; area_sh = 0.; area_gb = 0.
     do j=js,je
        do i=is,ie
           slat = lat(i,j)*rad2deg
           area_gb = area_gb + area(i,j)
           t_gb = t_gb + a2(i,j)*area(i,j)
           if( (slat>-20. .and. slat<20.) ) then
                area_eq = area_eq + area(i,j)
                t_eq = t_eq + a2(i,j)*area(i,j)
           elseif( slat>=20. .and. slat<80. ) then
                area_nh = area_nh + area(i,j)
                t_nh = t_nh + a2(i,j)*area(i,j)
           elseif( slat<=-20. .and. slat>-80. ) then
                area_sh = area_sh + area(i,j)
                t_sh = t_sh + a2(i,j)*area(i,j)
           endif
        enddo
     enddo
     call mp_reduce_sum(area_gb)
     call mp_reduce_sum(   t_gb)
     call mp_reduce_sum(area_nh)
     call mp_reduce_sum(   t_nh)
     call mp_reduce_sum(area_sh)
     call mp_reduce_sum(   t_sh)
     call mp_reduce_sum(area_eq)
     call mp_reduce_sum(   t_eq)
     !Bugfix for non-global domains
     if (area_gb <= 1.) area_gb = -1.0
     if (area_nh <= 1.) area_nh = -1.0
     if (area_sh <= 1.) area_sh = -1.0
     if (area_eq <= 1.) area_eq = -1.0
     if (is_master()) write(*,*) qname, t_gb/area_gb, t_nh/area_nh, t_sh/area_sh, t_eq/area_eq

 end subroutine prt_gb_nh_sh

 subroutine cs3_interpolator(is, ie, js, je, km, qin, kd, pout, wz, pe, id, qout, iv)
! iv =-1: winds
! iv = 0: positive definite scalars
! iv = 1: temperature
 integer,  intent(in):: is, ie, js, je, km, iv
 integer,  intent(in):: kd      !< vertical dimension of the ouput height
 integer,  intent(in):: id(kd)
 real, intent(in):: pout(kd)    ! must be monotonically increasing with increasing k
 real, intent(in):: pe(is:ie,km+1,js:je)
 real, intent(in):: qin(is:ie,js:je,km)
 real, intent(in):: wz(is:ie,js:je,km+1)
 real, intent(out):: qout(is:ie,js:je,kd)
! local:
 real, parameter:: gcp = grav / cp_air
 real:: qe(is:ie,km+1)
 real, dimension(is:ie,km):: q2, dp
 real:: s0, a6
 integer:: i,j,k, n, k1

!$OMP parallel do default(none) shared(iv,id,is,ie,js,je,km,kd,pout,qin,qout,pe,wz) & 
!$OMP             private(k1,s0,a6,q2,dp,qe)
 do j=js,je

   do i=is,ie
      do k=1,km
         dp(i,k) = pe(i,k+1,j) - pe(i,k,j)
         q2(i,k) = qin(i,j,k)
      enddo
   enddo

   call cs_prof(q2, dp, qe, km, is, ie, iv)

   do i=is,ie
     k1 = 1
     do n=1,kd
        if ( id(n) > 0 ) then
          if( pout(n) <= pe(i,1,j) ) then
! Higher than the top:
              qout(i,j,n) = qe(i,1)
          elseif ( pout(n) >= pe(i,km+1,j) ) then
! lower than the bottom surface:
            if ( iv==1 ) then    ! Temperature
! lower than the bottom surface:
! mean (hydro) potential temp based on lowest 2-3 layers (NCEP method)
! temp = ptm * p**cappa = ptm * exp(cappa*log(pout))
               qout(i,j,n) = gcp*exp(kappa*pout(n)) * (wz(i,j,km-2) - wz(i,j,km))  /   &
                               ( exp(kappa*pe(i,km,j)) - exp(kappa*pe(i,km-2,j)) )
            else
               qout(i,j,n) = qe(i,km+1)
            endif
          else 
            do k=k1,km
               if ( pout(n)>=pe(i,k,j) .and. pout(n) <= pe(i,k+1,j) ) then
! PPM distribution: f(s) = AL + s*[(AR-AL) + A6*(1-s)]         ( 0 <= s <= 1 )
                   a6 = 3.*(2.*q2(i,k) - (qe(i,k)+qe(i,k+1)))
                   s0 = (pout(n)-pe(i,k,j)) / dp(i,k)
                   qout(i,j,n) = qe(i,k) + s0*(qe(i,k+1)-qe(i,k)+a6*(1.-s0))
                   k1 = k     ! next level
                   go to 500
               endif
            enddo
          endif
500       if ( iv==0 ) qout(i,j,n) = max(0., qout(i,j,n))
        endif
     enddo
   enddo
 enddo

! Send_data here

 end subroutine cs3_interpolator

 subroutine cs_interpolator(is, ie, js, je, km, qin, zout, wz, qout, qmin)
 integer,  intent(in):: is, ie, js, je, km
 real, intent(in):: zout, qmin
 real, intent(in):: qin(is:ie,js:je,km)
 real, intent(in):: wz(is:ie,js:je,km+1)
 real, intent(out):: qout(is:ie,js:je)
! local:
 real:: qe(is:ie,km+1)
 real, dimension(is:ie,km):: q2, dz
 real:: s0, a6
 integer:: i,j,k

!$OMP parallel do default(none) shared(qmin,is,ie,js,je,km,zout,qin,qout,wz) & 
!$OMP             private(s0,a6,q2,dz,qe)
 do j=js,je

   do i=is,ie
      do k=1,km
         dz(i,k) = wz(i,j,k) - wz(i,j,k+1)
         q2(i,k) = qin(i,j,k)
      enddo
   enddo

   call cs_prof(q2, dz, qe, km, is, ie, 1)

   do i=is,ie
      if( zout >= wz(i,j,1) ) then
! Higher than the top:
          qout(i,j) = qe(i,1)
      elseif ( zout <= wz(i,j,km+1) ) then
          qout(i,j) = qe(i,km+1)
      else 
          do k=1,km
             if ( zout<=wz(i,j,k) .and. zout >= wz(i,j,k+1) ) then
! PPM distribution: f(s) = AL + s*[(AR-AL) + A6*(1-s)]         ( 0 <= s <= 1 )
                  a6 = 3.*(2.*q2(i,k) - (qe(i,k)+qe(i,k+1)))
                  s0 = (wz(i,j,k)-zout) / dz(i,k)
                  qout(i,j) = qe(i,k) + s0*(qe(i,k+1)-qe(i,k)+a6*(1.-s0))
                  go to 500
             endif
          enddo
      endif
500   qout(i,j) = max(qmin, qout(i,j))
   enddo
 enddo

! Send_data here

 end subroutine cs_interpolator

 subroutine cs_prof(q2, delp, q, km, i1, i2, iv)
! Latest: Dec 2015 S.-J. Lin, NOAA/GFDL
 integer, intent(in):: i1, i2, km
 integer, intent(in):: iv
 real, intent(in)   :: q2(i1:i2,km)
 real, intent(in)   :: delp(i1:i2,km)     ! <layer pressure thickness
 real, intent(out):: q(i1:i2,km+1)
!-----------------------------------------------------------------------
 real  gam(i1:i2,km)
 real   d4(i1:i2)
 real   bet, a_bot, grat
 integer i, k

  do i=i1,i2
         grat = delp(i,2) / delp(i,1)   ! grid ratio
          bet = grat*(grat+0.5)
       q(i,1) = ( (grat+grat)*(grat+1.)*q2(i,1) + q2(i,2) ) / bet
     gam(i,1) = ( 1. + grat*(grat+1.5) ) / bet
  enddo

  do k=2,km
     do i=i1,i2
           d4(i) = delp(i,k-1) / delp(i,k)
             bet =  2. + d4(i) + d4(i) - gam(i,k-1)
          q(i,k) = ( 3.*(q2(i,k-1)+d4(i)*q2(i,k)) - q(i,k-1) )/bet
        gam(i,k) = d4(i) / bet
     enddo
  enddo
 
  do i=i1,i2
         a_bot = 1. + d4(i)*(d4(i)+1.5)
     q(i,km+1) = (2.*d4(i)*(d4(i)+1.)*q2(i,km)+q2(i,km-1)-a_bot*q(i,km))  &
               / ( d4(i)*(d4(i)+0.5) - a_bot*gam(i,km) )
  enddo

  do k=km,1,-1
     do i=i1,i2
        q(i,k) = q(i,k) - gam(i,k)*q(i,k+1)
     enddo
  enddo

! Apply *large-scale* constraints 
  do i=i1,i2
     q(i,2) = min( q(i,2), max(q2(i,1), q2(i,2)) )
     q(i,2) = max( q(i,2), min(q2(i,1), q2(i,2)) )
  enddo

  do k=2,km
     do i=i1,i2
        gam(i,k) = q2(i,k) - q2(i,k-1)
     enddo
  enddo

! Interior:
  do k=3,km-1
     do i=i1,i2
        if ( gam(i,k-1)*gam(i,k+1)>0. ) then
! Apply large-scale constraint to ALL fields if not local max/min
             q(i,k) = min( q(i,k), max(q2(i,k-1),q2(i,k)) )
             q(i,k) = max( q(i,k), min(q2(i,k-1),q2(i,k)) )
        else
          if ( gam(i,k-1) > 0. ) then
! There exists a local max
               q(i,k) = max(q(i,k), min(q2(i,k-1),q2(i,k)))
          else
! There exists a local min
               q(i,k) = min(q(i,k), max(q2(i,k-1),q2(i,k)))
               if ( iv==0 ) q(i,k) = max(0., q(i,k))
          endif
        endif
     enddo
  enddo

! Bottom:
  do i=i1,i2
     q(i,km) = min( q(i,km), max(q2(i,km-1), q2(i,km)) )
     q(i,km) = max( q(i,km), min(q2(i,km-1), q2(i,km)) )
  enddo
  
 end subroutine cs_prof


 subroutine interpolate_vertical(is, ie, js, je, km, plev, peln, a3, a2)

 integer,  intent(in):: is, ie, js, je, km
 real, intent(in):: peln(is:ie,km+1,js:je)
 real, intent(in):: a3(is:ie,js:je,km)
 real, intent(in):: plev
 real, intent(out):: a2(is:ie,js:je)
! local:
 real pm(km)
 real logp
 integer i,j,k

 logp = log(plev)

!$OMP parallel do default(none) shared(is,ie,js,je,km,peln,logp,a2,a3) & 
!$OMP                          private(pm)
 do j=js,je
    do 1000 i=is,ie

       do k=1,km
          pm(k) = 0.5*(peln(i,k,j)+peln(i,k+1,j))
       enddo

       if( logp <= pm(1) ) then
           a2(i,j) = a3(i,j,1)
       elseif ( logp >= pm(km) ) then
           a2(i,j) = a3(i,j,km)
       else 
           do k=1,km-1
              if( logp <= pm(k+1) .and. logp >= pm(k) ) then
                  a2(i,j) = a3(i,j,k) + (a3(i,j,k+1)-a3(i,j,k))*(logp-pm(k))/(pm(k+1)-pm(k))
                  go to 1000
              endif
           enddo
       endif
1000   continue
 enddo

 end subroutine interpolate_vertical


 subroutine interpolate_z(is, ie, js, je, km, zl, hght, a3, a2)

 integer,  intent(in):: is, ie, js, je, km
 real, intent(in):: hght(is:ie,js:je,km+1)  !< hght(k) > hght(k+1)
 real, intent(in):: a3(is:ie,js:je,km)
 real, intent(in):: zl
 real, intent(out):: a2(is:ie,js:je)
! local:
 real zm(km)
 integer i,j,k


!$OMP parallel do default(none) shared(is,ie,js,je,km,hght,zl,a2,a3) private(zm)
 do j=js,je
    do 1000 i=is,ie
       do k=1,km
          zm(k) = 0.5*(hght(i,j,k)+hght(i,j,k+1))
       enddo
       if( zl >= zm(1) ) then
           a2(i,j) = a3(i,j,1)
       elseif ( zl <= zm(km) ) then
           a2(i,j) = a3(i,j,km)
       else 
           do k=1,km-1
              if( zl <= zm(k) .and. zl >= zm(k+1) ) then
                  a2(i,j) = a3(i,j,k) + (a3(i,j,k+1)-a3(i,j,k))*(zm(k)-zl)/(zm(k)-zm(k+1))
                  go to 1000
              endif
           enddo
       endif
1000   continue
 enddo

 end subroutine interpolate_z

 subroutine helicity_relative(is, ie, js, je, ng, km, zvir, sphum, srh,   &
                              ua, va, delz, q, hydrostatic, pt, peln, phis, grav, z_bot, z_top)
! !INPUT PARAMETERS:
   integer, intent(in):: is, ie, js, je, ng, km, sphum
   real, intent(in):: grav, zvir, z_bot, z_top
   real, intent(in), dimension(is-ng:ie+ng,js-ng:je+ng,km):: pt, ua, va
   real, intent(in):: delz(is-ng:ie+ng,js-ng:je+ng,km)
   real, intent(in):: q(is-ng:ie+ng,js-ng:je+ng,km,*)
   real, intent(in):: phis(is-ng:ie+ng,js-ng:je+ng)
   real, intent(in):: peln(is:ie,km+1,js:je) 
   logical, intent(in):: hydrostatic
   real, intent(out):: srh(is:ie,js:je)   ! unit: (m/s)**2
!   real, parameter:: z_crit = 3.e3   ! lowest 3-km
!---------------------------------------------------------------------------------
! SRH = 150-299 ... supercells possible with weak tornadoes
! SRH = 300-449 ... very favourable to supercells development and strong tornadoes
! SRH > 450 ... violent tornadoes
!---------------------------------------------------------------------------------
! if z_top = 1E3, the threshold for supercells is 100 (m/s)**2
! Coded by S.-J. Lin for CONUS regional climate simulations
!
   real:: rdg
   real, dimension(is:ie):: zh, uc, vc, dz, zh0
   integer i, j, k, k0, k1
   logical below(is:ie)

   rdg = rdgas / grav

!$OMP parallel do default(none) shared(is,ie,js,je,km,hydrostatic,rdg,pt,zvir,sphum, &
#ifdef MULTI_GASES
!$OMP                                  num_gas,                         &
#endif
!$OMP                                  peln,delz,ua,va,srh,z_bot,z_top) &
!$OMP                          private(zh,uc,vc,dz,k0,k1,zh0,below)
   do j=js,je

      do i=is,ie
         uc(i) = 0.
         vc(i) = 0.
         zh(i) = 0.
         srh(i,j) = 0.
         below(i) = .true.
         zh0(i) = 0.

!        if ( phis(i,j)/grav < 1.E3 ) then
         do k=km,1,-1
            if ( hydrostatic ) then
#ifdef MULTI_GASES
                 dz(i) = rdg*pt(i,j,k)*virq(q(i,j,k,1:num_gas))*(peln(i,k+1,j)-peln(i,k,j))
#else
                 dz(i) = rdg*pt(i,j,k)*(1.+zvir*q(i,j,k,sphum))*(peln(i,k+1,j)-peln(i,k,j))
#endif
            else
                 dz(i) = - delz(i,j,k)
            endif
            zh(i) = zh(i) + dz(i)
            if (zh(i) <= z_bot ) continue
            if (zh(i) > z_bot .and. below(i)) then
               uc(i) = ua(i,j,k)*dz(i)
               vc(i) = va(i,j,k)*dz(i)
               zh0(i) = zh(i) - dz(i)
               k1 = k
               below(i) = .false.
! Compute mean winds below z_top
            elseif ( zh(i) < z_top ) then
                uc(i) = uc(i) + ua(i,j,k)*dz(i)
                vc(i) = vc(i) + va(i,j,k)*dz(i)
                k0 = k
            else
                uc(i) = uc(i) / (zh(i)-dz(i) - zh0(i))
                vc(i) = vc(i) / (zh(i)-dz(i) - zh0(i))
                goto 123
            endif
         enddo 
123      continue

! Lowest layer wind shear computed betw top edge and mid-layer
         k = k1
         srh(i,j) = 0.5*(va(i,j,k1)-vc(i))*(ua(i,j,k1-1)-ua(i,j,k1))  -  &
                    0.5*(ua(i,j,k1)-uc(i))*(va(i,j,k1-1)-va(i,j,k1))
         do k=k0, k1-1
            srh(i,j) = srh(i,j) + 0.5*(va(i,j,k)-vc(i))*(ua(i,j,k-1)-ua(i,j,k+1)) -  &
                                  0.5*(ua(i,j,k)-uc(i))*(va(i,j,k-1)-va(i,j,k+1))
         enddo
!        endif
      enddo  ! i-loop
   enddo   ! j-loop

 end subroutine helicity_relative

 subroutine helicity_relative_CAPS(is, ie, js, je, ng, km, zvir, sphum, srh, uc, vc,  &
                              ua, va, delz, q, hydrostatic, pt, peln, phis, grav, z_bot, z_top)
! !INPUT PARAMETERS:
   integer, intent(in):: is, ie, js, je, ng, km, sphum
   real, intent(in):: grav, zvir, z_bot, z_top
   real, intent(in), dimension(is-ng:ie+ng,js-ng:je+ng,km):: pt, ua, va
   real, intent(in):: delz(is-ng:ie+ng,js-ng:je+ng,km)
   real, intent(in):: q(is-ng:ie+ng,js-ng:je+ng,km,*)
   real, intent(in):: phis(is-ng:ie+ng,js-ng:je+ng)
   real, intent(in):: peln(is:ie,km+1,js:je) 
   real, intent(in):: uc(is:ie,js:je), vc(is:ie,js:je)
   logical, intent(in):: hydrostatic
   real, intent(out):: srh(is:ie,js:je)   ! unit: (m/s)**2
!---------------------------------------------------------------------------------
! SRH = 150-299 ... supercells possible with weak tornadoes
! SRH = 300-449 ... very favourable to supercells development and strong tornadoes
! SRH > 450 ... violent tornadoes
!---------------------------------------------------------------------------------
! if z_crit = 1E3, the threshold for supercells is 100 (m/s)**2
! Coded by S.-J. Lin for CONUS regional climate simulations
!
   real:: rdg
   real, dimension(is:ie):: zh, dz, zh0
   integer i, j, k, k0, k1, n
   logical below

   rdg = rdgas / grav

!$OMP parallel do default(none) shared(is,ie,js,je,km,hydrostatic,rdg,pt,zvir,sphum, &
#ifdef MULTI_GASES
!$OMP                                  num_gas,                               &
#endif
!$OMP                                  peln,delz,ua,va,srh,uc,vc,z_bot,z_top) &
!$OMP                          private(zh,dz,k0,k1,zh0,below)
   do j=js,je

      do i=is,ie
         srh(i,j) = 0.
         zh(i) = 0.
         zh0 = 0.
         below = .true.

  K_LOOP:do k=km,1,-1
            if ( hydrostatic ) then
#ifdef MULTI_GASES
                 dz(i) = rdg*pt(i,j,k)*virq(q(i,j,k,1:num_gas))*(peln(i,k+1,j)-peln(i,k,j))
#else
                 dz(i) = rdg*pt(i,j,k)*(1.+zvir*q(i,j,k,sphum))*(peln(i,k+1,j)-peln(i,k,j))
#endif
            else
                 dz(i) = -delz(i,j,k)
            endif

            zh(i) = zh(i) + dz(i)
            if (zh(i) <= z_bot ) continue
            if (zh(i) > z_bot .and. below) then
               zh0(i) = zh(i) - dz(i)
               k1 = k
               below = .false.
! Compute mean winds below z_top
            elseif ( zh(i) < z_top ) then
                k0 = k
            else
               EXIT K_LOOP
            endif

         enddo K_LOOP

! Lowest layer wind shear computed betw top edge and mid-layer
         k = k1
         srh(i,j) = 0.5*(va(i,j,k1)-vc(i,j))*(ua(i,j,k1-1)-ua(i,j,k1))  -  &
                    0.5*(ua(i,j,k1)-uc(i,j))*(va(i,j,k1-1)-va(i,j,k1))
         do k=k0, k1-1
            srh(i,j) = srh(i,j) + 0.5*(va(i,j,k)-vc(i,j))*(ua(i,j,k-1)-ua(i,j,k+1)) -  &
                                  0.5*(ua(i,j,k)-uc(i,j))*(va(i,j,k-1)-va(i,j,k+1))
         enddo
      enddo  ! i-loop
   enddo   ! j-loop

 end subroutine helicity_relative_CAPS


 subroutine bunkers_vector(is, ie, js, je, ng, km, zvir, sphum, uc, vc,  &
                           ua, va, delz, q, hydrostatic, pt, peln, phis, grav)

   integer, intent(in):: is, ie, js, je, ng, km, sphum
   real, intent(in):: grav, zvir
   real, intent(in), dimension(is-ng:ie+ng,js-ng:je+ng,km):: pt, ua, va
   real, intent(in):: delz(is-ng:ie+ng,js-ng:je+ng,km)
   real, intent(in):: q(is-ng:ie+ng,js-ng:je+ng,km,*)
   real, intent(in):: phis(is-ng:ie+ng,js-ng:je+ng)
   real, intent(in):: peln(is:ie,km+1,js:je) 
   logical, intent(in):: hydrostatic
   real, intent(out):: uc(is:ie,js:je), vc(is:ie,js:je)

   real:: rdg
   real :: zh, dz, usfc, vsfc, u6km, v6km, umn, vmn
   real :: ushr, vshr, shrmag
   integer i, j, k, n
   real, parameter :: bunkers_d = 7.5 ! Empirically derived parameter
   logical :: has_sfc, has_6km

   rdg = rdgas / grav

!$OMP parallel do default(none) shared(is,ie,js,je,ng,km,hydrostatic,rdg,pt,zvir,sphum, &
#ifdef MULTI_GASES
!$OMP                                  num_gas,               &
#endif
!$OMP                                  peln,delz,ua,va,uc,vc) &
!$OMP                           private(zh,dz,usfc,vsfc,u6km,v6km,umn,vmn, &
!$OMP                                  ushr,vshr,shrmag)
   do j=js,je
      do i=is,ie
         zh = 0.
         usfc = 0.
         vsfc = 0.
         u6km = 0.
         v6km = 0.
         umn = 0.
         vmn = 0.

         usfc = ua(i,j,km)
         vsfc = va(i,j,km)

  K_LOOP:do k=km,1,-1
            if ( hydrostatic ) then
#ifdef MULTI_GASES
                 dz = rdg*pt(i,j,k)*virq(q(i,j,k,1:num_gas))*(peln(i,k+1,j)-peln(i,k,j))
#else
                 dz = rdg*pt(i,j,k)*(1.+zvir*q(i,j,k,sphum))*(peln(i,k+1,j)-peln(i,k,j))
#endif
            else
                 dz = -delz(i,j,k)
            endif
            zh = zh + dz

            if (zh < 6000) then
                u6km = ua(i,j,k)
                v6km = va(i,j,k)

                umn = umn + ua(i,j,k)*dz
                vmn = vmn + va(i,j,k)*dz
            else
               EXIT K_LOOP
            endif

         enddo K_LOOP

         u6km = u6km + (ua(i,j,k) - u6km) / dz * (6000. - (zh - dz))
         v6km = v6km + (va(i,j,k) - v6km) / dz * (6000. - (zh - dz))

         umn = umn / (zh - dz)
         vmn = vmn / (zh - dz)

         ushr = u6km - usfc
         vshr = v6km - vsfc
         shrmag = sqrt(ushr * ushr + vshr * vshr)
         uc(i,j) = umn + bunkers_d * vshr / shrmag
         vc(i,j) = vmn - bunkers_d * ushr / shrmag

      enddo  ! i-loop
   enddo   ! j-loop

 end subroutine bunkers_vector


 subroutine updraft_helicity(is, ie, js, je, ng, km, zvir, sphum, uh,   &
                             w, vort, delz, q, hydrostatic, pt, peln, phis, grav, z_bot, z_top)
! !INPUT PARAMETERS:
   integer, intent(in):: is, ie, js, je, ng, km, sphum
   real, intent(in):: grav, zvir, z_bot, z_top
   real, intent(in), dimension(is-ng:ie+ng,js-ng:je+ng,km):: pt, w
   real, intent(in), dimension(is:ie,js:je,km):: vort
   real, intent(in):: delz(is-ng:ie+ng,js-ng:je+ng,km)
   real, intent(in):: q(is-ng:ie+ng,js-ng:je+ng,km,*)
   real, intent(in):: phis(is-ng:ie+ng,js-ng:je+ng)
   real, intent(in):: peln(is:ie,km+1,js:je) 
   logical, intent(in):: hydrostatic
   real, intent(out):: uh(is:ie,js:je)   ! unit: (m/s)**2
! Coded by S.-J. Lin for CONUS regional climate simulations
! Modified for UH by LMH
!
   real:: rdg
   real, dimension(is:ie):: zh, dz, zh0
   integer i, j, k, n
   logical below(is:ie)

   rdg = rdgas / grav

!$OMP parallel do default(none) shared(is,ie,js,je,ng,km,hydrostatic,rdg,pt,zvir,sphum, &
#ifdef MULTI_GASES
!$OMP                                  num_gas,                         &
#endif
!$OMP                                  peln,delz,w,vort,uh,z_bot,z_top) &
!$OMP                          private(zh,dz,zh0,below)
   do j=js,je

      do i=is,ie
         zh(i) = 0.
         uh(i,j) = 0.
         below(i) = .true.
         zh0(i) = 0.

!        if ( phis(i,j)/grav < 1.E3 ) then
         do k=km,1,-1
            if ( hydrostatic ) then
#ifdef MULTI_GASES
                 dz(i) = rdg*pt(i,j,k)*virq(q(i,j,k,1:num_gas))*(peln(i,k+1,j)-peln(i,k,j))
#else
                 dz(i) = rdg*pt(i,j,k)*(1.+zvir*q(i,j,k,sphum))*(peln(i,k+1,j)-peln(i,k,j))
#endif
            else
                 dz(i) = - delz(i,j,k)
            endif
            zh(i) = zh(i) + dz(i)
            if (zh(i) <= z_bot ) continue
            if (zh(i) > z_bot .and. below(i)) then
               uh(i,j) = vort(i,j,k)*w(i,j,k)*(zh(i) - z_bot)
               below(i) = .false.
! Compute mean winds below z_top
            elseif ( zh(i) < z_top ) then
               uh(i,j) = uh(i,j) + vort(i,j,k)*w(i,j,k)*dz(i)
            else
               uh(i,j) = uh(i,j) + vort(i,j,k)*w(i,j,k)*(z_top - (zh(i)-dz(i)) ) 
               goto 123
            endif
         enddo
123      continue

      enddo  ! i-loop
   enddo   ! j-loop

 end subroutine updraft_helicity

!>@brief The subroutine 'pv_entropy' computes potential vorticity.
!>@author Shian-Jiann Lin
 subroutine pv_entropy(is, ie, js, je, ng, km, vort, f_d, pt, pkz, delp, grav)

! !INPUT PARAMETERS:
   integer, intent(in)::  is, ie, js, je, ng, km
   real, intent(in):: grav
   real, intent(in):: pt(is-ng:ie+ng,js-ng:je+ng,km) 
   real, intent(in):: pkz(is:ie,js:je,km) 
   real, intent(in):: delp(is-ng:ie+ng,js-ng:je+ng,km)
   real, intent(in):: f_d(is-ng:ie+ng,js-ng:je+ng) 

! vort is relative vorticity as input. Becomes PV on output
      real, intent(inout):: vort(is:ie,js:je,km)

! !DESCRIPTION:
!        EPV = 1/r * (vort+f_d) * d(S)/dz; where S is a conservative scalar
!        r the fluid density, and S is chosen to be the entropy here: S = log(pt)
!        pt == potential temperature.
! Computation are performed assuming the input is on "x-y-z" Cartesian coordinate.
! The approximation made here is that the relative vorticity computed on constant
! z-surface is not that different from the hybrid sigma-p coordinate.
! See page 39, Pedlosky 1979: Geophysical Fluid Dynamics
!
! The follwoing simplified form is strictly correct only if vort is computed on 
! constant z surfaces. In addition hydrostatic approximation is made.
!        EPV = - GRAV * (vort+f_d) / del(p) * del(pt) / pt 
! where del() is the vertical difference operator.
!
! programmer: S.-J. Lin, shian-jiann.lin@noaa.gov
!
!EOP
!---------------------------------------------------------------------
!BOC
      real w3d(is:ie,js:je,km)
      real te(is:ie,js:je,km+1), t2(is:ie,km), delp2(is:ie,km)
      real te2(is:ie,km+1)
      integer i, j, k

#ifdef SW_DYNAMICS
!$OMP parallel do default(none) shared(is,ie,js,je,vort,grav,f_d,delp)
        do j=js,je
          do i=is,ie
            vort(i,j,1) = grav * (vort(i,j,1)+f_d(i,j)) / delp(i,j,1)
          enddo
        enddo
#else
! Compute PT at layer edges.
!$OMP parallel do default(none) shared(is,ie,js,je,km,pt,pkz,w3d,delp,te2,te) &
!$OMP                          private(t2, delp2) 
     do j=js,je
        do k=1,km
          do i=is,ie
               t2(i,k) = pt(i,j,k) / pkz(i,j,k)
              w3d(i,j,k) = t2(i,k)
            delp2(i,k) = delp(i,j,k)
          enddo
        enddo

        call ppme(t2, te2, delp2, ie-is+1, km)

        do k=1,km+1
           do i=is,ie
              te(i,j,k) = te2(i,k)
           enddo
        enddo
     enddo

!$OMP parallel do default(none) shared(is,ie,js,je,km,vort,f_d,te,w3d,delp,grav)
     do k=1,km
        do j=js,je
          do i=is,ie
! Entropy is the thermodynamic variable in the following form
            vort(i,j,k) = (vort(i,j,k)+f_d(i,j)) * ( te(i,j,k)-te(i,j,k+1) )  &
                          / ( w3d(i,j,k)*delp(i,j,k) )  * grav
          enddo
        enddo
     enddo
#endif

 end subroutine pv_entropy


 subroutine ppme(p,qe,delp,im,km)

  integer, intent(in):: im, km
  real, intent(in)::    p(im,km)
  real, intent(in):: delp(im,km)
  real, intent(out)::qe(im,km+1)

! local arrays.
      real dc(im,km),delq(im,km), a6(im,km)
      real c1, c2, c3, tmp, qmax, qmin
      real a1, a2, s1, s2, s3, s4, ss3, s32, s34, s42
      real a3, b2, sc, dm, d1, d2, f1, f2, f3, f4
      real qm, dq
      integer i, k, km1

      km1 = km - 1

      do 500 k=2,km
      do 500 i=1,im
500   a6(i,k) = delp(i,k-1) + delp(i,k)

      do 1000 k=1,km1
      do 1000 i=1,im
      delq(i,k) = p(i,k+1) - p(i,k)
1000  continue

      do 1220 k=2,km1
      do 1220 i=1,im
      c1 = (delp(i,k-1)+0.5*delp(i,k))/a6(i,k+1)
      c2 = (delp(i,k+1)+0.5*delp(i,k))/a6(i,k)
      tmp = delp(i,k)*(c1*delq(i,k) + c2*delq(i,k-1)) /    &
                                    (a6(i,k)+delp(i,k+1))
      qmax = max(p(i,k-1),p(i,k),p(i,k+1)) - p(i,k)
      qmin = p(i,k) - min(p(i,k-1),p(i,k),p(i,k+1))
      dc(i,k) = sign(min(abs(tmp),qmax,qmin), tmp)
1220  continue

!****6***0*********0*********0*********0*********0*********0**********72
! 4th order interpolation of the provisional cell edge value
!****6***0*********0*********0*********0*********0*********0**********72

   do k=3,km1
      do i=1,im
         c1 = delq(i,k-1)*delp(i,k-1) / a6(i,k)
         a1 = a6(i,k-1) / (a6(i,k) + delp(i,k-1))
         a2 = a6(i,k+1) / (a6(i,k) + delp(i,k))
         qe(i,k) = p(i,k-1) + c1 + 2./(a6(i,k-1)+a6(i,k+1)) *        &
                   ( delp(i,k)*(c1*(a1 - a2)+a2*dc(i,k-1)) -         &
                                delp(i,k-1)*a1*dc(i,k  ) )
      enddo
   enddo

! three-cell parabolic subgrid distribution at model top

   do i=1,im
! three-cell PP-distribution
! Compute a,b, and c of q = aP**2 + bP + c using cell averages and delp
! a3 = a / 3
! b2 = b / 2
      s1 = delp(i,1)
      s2 = delp(i,2) + s1
!
      s3 = delp(i,2) + delp(i,3)
      s4 = s3 + delp(i,4)
      ss3 =  s3 + s1
      s32 = s3*s3
      s42 = s4*s4
      s34 = s3*s4
! model top
      a3 = (delq(i,2) - delq(i,1)*s3/s2) / (s3*ss3)
!
      if(abs(a3) .gt. 1.e-14) then
         b2 =  delq(i,1)/s2 - a3*(s1+s2)
         sc = -b2/(3.*a3)
         if(sc .lt. 0. .or. sc .gt. s1) then
             qe(i,1) = p(i,1) - s1*(a3*s1 + b2)
         else
             qe(i,1) = p(i,1) - delq(i,1)*s1/s2
         endif
      else
! Linear
         qe(i,1) = p(i,1) - delq(i,1)*s1/s2
      endif
      dc(i,1) = p(i,1) - qe(i,1)
! compute coef. for the off-centered area preserving cubic poly.
      dm = delp(i,1) / (s34*ss3*(delp(i,2)+s3)*(s4+delp(i,1)))
      f1 = delp(i,2)*s34 / ( s2*ss3*(s4+delp(i,1)) )
      f2 = (delp(i,2)+s3) * (ss3*(delp(i,2)*s3+s34+delp(i,2)*s4)   &
            + s42*(delp(i,2)+s3+s32/s2))
      f3 = -delp(i,2)*( ss3*(s32*(s3+s4)/(s4-delp(i,2))            &
            + (delp(i,2)*s3+s34+delp(i,2)*s4))                     &
            + s42*(delp(i,2)+s3) )
      f4 = ss3*delp(i,2)*s32*(delp(i,2)+s3) / (s4-delp(i,2))
      qe(i,2) = f1*p(i,1)+(f2*p(i,2)+f3*p(i,3)+f4*p(i,4))*dm
   enddo

! Bottom
! Area preserving cubic with 2nd deriv. = 0 at the surface
   do i=1,im
      d1 = delp(i,km)
      d2 = delp(i,km1)
      qm = (d2*p(i,km)+d1*p(i,km1)) / (d1+d2)
      dq = 2.*(p(i,km1)-p(i,km)) / (d1+d2)
      c1 = (qe(i,km1)-qm-d2*dq) / (d2*(2.*d2*d2+d1*(d2+3.*d1)))
      c3 = dq - 2.0*c1*(d2*(5.*d1+d2)-3.*d1**2)
      qe(i,km  ) = qm - c1*d1*d2*(d2+3.*d1)
      qe(i,km+1) = d1*(8.*c1*d1**2-c3) + qe(i,km)
   enddo

 end subroutine ppme

subroutine rh_calc (pfull, t, qv, rh, do_cmip)
  
   real, intent (in),  dimension(:,:) :: pfull, t, qv
   real, intent (out), dimension(:,:) :: rh
   real, dimension(size(t,1),size(t,2)) :: esat
   logical, intent(in), optional :: do_cmip

   real, parameter :: d622 = rdgas/rvgas
   real, parameter :: d378 = 1.-d622

   logical :: do_simple = .false.

! because Betts-Miller uses a simplified scheme for calculating the relative humidity

     if (do_simple) then
        call lookup_es (t, esat)
        rh(:,:) = pfull(:,:)
        rh(:,:) = MAX(rh(:,:),esat(:,:))  !limit where pfull ~ esat
        rh(:,:)=100.*qv(:,:)/(d622*esat(:,:)/rh(:,:))
     else
        if (present(do_cmip)) then
         call compute_qs (t, pfull, rh, q=qv, es_over_liq_and_ice = .true.)
         rh(:,:)=100.*qv(:,:)/rh(:,:)
        else
        call compute_qs (t, pfull, rh, q=qv)
        rh(:,:)=100.*qv(:,:)/rh(:,:)
     endif
     endif

end subroutine rh_calc

#ifdef SIMPLIFIED_THETA_E

!>@brief The subroutine 'eqv_pot' calculates the equivalent potential temperature using 
!! a simplified method.
!>@author Shian-Jiann Lin
#ifdef MULTI_GASES
subroutine eqv_pot(theta_e, pt, delp, delz, peln, pkz, qi, is, ie, js, je, ng, npz, &
                   hydrostatic, moist)
#else
subroutine eqv_pot(theta_e, pt, delp, delz, peln, pkz, q, is, ie, js, je, ng, npz, &
                   hydrostatic, moist)
#endif
    integer, intent(in):: is,ie,js,je,ng,npz
#ifdef MULTI_GASES
    real, intent(in), dimension(is-ng:ie+ng,js-ng:je+ng,npz,*):: qi
#endif
    real, intent(in), dimension(is-ng:ie+ng,js-ng:je+ng,npz):: pt, delp, q
    real, intent(in), dimension(is-ng:     ,js-ng:     ,1: ):: delz
    real, intent(in), dimension(is:ie,npz+1,js:je):: peln
    real, intent(in):: pkz(is:ie,js:je,npz) 
    logical, intent(in):: hydrostatic, moist
! Output:
    real, dimension(is:ie,js:je,npz), intent(out) :: theta_e  !< eqv pot
! local
    real, parameter:: tice = 273.16
    real, parameter:: c_liq = 4190.       !< heat capacity of water at 0C
#ifdef SIM_NGGPS
    real, parameter:: dc_vap = 0.
#else
    real, parameter:: dc_vap = cp_vapor - c_liq     !< = -2344. isobaric heating/cooling
#endif
    real(kind=R_GRID), dimension(is:ie):: pd, rq
    real(kind=R_GRID) :: wfac
    integer :: i,j,k

    if ( moist ) then
         wfac = 1.
    else
         wfac = 0.
    endif
#ifdef MULLTI_GASES
    do j=js,je
       do i=is,ie
          do k=1,npz
             q(i,j,k) = qi(i,j,k,1)
          enddo
       enddo
    enddo
#endif

!$OMP parallel do default(none) shared(pk0,wfac,moist,pkz,is,ie,js,je,npz,pt,q,delp,peln,delz,theta_e,hydrostatic)  &
!$OMP  private(pd, rq)
    do k = 1,npz
       do j = js,je

        if ( hydrostatic ) then
            do i=is,ie
               rq(i) = max(0., wfac*q(i,j,k))
               pd(i) = (1.-rq(i))*delp(i,j,k) / (peln(i,k+1,j) - peln(i,k,j))
            enddo
        else
! Dry pressure: p = r R T
            do i=is,ie
               rq(i) = max(0., wfac*q(i,j,k))
               pd(i) = -rdgas*pt(i,j,k)*(1.-rq(i))*delp(i,j,k)/(grav*delz(i,j,k))
            enddo
        endif

        if ( moist ) then
            do i=is,ie
               rq(i) = max(0., q(i,j,k))
!              rh(i) = max(1.e-12, rq(i)/wqs1(pt(i,j,k),den(i)))   ! relative humidity
!              theta_e(i,j,k) = exp(rq(i)/cp_air*((hlv+dc_vap*(pt(i,j,k)-tice))/pt(i,j,k) -   &
!                                   rvgas*log(rh(i))) + kappa*log(1.e5/pd(i))) * pt(i,j,k)
! Simplified form: (ignoring the RH term)
#ifdef SIM_NGGPS
#ifdef MULTI_GASES
               theta_e(i,j,k) = pt(i,j,k)*exp(kappa * (virqd(qi(i,j,k,:))/vicpqd(qi(i,j,k,:)))*log(1.e5/pd(i))) *  &
                                          exp(rq(i)*hlv/(cp_air*vicpqd(qi(i,j,k,:))*pt(i,j,k)))
#else
               theta_e(i,j,k) = pt(i,j,k)*exp(kappa*log(1.e5/pd(i))) *  &
                                          exp(rq(i)*hlv/(cp_air*pt(i,j,k)))
#endif
#else
#ifdef MULTI_GASES
               theta_e(i,j,k) = pt(i,j,k)*exp( rq(i)/(cp_air*vicpqd(q(i,j,k,:))*pt(i,j,k))*(hlv+dc_vap*(pt(i,j,k)-tice)) &
                                             + rdgas*virqd(qi(i,j,k,:)) / (cp_air*vicpqd(qi(i,j,k,:)))*log(1.e5/pd(i)) )
#else
               theta_e(i,j,k) = pt(i,j,k)*exp( rq(i)/(cp_air*pt(i,j,k))*(hlv+dc_vap*(pt(i,j,k)-tice)) &
                                             + kappa*log(1.e5/pd(i)) )
#endif
#endif
            enddo
        else
          if ( hydrostatic ) then
             do i=is,ie
                theta_e(i,j,k) = pt(i,j,k)*pk0/pkz(i,j,k)
             enddo
          else
             do i=is,ie
!               theta_e(i,j,k) = pt(i,j,k)*(1.e5/pd(i))**kappa
#ifdef MULTI_GASES
                theta_e(i,j,k) = pt(i,j,k)*exp( kappa * (virqd(qi(i,j,k,:))/vicpqd(qi(i,j,k,:)))*log(1.e5/pd(i)) )
#else
                theta_e(i,j,k) = pt(i,j,k)*exp( kappa*log(1.e5/pd(i)) )
#endif
             enddo
          endif
        endif
      enddo ! j-loop
    enddo   ! k-loop

end subroutine eqv_pot

#else

!>@brief The subroutine 'eqv_pot' calculates the equivalent potential temperature.
!>@author Xi Chen
!>@date 28 July 2015
!> Modfied by Shian-Jiann Lin
#ifdef MULTI_GASES
subroutine eqv_pot(theta_e, pt, delp, delz, peln, pkz, qi, is, ie, js, je, ng, npz, &
#else
subroutine eqv_pot(theta_e, pt, delp, delz, peln, pkz, q, is, ie, js, je, ng, npz, &
#endif
                   hydrostatic, moist)
! Modified by SJL
    integer, intent(in):: is,ie,js,je,ng,npz
#ifdef MULTI_GASES
    real, intent(in), dimension(is-ng:ie+ng,js-ng:je+ng,npz,*):: qi
#else
    real, intent(in), dimension(is-ng:ie+ng,js-ng:je+ng,npz):: q
#endif
    real, intent(in), dimension(is-ng:ie+ng,js-ng:je+ng,npz):: pt, delp
    real, intent(in), dimension(is-ng:     ,js-ng:     ,1: ):: delz
    real, intent(in), dimension(is:ie,npz+1,js:je):: peln
    real, intent(in):: pkz(is:ie,js:je,npz) 
    logical, intent(in):: hydrostatic, moist
! Output:
    real, dimension(is:ie,js:je,npz), intent(out) :: theta_e  !< eqv pot
! local
#ifdef MULTI_GASES
    real, dimension(is-ng:ie+ng,js-ng:je+ng,npz):: q
#endif
    real, parameter:: cv_vap = cp_vapor - rvgas  ! 1384.5
    real, parameter:: cappa_b = 0.2854
    real(kind=R_GRID):: cv_air, cappa, zvir
    real(kind=R_GRID):: p_mb(is:ie)
    real(kind=R_GRID) :: r, e, t_l, rdg, capa
    integer :: i,j,k, n

#ifdef MULTI_GASES
    q(:,:,:) = qi(:,:,:,1)
#endif
    cv_air =  cp_air - rdgas
    rdg = -rdgas/grav
    if ( moist ) then
         zvir = rvgas/rdgas - 1.
    else
         zvir = 0.
    endif

!$OMP parallel do default(none) shared(moist,pk0,pkz,cv_air,zvir,rdg,is,ie,js,je,ng,npz, &
#ifdef MULTI_GASES
!$OMP      qi,num_gas,                                                                   &
#endif
!$OMP      pt,q,delp,peln,delz,theta_e,hydrostatic)  &
!$OMP      private(cappa,p_mb, r, e, t_l, capa)
    do k = 1,npz
       cappa = cappa_b
      do j = js,je
! get pressure in mb
        if ( hydrostatic ) then
            do i=is,ie
               p_mb(i) = 0.01*delp(i,j,k) / (peln(i,k+1,j) - peln(i,k,j))
            enddo
        else
            do i=is,ie
#ifdef MULTI_GASES
               p_mb(i) = 0.01*rdg*delp(i,j,k)/delz(i,j,k)*pt(i,j,k)*virq(qi(i,j,k,1:num_gas))
#else
               p_mb(i) = 0.01*rdg*delp(i,j,k)/delz(i,j,k)*pt(i,j,k)*(1.+zvir*q(i,j,k))
#endif
            enddo
        endif
        if ( moist ) then
          do i = is,ie
#ifdef MULTI_GASES
          cappa = rdgas/(rdgas+((1.-q(i,j,k))*cv_air+q(i,j,k)*cv_vap)/virq(qi(i,j,k,1:num_gas)))
#else
          cappa = rdgas/(rdgas+((1.-q(i,j,k))*cv_air+q(i,j,k)*cv_vap)/(1.+zvir*q(i,j,k)))
#endif
! get "dry" mixing ratio of m_vapor/m_tot in g/kg
          r = q(i,j,k)/(1.-q(i,j,k))*1000.
          r = max(1.e-10, r)
! get water vapor pressure
          e = p_mb(i)*r/(622.+r)
! get temperature at the lifting condensation level
! eq. 21 of Bolton 1980
          t_l = 2840./(3.5*log(pt(i,j,k))-log(e)-4.805)+55.
! get the equivalent potential temperature
!         theta_e(i,j,k) = pt(i,j,k)*exp( (cappa*(1.-0.28e-3*r)*log(1000./p_mb(i))) * &
!                          exp( (3.376/t_l-0.00254)*r*(1.+0.81e-3*r) )
           capa = cappa*(1. - r*0.28e-3)
           theta_e(i,j,k) = exp( (3.376/t_l-0.00254)*r*(1.+r*0.81e-3) )*pt(i,j,k)*(1000./p_mb(i))**capa
          enddo
        else
          if ( hydrostatic ) then
             do i = is,ie
                theta_e(i,j,k) = pt(i,j,k)*pk0/pkz(i,j,k)
             enddo
          else
             do i = is,ie
#ifdef MULTI_GASES
                theta_e(i,j,k) = pt(i,j,k)*exp( kappa * virqd(qi(i,j,k,1:num_gas))/vicpqd(qi(i,j,k,1:num_gas)) *log(1000./p_mb(i)) )
#else
                theta_e(i,j,k) = pt(i,j,k)*exp( kappa*log(1000./p_mb(i)) )
#endif
             enddo
          endif
        endif
      enddo ! j-loop
    enddo   ! k-loop

end subroutine eqv_pot

#endif

!>@brief The subroutine 'nh_total_energy computes vertically-integrated
!! total energy per column.
 subroutine nh_total_energy(is, ie, js, je, isd, ied, jsd, jed, km,  &
                            w, delz, pt, delp, q, hs, area, domain,  &
                            sphum, liq_wat, rainwat, ice_wat,        &
                            snowwat, graupel, nwat, ua, va, moist_phys, te)
! INPUT PARAMETERS:
   integer,  intent(in):: km, is, ie, js, je, isd, ied, jsd, jed
   integer,  intent(in):: nwat, sphum, liq_wat, rainwat, ice_wat, snowwat, graupel
   real, intent(in), dimension(isd:ied,jsd:jed,km):: ua, va, pt, delp, w, delz
   real, intent(in), dimension(isd:ied,jsd:jed,km,nwat):: q
   real, intent(in):: hs(isd:ied,jsd:jed)  !< surface geopotential
   real, intent(in):: area(isd:ied, jsd:jed)
   logical, intent(in):: moist_phys
   type(domain2d), intent(INOUT) :: domain
   real, intent(out):: te(is:ie,js:je)   !< vertically integrated TE
! Local
   real, parameter:: c_liq = 4190.       !< heat capacity of water at 0C
   real(kind=R_Grid) ::    area_l(isd:ied, jsd:jed)
   real, parameter:: cv_vap = cp_vapor - rvgas  !< 1384.5
   real  phiz(is:ie,km+1)
   real, dimension(is:ie):: cvm, qc
   real cv_air, psm
   integer i, j, k

   area_l = area
   cv_air =  cp_air - rdgas

!$OMP parallel do default(none) shared(te,nwat,is,ie,js,je,isd,ied,jsd,jed,km,ua,va,   &
#ifdef MULTI_GASES
!$OMP          num_gas,                                                                &
#endif
!$OMP          w,q,pt,delp,delz,hs,cv_air,moist_phys,sphum,liq_wat,rainwat,ice_wat,snowwat,graupel) &
!$OMP          private(phiz,cvm, qc)
  do j=js,je

     do i=is,ie
        te(i,j) = 0.
        phiz(i,km+1) = hs(i,j)
     enddo

     do i=is,ie
        do k=km,1,-1
           phiz(i,k) = phiz(i,k+1) - grav*delz(i,j,k)
        enddo
     enddo

     if ( moist_phys ) then
        do k=1,km
           call moist_cv(is,ie,isd,ied,jsd,jed, km, j, k, nwat, sphum, liq_wat, rainwat,    &
                         ice_wat, snowwat, graupel, q, qc, cvm)
           do i=is,ie
              te(i,j) = te(i,j) + delp(i,j,k)*( cvm(i)*pt(i,j,k) + hlv*q(i,j,k,sphum) +  &
                      0.5*(phiz(i,k)+phiz(i,k+1)+ua(i,j,k)**2+va(i,j,k)**2+w(i,j,k)**2) )
           enddo
        enddo
     else
       do k=1,km
          do i=is,ie
#ifdef MULTI_GASES
             te(i,j) = te(i,j) + delp(i,j,k)*( cv_air*vicvqd(q(i,j,k,1:num_gas))*pt(i,j,k) +  &
                     0.5*(phiz(i,k)+phiz(i,k+1)+ua(i,j,k)**2+va(i,j,k)**2+w(i,j,k)**2) )
#else
             te(i,j) = te(i,j) + delp(i,j,k)*( cv_air*pt(i,j,k) +  &
                     0.5*(phiz(i,k)+phiz(i,k+1)+ua(i,j,k)**2+va(i,j,k)**2+w(i,j,k)**2) )
#endif
          enddo
       enddo
     endif
! Unit: kg*(m/s)^2/m^2 = Joule/m^2
     do i=is,ie
        te(i,j) = te(i,j)/grav
     enddo
  enddo

  psm = g_sum(domain, te, is, ie, js, je, 3, area_l, 1) 
  if( master ) write(*,*) 'TE ( Joule/m^2 * E9) =',  psm * 1.E-9

  end subroutine nh_total_energy

!>@brief The subroutine 'dbzcalc' computes equivalent reflectivity factor (in dBZ) at
!! each model grid point.
!>@details In calculating Ze, the RIP algorithm makes
!! assumptions consistent with those made in an early version
!! (ca. 1996) of the bulk mixed-phase microphysical scheme in the MM5
!!  model (i.e., the scheme known as "Resiner-2").
!!  More information on the derivation of simulated reflectivity in RIP
!!  can be found in Stoelinga (2005, unpublished write-up).  Contact
!!  Mark Stoelinga (stoeling@atmos.washington.edu) for a copy. 
!>@date 22 September, 2016 - modified for use with GFDL cloud microphysics parameters.
 subroutine dbzcalc(q, pt, delp, peln, delz, &
      dbz, maxdbz, allmax, bd, npz, ncnst, &
      hydrostatic, zvir, in0r, in0s, in0g, iliqskin)

! Code from Mark Stoelinga's dbzcalc.f from the RIP package. 
! Currently just using values taken directly from that code, which is
! consistent for the MM5 Reisner-2 microphysics. From that file:

!     This routine computes equivalent reflectivity factor (in dBZ) at
!     each model grid point.  In calculating Ze, the RIP algorithm makes
!     assumptions consistent with those made in an early version
!     (ca. 1996) of the bulk mixed-phase microphysical scheme in the MM5
!     model (i.e., the scheme known as "Resiner-2").  For each species:
!
!     1. Particles are assumed to be spheres of constant density.  The
!     densities of rain drops, snow particles, and graupel particles are
!     taken to be rho_r = rho_l = 1000 kg m^-3, rho_s = 100 kg m^-3, and
!     rho_g = 400 kg m^-3, respectively. (l refers to the density of
!     liquid water.)
!
!     2. The size distribution (in terms of the actual diameter of the
!     particles, rather than the melted diameter or the equivalent solid
!     ice sphere diameter) is assumed to follow an exponential
!     distribution of the form N(D) = N_0 * exp( lambda*D ).
!
!     3. If in0X=0, the intercept parameter is assumed constant (as in
!     early Reisner-2), with values of 8x10^6, 2x10^7, and 4x10^6 m^-4,
!     for rain, snow, and graupel, respectively.  Various choices of
!     in0X are available (or can be added).  Currently, in0X=1 gives the
!     variable intercept for each species that is consistent with
!     Thompson, Rasmussen, and Manning (2004, Monthly Weather Review,
!     Vol. 132, No. 2, pp. 519-542.)
!
!     4. If iliqskin=1, frozen particles that are at a temperature above
!     freezing are assumed to scatter as a liquid particle.
!
!     More information on the derivation of simulated reflectivity in RIP
!     can be found in Stoelinga (2005, unpublished write-up).  Contact
!     Mark Stoelinga (stoeling@atmos.washington.edu) for a copy.  

! 22sep16: Modifying to use the GFDL MP parameters. If doing so remember
!   that the GFDL MP assumes a constant intercept (in0X = .false.)
!   Ferrier-Aligo has an option for fixed slope (rather than fixed intercept).
!   Thompson presumably is an extension of Reisner MP.

   type(fv_grid_bounds_type), intent(IN) :: bd
   integer, intent(IN) :: npz, ncnst
   real,    intent(IN),  dimension(bd%isd:bd%ied, bd%jsd:bd%jed, npz) :: pt, delp, delz
   real,    intent(IN),  dimension(bd%isd:bd%ied, bd%jsd:bd%jed, npz, ncnst) :: q
   real,    intent(IN),  dimension(bd%is :bd%ie,  npz+1, bd%js:bd%je) :: peln
   real,    intent(OUT), dimension(bd%is :bd%ie,  bd%js :bd%je , npz) :: dbz
   real,    intent(OUT), dimension(bd%is :bd%ie,  bd%js :bd%je)      :: maxdbz
   logical, intent(IN) :: hydrostatic, in0r, in0s, in0g, iliqskin
   real,    intent(IN) :: zvir
   real,    intent(OUT) :: allmax

   !Parameters for constant intercepts (in0[rsg] = .false.)
   !Using GFDL MP values
   real(kind=R_GRID), parameter:: rn0_r = 8.e6 ! m^-4
   real(kind=R_GRID), parameter:: rn0_s = 3.e6 ! m^-4
   real(kind=R_GRID), parameter:: rn0_g = 4.e6 ! m^-4
   real(kind=R_GRID), parameter:: vconr = 2503.23638966667
   real(kind=R_GRID), parameter:: vcong =   87.2382675
   real(kind=R_GRID), parameter:: vcons =    6.6280504
   real(kind=R_GRID), parameter:: normr = 25132741228.7183
   real(kind=R_GRID), parameter:: normg =  5026548245.74367
   real(kind=R_GRID), parameter:: norms =   942477796.076938

   !Constants for variable intercepts
   !Will need to be changed based on MP scheme
   real, parameter :: r1=1.e-15
   real, parameter :: ron=8.e6
   real, parameter :: ron2=1.e10
   real, parameter :: son=2.e7
   real, parameter :: gon=5.e7
   real, parameter :: ron_min = 8.e6
   real, parameter :: ron_qr0 = 0.00010
   real, parameter :: ron_delqr0 = 0.25*ron_qr0
   real, parameter :: ron_const1r = (ron2-ron_min)*0.5
   real, parameter :: ron_const2r = (ron2+ron_min)*0.5

   !Other constants
   real, parameter :: gamma_seven = 720.
   !The following values are also used in GFDL MP
   real, parameter :: rho_r  = 1.0e3  ! LFO83
   real, parameter :: rho_s  = 100.   ! kg m^-3 
   real, parameter :: rho_g0 = 400.   ! kg m^-3
   real, parameter :: rho_g  = 500.   ! graupel-hail mix
!  real, parameter :: rho_g  = 900.   ! hail/frozen rain
   real, parameter :: alpha  = 0.224
   real(kind=R_GRID), parameter :: factor_r = gamma_seven * 1.e18 * (1./(pi*rho_r))**1.75
   real(kind=R_GRID), parameter :: factor_s = gamma_seven * 1.e18 * (1./(pi*rho_s))**1.75 &
        * (rho_s/rho_r)**2 * alpha
   real(kind=R_GRID), parameter :: factor_g = gamma_seven * 1.e18 * (1./(pi*rho_g))**1.75 &
        * (rho_g/rho_r)**2 * alpha
   real, parameter :: qmin = 1.E-12
   real, parameter :: tice = 273.16

! Double precision
   real(kind=R_GRID):: rhoair(bd%is:bd%ie)
   real(kind=R_GRID):: qr1, qs1, qg1, t1, t2, t3, rwat, denfac, vtr, vtg, vts
   real(kind=R_GRID):: factorb_s, factorb_g
   real(kind=R_GRID):: temp_c, pres, sonv, gonv, ronv, z_e

   integer :: i,j,k
   integer :: is, ie, js, je

   is = bd%is
   ie = bd%ie
   js = bd%js
   je = bd%je
   if (rainwat < 1) return

   dbz(:,:,1:mp_top) = -20.
   maxdbz(:,:) = -20. !Minimum value
   allmax = -20.


!$OMP parallel do default(shared) private(rhoair,t1,t2,t3,denfac,vtr,vtg,vts,z_e)
   do k=mp_top+1, npz
   do j=js, je
      if (hydrostatic) then
         do i=is, ie
#ifdef MULTI_GASES
            rhoair(i) = delp(i,j,k)/( (peln(i,k+1,j)-peln(i,k,j)) * rdgas * pt(i,j,k) * virq(q(i,j,k,1:num_gas)) )
#else
            rhoair(i) = delp(i,j,k)/( (peln(i,k+1,j)-peln(i,k,j)) * rdgas * pt(i,j,k) * ( 1. + zvir*q(i,j,k,sphum) ) )
#endif
         enddo
      else
         do i=is, ie
            rhoair(i) = -delp(i,j,k)/(grav*delz(i,j,k)) ! moist air density
         enddo
      endif
      do i=is, ie
! The following form vectorizes better & more consistent with GFDL_MP
! SJL notes: Marshall-Palmer, dBZ = 200*precip**1.6, precip = 3.6e6*t1/rho_r*vtr  ! [mm/hr]
! GFDL_MP terminal fall speeds are used
! Date modified 20170701
! Account for excessively high cloud water -> autoconvert (diag only) excess cloud water
         t1 = rhoair(i)*max(qmin, q(i,j,k,rainwat)+dim(q(i,j,k,liq_wat), 1.0e-3))
         t2 = rhoair(i)*max(qmin, q(i,j,k,snowwat))
         if (graupel > 0) then
           t3 = rhoair(i)*max(qmin, q(i,j,k,graupel))
         else
           t3 = rhoair(i)*qmin
         endif
         denfac = sqrt(min(10., 1.2/rhoair(i)))
         vtr = max(1.e-3, vconr*denfac*exp(0.2   *log(t1/normr)))
         vtg = max(1.e-3, vcong*denfac*exp(0.125 *log(t3/normg)))
!     vts = max(1.e-3, vcons*denfac*exp(0.0625*log(t2/norms)))
         z_e = 200.*(exp(1.6*log(3.6e6*t1/rho_r*vtr)) + exp(1.6*log(3.6e6*t3/rho_g0*vtg))) + (factor_s/alpha)*t2*exp(0.75*log(t2/rn0_s))
!     z_e = 200.*(exp(1.6*log(3.6e6*t1/rho_r*vtr)) + exp(1.6*log(3.6e6*t3/rho_g*vtg)) + exp(1.6*log(3.6e6*t2/rho_s*vts)))
         dbz(i,j,k) = 10.*log10( max(0.01, z_e) )
      enddo
   enddo
   enddo

!$OMP parallel do default(shared)
   do j=js, je
      do k=mp_top+1, npz
         do i=is, ie
            maxdbz(i,j) = max(dbz(i,j,k), maxdbz(i,j))
         enddo
      enddo
   enddo

   do j=js, je
      do i=is, ie
         allmax = max(maxdbz(i,j), allmax)
      enddo
   enddo

 end subroutine dbzcalc
!
 subroutine max_vorticity_hy1(is, ie, js, je, km, vort, maxvorthy1)
   integer, intent(in):: is, ie, js, je, km
   real, intent(in), dimension(is:ie,js:je,km):: vort
   real, intent(inout), dimension(is:ie,js:je):: maxvorthy1
   integer i, j, k

   do j=js,je
      do i=is,ie
         maxvorthy1(i,j)=max(maxvorthy1(i,j),vort(i,j,km))
      enddo  ! i-loop
   enddo   ! j-loop
 end subroutine max_vorticity_hy1
!
! subroutine max_vorticity(is, ie, js, je, ng, km, zvir, sphum, delz, q, hydrostatic, &
!                          pt, peln, phis, grav, vort, maxvorthy1, maxvort, z_bot, z_top)
 subroutine max_vorticity(is, ie, js, je, ng, km, zvir, sphum, delz, q, hydrostatic, &
                          pt, peln, phis, grav, vort, maxvort, z_bot, z_top)
   integer, intent(in):: is, ie, js, je, ng, km, sphum
   real, intent(in):: grav, zvir, z_bot, z_top
   real, intent(in), dimension(is-ng:ie+ng,js-ng:je+ng,km):: pt
   real, intent(in), dimension(is:ie,js:je,km):: vort
   real, intent(in):: delz(is-ng:ie+ng,js-ng:je+ng,km)
   real, intent(in):: q(is-ng:ie+ng,js-ng:je+ng,km,*)
   real, intent(in):: phis(is-ng:ie+ng,js-ng:je+ng)
   real, intent(in):: peln(is:ie,km+1,js:je)
   logical, intent(in):: hydrostatic
!   real, intent(inout), dimension(is:ie,js:je):: maxvorthy1,maxvort
   real, intent(inout), dimension(is:ie,js:je):: maxvort

   real:: rdg
   real, dimension(is:ie):: zh, dz, zh0
   integer i, j, k,klevel
   logical below(is:ie)

   rdg = rdgas / grav

   do j=js,je

      do i=is,ie
         zh(i) = 0.
         below(i) = .true.
         zh0(i) = 0.

     K_LOOP:do k=km,1,-1
            if ( hydrostatic ) then
                 dz(i) = rdg*pt(i,j,k)*(1.+zvir*q(i,j,k,sphum))*(peln(i,k+1,j)-peln(i,k,j))
            else
                 dz(i) = - delz(i,j,k)
            endif
            zh(i) = zh(i) + dz(i)
            if (zh(i) <= z_bot ) continue
            if (zh(i) > z_bot .and. below(i)) then
               maxvort(i,j) = max(maxvort(i,j),vort(i,j,k))
               below(i) = .false.
            elseif ( zh(i) < z_top ) then
               maxvort(i,j) = max(maxvort(i,j),vort(i,j,k))
            else
               maxvort(i,j) = max(maxvort(i,j),vort(i,j,k))
               EXIT K_LOOP 
            endif
         enddo K_LOOP
!      maxvorthy1(i,j)=max(maxvorthy1(i,j),vort(i,j,km))
      enddo  ! i-loop
   enddo   ! j-loop


 end subroutine max_vorticity

 subroutine max_uh(is, ie, js, je, ng, km, zvir, sphum, uphmax,uphmin,   &
                  w, vort, delz, q, hydrostatic, pt, peln, phis, grav, z_bot, z_top)
! !INPUT PARAMETERS:
   integer, intent(in):: is, ie, js, je, ng, km, sphum
   real, intent(in):: grav, zvir, z_bot, z_top
   real, intent(in), dimension(is-ng:ie+ng,js-ng:je+ng,km):: pt, w
   real, intent(in), dimension(is:ie,js:je,km):: vort
   real, intent(in):: delz(is-ng:ie+ng,js-ng:je+ng,km)
   real, intent(in):: q(is-ng:ie+ng,js-ng:je+ng,km,*)
   real, intent(in):: phis(is-ng:ie+ng,js-ng:je+ng)
   real, intent(in):: peln(is:ie,km+1,js:je)
   logical, intent(in):: hydrostatic
   real :: uh(is:ie,js:je)   ! unit: (m/s)**2
   real, intent(inout), dimension(is:ie,js:je):: uphmax,uphmin
! Coded by S.-J. Lin for CONUS regional climate simulations
! Modified for UH by LMH
!
   real:: rdg
   real, dimension(is:ie):: zh, dz, zh0
   integer i, j, k
   logical below(is:ie)

   rdg = rdgas / grav
   do j=js,je

      do i=is,ie
         zh(i) = 0.
         uh(i,j) = 0.
         below(i) = .true.
         zh0(i) = 0.

!        if ( phis(i,j)/grav < 1.E3 ) then
  K_LOOP:do k=km,1,-1
            if ( hydrostatic ) then
                 dz(i) = rdg*pt(i,j,k)*(1.+zvir*q(i,j,k,sphum))*(peln(i,k+1,j)-peln(i,k,j))
            else
                 dz(i) = - delz(i,j,k)
            endif
            zh(i) = zh(i) + dz(i)
            if (zh(i) <= z_bot ) continue
            if (zh(i) > z_bot .and. below(i)) then
               if(w(i,j,k).lt.0)then
                  uh(i,j) = 0.
                  EXIT K_LOOP
               endif 
               uh(i,j) = vort(i,j,k)*w(i,j,k)*(zh(i) - z_bot)
               below(i) = .false.
! Compute mean winds below z_top
            elseif ( zh(i) < z_top ) then
               if(w(i,j,k).lt.0)then
                  uh(i,j) = 0.
                  EXIT K_LOOP
               endif
               uh(i,j) = uh(i,j) + vort(i,j,k)*w(i,j,k)*dz(i)
            else
               if(w(i,j,k).lt.0)then
                  uh(i,j) = 0.
                  EXIT K_LOOP
               endif
               uh(i,j) = uh(i,j) + vort(i,j,k)*w(i,j,k)*(z_top - (zh(i)-dz(i)) )
               EXIT K_LOOP
            endif
         enddo K_LOOP
        if (uh(i,j) > uphmax(i,j)) then 
           uphmax(i,j) = uh(i,j)
        elseif (uh(i,j) < uphmin(i,j)) then 
           uphmin(i,j) = uh(i,j)
        endif 
      enddo  ! i-loop
   enddo   ! j-loop

 end subroutine max_uh 
 subroutine max_vv(is,ie,js,je,npz,ng,up2,dn2,pe,w)
! !INPUT PARAMETERS:
   integer, intent(in):: is, ie, js, je, ng, npz
   integer :: i,j,k
   real, intent(in), dimension(is-ng:ie+ng,js-ng:je+ng,npz):: w
   real, intent(in):: pe(is-1:ie+1,npz+1,js-1:je+1)
   real, intent(inout), dimension(is:ie,js:je):: up2,dn2
      do j=js,je
         do i=is,ie
            do k=3,npz
              if (pe(i,k,j) >= 100.e2) then 
                  up2(i,j) = max(up2(i,j),w(i,j,k))
                  dn2(i,j) = min(dn2(i,j),w(i,j,k))
              endif
             enddo
         enddo
      enddo
 end subroutine max_vv 

 subroutine fv_diag_init_gn(Atm)
   type(fv_atmos_type), intent(inout), target :: Atm
   
   if (Atm%grid_Number > 1) then
      write(gn,"(A2,I1)") " g", Atm%grid_number
   else
      gn = ""
   end if
   
 end subroutine fv_diag_init_gn

!>@brief The subroutine 'getcape' calculates the Convective Available
!! Potential Energy (CAPE) from a Sounding
!>@author George H. Bryan
!! Mesoscale and Microscale Meteorology Division
!! National Center for Atmospheric Research
!! Boulder, Colorado, USA
!! gbryan@ucar.edu
!>@details: Last modified 10 October 2008
    subroutine getcape( nk , p , t , dz, q, the, cape , cin, source_in )
    implicit none

    integer, intent(in) :: nk
    real, dimension(nk), intent(in) :: p,t,dz,q,the
    real, intent(out) :: cape,cin
    integer, intent(IN), OPTIONAL :: source_in

!-----------------------------------------------------------------------
!
!  getcape - a fortran90 subroutine to calculate Convective Available
!            Potential Energy (CAPE) from a sounding.
!
!  Version 1.02                           Last modified:  10 October 2008
!
!  Author:  George H. Bryan
!           Mesoscale and Microscale Meteorology Division
!           National Center for Atmospheric Research
!           Boulder, Colorado, USA
!           gbryan@ucar.edu
!
!  Disclaimer:  This code is made available WITHOUT WARRANTY.
!
!  References:  Bolton (1980, MWR, p. 1046) (constants and definitions)
!               Bryan and Fritsch (2004, MWR, p. 2421) (ice processes)
!
!-----------------------------------------------------------------------
!
!  Input:     nk - number of levels in the sounding (integer)
!
!           p - one-dimensional array of pressure (Pa) (real)
!
!           t - one-dimensional array of temperature (K) (real)
!
!           dz - one-dimensional array of height thicknesses (m) (real)
!
!           q - one-dimensional array of specific humidity (kg/kg) (real)
!
!          source - source parcel:
!                   1 = surface (default)
!                   2 = most unstable (max theta-e)
!                   3 = mixed-layer (specify ml_depth)
!
!  Output:  cape - Convective Available Potential Energy (J/kg) (real)
!
!            cin - Convective Inhibition (J/kg) (real)
!
!-----------------------------------------------------------------------
!  User options:

    real, parameter :: pinc = 10000.0   !< Pressure increment (Pa)
                                        ! (smaller number yields more accurate
                                        !  results,larger number makes code 
                                        !  go faster)


    real, parameter :: ml_depth =  200.0 !< depth (m) of mixed layer 
                                         !! for source=3

    integer, parameter :: adiabat = 1   !< Formulation of moist adiabat:
                                        !< 1 = pseudoadiabatic, liquid only
                                        !< 2 = reversible, liquid only
                                        !< 3 = pseudoadiabatic, with ice
                                        !< 4 = reversible, with ice

!-----------------------------------------------------------------------
!ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
!-----------------------------------------------------------------------
!            No need to modify anything below here:
!-----------------------------------------------------------------------

    integer :: source = 1
    logical :: doit,ice,cloud,not_converged
    integer :: k,kmin,n,nloop,i,orec
    real, dimension(nk) :: pi,th,thv,z,pt,pb,pc,pn,ptv

    real :: maxthe,parea,narea,lfc
    real :: th1,p1,t1,qv1,ql1,qi1,b1,pi1,thv1,qt,dp,frac
    real :: th2,p2,t2,qv2,ql2,qi2,b2,pi2,thv2
    real :: thlast,fliq,fice,tbar,qvbar,qlbar,qibar,lhv,lhs,lhf,rm,cpm
    real*8 :: avgth,avgqv

!-----------------------------------------------------------------------

    real, parameter :: g     = 9.81
    real, parameter :: p00   = 100000.0
    real, parameter :: cp    = 1005.7
    real, parameter :: rd    = 287.04
    real, parameter :: rv    = 461.5
    real, parameter :: xlv   = 2501000.0
    real, parameter :: xls   = 2836017.0
    real, parameter :: t0    = 273.15
    real, parameter :: cpv   = 1875.0
    real, parameter :: cpl   = 4190.0
    real, parameter :: cpi   = 2118.636
    real, parameter :: lv1   = xlv+(cpl-cpv)*t0
    real, parameter :: lv2   = cpl-cpv
    real, parameter :: ls1   = xls+(cpi-cpv)*t0
    real, parameter :: ls2   = cpi-cpv

    real, parameter :: rp00  = 1.0/p00
    real, parameter :: eps   = rd/rv
    real, parameter :: reps  = rv/rd
    real, parameter :: rddcp = rd/cp
    real, parameter :: cpdrd = cp/rd
    real, parameter :: cpdg  = cp/g

    real, parameter :: converge = 0.1

    integer, parameter :: debug_level =   0

    if (present(source_in)) source = source_in

!-----------------------------------------------------------------------

!---- convert p,t to mks units; get pi,th,thv ----!

    do k=1,nk
       pi(k) = (p(k)*rp00)**rddcp
       th(k) = t(k)/pi(k)
      thv(k) = th(k)*(1.0+reps*q(k))/(1.0+q(k))
    enddo

!---- get height using the hydrostatic equation ----!

    z(nk) = 0.5*dz(nk)
    do k=nk-1,1,-1
      z(k) = z(k+1) + 0.5*(dz(k+1)+dz(k))
    enddo

!---- find source parcel ----!

  IF(source.eq.1)THEN
    ! use surface parcel
    kmin = nk

  ELSEIF(source.eq.2)THEN
    ! use most unstable parcel (max theta-e)

    IF(p(1).lt.50000.0)THEN
      ! first report is above 500 mb ... just use the first level reported
      kmin = nk
      maxthe = the(nk)
    ELSE
      ! find max thetae below 500 mb
      maxthe = 0.0
      do k=nk,1,-1
        if(p(k).ge.50000.0)then
          if( the(nk).gt.maxthe )then
            maxthe = the(nk)
            kmin = k
          endif
        endif
      enddo
    ENDIF
    if(debug_level.ge.100) print *,'  kmin,maxthe = ',kmin,maxthe

!!$  ELSEIF(source.eq.3)THEN
!!$    ! use mixed layer
!!$
!!$    IF( dz(nk).gt.ml_depth )THEN
!!$      ! the second level is above the mixed-layer depth:  just use the
!!$      ! lowest level
!!$
!!$      avgth = th(nk)
!!$      avgqv = q(nk)
!!$      kmin = nk
!!$
!!$    ELSEIF( z(1).lt.ml_depth )THEN
!!$      ! the top-most level is within the mixed layer:  just use the
!!$      ! upper-most level (not 
!!$
!!$      avgth = th(1)
!!$      avgqv = q(1)
!!$      kmin = 1
!!$
!!$    ELSE
!!$      ! calculate the mixed-layer properties:
!!$
!!$      avgth = 0.0
!!$      avgqv = 0.0
!!$      k = nk-1
!!$      if(debug_level.ge.100) print *,'  ml_depth = ',ml_depth
!!$      if(debug_level.ge.100) print *,'  k,z,th,q:'
!!$      if(debug_level.ge.100) print *,nk,z(nk),th(nk),q(nk)
!!$
!!$      do while( (z(k).le.ml_depth) .and. (k.ge.1) )
!!$
!!$        if(debug_level.ge.100) print *,k,z(k),th(k),q(k)
!!$
!!$        avgth = avgth + dz(k)*th(k)
!!$        avgqv = avgqv + dz(k)*q(k)
!!$
!!$        k = k - 1
!!$
!!$      enddo
!!$
!!$      th2 = th(k+1)+(th(k)-th(k+1))*(ml_depth-z(k-1))/dz(k)
!!$      qv2 =  q(k+1)+( q(k)- q(k+1))*(ml_depth-z(k-1))/dz(k)
!!$
!!$      if(debug_level.ge.100) print *,999,ml_depth,th2,qv2
!!$
!!$      avgth = avgth + 0.5*(ml_depth-z(k-1))*(th2+th(k-1))
!!$      avgqv = avgqv + 0.5*(ml_depth-z(k-1))*(qv2+q(k-1))
!!$
!!$      if(debug_level.ge.100) print *,k,z(k),th(k),q(k)
!!$
!!$      avgth = avgth/ml_depth
!!$      avgqv = avgqv/ml_depth
!!$
!!$      kmin = nk
!!$
!!$    ENDIF
!!$
!!$    if(debug_level.ge.100) print *,avgth,avgqv

  ELSE

    print *
    print *,'  Unknown value for source'
    print *
    print *,'  source = ',source
    print *
    call mpp_error(FATAL, " Unknown CAPE source")

  ENDIF

!---- define parcel properties at initial location ----!
    narea = 0.0

  if( (source.eq.1).or.(source.eq.2) )then
    k    = kmin
    th2  = th(kmin)
    pi2  = pi(kmin)
    p2   = p(kmin)
    t2   = t(kmin)
    thv2 = thv(kmin)
    qv2  = q(kmin)
    b2   = 0.0
  elseif( source.eq.3 )then
    k    = kmin
    th2  = avgth
    qv2  = avgqv
    thv2 = th2*(1.0+reps*qv2)/(1.0+qv2)
    pi2  = pi(kmin)
    p2   = p(kmin)
    t2   = th2*pi2
    b2   = g*( thv2-thv(kmin) )/thv(kmin)
  endif

    ql2 = 0.0
    qi2 = 0.0
    qt  = qv2

    cape = 0.0
    cin  = 0.0
    lfc  = 0.0

    doit = .true.
    cloud = .false.
    if(adiabat.eq.1.or.adiabat.eq.2)then
      ice = .false.
    else
      ice = .true.
    endif

!      the = getthe(p2,t2,t2,qv2)
!      if(debug_level.ge.100) print *,'  the = ',the

!---- begin ascent of parcel ----!

      if(debug_level.ge.100)then
        print *,'  Start loop:'
        print *,'  p2,th2,qv2 = ',p2,th2,qv2
      endif

    do while( doit .and. (k.gt.1) )

        k = k-1
       b1 =  b2

       dp = p(k)-p(k-1)

      if( dp.lt.pinc )then
        nloop = 1
      else
        nloop = 1 + int( dp/pinc )
        dp = dp/float(nloop)
      endif

      do n=1,nloop

         p1 =  p2
         t1 =  t2
        pi1 = pi2
        th1 = th2
        qv1 = qv2
        ql1 = ql2
        qi1 = qi2
        thv1 = thv2

        p2 = p2 - dp
        pi2 = (p2*rp00)**rddcp

        thlast = th1
        i = 0
        not_converged = .true.

        do while( not_converged )
          i = i + 1
          t2 = thlast*pi2
          if(ice)then
            fliq = max(min((t2-233.15)/(273.15-233.15),1.0),0.0)
            fice = 1.0-fliq
          else
            fliq = 1.0
            fice = 0.0
          endif
          qv2 = min( qt , fliq*getqvs(p2,t2) + fice*getqvi(p2,t2) )
          qi2 = max( fice*(qt-qv2) , 0.0 )
          ql2 = max( qt-qv2-qi2 , 0.0 )

          tbar  = 0.5*(t1+t2)
          qvbar = 0.5*(qv1+qv2)
          qlbar = 0.5*(ql1+ql2)
          qibar = 0.5*(qi1+qi2)

          lhv = lv1-lv2*tbar
          lhs = ls1-ls2*tbar
          lhf = lhs-lhv

          rm=rd+rv*qvbar
          cpm=cp+cpv*qvbar+cpl*qlbar+cpi*qibar
          th2=th1*exp(  lhv*(ql2-ql1)/(cpm*tbar)     &
                       +lhs*(qi2-qi1)/(cpm*tbar)     &
                       +(rm/cpm-rd/cp)*alog(p2/p1) )

          if(i.gt.90) print *,i,th2,thlast,th2-thlast
          if(i.gt.100)then
            print *
            print *,'  Error:  lack of convergence'
            print *
            print *,'  ... stopping iteration '
            print *
            stop 1001
          endif
          if( abs(th2-thlast).gt.converge )then
            thlast=thlast+0.3*(th2-thlast)
          else
            not_converged = .false.
          endif
        enddo

        ! Latest pressure increment is complete.  Calculate some
        ! important stuff:

        if( ql2.ge.1.0e-10 ) cloud = .true.

        IF(adiabat.eq.1.or.adiabat.eq.3)THEN
          ! pseudoadiabat
          qt  = qv2
          ql2 = 0.0
          qi2 = 0.0
        ELSEIF(adiabat.le.0.or.adiabat.ge.5)THEN
          print *
          print *,'  Undefined adiabat'
          print *
          stop 10000
        ENDIF

      enddo

      thv2 = th2*(1.0+reps*qv2)/(1.0+qv2+ql2+qi2)
        b2 = g*( thv2-thv(k) )/thv(k)

!      the = getthe(p2,t2,t2,qv2)

      ! Get contributions to CAPE and CIN:

      if( (b2.ge.0.0) .and. (b1.lt.0.0) )then
        ! first trip into positive area
        !ps = p(k-1)+(p(k)-p(k-1))*(0.0-b1)/(b2-b1)
        frac = b2/(b2-b1)
        parea =  0.5*b2*dz(k)*frac
        narea = narea-0.5*b1*dz(k)*(1.0-frac)
        if(debug_level.ge.200)then
          print *,'      b1,b2 = ',b1,b2
          !print *,'      p1,ps,p2 = ',p(k-1),ps,p(k)
          print *,'      frac = ',frac
          print *,'      parea = ',parea
          print *,'      narea = ',narea
        endif
        cin  = cin  + narea
        narea = 0.0
      elseif( (b2.lt.0.0) .and. (b1.gt.0.0) )then
        ! first trip into neg area
        !ps = p(k-1)+(p(k)-p(k-1))*(0.0-b1)/(b2-b1)
        frac = b1/(b1-b2)
        parea =  0.5*b1*dz(k)*frac
        narea = -0.5*b2*dz(k)*(1.0-frac)
        if(debug_level.ge.200)then
          print *,'      b1,b2 = ',b1,b2
          !print *,'      p1,ps,p2 = ',p(k-1),ps,p(k)
          print *,'      frac = ',frac
          print *,'      parea = ',parea
          print *,'      narea = ',narea
        endif
      elseif( b2.lt.0.0 )then
        ! still collecting negative buoyancy
        parea =  0.0
        narea = narea-0.5*dz(k)*(b1+b2)
      else
        ! still collecting positive buoyancy
        parea =  0.5*dz(k)*(b1+b2)
        narea =  0.0
      endif

      cape = cape + max(0.0,parea)

      if(debug_level.ge.200)then
        write(6,102) p2,b1,b2,cape,cin,cloud
102     format(5(f13.4),2x,l1)
      endif

      if( (p(k).le.10000.0).and.(b2.lt.0.0) )then
        ! stop if b < 0 and p < 100 mb
        doit = .false.
      endif

    enddo

!---- All done ----!

    return
  end subroutine getcape
!-----------------------------------------------------------------------


  real function getqvs(p,t)
    implicit none

    real :: p,t,es

    real, parameter :: eps = 287.04/461.5

    es = 611.2*exp(17.67*(t-273.15)/(t-29.65))
    getqvs = eps*es/(p-es)

    return
  end function getqvs
!-----------------------------------------------------------------------


  real function getqvi(p,t)
    implicit none

    real :: p,t,es

    real, parameter :: eps = 287.04/461.5

    es = 611.2*exp(21.8745584*(t-273.15)/(t-7.66))
    getqvi = eps*es/(p-es)

    return
  end function getqvi
!-----------------------------------------------------------------------

end module fv_diagnostics_mod