floodmodeller-api 0.4.2.post1__py3-none-any.whl → 0.4.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- floodmodeller_api/__init__.py +8 -9
- floodmodeller_api/_base.py +184 -176
- floodmodeller_api/backup.py +273 -273
- floodmodeller_api/dat.py +909 -831
- floodmodeller_api/diff.py +136 -119
- floodmodeller_api/ied.py +307 -306
- floodmodeller_api/ief.py +647 -637
- floodmodeller_api/ief_flags.py +253 -253
- floodmodeller_api/inp.py +266 -266
- floodmodeller_api/libs/libifcoremd.dll +0 -0
- floodmodeller_api/libs/libifcoremt.so.5 +0 -0
- floodmodeller_api/libs/libifport.so.5 +0 -0
- floodmodeller_api/{libmmd.dll → libs/libimf.so} +0 -0
- floodmodeller_api/libs/libintlc.so.5 +0 -0
- floodmodeller_api/libs/libmmd.dll +0 -0
- floodmodeller_api/libs/libsvml.so +0 -0
- floodmodeller_api/libs/libzzn_read.so +0 -0
- floodmodeller_api/libs/zzn_read.dll +0 -0
- floodmodeller_api/logs/__init__.py +2 -2
- floodmodeller_api/logs/lf.py +320 -312
- floodmodeller_api/logs/lf_helpers.py +354 -352
- floodmodeller_api/logs/lf_params.py +643 -529
- floodmodeller_api/mapping.py +84 -0
- floodmodeller_api/test/__init__.py +4 -4
- floodmodeller_api/test/conftest.py +9 -8
- floodmodeller_api/test/test_backup.py +117 -117
- floodmodeller_api/test/test_dat.py +221 -92
- floodmodeller_api/test/test_data/All Units 4_6.DAT +1081 -1081
- floodmodeller_api/test/test_data/All Units 4_6.feb +1081 -1081
- floodmodeller_api/test/test_data/BRIDGE.DAT +926 -926
- floodmodeller_api/test/test_data/Culvert_Inlet_Outlet.dat +36 -36
- floodmodeller_api/test/test_data/Culvert_Inlet_Outlet.feb +36 -36
- floodmodeller_api/test/test_data/DamBreakADI.xml +52 -52
- floodmodeller_api/test/test_data/DamBreakFAST.xml +58 -58
- floodmodeller_api/test/test_data/DamBreakFAST_dy.xml +53 -53
- floodmodeller_api/test/test_data/DamBreakTVD.xml +55 -55
- floodmodeller_api/test/test_data/DefenceBreach.xml +53 -53
- floodmodeller_api/test/test_data/DefenceBreachFAST.xml +60 -60
- floodmodeller_api/test/test_data/DefenceBreachFAST_dy.xml +55 -55
- floodmodeller_api/test/test_data/Domain1+2_QH.xml +76 -76
- floodmodeller_api/test/test_data/Domain1_H.xml +41 -41
- floodmodeller_api/test/test_data/Domain1_Q.xml +41 -41
- floodmodeller_api/test/test_data/Domain1_Q_FAST.xml +48 -48
- floodmodeller_api/test/test_data/Domain1_Q_FAST_dy.xml +48 -48
- floodmodeller_api/test/test_data/Domain1_Q_xml_expected.json +263 -0
- floodmodeller_api/test/test_data/Domain1_W.xml +41 -41
- floodmodeller_api/test/test_data/EX1.DAT +321 -321
- floodmodeller_api/test/test_data/EX1.ext +107 -107
- floodmodeller_api/test/test_data/EX1.feb +320 -320
- floodmodeller_api/test/test_data/EX1.gxy +107 -107
- floodmodeller_api/test/test_data/EX17.DAT +421 -422
- floodmodeller_api/test/test_data/EX17.ext +213 -213
- floodmodeller_api/test/test_data/EX17.feb +422 -422
- floodmodeller_api/test/test_data/EX18.DAT +375 -375
- floodmodeller_api/test/test_data/EX18_DAT_expected.json +3876 -0
- floodmodeller_api/test/test_data/EX2.DAT +302 -302
- floodmodeller_api/test/test_data/EX3.DAT +926 -926
- floodmodeller_api/test/test_data/EX3_DAT_expected.json +16235 -0
- floodmodeller_api/test/test_data/EX3_IEF_expected.json +61 -0
- floodmodeller_api/test/test_data/EX6.DAT +2084 -2084
- floodmodeller_api/test/test_data/EX6.ext +532 -532
- floodmodeller_api/test/test_data/EX6.feb +2084 -2084
- floodmodeller_api/test/test_data/EX6_DAT_expected.json +31647 -0
- floodmodeller_api/test/test_data/Event Data Example.DAT +336 -336
- floodmodeller_api/test/test_data/Event Data Example.ext +107 -107
- floodmodeller_api/test/test_data/Event Data Example.feb +336 -336
- floodmodeller_api/test/test_data/Linked1D2D.xml +52 -52
- floodmodeller_api/test/test_data/Linked1D2DFAST.xml +53 -53
- floodmodeller_api/test/test_data/Linked1D2DFAST_dy.xml +48 -48
- floodmodeller_api/test/test_data/Linked1D2D_xml_expected.json +313 -0
- floodmodeller_api/test/test_data/blockage.dat +50 -50
- floodmodeller_api/test/test_data/blockage.ext +45 -45
- floodmodeller_api/test/test_data/blockage.feb +9 -9
- floodmodeller_api/test/test_data/blockage.gxy +71 -71
- floodmodeller_api/test/test_data/defaultUnits.dat +127 -127
- floodmodeller_api/test/test_data/defaultUnits.ext +45 -45
- floodmodeller_api/test/test_data/defaultUnits.feb +9 -9
- floodmodeller_api/test/test_data/defaultUnits.fmpx +58 -58
- floodmodeller_api/test/test_data/defaultUnits.gxy +85 -85
- floodmodeller_api/test/test_data/ex3.ief +20 -20
- floodmodeller_api/test/test_data/ex3.lf1 +2800 -2800
- floodmodeller_api/test/test_data/ex4.DAT +1374 -1374
- floodmodeller_api/test/test_data/ex4_changed.DAT +1374 -1374
- floodmodeller_api/test/test_data/example1.inp +329 -329
- floodmodeller_api/test/test_data/example2.inp +158 -158
- floodmodeller_api/test/test_data/example3.inp +297 -297
- floodmodeller_api/test/test_data/example4.inp +388 -388
- floodmodeller_api/test/test_data/example5.inp +147 -147
- floodmodeller_api/test/test_data/example6.inp +154 -154
- floodmodeller_api/test/test_data/jump.dat +176 -176
- floodmodeller_api/test/test_data/network.dat +1374 -1374
- floodmodeller_api/test/test_data/network.ext +45 -45
- floodmodeller_api/test/test_data/network.exy +1 -1
- floodmodeller_api/test/test_data/network.feb +45 -45
- floodmodeller_api/test/test_data/network.ied +45 -45
- floodmodeller_api/test/test_data/network.ief +20 -20
- floodmodeller_api/test/test_data/network.inp +147 -147
- floodmodeller_api/test/test_data/network.pxy +57 -57
- floodmodeller_api/test/test_data/network.zzd +122 -122
- floodmodeller_api/test/test_data/network_dat_expected.json +21837 -0
- floodmodeller_api/test/test_data/network_from_tabularCSV.csv +87 -87
- floodmodeller_api/test/test_data/network_ied_expected.json +287 -0
- floodmodeller_api/test/test_data/rnweir.dat +9 -9
- floodmodeller_api/test/test_data/rnweir.ext +45 -45
- floodmodeller_api/test/test_data/rnweir.feb +9 -9
- floodmodeller_api/test/test_data/rnweir.gxy +45 -45
- floodmodeller_api/test/test_data/rnweir_default.dat +74 -74
- floodmodeller_api/test/test_data/rnweir_default.ext +45 -45
- floodmodeller_api/test/test_data/rnweir_default.feb +9 -9
- floodmodeller_api/test/test_data/rnweir_default.fmpx +58 -58
- floodmodeller_api/test/test_data/rnweir_default.gxy +53 -53
- floodmodeller_api/test/test_data/unit checks.dat +16 -16
- floodmodeller_api/test/test_ied.py +29 -29
- floodmodeller_api/test/test_ief.py +125 -24
- floodmodeller_api/test/test_inp.py +47 -48
- floodmodeller_api/test/test_json.py +114 -0
- floodmodeller_api/test/test_logs_lf.py +48 -51
- floodmodeller_api/test/test_tool.py +165 -152
- floodmodeller_api/test/test_toolbox_structure_log.py +234 -239
- floodmodeller_api/test/test_xml2d.py +151 -156
- floodmodeller_api/test/test_zzn.py +36 -34
- floodmodeller_api/to_from_json.py +218 -0
- floodmodeller_api/tool.py +332 -329
- floodmodeller_api/toolbox/__init__.py +5 -5
- floodmodeller_api/toolbox/example_tool.py +45 -45
- floodmodeller_api/toolbox/model_build/__init__.py +2 -2
- floodmodeller_api/toolbox/model_build/add_siltation_definition.py +100 -98
- floodmodeller_api/toolbox/model_build/structure_log/__init__.py +1 -1
- floodmodeller_api/toolbox/model_build/structure_log/structure_log.py +287 -289
- floodmodeller_api/toolbox/model_build/structure_log_definition.py +76 -76
- floodmodeller_api/units/__init__.py +10 -10
- floodmodeller_api/units/_base.py +214 -212
- floodmodeller_api/units/boundaries.py +467 -467
- floodmodeller_api/units/comment.py +52 -55
- floodmodeller_api/units/conduits.py +382 -402
- floodmodeller_api/units/helpers.py +123 -131
- floodmodeller_api/units/iic.py +107 -101
- floodmodeller_api/units/losses.py +305 -306
- floodmodeller_api/units/sections.py +444 -446
- floodmodeller_api/units/structures.py +1690 -1683
- floodmodeller_api/units/units.py +93 -104
- floodmodeller_api/units/unsupported.py +44 -44
- floodmodeller_api/units/variables.py +87 -89
- floodmodeller_api/urban1d/__init__.py +11 -11
- floodmodeller_api/urban1d/_base.py +188 -179
- floodmodeller_api/urban1d/conduits.py +93 -85
- floodmodeller_api/urban1d/general_parameters.py +58 -58
- floodmodeller_api/urban1d/junctions.py +81 -79
- floodmodeller_api/urban1d/losses.py +81 -74
- floodmodeller_api/urban1d/outfalls.py +114 -110
- floodmodeller_api/urban1d/raingauges.py +111 -111
- floodmodeller_api/urban1d/subsections.py +92 -98
- floodmodeller_api/urban1d/xsections.py +147 -144
- floodmodeller_api/util.py +77 -21
- floodmodeller_api/validation/parameters.py +660 -660
- floodmodeller_api/validation/urban_parameters.py +388 -404
- floodmodeller_api/validation/validation.py +110 -108
- floodmodeller_api/version.py +1 -1
- floodmodeller_api/xml2d.py +688 -673
- floodmodeller_api/xml2d_template.py +37 -37
- floodmodeller_api/zzn.py +387 -363
- {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.3.dist-info}/LICENSE.txt +13 -13
- {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.3.dist-info}/METADATA +82 -82
- floodmodeller_api-0.4.3.dist-info/RECORD +179 -0
- {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.3.dist-info}/WHEEL +1 -1
- floodmodeller_api/libifcoremd.dll +0 -0
- floodmodeller_api/test/test_data/EX3.bmp +0 -0
- floodmodeller_api/test/test_data/test_output.csv +0 -87
- floodmodeller_api/zzn_read.dll +0 -0
- floodmodeller_api-0.4.2.post1.dist-info/RECORD +0 -164
- {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.3.dist-info}/entry_points.txt +0 -0
- {floodmodeller_api-0.4.2.post1.dist-info → floodmodeller_api-0.4.3.dist-info}/top_level.txt +0 -0
floodmodeller_api/inp.py
CHANGED
|
@@ -1,266 +1,266 @@
|
|
|
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
|
-
from
|
|
20
|
-
|
|
21
|
-
from .
|
|
22
|
-
from .
|
|
23
|
-
from .
|
|
24
|
-
from .
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
"\n".join(self._raw_data)
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
== "
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
line.
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
)
|
|
173
|
-
|
|
174
|
-
# Create appropriate sub-class instences for supported units
|
|
175
|
-
elif (
|
|
176
|
-
subsections.SUPPORTED_SUBSECTIONS[block["Subsection_Type"]]["group"] == "units"
|
|
177
|
-
):
|
|
178
|
-
subsection_class = subsections.SUPPORTED_SUBSECTIONS[block["Subsection_Type"]][
|
|
179
|
-
"class"
|
|
180
|
-
]
|
|
181
|
-
|
|
182
|
-
subsection_attribute = subsections.SUPPORTED_SUBSECTIONS[
|
|
183
|
-
block["Subsection_Type"]
|
|
184
|
-
]["attribute"]
|
|
185
|
-
|
|
186
|
-
setattr(
|
|
187
|
-
self,
|
|
188
|
-
subsection_attribute,
|
|
189
|
-
subsection_class(raw_subsection_data),
|
|
190
|
-
)
|
|
191
|
-
subsection = getattr(self, subsection_attribute)
|
|
192
|
-
subsection_units = getattr(subsection, subsection._attribute)
|
|
193
|
-
setattr(self, subsection._attribute, subsection_units)
|
|
194
|
-
|
|
195
|
-
# No action if subsection not supported. Leave block as raw data
|
|
196
|
-
|
|
197
|
-
def _update_inp_struct(self):
|
|
198
|
-
"""Internal method used to update self._inp_struct which details the overall structure of the inp file as a list of blocks, each of which
|
|
199
|
-
are a dictionary containing the 'start', 'end' and 'type' of the block.
|
|
200
|
-
|
|
201
|
-
"""
|
|
202
|
-
# Generate INP file structure
|
|
203
|
-
inp_struct = []
|
|
204
|
-
in_block = False
|
|
205
|
-
unit_block = {}
|
|
206
|
-
for idx, line in enumerate(self._raw_data):
|
|
207
|
-
# TODO: Add functionality to compare first four characters only (alphanumeric) - need to consider names shorter than 4 characters, and those with _ within name
|
|
208
|
-
|
|
209
|
-
# Check if subsection is known
|
|
210
|
-
if line.upper() in subsections.ALL_SUBSECTIONS:
|
|
211
|
-
if in_block is True:
|
|
212
|
-
unit_block["end"] = idx - 1 # add ending index
|
|
213
|
-
inp_struct.append(unit_block) # append existing block bdy to the inp_struct
|
|
214
|
-
unit_block = {} # reset bdy block
|
|
215
|
-
|
|
216
|
-
unit_block["Subsection_Type"] = line.upper()
|
|
217
|
-
unit_block["start"] = idx
|
|
218
|
-
in_block = True
|
|
219
|
-
|
|
220
|
-
if len(unit_block) != 0:
|
|
221
|
-
# Only adds end block if there is a block present (i.e. an empty inp stays empty)
|
|
222
|
-
# add ending index for final block
|
|
223
|
-
unit_block["end"] = len(self._raw_data) - 1
|
|
224
|
-
inp_struct.append(unit_block) # add final block
|
|
225
|
-
|
|
226
|
-
self._inp_struct = inp_struct
|
|
227
|
-
|
|
228
|
-
def diff(self, other:
|
|
229
|
-
"""Compares the INP class against another INP class to check whether they are
|
|
230
|
-
equivalent, or if not, what the differences are. Two instances of an INP class are
|
|
231
|
-
deemed equivalent if all of their attributes are equal except for the filepath and
|
|
232
|
-
raw data. For example, two INP files from different filepaths that had the same
|
|
233
|
-
data except maybe some differences in decimal places and some default parameters
|
|
234
|
-
ommitted, would be classed as equaivalent as they would produce the same INP instance
|
|
235
|
-
and write the exact same data.
|
|
236
|
-
|
|
237
|
-
The result is printed to the console. If you need to access the returned data, use
|
|
238
|
-
the method ``INP._get_diff()``
|
|
239
|
-
|
|
240
|
-
Args:
|
|
241
|
-
other (floodmodeller_api.INP): Other instance of an INP class
|
|
242
|
-
force_print (bool): Forces the API to print every difference found, rather than
|
|
243
|
-
just the first 25 differences. Defaults to False.
|
|
244
|
-
"""
|
|
245
|
-
self._diff(other, force_print=force_print)
|
|
246
|
-
|
|
247
|
-
def update(self) -> None:
|
|
248
|
-
"""Updates the existing INP based on any altered attributes"""
|
|
249
|
-
|
|
250
|
-
self._update()
|
|
251
|
-
|
|
252
|
-
def save(self, filepath:
|
|
253
|
-
"""Saves the INP to the given location, if pointing to an existing file it will be overwritten.
|
|
254
|
-
Once saved, the INP() class will continue working from the saved location, therefore any further calls to INP.update() will
|
|
255
|
-
update in the latest saved location rather than the original source INP used to construct the class
|
|
256
|
-
|
|
257
|
-
Args:
|
|
258
|
-
filepath (str): Filepath to new save location including the name and '.inp' extension
|
|
259
|
-
|
|
260
|
-
Raises:
|
|
261
|
-
TypeError: Raised if given filepath doesn't point to a file suffixed '.inp'
|
|
262
|
-
|
|
263
|
-
"""
|
|
264
|
-
|
|
265
|
-
filepath = Path(filepath).absolute()
|
|
266
|
-
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 pathlib import Path
|
|
20
|
+
|
|
21
|
+
from . import units
|
|
22
|
+
from ._base import FMFile
|
|
23
|
+
from .units.helpers import _to_str, join_n_char_ljust
|
|
24
|
+
from .urban1d import subsections
|
|
25
|
+
from .urban1d.general_parameters import DEFAULT_OPTIONS
|
|
26
|
+
from .validation import _validate_unit
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class INP(FMFile):
|
|
30
|
+
"""Reads and writes Flood Modeller 1DUrban file format '.inp'
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
inp_filepath (str, optional): Full filepath to inp file. If not specified, a new INP class will be created. Defaults to None.
|
|
34
|
+
|
|
35
|
+
Output:
|
|
36
|
+
Initiates 'INP' class object
|
|
37
|
+
|
|
38
|
+
Raises:
|
|
39
|
+
TypeError: Raised if inp_filepath does not point to a .inp file
|
|
40
|
+
FileNotFoundError: Raised if inp_filepath points to a file which does not exist
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
_filetype: str = "INP"
|
|
44
|
+
_suffix: str = ".inp"
|
|
45
|
+
|
|
46
|
+
def __init__(self, inp_filepath: str | Path | None = None, from_json: bool = False):
|
|
47
|
+
try:
|
|
48
|
+
if from_json:
|
|
49
|
+
return
|
|
50
|
+
if inp_filepath is not None:
|
|
51
|
+
FMFile.__init__(self, inp_filepath)
|
|
52
|
+
self._read()
|
|
53
|
+
|
|
54
|
+
else:
|
|
55
|
+
self._create_from_blank()
|
|
56
|
+
|
|
57
|
+
self._get_section_definitions()
|
|
58
|
+
except Exception as e:
|
|
59
|
+
self._handle_exception(e, when="read")
|
|
60
|
+
|
|
61
|
+
def _read(self):
|
|
62
|
+
# Read INP file
|
|
63
|
+
with open(self._filepath) as inp_file:
|
|
64
|
+
self._raw_data = [line.rstrip("\n") for line in inp_file.readlines()]
|
|
65
|
+
|
|
66
|
+
# Generate INP file structure
|
|
67
|
+
self._update_inp_struct()
|
|
68
|
+
|
|
69
|
+
def _write(self) -> str:
|
|
70
|
+
"""Returns string representation of the current INP data
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
str: Full string representation of INP in its most recent state (including changes not yet saved to disk)
|
|
74
|
+
"""
|
|
75
|
+
try:
|
|
76
|
+
_validate_unit(self, urban=True)
|
|
77
|
+
|
|
78
|
+
block_shift = 0 # Used to allow changes in the length of subsections.
|
|
79
|
+
|
|
80
|
+
for block in self._inp_struct:
|
|
81
|
+
if block["Subsection_Type"] in subsections.SUPPORTED_SUBSECTIONS:
|
|
82
|
+
subsection_data = self._raw_data[
|
|
83
|
+
block["start"] + block_shift : block["end"] + 1 + block_shift
|
|
84
|
+
]
|
|
85
|
+
prev_block_len = len(subsection_data)
|
|
86
|
+
|
|
87
|
+
if (
|
|
88
|
+
subsections.SUPPORTED_SUBSECTIONS[block["Subsection_Type"]]["group"]
|
|
89
|
+
== "general"
|
|
90
|
+
):
|
|
91
|
+
# General parameters
|
|
92
|
+
|
|
93
|
+
if block["Subsection_Type"] == "[OPTIONS]":
|
|
94
|
+
# Options subsection
|
|
95
|
+
|
|
96
|
+
new_subsection_data = [
|
|
97
|
+
"[OPTIONS]",
|
|
98
|
+
";;Option Value",
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
for param, value in self.options.items():
|
|
102
|
+
if value is not None:
|
|
103
|
+
option_line = join_n_char_ljust(21, param.upper(), value)
|
|
104
|
+
new_subsection_data.append(option_line)
|
|
105
|
+
|
|
106
|
+
new_subsection_data.append("") # blank line before next section
|
|
107
|
+
|
|
108
|
+
else: # Of unit type
|
|
109
|
+
subsection = getattr(
|
|
110
|
+
self,
|
|
111
|
+
subsections.SUPPORTED_SUBSECTIONS[block["Subsection_Type"]][
|
|
112
|
+
"attribute"
|
|
113
|
+
],
|
|
114
|
+
) # Get unit object
|
|
115
|
+
new_subsection_data = (
|
|
116
|
+
subsection._write()
|
|
117
|
+
) # String representation of unit object
|
|
118
|
+
|
|
119
|
+
new_block_len = len(new_subsection_data)
|
|
120
|
+
|
|
121
|
+
self._raw_data[
|
|
122
|
+
block["start"] + block_shift : block["end"] + 1 + block_shift
|
|
123
|
+
] = new_subsection_data # Replace existing subsection with new subsection string
|
|
124
|
+
block_shift += (
|
|
125
|
+
new_block_len - prev_block_len
|
|
126
|
+
) # adjust block shift for change in number of lines in block
|
|
127
|
+
|
|
128
|
+
# Regenerate INP file structure
|
|
129
|
+
self._update_inp_struct()
|
|
130
|
+
|
|
131
|
+
# Write _raw_data out to INP file.
|
|
132
|
+
return "\n".join(self._raw_data) + "\n"
|
|
133
|
+
|
|
134
|
+
except Exception as e:
|
|
135
|
+
self._handle_exception(e, when="write")
|
|
136
|
+
|
|
137
|
+
def _create_from_blank(self):
|
|
138
|
+
raise NotImplementedError(
|
|
139
|
+
"Creating new 1D urban models (INP files) is not yet supported by floodmodeller_api, only existing models can be read",
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
def _get_section_definitions(self):
|
|
143
|
+
"""Internal method used to get section definitions for each supported unit type and general parameters."""
|
|
144
|
+
|
|
145
|
+
# Loop through all blocks (subsections) within INP and process if of a supported type.
|
|
146
|
+
for block in self._inp_struct:
|
|
147
|
+
if block["Subsection_Type"] in subsections.SUPPORTED_SUBSECTIONS:
|
|
148
|
+
raw_subsection_data = self._raw_data[
|
|
149
|
+
block["start"] : block["end"] + 1
|
|
150
|
+
] # Raw data for subsection block of INP file
|
|
151
|
+
|
|
152
|
+
# Check if subsection type is 'general'
|
|
153
|
+
if (
|
|
154
|
+
subsections.SUPPORTED_SUBSECTIONS[block["Subsection_Type"]]["group"]
|
|
155
|
+
== "general"
|
|
156
|
+
):
|
|
157
|
+
if block["Subsection_Type"] == "[OPTIONS]":
|
|
158
|
+
self.options = DEFAULT_OPTIONS.copy()
|
|
159
|
+
for line in raw_subsection_data:
|
|
160
|
+
if (
|
|
161
|
+
line.upper() not in subsections.SUPPORTED_SUBSECTIONS
|
|
162
|
+
and line.strip() != ""
|
|
163
|
+
and not line.startswith(";")
|
|
164
|
+
):
|
|
165
|
+
data = units.helpers.split_n_char(line, 21)
|
|
166
|
+
|
|
167
|
+
# Set type to Float or Stirng, as appropirate.
|
|
168
|
+
self.options[data[0].lower()] = _to_str(
|
|
169
|
+
data[1],
|
|
170
|
+
None,
|
|
171
|
+
check_float=True,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# Create appropriate sub-class instences for supported units
|
|
175
|
+
elif (
|
|
176
|
+
subsections.SUPPORTED_SUBSECTIONS[block["Subsection_Type"]]["group"] == "units"
|
|
177
|
+
):
|
|
178
|
+
subsection_class = subsections.SUPPORTED_SUBSECTIONS[block["Subsection_Type"]][
|
|
179
|
+
"class"
|
|
180
|
+
]
|
|
181
|
+
|
|
182
|
+
subsection_attribute = subsections.SUPPORTED_SUBSECTIONS[
|
|
183
|
+
block["Subsection_Type"]
|
|
184
|
+
]["attribute"]
|
|
185
|
+
|
|
186
|
+
setattr(
|
|
187
|
+
self,
|
|
188
|
+
subsection_attribute,
|
|
189
|
+
subsection_class(raw_subsection_data),
|
|
190
|
+
)
|
|
191
|
+
subsection = getattr(self, subsection_attribute)
|
|
192
|
+
subsection_units = getattr(subsection, subsection._attribute)
|
|
193
|
+
setattr(self, subsection._attribute, subsection_units)
|
|
194
|
+
|
|
195
|
+
# No action if subsection not supported. Leave block as raw data
|
|
196
|
+
|
|
197
|
+
def _update_inp_struct(self):
|
|
198
|
+
"""Internal method used to update self._inp_struct which details the overall structure of the inp file as a list of blocks, each of which
|
|
199
|
+
are a dictionary containing the 'start', 'end' and 'type' of the block.
|
|
200
|
+
|
|
201
|
+
"""
|
|
202
|
+
# Generate INP file structure
|
|
203
|
+
inp_struct = []
|
|
204
|
+
in_block = False
|
|
205
|
+
unit_block = {}
|
|
206
|
+
for idx, line in enumerate(self._raw_data):
|
|
207
|
+
# TODO: Add functionality to compare first four characters only (alphanumeric) - need to consider names shorter than 4 characters, and those with _ within name
|
|
208
|
+
|
|
209
|
+
# Check if subsection is known
|
|
210
|
+
if line.upper() in subsections.ALL_SUBSECTIONS:
|
|
211
|
+
if in_block is True:
|
|
212
|
+
unit_block["end"] = idx - 1 # add ending index
|
|
213
|
+
inp_struct.append(unit_block) # append existing block bdy to the inp_struct
|
|
214
|
+
unit_block = {} # reset bdy block
|
|
215
|
+
|
|
216
|
+
unit_block["Subsection_Type"] = line.upper()
|
|
217
|
+
unit_block["start"] = idx
|
|
218
|
+
in_block = True
|
|
219
|
+
|
|
220
|
+
if len(unit_block) != 0:
|
|
221
|
+
# Only adds end block if there is a block present (i.e. an empty inp stays empty)
|
|
222
|
+
# add ending index for final block
|
|
223
|
+
unit_block["end"] = len(self._raw_data) - 1
|
|
224
|
+
inp_struct.append(unit_block) # add final block
|
|
225
|
+
|
|
226
|
+
self._inp_struct = inp_struct
|
|
227
|
+
|
|
228
|
+
def diff(self, other: INP, force_print: bool = False) -> None:
|
|
229
|
+
"""Compares the INP class against another INP class to check whether they are
|
|
230
|
+
equivalent, or if not, what the differences are. Two instances of an INP class are
|
|
231
|
+
deemed equivalent if all of their attributes are equal except for the filepath and
|
|
232
|
+
raw data. For example, two INP files from different filepaths that had the same
|
|
233
|
+
data except maybe some differences in decimal places and some default parameters
|
|
234
|
+
ommitted, would be classed as equaivalent as they would produce the same INP instance
|
|
235
|
+
and write the exact same data.
|
|
236
|
+
|
|
237
|
+
The result is printed to the console. If you need to access the returned data, use
|
|
238
|
+
the method ``INP._get_diff()``
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
other (floodmodeller_api.INP): Other instance of an INP class
|
|
242
|
+
force_print (bool): Forces the API to print every difference found, rather than
|
|
243
|
+
just the first 25 differences. Defaults to False.
|
|
244
|
+
"""
|
|
245
|
+
self._diff(other, force_print=force_print)
|
|
246
|
+
|
|
247
|
+
def update(self) -> None:
|
|
248
|
+
"""Updates the existing INP based on any altered attributes"""
|
|
249
|
+
|
|
250
|
+
self._update()
|
|
251
|
+
|
|
252
|
+
def save(self, filepath: str | Path) -> None:
|
|
253
|
+
"""Saves the INP to the given location, if pointing to an existing file it will be overwritten.
|
|
254
|
+
Once saved, the INP() class will continue working from the saved location, therefore any further calls to INP.update() will
|
|
255
|
+
update in the latest saved location rather than the original source INP used to construct the class
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
filepath (str): Filepath to new save location including the name and '.inp' extension
|
|
259
|
+
|
|
260
|
+
Raises:
|
|
261
|
+
TypeError: Raised if given filepath doesn't point to a file suffixed '.inp'
|
|
262
|
+
|
|
263
|
+
"""
|
|
264
|
+
|
|
265
|
+
filepath = Path(filepath).absolute()
|
|
266
|
+
self._save(filepath)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
from .lf import LF1, LF2, lf_factory
|
|
2
|
-
from .lf_params import error_2d_dict
|
|
1
|
+
from .lf import LF1, LF2, lf_factory
|
|
2
|
+
from .lf_params import error_2d_dict
|