Skip to content

Commit 5c4ba44

Browse files
authored
support path fields (#213)
leaves open the possibility of file variables that don't use FILEIN or FILEOUT although I think they all do right now. also cleanup an unused function in the converter
1 parent 9654d5f commit 5c4ba44

File tree

11 files changed

+124
-65
lines changed

11 files changed

+124
-65
lines changed

flopy4/mf6/converter.py

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,17 @@
1818
from flopy4.mf6.config import SPARSE_THRESHOLD
1919
from flopy4.mf6.constants import FILL_DNODATA
2020
from flopy4.mf6.context import Context
21-
from flopy4.mf6.spec import fields_dict
21+
from flopy4.mf6.spec import FileInOut
2222

2323

24-
def _attach_field_metadata(
25-
dataset: xr.Dataset, component_type: type, field_names: list[str]
26-
) -> None:
27-
# TODO: attach metadata to array attrs instead of dataset attrs
28-
field_metadata = {}
29-
component_fields = fields_dict(component_type)
30-
for field_name in field_names:
31-
if field_name in component_fields:
32-
field_metadata[field_name] = component_fields[field_name].metadata
33-
dataset.attrs["field_metadata"] = field_metadata
34-
35-
36-
def _path_to_tuple(field_name: str, path_value: Path) -> tuple:
37-
if field_name.endswith("_file"):
38-
base_name = field_name.replace("_file", "").upper()
39-
return (base_name, "FILEOUT", str(path_value))
40-
return (field_name.upper(), "FILEOUT", str(path_value))
24+
def path_to_tuple(name: str, value: Path, inout: FileInOut) -> tuple[str, ...]:
25+
t = [name.upper()]
26+
if name.endswith("_file"):
27+
t[0] = name.replace("_file", "").upper()
28+
if inout:
29+
t.append(inout.upper())
30+
t.append(str(value))
31+
return tuple(t)
4132

4233

4334
def get_binding_blocks(value: Component) -> dict[str, dict[str, list[tuple[str, ...]]]]:
@@ -100,9 +91,11 @@ def unstructure_component(value: Component) -> dict[str, Any]:
10091
# (and split the period data into separate kper-indexed blocks)
10192
# - other values to their original form
10293
if isinstance(field_value, Path):
103-
rec = _path_to_tuple(field_name, field_value)
94+
field_spec = xatspec.attrs[field_name]
95+
field_meta = getattr(field_spec, "metadata", {})
96+
t = path_to_tuple(field_name, field_value, inout=field_meta.get("inout", "fileout"))
10497
# name may have changed e.g dropping '_file' suffix
105-
blocks[block_name][rec[0]] = rec
98+
blocks[block_name][t[0]] = t
10699
elif isinstance(field_value, datetime):
107100
blocks[block_name][field_name] = field_value.isoformat()
108101
elif (
@@ -165,7 +158,6 @@ def unstructure_component(value: Component) -> dict[str, Any]:
165158

166159
if block_name in period_data and isinstance(period_data[block_name], dict):
167160
dataset = xr.Dataset(period_data[block_name])
168-
_attach_field_metadata(dataset, type(value), list(period_data[block_name].keys())) # type: ignore
169161
blocks[block_name] = {block_name: dataset}
170162
del period_data[block_name]
171163

@@ -177,7 +169,6 @@ def unstructure_component(value: Component) -> dict[str, Any]:
177169

178170
for kper, block in period_blocks.items():
179171
dataset = xr.Dataset(block)
180-
_attach_field_metadata(dataset, type(value), list(block.keys()))
181172
blocks[f"{block_name} {kper + 1}"] = {block_name: dataset}
182173

183174
# make sure options block always comes first

flopy4/mf6/gwf/__init__.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
from flopy4.mf6.gwf.oc import Oc
1616
from flopy4.mf6.gwf.wel import Wel
1717
from flopy4.mf6.model import Model
18-
from flopy4.mf6.spec import field
18+
from flopy4.mf6.spec import field, path
1919
from flopy4.mf6.utils import open_cbc, open_hds
20+
from flopy4.utils import to_path
2021

2122
__all__ = ["Gwf", "Chd", "Dis", "Drn", "Ic", "Npf", "Oc", "Wel"]
2223

@@ -61,9 +62,15 @@ def budget(self):
6162
print_flows: bool = field(block="options", default=False)
6263
save_flows: bool = field(block="options", default=False)
6364
newtonoptions: Optional[NewtonOptions] = field(block="options", default=None)
64-
nc_mesh2d_filerecord: Optional[Path] = field(block="options", default=None)
65-
nc_structured_filerecord: Optional[Path] = field(block="options", default=None)
66-
nc_filerecord: Optional[Path] = field(block="options", default=None)
65+
nc_mesh2d_filerecord: Optional[Path] = path(
66+
block="options", default=None, converter=to_path, inout="fileout"
67+
)
68+
nc_structured_filerecord: Optional[Path] = path(
69+
block="options", default=None, converter=to_path, inout="fileout"
70+
)
71+
nc_filerecord: Optional[Path] = path(
72+
block="options", default=None, converter=to_path, inout="fileout"
73+
)
6774
dis: Dis = field(converter=convert_grid, block="packages")
6875
ic: Ic = field(block="packages")
6976
oc: Oc = field(block="packages")

flopy4/mf6/gwf/chd.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
from flopy4.mf6.component import update_maxbound
1010
from flopy4.mf6.converter import dict_to_array
1111
from flopy4.mf6.package import Package
12-
from flopy4.mf6.spec import array, field
12+
from flopy4.mf6.spec import array, field, path
13+
from flopy4.utils import to_path
1314

1415

1516
@xattree
@@ -21,8 +22,12 @@ class Chd(Package):
2122
print_input: bool = field(block="options", default=False)
2223
print_flows: bool = field(block="options", default=False)
2324
save_flows: bool = field(block="options", default=False)
24-
ts_filerecord: Optional[Path] = field(block="options", default=None)
25-
obs_filerecord: Optional[Path] = field(block="options", default=None)
25+
ts_filerecord: Optional[Path] = path(
26+
block="options", default=None, converter=to_path, inout="filein"
27+
)
28+
obs_filerecord: Optional[Path] = path(
29+
block="options", default=None, converter=to_path, inout="fileout"
30+
)
2631
dev_no_newton: bool = field(default=False, block="options")
2732
maxbound: Optional[int] = field(block="dimensions", default=None, init=False)
2833
head: Optional[NDArray[np.float64]] = array(

flopy4/mf6/gwf/drn.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
from flopy4.mf6.component import update_maxbound
1010
from flopy4.mf6.converter import dict_to_array
1111
from flopy4.mf6.package import Package
12-
from flopy4.mf6.spec import array, field
12+
from flopy4.mf6.spec import array, field, path
13+
from flopy4.utils import to_path
1314

1415

1516
@xattree
@@ -22,8 +23,12 @@ class Drn(Package):
2223
print_input: bool = field(block="options", default=False)
2324
print_flows: bool = field(block="options", default=False)
2425
save_flows: bool = field(block="options", default=False)
25-
ts_filerecord: Optional[Path] = field(block="options", default=None)
26-
obs_filerecord: Optional[Path] = field(block="options", default=None)
26+
ts_filerecord: Optional[Path] = path(
27+
block="options", default=None, converter=to_path, inout="filein"
28+
)
29+
obs_filerecord: Optional[Path] = path(
30+
block="options", default=None, converter=to_path, inout="fileout"
31+
)
2732
mover: bool = field(block="options", default=False)
2833
dev_cubic_scaling: bool = field(default=False, block="options")
2934
maxbound: Optional[int] = field(block="dimensions", default=None, init=False)

flopy4/mf6/gwf/npf.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88

99
from flopy4.mf6.converter import dict_to_array
1010
from flopy4.mf6.package import Package
11-
from flopy4.mf6.spec import array, field
11+
from flopy4.mf6.spec import array, field, path
12+
from flopy4.utils import to_path
1213

1314

1415
@xattree
@@ -42,7 +43,9 @@ class Xt3dOptions:
4243
save_saturation: bool = field(block="options", default=None)
4344
k22overk: bool = field(block="options", default=None)
4445
k33overk: bool = field(block="options", default=None)
45-
tvk_filerecord: Optional[Path] = field(block="options", default=None)
46+
tvk_filerecord: Optional[Path] = path(
47+
block="options", default=None, converter=to_path, inout="filein"
48+
)
4649
export_array_ascii: bool = field(block="options", default=False)
4750
export_array_netcdf: bool = field(block="options", default=False)
4851
dev_no_newton: bool = field(block="options", default=False)

flopy4/mf6/gwf/oc.py

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from flopy4.mf6.converter import dict_to_array
1010
from flopy4.mf6.package import Package
11-
from flopy4.mf6.spec import array, field
11+
from flopy4.mf6.spec import array, field, path
1212
from flopy4.utils import to_path
1313

1414

@@ -35,20 +35,14 @@ class Period:
3535
rtype: str = field()
3636
steps: "Oc.Steps" = field()
3737

38-
budget_file: Optional[Path] = field(
39-
block="options",
40-
converter=to_path,
41-
default=None,
38+
budget_file: Optional[Path] = path(
39+
block="options", converter=to_path, default=None, inout="fileout"
4240
)
43-
budget_csv_file: Optional[Path] = field(
44-
block="options",
45-
converter=to_path,
46-
default=None,
41+
budget_csv_file: Optional[Path] = path(
42+
block="options", converter=to_path, default=None, inout="fileout"
4743
)
48-
head_file: Optional[Path] = field(
49-
block="options",
50-
converter=to_path,
51-
default=None,
44+
head_file: Optional[Path] = path(
45+
block="options", converter=to_path, default=None, inout="fileout"
5246
)
5347
# TODO: needs coverter and then rename?
5448
head: Optional[Format] = field(block="options", default=None)

flopy4/mf6/gwf/rch.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
from flopy4.mf6.component import update_maxbound
1010
from flopy4.mf6.converter import dict_to_array
1111
from flopy4.mf6.package import Package
12-
from flopy4.mf6.spec import array, field
12+
from flopy4.mf6.spec import array, field, path
13+
from flopy4.utils import to_path
1314

1415

1516
@xattree
@@ -22,8 +23,12 @@ class Rch(Package):
2223
print_input: bool = field(block="options", default=False)
2324
print_flows: bool = field(block="options", default=False)
2425
save_flows: bool = field(block="options", default=False)
25-
ts_filerecord: Optional[Path] = field(block="options", default=None)
26-
obs_filerecord: Optional[Path] = field(block="options", default=None)
26+
ts_filerecord: Optional[Path] = path(
27+
block="options", default=None, converter=to_path, inout="filein"
28+
)
29+
obs_filerecord: Optional[Path] = path(
30+
block="options", default=None, converter=to_path, inout="fileout"
31+
)
2732
maxbound: Optional[int] = field(block="dimensions", default=None, init=False)
2833
recharge: Optional[NDArray[np.float64]] = array(
2934
block="period",

flopy4/mf6/gwf/sto.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,18 @@
88

99
from flopy4.mf6.converter import dict_to_array
1010
from flopy4.mf6.package import Package
11-
from flopy4.mf6.spec import array, field
11+
from flopy4.mf6.spec import array, field, path
12+
from flopy4.utils import to_path
1213

1314

1415
@xattree
1516
class Sto(Package):
1617
save_flows: bool = field(block="options", default=False)
1718
storagecoefficient: bool = field(block="options", default=False)
1819
ss_confined_only: bool = field(block="options", default=False)
19-
tvs_filerecord: Optional[Path] = field(block="options", default=None)
20+
tvs_filerecord: Optional[Path] = path(
21+
block="options", default=None, converter=to_path, inout="filein"
22+
)
2023
export_array_ascii: bool = field(block="options", default=False)
2124
export_array_netcdf: bool = field(block="options", default=False)
2225
dev_original_specific_storage: bool = field(block="options", default=False)

flopy4/mf6/gwf/wel.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
from flopy4.mf6.component import update_maxbound
1010
from flopy4.mf6.converter import dict_to_array
1111
from flopy4.mf6.package import Package
12-
from flopy4.mf6.spec import array, field
12+
from flopy4.mf6.spec import array, field, path
13+
from flopy4.utils import to_path
1314

1415

1516
@xattree
@@ -22,9 +23,15 @@ class Wel(Package):
2223
print_flows: bool = field(block="options", default=False)
2324
save_flows: bool = field(block="options", default=False)
2425
auto_flow_reduce: float = field(block="options", default=None)
25-
afrcsv_filerecord: Optional[Path] = field(block="options", default=None)
26-
ts_filerecord: Optional[Path] = field(block="options", default=None)
27-
obs_filerecord: Optional[Path] = field(block="options", default=None)
26+
afrcsv_filerecord: Optional[Path] = path(
27+
block="options", default=None, converter=to_path, inout="fileout"
28+
)
29+
ts_filerecord: Optional[Path] = path(
30+
block="options", default=None, converter=to_path, inout="filein"
31+
)
32+
obs_filerecord: Optional[Path] = path(
33+
block="options", default=None, converter=to_path, inout="fileout"
34+
)
2835
mover: bool = field(block="options", default=False)
2936
maxbound: Optional[int] = field(block="dimensions", default=None, init=False)
3037
q: Optional[NDArray[np.float64]] = array(

flopy4/mf6/ims.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
from xattree import xattree
55

66
from flopy4.mf6.solution import Solution
7-
from flopy4.mf6.spec import field
7+
from flopy4.mf6.spec import field, path
8+
from flopy4.utils import to_path
89

910

1011
@xattree
@@ -13,14 +14,18 @@ class Ims(Solution):
1314

1415
print_option: Optional[str] = field(block="options", default=None)
1516
complexity: str = field(block="options", default="simple")
16-
csv_outer_output_file: Optional[Path] = field(default=None, block="options")
17-
csv_inner_output_file: Optional[Path] = field(block="options", default=None)
18-
no_ptc: bool = field(default=False, block="options")
19-
no_ptc_option: Optional[str] = field(default=None, block="options")
17+
csv_outer_output_file: Optional[Path] = path(
18+
block="options", default=None, converter=to_path, inout="fileout"
19+
)
20+
csv_inner_output_file: Optional[Path] = path(
21+
block="options", default=None, converter=to_path, inout="fileout"
22+
)
23+
no_ptc: bool = field(block="options", default=False)
24+
no_ptc_option: Optional[str] = field(block="options", default=None)
2025
ats_outer_maximum_fraction: Optional[float] = field(block="options", default=None)
21-
outer_dvclose: Optional[float] = field(default=None, block="nonlinear")
22-
outer_maximum: Optional[int] = field(default=None, block="nonlinear")
23-
under_relaxation: Optional[str] = field(default=None, block="nonlinear")
26+
outer_dvclose: Optional[float] = field(block="nonlinear", default=None)
27+
outer_maximum: Optional[int] = field(block="nonlinear", default=None)
28+
under_relaxation: Optional[str] = field(block="nonlinear", default=None)
2429
under_relaxation_gamma: Optional[float] = field(block="nonlinear", default=None)
2530
under_relaxation_theta: Optional[float] = field(block="nonlinear", default=None)
2631
under_relaxation_kappa: Optional[float] = field(block="nonlinear", default=None)

0 commit comments

Comments
 (0)