Skip to content

Commit 7270eae

Browse files
committed
component filename, default fmt ascii, revert sim path -> workspace
1 parent 80c9912 commit 7270eae

File tree

7 files changed

+38
-25
lines changed

7 files changed

+38
-25
lines changed

docs/examples/quickstart.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
workspace = Path(__file__).parent / name
1414
time = ModelTime(perlen=[1.0], nstp=[1])
1515
grid = StructuredGrid(nlay=1, nrow=10, ncol=10)
16-
sim = Simulation(name=name, path=workspace, tdis=time)
16+
sim = Simulation(name=name, workspace=workspace, tdis=time)
1717
ims = Ims(parent=sim)
1818
gwf_name = "mymodel"
1919
gwf = Gwf(parent=sim, name=gwf_name, save_flows=True, dis=grid)

docs/examples/quickstart_expanded.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
ws = "./mymodel"
3333
name = "mymodel"
34-
sim = Simulation(name=name, path=ws, exe="mf6")
34+
sim = Simulation(name=name, workspace=ws, exe="mf6")
3535
tdis = Tdis(sim)
3636
gwf = Gwf(sim, name=name, save_flows=True)
3737
dis = Dis(gwf, nrow=10, ncol=10)

flopy4/mf6/__init__.py

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

88
def _default_filename(component: Component) -> str:
99
"""Default path for a component, based on its name."""
10-
if hasattr(component, "filename") and component.filename is not None:
11-
return component.filename
10+
if (filename := component.filename):
11+
return filename
1212
name = component.name # type: ignore
1313
cls_name = component.__class__.__name__.lower()
1414
return f"{name}.{cls_name}"

flopy4/mf6/component.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from modflow_devtools.dfn import Dfn, Field
55
from xattree import xattree
66

7-
from flopy4.mf6.spec import fields_dict, to_dfn_field
7+
from flopy4.mf6.spec import field, fields_dict, to_dfn_field
88
from flopy4.uio import IO, Loader, Writer
99

1010
COMPONENTS = {}
@@ -27,6 +27,10 @@ class Component(ABC, MutableMapping):
2727
_load = IO(Loader) # type: ignore
2828
_write = IO(Writer) # type: ignore
2929

30+
# NOTE: this needs to be overridden in subclasses
31+
# with required fields, otherwise attrs complains
32+
filename: str = field(default=None)
33+
3034
@classmethod
3135
def __attrs_init_subclass__(cls):
3236
COMPONENTS[cls.__name__.lower()] = cls
@@ -51,11 +55,11 @@ def __len__(self):
5155
def get_dfn(cls) -> Dfn:
5256
fields = {field_name: to_dfn_field(field) for field_name, field in fields_dict(cls).items()}
5357
blocks: dict[str, dict[str, Field]] = {}
54-
for field_name, field in fields.items():
55-
if (block := field.get("block", None)) is not None:
56-
blocks.setdefault(block, {})[field_name] = field
58+
for field_name, field_ in fields.items():
59+
if (block := field_.get("block", None)) is not None:
60+
blocks.setdefault(block, {})[field_name] = field_
5761
else:
58-
blocks[field_name] = field
62+
blocks[field_name] = field_
5963

6064
return Dfn(
6165
name=cls.__name__.lower(),

flopy4/mf6/exchange.py

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

99
@xattree
1010
class Exchange(Package):
11-
exgtype: type = field()
12-
exgfile: Path = field()
11+
exgtype: type = field() # type: ignore
12+
exgfile: Path = field() # type: ignore
1313
exgmnamea: Optional[str] = field(default=None)
1414
exgmnameb: Optional[str] = field(default=None)

flopy4/mf6/simulation.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
from os import PathLike
22
from pathlib import Path
3-
from typing import ClassVar
3+
from warnings import warn
44

55
from flopy.discretization.modeltime import ModelTime
66
from modflow_devtools.misc import cd, run_cmd
7-
from xattree import field, xattree
7+
from xattree import xattree
88

99
from flopy4.mf6.component import Component
1010
from flopy4.mf6.exchange import Exchange
1111
from flopy4.mf6.model import Model
1212
from flopy4.mf6.solution import Solution
13+
from flopy4.mf6.spec import field
1314
from flopy4.mf6.tdis import Tdis
1415

1516

@@ -27,31 +28,39 @@ class Simulation(Component):
2728
exchanges: dict[str, Exchange] = field()
2829
solutions: dict[str, Solution] = field()
2930
tdis: Tdis = field(converter=convert_time)
30-
# TODO: decorator for components bound
31-
# to some directory or file path?
32-
path: Path = field(default=None)
33-
filename: ClassVar[str] = "mfsim.nam"
31+
workspace: Path = field(default=None)
32+
filename: str = field(default="mfsim.nam")
33+
34+
def __attrs_post_init__(self):
35+
"""Post-initialization hook to set up the simulation."""
36+
super().__attrs_post_init__()
37+
if self.filename != "mfsim.nam":
38+
warn(
39+
"Simulation filename must be 'mfsim.nam'.",
40+
UserWarning,
41+
)
42+
self.filename = "mfsim.nam"
3443

3544
@property
3645
def time(self) -> ModelTime:
3746
return self.tdis.to_time()
3847

3948
def run(self, exe: str | PathLike = "mf6", verbose: bool = False) -> None:
4049
"""Run the simulation using the given executable."""
41-
if self.path is None:
50+
if self.workspace is None:
4251
raise ValueError(f"Simulation {self.name} has no workspace path.")
43-
with cd(self.path):
52+
with cd(self.workspace):
4453
stdout, stderr, retcode = run_cmd(exe, verbose=verbose)
4554
if retcode != 0:
4655
raise RuntimeError(
4756
f"Simulation {self.name}: {exe} failed to run with returncode " # type: ignore
4857
f"{retcode}, and error message:\n\n{stdout + stderr} "
4958
)
5059

51-
def load(self, format):
52-
with cd(self.path):
60+
def load(self, format="ascii"):
61+
with cd(self.workspace):
5362
super().load(format)
5463

55-
def write(self, format):
56-
with cd(self.path):
64+
def write(self, format="ascii"):
65+
with cd(self.workspace):
5766
super().write(format)

test/test_component.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,15 +275,15 @@ def test_ims_dfn():
275275
def test_write_ascii(tmp_path):
276276
time = ModelTime(perlen=[1.0], nstp=[1], tsmult=[1.0])
277277
grid = StructuredGrid(nlay=1, nrow=10, ncol=10)
278-
sim = Simulation(tdis=time, path=tmp_path)
278+
sim = Simulation(tdis=time, workspace=tmp_path)
279279
# TODO fix errors
280280
# gwf = Gwf(parent=sim, dis=grid)
281281
# ic = Ic(parent=gwf)
282282
# oc = Oc(parent=gwf)
283283
# npf = Npf(parent=gwf)
284284
# chd = Chd(parent=gwf, head={"*": {(0, 0, 0): 1.0, (0, 9, 9): 0.0}})
285285

286-
sim.write("ascii")
286+
sim.write()
287287

288288
files = list(Path(tmp_path).glob("*"))
289289
file_names = [f.name for f in files]

0 commit comments

Comments
 (0)