floodmodeller-api 0.4.2.post1__py3-none-any.whl → 0.4.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- floodmodeller_api/__init__.py +8 -9
- floodmodeller_api/_base.py +184 -176
- floodmodeller_api/backup.py +273 -273
- floodmodeller_api/dat.py +909 -831
- floodmodeller_api/diff.py +136 -119
- floodmodeller_api/ied.py +307 -306
- floodmodeller_api/ief.py +647 -637
- floodmodeller_api/ief_flags.py +253 -253
- floodmodeller_api/inp.py +266 -266
- floodmodeller_api/libs/libifcoremd.dll +0 -0
- floodmodeller_api/libs/libifcoremt.so.5 +0 -0
- floodmodeller_api/libs/libifport.so.5 +0 -0
- floodmodeller_api/{libmmd.dll → libs/libimf.so} +0 -0
- floodmodeller_api/libs/libintlc.so.5 +0 -0
- floodmodeller_api/libs/libmmd.dll +0 -0
- floodmodeller_api/libs/libsvml.so +0 -0
- floodmodeller_api/libs/libzzn_read.so +0 -0
- floodmodeller_api/libs/zzn_read.dll +0 -0
- floodmodeller_api/logs/__init__.py +2 -2
- floodmodeller_api/logs/lf.py +320 -312
- floodmodeller_api/logs/lf_helpers.py +354 -352
- floodmodeller_api/logs/lf_params.py +643 -529
- floodmodeller_api/mapping.py +84 -0
- floodmodeller_api/test/__init__.py +4 -4
- floodmodeller_api/test/conftest.py +9 -8
- floodmodeller_api/test/test_backup.py +117 -117
- floodmodeller_api/test/test_dat.py +221 -92
- floodmodeller_api/test/test_data/All Units 4_6.DAT +1081 -1081
- floodmodeller_api/test/test_data/All Units 4_6.feb +1081 -1081
- floodmodeller_api/test/test_data/BRIDGE.DAT +926 -926
- floodmodeller_api/test/test_data/Culvert_Inlet_Outlet.dat +36 -36
- floodmodeller_api/test/test_data/Culvert_Inlet_Outlet.feb +36 -36
- floodmodeller_api/test/test_data/DamBreakADI.xml +52 -52
- floodmodeller_api/test/test_data/DamBreakFAST.xml +58 -58
- floodmodeller_api/test/test_data/DamBreakFAST_dy.xml +53 -53
- floodmodeller_api/test/test_data/DamBreakTVD.xml +55 -55
- floodmodeller_api/test/test_data/DefenceBreach.xml +53 -53
- floodmodeller_api/test/test_data/DefenceBreachFAST.xml +60 -60
- floodmodeller_api/test/test_data/DefenceBreachFAST_dy.xml +55 -55
- floodmodeller_api/test/test_data/Domain1+2_QH.xml +76 -76
- floodmodeller_api/test/test_data/Domain1_H.xml +41 -41
- floodmodeller_api/test/test_data/Domain1_Q.xml +41 -41
- floodmodeller_api/test/test_data/Domain1_Q_FAST.xml +48 -48
- floodmodeller_api/test/test_data/Domain1_Q_FAST_dy.xml +48 -48
- floodmodeller_api/test/test_data/Domain1_Q_xml_expected.json +263 -0
- floodmodeller_api/test/test_data/Domain1_W.xml +41 -41
- floodmodeller_api/test/test_data/EX1.DAT +321 -321
- floodmodeller_api/test/test_data/EX1.ext +107 -107
- floodmodeller_api/test/test_data/EX1.feb +320 -320
- floodmodeller_api/test/test_data/EX1.gxy +107 -107
- floodmodeller_api/test/test_data/EX17.DAT +421 -422
- floodmodeller_api/test/test_data/EX17.ext +213 -213
- floodmodeller_api/test/test_data/EX17.feb +422 -422
- floodmodeller_api/test/test_data/EX18.DAT +375 -375
- floodmodeller_api/test/test_data/EX18_DAT_expected.json +3876 -0
- floodmodeller_api/test/test_data/EX2.DAT +302 -302
- floodmodeller_api/test/test_data/EX3.DAT +926 -926
- floodmodeller_api/test/test_data/EX3_DAT_expected.json +16235 -0
- floodmodeller_api/test/test_data/EX3_IEF_expected.json +61 -0
- floodmodeller_api/test/test_data/EX6.DAT +2084 -2084
- floodmodeller_api/test/test_data/EX6.ext +532 -532
- floodmodeller_api/test/test_data/EX6.feb +2084 -2084
- floodmodeller_api/test/test_data/EX6_DAT_expected.json +31647 -0
- floodmodeller_api/test/test_data/Event Data Example.DAT +336 -336
- floodmodeller_api/test/test_data/Event Data Example.ext +107 -107
- floodmodeller_api/test/test_data/Event Data Example.feb +336 -336
- floodmodeller_api/test/test_data/Linked1D2D.xml +52 -52
- floodmodeller_api/test/test_data/Linked1D2DFAST.xml +53 -53
- floodmodeller_api/test/test_data/Linked1D2DFAST_dy.xml +48 -48
- floodmodeller_api/test/test_data/Linked1D2D_xml_expected.json +313 -0
- floodmodeller_api/test/test_data/blockage.dat +50 -50
- floodmodeller_api/test/test_data/blockage.ext +45 -45
- floodmodeller_api/test/test_data/blockage.feb +9 -9
- floodmodeller_api/test/test_data/blockage.gxy +71 -71
- floodmodeller_api/test/test_data/defaultUnits.dat +127 -127
- floodmodeller_api/test/test_data/defaultUnits.ext +45 -45
- floodmodeller_api/test/test_data/defaultUnits.feb +9 -9
- floodmodeller_api/test/test_data/defaultUnits.fmpx +58 -58
- floodmodeller_api/test/test_data/defaultUnits.gxy +85 -85
- floodmodeller_api/test/test_data/ex3.ief +20 -20
- floodmodeller_api/test/test_data/ex3.lf1 +2800 -2800
- floodmodeller_api/test/test_data/ex4.DAT +1374 -1374
- floodmodeller_api/test/test_data/ex4_changed.DAT +1374 -1374
- floodmodeller_api/test/test_data/example1.inp +329 -329
- floodmodeller_api/test/test_data/example2.inp +158 -158
- floodmodeller_api/test/test_data/example3.inp +297 -297
- floodmodeller_api/test/test_data/example4.inp +388 -388
- floodmodeller_api/test/test_data/example5.inp +147 -147
- floodmodeller_api/test/test_data/example6.inp +154 -154
- floodmodeller_api/test/test_data/jump.dat +176 -176
- floodmodeller_api/test/test_data/network.dat +1374 -1374
- floodmodeller_api/test/test_data/network.ext +45 -45
- floodmodeller_api/test/test_data/network.exy +1 -1
- floodmodeller_api/test/test_data/network.feb +45 -45
- floodmodeller_api/test/test_data/network.ied +45 -45
- floodmodeller_api/test/test_data/network.ief +20 -20
- floodmodeller_api/test/test_data/network.inp +147 -147
- floodmodeller_api/test/test_data/network.pxy +57 -57
- floodmodeller_api/test/test_data/network.zzd +122 -122
- floodmodeller_api/test/test_data/network_dat_expected.json +21837 -0
- floodmodeller_api/test/test_data/network_from_tabularCSV.csv +87 -87
- floodmodeller_api/test/test_data/network_ied_expected.json +287 -0
- floodmodeller_api/test/test_data/rnweir.dat +9 -9
- floodmodeller_api/test/test_data/rnweir.ext +45 -45
- floodmodeller_api/test/test_data/rnweir.feb +9 -9
- floodmodeller_api/test/test_data/rnweir.gxy +45 -45
- floodmodeller_api/test/test_data/rnweir_default.dat +74 -74
- floodmodeller_api/test/test_data/rnweir_default.ext +45 -45
- floodmodeller_api/test/test_data/rnweir_default.feb +9 -9
- floodmodeller_api/test/test_data/rnweir_default.fmpx +58 -58
- floodmodeller_api/test/test_data/rnweir_default.gxy +53 -53
- floodmodeller_api/test/test_data/unit checks.dat +16 -16
- floodmodeller_api/test/test_ied.py +29 -29
- floodmodeller_api/test/test_ief.py +125 -24
- floodmodeller_api/test/test_inp.py +47 -48
- floodmodeller_api/test/test_json.py +114 -0
- floodmodeller_api/test/test_logs_lf.py +48 -51
- floodmodeller_api/test/test_tool.py +165 -152
- floodmodeller_api/test/test_toolbox_structure_log.py +234 -239
- floodmodeller_api/test/test_xml2d.py +151 -156
- floodmodeller_api/test/test_zzn.py +36 -34
- floodmodeller_api/to_from_json.py +218 -0
- floodmodeller_api/tool.py +332 -329
- floodmodeller_api/toolbox/__init__.py +5 -5
- floodmodeller_api/toolbox/example_tool.py +45 -45
- floodmodeller_api/toolbox/model_build/__init__.py +2 -2
- floodmodeller_api/toolbox/model_build/add_siltation_definition.py +100 -98
- floodmodeller_api/toolbox/model_build/structure_log/__init__.py +1 -1
- floodmodeller_api/toolbox/model_build/structure_log/structure_log.py +287 -289
- floodmodeller_api/toolbox/model_build/structure_log_definition.py +76 -76
- floodmodeller_api/units/__init__.py +10 -10
- floodmodeller_api/units/_base.py +214 -212
- floodmodeller_api/units/boundaries.py +467 -467
- floodmodeller_api/units/comment.py +52 -55
- floodmodeller_api/units/conduits.py +382 -402
- floodmodeller_api/units/helpers.py +123 -131
- floodmodeller_api/units/iic.py +107 -101
- floodmodeller_api/units/losses.py +305 -306
- floodmodeller_api/units/sections.py +444 -446
- floodmodeller_api/units/structures.py +1690 -1683
- floodmodeller_api/units/units.py +93 -104
- floodmodeller_api/units/unsupported.py +44 -44
- floodmodeller_api/units/variables.py +87 -89
- floodmodeller_api/urban1d/__init__.py +11 -11
- floodmodeller_api/urban1d/_base.py +188 -179
- floodmodeller_api/urban1d/conduits.py +93 -85
- floodmodeller_api/urban1d/general_parameters.py +58 -58
- floodmodeller_api/urban1d/junctions.py +81 -79
- floodmodeller_api/urban1d/losses.py +81 -74
- floodmodeller_api/urban1d/outfalls.py +114 -110
- floodmodeller_api/urban1d/raingauges.py +111 -111
- floodmodeller_api/urban1d/subsections.py +92 -98
- floodmodeller_api/urban1d/xsections.py +147 -144
- floodmodeller_api/util.py +77 -21
- floodmodeller_api/validation/parameters.py +660 -660
- floodmodeller_api/validation/urban_parameters.py +388 -404
- floodmodeller_api/validation/validation.py +110 -108
- floodmodeller_api/version.py +1 -1
- floodmodeller_api/xml2d.py +688 -673
- floodmodeller_api/xml2d_template.py +37 -37
- floodmodeller_api/zzn.py +387 -363
- {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.3.dist-info}/LICENSE.txt +13 -13
- {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.3.dist-info}/METADATA +82 -82
- floodmodeller_api-0.4.3.dist-info/RECORD +179 -0
- {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.3.dist-info}/WHEEL +1 -1
- floodmodeller_api/libifcoremd.dll +0 -0
- floodmodeller_api/test/test_data/EX3.bmp +0 -0
- floodmodeller_api/test/test_data/test_output.csv +0 -87
- floodmodeller_api/zzn_read.dll +0 -0
- floodmodeller_api-0.4.2.post1.dist-info/RECORD +0 -164
- {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.3.dist-info}/entry_points.txt +0 -0
- {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.3.dist-info}/top_level.txt +0 -0
floodmodeller_api/logs/lf.py
CHANGED
|
@@ -1,312 +1,320 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Flood Modeller Python API
|
|
3
|
-
Copyright (C)
|
|
4
|
-
|
|
5
|
-
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
|
|
6
|
-
as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
7
|
-
|
|
8
|
-
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
9
|
-
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
10
|
-
|
|
11
|
-
You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.
|
|
12
|
-
|
|
13
|
-
If you have any query about this program or this License, please contact us at support@floodmodeller.com or write to the following
|
|
14
|
-
address: Jacobs UK Limited, Flood Modeller, Cottons Centre, Cottons Lane, London, SE1 2QG, United Kingdom.
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
from
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
from
|
|
24
|
-
from .
|
|
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
|
-
self.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
#
|
|
64
|
-
|
|
65
|
-
self.
|
|
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
|
-
for
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
self.
|
|
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
|
-
def _get_index(self):
|
|
133
|
-
"""Finds key and dataframe for variable that is the index"""
|
|
134
|
-
|
|
135
|
-
for key in self._data_to_extract:
|
|
136
|
-
try:
|
|
137
|
-
self._data_to_extract[key]["is_index"]
|
|
138
|
-
index_key = key
|
|
139
|
-
index_df = self._extracted_data[key].data.get_value()
|
|
140
|
-
return index_key, index_df
|
|
141
|
-
|
|
142
|
-
except KeyError:
|
|
143
|
-
pass
|
|
144
|
-
|
|
145
|
-
raise Exception("No index variable found")
|
|
146
|
-
|
|
147
|
-
def _set_attributes(self):
|
|
148
|
-
"""Makes each Parser value an attribute; "last" values in dictionary"""
|
|
149
|
-
|
|
150
|
-
index_key, index_df = self._get_index()
|
|
151
|
-
|
|
152
|
-
info = {}
|
|
153
|
-
|
|
154
|
-
for key in self._data_to_extract:
|
|
155
|
-
data_type = self._data_to_extract[key]["data_type"]
|
|
156
|
-
value = self._extracted_data[key].data.get_value(index_key, index_df)
|
|
157
|
-
|
|
158
|
-
if data_type == "all":
|
|
159
|
-
setattr(self, key, value)
|
|
160
|
-
elif data_type == "last" and value is not None:
|
|
161
|
-
info[key] = value
|
|
162
|
-
|
|
163
|
-
self.info = info
|
|
164
|
-
|
|
165
|
-
def _del_attributes(self):
|
|
166
|
-
"""Deletes each Parser value direct attribute of LF"""
|
|
167
|
-
|
|
168
|
-
for key in self._data_to_extract:
|
|
169
|
-
data_type = self._data_to_extract[key]["data_type"]
|
|
170
|
-
if data_type == "all":
|
|
171
|
-
delattr(self, key)
|
|
172
|
-
|
|
173
|
-
delattr(self, "info")
|
|
174
|
-
|
|
175
|
-
def to_dataframe(self) -> pd.DataFrame:
|
|
176
|
-
"""Collects parameter values that change throughout simulation into a dataframe
|
|
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
|
-
def
|
|
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
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
1
|
+
"""
|
|
2
|
+
Flood Modeller Python API
|
|
3
|
+
Copyright (C) 2024 Jacobs U.K. Limited
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
|
|
6
|
+
as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
7
|
+
|
|
8
|
+
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
9
|
+
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
10
|
+
|
|
11
|
+
You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.
|
|
12
|
+
|
|
13
|
+
If you have any query about this program or this License, please contact us at support@floodmodeller.com or write to the following
|
|
14
|
+
address: Jacobs UK Limited, Flood Modeller, Cottons Centre, Cottons Lane, London, SE1 2QG, United Kingdom.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from typing import TYPE_CHECKING
|
|
20
|
+
|
|
21
|
+
import pandas as pd
|
|
22
|
+
|
|
23
|
+
from .._base import FMFile
|
|
24
|
+
from .lf_helpers import state_factory
|
|
25
|
+
from .lf_params import lf1_steady_data_to_extract, lf1_unsteady_data_to_extract, lf2_data_to_extract
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class LF(FMFile):
|
|
32
|
+
"""Reads and processes Flood Modeller log file
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
lf1_filepath (str): Full filepath to model log file
|
|
36
|
+
data_to_extract (dict): Dictionary defining each line type to parse
|
|
37
|
+
steady (bool): True if for a steady-state simulation
|
|
38
|
+
|
|
39
|
+
Output:
|
|
40
|
+
Initiates 'LF' class object
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
lf_filepath: str | Path | None,
|
|
46
|
+
data_to_extract: dict,
|
|
47
|
+
steady: bool = False,
|
|
48
|
+
):
|
|
49
|
+
try:
|
|
50
|
+
FMFile.__init__(self, lf_filepath)
|
|
51
|
+
|
|
52
|
+
self._data_to_extract = data_to_extract
|
|
53
|
+
self._init_counters()
|
|
54
|
+
self._init_parsers()
|
|
55
|
+
self._state = state_factory(steady, self._extracted_data)
|
|
56
|
+
|
|
57
|
+
self._read()
|
|
58
|
+
|
|
59
|
+
except Exception as e:
|
|
60
|
+
self._handle_exception(e, when="read")
|
|
61
|
+
|
|
62
|
+
def _read(self, force_reread: bool = False, suppress_final_step: bool = False):
|
|
63
|
+
# Read LF file
|
|
64
|
+
with open(self._filepath) as lf_file:
|
|
65
|
+
self._raw_data = [line.rstrip("\n") for line in lf_file.readlines()]
|
|
66
|
+
|
|
67
|
+
# Force rereading from start of file
|
|
68
|
+
if force_reread is True:
|
|
69
|
+
self._del_attributes()
|
|
70
|
+
self._init_counters()
|
|
71
|
+
self._init_parsers()
|
|
72
|
+
|
|
73
|
+
# Process file
|
|
74
|
+
self._update_data()
|
|
75
|
+
|
|
76
|
+
if not suppress_final_step:
|
|
77
|
+
self._set_attributes()
|
|
78
|
+
|
|
79
|
+
def read(self, force_reread: bool = False, suppress_final_step: bool = False) -> None:
|
|
80
|
+
"""Reads log file
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
force_reread (bool): If False, starts reading from where it stopped last time. If True, starts reading from the start of the file.
|
|
84
|
+
suppress_final_step (bool): If False, dataframes and dictionary are not created as attributes.
|
|
85
|
+
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
self._read(force_reread, suppress_final_step)
|
|
89
|
+
|
|
90
|
+
def _init_counters(self):
|
|
91
|
+
"""Initialises counters that keep track of file during simulation"""
|
|
92
|
+
|
|
93
|
+
self._no_lines = 0 # number of lines that have been read so far
|
|
94
|
+
self._no_iters = 0 # number of iterations so far
|
|
95
|
+
|
|
96
|
+
def _init_parsers(self):
|
|
97
|
+
"""Creates dictionary of Parser objects for each entry in data_to_extract"""
|
|
98
|
+
|
|
99
|
+
self._extracted_data = {}
|
|
100
|
+
|
|
101
|
+
for key in self._data_to_extract:
|
|
102
|
+
subdictionary = self._data_to_extract[key]
|
|
103
|
+
subdictionary_class = subdictionary["class"]
|
|
104
|
+
subdictionary_kwargs = {k: v for k, v in subdictionary.items() if k != "class"}
|
|
105
|
+
subdictionary_kwargs["name"] = key
|
|
106
|
+
self._extracted_data[key] = subdictionary_class(**subdictionary_kwargs)
|
|
107
|
+
|
|
108
|
+
def _update_data(self):
|
|
109
|
+
"""Updates value of each Parser object based on raw data"""
|
|
110
|
+
|
|
111
|
+
# loop through lines that haven't already been read
|
|
112
|
+
raw_lines = self._raw_data[self._no_lines :]
|
|
113
|
+
for raw_line in raw_lines:
|
|
114
|
+
# loop through parser types
|
|
115
|
+
for key in self._data_to_extract:
|
|
116
|
+
parser = self._extracted_data[key]
|
|
117
|
+
|
|
118
|
+
# lines which start with prefix
|
|
119
|
+
if raw_line.startswith(parser.prefix):
|
|
120
|
+
# store everything after prefix
|
|
121
|
+
end_of_line = raw_line.split(parser.prefix)[1].lstrip()
|
|
122
|
+
parser.process_line(end_of_line)
|
|
123
|
+
|
|
124
|
+
# index marks the end of an iteration
|
|
125
|
+
if parser.is_index is True:
|
|
126
|
+
self._sync_cols()
|
|
127
|
+
self._no_iters += 1
|
|
128
|
+
|
|
129
|
+
# update counter
|
|
130
|
+
self._no_lines += 1
|
|
131
|
+
|
|
132
|
+
def _get_index(self):
|
|
133
|
+
"""Finds key and dataframe for variable that is the index"""
|
|
134
|
+
|
|
135
|
+
for key in self._data_to_extract:
|
|
136
|
+
try:
|
|
137
|
+
self._data_to_extract[key]["is_index"]
|
|
138
|
+
index_key = key
|
|
139
|
+
index_df = self._extracted_data[key].data.get_value()
|
|
140
|
+
return index_key, index_df
|
|
141
|
+
|
|
142
|
+
except KeyError:
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
raise Exception("No index variable found")
|
|
146
|
+
|
|
147
|
+
def _set_attributes(self):
|
|
148
|
+
"""Makes each Parser value an attribute; "last" values in dictionary"""
|
|
149
|
+
|
|
150
|
+
index_key, index_df = self._get_index()
|
|
151
|
+
|
|
152
|
+
info = {}
|
|
153
|
+
|
|
154
|
+
for key in self._data_to_extract:
|
|
155
|
+
data_type = self._data_to_extract[key]["data_type"]
|
|
156
|
+
value = self._extracted_data[key].data.get_value(index_key, index_df)
|
|
157
|
+
|
|
158
|
+
if data_type == "all":
|
|
159
|
+
setattr(self, key, value)
|
|
160
|
+
elif data_type == "last" and value is not None:
|
|
161
|
+
info[key] = value
|
|
162
|
+
|
|
163
|
+
self.info = info
|
|
164
|
+
|
|
165
|
+
def _del_attributes(self):
|
|
166
|
+
"""Deletes each Parser value direct attribute of LF"""
|
|
167
|
+
|
|
168
|
+
for key in self._data_to_extract:
|
|
169
|
+
data_type = self._data_to_extract[key]["data_type"]
|
|
170
|
+
if data_type == "all":
|
|
171
|
+
delattr(self, key)
|
|
172
|
+
|
|
173
|
+
delattr(self, "info")
|
|
174
|
+
|
|
175
|
+
def to_dataframe(self, *, include_tuflow: bool = False) -> pd.DataFrame:
|
|
176
|
+
"""Collects parameter values that change throughout simulation into a dataframe
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
include_tuflow (bool): Include diagnostics for linked TUFLOW models
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
pd.DataFrame: DataFrame of log file parameters indexed by simulation time (unsteady) or network iterations (steady)
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
# TODO: make more like ZZN.to_dataframe
|
|
186
|
+
|
|
187
|
+
data_type_all = {
|
|
188
|
+
k: getattr(self, k)
|
|
189
|
+
for k, v in self._data_to_extract.items()
|
|
190
|
+
if v["data_type"] == "all" and (include_tuflow or "tuflow" not in k)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
df = pd.concat(data_type_all, axis=1)
|
|
194
|
+
df.columns = df.columns.droplevel()
|
|
195
|
+
|
|
196
|
+
df.sort_index(inplace=True)
|
|
197
|
+
|
|
198
|
+
return df
|
|
199
|
+
|
|
200
|
+
def _sync_cols(self):
|
|
201
|
+
"""Ensures Parser values (of type "all") have an entry each iteration"""
|
|
202
|
+
|
|
203
|
+
# loop through parser types
|
|
204
|
+
for key in self._data_to_extract:
|
|
205
|
+
parser = self._extracted_data[key]
|
|
206
|
+
|
|
207
|
+
# sync parser types that are not the index
|
|
208
|
+
if (
|
|
209
|
+
parser.is_index is False # if their number of values is not in sync
|
|
210
|
+
and parser.data_type == "all"
|
|
211
|
+
and parser.data.no_values < (self._no_iters + int(parser.before_index))
|
|
212
|
+
):
|
|
213
|
+
# append nan to the list
|
|
214
|
+
parser.data.update(parser._nan)
|
|
215
|
+
|
|
216
|
+
def _print_no_lines(self):
|
|
217
|
+
"""Prints number of lines that have been read so far"""
|
|
218
|
+
|
|
219
|
+
print("Last line read: " + str(self._no_lines))
|
|
220
|
+
|
|
221
|
+
def report_progress(self) -> float:
|
|
222
|
+
"""Returns progress for unsteady simulations
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
float: Last progress percentage recorded in log file
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
return self._state.report_progress()
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class LF1(LF):
|
|
232
|
+
"""Reads and processes Flood Modeller 1D log file '.lf1'
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
lf1_filepath (str): Full filepath to model lf1 file
|
|
236
|
+
steady (bool): True for steady-state simulations
|
|
237
|
+
|
|
238
|
+
**Attributes (unsteady)**
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
info (dict): Parameters with one value per simulation
|
|
242
|
+
mass_error (pandas.DataFrame): Mass error
|
|
243
|
+
timestep (pandas.DataFrame): Timestep
|
|
244
|
+
elapsed (pandas.DataFrame): Elapsed
|
|
245
|
+
tuflow_vol (pandas.DataFrame): TUFLOW HPC Vol
|
|
246
|
+
tuflow_n_wet (pandas.DataFrame): TUFLOW HPC nWet
|
|
247
|
+
tuflow_dt (pandas.DataFrame): TUFLOW HPC dt
|
|
248
|
+
simulated (pandas.DataFrame): Simulated
|
|
249
|
+
iterations (pandas.DataFrame): PlotI1
|
|
250
|
+
convergence (pandas.DataFrame): PlotC1
|
|
251
|
+
flow (pandas.DataFrame): PlotF1
|
|
252
|
+
|
|
253
|
+
**Attributes (steady)**
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
info (dict): Parameters with one value per simulation
|
|
257
|
+
network_iteration (pandas.DataFrame): Network iteration
|
|
258
|
+
largest_change_in_split_from_last_iteration (pandas.DataFrame): Largest change in split from last iteration
|
|
259
|
+
|
|
260
|
+
Output:
|
|
261
|
+
Initiates 'LF1' class object
|
|
262
|
+
"""
|
|
263
|
+
|
|
264
|
+
_filetype: str = "LF1"
|
|
265
|
+
_suffix: str = ".lf1"
|
|
266
|
+
|
|
267
|
+
def __init__(self, lf_filepath: str | Path | None, steady: bool = False):
|
|
268
|
+
if steady is False:
|
|
269
|
+
data_to_extract = lf1_unsteady_data_to_extract
|
|
270
|
+
else:
|
|
271
|
+
data_to_extract = lf1_steady_data_to_extract
|
|
272
|
+
|
|
273
|
+
super().__init__(lf_filepath, data_to_extract, steady)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
class LF2(LF):
|
|
277
|
+
"""Reads and processes Flood Modeller 1D log file '.lf2'
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
lf2_filepath (str): Full filepath to model lf2 file
|
|
281
|
+
|
|
282
|
+
**Attributes**
|
|
283
|
+
|
|
284
|
+
Args:
|
|
285
|
+
info (dict): Parameters with one value per simulation
|
|
286
|
+
simulated (pandas.DataFrame): Simulated
|
|
287
|
+
wet_cells (pandas.DataFrame): Wet cells
|
|
288
|
+
2D_boundary_inflow (pandas.DataFrame): 2D boundary inflow
|
|
289
|
+
2D_boundary_outflow (pandas.DataFrame): 2D boundary outflow
|
|
290
|
+
1D_link_flow (pandas.DataFrame): 1D link flow
|
|
291
|
+
change_in_volume (pandas.DataFrame): Change in volume
|
|
292
|
+
volume (pandas.DataFrame): Volume
|
|
293
|
+
inst_mass_err (pandas.DataFrame): Inst mass error
|
|
294
|
+
mass_error (pandas.DataFrame): Mass error
|
|
295
|
+
largest_cr (pandas.DataFrame): Largest Cr
|
|
296
|
+
elapsed (pandas.DataFrame): Elapsed
|
|
297
|
+
|
|
298
|
+
Output:
|
|
299
|
+
Initiates 'LF2' class object
|
|
300
|
+
"""
|
|
301
|
+
|
|
302
|
+
_filetype: str = "LF2"
|
|
303
|
+
_suffix: str = ".lf2"
|
|
304
|
+
|
|
305
|
+
def __init__(self, lf_filepath: str | Path | None):
|
|
306
|
+
data_to_extract = {
|
|
307
|
+
**lf1_unsteady_data_to_extract,
|
|
308
|
+
**lf2_data_to_extract,
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
super().__init__(lf_filepath, data_to_extract, steady=False)
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def lf_factory(filepath: str, suffix: str, steady: bool) -> LF:
|
|
315
|
+
if suffix == "lf1":
|
|
316
|
+
return LF1(filepath, steady)
|
|
317
|
+
if suffix == "lf2":
|
|
318
|
+
return LF2(filepath)
|
|
319
|
+
flow_type = "steady" if steady else "unsteady"
|
|
320
|
+
raise ValueError(f"Unexpected log file type {suffix} for {flow_type} flow")
|