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
floodmodeller_api/ied.py
CHANGED
|
@@ -1,306 +1,302 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Flood Modeller Python API
|
|
3
|
-
Copyright (C)
|
|
4
|
-
|
|
5
|
-
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
|
|
6
|
-
as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
7
|
-
|
|
8
|
-
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
9
|
-
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
10
|
-
|
|
11
|
-
You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.
|
|
12
|
-
|
|
13
|
-
If you have any query about this program or this License, please contact us at support@floodmodeller.com or write to the following
|
|
14
|
-
address: Jacobs UK Limited, Flood Modeller, Cottons Centre, Cottons Lane, London, SE1 2QG, United Kingdom.
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
from
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
from .
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
self.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
#
|
|
63
|
-
self.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
self.
|
|
149
|
-
self.
|
|
150
|
-
self.
|
|
151
|
-
self.
|
|
152
|
-
self.
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
unit_name = unit_data[
|
|
181
|
-
subtype =
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
comment_n
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
"""
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
Once saved, the IED() class will continue working from the saved location, therefore any further calls to IED.update() will update in the latest saved location
|
|
304
|
-
rather than the original source IED used to construct the class"""
|
|
305
|
-
|
|
306
|
-
self._save(filepath)
|
|
1
|
+
"""
|
|
2
|
+
Flood Modeller Python API
|
|
3
|
+
Copyright (C) 2024 Jacobs U.K. Limited
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
|
|
6
|
+
as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
7
|
+
|
|
8
|
+
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
9
|
+
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
10
|
+
|
|
11
|
+
You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.
|
|
12
|
+
|
|
13
|
+
If you have any query about this program or this License, please contact us at support@floodmodeller.com or write to the following
|
|
14
|
+
address: Jacobs UK Limited, Flood Modeller, Cottons Centre, Cottons Lane, London, SE1 2QG, United Kingdom.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from typing import TYPE_CHECKING, Any
|
|
20
|
+
|
|
21
|
+
from . import units
|
|
22
|
+
from ._base import FMFile
|
|
23
|
+
from .util import handle_exception
|
|
24
|
+
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class IED(FMFile):
|
|
30
|
+
"""Reads and write Flood Modeller event data format '.ied'
|
|
31
|
+
Args:
|
|
32
|
+
ied_filepath (str, optional): Full filepath to ied file. If not specified, a new IED class will be created.
|
|
33
|
+
|
|
34
|
+
Output:
|
|
35
|
+
Initiates 'IED' class object
|
|
36
|
+
|
|
37
|
+
Raises:
|
|
38
|
+
TypeError: Raised if ied_filepath does not point to a .ied file
|
|
39
|
+
FileNotFoundError: Raised if ied_filepath points to a file which does not exist
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
_filetype: str = "IED"
|
|
43
|
+
_suffix: str = ".ied"
|
|
44
|
+
|
|
45
|
+
@handle_exception(when="read")
|
|
46
|
+
def __init__(self, ied_filepath: str | Path | None = None, from_json: bool = False):
|
|
47
|
+
if from_json:
|
|
48
|
+
return
|
|
49
|
+
if ied_filepath is not None:
|
|
50
|
+
FMFile.__init__(self, ied_filepath)
|
|
51
|
+
|
|
52
|
+
self._read()
|
|
53
|
+
|
|
54
|
+
else:
|
|
55
|
+
# No filepath specified, create new 'blank' IED in memory
|
|
56
|
+
self._ied_struct: list[dict[str, Any]] = []
|
|
57
|
+
self._raw_data: list[str] = []
|
|
58
|
+
|
|
59
|
+
self._get_unit_definitions()
|
|
60
|
+
|
|
61
|
+
def _read(self):
|
|
62
|
+
# Read IED data
|
|
63
|
+
with open(self._filepath) as ied_file:
|
|
64
|
+
self._raw_data = [line.rstrip("\n") for line in ied_file.readlines()]
|
|
65
|
+
|
|
66
|
+
# Generate IED structure
|
|
67
|
+
self._update_ied_struct()
|
|
68
|
+
|
|
69
|
+
@handle_exception(when="write")
|
|
70
|
+
def _write(self) -> str: # noqa: C901, PLR0912
|
|
71
|
+
"""Returns string representation of the current IED data"""
|
|
72
|
+
block_shift = 0
|
|
73
|
+
existing_units: dict[str, list[str]] = {
|
|
74
|
+
"boundaries": [],
|
|
75
|
+
"structures": [],
|
|
76
|
+
"sections": [],
|
|
77
|
+
"conduits": [],
|
|
78
|
+
"losses": [],
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
for block in self._ied_struct:
|
|
82
|
+
# Check for all supported boundary types
|
|
83
|
+
if block["Type"] in units.SUPPORTED_UNIT_TYPES:
|
|
84
|
+
unit_data = self._raw_data[
|
|
85
|
+
block["start"] + block_shift : block["end"] + 1 + block_shift
|
|
86
|
+
]
|
|
87
|
+
prev_block_len = len(unit_data)
|
|
88
|
+
if units.SUPPORTED_UNIT_TYPES[block["Type"]]["has_subtype"]:
|
|
89
|
+
unit_name = unit_data[2][:12].strip()
|
|
90
|
+
else:
|
|
91
|
+
unit_name = unit_data[1][:12].strip()
|
|
92
|
+
|
|
93
|
+
# Get unit object
|
|
94
|
+
unit_group = getattr(self, units.SUPPORTED_UNIT_TYPES[block["Type"]]["group"])
|
|
95
|
+
if unit_name in unit_group:
|
|
96
|
+
# block still exists
|
|
97
|
+
new_unit_data = unit_group[unit_name]._write()
|
|
98
|
+
existing_units[units.SUPPORTED_UNIT_TYPES[block["Type"]]["group"]].append(
|
|
99
|
+
unit_name,
|
|
100
|
+
)
|
|
101
|
+
else:
|
|
102
|
+
# Bdy block has been deleted
|
|
103
|
+
new_unit_data = []
|
|
104
|
+
|
|
105
|
+
new_block_len = len(new_unit_data)
|
|
106
|
+
self._raw_data[block["start"] + block_shift : block["end"] + 1 + block_shift] = (
|
|
107
|
+
new_unit_data
|
|
108
|
+
)
|
|
109
|
+
# adjust block shift for change in number of lines in bdy block
|
|
110
|
+
block_shift += new_block_len - prev_block_len
|
|
111
|
+
|
|
112
|
+
# Add any new units
|
|
113
|
+
for group_name, _units in existing_units.items():
|
|
114
|
+
for name, unit in getattr(self, group_name).items():
|
|
115
|
+
if name not in _units:
|
|
116
|
+
# Newly added unit
|
|
117
|
+
# Ensure that the 'name' attribute matches name key in boundaries
|
|
118
|
+
self._raw_data.extend(unit._write())
|
|
119
|
+
|
|
120
|
+
# Update ied_struct
|
|
121
|
+
self._update_ied_struct()
|
|
122
|
+
|
|
123
|
+
# Update unit names
|
|
124
|
+
for unit_group, unit_group_name in [
|
|
125
|
+
(self.boundaries, "boundaries"),
|
|
126
|
+
(self.sections, "sections"),
|
|
127
|
+
(self.structures, "structures"),
|
|
128
|
+
(self.conduits, "conduits"),
|
|
129
|
+
(self.losses, "losses"),
|
|
130
|
+
]:
|
|
131
|
+
for name, unit in unit_group.copy().items():
|
|
132
|
+
if name != unit.name:
|
|
133
|
+
# Check if new name already exists as a label
|
|
134
|
+
if unit.name in unit_group:
|
|
135
|
+
raise Exception(
|
|
136
|
+
f'Error: Cannot update label "{name}" to "{unit.name}" because "{unit.name}" already exists in the Network {unit_group_name} group',
|
|
137
|
+
)
|
|
138
|
+
unit_group[unit.name] = unit
|
|
139
|
+
del unit_group[name]
|
|
140
|
+
|
|
141
|
+
return "\n".join(self._raw_data) + "\n"
|
|
142
|
+
|
|
143
|
+
def _get_unit_definitions(self):
|
|
144
|
+
# Get unit definitions
|
|
145
|
+
self.sections = {}
|
|
146
|
+
self.boundaries = {}
|
|
147
|
+
self.structures = {}
|
|
148
|
+
self.conduits = {}
|
|
149
|
+
self.losses = {}
|
|
150
|
+
self._unsupported = {}
|
|
151
|
+
self._all_units = []
|
|
152
|
+
for block in self._ied_struct:
|
|
153
|
+
unit_data = self._raw_data[block["start"] : block["end"] + 1]
|
|
154
|
+
# Check for all supported boundary types, starting just with QTBDY type
|
|
155
|
+
if block["Type"] in units.SUPPORTED_UNIT_TYPES:
|
|
156
|
+
# Check to see whether unit type has associated subtypes so that unit name can be correctly assigned
|
|
157
|
+
if units.SUPPORTED_UNIT_TYPES[block["Type"]]["has_subtype"]:
|
|
158
|
+
# Takes first 12 characters as name
|
|
159
|
+
unit_name = unit_data[2][:12].strip()
|
|
160
|
+
else:
|
|
161
|
+
unit_name = unit_data[1][:12].strip()
|
|
162
|
+
|
|
163
|
+
# Create instance of unit and add to relevant group
|
|
164
|
+
unit_group = getattr(self, units.SUPPORTED_UNIT_TYPES[block["Type"]]["group"])
|
|
165
|
+
if unit_name in unit_group:
|
|
166
|
+
raise Exception(
|
|
167
|
+
f'Duplicate label ({unit_name}) encountered within category: {units.SUPPORTED_UNIT_TYPES[block["Type"]]["group"]}',
|
|
168
|
+
)
|
|
169
|
+
unit_group[unit_name] = eval(f'units.{block["Type"]}({unit_data})')
|
|
170
|
+
|
|
171
|
+
self._all_units.append(unit_group[unit_name])
|
|
172
|
+
|
|
173
|
+
elif block["Type"] in units.UNSUPPORTED_UNIT_TYPES:
|
|
174
|
+
# Check to see whether unit type has associated subtypes so that unit name can be correctly assigned
|
|
175
|
+
if units.UNSUPPORTED_UNIT_TYPES[block["Type"]]["has_subtype"]:
|
|
176
|
+
# Takes first 12 characters as name
|
|
177
|
+
unit_name = unit_data[2][:12].strip()
|
|
178
|
+
subtype = True
|
|
179
|
+
else:
|
|
180
|
+
unit_name = unit_data[1][:12].strip()
|
|
181
|
+
subtype = False
|
|
182
|
+
|
|
183
|
+
self._unsupported[f"{unit_name} ({block['Type']})"] = units.UNSUPPORTED(
|
|
184
|
+
unit_data,
|
|
185
|
+
12,
|
|
186
|
+
unit_name=unit_name,
|
|
187
|
+
unit_type=block["Type"],
|
|
188
|
+
subtype=subtype,
|
|
189
|
+
)
|
|
190
|
+
self._all_units.append(self._unsupported[f"{unit_name} ({block['Type']})"])
|
|
191
|
+
|
|
192
|
+
print()
|
|
193
|
+
|
|
194
|
+
def _update_ied_struct(self): # noqa: C901, PLR0912, PLR0915
|
|
195
|
+
# Generate IED structure
|
|
196
|
+
ied_struct = []
|
|
197
|
+
in_block = False
|
|
198
|
+
bdy_block = {}
|
|
199
|
+
comment_n = None
|
|
200
|
+
in_comment = False
|
|
201
|
+
|
|
202
|
+
for idx, line in enumerate(self._raw_data):
|
|
203
|
+
# Deal with comment blocks explicitly as they could contain unit keywords
|
|
204
|
+
if in_comment and comment_n is None:
|
|
205
|
+
comment_n = int(line.strip())
|
|
206
|
+
continue
|
|
207
|
+
if in_comment:
|
|
208
|
+
comment_n -= 1
|
|
209
|
+
if comment_n == 0:
|
|
210
|
+
bdy_block["end"] = idx # add ending index
|
|
211
|
+
# append existing bdy block to the ied_struct
|
|
212
|
+
ied_struct.append(bdy_block)
|
|
213
|
+
bdy_block = {} # reset bdy block
|
|
214
|
+
in_comment = False
|
|
215
|
+
in_block = False
|
|
216
|
+
comment_n = None
|
|
217
|
+
continue # move onto next line as still in comment block
|
|
218
|
+
|
|
219
|
+
if line == "COMMENT":
|
|
220
|
+
in_comment = True
|
|
221
|
+
if in_block is True:
|
|
222
|
+
bdy_block["end"] = idx - 1 # add ending index
|
|
223
|
+
# append existing bdy block to the ied_struct
|
|
224
|
+
ied_struct.append(bdy_block)
|
|
225
|
+
bdy_block = {} # reset bdy block
|
|
226
|
+
# start new block for COMMENT
|
|
227
|
+
bdy_block["Type"] = line.split(" ")[0]
|
|
228
|
+
bdy_block["start"] = idx # add starting index
|
|
229
|
+
continue
|
|
230
|
+
|
|
231
|
+
if len(line.split(" ")[0]) > 1:
|
|
232
|
+
if line.split(" ")[0] in units.ALL_UNIT_TYPES:
|
|
233
|
+
if in_block is True:
|
|
234
|
+
bdy_block["end"] = idx - 1 # add ending index
|
|
235
|
+
# append existing bdy block to the ief_struct
|
|
236
|
+
ied_struct.append(bdy_block)
|
|
237
|
+
bdy_block = {} # reset bdy block
|
|
238
|
+
in_block = True
|
|
239
|
+
bdy_block["Type"] = line.split(" ")[0] # start new bdy block
|
|
240
|
+
bdy_block["start"] = idx # add starting index
|
|
241
|
+
|
|
242
|
+
elif " ".join(line.split(" ")[:2]) in units.ALL_UNIT_TYPES:
|
|
243
|
+
if in_block is True:
|
|
244
|
+
bdy_block["end"] = idx - 1 # add ending index
|
|
245
|
+
# append existing bdy block to the ief_struct
|
|
246
|
+
ied_struct.append(bdy_block)
|
|
247
|
+
bdy_block = {} # reset bdy block
|
|
248
|
+
in_block = True
|
|
249
|
+
bdy_block["Type"] = " ".join(line.split(" ")[:2]) # start new bdy block
|
|
250
|
+
bdy_block["start"] = idx # add starting index
|
|
251
|
+
else:
|
|
252
|
+
continue
|
|
253
|
+
elif line in units.ALL_UNIT_TYPES:
|
|
254
|
+
if in_block is True:
|
|
255
|
+
bdy_block["end"] = idx - 1 # add ending index
|
|
256
|
+
# append existing bdy block to the ief_struct
|
|
257
|
+
ied_struct.append(bdy_block)
|
|
258
|
+
bdy_block = {} # reset bdy block
|
|
259
|
+
in_block = True
|
|
260
|
+
bdy_block["Type"] = line # start new bdy block
|
|
261
|
+
bdy_block["start"] = idx # add starting index
|
|
262
|
+
else:
|
|
263
|
+
continue
|
|
264
|
+
|
|
265
|
+
if len(bdy_block) != 0:
|
|
266
|
+
# Only adds end block if there is a bdy block present (i.e. an empty IED stays empty)
|
|
267
|
+
# add ending index for final block
|
|
268
|
+
bdy_block["end"] = len(self._raw_data) - 1
|
|
269
|
+
ied_struct.append(bdy_block) # add final block
|
|
270
|
+
|
|
271
|
+
self._ied_struct = ied_struct
|
|
272
|
+
|
|
273
|
+
def diff(self, other: IED, force_print: bool = False) -> None:
|
|
274
|
+
"""Compares the IED class against another IED class to check whether they are
|
|
275
|
+
equivalent, or if not, what the differences are. Two instances of an IED class are
|
|
276
|
+
deemed equivalent if all of their attributes are equal except for the filepath and
|
|
277
|
+
raw data. For example, two IED files from different filepaths that had the same
|
|
278
|
+
data except maybe some differences in decimal places and some default parameters
|
|
279
|
+
ommitted, would be classed as equaivalent as they would produce the same IED instance
|
|
280
|
+
and write the exact same data.
|
|
281
|
+
|
|
282
|
+
The result is printed to the console. If you need to access the returned data, use
|
|
283
|
+
the method ``IED._get_diff()``
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
other (floodmodeller_api.IED): Other instance of an IED class
|
|
287
|
+
force_print (bool): Forces the API to print every difference found, rather than
|
|
288
|
+
just the first 25 differences. Defaults to False.
|
|
289
|
+
"""
|
|
290
|
+
self._diff(other, force_print=force_print)
|
|
291
|
+
|
|
292
|
+
def update(self) -> None:
|
|
293
|
+
"""Updates the existing IED based on any altered attributes"""
|
|
294
|
+
|
|
295
|
+
self._update()
|
|
296
|
+
|
|
297
|
+
def save(self, filepath: str | Path) -> None:
|
|
298
|
+
"""Saves the IED to the given location, if pointing to an existing file it will be overwritten.
|
|
299
|
+
Once saved, the IED() class will continue working from the saved location, therefore any further calls to IED.update() will update in the latest saved location
|
|
300
|
+
rather than the original source IED used to construct the class"""
|
|
301
|
+
|
|
302
|
+
self._save(filepath)
|