Skip to content

Commit e3048b7

Browse files
committed
tidier converter
1 parent f1c2953 commit e3048b7

File tree

5 files changed

+223
-203
lines changed

5 files changed

+223
-203
lines changed

flopy4/mf6/binding.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from attrs import define
2+
3+
from flopy4.mf6.component import Component
4+
from flopy4.mf6.exchange import Exchange
5+
from flopy4.mf6.model import Model
6+
from flopy4.mf6.package import Package
7+
from flopy4.mf6.solution import Solution
8+
9+
10+
@define
11+
class Binding:
12+
"""
13+
An MF6 component binding: a record representation of the
14+
component for writing to a parent component's name file.
15+
"""
16+
17+
type: str
18+
fname: str
19+
terms: tuple[str, ...] | None = None
20+
21+
def to_tuple(self) -> tuple[str, ...]:
22+
if self.terms and any(self.terms):
23+
return (self.type, self.fname, *self.terms)
24+
else:
25+
return (self.type, self.fname)
26+
27+
@classmethod
28+
def from_component(cls, component: Component) -> "Binding":
29+
def _get_binding_type(component: Component) -> str:
30+
cls_name = component.__class__.__name__
31+
if isinstance(component, Exchange):
32+
return f"{'-'.join([cls_name[:2], cls_name[3:]]).upper()}6"
33+
elif isinstance(component, Solution):
34+
return f"{component.slntype}6"
35+
else:
36+
return f"{cls_name.upper()}6"
37+
38+
def _get_binding_terms(component: Component) -> tuple[str, ...] | None:
39+
if isinstance(component, Exchange):
40+
return (component.exgmnamea, component.exgmnameb) # type: ignore
41+
elif isinstance(component, Solution):
42+
return tuple(component.models)
43+
elif isinstance(component, (Model, Package)):
44+
return (component.name,) # type: ignore
45+
return None
46+
47+
return cls(
48+
type=_get_binding_type(component),
49+
fname=component.filename or component.default_filename(),
50+
terms=_get_binding_terms(component),
51+
)

flopy4/mf6/codec/writer/filters.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,15 @@ def array2const(value: xr.DataArray) -> Scalar:
136136
return f"{value.max().item():.8f}"
137137

138138

139-
def data2list(value: list | tuple | dict | xr.Dataset | xr.DataArray):
139+
def data2list(value: list | dict | xr.Dataset | xr.DataArray):
140140
"""
141141
Yield records (tuples) from data in a `list`, `dict`, `DataArray` or `Dataset`.
142142
"""
143143

144-
if isinstance(value, (list, tuple)):
144+
if isinstance(value, list):
145145
for rec in value:
146+
if not isinstance(rec, tuple):
147+
raise ValueError(f"Unsupported record type: {type(rec)}")
146148
yield rec
147149
return
148150

flopy4/mf6/component.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
from abc import ABC
22
from collections.abc import MutableMapping
33
from pathlib import Path
4-
from typing import ClassVar
4+
from typing import Any, ClassVar
55

66
import numpy as np
77
from attrs import fields
88
from modflow_devtools.dfn import Dfn, Field
99
from packaging.version import Version
10+
from xattree import asdict as xattree_asdict
1011
from xattree import xattree
1112

1213
from flopy4.mf6.constants import FILL_DNODATA, MF6
@@ -197,3 +198,16 @@ def write(self, format: str = MF6) -> None:
197198
self._write(format=format)
198199
for child in self.children.values(): # type: ignore
199200
child.write(format=format)
201+
202+
def to_dict(self, blocks: bool = False) -> dict[str, Any]:
203+
"""Convert the component to a dictionary representation."""
204+
data = xattree_asdict(self)
205+
if blocks:
206+
blocks_ = {}
207+
for field_name, field_meta in self.data.attrs["metadata"].items():
208+
block_name = field_meta["block"]
209+
if block_name not in blocks_:
210+
blocks_[block_name] = {}
211+
blocks_[block_name][field_name] = data[field_name]
212+
return blocks_
213+
return data

flopy4/mf6/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import numpy as np
22

33
MF6 = "mf6"
4+
PERIOD = "period"
45
FILL_DEFAULT = np.nan
56
FILL_DNODATA = 1e30

0 commit comments

Comments
 (0)