diff --git a/datm/CMakeLists.txt b/datm/CMakeLists.txt index b72fd41bdf..61785d7d1c 100644 --- a/datm/CMakeLists.txt +++ b/datm/CMakeLists.txt @@ -3,7 +3,8 @@ project(datm Fortran) add_library(datm atm_comp_nuopc.F90 datm_datamode_clmncep_mod.F90 datm_datamode_core2_mod.F90 - datm_datamode_jra_mod.F90) + datm_datamode_jra_mod.F90 + datm_datamode_era5_mod.F90) add_dependencies(datm dshr streams) target_include_directories (datm PUBLIC ${ESMF_F90COMPILEPATHS}) diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index 22095cdd71..2801a50e07 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -43,6 +43,11 @@ module atm_comp_nuopc use datm_datamode_clmncep_mod , only : datm_datamode_clmncep_advance use datm_datamode_clmncep_mod , only : datm_datamode_clmncep_restart_write use datm_datamode_clmncep_mod , only : datm_datamode_clmncep_restart_read + use datm_datamode_era5_mod , only : datm_datamode_era5_advertise + use datm_datamode_era5_mod , only : datm_datamode_era5_init_pointers + use datm_datamode_era5_mod , only : datm_datamode_era5_advance + use datm_datamode_era5_mod , only : datm_datamode_era5_restart_write + use datm_datamode_era5_mod , only : datm_datamode_era5_restart_read implicit none private ! except @@ -275,7 +280,8 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if ( trim(datamode) == 'CORE2_NYF' .or. & trim(datamode) == 'CORE2_IAF' .or. & trim(datamode) == 'CORE_IAF_JRA' .or. & - trim(datamode) == 'CLMNCEP') then + trim(datamode) == 'CLMNCEP' .or. & + trim(datamode) == 'ERA5') then else call shr_sys_abort(' ERROR illegal datm datamode = '//trim(datamode)) endif @@ -293,6 +299,9 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) call datm_datamode_clmncep_advertise(exportState, fldsExport, flds_scalar_name, & flds_co2, flds_wiso, flds_presaero, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case ('ERA5') + call datm_datamode_era5_advertise(exportState, fldsExport, flds_scalar_name, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return end select end subroutine InitializeAdvertise @@ -528,6 +537,9 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe case('CLMNCEP') call datm_datamode_clmncep_init_pointers(importState, exportState, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('ERA5') + call datm_datamode_era5_init_pointers(exportState, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return end select ! Read restart if needed @@ -539,6 +551,8 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe call datm_datamode_jra_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) case('CLMNCEP') call datm_datamode_clmncep_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) + case('ERA5') + call datm_datamode_era5_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) end select end if @@ -581,6 +595,10 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe case('CLMNCEP') call datm_datamode_clmncep_advance(importstate, exportstate, masterproc, logunit, mpicom, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('ERA5') + call datm_datamode_era5_advance(exportstate, masterproc, logunit, mpicom, target_ymd, & + target_tod, sdat%model_calendar, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return end select ! Write restarts if needed @@ -598,6 +616,10 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe call datm_datamode_clmncep_restart_write(case_name, inst_suffix, target_ymd, target_tod, & logunit, mpicom, my_task, sdat) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('ERA5') + call datm_datamode_era5_restart_write(case_name, inst_suffix, target_ymd, target_tod, & + logunit, mpicom, my_task, sdat) + if (ChkErr(rc,__LINE__,u_FILE_u)) return end select end if @@ -606,7 +628,7 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe ! Diagnostics if (diagnose_data) then - call dshr_state_diagnose(exportState, flds_scalar_name, subname//':ES',rc=rc) + call dshr_state_diagnose(exportState, flds_scalar_name, subname//':ES', rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end if diff --git a/datm/cime_config/config_component.xml b/datm/cime_config/config_component.xml index c9448a0d15..1c0522bf87 100644 --- a/datm/cime_config/config_component.xml +++ b/datm/cime_config/config_component.xml @@ -10,7 +10,7 @@ This file may have atm desc entries. --> - Data driven ATM + Data driven ATM QIAN data set QIAN with water isotopes CRUNCEP data set @@ -23,6 +23,7 @@ COREv2 interannual forcing interannual JRA55 forcing interannual JRA55 forcing, v1.4, through 2018 + ERA5 interannual forcing @@ -36,7 +37,7 @@ char - CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,CORE_IAF_JRA_1p4_2018 + CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,CLM1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,CORE_IAF_JRA_1p4_2018,ERA5 CORE2_NYF run_component_datm env_run.xml @@ -56,6 +57,7 @@ CLMNLDAS2 CLM1PT CPLHIST + ERA5 diff --git a/datm/cime_config/namelist_definition_datm.xml b/datm/cime_config/namelist_definition_datm.xml index 6b8360039e..77bcbb4210 100644 --- a/datm/cime_config/namelist_definition_datm.xml +++ b/datm/cime_config/namelist_definition_datm.xml @@ -30,6 +30,7 @@ CORE2_IAF = CORE2 intra-annual year forcing (for forcing POP and CICE) CORE_IAF_JRA = JRA55 intra-annual year forcing (for forcing POP and CICE) CORE_IAF_JRA_1p4_2018 = JRA55 intra-annual year forcing, v1.4, through 2018 (for forcing POP and CICE) + ERA5 = ERA5 intra-annual year forcing CPLHIST = Streams for lnd or ocn/ice forcing used for spinup Currently the following optional streams are supported @@ -239,6 +240,9 @@ CORE2_IAF.NCEP.DENS.SOFS,CORE2_IAF.NCEP.PSLV.SOFS,CORE2_IAF.PREC.SOFS.DAILY,CORE2_IAF.LWDN.SOFS.DAILY,CORE2_IAF.SWDN.SOFS.DAILY,CORE2_IAF.SWUP.SOFS.DAILY,CORE2_IAF.SHUM.SOFS.6HOUR,CORE2_IAF.TBOT.SOFS.6HOUR,CORE2_IAF.U.SOFS.6HOUR,CORE2_IAF.V.SOFS.6HOUR,CORE2_IAF.CORE2.ArcFactor + + ERA5_HOURLY + CPLHISTForcing.Solar,CPLHISTForcing.nonSolarFlux,CPLHISTForcing.State3hr,CPLHISTForcing.State1hr @@ -440,6 +444,12 @@ $DIN_LOC_ROOT/share/meshes/T62_040121_ESMFmesh_c20190714.nc + + + + + $DIN_LOC_ROOT/share/meshes/TL639_200618_ESMFmesh.nc + @@ -1763,6 +1773,23 @@ $DIN_LOC_ROOT/atm/datm7/CORE2/CORE2.t_10.ArcFactor.T62.1997-2004.nc + + + + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.01.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.02.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.03.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.04.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.05.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.06.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.07.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.08.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.09.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.10.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.11.200618.nc + $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.12.200618.nc + + @@ -2172,6 +2199,32 @@ TarcFactor tarcf + + + + + u10 Sa_u + v10 Sa_v + t2m Sa_tbot + d2m Sa_tdew + msl Sa_pslv + sp Sa_pbot + tp Faxa_rain + cp Faxa_rainc + lsp Faxa_rainl + csf Faxa_snowc + lsf Faxa_snowl + ssrd Faxa_swdn + strd Faxa_lwdn + aluvp Faxa_swvdr + aluvd Faxa_swvdf + alnip Faxa_swndr + alnid Faxa_swndf + sshf Faxa_sen + slhf Faxa_lat + ewss Faxa_taux + nsss Faxa_tauy + @@ -2285,6 +2338,7 @@ 1 1 1 + 1900 1850 2015 1979 @@ -2347,6 +2401,7 @@ 1958 1958 1958 + 2019 1850 2015 2006 @@ -2407,6 +2462,7 @@ 2016 2016 2016 + 2019 2014 2500 2012 @@ -2600,6 +2656,7 @@ u:v u:v u:v + u:v,taux:tauy @@ -2630,7 +2687,7 @@ char datm datm_nml - CLMNCEP,COPYALL,CORE2_NYF,CORE2_IAF,CORE_IAF_JRA + CLMNCEP,COPYALL,CORE2_NYF,CORE2_IAF,CORE_IAF_JRA,ERA5 general method that operates on the data. this is generally implemented in the data models but is set in the strdata method for @@ -2669,6 +2726,8 @@ mode replicates code previously found in CLM (circa 2005), before the LMWG started using the CCSM flux coupler and data models to do active-land-only simulations. + datamode = "ERA5" + Fifth generation ECMWF atmospheric reanalysis of the global climate COPYALL @@ -2676,6 +2735,7 @@ CORE2_NYF CORE2_IAF CORE_IAF_JRA + ERA5 COPYALL diff --git a/datm/datm_datamode_era5_mod.F90 b/datm/datm_datamode_era5_mod.F90 new file mode 100644 index 0000000000..6c924d101d --- /dev/null +++ b/datm/datm_datamode_era5_mod.F90 @@ -0,0 +1,379 @@ +module datm_datamode_era5_mod + + use ESMF + use NUOPC , only : NUOPC_Advertise + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_sys_mod , only : shr_sys_abort + use shr_precip_mod , only : shr_precip_partition_rain_snow_ramp + use shr_mpi_mod , only : shr_mpi_max + use shr_const_mod , only : shr_const_tkfrz, shr_const_rhofw, shr_const_rdair + use dshr_methods_mod , only : dshr_state_getfldptr, chkerr + use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_get_stream_pointer + use dshr_mod , only : dshr_restart_read, dshr_restart_write + use dshr_strdata_mod , only : shr_strdata_type + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add + + implicit none + private ! except + + public :: datm_datamode_era5_advertise + public :: datm_datamode_era5_init_pointers + public :: datm_datamode_era5_advance + public :: datm_datamode_era5_restart_write + public :: datm_datamode_era5_restart_read + private :: datm_eSat ! determine saturation vapor pressure + + ! export state data + real(r8), pointer :: Sa_z(:) => null() + real(r8), pointer :: Sa_u(:) => null() + real(r8), pointer :: Sa_v(:) => null() + real(r8), pointer :: Sa_tbot(:) => null() + real(r8), pointer :: Sa_ptem(:) => null() + real(r8), pointer :: Sa_shum(:) => null() + real(r8), pointer :: Sa_dens(:) => null() + real(r8), pointer :: Sa_pbot(:) => null() + real(r8), pointer :: Sa_pslv(:) => null() + real(r8), pointer :: Faxa_lwdn(:) => null() + real(r8), pointer :: Faxa_rain(:) => null() + real(r8), pointer :: Faxa_rainc(:) => null() + real(r8), pointer :: Faxa_rainl(:) => null() + real(r8), pointer :: Faxa_snowc(:) => null() + real(r8), pointer :: Faxa_snowl(:) => null() + real(r8), pointer :: Faxa_swndr(:) => null() + real(r8), pointer :: Faxa_swndf(:) => null() + real(r8), pointer :: Faxa_swvdr(:) => null() + real(r8), pointer :: Faxa_swvdf(:) => null() + real(r8), pointer :: Faxa_swnet(:) => null() + real(r8), pointer :: Faxa_swdn(:) => null() + real(r8), pointer :: Faxa_sen(:) => null() + real(r8), pointer :: Faxa_lat(:) => null() + real(r8), pointer :: Faxa_taux(:) => null() + real(r8), pointer :: Faxa_tauy(:) => null() + + ! stream data + real(r8), pointer :: strm_tdew(:) => null() + + logical :: atm_prognostic = .false. + real(r8) :: tbotmax ! units detector + real(r8) :: tdewmax ! units detector + + real(r8) , parameter :: tKFrz = SHR_CONST_TKFRZ + real(r8) , parameter :: rdair = SHR_CONST_RDAIR ! dry air gas constant ~ J/K/kg + real(r8) , parameter :: rhofw = SHR_CONST_RHOFW ! density of fresh water ~ kg/m^3 + + character(*), parameter :: nullstr = 'undefined' + character(*), parameter :: rpfile = 'rpointer.atm' + character(*), parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine datm_datamode_era5_advertise(exportState, fldsexport, & + flds_scalar_name, rc) + + ! input/output variables + type(esmf_State) , intent(inout) :: exportState + type(fldlist_type) , pointer :: fldsexport + character(len=*) , intent(in) :: flds_scalar_name + integer , intent(out) :: rc + + ! local variables + type(fldlist_type), pointer :: fldList + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + call dshr_fldList_add(fldsExport, 'Sa_z' ) + call dshr_fldList_add(fldsExport, 'Sa_u' ) + call dshr_fldList_add(fldsExport, 'Sa_v' ) + call dshr_fldList_add(fldsExport, 'Sa_tbot' ) + call dshr_fldList_add(fldsExport, 'Sa_ptem' ) + call dshr_fldList_add(fldsExport, 'Sa_dens' ) + call dshr_fldList_add(fldsExport, 'Sa_pslv' ) + call dshr_fldList_add(fldsExport, 'Sa_pbot' ) + call dshr_fldList_add(fldsExport, 'Sa_shum' ) + call dshr_fldList_add(fldsExport, 'Faxa_rain' ) + call dshr_fldList_add(fldsExport, 'Faxa_rainc' ) + call dshr_fldList_add(fldsExport, 'Faxa_rainl' ) + call dshr_fldList_add(fldsExport, 'Faxa_snowc' ) + call dshr_fldList_add(fldsExport, 'Faxa_snowl' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swnet' ) + call dshr_fldList_add(fldsExport, 'Faxa_lwdn' ) + call dshr_fldList_add(fldsExport, 'Faxa_swdn' ) + call dshr_fldList_add(fldsExport, 'Faxa_sen' ) + call dshr_fldList_add(fldsExport, 'Faxa_lat' ) + call dshr_fldList_add(fldsExport, 'Faxa_taux' ) + call dshr_fldList_add(fldsExport, 'Faxa_tauy' ) + + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(datm_comp_advertise): Fr_atm'//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + end subroutine datm_datamode_era5_advertise + + !=============================================================================== + subroutine datm_datamode_era5_init_pointers(exportState, sdat, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + type(shr_strdata_type) , intent(in) :: sdat + integer , intent(out) :: rc + + ! local variables + type(ESMF_StateItem_Flag) :: itemFlag + character(len=*), parameter :: subname='(datm_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! initialize pointers for module level stream arrays + call shr_strdata_get_stream_pointer( sdat, 'Sa_tdew' , strm_tdew , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! get export state pointers + call dshr_state_getfldptr(exportState, 'Sa_z' , fldptr1=Sa_z , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_tbot' , fldptr1=Sa_tbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pbot' , fldptr1=Sa_pbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_ptem' , fldptr1=Sa_ptem , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_shum' , fldptr1=Sa_shum , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_dens' , fldptr1=Sa_dens , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rain' , fldptr1=Faxa_rain , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rainc' , fldptr1=Faxa_rainc , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rainl' , fldptr1=Faxa_rainl , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snowc' , fldptr1=Faxa_snowc , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snowl' , fldptr1=Faxa_snowl , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdr' , fldptr1=Faxa_swvdr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdf' , fldptr1=Faxa_swvdf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndr' , fldptr1=Faxa_swndr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndf' , fldptr1=Faxa_swndf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swnet' , fldptr1=Faxa_swnet , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swdn' , fldptr1=Faxa_swdn , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_lwdn' , fldptr1=Faxa_lwdn , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_sen' , fldptr1=Faxa_sen , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_lat' , fldptr1=Faxa_lat , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_taux' , fldptr1=Faxa_taux , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_tauy' , fldptr1=Faxa_tauy , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine datm_datamode_era5_init_pointers + + !=============================================================================== + subroutine datm_datamode_era5_advance(exportstate, masterproc, logunit, mpicom, target_ymd, target_tod, model_calendar, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + logical , intent(in) :: masterproc + integer , intent(in) :: logunit + integer , intent(in) :: mpicom + integer , intent(in) :: target_ymd + integer , intent(in) :: target_tod + character(len=*) , intent(in) :: model_calendar + integer , intent(out) :: rc + + ! local variables + logical :: first_time = .true. + integer :: n,kf ! indices + integer :: lsize ! size of attr vect + real(r8) :: rtmp + real(r8) :: swndr + real(r8) :: swndf + real(r8) :: swvdr + real(r8) :: swvdf + real(r8) :: ratio_rvrf + real(r8) :: tbot, pbot + real(r8) :: vp + real(r8) :: ea, e, qsat, frac + character(len=*), parameter :: subname='(datm_datamode_era5_advance): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + lsize = size(strm_tdew) + + if (first_time) then + ! determine tbotmax (see below for use) + rtmp = maxval(Sa_tbot(:)) + call shr_mpi_max(rtmp, tbotmax, mpicom, 'datm_tbot', all=.true.) + if (masterproc) write(logunit,*) trim(subname),' tbotmax = ',tbotmax + + ! determine tdewmax (see below for use) + rtmp = maxval(strm_tdew(:)) + call shr_mpi_max(rtmp, tdewmax, mpicom, 'datm_tdew', all=.true.) + if (masterproc) write(logunit,*) trim(subname),' tdewmax = ',tdewmax + + ! reset first_time + first_time = .false. + end if + + do n = 1, lsize + !--- bottom layer height --- + Sa_z(n) = 10.0_r8 + + !--- temperature --- + if (tbotmax < 50.0_r8) Sa_tbot(n) = Sa_tbot(n) + tkFrz + ! Limit very cold forcing to 180K + Sa_tbot(n) = max(180._r8, Sa_tbot(n)) + Sa_ptem(n) = Sa_tbot(n) + + !--- specific humidity --- + tbot = Sa_tbot(n) + pbot = Sa_pbot(n) + if (tdewmax < 50.0_r8) strm_tdew(n) = strm_tdew(n) + tkFrz + e = datm_eSat(strm_tdew(n),tbot) + qsat = (0.622_r8 * e)/(pbot - 0.378_r8 * e) + Sa_shum(n) = qsat + + !--- density --- + vp = (Sa_shum(n)*pbot) / (0.622_r8 + 0.378_r8 * Sa_shum(n)) + Sa_dens(n) = (pbot - 0.378_r8 * vp) / (tbot*rdair) + + !--- shortwave radiation (Faxa_* basically holds albedo) --- + Faxa_swvdr(n) = Faxa_swdn(n)*Faxa_swvdr(n) + Faxa_swndr(n) = Faxa_swdn(n)*Faxa_swndr(n) + Faxa_swvdf(n) = Faxa_swdn(n)*Faxa_swvdf(n) + Faxa_swndf(n) = Faxa_swdn(n)*Faxa_swndf(n) + + !--- swnet: a diagnostic quantity --- + Faxa_swnet(n) = Faxa_swndr(n) + Faxa_swvdr(n) + Faxa_swndf(n) + Faxa_swvdf(n) + end do + + !---------------------------------------------------------- + ! unit conversions (temporal resolution is hourly) + !---------------------------------------------------------- + + ! convert J/m^2 to W/m^2 + Faxa_lwdn(:) = Faxa_lwdn(:)/3600.0_r8 + Faxa_swdn(:) = Faxa_swdn(:)/3600.0_r8 + Faxa_swvdr(:) = Faxa_swvdr(:)/3600.0_r8 + Faxa_swndr(:) = Faxa_swndr(:)/3600.0_r8 + Faxa_swvdf(:) = Faxa_swvdf(:)/3600.0_r8 + Faxa_swndf(:) = Faxa_swndf(:)/3600.0_r8 + Faxa_swnet(:) = Faxa_swnet(:)/3600.0_r8 + Faxa_sen(:) = Faxa_sen(:)/3600.0_r8 + Faxa_lat(:) = Faxa_lat(:)/3600.0_r8 + + ! convert m to kg/m^2/s + Faxa_rain(:) = Faxa_rain(:)/3600.0_r8*rhofw + Faxa_rainc(:) = Faxa_rainc(:)/3600.0_r8*rhofw + Faxa_rainl(:) = Faxa_rainl(:)/3600.0_r8*rhofw + Faxa_snowc(:) = Faxa_snowc(:)/3600.0_r8*rhofw + Faxa_snowl(:) = Faxa_snowl(:)/3600.0_r8*rhofw + + ! convert N/m^2 s to N/m^2 + Faxa_taux(:) = Faxa_taux(:)/3600.0_r8 + Faxa_tauy(:) = Faxa_tauy(:)/3600.0_r8 + + end subroutine datm_datamode_era5_advance + + !=============================================================================== + subroutine datm_datamode_era5_restart_write(case_name, inst_suffix, ymd, tod, & + logunit, mpicom, my_task, sdat) + + ! input/output variables + character(len=*) , intent(in) :: case_name + character(len=*) , intent(in) :: inst_suffix + integer , intent(in) :: ymd ! model date + integer , intent(in) :: tod ! model sec into model date + integer , intent(in) :: logunit + integer , intent(in) :: my_task + integer , intent(in) :: mpicom + type(shr_strdata_type) , intent(inout) :: sdat + !------------------------------------------------------------------------------- + + call dshr_restart_write(rpfile, case_name, 'datm', inst_suffix, ymd, tod, & + logunit, mpicom, my_task, sdat) + + end subroutine datm_datamode_era5_restart_write + + !=============================================================================== + subroutine datm_datamode_era5_restart_read(rest_filem, inst_suffix, logunit, my_task, mpicom, sdat) + + ! input/output arguments + character(len=*) , intent(inout) :: rest_filem + character(len=*) , intent(in) :: inst_suffix + integer , intent(in) :: logunit + integer , intent(in) :: my_task + integer , intent(in) :: mpicom + type(shr_strdata_type) , intent(inout) :: sdat + !------------------------------------------------------------------------------- + + call dshr_restart_read(rest_filem, rpfile, inst_suffix, nullstr, logunit, my_task, mpicom, sdat) + + end subroutine datm_datamode_era5_restart_read + + real(r8) function datm_eSat(tK,tKbot) + + !---------------------------------------------------------------------------- + ! use polynomials to calculate saturation vapor pressure and derivative with + ! respect to temperature: over water when t > 0 c and over ice when t <= 0 c + ! required to convert relative humidity to specific humidity + !---------------------------------------------------------------------------- + + ! input/output variables + real(r8),intent(in) :: tK ! temp used in polynomial calculation + real(r8),intent(in) :: tKbot ! bottom atm temp + + ! local variables + real(r8) :: t ! tK converted to Celcius + real(r8),parameter :: tkFrz = shr_const_tkfrz ! freezing T of fresh water ~ K + + !--- coefficients for esat over water --- + real(r8),parameter :: a0=6.107799961_r8 + real(r8),parameter :: a1=4.436518521e-01_r8 + real(r8),parameter :: a2=1.428945805e-02_r8 + real(r8),parameter :: a3=2.650648471e-04_r8 + real(r8),parameter :: a4=3.031240396e-06_r8 + real(r8),parameter :: a5=2.034080948e-08_r8 + real(r8),parameter :: a6=6.136820929e-11_r8 + + !--- coefficients for esat over ice --- + real(r8),parameter :: b0=6.109177956_r8 + real(r8),parameter :: b1=5.034698970e-01_r8 + real(r8),parameter :: b2=1.886013408e-02_r8 + real(r8),parameter :: b3=4.176223716e-04_r8 + real(r8),parameter :: b4=5.824720280e-06_r8 + real(r8),parameter :: b5=4.838803174e-08_r8 + real(r8),parameter :: b6=1.838826904e-10_r8 + + t = min( 50.0_r8, max(-50.0_r8,(tK-tKfrz)) ) + if ( tKbot < tKfrz) then + datm_eSat = 100.0_r8*(b0+t*(b1+t*(b2+t*(b3+t*(b4+t*(b5+t*b6)))))) + else + datm_eSat = 100.0_r8*(a0+t*(a1+t*(a2+t*(a3+t*(a4+t*(a5+t*a6)))))) + end if + + end function datm_eSat + +end module datm_datamode_era5_mod