Skip to content

Commit ca3945d

Browse files
author
Joost Delsman
committed
store relative path in render to use in save
1 parent 9842e27 commit ca3945d

File tree

3 files changed

+113
-70
lines changed

3 files changed

+113
-70
lines changed

imod/wq/ani.py

Lines changed: 79 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,58 +6,65 @@
66
import imod
77
from imod.wq.pkgbase import Package
88

9+
910
class HorizontalAnisotropyFile(Package):
1011
"""
1112
Horizontal Anisotropy package.
1213
1314
Parameters
1415
----------
1516
anifile: str
16-
is the file location of the imod-wq ani-file. This file contains the
17+
is the file location of the imod-wq ani-file. This file contains the
1718
anisotropy factor and angle of each layer, either as a constant or a
18-
reference to the file location of an '.arr' file. No checks are
19-
implemented for this file, user is responsible for consistency with
19+
reference to the file location of an '.arr' file. No checks are
20+
implemented for this file, user is responsible for consistency with
2021
model.
2122
"""
2223

2324
_pkg_id = "ani"
2425

25-
_template = (
26-
"[ani]\n"
27-
" anifile = {anifile}\n"
28-
)
26+
_template = "[ani]\n" " anifile = {anifile}\n\n"
2927

3028
def __init__(
3129
self,
3230
anifile,
3331
):
3432
super().__init__()
3533
self["anifile"] = anifile
36-
37-
def _render(self, directory, *args, **kwargs):
38-
path_ani = pathlib.Path(str(self['anifile'].values))
39-
d = {"anifile": f"ani/{path_ani.name}"}
34+
35+
def _render(self, modelname, directory, nlayer):
36+
# write ani file
37+
# in render function, as here we know where the model is run from
38+
# and how many layers: store this info for later use in save
39+
self.anifile = f"{modelname}.ani"
40+
self.rendir = directory
41+
self.nlayer = nlayer
42+
43+
d = {"anifile": f"{directory.as_posix()}/{modelname}.ani"}
4044

4145
return self._template.format(**d)
42-
46+
4347
def save(self, directory):
44-
"""Overload save function.
45-
Saves anifile to location, along with referenced .arr files"""
46-
directory.mkdir(exist_ok=True)
47-
48-
path_ani = pathlib.Path(str(self['anifile'].values))
49-
48+
"""Overload save function.
49+
Saves anifile to location, along with referenced .arr files
50+
assumes _render() to have run previously"""
51+
directory.mkdir(exist_ok=True) # otherwise handled by idf.save
52+
53+
path_ani = pathlib.Path(str(self["anifile"].values))
54+
5055
# regex adapted from stackoverflow: https://stackoverflow.com/questions/54990405/a-general-regex-to-extract-file-paths-not-urls
51-
rgx = r'((?:[a-zA-Z]:|(?<![:/\\])[\\\/](?!CLOSE)(?!close )|\~[\\\/]|(?:\.{1,2}[\\\/])+)[\w+\\\s_\-\(\)\/]*(?:\.\w+)*)'
52-
with open(path_ani, "r") as f, open(directory / path_ani.name, "w") as f2:
56+
rgx = r"((?:[a-zA-Z]:|(?<![:/\\])[\\\/](?!CLOSE)(?!close )|\~[\\\/]|(?:\.{1,2}[\\\/])+)[\w+\\\s_\-\(\)\/]*(?:\.\w+)*)"
57+
with open(path_ani, "r") as f, open(directory / self.anifile, "w") as f2:
5358
for line in f:
5459
p = re.search(rgx, line)
5560
if p:
56-
# path to file detected,
61+
# path to file detected,
5762
# replace to relative and
5863
# copy to directory
5964
path = pathlib.Path(p[0])
60-
f2.write(line.replace(p[0], f"{directory.stem}/{path.name}"))
65+
f2.write(
66+
line.replace(p[0], f"{self.rendir.as_posix()}/{path.name}")
67+
)
6168
if not path.is_absolute():
6269
path = path_ani.parent / path
6370
shutil.copyfile(path, directory / path.name)
@@ -72,47 +79,50 @@ class HorizontalAnisotropy(Package):
7279
"""
7380
Horizontal Anisotropy package.
7481
Anisotropy is a phenomenon for which the permeability k is not equal along the x- and y Cartesian axis.
75-
82+
7683
Parameters
7784
----------
7885
factor : float or xr.DataArray of floats
79-
The anisotropic factor perpendicular to the main principal axis (axis of highest permeability).
86+
The anisotropic factor perpendicular to the main principal axis (axis of highest permeability).
8087
Factor between 0.0 (full anisotropic) and 1.0 (full isotropic).
8188
angle : float or xr.DataArray of floats
8289
The angle along the main principal axis (highest permeability) measured in degrees from north (0),
8390
east (90), south (180) and west (270).
84-
fn_ani : filename for created anifile, optional
85-
Default: ani.ani
8691
"""
8792

8893
_pkg_id = "ani"
8994

90-
_template = (
91-
"[ani]\n"
92-
" anifile = {anifile}\n"
93-
)
95+
_template = "[ani]\n" " anifile = {anifile}\n\n"
9496

9597
def __init__(
9698
self,
9799
factor,
98100
angle,
99-
fn_ani="ani.ani"
100101
):
101102
super().__init__()
102103
self["factor"] = factor
103-
self["factor"] = self["factor"].fillna(1.)
104+
self["factor"] = self["factor"].fillna(1.0)
104105
self["angle"] = angle
105-
self["angle"] = self["angle"].fillna(0.)
106-
self["fn_ani"] = fn_ani
107-
108-
def _render(self, directory, *args, **kwargs):
109-
d = {"anifile": f"ani/{str(self['fn_ani'].values)}"}
106+
self["angle"] = self["angle"].fillna(0.0)
107+
108+
def _render(self, modelname, directory, nlayer):
109+
# write ani file
110+
# in render function, as here we know where the model is run from
111+
# and how many layers: store this info for later use in save
112+
self.anifile = f"{modelname}.ani"
113+
self.rendir = directory
114+
self.nlayer = nlayer
115+
116+
d = {"anifile": f"{directory.as_posix()}/{modelname}.ani"}
110117

111118
return self._template.format(**d)
112-
119+
113120
def save(self, directory):
114-
"""Overload save function.
115-
Saves anifile to location, along with referenced .arr files"""
121+
"""Overload save function.
122+
Saves anifile to location, along with created .arr files
123+
assumes _render() to have run previously"""
124+
directory.mkdir(exist_ok=True) # otherwise handled by idf.save
125+
116126
def _write(path, a, nodata=1.0e20, dtype=np.float32):
117127
if not np.all(a == a[0][0]):
118128
return np.savetxt(path, a, fmt="%.5f", delimiter=" ")
@@ -124,22 +134,39 @@ def _write(path, a, nodata=1.0e20, dtype=np.float32):
124134
if "y" in da.coords and "x" in da.coords:
125135
path = pathlib.Path(directory).joinpath(f"{name}.arr")
126136
if name == "factor":
127-
nodata = 1.
137+
nodata = 1.0
128138
elif name == "angle":
129-
nodata = 0.
139+
nodata = 0.0
130140
else:
131141
nodata = 1.0e20
132-
imod.array_io.writing._save(path, da, nodata=nodata, pattern=None, dtype=np.float32, write=_write)
133-
134-
# write ani file
135-
with open(directory / f"{str(self['fn_ani'].values)}", "w") as f:
136-
for l in self.dataset.layer.values:
137-
for prm in ["factor","angle"]:
138-
a = self.dataset[prm].sel(layer=l).values
139-
if not np.all(a == a[0][0]):
140-
f.write(f"open/close {directory.as_posix()}/{prm}_l{float(l):.0f}.arr 1.0D0 (FREE) -1 {prm}_l{float(l):.0f}\n")
142+
imod.array_io.writing._save(
143+
path,
144+
da,
145+
nodata=nodata,
146+
pattern=None,
147+
dtype=np.float32,
148+
write=_write,
149+
)
150+
151+
# save anifile with data stored during _render
152+
with open(directory / self.anifile, "w") as f:
153+
for l in range(1, self.nlayer + 1):
154+
for prm in ["factor", "angle"]:
155+
da = self.dataset[prm]
156+
if "layer" in da.coords and "y" in da.coords and "x" in da.coords:
157+
a = da.sel(layer=l).values
158+
if not np.all(a == a[0][0]):
159+
f.write(
160+
f"open/close {self.rendir.as_posix()}/{prm}_l{float(l):.0f}.arr 1.0D0 (FREE) -1 {prm}_l{float(l):.0f}\n"
161+
)
162+
else:
163+
f.write(
164+
f"constant {float(a[0][0]):.5f} {prm}_l{float(l):.0f}\n"
165+
)
141166
else:
142-
f.write(f"constant {float(a[0][0]):.5f} {prm}_l{float(l):.0f}\n")
167+
f.write(
168+
f"constant {float(self.dataset[prm].values):.5f} {prm}_l{float(l):.0f}\n"
169+
)
143170

144171
def _pkgcheck(self, ibound=None):
145172
pass

imod/wq/hfb.py

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,46 @@
22
import shutil
33
from imod.wq.pkgbase import Package
44

5+
56
class HorizontalFlowBarrier(Package):
67
"""
78
Horizontal Flow Barrier package.
89
910
Parameters
1011
----------
1112
hfbfile: str
12-
is the file location of the imod-wq hfb-file. This file contains cell-
13+
is the file location of the imod-wq hfb-file. This file contains cell-
1314
to-cell resistance values. The hfb file can be constructed from generate
14-
files using imod-batch. No checks are implemented for this file, user is
15+
files using imod-batch. No checks are implemented for this file, user is
1516
responsible for consistency with model.
1617
"""
1718

1819
_pkg_id = "hfb"
1920

20-
_template = (
21-
"[hfb]\n"
22-
" hfbfile = {hfbfile}\n"
23-
)
21+
_template = "[hfb]\n" " hfbfile = {hfbfile}\n\n"
2422

2523
def __init__(
2624
self,
2725
hfbfile,
2826
):
2927
super().__init__()
3028
self["hfbfile"] = hfbfile
31-
32-
def _render(self, directory, *args, **kwargs):
33-
path_hfb = pathlib.Path(str(self["hfbfile"].values))
34-
d = {"hfbfile": f"hfb/{path_hfb.name}"}
29+
30+
def _render(self, modelname, directory, *args, **kwargs):
31+
self.hfbfile = f"{modelname}.hfb"
32+
d = {"hfbfile": f"{directory.as_posix()}/{modelname}.hfb"}
3533

3634
return self._template.format(**d)
37-
35+
3836
def save(self, directory):
39-
"""Overloads save function.
40-
Saves hfbfile to directory"""
41-
directory.mkdir(exist_ok=True)
42-
37+
"""Overloads save function.
38+
Saves hfbfile to directory
39+
assumes _render() to have run previously"""
40+
directory.mkdir(exist_ok=True) # otherwise handled by idf.save
41+
4342
path_hfb = pathlib.Path(str(self["hfbfile"].values))
44-
45-
shutil.copyfile(path_hfb, directory / path_hfb.name)
43+
44+
shutil.copyfile(path_hfb, directory / self.hfbfile)
4645

4746
def _pkgcheck(self, ibound=None):
4847
pass

imod/wq/model.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,16 @@ def _bas_btn_rch_evt_mal_tvc_sinkssources(self):
605605

606606
return n_extra
607607

608+
def _render_anihfb(self, modelname, directory, nlayer):
609+
out = ""
610+
for key in ("ani", "hfb"):
611+
pkgkey = self._get_pkgkey(key)
612+
if pkgkey is not None:
613+
out += self[pkgkey]._render(
614+
modelname=modelname, directory=directory / pkgkey, nlayer=nlayer
615+
)
616+
return out
617+
608618
def render(self, directory, result_dir, writehelp):
609619
"""
610620
Render the runfile as a string, package by package.
@@ -636,6 +646,13 @@ def render(self, directory, result_dir, writehelp):
636646
)
637647
)
638648

649+
# ani and hfb packages
650+
content.append(
651+
self._render_anihfb(
652+
modelname=self.modelname, directory=directory, nlayer=nlayer
653+
)
654+
)
655+
639656
# multi-system package group: chd, drn, ghb, riv, wel
640657
modflowcontent, ssm_content, n_sinkssources = self._render_groups(
641658
directory=directory, globaltimes=globaltimes
@@ -666,7 +683,7 @@ def render(self, directory, result_dir, writehelp):
666683
directory=directory, globaltimes=globaltimes, nlayer=nlayer
667684
)
668685
)
669-
for key in ("vdf", "adv", "dsp", "ani", "hfb"):
686+
for key in ("vdf", "adv", "dsp"):
670687
content.append(
671688
self._render_pkg(
672689
key=key, directory=directory, globaltimes=globaltimes, nlayer=nlayer

0 commit comments

Comments
 (0)