LCOV - code coverage report
Current view: | top level - control - scamMod.F90 (source / functions) |  |  | Hit | Total | Coverage
Test: | coverage.info |  | Lines: | 7 | 621 | 1.1 %
Date: | 2025-01-13 21:54:50 |  | Functions: | 1 | 7 | 14.3 %

              Line data    Source code
           1             : module scamMod
           2             :   !----------------------------------------------------------------------
           3             :   !
           4             :   ! This module provides control variables and namelist functionality
           5             :   ! for SCAM.
           6             :   !
           7             :   ! As with global CAM, SCAM is initialized with state information
           8             :   ! from the initial and boundary files. For each succeeding timestep
           9             :   ! SCAM calculates the physics tendencies and combines these with
          10             :   ! the advective tendencies provided by the IOP file to produce
          11             :   ! a forcast. Generally, the control variables in this module
          12             :   ! determine what data and parameterizations will be used to make
          13             :   ! the forecast. For instance, many of the control variables in
          14             :   ! this module provide flexibility to affect the forecast by overriding
          15             :   ! parameterization prognosed tendencies with observed tendencies
          16             :   ! of a particular field program recorded on the IOP file.
          17             :   !
          18             :   ! Public functions/subroutines:
          19             :   !   scam_readnl
          20             :   !-----------------------------------------------------------------------
          21             :
          22             : use shr_kind_mod,   only: r8 => shr_kind_r8, cl => shr_kind_cl
          23             : use spmd_utils,     only: masterproc,npes
          24             : use pmgrid,         only: plon, plat, plev, plevp
          25             : use constituents,   only: cnst_get_ind, pcnst, cnst_name
          26             : use netcdf,         only: NF90_NOERR,NF90_CLOSE,NF90_GET_VAR,NF90_INQUIRE_DIMENSION, &
          27             :                           NF90_INQ_DIMID, NF90_INQ_VARID, NF90_NOWRITE, NF90_OPEN, &
          28             :                           NF90_GET_ATT,NF90_GLOBAL,NF90_INQUIRE_ATTRIBUTE, &
          29             :                           NF90_INQUIRE_VARIABLE, NF90_MAX_VAR_DIMS, nf90_get_var
          30             : use shr_scam_mod,   only: shr_scam_getCloseLatLon
          31             : use cam_logfile,    only: iulog
          32             : use cam_abortutils, only: endrun
          33             : use time_manager,   only: get_curr_date, get_nstep,is_first_step,get_start_date,timemgr_time_inc
          34             : use error_messages, only: handle_ncerr
          35             :
          36             :
          37             : implicit none
          38             : private
          39             :
          40             : ! PUBLIC INTERFACES:
          41             :
          42             : public :: scam_readnl         ! read SCAM namelist options
          43             : public :: readiopdata         ! read iop boundary data
          44             : public :: setiopupdate        ! find index in iopboundary data for current time
          45             : public :: plevs0              ! Define the pressures of the interfaces and midpoints
          46             : public :: scmiop_flbc_inti
          47             : public :: setiopupdate_init
          48             :
          49             : ! PUBLIC MODULE DATA:
          50             :
          51             : real(r8), public ::  pressure_levels(plev)
          52             : real(r8), public ::  scmlat   ! input namelist latitude for scam
          53             : real(r8), public ::  scmlon   ! input namelist longitude for scam
          54             : real(r8), public ::  closeioplat   ! closest iop latitude for scam
          55             : real(r8), public ::  closeioplon   ! closest iop longitude for scam
          56             : integer,  public ::  closeioplatidx   ! file array index of closest iop latitude for scam
          57             : integer,  public ::  closeioplonidx   ! file array index closest iop longitude for scam
          58             :
          59             :
          60             : integer, parameter :: num_switches = 20
          61             : integer, parameter :: max_path_len = 128
          62             :
          63             : logical, public ::  single_column         ! Using IOP file or not
          64             : logical, public ::  use_iop               ! Using IOP file or not
          65             : logical, public ::  use_pert_init         ! perturb initial values
          66             : logical, public ::  use_pert_frc          ! perturb forcing
          67             : logical, public ::  switch(num_switches)  ! Logical flag settings from GUI
          68             : logical, public ::  l_uvphys              ! If true, update u/v after TPHYS
          69             : logical, public ::  l_uvadvect            ! If true, T, U & V will be passed to SLT
          70             : logical, public ::  l_conv                ! use flux divergence terms for T and q?
          71             : logical, public ::  l_divtr               ! use flux divergence terms for constituents?
          72             : logical, public ::  l_diag                ! do we want available diagnostics?
          73             :
          74             : integer, public ::  error_code            ! Error code from netCDF reads
          75             : integer, public ::  initTimeIdx
          76             : integer, public ::  seedval
          77             : integer :: bdate, last_date, last_sec
          78             :
          79             : character(len=max_path_len), public ::  modelfile
          80             : character(len=max_path_len), public ::  analysisfile
          81             : character(len=max_path_len), public ::  sicfile
          82             : character(len=max_path_len), public ::  userfile
          83             : character(len=max_path_len), public ::  sstfile
          84             : character(len=max_path_len), public ::  lsmpftfile
          85             : character(len=max_path_len), public ::  pressfile
          86             : character(len=max_path_len), public ::  topofile
          87             : character(len=max_path_len), public ::  ozonefile
          88             : character(len=max_path_len), public ::  iopfile
          89             : character(len=max_path_len), public ::  absemsfile
          90             : character(len=max_path_len), public ::  aermassfile
          91             : character(len=max_path_len), public ::  aeropticsfile
          92             : character(len=max_path_len), public ::  timeinvfile
          93             : character(len=max_path_len), public ::  lsmsurffile
          94             : character(len=max_path_len), public ::  lsminifile
          95             :
          96             : ! note that scm_zadv_q is set to slt to be consistent with CAM BFB testing
          97             :
          98             :
          99             : character(len=16), public    :: scm_zadv_T  = 'eulc            '
         100             : character(len=16), public    :: scm_zadv_q  = 'slt             '
         101             : character(len=16), public    :: scm_zadv_uv = 'eulc            '
         102             :
         103             : real(r8), public ::  fixmascam
         104             : real(r8), public ::  betacam
         105             : real(r8), public ::  alphacam(pcnst)
         106             : real(r8), public ::  dqfxcam(plon,plev,pcnst)
         107             :
         108             : real(r8), public ::      divq3d(plev,pcnst)  ! 3D q advection
         109             : real(r8), public ::      divt3d(plev)        ! 3D T advection
         110             : real(r8), public ::      divu3d(plev)        ! 3D U advection
         111             : real(r8), public ::      divv3d(plev)        ! 3D V advection
         112             : real(r8), public ::      vertdivq(plev,pcnst)! vertical q advection
         113             : real(r8), public ::      vertdivt(plev)      ! vertical T advection
         114             : real(r8), public ::      vertdivu(plev)      ! vertical T advection
         115             : real(r8), public ::      vertdivv(plev)      ! vertical T advection
         116             : real(r8), public ::      ptend               ! surface pressure tendency
         117             : real(r8), public ::      qdiff(plev)         ! model minus observed humidity
         118             : real(r8), public ::      qobs(plev)          ! actual W.V. Mixing ratio
         119             : real(r8), public ::      qinitobs(plev,pcnst)! initial tracer field
         120             : real(r8), public ::      cldliqobs(plev)     ! actual W.V. Mixing ratio
         121             : real(r8), public ::      cldiceobs(plev)     ! actual W.V. Mixing ratio
         122             : real(r8), public ::      numliqobs(plev)     ! actual
         123             : real(r8), public ::      numiceobs(plev)     ! actual
         124             : real(r8), public ::      precobs(1)          ! observed precipitation
         125             : real(r8), public ::      lhflxobs(1)         ! observed surface latent heat flux
         126             : real(r8), public ::      heat_glob_scm(1)    ! observed heat total
         127             : real(r8), public ::      shflxobs(1)         ! observed surface sensible heat flux
         128             : real(r8), public ::      q1obs(plev)         ! observed apparent heat source
         129             : real(r8), public ::      q2obs(plev)         ! observed apparent heat sink
         130             : real(r8), public ::      tdiff(plev)         ! model minus observed temp
         131             : real(r8), public ::      tground(1)          ! ground temperature
         132             : real(r8), public ::      psobs               ! observed surface pressure
         133             : real(r8), public ::      tobs(plev)          ! observed temperature
         134             : real(r8), public ::      tsair(1)            ! air temperature at the surface
         135             : real(r8), public ::      udiff(plev)         ! model minus observed uwind
         136             : real(r8), public ::      uobs(plev)          ! actual u wind
         137             : real(r8), public ::      vdiff(plev)         ! model minus observed vwind
         138             : real(r8), public ::      vobs(plev)          ! actual v wind
         139             : real(r8), public ::      cldobs(plev)        ! observed cld
         140             : real(r8), public ::      clwpobs(plev)       ! observed clwp
         141             : real(r8), public ::      aldirobs(1)         ! observed aldir
         142             : real(r8), public ::      aldifobs(1)         ! observed aldif
         143             : real(r8), public ::      asdirobs(1)         ! observed asdir
         144             : real(r8), public ::      asdifobs(1)         ! observed asdif
         145             :
         146             : real(r8), public ::      co2vmrobs(1)        ! observed co2vmr
         147             : real(r8), public ::      ch4vmrobs(1)        ! observed ch3vmr
         148             : real(r8), public ::      n2ovmrobs(1)        ! observed n2ovmr
         149             : real(r8), public ::      f11vmrobs(1)        ! observed f11vmr
         150             : real(r8), public ::      f12vmrobs(1)        ! observed f12vmr
         151             : real(r8), public ::      soltsiobs(1)        ! observed solar
         152             :
         153             : real(r8), public ::      wfld(plev)          ! Vertical motion (slt)
         154             : real(r8), public ::      wfldh(plevp)        ! Vertical motion (slt)
         155             : real(r8), public ::      divq(plev,pcnst)    ! Divergence of moisture
         156             : real(r8), public ::      divt(plev)          ! Divergence of temperature
         157             : real(r8), public ::      divu(plev)          ! Horiz Divergence of E/W
         158             : real(r8), public ::      divv(plev)          ! Horiz Divergence of N/S
         159             :                                              ! mo_drydep algorithm
         160             : real(r8), public, pointer :: loniop(:)
         161             : real(r8), public, pointer :: latiop(:)
         162             :
         163             : integer, public ::     iopTimeIdx            ! index into iop dataset
         164             : integer, public ::     steplength            ! Length of time-step
         165             : integer, public ::     base_date             ! Date in (yyyymmdd) of start time
         166             : integer, public ::     base_secs             ! Time of day of start time (sec)
         167             :
         168             : ! SCAM public data defaults
         169             :
         170             : logical, public ::  doiopupdate            = .false. ! do we need to read next iop timepoint
         171             : logical, public ::  have_lhflx             = .false. ! dataset contains lhflx
         172             : logical, public ::  have_shflx             = .false. ! dataset contains shflx
         173             : logical, public ::  have_heat_glob         = .false. ! dataset contains heat total
         174             : logical, public ::  have_tg                = .false. ! dataset contains tg
         175             : logical, public ::  have_tsair             = .false. ! dataset contains tsair
         176             : logical, public ::  have_divq              = .false. ! dataset contains divq
         177             : logical, public ::  have_divt              = .false. ! dataset contains divt
         178             : logical, public ::  have_divq3d            = .false. ! dataset contains divq3d
         179             : logical, public ::  have_vertdivu          = .false. ! dataset contains vertdivu
         180             : logical, public ::  have_vertdivv          = .false. ! dataset contains vertdivv
         181             : logical, public ::  have_vertdivt          = .false. ! dataset contains vertdivt
         182             : logical, public ::  have_vertdivq          = .false. ! dataset contains vertdivq
         183             : logical, public ::  have_divt3d            = .false. ! dataset contains divt3d
         184             : logical, public ::  have_divu3d            = .false. ! dataset contains divu3d
         185             : logical, public ::  have_divv3d            = .false. ! dataset contains divv3d
         186             : logical, public ::  have_divu              = .false. ! dataset contains divu
         187             : logical, public ::  have_divv              = .false. ! dataset contains divv
         188             : logical, public ::  have_omega             = .false. ! dataset contains omega
         189             : logical, public ::  have_phis              = .false. ! dataset contains phis
         190             : logical, public ::  have_ptend             = .false. ! dataset contains ptend
         191             : logical, public ::  have_ps                = .false. ! dataset contains ps
         192             : logical, public ::  have_q                 = .false. ! dataset contains q
         193             : logical, public ::  have_q1                = .false. ! dataset contains Q1
         194             : logical, public ::  have_q2                = .false. ! dataset contains Q2
         195             : logical, public ::  have_prec              = .false. ! dataset contains prec
         196             : logical, public ::  have_t                 = .false. ! dataset contains t
         197             : logical, public ::  have_u                 = .false. ! dataset contains u
         198             : logical, public ::  have_v                 = .false. ! dataset contains v
         199             : logical, public ::  have_cld               = .false. ! dataset contains cld
         200             : logical, public ::  have_cldliq            = .false. ! dataset contains cldliq
         201             : logical, public ::  have_cldice            = .false. ! dataset contains cldice
         202             : logical, public ::  have_numliq            = .false. ! dataset contains numliq
         203             : logical, public ::  have_numice            = .false. ! dataset contains numice
         204             : logical, public ::  have_clwp              = .false. ! dataset contains clwp
         205             : logical, public ::  have_aldir             = .false. ! dataset contains aldir
         206             : logical, public ::  have_aldif             = .false. ! dataset contains aldif
         207             : logical, public ::  have_asdir             = .false. ! dataset contains asdir
         208             : logical, public ::  have_asdif             = .false. ! dataset contains asdif
         209             : logical, public ::  use_camiop             = .false. ! use cam generated forcing
         210             : logical, public ::  use_3dfrc              = .false. ! use 3d forcing
         211             : logical, public ::  isrestart              = .false. ! If this is a restart step or not
         212             :
         213             : ! SCAM namelist defaults
         214             :
         215             : logical, public ::  scm_backfill_iop_w_init = .false. ! Backfill missing IOP data from initial file
         216             : logical, public ::  scm_relaxation         = .false. ! Use relaxation
         217             : logical, public ::  scm_crm_mode           = .false. ! Use column radiation mode
         218             : logical, public ::  scm_cambfb_mode        = .false. ! Use extra CAM IOP fields to assure bit for bit match with CAM run
         219             : logical, public ::  scm_use_obs_T          = .false. ! Use the SCAM-IOP observed T at each timestep instead of forecasting.
         220             : logical, public ::  scm_force_latlon       = .false. ! force scam to use the lat lon fields specified in the namelist not closest
         221             : real(r8), public              ::  scm_relaxation_low      ! lowest level to apply relaxation
         222             : real(r8), public              ::  scm_relaxation_high     ! highest level to apply relaxation
         223             : real(r8), public              ::  scm_relax_top_p         = 0._r8       ! upper bound for scm relaxation
         224             : real(r8), public              ::  scm_relax_bot_p         = huge(1._r8) ! lower bound for scm relaxation
         225             : real(r8), public              ::  scm_relax_tau_sec       = 10800._r8   ! relaxation time constant (sec)
         226             :
         227             : ! +++BPM:
         228             : ! modification... allow a linear ramp in relaxation time scale:
         229             : logical, public :: scm_relax_linear = .false.
         230             : real(r8), public    :: scm_relax_tau_bot_sec = 10800._r8
         231             : real(r8), public    :: scm_relax_tau_top_sec = 10800._r8
         232             : character(len=26), public  :: scm_relax_fincl(pcnst)
         233             :
         234             : !
         235             : ! note that scm_use_obs_uv is set to true to be consistent with CAM BFB testing
         236             : !
         237             :
         238             : logical, public ::  scm_use_obs_uv         = .true. ! Use the SCAM-IOP observed u,v at each time step instead of forecasting.
         239             :
         240             : logical, public ::  scm_use_obs_qv         = .false. ! Use the SCAM-IOP observed qv  at each time step instead of forecasting.
         241             : logical, public ::  scm_use_3dfrc          = .false. ! Use CAMIOP 3d forcing if true, else use dycore vertical plus horizontal
         242             : logical, public ::  scm_iop_lhflxshflxTg   = .false. !turn off LW rad
         243             : logical, public ::  scm_iop_Tg             = .false. !turn off LW rad
         244             :
         245             : character(len=200), public ::  scm_clubb_iop_name   ! IOP name for CLUBB
         246             :
         247             : integer, allocatable, public :: tsec(:)
         248             : integer, public :: ntime
         249             :
         250             : !=======================================================================
         251             : contains
         252             : !=======================================================================
         253             :
         254        1536 : subroutine scam_readnl(nlfile,single_column_in,scmlat_in,scmlon_in)
         255             :
         256             :   use namelist_utils,  only: find_group_name
         257             :   use units,           only: getunit, freeunit
         258             :   use dycore,          only: dycore_is
         259             :   use wrap_nf,         only: wrap_open
         260             :
         261             :
         262             : !---------------------------Arguments-----------------------------------
         263             :
         264             :   character(len=*), intent(in) :: nlfile  ! filepath for file containing namelist input  (nlfile=atm_in)
         265             :   logical,          intent(in) :: single_column_in
         266             :   real(r8),         intent(in) :: scmlat_in
         267             :   real(r8),         intent(in) :: scmlon_in
         268             :
         269             :   ! Local variables
         270             :   character(len=*), parameter :: sub = 'scam_readnl'
         271             :   integer :: unitn, ierr, i
         272             :   integer  :: ncid
         273             :   integer  :: iatt
         274             :   logical  :: adv
         275             :
         276             : ! this list should include any variable that you might want to include in the namelist
         277             :   namelist /scam_nl/ iopfile, scm_iop_lhflxshflxTg, scm_iop_Tg, scm_relaxation, &
         278             :        scm_relax_top_p,scm_relax_bot_p,scm_relax_tau_sec, &
         279             :        scm_cambfb_mode,scm_crm_mode,scm_zadv_uv,scm_zadv_T,scm_zadv_q,&
         280             :        scm_use_obs_T, scm_use_obs_uv, scm_use_obs_qv, scm_use_3dfrc, &
         281             :        scm_relax_linear, scm_relax_tau_top_sec, &
         282             :        scm_relax_tau_bot_sec, scm_force_latlon, scm_relax_fincl, &
         283             :        scm_backfill_iop_w_init
         284             :
         285        1536 :   single_column=single_column_in
         286             :
         287        1536 :   iopfile            = ' '
         288        1536 :   scm_clubb_iop_name = ' '
         289        6144 :   scm_relax_fincl(:) = ' '
         290        1536 :   if( single_column ) then
         291           0 :      if( npes>1) call endrun('SCAM_READNL: SCAM doesnt support using more than 1 pe.')
         292             :
         293           0 :      if ( .not. (dycore_is('EUL') .or. dycore_is('SE')) .or. plon /= 1 .or. plat /=1 ) then
         294           0 :         call endrun('SCAM_SETOPTS: must compile model for SCAM mode when namelist parameter single_column is .true.')
         295             :      endif
         296             :
         297           0 :      scmlat=scmlat_in
         298           0 :      scmlon=scmlon_in
         299             :
         300           0 :      if( scmlat < -90._r8 .or. scmlat > 90._r8 ) then
         301           0 :         call endrun('SCAM_READNL: SCMLAT must be between -90. and 90. degrees.')
         302           0 :      elseif( scmlon < 0._r8 .or. scmlon > 360._r8 ) then
         303           0 :         call endrun('SCAM_READNL: SCMLON must be between 0. and 360. degrees.')
         304             :      end if
         305             :
         306             :      ! Read namelist
         307           0 :      if (masterproc) then
         308           0 :         unitn = getunit()
         309           0 :         open( unitn, file=trim(nlfile), status='old' )
         310           0 :         call find_group_name(unitn, 'scam_nl', status=ierr)
         311           0 :         if (ierr == 0) then
         312           0 :            read(unitn, scam_nl, iostat=ierr)
         313           0 :            if (ierr /= 0) then
         314           0 :               call endrun(sub // ':: ERROR reading namelist')
         315             :            end if
         316             :         end if
         317           0 :         close(unitn)
         318           0 :         call freeunit(unitn)
         319             :      end if
         320             :
         321             :      ! Error checking:
         322             :
         323           0 :      iopfile = trim(iopfile)
         324           0 :      if( iopfile /= "" ) then
         325           0 :         use_iop = .true.
         326             :      else
         327           0 :         call endrun('SCAM_READNL: must specify IOP file for single column mode')
         328             :      endif
         329             :
         330           0 :      call wrap_open( iopfile, NF90_NOWRITE, ncid )
         331             :
         332           0 :      if( nf90_inquire_attribute( ncid, NF90_GLOBAL, 'CAM_GENERATED_FORCING', iatt ) ==  NF90_NOERR ) then
         333           0 :         use_camiop = .true.
         334             :      else
         335           0 :         use_camiop = .false.
         336             :      endif
         337             :
         338             :      ! If we are not forcing the lat and lon from the namelist use the closest lat and lon that is found in the IOP file.
         339           0 :      if (.not.scm_force_latlon) then
         340           0 :         call shr_scam_GetCloseLatLon( ncid, scmlat, scmlon, closeioplat, closeioplon, closeioplatidx, closeioplonidx )
         341           0 :         write(iulog,*) 'SCAM_READNL: using closest IOP column to lat/lon specified in drv_in'
         342           0 :         write(iulog,*) '   requested lat,lon    =',scmlat,', ',scmlon
         343           0 :         write(iulog,*) '   closest IOP lat,lon  =',closeioplat,', ',closeioplon
         344           0 :         scmlat = closeioplat
         345           0 :         scmlon = closeioplon
         346             :      end if
         347             :
         348           0 :      if (masterproc) then
         349           0 :         write (iulog,*) 'Single Column Model Options: '
         350           0 :         write (iulog,*) '============================='
         351           0 :         write (iulog,*) '  iopfile                     = ',trim(iopfile)
         352           0 :         write (iulog,*) '  scm_backfill_iop_w_init     = ',scm_backfill_iop_w_init
         353           0 :         write (iulog,*) '  scm_cambfb_mode             = ',scm_cambfb_mode
         354           0 :         write (iulog,*) '  scm_crm_mode                = ',scm_crm_mode
         355           0 :         write (iulog,*) '  scm_force_latlon            = ',scm_force_latlon
         356           0 :         write (iulog,*) '  scm_iop_Tg                  = ',scm_iop_Tg
         357           0 :         write (iulog,*) '  scm_iop_lhflxshflxTg        = ',scm_iop_lhflxshflxTg
         358           0 :         write (iulog,*) '  scm_relaxation              = ',scm_relaxation
         359           0 :         write (iulog,*) '  scm_relax_bot_p             = ',scm_relax_bot_p
         360           0 :         write (iulog,*) '  scm_relax_linear            = ',scm_relax_linear
         361           0 :         write (iulog,*) '  scm_relax_tau_bot_sec       = ',scm_relax_tau_bot_sec
         362           0 :         write (iulog,*) '  scm_relax_tau_sec           = ',scm_relax_tau_sec
         363           0 :         write (iulog,*) '  scm_relax_tau_top_sec       = ',scm_relax_tau_top_sec
         364           0 :         write (iulog,*) '  scm_relax_top_p             = ',scm_relax_top_p
         365           0 :         write (iulog,*) '  scm_use_obs_T               = ',scm_use_obs_T
         366           0 :         write (iulog,*) '  scm_use_3dfrc               = ',scm_use_3dfrc
         367           0 :         write (iulog,*) '  scm_use_obs_qv              = ',scm_use_obs_qv
         368           0 :         write (iulog,*) '  scm_use_obs_uv              = ',scm_use_obs_uv
         369           0 :         write (iulog,*) '  scm_zadv_T                  = ',trim(scm_zadv_T)
         370           0 :         write (iulog,*) '  scm_zadv_q                  = ',trim(scm_zadv_q)
         371           0 :         write (iulog,*) '  scm_zadv_uv                 = ',trim(scm_zadv_uv)
         372           0 :         write (iulog,*) '  scm_relax_finc: '
         373             :         ! output scm_relax_fincl character array
         374           0 :         do i=1,pcnst
         375           0 :            if (scm_relax_fincl(i) /= '') then
         376           0 :               adv = mod(i,4)==0
         377           0 :               if (adv) then
         378           0 :                  write (iulog, "(A18)") "'"//trim(scm_relax_fincl(i))//"',"
         379             :               else
         380           0 :                  write (iulog, "(A18)", ADVANCE="NO") "'"//trim(scm_relax_fincl(i))//"',"
         381             :               end if
         382             :            else
         383             :               exit
         384             :            end if
         385             :         end do
         386           0 :         print *
         387             :      end if
         388             :   end if
         389             :
         390        1536 : end subroutine scam_readnl
         391           0 : subroutine readiopdata(hyam, hybm, hyai, hybi, ps0)
         392             : !-----------------------------------------------------------------------
         393             : !
         394             : !     Open and read netCDF file containing initial IOP  conditions
         395             : !
         396             : !---------------------------Code history--------------------------------
         397             : !
         398             : !     Written by J.  Truesdale    August, 1996, revised January, 1998
         399             : !
         400             : !-----------------------------------------------------------------------
         401             :         use getinterpnetcdfdata, only: getinterpncdata
         402             :         use string_utils,        only: to_lower
         403             :         use wrap_nf,             only: wrap_inq_dimid,wrap_get_vara_realx
         404             : !-----------------------------------------------------------------------
         405             :    implicit none
         406             :
         407             :    character(len=*), parameter ::  sub = "read_iop_data"
         408             : !
         409             : !------------------------------Input Arguments--------------------------
         410             : !
         411             :    real(r8),intent(in) :: hyam(plev),hybm(plev),hyai(plevp),hybi(plevp),ps0
         412             : !
         413             : !------------------------------Locals-----------------------------------
         414             : !
         415             :    integer :: NCID, status
         416             :    integer :: time_dimID, lev_dimID,  lev_varID, varid
         417             :    integer :: i,j
         418             :    integer :: nlev
         419             :    integer :: total_levs
         420             :    integer :: u_attlen
         421             :
         422             :    integer :: k, m
         423             :    integer :: icldliq,icldice
         424             :    integer :: inumliq,inumice
         425             :
         426             :    logical :: have_srf              ! value at surface is available
         427             :    logical :: fill_ends             !
         428             :    logical :: have_cnst(pcnst)
         429             :    real(r8) :: dummy
         430             :    real(r8) :: srf(1)                  ! value at surface
         431             :    real(r8) :: hyamiop(plev)  ! a hybrid coef midpoint
         432             :    real(r8) :: hybmiop(plev)  ! b hybrid coef midpoint
         433             :    real(r8) :: pmid(plev)  ! pressure at model levels (time n)
         434             :    real(r8) :: pint(plevp) ! pressure at model interfaces (n  )
         435             :    real(r8) :: pdel(plev)  ! pdel(k)   = pint  (k+1)-pint  (k)
         436             :    real(r8) :: weight
         437             :    real(r8) :: tmpdata(1)
         438             :    real(r8) :: coldata(plev)
         439           0 :    real(r8), allocatable :: dplevs( : )
         440             :    integer :: strt4(4),cnt4(4)
         441             :    integer :: nstep
         442             :    integer :: ios
         443             :    character(len=128) :: units ! Units
         444             :
         445           0 :    nstep = get_nstep()
         446           0 :    fill_ends= .false.
         447             :
         448             : !
         449             : !     Open IOP dataset
         450             : !
         451             :    call handle_ncerr( nf90_open (iopfile, 0, ncid),&
         452           0 :        'ERROR - scamMod.F90:readiopdata', __LINE__)
         453             :
         454             : !
         455             : !     if the dataset is a CAM generated dataset set use_camiop to true
         456             : !       CAM IOP datasets have a global attribute called CAM_GENERATED_IOP
         457             : !
         458           0 :    if ( nf90_inquire_attribute( ncid, NF90_GLOBAL, 'CAM_GENERATED_FORCING', attnum=i )== NF90_NOERR ) then
         459           0 :       use_camiop = .true.
         460             :    else
         461           0 :       use_camiop = .false.
         462             :    endif
         463             :
         464             : !=====================================================================
         465             : !
         466             : !     Read time variables
         467             :
         468             :
         469           0 :    status = nf90_inq_dimid (ncid, 'time', time_dimID )
         470           0 :    if (status /= NF90_NOERR) then
         471           0 :       status = nf90_inq_dimid (ncid, 'tsec', time_dimID )
         472           0 :       if (status /= NF90_NOERR) then
         473           0 :          if (masterproc) write(iulog,*) sub//':ERROR - Could not find dimension ID for time/tsec'
         474           0 :          status = NF90_CLOSE ( ncid )
         475           0 :          call endrun(sub // ':ERROR - time/tsec must be present on the IOP file.')
         476             :       end if
         477             :    end if
         478             :
         479             :    call handle_ncerr( nf90_inquire_dimension( ncid, time_dimID, len=ntime ),&
         480           0 :          'Error - scamMod.F90:readiopdata unable to find time dimension', __LINE__)
         481             :
         482             : !
         483             : !======================================================
         484             : !     read level data
         485             : !
         486           0 :    status = NF90_INQ_DIMID( ncid, 'lev', lev_dimID )
         487           0 :    if ( status /= nf90_noerr ) then
         488           0 :       if (masterproc) write(iulog,*) sub//':ERROR - Could not find variable dim ID  for lev'
         489           0 :       status = NF90_CLOSE ( ncid )
         490           0 :       call endrun(sub // ':ERROR - Could not find variable dim ID for lev')
         491             :    end if
         492             :
         493             :    call handle_ncerr( nf90_inquire_dimension( ncid, lev_dimID, len=nlev ),&
         494           0 :          'Error - scamMod.f90:readiopdata unable to find level dimension', __LINE__)
         495             :
         496           0 :    allocate(dplevs(nlev+1),stat=ios)
         497           0 :    if( ios /= 0 ) then
         498           0 :       write(iulog,*) sub//':ERROR: failed to allocate dplevs; error = ',ios
         499           0 :       call endrun(sub//':ERROR:readiopdata failed to allocate dplevs')
         500             :    end if
         501             :
         502           0 :    status = NF90_INQ_VARID( ncid, 'lev', lev_varID )
         503           0 :    if ( status /= nf90_noerr ) then
         504           0 :       if (masterproc) write(iulog,*) sub//':ERROR - scamMod.F90:readiopdata:Could not find variable ID for lev'
         505           0 :       status = NF90_CLOSE ( ncid )
         506           0 :       call endrun(sub//':ERROR:ould not find variable ID for lev')
         507             :    end if
         508             :
         509           0 :    call handle_ncerr( nf90_get_var (ncid, lev_varID, dplevs(:nlev)),&
         510           0 :                     'Error - scamMod.F90:readiopdata unable to read pressure levels', __LINE__)
         511             : !
         512             : !CAM generated forcing already has pressure on millibars convert standard IOP if needed.
         513             : !
         514             :    call handle_ncerr(nf90_inquire_attribute(ncid, lev_varID, 'units', len=u_attlen),&
         515           0 :                     'Error - scamMod.F90:readiopdata unable to find units attribute', __LINE__)
         516             :    call handle_ncerr(nf90_get_att(ncid, lev_varID, 'units', units),&
         517           0 :                     'Error - scamMod.F90:readiopdata unable to read units attribute', __LINE__)
         518           0 :    units=trim(to_lower(units(1:u_attlen)))
         519             :
         520           0 :    if ( units=='pa' .or. units=='pascal' .or. units=='pascals' ) then
         521             : !
         522             : !     convert pressure from Pascals to Millibars ( lev is expressed in pascals in iop datasets )
         523             : !
         524           0 :       do i=1,nlev
         525           0 :          dplevs( i ) = dplevs( i )/100._r8
         526             :       end do
         527             :    endif
         528             :
         529           0 :    status = nf90_inq_varid( ncid, 'Ps', varid   )
         530           0 :    if ( status /= nf90_noerr ) then
         531           0 :       have_ps= .false.
         532           0 :       if (masterproc) write(iulog,*) sub//':Could not find variable Ps'
         533           0 :       if ( .not. scm_backfill_iop_w_init ) then
         534           0 :          status = NF90_CLOSE( ncid )
         535           0 :          call endrun(sub//':ERROR :IOP file must contain Surface Pressure (Ps) variable')
         536             :       else
         537           0 :          if ( is_first_step() .and. masterproc) write(iulog,*) 'Using surface pressure value from IC file if present'
         538             :       endif
         539             :    else
         540           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         541           0 :       status = nf90_get_var(ncid, varid, psobs, strt4)
         542           0 :       have_ps = .true.
         543             :    endif
         544             :
         545             :
         546             : !  If the IOP dataset has hyam,hybm,etc it is assumed to be a hybrid level
         547             : !  dataset
         548             :
         549           0 :    status =  nf90_inq_varid( ncid, 'hyam', varid   )
         550           0 :    if ( status == nf90_noerr .and. have_ps) then
         551           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         552           0 :       status = nf90_get_var(ncid, varid, hyamiop, strt4)
         553           0 :       status =  nf90_inq_varid( ncid, 'hybm', varid   )
         554           0 :       status = nf90_get_var(ncid, varid, hybmiop, strt4)
         555           0 :       do i = 1, nlev
         556           0 :          dplevs( i ) = 1000.0_r8 * hyamiop( i ) + psobs * hybmiop( i ) / 100.0_r8
         557             :       end do
         558             :    endif
         559             :
         560             : !     add the surface pressure to the pressure level data, so that
         561             : !     surface boundary condition will be set properly,
         562             : !     making sure that it is the highest pressure in the array.
         563             : !
         564             :
         565           0 :    total_levs = nlev+1
         566           0 :    dplevs(nlev+1) = psobs/100.0_r8 ! ps is expressed in pascals
         567           0 :    do i= nlev, 1, -1
         568           0 :       if ( dplevs(i) > psobs/100.0_r8) then
         569           0 :          total_levs = i
         570           0 :          dplevs(i) = psobs/100.0_r8
         571             :       end if
         572             :    end do
         573           0 :    if (.not. use_camiop ) then
         574           0 :       nlev = total_levs
         575             :    endif
         576           0 :    if ( nlev == 1 ) then
         577           0 :       if (masterproc) write(iulog,*) sub//':Error - scamMod.F90:readiopdata: Ps too low!'
         578           0 :       call endrun(sub//':ERROR:Ps value on datasets is incongurent with levs data - mismatch in units?')
         579             :    endif
         580             :
         581             : !=====================================================================
         582             : !get global vmrs from camiop file
         583           0 :    status =  nf90_inq_varid( ncid, 'co2vmr', varid   )
         584           0 :    if ( status == nf90_noerr) then
         585           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         586           0 :       call wrap_get_vara_realx (ncid,varid,strt4,cnt4,co2vmrobs)
         587             :    else
         588           0 :       if (is_first_step()) write(iulog,*)'using column value of co2vmr from boundary data as global volume mixing ratio'
         589             :    end if
         590           0 :    status =  nf90_inq_varid( ncid, 'ch4vmr', varid   )
         591           0 :    if ( status == nf90_noerr) then
         592           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         593           0 :       call wrap_get_vara_realx (ncid,varid,strt4,cnt4,ch4vmrobs)
         594             :    else
         595           0 :       if (is_first_step()) write(iulog,*)'using column value of ch4vmr from boundary data as global volume mixing ratio'
         596             :    end if
         597           0 :    status =  nf90_inq_varid( ncid, 'n2ovmr', varid   )
         598           0 :    if ( status == nf90_noerr) then
         599           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         600           0 :       call wrap_get_vara_realx (ncid,varid,strt4,cnt4,n2ovmrobs)
         601             :    else
         602           0 :       if (is_first_step()) write(iulog,*)'using column value of n2ovmr from boundary data as global volume mixing ratio'
         603             :    end if
         604           0 :    status =  nf90_inq_varid( ncid, 'f11vmr', varid   )
         605           0 :    if ( status == nf90_noerr) then
         606           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         607           0 :       call wrap_get_vara_realx (ncid,varid,strt4,cnt4,f11vmrobs)
         608             :    else
         609           0 :       if (is_first_step()) write(iulog,*)'using column value of f11vmr from boundary data as global volume mixing ratio'
         610             :    end if
         611           0 :    status =  nf90_inq_varid( ncid, 'f12vmr', varid   )
         612           0 :    if ( status == nf90_noerr) then
         613           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         614           0 :       call wrap_get_vara_realx (ncid,varid,strt4,cnt4,f12vmrobs)
         615             :    else
         616           0 :       if (is_first_step()) write(iulog,*)'using column value of f12vmr from boundary data as global volume mixing ratio'
         617             :    end if
         618           0 :    status =  nf90_inq_varid( ncid, 'soltsi', varid   )
         619           0 :    if ( status == nf90_noerr) then
         620           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         621           0 :       call wrap_get_vara_realx (ncid,varid,strt4,cnt4,soltsiobs)
         622             :    else
         623           0 :       if (is_first_step()) write(iulog,*)'using column value of soltsi from boundary data as global solar tsi'
         624             :    end if
         625             : !=====================================================================
         626             : !get state variables from camiop file
         627             :
         628           0 :    status =  nf90_inq_varid( ncid, 'Tsair', varid   )
         629           0 :    if ( status /= nf90_noerr ) then
         630           0 :       have_tsair = .false.
         631             :    else
         632           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         633           0 :       call wrap_get_vara_realx (ncid,varid,strt4,cnt4,tsair)
         634           0 :       have_tsair = .true.
         635             :    endif
         636             : !
         637             : !      read in Tobs  For cam generated iop readin small t to avoid confusion
         638             : !      with capital T defined in cam
         639             : !
         640           0 :    tobs(:)= 0._r8
         641             :
         642           0 :    if ( use_camiop ) then
         643             :      call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx,'t', have_tsair, &
         644             :           tsair(1), fill_ends, scm_crm_mode, &
         645           0 :           dplevs, nlev,psobs, hyam, hybm,tobs, status )
         646             :    else
         647             :      call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx,'T', have_tsair, &
         648             :           tsair(1), fill_ends, scm_crm_mode, &
         649           0 :           dplevs, nlev,psobs, hyam, hybm, tobs, status )
         650             :    endif
         651           0 :    if ( status /= nf90_noerr ) then
         652           0 :       have_t = .false.
         653           0 :       if (masterproc) write(iulog,*) sub//':Could not find variable T on IOP file'
         654           0 :       if ( scm_backfill_iop_w_init ) then
         655           0 :          if (masterproc) write(iulog,*) sub//':Using value of T(tobs) from IC file if it exists'
         656             :       else
         657           0 :          if (masterproc) write(iulog,*) sub//':set tobs to 0.'
         658             :       endif
         659             : !
         660             : !     set T3 to Tobs on first time step
         661             : !
         662             :    else
         663           0 :       have_t = .true.
         664             :    endif
         665             :
         666           0 :    status = nf90_inq_varid( ncid, 'Tg', varid   )
         667           0 :    if (status /= nf90_noerr) then
         668           0 :       if (masterproc) write(iulog,*) sub//':Could not find variable Tg on IOP dataset'
         669           0 :       if ( have_tsair ) then
         670           0 :          if (masterproc) write(iulog,*) sub//':Using Tsair'
         671           0 :          tground = tsair     ! use surface value from T field
         672           0 :          have_Tg = .true.
         673             :       else
         674           0 :          have_Tg = .true.
         675           0 :          if (masterproc) write(iulog,*) sub//':Using T at lowest level from IOP dataset'
         676           0 :          tground = tobs(plev)
         677             :       endif
         678             :    else
         679           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         680           0 :       call wrap_get_vara_realx (ncid,varid,strt4,cnt4,tground)
         681           0 :       have_Tg = .true.
         682             :    endif
         683             :
         684           0 :    status = nf90_inq_varid( ncid, 'qsrf', varid   )
         685             :
         686           0 :    if ( status /= nf90_noerr ) then
         687           0 :       have_srf = .false.
         688             :    else
         689           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         690           0 :       status = nf90_get_var(ncid, varid, srf(1), strt4)
         691           0 :       have_srf = .true.
         692             :    endif
         693             :
         694           0 :    qobs(:)= 0._r8
         695             :    call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx,  'q', have_srf, &
         696             :       srf(1), fill_ends, scm_crm_mode, &
         697           0 :       dplevs, nlev,psobs, hyam, hybm, qobs, status )
         698           0 :    if ( status /= nf90_noerr ) then
         699           0 :       have_q = .false.
         700           0 :       if (masterproc) write(iulog,*) sub//':Could not find variable q on IOP file'
         701           0 :       if ( scm_backfill_iop_w_init ) then
         702           0 :          if (masterproc) write(iulog,*) sub//':Using values for q from IC file if available'
         703             :       else
         704           0 :          if (masterproc) write(iulog,*) sub//':Setting qobs to 0.'
         705             :       endif
         706             :    else
         707           0 :       have_q = .true.
         708             :    endif
         709             :
         710           0 :    cldobs = 0._r8
         711             :    call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx,  'cld', .false., &
         712           0 :       dummy, fill_ends, scm_crm_mode, dplevs, nlev,psobs, hyam, hybm, cldobs, status )
         713           0 :    if ( status /= nf90_noerr ) then
         714           0 :       have_cld = .false.
         715             :    else
         716           0 :       have_cld = .true.
         717             :    endif
         718             :
         719           0 :    clwpobs = 0._r8
         720             :    call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx,  'clwp', .false., &
         721           0 :       dummy, fill_ends, scm_crm_mode, dplevs, nlev,psobs, hyam, hybm, clwpobs, status )
         722           0 :    if ( status /= nf90_noerr ) then
         723           0 :       have_clwp = .false.
         724             :    else
         725           0 :       have_clwp = .true.
         726             :    endif
         727             :
         728             : !
         729             : !       read divq (horizontal advection)
         730             : !
         731           0 :    status = nf90_inq_varid( ncid, 'divqsrf', varid   )
         732           0 :    if ( status /= nf90_noerr ) then
         733           0 :       have_srf = .false.
         734             :    else
         735           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         736           0 :       status = nf90_get_var(ncid, varid, srf(1), strt4)
         737           0 :       have_srf = .true.
         738             :    endif
         739             :
         740           0 :    divq(:,:)=0._r8
         741             :
         742             :    call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, &
         743             :         'divq', have_srf, srf(1), fill_ends, scm_crm_mode, &
         744           0 :         dplevs, nlev,psobs, hyam, hybm, divq(:,1), status )
         745           0 :    if ( status /= nf90_noerr ) then
         746           0 :       have_divq = .false.
         747             :    else
         748           0 :       have_divq = .true.
         749             :    endif
         750             :
         751             : !
         752             : !     read vertdivq if available
         753             : !
         754           0 :    status = nf90_inq_varid( ncid, 'vertdivqsrf', varid   )
         755           0 :    if ( status /= nf90_noerr ) then
         756           0 :       have_srf = .false.
         757             :    else
         758           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         759           0 :       status = nf90_get_var(ncid, varid, srf(1), strt4)
         760           0 :       have_srf = .true.
         761             :    endif
         762             :
         763           0 :    vertdivq=0._r8
         764             :
         765             :    call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'vertdivq', &
         766             :         have_srf, srf(1), fill_ends, scm_crm_mode, &
         767           0 :         dplevs, nlev,psobs, hyam, hybm, vertdivq(:,1), status )
         768           0 :    if ( status /= nf90_noerr ) then
         769           0 :       have_vertdivq = .false.
         770             :    else
         771           0 :       have_vertdivq = .true.
         772             :    endif
         773             :
         774           0 :    status = nf90_inq_varid( ncid, 'vertdivqsrf', varid   )
         775           0 :    if ( status /= nf90_noerr ) then
         776           0 :       have_srf = .false.
         777             :    else
         778           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         779           0 :       status = nf90_get_var(ncid, varid, srf(1), strt4)
         780           0 :       have_srf = .true.
         781             :    endif
         782             : !
         783             : !   add calls to get dynamics tendencies for all prognostic consts
         784             : !
         785           0 :    divq3d=0._r8
         786             :
         787           0 :    do m = 1, pcnst
         788           0 :       call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, trim(cnst_name(m))//'_dten', &
         789             :       have_srf, srf(1), fill_ends, scm_crm_mode, &
         790           0 :       dplevs, nlev,psobs, hyam, hybm, divq3d(:,m), status )
         791           0 :       write(iulog,*)'checking ',trim(cnst_name(m))//'_dten',status
         792           0 :       if ( status /= nf90_noerr ) then
         793           0 :          have_cnst(m) = .false.
         794           0 :          divq3d(1:,m)=0._r8
         795             :       else
         796           0 :          if (m==1) have_divq3d = .true.
         797           0 :          have_cnst(m) = .true.
         798             :       endif
         799             :
         800           0 :       coldata = 0._r8
         801             :       call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, trim(cnst_name(m))//'_dqfx', &
         802             :       have_srf, srf(1), fill_ends, scm_crm_mode, &
         803           0 :       dplevs, nlev,psobs, hyam, hybm, coldata, status )
         804           0 :       if ( STATUS /= NF90_NOERR ) then
         805           0 :          dqfxcam(1,:,m)=0._r8
         806             :       else
         807           0 :          dqfxcam(1,:,m)=coldata(:)
         808             :       endif
         809             :
         810           0 :       tmpdata = 0._r8
         811             :       call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, trim(cnst_name(m))//'_alph', &
         812             :       have_srf, srf(1), fill_ends, scm_crm_mode, &
         813           0 :       dplevs, nlev,psobs, hyam, hybm, tmpdata, status )
         814           0 :       if ( status /= nf90_noerr ) then
         815           0 :          alphacam(m)=0._r8
         816             :       else
         817           0 :           alphacam(m)=tmpdata(1)
         818             :       endif
         819             :
         820             :    end do
         821             :
         822             :
         823           0 :    numliqobs = 0._r8
         824           0 :    call cnst_get_ind('NUMLIQ', inumliq, abort=.false.)
         825           0 :    if ( inumliq > 0 ) then
         826           0 :       have_srf = .false.
         827             :       call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'NUMLIQ', &
         828             :            have_srf, srf(1), fill_ends, scm_crm_mode, &
         829           0 :            dplevs, nlev,psobs, hyam, hybm, numliqobs, status )
         830           0 :       if ( status /= nf90_noerr ) then
         831           0 :          have_numliq = .false.
         832             :       else
         833           0 :          have_numliq = .true.
         834             :       endif
         835             :    else
         836           0 :          have_numliq = .false.
         837             :    end if
         838             :
         839           0 :    have_srf = .false.
         840             :
         841           0 :    cldliqobs = 0._r8
         842           0 :    call cnst_get_ind('CLDLIQ', icldliq, abort=.false.)
         843           0 :    if ( icldliq > 0 ) then
         844             :       call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'CLDLIQ', &
         845             :            have_srf, srf(1), fill_ends, scm_crm_mode, &
         846           0 :            dplevs, nlev,psobs, hyam, hybm, cldliqobs, status )
         847           0 :       if ( status /= nf90_noerr ) then
         848           0 :          have_cldliq = .false.
         849             :       else
         850           0 :          have_cldliq = .true.
         851             :       endif
         852             :    else
         853           0 :          have_cldliq = .false.
         854             :    endif
         855             :
         856           0 :    cldiceobs = 0._r8
         857           0 :    call cnst_get_ind('CLDICE', icldice, abort=.false.)
         858           0 :    if ( icldice > 0 ) then
         859             :       call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'CLDICE', &
         860             :            have_srf, srf(1), fill_ends, scm_crm_mode, &
         861           0 :            dplevs, nlev,psobs, hyam, hybm, cldiceobs, status )
         862           0 :       if ( status /= nf90_noerr ) then
         863           0 :          have_cldice = .false.
         864             :       else
         865           0 :          have_cldice = .true.
         866             :       endif
         867             :    else
         868           0 :       have_cldice = .false.
         869             :    endif
         870             :
         871           0 :    numiceobs = 0._r8
         872           0 :    call cnst_get_ind('NUMICE', inumice, abort=.false.)
         873           0 :    if ( inumice > 0 ) then
         874           0 :       have_srf = .false.
         875             :       call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'NUMICE', &
         876             :          have_srf, srf(1), fill_ends, scm_crm_mode, &
         877           0 :          dplevs, nlev,psobs, hyam, hybm, numiceobs, status )
         878           0 :       if ( status /= nf90_noerr ) then
         879           0 :          have_numice = .false.
         880             :       else
         881           0 :          have_numice = .true.
         882             :       endif
         883             :    else
         884           0 :       have_numice = .false.
         885             :    end if
         886             :
         887             : !
         888             : !       read divu (optional field)
         889             : !
         890           0 :    status = nf90_inq_varid( ncid, 'divusrf', varid   )
         891           0 :    if ( status /= nf90_noerr ) then
         892           0 :       have_srf = .false.
         893             :    else
         894           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         895           0 :       status = nf90_get_var(ncid, varid, srf(1), strt4)
         896           0 :       have_srf = .true.
         897             :    endif
         898             :
         899           0 :    divu = 0._r8
         900             :    call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divu', &
         901             :       have_srf, srf(1), fill_ends, scm_crm_mode, &
         902           0 :       dplevs, nlev,psobs, hyam, hybm, divu, status )
         903           0 :    if ( status /= nf90_noerr ) then
         904           0 :       have_divu = .false.
         905             :    else
         906           0 :       have_divu = .true.
         907             :    endif
         908             : !
         909             : !       read divv (optional field)
         910             : !
         911           0 :    status = nf90_inq_varid( ncid, 'divvsrf', varid   )
         912           0 :    if ( status /= nf90_noerr ) then
         913           0 :       have_srf = .false.
         914             :    else
         915           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         916           0 :       status = nf90_get_var(ncid, varid, srf(1), strt4)
         917           0 :       have_srf = .true.
         918             :    endif
         919             :
         920           0 :    divv = 0._r8
         921             :    call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divv', &
         922             :       have_srf, srf(1), fill_ends, scm_crm_mode, &
         923           0 :       dplevs, nlev,psobs, hyam, hybm, divv, status )
         924           0 :    if ( status /= nf90_noerr ) then
         925           0 :       have_divv = .false.
         926             :    else
         927           0 :       have_divv = .true.
         928             :    endif
         929             : !
         930             : !       read divt (optional field)
         931             : !
         932           0 :    status = nf90_inq_varid( ncid, 'divtsrf', varid   )
         933           0 :    if ( status /= nf90_noerr ) then
         934           0 :       have_srf = .false.
         935             :    else
         936           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         937           0 :       status = nf90_get_var(ncid, varid, srf(1), strt4)
         938           0 :       have_srf = .true.
         939             :    endif
         940             :
         941           0 :    divt=0._r8
         942             :    call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, &
         943             :       'divT', have_srf, srf(1), fill_ends, scm_crm_mode, &
         944           0 :       dplevs, nlev,psobs, hyam, hybm, divt, status )
         945           0 :    if ( status /= nf90_noerr ) then
         946           0 :       have_divt = .false.
         947             :    else
         948           0 :       have_divt = .true.
         949             :    endif
         950             :
         951             : !
         952             : !     read vertdivt if available
         953             : !
         954           0 :    status = nf90_inq_varid( ncid, 'vertdivTsrf', varid   )
         955           0 :    if ( status /= nf90_noerr ) then
         956           0 :       have_srf = .false.
         957             :    else
         958           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         959           0 :       status = nf90_get_var(ncid, varid, srf(1), strt4)
         960           0 :       have_srf = .true.
         961             :    endif
         962             :
         963           0 :    vertdivt=0._r8
         964             :    call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'vertdivTx', &
         965             :       have_srf, srf(1), fill_ends, scm_crm_mode, &
         966           0 :       dplevs, nlev,psobs, hyam, hybm, vertdivt, status )
         967           0 :    if ( status /= nf90_noerr ) then
         968             :       call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'vertdivT', &
         969             :            have_srf, srf(1), fill_ends, scm_crm_mode, &
         970           0 :            dplevs, nlev,psobs, hyam, hybm, vertdivt, status )
         971           0 :       if ( status /= nf90_noerr ) then
         972           0 :          have_vertdivt = .false.
         973             :       else
         974           0 :          have_vertdivt = .true.
         975             :       endif
         976             :    else
         977           0 :       have_vertdivt = .true.
         978             :    endif
         979             : !
         980             : !       read divt3d (combined vertical/horizontal advection)
         981             : !      (optional field)
         982             :
         983           0 :    status = nf90_inq_varid( ncid, 'divT3dsrf', varid   )
         984           0 :    if ( status /= nf90_noerr ) then
         985           0 :       have_srf = .false.
         986             :    else
         987           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
         988           0 :       status = nf90_get_var(ncid, varid, srf(1), strt4)
         989           0 :       have_srf = .true.
         990             :    endif
         991             :
         992           0 :    divT3d = 0._r8
         993             :
         994             :    call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divT3d', &
         995             :       have_srf, srf(1), fill_ends, scm_crm_mode, &
         996           0 :       dplevs, nlev,psobs, hyam, hybm, divt3d, status )
         997           0 :       write(iulog,*)'checking divT3d:',status,nf90_noerr
         998           0 :    if ( status /= nf90_noerr ) then
         999           0 :       have_divt3d = .false.
        1000             :    else
        1001           0 :       have_divt3d = .true.
        1002             :    endif
        1003             :
        1004           0 :    divU3d = 0._r8
        1005             :
        1006             :    call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divU3d', &
        1007             :       have_srf, srf(1), fill_ends, scm_crm_mode, &
        1008           0 :       dplevs, nlev,psobs, hyam, hybm, divu3d, status )
        1009           0 :    if ( status /= nf90_noerr ) then
        1010           0 :       have_divu3d = .false.
        1011             :    else
        1012           0 :       have_divu3d = .true.
        1013             :    endif
        1014             :
        1015           0 :    divV3d = 0._r8
        1016             :
        1017             :    call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'divV3d', &
        1018             :       have_srf, srf(1), fill_ends, scm_crm_mode, &
        1019           0 :       dplevs, nlev,psobs, hyam, hybm, divv3d, status )
        1020           0 :    if ( status /= nf90_noerr ) then
        1021           0 :       have_divv3d = .false.
        1022             :    else
        1023           0 :       have_divv3d = .true.
        1024             :    endif
        1025             :
        1026           0 :    status = nf90_inq_varid( ncid, 'Ptend', varid   )
        1027           0 :    if ( status /= nf90_noerr ) then
        1028           0 :       have_ptend = .false.
        1029           0 :       if (masterproc) write(iulog,*) sub//':Could not find variable Ptend. Setting to zero'
        1030           0 :       ptend = 0.0_r8
        1031             :    else
        1032           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
        1033           0 :       status = nf90_get_var(ncid, varid, srf(1), strt4)
        1034           0 :       have_ptend = .true.
        1035           0 :       ptend= srf(1)
        1036             :    endif
        1037             :
        1038           0 :    wfld=0._r8
        1039             :
        1040             :    call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, &
        1041             :       'omega', .true., ptend, fill_ends, scm_crm_mode, &
        1042           0 :       dplevs, nlev,psobs, hyam, hybm, wfld, status )
        1043           0 :    if ( status /= nf90_noerr ) then
        1044           0 :       have_omega = .false.
        1045           0 :       if (masterproc) write(iulog,*) sub//':Could not find variable omega on IOP'
        1046           0 :       if ( scm_backfill_iop_w_init ) then
        1047           0 :          if (masterproc) write(iulog,*) sub//'Using omega from IC file'
        1048             :       else
        1049           0 :          if (masterproc) write(iulog,*) sub//'setting Omega to 0. throughout the column'
        1050             :       endif
        1051             :    else
        1052           0 :       have_omega = .true.
        1053             :    endif
        1054           0 :    call plevs0(plev, psobs, ps0, hyam, hybm, hyai, hybi, pint, pmid ,pdel)
        1055             : !
        1056             : ! Build interface vector for the specified omega profile
        1057             : ! (weighted average in pressure of specified level values)
        1058             : !
        1059           0 :    wfldh(:) = 0.0_r8
        1060             :
        1061           0 :    do k=2,plev
        1062           0 :       weight = (pint(k) - pmid(k-1))/(pmid(k) - pmid(k-1))
        1063           0 :       wfldh(k) = (1.0_r8 - weight)*wfld(k-1) + weight*wfld(k)
        1064             :    end do
        1065             :
        1066           0 :    status = nf90_inq_varid( ncid, 'usrf', varid   )
        1067           0 :    if ( status /= nf90_noerr ) then
        1068           0 :       have_srf = .false.
        1069             :    else
        1070           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
        1071           0 :       call wrap_get_vara_realx (ncid,varid,strt4,cnt4,srf)
        1072           0 :       have_srf = .true.
        1073             :    endif
        1074             :
        1075           0 :    uobs=0._r8
        1076             :
        1077             :    call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, &
        1078             :       'u', have_srf, srf(1), fill_ends, scm_crm_mode, &
        1079           0 :       dplevs, nlev,psobs, hyam, hybm, uobs, status )
        1080           0 :    if ( status /= nf90_noerr ) then
        1081           0 :       have_u = .false.
        1082             :    else
        1083           0 :       have_u = .true.
        1084             :    endif
        1085             :
        1086           0 :    status = nf90_inq_varid( ncid, 'vsrf', varid   )
        1087           0 :    if ( status /= nf90_noerr ) then
        1088           0 :       have_srf = .false.
        1089             :    else
        1090           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
        1091           0 :       call wrap_get_vara_realx (ncid,varid,strt4,cnt4,srf)
        1092           0 :       have_srf = .true.
        1093             :    endif
        1094             :
        1095           0 :    vobs=0._r8
        1096             :
        1097             :    call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, &
        1098             :       'v', have_srf, srf(1), fill_ends, scm_crm_mode, &
        1099           0 :       dplevs, nlev,psobs, hyam, hybm, vobs, status )
        1100           0 :    if ( status /= nf90_noerr ) then
        1101           0 :       have_v = .false.
        1102             :    else
        1103           0 :       have_v = .true.
        1104             :    endif
        1105             :
        1106           0 :    status = nf90_inq_varid( ncid, 'Prec', varid   )
        1107           0 :    if ( status /= nf90_noerr ) then
        1108           0 :       have_prec = .false.
        1109             :    else
        1110           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
        1111           0 :       call wrap_get_vara_realx (ncid,varid,strt4,cnt4,precobs)
        1112           0 :       have_prec = .true.
        1113             :    endif
        1114             :
        1115           0 :    q1obs = 0._r8
        1116             :
        1117             :    call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'Q1', &
        1118             :       .false., dummy, fill_ends, scm_crm_mode, & ! datasets don't contain Q1 at surface
        1119           0 :       dplevs, nlev,psobs, hyam, hybm, q1obs, status )
        1120           0 :    if ( status /= nf90_noerr ) then
        1121           0 :       have_q1 = .false.
        1122             :    else
        1123           0 :       have_q1 = .true.
        1124             :    endif
        1125             :
        1126           0 :    q1obs = 0._r8
        1127             :
        1128             :    call getinterpncdata( ncid, scmlat, scmlon, ioptimeidx, 'Q2', &
        1129             :       .false., dummy, fill_ends, scm_crm_mode, & ! datasets don't contain Q2 at surface
        1130           0 :       dplevs, nlev,psobs, hyam, hybm, q1obs, status )
        1131           0 :    if ( status /= nf90_noerr ) then
        1132           0 :       have_q2 = .false.
        1133             :    else
        1134           0 :       have_q2 = .true.
        1135             :    endif
        1136             :
        1137             : !  Test for BOTH 'lhflx' and 'lh' without overwriting 'have_lhflx'.
        1138             : !  Analagous changes made for the surface heat flux
        1139             :
        1140           0 :    status = nf90_inq_varid( ncid, 'lhflx', varid   )
        1141           0 :    if ( status /= nf90_noerr ) then
        1142           0 :       status = nf90_inq_varid( ncid, 'lh', varid   )
        1143           0 :       if ( status /= nf90_noerr ) then
        1144           0 :         have_lhflx = .false.
        1145             :       else
        1146           0 :          call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
        1147           0 :          call wrap_get_vara_realx (ncid,varid,strt4,cnt4,lhflxobs)
        1148           0 :          have_lhflx = .true.
        1149             :       endif
        1150             :    else
        1151           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
        1152           0 :       call wrap_get_vara_realx (ncid,varid,strt4,cnt4,lhflxobs)
        1153           0 :       have_lhflx = .true.
        1154             :    endif
        1155             :
        1156           0 :    status = nf90_inq_varid( ncid, 'shflx', varid   )
        1157           0 :    if ( status /= nf90_noerr ) then
        1158           0 :       status = nf90_inq_varid( ncid, 'sh', varid   )
        1159           0 :       if ( status /= nf90_noerr ) then
        1160           0 :         have_shflx = .false.
        1161             :       else
        1162           0 :          call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
        1163           0 :         call wrap_get_vara_realx (ncid,varid,strt4,cnt4,shflxobs)
        1164           0 :         have_shflx = .true.
        1165             :       endif
        1166             :    else
        1167           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
        1168           0 :       call wrap_get_vara_realx (ncid,varid,strt4,cnt4,shflxobs)
        1169           0 :       have_shflx = .true.
        1170             :    endif
        1171             :
        1172             :    ! If REPLAY is used, then need to read in the global
        1173             :    !   energy fixer
        1174           0 :    status = nf90_inq_varid( ncid, 'heat_glob', varid   )
        1175           0 :    if (status /= nf90_noerr) then
        1176           0 :       have_heat_glob = .false.
        1177             :    else
        1178           0 :       call wrap_get_vara_realx (ncid,varid,strt4,cnt4,heat_glob_scm)
        1179           0 :       have_heat_glob = .true.
        1180             :    endif
        1181             :
        1182             : !
        1183             : !     fill in 3d forcing variables if we have both horizontal
        1184             : !     and vertical components, but not the 3d
        1185             : !
        1186           0 :    if ( .not. have_cnst(1) .and. have_divq .and. have_vertdivq ) then
        1187           0 :       do k=1,plev
        1188           0 :          do m=1,pcnst
        1189           0 :             divq3d(k,m) = divq(k,m) + vertdivq(k,m)
        1190             :          enddo
        1191             :       enddo
        1192           0 :       have_divq3d = .true.
        1193             :    endif
        1194             :
        1195           0 :    if ( .not. have_divt3d .and. have_divt .and. have_vertdivt ) then
        1196           0 :       if (masterproc) write(iulog,*) sub//'Don''t have divt3d - using divt and vertdivt'
        1197           0 :       do k=1,plev
        1198           0 :          divt3d(k) = divt(k) + vertdivt(k)
        1199             :       enddo
        1200           0 :       have_divt3d = .true.
        1201             :    endif
        1202             : !
        1203             : !     make sure that use_3dfrc flag is set to true if we only have
        1204             : !     3d forcing available
        1205             : !
        1206           0 :    if (scm_use_3dfrc) then
        1207           0 :       if (have_divt3d .and. have_divq3d) then
        1208           0 :          use_3dfrc = .true.
        1209             :       else
        1210           0 :          call endrun(sub//':ERROR :IOP file must have both divt3d and divq3d forcing when scm_use_3dfrc is set to .true.')
        1211             :       endif
        1212             :    endif
        1213             :
        1214           0 :    status =  nf90_inq_varid( ncid, 'beta', varid   )
        1215           0 :    if ( status /= nf90_noerr ) then
        1216           0 :       betacam = 0._r8
        1217             :    else
        1218           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
        1219           0 :       status = nf90_get_var(ncid, varid, srf(1), strt4)
        1220           0 :       betacam=srf(1)
        1221             :    endif
        1222             :
        1223           0 :    status =  nf90_inq_varid( ncid, 'fixmas', varid   )
        1224           0 :    if ( status /= nf90_noerr ) then
        1225           0 :       fixmascam=1.0_r8
        1226             :    else
        1227           0 :       call get_start_count(ncid, varid, scmlat, scmlon, ioptimeidx, strt4, cnt4)
        1228           0 :       status = nf90_get_var(ncid, varid, srf(1), strt4)
        1229           0 :       fixmascam=srf(1)
        1230             :    endif
        1231             :
        1232           0 :    status = nf90_close( ncid )
        1233             :
        1234           0 :    deallocate(dplevs)
        1235             :
        1236           0 : end subroutine readiopdata
        1237             :
        1238           0 : subroutine setiopupdate
        1239             :
        1240             : !-----------------------------------------------------------------------
        1241             : !
        1242             : ! Open and read netCDF file to extract time information
        1243             : !
        1244             : !---------------------------Code history--------------------------------
        1245             : !
        1246             : ! Written by John Truesdale    August, 1996
        1247             : !
        1248             : !-----------------------------------------------------------------------
        1249             :   implicit none
        1250             :
        1251             :   character(len=*), parameter ::  sub = "setiopupdate"
        1252             :
        1253             : !------------------------------Locals-----------------------------------
        1254             :
        1255             :    integer :: next_date, next_sec
        1256             :    integer :: ncsec,ncdate                      ! current time of day,date
        1257             :    integer :: yr, mon, day                      ! year, month, and day component
        1258             : !------------------------------------------------------------------------------
        1259             :
        1260           0 :    call get_curr_date(yr,mon,day,ncsec)
        1261           0 :    ncdate=yr*10000 + mon*100 + day
        1262             :
        1263             : !------------------------------------------------------------------------------
        1264             : !     Check if iop data needs to be updated and set doiopupdate accordingly
        1265             : !------------------------------------------------------------------------------
        1266             :
        1267           0 :    if ( is_first_step() ) then
        1268           0 :       doiopupdate = .true.
        1269             :
        1270             :    else
        1271             :
        1272           0 :       call timemgr_time_inc(bdate, 0, next_date, next_sec, inc_s=tsec(iopTimeIdx+1))
        1273           0 :       if ( ncdate > next_date .or. (ncdate == next_date &
        1274             :          .and. ncsec >= next_sec)) then
        1275           0 :          doiopupdate = .true.
        1276             :          ! check to see if we need to move iopindex ahead more than 1 step
        1277           0 :          do while ( ncdate > next_date .or. (ncdate == next_date .and. ncsec >= next_sec))
        1278           0 :             iopTimeIdx = iopTimeIdx + 1
        1279           0 :             call timemgr_time_inc(bdate, 0, next_date, next_sec, inc_s=tsec(iopTimeIdx+1))
        1280             :          end do
        1281             : #if DEBUG > 2
        1282             :          if (masterproc) write(iulog,*) sub//'nstep = ',get_nstep()
        1283             :          if (masterproc) write(iulog,*) sub//'ncdate=',ncdate,' ncsec=',ncsec
        1284             :          if (masterproc) write(iulog,*) sub//'next_date=',next_date,' next_sec=',next_sec
        1285             :          if (masterproc) write(iulog,*) sub//':******* do iop update'
        1286             : #endif
        1287             :       else
        1288           0 :          doiopupdate = .false.
        1289             :       end if
        1290             :    endif                     ! if (endstep = 1 )
        1291             : !
        1292             : !     make sure we're
        1293             : !     not going past end of iop data
        1294             : !
        1295           0 :    if ( ncdate > last_date .or. (ncdate == last_date &
        1296             :       .and. ncsec > last_sec))  then
        1297           0 :       call endrun(sub//':ERROR: Reached the end of the time varient dataset')
        1298             :    endif
        1299             :
        1300             : #if DEBUG > 1
        1301             :    if (masterproc) write(iulog,*) sub//':iop time index = ' , ioptimeidx
        1302             : #endif
        1303             :
        1304           0 : end subroutine setiopupdate
        1305             :
        1306             : !===============================================================================
        1307             :
        1308           0 : subroutine plevs0 (nver, ps, ps0, hyam, hybm, hyai, hybi, pint    ,pmid    ,pdel)
        1309             :
        1310             : !-----------------------------------------------------------------------
        1311             : !
        1312             : ! Purpose:
        1313             : ! Define the pressures of the interfaces and midpoints from the
        1314             : ! coordinate definitions and the surface pressure.
        1315             : !
        1316             : ! Author: B. Boville
        1317             : !
        1318             : !-----------------------------------------------------------------------
        1319             :   implicit none
        1320             :
        1321             :
        1322             : !-----------------------------------------------------------------------
        1323             :   integer , intent(in)  :: nver         ! vertical dimension
        1324             :   real(r8), intent(in)  :: ps           ! Surface pressure (pascals)
        1325             :   real(r8), intent(in)  :: ps0          ! reference pressure (pascals)
        1326             :   real(r8), intent(in)  :: hyam(plev)   ! hybrid midpoint coef
        1327             :   real(r8), intent(in)  :: hybm(plev)   ! hybrid midpoint coef
        1328             :   real(r8), intent(in)  :: hyai(plevp)  ! hybrid interface coef
        1329             :   real(r8), intent(in)  :: hybi(plevp)  ! hybrid interface coef
        1330             :   real(r8), intent(out) :: pint(nver+1) ! Pressure at model interfaces
        1331             :   real(r8), intent(out) :: pmid(nver)   ! Pressure at model levels
        1332             :   real(r8), intent(out) :: pdel(nver)   ! Layer thickness (pint(k+1) - pint(k))
        1333             : !-----------------------------------------------------------------------
        1334             :
        1335             : !---------------------------Local workspace-----------------------------
        1336             :   integer :: k             ! Longitude, level indices
        1337             : !-----------------------------------------------------------------------
        1338             : !
        1339             : ! Set interface pressures
        1340             : !
        1341             : !$OMP PARALLEL DO PRIVATE (K)
        1342           0 :   do k=1,nver+1
        1343           0 :      pint(k) = hyai(k)*ps0 + hybi(k)*ps
        1344             :   end do
        1345             : !
        1346             : ! Set midpoint pressures and layer thicknesses
        1347             : !
        1348             : !$OMP PARALLEL DO PRIVATE (K)
        1349           0 :   do k=1,nver
        1350           0 :      pmid(k) = hyam(k)*ps0 + hybm(k)*ps
        1351           0 :      pdel(k) = pint(k+1) - pint(k)
        1352             :   end do
        1353             :
        1354           0 : end subroutine plevs0
        1355             :
        1356           0 : subroutine scmiop_flbc_inti ( co2vmr, ch4vmr, n2ovmr, f11vmr, f12vmr )
        1357             :   !-----------------------------------------------------------------------
        1358             :   !
        1359             :   ! Purpose:
        1360             :   ! Get start count for variable
        1361             :   !
        1362             :   !-----------------------------------------------------------------------
        1363             :
        1364             :   implicit none
        1365             :
        1366             :   real(r8), intent(out)  :: co2vmr, ch4vmr, n2ovmr, f11vmr, f12vmr
        1367             :
        1368             :   !-----------------------------------------------------------------------
        1369             :
        1370           0 :   co2vmr=co2vmrobs(1)
        1371           0 :   ch4vmr=ch4vmrobs(1)
        1372           0 :   n2ovmr=n2ovmrobs(1)
        1373           0 :   f11vmr=f11vmrobs(1)
        1374           0 :   f12vmr=f12vmrobs(1)
        1375           0 : end subroutine scmiop_flbc_inti
        1376             :
        1377           0 : subroutine get_start_count (ncid    ,varid  ,scmlat, scmlon, timeidx, start    ,count)
        1378             :
        1379             :   !-----------------------------------------------------------------------
        1380             :   !
        1381             :   ! Purpose:
        1382             :   ! set global lower boundary conditions
        1383             :   !
        1384             :   !-----------------------------------------------------------------------
        1385             :
        1386             :   implicit none
        1387             :
        1388             :   character(len=*), parameter ::  sub = "get_start_count"
        1389             :
        1390             : !-----------------------------------------------------------------------
        1391             :   integer , intent(in)    :: ncid         ! file id
        1392             :   integer , intent(in)    :: varid        ! variable id
        1393             :   integer , intent(in)    :: TimeIdx      ! time index
        1394             :   real(r8), intent(in)    :: scmlat,scmlon! scm lat/lon
        1395             :   integer , intent(out) :: start(:),count(:)
        1396             :
        1397             : !---------------------------Local workspace-----------------------------
        1398             :   integer            :: dims_set,nlev,var_ndims
        1399             :   logical            :: usable_var
        1400             :   character(len=cl)  :: dim_name
        1401             :   integer            :: var_dimIDs( NF90_MAX_VAR_DIMS )
        1402             :   real(r8)           :: closelat,closelon
        1403             :   integer            :: latidx,lonidx,status,i
        1404             : !-----------------------------------------------------------------------
        1405             :
        1406           0 :    call shr_scam_GetCloseLatLon(ncid,scmlat,scmlon,closelat,closelon,latidx,lonidx)
        1407             :
        1408           0 :    STATUS = NF90_INQUIRE_VARIABLE( NCID, varID, ndims=var_ndims )
        1409             : !
        1410             : !     surface variables
        1411             : !
        1412           0 :    if ( var_ndims == 0 ) then
        1413           0 :       call endrun(sub//':ERROR: var_ndims is 0 for varid:',varid)
        1414             :    endif
        1415             :
        1416           0 :    STATUS = NF90_INQUIRE_VARIABLE( NCID, varID, dimids=var_dimIDs)
        1417           0 :    if ( STATUS /= NF90_NOERR ) then
        1418           0 :       write(iulog,* ) sub//'ERROR - Cant get dimension IDs for varid', varid
        1419           0 :       call endrun(sub//':ERROR: Cant get dimension IDs for varid',varid)
        1420             :    endif
        1421             : !
        1422             : !     Initialize the start and count arrays
        1423             : !
        1424           0 :    dims_set = 0
        1425           0 :    nlev = 1
        1426           0 :    do i =  var_ndims, 1, -1
        1427             :
        1428           0 :       usable_var = .false.
        1429           0 :       STATUS = NF90_INQUIRE_DIMENSION( NCID, var_dimIDs( i ), dim_name )
        1430             :
        1431           0 :       if ( trim(dim_name) == 'lat' ) then
        1432           0 :          start( i ) =  latIdx
        1433           0 :          count( i ) = 1           ! Extract a single value
        1434           0 :          dims_set = dims_set + 1
        1435           0 :          usable_var = .true.
        1436             :       endif
        1437             :
        1438           0 :       if ( trim(dim_name) == 'lon' .or. trim(dim_name) == 'ncol' .or. trim(dim_name) == 'ncol_d' ) then
        1439           0 :          start( i ) = lonIdx
        1440           0 :          count( i ) = 1           ! Extract a single value
        1441           0 :          dims_set = dims_set + 1
        1442           0 :          usable_var = .true.
        1443             :       endif
        1444             :
        1445           0 :       if ( trim(dim_name) == 'lev' ) then
        1446           0 :          STATUS = NF90_INQUIRE_DIMENSION( NCID, var_dimIDs( i ), len=nlev )
        1447           0 :          start( i ) = 1
        1448           0 :          count( i ) = nlev       ! Extract all levels
        1449           0 :          dims_set = dims_set + 1
        1450           0 :          usable_var = .true.
        1451             :       endif
        1452             :
        1453           0 :       if ( trim(dim_name) == 'ilev' ) then
        1454           0 :          STATUS = NF90_INQUIRE_DIMENSION( NCID, var_dimIDs( i ), len=nlev )
        1455           0 :          start( i ) = 1
        1456           0 :          count( i ) = nlev        ! Extract all levels
        1457           0 :          dims_set = dims_set + 1
        1458           0 :          usable_var = .true.
        1459             :       endif
        1460             :
        1461           0 :       if ( trim(dim_name) == 'time' .OR. trim(dim_name) == 'tsec' ) then
        1462           0 :          start( i ) = TimeIdx
        1463           0 :          count( i ) = 1           ! Extract a single value
        1464           0 :          dims_set = dims_set + 1
        1465           0 :          usable_var = .true.
        1466             :       endif
        1467             :    end do
        1468           0 :  end subroutine get_start_count
        1469             :
        1470             : !=========================================================================
        1471           0 : subroutine setiopupdate_init
        1472             :
        1473             : !-----------------------------------------------------------------------
        1474             : !
        1475             : ! Open and read netCDF file to extract time information
        1476             : !   This subroutine should be called at the first SCM time step
        1477             : !
        1478             : !---------------------------Code history--------------------------------
        1479             : !
        1480             : ! Written by John Truesdale    August, 1996
        1481             : ! Modified for E3SM by  Peter Bogenschutz 2017 - onward
        1482             : !
        1483             : !-----------------------------------------------------------------------
        1484             :   implicit none
        1485             :
        1486             : !------------------------------Locals-----------------------------------
        1487             :
        1488             :    integer :: NCID,i
        1489             :    integer :: tsec_varID, time_dimID
        1490             :    integer :: bdate_varID
        1491             :    integer :: STATUS
        1492             :    integer :: next_date, next_sec
        1493             :    integer :: ncsec,ncdate                      ! current time of day,date
        1494             :    integer :: yr, mon, day                      ! year, month, and day component
        1495             :    integer :: start_ymd,start_tod
        1496             :
        1497             :    character(len=*), parameter ::  sub = "setiopupdate_init"
        1498             : !!------------------------------------------------------------------------------
        1499             :
        1500             :    ! Open and read pertinent information from the IOP file
        1501             :
        1502             :    call handle_ncerr( nf90_open (iopfile, 0, ncid),&
        1503           0 :         'ERROR - scamMod.F90:setiopupdate_init Failed to open iop file', __LINE__)
        1504             :
        1505             :    ! Read time (tsec) variable
        1506             :
        1507           0 :     STATUS = NF90_INQ_VARID( NCID, 'tsec', tsec_varID )
        1508           0 :     if ( STATUS /= NF90_NOERR ) then
        1509           0 :        write(iulog,*)sub//':ERROR: Cant get variable ID for tsec'
        1510           0 :        STATUS = NF90_CLOSE ( NCID )
        1511           0 :        call endrun(sub//':ERROR: Cant get variable ID for tsec')
        1512             :     end if
        1513             :
        1514           0 :     STATUS = NF90_INQ_VARID( NCID, 'bdate', bdate_varID )
        1515           0 :     if ( STATUS /= NF90_NOERR ) then
        1516           0 :        STATUS = NF90_INQ_VARID( NCID, 'basedate', bdate_varID )
        1517           0 :        if ( STATUS /= NF90_NOERR ) then
        1518           0 :           write(iulog,*)'ERROR - setiopupdate:Cant get variable ID for base date'
        1519           0 :           STATUS = NF90_CLOSE ( NCID )
        1520           0 :           call endrun(sub//':ERROR: Cant get variable ID for base date')
        1521             :        endif
        1522             :     endif
        1523             :
        1524           0 :     STATUS = NF90_INQ_DIMID( NCID, 'time', time_dimID )
        1525           0 :     if ( STATUS /= NF90_NOERR )  then
        1526           0 :        STATUS = NF90_INQ_DIMID( NCID, 'tsec', time_dimID )
        1527           0 :        if ( STATUS /= NF90_NOERR )  then
        1528           0 :           write(iulog,* )'ERROR - setiopupdate:Could not find variable dim ID for time'
        1529           0 :           STATUS = NF90_CLOSE ( NCID )
        1530           0 :           call endrun(sub//':ERROR:Could not find variable dim ID for time')
        1531             :        end if
        1532             :     end if
        1533             :
        1534           0 :     if ( STATUS /= NF90_NOERR )  &
        1535           0 :        write(iulog,*)'ERROR - setiopupdate:Cant get variable dim ID for time'
        1536             :
        1537           0 :     STATUS = NF90_INQUIRE_DIMENSION( NCID, time_dimID, len=ntime )
        1538           0 :     if ( STATUS /= NF90_NOERR )then
        1539           0 :        write(iulog,*)'ERROR - setiopupdate:Cant get time dimlen'
        1540             :     endif
        1541             :
        1542           0 :     if (.not.allocated(tsec)) allocate(tsec(ntime))
        1543             :
        1544           0 :     STATUS = NF90_GET_VAR( NCID, tsec_varID, tsec )
        1545           0 :     if ( STATUS /= NF90_NOERR )then
        1546           0 :        write(iulog,*)'ERROR - setiopupdate:Cant get variable tsec'
        1547             :     endif
        1548           0 :     STATUS = NF90_GET_VAR( NCID, bdate_varID, bdate )
        1549           0 :     if ( STATUS /= NF90_NOERR )then
        1550           0 :        write(iulog,*)'ERROR - setiopupdate:Cant get variable bdate'
        1551             :     endif
        1552             :
        1553             :     ! Close the netCDF file
        1554           0 :     STATUS = NF90_CLOSE( NCID )
        1555             :
        1556             :     ! determine the last date in the iop dataset
        1557             :
        1558           0 :     call timemgr_time_inc(bdate, 0, last_date, last_sec, inc_s=tsec(ntime))
        1559             :
        1560             :     ! set the iop dataset index
        1561           0 :     iopTimeIdx=0
        1562           0 :     do i=1,ntime           ! set the first ioptimeidx
        1563           0 :        call timemgr_time_inc(bdate, 0, next_date, next_sec, inc_s=tsec(i))
        1564           0 :        call get_start_date(yr,mon,day,start_tod)
        1565           0 :        start_ymd = yr*10000 + mon*100 + day
        1566             :
        1567           0 :        if ( start_ymd > next_date .or. (start_ymd == next_date &
        1568           0 :           .and. start_tod >= next_sec)) then
        1569           0 :           iopTimeIdx = i
        1570             :        endif
        1571             :     enddo
        1572             :
        1573           0 :     call get_curr_date(yr,mon,day,ncsec)
        1574           0 :     ncdate=yr*10000 + mon*100 + day
        1575             :
        1576           0 :     if (iopTimeIdx == 0.or.iopTimeIdx >= ntime) then
        1577           0 :        call timemgr_time_inc(bdate, 0, next_date, next_sec, inc_s=tsec(1))
        1578           0 :        write(iulog,*) 'Error::setiopupdate: Current model time does not fall within IOP period'
        1579           0 :        write(iulog,*) ' Current CAM Date is ',ncdate,' and ',ncsec,' seconds'
        1580           0 :        write(iulog,*) ' IOP start is        ',next_date,' and ',next_sec,'seconds'
        1581           0 :        write(iulog,*) ' IOP end is          ',last_date,' and ',last_sec,'seconds'
        1582           0 :        call endrun(sub//':ERROR: Current model time does not fall within IOP period')
        1583             :     endif
        1584             :
        1585           0 :     doiopupdate = .true.
        1586             :
        1587           0 : end subroutine setiopupdate_init
        1588             :
        1589             : end module scamMod

Generated by: LCOV version 1.14