diff --git a/ccpp/config/ccpp_prebuild_config.py b/ccpp/config/ccpp_prebuild_config.py index 52f576eda..2698259f8 100755 --- a/ccpp/config/ccpp_prebuild_config.py +++ b/ccpp/config/ccpp_prebuild_config.py @@ -148,9 +148,9 @@ 'ccpp/physics/physics/CONV/Chikira_Sugiyama/cs_conv.F90', 'ccpp/physics/physics/CONV/Chikira_Sugiyama/cs_conv_post.F90', 'ccpp/physics/physics/CONV/Chikira_Sugiyama/cs_conv_aw_adj.F90', - 'ccpp/physics/physics/CONV/nTiedtke/cu_ntiedtke_pre.F90', - 'ccpp/physics/physics/CONV/nTiedtke/cu_ntiedtke.F90', - 'ccpp/physics/physics/CONV/nTiedtke/cu_ntiedtke_post.F90', + 'ccpp/physics/physics/CONV/nTiedtke/ufs_cu_ntiedtke_pre.F90', + 'ccpp/physics/physics/CONV/nTiedtke/ufs_cu_ntiedtke.F90', + 'ccpp/physics/physics/CONV/nTiedtke/ufs_cu_ntiedtke_post.F90', 'ccpp/physics/physics/CONV/SAMF/samfdeepcnv.f', 'ccpp/physics/physics/CONV/SAMF/samfshalcnv.f', 'ccpp/physics/physics/CONV/SAS/sascnvn.F', @@ -229,9 +229,9 @@ 'ccpp/physics/physics/tools/get_phi_fv3.F90', # CNU_NTIEDTKE - 'ccpp/physics/physics/mmm_physics/mmm_cu_ntiedtke.F90' , - 'ccpp/physics/physics/CONV/nTiedtke/mmm_cu_ntiedtke_pre.F90' , - 'ccpp/physics/physics/CONV/nTiedtke/mmm_cu_ntiedtke_post.F90' , + 'ccpp/physics/physics/CONV/nTiedtke/gfs_mmm_cu_ntiedtke_pre.F90' , + 'ccpp/physics/physics/mmm_physics/cu_ntiedtke.F90' , + 'ccpp/physics/physics/CONV/nTiedtke/gfs_mmm_cu_ntiedtke_post.F90' , # NCAR MMM # 'ccpp/physics/physics/mmm_physics/sfclayrev_pre.F90' , diff --git a/ccpp/physics b/ccpp/physics index 5e80ddaab..9ea413cd1 160000 --- a/ccpp/physics +++ b/ccpp/physics @@ -1 +1 @@ -Subproject commit 5e80ddaabe23d2bf91030d9c4108332afb380d86 +Subproject commit 9ea413cd1c204da26667ed084406c4fe2c3db7d7 diff --git a/ccpp/physics_namelists/input_RAP_ntiedtke.nml b/ccpp/physics_namelists/input_RAP_ntiedtke.nml index 8559dc662..2b0b09aaa 100644 --- a/ccpp/physics_namelists/input_RAP_ntiedtke.nml +++ b/ccpp/physics_namelists/input_RAP_ntiedtke.nml @@ -50,8 +50,8 @@ random_clds = .false. trans_trac = .true. cnvcld = .true. - imfshalcnv = 3 - imfdeepcnv = 3 + imfshalcnv = 6 + imfdeepcnv = 6 ras = .false. cdmbgwd = 0.14,1.8,1.0,1.0 do_mynnsfclay= .true. diff --git a/ccpp/physics_namelists/input_RAP_ufs_ntiedtke.nml b/ccpp/physics_namelists/input_RAP_ufs_ntiedtke.nml new file mode 100644 index 000000000..02de606f7 --- /dev/null +++ b/ccpp/physics_namelists/input_RAP_ufs_ntiedtke.nml @@ -0,0 +1,132 @@ +&gfs_physics_nml + fhzero = 6 + h2o_phys = .true. + ldiag3d = .true. + qdiag3d = .true. + print_diff_pgr = .false. + fhcyc = 24 + use_ufo = .true. + pre_rad = .false. + imp_physics = 8 + ltaerosol = .true. + lradar = .true. + sedi_semi = .true. + decfl = 10 + nssl_cccn = 0.6e9 + nssl_alphah = 0.0 + nssl_alphahl = 1.0 + nssl_hail_on = .false. + nssl_ccn_on = .true. + nssl_invertccn = .true. + dt_inner = 60 + ttendlim = -999 + pdfcld = .false. + fhswr = 1200. + fhlwr = 1200. + ialb = 2 + iems = 2 + iaer = 5111 + icliq_sw = 1 + iovr = 1 + icloud = 0 + ico2 = 2 + isubc_sw = 2 + isubc_lw = 2 + isol = 2 + lwhtr = .true. + swhtr = .true. + cnvgwd = .true. + do_deep = .true. + shal_cnv = .true. + cal_pre = .false. + redrag = .true. + dspheat = .true. + hybedmf = .false. + satmedmf = .false. + isatmedmf = 0 + do_mynnedmf = .true. + lheatstrg = .false. + lseaspray = .false. + random_clds = .false. + trans_trac = .true. + cnvcld = .true. + imfshalcnv = 4 + imfdeepcnv = 4 + ras = .false. + cdmbgwd = 0.14,1.8,1.0,1.0 + do_mynnsfclay= .true. + prslrd0 = 0. + ivegsrc = 1 + isot = 1 + lsm = 3 + lsoil = 4 + lsoil_lsm = 9 + kice = 9 + iopt_dveg = 4 + iopt_crs = 2 + iopt_btr = 1 + iopt_run = 1 + iopt_sfc = 3 + iopt_frz = 1 + iopt_inf = 1 + iopt_rad = 3 + iopt_alb = 1 + iopt_snf = 4 + iopt_tbot = 2 + iopt_stc = 3 + iopt_trs = 2 + debug = .false. + oz_phys = .false. + oz_phys_2015 = .true. + nstf_name = 2,0,0,0,0 + nst_anl = .true. + lkm = 0 + psautco = 0.0008,0.0005 + prautco = 0.00015,0.00015 + lgfdlmprad = .true. + cplchm = .false. + cplwav = .false. + cplwav2atm = .false. + effr_in = .true. + ldiag_ugwp = .false. + do_ugwp = .false. + do_tofd = .false. + gwd_opt = 3 + ldiag_ugwp = .false. + do_ugwp_v0 = .false. + do_ugwp_v0_orog_only = .false. + do_gsl_drag_ls_bl = .true. + do_gsl_drag_ss = .true. + do_gsl_drag_tofd = .true. + do_ugwp_v1 = .false. + do_ugwp_v1_orog_only = .false. + do_sppt = .false. + do_shum = .false. + do_skeb = .false. + do_ysu = .true. + lndp_type = 0 + n_var_lndp = 0 + fscav_aero = "'*:0.0'" + icloud_bl = 1 + bl_mynn_tkeadvect = .true. + bl_mynn_edmf = 1 + bl_mynn_edmf_mom = 1 + do_RRTMGP = .false. + doGP_cldoptics_LUT = .false. + doGP_lwscat = .false. +/ + +&cires_ugwp_nml + knob_ugwp_solver = 2 + knob_ugwp_source = 1,1,0,0 + knob_ugwp_wvspec = 1,25,25,25 + knob_ugwp_azdir = 2,4,4,4 + knob_ugwp_stoch = 0,0,0,0 + knob_ugwp_effac = 1,1,1,1 + knob_ugwp_doaxyz = 1 + knob_ugwp_doheat = 1 + knob_ugwp_dokdis = 1 + knob_ugwp_ndx4lh = 1 + knob_ugwp_version = 0 + launch_level = 54 +/ diff --git a/ccpp/suites/suite_SCM_RAP_ntiedtke.xml b/ccpp/suites/suite_SCM_RAP_ntiedtke.xml index 3a9c464a1..30128a092 100644 --- a/ccpp/suites/suite_SCM_RAP_ntiedtke.xml +++ b/ccpp/suites/suite_SCM_RAP_ntiedtke.xml @@ -19,7 +19,6 @@ rad_sw_pre rrtmg_sw rrtmg_sw_post - rrtmg_lw sgscloud_radpost rrtmg_lw_post @@ -59,29 +58,25 @@ drag_suite GFS_GWD_generic_post GFS_suite_stateout_update - h2ophys get_phi_fv3 GFS_suite_interstitial_3 GFS_DCNV_generic_pre - cu_gf_driver_pre - cu_gf_driver + gfs_mmm_cu_ntiedtke_pre + cu_ntiedtke + gfs_mmm_cu_ntiedtke_post GFS_DCNV_generic_post GFS_SCNV_generic_pre GFS_SCNV_generic_post GFS_suite_interstitial_4 cnvc90 GFS_MP_generic_pre - - - - mmm_cu_ntiedtke_pre - mmm_cu_ntiedtke - mmm_cu_ntiedtke_post + mp_thompson_pre + mp_thompson + mp_thompson_post GFS_MP_generic_post - cu_gf_driver_post maximum_hourly_diagnostics - GFS_physics_post + GFS_physics_post diff --git a/ccpp/suites/suite_SCM_RAP_ufs_ntiedtke.xml b/ccpp/suites/suite_SCM_RAP_ufs_ntiedtke.xml new file mode 100644 index 000000000..8c0363acf --- /dev/null +++ b/ccpp/suites/suite_SCM_RAP_ufs_ntiedtke.xml @@ -0,0 +1,83 @@ + + + + + + + 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 + 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 + 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 + h2ophys + get_phi_fv3 + GFS_suite_interstitial_3 + GFS_DCNV_generic_pre + ufs_cu_ntiedtke_pre + ufs_cu_ntiedtke + ufs_cu_ntiedtke_post + 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 + maximum_hourly_diagnostics + GFS_physics_post + + + + diff --git a/scm/src/CCPP_typedefs.F90 b/scm/src/CCPP_typedefs.F90 index 437fb37ce..707694327 100644 --- a/scm/src/CCPP_typedefs.F90 +++ b/scm/src/CCPP_typedefs.F90 @@ -252,6 +252,8 @@ module CCPP_typedefs real (kind=kind_phys), pointer :: rainmp(:) => null() !< real (kind=kind_phys), pointer :: raincd(:) => null() !< real (kind=kind_phys), pointer :: raincs(:) => null() !< + real (kind=kind_phys), pointer :: raincd_mm(:) => null() !< + real (kind=kind_phys), pointer :: raincs_mm(:) => null() !< real (kind=kind_phys), pointer :: rainmcadj(:) => null() !< real (kind=kind_phys), pointer :: rainp(:,:) => null() !< real (kind=kind_phys), pointer :: rb(:) => null() !< @@ -356,6 +358,7 @@ module CCPP_typedefs real (kind=kind_phys), pointer :: tv_lay(:,:) => null() !< real (kind=kind_phys), pointer :: qs_lay(:,:) => null() !< real (kind=kind_phys), pointer :: q_lay(:,:) => null() !< + real (kind=kind_phys), pointer :: dqvdt_nonphy(:,:) => null() !< real (kind=kind_phys), pointer :: deltaZ(:,:) => null() !< real (kind=kind_phys), pointer :: deltaZc(:,:) => null() !< real (kind=kind_phys), pointer :: deltaP(:,:) => null() !< @@ -420,6 +423,8 @@ module CCPP_typedefs real (kind=kind_phys), pointer :: xland(:) => null() real (kind=kind_phys), pointer :: qcx(:,:) => null() real (kind=kind_phys), pointer :: qix(:,:) => null() + real (kind=kind_phys), pointer :: geoph(:,:) => null() + real (kind=kind_phys), pointer :: geophi(:,:) => null() real (kind=kind_phys), pointer :: hfx(:) => null() real (kind=kind_phys), pointer :: qfx(:) => null() real (kind=kind_phys), pointer :: qgh(:) => null() @@ -661,6 +666,8 @@ subroutine gfs_interstitial_create (Interstitial, IM, Model) allocate (Interstitial%qss_water (IM)) allocate (Interstitial%raincd (IM)) allocate (Interstitial%raincs (IM)) + allocate (Interstitial%raincd_mm (IM)) + allocate (Interstitial%raincs_mm (IM)) allocate (Interstitial%rainmcadj (IM)) allocate (Interstitial%rainp (IM,Model%levs)) allocate (Interstitial%rb (IM)) @@ -856,9 +863,13 @@ subroutine gfs_interstitial_create (Interstitial, IM, Model) end if ! RRTMGP and NCAR MMM physics - if (Model%do_ysu .or. Model%do_RRTMGP .or. Model%do_mmm_sfclayrev) then + if (Model%do_ysu .or. Model%do_RRTMGP .or. Model%do_mmm_sfclayrev .or. Model%imfdeepcnv .eq. Model%imfdeepcnv_mmm_ntiedtke & + .or. Model%imfshalcnv .eq. Model%imfshalcnv_mmm_ntiedtke) then allocate (Interstitial%q_lay (IM, Model%levs)) allocate (Interstitial%deltaZ (IM, Model%levs)) + allocate (Interstitial%dqvdt_nonphy (IM, Model%levs)) + allocate (Interstitial%geoph (IM, Model%levs)) + allocate (Interstitial%geophi (IM, Model%levs)) end if ! NCAR MMM physics @@ -876,7 +887,8 @@ subroutine gfs_interstitial_create (Interstitial, IM, Model) Interstitial%scm_force_flux = .false. ! If MMM surface scheme used, fluxes are not prescribed endif - if (Model%do_ysu .or. Model%do_mmm_sfclayrev) then + if (Model%do_ysu .or. Model%do_mmm_sfclayrev .or. Model%imfdeepcnv .eq. Model%imfdeepcnv_mmm_ntiedtke & + .or. Model%imfshalcnv .eq. Model%imfshalcnv_mmm_ntiedtke) then allocate (Interstitial%xland (IM)) allocate (Interstitial%hfx (IM)) allocate (Interstitial%qfx (IM)) @@ -1404,6 +1416,8 @@ subroutine gfs_interstitial_phys_reset (Interstitial, Model) Interstitial%qss_water = Model%huge Interstitial%raincd = clear_val Interstitial%raincs = clear_val + Interstitial%raincd_mm = clear_val + Interstitial%raincs_mm = clear_val Interstitial%rainmcadj = clear_val Interstitial%rainp = clear_val Interstitial%rb = clear_val @@ -1491,9 +1505,13 @@ subroutine gfs_interstitial_phys_reset (Interstitial, Model) end if ! RRTMGP and NCAR MMM physics - if (Model%do_ysu .or. Model%do_RRTMGP .or. Model%do_mmm_sfclayrev) then + if (Model%do_ysu .or. Model%do_RRTMGP .or. Model%do_mmm_sfclayrev .or. Model%imfdeepcnv .eq. Model%imfdeepcnv_mmm_ntiedtke & + .or. Model%imfshalcnv .eq. Model%imfshalcnv_mmm_ntiedtke) then Interstitial%q_lay = clear_val Interstitial%deltaZ = clear_val + Interstitial%dqvdt_nonphy = clear_val + Interstitial%geoph = clear_val + Interstitial%geophi = clear_val endif ! NCAR MMM physics @@ -1517,7 +1535,8 @@ subroutine gfs_interstitial_phys_reset (Interstitial, Model) Interstitial%its = 0 Interstitial%ite = 0 endif - if (Model%do_ysu .or. Model%do_mmm_sfclayrev) then + if (Model%do_ysu .or. Model%do_mmm_sfclayrev .or. Model%imfdeepcnv .eq. Model%imfdeepcnv_mmm_ntiedtke & + .or. Model%imfshalcnv .eq. Model%imfshalcnv_mmm_ntiedtke) then Interstitial%xland = 0 Interstitial%hfx = clear_val Interstitial%qfx = clear_val diff --git a/scm/src/CCPP_typedefs.meta b/scm/src/CCPP_typedefs.meta index 3477cd9da..7914a2331 100644 --- a/scm/src/CCPP_typedefs.meta +++ b/scm/src/CCPP_typedefs.meta @@ -380,6 +380,14 @@ dimensions = (horizontal_loop_extent) type = real kind = kind_phys +[dqvdt_nonphy] + standard_name = tendendy_of_water_vapor_mixing_ratio_due_to_nonphysics + long_name = moisture tendency due to dynamics only + units = kg kg-1 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + active = (control_for_deep_convection_scheme == identifier_for_mmm_new_tiedtke_deep_convection .or. control_for_shallow_convection_scheme == identifier_for_mmm_new_tiedtke_shallow_convection) [cnv_dqldt] standard_name = tendency_of_cloud_water_due_to_convective_microphysics long_name = tendency of cloud water due to convective microphysics @@ -1726,6 +1734,20 @@ dimensions = (horizontal_loop_extent) type = real kind = kind_phys +[raincd_mm] + standard_name = lwe_thickness_of_deep_convective_precipitation_amount_in_mm + long_name = deep convective rainfall amount on physics timestep in mm + units = mm + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[raincs_mm] + standard_name = lwe_thickness_of_shallow_convective_precipitation_amount_in_mm + long_name = shallow convective rainfall amount on physics timestep in mm + units = mm + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys [rainmcadj] standard_name = lwe_thickness_of_moist_convective_adj_precipitation_amount long_name = adjusted moist convective rainfall amount on physics timestep @@ -2858,7 +2880,22 @@ dimensions = (horizontal_loop_extent,vertical_layer_dimension) type = real kind = kind_phys - active = (flag_for_rrtmgp_radiation_scheme .or. flag_for_ysu_pbl_scheme) + active = (flag_for_rrtmgp_radiation_scheme .or. flag_for_ysu_pbl_scheme .or. control_for_deep_convection_scheme == identifier_for_mmm_new_tiedtke_deep_convection .or. control_for_shallow_convection_scheme == identifier_for_mmm_new_tiedtke_shallow_convection) +[geoph] + standard_name = geopotential_height + long_name = geopotential height at model layer centers + units = m + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + active = (control_for_deep_convection_scheme == identifier_for_mmm_new_tiedtke_deep_convection .or. control_for_shallow_convection_scheme == identifier_for_mmm_new_tiedtke_shallow_convection) +[geophi] + standard_name = geopotential_height_at_interface + long_name = geopotential height at model layer interfaces + units = m + dimensions = (horizontal_loop_extent,vertical_interface_dimension) + type = real + kind = kind_phys + active = (control_for_deep_convection_scheme == identifier_for_mmm_new_tiedtke_deep_convection .or. control_for_shallow_convection_scheme == identifier_for_mmm_new_tiedtke_shallow_convection) [deltaZ] standard_name = layer_thickness long_name = layer_thickness @@ -2897,7 +2934,7 @@ dimensions = (horizontal_loop_extent) type = real kind = kind_phys - active = (flag_for_ysu_pbl_scheme .or. flag_for_mmm_sfclayrev_scheme) + active = (flag_for_ysu_pbl_scheme .or. flag_for_mmm_sfclayrev_scheme .or. control_for_deep_convection_scheme == identifier_for_mmm_new_tiedtke_deep_convection .or. control_for_shallow_convection_scheme == identifier_for_mmm_new_tiedtke_shallow_convection) [znt] standard_name = surface_roughness_length_in_m long_name = surface roughness length in meter @@ -2953,7 +2990,7 @@ dimensions = (horizontal_loop_extent) type = real kind = kind_phys - active = (flag_for_ysu_pbl_scheme .or. flag_for_mmm_sfclayrev_scheme) + active = (flag_for_ysu_pbl_scheme .or. flag_for_mmm_sfclayrev_scheme .or. control_for_deep_convection_scheme == identifier_for_mmm_new_tiedtke_deep_convection .or. control_for_shallow_convection_scheme == identifier_for_mmm_new_tiedtke_shallow_convection) [qfx] standard_name = kinematic_surface_upward_latent_heat_flux long_name = kinematic surface upward latent heat flux @@ -2961,7 +2998,7 @@ dimensions = (horizontal_loop_extent) type = real kind = kind_phys - active = (flag_for_ysu_pbl_scheme .or. flag_for_mmm_sfclayrev_scheme) + active = (flag_for_ysu_pbl_scheme .or. flag_for_mmm_sfclayrev_scheme .or. control_for_deep_convection_scheme == identifier_for_mmm_new_tiedtke_deep_convection .or. control_for_shallow_convection_scheme == identifier_for_mmm_new_tiedtke_shallow_convection) [qgh] standard_name = saturation_mixing_ratio_at_lowest_model_level long_name = saturation water vapor mixing ratio at lowest model level diff --git a/scm/src/GFS_typedefs.F90 b/scm/src/GFS_typedefs.F90 index 91757f3e3..bd0d7f050 100644 --- a/scm/src/GFS_typedefs.F90 +++ b/scm/src/GFS_typedefs.F90 @@ -1192,6 +1192,7 @@ module GFS_typedefs integer :: imfshalcnv_gf = 3 !< flag for scale- & aerosol-aware Grell-Freitas scheme (GSD) integer :: imfshalcnv_ntiedtke = 4 !< flag for new Tiedtke scheme (CAPS) integer :: imfshalcnv_c3 = 5 !< flag for the Community Convective Cloud (C3) scheme + integer :: imfshalcnv_mmm_ntiedtke = 6 !< flag for MMM's new Tiedtke scheme (CAPS) logical :: hwrf_samfdeep !< flag for HWRF SAMF deepcnv scheme (HWRF) logical :: progsigma !< flag for prognostic area fraction in samf ddepcnv scheme (GFS) integer :: imfdeepcnv !< flag for mass-flux deep convection scheme @@ -1206,6 +1207,7 @@ module GFS_typedefs integer :: imfdeepcnv_gf = 3 !< flag for scale- & aerosol-aware Grell-Freitas scheme (GSD) integer :: imfdeepcnv_ntiedtke = 4 !< flag for new Tiedtke scheme (CAPS) integer :: imfdeepcnv_c3 = 5 !< flag for the Community Convective Cloud (C3) scheme + integer :: imfdeepcnv_mmm_ntiedtke = 6 !< flag for MMM new Tiedtke scheme (CAPS) logical :: hwrf_samfshal !< flag for HWRF SAMF shalcnv scheme (HWRF) integer :: isatmedmf !< flag for scale-aware TKE-based moist edmf scheme !< 0: initial version of satmedmf (Nov. 2018) @@ -5964,6 +5966,12 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & error stop end if + if ( (Model%imfdeepcnv == Model%imfdeepcnv_mmm_ntiedtke .or. Model%imfshalcnv == Model%imfshalcnv_mmm_ntiedtke) .and. & + .not. (Model%imfdeepcnv == Model%imfdeepcnv_mmm_ntiedtke .and. Model%imfshalcnv == Model%imfshalcnv_mmm_ntiedtke) ) then + write(0,*) "Logic error: if NTDK deep convection is used, must also use NTDK shallow convection (and vice versa)" + error stop + end if + if (.not. Model%cscnv) then if (Model%ras) then print *,' RAS Convection scheme used with ccwf=',Model%ccwf @@ -5979,6 +5987,8 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & print *,' Grell-Freitas scale & aerosol-aware mass-flux deep conv scheme' elseif(Model%imfdeepcnv == Model%imfdeepcnv_ntiedtke) then print *,' New Tiedtke cumulus scheme' + elseif(Model%imfdeepcnv == Model%imfdeepcnv_mmm_ntiedtke) then + print *,' MMM New Tiedtke cumulus scheme' elseif(Model%imfdeepcnv == Model%imfdeepcnv_c3) then print *,' New unified cumulus convection scheme' endif @@ -6026,6 +6036,8 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & print *,' Grell-Freitas scale- & aerosol-aware mass-flux shallow conv scheme (2013)' elseif (Model%imfshalcnv == Model%imfshalcnv_ntiedtke) then print *,' New Tiedtke cumulus scheme' + elseif (Model%imfshalcnv == Model%imfshalcnv_mmm_ntiedtke) then + print *,' MMM New Tiedtke cumulus scheme' elseif (Model%imfshalcnv == Model%imfshalcnv_c3) then print *,' New unified cumulus scheme' else @@ -6340,6 +6352,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & Model%lmfdeep2 = (Model%imfdeepcnv == Model%imfdeepcnv_samf & .or. Model%imfdeepcnv == Model%imfdeepcnv_gf & .or. Model%imfdeepcnv == Model%imfdeepcnv_ntiedtke & + .or. Model%imfdeepcnv == Model%imfdeepcnv_mmm_ntiedtke & .or. Model%imfdeepcnv == Model%imfdeepcnv_c3) !--- END CODE FROM GLOOPR @@ -7350,7 +7363,7 @@ subroutine tbd_create (Tbd, IM, Model) allocate (Tbd%hpbl (IM)) Tbd%hpbl = clear_val - if (Model%imfdeepcnv == Model%imfdeepcnv_gf .or. Model%imfdeepcnv == Model%imfdeepcnv_ntiedtke .or. Model%imfdeepcnv == Model%imfdeepcnv_samf .or. Model%imfshalcnv == Model%imfshalcnv_samf .or. Model%imfdeepcnv == Model%imfdeepcnv_c3 .or. Model%imfshalcnv == Model%imfshalcnv_c3) then + if (Model%imfdeepcnv == Model%imfdeepcnv_gf .or. Model%imfdeepcnv == Model%imfdeepcnv_ntiedtke .or. Model%imfdeepcnv == Model%imfdeepcnv_mmm_ntiedtke .or. Model%imfdeepcnv == Model%imfdeepcnv_samf .or. Model%imfshalcnv == Model%imfshalcnv_samf .or. Model%imfdeepcnv == Model%imfdeepcnv_c3 .or. Model%imfshalcnv == Model%imfshalcnv_c3) then allocate(Tbd%prevsq(IM, Model%levs)) Tbd%prevsq = clear_val endif @@ -7360,7 +7373,7 @@ subroutine tbd_create (Tbd, IM, Model) Tbd%ud_mf = zero endif - if (Model%imfdeepcnv == Model%imfdeepcnv_gf .or. Model%imfdeepcnv == Model%imfdeepcnv_ntiedtke .or. Model%imfdeepcnv == Model%imfdeepcnv_c3) then + if (Model%imfdeepcnv == Model%imfdeepcnv_gf .or. Model%imfdeepcnv == Model%imfdeepcnv_ntiedtke .or. Model%imfdeepcnv == Model%imfdeepcnv_mmm_ntiedtke .or. Model%imfdeepcnv == Model%imfdeepcnv_c3 .or. Model%imfdeepcnv == Model%imfdeepcnv_ntiedtke .or. Model%imfshalcnv == Model%imfshalcnv_ntiedtke) then allocate(Tbd%forcet(IM, Model%levs)) allocate(Tbd%forceq(IM, Model%levs)) allocate(Tbd%prevst(IM, Model%levs)) diff --git a/scm/src/GFS_typedefs.meta b/scm/src/GFS_typedefs.meta index 1805bbea8..2804273ff 100644 --- a/scm/src/GFS_typedefs.meta +++ b/scm/src/GFS_typedefs.meta @@ -5563,6 +5563,12 @@ units = flag dimensions = () type = integer +[imfshalcnv_mmm_ntiedtke] + standard_name = identifier_for_mmm_new_tiedtke_shallow_convection + long_name = flag for MMM new Tiedtke shallow convection scheme + units = flag + dimensions = () + type = integer [imfdeepcnv] standard_name = control_for_deep_convection_scheme long_name = flag for mass-flux deep convection scheme @@ -5599,6 +5605,12 @@ units = flag dimensions = () type = integer +[imfdeepcnv_mmm_ntiedtke] + standard_name = identifier_for_mmm_new_tiedtke_deep_convection + long_name = flag for MMM new Tiedtke deep convection scheme + units = flag + dimensions = () + type = integer [ichoice] standard_name = identifier_for_c3_or_gf_deep_convection_closure long_name = flag for C3 or GF deep convection closure @@ -8255,7 +8267,7 @@ dimensions = (horizontal_loop_extent,vertical_layer_dimension) type = real kind = kind_phys - active = (control_for_deep_convection_scheme == identifier_for_grell_freitas_deep_convection .or. control_for_deep_convection_scheme == identifier_for_c3_deep_convection .or. control_for_deep_convection_scheme == identifier_for_new_tiedtke_deep_convection) + active = (control_for_deep_convection_scheme == identifier_for_grell_freitas_deep_convection .or. control_for_deep_convection_scheme == identifier_for_c3_deep_convection .or. control_for_deep_convection_scheme == identifier_for_new_tiedtke_deep_convection .or. control_for_deep_convection_scheme == identifier_for_mmm_new_tiedtke_deep_convection) [forceq] standard_name = tendendy_of_specific_humidity_due_to_nonphysics long_name = moisture tendency due to dynamics only @@ -8263,7 +8275,7 @@ dimensions = (horizontal_loop_extent,vertical_layer_dimension) type = real kind = kind_phys - active = (control_for_deep_convection_scheme == identifier_for_grell_freitas_deep_convection .or. control_for_deep_convection_scheme == identifier_for_c3_deep_convection .or. control_for_deep_convection_scheme == identifier_for_new_tiedtke_deep_convection) + active = (control_for_deep_convection_scheme == identifier_for_grell_freitas_deep_convection .or. control_for_deep_convection_scheme == identifier_for_c3_deep_convection .or. control_for_deep_convection_scheme == identifier_for_new_tiedtke_deep_convection .or. control_for_deep_convection_scheme == identifier_for_mmm_new_tiedtke_deep_convection) [prevst] standard_name = air_temperature_on_previous_timestep long_name = temperature from previous time step @@ -8271,7 +8283,7 @@ dimensions = (horizontal_loop_extent,vertical_layer_dimension) type = real kind = kind_phys - active = (control_for_deep_convection_scheme == identifier_for_grell_freitas_deep_convection .or. control_for_deep_convection_scheme == identifier_for_c3_deep_convection .or. control_for_deep_convection_scheme == identifier_for_new_tiedtke_deep_convection) + active = (control_for_deep_convection_scheme == identifier_for_grell_freitas_deep_convection .or. control_for_deep_convection_scheme == identifier_for_c3_deep_convection .or. control_for_deep_convection_scheme == identifier_for_new_tiedtke_deep_convection .or. control_for_deep_convection_scheme == identifier_for_mmm_new_tiedtke_deep_convection) [prevsq] standard_name = specific_humidity_on_previous_timestep long_name = moisture from previous time step @@ -8279,7 +8291,7 @@ dimensions = (horizontal_loop_extent,vertical_layer_dimension) type = real kind = kind_phys - active = (control_for_deep_convection_scheme == identifier_for_grell_freitas_deep_convection .or. control_for_deep_convection_scheme == identifier_for_c3_deep_convection .or. control_for_deep_convection_scheme == identifier_for_new_tiedtke_deep_convection .or. control_for_deep_convection_scheme == identifer_for_scale_aware_mass_flux_deep_convection .or. control_for_shallow_convection_scheme == identifier_for_scale_aware_mass_flux_shallow_convection) + active = (control_for_deep_convection_scheme == identifier_for_grell_freitas_deep_convection .or. control_for_deep_convection_scheme == identifier_for_c3_deep_convection .or. control_for_deep_convection_scheme == identifier_for_new_tiedtke_deep_convection .or. control_for_deep_convection_scheme == identifer_for_scale_aware_mass_flux_deep_convection .or. control_for_shallow_convection_scheme == identifier_for_scale_aware_mass_flux_shallow_convection .or. control_for_deep_convection_scheme == identifier_for_mmm_new_tiedtke_deep_convection) [cactiv] standard_name = counter_for_grell_freitas_convection long_name = convective activity memory diff --git a/scm/src/run_scm.py b/scm/src/run_scm.py index c14938fe0..926fb68ba 100755 --- a/scm/src/run_scm.py +++ b/scm/src/run_scm.py @@ -3,7 +3,6 @@ import argparse import f90nml import logging -import numpy as np import os import re import shutil @@ -32,10 +31,6 @@ # Path to default bin directory (relative to scm_root) DEFAULT_BIN_DIR = 'scm/bin' -# Default command string to run MPI apps (number of processes should be 1 since SCM is not set up to use more than 1 yet) -DEFAULT_MPI_COMMAND = 'mpirun -np 1' - - # Copy executable to run directory if true (otherwise it will be linked) COPY_EXECUTABLE = False @@ -122,10 +117,8 @@ parser.add_argument('--n_itt_out', help='period of instantaneous output (number of timesteps)', required=False, type=int) parser.add_argument('--n_itt_diag', help='period of diagnostic output (number of timesteps)', required=False, type=int) parser.add_argument('-dt', '--timestep', help='timestep (s)', required=False, type=float) -parser.add_argument('--stop_on_error', help='when running multiple SCM runs, stop on first error', required=False, action='store_true') parser.add_argument('-v', '--verbose', help='set logging level to debug and write log to file', action='count', default=0) parser.add_argument('-f', '--file', help='name of file where SCM runs are defined') -parser.add_argument('--mpi_command', help='command used to invoke the executable via MPI (including options)', required=False) ############################################################################### # Functions and subroutines # @@ -157,17 +150,17 @@ def execute(cmd, ignore_error = False): stderr = subprocess.PIPE, shell = True) (stdout, stderr) = p.communicate() status = p.returncode - message = 'Execution of "{0}" returned with exit code {1}\n'.format(cmd, status) - message += ' stdout: "{0}"\n'.format(stdout.decode(encoding='ascii', errors='ignore').rstrip('\n')) - message += ' stderr: "{0}"'.format(stderr.decode(encoding='ascii', errors='ignore').rstrip('\n')) - if status == 0: + message = 'Execution of "{0}" returned with exit code {1}\n'.format(cmd, status) + message += ' stdout: "{0}"\n'.format(stdout.decode(encoding='ascii', errors='ignore').rstrip('\n')) + message += ' stderr: "{0}"'.format(stderr.decode(encoding='ascii', errors='ignore').rstrip('\n')) logging.debug(message) elif not ignore_error: + message = 'Execution of command "{0}" failed, exit code {1}\n'.format(cmd, status) + message += ' stdout: "{0}"\n'.format(stdout.decode(encoding='ascii', errors='ignore').rstrip('\n')) + message += ' stderr: "{0}"'.format(stderr.decode(encoding='ascii', errors='ignore').rstrip('\n')) logging.critical(message) raise Exception('Execution of command "{0}" failed, exit code {1}\n'.format(cmd, status)) - else: - logging.error(message) return (status, stdout.decode(encoding='ascii', errors='ignore').rstrip('\n'), stderr.decode(encoding='ascii', errors='ignore').rstrip('\n')) def parse_arguments(): @@ -192,18 +185,13 @@ def parse_arguments(): run_dir = args.run_dir bin_dir = args.bin_dir timestep = args.timestep - mpi_command = args.mpi_command - stop_on_error = args.stop_on_error - - if not case and not file: - parser.error('Either "--case" or "--file" must be specified. Use "--help" for more information.') - + if not sdf: sdf = DEFAULT_SUITE - + return (file, case, sdf, namelist, tracers, gdb, runtime, runtime_mult, docker, \ verbose, levels, npz_type, vert_coord_file, case_data_dir, n_itt_out, \ - n_itt_diag, run_dir, bin_dir, timestep, mpi_command, stop_on_error) + n_itt_diag, run_dir, bin_dir, timestep) def find_gdb(): """Detect gdb, abort if not found""" @@ -224,28 +212,28 @@ def __init__(self, case, suite, runtime, runtime_mult, levels, npz_type, vert_co """Initialize experiment. This routine does most of the work, including setting and checking the experiment configuration (namelist).""" - + self._case = case self._suite_obj = suite self._suite = suite._name self._name = case + '_' + self._suite - + self._physics_namelist = suite.namelist - + #check to see that the physics namelists exists in the right dir if not os.path.isfile(os.path.join(SCM_ROOT, PHYSICS_NAMELIST_DIR, self._physics_namelist)): message = 'The physics namelist {0} was not found'.format(os.path.join(SCM_ROOT, PHYSICS_NAMELIST_DIR, self._physics_namelist)) logging.critical(message) raise Exception(message) - + self._tracers = suite.tracers - + #check to see that the tracers exists in the right dir if not os.path.isfile(os.path.join(SCM_ROOT, TRACERS_DIR, self._tracers)): message = 'The tracer configuration {0} was not found'.format(os.path.join(TRACERS_DIR, self._tracers)) logging.critical(message) raise Exception(message) - + #check to see if the case namelists exists in the right dir self._namelist = os.path.join(SCM_ROOT, CASE_NAMELIST_DIR, self._case + '.nml') if not os.path.isfile(self._namelist): @@ -261,14 +249,14 @@ def __init__(self, case, suite, runtime, runtime_mult, levels, npz_type, vert_co self._runtime = None message = 'Namelist runtime adjustment {0} IS NOT applied'.format(self._runtime) logging.debug(message) - + if runtime_mult: self._runtime_mult = runtime_mult - message = 'Existing case namelist or DEPHY runtime multiplied by {0}'.format(self._runtime_mult) + message = 'Existing case namelist runtime multiplied by {0}'.format(self._runtime_mult) logging.debug(message) else: self._runtime_mult = None - + if levels: self._levels = levels message = 'The number of vertical levels is set to {0}'.format(self._levels) @@ -277,7 +265,7 @@ def __init__(self, case, suite, runtime, runtime_mult, levels, npz_type, vert_co self._levels = None message = 'The number of vertical levels contained in the case configuration file is used if present, otherwise the default value in scm_input.F90 is used.' logging.debug(message) - + if npz_type: self._npz_type = npz_type message = 'The npz_type of vertical levels is set to {0}'.format(self._npz_type) @@ -301,7 +289,7 @@ def __init__(self, case, suite, runtime, runtime_mult, levels, npz_type, vert_co self._vert_coord_file = None message = 'The npz_type contained in the case configuration file is used if present, otherwise the default value in scm_input.F90 is used.' logging.debug(message) - + if case_data_dir: self._case_data_dir = case_data_dir else: @@ -311,12 +299,12 @@ def __init__(self, case, suite, runtime, runtime_mult, levels, npz_type, vert_co message = 'The case data directory {0} was not found'.format(self._case_data_dir) logging.critical(message) raise Exception(message) - + if n_itt_out: self._n_itt_out = n_itt_out else: self._n_itt_out = DEFAULT_OUTPUT_PERIOD - + if n_itt_diag: self._n_itt_diag = n_itt_diag else: @@ -326,7 +314,7 @@ def __init__(self, case, suite, runtime, runtime_mult, levels, npz_type, vert_co self._timestep = timestep else: self._timestep = suite.timestep - + @property def name(self): """Get the name of the experiment.""" @@ -346,27 +334,27 @@ def namelist(self): def namelist(self, value): """Set the case namelist of the experiment.""" self._namelist = value - + @property def case(self): """Get the case of the experiment.""" return self._case - + @name.setter def case(self, value): """Set the case of the experiment.""" self._case = value - + @property def suite(self): """Get the suite of the experiment.""" return self._suite - + @suite.setter def suite(self, value): """Set the suite of the experiment.""" self._suite = value - + @property def physics_namelist(self): """Get the physics namelist of the experiment.""" @@ -376,7 +364,7 @@ def physics_namelist(self): def physics_namelist(self, value): """Set the physics namelist of the experiment.""" self._physics_namelist = value - + @property def tracers(self): """Get the tracer file for the experiment.""" @@ -386,7 +374,7 @@ def tracers(self): def tracers(self, value): """Set the tracer file for the experiment.""" self._tracers = value - + @property def levels(self): """Get the number of vertical levels for the experiment.""" @@ -396,7 +384,7 @@ def levels(self): def levels(self, value): """Set the number of vertical levels for the experiment.""" self._levels = value - + @property def npz_type(self): """Get the vertical level type for the experiment.""" @@ -406,7 +394,7 @@ def npz_type(self): def npz_type(self, value): """Set the vertical level type for the experiment.""" self._npz_type = value - + @property def vert_coord_file(self): """Get the file containing vertical levels for the experiment.""" @@ -416,7 +404,7 @@ def vert_coord_file(self): def vert_coord_file(self, value): """Set the file containing vertical levels for the experiment.""" self._vert_coord_file = value - + @property def case_data_dir(self): """Get the case data directory for the experiment.""" @@ -426,7 +414,7 @@ def case_data_dir(self): def case_data_dir(self, value): """Set the case data directory for the experiment.""" self._case_data_dir = value - + @property def n_itt_out(self): """Get the output period (in timesteps) for the experiment.""" @@ -436,7 +424,7 @@ def n_itt_out(self): def n_itt_out(self, value): """Set the output period (in timesteps) for the experiment.""" self._n_itt_out = value - + @property def n_itt_diag(self): """Get the diagnostic period (in timesteps) for the experiment.""" @@ -446,10 +434,10 @@ def n_itt_diag(self): def n_itt_diag(self, value): """Set the diagnostic period (in timesteps) for the experiment.""" self._n_itt_diag = value - + def setup_rundir(self): """Set up run directory for this experiment.""" - + # Parse case configuration namelist and extract # - output directory # - surface_flux_spec @@ -463,9 +451,11 @@ def setup_rundir(self): message = 'The --runtime_mult argument must be greater than 0 ({0} was entered)'.format(self._runtime_mult) logging.critical(message) raise Exception(message) - else: - case_nml['case_config']['runtime_mult'] = self._runtime_mult - + try: + old_runtime = case_nml['case_config']['runtime'] + case_nml['case_config']['runtime'] = old_runtime*self._runtime_mult + except KeyError: + logging.info('The runtime multiplier argument was set, but the runtime is not set in {0} '.format(self._namelist)) # If the number of levels is specified, set the namelist value if self._levels: case_nml['case_config']['n_levels'] = self._levels @@ -480,7 +470,7 @@ def setup_rundir(self): case_nml['case_config']['n_itt_diag'] = self._n_itt_diag if self._timestep: case_nml['case_config']['dt'] = self._timestep - # look for the output_dir variable in the case configuration namelist and use it if it does; + # look for the output_dir variable in the case configuration namelist and use it if it does; # if it doesn't exist, create a default output directory name (from the case and suite names) and create a namelist patch try: output_dir = case_nml['case_config']['output_dir'] @@ -493,7 +483,7 @@ def setup_rundir(self): output_dir = 'output_' + self._case + '_' + self._suite + '_' + os.path.splitext(self._physics_namelist)[0] output_dir_patch_nml = {'case_config':{'output_dir':output_dir}} custom_output_dir = False - + #if using the DEPHY format, need to also check the case data file for the surfaceForcing global attribute for 'Flux' or 'surfaceFlux', which denotes prescribed surface fluxes try: input_type = case_nml['case_config']['input_type'] @@ -503,7 +493,7 @@ def setup_rundir(self): nc_fid = Dataset(os.path.join(SCM_ROOT, self._case_data_dir) + '/' + self._case + '_SCM_driver.nc' , 'r') surfaceForcing = nc_fid.getncattr('surface_forcing_temp') nc_fid.close() - if (surfaceForcing.lower() == 'kinematic' or surfaceForcing.lower() == 'surface_flux'): + if (surfaceForcing.lower() == 'flux' or surfaceForcing.lower() == 'surface_flux'): surface_flux_spec = True except KeyError: # if not using DEPHY format, check to see if surface fluxes are specified in the case configuration file (default is False) @@ -511,34 +501,34 @@ def setup_rundir(self): surface_flux_spec = case_nml['case_config']['sfc_flux_spec'] except KeyError: surface_flux_spec = False - + # If surface fluxes are specified for this case, use the SDF modified to use them if surface_flux_spec: logging.info('Specified surface fluxes are used for case {0}. Switching to SDF {1} from {2}'.format(self._case,'suite_' + self._suite + '_ps' + '.xml','suite_' + self._suite + '.xml')) self._suite = self._suite + '_ps' - + # Create physics_config namelist for experiment configuration file physics_config = {"physics_suite":self._suite, "physics_nml":self._physics_namelist,} physics_config_dict = {"physics_config":physics_config} physics_config_nml = f90nml.namelist.Namelist(physics_config_dict) - + # Create STANDARD_EXPERIMENT_NAMELIST in the run directory with the case configuration and physics configuration namelists logging.info('Creating experiment configuration namelist {0} in the run directory from {1} using {2} and {3} '.format(STANDARD_EXPERIMENT_NAMELIST,self._namelist,self._suite,self._physics_namelist)) - + with open(os.path.join(SCM_RUN, STANDARD_EXPERIMENT_NAMELIST), "w+") as nml_file: case_nml.write(nml_file) - + with open(os.path.join(SCM_RUN, STANDARD_EXPERIMENT_NAMELIST), "a") as nml_file: physics_config_nml.write(nml_file) - + # if using the default output dir name created in this script, patch the experiment namelist with the new output_dir variable if(not custom_output_dir): # GJF TODO: this implementation is clunky; newer versions of f90nml can handle this better, but this works with v0.19 so no need to require newer version f90nml.patch(os.path.join(SCM_RUN, STANDARD_EXPERIMENT_NAMELIST), output_dir_patch_nml, 'temp.nml') cmd = "mv {0} {1}".format('temp.nml', os.path.join(SCM_RUN, STANDARD_EXPERIMENT_NAMELIST)) execute(cmd) - + # Link physics namelist to run directory with its original name logging.debug('Linking physics namelist {0} to run directory'.format(self._physics_namelist)) if os.path.isfile(os.path.join(SCM_RUN, self._physics_namelist)): @@ -555,7 +545,7 @@ def setup_rundir(self): logging.info('Found optional prescribed surface physics namelist {0}; linking it to run directory'.format(opt_ps_nml_filename)) cmd = "ln -sf {0} {1}".format(opt_ps_nml_filename, os.path.join(SCM_RUN, self._physics_namelist)) execute(cmd) - + # Link tracer configuration to run directory with standard name logging.debug('Linking tracer configuration {0} to run directory'.format(self._tracers)) if os.path.isfile(os.path.join(SCM_RUN, self._tracers)): @@ -566,7 +556,7 @@ def setup_rundir(self): raise Exception(message) cmd = "ln -sf {0} {1}".format(os.path.join(SCM_ROOT, TRACERS_DIR, self._tracers), os.path.join(SCM_RUN, TRACERS_LINK)) execute(cmd) - + # Link case data file to run directory with original name try: input_type = case_nml['case_config']['input_type'] @@ -585,7 +575,7 @@ def setup_rundir(self): raise Exception(message) cmd = "ln -sf {0} {1}".format(os.path.join(SCM_ROOT, self._case_data_dir, case_data_netcdf_file), os.path.join(SCM_RUN, case_data_netcdf_file)) execute(cmd) - + # Link vertical coordinate file to run directory with its original name if (self._npz_type == 'input'): logging.debug('Linking vertical coordinate file {0} to run directory'.format(self._vert_coord_file)) @@ -597,7 +587,7 @@ def setup_rundir(self): raise Exception(message) cmd = "ln -sf {0} {1}".format(os.path.join(SCM_ROOT, VERT_COORD_DATA_DIR, self._vert_coord_file), os.path.join(SCM_RUN, self._vert_coord_file)) execute(cmd) - + # Link physics SDF to run directory physics_suite = 'suite_' + self._suite + '.xml' logging.debug('Linking physics suite {0} to run directory'.format(physics_suite)) @@ -609,7 +599,7 @@ def setup_rundir(self): raise Exception(message) cmd = "ln -sf {0} {1}".format(os.path.join(SCM_ROOT, PHYSICS_SUITE_DIR, physics_suite), os.path.join(SCM_RUN, physics_suite)) execute(cmd) - + # Link physics data needed for schemes to run directory logging.debug('Linking physics input data from {0} into run directory'.format(os.path.join(SCM_ROOT, PHYSICS_DATA_DIR))) for entry in os.listdir(os.path.join(SCM_ROOT, PHYSICS_DATA_DIR)): @@ -618,7 +608,7 @@ def setup_rundir(self): logging.debug('Linking file {0}'.format(entry)) cmd = 'ln -sf {0} {1}'.format(os.path.join(SCM_ROOT, PHYSICS_DATA_DIR, entry), os.path.join(SCM_RUN, entry)) execute(cmd) - + # Link reference profile data to run directory logging.debug('Linking reference profile data from {0} into run directory'.format(os.path.join(SCM_ROOT, REFERENCE_PROFILE_DIR))) for entry in REFERENCE_PROFILE_FILE_LIST: @@ -627,7 +617,7 @@ def setup_rundir(self): logging.debug('Linking file {0}'.format(entry)) cmd = 'ln -sf {0} {1}'.format(os.path.join(SCM_ROOT, REFERENCE_PROFILE_DIR, entry), os.path.join(SCM_RUN, entry)) execute(cmd) - + # Parse physics namelist and extract # - oz_phys # - oz_phys_2015 @@ -648,7 +638,7 @@ def setup_rundir(self): message = 'Logic error, both oz_phys and oz_phys_2015 are set to true in the physics namelist' logging.critical(message) raise Exception(message) - + # Link input data for oz_phys or oz_phys_2015 if os.path.exists(os.path.join(SCM_RUN, OZ_PHYS_LINK)): os.remove(os.path.join(SCM_RUN, OZ_PHYS_LINK)) @@ -660,13 +650,13 @@ def setup_rundir(self): logging.debug('Linking input data for oz_phys_2015') cmd = 'ln -sf {0} {1}'.format(os.path.join(SCM_RUN, OZ_PHYS_2015_TARGET), os.path.join(SCM_RUN, OZ_PHYS_LINK)) execute(cmd) - + # Look for do_ugwp_v1 try: do_ugwp_v1 = nml['gfs_physics_nml']['do_ugwp_v1'] except KeyError: do_ugwp_v1 = DEFAULT_DO_UGWP_V1 - + # Link the tau file if do_ugwp_v1 if do_ugwp_v1: if os.path.exists(os.path.join(SCM_RUN, TAU_LINK)): @@ -674,7 +664,7 @@ def setup_rundir(self): logging.debug('Linking input data for UGWP_v1') cmd = 'ln -sf {0} {1}'.format(os.path.join(SCM_RUN, TAU_TARGET), os.path.join(SCM_RUN, TAU_LINK)) execute(cmd) - + # Link scripts needed to run SCM analysis logging.debug('Linking analysis scripts from {0} into run directory'.format(os.path.join(SCM_ROOT, SCM_ANALYSIS_SCRIPT_DIR))) analysis_script_files = ['scm_analysis.py','configspec.ini'] @@ -684,7 +674,7 @@ def setup_rundir(self): logging.debug('Linking file {0}'.format(entry)) cmd = 'ln -sf {0} {1}'.format(os.path.join(SCM_ROOT, SCM_ANALYSIS_SCRIPT_DIR, entry), os.path.join(SCM_RUN, entry)) execute(cmd) - + # Link plot configuration files needed to run SCM analysis logging.debug('Linking plot configuration files from {0} into run directory'.format(os.path.join(SCM_ROOT, SCM_ANALYSIS_CONFIG_DIR))) for entry in os.listdir(os.path.join(SCM_ROOT, SCM_ANALYSIS_CONFIG_DIR)): @@ -693,18 +683,18 @@ def setup_rundir(self): logging.debug('Linking file {0}'.format(entry)) cmd = 'ln -sf {0} {1}'.format(os.path.join(SCM_ROOT, SCM_ANALYSIS_CONFIG_DIR, entry), os.path.join(SCM_RUN, entry)) execute(cmd) - + # Create output directory (delete existing directory) logging.debug('Creating output directory {0} in run directory'.format(output_dir)) if os.path.isdir(os.path.join(SCM_RUN, output_dir)): shutil.rmtree(os.path.join(SCM_RUN, output_dir)) os.makedirs(os.path.join(SCM_RUN, output_dir)) - + # Write experiment configuration file to output directory logging.debug('Writing experiment configuration {0}.nml to output directory'.format(self._name)) cmd = 'cp {0} {1}'.format(os.path.join(SCM_RUN, STANDARD_EXPERIMENT_NAMELIST), os.path.join(SCM_RUN, output_dir,self._name + '.nml')) execute(cmd) - + # Move executable to run dir if COPY_EXECUTABLE: logging.debug('Copying executable to run directory') @@ -714,7 +704,7 @@ def setup_rundir(self): logging.debug('Linking executable to run directory') cmd = 'ln -sf {0} {1}'.format(os.path.join(SCM_ROOT, SCM_BIN, EXECUTABLE_NAME), os.path.join(SCM_RUN, EXECUTABLE_NAME)) execute(cmd) - + #Inform user of timestep and output intervals if self._timestep: logging.info('Using {0}s as the timestep with an instantaneous output period of {1}s and a diagnostic output period of {2}s'.format( @@ -722,19 +712,15 @@ def setup_rundir(self): else: logging.info('Using the default timestep in src/scm_input.F90 with an instantaneous output period of {0}*dt and a diagnostic output period of {1}*dt'.format( case_nml['case_config']['n_itt_out'],case_nml['case_config']['n_itt_diag'])) - + return os.path.join(SCM_RUN, output_dir) -def launch_executable(use_gdb, gdb, mpi_command, ignore_error = False): +def launch_executable(use_gdb, gdb, ignore_error = False): """Configure model run command and pass control to shell/gdb""" if use_gdb: - if not mpi_command: - mpi_command = DEFAULT_MPI_COMMAND + ' xterm -e ' - cmd = '(cd {scm_run} && {mpi_command} {gdb} {executable})'.format(scm_run=SCM_RUN, mpi_command=mpi_command, gdb=gdb, executable=EXECUTABLE) + cmd = '(cd {scm_run} && {gdb} {executable})'.format(scm_run=SCM_RUN, gdb=gdb, executable=EXECUTABLE) else: - if not mpi_command: - mpi_command = DEFAULT_MPI_COMMAND - cmd = '(cd {scm_run} && time {mpi_command} {executable})'.format(scm_run=SCM_RUN, mpi_command=mpi_command, executable=EXECUTABLE) + cmd = '(cd {scm_run} && time {executable})'.format(scm_run=SCM_RUN, executable=EXECUTABLE) logging.info('Passing control to "{0}"'.format(cmd)) time.sleep(1) # This will abort in 'execute' in the event of an error if ignore_error = False @@ -758,7 +744,7 @@ def launch_executable(use_gdb, gdb, mpi_command, ignore_error = False): else: time_elapsed = int(minutes)*60 + float(seconds) return (status, time_elapsed) - + def copy_outdir(exp_dir): """Copy output directory to /home for this experiment.""" dir_name = os.path.basename(exp_dir) @@ -767,79 +753,11 @@ def copy_outdir(exp_dir): shutil.rmtree(home_output_dir) shutil.copytree(exp_dir, home_output_dir) - -def print_report_line(case_s, suite, namelist, max_str_lens): - case_l = max_str_lens.case - suite_l = max_str_lens.suite - namelist_l = max_str_lens.namelist - logging.info(f"| {case_s:<{case_l}} | {suite:<{suite_l}} | {namelist:<{namelist_l}} |") - - -def print_report(logs, total_count, max_str_lens, - passing=False, failing=False): - case_l = max_str_lens.case - suite_l = max_str_lens.suite - namelist_l = max_str_lens.namelist - status_l = max_str_lens.status - header_printed = False - column_width = (case_l + suite_l + namelist_l + status_l + 13) - - # print formatted summary - print("") - if (passing): - print("Passing Summary:") - if (failing): - print("Failure Summary:") - print("-" * column_width) - for log in logs: - case_s, suite, namelist, status = log - print(f"| {case_s:<{case_l}} | {suite:<{suite_l}} | {namelist:<{namelist_l}} | {status:<{status_l}} |") - if not header_printed: - print("-" * column_width) - header_printed = True - - print("-" * column_width) - if (passing): - # error_log contains header, subtracting 1 from error - passing_count = logs.shape[0] - 1 - print(f"[{passing_count}/{total_count}] passing cases") - if (failing): - error_count = logs.shape[0] - 1 - print(f"[{error_count}/{total_count}] failed cases") - - -class MaxStrLengths: - def __init__(self, max_case_len, max_suite_len, - max_namelist_len, max_status_len): - self.case = max_case_len - self.suite = max_suite_len - self.namelist = max_namelist_len - self.status = max_status_len - - -def find_max_str_lengths(run_list): - max_case_len = 0 - max_suite_len = 0 - max_status_len = len('status') - - # Loop through the list of dictionaries to find the longest lengths - for item in run_list: - max_case_len = max(max_case_len, len(item['case'])) - max_suite_len = max(max_suite_len, len(item['suite'])) - - # add 6, e.g. diff between len('SCM_HRRR_gf') and len('input_HRRR_gf.nml') - max_namelist_len = max_suite_len + 6 - max_str_lens = MaxStrLengths(max_case_len, max_suite_len, - max_namelist_len, max_status_len) - return max_str_lens - - def main(): (file, case, sdf, namelist, tracers, use_gdb, runtime, runtime_mult, docker, \ verbose, levels, npz_type, vert_coord_file, case_data_dir, n_itt_out, \ - n_itt_diag, run_dir, bin_dir, timestep, mpi_command, stop_on_error \ - ) = parse_arguments() - + n_itt_diag, run_dir, bin_dir, timestep) = parse_arguments() + setup_logging(verbose) global SCM_ROOT @@ -855,7 +773,7 @@ def main(): SCM_BIN = bin_dir else: SCM_BIN = os.path.join(SCM_ROOT, DEFAULT_BIN_DIR) - + global SCM_RUN if run_dir: SCM_RUN = run_dir @@ -863,10 +781,10 @@ def main(): SCM_RUN = os.path.join(SCM_ROOT, DEFAULT_RUN_DIR) if not os.path.isdir(SCM_RUN): os.makedirs(SCM_RUN) - + global EXECUTABLE EXECUTABLE = os.path.join(SCM_RUN, EXECUTABLE_NAME) - + # Debugger if use_gdb: gdb = find_gdb() @@ -891,20 +809,13 @@ def main(): if (namelist != None): run_list[0]["namelist"] = namelist if (tracers != None): run_list[0]["tracers"] = tracers - - # setup variables - error_logs = [["Failed Case", "Suite", "Namelist", "Status"]] - pass_logs = [["Passing Case", "Suite", "Namelist", "Status"]] - max_str_lens = find_max_str_lengths(run_list) - failed_case = False - irun = 0 - # Loop through all input "run dictionaires" + irun = 0 for run in run_list: # # Is this a "supported" SCM configuration? - # (e.g Do we have default namelist and tracer files for this suite?) + # (e.g Do we have defualt namelist and tracer files for this suite?) # If supported, copy default configuration, modify below if necessary. # active_suite = None @@ -924,9 +835,9 @@ def main(): logging.info('Using provided namelist for suite={0}'.format(run["suite"])) except: logging.info('Using default namelist for suite={0}'.format(run["suite"])) - + # If tracer file provided, use. Otherwise use default tracer file for this suite - try: + try: active_suite.tracers = run["tracers"] logging.info('Using provided tracer file for suite={0}'.format(run["suite"])) except: @@ -939,7 +850,7 @@ def main(): # If namelist and tracer file provided, use. Otherwise error. if ("namelist" in run) and ("tracers" in run): irun = irun + 1 - if timestep: + if timestep: active_suite = suite(run["suite"], run["tracers"], run["namelist"], timestep, -1, False) else: active_suite = suite(run["suite"], run["tracers"], run["namelist"], -1, -1, False) @@ -951,7 +862,6 @@ def main(): # # Run the SCM case # - print_report_line(run["case"], run["suite"], active_suite.namelist, max_str_lens) logging.info('Executing process {0} of {1}: case={2}, suite={3}, namelist={4}'.format( irun, len(run_list), run["case"], run["suite"], active_suite.namelist)) # @@ -963,36 +873,19 @@ def main(): l_ignore_error = MULTIRUN_IGNORE_ERROR else: l_ignore_error = False - if stop_on_error: - l_ignore_error = False - - (status, time_elapsed) = launch_executable(use_gdb, gdb, mpi_command, ignore_error = l_ignore_error) + (status, time_elapsed) = launch_executable(use_gdb, gdb, ignore_error = l_ignore_error) # if status == 0: logging.info('Process "(case={0}, suite={1}, namelist={2}" completed successfully'. \ format(run["case"], run["suite"], active_suite.namelist)) - pass_logs = np.append(pass_logs, - [[run["case"], run["suite"], active_suite.namelist, status]], - axis=0) else: - failed_case = True - error_str = 'Process "(case={0}, suite={1}, namelist={2}" exited with code {3}'. \ - format( run["case"], run["suite"], active_suite.namelist, status) - logging.warning(error_str) - error_logs = np.append(error_logs, - [[run["case"], run["suite"], active_suite.namelist, status]], - axis=0) + logging.warning('Process "(case={0}, suite={1}, namelist={2}" exited with code {3}'. \ + format( run["case"], run["suite"], active_suite.namelist, status)) # if time_elapsed: logging.info(' Elapsed time: {0}s'.format(time_elapsed)) if docker: copy_outdir(exp_dir) - print_report(pass_logs, len(run_list), max_str_lens, passing=True) - if (failed_case): - print_report(error_logs, len(run_list), max_str_lens, failing=True) - sys.exit(1) - - if __name__ == '__main__': main() diff --git a/scm/src/scm_physical_constants.F90 b/scm/src/scm_physical_constants.F90 index c500330c4..0680e8083 100644 --- a/scm/src/scm_physical_constants.F90 +++ b/scm/src/scm_physical_constants.F90 @@ -24,7 +24,7 @@ module scm_physical_constants real(kind=dp),parameter:: con_cvap =1.8460e+3 real(kind=dp),parameter:: con_hvap =2.5000e+6 !< latent heat of vaporization of water at 0C real(kind=dp),parameter:: con_hfus =3.3358e+5 !< latent heat of fusion of water at 0C - real(kind=dp),parameter:: con_xls =2.85e+6 !< latent heat of sublimation of water at 0C + real(kind=dp),parameter:: con_xls =2.8440E06 !< latent heat of sublimation of snow/ice at 0C real(kind=dp),parameter:: con_psat =6.1078e+2_dp !< pres at H2O 3pt (\f$Pa\f$) real(kind=dp),parameter:: con_t0c =2.7315e+2 real(kind=dp),parameter:: con_ttp =2.7316e+2 diff --git a/scm/src/scm_physical_constants.meta b/scm/src/scm_physical_constants.meta index 75dab5678..1b29ed9de 100644 --- a/scm/src/scm_physical_constants.meta +++ b/scm/src/scm_physical_constants.meta @@ -119,8 +119,8 @@ type = real kind = kind_phys [con_xls] - standard_name = latent_heat_of_sublimation_of_water_at_0C - long_name = latent heat of sublimation of water at 0C + standard_name = latent_heat_of_sublimation_of_ice_snow_at_0C + long_name = latent heat of sublimation of snow/ice at 0C units = J kg-1 dimensions = () type = real @@ -299,4 +299,4 @@ units = K dimensions = () type = real - kind = kind_phys \ No newline at end of file + kind = kind_phys diff --git a/scm/src/suite_info.py b/scm/src/suite_info.py index f74fee7cd..811cdd433 100755 --- a/scm/src/suite_info.py +++ b/scm/src/suite_info.py @@ -61,6 +61,7 @@ def timestep(self, value): suite_list.append(suite('SCM_RAP_mmm', 'tracers_RAP.txt', 'input_RAP_mmm.nml', 600.0, 600.0 , False)) suite_list.append(suite('SCM_RAP_mmm_YSU', 'tracers_RAP.txt', 'input_RAP_mmm_YSU.nml', 600.0, 600.0 , False)) suite_list.append(suite('SCM_RAP_ntiedtke', 'tracers_RAP.txt', 'input_RAP_ntiedtke.nml', 600.0, 600.0 , False)) +suite_list.append(suite('SCM_RAP_ufs_ntiedtke', 'tracers_RAP.txt', 'input_RAP_ufs_ntiedtke.nml', 600.0, 600.0 , False)) suite_list.append(suite('SCM_RAP_sfclayrev', 'tracers_RAP.txt', 'input_RAP_sfclayrev.nml', 600.0, 600.0 , False)) suite_list.append(suite('SCM_GFS_v17_p8_mmm', 'tracers_GFS_v17_p8.txt', 'input_GFS_v17_p8_mmm.nml', 600.0, 600.0, False)) suite_list.append(suite('SCM_GFS_v17_p8_YSU', 'tracers_GFS_v17_p8.txt', 'input_GFS_v17_p8_YSU.nml', 600.0, 600.0, False))