diff --git a/CMakeLists.txt b/CMakeLists.txt index db576a054f..226aea148a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,6 +85,7 @@ add_library(fv3atm cpl/module_block_data.F90 cpl/module_cplfields.F90 cpl/module_cap_cpl.F90 + io/clm_lake_io.F90 io/FV3GFS_io.F90 io/FV3GFS_restart_io.F90 io/module_write_netcdf.F90 diff --git a/ccpp/config/ccpp_prebuild_config.py b/ccpp/config/ccpp_prebuild_config.py index dda560ed57..aaf540bcc3 100755 --- a/ccpp/config/ccpp_prebuild_config.py +++ b/ccpp/config/ccpp_prebuild_config.py @@ -183,6 +183,7 @@ 'physics/physics/lsm_noah.f', 'physics/physics/noahmpdrv.F90', 'physics/physics/flake_driver.F90', + 'physics/physics/clm_lake.f90', 'physics/physics/sfc_nst_pre.f', 'physics/physics/sfc_nst.f', 'physics/physics/sfc_nst_post.f', diff --git a/ccpp/data/CCPP_typedefs.F90 b/ccpp/data/CCPP_typedefs.F90 index b886beb3e4..9a6a387ba0 100644 --- a/ccpp/data/CCPP_typedefs.F90 +++ b/ccpp/data/CCPP_typedefs.F90 @@ -184,7 +184,6 @@ module CCPP_typedefs integer, pointer :: idxday(:) => null() !< logical, pointer :: icy(:) => null() !< logical, pointer :: lake(:) => null() !< - logical, pointer :: use_flake(:) => null() !< logical, pointer :: ocean(:) => null() !< integer :: ipr !< integer, pointer :: islmsk(:) => null() !< @@ -647,7 +646,6 @@ subroutine gfs_interstitial_create (Interstitial, IM, Model) allocate (Interstitial%idxday (IM)) allocate (Interstitial%icy (IM)) allocate (Interstitial%lake (IM)) - allocate (Interstitial%use_flake (IM)) allocate (Interstitial%ocean (IM)) allocate (Interstitial%islmsk (IM)) allocate (Interstitial%islmsk_cice (IM)) @@ -1327,7 +1325,6 @@ subroutine gfs_interstitial_phys_reset (Interstitial, Model) Interstitial%dry = .false. Interstitial%icy = .false. Interstitial%lake = .false. - Interstitial%use_flake = .false. Interstitial%ocean = .false. Interstitial%islmsk = 0 Interstitial%islmsk_cice = 0 diff --git a/ccpp/data/CCPP_typedefs.meta b/ccpp/data/CCPP_typedefs.meta index 09c4feda55..3fd32d7c96 100644 --- a/ccpp/data/CCPP_typedefs.meta +++ b/ccpp/data/CCPP_typedefs.meta @@ -1238,12 +1238,6 @@ units = flag dimensions = (horizontal_loop_extent) type = logical -[use_flake] - standard_name = flag_for_using_flake - long_name = flag indicating lake points using flake model - units = flag - dimensions = (horizontal_loop_extent) - type = logical [ocean] standard_name = flag_nonzero_ocean_surface_fraction long_name = flag indicating presence of some ocean surface area fraction diff --git a/ccpp/data/GFS_typedefs.F90 b/ccpp/data/GFS_typedefs.F90 index 0a394587f0..d831942f28 100644 --- a/ccpp/data/GFS_typedefs.F90 +++ b/ccpp/data/GFS_typedefs.F90 @@ -1,7 +1,7 @@ module GFS_typedefs use machine, only: kind_phys, kind_dbl_prec, kind_sngl_prec - use physcons, only: con_cp, con_fvirt, con_g, & + use physcons, only: con_cp, con_fvirt, con_g, rholakeice, & con_hvap, con_hfus, con_pi, con_rd, con_rv, & con_t0c, con_cvap, con_cliq, con_eps, con_epsq, & con_epsm1, con_ttp, rlapse, con_jcal, con_rhw0, & @@ -211,8 +211,26 @@ module GFS_typedefs real (kind=kind_phys), pointer :: slmsk (:) => null() !< sea/land mask array (sea:0,land:1,sea-ice:2) real (kind=kind_phys), pointer :: oceanfrac(:) => null() !< ocean fraction [0:1] real (kind=kind_phys), pointer :: landfrac(:) => null() !< land fraction [0:1] + +!--- In (lakes) real (kind=kind_phys), pointer :: lakefrac(:) => null() !< lake fraction [0:1] real (kind=kind_phys), pointer :: lakedepth(:) => null() !< lake depth [ m ] + real (kind=kind_phys), pointer :: clm_lakedepth(:) => null() !< clm internal lake depth [ m ] + integer, pointer :: use_lake_model(:) => null()!1=run lake, 2=run lake&nsst, 0=no lake + real (kind=kind_phys), pointer :: lake_t2m (:) => null() !< 2 meter temperature from CLM Lake model + real (kind=kind_phys), pointer :: lake_q2m (:) => null() !< 2 meter humidity from CLM Lake model + + real (kind=kind_phys), pointer :: h_ML(:) => null() !Mixed Layer depth of lakes [m] + real (kind=kind_phys), pointer :: t_ML(:) => null() !Mixing layer temperature in K + real (kind=kind_phys), pointer :: t_mnw(:) => null() !Mean temperature of the water column [K] + real (kind=kind_phys), pointer :: h_talb(:) => null() !the thermally active layer depth of the bottom sediments [m] + real (kind=kind_phys), pointer :: t_talb(:) => null() !Temperature at the bottom of the sediment upper layer [K] + real (kind=kind_phys), pointer :: t_bot1(:) => null() !Temperature at the water-bottom sediment interface [K] + real (kind=kind_phys), pointer :: t_bot2(:) => null() !Temperature for bottom layer of water [K] + real (kind=kind_phys), pointer :: c_t(:) => null() !Shape factor of water temperature vertical profile + real (kind=kind_phys), pointer :: T_snow(:) => null() !temperature of snow on a lake [K] + real (kind=kind_phys), pointer :: T_ice(:) => null() !temperature of ice on a lake [K] + real (kind=kind_phys), pointer :: tsfc (:) => null() !< surface air temperature in K real (kind=kind_phys), pointer :: vegtype_frac (:,:) => null() !< fractions [0:1] of veg. categories real (kind=kind_phys), pointer :: soiltype_frac(:,:) => null() !< fractions [0:1] of soil categories @@ -409,6 +427,36 @@ module GFS_typedefs real (kind=kind_phys), pointer :: dsnowprv (:) => null() !< snow precipitation rate from previous timestep real (kind=kind_phys), pointer :: dgraupelprv(:) => null() !< graupel precipitation rate from previous timestep + ! CLM Lake model internal variables: + real (kind=kind_phys), pointer :: lake_albedo(:) => null() ! + real (kind=kind_phys), pointer :: lake_z3d(:,:) => null() ! + real (kind=kind_phys), pointer :: lake_dz3d(:,:) => null() ! + real (kind=kind_phys), pointer :: lake_soil_watsat3d(:,:) => null() ! + real (kind=kind_phys), pointer :: lake_csol3d(:,:) => null() ! + real (kind=kind_phys), pointer :: lake_soil_tkmg3d(:,:) => null() ! + real (kind=kind_phys), pointer :: lake_soil_tkdry3d(:,:) => null() ! + real (kind=kind_phys), pointer :: lake_soil_tksatu3d(:,:) => null() ! + real (kind=kind_phys), pointer :: lake_h2osno2d(:) => null() ! + real (kind=kind_phys), pointer :: lake_sndpth2d(:) => null() ! + real (kind=kind_phys), pointer :: lake_snl2d(:) => null() ! + real (kind=kind_phys), pointer :: lake_snow_z3d(:,:) => null() ! + real (kind=kind_phys), pointer :: lake_snow_dz3d(:,:) => null() ! + real (kind=kind_phys), pointer :: lake_snow_zi3d(:,:) => null() ! + real (kind=kind_phys), pointer :: lake_h2osoi_vol3d(:,:) => null() ! + real (kind=kind_phys), pointer :: lake_h2osoi_liq3d(:,:) => null() ! + real (kind=kind_phys), pointer :: lake_h2osoi_ice3d(:,:) => null() ! + real (kind=kind_phys), pointer :: lake_tsfc(:) => null() ! + real (kind=kind_phys), pointer :: lake_t_soisno3d(:,:) => null() ! + real (kind=kind_phys), pointer :: lake_t_lake3d(:,:) => null() ! + real (kind=kind_phys), pointer :: lake_savedtke12d(:)=> null() ! + real (kind=kind_phys), pointer :: lake_icefrac3d(:,:)=> null() + real (kind=kind_phys), pointer :: lake_rho0(:)=> null() + real (kind=kind_phys), pointer :: lake_ht(:)=> null() + real (kind=kind_phys), pointer :: lake_clay3d(:,:) => null() + real (kind=kind_phys), pointer :: lake_sand3d(:,:) => null() + integer, pointer :: lake_is_salty(:) => null() + integer, pointer :: lake_cannot_freeze(:) => null() + real (kind=kind_phys), pointer :: clm_lake_initialized(:) => null() !< lakeini was called !--- aerosol surface emissions for Thompson microphysics & smoke dust real (kind=kind_phys), pointer :: emdust (:) => null() !< instantaneous dust emission real (kind=kind_phys), pointer :: emseas (:) => null() !< instantaneous sea salt emission @@ -1012,8 +1060,24 @@ module GFS_typedefs integer :: ntsflg !< flag for updating skin temperature in the GFDL surface layer scheme real(kind=kind_phys) :: sfenth !< enthalpy flux factor 0 zot via charnock ..>0 zot enhanced>15m/s -!--- flake model parameters - integer :: lkm !< flag for flake model +!--- lake model parameters + integer :: lkm !< =0 no lake, =1 lake, =2 lake&nsst + integer :: iopt_lake !< =1 flake, =2 clm lake + integer :: iopt_lake_flake = 1 + integer :: iopt_lake_clm = 2 + real(kind_phys) :: lakedepth_threshold !< lakedepth must be GREATER than this value to enable a lake model + real(kind_phys) :: lakefrac_threshold !< lakefrac must be GREATER than this value to enable a lake model + logical :: use_lake2m !< use 2m T & Q calculated by the lake model + +!--- clm lake model parameters + integer :: nlevlake_clm_lake !< Number of lake levels for clm lake model + integer :: nlevsoil_clm_lake !< Number of soil levels for clm lake model + integer :: nlevsnow_clm_lake !< Number of snow levels for clm lake model + integer :: nlevsnowsoil_clm_lake !< -nlevsnow:nlevsoil dimensioned variables + integer :: nlevsnowsoil1_clm_lake !< -nlevsnow+1:nlevsoil dimensioned variables + real(kind_phys) :: clm_lake_depth_default !< minimum lake elevation in clm lake model + logical :: clm_lake_use_lakedepth !< initialize lake from lakedepth + logical :: clm_lake_debug !< verbose debugging in clm_lake !--- tuning parameters for physical parameterizations logical :: ras !< flag for ras convection scheme @@ -1207,6 +1271,7 @@ module GFS_typedefs !< nstf_name(5) : zsea2 in mm !--- fractional grid logical :: frac_grid !< flag for fractional grid + logical :: frac_ice !< flag for fractional ice when fractional grid is not in use logical :: ignore_lake !< flag for ignoring lakes real(kind=kind_phys) :: min_lakeice !< minimum lake ice value real(kind=kind_phys) :: min_seaice !< minimum sea ice value @@ -2174,6 +2239,26 @@ subroutine sfcprop_create (Sfcprop, IM, Model) allocate (Sfcprop%soiltype_frac(IM,Model%nsoilcat)) allocate (Sfcprop%lakefrac (IM)) allocate (Sfcprop%lakedepth(IM)) + + allocate (Sfcprop%use_lake_model(IM)) + + if(Model%lkm > 0) then + if(Model%iopt_lake==Model%iopt_lake_clm) then + allocate (Sfcprop%clm_lakedepth(IM)) + else if(Model%iopt_lake==Model%iopt_lake_flake) then + allocate (Sfcprop%h_ML (IM)) + allocate (Sfcprop%t_ML (IM)) + allocate (Sfcprop%t_mnw (IM)) + allocate (Sfcprop%h_talb (IM)) + allocate (Sfcprop%t_talb (IM)) + allocate (Sfcprop%t_bot1 (IM)) + allocate (Sfcprop%t_bot2 (IM)) + allocate (Sfcprop%c_t (IM)) + endif + allocate (Sfcprop%T_snow (IM)) + allocate (Sfcprop%T_ice (IM)) + endif + allocate (Sfcprop%tsfc (IM)) allocate (Sfcprop%tsfco (IM)) allocate (Sfcprop%tsfcl (IM)) @@ -2211,6 +2296,25 @@ subroutine sfcprop_create (Sfcprop, IM, Model) Sfcprop%soiltype_frac = clear_val Sfcprop%lakefrac = clear_val Sfcprop%lakedepth = clear_val + + Sfcprop%use_lake_model = zero + if(Model%lkm > 0) then + if(Model%iopt_lake==Model%iopt_lake_clm) then + Sfcprop%clm_lakedepth = clear_val + else if(Model%iopt_lake==Model%iopt_lake_flake) then + Sfcprop%h_ML = clear_val + Sfcprop%t_ML = clear_val + Sfcprop%t_mnw = clear_val + Sfcprop%h_talb = clear_val + Sfcprop%t_talb = clear_val + Sfcprop%t_bot1 = clear_val + Sfcprop%t_bot2 = clear_val + Sfcprop%c_t = clear_val + endif + Sfcprop%T_snow = clear_val + Sfcprop%T_ice = clear_val + endif + Sfcprop%tsfc = clear_val Sfcprop%tsfco = clear_val Sfcprop%tsfcl = clear_val @@ -2402,18 +2506,20 @@ subroutine sfcprop_create (Sfcprop, IM, Model) Sfcprop%xlaixy = clear_val Sfcprop%rca = clear_val end if - if (Model%lsm == Model%lsm_ruc .or. Model%lsm == Model%lsm_noahmp) then - allocate(Sfcprop%raincprv (IM)) - allocate(Sfcprop%rainncprv (IM)) + if (Model%lsm == Model%lsm_ruc .or. Model%lsm == Model%lsm_noahmp .or. & + (Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_clm)) then + allocate(Sfcprop%raincprv (IM)) + allocate(Sfcprop%rainncprv (IM)) + Sfcprop%raincprv = clear_val + Sfcprop%rainncprv = clear_val + if (Model%lsm == Model%lsm_ruc .or. Model%lsm == Model%lsm_noahmp) then allocate(Sfcprop%iceprv (IM)) allocate(Sfcprop%snowprv (IM)) allocate(Sfcprop%graupelprv(IM)) - - Sfcprop%raincprv = clear_val - Sfcprop%rainncprv = clear_val Sfcprop%iceprv = clear_val Sfcprop%snowprv = clear_val Sfcprop%graupelprv = clear_val + end if end if ! Noah MP allocate and init when used ! @@ -2589,6 +2695,73 @@ subroutine sfcprop_create (Sfcprop, IM, Model) Sfcprop%conv_act_m = zero end if + ! CLM Lake Model variables + if (Model%lkm/=0 .and. Model%iopt_lake==Model%iopt_lake_clm) then + allocate(Sfcprop%lake_t2m(IM)) + allocate(Sfcprop%lake_q2m(IM)) + allocate(Sfcprop%lake_albedo(IM)) + allocate(Sfcprop%lake_z3d(IM,Model%nlevlake_clm_lake)) + allocate(Sfcprop%lake_dz3d(IM,Model%nlevlake_clm_lake)) + allocate(Sfcprop%lake_soil_watsat3d(IM,Model%nlevlake_clm_lake)) + allocate(Sfcprop%lake_csol3d(IM,Model%nlevlake_clm_lake)) + allocate(Sfcprop%lake_soil_tkmg3d(IM,Model%nlevlake_clm_lake)) + allocate(Sfcprop%lake_soil_tkdry3d(IM,Model%nlevlake_clm_lake)) + allocate(Sfcprop%lake_soil_tksatu3d(IM,Model%nlevlake_clm_lake)) + allocate(Sfcprop%lake_h2osno2d(IM)) + allocate(Sfcprop%lake_sndpth2d(IM)) + allocate(Sfcprop%lake_snl2d(IM)) + allocate(Sfcprop%lake_snow_z3d(IM,Model%nlevsnowsoil1_clm_lake)) + allocate(Sfcprop%lake_snow_dz3d(IM,Model%nlevsnowsoil1_clm_lake)) + allocate(Sfcprop%lake_snow_zi3d(IM,Model%nlevsnowsoil_clm_lake)) + allocate(Sfcprop%lake_h2osoi_vol3d(IM,Model%nlevsnowsoil1_clm_lake)) + allocate(Sfcprop%lake_h2osoi_liq3d(IM,Model%nlevsnowsoil1_clm_lake)) + allocate(Sfcprop%lake_h2osoi_ice3d(IM,Model%nlevsnowsoil1_clm_lake)) + allocate(Sfcprop%lake_tsfc(IM)) + allocate(Sfcprop%lake_t_soisno3d(IM,Model%nlevsnowsoil1_clm_lake)) + allocate(Sfcprop%lake_t_lake3d(IM,Model%nlevlake_clm_lake)) + allocate(Sfcprop%lake_savedtke12d(IM)) + allocate(Sfcprop%lake_icefrac3d(IM,Model%nlevlake_clm_lake)) + allocate(Sfcprop%lake_rho0(IM)) + allocate(Sfcprop%lake_ht(IM)) + allocate(Sfcprop%lake_clay3d(IM,Model%nlevsoil_clm_lake)) + allocate(Sfcprop%lake_sand3d(IM,Model%nlevsoil_clm_lake)) + allocate(Sfcprop%lake_is_salty(IM)) + allocate(Sfcprop%lake_cannot_freeze(IM)) + allocate(Sfcprop%clm_lake_initialized(IM)) + + Sfcprop%lake_t2m = clear_val + Sfcprop%lake_q2m = clear_val + Sfcprop%lake_albedo = clear_val + Sfcprop%lake_z3d = clear_val + Sfcprop%lake_dz3d = clear_val + Sfcprop%lake_soil_watsat3d = clear_val + Sfcprop%lake_csol3d = clear_val + Sfcprop%lake_soil_tkmg3d = clear_val + Sfcprop%lake_soil_tkdry3d = clear_val + Sfcprop%lake_soil_tksatu3d = clear_val + Sfcprop%lake_h2osno2d = clear_val + Sfcprop%lake_sndpth2d = clear_val + Sfcprop%lake_snl2d = clear_val + Sfcprop%lake_snow_z3d = clear_val + Sfcprop%lake_snow_dz3d = clear_val + Sfcprop%lake_snow_zi3d = clear_val + Sfcprop%lake_h2osoi_vol3d = clear_val + Sfcprop%lake_h2osoi_liq3d = clear_val + Sfcprop%lake_h2osoi_ice3d = clear_val + Sfcprop%lake_tsfc = clear_val + Sfcprop%lake_t_soisno3d = clear_val + Sfcprop%lake_t_lake3d = clear_val + Sfcprop%lake_savedtke12d = clear_val + Sfcprop%lake_icefrac3d = clear_val + Sfcprop%lake_rho0 = -111 + Sfcprop%lake_ht = -111 + Sfcprop%lake_clay3d = clear_val + Sfcprop%lake_sand3d = clear_val + Sfcprop%lake_is_salty = zero + Sfcprop%lake_cannot_freeze = zero + Sfcprop%clm_lake_initialized = zero + endif + if(Model%rrfs_sd) then !--- needed for smoke aerosol option allocate (Sfcprop%emdust (IM)) @@ -3266,6 +3439,18 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & !--- Thompson,GFDL microphysical parameter logical :: lrefres = .false. !< flag for radar reflectivity in restart file + !--- CLM Lake Model parameters (MUST match clm_lake.F90) + integer, parameter :: nlevlake_clm_lake = 10 !< number of lake levels + integer, parameter :: nlevsoil_clm_lake = 10 !< number of soil levels + integer, parameter :: nlevsnow_clm_lake = 5 !< number of snow levels + integer, parameter :: nlevsnowsoil_clm_lake = nlevsnow_clm_lake+nlevsoil_clm_lake+1 !< -nlevsno:nlevsoil dimensioned variables + integer, parameter :: nlevsnowsoil1_clm_lake = nlevsnow_clm_lake+nlevsoil_clm_lake !< -nlevsno+1:nlevsoil dimensioned variables + + !--- CLM Lake configurables + real(kind_phys) :: clm_lake_depth_default = 50 !< default lake depth in clm lake model + logical :: clm_lake_use_lakedepth = .true. !< initialize depth from lakedepth + logical :: clm_lake_debug = .false. !< verbose debugging in clm_lake + !--- land/surface model parameters integer :: lsm = 1 !< flag for land surface model to use =0 for osu lsm; =1 for noah lsm; =2 for noah mp lsm; =3 for RUC lsm integer :: lsoil = 4 !< number of soil layers @@ -3319,7 +3504,11 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & real(kind=kind_phys) :: sfenth = 0.0 !< enthalpy flux factor 0 zot via charnock ..>0 zot enhanced>15m/s !--- flake model parameters - integer :: lkm = 0 !< flag for flake model - default no flake + integer :: lkm = 0 !< =1 run lake, =2 run lake&nsst =0 no lake + integer :: iopt_lake = 2 !< =1 flake, =2 clm lake (default) + real(kind_phys) :: lakedepth_threshold = 1.0 !< lakedepth must be GREATER than this value to enable a lake model + real(kind_phys) :: lakefrac_threshold = 0.0 !< lakefrac must be GREATER than this value to enable a lake model + logical :: use_lake2m = .false. !< use 2m T & Q from clm lake model !--- tuning parameters for physical parameterizations logical :: ras = .false. !< flag for ras convection scheme @@ -3504,6 +3693,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & !< nstf_name(5) : zsea2 in mm !--- fractional grid logical :: frac_grid = .false. !< flag for fractional grid + logical :: frac_ice = .false. !< flag for fractional ice when fractional grid is not in use logical :: ignore_lake = .true. !< flag for ignoring lakes real(kind=kind_phys) :: min_lakeice = 0.15d0 !< minimum lake ice value real(kind=kind_phys) :: min_seaice = 1.0d-11 !< minimum sea ice value @@ -3706,7 +3896,9 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & ! GFDL surface layer options lcurr_sf, pert_cd, ntsflg, sfenth, & !--- lake model control - lkm, & + lkm, iopt_lake, lakedepth_threshold, lakefrac_threshold, & + clm_lake_depth_default, clm_lake_use_lakedepth, & + clm_lake_debug, use_lake2m, & !--- physical parameterizations ras, trans_trac, old_monin, cnvgwd, mstrat, moist_adj, & cscnv, cal_pre, do_aw, do_shoc, shocaftcnv, shoc_cld, & @@ -3749,7 +3941,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & !--- near surface sea temperature model nst_anl, lsea, nstf_name, & frac_grid, min_lakeice, min_seaice, min_lake_height, & - ignore_lake, & + ignore_lake, frac_ice, & !--- surface layer sfc_z0_type, & !--- switch beteeen local and standard potential temperature @@ -4418,8 +4610,22 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & Model%ntsflg = ntsflg Model%sfenth = sfenth -!--- flake model parameters +!--- lake model parameters Model%lkm = lkm + Model%iopt_lake = iopt_lake + Model%use_lake2m = use_lake2m + Model%lakedepth_threshold = lakedepth_threshold + Model%lakefrac_threshold = lakefrac_threshold + +!--- clm lake model parameters + Model%nlevlake_clm_lake = nlevlake_clm_lake + Model%nlevsoil_clm_lake = nlevsoil_clm_lake + Model%nlevsnow_clm_lake = nlevsnow_clm_lake + Model%nlevsnowsoil_clm_lake = nlevsnowsoil_clm_lake + Model%nlevsnowsoil1_clm_lake = nlevsnowsoil1_clm_lake + Model%clm_lake_depth_default = clm_lake_depth_default + Model%clm_lake_use_lakedepth = clm_lake_use_lakedepth + Model%clm_lake_debug = clm_lake_debug ! Noah MP options from namelist ! @@ -4623,6 +4829,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & !--- fractional grid Model%frac_grid = frac_grid + Model%frac_ice = frac_ice Model%ignore_lake = ignore_lake Model%min_lakeice = min_lakeice Model%min_seaice = min_seaice @@ -4851,6 +5058,18 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & Model%ntocl = get_tracer_index(Model%tracer_names, 'oc2', Model%me, Model%master, Model%debug) end if + ! Lake & fractional grid safety checks + if(Model%me==Model%master) then + if(Model%lkm>0 .and. Model%frac_grid) then + write(0,*) 'WARNING: Lake fractional grid support is experimental. Use at your own risk!' + else if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_clm .and. .not. Model%frac_ice) then + write(0,*) 'WARNING: CLM Lake Model will not work without frac_ice=.true.' + endif + if(Model%lkm==2) then + write(0,*) 'WARNING: Running both lake and nsst on lake points is experimental. Use at your own risk!' + endif + endif + if(ldiag3d) then ! Flags used to turn on or off tracer "causes" have_pbl_edmf = Model%hybedmf .or. Model%satmedmf .or. Model%do_mynnedmf @@ -5382,12 +5601,27 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & ! endif print *,' nst_anl=',Model%nst_anl,' use_ufo=',Model%use_ufo,' frac_grid=',Model%frac_grid,& - ' ignore_lake=',ignore_lake + ' ignore_lake=',ignore_lake,' frac_ice=',Model%frac_ice print *,' min_lakeice=',Model%min_lakeice,' min_seaice=',Model%min_seaice, & 'min_lake_height=',Model%min_lake_height - print *, 'flake model parameters' - print *, 'lkm : ', Model%lkm + print *, 'lake model parameters' + print *, ' lake master flag lkm : ', Model%lkm + if(Model%lkm>0) then + print *, ' lake model selection : ', Model%iopt_lake + if(Model%iopt_lake==Model%iopt_lake_clm) then + print *,' CLM Lake model configuration' + print *,' use_lake2m = ',Model%use_lake2m + print *,' clm_lake_use_lakedepth = ',Model%clm_lake_use_lakedepth + print *,' clm_lake_depth_default = ',Model%clm_lake_depth_default + print *,' clm_lake_debug = ',Model%clm_lake_debug + print *,' nlevlake_clm_lake = ',Model%nlevlake_clm_lake + print *,' nlevsoil_clm_lake = ',Model%nlevsoil_clm_lake + print *,' nlevsnow_clm_lake = ',Model%nlevsnow_clm_lake + print *,' nlevsnowsoil_clm_lake = ',Model%nlevsnowsoil_clm_lake + print *,' nlevsnowsoil1_clm_lake = ',Model%nlevsnowsoil1_clm_lake + endif + endif if (Model%nstf_name(1) > 0 ) then print *,' NSSTM is active ' diff --git a/ccpp/data/GFS_typedefs.meta b/ccpp/data/GFS_typedefs.meta index 4354f7c109..4ab11dd4cb 100644 --- a/ccpp/data/GFS_typedefs.meta +++ b/ccpp/data/GFS_typedefs.meta @@ -641,6 +641,108 @@ dimensions = (horizontal_loop_extent) type = real kind = kind_phys +[clm_lakedepth] + standard_name = clm_lake_depth + long_name = clm internal copy of lake depth with 10.0 replaced by default lake depth + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_execution_method > 0 .and. control_for_lake_model_selection == 2) +[use_lake_model] + standard_name = flag_for_using_lake_model + long_name = flag indicating lake points using a lake model + units = flag + dimensions = (horizontal_loop_extent) + type = integer +[lake_t2m] + standard_name = temperature_at_2m_from_clm_lake + long_name = temperature at 2m from clm lake + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_execution_method > 0 .and. control_for_lake_model_selection == 2) +[lake_q2m] + standard_name = specific_humidity_at_2m_from_clm_lake + long_name = specific humidity at 2m from clm lake + units = frac + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_execution_method > 0 .and. control_for_lake_model_selection == 2) +[h_ML] + standard_name = mixed_layer_depth_of_lakes + long_name = depth of lake mixing layer + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 1 .and. control_for_lake_model_execution_method > 0) +[t_ML] + standard_name = lake_mixed_layer_temperature + long_name = temperature of lake mixing layer + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 1 .and. control_for_lake_model_execution_method > 0) +[t_mnw] + standard_name = mean_temperature_of_the_water_column + long_name = thee mean temperature of the water column + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 1 .and. control_for_lake_model_execution_method > 0) +[h_talb] + standard_name = the_thermally_active_layer_depth_of_the_bottom_sediment + long_name = the depth of the thermally active layer of the bottom sediment + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 1 .and. control_for_lake_model_execution_method > 0) +[t_talb] + standard_name = temperature_at_the_bottom_of_the_sediment_upper_layer + long_name = the temperature at the bottom of the sediment upper layer + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 1 .and. control_for_lake_model_execution_method > 0) +[t_bot1] + standard_name = lake_bottom_temperature + long_name = the temperature at the water-bottom sediment interface + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 1 .and. control_for_lake_model_execution_method > 0) +[t_bot2] + standard_name = temperature_for_bottom_layer_of_water + long_name = the temperature at the lake bottom layer water + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 1 .and. control_for_lake_model_execution_method > 0) +[c_t] + standard_name = shape_factor_of_water_temperature_vertical_profile + long_name = the shape factor of water temperature vertical profile + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 1 .and. control_for_lake_model_execution_method > 0) +[T_snow] + standard_name = temperature_of_snow_on_lake + long_name = temperature of snow on a lake + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_execution_method > 0) [tsfc] standard_name = surface_skin_temperature long_name = surface skin temperature @@ -1811,7 +1913,7 @@ dimensions = (horizontal_loop_extent) type = real kind = kind_phys - active = (control_for_land_surface_scheme == identifier_for_ruc_land_surface_scheme .or. control_for_land_surface_scheme == identifier_for_noahmp_land_surface_scheme) + active = (control_for_land_surface_scheme == identifier_for_ruc_land_surface_scheme .or. control_for_land_surface_scheme == identifier_for_noahmp_land_surface_scheme .or. ( control_for_lake_model_execution_method > 0 .and. control_for_lake_model_selection == 2) ) [rainncprv] standard_name = lwe_thickness_of_explicit_precipitation_amount_on_previous_timestep long_name = explicit rainfall from previous timestep @@ -1819,7 +1921,7 @@ dimensions = (horizontal_loop_extent) type = real kind = kind_phys - active = (control_for_land_surface_scheme == identifier_for_ruc_land_surface_scheme .or. control_for_land_surface_scheme == identifier_for_noahmp_land_surface_scheme) + active = (control_for_land_surface_scheme == identifier_for_ruc_land_surface_scheme .or. control_for_land_surface_scheme == identifier_for_noahmp_land_surface_scheme .or. ( control_for_lake_model_execution_method > 0 .and. control_for_lake_model_selection == 2) ) [iceprv] standard_name = lwe_thickness_of_ice_precipitation_amount_on_previous_timestep long_name = ice amount from previous timestep @@ -1912,6 +2014,226 @@ dimensions = (horizontal_loop_extent) type = real kind = kind_phys +[lake_albedo] + standard_name = mid_day_surface_albedo_over_lake + long_name = mid day surface albedo over lake + units = fraction + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_z3d] + standard_name = depth_of_lake_interface_layers + long_name = depth of lake interface layers + units = fraction + dimensions = (horizontal_loop_extent, lake_vertical_dimension_for_clm_lake_model) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_dz3d] + standard_name = thickness_of_lake_layers + long_name = thickness of lake layers + units = fraction + dimensions = (horizontal_loop_extent, lake_vertical_dimension_for_clm_lake_model) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_soil_watsat3d] + standard_name = saturated_volumetric_soil_water_in_lake_model + long_name = saturated volumetric soil water in lake model + units = m + dimensions = (horizontal_loop_extent, lake_vertical_dimension_for_clm_lake_model) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_csol3d] + standard_name = soil_heat_capacity_in_lake_model + long_name = soil heat capacity in lake model + units = m + dimensions = (horizontal_loop_extent, lake_vertical_dimension_for_clm_lake_model) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_soil_tkmg3d] + standard_name = soil_mineral_thermal_conductivity_in_lake_model + long_name = soil mineral thermal conductivity in lake model + units = m + dimensions = (horizontal_loop_extent, lake_vertical_dimension_for_clm_lake_model) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_soil_tkdry3d] + standard_name = dry_soil_thermal_conductivity_in_lake_model + long_name = dry soil thermal conductivity in lake model + units = m + dimensions = (horizontal_loop_extent, lake_vertical_dimension_for_clm_lake_model) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_soil_tksatu3d] + standard_name = saturated_soil_thermal_conductivity_in_lake_model + long_name = saturated soil thermal conductivity in lake model + units = m + dimensions = (horizontal_loop_extent, lake_vertical_dimension_for_clm_lake_model) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_h2osno2d] + standard_name = water_equivalent_accumulated_snow_depth_in_clm_lake_model + long_name = water equiv of acc snow depth over lake in clm lake model + units = mm + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_sndpth2d] + standard_name = actual_snow_depth_in_clm_lake_model + long_name = actual acc snow depth over lake in clm lake model + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_snl2d] + standard_name = snow_layers_in_clm_lake_model + long_name = snow layers in clm lake model (treated as integer) + units = count + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_snow_z3d] + standard_name = snow_level_depth_in_clm_lake_model + long_name = snow level depth in clm lake model + units = m + dimensions = (horizontal_loop_extent,snow_plus_soil_minus_one_vertical_dimension_for_clm_lake_model) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_snow_dz3d] + standard_name = snow_level_thickness_in_clm_lake_model + long_name = snow level thickness in clm lake model + units = m + dimensions = (horizontal_loop_extent,snow_plus_soil_minus_one_vertical_dimension_for_clm_lake_model) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_snow_zi3d] + standard_name = snow_interface_depth_in_clm_lake_model + long_name = snow interface_depth in clm lake model + units = m + dimensions = (horizontal_loop_extent,snow_plus_soil_vertical_dimension_for_clm_lake_model) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_h2osoi_vol3d] + standard_name = volumetric_soil_water_in_clm_lake_model + long_name = volumetric soil water in clm lake model + units = m3 m-3 + dimensions = (horizontal_loop_extent,snow_plus_soil_minus_one_vertical_dimension_for_clm_lake_model) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_h2osoi_liq3d] + standard_name = soil_liquid_water_content_in_clm_lake_model + long_name = soil liquid water content in clm lake model + units = kg m-3 + dimensions = (horizontal_loop_extent,snow_plus_soil_minus_one_vertical_dimension_for_clm_lake_model) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_h2osoi_ice3d] + standard_name = soil_ice_water_content_in_clm_lake_model + long_name = soil ice water content in clm lake model + units = kg m-3 + dimensions = (horizontal_loop_extent,snow_plus_soil_minus_one_vertical_dimension_for_clm_lake_model) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_tsfc] + standard_name = skin_temperature_from_lake_model + long_name = skin temperature from lake model + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_t_soisno3d] + standard_name = soil_or_snow_layer_temperature_from_clm_lake_model + long_name = soil or snow layer temperature from clm lake model + units = K + dimensions = (horizontal_loop_extent,snow_plus_soil_minus_one_vertical_dimension_for_clm_lake_model) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_t_lake3d] + standard_name = lake_layer_temperature_from_clm_lake_model + long_name = lake layer temperature from clm lake model + units = K + dimensions = (horizontal_loop_extent,lake_vertical_dimension_for_clm_lake_model) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_savedtke12d] + standard_name = top_level_eddy_conductivity_from_previous_timestep_in_clm_lake_model + long_name = top level eddy conductivity from previous timestep in clm lake model + units = kg m-3 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_icefrac3d] + standard_name = lake_fractional_ice_cover_on_clm_lake_levels + long_name = lake fractional ice cover on clm lake levels + units = kg m-3 + dimensions = (horizontal_loop_extent,lake_vertical_dimension_for_clm_lake_model) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_ht] + standard_name = test_lake_ht + long_name = test_lake_ht + dimensions = (horizontal_loop_extent) + units = unitless + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[clm_lake_initialized] + standard_name = flag_for_clm_lake_initialization + long_name = set to true in clm_lake_run after likeini is called for that gridpoint + units = flag + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_clay3d] + standard_name = clm_lake_percent_clay + long_name = percent clay in clm lake model + units = percent + dimensions = (horizontal_loop_extent,soil_vertical_dimension_for_clm_lake_model) + type = integer + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_sand3d] + standard_name = clm_lake_percent_sand + long_name = percent sand in clm lake model + units = percent + dimensions = (horizontal_loop_extent,soil_vertical_dimension_for_clm_lake_model) + type = integer + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_is_salty] + standard_name = clm_lake_is_salty + long_name = lake at this point is salty (1) or not (0) + units = 1 + dimensions = (horizontal_loop_extent) + type = integer + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) +[lake_cannot_freeze] + standard_name = clm_lake_cannot_freeze + long_name = lake at this point is so salty it cannot freeze + units = 1 + dimensions = (horizontal_loop_extent) + type = integer + active = (control_for_lake_model_selection == 2 .and. control_for_lake_model_execution_method > 0) [emdust] standard_name = emission_of_dust_for_smoke long_name = emission of dust for smoke @@ -4332,6 +4654,41 @@ units = count dimensions = () type = integer +[nlevlake_clm_lake] + standard_name = lake_vertical_dimension_for_clm_lake_model + long_name = lake vertical dimension for clm lake model + units = count + dimensions = () + type = integer + active = (control_for_lake_surface_scheme == 2) +[nlevsoil_clm_lake] + standard_name = soil_vertical_dimension_for_clm_lake_model + long_name = soil vertical dimension for clm lake model + units = count + dimensions = () + type = integer + active = (control_for_lake_surface_scheme == 2) +[nlevsnow_clm_lake] + standard_name = snow_vertical_dimension_for_clm_lake_model + long_name = snow vertical dimension for clm lake model + units = count + dimensions = () + type = integer + active = (control_for_lake_surface_scheme == 2) +[nlevsnowsoil_clm_lake] + standard_name = snow_plus_soil_vertical_dimension_for_clm_lake_model + long_name = snow plus soil vertical dimension for clm lake model + units = count + dimensions = () + type = integer + active = (control_for_lake_surface_scheme == 2) +[nlevsnowsoil1_clm_lake] + standard_name = snow_plus_soil_minus_one_vertical_dimension_for_clm_lake_model + long_name = snow plus soil minus one vertical dimension for clm lake model + units = count + dimensions = () + type = integer + active = (control_for_lake_surface_scheme == 2) [lsoil] standard_name = vertical_dimension_of_soil long_name = number of soil layers @@ -4579,9 +4936,47 @@ dimensions = () type = real kind = kind_phys +[lakefrac_threshold] + standard_name = lakefrac_threshold_for_enabling_lake_model + long_name = fraction of horizontal grid area occupied by lake must be greater than this value to enable a lake model + units = frac + dimensions = () + type = real + kind = kind_phys +[lakedepth_threshold] + standard_name = lake_depth_threshold_for_enabling_lake_model + long_name = lake depth must be greater than this value to enable a lake model + units = m + dimensions = () + type = real + kind = kind_phys +[iopt_lake] + standard_name = control_for_lake_model_selection + long_name = control for lake model selection + units = 1 + dimensions = () + type = integer +[iopt_lake_flake] + standard_name = flake_model_control_selection_value + long_name = value that indicates flake model in the control for lake model selection + units = 1 + dimensions = () + type = integer +[iopt_lake_clm] + standard_name = clm_lake_model_control_selection_value + long_name = value that indicates clm lake model in the control for lake model selection + units = 1 + dimensions = () + type = integer +[use_lake2m] + standard_name = use_2m_diagnostics_calculated_by_lake_model + long_name = model 2m diagnostics use the temperature and humidity calculated by the lake model + units = flag + dimensions = () + type = integer [lkm] - standard_name = control_for_lake_surface_scheme - long_name = flag for lake surface model + standard_name = control_for_lake_model_execution_method + long_name = control for lake model execution: 0=no lake, 1=lake, 2=lake+nsst units = flag dimensions = () type = integer @@ -5153,6 +5548,12 @@ units = flag dimensions = () type = logical +[frac_ice] + standard_name = flag_for_fractional_ice_when_fractional_landmask_is_disabled + long_name = flag for fractional ice when fractional landmask is disabled + units = flag + dimensions = () + type = logical [min_lakeice] standard_name = min_lake_ice_area_fraction long_name = minimum lake ice value @@ -6691,6 +7092,25 @@ units = flag dimensions = () type = logical +[clm_lake_depth_default] + standard_name = default_lake_depth_in_clm_lake_model + long_name = default lake depth in clm lake model + units = m + dimensions = () + type = real + kind = kind_phys +[clm_lake_use_lakedepth] + standard_name = flag_for_initializing_clm_lake_depth_from_lake_depth + long_name = flag for initializing clm lake depth from lake depth + units = flag + dimensions = () + type = logical +[clm_lake_debug] + standard_name = flag_for_verbose_debugging_in_clm_lake_model + long_name = flag for verbose debugging in clm lake model + units = flag + dimensions = () + type = logical [fire_aux_data_levels] standard_name = fire_auxiliary_data_extent long_name = number of levels of fire auxiliary data @@ -9446,6 +9866,13 @@ dimensions = () type = real kind = kind_phys +[rholakeice] + standard_name = density_of_ice_on_lake + long_name = density of ice on a lake + units = kg m-3 + dimensions = () + type = real + kind = kind_phys [con_csol] standard_name = specific_heat_of_ice_at_constant_pressure long_name = specific heat of ice at constant pressure diff --git a/ccpp/driver/GFS_diagnostics.F90 b/ccpp/driver/GFS_diagnostics.F90 index 83d20ea595..c1598a28cb 100644 --- a/ccpp/driver/GFS_diagnostics.F90 +++ b/ccpp/driver/GFS_diagnostics.F90 @@ -1874,6 +1874,45 @@ subroutine GFS_externaldiag_populate (ExtDiag, Model, Statein, Stateout, Sfcprop ! if(mpp_pe()==mpp_root_pe())print *,'in gfdl_diag_register,af totgrp,idx=',idx + if(associated(Coupling(1)%sfcdlw)) then + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'sfcdlw' + ExtDiag(idx)%desc = 'sfcdlw' + ExtDiag(idx)%unit = 'W m-2' + ExtDiag(idx)%mod_name = 'gfs_phys' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Coupling(nb)%sfcdlw(:) + enddo + endif + + if(associated(Coupling(1)%htrlw)) then + idx = idx + 1 + ExtDiag(idx)%axes = 3 + ExtDiag(idx)%name = 'htrlw' + ExtDiag(idx)%desc = 'htrlw' + ExtDiag(idx)%unit = 'W m-2' + ExtDiag(idx)%mod_name = 'gfs_phys' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var3 => Coupling(nb)%htrlw(:,:) + enddo + endif + + if(associated(Radtend(1)%lwhc)) then + idx = idx + 1 + ExtDiag(idx)%axes = 3 + ExtDiag(idx)%name = 'lwhc' + ExtDiag(idx)%desc = 'lwhc' + ExtDiag(idx)%unit = 'K s-1' + ExtDiag(idx)%mod_name = 'gfs_phys' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var3 => Radtend(nb)%lwhc(:,:) + enddo + endif + !--- physics instantaneous diagnostics --- idx = idx + 1 ExtDiag(idx)%axes = 2 @@ -2553,6 +2592,207 @@ subroutine GFS_externaldiag_populate (ExtDiag, Model, Statein, Stateout, Sfcprop enddo endif + if (Model%lkm/=0) then + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'lakefrac' + ExtDiag(idx)%desc = 'Lake Fraction' + ExtDiag(idx)%unit = 'fraction' + ExtDiag(idx)%mod_name = 'gfs_sfc' + ExtDiag(idx)%intpl_method = 'nearest_stod' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Sfcprop(nb)%lakefrac(:) + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'lakedepth' + ExtDiag(idx)%desc = 'Lake Depth' + ExtDiag(idx)%unit = 'm' + ExtDiag(idx)%mod_name = 'gfs_sfc' + ExtDiag(idx)%intpl_method = 'nearest_stod' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Sfcprop(nb)%lakedepth(:) + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'T_snow' + ExtDiag(idx)%desc = 'Temperature of snow on a lake' + ExtDiag(idx)%unit = 'K' + ExtDiag(idx)%mod_name = 'gfs_sfc' + ExtDiag(idx)%intpl_method = 'nearest_stod' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Sfcprop(nb)%T_snow(:) + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'T_ice' + ExtDiag(idx)%desc = 'Temperature of ice on a lake' + ExtDiag(idx)%unit = 'K' + ExtDiag(idx)%mod_name = 'gfs_sfc' + ExtDiag(idx)%intpl_method = 'nearest_stod' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Sfcprop(nb)%T_ice(:) + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'use_lake_model' + ExtDiag(idx)%desc = 'Lake Model Flag' + ExtDiag(idx)%unit = 'flag' + ExtDiag(idx)%mod_name = 'gfs_sfc' + ExtDiag(idx)%intpl_method = 'nearest_stod' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%int2 => Sfcprop(nb)%use_lake_model(:) + enddo + + if(Model%iopt_lake==Model%iopt_lake_clm) then + + ! Populate the 3D arrays separately since the code is complicated: + call clm_lake_externaldiag_populate(ExtDiag, Model, Sfcprop, idx, cn_one, nblks) + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'lake_is_salty' + ExtDiag(idx)%desc = 'lake point is considered salty by clm lake model' + ExtDiag(idx)%unit = '1' + ExtDiag(idx)%mod_name = 'gfs_sfc' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%int2 => Sfcprop(nb)%lake_is_salty(:) + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'lake_cannot_freeze' + ExtDiag(idx)%desc = 'clm lake model considers the point to be so salty it cannot freeze' + ExtDiag(idx)%unit = '1' + ExtDiag(idx)%mod_name = 'gfs_sfc' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%int2 => Sfcprop(nb)%lake_cannot_freeze(:) + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'lake_t2m' + ExtDiag(idx)%desc = 'Temperature at 2 m from Lake Model' + ExtDiag(idx)%unit = 'K' + ExtDiag(idx)%intpl_method = 'nearest_stod' + ExtDiag(idx)%mod_name = 'gfs_sfc' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Sfcprop(nb)%lake_t2m(:) + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'lake_q2m' + ExtDiag(idx)%desc = 'Humidity at 2 m from Lake Model' + ExtDiag(idx)%unit = '%' + ExtDiag(idx)%mod_name = 'gfs_sfc' + ExtDiag(idx)%intpl_method = 'nearest_stod' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Sfcprop(nb)%lake_q2m(:) + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'lake_albedo' + ExtDiag(idx)%desc = 'mid day surface albedo over lake' + ExtDiag(idx)%unit = 'fraction' + ExtDiag(idx)%mod_name = 'gfs_sfc' + ExtDiag(idx)%intpl_method = 'nearest_stod' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Sfcprop(nb)%lake_albedo(:) + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'lake_h2osno2d' + ExtDiag(idx)%desc = 'water equiv of acc snow depth over lake' + ExtDiag(idx)%unit = 'mm' + ExtDiag(idx)%mod_name = 'gfs_sfc' + ExtDiag(idx)%intpl_method = 'nearest_stod' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Sfcprop(nb)%lake_h2osno2d(:) + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'lake_sndpth2d' + ExtDiag(idx)%desc = 'actual acc snow depth over lake in clm lake model' + ExtDiag(idx)%unit = 'm' + ExtDiag(idx)%mod_name = 'gfs_sfc' + ExtDiag(idx)%intpl_method = 'nearest_stod' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Sfcprop(nb)%lake_sndpth2d(:) + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'lake_snl2d' + ExtDiag(idx)%desc = 'snow layers in clm lake model (treated as integer)' + ExtDiag(idx)%unit = 'count' + ExtDiag(idx)%mod_name = 'gfs_sfc' + ExtDiag(idx)%intpl_method = 'nearest_stod' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Sfcprop(nb)%lake_snl2d(:) + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'lake_tsfc' + ExtDiag(idx)%desc = 'skin temperature from clm lake model' + ExtDiag(idx)%unit = 'K' + ExtDiag(idx)%mod_name = 'gfs_sfc' + ExtDiag(idx)%intpl_method = 'nearest_stod' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Sfcprop(nb)%lake_tsfc(:) + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'lake_savedtke12d' + ExtDiag(idx)%desc = 'top level eddy conductivity from previous timestep in clm lake model' + ExtDiag(idx)%unit = 'kg m-3' + ExtDiag(idx)%mod_name = 'gfs_sfc' + ExtDiag(idx)%intpl_method = 'nearest_stod' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Sfcprop(nb)%lake_savedtke12d(:) + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'lake_ht' + ExtDiag(idx)%desc = 'lake_ht' + ExtDiag(idx)%unit = 'unitless' + ExtDiag(idx)%mod_name = 'gfs_sfc' + ExtDiag(idx)%intpl_method = 'nearest_stod' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Sfcprop(nb)%lake_ht(:) + enddo + + endif + + endif + if (Model%ldiag_ugwp) THEN ! ! VAY-2018: Momentum and Temp-re tendencies @@ -3715,6 +3955,28 @@ subroutine GFS_externaldiag_populate (ExtDiag, Model, Statein, Stateout, Sfcprop ExtDiag(idx)%data(nb)%var2 => sfcprop(nb)%weasd(:) enddo + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'weasdi' + ExtDiag(idx)%desc = 'surface snow water equivalent over ice' + ExtDiag(idx)%unit = 'kg/m**2' + ExtDiag(idx)%mod_name = 'gfs_sfc' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => sfcprop(nb)%weasdi(:) + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'snodi' + ExtDiag(idx)%desc = 'water equivalent snow depth over ice' + ExtDiag(idx)%unit = 'mm' + ExtDiag(idx)%mod_name = 'gfs_sfc' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => sfcprop(nb)%weasdi(:) + enddo + idx = idx + 1 ExtDiag(idx)%axes = 2 ExtDiag(idx)%name = 'hgtsfc' @@ -4787,6 +5049,131 @@ subroutine GFS_externaldiag_populate (ExtDiag, Model, Statein, Stateout, Sfcprop end subroutine GFS_externaldiag_populate + subroutine clm_lake_externaldiag_populate(ExtDiag, Model, Sfcprop, idx, cn_one, nblks) + implicit none + type(GFS_externaldiag_type), intent(inout) :: ExtDiag(:) + type(GFS_control_type), intent(in) :: Model + type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) + integer, intent(inout) :: idx + integer, intent(in) :: nblks + real(kind=kind_phys), intent(in) :: cn_one + character(:), allocatable :: fullname + + integer :: nk, idx0, iblk + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_z3d, 'lake_z3d', 'lake_depth_on_interface_levels', 'm') + enddo + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_clay3d, 'lake_clay3d', 'percent clay on soil levels in clm lake model', '%') + enddo + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_sand3d, 'lake_sand3d', 'percent sand on soil levels in clm lake model', '%') + enddo + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_dz3d, 'lake_dz3d', 'lake level thickness', 'm') + enddo + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_soil_watsat3d, 'lake_soil_watsat3d', 'saturated volumetric soil water', 'm3 m-3') + enddo + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_csol3d, 'lake_csol3d', 'soil heat capacity', 'J m-3 K-1') + enddo + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_soil_tkmg3d, 'lake_soil_tkmg3d', 'soil thermal conductivity, minerals', 'W m-1 K-1') + enddo + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_soil_tkdry3d, 'lake_soil_tkdry3d', 'soil thermal conductivity, dry soil', 'W m-1 K-1') + enddo + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_soil_tksatu3d, 'lake_soil_tksatu3d', 'soil thermal conductivity, saturated soil', 'W m-1 K-1') + enddo + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_snow_z3d, 'lake_snow_z3d', 'lake snow level depth', 'm') + enddo + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_snow_dz3d, 'lake_snow_dz3d', 'lake snow level thickness', 'm') + enddo + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_snow_zi3d, 'lake_snow_zi3d', 'lake snow interface depth', 'm') + enddo + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_h2osoi_vol3d, 'lake_h2osoi_vol3d', 'volumetric soil water', 'm3 m-3') + enddo + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_h2osoi_liq3d, 'lake_h2osoi_liq3d', 'soil liquid water content', 'kg m-2') + enddo + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_h2osoi_ice3d, 'lake_h2osoi_ice3d', 'soil ice water content', 'kg m-2') + enddo + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_t_soisno3d, 'lake_t_soisno3d', 'snow or soil level temperature', 'K') + enddo + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_t_lake3d, 'lake_t_lake3d', 'lake layer temperature', 'K') + enddo + + do iblk=1,nblks + call link_all_levels(Sfcprop(iblk)%lake_icefrac3d, 'lake_icefrac3d', 'lake fractional ice cover', 'fraction') + enddo + + contains + + subroutine link_all_levels(var3d, varname, levelname, unit) + implicit none + real(kind=kind_phys), target :: var3d(:,:) + character(len=*), intent(in) :: varname, levelname, unit + integer k, b, namelen + + if(iblk==1) then + namelen = 30+max(len(varname),len(levelname)) + allocate(character(namelen) :: fullname) + idx0 = idx + endif + + var_z_loop: do k=1,size(var3d,2) + idx = idx0 + k + if(iblk==1) then + ExtDiag(idx)%axes = 2 + write(fullname,"(A,'_',I0)") trim(varname),k + ExtDiag(idx)%name = trim(fullname) + write(fullname,"(A,' level ',I0,' of ',I0)") trim(levelname),k,size(var3d,2) + ExtDiag(idx)%desc = trim(fullname) + ExtDiag(idx)%unit = trim(unit) + ExtDiag(idx)%mod_name = 'gfs_sfc' + ExtDiag(idx)%intpl_method = 'nearest_stod' + + allocate (ExtDiag(idx)%data(nblks)) + do b=1,nblks + nullify(ExtDiag(idx)%data(b)%var2) + enddo + endif + + ExtDiag(idx)%data(iblk)%var2 => var3d(:,k) + enddo var_z_loop + + if(iblk==nblks) then + deallocate(fullname) + endif + end subroutine link_all_levels + end subroutine clm_lake_externaldiag_populate + function soil_layer_depth(lsm, lsm_ruc, lsm_noah, layer) result(layer_depth) character(len=30) :: layer_depth integer, intent(in) :: lsm, lsm_ruc, lsm_noah, layer diff --git a/ccpp/driver/GFS_restart.F90 b/ccpp/driver/GFS_restart.F90 index c68f48535c..a1447b67b8 100644 --- a/ccpp/driver/GFS_restart.F90 +++ b/ccpp/driver/GFS_restart.F90 @@ -63,6 +63,7 @@ subroutine GFS_restart_populate (Restart, Model, Statein, Stateout, Sfcprop, & integer :: ndiag_idx(20), itime integer :: nblks, num, nb, max_rstrt, offset character(len=2) :: c2 = '' + logical :: surface_layer_saves_rainprev nblks = size(Init_parm%blksz) max_rstrt = size(Restart%name2d) @@ -106,6 +107,12 @@ subroutine GFS_restart_populate (Restart, Model, Statein, Stateout, Sfcprop, & Restart%ldiag = 3 + Model%ntot2d + Model%nctp + ndiag_rst Restart%num2d = 3 + Model%ntot2d + Model%nctp + ndiag_rst + ! The CLM Lake Model needs raincprev and rainncprv, which some + ! surface layer schemes save, and some don't. If the surface layer + ! scheme does not save that variable, then it'll be saved + ! separately for clm_lake. + surface_layer_saves_rainprev = .false. + ! GF if (Model%imfdeepcnv == Model%imfdeepcnv_gf) then Restart%num2d = Restart%num2d + 3 @@ -121,15 +128,22 @@ subroutine GFS_restart_populate (Restart, Model, Statein, Stateout, Sfcprop, & ! NoahMP if (Model%lsm == Model%lsm_noahmp) then Restart%num2d = Restart%num2d + 10 + surface_layer_saves_rainprev = .true. endif ! RUC if (Model%lsm == Model%lsm_ruc) then Restart%num2d = Restart%num2d + 5 + surface_layer_saves_rainprev = .true. endif ! MYNN SFC if (Model%do_mynnsfclay) then Restart%num2d = Restart%num2d + 13 endif + ! Save rain prev for lake if surface layer doesn't. + if (Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_clm .and. & + .not.surface_layer_saves_rainprev) then + Restart%num2d = Restart%num2d + 2 + endif ! Thompson aerosol-aware if (Model%imp_physics == Model%imp_physics_thompson .and. Model%ltaerosol) then Restart%num2d = Restart%num2d + 2 @@ -429,6 +443,20 @@ subroutine GFS_restart_populate (Restart, Model, Statein, Stateout, Sfcprop, & Restart%data(nb,num)%var2p => Sfcprop(nb)%qss(:) enddo endif + ! Save rain prev for lake if surface layer doesn't. + if (Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_clm .and. & + .not.surface_layer_saves_rainprev) then + num = num + 1 + Restart%name2d(num) = 'raincprv' + do nb = 1,nblks + Restart%data(nb,num)%var2p => Sfcprop(nb)%raincprv(:) + enddo + num = num + 1 + Restart%name2d(num) = 'rainncprv' + do nb = 1,nblks + Restart%data(nb,num)%var2p => Sfcprop(nb)%rainncprv(:) + enddo + endif ! Thompson aerosol-aware if (Model%imp_physics == Model%imp_physics_thompson .and. Model%ltaerosol) then num = num + 1 diff --git a/ccpp/physics b/ccpp/physics index 494356c907..eda81a58a1 160000 --- a/ccpp/physics +++ b/ccpp/physics @@ -1 +1 @@ -Subproject commit 494356c90724cc020c8b6e7e4089767324c4b215 +Subproject commit eda81a58a1e3dd87c945f0d9cc43d53a1c858d65 diff --git a/ccpp/suites/suite_FV3_GFS_v16_clm_lake.xml b/ccpp/suites/suite_FV3_GFS_v16_clm_lake.xml new file mode 100644 index 0000000000..fb8dcd3ec3 --- /dev/null +++ b/ccpp/suites/suite_FV3_GFS_v16_clm_lake.xml @@ -0,0 +1,95 @@ + + + + + + + fv_sat_adj + + + + + GFS_time_vary_pre + GFS_rrtmg_setup + GFS_rad_time_vary + GFS_phys_time_vary + + + + + GFS_suite_interstitial_rad_reset + GFS_rrtmg_pre + GFS_radiation_surface + rad_sw_pre + rrtmg_sw + rrtmg_sw_post + rrtmg_lw_pre + rrtmg_lw + rrtmg_lw_post + GFS_rrtmg_post + + + + + GFS_suite_interstitial_phys_reset + GFS_suite_stateout_reset + get_prs_fv3 + GFS_suite_interstitial_1 + GFS_surface_generic_pre + GFS_surface_composites_pre + dcyc2t3 + GFS_surface_composites_inter + GFS_suite_interstitial_2 + + + + sfc_diff + GFS_surface_loop_control_part1 + sfc_nst_pre + sfc_nst + sfc_nst_post + lsm_noah + clm_lake + sfc_sice + GFS_surface_loop_control_part2 + + + + GFS_surface_composites_post + sfc_diag + sfc_diag_post + GFS_surface_generic_post + GFS_PBL_generic_pre + satmedmfvdifq + GFS_PBL_generic_post + GFS_GWD_generic_pre + cires_ugwp + cires_ugwp_post + GFS_GWD_generic_post + GFS_suite_stateout_update + ozphys_2015 + h2ophys + get_phi_fv3 + GFS_suite_interstitial_3 + GFS_DCNV_generic_pre + samfdeepcnv + GFS_DCNV_generic_post + GFS_SCNV_generic_pre + samfshalcnv + GFS_SCNV_generic_post + GFS_suite_interstitial_4 + cnvc90 + GFS_MP_generic_pre + gfdl_cloud_microphys + GFS_MP_generic_post + maximum_hourly_diagnostics + phys_tend + + + + + GFS_stochastics + + + + diff --git a/ccpp/suites/suite_FV3_HRRR.xml b/ccpp/suites/suite_FV3_HRRR.xml index 01c493d5a3..6ac35db14f 100644 --- a/ccpp/suites/suite_FV3_HRRR.xml +++ b/ccpp/suites/suite_FV3_HRRR.xml @@ -43,7 +43,7 @@ mynnsfc_wrapper GFS_surface_loop_control_part1 lsm_ruc - flake_driver + clm_lake GFS_surface_loop_control_part2 diff --git a/ccpp/suites/suite_FV3_HRRR_flake.xml b/ccpp/suites/suite_FV3_HRRR_flake.xml new file mode 100644 index 0000000000..3adea10694 --- /dev/null +++ b/ccpp/suites/suite_FV3_HRRR_flake.xml @@ -0,0 +1,82 @@ + + + + + + + GFS_time_vary_pre + GFS_rrtmg_setup + GFS_rad_time_vary + GFS_phys_time_vary + + + + + GFS_suite_interstitial_rad_reset + sgscloud_radpre + GFS_rrtmg_pre + GFS_radiation_surface + rad_sw_pre + rrtmg_sw + rrtmg_sw_post + rrtmg_lw_pre + rrtmg_lw + sgscloud_radpost + rrtmg_lw_post + GFS_rrtmg_post + + + + + GFS_suite_interstitial_phys_reset + GFS_suite_stateout_reset + get_prs_fv3 + GFS_suite_interstitial_1 + GFS_surface_generic_pre + GFS_surface_composites_pre + dcyc2t3 + GFS_surface_composites_inter + GFS_suite_interstitial_2 + + + + mynnsfc_wrapper + GFS_surface_loop_control_part1 + lsm_ruc + flake_driver + GFS_surface_loop_control_part2 + + + + GFS_surface_composites_post + sfc_diag + sfc_diag_post + GFS_surface_generic_post + rrfs_smoke_wrapper + mynnedmf_wrapper + rrfs_smoke_postpbl + GFS_GWD_generic_pre + drag_suite + GFS_GWD_generic_post + GFS_suite_stateout_update + ozphys_2015 + h2ophys + get_phi_fv3 + GFS_suite_interstitial_3 + GFS_suite_interstitial_4 + GFS_MP_generic_pre + mp_thompson_pre + mp_thompson + mp_thompson_post + GFS_MP_generic_post + maximum_hourly_diagnostics + phys_tend + + + + + GFS_stochastics + + + + diff --git a/ccpp/suites/suite_FV3_RAP_clm_lake.xml b/ccpp/suites/suite_FV3_RAP_clm_lake.xml new file mode 100644 index 0000000000..9a28a64212 --- /dev/null +++ b/ccpp/suites/suite_FV3_RAP_clm_lake.xml @@ -0,0 +1,91 @@ + + + + + + + GFS_time_vary_pre + GFS_rrtmg_setup + GFS_rad_time_vary + GFS_phys_time_vary + + + + + GFS_suite_interstitial_rad_reset + sgscloud_radpre + GFS_rrtmg_pre + GFS_radiation_surface + rad_sw_pre + rrtmg_sw + rrtmg_sw_post + rrtmg_lw_pre + rrtmg_lw + sgscloud_radpost + rrtmg_lw_post + GFS_rrtmg_post + + + + + GFS_suite_interstitial_phys_reset + GFS_suite_stateout_reset + get_prs_fv3 + GFS_suite_interstitial_1 + GFS_surface_generic_pre + GFS_surface_composites_pre + dcyc2t3 + GFS_surface_composites_inter + GFS_suite_interstitial_2 + + + + mynnsfc_wrapper + GFS_surface_loop_control_part1 + sfc_nst_pre + sfc_nst + sfc_nst_post + lsm_ruc + clm_lake + GFS_surface_loop_control_part2 + + + + GFS_surface_composites_post + sfc_diag + sfc_diag_post + GFS_surface_generic_post + mynnedmf_wrapper + GFS_GWD_generic_pre + drag_suite + GFS_GWD_generic_post + GFS_suite_stateout_update + ozphys_2015 + h2ophys + get_phi_fv3 + GFS_suite_interstitial_3 + GFS_DCNV_generic_pre + cu_gf_driver_pre + cu_gf_driver + GFS_DCNV_generic_post + GFS_SCNV_generic_pre + GFS_SCNV_generic_post + GFS_suite_interstitial_4 + cnvc90 + GFS_MP_generic_pre + mp_thompson_pre + mp_thompson + mp_thompson_post + GFS_MP_generic_post + cu_gf_driver_post + maximum_hourly_diagnostics + phys_tend + + + + + GFS_stochastics + + + + diff --git a/io/FV3GFS_io.F90 b/io/FV3GFS_io.F90 index a84eabcfb7..876248d162 100644 --- a/io/FV3GFS_io.F90 +++ b/io/FV3GFS_io.F90 @@ -33,7 +33,7 @@ module FV3GFS_io_mod use diag_util_mod, only: find_input_field use constants_mod, only: grav, rdgas use physcons, only: con_tice !saltwater freezing temp (K) - + use clm_lake_io, only: clm_lake_data_type ! !--- GFS_typedefs use GFS_typedefs, only: GFS_sfcprop_type, GFS_control_type, & @@ -99,7 +99,7 @@ module FV3GFS_io_mod real(kind=kind_phys),dimension(:,:,:),allocatable:: uwork3d logical :: uwork_set = .false. character(128) :: uwindname - integer, parameter, public :: DIAG_SIZE = 500 + integer, parameter, public :: DIAG_SIZE = 800 real, parameter :: missing_value = 9.99e20_r8 real, parameter:: stndrd_atmos_ps = 101325.0_r8 real, parameter:: stndrd_atmos_lapse = 0.0065_r8 @@ -243,6 +243,10 @@ subroutine FV3GFS_GFS_checksum (Model, GFS_Data, Atm_block) nsfcprop2d = nsfcprop2d + 16 endif + if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_flake) then + nsfcprop2d = nsfcprop2d + 10 + endif + allocate (temp2d(isc:iec,jsc:jec,nsfcprop2d+Model%ntot2d+Model%nctp)) allocate (temp3d(isc:iec,jsc:jec,1:lev,14+Model%ntot3d+2*ntr)) allocate (temp3dlevsp1(isc:iec,jsc:jec,1:lev+1,3)) @@ -480,6 +484,20 @@ subroutine FV3GFS_GFS_checksum (Model, GFS_Data, Atm_block) call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%qrain) endif nstf_name_choice +! Flake + if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%T_snow) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%T_ice) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%h_ML) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%t_ML) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%t_mnw) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%h_talb) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%t_talb) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%t_bot1) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%t_bot2) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%c_t) + endif + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Tbd%phy_f2d) call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Tbd%phy_fctd) @@ -837,6 +855,19 @@ pure subroutine fill_Sfcprop_names(Model,sfc_name2,sfc_name3,nvar_s2m,warm_start else if (Model%lsm == Model%lsm_ruc .and. Model%rdlai) then nt=nt+1 ; sfc_name2(nt) = 'lai' endif + + if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then + nt=nt+1 ; sfc_name2(nt) = 'T_snow' + nt=nt+1 ; sfc_name2(nt) = 'T_ice' + nt=nt+1 ; sfc_name2(nt) = 'h_ML' + nt=nt+1 ; sfc_name2(nt) = 't_ML' + nt=nt+1 ; sfc_name2(nt) = 't_mnw' + nt=nt+1 ; sfc_name2(nt) = 'h_talb' + nt=nt+1 ; sfc_name2(nt) = 't_talb' + nt=nt+1 ; sfc_name2(nt) = 't_bot1' + nt=nt+1 ; sfc_name2(nt) = 't_bot2' + nt=nt+1 ; sfc_name2(nt) = 'c_t' + endif end subroutine fill_sfcprop_names !---------------------------------------------------------------------- @@ -868,7 +899,7 @@ subroutine sfc_prop_restart_read (Sfcprop, Atm_block, Model, fv_domain, warm_sta integer :: nvar_oro_ls_ss integer :: nvar_vegfr, nvar_soilfr integer :: nvar_s2r, nvar_s2mp, nvar_s3mp, isnow - integer :: nvar_emi, nvar_dust12m, nvar_rrfssd + integer :: nvar_emi, nvar_dust12m, nvar_gbbepx, nvar_before_lake, nvar_s2l, nvar_rrfssd integer, allocatable :: ii1(:), jj1(:) real(kind=kind_phys), pointer, dimension(:,:) :: var2_p => NULL() real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p => NULL() @@ -887,6 +918,7 @@ subroutine sfc_prop_restart_read (Sfcprop, Atm_block, Model, fv_domain, warm_sta logical :: amiopen logical :: is_lsoil + type(clm_lake_data_type) :: clm_lake type(rrfs_sd_data_type) :: rrfs_sd_data nvar_o2 = 19 @@ -1042,8 +1074,20 @@ subroutine sfc_prop_restart_read (Sfcprop, Atm_block, Model, fv_domain, warm_sta Sfcprop(nb)%lakefrac(ix) = -9999.0 num = num + 1 ; Sfcprop(nb)%landfrac(ix) = oro_var2(i,j,num) !land frac [0:1] - num = num + 1 ; Sfcprop(nb)%lakefrac(ix) = oro_var2(i,j,num) !lake frac [0:1] - num = num + 1 ; Sfcprop(nb)%lakedepth(ix) = oro_var2(i,j,num) !lake depth [m] !YWu + if (Model%lkm > 0 ) then + if(oro_var2(i,j,num+1)>Model%lakefrac_threshold .and. & + oro_var2(i,j,num+2)>Model%lakedepth_threshold) then + Sfcprop(nb)%lakefrac(ix) = oro_var2(i,j,num+1) !lake frac [0:1] + Sfcprop(nb)%lakedepth(ix) = oro_var2(i,j,num+2) !lake depth [m] !YWu + else + Sfcprop(nb)%lakefrac(ix) = 0 + Sfcprop(nb)%lakedepth(ix) = -9999 + endif + else + Sfcprop(nb)%lakefrac(ix) = oro_var2(i,j,num+1) !lake frac [0:1] + Sfcprop(nb)%lakedepth(ix) = oro_var2(i,j,num+2) !lake depth [m] !YWu + endif + num = num + 2 ! To account for lakefrac and lakedepth Sfcprop(nb)%vegtype_frac(ix,:) = -9999.0 Sfcprop(nb)%soiltype_frac(ix,:) = -9999.0 @@ -1069,6 +1113,14 @@ subroutine sfc_prop_restart_read (Sfcprop, Atm_block, Model, fv_domain, warm_sta if (Model%cplwav) then nvar_s2m = nvar_s2m + 1 endif +! CLM Lake and Flake + if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake ) then + nvar_s2l = 10 + else + nvar_s2l = 0 + endif + + nvar_before_lake=nvar_s2m+nvar_s2o+nvar_s2r+nvar_s2mp !--- deallocate containers and free restart container deallocate(oro_name2, oro_var2) @@ -1332,9 +1384,9 @@ subroutine sfc_prop_restart_read (Sfcprop, Atm_block, Model, fv_domain, warm_sta if (.not. allocated(sfc_name2)) then !--- allocate the various containers needed for restarts - allocate(sfc_name2(nvar_s2m+nvar_s2o+nvar_s2mp+nvar_s2r)) + allocate(sfc_name2(nvar_s2m+nvar_s2o+nvar_s2mp+nvar_s2r+nvar_s2l)) allocate(sfc_name3(0:nvar_s3+nvar_s3mp)) - allocate(sfc_var2(nx,ny,nvar_s2m+nvar_s2o+nvar_s2mp+nvar_s2r)) + allocate(sfc_var2(nx,ny,nvar_s2m+nvar_s2o+nvar_s2mp+nvar_s2r+nvar_s2l)) ! Note that this may cause problems with RUC LSM for coldstart runs from GFS data ! if the initial conditions do contain this variable, because Model%kice is 9 for ! RUC LSM, but tiice in the initial conditions will only have two vertical layers @@ -1391,6 +1443,14 @@ subroutine sfc_prop_restart_read (Sfcprop, Atm_block, Model, fv_domain, warm_sta call register_axis(Sfc_restart, 'Time', unlimited) end if + ! Tell CLM Lake to allocate data, and register its axes and fields + if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_clm) then + call clm_lake%allocate_data(Model) + call clm_lake%copy_to_temporaries(Model,Sfcprop,Atm_block) + call clm_lake%register_axes(Model, Sfc_restart) + call clm_lake%register_fields(Sfc_restart) + endif + if(Model%rrfs_sd) then call rrfs_sd_data%allocate_data(Model) call rrfs_sd_data%fill_data(Model, Sfcprop, Atm_block) @@ -1466,6 +1526,20 @@ subroutine sfc_prop_restart_read (Sfcprop, Atm_block, Model, fv_domain, warm_sta end if enddo endif ! noahmp + +! Flake + if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then + mand = .false. + do num = nvar_before_lake+1,nvar_before_lake+nvar_s2l + var2_p => sfc_var2(:,:,num) + if(is_lsoil) then + call register_restart_field(Sfc_restart, sfc_name2(num),var2_p,dimensions=(/'lat','lon'/), is_optional=.not.mand) + else + call register_restart_field(Sfc_restart, sfc_name2(num),var2_p,dimensions=(/'Time ','yaxis_1','xaxis_1'/), is_optional=.not.mand) + endif + enddo + endif + nullify(var2_p) endif ! if not allocated @@ -1547,6 +1621,11 @@ subroutine sfc_prop_restart_read (Sfcprop, Atm_block, Model, fv_domain, warm_sta call read_restart(Sfc_restart, ignore_checksum=ignore_rst_cksum) call close_file(Sfc_restart) + ! Tell clm_lake to copy data to temporary arrays + if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_clm) then + call clm_lake%copy_from_temporaries(Model,Sfcprop,Atm_block) + endif + if(Model%rrfs_sd) then call rrfs_sd_data%copy_from_temporaries(Model,Sfcprop,Atm_block) end if @@ -1839,7 +1918,18 @@ subroutine sfc_prop_restart_read (Sfcprop, Atm_block, Model, fv_domain, warm_sta call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%deeprechxy) call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%rechxy) endif - + if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then + call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%T_snow) + call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%T_ice) + call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%h_ML) + call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_ML) + call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_mnw) + call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%h_talb) + call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_talb) + call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_bot1) + call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_bot2) + call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%c_t) + endif if (Model%lsm == Model%lsm_noah .or. Model%lsm == Model%lsm_noahmp .or. (.not.warm_start)) then !--- 3D variables nt=0 @@ -2114,7 +2204,7 @@ subroutine sfc_prop_restart_read (Sfcprop, Atm_block, Model, fv_domain, warm_sta enddo endif - ! A standard-compliant Fortran 2003 compiler will call rrfs_sd_final here + ! A standard-compliant Fortran 2003 compiler will call clm_lake_final and rrfs_sd_final here. end subroutine sfc_prop_restart_read @@ -2141,7 +2231,7 @@ subroutine sfc_prop_restart_write (Sfcprop, Atm_block, Model, fv_domain, timesta integer :: isc, iec, jsc, jec, npz, nx, ny integer :: id_restart integer :: nvar2m, nvar2o, nvar3 - integer :: nvar2r, nvar2mp, nvar3mp + integer :: nvar2r, nvar2mp, nvar3mp, nvar_before_lake, nvar2l logical :: mand integer, allocatable :: ii1(:), jj1(:) character(len=32) :: fn_srf = 'sfc_data.nc' @@ -2159,6 +2249,7 @@ subroutine sfc_prop_restart_write (Sfcprop, Atm_block, Model, fv_domain, timesta !--- variables used for fms2_io register axis integer :: is, ie integer, allocatable, dimension(:) :: buffer + type(clm_lake_data_type), target :: clm_lake !--- temporary variables for storing rrfs_sd fields type(rrfs_sd_data_type) :: rrfs_sd_data @@ -2190,6 +2281,14 @@ subroutine sfc_prop_restart_write (Sfcprop, Atm_block, Model, fv_domain, timesta nvar2mp = 29 nvar3mp = 5 endif +!CLM Lake and Flake + if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then + nvar2l = 10 + else + nvar2l = 0 + endif + + nvar_before_lake=nvar2m+nvar2o+nvar2r+nvar2mp isc = Atm_block%isc iec = Atm_block%iec @@ -2199,11 +2298,13 @@ subroutine sfc_prop_restart_write (Sfcprop, Atm_block, Model, fv_domain, timesta nx = (iec - isc + 1) ny = (jec - jsc + 1) + nvar_before_lake=nvar2m+nvar2o+nvar2r+nvar2mp + if (Model%lsm == Model%lsm_ruc) then if (allocated(sfc_name2)) then ! Re-allocate if one or more of the dimensions don't match - if (size(sfc_name2).ne.nvar2m+nvar2o+nvar2mp+nvar2r .or. & - size(sfc_name3).ne.nvar3+nvar3mp .or. & + if (size(sfc_name2).ne.nvar2m+nvar2o+nvar2mp+nvar2r+nvar2l .or. & + size(sfc_name3).ne.nvar3+nvar3mp .or. & size(sfc_var3,dim=3).ne.Model%lsoil_lsm) then !--- deallocate containers and free restart container deallocate(sfc_name2) @@ -2285,6 +2386,13 @@ subroutine sfc_prop_restart_write (Sfcprop, Atm_block, Model, fv_domain, timesta else call mpp_error(FATAL, 'Error in opening file'//trim(infile) ) end if if_amiopen + + ! Tell clm_lake to allocate data, register its axes, and call write_data for each axis's variable + if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_clm) then + call clm_lake%allocate_data(Model) + call clm_lake%register_axes(Model, Sfc_restart) + call clm_lake%write_axes(Model, Sfc_restart) + endif if(Model%rrfs_sd) then call rrfs_sd_data%allocate_data(Model) @@ -2294,9 +2402,9 @@ subroutine sfc_prop_restart_write (Sfcprop, Atm_block, Model, fv_domain, timesta if (.not. allocated(sfc_name2)) then !--- allocate the various containers needed for restarts - allocate(sfc_name2(nvar2m+nvar2o+nvar2mp+nvar2r)) + allocate(sfc_name2(nvar2m+nvar2o+nvar2mp+nvar2r+nvar2l)) allocate(sfc_name3(0:nvar3+nvar3mp)) - allocate(sfc_var2(nx,ny,nvar2m+nvar2o+nvar2mp+nvar2r)) + allocate(sfc_var2(nx,ny,nvar2m+nvar2o+nvar2mp+nvar2r+nvar2l)) if (Model%lsm == Model%lsm_noah .or. Model%lsm == Model%lsm_noahmp) then allocate(sfc_var3(nx,ny,Model%lsoil,nvar3)) elseif (Model%lsm == Model%lsm_ruc) then @@ -2316,6 +2424,20 @@ subroutine sfc_prop_restart_write (Sfcprop, Atm_block, Model, fv_domain, timesta call fill_Sfcprop_names(Model,sfc_name2,sfc_name3,nvar2m,.true.) end if + if(Model%lkm>0) then + if(Model%iopt_lake==Model%iopt_lake_flake ) then + if(Model%me==0) then + if(size(sfc_name2)/=nvar_before_lake+10) then +3814 format("ERROR: size mismatch size(sfc_name2)=",I0," /= nvar_before_lake+10=",I0) + write(0,3814) size(sfc_name2),nvar_before_lake+10 + endif + endif + else if(Model%iopt_lake==Model%iopt_lake_clm) then + ! Tell clm_lake to register all of its fields + call clm_lake%register_fields(Sfc_restart) + endif + endif + if(Model%rrfs_sd) then call rrfs_sd_data%register_fields endif @@ -2427,7 +2549,22 @@ subroutine sfc_prop_restart_write (Sfcprop, Atm_block, Model, fv_domain, timesta nullify(var3_p3) endif ! lsm = lsm_noahmp - if(Model%rrfs_sd) then + !Flake + if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then + mand = .false. + do num = nvar_before_lake+1,nvar_before_lake+nvar2l + var2_p => sfc_var2(:,:,num) + call register_restart_field(Sfc_restart, sfc_name2(num),var2_p,dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/),& + &is_optional=.not.mand) + enddo + endif + + ! Tell clm_lake to copy Sfcprop data to its internal temporary arrays. + if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_clm) then + call clm_lake%copy_to_temporaries(Model,Sfcprop,Atm_block) + endif + + if(Model%rrfs_sd) then call rrfs_sd_data%copy_to_temporaries(Model,Sfcprop,Atm_block) endif @@ -2570,6 +2707,19 @@ subroutine sfc_prop_restart_write (Sfcprop, Atm_block, Model, fv_domain, timesta call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%deeprechxy) call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%rechxy) endif +! Flake + if(Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%T_snow) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%T_ice) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%h_ML) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_ML) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_mnw) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%h_talb) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_talb) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_bot1) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_bot2) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%c_t) + endif do k = 1,Model%kice do ix = 1, Atm_block%blksz(nb) ice=Sfcprop(nb)%tiice(ix,k) @@ -2644,7 +2794,7 @@ subroutine sfc_prop_restart_write (Sfcprop, Atm_block, Model, fv_domain, timesta call write_restart(Sfc_restart) call close_file(Sfc_restart) - ! A standard-compliant Fortran 2003 compiler will call rrfs_sd_final here + ! A standard-compliant Fortran 2003 compiler will call rrfs_sd_final and clm_lake_final here end subroutine sfc_prop_restart_write diff --git a/io/clm_lake_io.F90 b/io/clm_lake_io.F90 new file mode 100644 index 0000000000..6a47f3ab6a --- /dev/null +++ b/io/clm_lake_io.F90 @@ -0,0 +1,432 @@ +module clm_lake_io + use GFS_typedefs, only: GFS_sfcprop_type, GFS_control_type, & + GFS_data_type, kind_phys + use GFS_restart, only: GFS_restart_type + use GFS_diagnostics, only: GFS_externaldiag_type + use block_control_mod, only: block_control_type + use fms2_io_mod, only: FmsNetcdfDomainFile_t, unlimited, & + open_file, close_file, & + register_axis, register_restart_field, & + register_variable_attribute, register_field, & + read_restart, write_restart, write_data, & + get_global_io_domain_indices, variable_exists + + implicit none + + type clm_lake_data_type + ! The clm_lake_data_type derived type is a class that stores + ! temporary arrays used to read or write CLM Lake model restart + ! and axis variables. It can safely be declared and unused, but + ! you should only call these routines if the CLM Lake Model was + ! (or will be) used by this execution of the FV3. It is the + ! responsibility of the caller to ensure the necessary data is in + ! Sfc_restart, Sfcprop, and Model. + + ! All 2D variables needed for a restart + real(kind_phys), pointer, private, dimension(:,:) :: & + T_snow=>null(), T_ice=>null(), & + lake_snl2d=>null(), lake_h2osno2d=>null(), lake_tsfc=>null(), clm_lakedepth=>null(), & + lake_savedtke12d=>null(), lake_sndpth2d=>null(), clm_lake_initialized=>null() + + ! All 3D variables needed for a restart + real(kind_phys), pointer, private, dimension(:,:,:) :: & + lake_z3d=>null(), lake_dz3d=>null(), lake_soil_watsat3d=>null(), & + lake_csol3d=>null(), lake_soil_tkmg3d=>null(), lake_soil_tkdry3d=>null(), & + lake_soil_tksatu3d=>null(), lake_snow_z3d=>null(), lake_snow_dz3d=>null(), & + lake_snow_zi3d=>null(), lake_h2osoi_vol3d=>null(), lake_h2osoi_liq3d=>null(), & + lake_h2osoi_ice3d=>null(), lake_t_soisno3d=>null(), lake_t_lake3d=>null(), & + lake_icefrac3d=>null(), lake_clay3d=>null(), lake_sand3d=>null() + + contains + + ! register_axes calls registers_axis on Sfc_restart for all required axes + procedure, public :: register_axes => clm_lake_register_axes + + ! allocate_data allocates all of the pointers in this object + procedure, public :: allocate_data => clm_lake_allocate_data + + ! register_fields calls register_field on Sfc_restart for all CLM Lake model restart variables + procedure, public :: register_fields => clm_lake_register_fields + + ! deallocate_data deallocates all pointers, allowing this object to be used repeatedly. + ! It is safe to call deallocate_data if no data has been allocated. + procedure, public :: deallocate_data => clm_lake_deallocate_data + + ! write_axes writes variables to Sfc_restart, with the name of + ! each axis, containing the appropriate information + procedure, public :: write_axes => clm_lake_write_axes + + ! copy_to_temporaries copies from Sfcprop to internal pointers (declared above) + procedure, public :: copy_to_temporaries => clm_lake_copy_to_temporaries + + ! copy_to_temporaries copies from internal pointers (declared above) to Sfcprop + procedure, public :: copy_from_temporaries => clm_lake_copy_from_temporaries + + ! A fortran 2003 compliant compiler will call clm_lake_final + ! automatically when an object of this type goes out of + ! scope. This will deallocate any arrays via a call to + ! deallocate_data. It is safe to call this routine if no data has + ! been allocated. + final :: clm_lake_final + end type clm_lake_data_type + + CONTAINS + subroutine clm_lake_allocate_data(data,Model) + ! Deallocate all data, and reallocate to the size specified in Model + implicit none + class(clm_lake_data_type) :: data + type(GFS_control_type), intent(in) :: Model + + integer :: nx, ny + call data%deallocate_data + + nx=Model%nx + ny=Model%ny + + allocate(data%T_snow(nx,ny)) + allocate(data%T_ice(nx,ny)) + allocate(data%lake_snl2d(nx,ny)) + allocate(data%lake_h2osno2d(nx,ny)) + allocate(data%lake_tsfc(nx,ny)) + allocate(data%lake_savedtke12d(nx,ny)) + allocate(data%lake_sndpth2d(nx,ny)) + allocate(data%clm_lakedepth(nx,ny)) + allocate(data%clm_lake_initialized(nx,ny)) + + allocate(data%lake_z3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(data%lake_dz3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(data%lake_soil_watsat3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(data%lake_csol3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(data%lake_soil_tkmg3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(data%lake_soil_tkdry3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(data%lake_soil_tksatu3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(data%lake_snow_z3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) + allocate(data%lake_snow_dz3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) + allocate(data%lake_snow_zi3d(nx,ny,Model%nlevsnowsoil_clm_lake)) + allocate(data%lake_h2osoi_vol3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) + allocate(data%lake_h2osoi_liq3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) + allocate(data%lake_h2osoi_ice3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) + allocate(data%lake_t_soisno3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) + allocate(data%lake_t_lake3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(data%lake_icefrac3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(data%lake_clay3d(nx,ny,Model%nlevsoil_clm_lake)) + allocate(data%lake_sand3d(nx,ny,Model%nlevsoil_clm_lake)) + end subroutine clm_lake_allocate_data + + subroutine clm_lake_register_axes(data,Model,Sfc_restart) + ! Register all five axes needed by CLM Lake restart data + implicit none + class(clm_lake_data_type) :: data + type(GFS_control_type), intent(in) :: Model + type(FmsNetcdfDomainFile_t) :: Sfc_restart + call register_axis(Sfc_restart, 'levlake_clm_lake', dimension_length=Model%nlevlake_clm_lake) + + call register_axis(Sfc_restart, 'levsoil_clm_lake', dimension_length=Model%nlevsoil_clm_lake) + + call register_axis(Sfc_restart, 'levsnow_clm_lake', dimension_length=Model%nlevsnow_clm_lake) + + call register_axis(Sfc_restart, 'levsnowsoil_clm_lake', dimension_length=Model%nlevsnowsoil_clm_lake) + + call register_axis(Sfc_restart, 'levsnowsoil1_clm_lake', dimension_length=Model%nlevsnowsoil1_clm_lake) + end subroutine clm_lake_register_axes + + subroutine clm_lake_write_axes(data, Model, Sfc_restart) + ! Create variables with the name name as each clm_lake axis, and + ! fill the variable with the appropriate indices + implicit none + class(clm_lake_data_type) :: data + type(GFS_control_type), intent(in) :: Model + type(FmsNetcdfDomainFile_t) :: Sfc_restart + real(kind_phys) :: levlake_clm_lake(Model%nlevlake_clm_lake) + real(kind_phys) :: levsoil_clm_lake(Model%nlevsoil_clm_lake) + real(kind_phys) :: levsnow_clm_lake(Model%nlevsnow_clm_lake) + real(kind_phys) :: levsnowsoil_clm_lake(Model%nlevsnowsoil_clm_lake) + real(kind_phys) :: levsnowsoil1_clm_lake(Model%nlevsnowsoil1_clm_lake) + integer :: i + call register_field(Sfc_restart, 'levlake_clm_lake', 'double', (/'levlake_clm_lake'/)) + call register_variable_attribute(Sfc_restart, 'levlake_clm_lake', 'cartesian_axis' ,'Z', str_len=1) + + call register_field(Sfc_restart, 'levsoil_clm_lake', 'double', (/'levsoil_clm_lake'/)) + call register_variable_attribute(Sfc_restart, 'levsoil_clm_lake', 'cartesian_axis' ,'Z', str_len=1) + + call register_field(Sfc_restart, 'levsnow_clm_lake', 'double', (/'levsnow_clm_lake'/)) + call register_variable_attribute(Sfc_restart, 'levsnow_clm_lake', 'cartesian_axis' ,'Z', str_len=1) + + call register_field(Sfc_restart, 'levsnowsoil_clm_lake', 'double', (/'levsnowsoil_clm_lake'/)) + call register_variable_attribute(Sfc_restart, 'levsnowsoil_clm_lake', 'cartesian_axis' ,'Z', str_len=1) + + call register_field(Sfc_restart, 'levsnowsoil1_clm_lake', 'double', (/'levsnowsoil1_clm_lake'/)) + call register_variable_attribute(Sfc_restart, 'levsnowsoil1_clm_lake', 'cartesian_axis' ,'Z', str_len=1) + + do i=1,Model%nlevlake_clm_lake + levlake_clm_lake(i) = i + enddo + do i=1,Model%nlevsoil_clm_lake + levsoil_clm_lake(i) = i + enddo + do i=1,Model%nlevsnow_clm_lake + levsnow_clm_lake(i) = i + enddo + do i=-Model%nlevsnow_clm_lake,Model%nlevsoil_clm_lake + levsnowsoil_clm_lake(i+Model%nlevsnow_clm_lake+1) = i + enddo + do i=-Model%nlevsnow_clm_lake+1,Model%nlevsoil_clm_lake + levsnowsoil1_clm_lake(i+Model%nlevsnow_clm_lake) = i + enddo + + call write_data(Sfc_restart, 'levlake_clm_lake', levlake_clm_lake) + call write_data(Sfc_restart, 'levsoil_clm_lake', levsoil_clm_lake) + call write_data(Sfc_restart, 'levsnow_clm_lake', levsnow_clm_lake) + call write_data(Sfc_restart, 'levsnowsoil_clm_lake', levsnowsoil_clm_lake) + call write_data(Sfc_restart, 'levsnowsoil1_clm_lake', levsnowsoil1_clm_lake) + end subroutine clm_lake_write_axes + + subroutine clm_lake_copy_to_temporaries(data, Model, Sfcprop, Atm_block) + ! Copies from Sfcprop variables to the corresponding data temporary variables. + ! Terrible things will happen if you don't call data%allocate_data first. + implicit none + class(clm_lake_data_type) :: data + type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) + type(GFS_control_type), intent(in) :: Model + type(block_control_type), intent(in) :: Atm_block + + integer :: nb, ix, isc, jsc, i, j + isc = Model%isc + jsc = Model%jsc + + ! Copy data to temporary arrays + +!$omp parallel do default(shared) private(i, j, nb, ix) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - isc + 1 + j = Atm_block%index(nb)%jj(ix) - jsc + 1 + + data%T_snow(i,j) = Sfcprop(nb)%T_snow(ix) + data%T_ice(i,j) = Sfcprop(nb)%T_ice(ix) + data%lake_snl2d(i,j) = Sfcprop(nb)%lake_snl2d(ix) + data%lake_h2osno2d(i,j) = Sfcprop(nb)%lake_h2osno2d(ix) + data%lake_tsfc(i,j) = Sfcprop(nb)%lake_tsfc(ix) + data%lake_savedtke12d(i,j) = Sfcprop(nb)%lake_savedtke12d(ix) + data%lake_sndpth2d(i,j) = Sfcprop(nb)%lake_sndpth2d(ix) + data%clm_lakedepth(i,j) = Sfcprop(nb)%clm_lakedepth(ix) + data%clm_lake_initialized(i,j) = Sfcprop(nb)%clm_lake_initialized(ix) + + data%lake_z3d(i,j,:) = Sfcprop(nb)%lake_z3d(ix,:) + data%lake_dz3d(i,j,:) = Sfcprop(nb)%lake_dz3d(ix,:) + data%lake_soil_watsat3d(i,j,:) = Sfcprop(nb)%lake_soil_watsat3d(ix,:) + data%lake_csol3d(i,j,:) = Sfcprop(nb)%lake_csol3d(ix,:) + data%lake_soil_tkmg3d(i,j,:) = Sfcprop(nb)%lake_soil_tkmg3d(ix,:) + data%lake_soil_tkdry3d(i,j,:) = Sfcprop(nb)%lake_soil_tkdry3d(ix,:) + data%lake_soil_tksatu3d(i,j,:) = Sfcprop(nb)%lake_soil_tksatu3d(ix,:) + data%lake_snow_z3d(i,j,:) = Sfcprop(nb)%lake_snow_z3d(ix,:) + data%lake_snow_dz3d(i,j,:) = Sfcprop(nb)%lake_snow_dz3d(ix,:) + data%lake_snow_zi3d(i,j,:) = Sfcprop(nb)%lake_snow_zi3d(ix,:) + data%lake_h2osoi_vol3d(i,j,:) = Sfcprop(nb)%lake_h2osoi_vol3d(ix,:) + data%lake_h2osoi_liq3d(i,j,:) = Sfcprop(nb)%lake_h2osoi_liq3d(ix,:) + data%lake_h2osoi_ice3d(i,j,:) = Sfcprop(nb)%lake_h2osoi_ice3d(ix,:) + data%lake_t_soisno3d(i,j,:) = Sfcprop(nb)%lake_t_soisno3d(ix,:) + data%lake_t_lake3d(i,j,:) = Sfcprop(nb)%lake_t_lake3d(ix,:) + data%lake_icefrac3d(i,j,:) = Sfcprop(nb)%lake_icefrac3d(ix,:) + data%lake_clay3d(i,j,:) = Sfcprop(nb)%lake_clay3d(ix,:) + data%lake_sand3d(i,j,:) = Sfcprop(nb)%lake_sand3d(ix,:) + enddo + enddo + end subroutine clm_lake_copy_to_temporaries + + subroutine clm_lake_copy_from_temporaries(data, Model, Sfcprop, Atm_block) + ! Copies from data temporary variables to the corresponding Sfcprop variables. + ! Terrible things will happen if you don't call data%allocate_data first. + implicit none + class(clm_lake_data_type) :: data + type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) + type(GFS_control_type), intent(in) :: Model + type(block_control_type), intent(in) :: Atm_block + + integer :: nb, ix, isc, jsc, i, j + isc = Model%isc + jsc = Model%jsc + + ! Copy data to temporary arrays + +!$omp parallel do default(shared) private(i, j, nb, ix) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - isc + 1 + j = Atm_block%index(nb)%jj(ix) - jsc + 1 + + Sfcprop(nb)%T_snow(ix) = data%T_snow(i,j) + Sfcprop(nb)%T_ice(ix) = data%T_ice(i,j) + Sfcprop(nb)%lake_snl2d(ix) = data%lake_snl2d(i,j) + Sfcprop(nb)%lake_h2osno2d(ix) = data%lake_h2osno2d(i,j) + Sfcprop(nb)%lake_tsfc(ix) = data%lake_tsfc(i,j) + Sfcprop(nb)%lake_savedtke12d(ix) = data%lake_savedtke12d(i,j) + Sfcprop(nb)%lake_sndpth2d(ix) = data%lake_sndpth2d(i,j) + Sfcprop(nb)%clm_lakedepth(ix) = data%clm_lakedepth(i,j) + Sfcprop(nb)%clm_lake_initialized(ix) = data%clm_lake_initialized(i,j) + + Sfcprop(nb)%lake_z3d(ix,:) = data%lake_z3d(i,j,:) + Sfcprop(nb)%lake_dz3d(ix,:) = data%lake_dz3d(i,j,:) + Sfcprop(nb)%lake_soil_watsat3d(ix,:) = data%lake_soil_watsat3d(i,j,:) + Sfcprop(nb)%lake_csol3d(ix,:) = data%lake_csol3d(i,j,:) + Sfcprop(nb)%lake_soil_tkmg3d(ix,:) = data%lake_soil_tkmg3d(i,j,:) + Sfcprop(nb)%lake_soil_tkdry3d(ix,:) = data%lake_soil_tkdry3d(i,j,:) + Sfcprop(nb)%lake_soil_tksatu3d(ix,:) = data%lake_soil_tksatu3d(i,j,:) + Sfcprop(nb)%lake_snow_z3d(ix,:) = data%lake_snow_z3d(i,j,:) + Sfcprop(nb)%lake_snow_dz3d(ix,:) = data%lake_snow_dz3d(i,j,:) + Sfcprop(nb)%lake_snow_zi3d(ix,:) = data%lake_snow_zi3d(i,j,:) + Sfcprop(nb)%lake_h2osoi_vol3d(ix,:) = data%lake_h2osoi_vol3d(i,j,:) + Sfcprop(nb)%lake_h2osoi_liq3d(ix,:) = data%lake_h2osoi_liq3d(i,j,:) + Sfcprop(nb)%lake_h2osoi_ice3d(ix,:) = data%lake_h2osoi_ice3d(i,j,:) + Sfcprop(nb)%lake_t_soisno3d(ix,:) = data%lake_t_soisno3d(i,j,:) + Sfcprop(nb)%lake_t_lake3d(ix,:) = data%lake_t_lake3d(i,j,:) + Sfcprop(nb)%lake_icefrac3d(ix,:) = data%lake_icefrac3d(i,j,:) + Sfcprop(nb)%lake_clay3d(ix,:) = data%lake_clay3d(i,j,:) + Sfcprop(nb)%lake_sand3d(ix,:) = data%lake_sand3d(i,j,:) + enddo + enddo + end subroutine clm_lake_copy_from_temporaries + + subroutine clm_lake_register_fields(data, Sfc_restart) + ! Registers all restart fields needed by the CLM Lake Model. + ! Terrible things will happen if you don't call data%allocate_data + ! and data%register_axes first. + implicit none + class(clm_lake_data_type) :: data + type(FmsNetcdfDomainFile_t) :: Sfc_restart + + ! Register 2D fields + call register_restart_field(Sfc_restart, 'T_snow', data%T_snow, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'T_ice', data%T_ice, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'lake_snl2d', data%lake_snl2d, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'lake_h2osno2d', data%lake_h2osno2d, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'lake_tsfc', data%lake_tsfc, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'lake_savedtke12d', data%lake_savedtke12d, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'lake_sndpth2d', data%lake_sndpth2d, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'clm_lakedepth', data%clm_lakedepth, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'clm_lake_initialized', data%clm_lake_initialized, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + + ! Register 3D fields + call register_restart_field(Sfc_restart, 'lake_z3d', data%lake_z3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'lake_dz3d', data%lake_dz3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_soil_watsat3d', data%lake_soil_watsat3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_csol3d', data%lake_csol3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_soil_tkmg3d', data%lake_soil_tkmg3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_soil_tkdry3d', data%lake_soil_tkdry3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_soil_tksatu3d', data%lake_soil_tksatu3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_snow_z3d', data%lake_snow_z3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_snow_dz3d', data%lake_snow_dz3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_snow_zi3d', data%lake_snow_zi3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsnowsoil_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_h2osoi_vol3d', data%lake_h2osoi_vol3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_h2osoi_liq3d', data%lake_h2osoi_liq3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_h2osoi_ice3d', data%lake_h2osoi_ice3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_t_soisno3d', data%lake_t_soisno3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_t_lake3d', data%lake_t_lake3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_icefrac3d', data%lake_icefrac3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_clay3d', data%lake_clay3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsoil_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_sand3d', data%lake_sand3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsoil_clm_lake ', 'Time '/), is_optional=.true.) + end subroutine clm_lake_register_fields + + subroutine clm_lake_final(data) + ! Final routine for clm_lake_data_type, called automatically when + ! an object of that type goes out of scope. This is simply a + ! wrapper around data%deallocate_data(). + implicit none + type(clm_lake_data_type) :: data + call clm_lake_deallocate_data(data) + end subroutine clm_lake_final + + subroutine clm_lake_deallocate_data(data) + ! Deallocates all data used, and nullifies the pointers. The data + ! object can safely be used again after this call. This is also + ! the implementation of the clm_lake_data_type final routine. + implicit none + class(clm_lake_data_type) :: data + + ! Deallocate and nullify any associated pointers + + ! This #define reduces code length by a lot +#define IF_ASSOC_DEALLOC_NULL(var) \ + if(associated(data%var)) then ; \ + deallocate(data%var) ; \ + nullify(data%var) ; \ + endif + + IF_ASSOC_DEALLOC_NULL(T_snow) + IF_ASSOC_DEALLOC_NULL(T_ice) + IF_ASSOC_DEALLOC_NULL(lake_snl2d) + IF_ASSOC_DEALLOC_NULL(lake_h2osno2d) + IF_ASSOC_DEALLOC_NULL(lake_tsfc) + IF_ASSOC_DEALLOC_NULL(lake_savedtke12d) + IF_ASSOC_DEALLOC_NULL(lake_sndpth2d) + IF_ASSOC_DEALLOC_NULL(clm_lakedepth) + IF_ASSOC_DEALLOC_NULL(clm_lake_initialized) + + IF_ASSOC_DEALLOC_NULL(lake_z3d) + IF_ASSOC_DEALLOC_NULL(lake_dz3d) + IF_ASSOC_DEALLOC_NULL(lake_soil_watsat3d) + IF_ASSOC_DEALLOC_NULL(lake_csol3d) + IF_ASSOC_DEALLOC_NULL(lake_soil_tkmg3d) + IF_ASSOC_DEALLOC_NULL(lake_soil_tkdry3d) + IF_ASSOC_DEALLOC_NULL(lake_soil_tksatu3d) + IF_ASSOC_DEALLOC_NULL(lake_snow_z3d) + IF_ASSOC_DEALLOC_NULL(lake_snow_dz3d) + IF_ASSOC_DEALLOC_NULL(lake_snow_zi3d) + IF_ASSOC_DEALLOC_NULL(lake_h2osoi_vol3d) + IF_ASSOC_DEALLOC_NULL(lake_h2osoi_liq3d) + IF_ASSOC_DEALLOC_NULL(lake_h2osoi_ice3d) + IF_ASSOC_DEALLOC_NULL(lake_t_soisno3d) + IF_ASSOC_DEALLOC_NULL(lake_t_lake3d) + IF_ASSOC_DEALLOC_NULL(lake_icefrac3d) + IF_ASSOC_DEALLOC_NULL(lake_clay3d) + IF_ASSOC_DEALLOC_NULL(lake_sand3d) + +#undef IF_ASSOC_DEALLOC_NULL + end subroutine clm_lake_deallocate_data + +end module clm_lake_io