floodmodeller-api 0.4.2.post1__py3-none-any.whl → 0.4.4__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 +169 -176
- floodmodeller_api/backup.py +273 -273
- floodmodeller_api/dat.py +889 -831
- floodmodeller_api/diff.py +136 -119
- floodmodeller_api/ied.py +302 -306
- floodmodeller_api/ief.py +553 -637
- floodmodeller_api/ief_flags.py +253 -253
- floodmodeller_api/inp.py +260 -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 +364 -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 +16 -8
- floodmodeller_api/test/test_backup.py +117 -117
- floodmodeller_api/test/test_conveyance.py +107 -0
- floodmodeller_api/test/test_dat.py +222 -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/conveyance_test.dat +165 -0
- floodmodeller_api/test/test_data/conveyance_test.feb +116 -0
- floodmodeller_api/test/test_data/conveyance_test.gxy +85 -0
- 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/expected_conveyance.csv +60 -0
- 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 +136 -24
- floodmodeller_api/test/test_inp.py +47 -48
- floodmodeller_api/test/test_json.py +114 -0
- floodmodeller_api/test/test_logs_lf.py +102 -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 +230 -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/conveyance.py +301 -0
- 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 +465 -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 +119 -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 +632 -673
- floodmodeller_api/xml2d_template.py +37 -37
- floodmodeller_api/zzn.py +414 -363
- {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.4.dist-info}/LICENSE.txt +13 -13
- {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.4.dist-info}/METADATA +85 -82
- floodmodeller_api-0.4.4.dist-info/RECORD +185 -0
- {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.4.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.4.dist-info}/entry_points.txt +0 -0
- {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.4.dist-info}/top_level.txt +0 -0
|
@@ -1,467 +1,467 @@
|
|
|
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
|
-
import pandas as pd
|
|
18
|
-
|
|
19
|
-
from floodmodeller_api.validation import _validate_unit
|
|
20
|
-
|
|
21
|
-
from ._base import Unit
|
|
22
|
-
from .helpers import (
|
|
23
|
-
_to_data_list,
|
|
24
|
-
_to_float,
|
|
25
|
-
_to_int,
|
|
26
|
-
_to_str,
|
|
27
|
-
join_10_char,
|
|
28
|
-
join_n_char_ljust,
|
|
29
|
-
split_10_char,
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class QTBDY(Unit):
|
|
34
|
-
"""Class to hold and process QTBDY boundary type
|
|
35
|
-
|
|
36
|
-
Args:
|
|
37
|
-
name (str, optional): Unit name. Defaults to None.
|
|
38
|
-
comment (str, optional): Comment included in unit. Defaults to None.
|
|
39
|
-
timeoffset (float, optional): Defaults to None.
|
|
40
|
-
timeunit (str, optional): Unit of time, e.g. 'HOURS', 'MINUTES' or 'SECONDS'. See Flood Modeller documentation for all available options. Defaults to None.
|
|
41
|
-
extendmethod (str, optional): Data extending method: 'EXTEND', 'NOEXTEND' or 'REPEAT'. Defaults to None.
|
|
42
|
-
interpmethod (str, optional): Data interpolation method: 'LINEAR' or 'SPLINE'. Defaults to None.
|
|
43
|
-
flowmultiplier (float, optional): Multiplier applied to all flow values at runtime. Defaults to None.
|
|
44
|
-
minflow (Float, optional): Minimum flow value applied to the boundary at runtime. Defaults to None.
|
|
45
|
-
data (pandas.Series, optional): Series object with variable ``'Flow'`` and index ``'Time'``. Defaults to None.
|
|
46
|
-
allow_override (str): Allow event parameters to be overridden from simulation file: ''/'OVERRIDE' or 'NOOVERRIDE'
|
|
47
|
-
|
|
48
|
-
Returns:
|
|
49
|
-
QTBDY: Flood Modeller QTBDY Unit class object
|
|
50
|
-
"""
|
|
51
|
-
|
|
52
|
-
_unit = "QTBDY"
|
|
53
|
-
|
|
54
|
-
def _create_from_blank(
|
|
55
|
-
self,
|
|
56
|
-
name="new_qtbdy",
|
|
57
|
-
comment="",
|
|
58
|
-
timeoffset=0.0,
|
|
59
|
-
timeunit="HOURS",
|
|
60
|
-
extendmethod="EXTEND",
|
|
61
|
-
interpmethod="LINEAR",
|
|
62
|
-
flowmultiplier=0.0,
|
|
63
|
-
minflow=0.0,
|
|
64
|
-
allow_override="OVERRIDE",
|
|
65
|
-
_something=0.0,
|
|
66
|
-
data=None,
|
|
67
|
-
):
|
|
68
|
-
# Initiate new QTBDY
|
|
69
|
-
|
|
70
|
-
for param, val in {
|
|
71
|
-
"name": name,
|
|
72
|
-
"comment": comment,
|
|
73
|
-
"timeunit": timeunit,
|
|
74
|
-
"extendmethod": extendmethod,
|
|
75
|
-
"interpmethod": interpmethod,
|
|
76
|
-
"timeoffset": timeoffset,
|
|
77
|
-
"flowmultiplier": flowmultiplier,
|
|
78
|
-
"minflow": minflow,
|
|
79
|
-
"allow_override": allow_override,
|
|
80
|
-
"_something": _something,
|
|
81
|
-
}.items():
|
|
82
|
-
setattr(self, param, val)
|
|
83
|
-
|
|
84
|
-
# AL Since this is most likely used when building a model,
|
|
85
|
-
# AL it would be nice to have a "name generator" to create
|
|
86
|
-
# AL a unique name with each call (ie new_qtbdy_12345 then new_qtbdy_02508)
|
|
87
|
-
# JP Yes this is a good idea, although I'm not sure how it would be best implemented
|
|
88
|
-
# since any two instances of the class being initialised would be unaware of each other?
|
|
89
|
-
# There is always the option to pass a name when constrcuting the class which may be better
|
|
90
|
-
|
|
91
|
-
self.data = (
|
|
92
|
-
data
|
|
93
|
-
if isinstance(data, pd.Series)
|
|
94
|
-
else pd.Series([0.0, 0.0], index=[0.0, 0.1], name="Flow")
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
def _read(self, qtbdy_block):
|
|
98
|
-
"""Function to read a given QTBDY block and store data as class attributes"""
|
|
99
|
-
self.name = qtbdy_block[1][: self._label_len].strip()
|
|
100
|
-
self.comment = qtbdy_block[0].replace("QTBDY", "").strip()
|
|
101
|
-
qtbdy_params = split_10_char(f"{qtbdy_block[2]:<90}")
|
|
102
|
-
self.nrows = int(qtbdy_params[0])
|
|
103
|
-
self.timeoffset = _to_float(qtbdy_params[1])
|
|
104
|
-
self._something = _to_float(qtbdy_params[2])
|
|
105
|
-
self.timeunit = _to_str(qtbdy_params[3], "HOURS", check_float=True)
|
|
106
|
-
self.extendmethod = _to_str(qtbdy_params[4], "EXTEND")
|
|
107
|
-
self.interpmethod = _to_str(qtbdy_params[5], "LINEAR")
|
|
108
|
-
self.flowmultiplier = _to_float(qtbdy_params[6])
|
|
109
|
-
self.minflow = _to_float(qtbdy_params[7])
|
|
110
|
-
self.allow_override = _to_str(qtbdy_params[8], "OVERRIDE") # ''/OVERRIDE or NOOVERRIDE
|
|
111
|
-
data_list = (
|
|
112
|
-
_to_data_list(qtbdy_block[3:], date_col=1)
|
|
113
|
-
if self.timeunit == "DATES"
|
|
114
|
-
else _to_data_list(qtbdy_block[3:])
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
self.data = pd.DataFrame(data_list, columns=["Flow", "Time"])
|
|
118
|
-
self.data = self.data.set_index("Time")
|
|
119
|
-
self.data = self.data["Flow"] # Convert to series
|
|
120
|
-
|
|
121
|
-
def _write(self):
|
|
122
|
-
"""Function to write a valid QTBDY block"""
|
|
123
|
-
_validate_unit(self) # Function to check the params are valid for QTBDY
|
|
124
|
-
header = "QTBDY " + self.comment
|
|
125
|
-
name = self.name[: self._label_len]
|
|
126
|
-
self.nrows = len(self.data)
|
|
127
|
-
|
|
128
|
-
qtbdy_params = join_10_char(
|
|
129
|
-
self.nrows,
|
|
130
|
-
float(self.timeoffset),
|
|
131
|
-
float(self._something),
|
|
132
|
-
self.timeunit,
|
|
133
|
-
self.extendmethod,
|
|
134
|
-
self.interpmethod,
|
|
135
|
-
float(self.flowmultiplier),
|
|
136
|
-
float(self.minflow),
|
|
137
|
-
self.allow_override,
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
if self.timeunit == "DATES":
|
|
141
|
-
qtbdy_data = [join_10_char(q) + t for t, q in self.data.items()]
|
|
142
|
-
else:
|
|
143
|
-
qtbdy_data = [join_10_char(q, t) for t, q in self.data.items()]
|
|
144
|
-
qtbdy_block = [header, name, qtbdy_params]
|
|
145
|
-
qtbdy_block.extend(qtbdy_data)
|
|
146
|
-
|
|
147
|
-
return qtbdy_block
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
class HTBDY(Unit):
|
|
151
|
-
"""Class to hold and process HTBDY boundary type
|
|
152
|
-
|
|
153
|
-
Args:
|
|
154
|
-
name (str, optional): Unit name. Defaults to None.
|
|
155
|
-
comment (str, optional): Comment included in unit. Defaults to None.
|
|
156
|
-
timeunit (str, optional): Unit of time, e.g. 'HOURS', 'MINUTES' or 'SECONDS'. See Flood Modeller documentation for all available options. Defaults to None.
|
|
157
|
-
extendmethod (str, optional): Data extending method: 'EXTEND', 'NOEXTEND' or 'REPEAT'. Defaults to None.
|
|
158
|
-
interpmethod (str, optional): Data interpolation method: 'LINEAR' or 'SPLINE'. Defaults to None.
|
|
159
|
-
data (pandas.Series, optional): Series object with columns ``'Time'`` and ``'Stage'``. Defaults to None.
|
|
160
|
-
|
|
161
|
-
Returns:
|
|
162
|
-
HTBDY: Flood Modeller HTBDY Unit class object
|
|
163
|
-
"""
|
|
164
|
-
|
|
165
|
-
_unit = "HTBDY"
|
|
166
|
-
|
|
167
|
-
def _create_from_blank(
|
|
168
|
-
self,
|
|
169
|
-
name="new_htbdy",
|
|
170
|
-
comment="",
|
|
171
|
-
timeunit="HOURS",
|
|
172
|
-
extendmethod="EXTEND",
|
|
173
|
-
interpmethod="LINEAR",
|
|
174
|
-
data=None,
|
|
175
|
-
):
|
|
176
|
-
# Initiate new HTBDY
|
|
177
|
-
|
|
178
|
-
for param, val in {
|
|
179
|
-
"name": name,
|
|
180
|
-
"comment": comment,
|
|
181
|
-
"timeunit": timeunit,
|
|
182
|
-
"extendmethod": extendmethod,
|
|
183
|
-
"interpmethod": interpmethod,
|
|
184
|
-
"_something": "",
|
|
185
|
-
}.items():
|
|
186
|
-
setattr(self, param, val)
|
|
187
|
-
|
|
188
|
-
self.data = (
|
|
189
|
-
data
|
|
190
|
-
if isinstance(data, pd.Series)
|
|
191
|
-
else pd.Series([0.0, 0.0], index=[0.0, 0.1], name="Stage")
|
|
192
|
-
)
|
|
193
|
-
|
|
194
|
-
def _read(self, htbdy_block):
|
|
195
|
-
"""Function to read a given HTBDY block and store data as class attributes"""
|
|
196
|
-
self.name = htbdy_block[1][: self._label_len].strip()
|
|
197
|
-
self.comment = htbdy_block[0].replace("HTBDY", "").strip()
|
|
198
|
-
htbdy_params = split_10_char(f"{htbdy_block[2]:<50}")
|
|
199
|
-
self.nrows = int(htbdy_params[0])
|
|
200
|
-
self._something = _to_str(htbdy_params[1], "")
|
|
201
|
-
self.timeunit = _to_str(htbdy_params[2], "HOURS", check_float=True)
|
|
202
|
-
self.extendmethod = _to_str(htbdy_params[3], "EXTEND")
|
|
203
|
-
self.interpmethod = _to_str(htbdy_params[4], "LINEAR")
|
|
204
|
-
|
|
205
|
-
data_list = (
|
|
206
|
-
_to_data_list(htbdy_block[3:], date_col=1)
|
|
207
|
-
if self.timeunit == "DATES"
|
|
208
|
-
else _to_data_list(htbdy_block[3:])
|
|
209
|
-
)
|
|
210
|
-
|
|
211
|
-
self.data = pd.DataFrame(data_list, columns=["Stage", "Time"])
|
|
212
|
-
self.data = self.data.set_index("Time")
|
|
213
|
-
self.data = self.data["Stage"] # Convert to series
|
|
214
|
-
|
|
215
|
-
def _write(self):
|
|
216
|
-
"""Function to write a valid HTBDY block"""
|
|
217
|
-
_validate_unit(self) # Function to check the params are valid for HTBDY
|
|
218
|
-
header = "HTBDY " + self.comment
|
|
219
|
-
name = self.name
|
|
220
|
-
self.nrows = len(self.data)
|
|
221
|
-
|
|
222
|
-
htbdy_params = join_10_char(
|
|
223
|
-
self.nrows,
|
|
224
|
-
self._something,
|
|
225
|
-
self.timeunit,
|
|
226
|
-
self.extendmethod,
|
|
227
|
-
self.interpmethod,
|
|
228
|
-
)
|
|
229
|
-
if self.timeunit == "DATES":
|
|
230
|
-
htbdy_data = [join_10_char(h) + t for t, h in self.data.items()]
|
|
231
|
-
else:
|
|
232
|
-
htbdy_data = [join_10_char(h, t) for t, h in self.data.items()]
|
|
233
|
-
htbdy_block = [header, name, htbdy_params]
|
|
234
|
-
htbdy_block.extend(htbdy_data)
|
|
235
|
-
|
|
236
|
-
return htbdy_block
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
class QHBDY(Unit):
|
|
240
|
-
"""Class to hold and process QHBDY boundary type
|
|
241
|
-
|
|
242
|
-
Args:
|
|
243
|
-
name (str, optional): Unit name. Defaults to None.
|
|
244
|
-
comment (str, optional): Comment included in unit. Defaults to None.
|
|
245
|
-
interpmethod (str, optional): Data interpolation method: 'LINEAR' or 'SPLINE'. Defaults to None.
|
|
246
|
-
data (pandas.Series, optional): Series object with columns ``'Flow'`` and ``'Stage'``. Defaults to None.
|
|
247
|
-
Returns:
|
|
248
|
-
QHBDY: Flood Modeller QHBDY Unit class object
|
|
249
|
-
"""
|
|
250
|
-
|
|
251
|
-
_unit = "QHBDY"
|
|
252
|
-
|
|
253
|
-
def _create_from_blank(self, name="new_qhbdy", comment="", interpmethod="LINEAR", data=None):
|
|
254
|
-
# Initiate new QHBDY
|
|
255
|
-
for param, val in {
|
|
256
|
-
"name": name,
|
|
257
|
-
"comment": comment,
|
|
258
|
-
"interpmethod": interpmethod,
|
|
259
|
-
}.items():
|
|
260
|
-
setattr(self, param, val)
|
|
261
|
-
self.data = (
|
|
262
|
-
data
|
|
263
|
-
if isinstance(data, pd.Series)
|
|
264
|
-
else pd.Series([0.0, 0.0], index=[0.0, 0.1], name="Stage")
|
|
265
|
-
)
|
|
266
|
-
|
|
267
|
-
def _read(self, qhbdy_block):
|
|
268
|
-
"""Function to read a given QHBDY block and store data as class attributes"""
|
|
269
|
-
self.name = qhbdy_block[1][: self._label_len].strip()
|
|
270
|
-
self.comment = qhbdy_block[0].replace("QHBDY", "").strip()
|
|
271
|
-
qhbdy_params = split_10_char(f"{qhbdy_block[2]:<30}")
|
|
272
|
-
self.nrows = int(qhbdy_params[0])
|
|
273
|
-
self.interpmethod = _to_str(qhbdy_params[2], "LINEAR")
|
|
274
|
-
|
|
275
|
-
data_list = _to_data_list(qhbdy_block[3:])
|
|
276
|
-
|
|
277
|
-
self.data = pd.DataFrame(data_list, columns=["Flow", "Stage"])
|
|
278
|
-
self.data = self.data.set_index("Stage")
|
|
279
|
-
self.data = self.data["Flow"] # Convert to series
|
|
280
|
-
|
|
281
|
-
def _write(self):
|
|
282
|
-
"""Function to write a valid QHBDY block"""
|
|
283
|
-
_validate_unit(self) # Function to check the params are valid for QHBDY
|
|
284
|
-
header = "QHBDY " + self.comment
|
|
285
|
-
name = self.name
|
|
286
|
-
self.nrows = len(self.data)
|
|
287
|
-
|
|
288
|
-
qhbdy_params = join_10_char(self.nrows, 0.000, self.interpmethod)
|
|
289
|
-
qhbdy_data = [f"{q:>10.3f}{h:>10.3f}" for h, q in self.data.items()]
|
|
290
|
-
qhbdy_block = [header, name, qhbdy_params]
|
|
291
|
-
qhbdy_block.extend(qhbdy_data)
|
|
292
|
-
|
|
293
|
-
return qhbdy_block
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
class REFHBDY(Unit):
|
|
297
|
-
"""Class to hold and process REFHBDY boundary type
|
|
298
|
-
|
|
299
|
-
Currently REFHBDY Units are read/edit only and cannot be created from scratch, therefore the
|
|
300
|
-
parameters below are only accessible upon instantiating a REFHBDY object from an existing
|
|
301
|
-
unit.
|
|
302
|
-
|
|
303
|
-
Args:
|
|
304
|
-
name (str): Unit name.
|
|
305
|
-
comment (str): Comment included in unit.
|
|
306
|
-
easting (int): Easting (m)
|
|
307
|
-
northing (int): Northing (m)
|
|
308
|
-
return_period(float): Flood return period (yrs)
|
|
309
|
-
time_delay (float): Time delay before start of hydrograph (hrs)
|
|
310
|
-
timestep (float): Time interval for unit hydrograph and rainfall profile
|
|
311
|
-
sim_type (str): Simulation Type required: 'FULL' (full hydrograph), 'PFONLY' (peak flow) or 'BFONLY' (baseflow)
|
|
312
|
-
scale_method (str): Hydrograph scaling method: 'PEAKVALUE' or 'SCALEFACT'
|
|
313
|
-
scale_value (float): Scaling value
|
|
314
|
-
boundary_type (str): Boundary type: 'HYDROGRAPH' or 'HYETOGRAPH'
|
|
315
|
-
scale_type (str): Full generated hydrograph or quick runnof component only: 'FULL' or 'RUNOFF'
|
|
316
|
-
minflow (float): Minimum flow value
|
|
317
|
-
allow_override (str): Allow event parameters to be overridden from simulation file: ''/'OVERRIDE' or 'NOOVERRIDE'
|
|
318
|
-
area (float): Catchment area (sq km)
|
|
319
|
-
saar (int): Seasonal average annual rainfall (mm)
|
|
320
|
-
urbext (float): Fraction of urbanised catchment area
|
|
321
|
-
season (str): Season for design rainfall profile: 'DEFAULT', 'SUMMER' or 'WINTER'
|
|
322
|
-
calc_source (str): ReFH calculation source: 'DLL' (recommended) or 'REPORT'
|
|
323
|
-
storm_area (float): Rainfall storm area (sq km)
|
|
324
|
-
storm_duration (float): Rainfall storm duration (hrs)
|
|
325
|
-
rainfall_comment (str): Comment added to rainfall section of unit
|
|
326
|
-
arf_method (str): Method for defining ARF: 'USER' or 'DESIGN'
|
|
327
|
-
arf (float): Areal reduction factor (only used if ``arf_method`` set to 'USER')
|
|
328
|
-
ddf_c (float): DDF Parameter c
|
|
329
|
-
ddf_d1 (float): DDF Parameter d1
|
|
330
|
-
ddf_d2 (float): DDF Parameter d2
|
|
331
|
-
ddf_d3 (float): DDF Parameter d3
|
|
332
|
-
ddf_e (float): DDF Parameter e
|
|
333
|
-
ddf_f (float): DDF Parameter f
|
|
334
|
-
|
|
335
|
-
Returns:
|
|
336
|
-
REFHBDY: Flood Modeller REFHBDY Unit class object
|
|
337
|
-
"""
|
|
338
|
-
|
|
339
|
-
_unit = "REFHBDY"
|
|
340
|
-
|
|
341
|
-
def _read(self, refhbdy_block):
|
|
342
|
-
"""Function to read a given REFHBDY block and store data as class attributes"""
|
|
343
|
-
# line 1 & 2
|
|
344
|
-
# Extract comment and revision number
|
|
345
|
-
b = refhbdy_block[0].replace("REFHBDY #revision#", "").strip()
|
|
346
|
-
self._revision = _to_int(b[0], 1)
|
|
347
|
-
self.comment = b[1:].strip()
|
|
348
|
-
self.name = refhbdy_block[1][: self._label_len].strip()
|
|
349
|
-
|
|
350
|
-
# line 3
|
|
351
|
-
refhbdy_params1 = split_10_char(refhbdy_block[2])
|
|
352
|
-
# TODO: work out what this is
|
|
353
|
-
self._something = _to_float(refhbdy_params1[0])
|
|
354
|
-
self.easting = int(float(refhbdy_params1[1]))
|
|
355
|
-
self.northing = int(float(refhbdy_params1[2]))
|
|
356
|
-
|
|
357
|
-
# line 4
|
|
358
|
-
refhbdy_opts = split_10_char(f"{refhbdy_block[3]:<90}")
|
|
359
|
-
self.time_delay = _to_float(refhbdy_opts[0])
|
|
360
|
-
# SD / timestep must be odd interval
|
|
361
|
-
self.timestep = _to_float(refhbdy_opts[1])
|
|
362
|
-
# '' : Full hydrograph, 'pfonly' : peak flow, 'bfonly' : baseflow only
|
|
363
|
-
self.sim_type = refhbdy_opts[2]
|
|
364
|
-
self.scale_method = _to_str(refhbdy_opts[3], "SCALEFACT") # PEAKVALUE or SCALEFACT
|
|
365
|
-
self.scale_value = _to_float(refhbdy_opts[4], 1.0)
|
|
366
|
-
self.boundary_type = _to_str(refhbdy_opts[5], "HYDROGRAPH") # HYDROGRAPH or HYETOGRAPH
|
|
367
|
-
self.scale_type = _to_str(refhbdy_opts[6], "FULL") # FULL or RUNOFF
|
|
368
|
-
self.minflow = _to_float(refhbdy_opts[7])
|
|
369
|
-
self.allow_override = refhbdy_opts[8] # ''/OVERRIDE or NOOVERRIDE
|
|
370
|
-
|
|
371
|
-
# line 5
|
|
372
|
-
refhbdy_params2 = split_10_char(f"{refhbdy_block[4]:<60}")
|
|
373
|
-
self.area = _to_float(refhbdy_params2[0])
|
|
374
|
-
try:
|
|
375
|
-
# Maintain SAAR as integer if already is, else use float
|
|
376
|
-
self.saar = int(refhbdy_params2[1])
|
|
377
|
-
except ValueError:
|
|
378
|
-
self.saar = float(refhbdy_params2[1])
|
|
379
|
-
self.urbext = _to_float(refhbdy_params2[2])
|
|
380
|
-
self.season = _to_str(refhbdy_params2[3], "DEFAULT") # DEFAULT, SUMMER or WINTER
|
|
381
|
-
self.calc_source = _to_str(refhbdy_params2[4], "DLL") # DLL or REPORT
|
|
382
|
-
self.use_urban_subdivisions =
|
|
383
|
-
if self.use_urban_subdivisions:
|
|
384
|
-
# Just keeping this raw for now as unlikely to be used.
|
|
385
|
-
self._urban_refh_data = refhbdy_block[5:8]
|
|
386
|
-
rainfall_params1, rainfall_params2, rainfall_params3 = refhbdy_block[8:11]
|
|
387
|
-
# Keeping rest raw for now to reduce dev time
|
|
388
|
-
self._raw_extra_lines = refhbdy_block[11:]
|
|
389
|
-
else:
|
|
390
|
-
rainfall_params1, rainfall_params2, rainfall_params3 = refhbdy_block[5:8]
|
|
391
|
-
# Keeping rest raw for now to reduce dev time
|
|
392
|
-
self._raw_extra_lines = refhbdy_block[8:]
|
|
393
|
-
|
|
394
|
-
# line 6
|
|
395
|
-
rainfall_params1 = split_10_char(rainfall_params1)
|
|
396
|
-
self.storm_area = _to_float(rainfall_params1[0])
|
|
397
|
-
self.storm_duration = _to_float(rainfall_params1[1])
|
|
398
|
-
# TODO: work out what this is
|
|
399
|
-
self._something2 = _to_float(rainfall_params1[2])
|
|
400
|
-
|
|
401
|
-
# line 7
|
|
402
|
-
self.rainfall_comment = rainfall_params2[20:]
|
|
403
|
-
rainfall_params2 = split_10_char(rainfall_params2[:20])
|
|
404
|
-
self.arf_method = rainfall_params2[1]
|
|
405
|
-
self._something3 = rainfall_params2[0] # TODO: work out what this is
|
|
406
|
-
|
|
407
|
-
# line 8
|
|
408
|
-
rainfall_params3 = split_10_char(rainfall_params3)
|
|
409
|
-
self.observed_rainfall_depth = _to_float(rainfall_params3[0])
|
|
410
|
-
self.return_period = _to_float(rainfall_params3[1])
|
|
411
|
-
self.arf = _to_float(rainfall_params3[2])
|
|
412
|
-
self.ddf_c = _to_float(rainfall_params3[3])
|
|
413
|
-
self.ddf_d1 = _to_float(rainfall_params3[4])
|
|
414
|
-
self.ddf_d2 = _to_float(rainfall_params3[5])
|
|
415
|
-
self.ddf_d3 = _to_float(rainfall_params3[6])
|
|
416
|
-
self.ddf_e = _to_float(rainfall_params3[7])
|
|
417
|
-
self.ddf_f = _to_float(rainfall_params3[8])
|
|
418
|
-
|
|
419
|
-
def _write(self):
|
|
420
|
-
"""Function to write a valid REFHBDY block"""
|
|
421
|
-
_validate_unit(self) # Function to check the params are valid for QTBDY
|
|
422
|
-
header = f"REFHBDY #revision#{self._revision} {self.comment}"
|
|
423
|
-
name = self.name[: self._label_len]
|
|
424
|
-
|
|
425
|
-
refhbdy_block = [header, name]
|
|
426
|
-
line3 = join_10_char(self._something, self.easting, self.northing)
|
|
427
|
-
self.sim_type = (
|
|
428
|
-
"" if self.sim_type.upper() == "FULL" else self.sim_type
|
|
429
|
-
) # Allow 'full' as an option
|
|
430
|
-
line4 = (
|
|
431
|
-
join_10_char(self.time_delay, self.timestep)
|
|
432
|
-
+ join_n_char_ljust(10, self.sim_type, self.scale_method)
|
|
433
|
-
+ join_10_char(self.scale_value)
|
|
434
|
-
+ join_n_char_ljust(10, self.boundary_type)
|
|
435
|
-
+ join_10_char(self.scale_type, self.minflow, self.allow_override)
|
|
436
|
-
)
|
|
437
|
-
use_urban_subdivisions = "" if not self.use_urban_subdivisions else "URBANREFH"
|
|
438
|
-
line5 = join_10_char(
|
|
439
|
-
self.area,
|
|
440
|
-
self.saar,
|
|
441
|
-
f"{self.urbext:.4f}",
|
|
442
|
-
self.season,
|
|
443
|
-
self.calc_source,
|
|
444
|
-
use_urban_subdivisions,
|
|
445
|
-
)
|
|
446
|
-
refhbdy_block.extend([line3, line4, line5])
|
|
447
|
-
|
|
448
|
-
if self.use_urban_subdivisions:
|
|
449
|
-
refhbdy_block.extend(self._urban_refh_data)
|
|
450
|
-
|
|
451
|
-
line6 = join_10_char(self.storm_area, self.storm_duration, self._something2)
|
|
452
|
-
line7 = join_10_char(self._something3, self.arf_method) + self.rainfall_comment
|
|
453
|
-
line8 = join_10_char(
|
|
454
|
-
self.observed_rainfall_depth,
|
|
455
|
-
self.return_period,
|
|
456
|
-
self.arf,
|
|
457
|
-
f"{self.ddf_c:.4f}",
|
|
458
|
-
f"{self.ddf_d1:.5f}",
|
|
459
|
-
f"{self.ddf_d2:.5f}",
|
|
460
|
-
f"{self.ddf_d3:.5f}",
|
|
461
|
-
f"{self.ddf_e:.5f}",
|
|
462
|
-
f"{self.ddf_f:.5f}",
|
|
463
|
-
)
|
|
464
|
-
|
|
465
|
-
refhbdy_block.extend([line6, line7, line8])
|
|
466
|
-
refhbdy_block.extend(self._raw_extra_lines)
|
|
467
|
-
return refhbdy_block
|
|
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
|
+
import pandas as pd
|
|
18
|
+
|
|
19
|
+
from floodmodeller_api.validation import _validate_unit
|
|
20
|
+
|
|
21
|
+
from ._base import Unit
|
|
22
|
+
from .helpers import (
|
|
23
|
+
_to_data_list,
|
|
24
|
+
_to_float,
|
|
25
|
+
_to_int,
|
|
26
|
+
_to_str,
|
|
27
|
+
join_10_char,
|
|
28
|
+
join_n_char_ljust,
|
|
29
|
+
split_10_char,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class QTBDY(Unit):
|
|
34
|
+
"""Class to hold and process QTBDY boundary type
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
name (str, optional): Unit name. Defaults to None.
|
|
38
|
+
comment (str, optional): Comment included in unit. Defaults to None.
|
|
39
|
+
timeoffset (float, optional): Defaults to None.
|
|
40
|
+
timeunit (str, optional): Unit of time, e.g. 'HOURS', 'MINUTES' or 'SECONDS'. See Flood Modeller documentation for all available options. Defaults to None.
|
|
41
|
+
extendmethod (str, optional): Data extending method: 'EXTEND', 'NOEXTEND' or 'REPEAT'. Defaults to None.
|
|
42
|
+
interpmethod (str, optional): Data interpolation method: 'LINEAR' or 'SPLINE'. Defaults to None.
|
|
43
|
+
flowmultiplier (float, optional): Multiplier applied to all flow values at runtime. Defaults to None.
|
|
44
|
+
minflow (Float, optional): Minimum flow value applied to the boundary at runtime. Defaults to None.
|
|
45
|
+
data (pandas.Series, optional): Series object with variable ``'Flow'`` and index ``'Time'``. Defaults to None.
|
|
46
|
+
allow_override (str): Allow event parameters to be overridden from simulation file: ''/'OVERRIDE' or 'NOOVERRIDE'
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
QTBDY: Flood Modeller QTBDY Unit class object
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
_unit = "QTBDY"
|
|
53
|
+
|
|
54
|
+
def _create_from_blank( # noqa: PLR0913
|
|
55
|
+
self,
|
|
56
|
+
name="new_qtbdy",
|
|
57
|
+
comment="",
|
|
58
|
+
timeoffset=0.0,
|
|
59
|
+
timeunit="HOURS",
|
|
60
|
+
extendmethod="EXTEND",
|
|
61
|
+
interpmethod="LINEAR",
|
|
62
|
+
flowmultiplier=0.0,
|
|
63
|
+
minflow=0.0,
|
|
64
|
+
allow_override="OVERRIDE",
|
|
65
|
+
_something=0.0,
|
|
66
|
+
data=None,
|
|
67
|
+
):
|
|
68
|
+
# Initiate new QTBDY
|
|
69
|
+
|
|
70
|
+
for param, val in {
|
|
71
|
+
"name": name,
|
|
72
|
+
"comment": comment,
|
|
73
|
+
"timeunit": timeunit,
|
|
74
|
+
"extendmethod": extendmethod,
|
|
75
|
+
"interpmethod": interpmethod,
|
|
76
|
+
"timeoffset": timeoffset,
|
|
77
|
+
"flowmultiplier": flowmultiplier,
|
|
78
|
+
"minflow": minflow,
|
|
79
|
+
"allow_override": allow_override,
|
|
80
|
+
"_something": _something,
|
|
81
|
+
}.items():
|
|
82
|
+
setattr(self, param, val)
|
|
83
|
+
|
|
84
|
+
# AL Since this is most likely used when building a model,
|
|
85
|
+
# AL it would be nice to have a "name generator" to create
|
|
86
|
+
# AL a unique name with each call (ie new_qtbdy_12345 then new_qtbdy_02508)
|
|
87
|
+
# JP Yes this is a good idea, although I'm not sure how it would be best implemented
|
|
88
|
+
# since any two instances of the class being initialised would be unaware of each other?
|
|
89
|
+
# There is always the option to pass a name when constrcuting the class which may be better
|
|
90
|
+
|
|
91
|
+
self.data = (
|
|
92
|
+
data
|
|
93
|
+
if isinstance(data, pd.Series)
|
|
94
|
+
else pd.Series([0.0, 0.0], index=[0.0, 0.1], name="Flow")
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
def _read(self, qtbdy_block):
|
|
98
|
+
"""Function to read a given QTBDY block and store data as class attributes"""
|
|
99
|
+
self.name = qtbdy_block[1][: self._label_len].strip()
|
|
100
|
+
self.comment = qtbdy_block[0].replace("QTBDY", "").strip()
|
|
101
|
+
qtbdy_params = split_10_char(f"{qtbdy_block[2]:<90}")
|
|
102
|
+
self.nrows = int(qtbdy_params[0])
|
|
103
|
+
self.timeoffset = _to_float(qtbdy_params[1])
|
|
104
|
+
self._something = _to_float(qtbdy_params[2])
|
|
105
|
+
self.timeunit = _to_str(qtbdy_params[3], "HOURS", check_float=True)
|
|
106
|
+
self.extendmethod = _to_str(qtbdy_params[4], "EXTEND")
|
|
107
|
+
self.interpmethod = _to_str(qtbdy_params[5], "LINEAR")
|
|
108
|
+
self.flowmultiplier = _to_float(qtbdy_params[6])
|
|
109
|
+
self.minflow = _to_float(qtbdy_params[7])
|
|
110
|
+
self.allow_override = _to_str(qtbdy_params[8], "OVERRIDE") # ''/OVERRIDE or NOOVERRIDE
|
|
111
|
+
data_list = (
|
|
112
|
+
_to_data_list(qtbdy_block[3:], date_col=1)
|
|
113
|
+
if self.timeunit == "DATES"
|
|
114
|
+
else _to_data_list(qtbdy_block[3:])
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
self.data = pd.DataFrame(data_list, columns=["Flow", "Time"])
|
|
118
|
+
self.data = self.data.set_index("Time")
|
|
119
|
+
self.data = self.data["Flow"] # Convert to series
|
|
120
|
+
|
|
121
|
+
def _write(self):
|
|
122
|
+
"""Function to write a valid QTBDY block"""
|
|
123
|
+
_validate_unit(self) # Function to check the params are valid for QTBDY
|
|
124
|
+
header = "QTBDY " + self.comment
|
|
125
|
+
name = self.name[: self._label_len]
|
|
126
|
+
self.nrows = len(self.data)
|
|
127
|
+
|
|
128
|
+
qtbdy_params = join_10_char(
|
|
129
|
+
self.nrows,
|
|
130
|
+
float(self.timeoffset),
|
|
131
|
+
float(self._something),
|
|
132
|
+
self.timeunit,
|
|
133
|
+
self.extendmethod,
|
|
134
|
+
self.interpmethod,
|
|
135
|
+
float(self.flowmultiplier),
|
|
136
|
+
float(self.minflow),
|
|
137
|
+
self.allow_override,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
if self.timeunit == "DATES":
|
|
141
|
+
qtbdy_data = [join_10_char(q) + t for t, q in self.data.items()]
|
|
142
|
+
else:
|
|
143
|
+
qtbdy_data = [join_10_char(q, t) for t, q in self.data.items()]
|
|
144
|
+
qtbdy_block = [header, name, qtbdy_params]
|
|
145
|
+
qtbdy_block.extend(qtbdy_data)
|
|
146
|
+
|
|
147
|
+
return qtbdy_block
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class HTBDY(Unit):
|
|
151
|
+
"""Class to hold and process HTBDY boundary type
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
name (str, optional): Unit name. Defaults to None.
|
|
155
|
+
comment (str, optional): Comment included in unit. Defaults to None.
|
|
156
|
+
timeunit (str, optional): Unit of time, e.g. 'HOURS', 'MINUTES' or 'SECONDS'. See Flood Modeller documentation for all available options. Defaults to None.
|
|
157
|
+
extendmethod (str, optional): Data extending method: 'EXTEND', 'NOEXTEND' or 'REPEAT'. Defaults to None.
|
|
158
|
+
interpmethod (str, optional): Data interpolation method: 'LINEAR' or 'SPLINE'. Defaults to None.
|
|
159
|
+
data (pandas.Series, optional): Series object with columns ``'Time'`` and ``'Stage'``. Defaults to None.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
HTBDY: Flood Modeller HTBDY Unit class object
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
_unit = "HTBDY"
|
|
166
|
+
|
|
167
|
+
def _create_from_blank( # noqa: PLR0913
|
|
168
|
+
self,
|
|
169
|
+
name="new_htbdy",
|
|
170
|
+
comment="",
|
|
171
|
+
timeunit="HOURS",
|
|
172
|
+
extendmethod="EXTEND",
|
|
173
|
+
interpmethod="LINEAR",
|
|
174
|
+
data=None,
|
|
175
|
+
):
|
|
176
|
+
# Initiate new HTBDY
|
|
177
|
+
|
|
178
|
+
for param, val in {
|
|
179
|
+
"name": name,
|
|
180
|
+
"comment": comment,
|
|
181
|
+
"timeunit": timeunit,
|
|
182
|
+
"extendmethod": extendmethod,
|
|
183
|
+
"interpmethod": interpmethod,
|
|
184
|
+
"_something": "",
|
|
185
|
+
}.items():
|
|
186
|
+
setattr(self, param, val)
|
|
187
|
+
|
|
188
|
+
self.data = (
|
|
189
|
+
data
|
|
190
|
+
if isinstance(data, pd.Series)
|
|
191
|
+
else pd.Series([0.0, 0.0], index=[0.0, 0.1], name="Stage")
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
def _read(self, htbdy_block):
|
|
195
|
+
"""Function to read a given HTBDY block and store data as class attributes"""
|
|
196
|
+
self.name = htbdy_block[1][: self._label_len].strip()
|
|
197
|
+
self.comment = htbdy_block[0].replace("HTBDY", "").strip()
|
|
198
|
+
htbdy_params = split_10_char(f"{htbdy_block[2]:<50}")
|
|
199
|
+
self.nrows = int(htbdy_params[0])
|
|
200
|
+
self._something = _to_str(htbdy_params[1], "")
|
|
201
|
+
self.timeunit = _to_str(htbdy_params[2], "HOURS", check_float=True)
|
|
202
|
+
self.extendmethod = _to_str(htbdy_params[3], "EXTEND")
|
|
203
|
+
self.interpmethod = _to_str(htbdy_params[4], "LINEAR")
|
|
204
|
+
|
|
205
|
+
data_list = (
|
|
206
|
+
_to_data_list(htbdy_block[3:], date_col=1)
|
|
207
|
+
if self.timeunit == "DATES"
|
|
208
|
+
else _to_data_list(htbdy_block[3:])
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
self.data = pd.DataFrame(data_list, columns=["Stage", "Time"])
|
|
212
|
+
self.data = self.data.set_index("Time")
|
|
213
|
+
self.data = self.data["Stage"] # Convert to series
|
|
214
|
+
|
|
215
|
+
def _write(self):
|
|
216
|
+
"""Function to write a valid HTBDY block"""
|
|
217
|
+
_validate_unit(self) # Function to check the params are valid for HTBDY
|
|
218
|
+
header = "HTBDY " + self.comment
|
|
219
|
+
name = self.name
|
|
220
|
+
self.nrows = len(self.data)
|
|
221
|
+
|
|
222
|
+
htbdy_params = join_10_char(
|
|
223
|
+
self.nrows,
|
|
224
|
+
self._something,
|
|
225
|
+
self.timeunit,
|
|
226
|
+
self.extendmethod,
|
|
227
|
+
self.interpmethod,
|
|
228
|
+
)
|
|
229
|
+
if self.timeunit == "DATES":
|
|
230
|
+
htbdy_data = [join_10_char(h) + t for t, h in self.data.items()]
|
|
231
|
+
else:
|
|
232
|
+
htbdy_data = [join_10_char(h, t) for t, h in self.data.items()]
|
|
233
|
+
htbdy_block = [header, name, htbdy_params]
|
|
234
|
+
htbdy_block.extend(htbdy_data)
|
|
235
|
+
|
|
236
|
+
return htbdy_block
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class QHBDY(Unit):
|
|
240
|
+
"""Class to hold and process QHBDY boundary type
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
name (str, optional): Unit name. Defaults to None.
|
|
244
|
+
comment (str, optional): Comment included in unit. Defaults to None.
|
|
245
|
+
interpmethod (str, optional): Data interpolation method: 'LINEAR' or 'SPLINE'. Defaults to None.
|
|
246
|
+
data (pandas.Series, optional): Series object with columns ``'Flow'`` and ``'Stage'``. Defaults to None.
|
|
247
|
+
Returns:
|
|
248
|
+
QHBDY: Flood Modeller QHBDY Unit class object
|
|
249
|
+
"""
|
|
250
|
+
|
|
251
|
+
_unit = "QHBDY"
|
|
252
|
+
|
|
253
|
+
def _create_from_blank(self, name="new_qhbdy", comment="", interpmethod="LINEAR", data=None):
|
|
254
|
+
# Initiate new QHBDY
|
|
255
|
+
for param, val in {
|
|
256
|
+
"name": name,
|
|
257
|
+
"comment": comment,
|
|
258
|
+
"interpmethod": interpmethod,
|
|
259
|
+
}.items():
|
|
260
|
+
setattr(self, param, val)
|
|
261
|
+
self.data = (
|
|
262
|
+
data
|
|
263
|
+
if isinstance(data, pd.Series)
|
|
264
|
+
else pd.Series([0.0, 0.0], index=[0.0, 0.1], name="Stage")
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
def _read(self, qhbdy_block):
|
|
268
|
+
"""Function to read a given QHBDY block and store data as class attributes"""
|
|
269
|
+
self.name = qhbdy_block[1][: self._label_len].strip()
|
|
270
|
+
self.comment = qhbdy_block[0].replace("QHBDY", "").strip()
|
|
271
|
+
qhbdy_params = split_10_char(f"{qhbdy_block[2]:<30}")
|
|
272
|
+
self.nrows = int(qhbdy_params[0])
|
|
273
|
+
self.interpmethod = _to_str(qhbdy_params[2], "LINEAR")
|
|
274
|
+
|
|
275
|
+
data_list = _to_data_list(qhbdy_block[3:])
|
|
276
|
+
|
|
277
|
+
self.data = pd.DataFrame(data_list, columns=["Flow", "Stage"])
|
|
278
|
+
self.data = self.data.set_index("Stage")
|
|
279
|
+
self.data = self.data["Flow"] # Convert to series
|
|
280
|
+
|
|
281
|
+
def _write(self):
|
|
282
|
+
"""Function to write a valid QHBDY block"""
|
|
283
|
+
_validate_unit(self) # Function to check the params are valid for QHBDY
|
|
284
|
+
header = "QHBDY " + self.comment
|
|
285
|
+
name = self.name
|
|
286
|
+
self.nrows = len(self.data)
|
|
287
|
+
|
|
288
|
+
qhbdy_params = join_10_char(self.nrows, 0.000, self.interpmethod)
|
|
289
|
+
qhbdy_data = [f"{q:>10.3f}{h:>10.3f}" for h, q in self.data.items()]
|
|
290
|
+
qhbdy_block = [header, name, qhbdy_params]
|
|
291
|
+
qhbdy_block.extend(qhbdy_data)
|
|
292
|
+
|
|
293
|
+
return qhbdy_block
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
class REFHBDY(Unit):
|
|
297
|
+
"""Class to hold and process REFHBDY boundary type
|
|
298
|
+
|
|
299
|
+
Currently REFHBDY Units are read/edit only and cannot be created from scratch, therefore the
|
|
300
|
+
parameters below are only accessible upon instantiating a REFHBDY object from an existing
|
|
301
|
+
unit.
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
name (str): Unit name.
|
|
305
|
+
comment (str): Comment included in unit.
|
|
306
|
+
easting (int): Easting (m)
|
|
307
|
+
northing (int): Northing (m)
|
|
308
|
+
return_period(float): Flood return period (yrs)
|
|
309
|
+
time_delay (float): Time delay before start of hydrograph (hrs)
|
|
310
|
+
timestep (float): Time interval for unit hydrograph and rainfall profile
|
|
311
|
+
sim_type (str): Simulation Type required: 'FULL' (full hydrograph), 'PFONLY' (peak flow) or 'BFONLY' (baseflow)
|
|
312
|
+
scale_method (str): Hydrograph scaling method: 'PEAKVALUE' or 'SCALEFACT'
|
|
313
|
+
scale_value (float): Scaling value
|
|
314
|
+
boundary_type (str): Boundary type: 'HYDROGRAPH' or 'HYETOGRAPH'
|
|
315
|
+
scale_type (str): Full generated hydrograph or quick runnof component only: 'FULL' or 'RUNOFF'
|
|
316
|
+
minflow (float): Minimum flow value
|
|
317
|
+
allow_override (str): Allow event parameters to be overridden from simulation file: ''/'OVERRIDE' or 'NOOVERRIDE'
|
|
318
|
+
area (float): Catchment area (sq km)
|
|
319
|
+
saar (int): Seasonal average annual rainfall (mm)
|
|
320
|
+
urbext (float): Fraction of urbanised catchment area
|
|
321
|
+
season (str): Season for design rainfall profile: 'DEFAULT', 'SUMMER' or 'WINTER'
|
|
322
|
+
calc_source (str): ReFH calculation source: 'DLL' (recommended) or 'REPORT'
|
|
323
|
+
storm_area (float): Rainfall storm area (sq km)
|
|
324
|
+
storm_duration (float): Rainfall storm duration (hrs)
|
|
325
|
+
rainfall_comment (str): Comment added to rainfall section of unit
|
|
326
|
+
arf_method (str): Method for defining ARF: 'USER' or 'DESIGN'
|
|
327
|
+
arf (float): Areal reduction factor (only used if ``arf_method`` set to 'USER')
|
|
328
|
+
ddf_c (float): DDF Parameter c
|
|
329
|
+
ddf_d1 (float): DDF Parameter d1
|
|
330
|
+
ddf_d2 (float): DDF Parameter d2
|
|
331
|
+
ddf_d3 (float): DDF Parameter d3
|
|
332
|
+
ddf_e (float): DDF Parameter e
|
|
333
|
+
ddf_f (float): DDF Parameter f
|
|
334
|
+
|
|
335
|
+
Returns:
|
|
336
|
+
REFHBDY: Flood Modeller REFHBDY Unit class object
|
|
337
|
+
"""
|
|
338
|
+
|
|
339
|
+
_unit = "REFHBDY"
|
|
340
|
+
|
|
341
|
+
def _read(self, refhbdy_block): # noqa: PLR0915
|
|
342
|
+
"""Function to read a given REFHBDY block and store data as class attributes"""
|
|
343
|
+
# line 1 & 2
|
|
344
|
+
# Extract comment and revision number
|
|
345
|
+
b = refhbdy_block[0].replace("REFHBDY #revision#", "").strip()
|
|
346
|
+
self._revision = _to_int(b[0], 1)
|
|
347
|
+
self.comment = b[1:].strip()
|
|
348
|
+
self.name = refhbdy_block[1][: self._label_len].strip()
|
|
349
|
+
|
|
350
|
+
# line 3
|
|
351
|
+
refhbdy_params1 = split_10_char(refhbdy_block[2])
|
|
352
|
+
# TODO: work out what this is
|
|
353
|
+
self._something = _to_float(refhbdy_params1[0])
|
|
354
|
+
self.easting = int(float(refhbdy_params1[1]))
|
|
355
|
+
self.northing = int(float(refhbdy_params1[2]))
|
|
356
|
+
|
|
357
|
+
# line 4
|
|
358
|
+
refhbdy_opts = split_10_char(f"{refhbdy_block[3]:<90}")
|
|
359
|
+
self.time_delay = _to_float(refhbdy_opts[0])
|
|
360
|
+
# SD / timestep must be odd interval
|
|
361
|
+
self.timestep = _to_float(refhbdy_opts[1])
|
|
362
|
+
# '' : Full hydrograph, 'pfonly' : peak flow, 'bfonly' : baseflow only
|
|
363
|
+
self.sim_type = refhbdy_opts[2]
|
|
364
|
+
self.scale_method = _to_str(refhbdy_opts[3], "SCALEFACT") # PEAKVALUE or SCALEFACT
|
|
365
|
+
self.scale_value = _to_float(refhbdy_opts[4], 1.0)
|
|
366
|
+
self.boundary_type = _to_str(refhbdy_opts[5], "HYDROGRAPH") # HYDROGRAPH or HYETOGRAPH
|
|
367
|
+
self.scale_type = _to_str(refhbdy_opts[6], "FULL") # FULL or RUNOFF
|
|
368
|
+
self.minflow = _to_float(refhbdy_opts[7])
|
|
369
|
+
self.allow_override = refhbdy_opts[8] # ''/OVERRIDE or NOOVERRIDE
|
|
370
|
+
|
|
371
|
+
# line 5
|
|
372
|
+
refhbdy_params2 = split_10_char(f"{refhbdy_block[4]:<60}")
|
|
373
|
+
self.area = _to_float(refhbdy_params2[0])
|
|
374
|
+
try:
|
|
375
|
+
# Maintain SAAR as integer if already is, else use float
|
|
376
|
+
self.saar = int(refhbdy_params2[1])
|
|
377
|
+
except ValueError:
|
|
378
|
+
self.saar = float(refhbdy_params2[1])
|
|
379
|
+
self.urbext = _to_float(refhbdy_params2[2])
|
|
380
|
+
self.season = _to_str(refhbdy_params2[3], "DEFAULT") # DEFAULT, SUMMER or WINTER
|
|
381
|
+
self.calc_source = _to_str(refhbdy_params2[4], "DLL") # DLL or REPORT
|
|
382
|
+
self.use_urban_subdivisions = refhbdy_params2[5] != ""
|
|
383
|
+
if self.use_urban_subdivisions:
|
|
384
|
+
# Just keeping this raw for now as unlikely to be used.
|
|
385
|
+
self._urban_refh_data = refhbdy_block[5:8]
|
|
386
|
+
rainfall_params1, rainfall_params2, rainfall_params3 = refhbdy_block[8:11]
|
|
387
|
+
# Keeping rest raw for now to reduce dev time
|
|
388
|
+
self._raw_extra_lines = refhbdy_block[11:]
|
|
389
|
+
else:
|
|
390
|
+
rainfall_params1, rainfall_params2, rainfall_params3 = refhbdy_block[5:8]
|
|
391
|
+
# Keeping rest raw for now to reduce dev time
|
|
392
|
+
self._raw_extra_lines = refhbdy_block[8:]
|
|
393
|
+
|
|
394
|
+
# line 6
|
|
395
|
+
rainfall_params1 = split_10_char(rainfall_params1)
|
|
396
|
+
self.storm_area = _to_float(rainfall_params1[0])
|
|
397
|
+
self.storm_duration = _to_float(rainfall_params1[1])
|
|
398
|
+
# TODO: work out what this is
|
|
399
|
+
self._something2 = _to_float(rainfall_params1[2])
|
|
400
|
+
|
|
401
|
+
# line 7
|
|
402
|
+
self.rainfall_comment = rainfall_params2[20:]
|
|
403
|
+
rainfall_params2 = split_10_char(rainfall_params2[:20])
|
|
404
|
+
self.arf_method = rainfall_params2[1]
|
|
405
|
+
self._something3 = rainfall_params2[0] # TODO: work out what this is
|
|
406
|
+
|
|
407
|
+
# line 8
|
|
408
|
+
rainfall_params3 = split_10_char(rainfall_params3)
|
|
409
|
+
self.observed_rainfall_depth = _to_float(rainfall_params3[0])
|
|
410
|
+
self.return_period = _to_float(rainfall_params3[1])
|
|
411
|
+
self.arf = _to_float(rainfall_params3[2])
|
|
412
|
+
self.ddf_c = _to_float(rainfall_params3[3])
|
|
413
|
+
self.ddf_d1 = _to_float(rainfall_params3[4])
|
|
414
|
+
self.ddf_d2 = _to_float(rainfall_params3[5])
|
|
415
|
+
self.ddf_d3 = _to_float(rainfall_params3[6])
|
|
416
|
+
self.ddf_e = _to_float(rainfall_params3[7])
|
|
417
|
+
self.ddf_f = _to_float(rainfall_params3[8])
|
|
418
|
+
|
|
419
|
+
def _write(self):
|
|
420
|
+
"""Function to write a valid REFHBDY block"""
|
|
421
|
+
_validate_unit(self) # Function to check the params are valid for QTBDY
|
|
422
|
+
header = f"REFHBDY #revision#{self._revision} {self.comment}"
|
|
423
|
+
name = self.name[: self._label_len]
|
|
424
|
+
|
|
425
|
+
refhbdy_block = [header, name]
|
|
426
|
+
line3 = join_10_char(self._something, self.easting, self.northing)
|
|
427
|
+
self.sim_type = (
|
|
428
|
+
"" if self.sim_type.upper() == "FULL" else self.sim_type
|
|
429
|
+
) # Allow 'full' as an option
|
|
430
|
+
line4 = (
|
|
431
|
+
join_10_char(self.time_delay, self.timestep)
|
|
432
|
+
+ join_n_char_ljust(10, self.sim_type, self.scale_method)
|
|
433
|
+
+ join_10_char(self.scale_value)
|
|
434
|
+
+ join_n_char_ljust(10, self.boundary_type)
|
|
435
|
+
+ join_10_char(self.scale_type, self.minflow, self.allow_override)
|
|
436
|
+
)
|
|
437
|
+
use_urban_subdivisions = "" if not self.use_urban_subdivisions else "URBANREFH"
|
|
438
|
+
line5 = join_10_char(
|
|
439
|
+
self.area,
|
|
440
|
+
self.saar,
|
|
441
|
+
f"{self.urbext:.4f}",
|
|
442
|
+
self.season,
|
|
443
|
+
self.calc_source,
|
|
444
|
+
use_urban_subdivisions,
|
|
445
|
+
)
|
|
446
|
+
refhbdy_block.extend([line3, line4, line5])
|
|
447
|
+
|
|
448
|
+
if self.use_urban_subdivisions:
|
|
449
|
+
refhbdy_block.extend(self._urban_refh_data)
|
|
450
|
+
|
|
451
|
+
line6 = join_10_char(self.storm_area, self.storm_duration, self._something2)
|
|
452
|
+
line7 = join_10_char(self._something3, self.arf_method) + self.rainfall_comment
|
|
453
|
+
line8 = join_10_char(
|
|
454
|
+
self.observed_rainfall_depth,
|
|
455
|
+
self.return_period,
|
|
456
|
+
self.arf,
|
|
457
|
+
f"{self.ddf_c:.4f}",
|
|
458
|
+
f"{self.ddf_d1:.5f}",
|
|
459
|
+
f"{self.ddf_d2:.5f}",
|
|
460
|
+
f"{self.ddf_d3:.5f}",
|
|
461
|
+
f"{self.ddf_e:.5f}",
|
|
462
|
+
f"{self.ddf_f:.5f}",
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
refhbdy_block.extend([line6, line7, line8])
|
|
466
|
+
refhbdy_block.extend(self._raw_extra_lines)
|
|
467
|
+
return refhbdy_block
|