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.
Files changed (178) hide show
  1. floodmodeller_api/__init__.py +8 -9
  2. floodmodeller_api/_base.py +169 -176
  3. floodmodeller_api/backup.py +273 -273
  4. floodmodeller_api/dat.py +889 -831
  5. floodmodeller_api/diff.py +136 -119
  6. floodmodeller_api/ied.py +302 -306
  7. floodmodeller_api/ief.py +553 -637
  8. floodmodeller_api/ief_flags.py +253 -253
  9. floodmodeller_api/inp.py +260 -266
  10. floodmodeller_api/libs/libifcoremd.dll +0 -0
  11. floodmodeller_api/libs/libifcoremt.so.5 +0 -0
  12. floodmodeller_api/libs/libifport.so.5 +0 -0
  13. floodmodeller_api/{libmmd.dll → libs/libimf.so} +0 -0
  14. floodmodeller_api/libs/libintlc.so.5 +0 -0
  15. floodmodeller_api/libs/libmmd.dll +0 -0
  16. floodmodeller_api/libs/libsvml.so +0 -0
  17. floodmodeller_api/libs/libzzn_read.so +0 -0
  18. floodmodeller_api/libs/zzn_read.dll +0 -0
  19. floodmodeller_api/logs/__init__.py +2 -2
  20. floodmodeller_api/logs/lf.py +364 -312
  21. floodmodeller_api/logs/lf_helpers.py +354 -352
  22. floodmodeller_api/logs/lf_params.py +643 -529
  23. floodmodeller_api/mapping.py +84 -0
  24. floodmodeller_api/test/__init__.py +4 -4
  25. floodmodeller_api/test/conftest.py +16 -8
  26. floodmodeller_api/test/test_backup.py +117 -117
  27. floodmodeller_api/test/test_conveyance.py +107 -0
  28. floodmodeller_api/test/test_dat.py +222 -92
  29. floodmodeller_api/test/test_data/All Units 4_6.DAT +1081 -1081
  30. floodmodeller_api/test/test_data/All Units 4_6.feb +1081 -1081
  31. floodmodeller_api/test/test_data/BRIDGE.DAT +926 -926
  32. floodmodeller_api/test/test_data/Culvert_Inlet_Outlet.dat +36 -36
  33. floodmodeller_api/test/test_data/Culvert_Inlet_Outlet.feb +36 -36
  34. floodmodeller_api/test/test_data/DamBreakADI.xml +52 -52
  35. floodmodeller_api/test/test_data/DamBreakFAST.xml +58 -58
  36. floodmodeller_api/test/test_data/DamBreakFAST_dy.xml +53 -53
  37. floodmodeller_api/test/test_data/DamBreakTVD.xml +55 -55
  38. floodmodeller_api/test/test_data/DefenceBreach.xml +53 -53
  39. floodmodeller_api/test/test_data/DefenceBreachFAST.xml +60 -60
  40. floodmodeller_api/test/test_data/DefenceBreachFAST_dy.xml +55 -55
  41. floodmodeller_api/test/test_data/Domain1+2_QH.xml +76 -76
  42. floodmodeller_api/test/test_data/Domain1_H.xml +41 -41
  43. floodmodeller_api/test/test_data/Domain1_Q.xml +41 -41
  44. floodmodeller_api/test/test_data/Domain1_Q_FAST.xml +48 -48
  45. floodmodeller_api/test/test_data/Domain1_Q_FAST_dy.xml +48 -48
  46. floodmodeller_api/test/test_data/Domain1_Q_xml_expected.json +263 -0
  47. floodmodeller_api/test/test_data/Domain1_W.xml +41 -41
  48. floodmodeller_api/test/test_data/EX1.DAT +321 -321
  49. floodmodeller_api/test/test_data/EX1.ext +107 -107
  50. floodmodeller_api/test/test_data/EX1.feb +320 -320
  51. floodmodeller_api/test/test_data/EX1.gxy +107 -107
  52. floodmodeller_api/test/test_data/EX17.DAT +421 -422
  53. floodmodeller_api/test/test_data/EX17.ext +213 -213
  54. floodmodeller_api/test/test_data/EX17.feb +422 -422
  55. floodmodeller_api/test/test_data/EX18.DAT +375 -375
  56. floodmodeller_api/test/test_data/EX18_DAT_expected.json +3876 -0
  57. floodmodeller_api/test/test_data/EX2.DAT +302 -302
  58. floodmodeller_api/test/test_data/EX3.DAT +926 -926
  59. floodmodeller_api/test/test_data/EX3_DAT_expected.json +16235 -0
  60. floodmodeller_api/test/test_data/EX3_IEF_expected.json +61 -0
  61. floodmodeller_api/test/test_data/EX6.DAT +2084 -2084
  62. floodmodeller_api/test/test_data/EX6.ext +532 -532
  63. floodmodeller_api/test/test_data/EX6.feb +2084 -2084
  64. floodmodeller_api/test/test_data/EX6_DAT_expected.json +31647 -0
  65. floodmodeller_api/test/test_data/Event Data Example.DAT +336 -336
  66. floodmodeller_api/test/test_data/Event Data Example.ext +107 -107
  67. floodmodeller_api/test/test_data/Event Data Example.feb +336 -336
  68. floodmodeller_api/test/test_data/Linked1D2D.xml +52 -52
  69. floodmodeller_api/test/test_data/Linked1D2DFAST.xml +53 -53
  70. floodmodeller_api/test/test_data/Linked1D2DFAST_dy.xml +48 -48
  71. floodmodeller_api/test/test_data/Linked1D2D_xml_expected.json +313 -0
  72. floodmodeller_api/test/test_data/blockage.dat +50 -50
  73. floodmodeller_api/test/test_data/blockage.ext +45 -45
  74. floodmodeller_api/test/test_data/blockage.feb +9 -9
  75. floodmodeller_api/test/test_data/blockage.gxy +71 -71
  76. floodmodeller_api/test/test_data/conveyance_test.dat +165 -0
  77. floodmodeller_api/test/test_data/conveyance_test.feb +116 -0
  78. floodmodeller_api/test/test_data/conveyance_test.gxy +85 -0
  79. floodmodeller_api/test/test_data/defaultUnits.dat +127 -127
  80. floodmodeller_api/test/test_data/defaultUnits.ext +45 -45
  81. floodmodeller_api/test/test_data/defaultUnits.feb +9 -9
  82. floodmodeller_api/test/test_data/defaultUnits.fmpx +58 -58
  83. floodmodeller_api/test/test_data/defaultUnits.gxy +85 -85
  84. floodmodeller_api/test/test_data/ex3.ief +20 -20
  85. floodmodeller_api/test/test_data/ex3.lf1 +2800 -2800
  86. floodmodeller_api/test/test_data/ex4.DAT +1374 -1374
  87. floodmodeller_api/test/test_data/ex4_changed.DAT +1374 -1374
  88. floodmodeller_api/test/test_data/example1.inp +329 -329
  89. floodmodeller_api/test/test_data/example2.inp +158 -158
  90. floodmodeller_api/test/test_data/example3.inp +297 -297
  91. floodmodeller_api/test/test_data/example4.inp +388 -388
  92. floodmodeller_api/test/test_data/example5.inp +147 -147
  93. floodmodeller_api/test/test_data/example6.inp +154 -154
  94. floodmodeller_api/test/test_data/expected_conveyance.csv +60 -0
  95. floodmodeller_api/test/test_data/jump.dat +176 -176
  96. floodmodeller_api/test/test_data/network.dat +1374 -1374
  97. floodmodeller_api/test/test_data/network.ext +45 -45
  98. floodmodeller_api/test/test_data/network.exy +1 -1
  99. floodmodeller_api/test/test_data/network.feb +45 -45
  100. floodmodeller_api/test/test_data/network.ied +45 -45
  101. floodmodeller_api/test/test_data/network.ief +20 -20
  102. floodmodeller_api/test/test_data/network.inp +147 -147
  103. floodmodeller_api/test/test_data/network.pxy +57 -57
  104. floodmodeller_api/test/test_data/network.zzd +122 -122
  105. floodmodeller_api/test/test_data/network_dat_expected.json +21837 -0
  106. floodmodeller_api/test/test_data/network_from_tabularCSV.csv +87 -87
  107. floodmodeller_api/test/test_data/network_ied_expected.json +287 -0
  108. floodmodeller_api/test/test_data/rnweir.dat +9 -9
  109. floodmodeller_api/test/test_data/rnweir.ext +45 -45
  110. floodmodeller_api/test/test_data/rnweir.feb +9 -9
  111. floodmodeller_api/test/test_data/rnweir.gxy +45 -45
  112. floodmodeller_api/test/test_data/rnweir_default.dat +74 -74
  113. floodmodeller_api/test/test_data/rnweir_default.ext +45 -45
  114. floodmodeller_api/test/test_data/rnweir_default.feb +9 -9
  115. floodmodeller_api/test/test_data/rnweir_default.fmpx +58 -58
  116. floodmodeller_api/test/test_data/rnweir_default.gxy +53 -53
  117. floodmodeller_api/test/test_data/unit checks.dat +16 -16
  118. floodmodeller_api/test/test_ied.py +29 -29
  119. floodmodeller_api/test/test_ief.py +136 -24
  120. floodmodeller_api/test/test_inp.py +47 -48
  121. floodmodeller_api/test/test_json.py +114 -0
  122. floodmodeller_api/test/test_logs_lf.py +102 -51
  123. floodmodeller_api/test/test_tool.py +165 -152
  124. floodmodeller_api/test/test_toolbox_structure_log.py +234 -239
  125. floodmodeller_api/test/test_xml2d.py +151 -156
  126. floodmodeller_api/test/test_zzn.py +36 -34
  127. floodmodeller_api/to_from_json.py +230 -0
  128. floodmodeller_api/tool.py +332 -329
  129. floodmodeller_api/toolbox/__init__.py +5 -5
  130. floodmodeller_api/toolbox/example_tool.py +45 -45
  131. floodmodeller_api/toolbox/model_build/__init__.py +2 -2
  132. floodmodeller_api/toolbox/model_build/add_siltation_definition.py +100 -98
  133. floodmodeller_api/toolbox/model_build/structure_log/__init__.py +1 -1
  134. floodmodeller_api/toolbox/model_build/structure_log/structure_log.py +287 -289
  135. floodmodeller_api/toolbox/model_build/structure_log_definition.py +76 -76
  136. floodmodeller_api/units/__init__.py +10 -10
  137. floodmodeller_api/units/_base.py +214 -212
  138. floodmodeller_api/units/boundaries.py +467 -467
  139. floodmodeller_api/units/comment.py +52 -55
  140. floodmodeller_api/units/conduits.py +382 -402
  141. floodmodeller_api/units/conveyance.py +301 -0
  142. floodmodeller_api/units/helpers.py +123 -131
  143. floodmodeller_api/units/iic.py +107 -101
  144. floodmodeller_api/units/losses.py +305 -306
  145. floodmodeller_api/units/sections.py +465 -446
  146. floodmodeller_api/units/structures.py +1690 -1683
  147. floodmodeller_api/units/units.py +93 -104
  148. floodmodeller_api/units/unsupported.py +44 -44
  149. floodmodeller_api/units/variables.py +87 -89
  150. floodmodeller_api/urban1d/__init__.py +11 -11
  151. floodmodeller_api/urban1d/_base.py +188 -179
  152. floodmodeller_api/urban1d/conduits.py +93 -85
  153. floodmodeller_api/urban1d/general_parameters.py +58 -58
  154. floodmodeller_api/urban1d/junctions.py +81 -79
  155. floodmodeller_api/urban1d/losses.py +81 -74
  156. floodmodeller_api/urban1d/outfalls.py +114 -110
  157. floodmodeller_api/urban1d/raingauges.py +111 -111
  158. floodmodeller_api/urban1d/subsections.py +92 -98
  159. floodmodeller_api/urban1d/xsections.py +147 -144
  160. floodmodeller_api/util.py +119 -21
  161. floodmodeller_api/validation/parameters.py +660 -660
  162. floodmodeller_api/validation/urban_parameters.py +388 -404
  163. floodmodeller_api/validation/validation.py +110 -108
  164. floodmodeller_api/version.py +1 -1
  165. floodmodeller_api/xml2d.py +632 -673
  166. floodmodeller_api/xml2d_template.py +37 -37
  167. floodmodeller_api/zzn.py +414 -363
  168. {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.4.dist-info}/LICENSE.txt +13 -13
  169. {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.4.dist-info}/METADATA +85 -82
  170. floodmodeller_api-0.4.4.dist-info/RECORD +185 -0
  171. {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.4.dist-info}/WHEEL +1 -1
  172. floodmodeller_api/libifcoremd.dll +0 -0
  173. floodmodeller_api/test/test_data/EX3.bmp +0 -0
  174. floodmodeller_api/test/test_data/test_output.csv +0 -87
  175. floodmodeller_api/zzn_read.dll +0 -0
  176. floodmodeller_api-0.4.2.post1.dist-info/RECORD +0 -164
  177. {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.4.dist-info}/entry_points.txt +0 -0
  178. {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) 2023 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(
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 = not 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
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