openswmm 5.3.0.dev0__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.
@@ -0,0 +1,716 @@
1
+ # Description: Unit tests for the openswmmcore solver module.
2
+ # Created by: Caleb Buahin (EPA/ORD/CESER/WID)
3
+ # Created on: 2024-11-19
4
+
5
+ # python imports
6
+ import unittest
7
+ from datetime import datetime
8
+
9
+ # third party imports
10
+ import os
11
+ import sys
12
+
13
+ # local imports
14
+ from .data import solver as example_solver_data
15
+ from openswmmcore import solver
16
+
17
+
18
+ class TestSWMMSolver(unittest.TestCase):
19
+
20
+ def setUp(self):
21
+ self.swmm_test_datetime = datetime(year=2024, month=11, day=16, hour=13, minute=33, second=21)
22
+ self.swmm_test_double_datetime = 45612.564826389
23
+
24
+ self.site_drainage_inp = example_solver_data.SITE_DRAINAGE_EXAMPLE_INPUT_FILE
25
+ self.site_drainage_rpt = example_solver_data.SITE_DRAINAGE_EXAMPLE_INPUT_FILE.replace(".inp", ".rpt")
26
+ self.site_drainage_out = example_solver_data.SITE_DRAINAGE_EXAMPLE_INPUT_FILE.replace(".inp", ".out")
27
+
28
+ @staticmethod
29
+ def progress_callback(progress: float) -> None:
30
+ """
31
+ Progress callback function for the SWMM solver
32
+ :param progress:
33
+ :return:
34
+ """
35
+ assert 0 <= progress <= 1.0
36
+
37
+ def test_get_swmm_version(self):
38
+ """
39
+ Test the version function of the SWMM solver
40
+ :return:
41
+ """
42
+ version = solver.version()
43
+ self.assertEqual(version, 53000, "SWMM version retrieved successfully")
44
+
45
+ def test_swmm_encode_date(self):
46
+ """
47
+ Test the encode_swmm_datetime function
48
+ :return:
49
+ """
50
+
51
+ swmm_datetime_encoded = solver.encode_swmm_datetime(dt=self.swmm_test_datetime)
52
+ self.assertAlmostEqual(swmm_datetime_encoded, self.swmm_test_double_datetime)
53
+
54
+ def test_swmm_decode_date(self):
55
+ """
56
+ Test the decode_swmm_datetime function
57
+ :return:
58
+ """
59
+ swmm_datetime = solver.decode_swmm_datetime(
60
+ swmm_datetime=self.swmm_test_double_datetime
61
+ )
62
+
63
+ self.assertEqual(swmm_datetime, self.swmm_test_datetime)
64
+
65
+ def test_run_solver(self):
66
+ """
67
+ Run the SWMM solver to solve the example input file
68
+
69
+ :return:
70
+ """
71
+
72
+ if os.path.exists(self.site_drainage_rpt):
73
+ os.remove(self.site_drainage_rpt)
74
+
75
+ if os.path.exists(self.site_drainage_out):
76
+ os.remove(self.site_drainage_out)
77
+
78
+ error = solver.run_solver(
79
+ inp_file=self.site_drainage_inp,
80
+ rpt_file=self.site_drainage_rpt,
81
+ out_file=self.site_drainage_out,
82
+ )
83
+
84
+ self.assertEqual(error, 0, "SWMM solver run successfully.")
85
+
86
+ # Assert output and report files were created
87
+ self.assertTrue(os.path.exists(self.site_drainage_rpt))
88
+ self.assertTrue(os.path.exists(self.site_drainage_out))
89
+
90
+ def test_run_solver_with_progress_callback(self):
91
+ """
92
+ Run the SWMM solver to solve the example input file with progress callback
93
+
94
+ :return:
95
+ """
96
+
97
+ if os.path.exists(self.site_drainage_rpt):
98
+ os.remove(self.site_drainage_rpt)
99
+
100
+ if os.path.exists(self.site_drainage_out):
101
+ os.remove(self.site_drainage_out)
102
+
103
+ error = solver.run_solver(
104
+ inp_file=example_solver_data.SITE_DRAINAGE_EXAMPLE_INPUT_FILE,
105
+ rpt_file=example_solver_data.SITE_DRAINAGE_EXAMPLE_INPUT_FILE.replace(".inp", ".rpt"),
106
+ out_file=example_solver_data.SITE_DRAINAGE_EXAMPLE_INPUT_FILE.replace(".inp", ".out"),
107
+ swmm_progress_callback=self.progress_callback
108
+ )
109
+
110
+ self.assertEqual(error, 0, "SWMM solver with callbacks run successfully.")
111
+
112
+ # Assert output and report files were created
113
+ self.assertTrue(os.path.exists(self.site_drainage_rpt))
114
+ self.assertTrue(os.path.exists(self.site_drainage_out))
115
+
116
+ def test_run_solver_invalid_inp_file(self):
117
+ """
118
+ Run the SWMM solver with an invalid input file path to test error handling
119
+ :return:
120
+ """
121
+
122
+ with self.assertRaises(Exception) as context:
123
+ report_file = example_solver_data.NON_EXISTENT_INPUT_FILE.replace(".inp", ".rpt")
124
+ output_file = example_solver_data.NON_EXISTENT_INPUT_FILE.replace(".inp", ".out")
125
+
126
+ solver.run_solver(
127
+ inp_file=example_solver_data.NON_EXISTENT_INPUT_FILE,
128
+ rpt_file=report_file,
129
+ out_file=output_file,
130
+ )
131
+
132
+ self.assertIn('ERROR 303: cannot open input file.', str(context.exception))
133
+
134
+ def test_run_without_context_manager(self):
135
+ """
136
+ Run the SWMM solver without a context manager
137
+ :return:
138
+ """
139
+
140
+ if os.path.exists(self.site_drainage_rpt):
141
+ os.remove(self.site_drainage_rpt)
142
+
143
+ if os.path.exists(self.site_drainage_out):
144
+ os.remove(self.site_drainage_out)
145
+
146
+ swmm_solver = solver.Solver(
147
+ inp_file=self.site_drainage_inp,
148
+ rpt_file=self.site_drainage_rpt,
149
+ out_file=self.site_drainage_out,
150
+ )
151
+
152
+ swmm_solver.execute()
153
+
154
+ # Assert output and report files were created
155
+ self.assertTrue(os.path.exists(self.site_drainage_rpt))
156
+ self.assertTrue(os.path.exists(self.site_drainage_out))
157
+
158
+ def test_run_without_context_manager_step_by_step(self):
159
+ """
160
+ Run the SWMM solver without a context manager and an invalid input file path to test error handling
161
+ :return:
162
+ """
163
+ if os.path.exists(self.site_drainage_rpt):
164
+ os.remove(self.site_drainage_rpt)
165
+
166
+ if os.path.exists(self.site_drainage_out):
167
+ os.remove(self.site_drainage_out)
168
+
169
+ swmm_solver = solver.Solver(
170
+ inp_file=self.site_drainage_inp,
171
+ rpt_file=self.site_drainage_rpt,
172
+ out_file=self.site_drainage_out,
173
+ )
174
+
175
+ swmm_solver.initialize()
176
+
177
+ while swmm_solver.solver_state != solver.SolverState.FINISHED:
178
+ swmm_solver.step()
179
+
180
+ swmm_solver.finalize()
181
+
182
+ # Assert output and report files were created
183
+ self.assertTrue(os.path.exists(self.site_drainage_rpt))
184
+ self.assertTrue(os.path.exists(self.site_drainage_out))
185
+
186
+ def test_run_solver_with_context_manager(self):
187
+ """
188
+ Run the SWMM solver with an invalid report file path to test error handling
189
+ :return:
190
+ """
191
+
192
+ with solver.Solver(
193
+ inp_file=example_solver_data.SITE_DRAINAGE_EXAMPLE_INPUT_FILE,
194
+ rpt_file=example_solver_data.NON_EXISTENT_INPUT_FILE.replace(".inp", ".rpt"),
195
+ out_file=example_solver_data.SITE_DRAINAGE_EXAMPLE_INPUT_FILE.replace(".inp", ".out"),
196
+ ) as swmm_solver:
197
+
198
+ swmm_solver.start()
199
+
200
+ for _ in swmm_solver:
201
+ pass
202
+
203
+ def test_solver_get_time_attributes(self):
204
+ """
205
+ Test the get_start_date function of the SWMM solver
206
+ :return:
207
+ """
208
+ with solver.Solver(
209
+ inp_file=self.site_drainage_inp,
210
+ rpt_file=self.site_drainage_rpt,
211
+ out_file=self.site_drainage_out
212
+ ) as swmm_solver:
213
+ # Initialize the solver
214
+ swmm_solver.start()
215
+
216
+ start_date = swmm_solver.start_datetime
217
+ end_date = swmm_solver.end_datetime
218
+ report_start_date = swmm_solver.report_start_datetime
219
+
220
+ self.assertEqual(start_date, datetime(year=1998, month=1, day=1))
221
+ self.assertEqual(end_date, datetime(year=1998, month=1, day=1, hour=6))
222
+ self.assertEqual(report_start_date, datetime(year=1998, month=1, day=1))
223
+
224
+ def test_solver_set_time_attributes(self):
225
+ """
226
+ Test the set_start_date function of the SWMM solver
227
+ :return:
228
+ """
229
+ with solver.Solver(
230
+ inp_file=self.site_drainage_inp,
231
+ rpt_file=self.site_drainage_rpt,
232
+ out_file=self.site_drainage_out
233
+ ) as swmm_solver:
234
+ # Initialize the solver
235
+
236
+ start_date = datetime(year=2000, month=1, day=2)
237
+ end_date = datetime(year=2000, month=1, day=2, hour=2)
238
+ report_start_date = datetime(year=2000, month=1, day=2)
239
+
240
+ swmm_solver.start_datetime = start_date
241
+ swmm_solver.end_datetime = end_date
242
+ swmm_solver.report_start_datetime = report_start_date
243
+
244
+ swmm_solver.start()
245
+
246
+ for i, t in enumerate(swmm_solver):
247
+ current_datetime = swmm_solver.current_datetime
248
+ self.assertTrue(start_date <= current_datetime <= end_date, "Current datetime is within the range")
249
+
250
+ def test_get_object_count(self):
251
+ """
252
+ Test the get_object_count function of the SWMM solver
253
+ :return:
254
+ """
255
+ with solver.Solver(
256
+ inp_file=self.site_drainage_inp,
257
+ rpt_file=self.site_drainage_rpt,
258
+ out_file=self.site_drainage_out
259
+ ) as swmm_solver:
260
+
261
+ swmm_solver.start()
262
+
263
+ num_raingages = swmm_solver.get_object_count(solver.SWMMObjects.RAIN_GAGE)
264
+ num_subcatchments = swmm_solver.get_object_count(solver.SWMMObjects.SUBCATCHMENT)
265
+ num_nodes = swmm_solver.get_object_count(solver.SWMMObjects.NODE)
266
+ num_links = swmm_solver.get_object_count(solver.SWMMObjects.LINK)
267
+ num_aquifers = swmm_solver.get_object_count(solver.SWMMObjects.AQUIFER)
268
+ num_snowpacks = swmm_solver.get_object_count(solver.SWMMObjects.SNOWPACK)
269
+ num_hydrographs = swmm_solver.get_object_count(solver.SWMMObjects.UNIT_HYDROGRAPH)
270
+ num_lids = swmm_solver.get_object_count(solver.SWMMObjects.LID)
271
+ num_streets = swmm_solver.get_object_count(solver.SWMMObjects.STREET)
272
+ num_inlets = swmm_solver.get_object_count(solver.SWMMObjects.INLET)
273
+ num_transects = swmm_solver.get_object_count(solver.SWMMObjects.TRANSECT)
274
+ num_xsections = swmm_solver.get_object_count(solver.SWMMObjects.XSECTION_SHAPE)
275
+ num_controls = swmm_solver.get_object_count(solver.SWMMObjects.CONTROL_RULE)
276
+ num_pollutants = swmm_solver.get_object_count(solver.SWMMObjects.POLLUTANT)
277
+ num_landuses = swmm_solver.get_object_count(solver.SWMMObjects.LANDUSE)
278
+ num_curves = swmm_solver.get_object_count(solver.SWMMObjects.CURVE)
279
+ num_timeseries = swmm_solver.get_object_count(solver.SWMMObjects.TIMESERIES)
280
+ num_time_patterns = swmm_solver.get_object_count(solver.SWMMObjects.TIME_PATTERN)
281
+
282
+ self.assertEqual(num_raingages, 1)
283
+ self.assertEqual(num_subcatchments, 7)
284
+ self.assertEqual(num_nodes, 12)
285
+ self.assertEqual(num_links, 11)
286
+ self.assertEqual(num_aquifers, 0)
287
+ self.assertEqual(num_snowpacks, 0)
288
+ self.assertEqual(num_hydrographs, 0)
289
+ self.assertEqual(num_lids, 0)
290
+ self.assertEqual(num_streets, 0)
291
+ self.assertEqual(num_inlets, 0)
292
+ self.assertEqual(num_transects, 0)
293
+ self.assertEqual(num_xsections, 0)
294
+ self.assertEqual(num_controls, 0)
295
+ self.assertEqual(num_pollutants, 1)
296
+ self.assertEqual(num_landuses, 4)
297
+ self.assertEqual(num_curves, 0)
298
+ self.assertEqual(num_timeseries, 3)
299
+ self.assertEqual(num_time_patterns, 0)
300
+
301
+ with self.assertRaises(solver.SWMMSolverException) as context:
302
+ swmm_solver.get_object_count(solver.SWMMObjects.SYSTEM)
303
+
304
+ self.assertIn('API Error -999904: invalid object type.', str(context.exception))
305
+
306
+ def test_get_object_names(self):
307
+ """
308
+ Test the get_object_names function of the SWMM solver
309
+ :return:
310
+ """
311
+
312
+ with solver.Solver(
313
+ inp_file=self.site_drainage_inp,
314
+ rpt_file=self.site_drainage_rpt,
315
+ out_file=self.site_drainage_out,
316
+ ) as swmm_solver:
317
+ swmm_solver.start()
318
+
319
+ raingage_names = swmm_solver.get_object_names(solver.SWMMObjects.RAIN_GAGE)
320
+ subcatchment_names = swmm_solver.get_object_names(solver.SWMMObjects.SUBCATCHMENT)
321
+ node_names = swmm_solver.get_object_names(solver.SWMMObjects.NODE)
322
+ link_names = swmm_solver.get_object_names(solver.SWMMObjects.LINK)
323
+ pollutant_names = swmm_solver.get_object_names(solver.SWMMObjects.POLLUTANT)
324
+ landuse_names = swmm_solver.get_object_names(solver.SWMMObjects.LANDUSE)
325
+ timeseries_names = swmm_solver.get_object_names(solver.SWMMObjects.TIMESERIES)
326
+
327
+ self.assertListEqual(raingage_names, ['RainGage'])
328
+ self.assertListEqual(subcatchment_names, ['S1', 'S2', 'S3', 'S4', 'S5', 'S6', 'S7'])
329
+ self.assertListEqual(node_names, ['J1', 'J2', 'J3', 'J4', 'J5', 'J6', 'J7', 'J8', 'J9', 'J10', 'J11', 'O1'])
330
+ self.assertListEqual(link_names, ['C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9', 'C10', 'C11'])
331
+ self.assertListEqual(pollutant_names, ['TSS'])
332
+ self.assertListEqual(landuse_names, ['Residential_1', 'Residential_2', 'Commercial', 'Undeveloped'])
333
+ self.assertListEqual(timeseries_names, ['2-yr', '10-yr', '100-yr'])
334
+
335
+ def test_get_object_index(self):
336
+ """
337
+ Test the get_object_index function of the SWMM solver
338
+ :return:
339
+ """
340
+
341
+ with solver.Solver(
342
+ inp_file=self.site_drainage_inp,
343
+ rpt_file=self.site_drainage_rpt,
344
+ out_file=self.site_drainage_out,
345
+ ) as swmm_solver:
346
+ swmm_solver.start()
347
+
348
+ rg_index = swmm_solver.get_object_index(solver.SWMMObjects.RAIN_GAGE, 'RainGage')
349
+ sc_index = swmm_solver.get_object_index(solver.SWMMObjects.SUBCATCHMENT, 'S2')
350
+ node_index = swmm_solver.get_object_index(solver.SWMMObjects.NODE, 'J6')
351
+ link_index = swmm_solver.get_object_index(solver.SWMMObjects.LINK, 'C10')
352
+ pollutant_index = swmm_solver.get_object_index(solver.SWMMObjects.POLLUTANT, 'TSS')
353
+ landuse_index = swmm_solver.get_object_index(solver.SWMMObjects.LANDUSE, 'Commercial')
354
+ timeseries_index = swmm_solver.get_object_index(solver.SWMMObjects.TIMESERIES, '10-yr')
355
+
356
+ self.assertEqual(rg_index, 0)
357
+ self.assertEqual(sc_index, 1)
358
+ self.assertEqual(node_index, 5)
359
+ self.assertEqual(link_index, 9)
360
+ self.assertEqual(pollutant_index, 0)
361
+ self.assertEqual(landuse_index, 2)
362
+ self.assertEqual(timeseries_index, 1)
363
+
364
+ def test_get_gage_value(self):
365
+ """
366
+ Test the get_gage_value function of the SWMM solver
367
+ :return:
368
+ """
369
+
370
+ with solver.Solver(
371
+ inp_file=self.site_drainage_inp,
372
+ rpt_file=self.site_drainage_rpt,
373
+ out_file=self.site_drainage_out,
374
+ ) as swmm_solver:
375
+ swmm_solver.start()
376
+
377
+ for t in range(12):
378
+ swmm_solver.step()
379
+
380
+ rg_value = swmm_solver.get_value(
381
+ object_type=solver.SWMMObjects.RAIN_GAGE,
382
+ property_type=solver.SWMMRainGageProperties.GAGE_TOTAL_PRECIPITATION,
383
+ index=0,
384
+ )
385
+
386
+ self.assertAlmostEqual(rg_value / 12.0, 0.3)
387
+
388
+ def test_set_gage_value(self):
389
+ """
390
+ Test the set_gage_value function of the SWMM solver
391
+ :return:
392
+ """
393
+
394
+ with solver.Solver(
395
+ inp_file=self.site_drainage_inp,
396
+ rpt_file=self.site_drainage_rpt,
397
+ out_file=self.site_drainage_out,
398
+ ) as swmm_solver:
399
+ swmm_solver.start()
400
+
401
+ swmm_solver.set_value(
402
+ object_type=solver.SWMMObjects.RAIN_GAGE,
403
+ property_type=solver.SWMMRainGageProperties.GAGE_RAINFALL,
404
+ index=0,
405
+ value=3.6
406
+ )
407
+
408
+ for _ in range(12):
409
+ swmm_solver.step()
410
+
411
+ rg_value = swmm_solver.get_value(
412
+ object_type=solver.SWMMObjects.RAIN_GAGE,
413
+ property_type=solver.SWMMRainGageProperties.GAGE_TOTAL_PRECIPITATION,
414
+ index=0,
415
+ )
416
+
417
+ self.assertAlmostEqual(rg_value, 3.6)
418
+
419
+ def test_get_sub_catchment_value(self):
420
+ """
421
+ Test the get_subcatchment_value function of the SWMM solver
422
+ :return:
423
+ """
424
+
425
+ with solver.Solver(
426
+ inp_file=self.site_drainage_inp,
427
+ rpt_file=self.site_drainage_rpt,
428
+ out_file=self.site_drainage_out,
429
+ ) as swmm_solver:
430
+ swmm_solver.start()
431
+
432
+ for t in range(12):
433
+ swmm_solver.step()
434
+
435
+ sc_value = swmm_solver.get_value(
436
+ object_type=solver.SWMMObjects.SUBCATCHMENT,
437
+ property_type=solver.SWMMSubcatchmentProperties.RUNOFF,
438
+ index=1,
439
+ )
440
+
441
+ self.assertAlmostEqual(sc_value, 17.527141504933294)
442
+
443
+ def test_set_sub_catchment_value(self):
444
+ """
445
+ Test the set_subcatchment_value function of the SWMM solver
446
+ :return:
447
+ """
448
+
449
+ with solver.Solver(
450
+ inp_file=self.site_drainage_inp,
451
+ rpt_file=self.site_drainage_rpt,
452
+ out_file=self.site_drainage_out,
453
+ ) as swmm_solver:
454
+
455
+ swmm_solver.set_value(
456
+ object_type=solver.SWMMObjects.SUBCATCHMENT,
457
+ property_type=solver.SWMMSubcatchmentProperties.WIDTH,
458
+ index=1,
459
+ value=100.0
460
+ )
461
+
462
+ swmm_solver.start()
463
+
464
+ for _ in range(12):
465
+ swmm_solver.step()
466
+
467
+ sc_value = swmm_solver.get_value(
468
+ object_type=solver.SWMMObjects.SUBCATCHMENT,
469
+ property_type=solver.SWMMSubcatchmentProperties.WIDTH,
470
+ index=1,
471
+ )
472
+
473
+ self.assertAlmostEqual(sc_value, 100.0)
474
+
475
+ def test_get_sub_catchment_initial_buildup(self):
476
+ """
477
+ Test the get_subcatchment_initial_buildup function of the SWMM solver
478
+
479
+ :return:
480
+ """
481
+
482
+ with solver.Solver(
483
+ inp_file=self.site_drainage_inp,
484
+ rpt_file=self.site_drainage_rpt,
485
+ out_file=self.site_drainage_out,
486
+ ) as swmm_solver:
487
+ swmm_solver.start()
488
+
489
+ sc_value = swmm_solver.get_value(
490
+ object_type=solver.SWMMObjects.SUBCATCHMENT,
491
+ property_type=solver.SWMMSubcatchmentProperties.POLLUTANT_BUILDUP,
492
+ index=0,
493
+ sub_index=0,
494
+ )
495
+
496
+ self.assertEqual(first=sc_value, second=80.0)
497
+
498
+ def test_set_sub_catchment_initial_buildup(self):
499
+ """
500
+ Test the get_subcatchment_initial_buildup function of the SWMM solver
501
+
502
+ :return:
503
+ """
504
+
505
+ # import matplotlib
506
+ # matplotlib.use('TkAgg')
507
+ #
508
+ # import matplotlib.pyplot as plt
509
+ # import pandas as pd
510
+ #
511
+ # fig, axes = plt.subplots(nrows=2, ncols=1 , sharex=True)
512
+
513
+ with solver.Solver(
514
+ inp_file=self.site_drainage_inp,
515
+ rpt_file=self.site_drainage_rpt,
516
+ out_file=self.site_drainage_out,
517
+ ) as swmm_solver:
518
+
519
+ swmm_solver.stride_step = 10000
520
+
521
+ swmm_solver.start()
522
+
523
+ for _ in swmm_solver:
524
+ pass
525
+
526
+ from openswmmcore import output
527
+ toutput = output.Output(output_file=self.site_drainage_out)
528
+
529
+ runoff = toutput.get_subcatchment_timeseries(
530
+ element_index='S1',
531
+ attribute=output.SubcatchAttribute.INFILTRATION_LOSS,
532
+ sub_index=0
533
+ )
534
+
535
+ results = toutput.get_subcatchment_timeseries(
536
+ element_index='S1',
537
+ attribute=output.SubcatchAttribute.POLLUTANT_CONCENTRATION,
538
+ sub_index=1
539
+ )
540
+ del toutput
541
+
542
+ # runoff = pd.Series(runoff, index=pd.to_datetime(list(runoff.keys())))
543
+ # runoff = pd.DataFrame(runoff, columns=['Runoff (cfs)'])
544
+ #
545
+ # runoff.plot()
546
+ # plt.show()
547
+ # matplotlib.use('TkAgg')
548
+ #
549
+ # runoff.plot(ax=axes[0])
550
+
551
+ # data = pd.Series(results, index=pd.to_datetime(list(results.keys())))
552
+ # data = pd.DataFrame(data, columns=['TSS Original (mg/L)'])
553
+ # data.plot(ax=axes[1], linewidth=3.0)
554
+
555
+ with solver.Solver(
556
+ inp_file=self.site_drainage_inp,
557
+ rpt_file=self.site_drainage_rpt,
558
+ out_file=self.site_drainage_out,
559
+ ) as swmm_solver:
560
+
561
+ swmm_solver.start()
562
+
563
+ for t, elapsed_time in enumerate(swmm_solver):
564
+
565
+ if t == 10:
566
+ swmm_solver.set_value(
567
+ object_type=solver.SWMMObjects.SUBCATCHMENT,
568
+ property_type=solver.SWMMSubcatchmentProperties.EXTERNAL_POLLUTANT_BUILDUP,
569
+ index='S1',
570
+ value=120.0,
571
+ sub_index=0,
572
+ )
573
+ swmm_solver.step(1)
574
+ swmm_solver.set_value(
575
+ object_type=solver.SWMMObjects.SUBCATCHMENT,
576
+ property_type=solver.SWMMSubcatchmentProperties.EXTERNAL_POLLUTANT_BUILDUP,
577
+ index='S1',
578
+ value=0.0,
579
+ sub_index=0,
580
+ )
581
+ else:
582
+ pass
583
+
584
+ toutput = output.Output(output_file=self.site_drainage_out)
585
+ results = toutput.get_subcatchment_timeseries(
586
+ element_index='S1',
587
+ attribute=output.SubcatchAttribute.POLLUTANT_CONCENTRATION,
588
+ sub_index=1
589
+ )
590
+ del toutput
591
+
592
+ # rdata = pd.Series(results, index=pd.to_datetime(list(results.keys())))
593
+ # rdata = pd.DataFrame(rdata, columns=['TSS Modified (mg/L)'])
594
+ # rdata.plot(ax=axes[1])
595
+ #
596
+ # plt.show()
597
+ # matplotlib.use('TkAgg')
598
+
599
+ def test_get_node_value(self):
600
+ """
601
+ Test the get_node_value function of the SWMM solver
602
+ :return:
603
+ """
604
+
605
+ with solver.Solver(
606
+ inp_file=example_solver_data.SITE_DRAINAGE_EXAMPLE_INPUT_FILE,
607
+ rpt_file=example_solver_data.NON_EXISTENT_INPUT_FILE.replace(".inp", ".rpt"),
608
+ out_file=example_solver_data.SITE_DRAINAGE_EXAMPLE_INPUT_FILE.replace(".inp", ".out"),
609
+ ) as swmm_solver:
610
+ swmm_solver.start()
611
+
612
+ for t in range(12):
613
+ swmm_solver.step()
614
+
615
+ node_value = swmm_solver.get_value(
616
+ object_type=solver.SWMMObjects.NODE,
617
+ property_type=solver.SWMMNodeProperties.TOTAL_INFLOW,
618
+ index=5,
619
+ )
620
+
621
+ self.assertAlmostEqual(node_value, 58.58717843671191)
622
+
623
+ def test_set_node_value(self):
624
+ """
625
+ Test the set_node_value function of the SWMM solver
626
+ :return:
627
+ """
628
+
629
+ with solver.Solver(
630
+ inp_file=example_solver_data.SITE_DRAINAGE_EXAMPLE_INPUT_FILE,
631
+ rpt_file=example_solver_data.NON_EXISTENT_INPUT_FILE.replace(".inp", ".rpt"),
632
+ out_file=example_solver_data.SITE_DRAINAGE_EXAMPLE_INPUT_FILE.replace(".inp", ".out"),
633
+ ) as swmm_solver:
634
+
635
+ swmm_solver.set_value(
636
+ object_type=solver.SWMMObjects.NODE,
637
+ property_type=solver.SWMMNodeProperties.INVERT_ELEVATION,
638
+ index=5,
639
+ value=10.0
640
+ )
641
+
642
+ swmm_solver.start()
643
+
644
+ for _ in range(12):
645
+ swmm_solver.step()
646
+
647
+ node_value = swmm_solver.get_value(
648
+ object_type=solver.SWMMObjects.NODE,
649
+ property_type=solver.SWMMNodeProperties.INVERT_ELEVATION,
650
+ index=5,
651
+ )
652
+
653
+ self.assertAlmostEqual(node_value, 10.0)
654
+
655
+ def test_get_link_value(self):
656
+ """
657
+ Test the get_link_value function of the SWMM solver
658
+ :return:
659
+ """
660
+
661
+ with solver.Solver(
662
+ inp_file=example_solver_data.SITE_DRAINAGE_EXAMPLE_INPUT_FILE,
663
+ rpt_file=example_solver_data.NON_EXISTENT_INPUT_FILE.replace(".inp", ".rpt"),
664
+ out_file=example_solver_data.SITE_DRAINAGE_EXAMPLE_INPUT_FILE.replace(".inp", ".out"),
665
+ ) as swmm_solver:
666
+ swmm_solver.start()
667
+
668
+ for t in range(12):
669
+ swmm_solver.step()
670
+
671
+ link_value = swmm_solver.get_value(
672
+ object_type=solver.SWMMObjects.LINK,
673
+ property_type=solver.SWMMLinkProperties.FLOW,
674
+ index=9,
675
+ )
676
+
677
+ link_value_by_name = swmm_solver.get_value(
678
+ object_type=solver.SWMMObjects.LINK,
679
+ property_type=solver.SWMMLinkProperties.FLOW,
680
+ index='C10',
681
+ )
682
+
683
+ self.assertAlmostEqual(first=link_value, second=102.01283173880869)
684
+ self.assertAlmostEqual(first=link_value, second=link_value_by_name)
685
+
686
+ def test_set_link_value(self):
687
+ """
688
+ Test the set_link_value function of the SWMM solver
689
+ :return:
690
+ """
691
+
692
+ with solver.Solver(
693
+ inp_file=example_solver_data.SITE_DRAINAGE_EXAMPLE_INPUT_FILE,
694
+ rpt_file=example_solver_data.NON_EXISTENT_INPUT_FILE.replace(".inp", ".rpt"),
695
+ out_file=example_solver_data.SITE_DRAINAGE_EXAMPLE_INPUT_FILE.replace(".inp", ".out"),
696
+ ) as swmm_solver:
697
+
698
+ swmm_solver.set_value(
699
+ object_type=solver.SWMMObjects.LINK,
700
+ property_type=solver.SWMMLinkProperties.START_NODE_OFFSET,
701
+ index=9,
702
+ value=1.0
703
+ )
704
+
705
+ swmm_solver.start()
706
+
707
+ for _ in range(12):
708
+ swmm_solver.step()
709
+
710
+ link_value = swmm_solver.get_value(
711
+ object_type=solver.SWMMObjects.LINK,
712
+ property_type=solver.SWMMLinkProperties.START_NODE_OFFSET,
713
+ index=9,
714
+ )
715
+
716
+ self.assertAlmostEqual(link_value, 1.0)