easysewer 0.0.1__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.
- easysewer/Area.py +294 -0
- easysewer/Curve.py +119 -0
- easysewer/Link.py +294 -0
- easysewer/Node.py +346 -0
- easysewer/Options.py +373 -0
- easysewer/OutputAPI.py +179 -0
- easysewer/Rain.py +209 -0
- easysewer/SolverAPI.py +154 -0
- easysewer/UDM.py +126 -0
- easysewer/__init__.py +7 -0
- easysewer/libs/linux/libswmm5.so +0 -0
- easysewer/libs/linux/swmm-output.so +0 -0
- easysewer/libs/win/swmm-output.dll +0 -0
- easysewer/libs/win/swmm5.dll +0 -0
- easysewer/utils.py +97 -0
- easysewer-0.0.1.dist-info/METADATA +16 -0
- easysewer-0.0.1.dist-info/RECORD +19 -0
- easysewer-0.0.1.dist-info/WHEEL +5 -0
- easysewer-0.0.1.dist-info/top_level.txt +1 -0
easysewer/Area.py
ADDED
@@ -0,0 +1,294 @@
|
|
1
|
+
"""
|
2
|
+
Subcatchment Area Management Module
|
3
|
+
|
4
|
+
This module handles subcatchment areas in the drainage network, including their
|
5
|
+
physical characteristics, infiltration parameters, and routing behavior.
|
6
|
+
"""
|
7
|
+
from .utils import *
|
8
|
+
|
9
|
+
|
10
|
+
class InfiltrationHorton:
|
11
|
+
def __init__(self):
|
12
|
+
self.maximum_rate = 50 # mm/h
|
13
|
+
self.minimum_rate = 5 # mm/h
|
14
|
+
self.decay_rate = 5 # 1/h
|
15
|
+
self.dry_time = 7 # day
|
16
|
+
self.maximum_infiltration_volume = 0 # mm, 0 if not applicable
|
17
|
+
|
18
|
+
|
19
|
+
class InfiltrationGreenAmpt:
|
20
|
+
def __init__(self):
|
21
|
+
self.soil_capillary_suction = 0
|
22
|
+
self.soil_saturated_hydraulic_conductivity = 0
|
23
|
+
self.initial_soil_moisture_deficit = 0
|
24
|
+
|
25
|
+
|
26
|
+
class InfiltrationCurveNumber:
|
27
|
+
def __init__(self):
|
28
|
+
self.curve_number = 0
|
29
|
+
self.dry_time = 0
|
30
|
+
self.soil_saturated_hydraulic_conductivity = 0
|
31
|
+
|
32
|
+
|
33
|
+
class Infiltration:
|
34
|
+
def __init__(self):
|
35
|
+
self.horton = InfiltrationHorton()
|
36
|
+
self.green_ampt = InfiltrationGreenAmpt()
|
37
|
+
self.curve_number = InfiltrationCurveNumber()
|
38
|
+
|
39
|
+
|
40
|
+
class Polygon:
|
41
|
+
def __init__(self):
|
42
|
+
self.area_name = None
|
43
|
+
self.x = []
|
44
|
+
self.y = []
|
45
|
+
|
46
|
+
|
47
|
+
class Area:
|
48
|
+
"""
|
49
|
+
Represents a subcatchment area in the drainage system.
|
50
|
+
|
51
|
+
Models a land area that generates runoff and routes it to a specific outlet point.
|
52
|
+
Includes properties for surface characteristics, infiltration, and routing.
|
53
|
+
|
54
|
+
Attributes:
|
55
|
+
name (str): Unique identifier for the subcatchment
|
56
|
+
rain_gage (str): Associated rain gage name
|
57
|
+
outlet (str): Outlet node name
|
58
|
+
area (float): Subcatchment area
|
59
|
+
impervious_ratio (float): Fraction of impervious area
|
60
|
+
width (float): Characteristic width of overland flow
|
61
|
+
slope (float): Average surface slope
|
62
|
+
curb_length (float): Length of curbs (for pollutant buildup)
|
63
|
+
snow_pack (str): Name of snow pack parameter set
|
64
|
+
manning_impervious (float): Manning's n for impervious area
|
65
|
+
manning_pervious (float): Manning's n for pervious area
|
66
|
+
depression_impervious (float): Depression storage for impervious area
|
67
|
+
depression_pervious (float): Depression storage for pervious area
|
68
|
+
impervious_without_depression (float): % of impervious area with no depression storage
|
69
|
+
route_type (str): Internal routing method
|
70
|
+
route_type_ratio (float): Fraction routed between subareas
|
71
|
+
infiltration (dict): Infiltration parameters
|
72
|
+
"""
|
73
|
+
def __init__(self):
|
74
|
+
self.name = ''
|
75
|
+
self.rain_gage = ''
|
76
|
+
self.outlet = ''
|
77
|
+
#
|
78
|
+
self.area = 0.0
|
79
|
+
self.impervious_ratio = 0
|
80
|
+
self.width = 0
|
81
|
+
self.slope = 0
|
82
|
+
#
|
83
|
+
self.curb_length = 0
|
84
|
+
self.snow_pack = ''
|
85
|
+
#
|
86
|
+
self.manning_impervious = 0
|
87
|
+
self.manning_pervious = 0
|
88
|
+
self.depression_impervious = 0
|
89
|
+
self.depression_pervious = 0
|
90
|
+
self.impervious_without_depression = 0
|
91
|
+
#
|
92
|
+
self.route_type = 'OUTLET'
|
93
|
+
self.route_type_ratio = 100
|
94
|
+
#
|
95
|
+
self.infiltration = Infiltration()
|
96
|
+
#
|
97
|
+
self.polygon = Polygon()
|
98
|
+
|
99
|
+
def __repr__(self):
|
100
|
+
return f'Subcatchment<{self.name}>'
|
101
|
+
|
102
|
+
|
103
|
+
class AreaList:
|
104
|
+
def __init__(self):
|
105
|
+
self.data = []
|
106
|
+
|
107
|
+
def __repr__(self):
|
108
|
+
return f'{len(self.data)} Areas'
|
109
|
+
|
110
|
+
def __len__(self):
|
111
|
+
return len(self.data)
|
112
|
+
|
113
|
+
def __getitem__(self, key):
|
114
|
+
if isinstance(key, int):
|
115
|
+
return self.data[key]
|
116
|
+
elif isinstance(key, str):
|
117
|
+
for item in self.data:
|
118
|
+
if item.name == key:
|
119
|
+
return item
|
120
|
+
raise KeyError(f"No item found with name '{key}'")
|
121
|
+
else:
|
122
|
+
raise TypeError("Key must be an integer or a string")
|
123
|
+
|
124
|
+
def __iter__(self):
|
125
|
+
return iter(self.data)
|
126
|
+
|
127
|
+
def __contains__(self, item):
|
128
|
+
return item in self.data
|
129
|
+
|
130
|
+
def add_area(self, area_information):
|
131
|
+
new_area = Area()
|
132
|
+
if 'name' in area_information:
|
133
|
+
new_area.name = area_information['name']
|
134
|
+
if 'rain_gage' in area_information:
|
135
|
+
new_area.rain_gage = area_information['rain_gage']
|
136
|
+
if 'outlet' in area_information:
|
137
|
+
new_area.outlet = area_information['outlet']
|
138
|
+
#
|
139
|
+
if 'area' in area_information:
|
140
|
+
new_area.area = area_information['area']
|
141
|
+
if 'impervious_ratio' in area_information:
|
142
|
+
new_area.impervious_ratio = area_information['impervious_ratio']
|
143
|
+
if 'width' in area_information:
|
144
|
+
new_area.width = area_information['width']
|
145
|
+
if 'slope' in area_information:
|
146
|
+
new_area.slope = area_information['slope']
|
147
|
+
#
|
148
|
+
if 'curb_length' in area_information:
|
149
|
+
new_area.curb_length = area_information['curb_length']
|
150
|
+
if 'snow_pack' in area_information:
|
151
|
+
new_area.snow_pack = area_information['snow_pack']
|
152
|
+
#
|
153
|
+
if 'manning_impervious' in area_information:
|
154
|
+
new_area.manning_impervious = area_information['manning_impervious']
|
155
|
+
if 'manning_pervious' in area_information:
|
156
|
+
new_area.manning_pervious = area_information['manning_pervious']
|
157
|
+
if 'depression_impervious' in area_information:
|
158
|
+
new_area.depression_impervious = area_information['depression_impervious']
|
159
|
+
if 'depression_pervious' in area_information:
|
160
|
+
new_area.depression_pervious = area_information['depression_pervious']
|
161
|
+
if 'impervious_without_depression' in area_information:
|
162
|
+
new_area.impervious_without_depression = area_information['impervious_without_depression']
|
163
|
+
#
|
164
|
+
if 'route_type' in area_information:
|
165
|
+
new_area.route_type = area_information['route_type']
|
166
|
+
if 'route_type_ratio' in area_information:
|
167
|
+
new_area.route_type_ratio = area_information['route_type_ratio']
|
168
|
+
#
|
169
|
+
if 'infiltration' in area_information:
|
170
|
+
new_area.infiltration = area_information['infiltration']
|
171
|
+
#
|
172
|
+
#
|
173
|
+
self.data.append(new_area)
|
174
|
+
|
175
|
+
def read_from_swmm_inp(self, filename, infiltration_type='Horton'):
|
176
|
+
sub_contents = get_swmm_inp_content(filename, '[SUBCATCHMENTS]')
|
177
|
+
# fill in default values
|
178
|
+
for index, line in enumerate(sub_contents):
|
179
|
+
if len(line.split()) == 8:
|
180
|
+
sub_contents[index] += ' VOID'
|
181
|
+
#
|
182
|
+
subarea_contents = get_swmm_inp_content(filename, '[SUBAREAS]')
|
183
|
+
# fill in default values
|
184
|
+
for index, line in enumerate(subarea_contents):
|
185
|
+
if len(line.split()) == 7:
|
186
|
+
subarea_contents[index] += ' 100'
|
187
|
+
content = combine_swmm_inp_contents(sub_contents, subarea_contents)
|
188
|
+
#
|
189
|
+
infiltration_contents = get_swmm_inp_content(filename, '[INFILTRATION]')
|
190
|
+
content = combine_swmm_inp_contents(content, infiltration_contents)
|
191
|
+
|
192
|
+
for line in content:
|
193
|
+
pair = line.split()
|
194
|
+
dic = {'name': pair[0],
|
195
|
+
'rain_gage': pair[1],
|
196
|
+
'outlet': pair[2],
|
197
|
+
'area': float(pair[3]),
|
198
|
+
'impervious_ratio': float(pair[4]),
|
199
|
+
'width': float(pair[5]),
|
200
|
+
'slope': float(pair[6]),
|
201
|
+
'curb_length': float(pair[7]),
|
202
|
+
'manning_impervious': float(pair[9]),
|
203
|
+
'manning_pervious': float(pair[10]),
|
204
|
+
'depression_impervious': float(pair[11]),
|
205
|
+
'depression_pervious': float(pair[12]),
|
206
|
+
'impervious_without_depression': float(pair[13]),
|
207
|
+
'route_type': pair[14]
|
208
|
+
}
|
209
|
+
if dic['curb_length'] < 10e-5:
|
210
|
+
dic['curb_length'] = int(0)
|
211
|
+
#
|
212
|
+
if pair[8] != 'VOID':
|
213
|
+
dic['snow_pack'] = pair[8]
|
214
|
+
if pair[15] != '100':
|
215
|
+
dic['route_type_ratio'] = float(pair[15])
|
216
|
+
#
|
217
|
+
new_infiltration = Infiltration()
|
218
|
+
|
219
|
+
match infiltration_type:
|
220
|
+
case 'Horton':
|
221
|
+
new_infiltration.horton.maximum_rate = float(pair[16])
|
222
|
+
new_infiltration.horton.minimum_rate = float(pair[17])
|
223
|
+
new_infiltration.horton.decay_rate = float(pair[18])
|
224
|
+
new_infiltration.horton.dry_time = float(pair[19])
|
225
|
+
new_infiltration.horton.maximum_infiltration_volume = float(pair[20])
|
226
|
+
case 'GreenAmpt':
|
227
|
+
new_infiltration.green_ampt.soil_capillary_suction = float(pair[16])
|
228
|
+
new_infiltration.green_ampt.soil_saturated_hydraulic_conductivity = float(pair[17])
|
229
|
+
new_infiltration.green_ampt.initial_soil_moisture_deficit = float(pair[18])
|
230
|
+
case 'CurveNumber':
|
231
|
+
new_infiltration.curve_number.curve_number = float(pair[16])
|
232
|
+
new_infiltration.curve_number.soil_saturated_hydraulic_conductivity = float(pair[17])
|
233
|
+
new_infiltration.curve_number.dry_time = float(pair[18])
|
234
|
+
|
235
|
+
dic['infiltration'] = new_infiltration
|
236
|
+
#
|
237
|
+
self.add_area(dic)
|
238
|
+
|
239
|
+
#
|
240
|
+
polygon_contents = get_swmm_inp_content(filename, '[Polygons]')
|
241
|
+
for line in polygon_contents:
|
242
|
+
pair = line.split()
|
243
|
+
for area in self.data:
|
244
|
+
if area.name == pair[0]:
|
245
|
+
area.polygon.x.append(float(pair[1]))
|
246
|
+
area.polygon.y.append(float(pair[2]))
|
247
|
+
area.polygon.area_name = pair[0]
|
248
|
+
return 0
|
249
|
+
|
250
|
+
def write_to_swmm_inp(self, filename, infiltration_type='Horton'):
|
251
|
+
with open(filename, 'a', encoding='utf-8') as f:
|
252
|
+
f.write('\n\n[SUBCATCHMENTS]\n')
|
253
|
+
f.write(
|
254
|
+
';;Name RainGage Outlet Area %Imperv Width %Slope CurbLen (SnowPack)\n')
|
255
|
+
for area in self.data:
|
256
|
+
f.write(
|
257
|
+
f'{area.name} {area.rain_gage} {area.outlet} {area.area:8.3f} {area.impervious_ratio:8.2f} {area.width:8.3f} {area.slope:8.2f} {area.curb_length:8} {area.snow_pack}\n')
|
258
|
+
#
|
259
|
+
f.write('\n\n[SUBAREAS]\n')
|
260
|
+
f.write(';;Subcatchment N-Imperv N-Perv S-Imperv S-Perv PctZero RouteTo (PctRouted)\n')
|
261
|
+
for area in self.data:
|
262
|
+
if area.route_type_ratio != 100:
|
263
|
+
f.write(
|
264
|
+
f'{area.name} {area.manning_impervious:8.3f} {area.manning_pervious:8.2f} {area.depression_impervious:8.2f} {area.depression_pervious:8.2f} {area.impervious_without_depression:8.2f} {area.route_type:8} {area.route_type_ratio:8}\n')
|
265
|
+
else:
|
266
|
+
f.write(
|
267
|
+
f'{area.name} {area.manning_impervious:8.3f} {area.manning_pervious:8.2f} {area.depression_impervious:8.2f} {area.depression_pervious:8.2f} {area.impervious_without_depression:8.2f} {area.route_type:8}\n')
|
268
|
+
#
|
269
|
+
f.write('\n\n[INFILTRATION]\n')
|
270
|
+
match infiltration_type:
|
271
|
+
case 'Horton':
|
272
|
+
f.write(';;;;Subcatchment MaxRate MinRate Decay DryTime MaxInfil \n')
|
273
|
+
for area in self.data:
|
274
|
+
f.write(
|
275
|
+
f'{area.name} {area.infiltration.horton.maximum_rate:8.1f} {area.infiltration.horton.minimum_rate:8.1f} {area.infiltration.horton.decay_rate:8.1f} {area.infiltration.horton.dry_time:8.1f} {area.infiltration.horton.maximum_infiltration_volume:8.1f}\n')
|
276
|
+
case 'GreenAmpt':
|
277
|
+
f.write(';;;;Subcatchment \n')
|
278
|
+
for area in self.data:
|
279
|
+
f.write(
|
280
|
+
f'{area.name} {area.infiltration.green_ampt.soil_capillary_suction:8} {area.infiltration.green_ampt.soil_saturated_hydraulic_conductivity:8} {area.infiltration.green_ampt.initial_soil_moisture_deficit:8}\n')
|
281
|
+
case 'CurveNumber':
|
282
|
+
f.write(';;;;Subcatchment \n')
|
283
|
+
for area in self.data:
|
284
|
+
f.write(
|
285
|
+
f'{area.name} {area.infiltration.curve_number.curve_number:8} {area.infiltration.curve_number.soil_saturated_hydraulic_conductivity:8} {area.infiltration.curve_number.dry_time:8}\n')
|
286
|
+
#
|
287
|
+
f.write('\n\n[Polygons]\n')
|
288
|
+
f.write(';;Subcatchment X-Coord Y-Coord\n')
|
289
|
+
for area in self.data:
|
290
|
+
if area.polygon.area_name is not None:
|
291
|
+
for xi, yi in zip(area.polygon.x, area.polygon.y):
|
292
|
+
f.write(f'{area.polygon.area_name} {xi} {yi}\n')
|
293
|
+
return 0
|
294
|
+
|
easysewer/Curve.py
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
"""
|
2
|
+
Curve and Pattern Management Module
|
3
|
+
|
4
|
+
This module handles various types of curves and patterns used in the drainage model,
|
5
|
+
including rating curves, shape curves, and time patterns for different parameters.
|
6
|
+
"""
|
7
|
+
from .utils import *
|
8
|
+
|
9
|
+
|
10
|
+
class Curve:
|
11
|
+
def __init__(self):
|
12
|
+
self.name = ''
|
13
|
+
self.type = ''
|
14
|
+
self.x = []
|
15
|
+
self.y = []
|
16
|
+
|
17
|
+
|
18
|
+
class Pattern:
|
19
|
+
def __init__(self):
|
20
|
+
self.name = ''
|
21
|
+
self.type = ''
|
22
|
+
self.value = []
|
23
|
+
|
24
|
+
|
25
|
+
class ValueList:
|
26
|
+
"""
|
27
|
+
Container for curves and patterns used in the model.
|
28
|
+
|
29
|
+
Manages collections of curves (rating curves, shape curves) and patterns
|
30
|
+
(time patterns) used throughout the drainage model.
|
31
|
+
|
32
|
+
Attributes:
|
33
|
+
curve_list (list): Collection of curve objects
|
34
|
+
pattern_list (list): Collection of pattern objects
|
35
|
+
"""
|
36
|
+
def __init__(self):
|
37
|
+
self.curve_list = []
|
38
|
+
self.pattern_list = []
|
39
|
+
|
40
|
+
def __repr__(self):
|
41
|
+
return 'ValueList'
|
42
|
+
|
43
|
+
def add_curve(self, new_curve):
|
44
|
+
self.curve_list.append(new_curve)
|
45
|
+
|
46
|
+
def add_pattern(self, new_pattern):
|
47
|
+
self.pattern_list.append(new_pattern)
|
48
|
+
|
49
|
+
def read_from_swmm_inp(self, filename):
|
50
|
+
#
|
51
|
+
content = get_swmm_inp_content(filename, '[CURVES]')
|
52
|
+
this_curve = Curve()
|
53
|
+
this_curve.name = 'initial'
|
54
|
+
for line in content:
|
55
|
+
pair = line.split()
|
56
|
+
name = pair[0]
|
57
|
+
if this_curve.name == 'initial':
|
58
|
+
this_curve.name = name
|
59
|
+
if this_curve.name != name:
|
60
|
+
self.add_curve(this_curve)
|
61
|
+
this_curve = Curve()
|
62
|
+
this_curve.name = name
|
63
|
+
if len(pair) % 2 == 0:
|
64
|
+
this_curve.type = pair[1]
|
65
|
+
x_list = [float(i) for index, i in enumerate(pair[2::]) if index % 2 == 0]
|
66
|
+
y_list = [float(i) for index, i in enumerate(pair[2::]) if index % 2 == 1]
|
67
|
+
else:
|
68
|
+
x_list = [float(i) for index, i in enumerate(pair[1::]) if index % 2 == 0]
|
69
|
+
y_list = [float(i) for index, i in enumerate(pair[1::]) if index % 2 == 1]
|
70
|
+
for x, y in zip(x_list, y_list):
|
71
|
+
this_curve.x.append(x)
|
72
|
+
this_curve.y.append(y)
|
73
|
+
if this_curve.name != 'initial':
|
74
|
+
self.add_curve(this_curve)
|
75
|
+
#
|
76
|
+
content = get_swmm_inp_content(filename, '[PATTERNS]')
|
77
|
+
this_pattern = Pattern()
|
78
|
+
this_pattern.name = 'initial'
|
79
|
+
for line in content:
|
80
|
+
pair = line.split()
|
81
|
+
name = pair[0]
|
82
|
+
if this_pattern.name == 'initial':
|
83
|
+
this_pattern.name = name
|
84
|
+
if this_pattern.name != name:
|
85
|
+
self.add_pattern(this_pattern)
|
86
|
+
this_pattern = Pattern()
|
87
|
+
this_pattern.name = name
|
88
|
+
if pair[1].isalpha():
|
89
|
+
this_pattern.type = pair[1]
|
90
|
+
for factor in pair[2::]:
|
91
|
+
this_pattern.value.append(factor)
|
92
|
+
else:
|
93
|
+
for factor in pair[1::]:
|
94
|
+
this_pattern.value.append(factor)
|
95
|
+
if this_pattern.name != 'initial':
|
96
|
+
self.add_pattern(this_pattern)
|
97
|
+
return 0
|
98
|
+
|
99
|
+
def write_to_swmm_inp(self, filename):
|
100
|
+
with open(filename, 'a', encoding='utf-8') as f:
|
101
|
+
f.write('\n\n[CURVES]\n')
|
102
|
+
f.write(';;Name Type X-Value Y-Value \n')
|
103
|
+
for curve in self.curve_list:
|
104
|
+
flag = 0
|
105
|
+
for x, y in zip(curve.x, curve.y):
|
106
|
+
if flag == 0:
|
107
|
+
f.write(f'{curve.name} {curve.type:8} {x} {y}\n')
|
108
|
+
flag = 1
|
109
|
+
else:
|
110
|
+
f.write(f'{curve.name} {x} {y}\n')
|
111
|
+
f.write(';\n')
|
112
|
+
#
|
113
|
+
f.write('\n\n[PATTERNS]\n')
|
114
|
+
f.write(';;Name Type Multipliers\n')
|
115
|
+
for pattern in self.pattern_list:
|
116
|
+
string = ' '.join(pattern.value)
|
117
|
+
f.write(f'{pattern.name} {pattern.type} {string}\n')
|
118
|
+
f.write(';\n')
|
119
|
+
return 0
|