Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4792227
Initial changes: Namelist replaced by dict
jjuyeonkim Sep 30, 2025
1ac933d
Creating utility function dycore_config_from_f90nml for creating Dyna…
jjuyeonkim Sep 30, 2025
4269fea
Instead of ndsl.Namelist, using f90nml.Namelist + dycore_config_from_…
jjuyeonkim Oct 1, 2025
df92423
Removing from_namelist and from_f90nml from DynamicalCoreConfig; Addi…
jjuyeonkim Oct 3, 2025
3b65f73
GEOS wrapper work around
jjuyeonkim Oct 3, 2025
d46eefe
Using self.config rather than self.namelist in TranslateDynCore
jjuyeonkim Oct 3, 2025
d0fcf5f
Linting and small tweaks
jjuyeonkim Oct 3, 2025
7a81f37
Adding --f90nml_namelist_only flag
jjuyeonkim Oct 3, 2025
9ea785b
more linting + comment revisions
jjuyeonkim Oct 3, 2025
917b4e7
Changed translate test flag: --legacy_namelist_support=False
jjuyeonkim Oct 6, 2025
df59228
Using --no_legacy_namelist flag for translate tests
jjuyeonkim Oct 6, 2025
b605a35
Adding target_groups to be parameter for dycore_config_from_f90nml
jjuyeonkim Oct 6, 2025
676f7fd
Cleanup: mainly using f90nml.Namelist where appropriate,
jjuyeonkim Oct 7, 2025
7b349da
Simple unit test for namelist_override + comment tweaks
jjuyeonkim Oct 9, 2025
e1937a6
Merge branch 'develop' into 20250925_namelist_helper
jjuyeonkim Oct 9, 2025
ff7fe0b
Adding from_f90nml back to DynamicalCoreConfig
jjuyeonkim Oct 10, 2025
73265cc
DynamicalCoreConfig from_dict, from_f90nml mods
jjuyeonkim Oct 15, 2025
f20d7aa
Merge branch 'develop' into 20250925_namelist_helper
jjuyeonkim Oct 15, 2025
1e3364f
Removing simple unit test
jjuyeonkim Oct 16, 2025
bd1c3a9
Adding self.config to TranslateCubedToLatLon
jjuyeonkim Oct 17, 2025
ec9acea
Update pyfv3/_config.py
jjuyeonkim Oct 17, 2025
a77a7a2
Comment fix
jjuyeonkim Oct 17, 2025
ad7f555
Merge branch '20250925_namelist_helper' of github.com:jjuyeonkim/PyFV…
jjuyeonkim Oct 17, 2025
9202d16
Using 'from __future__ import annotations'
jjuyeonkim Oct 17, 2025
8beb1cd
Adding note about fishy behavior in dycore config post init
jjuyeonkim Oct 17, 2025
3e3abda
Adding self.config into translate tests; Moving TranslateDycoreFortra…
jjuyeonkim Oct 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/translate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ jobs:
--backend=numpy \
--which_modules=FvTp2d \
--threshold_overrides_file=./tests/savepoint/translate/overrides/standard.yaml \
--no_legacy_namelist \
./tests/savepoint

- name: Numpy D_SW
Expand All @@ -100,6 +101,7 @@ jobs:
--backend=numpy \
--which_modules=D_SW \
--threshold_overrides_file=./tests/savepoint/translate/overrides/standard.yaml \
--no_legacy_namelist \
./tests/savepoint

- name: Numpy Remapping
Expand All @@ -110,6 +112,7 @@ jobs:
--backend=numpy \
--which_modules=Remapping \
--threshold_overrides_file=./tests/savepoint/translate/overrides/standard.yaml \
--no_legacy_namelist \
./tests/savepoint

- name: Orchestrated dace-cpu Acoustics
Expand All @@ -126,4 +129,5 @@ jobs:
--which_rank=0 \
--which_modules=DynCore \
--threshold_overrides_file=./tests/savepoint/translate/overrides/standard.yaml \
--no_legacy_namelist \
./tests/savepoint
143 changes: 51 additions & 92 deletions pyfv3/_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,20 @@

import f90nml
import yaml
from dacite import Config, from_dict

from ndsl.namelist import Namelist
from ndsl.utils import f90nml_as_dict


DEFAULT_INT = 0
DEFAULT_STR = ""
DEFAULT_FLOAT = 0.0
DEFAULT_BOOL = False
DEFAULT_DYCORE_NML_GROUPS = (
"main_nml",
"coupler_nml",
"fv_core_nml",
)


@dataclasses.dataclass(frozen=True)
Expand Down Expand Up @@ -278,6 +284,7 @@ class DynamicalCoreConfig:
sw_dynamics: bool = False
"""shallow water conditions"""
namelist_override: Optional[str] = None
target_nml_groups: Optional[Tuple[str, ...]] = DEFAULT_DYCORE_NML_GROUPS

def __post_init__(self):
if self.namelist_override is not None:
Expand All @@ -286,107 +293,59 @@ def __post_init__(self):
except FileNotFoundError:
print(f"{self.namelist_override} does not exist")
raise
dycore_config = self.from_f90nml(f90_nml)
dycore_config = self.from_f90nml(f90_nml, self.target_nml_groups)
Comment thread
romanc marked this conversation as resolved.
for var in dycore_config.__dict__.keys():
setattr(self, var, dycore_config.__dict__[var])
# Single tile cartesian grids
if self.grid_type > 3:
self.nf_omega = 0

@classmethod
def from_f90nml(cls, f90_namelist: f90nml.Namelist) -> "DynamicalCoreConfig":
namelist = Namelist.from_f90nml(f90_namelist)
return cls.from_namelist(namelist)
def from_f90nml(
cls,
nml: f90nml.Namelist,
target_groups: Tuple[str, ...] | None = DEFAULT_DYCORE_NML_GROUPS,
) -> "DynamicalCoreConfig":
"""Uses the nml to create a DynamicalCoreConfig.
Only the DEFAULT_DYCORE_NML_GROUPS from the nml are considered
when initializing the DynamicalCoreConfig.
Comment thread
jjuyeonkim marked this conversation as resolved.
Outdated

Args:
nml: f90nml.Namelist
target_groups: Tuple[str,...] | None
This list will be used to specify which groups in the nml to
use when initializing the DynamicalCoreConfig. If None, all
groups will be used. (Default: DEFAULT_DYCORE_NML_GROUPS)
"""
nml_dict = f90nml_as_dict(nml, flatten=True, target_groups=target_groups)
nml_dict["target_nml_groups"] = target_groups
return cls.from_dict(nml_dict)

@classmethod
def from_namelist(cls, namelist: Namelist) -> "DynamicalCoreConfig":
return cls(
dt_atmos=namelist.dt_atmos,
a_imp=namelist.a_imp,
beta=namelist.beta,
consv_te=namelist.consv_te,
d2_bg=namelist.d2_bg,
d2_bg_k1=namelist.d2_bg_k1,
d2_bg_k2=namelist.d2_bg_k2,
d4_bg=namelist.d4_bg,
d_con=namelist.d_con,
d_ext=namelist.d_ext,
dddmp=namelist.dddmp,
delt_max=namelist.delt_max,
do_sat_adj=namelist.do_sat_adj,
do_vort_damp=namelist.do_vort_damp,
fill=namelist.fill,
hord_dp=namelist.hord_dp,
hord_mt=namelist.hord_mt,
hord_tm=namelist.hord_tm,
hord_tr=namelist.hord_tr,
hord_vt=namelist.hord_vt,
hydrostatic=namelist.hydrostatic,
k_split=namelist.k_split,
ke_bg=namelist.ke_bg,
kord_mt=namelist.kord_mt,
kord_tm=namelist.kord_tm,
kord_tr=namelist.kord_tr,
kord_wz=namelist.kord_wz,
n_split=namelist.n_split,
nord=namelist.nord,
npx=namelist.npx,
npy=namelist.npy,
npz=namelist.npz,
ntiles=namelist.ntiles,
nwat=namelist.nwat,
p_fac=namelist.p_fac,
rf_cutoff=namelist.rf_cutoff,
tau=namelist.tau,
vtdm4=namelist.vtdm4,
z_tracer=namelist.z_tracer,
do_qa=namelist.do_qa,
layout=namelist.layout,
grid_type=namelist.grid_type,
u_max=namelist.u_max,
do_f3d=namelist.do_f3d,
inline_q=namelist.inline_q,
do_skeb=namelist.do_skeb,
check_negative=namelist.check_negative,
tau_r2g=namelist.tau_r2g,
tau_smlt=namelist.tau_smlt,
tau_g2r=namelist.tau_g2r,
tau_imlt=namelist.tau_imlt,
tau_i2s=namelist.tau_i2s,
tau_l2r=namelist.tau_l2r,
tau_g2v=namelist.tau_g2v,
tau_v2g=namelist.tau_v2g,
sat_adj0=namelist.sat_adj0,
ql_gen=namelist.ql_gen,
ql_mlt=namelist.ql_mlt,
qs_mlt=namelist.qs_mlt,
ql0_max=namelist.ql0_max,
t_sub=namelist.t_sub,
qi_gen=namelist.qi_gen,
qi_lim=namelist.qi_lim,
qi0_max=namelist.qi0_max,
rad_snow=namelist.rad_snow,
rad_rain=namelist.rad_rain,
rad_graupel=namelist.rad_graupel,
tintqs=namelist.tintqs,
dw_ocean=namelist.dw_ocean,
dw_land=namelist.dw_land,
icloud_f=namelist.icloud_f,
cld_min=namelist.cld_min,
tau_l2v=namelist.tau_l2v,
tau_v2l=namelist.tau_v2l,
c2l_ord=namelist.c2l_ord,
regional=namelist.regional,
m_split=namelist.m_split,
convert_ke=namelist.convert_ke,
breed_vortex_inline=namelist.breed_vortex_inline,
use_old_omega=namelist.use_old_omega,
rf_fast=namelist.rf_fast,
adiabatic=namelist.adiabatic,
nf_omega=namelist.nf_omega,
fv_sg_adj=namelist.fv_sg_adj,
n_sponge=namelist.n_sponge,
def from_dict(
cls,
data: dict,
) -> "DynamicalCoreConfig":

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
) -> "DynamicalCoreConfig":
) -> DynamicalCoreConfig:

You can add from __future__ import annotations at the top of the file and then you don't need to add quotes around types any more that the old type resolver couldn't resolve

@jjuyeonkim jjuyeonkim Oct 17, 2025

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll update this.

Edit -- NOTE: I made a slight tweak to Pace's tests/main/fv3core/test_config.py::test_types_match test to account for this change.

"""Uses the nml to create a DynamicalCoreConfig, using the data
dictionary.
Comment thread
jjuyeonkim marked this conversation as resolved.
Outdated

Args:
data: "flattened" dictionary where the keys match the class member variables
"""
# NOTE: We're setting strict to False so that extra keys in the data are
# ignored. Eventually, we'd like to turn this to True once we move away from
# expecting dicts that are basically flattened yamls and f90nml files.
dacite_config = Config(
strict=False,
type_hooks={
Tuple[int, int]: lambda x: tuple(x),
Tuple[str, ...]: lambda x: tuple(x) if x is not None else None,
},
)
dycore_config = from_dict(
data_class=DynamicalCoreConfig, data=data, config=dacite_config
)
return dycore_config

@classmethod
def from_yaml(cls, yaml_config: str) -> "DynamicalCoreConfig":
Expand Down
8 changes: 5 additions & 3 deletions pyfv3/testing/translate_dyncore.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from f90nml import Namelist

import ndsl.dsl.gt4py_utils as utils
from ndsl import Namelist, Quantity, StencilFactory
from ndsl import Quantity, StencilFactory
from ndsl.constants import X_DIM, X_INTERFACE_DIM, Y_DIM, Y_INTERFACE_DIM, Z_DIM
from ndsl.stencils.testing import ParallelTranslate2PyState
from pyfv3._config import DynamicalCoreConfig
Expand Down Expand Up @@ -121,7 +123,7 @@ def __init__(
self.max_error = 2e-6
self.ignore_near_zero_errors["wsd"] = 1e-18
self.stencil_factory = stencil_factory
self.namelist = namelist
self.config = DynamicalCoreConfig.from_f90nml(namelist)

def compute_parallel(self, inputs, communicator):
# ak, bk, and phis are numpy arrays at this point and
Expand Down Expand Up @@ -167,7 +169,7 @@ def compute_parallel(self, inputs, communicator):
grid_type=self.grid.grid_type,
nested=self.grid.nested,
stretched_grid=self.grid.stretched_grid,
config=DynamicalCoreConfig.from_namelist(self.namelist).acoustic_dynamics,
config=self.config.acoustic_dynamics,
phis=phis,
wsd=wsd.data,
state=state,
Expand Down
9 changes: 5 additions & 4 deletions pyfv3/testing/translate_fvdynamics.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
from typing import Any, Dict, Optional, Tuple

import pytest
from f90nml import Namelist

import ndsl.dsl.gt4py_utils as utils
from ndsl import Namelist, Quantity, StencilFactory
from ndsl import Quantity, StencilFactory
from ndsl.constants import (
X_DIM,
X_INTERFACE_DIM,
Expand All @@ -30,7 +31,7 @@ def __init__(
stencil_factory: StencilFactory,
):
super().__init__(grid, stencil_factory)
self.namelist = DynamicalCoreConfig.from_namelist(namelist)
self.config = DynamicalCoreConfig.from_f90nml(namelist)


class TranslateFVDynamics(ParallelTranslateBaseSlicing):
Expand Down Expand Up @@ -295,7 +296,7 @@ def __init__(
self.ignore_near_zero_errors["q_con"] = True
self.dycore: Optional[fv_dynamics.DynamicalCore] = None
self.stencil_factory = stencil_factory
self.namelist: DynamicalCoreConfig = DynamicalCoreConfig.from_namelist(namelist)
self.config = DynamicalCoreConfig.from_f90nml(namelist)

def state_from_inputs(self, inputs):
input_storages = super().state_from_inputs(inputs)
Expand Down Expand Up @@ -337,7 +338,7 @@ def compute_parallel(self, inputs, communicator):
stencil_factory=self.stencil_factory,
quantity_factory=self.grid.quantity_factory,
damping_coefficients=self.grid.damping_coefficients,
config=DynamicalCoreConfig.from_namelist(self.namelist),
config=self.config,
phis=state.phis,
state=state,
timestep=timedelta(seconds=inputs["bdt"]),
Expand Down
9 changes: 8 additions & 1 deletion pyfv3/wrappers/geos_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,14 @@ def __init__(

self.backend = backend
self.namelist = namelist
self.dycore_config = pyfv3.DynamicalCoreConfig.from_f90nml(self.namelist)
# TODO: After pace unit tests have been updated, or universal
# loader from namelist/yaml has been implemented, create a
# dycore_config using default groups or creation from yaml.
# This is a temporary work-around for now.
self.dycore_config = pyfv3.DynamicalCoreConfig.from_f90nml(
self.namelist,
target_groups=None,
)
self.dycore_config.dt_atmos = bdt
assert self.dycore_config.dt_atmos != 0

Expand Down
15 changes: 8 additions & 7 deletions tests/savepoint/translate/translate_a2b_ord4.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from typing import Any, Dict

from ndsl import Namelist, StencilFactory, orchestrate
from f90nml import Namelist

from ndsl import StencilFactory, orchestrate
from ndsl.constants import Z_DIM
from pyfv3.stencils import DivergenceDamping
from pyfv3.testing import TranslateDycoreFortranData2Py
Expand Down Expand Up @@ -51,11 +53,10 @@ def __init__(
stencil_factory: StencilFactory,
):
super().__init__(grid, namelist, stencil_factory)
assert namelist.grid_type < 3
assert self.config.grid_type < 3
self.in_vars["data_vars"] = {"wk": {}, "vort": {}, "delpc": {}, "nord_col": {}}
self.in_vars["parameters"] = ["dt"]
self.out_vars: Dict[str, Any] = {"wk": {}, "vort": {}}
self.namelist = namelist # type: ignore
self.stencil_factory = stencil_factory
self.compute_obj = A2B_Ord4Compute(stencil_factory)

Expand All @@ -69,10 +70,10 @@ def compute_from_storage(self, inputs):
self.grid.damping_coefficients,
self.grid.nested,
self.grid.stretched_grid,
self.namelist.dddmp,
self.namelist.d4_bg,
self.namelist.nord,
self.namelist.grid_type,
self.config.dddmp,
self.config.d4_bg,
self.config.nord,
self.config.grid_type,
nord_col,
nord_col,
)
Expand Down
19 changes: 11 additions & 8 deletions tests/savepoint/translate/translate_c_sw.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from ndsl import Namelist, QuantityFactory, StencilFactory
from f90nml import Namelist

from ndsl import QuantityFactory, StencilFactory
from pyfv3._config import DynamicalCoreConfig
from pyfv3.stencils import CGridShallowWaterDynamics
from pyfv3.testing import TranslateDycoreFortranData2Py


def get_c_sw_instance(
grid,
namelist: Namelist,
config: DynamicalCoreConfig,
stencil_factory: StencilFactory,
quantity_factory: QuantityFactory,
):
Expand All @@ -14,8 +17,8 @@ def get_c_sw_instance(
quantity_factory=quantity_factory,
grid_data=grid.grid_data,
nested=grid.nested,
grid_type=namelist.grid_type,
nord=namelist.nord,
grid_type=config.grid_type,
nord=config.nord,
)


Expand Down Expand Up @@ -75,7 +78,7 @@ def __init__(
):
super().__init__(grid, namelist, stencil_factory)
cgrid_shallow_water_lagrangian_dynamics = get_c_sw_instance(
grid, namelist, stencil_factory, self.grid.quantity_factory
grid, self.config, stencil_factory, self.grid.quantity_factory
)
self.compute_func = cgrid_shallow_water_lagrangian_dynamics # type: ignore
self.in_vars["data_vars"] = {
Expand Down Expand Up @@ -122,7 +125,7 @@ def __init__(
super().__init__(grid, namelist, stencil_factory)
self.max_error = 9e-10
self.cgrid_sw_lagrangian_dynamics = get_c_sw_instance(
grid, namelist, stencil_factory, self.grid.quantity_factory
grid, self.config, stencil_factory, self.grid.quantity_factory
)
self.in_vars["data_vars"] = {
"u": {
Expand Down Expand Up @@ -180,7 +183,7 @@ def __init__(
super().__init__(grid, namelist, stencil_factory)
self.max_error = 5e-9
self.cgrid_sw_lagrangian_dynamics = get_c_sw_instance(
grid, namelist, stencil_factory, self.grid.quantity_factory
grid, self.config, stencil_factory, self.grid.quantity_factory
)
self.in_vars["data_vars"] = {
"uc": {},
Expand Down Expand Up @@ -221,7 +224,7 @@ def __init__(
):
super().__init__(grid, namelist, stencil_factory)
cgrid_sw_lagrangian_dynamics = get_c_sw_instance(
grid, namelist, stencil_factory, self.grid.quantity_factory
grid, self.config, stencil_factory, self.grid.quantity_factory
)

def compute_func(*args, **kwargs):
Expand Down
Loading
Loading