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/Rain.py ADDED
@@ -0,0 +1,209 @@
1
+ """
2
+ Rainfall Data Management Module
3
+
4
+ This module handles rainfall data input and processing, including rain gages,
5
+ time series data, and rainfall patterns for the drainage model.
6
+ """
7
+
8
+ from .utils import *
9
+
10
+
11
+ def parse_swmm_datetime(date_str=None, time_str=None):
12
+ """Convert SWMM date and time strings to minutes since start of day
13
+
14
+ Args:
15
+ date_str: Optional date string in format 'MM/DD/YYYY'
16
+ time_str: Time string in format 'HH:MM' or 'H:MM'
17
+
18
+ Returns:
19
+ minutes: Integer minutes since start of day
20
+ """
21
+ if date_str is None:
22
+ # Just parse time when no date provided
23
+ hours, minutes = time_str.split(':')
24
+ return int(minutes) + 60 * int(hours)
25
+
26
+ # Parse date and time when both provided
27
+ from datetime import datetime
28
+ dt = datetime.strptime(f"{date_str} {time_str}", "%m/%d/%Y %H:%M")
29
+ return dt.hour * 60 + dt.minute
30
+
31
+
32
+ class TimeSeries:
33
+ def __init__(self):
34
+ self.name = ''
35
+ self.time = [] # in minutes
36
+ self.value = [] # in mm
37
+ self.has_date = False # whether the timeseries includes date information
38
+ self.start_date = None # store the start date if available
39
+
40
+ def __repr__(self):
41
+ if len(self.time) == 0:
42
+ return 'None'
43
+ else:
44
+ interval = self.time[1] - self.time[0]
45
+ total = sum([(v * interval / 60) for v in self.value])
46
+ total = round(total, 2)
47
+ return f'{self.name}: {self.time[-1]}min - {total}mm'
48
+
49
+
50
+ class RainGage:
51
+ """
52
+ Represents a rain gage station in the model.
53
+
54
+ Defines characteristics of rainfall measurement points including data format,
55
+ time intervals, and data source.
56
+
57
+ Attributes:
58
+ name (str): Unique identifier for the rain gage
59
+ format (str): Format of the rainfall data (INTENSITY/VOLUME/CUMULATIVE)
60
+ interval (float): Recording time interval
61
+ snow_catch (float): Snow catch deficiency correction
62
+ data_source (str): Source of the rainfall data
63
+ time_series (str): Name of associated time series data
64
+ """
65
+ def __init__(self):
66
+ self.name = ''
67
+ self.form = '' # INTENSIFY: mm/h
68
+ self.interval = ''
69
+ self.SCF = 1 # snow catch deficiency correction factor (use 1.0 for no adjustment)
70
+ self.source = '' # timeseries name
71
+
72
+ def __repr__(self):
73
+ return f'RainGage<{self.name}>: {self.source}'
74
+
75
+
76
+ class Rain:
77
+ """
78
+ Container class for managing rainfall data.
79
+
80
+ Manages collection of rain gages and their associated time series data
81
+ for the drainage model.
82
+
83
+ Attributes:
84
+ gage_list (list): Collection of RainGage objects
85
+ ts_list (list): Collection of time series data
86
+ """
87
+ def __init__(self):
88
+ self.ts_list = []
89
+ self.gage_list = []
90
+
91
+ def __repr__(self):
92
+ if len(self.gage_list) == 0:
93
+ return 'None'
94
+ elif len(self.gage_list) == 1:
95
+ return f'{self.gage_list[0]}'
96
+ else:
97
+ return 'Gages'
98
+
99
+ def add_ts(self, new_ts):
100
+ self.ts_list.append(new_ts)
101
+
102
+ def add_gage(self, new_gage):
103
+ self.gage_list.append(new_gage)
104
+
105
+ def read_from_swmm_inp(self, filename):
106
+ from datetime import datetime
107
+
108
+ content = get_swmm_inp_content(filename, '[TIMESERIES]')
109
+ this_timeseries = TimeSeries()
110
+ this_timeseries.name = 'initial'
111
+
112
+ for line in content:
113
+ parts = line.split()
114
+
115
+ # Skip empty lines or invalid formats
116
+ if len(parts) < 3:
117
+ continue
118
+
119
+ # Determine if this line has date information
120
+ has_date = len(parts) == 4
121
+
122
+ if has_date:
123
+ name, date, time, value = parts
124
+ minutes = parse_swmm_datetime(date_str=date, time_str=time)
125
+ else:
126
+ name, time, value = parts
127
+ minutes = parse_swmm_datetime(time_str=time)
128
+
129
+ value = float(value)
130
+
131
+ # Handle first timeseries
132
+ if this_timeseries.name == 'initial':
133
+ this_timeseries.name = name
134
+ this_timeseries.has_date = has_date
135
+ if has_date:
136
+ this_timeseries.start_date = datetime.strptime(date, "%m/%d/%Y").date()
137
+
138
+ # If we encounter a new timeseries name
139
+ if this_timeseries.name != name:
140
+ # Save the current timeseries
141
+ self.add_ts(this_timeseries)
142
+
143
+ # Start a new timeseries
144
+ this_timeseries = TimeSeries()
145
+ this_timeseries.name = name
146
+ this_timeseries.has_date = has_date
147
+ if has_date:
148
+ this_timeseries.start_date = datetime.strptime(date, "%m/%d/%Y").date()
149
+
150
+ # Add the data point
151
+ this_timeseries.time.append(minutes)
152
+ this_timeseries.value.append(value)
153
+
154
+ # Add the last timeseries if it exists
155
+ if this_timeseries.name != 'initial':
156
+ self.add_ts(this_timeseries)
157
+ # rain gage section
158
+ content = get_swmm_inp_content(filename, '[RAINGAGES]')
159
+ for line in content:
160
+ name, form, interval, SCF, _, tise = line.split()
161
+ this_gage = RainGage()
162
+ this_gage.name = name
163
+ this_gage.form = form
164
+ this_gage.interval = interval
165
+ this_gage.SCF = SCF
166
+ this_gage.source = tise
167
+ self.add_gage(this_gage)
168
+ return 0
169
+
170
+ def write_to_swmm_inp(self, filename):
171
+ from datetime import datetime, timedelta
172
+
173
+ def time_minute2text(minutes):
174
+ minutes = int(minutes)
175
+ hours, left = divmod(minutes, 60)
176
+ text = f'{hours}:{left:02}'
177
+ return text
178
+
179
+ def get_date_for_minutes(start_date, minutes):
180
+ """Convert minutes to date string, handling day rollovers"""
181
+ days, remaining_minutes = divmod(minutes, 24 * 60)
182
+ date = start_date + timedelta(days=days)
183
+ return date.strftime("%m/%d/%Y")
184
+
185
+ with open(filename, 'a', encoding='utf-8') as f:
186
+ f.write('\n\n[TIMESERIES]\n')
187
+ if any(ts.has_date for ts in self.ts_list):
188
+ f.write(';;Name Date Time Value\n')
189
+ f.write(';;-------------- ---------- ---------- ----------\n')
190
+ else:
191
+ f.write(';;Name Time Value\n')
192
+ f.write(';;---------- ---------- ----------\n')
193
+
194
+ for ts in self.ts_list:
195
+ for time, value in zip(ts.time, ts.value):
196
+ if ts.has_date:
197
+ date_str = get_date_for_minutes(ts.start_date, time)
198
+ time_str = time_minute2text(time % (24 * 60)) # Get time within the day
199
+ f.write(f'{ts.name:<14} {date_str} {time_str} {value:>.2f}\n')
200
+ else:
201
+ f.write(f'{ts.name} {time_minute2text(time)} {value:>.2f}\n')
202
+ f.write(';;\n')
203
+
204
+ f.write('\n\n[RAINGAGES]\n')
205
+ f.write(';;Name Format Interval SCF Source \n')
206
+ f.write(';;----- -------- --------- ---- ----------\n')
207
+ for gage in self.gage_list:
208
+ f.write(f'{gage.name} {gage.form} {gage.interval} {gage.SCF} TIMESERIES {gage.source}\n')
209
+ return 0
easysewer/SolverAPI.py ADDED
@@ -0,0 +1,154 @@
1
+ """
2
+ pass
3
+ """
4
+ import platform
5
+ import os
6
+ from ctypes import CDLL, c_char_p, c_int, c_double, c_float, byref, POINTER, create_string_buffer
7
+
8
+
9
+ class SWMMSolverAPI:
10
+ def __init__(self):
11
+ #
12
+ system = platform.system()
13
+ if system == 'Windows':
14
+ lib_path = os.path.join(os.path.dirname(__file__), 'libs', 'win', 'swmm5.dll')
15
+ elif system == 'Linux':
16
+ lib_path = os.path.join(os.path.dirname(__file__), 'libs', 'linux', 'libswmm5.so')
17
+ else:
18
+ raise OSError('Unsupported operating system')
19
+
20
+ self.swmm = CDLL(lib_path)
21
+ self._set_prototypes()
22
+
23
+ def _set_prototypes(self):
24
+ self.swmm.swmm_run.argtypes = [c_char_p, c_char_p, c_char_p]
25
+ self.swmm.swmm_run.restype = c_int
26
+
27
+ self.swmm.swmm_open.argtypes = [c_char_p, c_char_p, c_char_p]
28
+ self.swmm.swmm_open.restype = c_int
29
+
30
+ self.swmm.swmm_start.argtypes = [c_int]
31
+ self.swmm.swmm_start.restype = c_int
32
+
33
+ self.swmm.swmm_step.argtypes = [POINTER(c_double)]
34
+ self.swmm.swmm_step.restype = c_int
35
+
36
+ self.swmm.swmm_end.argtypes = []
37
+ self.swmm.swmm_end.restype = c_int
38
+
39
+ self.swmm.swmm_report.argtypes = []
40
+ self.swmm.swmm_report.restype = c_int
41
+
42
+ self.swmm.swmm_close.argtypes = []
43
+ self.swmm.swmm_close.restype = c_int
44
+
45
+ self.swmm.swmm_getMassBalErr.argtypes = [POINTER(c_float), POINTER(c_float), POINTER(c_float)]
46
+ self.swmm.swmm_getMassBalErr.restype = c_int
47
+
48
+ self.swmm.swmm_getVersion.argtypes = []
49
+ self.swmm.swmm_getVersion.restype = c_int
50
+
51
+ self.swmm.swmm_getError.argtypes = [c_char_p, c_int]
52
+ self.swmm.swmm_getError.restype = c_int
53
+
54
+ self.swmm.swmm_getWarnings.argtypes = []
55
+ self.swmm.swmm_getWarnings.restype = c_int
56
+
57
+ self.swmm.swmm_getCount.argtypes = [c_int]
58
+ self.swmm.swmm_getCount.restype = c_int
59
+
60
+ self.swmm.swmm_getName.argtypes = [c_int, c_int, c_char_p, c_int]
61
+ self.swmm.swmm_getName.restype = None
62
+
63
+ self.swmm.swmm_getIndex.argtypes = [c_int, c_char_p]
64
+ self.swmm.swmm_getIndex.restype = c_int
65
+
66
+ self.swmm.swmm_getValue.argtypes = [c_int, c_int]
67
+ self.swmm.swmm_getValue.restype = c_double
68
+
69
+ self.swmm.swmm_setValue.argtypes = [c_int, c_int, c_double]
70
+ self.swmm.swmm_setValue.restype = None
71
+
72
+ self.swmm.swmm_getSavedValue.argtypes = [c_int, c_int, c_int]
73
+ self.swmm.swmm_getSavedValue.restype = c_double
74
+
75
+ self.swmm.swmm_writeLine.argtypes = [c_char_p]
76
+ self.swmm.swmm_writeLine.restype = None
77
+
78
+ self.swmm.swmm_decodeDate.argtypes = [c_double, POINTER(c_int), POINTER(c_int), POINTER(c_int), POINTER(c_int), POINTER(c_int), POINTER(c_int), POINTER(c_int)]
79
+ self.swmm.swmm_decodeDate.restype = None
80
+
81
+ def run(self, input_file, report_file, output_file):
82
+ return self.swmm.swmm_run(input_file.encode('utf-8'), report_file.encode('utf-8'), output_file.encode('utf-8'))
83
+
84
+ def open(self, input_file, report_file, output_file):
85
+ return self.swmm.swmm_open(input_file.encode('utf-8'), report_file.encode('utf-8'), output_file.encode('utf-8'))
86
+
87
+ def start(self, save_flag):
88
+ return self.swmm.swmm_start(save_flag)
89
+
90
+ def step(self):
91
+ elapsed_time = c_double()
92
+ result = self.swmm.swmm_step(byref(elapsed_time))
93
+ return result, elapsed_time.value
94
+
95
+ def end(self):
96
+ return self.swmm.swmm_end()
97
+
98
+ def report(self):
99
+ return self.swmm.swmm_report()
100
+
101
+ def close(self):
102
+ return self.swmm.swmm_close()
103
+
104
+ def get_mass_bal_err(self):
105
+ runoff_err = c_float()
106
+ flow_err = c_float()
107
+ qual_err = c_float()
108
+ self.swmm.swmm_getMassBalErr(byref(runoff_err), byref(flow_err), byref(qual_err))
109
+ return runoff_err.value, flow_err.value, qual_err.value
110
+
111
+ def get_version(self):
112
+ return self.swmm.swmm_getVersion()
113
+
114
+ def get_error(self, msg_len=256):
115
+ err_msg = create_string_buffer(msg_len)
116
+ self.swmm.swmm_getError(err_msg, msg_len)
117
+ return err_msg.value.decode('utf-8')
118
+
119
+ def get_warnings(self):
120
+ return self.swmm.swmm_getWarnings()
121
+
122
+ def get_count(self, obj_type):
123
+ return self.swmm.swmm_getCount(obj_type)
124
+
125
+ def get_name(self, obj_type, index, size=256):
126
+ name = create_string_buffer(size)
127
+ self.swmm.swmm_getName(obj_type, index, name, size)
128
+ return name.value.decode('utf-8')
129
+
130
+ def get_index(self, obj_type, name):
131
+ return self.swmm.swmm_getIndex(obj_type, name.encode('utf-8'))
132
+
133
+ def get_value(self, property, index):
134
+ return self.swmm.swmm_getValue(property, index)
135
+
136
+ def set_value(self, property, index, value):
137
+ self.swmm.swmm_setValue(property, index, value)
138
+
139
+ def get_saved_value(self, property, index, period):
140
+ return self.swmm.swmm_getSavedValue(property, index, period)
141
+
142
+ def write_line(self, line):
143
+ self.swmm.swmm_writeLine(line.encode('utf-8'))
144
+
145
+ def decode_date(self, date):
146
+ year = c_int()
147
+ month = c_int()
148
+ day = c_int()
149
+ hour = c_int()
150
+ minute = c_int()
151
+ second = c_int()
152
+ day_of_week = c_int()
153
+ self.swmm.swmm_decodeDate(date, byref(year), byref(month), byref(day), byref(hour), byref(minute), byref(second), byref(day_of_week))
154
+ return (year.value, month.value, day.value, hour.value, minute.value, second.value, day_of_week.value)
easysewer/UDM.py ADDED
@@ -0,0 +1,126 @@
1
+ """
2
+ Urban Drainage Model (UDM) - Main Model Class
3
+
4
+ This module implements the core Urban Drainage Model functionality for hydraulic simulations.
5
+ It serves as the main interface for creating and managing drainage system models including
6
+ nodes (junctions, outfalls), links (conduits), subcatchment areas, and rainfall data.
7
+
8
+ The model supports:
9
+ - Reading/writing SWMM .inp files
10
+ - Managing network elements (nodes, links, areas)
11
+ - Handling rainfall and calculation settings
12
+ - Supporting various hydraulic elements like conduits and junctions
13
+ """
14
+
15
+ from .Options import CalculationInformation
16
+ from .Link import LinkList
17
+ from .Node import NodeList
18
+ from .Area import AreaList
19
+ from .Rain import Rain
20
+ from .Curve import ValueList
21
+ import json
22
+ from .utils import get_swmm_inp_content
23
+
24
+
25
+ class UrbanDrainageModel:
26
+ """
27
+ Main class for managing an Urban Drainage Model.
28
+
29
+ This class serves as the central point for managing all aspects of an urban drainage
30
+ model including network topology, hydraulic elements, and simulation settings.
31
+
32
+ Attributes:
33
+ calc (CalculationInformation): Calculation and simulation settings
34
+ link (LinkList): Collection of conduits and other hydraulic links
35
+ node (NodeList): Collection of junctions, outfalls and other nodes
36
+ area (AreaList): Collection of subcatchment areas
37
+ rain (Rain): Rainfall data and settings
38
+ value (ValueList): Curves and patterns for various model parameters
39
+ label (dict): Model metadata and labeling information
40
+
41
+ Args:
42
+ model_path (str, optional): Path to SWMM .inp file to load. Defaults to None.
43
+ """
44
+
45
+ def __init__(self, model_path=None):
46
+ # calculation related information
47
+ self.calc = CalculationInformation()
48
+
49
+ # entity related information
50
+ self.link = LinkList()
51
+ self.node = NodeList()
52
+ self.area = AreaList()
53
+
54
+ # rain related information
55
+ self.rain = Rain()
56
+ self.value = ValueList()
57
+
58
+ # label information
59
+ self.label = {}
60
+
61
+ # read model from the file if provided
62
+ if model_path is not None:
63
+ self.read_inp(model_path)
64
+
65
+ def __repr__(self):
66
+ """Returns a string representation of the model showing key components"""
67
+ return f'{self.link}, {self.node}, {self.area}'
68
+
69
+ def to_inp(self, filename):
70
+ """
71
+ Writes the model to a SWMM .inp file.
72
+
73
+ Args:
74
+ filename (str): Path to the output .inp file
75
+
76
+ Returns:
77
+ int: 0 on success
78
+ """
79
+ with open(filename, 'w', encoding='utf-8') as f:
80
+ # Write TITLE section first
81
+ f.write('[TITLE]\n')
82
+ if self.label:
83
+ try:
84
+ f.write(json.dumps(self.label, indent=2))
85
+ f.write('\n\n')
86
+ except:
87
+ f.write(str(self.label.get('TITLE', '')) + '\n\n')
88
+
89
+ # Continue with other sections
90
+ self.calc.write_to_swmm_inp(filename)
91
+ self.node.write_to_swmm_inp(filename)
92
+ self.link.write_to_swmm_inp(filename)
93
+ self.area.write_to_swmm_inp(filename)
94
+ self.rain.write_to_swmm_inp(filename)
95
+ self.value.write_to_swmm_inp(filename)
96
+ return 0
97
+
98
+ def read_inp(self, filename):
99
+ """
100
+ Reads a SWMM .inp file and populates the model.
101
+
102
+ Args:
103
+ filename (str): Path to the input .inp file
104
+
105
+ Returns:
106
+ int: 0 on success
107
+ """
108
+ # Read TITLE section
109
+ title_content = get_swmm_inp_content(filename, '[TITLE]')
110
+ if title_content:
111
+ try:
112
+ # Try to parse as JSON
113
+ json_text = '\n'.join(title_content)
114
+ self.label = json.loads(json_text)
115
+ except json.JSONDecodeError:
116
+ # If not JSON, store as plain text
117
+ self.label = {'TITLE': '\n'.join(title_content)}
118
+
119
+ # Continue with other sections
120
+ self.calc.read_from_swmm_inp(filename)
121
+ self.node.read_from_swmm_inp(filename)
122
+ self.link.read_from_swmm_inp(filename)
123
+ self.area.read_from_swmm_inp(filename)
124
+ self.rain.read_from_swmm_inp(filename)
125
+ self.value.read_from_swmm_inp(filename)
126
+ return 0
easysewer/__init__.py ADDED
@@ -0,0 +1,7 @@
1
+ """
2
+ pass
3
+ """
4
+ from .UDM import UrbanDrainageModel
5
+ from .UDM import UrbanDrainageModel as Model
6
+ from .OutputAPI import SWMMOutputAPI
7
+ from .SolverAPI import SWMMSolverAPI
Binary file
Binary file
Binary file
Binary file
easysewer/utils.py ADDED
@@ -0,0 +1,97 @@
1
+ """
2
+ Utility Functions Module
3
+
4
+ This module provides helper functions for file I/O operations and data processing
5
+ in the urban drainage model, particularly for SWMM input/output file handling.
6
+ """
7
+
8
+
9
+ def get_swmm_inp_content(filename, flag):
10
+ """
11
+ Extracts content from a specific section of a SWMM input file.
12
+
13
+ Args:
14
+ filename (str): Path to the SWMM input file
15
+ flag (str): Section identifier (e.g., '[TITLE]', '[JUNCTIONS]')
16
+
17
+ Returns:
18
+ list: Lines of content from the specified section
19
+ """
20
+ flag += '\n'
21
+ result = []
22
+
23
+ with open(filename, 'r', encoding='utf-8') as f:
24
+ # getting to the flag line
25
+ for line in f:
26
+ if line == flag:
27
+ break
28
+ # adding related lines to results
29
+ for line in f:
30
+ # finish when getting to another section
31
+ if line[0] == '[':
32
+ break
33
+ # skip if this line is blank or annotation
34
+ if line == '\n' or line[0] == ';':
35
+ continue
36
+ result.append(line[0:-1])
37
+
38
+ return result
39
+
40
+
41
+ def combine_swmm_inp_contents(content1, content2):
42
+ """
43
+ Combines two sections of SWMM input content based on matching identifiers.
44
+
45
+ Args:
46
+ content1 (list): Primary content lines
47
+ content2 (list): Secondary content lines to merge
48
+
49
+ Returns:
50
+ list: Combined content with merged information
51
+ """
52
+ # generate a name list of content1
53
+ index_dic = []
54
+ for line in content1:
55
+ pair = line.split()
56
+ index_dic.append(pair[0])
57
+ #
58
+ for line in content2:
59
+ pair = line.split()
60
+ index = index_dic.index(pair[0])
61
+ content1[index] = content1[index] + ' ' + ' '.join(pair[1::])
62
+ #
63
+ return content1
64
+
65
+
66
+ def get_swmm_rpt_content(filename, flag):
67
+ """
68
+ Extracts content from a specific section of a SWMM report file.
69
+
70
+ Args:
71
+ filename (str): Path to the SWMM report file
72
+ flag (str): Section identifier
73
+
74
+ Returns:
75
+ list: Lines of content from the specified report section
76
+ """
77
+ # example:
78
+ # res = ut.get_swmm_rpt_content('calculate_temp/test.rpt', 'Node G80F425')
79
+ flag = f' <<< {flag} >>>\n'
80
+ result = []
81
+ with open(filename, 'r', encoding='utf-8') as f:
82
+ # getting to the flag line
83
+ for line in f:
84
+ if line == flag:
85
+ break
86
+ # adding related lines to results
87
+ i = 0
88
+ for line in f:
89
+ # skip title bar ( four lines )
90
+ if i < 4:
91
+ i += 1
92
+ continue
93
+ # finish when getting to another section
94
+ if line == ' \n':
95
+ break
96
+ result.append(line[0:-1])
97
+ return result
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.4
2
+ Name: easysewer
3
+ Version: 0.0.1
4
+ Summary: An urban drainage modeling toolkit
5
+ Author-email: Yiran Ji <yiranji@zju.edu.cn>
6
+ License-Expression: AGPL-3.0-only
7
+ Project-URL: Homepage, https://github.com/yourusername/easysewer
8
+ Project-URL: Documentation, https://github.com/yourusername/easysewer#readme
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.10
12
+ Description-Content-Type: text/markdown
13
+
14
+ # EasySewer
15
+ 🚀 An urban drainage modeling toolkit
16
+ > Note: Project under active development
@@ -0,0 +1,19 @@
1
+ easysewer/Area.py,sha256=Y7SjlcA9byN4A3fk70D4M4hG8MulE0LLVJLqZ8FDt6c,13010
2
+ easysewer/Curve.py,sha256=C5X_CJ9CtuYcUFqdClFkxWYZOYHhQFBxENYg9jC6Dqs,4241
3
+ easysewer/Link.py,sha256=tZWGPg5EMcii6hfswNPp5MMz3wLdZPzuil9Sjv6OqXc,11802
4
+ easysewer/Node.py,sha256=trtXGPLDk1gkdKMXXwJ1hUOmsS6x2mVr4wh61Lxisqk,14092
5
+ easysewer/Options.py,sha256=zsmyDpiQO0Swsrqkzw_vow4lNKbiLsLX_0YQ6XWsSBI,18425
6
+ easysewer/OutputAPI.py,sha256=tD6-6VjBpG-DBlmvVhb9siZ_zgEe1lD1d0h2xPr72Qw,7519
7
+ easysewer/Rain.py,sha256=Hu_XtEXreIquf4uLxMgAiG_eRNc0OzuansDnZ1ozGAQ,7597
8
+ easysewer/SolverAPI.py,sha256=H1KZkS_03Mv2ruSNX6-Rg_fesTwL9O6R5TRCil2eC7o,5612
9
+ easysewer/UDM.py,sha256=DfEOFRyFR5guy7yEU_ve_XsRypXQ3k2nn5Slc5VAzOc,4385
10
+ easysewer/__init__.py,sha256=XD2zR0vua7-FMz5brRDY9FCzF_QNkPozfrOl7dvYALc,175
11
+ easysewer/utils.py,sha256=dkK5YwwaE2eLdiaY3YAEg78xv74TU6ff7Q3Rl3ltatI,2847
12
+ easysewer/libs/linux/libswmm5.so,sha256=UI5v1fCZ7LU9zkjLQMJqqJtzDefkFnL1iy3jmAlFsVo,839664
13
+ easysewer/libs/linux/swmm-output.so,sha256=248JHb0PUGyeo3tLj9fL4L114ySTSLBrUUA_k3VHnCQ,30928
14
+ easysewer/libs/win/swmm-output.dll,sha256=tN0K2ZRk7rlQZ-cLxlGLYZ6w269uvc5JuH1oVumADD0,71168
15
+ easysewer/libs/win/swmm5.dll,sha256=7LjGQXUyj8bdVuFzzY8-pObQV0VcUDI5KsAz-hstWls,915968
16
+ easysewer-0.0.1.dist-info/METADATA,sha256=GGX1eS11v3_hpeMxS1QsuqwJQi9wfJzEVZfVWTja_es,586
17
+ easysewer-0.0.1.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
18
+ easysewer-0.0.1.dist-info/top_level.txt,sha256=YJi065ohgpDZhPb0XuXfE6ExHMhHPlwveH40BgZ7kt4,10
19
+ easysewer-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (78.1.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ easysewer