Skip to content

Commit 46d3584

Browse files
committed
refactor(fortran_gen): harden errors, improve readability, add tests
1 parent 0c5f183 commit 46d3584

3 files changed

Lines changed: 71 additions & 19 deletions

File tree

toolchain/mfc/params/definitions.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,16 +1033,16 @@ def _init_registry():
10331033
# The generator emits `{type}, dimension({dim}) :: {name}` for each entry.
10341034
# Add here whenever a new array param needs no manual Fortran declaration.
10351035
FORTRAN_ARRAY_DIMS: dict[str, str] = {
1036-
"fluid_rho": "num_fluids_max", # pre
1037-
"alpha_rho_wrt": "num_fluids_max", # post
1038-
"alpha_rho_e_wrt": "num_fluids_max", # post
1039-
"alpha_wrt": "num_fluids_max", # post
1040-
"schlieren_alpha": "num_fluids_max", # post
1041-
"chem_wrt_Y": "num_species", # post (imported from m_thermochem)
1042-
"flux_wrt": "3", # post
1043-
"mom_wrt": "3", # post
1044-
"omega_wrt": "3", # post
1045-
"vel_wrt": "3", # post
1036+
"fluid_rho": "num_fluids_max",
1037+
"alpha_rho_wrt": "num_fluids_max",
1038+
"alpha_rho_e_wrt": "num_fluids_max",
1039+
"alpha_wrt": "num_fluids_max",
1040+
"schlieren_alpha": "num_fluids_max",
1041+
"chem_wrt_Y": "num_species",
1042+
"flux_wrt": "3",
1043+
"mom_wrt": "3",
1044+
"omega_wrt": "3",
1045+
"vel_wrt": "3",
10461046
}
10471047

10481048

toolchain/mfc/params/generators/fortran_gen.py

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@
2626
ParamType.LOG: "logical",
2727
}
2828

29+
_VALID_TARGETS = ("pre", "sim", "post")
30+
31+
32+
def _check_target(target: str) -> None:
33+
if target not in _VALID_TARGETS:
34+
raise ValueError(f"Unknown target {target!r}; expected one of {_VALID_TARGETS}")
35+
2936

3037
def get_namelist_var(name: str) -> str:
3138
"""Return the Fortran namelist root for a parameter name."""
@@ -79,7 +86,7 @@ def _format_namelist(vars_list: List[str]) -> str:
7986

8087
def generate_namelist_fpp(target: str) -> str:
8188
"""Return the namelist /user_inputs/ statement for a target as a string."""
82-
assert target in ("pre", "sim", "post")
89+
_check_target(target)
8390
all_vars = _vars_for_target(target)
8491

8592
if target != "sim":
@@ -92,15 +99,22 @@ def generate_namelist_fpp(target: str) -> str:
9299
opt_lines = _pack_namelist(opt, _CONT_PREFIX, _CONT2_PREFIX, _MAX_LINE)
93100
nl_with_cont = nl_lines[:]
94101
nl_with_cont[-1] += ", &"
95-
parts = [_HEADER.rstrip(), "#:if MFC_CASE_OPTIMIZATION"] + nl_lines + ["#:else"] + nl_with_cont + opt_lines + ["#:endif"]
102+
parts = (
103+
[_HEADER.rstrip(), "#:if MFC_CASE_OPTIMIZATION"]
104+
+ nl_lines
105+
+ ["#:else"]
106+
+ nl_with_cont
107+
+ opt_lines
108+
+ ["#:endif"]
109+
)
96110
else:
97111
parts = [_HEADER.rstrip()] + nl_lines
98112
return "\n".join(parts) + "\n"
99113

100114

101115
def generate_decls_fpp(target: str) -> str:
102116
"""Return Fortran declarations (scalars + known arrays) for a target."""
103-
assert target in ("pre", "sim", "post")
117+
_check_target(target)
104118
lines = [_HEADER.rstrip()]
105119
for name in _vars_for_target(target):
106120
if not _is_simple_scalar(name):
@@ -109,16 +123,23 @@ def generate_decls_fpp(target: str) -> str:
109123
continue
110124
if name in FORTRAN_ARRAY_DIMS:
111125
member = REGISTRY.all_params.get(f"{name}(1)")
112-
if member is not None:
113-
ftype = fortran_type_decl(member)
114-
dim = FORTRAN_ARRAY_DIMS[name]
115-
lines.append(f"{(ftype + ', dimension(' + dim + ')').ljust(_ARRAY_DECL_COL)}:: {name}")
126+
if member is None:
127+
raise ValueError(
128+
f"FORTRAN_ARRAY_DIMS[{name!r}] has no {name}(1) in the registry. "
129+
"Register at least one indexed variant (e.g. _r(f'{name}(1)', ...))."
130+
)
131+
ftype = fortran_type_decl(member)
132+
dim = FORTRAN_ARRAY_DIMS[name]
133+
lines.append(f"{(ftype + ', dimension(' + dim + ')').ljust(_ARRAY_DECL_COL)}:: {name}")
116134
continue
117135
param = REGISTRY.all_params.get(name)
118136
if param is None:
119137
continue
120138
if any(k.startswith(f"{name}(") for k in REGISTRY.all_params):
121-
continue
139+
raise ValueError(
140+
f"{name!r} has indexed variants (e.g. {name}(1)) but is missing from "
141+
"FORTRAN_ARRAY_DIMS. Add it there with its Fortran dimension expression."
142+
)
122143
lines.append(f"{fortran_type_decl(param).ljust(_DECL_COL)}:: {name}")
123144
return "\n".join(lines) + "\n"
124145

@@ -144,4 +165,9 @@ def get_generated_files(build_dir: Path) -> List[Tuple[Path, str]]:
144165
Paths match the cmake include directory structure:
145166
build_dir/include/{full_target}/generated_{namelist,decls}.fpp
146167
"""
147-
return [(build_dir / "include" / full / f"generated_{kind}.fpp", gen(short)) for short, full in TARGETS for kind, gen in [("namelist", generate_namelist_fpp), ("decls", generate_decls_fpp)]]
168+
result = []
169+
for short, full in TARGETS:
170+
inc = build_dir / "include" / full
171+
result.append((inc / "generated_namelist.fpp", generate_namelist_fpp(short)))
172+
result.append((inc / "generated_decls.fpp", generate_decls_fpp(short)))
173+
return result

toolchain/mfc/params_tests/test_fortran_gen.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,32 @@ def test_decls_case_dir():
123123
assert "character(LEN=path_len) :: case_dir" in generate_decls_fpp(target)
124124

125125

126+
def test_decls_array_dims():
127+
from mfc.params.generators.fortran_gen import generate_decls_fpp
128+
129+
post = generate_decls_fpp("post")
130+
assert "dimension(num_fluids_max)" in post and ":: alpha_wrt" in post
131+
assert "dimension(num_fluids_max)" in post and ":: alpha_rho_wrt" in post
132+
assert "dimension(3)" in post and ":: mom_wrt" in post
133+
# Structs and families must NOT appear as bare scalar declarations
134+
assert ":: fluid_pp" not in post
135+
assert ":: bc_x" not in post
136+
137+
pre = generate_decls_fpp("pre")
138+
assert "dimension(num_fluids_max)" in pre and ":: fluid_rho" in pre
139+
140+
141+
def test_check_target_raises_on_bad_target():
142+
import pytest
143+
144+
from mfc.params.generators.fortran_gen import generate_decls_fpp, generate_namelist_fpp
145+
146+
with pytest.raises(ValueError, match="Unknown target"):
147+
generate_namelist_fpp("bad")
148+
with pytest.raises(ValueError, match="Unknown target"):
149+
generate_decls_fpp("bad")
150+
151+
126152
def test_get_generated_files_returns_six():
127153
from pathlib import Path
128154

0 commit comments

Comments
 (0)