Skip to content

Commit 6be72ab

Browse files
committed
cleanup converter
1 parent 15a15b9 commit 6be72ab

File tree

1 file changed

+56
-47
lines changed

1 file changed

+56
-47
lines changed

flopy4/mf6/converter.py

Lines changed: 56 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def path_to_tuple(name: str, value: Path, inout: FileInOut) -> tuple[str, ...]:
3131
return tuple(t)
3232

3333

34-
def get_binding_blocks(value: Component) -> dict[str, dict[str, list[tuple[str, ...]]]]:
34+
def make_binding_blocks(value: Component) -> dict[str, dict[str, list[tuple[str, ...]]]]:
3535
if not isinstance(value, Context):
3636
return {}
3737

@@ -103,15 +103,20 @@ def unstructure_component(value: Component) -> dict[str, Any]:
103103
xatspec = xattree.get_xatspec(type(value))
104104
data = xattree.asdict(value)
105105

106-
blocks.update(binding_blocks := get_binding_blocks(value))
106+
# create child component binding blocks
107+
blocks.update(make_binding_blocks(value))
107108

109+
# process blocks in order, unstructuring fields as needed,
110+
# then slice period data into separate kper-indexed blocks
111+
# each of which contains a dataset indexed for that period.
108112
for block_name, block in blockspec.items():
109-
if block_name not in blocks:
110-
blocks[block_name] = {}
111-
period_data = {}
113+
period_data = {} # type: ignore
112114
period_blocks = {} # type: ignore
113115
period_block_name = None
114116

117+
if block_name not in blocks:
118+
blocks[block_name] = {}
119+
115120
for field_name in block.keys():
116121
# Skip child components that have been processed as bindings
117122
if isinstance(value, Context) and field_name in xatspec.children:
@@ -120,60 +125,64 @@ def unstructure_component(value: Component) -> dict[str, Any]:
120125
if child_spec.metadata["block"] == block_name: # type: ignore
121126
continue
122127

123-
field_value = data[field_name]
124-
# convert:
128+
# filter out empty values and false keywords, and convert:
125129
# - paths to records
126-
# - datetime to ISO format
127-
# - auxiliary fields to tuples
128-
# - xarray DataArrays with 'nper' dimension to kper-sliced datasets
129-
# (and split the period data into separate kper-indexed blocks)
130+
# - datetimes to ISO format
131+
# - filter out false keywords
132+
# - 'auxiliary' fields to tuples
133+
# - xarray DataArrays with 'nper' dim to dict of kper-sliced datasets
130134
# - other values to their original form
131-
if isinstance(field_value, Path):
132-
field_spec = xatspec.attrs[field_name]
133-
field_meta = getattr(field_spec, "metadata", {})
134-
t = path_to_tuple(field_name, field_value, inout=field_meta.get("inout", "fileout"))
135-
# name may have changed e.g dropping '_file' suffix
136-
blocks[block_name][t[0]] = t
137-
elif isinstance(field_value, datetime):
138-
blocks[block_name][field_name] = field_value.isoformat()
139-
elif (
140-
field_name == "auxiliary"
141-
and hasattr(field_value, "values")
142-
and field_value is not None
143-
):
144-
blocks[block_name][field_name] = tuple(field_value.values.tolist())
145-
elif isinstance(field_value, xr.DataArray) and "nper" in field_value.dims:
146-
has_spatial_dims = any(
147-
dim in field_value.dims for dim in ["nlay", "nrow", "ncol", "nodes"]
148-
)
149-
if has_spatial_dims:
150-
field_value = _hack_structured_grid_dims(
151-
field_value,
152-
structured_grid_dims=value.parent.data.dims, # type: ignore
135+
match field_value := data[field_name]:
136+
case None:
137+
continue
138+
case bool():
139+
if field_value:
140+
blocks[block_name][field_name] = field_value
141+
case Path():
142+
field_spec = xatspec.attrs[field_name]
143+
field_meta = getattr(field_spec, "metadata", {})
144+
t = path_to_tuple(
145+
field_name, field_value, inout=field_meta.get("inout", "fileout")
153146
)
154-
if "period" in block_name:
155-
period_block_name = block_name
156-
period_data[field_name] = {
157-
kper: field_value.isel(nper=kper)
158-
for kper in range(field_value.sizes["nper"])
159-
}
160-
else:
161-
blocks[block_name][field_name] = field_value
162-
else:
163-
if field_value is not None:
164-
# only include boolean fields (keywords) if true
165-
if isinstance(field_value, bool):
166-
if field_value:
167-
blocks[block_name][field_name] = field_value
147+
# name may have changed e.g dropping '_file' suffix
148+
blocks[block_name][t[0]] = t
149+
case datetime():
150+
blocks[block_name][field_name] = field_value.isoformat()
151+
case t if (
152+
field_name == "auxiliary"
153+
and hasattr(field_value, "values")
154+
and field_value is not None
155+
):
156+
blocks[block_name][field_name] = tuple(field_value.values.tolist())
157+
case xr.DataArray() if "nper" in field_value.dims:
158+
has_spatial_dims = any(
159+
dim in field_value.dims for dim in ["nlay", "nrow", "ncol", "nodes"]
160+
)
161+
if has_spatial_dims:
162+
field_value = _hack_structured_grid_dims(
163+
field_value,
164+
structured_grid_dims=value.parent.data.dims, # type: ignore
165+
)
166+
if "period" in block_name:
167+
period_block_name = block_name
168+
period_data[field_name] = {
169+
kper: field_value.isel(nper=kper)
170+
for kper in range(field_value.sizes["nper"])
171+
}
168172
else:
169173
blocks[block_name][field_name] = field_value
170174

175+
case _:
176+
blocks[block_name][field_name] = field_value
177+
178+
# invert key order, (arr_name, kper) -> (kper, arr_name)
171179
for arr_name, periods in period_data.items():
172180
for kper, arr in periods.items():
173181
if kper not in period_blocks:
174182
period_blocks[kper] = {}
175183
period_blocks[kper][arr_name] = arr
176184

185+
# setup indexed period blocks, combine arrays into datasets
177186
for kper, block in period_blocks.items():
178187
assert isinstance(period_block_name, str)
179188
blocks[f"{period_block_name} {kper + 1}"] = {

0 commit comments

Comments
 (0)