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,403 +1,382 @@
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
-
18
- import pandas as pd
19
-
20
- from floodmodeller_api.validation import _validate_unit
21
-
22
- from ._base import Unit
23
- from .helpers import (
24
- _to_float,
25
- _to_int,
26
- _to_str,
27
- join_10_char,
28
- join_n_char_ljust,
29
- split_10_char,
30
- split_n_char,
31
- )
32
-
33
-
34
- class CONDUIT(Unit):
35
- """The Conduit class supports two conduit sub-types in Flood Modeller: RECTANGULAR and CIRCULAR. Each of these sub-types forms
36
- a unique instance of the class which is differentiated by the `CONDUIT.subtype` attribute. All conduit types have the same common
37
- attributes:
38
-
39
- **Common Attributes**
40
-
41
- Args:
42
- name (str): Conduit section name
43
- spill (str): Spill label
44
- comment (str): Comment included in unit
45
- dist_to_next (float): Distance to next section in metres
46
- subtype (str): Defines the type of conduit unit (*Should not be changed*)
47
-
48
- **Rectangular Type (``CONDUIT.subtype == 'RECTANGULAR'``)**
49
-
50
- Args:
51
- friction_eq (str): Friction equation to use (``'MANNING'`` or ``'COLEBROOK-WHITE'``)
52
- invert (float): Elevation of invert above datum (m)
53
- width (float): Width of conduit (m)
54
- height (float): Height of conduit (m)
55
- use_bottom_slot (str): Whether to include bottom slot (``'ON'``, ``'OFF'`` or ``'GLOBAL'``). Setting it to 'GLOBAL' will use the default option specified in IEF.
56
- bottom_slot_dist (float): Distance of slot top above invert (m)
57
- bottom_slot_depth (float): Total depth of bottom slot (m)
58
- use_top_slot (str): Whether to include top slot (``'ON'``, ``'OFF'`` or ``'GLOBAL'``). Setting it to 'GLOBAL' will use the default option specified in IEF.
59
- top_slot_dist (float): Distance of slot bottom below soffit (m)
60
- top_slot_depth (float): Total depth of top slot (m)
61
- friction_on_invert (float): Friction value for conduit invert
62
- friction_on_walls (float): Friction value for conduit walls
63
- friction_on_soffit (float): Friction value for conduit soffit
64
-
65
- **Circular Type (``CONDUIT.subtype == 'CIRCULAR'``)**
66
-
67
- Args:
68
- friction_eq (str): Friction equation to use (``'MANNING'`` or ``'COLEBROOK-WHITE'``)
69
- invert (float): Elevation of invert above datum (m)
70
- diameter (float): Diameter of conduit (m)
71
- use_bottom_slot (str): Whether to include bottom slot (``'ON'``, ``'OFF'`` or ``'GLOBAL'``). Setting it to 'GLOBAL' will use the default option specified in IEF.
72
- bottom_slot_dist (float): Distance of slot top above invert (m)
73
- bottom_slot_depth (float): Total depth of bottom slot (m)
74
- use_top_slot (str): Whether to include top slot (``'ON'``, ``'OFF'`` or ``'GLOBAL'``). Setting it to 'GLOBAL' will use the default option specified in IEF.
75
- top_slot_dist (float): Distance of slot bottom below soffit (m)
76
- top_slot_depth (float): Total depth of top slot (m)
77
- friction_below_axis (float): Friction value for conduit below axis
78
- friction_above_axis (float): Friction value for conduit above axis
79
-
80
- **Sprung Type (``CONDUIT.subtype == 'SPRUNG'``)**
81
-
82
- Args:
83
- equation (str): Choose between the Manning's formulation and the Colbrook-White's formulation
84
- elevation_invert (float): Height of the conduit above datum (m)
85
- width (float): Width of conduit (m)
86
- height_springing (float): Height of conduit's springing (m)
87
- height_crown (float): Height of conduit's crown (m)
88
- use_bottom_slot (str): Whether to include bottom slot (``'ON'``, ``'OFF'`` or ``'GLOBAL'``). Setting it to 'GLOBAL' will use the default option specified in IEF.
89
- bottom_slot_dist (float): Distance of slot top above invert (m)
90
- bottom_slot_depth (float): Total depth of bottom slot (m)
91
- use_top_slot (str): Whether to include top slot (``'ON'``, ``'OFF'`` or ``'GLOBAL'``). Setting it to 'GLOBAL' will use the default option specified in IEF.
92
- top_slot_dist (float): Distance of slot bottom below soffit (m)
93
- top_slot_depth (float): Total depth of top slot (m)
94
- friction_on_invert (float): Friction value for conduit invert
95
- friction_on_walls (float): Friction value for conduit walls
96
- friction_on_soffit (float): Friction value for conduit soffit
97
-
98
- **Sprungarch Type (``CONDUIT.subtype == 'SPRUNGARCH'``)**
99
-
100
- Args:
101
- equation (str): Choose between the Manning's formulation and the Colbrook-White's formulation
102
- elevation_invert (float): Height of the conduit above datum (m)
103
- width (float): Width of conduit (m)
104
- height_springing (float): Height of conduit's springing (m)
105
- height_crown (float): Height of conduit's crown (m)
106
- use_bottom_slot (str): Whether to include bottom slot (``'ON'``, ``'OFF'`` or ``'GLOBAL'``). Setting it to 'GLOBAL' will use the default option specified in IEF.
107
- bottom_slot_dist (float): Distance of slot top above invert (m)
108
- bottom_slot_depth (float): Total depth of bottom slot (m)
109
- use_top_slot (str): Whether to include top slot (``'ON'``, ``'OFF'`` or ``'GLOBAL'``). Setting it to 'GLOBAL' will use the default option specified in IEF.
110
- top_slot_dist (float): Distance of slot bottom below soffit (m)
111
- top_slot_depth (float): Total depth of top slot (m)
112
- friction_on_invert (float): Friction value for conduit invert
113
- friction_on_walls (float): Friction value for conduit walls
114
- friction_on_soffit (float): Friction value for conduit soffit
115
-
116
- **Section Type (``CONDUIT.subtype == 'SECTION'``)**
117
-
118
- Args:
119
- None - common args attributes only
120
-
121
- Raises:
122
- NotImplementedError: Raised if class is initialised without existing Conduit block (i.e. if attempting to create new
123
- Conduit unit). This will be an option for future releases
124
-
125
- Returns:
126
- CONDUIT: Flood Modeller CONDUIT Unit class object
127
- """
128
-
129
- _unit = "CONDUIT"
130
-
131
- def _create_from_blank(
132
- self,
133
- name="new_unit",
134
- spill="",
135
- comment="",
136
- dist_to_next=0.0,
137
- subtype="SECTION",
138
- friction_eq="MANNING",
139
- invert=0.0,
140
- width=0.0,
141
- height=0.0,
142
- use_bottom_slot="GLOBAL",
143
- bottom_slot_dist=0.0,
144
- bottom_slot_depth=0.0,
145
- use_top_slot="GLOBAL",
146
- top_slot_dist=0.0,
147
- top_slot_depth=0.0,
148
- friction_on_invert=0.0,
149
- friction_on_walls=0.0,
150
- friction_on_soffit=0.0,
151
- diameter=0.0,
152
- friction_above_axis=0.0,
153
- ):
154
- for param, val in {
155
- "name": name,
156
- "spill": spill,
157
- "comment": comment,
158
- "dist_to_next": dist_to_next,
159
- "subtype": subtype,
160
- "friction_eq": friction_eq,
161
- "invert": invert,
162
- "width": width,
163
- "height": height,
164
- "use_bottom_slot": use_bottom_slot,
165
- "bottom_slot_dist": bottom_slot_dist,
166
- "bottom_slot_depth": bottom_slot_depth,
167
- "use_top_slot": use_top_slot,
168
- "top_slot_dist": top_slot_dist,
169
- "top_slot_depth": top_slot_depth,
170
- "friction_on_invert": friction_on_invert,
171
- "friction_on_walls": friction_on_walls,
172
- "friction_on_soffit": friction_on_soffit,
173
- "diameter": diameter,
174
- "friction_above_axis": friction_above_axis,
175
- }.items():
176
- if param == "subtype":
177
- self._subtype = val
178
- else:
179
- setattr(self, param, val)
180
-
181
- def _read(self, c_block):
182
- """Function to read a given CONDUIT block and store data as class attributes"""
183
- self._subtype = c_block[1].split(" ")[0].strip()
184
- # Extends label line to be correct length before splitting to pick up blank labels
185
- labels = split_n_char(f"{c_block[2]:<{2*self._label_len}}", self._label_len)
186
- self.name = labels[0]
187
- self.spill = labels[1]
188
- self.comment = c_block[0].replace("CONDUIT", "").strip()
189
-
190
- # Read CIRCULAR type unit
191
- if self._subtype == "CIRCULAR":
192
- # Read Params
193
- self.dist_to_next = _to_float(split_10_char(c_block[3])[0])
194
- self.friction_eq = c_block[4].strip()
195
- params = split_10_char(f"{c_block[5]:<80}")
196
- self.invert = _to_float(params[0])
197
- self.diameter = _to_float(params[1])
198
- self.use_bottom_slot = _to_str(params[2], "GLOBAL")
199
- self.bottom_slot_dist = _to_float(params[3])
200
- self.bottom_slot_depth = _to_float(params[4])
201
- self.use_top_slot = _to_str(params[5], "GLOBAL")
202
- self.top_slot_dist = _to_float(params[6])
203
- self.top_slot_depth = _to_float(params[7])
204
- friction_params = split_10_char(f"{c_block[6]:<20}")
205
- self.friction_below_axis = _to_float(friction_params[0])
206
- self.friction_above_axis = _to_float(friction_params[1])
207
-
208
- elif self._subtype == "RECTANGULAR":
209
- # Read Params
210
- self.dist_to_next = _to_float(split_10_char(c_block[3])[0])
211
- self.friction_eq = c_block[4].strip()
212
- params = split_10_char(f"{c_block[5]:<90}")
213
- self.invert = _to_float(params[0])
214
- self.width = _to_float(params[1])
215
- self.height = _to_float(params[2])
216
- self.use_bottom_slot = _to_str(params[3], "GLOBAL")
217
- self.bottom_slot_dist = _to_float(params[4])
218
- self.bottom_slot_depth = _to_float(params[5])
219
- self.use_top_slot = _to_str(params[6], "GLOBAL")
220
- self.top_slot_dist = _to_float(params[7])
221
- self.top_slot_depth = _to_float(params[8])
222
- friction_params = split_10_char(f"{c_block[6]:<30}")
223
- self.friction_on_invert = _to_float(friction_params[0])
224
- self.friction_on_walls = _to_float(friction_params[1])
225
- self.friction_on_soffit = _to_float(friction_params[2])
226
-
227
- elif self._subtype == "SPRUNG":
228
- self.dist_to_next = _to_float(split_10_char(c_block[3])[0])
229
- self.equation = _to_str(c_block[4], "MANNING")
230
- params = split_10_char(f"{c_block[5]:<100}")
231
- self.elevation_invert = _to_float(params[0])
232
- self.width = _to_float(params[1])
233
- self.height_springing = _to_float(params[2])
234
- self.height_crown = _to_float(params[3])
235
- self.use_bottom_slot = _to_str(params[4], "GLOBAL")
236
- self.bottom_slot_dist = _to_float(params[5])
237
- self.bottom_slot_depth = _to_float(params[6])
238
- self.use_top_slot = _to_str(params[7], "GLOBAL")
239
- self.top_slot_dist = _to_float(params[8])
240
- self.top_slot_depth = _to_float(params[9])
241
- friction_params = split_10_char(f"{c_block[6]:<30}")
242
- self.friction_on_invert = _to_float(friction_params[0])
243
- self.friction_on_walls = _to_float(friction_params[1])
244
- self.friction_on_soffit = _to_float(friction_params[2])
245
-
246
- elif self._subtype == "SPRUNGARCH":
247
- self.dist_to_next = _to_float(split_10_char(c_block[3])[0])
248
- self.equation = _to_str(c_block[4], "MANNING")
249
- params = split_10_char(f"{c_block[5]:<100}")
250
- self.elevation_invert = _to_float(params[0])
251
- self.width = _to_float(params[1])
252
- self.height_springing = _to_float(params[2])
253
- self.height_crown = _to_float(params[3])
254
- self.use_bottom_slot = _to_str(params[4], "GLOBAL")
255
- self.bottom_slot_dist = _to_float(params[5])
256
- self.bottom_slot_depth = _to_float(params[6])
257
- self.use_top_slot = _to_str(params[7], "GLOBAL")
258
- self.top_slot_dist = _to_float(params[8])
259
- self.top_slot_depth = _to_float(params[9])
260
- friction_params = split_10_char(f"{c_block[6]:<30}")
261
- self.friction_on_invert = _to_float(friction_params[0])
262
- self.friction_on_walls = _to_float(friction_params[1])
263
- self.friction_on_soffit = _to_float(friction_params[2])
264
-
265
- elif self._subtype == "SECTION":
266
- self.dist_to_next = _to_float(split_10_char(c_block[3])[0])
267
- end_index = 5 + _to_int(c_block[4])
268
- x = []
269
- y = []
270
- friction = []
271
- for i in range(5, end_index):
272
- row_data = split_10_char(f"{c_block[i]:<30}")
273
- x.append(_to_float(row_data[0]))
274
- y.append(_to_float(row_data[1]))
275
- friction.append(_to_float(row_data[2]))
276
- self.coords = pd.DataFrame({"x": x, "y": y, "cw_friction": friction})
277
-
278
- else:
279
- # This else block is triggered for conduit subtypes which aren't yet supported, and just keeps the '_block' in it's raw state to write back.
280
- print(
281
- f'This Conduit sub-type: "{self._subtype}" is currently unsupported for reading/editing'
282
- )
283
- self._raw_block = c_block
284
-
285
- def _write(self):
286
- """Function to write a valid CONDUIT block"""
287
- _validate_unit(self) # Function to check the params are valid for CONDUIT unit
288
- header = "CONDUIT " + self.comment
289
- labels = join_n_char_ljust(self._label_len, self.name, self.spill)
290
- c_block = [header, self._subtype, labels]
291
-
292
- if self._subtype == "CIRCULAR":
293
- params = join_10_char(
294
- self.invert,
295
- self.diameter,
296
- self.use_bottom_slot,
297
- self.bottom_slot_dist,
298
- self.bottom_slot_depth,
299
- self.use_top_slot,
300
- self.top_slot_dist,
301
- self.top_slot_depth,
302
- )
303
- friction_params = f"{self.friction_below_axis:>10.4f}{self.friction_above_axis:>10.4f}"
304
- c_block.extend(
305
- [
306
- f"{self.dist_to_next:>10.3f}",
307
- self.friction_eq,
308
- params,
309
- friction_params,
310
- ]
311
- )
312
- return c_block
313
-
314
- elif self._subtype == "RECTANGULAR":
315
- params = join_10_char(
316
- self.invert,
317
- self.width,
318
- self.height,
319
- self.use_bottom_slot,
320
- self.bottom_slot_dist,
321
- self.bottom_slot_depth,
322
- self.use_top_slot,
323
- self.top_slot_dist,
324
- self.top_slot_depth,
325
- )
326
- friction_params = f"{self.friction_on_invert:>10.4f}{self.friction_on_walls:>10.4f}{self.friction_on_soffit:>10.4f}"
327
- c_block.extend(
328
- [
329
- f"{self.dist_to_next:>10.3f}",
330
- self.friction_eq,
331
- params,
332
- friction_params,
333
- ]
334
- )
335
- return c_block
336
-
337
- elif self._subtype == "SPRUNG":
338
- c_block.extend(
339
- [
340
- str(self.dist_to_next),
341
- self.equation,
342
- join_10_char(
343
- self.elevation_invert,
344
- self.width,
345
- self.height_springing,
346
- self.height_crown,
347
- self.use_bottom_slot,
348
- self.bottom_slot_dist,
349
- self.bottom_slot_depth,
350
- self.use_top_slot,
351
- self.top_slot_dist,
352
- self.top_slot_depth,
353
- ),
354
- join_10_char(
355
- self.friction_on_invert,
356
- self.friction_on_walls,
357
- self.friction_on_soffit,
358
- ),
359
- ]
360
- )
361
- return c_block
362
-
363
- elif self._subtype == "SPRUNGARCH":
364
- c_block.extend(
365
- [
366
- str(self.dist_to_next),
367
- self.equation,
368
- join_10_char(
369
- self.elevation_invert,
370
- self.width,
371
- self.height_springing,
372
- self.height_crown,
373
- self.use_bottom_slot,
374
- self.bottom_slot_dist,
375
- self.bottom_slot_depth,
376
- self.use_top_slot,
377
- self.top_slot_dist,
378
- self.top_slot_depth,
379
- ),
380
- join_10_char(
381
- self.friction_on_invert,
382
- self.friction_on_walls,
383
- self.friction_on_soffit,
384
- ),
385
- ]
386
- )
387
- return c_block
388
-
389
- elif self._subtype == "SECTION":
390
- c_block.extend(
391
- [
392
- join_10_char(self.dist_to_next),
393
- join_10_char(len(self.coords)),
394
- ]
395
- )
396
- for index, coord in self.coords.iterrows():
397
- c_block.extend(
398
- [join_10_char(coord.x, coord.y) + join_10_char(coord.cw_friction, dp=6)]
399
- )
400
- return c_block
401
-
402
- else:
403
- return self._raw_block
1
+ """
2
+ Flood Modeller Python API
3
+ Copyright (C) 2024 Jacobs U.K. Limited
4
+
5
+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
6
+ as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
7
+
8
+ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
9
+ of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
10
+
11
+ You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.
12
+
13
+ If you have any query about this program or this License, please contact us at support@floodmodeller.com or write to the following
14
+ address: Jacobs UK Limited, Flood Modeller, Cottons Centre, Cottons Lane, London, SE1 2QG, United Kingdom.
15
+ """
16
+
17
+ import pandas as pd
18
+
19
+ from floodmodeller_api.validation import _validate_unit
20
+
21
+ from ._base import Unit
22
+ from .helpers import (
23
+ _to_float,
24
+ _to_int,
25
+ _to_str,
26
+ join_10_char,
27
+ join_n_char_ljust,
28
+ split_10_char,
29
+ split_n_char,
30
+ )
31
+
32
+
33
+ class CONDUIT(Unit):
34
+ """The Conduit class supports two conduit sub-types in Flood Modeller: RECTANGULAR and CIRCULAR. Each of these sub-types forms
35
+ a unique instance of the class which is differentiated by the `CONDUIT.subtype` attribute. All conduit types have the same common
36
+ attributes:
37
+
38
+ **Common Attributes**
39
+
40
+ Args:
41
+ name (str): Conduit section name
42
+ spill (str): Spill label
43
+ comment (str): Comment included in unit
44
+ dist_to_next (float): Distance to next section in metres
45
+ subtype (str): Defines the type of conduit unit (*Should not be changed*)
46
+
47
+ **Rectangular Type (``CONDUIT.subtype == 'RECTANGULAR'``)**
48
+
49
+ Args:
50
+ friction_eq (str): Friction equation to use (``'MANNING'`` or ``'COLEBROOK-WHITE'``)
51
+ invert (float): Elevation of invert above datum (m)
52
+ width (float): Width of conduit (m)
53
+ height (float): Height of conduit (m)
54
+ use_bottom_slot (str): Whether to include bottom slot (``'ON'``, ``'OFF'`` or ``'GLOBAL'``). Setting it to 'GLOBAL' will use the default option specified in IEF.
55
+ bottom_slot_dist (float): Distance of slot top above invert (m)
56
+ bottom_slot_depth (float): Total depth of bottom slot (m)
57
+ use_top_slot (str): Whether to include top slot (``'ON'``, ``'OFF'`` or ``'GLOBAL'``). Setting it to 'GLOBAL' will use the default option specified in IEF.
58
+ top_slot_dist (float): Distance of slot bottom below soffit (m)
59
+ top_slot_depth (float): Total depth of top slot (m)
60
+ friction_on_invert (float): Friction value for conduit invert
61
+ friction_on_walls (float): Friction value for conduit walls
62
+ friction_on_soffit (float): Friction value for conduit soffit
63
+
64
+ **Circular Type (``CONDUIT.subtype == 'CIRCULAR'``)**
65
+
66
+ Args:
67
+ friction_eq (str): Friction equation to use (``'MANNING'`` or ``'COLEBROOK-WHITE'``)
68
+ invert (float): Elevation of invert above datum (m)
69
+ diameter (float): Diameter of conduit (m)
70
+ use_bottom_slot (str): Whether to include bottom slot (``'ON'``, ``'OFF'`` or ``'GLOBAL'``). Setting it to 'GLOBAL' will use the default option specified in IEF.
71
+ bottom_slot_dist (float): Distance of slot top above invert (m)
72
+ bottom_slot_depth (float): Total depth of bottom slot (m)
73
+ use_top_slot (str): Whether to include top slot (``'ON'``, ``'OFF'`` or ``'GLOBAL'``). Setting it to 'GLOBAL' will use the default option specified in IEF.
74
+ top_slot_dist (float): Distance of slot bottom below soffit (m)
75
+ top_slot_depth (float): Total depth of top slot (m)
76
+ friction_below_axis (float): Friction value for conduit below axis
77
+ friction_above_axis (float): Friction value for conduit above axis
78
+
79
+ **Sprung Type (``CONDUIT.subtype == 'SPRUNG'``)**
80
+
81
+ Args:
82
+ equation (str): Choose between the Manning's formulation and the Colbrook-White's formulation
83
+ elevation_invert (float): Height of the conduit above datum (m)
84
+ width (float): Width of conduit (m)
85
+ height_springing (float): Height of conduit's springing (m)
86
+ height_crown (float): Height of conduit's crown (m)
87
+ use_bottom_slot (str): Whether to include bottom slot (``'ON'``, ``'OFF'`` or ``'GLOBAL'``). Setting it to 'GLOBAL' will use the default option specified in IEF.
88
+ bottom_slot_dist (float): Distance of slot top above invert (m)
89
+ bottom_slot_depth (float): Total depth of bottom slot (m)
90
+ use_top_slot (str): Whether to include top slot (``'ON'``, ``'OFF'`` or ``'GLOBAL'``). Setting it to 'GLOBAL' will use the default option specified in IEF.
91
+ top_slot_dist (float): Distance of slot bottom below soffit (m)
92
+ top_slot_depth (float): Total depth of top slot (m)
93
+ friction_on_invert (float): Friction value for conduit invert
94
+ friction_on_walls (float): Friction value for conduit walls
95
+ friction_on_soffit (float): Friction value for conduit soffit
96
+
97
+ **Sprungarch Type (``CONDUIT.subtype == 'SPRUNGARCH'``)**
98
+
99
+ Args:
100
+ equation (str): Choose between the Manning's formulation and the Colbrook-White's formulation
101
+ elevation_invert (float): Height of the conduit above datum (m)
102
+ width (float): Width of conduit (m)
103
+ height_springing (float): Height of conduit's springing (m)
104
+ height_crown (float): Height of conduit's crown (m)
105
+ use_bottom_slot (str): Whether to include bottom slot (``'ON'``, ``'OFF'`` or ``'GLOBAL'``). Setting it to 'GLOBAL' will use the default option specified in IEF.
106
+ bottom_slot_dist (float): Distance of slot top above invert (m)
107
+ bottom_slot_depth (float): Total depth of bottom slot (m)
108
+ use_top_slot (str): Whether to include top slot (``'ON'``, ``'OFF'`` or ``'GLOBAL'``). Setting it to 'GLOBAL' will use the default option specified in IEF.
109
+ top_slot_dist (float): Distance of slot bottom below soffit (m)
110
+ top_slot_depth (float): Total depth of top slot (m)
111
+ friction_on_invert (float): Friction value for conduit invert
112
+ friction_on_walls (float): Friction value for conduit walls
113
+ friction_on_soffit (float): Friction value for conduit soffit
114
+
115
+ **Section Type (``CONDUIT.subtype == 'SECTION'``)**
116
+
117
+ Args:
118
+ None - common args attributes only
119
+
120
+ Raises:
121
+ NotImplementedError: Raised if class is initialised without existing Conduit block (i.e. if attempting to create new
122
+ Conduit unit). This will be an option for future releases
123
+
124
+ Returns:
125
+ CONDUIT: Flood Modeller CONDUIT Unit class object
126
+ """
127
+
128
+ _unit = "CONDUIT"
129
+
130
+ def _create_from_blank( # noqa: PLR0913
131
+ self,
132
+ name="new_unit",
133
+ spill="",
134
+ comment="",
135
+ dist_to_next=0.0,
136
+ subtype="SECTION",
137
+ friction_eq="MANNING",
138
+ invert=0.0,
139
+ width=0.0,
140
+ height=0.0,
141
+ use_bottom_slot="GLOBAL",
142
+ bottom_slot_dist=0.0,
143
+ bottom_slot_depth=0.0,
144
+ use_top_slot="GLOBAL",
145
+ top_slot_dist=0.0,
146
+ top_slot_depth=0.0,
147
+ friction_on_invert=0.0,
148
+ friction_on_walls=0.0,
149
+ friction_on_soffit=0.0,
150
+ diameter=0.0,
151
+ friction_above_axis=0.0,
152
+ ):
153
+ for param, val in {
154
+ "name": name,
155
+ "spill": spill,
156
+ "comment": comment,
157
+ "dist_to_next": dist_to_next,
158
+ "subtype": subtype,
159
+ "friction_eq": friction_eq,
160
+ "invert": invert,
161
+ "width": width,
162
+ "height": height,
163
+ "use_bottom_slot": use_bottom_slot,
164
+ "bottom_slot_dist": bottom_slot_dist,
165
+ "bottom_slot_depth": bottom_slot_depth,
166
+ "use_top_slot": use_top_slot,
167
+ "top_slot_dist": top_slot_dist,
168
+ "top_slot_depth": top_slot_depth,
169
+ "friction_on_invert": friction_on_invert,
170
+ "friction_on_walls": friction_on_walls,
171
+ "friction_on_soffit": friction_on_soffit,
172
+ "diameter": diameter,
173
+ "friction_above_axis": friction_above_axis,
174
+ }.items():
175
+ if param == "subtype":
176
+ self._subtype = val
177
+ else:
178
+ setattr(self, param, val)
179
+
180
+ def _read(self, c_block): # noqa: PLR0915
181
+ """Function to read a given CONDUIT block and store data as class attributes"""
182
+ self._subtype = c_block[1].split(" ")[0].strip()
183
+ # Extends label line to be correct length before splitting to pick up blank labels
184
+ labels = split_n_char(f"{c_block[2]:<{2*self._label_len}}", self._label_len)
185
+ self.name = labels[0]
186
+ self.spill = labels[1]
187
+ self.comment = c_block[0].replace("CONDUIT", "").strip()
188
+
189
+ # Read CIRCULAR type unit
190
+ if self._subtype == "CIRCULAR":
191
+ # Read Params
192
+ self.dist_to_next = _to_float(split_10_char(c_block[3])[0])
193
+ self.friction_eq = c_block[4].strip()
194
+ params = split_10_char(f"{c_block[5]:<80}")
195
+ self.invert = _to_float(params[0])
196
+ self.diameter = _to_float(params[1])
197
+ self.use_bottom_slot = _to_str(params[2], "GLOBAL")
198
+ self.bottom_slot_dist = _to_float(params[3])
199
+ self.bottom_slot_depth = _to_float(params[4])
200
+ self.use_top_slot = _to_str(params[5], "GLOBAL")
201
+ self.top_slot_dist = _to_float(params[6])
202
+ self.top_slot_depth = _to_float(params[7])
203
+ friction_params = split_10_char(f"{c_block[6]:<20}")
204
+ self.friction_below_axis = _to_float(friction_params[0])
205
+ self.friction_above_axis = _to_float(friction_params[1])
206
+
207
+ elif self._subtype == "RECTANGULAR":
208
+ # Read Params
209
+ self.dist_to_next = _to_float(split_10_char(c_block[3])[0])
210
+ self.friction_eq = c_block[4].strip()
211
+ params = split_10_char(f"{c_block[5]:<90}")
212
+ self.invert = _to_float(params[0])
213
+ self.width = _to_float(params[1])
214
+ self.height = _to_float(params[2])
215
+ self.use_bottom_slot = _to_str(params[3], "GLOBAL")
216
+ self.bottom_slot_dist = _to_float(params[4])
217
+ self.bottom_slot_depth = _to_float(params[5])
218
+ self.use_top_slot = _to_str(params[6], "GLOBAL")
219
+ self.top_slot_dist = _to_float(params[7])
220
+ self.top_slot_depth = _to_float(params[8])
221
+ friction_params = split_10_char(f"{c_block[6]:<30}")
222
+ self.friction_on_invert = _to_float(friction_params[0])
223
+ self.friction_on_walls = _to_float(friction_params[1])
224
+ self.friction_on_soffit = _to_float(friction_params[2])
225
+
226
+ elif self._subtype in ("SPRUNG", "SPRUNGARCH"):
227
+ self.dist_to_next = _to_float(split_10_char(c_block[3])[0])
228
+ self.equation = _to_str(c_block[4], "MANNING")
229
+ params = split_10_char(f"{c_block[5]:<100}")
230
+ self.elevation_invert = _to_float(params[0])
231
+ self.width = _to_float(params[1])
232
+ self.height_springing = _to_float(params[2])
233
+ self.height_crown = _to_float(params[3])
234
+ self.use_bottom_slot = _to_str(params[4], "GLOBAL")
235
+ self.bottom_slot_dist = _to_float(params[5])
236
+ self.bottom_slot_depth = _to_float(params[6])
237
+ self.use_top_slot = _to_str(params[7], "GLOBAL")
238
+ self.top_slot_dist = _to_float(params[8])
239
+ self.top_slot_depth = _to_float(params[9])
240
+ friction_params = split_10_char(f"{c_block[6]:<30}")
241
+ self.friction_on_invert = _to_float(friction_params[0])
242
+ self.friction_on_walls = _to_float(friction_params[1])
243
+ self.friction_on_soffit = _to_float(friction_params[2])
244
+
245
+ elif self._subtype == "SECTION":
246
+ self.dist_to_next = _to_float(split_10_char(c_block[3])[0])
247
+ end_index = 5 + _to_int(c_block[4])
248
+ x = []
249
+ y = []
250
+ friction = []
251
+ for i in range(5, end_index):
252
+ row_data = split_10_char(f"{c_block[i]:<30}")
253
+ x.append(_to_float(row_data[0]))
254
+ y.append(_to_float(row_data[1]))
255
+ friction.append(_to_float(row_data[2]))
256
+ self.coords = pd.DataFrame({"x": x, "y": y, "cw_friction": friction})
257
+
258
+ else:
259
+ # This else block is triggered for conduit subtypes which aren't yet supported, and just keeps the '_block' in it's raw state to write back.
260
+ print(
261
+ f'This Conduit sub-type: "{self._subtype}" is currently unsupported for reading/editing',
262
+ )
263
+ self._raw_block = c_block
264
+
265
+ def _write(self):
266
+ """Function to write a valid CONDUIT block"""
267
+ _validate_unit(self) # Function to check the params are valid for CONDUIT unit
268
+ header = "CONDUIT " + self.comment
269
+ labels = join_n_char_ljust(self._label_len, self.name, self.spill)
270
+ c_block = [header, self._subtype, labels]
271
+
272
+ if self._subtype == "CIRCULAR":
273
+ params = join_10_char(
274
+ self.invert,
275
+ self.diameter,
276
+ self.use_bottom_slot,
277
+ self.bottom_slot_dist,
278
+ self.bottom_slot_depth,
279
+ self.use_top_slot,
280
+ self.top_slot_dist,
281
+ self.top_slot_depth,
282
+ )
283
+ friction_params = f"{self.friction_below_axis:>10.4f}{self.friction_above_axis:>10.4f}"
284
+ c_block.extend(
285
+ [
286
+ f"{self.dist_to_next:>10.3f}",
287
+ self.friction_eq,
288
+ params,
289
+ friction_params,
290
+ ],
291
+ )
292
+ return c_block
293
+
294
+ if self._subtype == "RECTANGULAR":
295
+ params = join_10_char(
296
+ self.invert,
297
+ self.width,
298
+ self.height,
299
+ self.use_bottom_slot,
300
+ self.bottom_slot_dist,
301
+ self.bottom_slot_depth,
302
+ self.use_top_slot,
303
+ self.top_slot_dist,
304
+ self.top_slot_depth,
305
+ )
306
+ friction_params = f"{self.friction_on_invert:>10.4f}{self.friction_on_walls:>10.4f}{self.friction_on_soffit:>10.4f}"
307
+ c_block.extend(
308
+ [
309
+ f"{self.dist_to_next:>10.3f}",
310
+ self.friction_eq,
311
+ params,
312
+ friction_params,
313
+ ],
314
+ )
315
+ return c_block
316
+
317
+ if self._subtype == "SPRUNG":
318
+ c_block.extend(
319
+ [
320
+ str(self.dist_to_next),
321
+ self.equation,
322
+ join_10_char(
323
+ self.elevation_invert,
324
+ self.width,
325
+ self.height_springing,
326
+ self.height_crown,
327
+ self.use_bottom_slot,
328
+ self.bottom_slot_dist,
329
+ self.bottom_slot_depth,
330
+ self.use_top_slot,
331
+ self.top_slot_dist,
332
+ self.top_slot_depth,
333
+ ),
334
+ join_10_char(
335
+ self.friction_on_invert,
336
+ self.friction_on_walls,
337
+ self.friction_on_soffit,
338
+ ),
339
+ ],
340
+ )
341
+ return c_block
342
+
343
+ if self._subtype == "SPRUNGARCH":
344
+ c_block.extend(
345
+ [
346
+ str(self.dist_to_next),
347
+ self.equation,
348
+ join_10_char(
349
+ self.elevation_invert,
350
+ self.width,
351
+ self.height_springing,
352
+ self.height_crown,
353
+ self.use_bottom_slot,
354
+ self.bottom_slot_dist,
355
+ self.bottom_slot_depth,
356
+ self.use_top_slot,
357
+ self.top_slot_dist,
358
+ self.top_slot_depth,
359
+ ),
360
+ join_10_char(
361
+ self.friction_on_invert,
362
+ self.friction_on_walls,
363
+ self.friction_on_soffit,
364
+ ),
365
+ ],
366
+ )
367
+ return c_block
368
+
369
+ if self._subtype == "SECTION":
370
+ c_block.extend(
371
+ [
372
+ join_10_char(self.dist_to_next),
373
+ join_10_char(len(self.coords)),
374
+ ],
375
+ )
376
+ for _, coord in self.coords.iterrows():
377
+ c_block.extend(
378
+ [join_10_char(coord.x, coord.y) + join_10_char(coord.cw_friction, dp=6)],
379
+ )
380
+ return c_block
381
+
382
+ return self._raw_block