/
external_file_handling_tutorial.py
252 lines (189 loc) · 7.39 KB
/
external_file_handling_tutorial.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# ---
# jupyter:
# jupytext:
# notebook_metadata_filter: all
# text_representation:
# extension: .py
# format_name: light
# format_version: '1.5'
# jupytext_version: 1.14.5
# kernelspec:
# display_name: Python 3 (ipykernel)
# language: python
# name: python3
# metadata:
# section: flopy
# authors:
# - name: Jeremy White
# ---
# # External file handling
#
# +
import os
import sys
from tempfile import TemporaryDirectory
import numpy as np
import flopy
from flopy.utils import flopy_io
print(sys.version)
print(f"numpy version: {np.__version__}")
print(f"flopy version: {flopy.__version__}")
# +
# make a model
nlay, nrow, ncol = 10, 20, 5
temp_dir = TemporaryDirectory()
model_ws = temp_dir.name
# the place for all of your hand made and costly model inputs
array_dir = os.path.join(temp_dir.name, "array_dir")
os.mkdir(array_dir)
ml = flopy.modflow.Modflow(model_ws=model_ws)
dis = flopy.modflow.ModflowDis(
ml, nlay=nlay, nrow=nrow, ncol=ncol, steady=False, nper=2
)
# -
# make an ``hk`` and ```vka``` array. We'll save ```hk``` to files - pretent that you spent months making this important model property. Then make an ```lpf```
hk = np.zeros((nlay, nrow, ncol)) + 5.0
vka = np.zeros_like(hk)
fnames = []
for i, h in enumerate(hk):
fname = os.path.join(array_dir, f"hk_{i + 1}.ref")
fnames.append(fname)
np.savetxt(fname, h)
vka[i] = i + 1
lpf = flopy.modflow.ModflowLpf(ml, hk=fnames, vka=vka)
# Let's also have some recharge with mixed args as well. Pretend the recharge in the second stress period is very important and precise
warmup_recharge = np.ones((nrow, ncol))
important_recharge = np.random.random((nrow, ncol))
fname = os.path.join(array_dir, "important_recharge.ref")
np.savetxt(fname, important_recharge)
rch = flopy.modflow.ModflowRch(ml, rech={0: warmup_recharge, 1: fname})
ml.write_input()
# Let's look at the files that were created
# +
from pprint import pprint
print("model_ws:", flopy_io.scrub_login(ml.model_ws))
pprint([flopy_io.scrub_login(p) for p in os.listdir(ml.model_ws)])
# -
# We see that a copy of the ``hk`` files as well as the important recharge file were made in the ```model_ws```.Let's looks at the ```lpf``` file
open(os.path.join(ml.model_ws, f"{ml.name}.lpf")).readlines()[:20]
# We see that the ```open/close``` approach was used - this is because ``ml.array_free_format`` is ``True``. Notice that ```vka``` is written internally
ml.array_free_format
# Now change ```model_ws```
ml.model_ws = os.path.join(model_ws, "new_external_demo_dir")
# Now when we call ``write_input()``, a copy of external files are made in the current ```model_ws```
ml.write_input()
# list the files in model_ws that have 'hk' in the name
print(
"\n".join(
[
name
for name in os.listdir(ml.model_ws)
if "hk" in name or "impor" in name
]
)
)
# Now we see that the external files were copied to the new ```model_ws```
#
# ### Using ```external_path```
#
# It is sometimes useful when first building a model to write the model arrays as external files for processing and parameter estimation. The ```model``` attribute ```external_path``` triggers this behavior
# +
# make a model - same code as before except for the model constructor
nlay, nrow, ncol = 10, 20, 5
model_ws = os.path.join(model_ws, "external_demo")
os.mkdir(model_ws)
# the place for all of your hand made and costly model inputs
array_dir = os.path.join(model_ws, "array_dir")
os.mkdir(array_dir)
# lets make an external path relative to the model_ws
ml = flopy.modflow.Modflow(
model_ws=model_ws, external_path=os.path.join(model_ws, "ref")
)
dis = flopy.modflow.ModflowDis(
ml, nlay=nlay, nrow=nrow, ncol=ncol, steady=False, nper=2
)
hk = np.zeros((nlay, nrow, ncol)) + 5.0
vka = np.zeros_like(hk)
fnames = []
for i, h in enumerate(hk):
fname = os.path.join(array_dir, f"hk_{i + 1}.ref")
fnames.append(fname)
np.savetxt(fname, h)
vka[i] = i + 1
lpf = flopy.modflow.ModflowLpf(ml, hk=fnames, vka=vka)
warmup_recharge = np.ones((nrow, ncol))
important_recharge = np.random.random((nrow, ncol))
fname = os.path.join(array_dir, "important_recharge.ref")
np.savetxt(fname, important_recharge)
rch = flopy.modflow.ModflowRch(ml, rech={0: warmup_recharge, 1: fname})
# -
# We can see that the model constructor created both ```model_ws``` and ```external_path``` which is _relative to the model_ws_
os.listdir(ml.model_ws)
# Now, when we call ```write_input()```, any array properties that were specified as ```np.ndarray``` will be written externally. If a scalar was passed as the argument, the value remains internal to the model input files
ml.write_input()
# open(os.path.join(ml.model_ws, ml.name + ".lpf"), "r").readlines()[:20]
# Now, ```vka``` was also written externally, but not the storage properties.Let's verify the contents of the external path directory. We see our hard-fought ```hk``` and ```important_recharge``` arrays, as well as the ``vka`` arrays.
ml.lpf.ss.how = "internal"
ml.write_input()
# open(os.path.join(ml.model_ws, ml.name + ".lpf"), "r").readlines()[:20]
print("\n".join(os.listdir(os.path.join(ml.model_ws, ml.external_path))))
# ### Fixed format
#
# All of this behavior also works for fixed-format type models (really, really old models - I mean OLD!)
# +
# make a model - same code as before except for the model constructor
nlay, nrow, ncol = 10, 20, 5
# lets make an external path relative to the model_ws
ml = flopy.modflow.Modflow(model_ws=model_ws, external_path="ref")
# explicitly reset the free_format flag BEFORE ANY PACKAGES ARE MADE!!!
ml.array_free_format = False
dis = flopy.modflow.ModflowDis(
ml, nlay=nlay, nrow=nrow, ncol=ncol, steady=False, nper=2
)
hk = np.zeros((nlay, nrow, ncol)) + 5.0
vka = np.zeros_like(hk)
fnames = []
for i, h in enumerate(hk):
fname = os.path.join(array_dir, f"hk_{i + 1}.ref")
fnames.append(fname)
np.savetxt(fname, h)
vka[i] = i + 1
lpf = flopy.modflow.ModflowLpf(ml, hk=fnames, vka=vka)
ml.lpf.ss.how = "internal"
warmup_recharge = np.ones((nrow, ncol))
important_recharge = np.random.random((nrow, ncol))
fname = os.path.join(array_dir, "important_recharge.ref")
np.savetxt(fname, important_recharge)
rch = flopy.modflow.ModflowRch(ml, rech={0: warmup_recharge, 1: fname})
ml.write_input()
# -
# We see that now the external arrays are being handled through the name file. Let's look at the name file
open(os.path.join(ml.model_ws, f"{ml.name}.nam")).readlines()
# ### Free and binary format
ml.dis.botm[0].format.binary = True
ml.write_input()
open(os.path.join(ml.model_ws, f"{ml.name}.nam")).readlines()
open(os.path.join(ml.model_ws, f"{ml.name}.dis")).readlines()
# ### The ```.how``` attribute
# ```Util2d``` includes a ```.how``` attribute that gives finer grained control of how arrays will written
ml.lpf.hk[0].how
# This will raise an error since our model does not support free format...
try:
ml.lpf.hk[0].how = "openclose"
ml.lpf.hk[0].how
ml.write_input()
except Exception as e:
print("\n", e, "\n")
# So let's reset hk layer 1 back to external...
ml.lpf.hk[0].how = "external"
ml.lpf.hk[0].how
ml.dis.top.how = "external"
ml.write_input()
open(os.path.join(ml.model_ws, f"{ml.name}.dis")).readlines()
open(os.path.join(ml.model_ws, f"{ml.name}.lpf")).readlines()
open(os.path.join(ml.model_ws, f"{ml.name}.nam")).readlines()
try:
# ignore PermissionError on Windows
temp_dir.cleanup()
except:
pass