From 9b598d5ffee443195d2cabea2e7745addb4998b7 Mon Sep 17 00:00:00 2001 From: Janice Kim Date: Mon, 8 Sep 2025 16:06:26 -0400 Subject: [PATCH 1/4] NDSL Issue#64 Simplifying Namelist + inheriting from f90nml.Namelist Modifying workflow tests until namelist refactor is completed --- .github/workflows/fv3_translate_tests.yaml | 4 +- .github/workflows/pace_tests.yaml | 4 +- .github/workflows/shield_tests.yaml | 4 +- ndsl/namelist.py | 668 +++------------------ ndsl/stencils/testing/conftest.py | 2 +- 5 files changed, 79 insertions(+), 603 deletions(-) diff --git a/.github/workflows/fv3_translate_tests.yaml b/.github/workflows/fv3_translate_tests.yaml index f28e5ad1..5e794b7d 100644 --- a/.github/workflows/fv3_translate_tests.yaml +++ b/.github/workflows/fv3_translate_tests.yaml @@ -8,9 +8,11 @@ on: branches: - main # ... when merging into the main branch +# TODO: Revert tests back to GFDL (not jjuyeonkim) after merging +# https://github.com/NOAA-GFDL/NDSL/issues/64 jobs: fv3_translate_tests: - uses: NOAA-GFDL/pyFV3/.github/workflows/translate.yaml@develop + uses: jjuyeonkim/pyFV3/.github/workflows/translate.yaml@20250723_namelist_1 with: component_trigger: true component_name: NDSL diff --git a/.github/workflows/pace_tests.yaml b/.github/workflows/pace_tests.yaml index ea3d40b3..03517faa 100644 --- a/.github/workflows/pace_tests.yaml +++ b/.github/workflows/pace_tests.yaml @@ -8,9 +8,11 @@ on: branches: - main # ... when merging into the main branch +# TODO: Revert tests back to GFDL (not jjuyeonkim) after merging +# https://github.com/NOAA-GFDL/NDSL/issues/64 jobs: pace_main_tests: - uses: NOAA-GFDL/pace/.github/workflows/main_unit_tests.yaml@develop + uses: jjuyeonkim/pace/.github/workflows/main_unit_tests.yaml@20250723_namelist_1 with: component_trigger: true component_name: NDSL diff --git a/.github/workflows/shield_tests.yaml b/.github/workflows/shield_tests.yaml index 53ba510b..22f3c094 100644 --- a/.github/workflows/shield_tests.yaml +++ b/.github/workflows/shield_tests.yaml @@ -8,9 +8,11 @@ on: branches: - main # ... when merging into the main branch +# TODO: Revert tests back to GFDL (not jjuyeonkim) after merging +# https://github.com/NOAA-GFDL/NDSL/issues/64 jobs: shield_translate_tests: - uses: NOAA-GFDL/pySHiELD/.github/workflows/translate.yaml@develop + uses: jjuyeonkim/pySHiELD/.github/workflows/translate.yaml@20250820_namelist_1 with: component_trigger: true component_name: NDSL diff --git a/ndsl/namelist.py b/ndsl/namelist.py index e040c2cc..4080621e 100644 --- a/ndsl/namelist.py +++ b/ndsl/namelist.py @@ -12,610 +12,80 @@ # Global set of namelist defaults, attached to class for namespacing and static typing class NamelistDefaults: - layout = (1, 1) - grid_type = 0 - dx_const = 1000.0 - dy_const = 1000.0 - deglat = 15.0 - u_max = 350.0 - do_f3d = False - inline_q = False - do_skeb = False - """Save dissipation estimate""" - use_logp = False - moist_phys = True - check_negative = False - # gfdl_cloud_microphys.F90 - tau_r2g = 900.0 - """rain freezing during fast_sat""" - tau_smlt = 900.0 - """snow melting""" - tau_g2r = 600.0 - """graupel melting to rain""" - tau_imlt = 600.0 - """cloud ice melting""" - tau_i2s = 1000.0 - """cloud ice to snow auto - conversion""" - tau_l2r = 900.0 - """cloud water to rain auto - conversion""" - tau_g2v = 1200.0 - """graupel sublimation""" - tau_v2g = 21600.0 - """graupel deposition -- make it a slow process""" - sat_adj0 = 0.90 - """adjustment factor (0: no, 1: full) during fast_sat_adj""" - ql_gen = 1.0e-3 - """max new cloud water during remapping step if fast_sat_adj = .t.""" - ql_mlt = 2.0e-3 - """max value of cloud water allowed from melted cloud ice""" - qs_mlt = 1.0e-6 - """max cloud water due to snow melt""" - ql0_max = 2.0e-3 - """max cloud water value (auto converted to rain)""" - t_sub = 184.0 - """min temp for sublimation of cloud ice""" - qi_gen = 1.82e-6 - """max cloud ice generation during remapping step""" - qi_lim = 1.0 - """cloud ice limiter to prevent large ice build up""" - qi0_max = 1.0e-4 - """max cloud ice value (by other sources)""" - rad_snow = True - """consider snow in cloud fraction calculation""" - rad_rain = True - """consider rain in cloud fraction calculation""" - rad_graupel = True - """consider graupel in cloud fraction calculation""" - tintqs = False - """use temperature in the saturation mixing in PDF""" - dw_ocean = 0.10 - """base value for ocean""" - dw_land = 0.15 - """base value for subgrid deviation / variability over land""" - # cloud scheme 0 - ? - # 1: old fvgfs gfdl) mp implementation - # 2: binary cloud scheme (0 / 1) - icloud_f = 0 - cld_min = 0.05 - """minimum cloud fraction""" - tau_l2v = 300.0 - """cloud water to water vapor (evaporation)""" - tau_v2l = 90.0 - """water vapor to cloud water (condensation)""" - c2l_ord = 4 - regional = False - m_split = 0 - convert_ke = False - breed_vortex_inline = False - use_old_omega = True - use_logp = False - rf_fast = False - p_ref = 1e5 - """Surface pressure used to construct a horizontally-uniform reference""" - adiabatic = False - nf_omega = 1 - fv_sg_adj = -1 - n_sponge = 1 - fast_sat_adj = True - qc_crt = 5.0e-8 - """Minimum condensate mixing ratio to allow partial cloudiness""" - c_cracw = 0.8 - """Rain accretion efficiency""" - c_paut = 0.5 - """Autoconversion cloud water to rain (use 0.5 to reduce autoconversion)""" - c_pgacs = 0.01 - """Snow to graupel "accretion" eff. (was 0.1 in zetac)""" - c_psaci = 0.05 - """Accretion: cloud ice to snow (was 0.1 in zetac)""" - ccn_l = 300.0 - """CCN over land (cm^-3)""" - ccn_o = 100.0 - """CCN over ocean (cm^-3)""" - const_vg = False - """Fall velocity tuning constant of graupel""" - const_vi = False - """Fall velocity tuning constant of ice""" - const_vr = False - """Fall velocity tuning constant of rain water""" - const_vs = False - """Fall velocity tuning constant of snow""" - vi_fac = 1.0 - """if const_vi: 1/3""" - vs_fac = 1.0 - """if const_vs: 1.""" - vg_fac = 1.0 - """if const_vg: 2.""" - vr_fac = 1.0 - """if const_vr: 4.""" - de_ice = False - """To prevent excessive build-up of cloud ice from external sources""" - do_qa = True - """Do inline cloud fraction""" - do_sedi_heat = False - """Transport of heat in sedimentation""" - do_sedi_w = True - """Transport of vertical motion in sedimentation""" - fix_negative = True - """Fix negative water species""" - irain_f = 0 - """Cloud water to rain auto conversion scheme""" - mono_prof = False - """Perform terminal fall with mono ppm scheme""" - mp_time = 225.0 - """Maximum microphysics timestep (sec)""" - prog_ccn = False - """Do prognostic ccn (yi ming's method)""" - qi0_crt = 8e-05 - """Cloud ice to snow autoconversion threshold""" - qs0_crt = 0.003 - """Snow to graupel density threshold (0.6e-3 in purdue lin scheme)""" - rh_inc = 0.2 - """RH increment for complete evaporation of cloud water and cloud ice""" - rh_inr = 0.3 - """RH increment for minimum evaporation of rain""" - rthresh = 1e-05 - """Critical cloud drop radius (micrometers)""" - sedi_transport = True - """Transport of momentum in sedimentation""" - use_ppm = False - """Use ppm fall scheme""" - vg_max = 16.0 - """Maximum fall speed for graupel""" - vi_max = 1.0 - """Maximum fall speed for ice""" - vr_max = 16.0 - """Maximum fall speed for rain""" - vs_max = 2.0 - """Maximum fall speed for snow""" - z_slope_ice = True - """Use linear mono slope for autoconversions""" - z_slope_liq = True - """Use linear mono slope for autoconversions""" - tice = 273.16 - """set tice = 165. to turn off ice - phase phys (kessler emulator)""" - alin = 842.0 - """value for 'a' in lin1983""" - clin = 4.8 - """"c" in lin 1983, 4.8 -- > 6. (to enhance ql -- > qs)""" - mom4ice = False - lsm = 1 - redrag = False - isatmedmf = 0 - """which version of satmedmfvdif to use""" - dspheat = False - """flag for tke dissipative heating""" - xkzm_h = 1.0 - """background vertical diffusion for heat q over ocean""" - xkzm_m = 1.0 - """background vertical diffusion for momentum over ocean""" - xkzm_hl = 1.0 - """background vertical diffusion for heat q over land""" - xkzm_ml = 1.0 - """background vertical diffusion for momentum over land""" - xkzm_hi = 1.0 - """background vertical diffusion for heat q over ice""" - xkzm_mi = 1.0 - """background vertical diffusion for momentum over ice""" - xkzm_ho = 1.0 - """background vertical diffusion for heat q over ocean""" - xkzm_mo = 1.0 - """background vertical diffusion for momentum over ocean""" - xkzm_s = 1.0 - """sigma threshold for background mom. diffusion""" - xkzm_lim = 0.01 - """background vertical diffusion limit""" - xkzminv = 0.15 - """diffusivity in inversion layers""" - xkgdx = 25.0e3 - """background vertical diffusion threshold""" - rlmn = 30.0 - """lower-limiter on asymtotic mixing length in satmedmfdiff""" - rlmx = 300.0 - """upper-limiter on asymtotic mixing length in satmedmfdiff""" - do_dk_hb19 = False - """flag for using hb19 background diff formula in satmedmfdiff""" - cap_k0_land = True - """flag for applying limter on background diff in inversion layer over land in satmedmfdiff""" - ncld = 1 - """choice of cloud scheme""" - c0s_shal = 0.002 - """c_e for shallow convection (Han and Pan, 2011, eq(6))""" - c1_shal = 5.0e-4 - """conversion parameter of detrainment from liquid water into convetive precipitaiton""" - clam_shal = 0.3 - """conversion parameter of detrainment from liquid water into grid-scale cloud water""" - pgcon_shal = 0.55 - """control the reduction in momentum transport""" - asolfac_shal = 0.89 - """aerosol-aware parameter based on Lim & Hong (2012): asolfac= cx / c0s(=.002), cx = min([-0.7 ln(Nccn) + 24]*1.e-4, c0s), Nccn: CCN number concentration in cm^(-3), Until a realistic Nccn is provided, typical Nccns are assumed, as Nccn=100 for sea and Nccn=7000 for land""" - lsoil = 4 - """Number of soil levels in land surface model""" - sw_dynamics = False - """flag for turning on shallow water conditions in dyn core""" - - @classmethod - def as_dict(cls): - return { - name: default - for name, default in cls.__dict__.items() - if not name.startswith("_") - } - - -@dataclasses.dataclass -class Namelist: - # data_set: Any - # date_out_of_range: str - # do_sst_pert: bool - # interp_oi_sst: bool - # no_anom_sst: bool - # sst_pert: float - # sst_pert_type: str - # use_daily: bool - # use_ncep_ice: bool - # use_ncep_sst: bool - # blocksize: int - # chksum_debug: bool - """ - note: dycore_only may not be used in this model - the same way it is in the Fortran version, watch for - consequences of these inconsistencies, or more closely - parallel the Fortran structure - """ - dycore_only: bool = DEFAULT_BOOL - # fdiag: float - # knob_ugwp_azdir: Tuple[int, int, int, int] - # knob_ugwp_doaxyz: int - # knob_ugwp_doheat: int - # knob_ugwp_dokdis: int - # knob_ugwp_effac: Tuple[int, int, int, int] - # knob_ugwp_ndx4lh: int - # knob_ugwp_solver: int - # knob_ugwp_source: Tuple[int, int, int, int] - # knob_ugwp_stoch: Tuple[int, int, int, int] - # knob_ugwp_version: int - # knob_ugwp_wvspec: Tuple[int, int, int, int] - # launch_level: int - # reiflag: int - # reimax: float - # reimin: float - # rewmax: float - # rewmin: float - # atmos_nthreads: int - # calendar: Any - # current_date: Any - days: int = 0 dt_atmos: int = DEFAULT_INT - # dt_ocean: Any - hours: int = 0 - # memuse_verbose: Any - minutes: int = 0 - # months: Any - # ncores_per_node: Any - seconds: int = 0 - # use_hyper_thread: Any - # max_axes: Any - # max_files: Any - # max_num_axis_sets: Any - # prepend_date: Any - # checker_tr: Any - # filtered_terrain: Any - # gfs_dwinds: Any - # levp: Any - # nt_checker: Any - # checksum_required: Any - # max_files_r: Any - # max_files_w: Any - # clock_grain: Any - # domains_stack_size: Any - # print_memory_usage: Any - a_imp: float = DEFAULT_FLOAT - # adjust_dry_mass: Any - beta: float = DEFAULT_FLOAT - # consv_am: Any - consv_te: float = DEFAULT_FLOAT - d2_bg: float = DEFAULT_FLOAT - d2_bg_k1: float = DEFAULT_FLOAT - d2_bg_k2: float = DEFAULT_FLOAT - d4_bg: float = DEFAULT_FLOAT - d_con: float = DEFAULT_FLOAT - d_ext: float = DEFAULT_FLOAT - dddmp: float = DEFAULT_FLOAT - delt_max: float = DEFAULT_FLOAT - # dnats: int - do_sat_adj: bool = DEFAULT_BOOL - do_vort_damp: bool = DEFAULT_BOOL - # dwind_2d: Any - # external_ic: Any - fill: bool = DEFAULT_BOOL - # fill_dp: bool - # fv_debug: Any - # gfs_phil: Any - hord_dp: int = DEFAULT_INT - hord_mt: int = DEFAULT_INT - hord_tm: int = DEFAULT_INT - hord_tr: int = DEFAULT_INT - hord_vt: int = DEFAULT_INT - hydrostatic: bool = DEFAULT_BOOL - # io_layout: Any - k_split: int = DEFAULT_INT - ke_bg: float = DEFAULT_FLOAT - kord_mt: int = DEFAULT_INT - kord_tm: int = DEFAULT_INT - kord_tr: int = DEFAULT_INT - kord_wz: int = DEFAULT_INT - layout: Tuple[int, int] = (1, 1) - # make_nh: bool - # mountain: bool - n_split: int = DEFAULT_INT - # na_init: Any - # ncep_ic: Any - # nggps_ic: Any - nord: int = DEFAULT_INT npx: int = DEFAULT_INT npy: int = DEFAULT_INT npz: int = DEFAULT_INT - ntiles: int = DEFAULT_INT - # nudge: Any - # nudge_qv: Any - nwat: int = DEFAULT_INT - p_fac: float = DEFAULT_FLOAT - # phys_hydrostatic: Any - # print_freq: Any - # range_warn: Any - # reset_eta: Any - rf_cutoff: float = DEFAULT_FLOAT - tau: float = DEFAULT_FLOAT - # tau_h2o: Any - # use_hydro_pressure: Any - vtdm4: float = DEFAULT_FLOAT - # warm_start: bool - z_tracer: bool = DEFAULT_BOOL - c_cracw: float = NamelistDefaults.c_cracw - c_paut: float = NamelistDefaults.c_paut - c_pgacs: float = NamelistDefaults.c_pgacs - c_psaci: float = NamelistDefaults.c_psaci - ccn_l: float = NamelistDefaults.ccn_l - ccn_o: float = NamelistDefaults.ccn_o - const_vg: bool = NamelistDefaults.const_vg - const_vi: bool = NamelistDefaults.const_vi - const_vr: bool = NamelistDefaults.const_vr - const_vs: bool = NamelistDefaults.const_vs - qc_crt: float = NamelistDefaults.qc_crt - vs_fac: float = NamelistDefaults.vs_fac - vg_fac: float = NamelistDefaults.vg_fac - vi_fac: float = NamelistDefaults.vi_fac - vr_fac: float = NamelistDefaults.vr_fac - de_ice: bool = NamelistDefaults.de_ice - do_qa: bool = NamelistDefaults.do_qa - do_sedi_heat: bool = NamelistDefaults.do_sedi_heat - do_sedi_w: bool = NamelistDefaults.do_sedi_w - fast_sat_adj: bool = NamelistDefaults.fast_sat_adj - fix_negative: bool = NamelistDefaults.fix_negative - irain_f: int = NamelistDefaults.irain_f - mono_prof: bool = NamelistDefaults.mono_prof - mp_time: float = NamelistDefaults.mp_time - prog_ccn: bool = NamelistDefaults.prog_ccn - qi0_crt: float = NamelistDefaults.qi0_crt - qs0_crt: float = NamelistDefaults.qs0_crt - rh_inc: float = NamelistDefaults.rh_inc - rh_inr: float = NamelistDefaults.rh_inr - # rh_ins: Any - rthresh: float = NamelistDefaults.rthresh - sedi_transport: bool = NamelistDefaults.sedi_transport - # use_ccn: Any - use_ppm: bool = NamelistDefaults.use_ppm - vg_max: float = NamelistDefaults.vg_max - vi_max: float = NamelistDefaults.vi_max - vr_max: float = NamelistDefaults.vr_max - vs_max: float = NamelistDefaults.vs_max - z_slope_ice: bool = NamelistDefaults.z_slope_ice - z_slope_liq: bool = NamelistDefaults.z_slope_liq - tice: float = NamelistDefaults.tice - alin: float = NamelistDefaults.alin - clin: float = NamelistDefaults.clin - mom4ice: bool = NamelistDefaults.mom4ice - lsm: int = NamelistDefaults.lsm - redrag: bool = NamelistDefaults.redrag - isatmedmf: int = NamelistDefaults.isatmedmf - dspheat: bool = NamelistDefaults.dspheat - xkzm_h: float = NamelistDefaults.xkzm_h - xkzm_m: float = NamelistDefaults.xkzm_m - xkzm_hl: float = NamelistDefaults.xkzm_hl - xkzm_ml: float = NamelistDefaults.xkzm_ml - xkzm_hi: float = NamelistDefaults.xkzm_hi - xkzm_mi: float = NamelistDefaults.xkzm_mi - xkzm_ho: float = NamelistDefaults.xkzm_ho - xkzm_mo: float = NamelistDefaults.xkzm_mo - xkzm_s: float = NamelistDefaults.xkzm_s - xkzm_lim: float = NamelistDefaults.xkzm_lim - xkzminv: float = NamelistDefaults.xkzminv - xkgdx: float = NamelistDefaults.xkgdx - rlmn: float = NamelistDefaults.rlmn - rlmx: float = NamelistDefaults.rlmx - do_dk_hb19: bool = NamelistDefaults.do_dk_hb19 - cap_k0_land: bool = NamelistDefaults.cap_k0_land - c0s_shal: float = NamelistDefaults.c0s_shal - c1_shal: float = NamelistDefaults.c1_shal - clam_shal: float = NamelistDefaults.clam_shal - pgcon_shal: float = NamelistDefaults.pgcon_shal - asolfac_shal: float = NamelistDefaults.asolfac_shal - ncld: int = NamelistDefaults.ncld - # cal_pre: Any - # cdmbgwd: Any - # cnvcld: Any - # cnvgwd: Any - # debug: Any - # do_deep: Any - # dspheat: Any - # fhcyc: Any - # fhlwr: Any - # fhswr: Any - # fhzero: Any - # hybedmf: Any - # iaer: Any - # ialb: Any - # ico2: Any - # iems: Any - # imfdeepcnv: Any - # imfshalcnv: Any - # imp_physics: Any - # isol: Any - # isot: Any - # isubc_lw: Any - # isubc_sw: Any - # ivegsrc: Any - # ldiag3d: Any - # lwhtr: Any - # nst_anl: Any - # pdfcld: Any - # pre_rad: Any - # prslrd0: Any - # random_clds: Any - # redrag: Any - # satmedmf: Any - # shal_cnv: Any - # swhtr: Any - # trans_trac: Any - # use_ufo: Any - # xkzm_h: Any - # xkzm_m: Any - # xkzminv: Any - # interp_method: Any - # lat_s: Any - # lon_s: Any - # ntrunc: Any - # fabsl: Any - # faisl: Any - # faiss: Any - # fnabsc: Any - # fnacna: Any - # fnaisc: Any - # fnalbc: Any - # fnalbc2: Any - # fnglac: Any - # fnmskh: Any - # fnmxic: Any - # fnslpc: Any - # fnsmcc: Any - # fnsnoa: Any - # fnsnoc: Any - # fnsotc: Any - # fntg3c: Any - # fntsfa: Any - # fntsfc: Any - # fnvegc: Any - # fnvetc: Any - # fnvmnc: Any - # fnvmxc: Any - # fnzorc: Any - # fsicl: Any - # fsics: Any - # fslpl: Any - # fsmcl: Any - # fsnol: Any - # fsnos: Any - # fsotl: Any - # ftsfl: Any - # ftsfs: Any - # fvetl: Any - # fvmnl: Any - # fvmxl: Any - # ldebug: Any - grid_type: int = NamelistDefaults.grid_type - dx_const: float = NamelistDefaults.dx_const - dy_const: float = NamelistDefaults.dy_const - deglat: float = NamelistDefaults.deglat - u_max: float = NamelistDefaults.u_max - do_f3d: bool = NamelistDefaults.do_f3d - inline_q: bool = NamelistDefaults.inline_q - do_skeb: bool = NamelistDefaults.do_skeb - """save dissipation estimate""" - use_logp: bool = NamelistDefaults.use_logp - moist_phys: bool = NamelistDefaults.moist_phys - check_negative: bool = NamelistDefaults.check_negative - # gfdl_cloud_microphys.F90 - tau_r2g: float = NamelistDefaults.tau_r2g - """rain freezing during fast_sat""" - tau_smlt: float = NamelistDefaults.tau_smlt - """snow melting""" - tau_g2r: float = NamelistDefaults.tau_g2r - """graupel melting to rain""" - tau_imlt: float = NamelistDefaults.tau_imlt - """cloud ice melting""" - tau_i2s: float = NamelistDefaults.tau_i2s - """cloud ice to snow auto - conversion""" - tau_l2r: float = NamelistDefaults.tau_l2r - """cloud water to rain auto - conversion""" - tau_g2v: float = NamelistDefaults.tau_g2v - """graupel sublimation""" - tau_v2g: float = NamelistDefaults.tau_v2g - """graupel deposition -- make it a slow process""" - sat_adj0: float = NamelistDefaults.sat_adj0 - """adjustment factor (0: no 1: full) during fast_sat_adj""" - ql_gen: float = 1.0e-3 - """max new cloud water during remapping step if fast_sat_adj = .t.""" - ql_mlt: float = NamelistDefaults.ql_mlt - """max value of cloud water allowed from melted cloud ice""" - qs_mlt: float = NamelistDefaults.qs_mlt - """max cloud water due to snow melt""" - ql0_max: float = NamelistDefaults.ql0_max - """max cloud water value (auto converted to rain)""" - t_sub: float = NamelistDefaults.t_sub - """min temp for sublimation of cloud ice""" - qi_gen: float = NamelistDefaults.qi_gen - """max cloud ice generation during remapping step""" - qi_lim: float = NamelistDefaults.qi_lim - """cloud ice limiter to prevent large ice build up""" - qi0_max: float = NamelistDefaults.qi0_max - """max cloud ice value (by other sources)""" - rad_snow: bool = NamelistDefaults.rad_snow - """consider snow in cloud fraction calculation""" - rad_rain: bool = NamelistDefaults.rad_rain - """consider rain in cloud fraction calculation""" - rad_graupel: bool = NamelistDefaults.rad_graupel - """consider graupel in cloud fraction calculation""" - tintqs: bool = NamelistDefaults.tintqs - """use temperature in the saturation mixing in PDF""" - dw_ocean: float = NamelistDefaults.dw_ocean - """base value for ocean""" - dw_land: float = NamelistDefaults.dw_land - """base value for subgrid deviation / variability over land""" - # cloud scheme 0 - ? - # 1: old fvgfs gfdl) mp implementation - # 2: binary cloud scheme (0 / 1) - icloud_f: int = NamelistDefaults.icloud_f - cld_min: float = NamelistDefaults.cld_min - """minimum cloud fraction""" - tau_l2v: float = NamelistDefaults.tau_l2v - """cloud water to water vapor (evaporation)""" - tau_v2l: float = NamelistDefaults.tau_v2l - """water vapor to cloud water (condensation)""" - c2l_ord: int = NamelistDefaults.c2l_ord - regional: bool = NamelistDefaults.regional - m_split: int = NamelistDefaults.m_split - convert_ke: bool = NamelistDefaults.convert_ke - breed_vortex_inline: bool = NamelistDefaults.breed_vortex_inline - use_old_omega: bool = NamelistDefaults.use_old_omega - rf_fast: bool = NamelistDefaults.rf_fast - adiabatic: bool = NamelistDefaults.adiabatic - nf_omega: int = NamelistDefaults.nf_omega - fv_sg_adj: int = NamelistDefaults.fv_sg_adj - n_sponge: int = NamelistDefaults.n_sponge - lsoil: int = NamelistDefaults.lsoil - daily_mean: bool = False - sw_dynamics: bool = NamelistDefaults.sw_dynamics - """Flag to replace cosz with daily mean value in physics""" + layout: Tuple[int, int] = (1, 1) + + +@dataclasses.dataclass +class Namelist(f90nml.Namelist): + dt_atmos: int = NamelistDefaults.dt_atmos + npx: int = NamelistDefaults.npx + npy: int = NamelistDefaults.npy + npz: int = NamelistDefaults.npz + layout: Tuple[int, int] = NamelistDefaults.layout + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # The following loop was generated by Gemini and vetted to + # iterate through all namelist keys to update the dataclass fields. + # If a parameter name matches our dataclass fields, + # we update its value. We also keep track of values + # we've found before to check for inconsistencies (in which + # case, we raise a ValueError). + config_fields = {f.name for f in dataclasses.fields(self)} + seen_params = {} + for group_name, group_params in self.items(): + for param_name, param_value in group_params.items(): + if param_name in config_fields: + if param_name in seen_params: + if seen_params[param_name] != param_value: + # If seen before with a differenv value, raise a ValueError + raise ValueError( + f"Inconsistent values found within namelist for '{param_name}'." + ) + else: + # We're seeing this param for the first time, and we can update + # our field value. + seen_params[param_name] = param_value + setattr(self, param_name, param_value) + + def namelist_groups_to_flatish_dict(self, target_groups: list = None): + """Returns a flat dict containing key-value pairs from the specified + target_groups, along with the dataclass fields and values. + + Example: If the target_groups are ["coupler_nml", "fv_core_nml"], + the returned flat dict would contain the key-value pairs from those groups + only, along with the dataclass fields/values (e.g., dt_atmos). + + If no target_groups are specified, then the flattened return dict + will pull from all groups, along with the dataclass fields and values. + + Raises ValueError if any duplicate keys from different groups have + conflicting values, in which case we won't know which value to take. + + Args: + target_groups: list of namelist groups (default is None) + """ + + if target_groups is None: + extracted_nml = self + else: + # Disclaimer - This line was generated by Gemini and reviewed before use: + extracted_groups = { + group: self[group] for group in target_groups if group in self + } + extracted_nml = f90nml.Namelist(extracted_groups) + + flatish_dict = namelist_to_flatish_dict(extracted_nml) - @classmethod - def from_f90nml(cls, namelist: f90nml.Namelist): - namelist_dict = namelist_to_flatish_dict(namelist.items()) - namelist_dict = { - key: value - for key, value in namelist_dict.items() - if key in cls.__dataclass_fields__ # type: ignore - } - return cls(**namelist_dict) + # Also, add in dataclass fields (self.npx, self.layout, etc.) + for key in self.__dataclass_fields__: # type: ignore + flatish_dict[key] = getattr(self, key) + return flatish_dict def namelist_to_flatish_dict(nml_input): diff --git a/ndsl/stencils/testing/conftest.py b/ndsl/stencils/testing/conftest.py index 4b62dc5f..b45a1c45 100644 --- a/ndsl/stencils/testing/conftest.py +++ b/ndsl/stencils/testing/conftest.py @@ -225,7 +225,7 @@ def get_savepoint_restriction(metafunc): def get_namelist(namelist_filename): - return Namelist.from_f90nml(f90nml.read(namelist_filename)) + return Namelist(f90nml.read(namelist_filename)) def get_config(backend: str, communicator: Optional[Communicator]): From 08f7f00d511e85b8b6f83ed9486457d20ec279dd Mon Sep 17 00:00:00 2001 From: Janice Kim Date: Tue, 9 Sep 2025 18:53:27 -0400 Subject: [PATCH 2/4] Issue #64: Temporarily tweaking github workflow yamls for CI to point to jjuyeonkim fork --- .github/workflows/fv3_translate_tests.yaml | 2 +- .github/workflows/pace_tests.yaml | 2 +- .github/workflows/shield_tests.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/fv3_translate_tests.yaml b/.github/workflows/fv3_translate_tests.yaml index 5e794b7d..99d8feae 100644 --- a/.github/workflows/fv3_translate_tests.yaml +++ b/.github/workflows/fv3_translate_tests.yaml @@ -12,7 +12,7 @@ on: # https://github.com/NOAA-GFDL/NDSL/issues/64 jobs: fv3_translate_tests: - uses: jjuyeonkim/pyFV3/.github/workflows/translate.yaml@20250723_namelist_1 + uses: jjuyeonkim/pyFV3/.github/workflows/translate.yaml@20250908_namelist_2 with: component_trigger: true component_name: NDSL diff --git a/.github/workflows/pace_tests.yaml b/.github/workflows/pace_tests.yaml index 03517faa..974331d4 100644 --- a/.github/workflows/pace_tests.yaml +++ b/.github/workflows/pace_tests.yaml @@ -12,7 +12,7 @@ on: # https://github.com/NOAA-GFDL/NDSL/issues/64 jobs: pace_main_tests: - uses: jjuyeonkim/pace/.github/workflows/main_unit_tests.yaml@20250723_namelist_1 + uses: jjuyeonkim/pace/.github/workflows/main_unit_tests.yaml@20250908_namelist_2 with: component_trigger: true component_name: NDSL diff --git a/.github/workflows/shield_tests.yaml b/.github/workflows/shield_tests.yaml index 22f3c094..ea4992f9 100644 --- a/.github/workflows/shield_tests.yaml +++ b/.github/workflows/shield_tests.yaml @@ -12,7 +12,7 @@ on: # https://github.com/NOAA-GFDL/NDSL/issues/64 jobs: shield_translate_tests: - uses: jjuyeonkim/pySHiELD/.github/workflows/translate.yaml@20250820_namelist_1 + uses: jjuyeonkim/pySHiELD/.github/workflows/translate.yaml@20250908_namelist_2 with: component_trigger: true component_name: NDSL From 87ca0907c1dac57f3587ec6f09a0ebe9c10660e2 Mon Sep 17 00:00:00 2001 From: Janice Kim Date: Tue, 16 Sep 2025 09:54:49 -0400 Subject: [PATCH 3/4] [TEST] jjuyeonkim ref CI tweaks for NDSL Issue#64 --- .github/workflows/fv3_translate_tests.yaml | 8 ++++++++ .github/workflows/lint.yaml | 10 ++++++++++ .github/workflows/pace_tests.yaml | 8 ++++++++ .github/workflows/shield_tests.yaml | 8 ++++++++ 4 files changed, 34 insertions(+) diff --git a/.github/workflows/fv3_translate_tests.yaml b/.github/workflows/fv3_translate_tests.yaml index 99d8feae..c81a7fef 100644 --- a/.github/workflows/fv3_translate_tests.yaml +++ b/.github/workflows/fv3_translate_tests.yaml @@ -1,3 +1,10 @@ +# TODO: Revert tests back to NOAA-GFDL version (not jjuyeonkim) after +# NDSL/issues#64's PRs close and are all merged. These PRs include: +# https://github.com/NOAA-GFDL/NDSL/pull/218 +# https://github.com/NOAA-GFDL/PyFV3/pull/83 +# https://github.com/NOAA-GFDL/PySHiELD/pull/58 +# https://github.com/NOAA-GFDL/pace/pull/145 +# name: "FV3 translate tests" # Run these these whenever ... @@ -7,6 +14,7 @@ on: push: branches: - main # ... when merging into the main branch + - 20250908_namelist_2 # TODO: Revert tests back to GFDL (not jjuyeonkim) after merging # https://github.com/NOAA-GFDL/NDSL/issues/64 diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index afd96c1c..b63de9aa 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -1,3 +1,10 @@ +# TODO: Revert tests back to NOAA-GFDL version (not jjuyeonkim) after +# NDSL/issues#64's PRs close and are all merged. These PRs include: +# https://github.com/NOAA-GFDL/NDSL/pull/218 +# https://github.com/NOAA-GFDL/PyFV3/pull/83 +# https://github.com/NOAA-GFDL/PySHiELD/pull/58 +# https://github.com/NOAA-GFDL/pace/pull/145 +# name: "Lint" # Run these these whenever ... @@ -7,6 +14,7 @@ on: push: branches: - main # ... when merging into the main branch + - 20250908_namelist_2 # cancel running jobs if theres a newer push concurrency: @@ -19,6 +27,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 + with: + ref: 20250908_namelist_2 - name: Setup Python 3.11 uses: actions/setup-python@v5 diff --git a/.github/workflows/pace_tests.yaml b/.github/workflows/pace_tests.yaml index 974331d4..d882cb32 100644 --- a/.github/workflows/pace_tests.yaml +++ b/.github/workflows/pace_tests.yaml @@ -1,3 +1,10 @@ +# TODO: Revert tests back to NOAA-GFDL version (not jjuyeonkim) after +# NDSL/issues#64's PRs close and are all merged. These PRs include: +# https://github.com/NOAA-GFDL/NDSL/pull/218 +# https://github.com/NOAA-GFDL/PyFV3/pull/83 +# https://github.com/NOAA-GFDL/PySHiELD/pull/58 +# https://github.com/NOAA-GFDL/pace/pull/145 +# name: "pace main tests" # Run these these whenever ... @@ -7,6 +14,7 @@ on: push: branches: - main # ... when merging into the main branch + - 20250908_namelist_2 # TODO: Revert tests back to GFDL (not jjuyeonkim) after merging # https://github.com/NOAA-GFDL/NDSL/issues/64 diff --git a/.github/workflows/shield_tests.yaml b/.github/workflows/shield_tests.yaml index ea4992f9..49cbfe46 100644 --- a/.github/workflows/shield_tests.yaml +++ b/.github/workflows/shield_tests.yaml @@ -1,3 +1,10 @@ +# TODO: Revert tests back to NOAA-GFDL version (not jjuyeonkim) after +# NDSL/issues#64's PRs close and are all merged. These PRs include: +# https://github.com/NOAA-GFDL/NDSL/pull/218 +# https://github.com/NOAA-GFDL/PyFV3/pull/83 +# https://github.com/NOAA-GFDL/PySHiELD/pull/58 +# https://github.com/NOAA-GFDL/pace/pull/145 +# name: "SHiELD Translate tests" # Run these these whenever ... @@ -7,6 +14,7 @@ on: push: branches: - main # ... when merging into the main branch + - 20250908_namelist_2 # TODO: Revert tests back to GFDL (not jjuyeonkim) after merging # https://github.com/NOAA-GFDL/NDSL/issues/64 From ee305a257e2ec35dff63055770bcbb38941845dd Mon Sep 17 00:00:00 2001 From: Janice Kim Date: Tue, 16 Sep 2025 16:52:25 -0400 Subject: [PATCH 4/4] NDSL Issue#64: jjuyeonkim CI Checks --- .github/workflows/lint.yaml | 1 + pyproject.toml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index f1385a13..893ab1e5 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -28,6 +28,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v5 with: + repository: jjuyeonkim/ndsl ref: 20250908_namelist_2 - name: Setup Python 3.11 diff --git a/pyproject.toml b/pyproject.toml index f8124bc6..f00c5abe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,8 @@ test = ["pytest", "coverage"] ndsl-serialbox_to_netcdf = "ndsl.stencils.testing.serialbox_to_netcdf:entry_point" [project.urls] -Repository = "https://github.com/NOAA-GFDL/NDSL" +# TODO: Revert repo back to GFDL develop (not jjuyeonkim) after merging https://github.com/NOAA-GFDL/NDSL/issues/64 +Repository = "https://github.com/jjuyeonkim/NDSL" [tool.aliases]