!> @file
!! @brief Process atmospheric fields.
!! @author George Gayno NCEP/EMC

!> Process atmospheric fields. Horizontally interpolate from input to
!! target FV3 grid using ESMF regridding. Adjust surface pressure
!! according to terrain differences between input and target
!! grid. Vertically interpolate to target FV3 grid vertical
!! levels. Processing based on the spectral GFS version of CHGRES.
!! 
!! For variables "b4adj" indicates fields on the target grid before
!! vertical adjustment. "target" indicates data on target grid.
!! "input" indicates data on input grid. "_s" indicates fields on the
!! 'south' edge of the grid box.  "_w" indicate fields on the 'west'
!! edge of the grid box.  Otherwise, fields are at the center of the
!! grid box.
!!
!! @author George Gayno NCEP/EMC
 module atmosphere

 use esmf

 use atmosphere_target_data, only    : lev_target, levp1_target, nvcoord_target, &
                                       vcoord_target, delp_target_grid, &
                                       dzdt_target_grid, ps_target_grid, &
                                       temp_target_grid, tracers_target_grid, &
                                       u_s_target_grid, v_s_target_grid, &
                                       u_w_target_grid, v_w_target_grid, &
                                       zh_target_grid, qnwfa_climo_target_grid, &
                                       qnifa_climo_target_grid

 use atm_input_data, only            : lev_input, &
                                       levp1_input, &
                                       tracers_input_grid, &
                                       dzdt_input_grid, &
                                       ps_input_grid, &
                                       xwind_input_grid,   &
                                       ywind_input_grid,   &
                                       zwind_input_grid,   &
                                       temp_input_grid,   &
                                       pres_input_grid,   &
                                       terrain_input_grid, &
                                       read_input_atm_data, &
                                       cleanup_input_atm_data

 use model_grid, only                : target_grid,  &
                                       latitude_s_target_grid,  &
                                       longitude_s_target_grid, &
                                       latitude_w_target_grid,  &
                                       longitude_w_target_grid, &
                                       terrain_target_grid

 use program_setup, only             : vcoord_file_target_grid, &
                                       wam_cold_start, wam_parm_file, & 
                                       cycle_year, cycle_mon,     &
                                       cycle_day, cycle_hour,     &
                                       regional, &
                                       tracers, num_tracers,      &
                                       num_tracers_input,         & 
                                       atm_weight_file, &
                                       use_thomp_mp_climo

 use thompson_mp_climo_data, only    : read_thomp_mp_climo_data,  &
                                       cleanup_thomp_mp_climo_input_data, &
                                       qnifa_climo_input_grid, &
                                       qnwfa_climo_input_grid, &
                                       thomp_pres_climo_input_grid, &
                                       lev_thomp_mp_climo

 use write_data, only                : write_fv3_atm_header_netcdf, &
                                       write_fv3_atm_bndy_data_netcdf, &
                                       write_fv3_atm_data_netcdf

 use utilities, only                 : error_handler

 implicit none

 private

 type(esmf_field)                       :: dzdt_b4adj_target_grid !< vertical vel before vert adj
 type(esmf_field), allocatable          :: tracers_b4adj_target_grid(:) !< tracers before vert adj
 type(esmf_field)                       :: ps_b4adj_target_grid !< sfc pres before terrain adj
 type(esmf_field)                       :: pres_target_grid !< 3-d pressure
 type(esmf_field)                       :: pres_b4adj_target_grid !< 3-d pres before terrain adj
 type(esmf_field)                       :: temp_b4adj_target_grid !< temp before vert adj
 type(esmf_field)                       :: terrain_interp_to_target_grid !< Input grid terrain interpolated to target grid.   
 type(esmf_field)                       :: xwind_target_grid !< x-component wind, grid box center
 type(esmf_field)                       :: ywind_target_grid !< y-component wind, grid box center
 type(esmf_field)                       :: zwind_target_grid !< z-component wind, grid box center
 type(esmf_field)                       :: xwind_b4adj_target_grid !< x-component wind, before vert adj
 type(esmf_field)                       :: ywind_b4adj_target_grid !< y-component wind, before vert adj
 type(esmf_field)                       :: zwind_b4adj_target_grid !< z-component wind, before vert adj
 type(esmf_field)                       :: xwind_s_target_grid !< x-component wind, 'south' edge
 type(esmf_field)                       :: ywind_s_target_grid !< y-component wind, 'south' edge
 type(esmf_field)                       :: zwind_s_target_grid !< z-component wind, 'south' edge
 type(esmf_field)                       :: xwind_w_target_grid !< x-component wind, 'west' edge
 type(esmf_field)                       :: ywind_w_target_grid !< y-component wind, 'west' edge
 type(esmf_field)                       :: zwind_w_target_grid !< z-component wind, 'west' edge

! Fields associated with thompson microphysics climatological tracers.

 type(esmf_field)                       :: qnifa_climo_b4adj_target_grid !< number concentration of ice
                                           !! friendly aerosols before vert adj
 type(esmf_field)                       :: qnwfa_climo_b4adj_target_grid !< number concentration of water
                                           !! friendly aerosols before vert adj
 type(esmf_field)                       :: thomp_pres_climo_b4adj_target_grid !< pressure of each level on
                                           !! target grid

 public :: atmosphere_driver
 public :: read_vcoord_info

 contains

!> Driver routine to process for atmospheric fields.
!!
!! @param[in] localpet ESMF local persistent execution thread 
!! @author George Gayno
 subroutine atmosphere_driver(localpet)

 use mpi_f08

 implicit none

 integer, intent(in)                :: localpet

 integer                            :: isrctermprocessing
 integer                            :: rc, n

 type(esmf_regridmethod_flag)       :: method
 type(esmf_routehandle)             :: regrid_bl

 real(esmf_kind_r8), parameter      :: p0=101325.0
 real(esmf_kind_r8), parameter      :: rd = 287.058
 real(esmf_kind_r8), parameter      :: grav = 9.81
 real(esmf_kind_r8), parameter      :: lapse = -6.5e-03

 real(esmf_kind_r8), parameter      :: exponent = rd*lapse/grav
 real(esmf_kind_r8), parameter      :: one_over_exponent = 1.0 / exponent

 real(esmf_kind_r8), pointer        :: psptr(:,:), tempptr(:,:,:)

!-----------------------------------------------------------------------------------
! Read atmospheric fields on the input grid.
!-----------------------------------------------------------------------------------

 call read_input_atm_data(localpet)

!-----------------------------------------------------------------------------------
! Read vertical coordinate info for target grid.
!-----------------------------------------------------------------------------------

 call read_vcoord_info

!-----------------------------------------------------------------------------------
! Create target grid field objects to hold data before vertical adjustment.
!-----------------------------------------------------------------------------------

 call create_atm_b4adj_esmf_fields

!-----------------------------------------------------------------------------------
! Horizontally interpolate.  If specified, use weights from file.
!-----------------------------------------------------------------------------------

 isrctermprocessing = 1

 if (trim(atm_weight_file) /= "NULL") then

   print*,"- CALL FieldSMMStore FOR ATMOSPHERIC FIELDS."

   call ESMF_FieldSMMStore(temp_input_grid, &
                           temp_b4adj_target_grid, &
                           atm_weight_file, &
                           routehandle=regrid_bl, &
                           srctermprocessing=isrctermprocessing, rc=rc)
   if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
      call error_handler("IN FieldSMMStore", rc)

 else

   print*,"- CALL FieldRegridStore FOR ATMOSPHERIC FIELDS."

   method=ESMF_REGRIDMETHOD_BILINEAR

   call ESMF_FieldRegridStore(temp_input_grid, &
                              temp_b4adj_target_grid, &
                              polemethod=ESMF_POLEMETHOD_ALLAVG, &
                              srctermprocessing=isrctermprocessing, &
                              routehandle=regrid_bl, &
                              regridmethod=method, rc=rc)
   if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
      call error_handler("IN FieldRegridStore", rc)

 endif

 print*,"- CALL Field_Regrid FOR TEMPERATURE."
 call ESMF_FieldRegrid(temp_input_grid, &
                       temp_b4adj_target_grid, &
                       routehandle=regrid_bl, &
                       termorderflag=ESMF_TERMORDER_SRCSEQ, &
                       rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldRegrid", rc)

 print*,"- CALL Field_Regrid FOR PRESSURE."
 call ESMF_FieldRegrid(pres_input_grid, &
                       pres_b4adj_target_grid, &
                       routehandle=regrid_bl, &
                       termorderflag=ESMF_TERMORDER_SRCSEQ, &
                       rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldRegrid", rc)

 do n = 1, num_tracers_input
   print*,"- CALL Field_Regrid FOR TRACER ", trim(tracers(n))
   call ESMF_FieldRegrid(tracers_input_grid(n), &
                         tracers_b4adj_target_grid(n), &
                         routehandle=regrid_bl, &
                         termorderflag=ESMF_TERMORDER_SRCSEQ, rc=rc)
   if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
      call error_handler("IN FieldRegrid", rc)
      
 enddo

 print*,"- CALL Field_Regrid FOR VERTICAL VELOCITY."
 call ESMF_FieldRegrid(dzdt_input_grid, &
                       dzdt_b4adj_target_grid, &
                       routehandle=regrid_bl, &
                       termorderflag=ESMF_TERMORDER_SRCSEQ, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldRegrid", rc)
    
 nullify(tempptr)
 print*,"- CALL FieldGet FOR INPUT GRID VERTICAL VEL."
 call ESMF_FieldGet(dzdt_input_grid, &
                    farrayPtr=tempptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)
    
 print*, "MIN MAX W INPUT = ", minval(tempptr), maxval(tempptr)

 nullify(tempptr)
 print*,"- CALL FieldGet FOR VERTICAL VEL B4ADJ."
 call ESMF_FieldGet(dzdt_b4adj_target_grid, &
                    farrayPtr=tempptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)
    
 print*, "MIN MAX W B4ADJ = ", minval(tempptr), maxval(tempptr)
 
 nullify(psptr)
 print*,"- CALL FieldGet FOR INPUT SURFACE PRESSURE."
 call ESMF_FieldGet(ps_input_grid, &
                    farrayPtr=psptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

!------------------------------------------------------------------------------------
! Assume standard lapse rate when interpolating pressure (per Phil Pegion).
!------------------------------------------------------------------------------------

 psptr = (psptr/p0)**exponent

 print*,"- CALL Field_Regrid FOR SURFACE PRESSURE."
 call ESMF_FieldRegrid(ps_input_grid, &
                       ps_b4adj_target_grid, &
                       routehandle=regrid_bl, &
                       termorderflag=ESMF_TERMORDER_SRCSEQ, &
                       rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldRegrid", rc)

 nullify(psptr)
 print*,"- CALL FieldGet FOR INPUT SURFACE PRESSURE B4ADJ."
 call ESMF_FieldGet(ps_b4adj_target_grid, &
                    farrayPtr=psptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 psptr = p0 * psptr**one_over_exponent

 print*,"- CALL Field_Regrid FOR TERRAIN."
 call ESMF_FieldRegrid(terrain_input_grid, &
                       terrain_interp_to_target_grid, &
                       routehandle=regrid_bl, &
                       termorderflag=ESMF_TERMORDER_SRCSEQ, &
                       rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
      call error_handler("IN FieldRegrid", rc)

 print*,"- CALL Field_Regrid FOR x WIND."
 call ESMF_FieldRegrid(xwind_input_grid, &
                       xwind_b4adj_target_grid, &
                       routehandle=regrid_bl, &
                       termorderflag=ESMF_TERMORDER_SRCSEQ, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
      call error_handler("IN FieldRegrid", rc)

 print*,"- CALL Field_Regrid FOR y WIND."
 call ESMF_FieldRegrid(ywind_input_grid, &
                       ywind_b4adj_target_grid, &
                       routehandle=regrid_bl, &
                       termorderflag=ESMF_TERMORDER_SRCSEQ, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
      call error_handler("IN FieldRegrid", rc)

 print*,"- CALL Field_Regrid FOR z WIND."
 call ESMF_FieldRegrid(zwind_input_grid, &
                       zwind_b4adj_target_grid, &
                       routehandle=regrid_bl, &
                       termorderflag=ESMF_TERMORDER_SRCSEQ, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
      call error_handler("IN FieldRegrid", rc)



 print*,"- CALL FieldRegridRelease."
 call ESMF_FieldRegridRelease(routehandle=regrid_bl, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
      call error_handler("IN FieldRegridRelease", rc)

!-----------------------------------------------------------------------------------
! Deallocate input fields.
!-----------------------------------------------------------------------------------

 call cleanup_input_atm_data

!-----------------------------------------------------------------------------------
! Create target grid field objects to hold data after vertical interpolation.
!-----------------------------------------------------------------------------------

 call create_atm_esmf_fields

!-----------------------------------------------------------------------------------
! Adjust surface pressure for terrain differences.
!-----------------------------------------------------------------------------------

 call newps(localpet)

!-----------------------------------------------------------------------------------
! Compute 3-d pressure based on adjusted surface pressure.
!-----------------------------------------------------------------------------------

 call newpr1(localpet)

!-----------------------------------------------------------------------------------
! Vertically interpolate.
!-----------------------------------------------------------------------------------

 call vintg

 if( wam_cold_start ) then 
   call vintg_wam (cycle_year,cycle_mon,cycle_day,cycle_hour,wam_parm_file)
 endif

!-----------------------------------------------------------------------------------
! Compute height.
!-----------------------------------------------------------------------------------

 call compute_zh

!-----------------------------------------------------------------------------------
! Free up memory.
!-----------------------------------------------------------------------------------

 call cleanup_target_atm_b4adj_data

!-----------------------------------------------------------------------------------
! Interpolate winds to 'd' grid.
!-----------------------------------------------------------------------------------

 isrctermprocessing = 1
 method=ESMF_REGRIDMETHOD_BILINEAR

 print*,"- CALL FieldRegridStore FOR X-WIND WEST EDGE."
 call ESMF_FieldRegridStore(xwind_target_grid, &
                            xwind_w_target_grid, &
                            polemethod=ESMF_POLEMETHOD_ALLAVG, &
                            srctermprocessing=isrctermprocessing, &
                            routehandle=regrid_bl, &
                            extrapMethod=ESMF_EXTRAPMETHOD_NEAREST_STOD, &
                            regridmethod=method, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldRegridStore", rc)

 print*,"- CALL Field_Regrid FOR X-WIND WEST EDGE."
 call ESMF_FieldRegrid(xwind_target_grid, &
                       xwind_w_target_grid, &
                       routehandle=regrid_bl, &
                       termorderflag=ESMF_TERMORDER_SRCSEQ, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldRegrid", rc)

 print*,"- CALL Field_Regrid FOR Y-WIND WEST EDGE."
 call ESMF_FieldRegrid(ywind_target_grid, &
                       ywind_w_target_grid, &
                       routehandle=regrid_bl, &
                       termorderflag=ESMF_TERMORDER_SRCSEQ, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldRegrid", rc)

 print*,"- CALL Field_Regrid FOR Z-WIND WEST EDGE."
 call ESMF_FieldRegrid(zwind_target_grid, &
                       zwind_w_target_grid, &
                       routehandle=regrid_bl, &
                       termorderflag=ESMF_TERMORDER_SRCSEQ, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldRegrid", rc)

 print*,"- CALL FieldRegridRelease."
 call ESMF_FieldRegridRelease(routehandle=regrid_bl, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldRegridRelease", rc)

 isrctermprocessing = 1
 method=ESMF_REGRIDMETHOD_BILINEAR

 print*,"- CALL FieldRegridStore FOR X-WIND SOUTH EDGE."
 call ESMF_FieldRegridStore(xwind_target_grid, &
                            xwind_s_target_grid, &
                            polemethod=ESMF_POLEMETHOD_ALLAVG, &
                            srctermprocessing=isrctermprocessing, &
                            routehandle=regrid_bl, &
                            extrapMethod=ESMF_EXTRAPMETHOD_NEAREST_STOD, &
                            regridmethod=method, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldRegridStore", rc)

 print*,"- CALL Field_Regrid FOR X-WIND SOUTH EDGE."
 call ESMF_FieldRegrid(xwind_target_grid, &
                       xwind_s_target_grid, &
                       routehandle=regrid_bl, &
                       termorderflag=ESMF_TERMORDER_SRCSEQ, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldRegrid", rc)

 print*,"- CALL Field_Regrid FOR Y-WIND SOUTH EDGE."
 call ESMF_FieldRegrid(ywind_target_grid, &
                       ywind_s_target_grid, &
                       routehandle=regrid_bl, &
                       termorderflag=ESMF_TERMORDER_SRCSEQ, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldRegrid", rc)

 print*,"- CALL Field_Regrid FOR Z-WIND SOUTH EDGE."
 call ESMF_FieldRegrid(zwind_target_grid, &
                       zwind_s_target_grid, &
                       routehandle=regrid_bl, &
                       termorderflag=ESMF_TERMORDER_SRCSEQ, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldRegrid", rc)

 print*,"- CALL FieldRegridRelease."
 call ESMF_FieldRegridRelease(routehandle=regrid_bl, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldRegridRelease", rc)

!-----------------------------------------------------------------------------------
! Convert from 3-d to 2-d cartesian winds.
!-----------------------------------------------------------------------------------

 call convert_winds_to_uv
 
!-----------------------------------------------------------------------------------
! If selected, process thompson microphysics climatological fields.
!-----------------------------------------------------------------------------------

 if (use_thomp_mp_climo) then
   call read_thomp_mp_climo_data
   call horiz_interp_thomp_mp_climo
   call vintg_thomp_mp_climo
 endif 

!-----------------------------------------------------------------------------------
! Write target data to file.
!-----------------------------------------------------------------------------------

 call write_fv3_atm_header_netcdf(localpet)
 if (regional <= 1) call write_fv3_atm_data_netcdf(localpet)
 if (regional >= 1) call write_fv3_atm_bndy_data_netcdf(localpet)

!-----------------------------------------------------------------------------------
! Free up memory.
!-----------------------------------------------------------------------------------

 call cleanup_all_target_atm_data

 end subroutine atmosphere_driver

!> Create target grid field objects to hold data before vertical
!! interpolation. These will be defined with the same number of
!! vertical levels as the input grid.
!!
!! @author George Gayno
 subroutine create_atm_b4adj_esmf_fields

 implicit none

 integer                          :: rc, n

 allocate(tracers_b4adj_target_grid(num_tracers_input))

 do n = 1, num_tracers_input
   print*,"- CALL FieldCreate FOR TARGET GRID TRACER BEFORE ADJUSTMENT ", trim(tracers(n))
   tracers_b4adj_target_grid(n) = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_input/), rc=rc)
   if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
      call error_handler("IN FieldCreate", rc)
 enddo

 print*,"- CALL FieldCreate FOR TARGET GRID TEMPERATURE BEFORE ADJUSTMENT."
 temp_b4adj_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_input/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET GRID PRESSURE BEFORE ADJUSTMENT."
 pres_b4adj_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_input/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET GRID VERTICAL VELOCITY BEFORE ADJUSTMENT."
 dzdt_b4adj_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_input/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET GRID xwind."
 xwind_b4adj_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_input/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET GRID ywind."
 ywind_b4adj_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_input/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET GRID zwind."
 zwind_b4adj_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_input/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET TERRAIN."
 terrain_interp_to_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET SURFACE PRESSURE BEFORE ADJUSTMENT."
 ps_b4adj_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 end subroutine create_atm_b4adj_esmf_fields

!> Create target grid field objects.
!!
!! @author George Gayno
 subroutine create_atm_esmf_fields

 implicit none

 integer                          :: rc, n

 allocate(tracers_target_grid(num_tracers))

 do n = 1, num_tracers
    print*,"- CALL FieldCreate FOR TARGET GRID TRACERS ", trim(tracers(n))    
    tracers_target_grid(n) = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
   if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
      call error_handler("IN FieldCreate", rc)
 enddo

 print*,"- CALL FieldCreate FOR TARGET GRID TEMPERATURE."
 temp_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET GRID PRESSURE."
 pres_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET GRID VERTICAL VELOCITY."
 dzdt_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET GRID DELP."
 delp_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET GRID xwind."
 xwind_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET GRID ywind."
 ywind_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET GRID zwind."
 zwind_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET HEIGHT."
 zh_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/levp1_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET U_S."
 u_s_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_EDGE2, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET V_S."
 v_s_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_EDGE2, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET xwind_S."
 xwind_s_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_EDGE2, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET ywind_S."
 ywind_s_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_EDGE2, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET zwind_S."
 zwind_s_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_EDGE2, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET U_W."
 u_w_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_EDGE1, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET V_W."
 v_w_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_EDGE1, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET xwind_W."
 xwind_w_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_EDGE1, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET ywind_W."
 ywind_w_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_EDGE1, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET zwind_W."
 zwind_w_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_EDGE1, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET SURFACE PRESSURE."
 ps_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 end subroutine create_atm_esmf_fields

!> Convert 3-d component winds to u and v.
!!
!! @author George Gayno
 subroutine convert_winds_to_uv
 
 implicit none

 integer                         :: clb(3), cub(3)
 integer                         :: i, j, k, rc

 real(esmf_kind_r8), pointer     :: latptr(:,:)
 real(esmf_kind_r8), pointer     :: lonptr(:,:)
 real(esmf_kind_r8), pointer     :: uptr(:,:,:)
 real(esmf_kind_r8), pointer     :: vptr(:,:,:)
 real(esmf_kind_r8), pointer     :: xwindptr(:,:,:)
 real(esmf_kind_r8), pointer     :: ywindptr(:,:,:)
 real(esmf_kind_r8), pointer     :: zwindptr(:,:,:)
 real(esmf_kind_r8)              :: latrad, lonrad

!-----------------------------------------------------------------------------------
! Convert from 3-d cartesian to 2-cartesian winds
!-----------------------------------------------------------------------------------

 print*,'- CONVERT WINDS.'

 print*,"- CALL FieldGet FOR xwind_S."
 call ESMF_FieldGet(xwind_s_target_grid, &
                    computationalLBound=clb, &
                    computationalUBound=cub, &
                    farrayPtr=xwindptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR ywind_S."
 call ESMF_FieldGet(ywind_s_target_grid, &
                    farrayPtr=ywindptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR zwind_S."
 call ESMF_FieldGet(zwind_s_target_grid, &
                    farrayPtr=zwindptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR U_S."
 call ESMF_FieldGet(u_s_target_grid, &
                    farrayPtr=uptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR V_S."
 call ESMF_FieldGet(v_s_target_grid, &
                    farrayPtr=vptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR LATITUDE_S."
 call ESMF_FieldGet(latitude_s_target_grid, &
                    farrayPtr=latptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR LONGITUDE_S."
 call ESMF_FieldGet(longitude_s_target_grid, &
                    farrayPtr=lonptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 do i = clb(1), cub(1)
   do j = clb(2), cub(2)
     latrad = latptr(i,j) * acos(-1.) / 180.0
     lonrad = lonptr(i,j) * acos(-1.) / 180.0
     do k = clb(3), cub(3)
       uptr(i,j,k) = xwindptr(i,j,k) * cos(lonrad) + ywindptr(i,j,k) * sin(lonrad)
       vptr(i,j,k) = -xwindptr(i,j,k) * sin(latrad) * sin(lonrad) + &
                      ywindptr(i,j,k) * sin(latrad) * cos(lonrad) + &
                      zwindptr(i,j,k) * cos(latrad)
     enddo
   enddo
 enddo

 print*,"- CALL FieldGet FOR xwind_w."
 call ESMF_FieldGet(xwind_w_target_grid, &
                    computationalLBound=clb, &
                    computationalUBound=cub, &
                    farrayPtr=xwindptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR ywind_w."
 call ESMF_FieldGet(ywind_w_target_grid, &
                    farrayPtr=ywindptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR zwind_w."
 call ESMF_FieldGet(zwind_w_target_grid, &
                    farrayPtr=zwindptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR U_W."
 call ESMF_FieldGet(u_w_target_grid, &
                    farrayPtr=uptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR V_W."
 call ESMF_FieldGet(v_w_target_grid, &
                    farrayPtr=vptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR LATITUDE_W."
 call ESMF_FieldGet(latitude_w_target_grid, &
                    farrayPtr=latptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR LONGITUDE_W."
 call ESMF_FieldGet(longitude_w_target_grid, &
                    farrayPtr=lonptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 do i = clb(1), cub(1)
   do j = clb(2), cub(2)
     latrad = latptr(i,j) * acos(-1.) / 180.0
     lonrad = lonptr(i,j) * acos(-1.) / 180.0
     do k = clb(3), cub(3)
       uptr(i,j,k) = xwindptr(i,j,k) * cos(lonrad) + ywindptr(i,j,k) * sin(lonrad)
       vptr(i,j,k) = -xwindptr(i,j,k) * sin(latrad) * sin(lonrad) + &
                      ywindptr(i,j,k) * sin(latrad) * cos(lonrad) + &
                      zwindptr(i,j,k) * cos(latrad)
     enddo
   enddo
 enddo

 end subroutine convert_winds_to_uv

!> Computes 3-D pressure given an adjusted surface pressure.
!!                                                                       
!! program history log:                                                  
!! 2005-04-11  Hann-Ming Henry Juang    hybrid sigma, sigma-p, and sigma-
!! - PRGMMR: Henry Juang    ORG: W/NMC23     DATE: 2005-04-11            
!! - PRGMMR: Fanglin Yang   ORG: W/NMC23     DATE: 2006-11-28            
!! - PRGMMR: S. Moorthi     ORG: NCEP/EMC    DATE: 2006-12-12            
!! - PRGMMR: S. Moorthi     ORG: NCEP/EMC    DATE: 2007-01-02            
!!                                                                       
!!   INPUT ARGUMENT LIST:                                                
!!     IM           INTEGER NUMBER OF POINTS TO COMPUTE                  
!!     KM           INTEGER NUMBER OF LEVELS                             
!!     IDVC         INTEGER VERTICAL COORDINATE ID                       
!!                  (1 FOR SIGMA AND 2 FOR HYBRID)                       
!!     IDSL         INTEGER TYPE OF SIGMA STRUCTURE                      
!!                  (1 FOR PHILLIPS OR 2 FOR MEAN)                       
!!     NVCOORD      INTEGER NUMBER OF VERTICAL COORDINATES               
!!     VCOORD       REAL (KM+1,NVCOORD) VERTICAL COORDINATE VALUES       
!!                  FOR IDVC=1, NVCOORD=1: SIGMA INTERFACE               
!!                  FOR IDVC=2, NVCOORD=2: HYBRID INTERFACE A AND B      
!!                  FOR IDVC=3, NVCOORD=3: JUANG GENERAL HYBRID INTERFACE
!!                     AK  REAL (KM+1) HYBRID INTERFACE A                
!!                     BK  REAL (KM+1) HYBRID INTERFACE B                
!!     PS           REAL (IX) SURFACE PRESSURE (PA)                      
!!   OUTPUT ARGUMENT LIST:                                               
!!     PM           REAL (IX,KM) MID-LAYER PRESSURE (PA)                 
!!     DP           REAL (IX,KM) LAYER DELTA PRESSURE (PA)
!!
!! @param[in] localpet ESMF local persistent execution thread  
!!
!! @author Hann Ming Henry Juang, Juang, Fanglin Yang, S. Moorthi
 subroutine newpr1(localpet)
 implicit none 

 integer, intent(in) :: localpet

 integer                         :: idsl, idvc, rc
 integer                         :: i, j, k, clb(3), cub(3)

 real(esmf_kind_r8), parameter   :: rd=287.05
 real(esmf_kind_r8), parameter   :: cp=1004.6
 real(esmf_kind_r8), parameter   :: rocp=rd/cp
 real(esmf_kind_r8), parameter   :: rocp1=rocp+1
 real(esmf_kind_r8), parameter   :: rocpr=1/rocp

 real(esmf_kind_r8), pointer     :: delp_ptr(:,:,:)
 real(esmf_kind_r8), pointer     :: pptr(:,:,:)    ! adjusted 3-d p.
 real(esmf_kind_r8), pointer     :: psptr(:,:)  ! adjusted surface p.
 real(esmf_kind_r8)              :: ak, bk
 real(esmf_kind_r8), allocatable :: pi(:,:,:)
                
 print*,"COMPUTE 3-D PRESSURE FROM ADJUSTED SURFACE PRESSURE."

 idvc = 2 ! hard wire for now.
 idsl = 2 ! hard wire for now.

 print*,"- CALL FieldGet FOR 3-D PRES."
 call ESMF_FieldGet(pres_target_grid, &
                    computationalLBound=clb, &
                    computationalUBound=cub, &
                    farrayPtr=pptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR DELP."
 call ESMF_FieldGet(delp_target_grid, &
                    computationalLBound=clb, &
                    computationalUBound=cub, &
                    farrayPtr=delp_ptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR SURFACE PRESSURE AFTER ADJUSTMENT"
 call ESMF_FieldGet(ps_target_grid, &
                    farrayPtr=psptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 allocate(pi(clb(1):cub(1),clb(2):cub(2),1:levp1_target))
 
 if(idvc.eq.2) then
   do k=1,levp1_target
     ak = vcoord_target(k,1) 
     bk = vcoord_target(k,2) 
     do i= clb(1), cub(1)
       do j= clb(2), cub(2)
         pi(i,j,k) = ak + bk*psptr(i,j)
       enddo
     enddo
   enddo 
   do k=1,lev_target
     do i= clb(1), cub(1)
       do j= clb(2), cub(2)
         delp_ptr(i,j,k) = pi(i,j,k) - pi(i,j,k+1)
       enddo
     enddo
   enddo
 else 
   call error_handler("PROGRAM ONLY WORKS WITH IDVC 2", 1)
 endif

 if(idsl.eq.2) then 
   do k=1,lev_target
     do i= clb(1), cub(1)
       do j= clb(2), cub(2)
         pptr(i,j,k) = (pi(i,j,k)+pi(i,j,k+1))/2.0
       enddo
     enddo
   enddo 
 else 
   do k=1,lev_target
     do i= clb(1), cub(1)
       do j= clb(2), cub(2)
         pptr(i,j,k) = ((pi(i,j,k)**rocp1-pi(i,j,k+1)**rocp1)/        &
                        (rocp1*(pi(i,j,k)-pi(i,j,k+1))))**rocpr        
       enddo
     enddo
   enddo 
 endif 

 deallocate(pi)

 if (localpet == 0) then
    print*,'new pres ',pptr(clb(1),clb(2),:)
    print*,'delp     ',delp_ptr(clb(1),clb(2),:)
 endif

 end subroutine newpr1 

!> Computes adjusted surface pressure given a new terrain height.
!!
!! Computes a new surface pressure given a new orography. The new
!! pressure is computed assuming a hydrostatic balance and a constant
!! temperature lapse rate. Below ground, the lapse rate is assumed to
!! be -6.5 k/km.
!!
!! program history log:
!! -  91-10-31  mark iredell
!! -  2018-apr  adapt for fv3. george gayno
!!
!! @param[in] localpet ESMF local persistent execution thread 
!! @author Mark Iredell, George Gayno @date 92-10-31
 subroutine newps(localpet)

 implicit none

 integer, intent(in) :: localpet
 integer                         :: i, j, k, ii
 integer                         :: clb(3), cub(3), ls, rc

 real(esmf_kind_r8), pointer     :: pptr(:,:,:)
 real(esmf_kind_r8), pointer     :: psptr(:,:)
 real(esmf_kind_r8), pointer     :: psnewptr(:,:)  ! adjusted surface p.
 real(esmf_kind_r8), pointer     :: tptr(:,:,:)
 real(esmf_kind_r8), pointer     :: qptr(:,:,:)
 real(esmf_kind_r8), pointer     :: zsptr(:,:)
 real(esmf_kind_r8), pointer     :: zsnewptr(:,:)
 real(esmf_kind_r8), allocatable :: zu(:,:)
 real(esmf_kind_r8), parameter   :: beta=-6.5E-3
 real(esmf_kind_r8), parameter   :: epsilon=1.E-9
 real(esmf_kind_r8), parameter   :: g=9.80665
 real(esmf_kind_r8), parameter   :: rd=287.05
 real(esmf_kind_r8), parameter   :: rv=461.50
 real(esmf_kind_r8), parameter   :: gor=g/rd
 real(esmf_kind_r8), parameter   :: fv=rv/rd-1.
 real(esmf_kind_r8)              :: ftv, fgam, apu, fz0
 real(esmf_kind_r8)              :: atvu, atv, fz1, fp0
 real(esmf_kind_r8)              :: apd, azd, agam, azu
 real(esmf_kind_r8)              :: atvd, fp1, gamma, pu
 real(esmf_kind_r8)              :: tvu, pd, tvd
 real(esmf_kind_r8)              :: at, aq, ap, az

 ftv(at,aq)=at*(1+fv*aq)
 fgam(apu,atvu,apd,atvd)=-gor*log(atvd/atvu)/log(apd/apu)
 fz0(ap,atv,azd,apd)=azd+atv/gor*log(apd/ap)
 fz1(ap,atv,azd,apd,agam)=azd-atv/agam*((apd/ap)**(-agam/gor)-1)
 fp0(az,azu,apu,atvu)=apu*exp(-gor/atvu*(az-azu))
 fp1(az,azu,apu,atvu,agam)=apu*(1+agam/atvu*(az-azu))**(-gor/agam)

 print*,"- ADJUST SURFACE PRESSURE FOR NEW TERRAIN."

 print*,"- CALL FieldGet FOR 3-D PRES."
 call ESMF_FieldGet(pres_b4adj_target_grid, &
                    computationalLBound=clb, &
                    computationalUBound=cub, &
                    farrayPtr=pptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 if(localpet==0) then
   print*,'old pres ',pptr(clb(1),clb(2),:)
 endif

 print*,"- CALL FieldGet FOR TEMPERATURE"
 call ESMF_FieldGet(temp_b4adj_target_grid, &
                    farrayPtr=tptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)
    
! Find specific humidity in the array of tracer fields.

 do ii = 1, num_tracers
   if (trim(tracers(ii)) == "sphum") exit
 enddo

 print*,"- CALL FieldGet FOR SPECIFIC HUMIDITY"
 call ESMF_FieldGet(tracers_b4adj_target_grid(ii), &
                    farrayPtr=qptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)
    
 print*,"- CALL FieldGet FOR SURFACE PRESSURE BEFORE ADJUSTMENT"
 call ESMF_FieldGet(ps_b4adj_target_grid, &
                    farrayPtr=psptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR SURFACE PRESSURE AFTER ADJUSTMENT"
 call ESMF_FieldGet(ps_target_grid, &
                    farrayPtr=psnewptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR OLD TERRAIN"
 call ESMF_FieldGet(terrain_interp_to_target_grid, &
                    farrayPtr=zsptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR NEW TERRAIN"
 call ESMF_FieldGet(terrain_target_grid, &
                    farrayPtr=zsnewptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)

 allocate(zu(clb(1):cub(1),clb(2):cub(2)))

!-----------------------------------------------------------------------------------
! Note, this routine was adapted from the spectral GFS which labeled the lowest
! model layer as '1'.  
!-----------------------------------------------------------------------------------

!-----------------------------------------------------------------------------------
! Compute surface pressure below the original ground.
!-----------------------------------------------------------------------------------

 ls=0
 k=1
 gamma=beta
 do i=clb(1), cub(1)
 do j=clb(2), cub(2)
   pu=pptr(i,j,k)
   tvu=ftv(tptr(i,j,k),qptr(i,j,k))
   zu(i,j)=fz1(pu,tvu,zsptr(i,j),psptr(i,j),gamma)
   if(zsnewptr(i,j).le.zu(i,j)) then
     pu=pptr(i,j,k)
     tvu=ftv(tptr(i,j,k),qptr(i,j,k))
     if(abs(gamma).gt.epsilon) then
       psnewptr(i,j)=fp1(zsnewptr(i,j),zu(i,j),pu,tvu,gamma)
     else
       psnewptr(i,j)=fp0(zsnewptr(i,j),zu(i,j),pu,tvu)
     endif
   else
     psnewptr(i,j)=0
     ls=ls+1
   endif
 enddo
 enddo

!-----------------------------------------------------------------------------------
! Compute surface pressure above the original ground.
!-----------------------------------------------------------------------------------

 do k=2,cub(3)
   if(ls.gt.0) then
     do i=clb(1),cub(1)
     do j=clb(2),cub(2)
       if(psnewptr(i,j).eq.0) then
         pu=pptr(i,j,k)
         tvu=ftv(tptr(i,j,k),qptr(i,j,k))
         pd=pptr(i,j,k-1)
         tvd=ftv(tptr(i,j,k-1),qptr(i,j,k-1))
         gamma=fgam(pu,tvu,pd,tvd)
         if(abs(gamma).gt.epsilon) then
           zu(i,j)=fz1(pu,tvu,zu(i,j),pd,gamma)
         else
           zu(i,j)=fz0(pu,tvu,zu(i,j),pd)
         endif
         if(zsnewptr(i,j).le.zu(i,j)) then
           if(abs(gamma).gt.epsilon) then
             psnewptr(i,j)=fp1(zsnewptr(i,j),zu(i,j),pu,tvu,gamma)
           else
             psnewptr(i,j)=fp0(zsnewptr(i,j),zu(i,j),pu,tvu)
           endif
           ls=ls-1
         endif
       endif
     enddo
     enddo
   endif
 enddo

!-----------------------------------------------------------------------------------
! Compute surface pressure over the top.
!-----------------------------------------------------------------------------------


 if(ls.gt.0) then
   k=cub(3)
   gamma=0
   do i=clb(1),cub(1)
   do j=clb(2),cub(2)
     if(psnewptr(i,j).eq.0) then
       pu=pptr(i,j,k)
       tvu=ftv(tptr(i,j,k),qptr(i,j,k))
       psnewptr(i,j)=fp0(zsnewptr(i,j),zu(i,j),pu,tvu)
     endif
   enddo
   enddo
 endif

 deallocate(zu)

 if (localpet == 0) then
!  do i=clb(1),cub(1)
!  do j=clb(2),cub(2)
   do i=clb(1),clb(1)
   do j=clb(2),clb(2)
     print*,'sfcp adjust ',(zsnewptr(i,j)-zsptr(i,j)), psptr(i,j),psnewptr(i,j)
   enddo
   enddo
 endif

 end subroutine newps

!> Reads model vertical coordinate definition file (as specified by
!! namelist variable vcoord_file_target_grid).
!!
!! @author George Gayno
 subroutine read_vcoord_info
 implicit none

 integer                    :: istat, n, k

 print*
 print*,"OPEN VERTICAL COORD FILE: ", trim(vcoord_file_target_grid)
 open(14, file=trim(vcoord_file_target_grid), form='formatted', iostat=istat, action='read')
 if (istat /= 0) then
   call error_handler("OPENING VERTICAL COORD FILE", istat)
 endif

 read(14, *, iostat=istat) nvcoord_target, lev_target
 if (istat /= 0) then
   call error_handler("READING VERTICAL COORD FILE", istat)
 endif

 levp1_target = lev_target + 1

 allocate(vcoord_target(levp1_target, nvcoord_target))
 read(14, *, iostat=istat) ((vcoord_target(n,k), k=1,nvcoord_target), n=1,levp1_target)
 if (istat /= 0) then
   call error_handler("READING VERTICAL COORD FILE", istat)
 endif

 print*
 
 close(14)

 end subroutine read_vcoord_info

!> Horizontally interpolate thompson microphysics data to the target
!! model grid.
!!
!! @author George Gayno
 subroutine horiz_interp_thomp_mp_climo

 implicit none

 integer  :: isrctermprocessing, rc

 type(esmf_regridmethod_flag)       :: method
 type(esmf_routehandle)             :: regrid_bl

 isrctermprocessing=1

 print*,"- CALL FieldCreate FOR TARGET GRID THOMP CLIMO QNIFA BEFORE ADJUSTMENT."
 qnifa_climo_b4adj_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_thomp_mp_climo/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET GRID THOMP CLIMO QNWFA BEFORE ADJUSTMENT."
 qnwfa_climo_b4adj_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_thomp_mp_climo/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET GRID THOMP CLIMO PRESSURE BEFORE ADJUSTMENT."
 thomp_pres_climo_b4adj_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_thomp_mp_climo/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET GRID THOMP CLIMO QNIFA."
 qnifa_climo_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldCreate FOR TARGET GRID THOMP CLIMO QNWFA."
 qnwfa_climo_target_grid = ESMF_FieldCreate(target_grid, &
                                   typekind=ESMF_TYPEKIND_R8, &
                                   staggerloc=ESMF_STAGGERLOC_CENTER, &
                                   ungriddedLBound=(/1/), &
                                   ungriddedUBound=(/lev_target/), rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldCreate", rc)

 print*,"- CALL FieldRegridStore FOR THOMPSON CLIMO FIELDS."

 method=ESMF_REGRIDMETHOD_BILINEAR

 call ESMF_FieldRegridStore(qnifa_climo_input_grid, &
                            qnifa_climo_b4adj_target_grid, &
                            polemethod=ESMF_POLEMETHOD_ALLAVG, &
                            srctermprocessing=isrctermprocessing, &
                            routehandle=regrid_bl, &
                            regridmethod=method, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
      call error_handler("IN FieldRegridStore", rc)

 print*,"- CALL Field_Regrid FOR THOMP CLIMO QNIFA."
 call ESMF_FieldRegrid(qnifa_climo_input_grid, &
                       qnifa_climo_b4adj_target_grid, &
                       routehandle=regrid_bl, &
                       termorderflag=ESMF_TERMORDER_SRCSEQ, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldRegrid", rc)

 print*,"- CALL Field_Regrid FOR THOMP CLIMO QNWFA."
 call ESMF_FieldRegrid(qnwfa_climo_input_grid, &
                       qnwfa_climo_b4adj_target_grid, &
                       routehandle=regrid_bl, &
                       termorderflag=ESMF_TERMORDER_SRCSEQ, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldRegrid", rc)

 print*,"- CALL Field_Regrid FOR THOMP PRESSURE."
 call ESMF_FieldRegrid(thomp_pres_climo_input_grid, &
                       thomp_pres_climo_b4adj_target_grid, &
                       routehandle=regrid_bl, &
                       termorderflag=ESMF_TERMORDER_SRCSEQ, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldRegrid", rc)

 print*,"- CALL FieldRegridRelease."
 call ESMF_FieldRegridRelease(routehandle=regrid_bl, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
      call error_handler("IN FieldRegridRelease", rc)

!-----------------------------------------------------------------------------------
! Free up input data memory.
!-----------------------------------------------------------------------------------

 call cleanup_thomp_mp_climo_input_data

 end subroutine horiz_interp_thomp_mp_climo

!> Vertically interpolate atmospheric fields to target FV3 grid.
!!
!! Vertically interpolate thompson microphysics climo tracers to the
!! target model levels.
!!
!! @author George Gayno
 SUBROUTINE VINTG_THOMP_MP_CLIMO

 implicit none

 INTEGER                         :: CLB(3), CUB(3), RC
 INTEGER                         :: IM, KM1, KM2, NT
 INTEGER                         :: I, J, K

 REAL(ESMF_KIND_R8), ALLOCATABLE :: Z1(:,:,:), Z2(:,:,:)
 REAL(ESMF_KIND_R8), ALLOCATABLE :: C1(:,:,:,:),C2(:,:,:,:)

 REAL(ESMF_KIND_R8), POINTER     :: QNIFA1PTR(:,:,:)       ! input
 REAL(ESMF_KIND_R8), POINTER     :: QNIFA2PTR(:,:,:)       ! target
 REAL(ESMF_KIND_R8), POINTER     :: QNWFA1PTR(:,:,:)       ! input
 REAL(ESMF_KIND_R8), POINTER     :: QNWFA2PTR(:,:,:)       ! target
 REAL(ESMF_KIND_R8), POINTER     :: P1PTR(:,:,:)       ! input pressure
 REAL(ESMF_KIND_R8), POINTER     :: P2PTR(:,:,:)       ! target pressure

 print*,"- VERTICALY INTERPOLATE THOMP MP CLIMO TRACERS."

 print*,"- CALL FieldGet FOR 3-D THOMP PRES."
 call ESMF_FieldGet(thomp_pres_climo_b4adj_target_grid, &
                    computationalLBound=clb, &
                    computationalUBound=cub, &
                    farrayPtr=p1ptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
! The '1'/'2' arrays hold fields before/after interpolation.  
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 NT=  2  ! number of thomp tracers

 ALLOCATE(Z1(CLB(1):CUB(1),CLB(2):CUB(2),lev_thomp_mp_climo))
 ALLOCATE(Z2(CLB(1):CUB(1),CLB(2):CUB(2),LEV_TARGET))
 ALLOCATE(C1(CLB(1):CUB(1),CLB(2):CUB(2),lev_thomp_mp_climo,NT))
 ALLOCATE(C2(CLB(1):CUB(1),CLB(2):CUB(2),LEV_TARGET,NT))

 Z1 = -LOG(P1PTR)

 print*,"- CALL FieldGet FOR 3-D ADJUSTED PRESS"
 call ESMF_FieldGet(pres_target_grid, &
                    farrayPtr=P2PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 Z2 = -LOG(P2PTR)

!print*,'pres check 1 ', p1ptr(clb(1),clb(2),:)
!print*,'pres check 2 ', p2ptr(clb(1),clb(2),:)

 print*,"- CALL FieldGet FOR qnifa before vertical adjustment."
 call ESMF_FieldGet(qnifa_climo_b4adj_target_grid, &
                    farrayPtr=QNIFA1PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 C1(:,:,:,1) =  QNIFA1PTR(:,:,:)

 print*,"- CALL FieldGet FOR qnwfa before vertical adjustment."
 call ESMF_FieldGet(qnwfa_climo_b4adj_target_grid, &
                    farrayPtr=QNWFA1PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 C1(:,:,:,2) =  QNWFA1PTR(:,:,:)

! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!  PERFORM LAGRANGIAN ONE-DIMENSIONAL INTERPOLATION
!  THAT IS 4TH-ORDER IN INTERIOR, 2ND-ORDER IN OUTSIDE INTERVALS
!  AND 1ST-ORDER FOR EXTRAPOLATION.
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 IM = (CUB(1)-CLB(1)+1) * (CUB(2)-CLB(2)+1)
 KM1= LEV_THOMP_MP_CLIMO
 KM2= LEV_TARGET

 CALL TERP3(IM,1,1,1,1,NT,(IM*KM1),(IM*KM2), &
            KM1,IM,IM,Z1,C1,KM2,IM,IM,Z2,C2)

 print*,"- CALL FieldGet FOR ADJUSTED climo qnifa."
 call ESMF_FieldGet(qnifa_climo_target_grid, &
                    farrayPtr=QNIFA2PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR ADJUSTED climo qnwfa."
 call ESMF_FieldGet(qnwfa_climo_target_grid, &
                    farrayPtr=QNWFA2PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 DO K=1,LEV_TARGET
   DO I=CLB(1),CUB(1)
   DO J=CLB(2),CUB(2)
     QNIFA2PTR(I,J,K) = C2(I,J,K,1)
     QNWFA2PTR(I,J,K) = C2(I,J,K,2)
   ENDDO
   ENDDO
 ENDDO

 DEALLOCATE (Z1, Z2, C1, C2)

 call ESMF_FieldDestroy(qnifa_climo_b4adj_target_grid, rc=rc)
 call ESMF_FieldDestroy(qnwfa_climo_b4adj_target_grid, rc=rc)
 call ESMF_FieldDestroy(thomp_pres_climo_b4adj_target_grid, rc=rc)

 END SUBROUTINE VINTG_THOMP_MP_CLIMO


!> Vertically extend model top into thermosphere for whole atmosphere model.
!!
!! Use climatological data to extent model top into thermosphere for
!! temperature and consoder primary compositions of neutral atmosphere
!! in term of specific values of oxygen, single oxygen, and ozone.
!!
!! @param [in] year  initial year
!! @param [in] month  initial month
!! @param [in] day  initial day
!! @param [in] hour  initial hour
!! @param [in] pf    path to MSIS2.1 parm file
!!
!! @author Hann-Ming Henry Juang NCEP/EMC
 SUBROUTINE VINTG_WAM (YEAR,MONTH,DAY,HOUR,PF)

 IMPLICIT NONE

 include 'mpif.h'

 INTEGER, INTENT(IN)             :: YEAR,MONTH,DAY,HOUR
 CHARACTER(*), INTENT(IN)        :: PF

 REAL(ESMF_KIND_R8), PARAMETER   :: AMO  = 15.9994  ! molecular weight of o
 REAL(ESMF_KIND_R8), PARAMETER   :: AMO2 = 31.999   !molecular weight of o2
 REAL(ESMF_KIND_R8), PARAMETER   :: AMN2 = 28.013   !molecular weight of n2

 REAL(ESMF_KIND_R8)              :: COE,WFUN(10),DEGLAT,HOLD
 REAL(ESMF_KIND_R8)              :: SUMMASS,QVMASS,O3MASS
 INTEGER                         :: I, J, K, II, CLB(3), CUB(3), RC, KREF
 INTEGER                         :: IDAT(8),JDOW,JDAY,ICDAY

 REAL(ESMF_KIND_R8), ALLOCATABLE :: TEMP(:),ON(:),O2N(:),N2N(:),PRMB(:)
        
 REAL(ESMF_KIND_R8), POINTER     :: LATPTR(:,:)        ! output latitude
 REAL(ESMF_KIND_R8), POINTER     :: P1PTR(:,:,:)       ! input pressure
 REAL(ESMF_KIND_R8), POINTER     :: P2PTR(:,:,:)       ! output pressure
 REAL(ESMF_KIND_R8), POINTER     :: DZDT2PTR(:,:,:)    ! output vvel
 REAL(ESMF_KIND_R8), POINTER     :: T2PTR(:,:,:)       ! output temperature
 REAL(ESMF_KIND_R8), POINTER     :: Q2PTR(:,:,:)       ! output tracer
 REAL(ESMF_KIND_R8), POINTER     :: QVPTR(:,:,:)       ! output tracer
 REAL(ESMF_KIND_R8), POINTER     :: QOPTR(:,:,:)       ! output tracer
 REAL(ESMF_KIND_R8), POINTER     :: O2PTR(:,:,:)       ! output tracer
 REAL(ESMF_KIND_R8), POINTER     :: O3PTR(:,:,:)       ! output tracer
 REAL(ESMF_KIND_R8), POINTER     :: XWIND2PTR(:,:,:)  ! output wind (x component)
 REAL(ESMF_KIND_R8), POINTER     :: YWIND2PTR(:,:,:)  ! output wind (y component)
 REAL(ESMF_KIND_R8), POINTER     :: ZWIND2PTR(:,:,:)  ! output wind (z component)
 
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 print*,"VINTG_WAM:- VERTICALY EXTEND FIELDS FOR WAM COLD START."

! prepare date
 IDAT = 0
 JDOW = 0
 JDAY = 0
 ICDAY = 0
 IDAT(1)=year
 IDAT(2)=month
 IDAT(3)=day
 IDAT(5)=hour
 CALL W3DOXDAT(IDAT,JDOW,ICDAY,JDAY)
 print *,"VINTG_WAM: WAM START DATE FOR ICDAY=",ICDAY

! prepare weighting function
 DO K=1,10
   WFUN(K) = (K-1.0) / 9.0
 ENDDO

 ALLOCATE(TEMP(LEV_TARGET))
 ALLOCATE(PRMB(LEV_TARGET))
 ALLOCATE(  ON(LEV_TARGET))
 ALLOCATE( O2N(LEV_TARGET))
 ALLOCATE( N2N(LEV_TARGET))

! p1 (pascal)
 print*,"VINTG_WAM:- CALL FieldGet FOR 3-D PRES."
 call ESMF_FieldGet(pres_b4adj_target_grid, &
                    computationalLBound=clb, &
                    computationalUBound=cub, &
                    farrayPtr=p1ptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)
!print*,"VINTG_WAM: p1ptr ",(p1ptr(1,1,k),k=1,LEV_INPUT)

! p2 (pascal)
 print*,"VINTG_WAM:- CALL FieldGet FOR 3-D ADJUSTED PRESS"
 call ESMF_FieldGet(pres_target_grid, &
                    farrayPtr=P2PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)
!print*,"VINTG_WAM: p2ptr ",(p2ptr(1,1,k),k=1,LEV_TARGET)

! latitude in degree
 print*,"VINTG_WAM - CALL FieldGet FOR LATITUDE_S."
 call ESMF_FieldGet(latitude_s_target_grid, &
                    farrayPtr=LATPTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
    call error_handler("IN FieldGet", rc)
!print*,"VINTG_WAM: latptr ",(latptr(1,j),j=clb(2),cub(2))

! temp
 print*,"VINTG_WAM:- CALL FieldGet FOR 3-D ADJUSTED TEMP."
 call ESMF_FieldGet(temp_target_grid, &
                    farrayPtr=T2PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

! dzdt
 print*,"VINTG_WAM:- CALL FieldGet FOR ADJUSTED VERTICAL VELOCITY."
 call ESMF_FieldGet(dzdt_target_grid, &
                    farrayPtr=DZDT2PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

! wind
 print*,"VINTG_WAM:- CALL FieldGet FOR ADJUSTED WIND COMPONENTS."

 call ESMF_FieldGet(xwind_target_grid, &
                    farrayPtr=XWIND2PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 call ESMF_FieldGet(ywind_target_grid, &
                    farrayPtr=YWIND2PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 call ESMF_FieldGet(zwind_target_grid, &
                    farrayPtr=ZWIND2PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

!
! determine vertical blending point and modified extrapolation values
!
 DO I=CLB(1),CUB(1)
   DO J=CLB(2),CUB(2)

     DO K=1,LEV_TARGET
       IF(P2PTR(I,J,K).le.P1PTR(I,J,LEV_INPUT)) THEN
         KREF     =K-1
         EXIT
       ENDIF
     ENDDO
!
     DO K=KREF,LEV_TARGET
       COE = P2PTR(I,J,K) / P2PTR(I,J,KREF)
       XWIND2PTR(I,J,K) = COE*XWIND2PTR(I,J,K)
       YWIND2PTR(I,J,K) = COE*YWIND2PTR(I,J,K)
       ZWIND2PTR(I,J,K) = COE*ZWIND2PTR(I,J,K)
       DZDT2PTR(I,J,K)   = COE*DZDT2PTR(I,J,K)
     ENDDO

   ENDDO
 ENDDO

! 
! point necessary tracers
!
 DO II = 1, NUM_TRACERS

   print*,"VINTG_WAM:- CALL FieldGet FOR 3-D TRACER ", trim(tracers(ii))
   call ESMF_FieldGet(tracers_target_grid(ii), &
                      farrayPtr=Q2PTR, rc=rc)
   if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
          call error_handler("IN FieldGet", rc)

   DO J=CLB(2),CUB(2)
     DO I=CLB(1),CUB(1)
       DO K=1,LEV_TARGET
         IF(P2PTR(I,J,K).le.P1PTR(I,J,LEV_INPUT)) THEN
           KREF     =K-1
           EXIT
         ENDIF
       ENDDO
!
       DO K=KREF,LEV_TARGET
         COE = MIN(1.0, P2PTR(I,J,K) / P2PTR(I,J,KREF) )
         Q2PTR(I,J,K) = COE * Q2PTR(I,J,K)
       ENDDO
     ENDDO
   ENDDO

   IF (TRIM(TRACERS(II)) == "sphum") QVPTR => Q2PTR
   IF (TRIM(TRACERS(II)) == "spo"  ) QOPTR => Q2PTR
   IF (TRIM(TRACERS(II)) == "spo2" ) O2PTR => Q2PTR
   IF (TRIM(TRACERS(II)) == "spo3" ) O3PTR => Q2PTR

 ENDDO

!
! obtained wam gases distribution and temperature profile
!
 DO I=CLB(1),CUB(1)
   DO J=CLB(2),CUB(2)
!
     DEGLAT = LATPTR(I,J)
     DO K=1,LEV_TARGET
       PRMB(K) = P2PTR(I,J,K) * 0.01
     ENDDO
     CALL GETTEMP(ICDAY,DEGLAT,PRMB,LEV_TARGET,PF,TEMP,ON,O2N,N2N)
!
     DO K=1,LEV_TARGET
       SUMMASS = ON(K)*AMO+O2N(K)*AMO2+N2N(K)*AMN2
       QVMASS  = SUMMASS*QVPTR(I,J,K)/(1.-QVPTR(I,J,K))
       SUMMASS = SUMMASS+QVMASS
       O3MASS  = SUMMASS*O3PTR(I,J,K)
       SUMMASS = SUMMASS+O3MASS
       HOLD    = 1.0 / SUMMASS
       QOPTR(I,J,K) = ON (K)*AMO *HOLD
       O2PTR(I,J,K) = O2N(K)*AMO2*HOLD
       O3PTR(I,J,K) = O3MASS * HOLD
       QVPTR(I,J,K) = QVMASS * HOLD
     ENDDO
!
     DO K=1,LEV_TARGET
       IF(P2PTR(I,J,K).le.P1PTR(I,J,LEV_INPUT)) THEN
         KREF     =K-1
         EXIT
       ENDIF
     ENDDO
!
     DO K=KREF,LEV_TARGET
       T2PTR(I,J,K) = TEMP(K)
     ENDDO
     DO K=KREF-10,KREF-1
       T2PTR(I,J,K) = WFUN(K-KREF+11)  * TEMP(K) + &
                 (1.- WFUN(K-KREF+11)) * T2PTR(I,J,K)
     ENDDO
   ENDDO
 ENDDO

 DEALLOCATE (TEMP, PRMB, ON, O2N, N2N)

 END SUBROUTINE VINTG_WAM

!> Vertically interpolate upper-air fields.
!!
!! Vertically interpolate upper-air fields. Wind, temperature,
!! humidity and other tracers are interpolated. The interpolation is
!! cubic lagrangian in log pressure with a monotonic constraint in the
!! center of the domain. In the outer intervals it is linear in log
!! pressure. Outside the domain, fields are generally held constant,
!! except for temperature and humidity below the input domain, where
!! the temperature lapse rate is held fixed at -6.5 k/km and the
!! relative humidity is held constant. This routine expects fields
!! ordered from bottom to top of atmosphere.
!!
!! @author Mark Iredell @date 92-10-31
 SUBROUTINE VINTG
 use mpi_f08

 IMPLICIT NONE

 REAL(ESMF_KIND_R8), PARAMETER   :: DLTDZ=-6.5E-3*287.05/9.80665
 REAL(ESMF_KIND_R8), PARAMETER   :: DLPVDRT=-2.5E6/461.50
 REAL(ESMF_KIND_R8), PARAMETER   :: ONE = 1.0_ESMF_KIND_R8

 INTEGER                         :: I, J, K, CLB(3), CUB(3), RC
 INTEGER                         :: IM, KM1, KM2, NT, II

 REAL(ESMF_KIND_R8)              :: DZ
 REAL(ESMF_KIND_R8), ALLOCATABLE :: Z1(:,:,:), Z2(:,:,:)
 REAL(ESMF_KIND_R8), ALLOCATABLE :: C1(:,:,:,:),C2(:,:,:,:)
        
 REAL(ESMF_KIND_R8), POINTER     :: P1PTR(:,:,:)       ! input pressure
 REAL(ESMF_KIND_R8), POINTER     :: P2PTR(:,:,:)       ! output pressure
 REAL(ESMF_KIND_R8), POINTER     :: DZDT1PTR(:,:,:)    ! input vvel
 REAL(ESMF_KIND_R8), POINTER     :: DZDT2PTR(:,:,:)    ! output vvel
 REAL(ESMF_KIND_R8), POINTER     :: T1PTR(:,:,:)       ! input temperature
 REAL(ESMF_KIND_R8), POINTER     :: T2PTR(:,:,:)       ! output temperature
 REAL(ESMF_KIND_R8), POINTER     :: Q1PTR(:,:,:)       ! input tracer
 REAL(ESMF_KIND_R8), POINTER     :: Q2PTR(:,:,:)       ! output tracer
 REAL(ESMF_KIND_R8), POINTER     :: XWIND1PTR(:,:,:)  ! input wind (x component)
 REAL(ESMF_KIND_R8), POINTER     :: YWIND1PTR(:,:,:)  ! input wind (y component)
 REAL(ESMF_KIND_R8), POINTER     :: ZWIND1PTR(:,:,:)  ! input wind (z component)
 REAL(ESMF_KIND_R8), POINTER     :: XWIND2PTR(:,:,:)  ! output wind (x component)
 REAL(ESMF_KIND_R8), POINTER     :: YWIND2PTR(:,:,:)  ! output wind (y component)
 REAL(ESMF_KIND_R8), POINTER     :: ZWIND2PTR(:,:,:)  ! output wind (z component)
 
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!  COMPUTE LOG PRESSURE INTERPOLATING COORDINATE
!  AND COPY INPUT WIND, TEMPERATURE, HUMIDITY AND OTHER TRACERS
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 print*,"- VERTICALY INTERPOLATE FIELDS."

 print*,"- CALL FieldGet FOR 3-D PRES."
 call ESMF_FieldGet(pres_b4adj_target_grid, &
                    computationalLBound=clb, &
                    computationalUBound=cub, &
                    farrayPtr=p1ptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
! The '1'/'2' arrays hold fields before/after interpolation.  
! Note the 'z' component of the horizontal wind will be treated as a
! tracer.  So add one extra third dimension to these 3-d arrays.
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 ALLOCATE(Z1(CLB(1):CUB(1),CLB(2):CUB(2),LEV_INPUT))
 ALLOCATE(Z2(CLB(1):CUB(1),CLB(2):CUB(2),LEV_TARGET))
 ALLOCATE(C1(CLB(1):CUB(1),CLB(2):CUB(2),LEV_INPUT,NUM_TRACERS_INPUT+5))
 ALLOCATE(C2(CLB(1):CUB(1),CLB(2):CUB(2),LEV_TARGET,NUM_TRACERS_INPUT+5))

 Z1 = -LOG(P1PTR)

 print*,"- CALL FieldGet FOR 3-D ADJUSTED PRESS"
 call ESMF_FieldGet(pres_target_grid, &
                    farrayPtr=P2PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 Z2 = -LOG(P2PTR)
 
 print*,"- CALL FieldGet FOR x WIND."
 call ESMF_FieldGet(xwind_b4adj_target_grid, &
                    farrayPtr=XWIND1PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 C1(:,:,:,1) =  XWIND1PTR(:,:,:)

 print*,"- CALL FieldGet FOR y WIND."
 call ESMF_FieldGet(ywind_b4adj_target_grid, &
                    farrayPtr=YWIND1PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 C1(:,:,:,2) =  YWIND1PTR(:,:,:)

 print*,"- CALL FieldGet FOR z WIND."
 call ESMF_FieldGet(zwind_b4adj_target_grid, &
                    farrayPtr=ZWIND1PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 C1(:,:,:,3) =  ZWIND1PTR(:,:,:)

 print*,"- CALL FieldGet FOR VERTICAL VELOCITY."
 call ESMF_FieldGet(dzdt_b4adj_target_grid, &
                    farrayPtr=DZDT1PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 C1(:,:,:,4) =  DZDT1PTR(:,:,:)
 print*,"MIN MAX W TARGETB4 IN VINTG = ", minval(DZDT1PTR(:,:,:)), maxval(DZDT1PTR(:,:,:))

 print*,"- CALL FieldGet FOR 3-D TEMP."
 call ESMF_FieldGet(temp_b4adj_target_grid, &
                    farrayPtr=T1PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 C1(:,:,:,5) =  T1PTR(:,:,:)

 DO I = 1, NUM_TRACERS_INPUT

   print*,"- CALL FieldGet FOR 3-D TRACERS ", trim(tracers(i))
   call ESMF_FieldGet(tracers_b4adj_target_grid(i), &
                      farrayPtr=Q1PTR, rc=rc)
   if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
          call error_handler("IN FieldGet", rc)

   C1(:,:,:,5+I) =  Q1PTR(:,:,:)

 ENDDO

! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!  PERFORM LAGRANGIAN ONE-DIMENSIONAL INTERPOLATION
!  THAT IS 4TH-ORDER IN INTERIOR, 2ND-ORDER IN OUTSIDE INTERVALS
!  AND 1ST-ORDER FOR EXTRAPOLATION.
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 IM = (CUB(1)-CLB(1)+1) * (CUB(2)-CLB(2)+1)
 KM1= LEV_INPUT
 KM2= LEV_TARGET
 NT=  NUM_TRACERS_INPUT + 1 ! treat 'z' wind as tracer.

 CALL TERP3(IM,1,1,1,1,4+NT,(IM*KM1),(IM*KM2), &
            KM1,IM,IM,Z1,C1,KM2,IM,IM,Z2,C2)
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!  COPY OUTPUT WIND, TEMPERATURE, HUMIDITY AND OTHER TRACERS
!  EXCEPT BELOW THE INPUT DOMAIN, LET TEMPERATURE INCREASE WITH A FIXED
!  LAPSE RATE AND LET THE RELATIVE HUMIDITY REMAIN CONSTANT.
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

 print*,"- CALL FieldGet FOR 3-D ADJUSTED TEMP."
 call ESMF_FieldGet(temp_target_grid, &
                    farrayPtr=T2PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR ADJUSTED VERTICAL VELOCITY."
 call ESMF_FieldGet(dzdt_target_grid, &
                    farrayPtr=DZDT2PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR ADJUSTED xwind."
 call ESMF_FieldGet(xwind_target_grid, &
                    farrayPtr=XWIND2PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR ADJUSTED ywind."
 call ESMF_FieldGet(ywind_target_grid, &
                    farrayPtr=YWIND2PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR ADJUSTED zwind."
 call ESMF_FieldGet(zwind_target_grid, &
                    farrayPtr=ZWIND2PTR, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 DO K=1,LEV_TARGET
   DO I=CLB(1),CUB(1)
   DO J=CLB(2),CUB(2)
     XWIND2PTR(I,J,K)=C2(I,J,K,1)
     YWIND2PTR(I,J,K)=C2(I,J,K,2)
     ZWIND2PTR(I,J,K)=C2(I,J,K,3)
     DZDT2PTR(I,J,K)=C2(I,J,K,4)
     DZ=Z2(I,J,K)-Z1(I,J,1)
     IF(DZ.GE.0) THEN
       T2PTR(I,J,K)=C2(I,J,K,5)
     ELSE
       T2PTR(I,J,K)=C1(I,J,1,5)*EXP(DLTDZ*DZ)
     ENDIF
   ENDDO
   ENDDO
 ENDDO

 DO II = 1, NUM_TRACERS_INPUT

   print*,"- CALL FieldGet FOR 3-D TRACER ", trim(tracers(ii))
   call ESMF_FieldGet(tracers_target_grid(ii), &
                      farrayPtr=Q2PTR, rc=rc)
   if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
          call error_handler("IN FieldGet", rc)

   IF (TRIM(TRACERS(II)) == "sphum") THEN  ! specific humidity

     DO K=1,LEV_TARGET
       DO I=CLB(1),CUB(1)
       DO J=CLB(2),CUB(2)
         DZ=Z2(I,J,K)-Z1(I,J,1)
         IF(DZ.GE.0) THEN
           Q2PTR(I,J,K) = C2(I,J,K,5+II)
         ELSE
           Q2PTR(I,J,K) = C1(I,J,1,5+II)*EXP(DLPVDRT*(ONE/T2PTR(I,J,K)-ONE/T1PTR(I,J,1))-DZ)
         ENDIF
       ENDDO
       ENDDO
     ENDDO

   ELSE ! all other tracers

     DO K=1,LEV_TARGET
       DO I=CLB(1),CUB(1)
       DO J=CLB(2),CUB(2)
         Q2PTR(I,J,K) = C2(I,J,K,5+II)
       ENDDO
       ENDDO
     ENDDO

   ENDIF

 ENDDO

 DEALLOCATE (Z1, Z2, C1, C2)

 END SUBROUTINE VINTG

!> Cubically interpolate in one dimension.
!!                                                                       
!! Interpolate field(s) in one dimension along the column(s). The
!! interpolation is cubic lagrangian with a monotonic constraint in
!! the center of the domain. In the outer intervals it is linear.
!! Outside the domain, fields are held constant.
!!                                                                       
!! PROGRAM HISTORY LOG:                                                  
!! -  98-05-01  MARK IREDELL                                              
!! - 1999-01-04  IREDELL  USE ESSL SEARCH                                  
!!                                                                       
!! @param[in] im integer number of columns                            
!! @param[in] ixz1 integer column skip number for z1                    
!! @param[in] ixq1 integer column skip number for q1                    
!! @param[in] ixz2 integer column skip number for z2                    
!! @param[in] ixq2 integer column skip number for q2                    
!! @param[in] nm integer number of fields per column                  
!! @param[in] nxq1 integer field skip number for q1                     
!! @param[in] nxq2 integer field skip number for q2                     
!! @param[in] km1 integer number of input points                       
!! @param[in] kxz1 integer point skip number for z1                     
!! @param[in] kxq1 integer point skip number for q1                     
!! @param[in] z1 real (1+(im-1)*ixz1+(km1-1)*kxz1)                    
!!                  input coordinate values in which to interpolate      
!!                  (z1 must be strictly monotonic in either direction)  
!! @param[in] q1 real (1+(im-1)*ixq1+(km1-1)*kxq1+(nm-1)*nxq1)        
!!                  input fields to interpolate                          
!! @param[in] km2 integer number of output points                      
!! @param[in] kxz2 integer point skip number for z2                     
!! @param[in] kxq2 integer point skip number for q2                     
!! @param[in] z2 real (1+(im-1)*ixz2+(km2-1)*kxz2)                    
!!                  output coordinate values to which to interpolate     
!!                  (z2 need not be monotonic)                           
!! @param[out] q2 real (1+(im-1)*ixq2+(km2-1)*kxq2+(nm-1)*nxq2)        
!!                  output interpolated fields                           
!! @author Mark Iredell @date 98-05-01            
 SUBROUTINE TERP3(IM,IXZ1,IXQ1,IXZ2,IXQ2,NM,NXQ1,NXQ2,             &
                  KM1,KXZ1,KXQ1,Z1,Q1,KM2,KXZ2,KXQ2,Z2,Q2)      
      IMPLICIT NONE 
      INTEGER IM,IXZ1,IXQ1,IXZ2,IXQ2,NM,NXQ1,NXQ2 
      INTEGER KM1,KXZ1,KXQ1,KM2,KXZ2,KXQ2 
      INTEGER I,K1,K2,N 
      INTEGER K1S(IM,KM2) 
      REAL(ESMF_KIND_R8), PARAMETER :: ONE = 1.0_ESMF_KIND_R8
      REAL(ESMF_KIND_R8) :: Z1(1+(IM-1)*IXZ1+(KM1-1)*KXZ1) 
      REAL(ESMF_KIND_R8) :: Q1(1+(IM-1)*IXQ1+(KM1-1)*KXQ1+(NM-1)*NXQ1) 
      REAL(ESMF_KIND_R8) :: Z2(1+(IM-1)*IXZ2+(KM2-1)*KXZ2) 
      REAL(ESMF_KIND_R8) :: Q2(1+(IM-1)*IXQ2+(KM2-1)*KXQ2+(NM-1)*NXQ2) 
!     REAL(ESMF_KIND_R8) :: J2(1+(IM-1)*IXQ2+(KM2-1)*KXQ2+(NM-1)*NXQ2) 
      REAL(ESMF_KIND_R8) :: FFA(IM),FFB(IM),FFC(IM),FFD(IM) 
      REAL(ESMF_KIND_R8) :: GGA(IM),GGB(IM),GGC(IM),GGD(IM) 
      REAL(ESMF_KIND_R8) :: Z1A,Z1B,Z1C,Z1D,Q1A,Q1B,Q1C,Q1D,Z2S,Q2S
!     REAL(ESMF_KIND_R8) :: J2S 

! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
!  FIND THE SURROUNDING INPUT INTERVAL FOR EACH OUTPUT POINT.
      CALL RSEARCH(IM,KM1,IXZ1,KXZ1,Z1,KM2,IXZ2,KXZ2,Z2,1,IM,K1S) 

! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
!  GENERALLY INTERPOLATE CUBICALLY WITH MONOTONIC CONSTRAINT            
!  FROM TWO NEAREST INPUT POINTS ON EITHER SIDE OF THE OUTPUT POINT,    
!  BUT WITHIN THE TWO EDGE INTERVALS INTERPOLATE LINEARLY.              
!  KEEP THE OUTPUT FIELDS CONSTANT OUTSIDE THE INPUT DOMAIN.            
                                                                        
!$OMP PARALLEL DO DEFAULT(PRIVATE) SHARED(IM,IXZ1,IXQ1,IXZ2), &
!$OMP& SHARED(IXQ2,NM,NXQ1,NXQ2,KM1,KXZ1,KXQ1,Z1,Q1,KM2,KXZ2), &
!$OMP& SHARED(KXQ2,Z2,Q2,K1S)
      DO K2=1,KM2 
        DO I=1,IM 
          K1=K1S(I,K2) 
          IF(K1.EQ.1.OR.K1.EQ.KM1-1) THEN 
            Z2S=Z2(1+(I-1)*IXZ2+(K2-1)*KXZ2) 
            Z1A=Z1(1+(I-1)*IXZ1+(K1-1)*KXZ1) 
            Z1B=Z1(1+(I-1)*IXZ1+(K1+0)*KXZ1) 
            FFA(I)=(Z2S-Z1B)/(Z1A-Z1B) 
            FFB(I)=(Z2S-Z1A)/(Z1B-Z1A) 
            GGA(I)=ONE/(Z1A-Z1B) 
            GGB(I)=ONE/(Z1B-Z1A) 
          ELSEIF(K1.GT.1.AND.K1.LT.KM1-1) THEN 
            Z2S=Z2(1+(I-1)*IXZ2+(K2-1)*KXZ2) 
            Z1A=Z1(1+(I-1)*IXZ1+(K1-2)*KXZ1) 
            Z1B=Z1(1+(I-1)*IXZ1+(K1-1)*KXZ1) 
            Z1C=Z1(1+(I-1)*IXZ1+(K1+0)*KXZ1) 
            Z1D=Z1(1+(I-1)*IXZ1+(K1+1)*KXZ1) 
            FFA(I)=(Z2S-Z1B)/(Z1A-Z1B)*                                 &
                   (Z2S-Z1C)/(Z1A-Z1C)*                                 &
                   (Z2S-Z1D)/(Z1A-Z1D)                                  
            FFB(I)=(Z2S-Z1A)/(Z1B-Z1A)*                                 &
                   (Z2S-Z1C)/(Z1B-Z1C)*                                 &
                   (Z2S-Z1D)/(Z1B-Z1D)                                  
            FFC(I)=(Z2S-Z1A)/(Z1C-Z1A)*                                 &
                   (Z2S-Z1B)/(Z1C-Z1B)*                                 &
                   (Z2S-Z1D)/(Z1C-Z1D)                                  
            FFD(I)=(Z2S-Z1A)/(Z1D-Z1A)*                                 &
                   (Z2S-Z1B)/(Z1D-Z1B)*                                 &
                   (Z2S-Z1C)/(Z1D-Z1C)                                  
            GGA(I)=      ONE/(Z1A-Z1B)*                                 &
                   (Z2S-Z1C)/(Z1A-Z1C)*                                 &
                   (Z2S-Z1D)/(Z1A-Z1D)+                                 &
                   (Z2S-Z1B)/(Z1A-Z1B)*                                 &
                         ONE/(Z1A-Z1C)*                                 &
                   (Z2S-Z1D)/(Z1A-Z1D)+                                 &
                   (Z2S-Z1B)/(Z1A-Z1B)*                                 &
                   (Z2S-Z1C)/(Z1A-Z1C)*                                 &
                         ONE/(Z1A-Z1D)                                  
            GGB(I)=      ONE/(Z1B-Z1A)*                                 &
                   (Z2S-Z1C)/(Z1B-Z1C)*                                 &
                   (Z2S-Z1D)/(Z1B-Z1D)+                                 &
                   (Z2S-Z1A)/(Z1B-Z1A)*                                 &
                         ONE/(Z1B-Z1C)*                                 &
                   (Z2S-Z1D)/(Z1B-Z1D)+                                 &
                   (Z2S-Z1A)/(Z1B-Z1A)*                                 &
                   (Z2S-Z1C)/(Z1B-Z1C)*                                 &
                         ONE/(Z1B-Z1D)                                  
            GGC(I)=      ONE/(Z1C-Z1A)*                                 &
                   (Z2S-Z1B)/(Z1C-Z1B)*                                 &
                   (Z2S-Z1D)/(Z1C-Z1D)+                                 &
                   (Z2S-Z1A)/(Z1C-Z1A)*                                 &
                         ONE/(Z1C-Z1B)*                                 &
                   (Z2S-Z1D)/(Z1C-Z1D)+                                 &
                   (Z2S-Z1A)/(Z1C-Z1A)*                                 &
                   (Z2S-Z1B)/(Z1C-Z1B)*                                 &
                         ONE/(Z1C-Z1D)                                  
            GGD(I)=      ONE/(Z1D-Z1A)*                                 &
                   (Z2S-Z1B)/(Z1D-Z1B)*                                 &
                   (Z2S-Z1C)/(Z1D-Z1C)+                                 &
                   (Z2S-Z1A)/(Z1D-Z1A)*                                 &
                         ONE/(Z1D-Z1B)*                                 &
                   (Z2S-Z1C)/(Z1D-Z1C)+                                 &
                   (Z2S-Z1A)/(Z1D-Z1A)*                                 &
                   (Z2S-Z1B)/(Z1D-Z1B)*                                 &
                         ONE/(Z1D-Z1C)                                  
          ENDIF 
        ENDDO 

!  INTERPOLATE.                                                         
        DO N=1,NM 
          DO I=1,IM 
            K1=K1S(I,K2) 
            IF(K1.EQ.0) THEN 
              Q2S=Q1(1+(I-1)*IXQ1+(N-1)*NXQ1) 
!             J2S=0 
            ELSEIF(K1.EQ.KM1) THEN 
              Q2S=Q1(1+(I-1)*IXQ1+(KM1-1)*KXQ1+(N-1)*NXQ1) 
!             J2S=0 
            ELSEIF(K1.EQ.1.OR.K1.EQ.KM1-1) THEN 
              Q1A=Q1(1+(I-1)*IXQ1+(K1-1)*KXQ1+(N-1)*NXQ1) 
              Q1B=Q1(1+(I-1)*IXQ1+(K1+0)*KXQ1+(N-1)*NXQ1) 
              Q2S=FFA(I)*Q1A+FFB(I)*Q1B 
!             J2S=GGA(I)*Q1A+GGB(I)*Q1B 
            ELSE 
              Q1A=Q1(1+(I-1)*IXQ1+(K1-2)*KXQ1+(N-1)*NXQ1) 
              Q1B=Q1(1+(I-1)*IXQ1+(K1-1)*KXQ1+(N-1)*NXQ1) 
              Q1C=Q1(1+(I-1)*IXQ1+(K1+0)*KXQ1+(N-1)*NXQ1) 
              Q1D=Q1(1+(I-1)*IXQ1+(K1+1)*KXQ1+(N-1)*NXQ1) 
              Q2S=FFA(I)*Q1A+FFB(I)*Q1B+FFC(I)*Q1C+FFD(I)*Q1D 
!             J2S=GGA(I)*Q1A+GGB(I)*Q1B+GGC(I)*Q1C+GGD(I)*Q1D 
              IF(Q2S.LT.MIN(Q1B,Q1C)) THEN 
                Q2S=MIN(Q1B,Q1C) 
!               J2S=0 
              ELSEIF(Q2S.GT.MAX(Q1B,Q1C)) THEN 
                Q2S=MAX(Q1B,Q1C) 
!               J2S=0 
              ENDIF 
            ENDIF 
            Q2(1+(I-1)*IXQ2+(K2-1)*KXQ2+(N-1)*NXQ2)=Q2S 
!           J2(1+(I-1)*IXQ2+(K2-1)*KXQ2+(N-1)*NXQ2)=J2S 
          ENDDO 
        ENDDO 
      ENDDO 
!$OMP END PARALLEL DO                                                   

 END SUBROUTINE TERP3 

!> Search for a surrounding real interval.
!!                                                                       
!! This subprogram searches monotonic sequences of real numbers for
!! intervals that surround a given search set of real numbers. The
!! sequences may be monotonic in either direction; the real numbers
!! may be single or double precision; the input sequences and sets and
!! the output locations may be arbitrarily dimensioned.
!!                                                                       
!! If the array z1 is dimensioned (im,km1), then the skip numbers are
!! ixz1=1 and kxz1=im; if it is dimensioned (km1,im), then the skip
!! numbers are ixz1=km1 and kxz1=1; if it is dimensioned (im,jm,km1),
!! then the skip numbers are ixz1=1 and kxz1=im*jm; etcetera. Similar
!! examples apply to the skip numbers for z2 and l2.
!!                                                                       
!! Returned values of 0 or km1 indicate that the given search value    
!! is outside the range of the sequence. 
!!                                                                       
!! If a search value is identical to one of the sequence values then
!! the location returned points to the identical value. If the
!! sequence is not strictly monotonic and a search value is identical
!! to more than one of the sequence values, then the location returned
!! may point to any of the identical values.
!!                                                                       
!! to be exact, for each i from 1 to im and for each k from 1 to km2,
!! z=z2(1+(i-1)*ixz2+(k-1)*kxz2) is the search value and
!! l=l2(1+(i-1)*ixl2+(k-1)*kxl2) is the location returned.  if l=0,
!! then z is less than the start point z1(1+(i-1)*ixz1) for ascending
!! sequences (or greater than for descending sequences).  if l=km1,
!! then z is greater than or equal to the end point
!! z1(1+(i-1)*ixz1+(km1-1)*kxz1) for ascending sequences (or less than
!! or equal to for descending sequences).  otherwise z is between the
!! values z1(1+(i-1)*ixz1+(l-1)*kxz1) and z1(1+(i-1)*ixz1+(l-0)*kxz1)
!! and may equal the former.
!!                                                                       
!! @param[in] im integer number of sequences to search                
!! @param[in] km1 integer number of points in each sequence            
!! @param[in] ixz1 integer sequence skip number for z1                  
!! @param[in] kxz1 integer point skip number for z1                     
!! @param[in] z1 real (1+(im-1)*ixz1+(km1-1)*kxz1)                    
!!                  sequence values to search                            
!!                  (z1 must be monotonic in either direction)           
!! @param[in] km2 integer number of points to search for               
!!                  in each respective sequence                          
!! @param[in] ixz2 integer sequence skip number for z2                  
!! @param[in] kxz2 integer point skip number for z2                     
!! @param[in] z2 real (1+(im-1)*ixz2+(km2-1)*kxz2)                    
!!                  set of values to search for                          
!!                  (z2 need not be monotonic)                           
!! @param[in] ixl2 integer sequence skip number for l2                  
!! @param[in] kxl2 integer point skip number for l2                     
!!                                                                       
!! @param[out] l2 integer (1+(im-1)*ixl2+(km2-1)*kxl2)                 
!!                  interval locations having values from 0 to km1       
!!                  (z2 will be between z1(l2) and z1(l2+1))             
!!                                                                       
!! @author Mark Iredell @date 98-05-01            
 SUBROUTINE RSEARCH(IM,KM1,IXZ1,KXZ1,Z1,KM2,IXZ2,KXZ2,Z2,IXL2,KXL2,L2)
 IMPLICIT NONE 

 INTEGER,INTENT(IN)    :: IM,KM1,IXZ1,KXZ1,KM2,IXZ2,KXZ2,IXL2,KXL2 
 INTEGER,INTENT(OUT)   :: L2(1+(IM-1)*IXL2+(KM2-1)*KXL2) 

 REAL(ESMF_KIND_R8),INTENT(IN) :: Z1(1+(IM-1)*IXZ1+(KM1-1)*KXZ1) 
 REAL(ESMF_KIND_R8),INTENT(IN) :: Z2(1+(IM-1)*IXZ2+(KM2-1)*KXZ2) 

 INTEGER                       :: I,K2,L

 REAL(ESMF_KIND_R8)            :: Z 

  
! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
!  FIND THE SURROUNDING INPUT INTERVAL FOR EACH OUTPUT POINT.          
 DO I=1,IM 
   IF (Z1(1+(I-1)*IXZ1).LE.Z1(1+(I-1)*IXZ1+(KM1-1)*KXZ1)) THEN 
!  INPUT COORDINATE IS MONOTONICALLY ASCENDING.                        
     DO K2=1,KM2
       Z=Z2(1+(I-1)*IXZ2+(K2-1)*KXZ2)
       L=0 
       DO 
         IF(Z.LT.Z1(1+(I-1)*IXZ1+L*KXZ1)) EXIT 
         L=L+1 
         IF(L.EQ.KM1) EXIT 
       ENDDO
       L2(1+(I-1)*IXL2+(K2-1)*KXL2)=L 
     ENDDO 
   ELSE 
!   INPUT COORDINATE IS MONOTONICALLY DESCENDING.                       
     DO K2=1,KM2 
       Z=Z2(1+(I-1)*IXZ2+(K2-1)*KXZ2) 
       L=0 
       DO 
         IF(Z.GT.Z1(1+(I-1)*IXZ1+L*KXZ1)) EXIT 
         L=L+1 
         IF(L.EQ.KM1) EXIT 
       ENDDO
       L2(1+(I-1)*IXL2+(K2-1)*KXL2)=L 
     ENDDO 
   ENDIF 
 ENDDO 
                                                                        
 END SUBROUTINE RSEARCH 

!> Compute vertical level height
!! @author George Gayno
 subroutine compute_zh

 implicit none 

 integer                          :: i,ii, j,k, rc, clb(2), cub(2)

 real(esmf_kind_r8), allocatable  :: pe0(:), pn0(:)
 real(esmf_kind_r8), pointer      :: psptr(:,:)
 real(esmf_kind_r8), pointer      :: zhsfcptr(:,:)
 real(esmf_kind_r8), pointer      :: zhptr(:,:,:)
 real(esmf_kind_r8), pointer      :: tptr(:,:,:)
 real(esmf_kind_r8), pointer      :: qptr(:,:,:)
 real(esmf_kind_r8)               :: ak, bk, zvir, grd
 real(esmf_kind_r8), parameter    :: grav  = 9.80665 
 real(esmf_kind_r8), parameter    :: rdgas = 287.05 
 real(esmf_kind_r8), parameter    :: rvgas = 461.50 

 print*,"- COMPUTE HEIGHT"

 print*,"- CALL FieldGet FOR SURFACE PRESSURE"
 call ESMF_FieldGet(ps_target_grid, &
                    computationalLBound=clb, &
                    computationalUBound=cub, &
                    farrayPtr=psptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR TERRAIN HEIGHT"
 call ESMF_FieldGet(terrain_target_grid, &
                    farrayPtr=zhsfcptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR HEIGHT"
 call ESMF_FieldGet(zh_target_grid, &
                    farrayPtr=zhptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 print*,"- CALL FieldGet FOR TEMPERATURE"
 call ESMF_FieldGet(temp_target_grid, &
                    farrayPtr=tptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 do ii = 1, num_tracers
   if (trim(tracers(ii)) == "sphum") exit
 enddo

 print*,"- CALL FieldGet FOR SPECIFIC HUMIDITY"
 call ESMF_FieldGet(tracers_target_grid(ii), &
                    farrayPtr=qptr, rc=rc)
 if(ESMF_logFoundError(rcToCheck=rc,msg=ESMF_LOGERR_PASSTHRU,line=__LINE__,file=__FILE__)) &
         call error_handler("IN FieldGet", rc)

 grd = grav/rdgas 
 zvir = rvgas/rdgas - 1.0_esmf_kind_r8
                                                                        
 allocate(pe0(levp1_target))
 allocate(pn0(levp1_target))

 do j = clb(2), cub(2)
 do i = clb(1), cub(1)

   do k = 1, levp1_target
     ak = vcoord_target(k,1)
     ak = max(ak, 1.e-9)
     bk = vcoord_target(k,2)

     pe0(k) = ak + bk*psptr(i,j)
     pn0(k) = log(pe0(k))
   enddo

   zhptr(i,j,1) = zhsfcptr(i,j)

   do k = 2, levp1_target
     zhptr(i,j,k) = zhptr(i,j,k-1)+tptr(i,j,k-1)*(1.+zvir*qptr(i,j,k-1))*     &
              (pn0(k-1)-pn0(k))/grd
   enddo

 enddo
 enddo

 deallocate(pe0, pn0)

 end subroutine compute_zh 
 
!> Cleanup atmospheric field (before adjustment) objects.
!!
!! @author George Gayno
 subroutine cleanup_target_atm_b4adj_data

 implicit none

 integer                     :: i, rc

 print*,"- DESTROY TARGET GRID ATMOSPHERIC BEFORE ADJUSTMENT FIELDS."

 call ESMF_FieldDestroy(xwind_b4adj_target_grid, rc=rc)
 call ESMF_FieldDestroy(ywind_b4adj_target_grid, rc=rc)
 call ESMF_FieldDestroy(zwind_b4adj_target_grid, rc=rc)
 call ESMF_FieldDestroy(dzdt_b4adj_target_grid, rc=rc)
 call ESMF_FieldDestroy(ps_b4adj_target_grid, rc=rc)
 call ESMF_FieldDestroy(pres_b4adj_target_grid, rc=rc)
 call ESMF_FieldDestroy(temp_b4adj_target_grid, rc=rc)
 call ESMF_FieldDestroy(terrain_interp_to_target_grid, rc=rc)

 do i = 1, num_tracers_input
   call ESMF_FieldDestroy(tracers_b4adj_target_grid(i), rc=rc)
 enddo

 deallocate(tracers_b4adj_target_grid)

 end subroutine cleanup_target_atm_b4adj_data

!> Cleanup target grid atmospheric field objects.
!! @author George Gayno
 subroutine cleanup_all_target_atm_data

 use atmosphere_target_data, only : cleanup_atmosphere_target_data

 implicit none

 integer                     :: rc

 print*,"- DESTROY LOCAL TARGET GRID ATMOSPHERIC FIELDS."

 call ESMF_FieldDestroy(pres_target_grid, rc=rc)
 call ESMF_FieldDestroy(xwind_target_grid, rc=rc)
 call ESMF_FieldDestroy(ywind_target_grid, rc=rc)
 call ESMF_FieldDestroy(zwind_target_grid, rc=rc)
 call ESMF_FieldDestroy(xwind_s_target_grid, rc=rc)
 call ESMF_FieldDestroy(ywind_s_target_grid, rc=rc)
 call ESMF_FieldDestroy(zwind_s_target_grid, rc=rc)
 call ESMF_FieldDestroy(xwind_w_target_grid, rc=rc)
 call ESMF_FieldDestroy(ywind_w_target_grid, rc=rc)
 call ESMF_FieldDestroy(zwind_w_target_grid, rc=rc)

 call cleanup_atmosphere_target_data

 end subroutine cleanup_all_target_atm_data

 end module atmosphere