floodmodeller-api 0.5.2.post1__py3-none-any.whl → 0.5.3.post1__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/_base.py +10 -4
- floodmodeller_api/dat.py +2 -4
- floodmodeller_api/ied.py +1 -1
- floodmodeller_api/ief.py +20 -3
- floodmodeller_api/logs/lf.py +14 -7
- floodmodeller_api/logs/lf_helpers.py +2 -0
- floodmodeller_api/logs/lf_params.py +54 -26
- floodmodeller_api/mapping.py +2 -0
- floodmodeller_api/test/test_dat.py +13 -1
- floodmodeller_api/test/test_data/floodplain.dat +52 -0
- floodmodeller_api/test/test_data/lf_complex_ex.lf1 +51499 -0
- floodmodeller_api/test/test_data/multievent.ief +43 -0
- floodmodeller_api/test/test_fmfile.py +20 -0
- floodmodeller_api/test/test_ief.py +67 -0
- floodmodeller_api/test/test_logs_lf.py +57 -12
- floodmodeller_api/test/test_sluice.py +31 -0
- floodmodeller_api/test/test_unit.py +57 -0
- floodmodeller_api/units/__init__.py +2 -1
- floodmodeller_api/units/_base.py +18 -6
- floodmodeller_api/units/sections.py +4 -4
- floodmodeller_api/units/structures.py +143 -1
- floodmodeller_api/units/units.py +1 -1
- floodmodeller_api/validation/parameters.py +16 -0
- floodmodeller_api/version.py +1 -1
- floodmodeller_api/xml2d.py +1 -1
- {floodmodeller_api-0.5.2.post1.dist-info → floodmodeller_api-0.5.3.post1.dist-info}/METADATA +5 -3
- {floodmodeller_api-0.5.2.post1.dist-info → floodmodeller_api-0.5.3.post1.dist-info}/RECORD +31 -25
- {floodmodeller_api-0.5.2.post1.dist-info → floodmodeller_api-0.5.3.post1.dist-info}/WHEEL +1 -1
- {floodmodeller_api-0.5.2.post1.dist-info → floodmodeller_api-0.5.3.post1.dist-info}/entry_points.txt +0 -0
- {floodmodeller_api-0.5.2.post1.dist-info → floodmodeller_api-0.5.3.post1.dist-info/licenses}/LICENSE.txt +0 -0
- {floodmodeller_api-0.5.2.post1.dist-info → floodmodeller_api-0.5.3.post1.dist-info}/top_level.txt +0 -0
floodmodeller_api/_base.py
CHANGED
|
@@ -83,18 +83,24 @@ class FMFile(Jsonable):
|
|
|
83
83
|
def _read(self):
|
|
84
84
|
raise NotImplementedError
|
|
85
85
|
|
|
86
|
-
def
|
|
86
|
+
def update(self) -> None:
|
|
87
|
+
raise NotImplementedError
|
|
88
|
+
|
|
89
|
+
def save(self, filepath: str | Path) -> None:
|
|
90
|
+
raise NotImplementedError
|
|
91
|
+
|
|
92
|
+
def _update(self) -> None:
|
|
87
93
|
"""Updates the existing self._filetype based on any altered attributes"""
|
|
88
94
|
if self._filepath is None:
|
|
89
95
|
msg = f"{self._filetype} must be saved to a specific filepath before update() can be called."
|
|
90
96
|
raise UserWarning(msg)
|
|
91
97
|
|
|
92
98
|
string = self._write()
|
|
93
|
-
with open(self._filepath, "w", encoding=self.ENCODING) as _file:
|
|
99
|
+
with open(self._filepath, "w", encoding=self.ENCODING, newline="\r\n") as _file:
|
|
94
100
|
_file.write(string)
|
|
95
101
|
logging.info("%s File Updated!", self._filepath)
|
|
96
102
|
|
|
97
|
-
def _save(self, filepath):
|
|
103
|
+
def _save(self, filepath: str | Path) -> None:
|
|
98
104
|
filepath = Path(filepath).absolute()
|
|
99
105
|
if filepath.suffix.lower() != self._suffix:
|
|
100
106
|
msg = f'Given filepath does not point to a filepath suffixed "{self._suffix}". Please point to the full path to save the {self._filetype} file'
|
|
@@ -104,7 +110,7 @@ class FMFile(Jsonable):
|
|
|
104
110
|
Path.mkdir(filepath.parent)
|
|
105
111
|
|
|
106
112
|
string = self._write()
|
|
107
|
-
with open(filepath, "w", encoding=self.ENCODING) as _file:
|
|
113
|
+
with open(filepath, "w", encoding=self.ENCODING, newline="\r\n") as _file:
|
|
108
114
|
_file.write(string)
|
|
109
115
|
self._filepath = filepath # Updates the filepath attribute to the given path
|
|
110
116
|
|
floodmodeller_api/dat.py
CHANGED
|
@@ -88,7 +88,7 @@ class DAT(FMFile):
|
|
|
88
88
|
if self._gxy_data is not None:
|
|
89
89
|
gxy_string = self._gxy_data
|
|
90
90
|
new_gxy_path = filepath.with_suffix(".gxy")
|
|
91
|
-
with open(new_gxy_path, "w") as gxy_file:
|
|
91
|
+
with open(new_gxy_path, "w", encoding=self.ENCODING, newline="\r\n") as gxy_file:
|
|
92
92
|
gxy_file.write(gxy_string)
|
|
93
93
|
self._gxy_filepath = new_gxy_path
|
|
94
94
|
|
|
@@ -571,9 +571,7 @@ class DAT(FMFile):
|
|
|
571
571
|
raise Exception(msg)
|
|
572
572
|
# Changes done to account for unit types with spaces/dashes eg Flat-V Weir
|
|
573
573
|
unit_type_safe = unit_type.replace(" ", "_").replace("-", "_")
|
|
574
|
-
unit_group[unit_name] =
|
|
575
|
-
f"units.{unit_type_safe}({unit_data}, {self._label_len})",
|
|
576
|
-
)
|
|
574
|
+
unit_group[unit_name] = getattr(units, unit_type_safe)(unit_data, self._label_len)
|
|
577
575
|
self._all_units.append(unit_group[unit_name])
|
|
578
576
|
|
|
579
577
|
def _process_unsupported_unit(self, unit_type, unit_data) -> None:
|
floodmodeller_api/ied.py
CHANGED
|
@@ -183,7 +183,7 @@ class IED(FMFile):
|
|
|
183
183
|
if unit_name in unit_group:
|
|
184
184
|
msg = f'Duplicate label ({unit_name}) encountered within category: {units.SUPPORTED_UNIT_TYPES[block["Type"]]["group"]}'
|
|
185
185
|
raise Exception(msg)
|
|
186
|
-
unit_group[unit_name] =
|
|
186
|
+
unit_group[unit_name] = getattr(units, block["Type"])(unit_data)
|
|
187
187
|
|
|
188
188
|
self._all_units.append(unit_group[unit_name])
|
|
189
189
|
|
floodmodeller_api/ief.py
CHANGED
|
@@ -18,6 +18,7 @@ from __future__ import annotations
|
|
|
18
18
|
|
|
19
19
|
import csv
|
|
20
20
|
import logging
|
|
21
|
+
import re
|
|
21
22
|
import subprocess
|
|
22
23
|
import time
|
|
23
24
|
from io import StringIO
|
|
@@ -98,6 +99,8 @@ class IEF(FMFile):
|
|
|
98
99
|
self._ief_properties: list[str] = []
|
|
99
100
|
self.EventData: dict[str, str] = {}
|
|
100
101
|
self.flowtimeprofiles: list[FlowTimeProfile] = []
|
|
102
|
+
|
|
103
|
+
raw_eventdata: list[tuple[str, str]] = []
|
|
101
104
|
for line in raw_data:
|
|
102
105
|
# Handle any comments here (prefixed with ;)
|
|
103
106
|
if line.lstrip().startswith(";"):
|
|
@@ -116,7 +119,7 @@ class IEF(FMFile):
|
|
|
116
119
|
event_data_title = value
|
|
117
120
|
else:
|
|
118
121
|
event_data_title = prev_comment
|
|
119
|
-
|
|
122
|
+
raw_eventdata.append((event_data_title, value))
|
|
120
123
|
self._ief_properties.append("EventData")
|
|
121
124
|
|
|
122
125
|
elif prop.upper().startswith("FLOWTIMEPROFILE"):
|
|
@@ -134,6 +137,7 @@ class IEF(FMFile):
|
|
|
134
137
|
self._ief_properties.append(line)
|
|
135
138
|
prev_comment = None
|
|
136
139
|
|
|
140
|
+
self._eventdata_read_helper(raw_eventdata)
|
|
137
141
|
self._check_formatting(raw_data)
|
|
138
142
|
self._update_ief_properties() # call this here to ensure ief properties is correct
|
|
139
143
|
|
|
@@ -179,7 +183,10 @@ class IEF(FMFile):
|
|
|
179
183
|
# Add multiple EventData if present
|
|
180
184
|
for idx, key in enumerate(event_data):
|
|
181
185
|
if idx == event_index:
|
|
182
|
-
|
|
186
|
+
# we enter this block if we're ready to write the event data
|
|
187
|
+
# scrub off any extra bits we've added as part of the make-unique bit of reading.
|
|
188
|
+
title = re.sub(r"<\d>$", "", key)
|
|
189
|
+
ief_string += f";{title}\nEventData{eq}{event_data[key]!s}\n"
|
|
183
190
|
break
|
|
184
191
|
event_index += 1
|
|
185
192
|
|
|
@@ -328,6 +335,16 @@ class IEF(FMFile):
|
|
|
328
335
|
if removed == to_remove:
|
|
329
336
|
break
|
|
330
337
|
|
|
338
|
+
def _eventdata_read_helper(self, raw_eventdata: list[tuple[str, str]]) -> None:
|
|
339
|
+
# now we deal with the event data, and convert it into the dict-based .eventdata
|
|
340
|
+
for title, ied_path in raw_eventdata:
|
|
341
|
+
n = 0
|
|
342
|
+
new_title = title or "<0>" # set empty string to placeholder
|
|
343
|
+
while new_title in self.eventdata:
|
|
344
|
+
new_title = f"{title}<{n}>"
|
|
345
|
+
n += 1
|
|
346
|
+
self.eventdata[new_title] = ied_path
|
|
347
|
+
|
|
331
348
|
def _update_flowtimeprofile_info(self) -> None:
|
|
332
349
|
"""Update the flowtimeprofile data stored in ief properties"""
|
|
333
350
|
if not hasattr(self, "flowtimeprofiles") or len(self.flowtimeprofiles) == 0:
|
|
@@ -570,7 +587,7 @@ class IEF(FMFile):
|
|
|
570
587
|
|
|
571
588
|
return ZZN(result_path)
|
|
572
589
|
|
|
573
|
-
def get_log(self):
|
|
590
|
+
def get_log(self) -> LF1:
|
|
574
591
|
"""If log files for the simulation exist, this function returns them as a LF1 class object
|
|
575
592
|
|
|
576
593
|
Returns:
|
floodmodeller_api/logs/lf.py
CHANGED
|
@@ -124,16 +124,23 @@ class LF(FMFile):
|
|
|
124
124
|
for key in self._data_to_extract:
|
|
125
125
|
parser = self._extracted_data[key]
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
if parser.use_regex:
|
|
128
|
+
if not (match := parser.prefix.match(raw_line)):
|
|
129
|
+
continue
|
|
130
|
+
end_of_line = match.group(1).lstrip()
|
|
131
|
+
|
|
132
|
+
elif raw_line.startswith(parser.prefix):
|
|
129
133
|
# store everything after prefix
|
|
130
134
|
end_of_line = raw_line.split(parser.prefix)[1].lstrip()
|
|
131
|
-
parser.process_line(end_of_line)
|
|
132
135
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
136
|
+
else:
|
|
137
|
+
continue
|
|
138
|
+
parser.process_line(end_of_line)
|
|
139
|
+
|
|
140
|
+
# index marks the end of an iteration
|
|
141
|
+
if parser.is_index is True:
|
|
142
|
+
self._sync_cols()
|
|
143
|
+
self._no_iters += 1
|
|
137
144
|
|
|
138
145
|
# update counter
|
|
139
146
|
self._no_lines += 1
|
|
@@ -171,6 +171,7 @@ class Parser(ABC):
|
|
|
171
171
|
exclude: str | None = None,
|
|
172
172
|
is_index: bool | None = False,
|
|
173
173
|
before_index: bool | None = False,
|
|
174
|
+
use_regex: bool | None = False,
|
|
174
175
|
):
|
|
175
176
|
self._name = name
|
|
176
177
|
|
|
@@ -184,6 +185,7 @@ class Parser(ABC):
|
|
|
184
185
|
|
|
185
186
|
self.data_type = data_type
|
|
186
187
|
self.data = data_factory(data_type, name)
|
|
188
|
+
self.use_regex = use_regex
|
|
187
189
|
|
|
188
190
|
def process_line(self, raw_line: str) -> None:
|
|
189
191
|
"""self._process_line with exception handling of expected nan values"""
|
|
@@ -14,6 +14,8 @@ If you have any query about this program or this License, please contact us at s
|
|
|
14
14
|
address: Jacobs UK Limited, Flood Modeller, Cottons Centre, Cottons Lane, London, SE1 2QG, United Kingdom.
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
+
import re
|
|
18
|
+
|
|
17
19
|
from .lf_helpers import (
|
|
18
20
|
DateTimeParser,
|
|
19
21
|
FloatParser,
|
|
@@ -185,93 +187,108 @@ lf1_unsteady_data_to_extract = {
|
|
|
185
187
|
},
|
|
186
188
|
"initial_volume": {
|
|
187
189
|
"class": FloatSplitParser,
|
|
188
|
-
"prefix": "
|
|
190
|
+
"prefix": re.compile(r"^!!output1\s+Initial volume\s*:(.*)"),
|
|
189
191
|
"data_type": "last",
|
|
190
192
|
"split": "m3",
|
|
193
|
+
"use_regex": True,
|
|
191
194
|
},
|
|
192
195
|
"final_volume": {
|
|
193
196
|
"class": FloatSplitParser,
|
|
194
|
-
"prefix": "
|
|
197
|
+
"prefix": re.compile(r"^!!output1\s+Final volume\s*:(.*)"),
|
|
195
198
|
"data_type": "last",
|
|
196
199
|
"split": "m3",
|
|
200
|
+
"use_regex": True,
|
|
197
201
|
},
|
|
198
202
|
"total_boundary_inflow": {
|
|
199
203
|
"class": FloatSplitParser,
|
|
200
|
-
"prefix": "
|
|
204
|
+
"prefix": re.compile(r"^!!output1\s+Total boundary inflow\s*:(.*)"),
|
|
201
205
|
"data_type": "last",
|
|
202
206
|
"split": "m3",
|
|
207
|
+
"use_regex": True,
|
|
203
208
|
},
|
|
204
209
|
"total_boundary_outflow": {
|
|
205
210
|
"class": FloatSplitParser,
|
|
206
|
-
"prefix": "
|
|
211
|
+
"prefix": re.compile(r"^!!output1\s+Total boundary outflow\s*:(.*)"),
|
|
207
212
|
"data_type": "last",
|
|
208
213
|
"split": "m3",
|
|
214
|
+
"use_regex": True,
|
|
209
215
|
},
|
|
210
216
|
"total_lat_link_inflow": {
|
|
211
217
|
"class": FloatSplitParser,
|
|
212
|
-
"prefix": "
|
|
218
|
+
"prefix": re.compile(r"^!!output1\s+Total lat. link inflow\s*:(.*)"),
|
|
213
219
|
"data_type": "last",
|
|
214
220
|
"split": "m3",
|
|
221
|
+
"use_regex": True,
|
|
215
222
|
},
|
|
216
223
|
"total_lat_link_outflow": {
|
|
217
224
|
"class": FloatSplitParser,
|
|
218
|
-
"prefix": "
|
|
225
|
+
"prefix": re.compile(r"^!!output1\s+Total lat. link outflow\s*:(.*)"),
|
|
219
226
|
"data_type": "last",
|
|
220
227
|
"split": "m3",
|
|
228
|
+
"use_regex": True,
|
|
221
229
|
},
|
|
222
230
|
"max_system_volume": {
|
|
223
231
|
"class": FloatSplitParser,
|
|
224
|
-
"prefix": "
|
|
232
|
+
"prefix": re.compile(r"^!!output1\s+Max. system volume\s*:(.*)"),
|
|
225
233
|
"data_type": "last",
|
|
226
234
|
"split": "m3",
|
|
235
|
+
"use_regex": True,
|
|
227
236
|
},
|
|
228
237
|
"max_volume_increase": {
|
|
229
238
|
"class": FloatSplitParser,
|
|
230
|
-
"prefix": "
|
|
239
|
+
"prefix": re.compile(r"^!!output1\s+Max. \|volume\| increase\s*:(.*)"),
|
|
231
240
|
"data_type": "last",
|
|
232
241
|
"split": "m3",
|
|
242
|
+
"use_regex": True,
|
|
233
243
|
},
|
|
234
244
|
"max_boundary_inflow": {
|
|
235
245
|
"class": FloatSplitParser,
|
|
236
|
-
"prefix": "
|
|
246
|
+
"prefix": re.compile(r"^!!output1\s+Max. boundary inflow\s*:(.*)"),
|
|
237
247
|
"data_type": "last",
|
|
238
248
|
"split": "m3",
|
|
249
|
+
"use_regex": True,
|
|
239
250
|
},
|
|
240
251
|
"max_boundary_outflow": {
|
|
241
252
|
"class": FloatSplitParser,
|
|
242
|
-
"prefix": "
|
|
253
|
+
"prefix": re.compile(r"^!!output1\s+Max. boundary outflow\s*:(.*)"),
|
|
243
254
|
"data_type": "last",
|
|
244
255
|
"split": "m3",
|
|
256
|
+
"use_regex": True,
|
|
245
257
|
},
|
|
246
258
|
"net_volume_increase": {
|
|
247
259
|
"class": FloatSplitParser,
|
|
248
|
-
"prefix": "
|
|
260
|
+
"prefix": re.compile(r"^!!output1\s+Net increase in volume\s*:(.*)"),
|
|
249
261
|
"data_type": "last",
|
|
250
262
|
"split": "m3",
|
|
263
|
+
"use_regex": True,
|
|
251
264
|
},
|
|
252
265
|
"net_inflow_volume": {
|
|
253
266
|
"class": FloatSplitParser,
|
|
254
|
-
"prefix": "
|
|
267
|
+
"prefix": re.compile(r"^!!output1\s+Net inflow volume\s*:(.*)"),
|
|
255
268
|
"data_type": "last",
|
|
256
269
|
"split": "m3",
|
|
270
|
+
"use_regex": True,
|
|
257
271
|
},
|
|
258
272
|
"volume_discrepancy": {
|
|
259
273
|
"class": FloatSplitParser,
|
|
260
|
-
"prefix": "
|
|
274
|
+
"prefix": re.compile(r"^!!output1\s+Volume discrepancy\s*:(.*)"),
|
|
261
275
|
"data_type": "last",
|
|
262
276
|
"split": "m3",
|
|
277
|
+
"use_regex": True,
|
|
263
278
|
},
|
|
264
279
|
"mass_balance_error": {
|
|
265
280
|
"class": FloatSplitParser,
|
|
266
|
-
"prefix": "
|
|
281
|
+
"prefix": re.compile(r"^!!output1\s+Mass balance error\s*:(.*)"),
|
|
267
282
|
"data_type": "last",
|
|
268
283
|
"split": "%",
|
|
284
|
+
"use_regex": True,
|
|
269
285
|
},
|
|
270
286
|
"mass_balance_error_2": {
|
|
271
287
|
"class": FloatSplitParser,
|
|
272
|
-
"prefix": "
|
|
288
|
+
"prefix": re.compile(r"^!!output1\s+Mass balance error \[2\]\s*:(.*)"),
|
|
273
289
|
"data_type": "last",
|
|
274
290
|
"split": "%",
|
|
291
|
+
"use_regex": True,
|
|
275
292
|
},
|
|
276
293
|
"tuflow_start_time": {
|
|
277
294
|
"class": FloatParser,
|
|
@@ -453,43 +470,51 @@ lf2_data_to_extract = {
|
|
|
453
470
|
},
|
|
454
471
|
"timestep": {
|
|
455
472
|
"class": FloatParser,
|
|
456
|
-
"prefix": "
|
|
473
|
+
"prefix": re.compile(r"^!!output2\s+Model timestep\s*:(.*)"),
|
|
457
474
|
"data_type": "last",
|
|
475
|
+
"use_regex": True,
|
|
458
476
|
},
|
|
459
477
|
"wetting_drying_depth": {
|
|
460
478
|
"class": FloatParser,
|
|
461
|
-
"prefix": "
|
|
479
|
+
"prefix": re.compile(r"^!!output2\s+Wetting/drying depth\s*:(.*)"),
|
|
462
480
|
"data_type": "last",
|
|
481
|
+
"use_regex": True,
|
|
463
482
|
},
|
|
464
483
|
"beta": {
|
|
465
484
|
"class": FloatParser,
|
|
466
|
-
"prefix": "
|
|
485
|
+
"prefix": re.compile(r"^!!output2\s+Beta\s*:(.*)"),
|
|
467
486
|
"data_type": "last",
|
|
487
|
+
"use_regex": True,
|
|
468
488
|
},
|
|
469
489
|
"number_of_iterations": {
|
|
470
490
|
"class": FloatParser,
|
|
471
|
-
"prefix": "
|
|
491
|
+
"prefix": re.compile(r"^!!output2\s+Number of iterations\s*:(.*)"),
|
|
472
492
|
"data_type": "last",
|
|
493
|
+
"use_regex": True,
|
|
473
494
|
},
|
|
474
495
|
"calculation_depth": {
|
|
475
496
|
"class": FloatParser,
|
|
476
|
-
"prefix": "
|
|
497
|
+
"prefix": re.compile(r"^!!output2\s+Calculation depth\s*:(.*)"),
|
|
477
498
|
"data_type": "last",
|
|
499
|
+
"use_regex": True,
|
|
478
500
|
},
|
|
479
501
|
"friction_depth": {
|
|
480
502
|
"class": FloatParser,
|
|
481
|
-
"prefix": "
|
|
503
|
+
"prefix": re.compile(r"^!!output2\s+Friction depth\s*:(.*)"),
|
|
482
504
|
"data_type": "last",
|
|
505
|
+
"use_regex": True,
|
|
483
506
|
},
|
|
484
507
|
"eddy_viscosity": {
|
|
485
508
|
"class": FloatParser,
|
|
486
|
-
"prefix": "
|
|
509
|
+
"prefix": re.compile(r"^!!output2\s+Eddy Viscosity\s*:(.*)"),
|
|
487
510
|
"data_type": "last",
|
|
511
|
+
"use_regex": True,
|
|
488
512
|
},
|
|
489
513
|
"velocity_head_threshold": {
|
|
490
514
|
"class": FloatParser,
|
|
491
|
-
"prefix": "
|
|
515
|
+
"prefix": re.compile(r"^!!output2\s+Velocity head threshold\s*:(.*)"),
|
|
492
516
|
"data_type": "last",
|
|
517
|
+
"use_regex": True,
|
|
493
518
|
},
|
|
494
519
|
"rainfall_accumulation_depth": {
|
|
495
520
|
"class": FloatParser,
|
|
@@ -498,8 +523,9 @@ lf2_data_to_extract = {
|
|
|
498
523
|
},
|
|
499
524
|
"negative_depth_threshold": {
|
|
500
525
|
"class": FloatParser,
|
|
501
|
-
"prefix": "
|
|
526
|
+
"prefix": re.compile(r"^!!output2\s+Negative depth threshold\s*:(.*)"),
|
|
502
527
|
"data_type": "last",
|
|
528
|
+
"use_regex": True,
|
|
503
529
|
},
|
|
504
530
|
"memory_use_estimate": {
|
|
505
531
|
"class": FloatSplitParser,
|
|
@@ -509,8 +535,9 @@ lf2_data_to_extract = {
|
|
|
509
535
|
},
|
|
510
536
|
"friction_depth_threshold": {
|
|
511
537
|
"class": FloatParser,
|
|
512
|
-
"prefix": "
|
|
538
|
+
"prefix": re.compile(r"^!!output2\s+Friction depth threshold\s*:(.*)"),
|
|
513
539
|
"data_type": "last",
|
|
540
|
+
"use_regex": True,
|
|
514
541
|
},
|
|
515
542
|
"number_of_cells": {
|
|
516
543
|
"class": FloatParser,
|
|
@@ -529,8 +556,9 @@ lf2_data_to_extract = {
|
|
|
529
556
|
},
|
|
530
557
|
"final_mass_error": {
|
|
531
558
|
"class": FloatSplitParser,
|
|
532
|
-
"prefix": "
|
|
559
|
+
"prefix": re.compile(r"^!!output2\s+Final mass error\s*:(.*)"),
|
|
533
560
|
"data_type": "last",
|
|
561
|
+
"use_regex": True,
|
|
534
562
|
"split": "%",
|
|
535
563
|
},
|
|
536
564
|
"combined_mass_error": {
|
floodmodeller_api/mapping.py
CHANGED
|
@@ -13,6 +13,7 @@ from .units import (
|
|
|
13
13
|
CRUMP,
|
|
14
14
|
CULVERT,
|
|
15
15
|
FLAT_V_WEIR,
|
|
16
|
+
FLOODPLAIN,
|
|
16
17
|
HTBDY,
|
|
17
18
|
IIC,
|
|
18
19
|
INTERPOLATE,
|
|
@@ -81,6 +82,7 @@ api_class_mapping: dict[str, Any] = {
|
|
|
81
82
|
"floodmodeller_api.units.sections.INTERPOLATE": INTERPOLATE,
|
|
82
83
|
"floodmodeller_api.units.sections.REPLICATE": REPLICATE,
|
|
83
84
|
"floodmodeller_api.units.sections.RIVER": RIVER,
|
|
85
|
+
"floodmodeller_api.units.structures.FLOODPLAIN": FLOODPLAIN,
|
|
84
86
|
"floodmodeller_api.units.structures.BRIDGE": BRIDGE,
|
|
85
87
|
"floodmodeller_api.units.structures.CRUMP": CRUMP,
|
|
86
88
|
"floodmodeller_api.units.structures.FLAT_V_WEIR": FLAT_V_WEIR,
|
|
@@ -202,7 +202,7 @@ def test_diff(test_workspace, caplog):
|
|
|
202
202
|
dat_ex4.diff(dat_ex4_changed)
|
|
203
203
|
|
|
204
204
|
assert caplog.text == (
|
|
205
|
-
"INFO root:_base.py:
|
|
205
|
+
"INFO root:_base.py:141 Files not equivalent, 12 difference(s) found:\n"
|
|
206
206
|
" DAT->structures->MILLAu->RNWEIR..MILLAu->upstream_crest_height: 1.07 != 1.37\n"
|
|
207
207
|
" DAT->structures->MILLBu->RNWEIR..MILLBu->upstream_crest_height: 0.43 != 0.73\n"
|
|
208
208
|
" DAT->structures->ROAD1->RNWEIR..ROAD1->upstream_crest_height: 2.02 != 2.32\n"
|
|
@@ -218,6 +218,18 @@ def test_diff(test_workspace, caplog):
|
|
|
218
218
|
)
|
|
219
219
|
|
|
220
220
|
|
|
221
|
+
def test_diff_active_data(test_workspace):
|
|
222
|
+
dat = DAT(Path(test_workspace, "ex4.DAT"))
|
|
223
|
+
dat_copy = DAT(Path(test_workspace, "ex4.DAT"))
|
|
224
|
+
assert dat == dat_copy
|
|
225
|
+
|
|
226
|
+
for section in dat.sections.values():
|
|
227
|
+
if section.unit == "RIVER":
|
|
228
|
+
_ = section.active_data
|
|
229
|
+
|
|
230
|
+
assert dat == dat_copy
|
|
231
|
+
|
|
232
|
+
|
|
221
233
|
def test_valid_network(test_workspace: Path):
|
|
222
234
|
"""Test against network derived manually."""
|
|
223
235
|
dat = DAT(test_workspace / "network.dat")
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
|
|
2
|
+
#REVISION#1
|
|
3
|
+
4 0.750 0.900 0.100 0.001 12SI
|
|
4
|
+
10.000 0.010 0.010 0.700 0.100 0.700 0.000
|
|
5
|
+
RAD FILE
|
|
6
|
+
|
|
7
|
+
END GENERAL
|
|
8
|
+
RIVER
|
|
9
|
+
SECTION
|
|
10
|
+
1
|
|
11
|
+
5.000 0.0001 1000
|
|
12
|
+
1
|
|
13
|
+
0.000 0.000 0.000 1.000 0.000 0.000
|
|
14
|
+
RIVER
|
|
15
|
+
SECTION
|
|
16
|
+
2
|
|
17
|
+
5.000 0.0001 1000
|
|
18
|
+
1
|
|
19
|
+
0.000 0.000 0.000 1.000 0.000 0.000
|
|
20
|
+
RIVER
|
|
21
|
+
SECTION
|
|
22
|
+
3
|
|
23
|
+
0.000 1000.000
|
|
24
|
+
1
|
|
25
|
+
0.000 0.000 0.000 1.000
|
|
26
|
+
FLOODPLAIN floodplain comment
|
|
27
|
+
SECTION
|
|
28
|
+
3 down
|
|
29
|
+
1.000 0.800 150.000 75.000 FRICTION 0.100
|
|
30
|
+
3
|
|
31
|
+
0.000 1.000 0.030 0.00 0.00
|
|
32
|
+
10.000 1.500 0.030 0.00 0.00
|
|
33
|
+
90.000 1.800 0.030 0.00 0.00
|
|
34
|
+
RIVER
|
|
35
|
+
SECTION
|
|
36
|
+
down
|
|
37
|
+
0.000 1000.000
|
|
38
|
+
1
|
|
39
|
+
0.000 0.000 0.000 1.000
|
|
40
|
+
INITIAL CONDITIONS
|
|
41
|
+
label ? flow stage froude no velocity umode ustate z
|
|
42
|
+
3 y 0.000 0.000 0.000 0.000 0.000 0.000 0.000
|
|
43
|
+
1 y 0.000 0.000 0.000 0.000 0.000 0.000 0.000
|
|
44
|
+
2 y 0.000 0.000 0.000 0.000 0.000 0.000 0.000
|
|
45
|
+
down y 0.000 0.000 0.000 0.000 0.000 0.000 0.000
|
|
46
|
+
GISINFO
|
|
47
|
+
RIVER SECTION 1 0 0 0 0 0
|
|
48
|
+
RIVER SECTION 2 0 0 0 0 0
|
|
49
|
+
RIVER SECTION 3 0 0 0 0 0
|
|
50
|
+
FLOODPLAIN SECTION 3 0 0 0 0 0
|
|
51
|
+
RIVER SECTION down 0 0 0 0 0
|
|
52
|
+
down 0 0 0 0 0
|