floodmodeller-api 0.4.2__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.
Files changed (178) hide show
  1. floodmodeller_api/__init__.py +8 -9
  2. floodmodeller_api/_base.py +184 -176
  3. floodmodeller_api/backup.py +273 -273
  4. floodmodeller_api/dat.py +909 -838
  5. floodmodeller_api/diff.py +136 -119
  6. floodmodeller_api/ied.py +307 -311
  7. floodmodeller_api/ief.py +647 -646
  8. floodmodeller_api/ief_flags.py +253 -253
  9. floodmodeller_api/inp.py +266 -268
  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 +320 -314
  21. floodmodeller_api/logs/lf_helpers.py +354 -346
  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 +9 -8
  26. floodmodeller_api/test/test_backup.py +117 -117
  27. floodmodeller_api/test/test_dat.py +221 -92
  28. floodmodeller_api/test/test_data/All Units 4_6.DAT +1081 -1081
  29. floodmodeller_api/test/test_data/All Units 4_6.feb +1081 -1081
  30. floodmodeller_api/test/test_data/BRIDGE.DAT +926 -926
  31. floodmodeller_api/test/test_data/Culvert_Inlet_Outlet.dat +36 -36
  32. floodmodeller_api/test/test_data/Culvert_Inlet_Outlet.feb +36 -36
  33. floodmodeller_api/test/test_data/DamBreakADI.xml +52 -52
  34. floodmodeller_api/test/test_data/DamBreakFAST.xml +58 -58
  35. floodmodeller_api/test/test_data/DamBreakFAST_dy.xml +53 -53
  36. floodmodeller_api/test/test_data/DamBreakTVD.xml +55 -55
  37. floodmodeller_api/test/test_data/DefenceBreach.xml +53 -53
  38. floodmodeller_api/test/test_data/DefenceBreachFAST.xml +60 -60
  39. floodmodeller_api/test/test_data/DefenceBreachFAST_dy.xml +55 -55
  40. floodmodeller_api/test/test_data/Domain1+2_QH.xml +76 -76
  41. floodmodeller_api/test/test_data/Domain1_H.xml +41 -41
  42. floodmodeller_api/test/test_data/Domain1_Q.xml +41 -41
  43. floodmodeller_api/test/test_data/Domain1_Q_FAST.xml +48 -48
  44. floodmodeller_api/test/test_data/Domain1_Q_FAST_dy.xml +48 -48
  45. floodmodeller_api/test/test_data/Domain1_Q_xml_expected.json +263 -0
  46. floodmodeller_api/test/test_data/Domain1_W.xml +41 -41
  47. floodmodeller_api/test/test_data/EX1.DAT +321 -321
  48. floodmodeller_api/test/test_data/EX1.ext +107 -107
  49. floodmodeller_api/test/test_data/EX1.feb +320 -320
  50. floodmodeller_api/test/test_data/EX1.gxy +107 -107
  51. floodmodeller_api/test/test_data/EX17.DAT +421 -422
  52. floodmodeller_api/test/test_data/EX17.ext +213 -213
  53. floodmodeller_api/test/test_data/EX17.feb +422 -422
  54. floodmodeller_api/test/test_data/EX18.DAT +375 -375
  55. floodmodeller_api/test/test_data/EX18_DAT_expected.json +3876 -0
  56. floodmodeller_api/test/test_data/EX2.DAT +302 -302
  57. floodmodeller_api/test/test_data/EX3.DAT +926 -926
  58. floodmodeller_api/test/test_data/EX3_DAT_expected.json +16235 -0
  59. floodmodeller_api/test/test_data/EX3_IEF_expected.json +61 -0
  60. floodmodeller_api/test/test_data/EX6.DAT +2084 -2084
  61. floodmodeller_api/test/test_data/EX6.ext +532 -532
  62. floodmodeller_api/test/test_data/EX6.feb +2084 -2084
  63. floodmodeller_api/test/test_data/EX6_DAT_expected.json +31647 -0
  64. floodmodeller_api/test/test_data/Event Data Example.DAT +336 -336
  65. floodmodeller_api/test/test_data/Event Data Example.ext +107 -107
  66. floodmodeller_api/test/test_data/Event Data Example.feb +336 -336
  67. floodmodeller_api/test/test_data/Linked1D2D.xml +52 -52
  68. floodmodeller_api/test/test_data/Linked1D2DFAST.xml +53 -53
  69. floodmodeller_api/test/test_data/Linked1D2DFAST_dy.xml +48 -48
  70. floodmodeller_api/test/test_data/Linked1D2D_xml_expected.json +313 -0
  71. floodmodeller_api/test/test_data/blockage.dat +50 -50
  72. floodmodeller_api/test/test_data/blockage.ext +45 -45
  73. floodmodeller_api/test/test_data/blockage.feb +9 -9
  74. floodmodeller_api/test/test_data/blockage.gxy +71 -71
  75. floodmodeller_api/test/test_data/defaultUnits.dat +127 -127
  76. floodmodeller_api/test/test_data/defaultUnits.ext +45 -45
  77. floodmodeller_api/test/test_data/defaultUnits.feb +9 -9
  78. floodmodeller_api/test/test_data/defaultUnits.fmpx +58 -58
  79. floodmodeller_api/test/test_data/defaultUnits.gxy +85 -85
  80. floodmodeller_api/test/test_data/ex3.ief +20 -20
  81. floodmodeller_api/test/test_data/ex3.lf1 +2800 -2800
  82. floodmodeller_api/test/test_data/ex4.DAT +1374 -1374
  83. floodmodeller_api/test/test_data/ex4_changed.DAT +1374 -1374
  84. floodmodeller_api/test/test_data/example1.inp +329 -329
  85. floodmodeller_api/test/test_data/example2.inp +158 -158
  86. floodmodeller_api/test/test_data/example3.inp +297 -297
  87. floodmodeller_api/test/test_data/example4.inp +388 -388
  88. floodmodeller_api/test/test_data/example5.inp +147 -147
  89. floodmodeller_api/test/test_data/example6.inp +154 -154
  90. floodmodeller_api/test/test_data/jump.dat +176 -176
  91. floodmodeller_api/test/test_data/network.dat +1374 -1374
  92. floodmodeller_api/test/test_data/network.ext +45 -45
  93. floodmodeller_api/test/test_data/network.exy +1 -1
  94. floodmodeller_api/test/test_data/network.feb +45 -45
  95. floodmodeller_api/test/test_data/network.ied +45 -45
  96. floodmodeller_api/test/test_data/network.ief +20 -20
  97. floodmodeller_api/test/test_data/network.inp +147 -147
  98. floodmodeller_api/test/test_data/network.pxy +57 -57
  99. floodmodeller_api/test/test_data/network.zzd +122 -122
  100. floodmodeller_api/test/test_data/network_dat_expected.json +21837 -0
  101. floodmodeller_api/test/test_data/network_from_tabularCSV.csv +87 -87
  102. floodmodeller_api/test/test_data/network_ied_expected.json +287 -0
  103. floodmodeller_api/test/test_data/rnweir.dat +9 -9
  104. floodmodeller_api/test/test_data/rnweir.ext +45 -45
  105. floodmodeller_api/test/test_data/rnweir.feb +9 -9
  106. floodmodeller_api/test/test_data/rnweir.gxy +45 -45
  107. floodmodeller_api/test/test_data/rnweir_default.dat +74 -74
  108. floodmodeller_api/test/test_data/rnweir_default.ext +45 -45
  109. floodmodeller_api/test/test_data/rnweir_default.feb +9 -9
  110. floodmodeller_api/test/test_data/rnweir_default.fmpx +58 -58
  111. floodmodeller_api/test/test_data/rnweir_default.gxy +53 -53
  112. floodmodeller_api/test/test_data/unit checks.dat +16 -16
  113. floodmodeller_api/test/test_ied.py +29 -29
  114. floodmodeller_api/test/test_ief.py +125 -24
  115. floodmodeller_api/test/test_inp.py +47 -48
  116. floodmodeller_api/test/test_json.py +114 -0
  117. floodmodeller_api/test/test_logs_lf.py +48 -51
  118. floodmodeller_api/test/test_tool.py +165 -154
  119. floodmodeller_api/test/test_toolbox_structure_log.py +234 -239
  120. floodmodeller_api/test/test_xml2d.py +151 -156
  121. floodmodeller_api/test/test_zzn.py +36 -34
  122. floodmodeller_api/to_from_json.py +218 -0
  123. floodmodeller_api/tool.py +332 -330
  124. floodmodeller_api/toolbox/__init__.py +5 -5
  125. floodmodeller_api/toolbox/example_tool.py +45 -45
  126. floodmodeller_api/toolbox/model_build/__init__.py +2 -2
  127. floodmodeller_api/toolbox/model_build/add_siltation_definition.py +100 -94
  128. floodmodeller_api/toolbox/model_build/structure_log/__init__.py +1 -1
  129. floodmodeller_api/toolbox/model_build/structure_log/structure_log.py +287 -289
  130. floodmodeller_api/toolbox/model_build/structure_log_definition.py +76 -72
  131. floodmodeller_api/units/__init__.py +10 -10
  132. floodmodeller_api/units/_base.py +214 -209
  133. floodmodeller_api/units/boundaries.py +467 -469
  134. floodmodeller_api/units/comment.py +52 -55
  135. floodmodeller_api/units/conduits.py +382 -403
  136. floodmodeller_api/units/helpers.py +123 -132
  137. floodmodeller_api/units/iic.py +107 -101
  138. floodmodeller_api/units/losses.py +305 -308
  139. floodmodeller_api/units/sections.py +444 -445
  140. floodmodeller_api/units/structures.py +1690 -1684
  141. floodmodeller_api/units/units.py +93 -102
  142. floodmodeller_api/units/unsupported.py +44 -44
  143. floodmodeller_api/units/variables.py +87 -89
  144. floodmodeller_api/urban1d/__init__.py +11 -11
  145. floodmodeller_api/urban1d/_base.py +188 -177
  146. floodmodeller_api/urban1d/conduits.py +93 -85
  147. floodmodeller_api/urban1d/general_parameters.py +58 -58
  148. floodmodeller_api/urban1d/junctions.py +81 -79
  149. floodmodeller_api/urban1d/losses.py +81 -74
  150. floodmodeller_api/urban1d/outfalls.py +114 -107
  151. floodmodeller_api/urban1d/raingauges.py +111 -108
  152. floodmodeller_api/urban1d/subsections.py +92 -93
  153. floodmodeller_api/urban1d/xsections.py +147 -141
  154. floodmodeller_api/util.py +77 -21
  155. floodmodeller_api/validation/parameters.py +660 -660
  156. floodmodeller_api/validation/urban_parameters.py +388 -404
  157. floodmodeller_api/validation/validation.py +110 -112
  158. floodmodeller_api/version.py +1 -1
  159. floodmodeller_api/xml2d.py +688 -684
  160. floodmodeller_api/xml2d_template.py +37 -37
  161. floodmodeller_api/zzn.py +387 -365
  162. {floodmodeller_api-0.4.2.dist-info → floodmodeller_api-0.4.3.dist-info}/LICENSE.txt +13 -13
  163. {floodmodeller_api-0.4.2.dist-info → floodmodeller_api-0.4.3.dist-info}/METADATA +82 -82
  164. floodmodeller_api-0.4.3.dist-info/RECORD +179 -0
  165. {floodmodeller_api-0.4.2.dist-info → floodmodeller_api-0.4.3.dist-info}/WHEEL +1 -1
  166. floodmodeller_api-0.4.3.dist-info/entry_points.txt +3 -0
  167. floodmodeller_api/libifcoremd.dll +0 -0
  168. floodmodeller_api/test/test_data/EX3.bmp +0 -0
  169. floodmodeller_api/test/test_data/test_output.csv +0 -87
  170. floodmodeller_api/zzn_read.dll +0 -0
  171. floodmodeller_api-0.4.2.data/scripts/fmapi-add_siltation.bat +0 -2
  172. floodmodeller_api-0.4.2.data/scripts/fmapi-add_siltation.py +0 -3
  173. floodmodeller_api-0.4.2.data/scripts/fmapi-structure_log.bat +0 -2
  174. floodmodeller_api-0.4.2.data/scripts/fmapi-structure_log.py +0 -3
  175. floodmodeller_api-0.4.2.data/scripts/fmapi-toolbox.bat +0 -2
  176. floodmodeller_api-0.4.2.data/scripts/fmapi-toolbox.py +0 -41
  177. floodmodeller_api-0.4.2.dist-info/RECORD +0 -169
  178. {floodmodeller_api-0.4.2.dist-info → floodmodeller_api-0.4.3.dist-info}/top_level.txt +0 -0
@@ -1,177 +1,188 @@
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
- """ Holds the base unit class for all FM 1D units Units """
18
-
19
- from ..diff import check_item_with_dataframe_equal
20
-
21
-
22
- class UrbanUnit:
23
- _unit = None
24
- _subtype = None
25
- _name = None
26
-
27
- def __init__(self, unit_block=None, **kwargs):
28
- if unit_block is not None:
29
- self._read(unit_block)
30
- # TODO: add functionality to read description
31
- else:
32
- self._create_from_blank(**kwargs)
33
-
34
- @property
35
- def name(self):
36
- return self._name
37
-
38
- @name.setter
39
- def name(self, new_name):
40
- self._name = new_name
41
-
42
- # Update this bit
43
- def __repr__(self):
44
- if self._subtype is None:
45
- return f"<floodmodeller_api UrbanUnit Class: {self._unit}(name={self._name})>"
46
-
47
- def _create_from_blank(self):
48
- raise NotImplementedError(
49
- f"Creating new {self._unit} units is not yet supported by floodmodeller_api, only existing units can be read"
50
- )
51
-
52
- def __str__(self):
53
- return self._write()
54
-
55
- def _read(self):
56
- raise NotImplementedError
57
-
58
- def _write(self):
59
- raise NotImplementedError
60
-
61
- def _diff(self, other):
62
- diff = self._get_diff(other)
63
- if diff[0]:
64
- print("No difference, units are equivalent")
65
- else:
66
- print("\n".join([f"{name}: {reason}" for name, reason in diff[1]]))
67
-
68
- def _get_diff(self, other):
69
- return self.__eq__(other, return_diff=True)
70
-
71
- def __eq__(self, other, return_diff=False):
72
- result = True
73
- diff = []
74
- result, diff = check_item_with_dataframe_equal(
75
- self.__dict__,
76
- other.__dict__,
77
- name=f"{self._unit}.{self._subtype or ''}.{self._name}",
78
- diff=diff,
79
- )
80
- return (result, diff) if return_diff else result
81
-
82
-
83
- class UrbanSubsection:
84
- _name = None
85
- _urban_unit_class = None
86
-
87
- def __init__(self, subsection_block=None, **kwargs):
88
- if subsection_block is not None:
89
- self._read(subsection_block)
90
- else:
91
- self._create_from_blank(**kwargs)
92
-
93
- @property
94
- def name(self):
95
- return self._name
96
-
97
- @name.setter
98
- def name(self, new_name):
99
- self._name = new_name
100
-
101
- def __repr__(self):
102
- return f"<floodmodeller_api UrbanSubsection Class: {self._attribute}>"
103
-
104
- def _create_from_blank(self):
105
- raise NotImplementedError(
106
- f"Creating new {self._name} subsections is not yet supported by floodmodeller_api, only existing subsections can be read"
107
- )
108
-
109
- def __str__(self):
110
- return "\n".join(self._write())
111
-
112
- def _read(self, block):
113
- setattr(self, self._attribute, {})
114
- units = getattr(self, self._attribute)
115
-
116
- self._struct = []
117
-
118
- for line in block[1:]: # first line is subsection name
119
- if line.strip() != "" and not line.startswith(";"):
120
- unit = self._urban_unit_class(line)
121
- units[unit.name] = unit
122
- self._struct.append(unit)
123
-
124
- else:
125
- self._struct.append(line)
126
-
127
- def _write(self):
128
- block = []
129
-
130
- if self._attribute == "raingauges":
131
- # handle required miss-spelling of raingauge in subsection header
132
- block.append("[" + "RAINGAGES" + "]")
133
-
134
- else:
135
- block.append("[" + self._attribute.upper() + "]")
136
-
137
- for line in self._struct:
138
- if isinstance(line, self._urban_unit_class):
139
- block.append(line._write())
140
- else:
141
- block.append(line)
142
-
143
- units = getattr(self, self._attribute)
144
-
145
- for name, unit in units.copy().items():
146
- if name != unit.name:
147
- # Miss-match found
148
- # check that it is not an existing label in units
149
- if unit.name in units:
150
- raise Exception(
151
- f'Error: Cannot update label "{name}" to "{unit.name}" beacuase "{unit.name}" already exists in the {self._attribute} subsection'
152
- )
153
-
154
- units[unit.name] = unit
155
- del units[name]
156
-
157
- # TODO: update label in any other units where required.
158
-
159
- return block
160
-
161
- def _diff(self, other):
162
- diff = self._get_diff(other)
163
- if diff[0]:
164
- print("No difference, units are equivalent")
165
- else:
166
- print("\n".join([f"{name}: {reason}" for name, reason in diff[1]]))
167
-
168
- def _get_diff(self, other):
169
- return self.__eq__(other, return_diff=True)
170
-
171
- def __eq__(self, other, return_diff=False):
172
- result = True
173
- diff = []
174
- result, diff = check_item_with_dataframe_equal(
175
- self.__dict__, other.__dict__, name=f"{self._attribute.upper()}", diff=diff
176
- )
177
- return (result, diff) if return_diff else result
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
+ """ Holds the base unit class for all FM 1D units Units """
20
+
21
+ from ..diff import check_item_with_dataframe_equal
22
+ from ..to_from_json import Jsonable
23
+
24
+
25
+ class UrbanUnit(Jsonable):
26
+ _unit: str | None = None
27
+ _subtype: str | None = None
28
+ _name: str | None = None
29
+
30
+ def __init__(self, unit_block=None, from_json: bool = False, **kwargs):
31
+ if from_json:
32
+ return
33
+ if unit_block is not None:
34
+ self._read(unit_block)
35
+ # TODO: add functionality to read description
36
+ else:
37
+ self._create_from_blank(**kwargs)
38
+
39
+ @property
40
+ def name(self):
41
+ return self._name
42
+
43
+ @name.setter
44
+ def name(self, new_name):
45
+ self._name = new_name
46
+
47
+ # Update this bit
48
+ def __repr__(self):
49
+ if self._subtype is None:
50
+ return f"<floodmodeller_api UrbanUnit Class: {self._unit}(name={self._name})>"
51
+ return None
52
+
53
+ def _create_from_blank(self):
54
+ raise NotImplementedError(
55
+ f"Creating new {self._unit} units is not yet supported by floodmodeller_api, only existing units can be read",
56
+ )
57
+
58
+ def __str__(self):
59
+ return self._write()
60
+
61
+ def _read(self, unit_block):
62
+ raise NotImplementedError
63
+
64
+ def _write(self):
65
+ raise NotImplementedError
66
+
67
+ def _diff(self, other):
68
+ diff = self._get_diff(other)
69
+ if diff[0]:
70
+ print("No difference, units are equivalent")
71
+ else:
72
+ print("\n".join([f"{name}: {reason}" for name, reason in diff[1]]))
73
+
74
+ def _get_diff(self, other):
75
+ return self.__eq__(other, return_diff=True) # pylint: disable=unnecessary-dunder-call
76
+
77
+ def __eq__(self, other, return_diff=False):
78
+ result = True
79
+ diff = []
80
+ result, diff = check_item_with_dataframe_equal(
81
+ self.__dict__,
82
+ other.__dict__,
83
+ name=f"{self._unit}.{self._subtype or ''}.{self._name}",
84
+ diff=diff,
85
+ )
86
+ return (result, diff) if return_diff else result
87
+
88
+
89
+ class UrbanSubsection(Jsonable):
90
+ _name: str | None = None
91
+ _urban_unit_class: type[UrbanUnit] | None = None
92
+
93
+ def __init__(self, subsection_block=None, from_json: bool = False, **kwargs):
94
+ if from_json:
95
+ return
96
+ if subsection_block is not None:
97
+ self._read(subsection_block)
98
+ else:
99
+ self._create_from_blank(**kwargs)
100
+
101
+ @property
102
+ def name(self):
103
+ return self._name
104
+
105
+ @name.setter
106
+ def name(self, new_name):
107
+ self._name = new_name
108
+
109
+ def __repr__(self):
110
+ return f"<floodmodeller_api UrbanSubsection Class: {self._attribute}>"
111
+
112
+ def _create_from_blank(self):
113
+ raise NotImplementedError(
114
+ f"Creating new {self._name} subsections is not yet supported by floodmodeller_api, only existing subsections can be read",
115
+ )
116
+
117
+ def __str__(self):
118
+ return "\n".join(self._write())
119
+
120
+ def _read(self, block):
121
+ setattr(self, self._attribute, {})
122
+ units = getattr(self, self._attribute)
123
+
124
+ self._struct = []
125
+
126
+ for line in block[1:]: # first line is subsection name
127
+ if line.strip() != "" and not line.startswith(";"):
128
+ unit = self._urban_unit_class(line)
129
+ units[unit.name] = unit
130
+ self._struct.append(unit)
131
+
132
+ else:
133
+ self._struct.append(line)
134
+
135
+ def _write(self):
136
+ block = []
137
+
138
+ if self._attribute == "raingauges":
139
+ # handle required miss-spelling of raingauge in subsection header
140
+ block.append("[" + "RAINGAGES" + "]")
141
+
142
+ else:
143
+ block.append("[" + self._attribute.upper() + "]")
144
+
145
+ for line in self._struct:
146
+ if isinstance(line, self._urban_unit_class):
147
+ block.append(line._write())
148
+ else:
149
+ block.append(line)
150
+
151
+ units = getattr(self, self._attribute)
152
+
153
+ for name, unit in units.copy().items():
154
+ if name != unit.name:
155
+ # Miss-match found
156
+ # check that it is not an existing label in units
157
+ if unit.name in units:
158
+ raise Exception(
159
+ f'Error: Cannot update label "{name}" to "{unit.name}" beacuase "{unit.name}" already exists in the {self._attribute} subsection',
160
+ )
161
+
162
+ units[unit.name] = unit
163
+ del units[name]
164
+
165
+ # TODO: update label in any other units where required.
166
+
167
+ return block
168
+
169
+ def _diff(self, other):
170
+ diff = self._get_diff(other)
171
+ if diff[0]:
172
+ print("No difference, units are equivalent")
173
+ else:
174
+ print("\n".join([f"{name}: {reason}" for name, reason in diff[1]]))
175
+
176
+ def _get_diff(self, other):
177
+ return self.__eq__(other, return_diff=True) # pylint: disable=unnecessary-dunder-call
178
+
179
+ def __eq__(self, other, return_diff=False):
180
+ result = True
181
+ diff = []
182
+ result, diff = check_item_with_dataframe_equal(
183
+ self.__dict__,
184
+ other.__dict__,
185
+ name=f"{self._attribute.upper()}",
186
+ diff=diff,
187
+ )
188
+ return (result, diff) if return_diff else result
@@ -1,85 +1,93 @@
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
- from floodmodeller_api.units.helpers import _to_float, _to_str, join_n_char_ljust
17
- from floodmodeller_api.validation import _validate_unit
18
-
19
- from ._base import UrbanSubsection, UrbanUnit
20
-
21
-
22
- class CONDUIT(UrbanUnit):
23
- """Class to hold and process CONDUIT unit type
24
-
25
- Args:
26
- name (str): Unit name. (required)
27
- node1 (str): Name of upstream node. (required)
28
- node2 (str): Name of downstream node. (required)
29
- length (float): Conduit length (ft or m). (required)
30
- n (float): Mannings n value. (required)
31
- z1 (float): Offset of upstream end of conduit invert above the invert elevation of it's upstream node (ft or m). (required)
32
- z1 (float): Offset of downstream end of conduit invert above the invert elevation of it's downstream node (ft or m). (required)
33
- q0 (float): Flow in conduit at start of simulation (flow units).(optional, default 0)
34
- qmax (float): maximum flow allowed in the conduit (flow units) (optional, default unlimited)
35
-
36
- Returns:
37
- CONDUIT: Flood Modeller CONDUIT Unit class object
38
- """
39
-
40
- _unit = "CONDUIT"
41
-
42
- def _read(self, line):
43
- """Function to read a given CONDUIT line and store data as class attributes"""
44
-
45
- # TODO: add functionality to read comments
46
- # TODO: considering raising an exception if any of the required parameters are missing
47
-
48
- unit_data = line.split() # Get unit parameters
49
-
50
- # Extend length of unit_data if options variables not provided.
51
- while len(unit_data) < 9:
52
- unit_data.append("")
53
-
54
- # TODO: Update defaults. Presently atrbitary defaults added to allow API to work.
55
- # TODO: Consider re-naming variables to more intuitive names. Currently as as per SWMM manual
56
-
57
- self.name = _to_str(unit_data[0], "")
58
- self.node1 = _to_str(unit_data[1], "")
59
- self.node2 = _to_str(unit_data[2], "")
60
- self.length = _to_float(unit_data[3], 0.0)
61
- self.n = _to_float(unit_data[4], 0.0)
62
- self.z1 = _to_float(unit_data[5], 0.0)
63
- self.z2 = _to_float(unit_data[6], 0.0)
64
- self.q0 = _to_float(unit_data[7], 0.0) # Default as per FM
65
- self.qmax = _to_float(unit_data[8], 999999) # No limit
66
-
67
- # TODO: Consider linkage with other associated subsections i.e. [XSECTIONS] and [LOSSES]
68
-
69
- def _write(self):
70
- """Function to write a valid CONDUIT line"""
71
-
72
- _validate_unit(self, urban=True)
73
-
74
- # TODO:Improve indentation format when writing and include header for completeness
75
-
76
- return join_n_char_ljust(17, self.name, self.node1, self.node2) + join_n_char_ljust(
77
- 15, self.length, self.n, self.z1, self.z2, self.q0, self.qmax
78
- )
79
-
80
-
81
- class CONDUITS(UrbanSubsection):
82
- """Class to read/write the table of conduits"""
83
-
84
- _urban_unit_class = CONDUIT
85
- _attribute = "conduits"
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 floodmodeller_api.units.helpers import _to_float, _to_str, join_n_char_ljust
18
+ from floodmodeller_api.validation import _validate_unit
19
+
20
+ from ._base import UrbanSubsection, UrbanUnit
21
+
22
+
23
+ class CONDUIT(UrbanUnit):
24
+ """Class to hold and process CONDUIT unit type
25
+
26
+ Args:
27
+ name (str): Unit name. (required)
28
+ node1 (str): Name of upstream node. (required)
29
+ node2 (str): Name of downstream node. (required)
30
+ length (float): Conduit length (ft or m). (required)
31
+ n (float): Mannings n value. (required)
32
+ z1 (float): Offset of upstream end of conduit invert above the invert elevation of it's upstream node (ft or m). (required)
33
+ z1 (float): Offset of downstream end of conduit invert above the invert elevation of it's downstream node (ft or m). (required)
34
+ q0 (float): Flow in conduit at start of simulation (flow units).(optional, default 0)
35
+ qmax (float): maximum flow allowed in the conduit (flow units) (optional, default unlimited)
36
+
37
+ Returns:
38
+ CONDUIT: Flood Modeller CONDUIT Unit class object
39
+ """
40
+
41
+ _unit = "CONDUIT"
42
+ MIN_LENGTH = 9
43
+
44
+ def _read(self, line):
45
+ """Function to read a given CONDUIT line and store data as class attributes"""
46
+
47
+ # TODO: add functionality to read comments
48
+ # TODO: considering raising an exception if any of the required parameters are missing
49
+
50
+ unit_data = line.split() # Get unit parameters
51
+
52
+ # Extend length of unit_data if options variables not provided.
53
+ while len(unit_data) < self.MIN_LENGTH:
54
+ unit_data.append("")
55
+
56
+ # TODO: Update defaults. Presently atrbitary defaults added to allow API to work.
57
+ # TODO: Consider re-naming variables to more intuitive names. Currently as as per SWMM manual
58
+
59
+ self.name = _to_str(unit_data[0], "")
60
+ self.node1 = _to_str(unit_data[1], "")
61
+ self.node2 = _to_str(unit_data[2], "")
62
+ self.length = _to_float(unit_data[3], 0.0)
63
+ self.n = _to_float(unit_data[4], 0.0)
64
+ self.z1 = _to_float(unit_data[5], 0.0)
65
+ self.z2 = _to_float(unit_data[6], 0.0)
66
+ self.q0 = _to_float(unit_data[7], 0.0) # Default as per FM
67
+ self.qmax = _to_float(unit_data[8], 999999) # No limit
68
+
69
+ # TODO: Consider linkage with other associated subsections i.e. [XSECTIONS] and [LOSSES]
70
+
71
+ def _write(self):
72
+ """Function to write a valid CONDUIT line"""
73
+
74
+ _validate_unit(self, urban=True)
75
+
76
+ # TODO:Improve indentation format when writing and include header for completeness
77
+
78
+ return join_n_char_ljust(17, self.name, self.node1, self.node2) + join_n_char_ljust(
79
+ 15,
80
+ self.length,
81
+ self.n,
82
+ self.z1,
83
+ self.z2,
84
+ self.q0,
85
+ self.qmax,
86
+ )
87
+
88
+
89
+ class CONDUITS(UrbanSubsection):
90
+ """Class to read/write the table of conduits"""
91
+
92
+ _urban_unit_class = CONDUIT
93
+ _attribute = "conduits"