floodmodeller-api 0.5.1__py3-none-any.whl → 0.5.2__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 (86) hide show
  1. floodmodeller_api/__init__.py +10 -0
  2. floodmodeller_api/_base.py +29 -20
  3. floodmodeller_api/backup.py +12 -10
  4. floodmodeller_api/dat.py +162 -91
  5. floodmodeller_api/diff.py +1 -1
  6. floodmodeller_api/hydrology_plus/hydrology_plus_export.py +1 -1
  7. floodmodeller_api/ied.py +2 -4
  8. floodmodeller_api/ief.py +29 -17
  9. floodmodeller_api/ief_flags.py +1 -1
  10. floodmodeller_api/inp.py +4 -6
  11. floodmodeller_api/logs/lf.py +18 -12
  12. floodmodeller_api/logs/lf_helpers.py +2 -2
  13. floodmodeller_api/logs/lf_params.py +1 -5
  14. floodmodeller_api/mapping.py +9 -2
  15. floodmodeller_api/test/test_conveyance.py +9 -4
  16. floodmodeller_api/test/test_dat.py +166 -18
  17. floodmodeller_api/test/test_data/EX18_DAT_expected.json +164 -144
  18. floodmodeller_api/test/test_data/EX3_DAT_expected.json +6 -2
  19. floodmodeller_api/test/test_data/EX6_DAT_expected.json +12 -46
  20. floodmodeller_api/test/test_data/encoding_test_cp1252.dat +1081 -0
  21. floodmodeller_api/test/test_data/encoding_test_utf8.dat +1081 -0
  22. floodmodeller_api/test/test_data/integrated_bridge/AR_NoSP_NoBl_2O_NO_OneFRC.ied +33 -0
  23. floodmodeller_api/test/test_data/integrated_bridge/AR_vSP_25pc_1O.ied +32 -0
  24. floodmodeller_api/test/test_data/integrated_bridge/PL_vSP_25pc_1O.ied +34 -0
  25. floodmodeller_api/test/test_data/integrated_bridge/SBTwoFRCsStaggered.IED +32 -0
  26. floodmodeller_api/test/test_data/integrated_bridge/US_NoSP_NoBl_OR_RN.ied +28 -0
  27. floodmodeller_api/test/test_data/integrated_bridge/US_SP_NoBl_OR_frc_PT2-5_RN.ied +34 -0
  28. floodmodeller_api/test/test_data/integrated_bridge/US_fSP_NoBl_1O.ied +30 -0
  29. floodmodeller_api/test/test_data/integrated_bridge/US_nSP_NoBl_1O.ied +49 -0
  30. floodmodeller_api/test/test_data/integrated_bridge/US_vSP_NoBl_2O_Para.ied +35 -0
  31. floodmodeller_api/test/test_data/integrated_bridge.dat +40 -0
  32. floodmodeller_api/test/test_data/network.ied +2 -2
  33. floodmodeller_api/test/test_data/network_dat_expected.json +141 -243
  34. floodmodeller_api/test/test_data/network_ied_expected.json +2 -2
  35. floodmodeller_api/test/test_data/network_with_comments.ied +2 -2
  36. floodmodeller_api/test/test_ied.py +1 -1
  37. floodmodeller_api/test/test_ief.py +10 -2
  38. floodmodeller_api/test/test_integrated_bridge.py +159 -0
  39. floodmodeller_api/test/test_json.py +9 -3
  40. floodmodeller_api/test/test_logs_lf.py +45 -24
  41. floodmodeller_api/test/test_river.py +1 -1
  42. floodmodeller_api/test/test_toolbox_structure_log.py +0 -1
  43. floodmodeller_api/test/test_xml2d.py +5 -5
  44. floodmodeller_api/to_from_json.py +1 -1
  45. floodmodeller_api/tool.py +3 -5
  46. floodmodeller_api/toolbox/model_build/add_siltation_definition.py +1 -1
  47. floodmodeller_api/toolbox/model_build/structure_log/structure_log.py +12 -8
  48. floodmodeller_api/units/__init__.py +15 -0
  49. floodmodeller_api/units/_base.py +73 -10
  50. floodmodeller_api/units/_helpers.py +343 -0
  51. floodmodeller_api/units/boundaries.py +59 -71
  52. floodmodeller_api/units/comment.py +1 -1
  53. floodmodeller_api/units/conduits.py +57 -54
  54. floodmodeller_api/units/connectors.py +112 -0
  55. floodmodeller_api/units/controls.py +107 -0
  56. floodmodeller_api/units/iic.py +2 -9
  57. floodmodeller_api/units/losses.py +42 -42
  58. floodmodeller_api/units/sections.py +40 -43
  59. floodmodeller_api/units/structures.py +360 -530
  60. floodmodeller_api/units/units.py +25 -26
  61. floodmodeller_api/units/unsupported.py +5 -7
  62. floodmodeller_api/units/variables.py +2 -2
  63. floodmodeller_api/urban1d/_base.py +7 -8
  64. floodmodeller_api/urban1d/conduits.py +11 -21
  65. floodmodeller_api/urban1d/general_parameters.py +1 -1
  66. floodmodeller_api/urban1d/junctions.py +7 -11
  67. floodmodeller_api/urban1d/losses.py +13 -17
  68. floodmodeller_api/urban1d/outfalls.py +16 -21
  69. floodmodeller_api/urban1d/raingauges.py +3 -9
  70. floodmodeller_api/urban1d/subsections.py +3 -4
  71. floodmodeller_api/urban1d/xsections.py +11 -15
  72. floodmodeller_api/util.py +7 -4
  73. floodmodeller_api/validation/parameters.py +7 -3
  74. floodmodeller_api/validation/urban_parameters.py +1 -4
  75. floodmodeller_api/validation/validation.py +9 -4
  76. floodmodeller_api/version.py +1 -1
  77. floodmodeller_api/xml2d.py +9 -11
  78. floodmodeller_api/xml2d_template.py +1 -1
  79. floodmodeller_api/zz.py +7 -6
  80. {floodmodeller_api-0.5.1.dist-info → floodmodeller_api-0.5.2.dist-info}/LICENSE.txt +1 -1
  81. {floodmodeller_api-0.5.1.dist-info → floodmodeller_api-0.5.2.dist-info}/METADATA +11 -3
  82. {floodmodeller_api-0.5.1.dist-info → floodmodeller_api-0.5.2.dist-info}/RECORD +85 -70
  83. {floodmodeller_api-0.5.1.dist-info → floodmodeller_api-0.5.2.dist-info}/WHEEL +1 -1
  84. floodmodeller_api/units/helpers.py +0 -121
  85. {floodmodeller_api-0.5.1.dist-info → floodmodeller_api-0.5.2.dist-info}/entry_points.txt +0 -0
  86. {floodmodeller_api-0.5.1.dist-info → floodmodeller_api-0.5.2.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  """
2
2
  Flood Modeller Python API
3
- Copyright (C) 2024 Jacobs U.K. Limited
3
+ Copyright (C) 2025 Jacobs U.K. Limited
4
4
 
5
5
  This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
6
6
  as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
@@ -16,22 +16,22 @@ address: Jacobs UK Limited, Flood Modeller, Cottons Centre, Cottons Lane, London
16
16
 
17
17
  from __future__ import annotations
18
18
 
19
- from typing import ClassVar
19
+ import logging
20
20
 
21
21
  import pandas as pd
22
22
 
23
23
  from floodmodeller_api.validation import _validate_unit
24
24
 
25
25
  from ._base import Unit
26
- from .conveyance import calculate_cross_section_conveyance_cached
27
- from .helpers import (
28
- _to_float,
29
- _to_int,
26
+ from ._helpers import (
30
27
  join_10_char,
31
28
  join_n_char_ljust,
32
29
  split_10_char,
33
30
  split_n_char,
31
+ to_float,
32
+ to_int,
34
33
  )
34
+ from .conveyance import calculate_cross_section_conveyance_cached
35
35
 
36
36
 
37
37
  class RIVER(Unit):
@@ -58,7 +58,7 @@ class RIVER(Unit):
58
58
  """
59
59
 
60
60
  _unit = "RIVER"
61
- _required_columns: ClassVar[list[str]] = [
61
+ _required_columns = (
62
62
  "X",
63
63
  "Y",
64
64
  "Mannings n",
@@ -69,7 +69,7 @@ class RIVER(Unit):
69
69
  "Northing",
70
70
  "Deactivation",
71
71
  "SP. Marker",
72
- ]
72
+ )
73
73
 
74
74
  def _create_from_blank( # noqa: PLR0913
75
75
  self,
@@ -104,24 +104,18 @@ class RIVER(Unit):
104
104
  }.items():
105
105
  setattr(self, param, val)
106
106
 
107
- self._data = (
108
- data
109
- if isinstance(data, pd.DataFrame)
110
- else pd.DataFrame(
111
- [],
112
- columns=self._required_columns,
113
- )
114
- )
107
+ self._data = self._enforce_dataframe(data, self._required_columns)
115
108
  self._active_data = None
116
109
 
117
110
  def _read(self, riv_block):
118
111
  """Function to read a given RIVER block and store data as class attributes."""
119
112
 
120
113
  self._subtype = riv_block[1].split(" ")[0].strip()
114
+ # Extends label line to be correct length before splitting to pick up blank labels
115
+ labels = split_n_char(f"{riv_block[2]:<{7*self._label_len}}", self._label_len)
116
+
121
117
  # Only supporting 'SECTION' subtype for now
122
118
  if self.subtype == "SECTION":
123
- # Extends label line to be correct length before splitting to pick up blank labels
124
- labels = split_n_char(f"{riv_block[2]:<{7*self._label_len}}", self._label_len)
125
119
  self.name = labels[0]
126
120
  self.spill1 = labels[1]
127
121
  self.spill2 = labels[2]
@@ -129,19 +123,19 @@ class RIVER(Unit):
129
123
  self.lat2 = labels[4]
130
124
  self.lat3 = labels[5]
131
125
  self.lat4 = labels[6]
132
- self.comment = riv_block[0].replace("RIVER", "").strip()
126
+ self.comment = self._remove_unit_name(riv_block[0])
133
127
 
134
128
  params = split_10_char(f"{riv_block[3]:<40}")
135
- self.dist_to_next = _to_float(params[0])
136
- self.slope = _to_float(params[2], 0.0001)
137
- self.density = _to_float(params[3], 1000.0)
129
+ self.dist_to_next = to_float(params[0])
130
+ self.slope = to_float(params[2], 0.0001)
131
+ self.density = to_float(params[3], 1000.0)
138
132
  self.nrows = int(split_10_char(riv_block[4])[0])
139
133
  data_list = []
140
134
  for row in riv_block[5:]:
141
135
  row_split = split_10_char(f"{row:<100}")
142
- x = _to_float(row_split[0]) # chainage
143
- y = _to_float(row_split[1]) # elevation
144
- n = _to_float(row_split[2]) # Mannings
136
+ x = to_float(row_split[0]) # chainage
137
+ y = to_float(row_split[1]) # elevation
138
+ n = to_float(row_split[2]) # Mannings
145
139
  try:
146
140
  # panel marker
147
141
  panel = row_split[3][0] == "*"
@@ -150,15 +144,15 @@ class RIVER(Unit):
150
144
 
151
145
  try:
152
146
  # relative path length
153
- rpl = _to_float(row_split[3][1 if panel else 0 :].strip())
147
+ rpl = to_float(row_split[3][1 if panel else 0 :].strip())
154
148
  except IndexError:
155
149
  rpl = 0.000
156
150
  marker = row_split[4] # Marker
157
- easting = _to_float(row_split[5]) # easting
158
- northing = _to_float(row_split[6]) # northing
151
+ easting = to_float(row_split[5]) # easting
152
+ northing = to_float(row_split[6]) # northing
159
153
 
160
154
  deactivation = row_split[7] # deactivation marker
161
- sp_marker = _to_int(row_split[8]) # special marker
155
+ sp_marker = to_int(row_split[8]) # special marker
162
156
  data_list.append(
163
157
  [
164
158
  x,
@@ -180,11 +174,14 @@ class RIVER(Unit):
180
174
 
181
175
  else:
182
176
  # This else block is triggered for river subtypes which aren't yet supported, and just keeps the 'riv_block' in it's raw state to write back.
183
- print(
184
- f'This River sub-type: "{self.subtype}" is currently unsupported for reading/editing',
177
+ logging.warning(
178
+ "This River sub-type: '%s' is currently unsupported for reading/editing",
179
+ self.subtype,
185
180
  )
186
181
  self._raw_block = riv_block
187
182
  self.name = riv_block[2][: self._label_len].strip()
183
+ self.dist_to_next = to_float(riv_block[3][:10])
184
+ self.labels = labels
188
185
 
189
186
  self._active_data = None
190
187
 
@@ -194,7 +191,7 @@ class RIVER(Unit):
194
191
  if self.subtype == "SECTION":
195
192
  # Function to check the params are valid for RIVER SECTION unit
196
193
  _validate_unit(self)
197
- header = "RIVER " + self.comment
194
+ header = self._create_header()
198
195
  labels = join_n_char_ljust(
199
196
  self._label_len,
200
197
  self.name,
@@ -384,19 +381,19 @@ class INTERPOLATE(Unit):
384
381
  self.lat2 = labels[4]
385
382
  self.lat3 = labels[5]
386
383
  self.lat4 = labels[6]
387
- self.comment = block[0].replace("INTERPOLATE", "").strip()
384
+ self.comment = self._remove_unit_name(block[0])
388
385
 
389
386
  # First parameter line
390
387
  params1 = split_10_char(f"{block[2]:<30}")
391
- self.dist_to_next = _to_float(params1[0])
392
- self.easting = _to_float(params1[1])
393
- self.northing = _to_float(params1[2])
388
+ self.dist_to_next = to_float(params1[0])
389
+ self.easting = to_float(params1[1])
390
+ self.northing = to_float(params1[2])
394
391
 
395
392
  def _write(self):
396
393
  """Function to write a valid INTERPOLATE block"""
397
394
 
398
395
  _validate_unit(self)
399
- header = "INTERPOLATE " + self.comment
396
+ header = self._create_header()
400
397
  labels = join_n_char_ljust(
401
398
  self._label_len,
402
399
  self.name,
@@ -480,20 +477,20 @@ class REPLICATE(Unit):
480
477
  self.lat3 = labels[5]
481
478
  self.lat4 = labels[6]
482
479
 
483
- self.comment = block[0].replace("REPLICATE", "").strip()
480
+ self.comment = self._remove_unit_name(block[0])
484
481
 
485
482
  # First parameter line
486
483
  params1 = split_10_char(f"{block[2]:<40}")
487
- self.dist_to_next = _to_float(params1[0])
488
- self.bed_level_drop = _to_float(params1[1])
489
- self.easting = _to_float(params1[2])
490
- self.northing = _to_float(params1[3])
484
+ self.dist_to_next = to_float(params1[0])
485
+ self.bed_level_drop = to_float(params1[1])
486
+ self.easting = to_float(params1[2])
487
+ self.northing = to_float(params1[3])
491
488
 
492
489
  def _write(self):
493
490
  """Function to write a valid REPLICATE block"""
494
491
 
495
492
  _validate_unit(self)
496
- header = "REPLICATE " + self.comment
493
+ header = self._create_header()
497
494
  labels = join_n_char_ljust(
498
495
  self._label_len,
499
496
  self.name,