openswmm 6.0.0a1__tar.gz → 6.0.0.dev2__tar.gz

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 (371) hide show
  1. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/CMakeLists.txt +34 -0
  2. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/PKG-INFO +2 -3
  3. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/concepts.rst +15 -0
  4. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/links.rst +79 -3
  5. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/nodes.rst +51 -2
  6. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/solver.rst +63 -0
  7. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/statistics.rst +66 -6
  8. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/subcatchments.rst +47 -14
  9. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_2d.pxd +8 -7
  10. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_2d.pyi +31 -5
  11. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_2d.pyx +69 -10
  12. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_common.pxd +119 -36
  13. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_enums.py +5 -0
  14. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_gages.pyi +2 -1
  15. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_gages.pyx +7 -2
  16. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_geopackage.pyi +6 -3
  17. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_geopackage.pyx +101 -51
  18. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_hotstart.pyi +9 -4
  19. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_hotstart.pyx +32 -8
  20. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_links.pyi +219 -4
  21. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_links.pyx +457 -8
  22. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_nodes.pyi +95 -6
  23. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_nodes.pyx +196 -13
  24. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_output_reader.pyi +61 -4
  25. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_output_reader.pyx +128 -12
  26. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_solver.pyi +69 -1
  27. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_solver.pyx +126 -2
  28. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_statistics.pyi +111 -3
  29. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_statistics.pyx +206 -6
  30. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_subcatchments.pyi +66 -1
  31. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_subcatchments.pyx +136 -3
  32. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/pyproject.toml +71 -10
  33. openswmm-6.0.0.dev2/scripts/cibw_repair_windows.py +98 -0
  34. openswmm-6.0.0.dev2/tests/data/__pycache__/__init__.cpython-312.pyc +0 -0
  35. openswmm-6.0.0.dev2/tests/data/output/__pycache__/__init__.cpython-312.pyc +0 -0
  36. openswmm-6.0.0.dev2/tests/data/solver/__pycache__/__init__.cpython-312.pyc +0 -0
  37. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/non_existent_input_file.rpt +3 -3
  38. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/site_drainage_example.rpt +3 -3
  39. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/site_drainage_example_link.rpt +3 -3
  40. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/site_drainage_example_node.rpt +3 -3
  41. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/site_drainage_example_outfall.rpt +4 -4
  42. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/site_drainage_example_routing.rpt +3 -3
  43. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/site_drainage_example_runoff.rpt +3 -3
  44. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/site_drainage_example_subcatch.rpt +4 -4
  45. openswmm-6.0.0.dev2/tests/engine/test_concurrent_simulation.py +294 -0
  46. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_geopackage.py +65 -4
  47. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_integration.py +5 -3
  48. openswmm-6.0.0.dev2/tests/engine/test_new_api.py +724 -0
  49. openswmm-6.0.0.dev2/tests/engine/test_new_api.py.tmp +724 -0
  50. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_output_reader.py +90 -0
  51. openswmm-6.0.0.dev2/tests/engine/test_runoff_interface.py +170 -0
  52. openswmm-6.0.0.dev2/tests/engine/verify_geopackage_c_api.cpp +495 -0
  53. openswmm-6.0.0.dev2/tests/engine/verify_geopackage_c_api.sh +90 -0
  54. openswmm-6.0.0.dev2/tests/test_api_coverage.py +304 -0
  55. openswmm-6.0.0a1/scripts/repair_wheel_windows.py +0 -76
  56. openswmm-6.0.0a1/tests/engine/test_new_api.py +0 -295
  57. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/.claude/settings.local.json +0 -0
  58. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/CMakePresets.json +0 -0
  59. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/LICENSE +0 -0
  60. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/README.md +0 -0
  61. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/cmake/CythonHelpers.cmake +0 -0
  62. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/cmake/PatchNumpyPxd.cmake +0 -0
  63. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/create_schema_review_db.py +0 -0
  64. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/LEGACY_API_EXPANSION_PLAN.md +0 -0
  65. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/Makefile +0 -0
  66. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.buildinfo +0 -0
  67. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/__intersphinx_cache__/numpy_objects.inv +0 -0
  68. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/__intersphinx_cache__/python_objects.inv +0 -0
  69. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/api.doctree +0 -0
  70. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/environment.pickle +0 -0
  71. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/concepts.doctree +0 -0
  72. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/controls.doctree +0 -0
  73. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/editing.doctree +0 -0
  74. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/error_handling.doctree +0 -0
  75. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/forcing.doctree +0 -0
  76. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/gages.doctree +0 -0
  77. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/hotstart.doctree +0 -0
  78. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/index.doctree +0 -0
  79. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/inflows.doctree +0 -0
  80. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/infrastructure.doctree +0 -0
  81. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/install.doctree +0 -0
  82. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/links.doctree +0 -0
  83. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/massbalance.doctree +0 -0
  84. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/model_builder.doctree +0 -0
  85. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/nodes.doctree +0 -0
  86. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/output_reader.doctree +0 -0
  87. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/pollutants.doctree +0 -0
  88. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/quality.doctree +0 -0
  89. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/quickstart.doctree +0 -0
  90. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/solver.doctree +0 -0
  91. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/spatial.doctree +0 -0
  92. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/statistics.doctree +0 -0
  93. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/subcatchments.doctree +0 -0
  94. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/guide/tables.doctree +0 -0
  95. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/index.doctree +0 -0
  96. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/legacy/index.doctree +0 -0
  97. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/legacy/output.doctree +0 -0
  98. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/legacy/solver.doctree +0 -0
  99. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/license.doctree +0 -0
  100. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/.doctrees/migration/swmm5_to_swmm6.doctree +0 -0
  101. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_images/hydrocouple_logo.png +0 -0
  102. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_modules/index.html +0 -0
  103. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_modules/openswmm/legacy/engine/_forcing_log.html +0 -0
  104. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_modules/openswmm/legacy/engine/_links.html +0 -0
  105. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_modules/openswmm/legacy/engine/_nodes.html +0 -0
  106. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_modules/openswmm/legacy/engine/_raingages.html +0 -0
  107. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_modules/openswmm/legacy/engine/_subcatchments.html +0 -0
  108. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_modules/openswmm/legacy/engine/_system.html +0 -0
  109. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/api.rst.txt +0 -0
  110. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/concepts.rst.txt +0 -0
  111. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/controls.rst.txt +0 -0
  112. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/editing.rst.txt +0 -0
  113. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/error_handling.rst.txt +0 -0
  114. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/forcing.rst.txt +0 -0
  115. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/gages.rst.txt +0 -0
  116. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/hotstart.rst.txt +0 -0
  117. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/index.rst.txt +0 -0
  118. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/inflows.rst.txt +0 -0
  119. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/infrastructure.rst.txt +0 -0
  120. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/install.rst.txt +0 -0
  121. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/links.rst.txt +0 -0
  122. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/massbalance.rst.txt +0 -0
  123. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/model_builder.rst.txt +0 -0
  124. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/nodes.rst.txt +0 -0
  125. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/output_reader.rst.txt +0 -0
  126. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/pollutants.rst.txt +0 -0
  127. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/quality.rst.txt +0 -0
  128. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/quickstart.rst.txt +0 -0
  129. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/solver.rst.txt +0 -0
  130. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/spatial.rst.txt +0 -0
  131. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/statistics.rst.txt +0 -0
  132. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/subcatchments.rst.txt +0 -0
  133. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/guide/tables.rst.txt +0 -0
  134. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/index.rst.txt +0 -0
  135. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/legacy/index.rst.txt +0 -0
  136. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/legacy/output.rst.txt +0 -0
  137. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/legacy/solver.rst.txt +0 -0
  138. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/license.rst.txt +0 -0
  139. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sources/migration/swmm5_to_swmm6.rst.txt +0 -0
  140. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sphinx_design_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css +0 -0
  141. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_sphinx_design_static/design-tabs.js +0 -0
  142. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/base-stemmer.js +0 -0
  143. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/basic.css +0 -0
  144. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css +0 -0
  145. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/design-tabs.js +0 -0
  146. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/doctools.js +0 -0
  147. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/documentation_options.js +0 -0
  148. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/english-stemmer.js +0 -0
  149. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/file.png +0 -0
  150. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/hydrocouple_logo.png +0 -0
  151. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/language_data.js +0 -0
  152. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/minus.png +0 -0
  153. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/openswmm.css +0 -0
  154. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/plus.png +0 -0
  155. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/pygments.css +0 -0
  156. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/scripts/bootstrap.js +0 -0
  157. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/scripts/bootstrap.js.LICENSE.txt +0 -0
  158. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/scripts/bootstrap.js.map +0 -0
  159. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/scripts/pydata-sphinx-theme.js +0 -0
  160. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/scripts/pydata-sphinx-theme.js.map +0 -0
  161. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/searchtools.js +0 -0
  162. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/sphinx_highlight.js +0 -0
  163. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/styles/bootstrap.css +0 -0
  164. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/styles/bootstrap.css.map +0 -0
  165. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/styles/pydata-sphinx-theme.css +0 -0
  166. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/styles/pydata-sphinx-theme.css.map +0 -0
  167. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/styles/theme.css +0 -0
  168. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/vendor/fontawesome/6.5.1/LICENSE.txt +0 -0
  169. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/vendor/fontawesome/6.5.1/css/all.min.css +0 -0
  170. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/vendor/fontawesome/6.5.1/js/all.min.js +0 -0
  171. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/vendor/fontawesome/6.5.1/js/all.min.js.LICENSE.txt +0 -0
  172. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/vendor/fontawesome/6.5.1/webfonts/fa-brands-400.ttf +0 -0
  173. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/vendor/fontawesome/6.5.1/webfonts/fa-brands-400.woff2 +0 -0
  174. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/vendor/fontawesome/6.5.1/webfonts/fa-regular-400.ttf +0 -0
  175. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/vendor/fontawesome/6.5.1/webfonts/fa-regular-400.woff2 +0 -0
  176. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/vendor/fontawesome/6.5.1/webfonts/fa-solid-900.ttf +0 -0
  177. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/vendor/fontawesome/6.5.1/webfonts/fa-solid-900.woff2 +0 -0
  178. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/vendor/fontawesome/6.5.1/webfonts/fa-v4compatibility.ttf +0 -0
  179. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/vendor/fontawesome/6.5.1/webfonts/fa-v4compatibility.woff2 +0 -0
  180. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/_static/webpack-macros.html +0 -0
  181. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/api.html +0 -0
  182. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/genindex.html +0 -0
  183. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/concepts.html +0 -0
  184. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/controls.html +0 -0
  185. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/editing.html +0 -0
  186. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/error_handling.html +0 -0
  187. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/forcing.html +0 -0
  188. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/gages.html +0 -0
  189. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/hotstart.html +0 -0
  190. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/index.html +0 -0
  191. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/inflows.html +0 -0
  192. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/infrastructure.html +0 -0
  193. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/install.html +0 -0
  194. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/links.html +0 -0
  195. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/massbalance.html +0 -0
  196. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/model_builder.html +0 -0
  197. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/nodes.html +0 -0
  198. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/output_reader.html +0 -0
  199. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/pollutants.html +0 -0
  200. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/quality.html +0 -0
  201. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/quickstart.html +0 -0
  202. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/solver.html +0 -0
  203. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/spatial.html +0 -0
  204. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/statistics.html +0 -0
  205. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/subcatchments.html +0 -0
  206. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/guide/tables.html +0 -0
  207. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/index.html +0 -0
  208. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/legacy/index.html +0 -0
  209. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/legacy/output.html +0 -0
  210. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/legacy/solver.html +0 -0
  211. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/license.html +0 -0
  212. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/migration/swmm5_to_swmm6.html +0 -0
  213. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/objects.inv +0 -0
  214. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/py-modindex.html +0 -0
  215. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/search.html +0 -0
  216. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_build/html/searchindex.js +0 -0
  217. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/_static/openswmm.css +0 -0
  218. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/api.rst +0 -0
  219. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/conf.py +0 -0
  220. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/environment.yml +0 -0
  221. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/controls.rst +0 -0
  222. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/editing.rst +0 -0
  223. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/error_handling.rst +0 -0
  224. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/forcing.rst +0 -0
  225. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/gages.rst +0 -0
  226. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/hotstart.rst +0 -0
  227. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/index.rst +0 -0
  228. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/inflows.rst +0 -0
  229. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/infrastructure.rst +0 -0
  230. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/install.rst +0 -0
  231. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/massbalance.rst +0 -0
  232. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/model_builder.rst +0 -0
  233. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/output_reader.rst +0 -0
  234. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/pollutants.rst +0 -0
  235. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/quality.rst +0 -0
  236. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/quickstart.rst +0 -0
  237. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/spatial.rst +0 -0
  238. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/guide/tables.rst +0 -0
  239. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/images/hydrocouple_logo.png +0 -0
  240. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/index.rst +0 -0
  241. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/legacy/index.rst +0 -0
  242. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/legacy/output.rst +0 -0
  243. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/legacy/solver.rst +0 -0
  244. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/license.rst +0 -0
  245. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/make.bat +0 -0
  246. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/migration/swmm5_to_swmm6.rst +0 -0
  247. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/docs/requirements.txt +0 -0
  248. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/generate_geopackage_erd.py +0 -0
  249. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/CMakeLists.txt +0 -0
  250. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/__init__.py +0 -0
  251. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/data/__init__.py +0 -0
  252. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/CMakeLists.txt +0 -0
  253. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/__init__.pxd +0 -0
  254. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/__init__.py +0 -0
  255. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/__init__.pyi +0 -0
  256. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_controls.pyi +0 -0
  257. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_controls.pyx +0 -0
  258. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_dates.py +0 -0
  259. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_dates.pyi +0 -0
  260. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_edit.pyi +0 -0
  261. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_edit.pyx +0 -0
  262. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_enums.pyi +0 -0
  263. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_forcing.pyi +0 -0
  264. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_forcing.pyx +0 -0
  265. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_geometry.py +0 -0
  266. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_inflows.pyi +0 -0
  267. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_inflows.pyx +0 -0
  268. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_infrastructure.pyi +0 -0
  269. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_infrastructure.pyx +0 -0
  270. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_massbalance.pyi +0 -0
  271. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_massbalance.pyx +0 -0
  272. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_model.pyi +0 -0
  273. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_model.pyx +0 -0
  274. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_pollutants.pyi +0 -0
  275. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_pollutants.pyx +0 -0
  276. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_quality.pyi +0 -0
  277. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_quality.pyx +0 -0
  278. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_report.py +0 -0
  279. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_solver.pxd +0 -0
  280. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_spatial.pyi +0 -0
  281. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_spatial.pyx +0 -0
  282. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_tables.pyi +0 -0
  283. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/engine/_tables.pyx +0 -0
  284. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/CMakeLists.txt +0 -0
  285. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/__init__.py +0 -0
  286. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/engine/CMakeLists.txt +0 -0
  287. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/engine/__init__.pxd +0 -0
  288. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/engine/__init__.py +0 -0
  289. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/engine/_forcing_log.py +0 -0
  290. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/engine/_links.py +0 -0
  291. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/engine/_nodes.py +0 -0
  292. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/engine/_raingages.py +0 -0
  293. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/engine/_solver.c +0 -0
  294. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/engine/_solver.pyi +0 -0
  295. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/engine/_solver.pyx +0 -0
  296. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/engine/_subcatchments.py +0 -0
  297. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/engine/_system.py +0 -0
  298. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/engine/solver.pxd +0 -0
  299. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/output/CMakeLists.txt +0 -0
  300. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/output/__init__.pxd +0 -0
  301. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/output/__init__.py +0 -0
  302. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/output/_output.pyi +0 -0
  303. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/output/_output.pyx +0 -0
  304. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/legacy/output/output.pxd +0 -0
  305. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/output/CMakeLists.txt +0 -0
  306. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/output/__init__.pxd +0 -0
  307. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/output/__init__.py +0 -0
  308. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/output/_output.pyi +0 -0
  309. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/output/_output.pyx +0 -0
  310. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/output/output.pxd +0 -0
  311. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/solver/CMakeLists.txt +0 -0
  312. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/solver/__init__.pxd +0 -0
  313. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/solver/__init__.py +0 -0
  314. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/solver/_solver.pyi +0 -0
  315. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/solver/_solver.pyx +0 -0
  316. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/openswmm/solver/solver.pxd +0 -0
  317. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/requirements.txt +0 -0
  318. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/scripts/clean.sh +0 -0
  319. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/smoke_test.py +0 -0
  320. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/__init__.py +0 -0
  321. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/conftest.py +0 -0
  322. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/__init__.py +0 -0
  323. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/__pycache__/__init__.cpython-313.pyc +0 -0
  324. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/output/__init__.py +0 -0
  325. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/output/__pycache__/__init__.cpython-313.pyc +0 -0
  326. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/output/example_output_1.out +0 -0
  327. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/output/json_time_series.pickle +0 -0
  328. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/__init__.py +0 -0
  329. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/__pycache__/__init__.cpython-313.pyc +0 -0
  330. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/site_drainage_example.inp +0 -0
  331. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/site_drainage_example.out +0 -0
  332. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/site_drainage_example_link.out +0 -0
  333. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/site_drainage_example_node.out +0 -0
  334. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/site_drainage_example_outfall.out +0 -0
  335. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/site_drainage_example_routing.out +0 -0
  336. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/site_drainage_example_runoff.out +0 -0
  337. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/data/solver/site_drainage_example_subcatch.out +0 -0
  338. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/__init__.py +0 -0
  339. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/conftest.py +0 -0
  340. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_callbacks_and_xsect.py +0 -0
  341. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_controls_advancement.py +0 -0
  342. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_controls_inflows.py +0 -0
  343. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_edit.py +0 -0
  344. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_enums.py +0 -0
  345. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_gages.py +0 -0
  346. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_gages_expanded.py +0 -0
  347. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_hotstart.py +0 -0
  348. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_infrastructure.py +0 -0
  349. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_links.py +0 -0
  350. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_links_expanded.py +0 -0
  351. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_massbalance.py +0 -0
  352. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_massbalance_expanded.py +0 -0
  353. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_model_builder.py +0 -0
  354. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_new_modules.py +0 -0
  355. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_nodes.py +0 -0
  356. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_nodes_expanded.py +0 -0
  357. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_opened_state_editing.py +0 -0
  358. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_quality_pollutants.py +0 -0
  359. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_rdii_advancement.py +0 -0
  360. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_solver.py +0 -0
  361. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_spatial.py +0 -0
  362. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_subcatchments.py +0 -0
  363. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_subcatchments_expanded.py +0 -0
  364. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_tables.py +0 -0
  365. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/engine/test_workflow.py +0 -0
  366. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/legacy/__init__.py +0 -0
  367. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/legacy/test_output.py +0 -0
  368. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/legacy/test_phase1_enum_coverage.py +0 -0
  369. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/legacy/test_phase2_statistics.py +0 -0
  370. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/legacy/test_phase3_oop_wrappers.py +0 -0
  371. {openswmm-6.0.0a1 → openswmm-6.0.0.dev2}/tests/legacy/test_solver.py +0 -0
@@ -11,6 +11,40 @@
11
11
 
12
12
  cmake_minimum_required(VERSION 3.24)
13
13
 
14
+ # ============================================================================
15
+ # Source-distribution guard: the sdist on PyPI is metadata-only and does NOT
16
+ # carry the OpenSWMM C/C++ engine source tree. Detect that we have neither a
17
+ # pre-built engine prefix nor the parent project's CMakeLists.txt reachable
18
+ # via add_subdirectory(..) and fail with a clear, actionable error rather
19
+ # than letting vcpkg or the C compiler emit a confusing one. Without this
20
+ # guard, a stray VCPKG_ROOT in the user's environment causes the auto-load
21
+ # block below to fire and vcpkg then tries to read a vcpkg.json next to the
22
+ # unpacked sdist that does not exist.
23
+ # ============================================================================
24
+ if(NOT DEFINED OPENSWMM_ENGINE_INSTALL_PREFIX
25
+ AND NOT DEFINED ENV{OPENSWMM_ENGINE_INSTALL_PREFIX}
26
+ AND NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../CMakeLists.txt")
27
+ message(FATAL_ERROR
28
+ "openswmm cannot be built from this source distribution: the sdist "
29
+ "does not bundle the OpenSWMM C/C++ engine sources, and no pre-built "
30
+ "engine was supplied via -DOPENSWMM_ENGINE_INSTALL_PREFIX=<path>.\n"
31
+ "\n"
32
+ "Install a pre-built wheel instead:\n"
33
+ " python -m pip install openswmm\n"
34
+ "\n"
35
+ "Wheels are published for Python 3.9-3.13 on Linux x86_64, macOS "
36
+ "(arm64 and x86_64), and Windows x64. If pip fell back to this "
37
+ "sdist, no wheel matched your platform/interpreter -- check the "
38
+ "available files at https://pypi.org/project/openswmm/#files and, "
39
+ "if needed, switch to a supported Python version.\n"
40
+ "\n"
41
+ "Source builds are supported only from a full git checkout of the "
42
+ "openswmm.engine repository:\n"
43
+ " git clone https://github.com/hydrocouple/openswmm.engine\n"
44
+ " cd openswmm.engine/python\n"
45
+ " pip install . --no-build-isolation")
46
+ endif()
47
+
14
48
  # ============================================================================
15
49
  # vcpkg manifest directory: the vcpkg.json lives one directory above python/.
16
50
  # Set VCPKG_MANIFEST_DIR before project() so vcpkg's toolchain file sees it.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openswmm
3
- Version: 6.0.0a1
3
+ Version: 6.0.0.dev2
4
4
  Summary: Python bindings for the OpenSWMM stormwater modelling engine.
5
5
  Keywords: SWMM,stormwater,hydrology,hydraulics,water resources,environmental engineering
6
6
  Author-Email: Caleb Buahin <caleb.buahin@gmail.com>
@@ -23,7 +23,6 @@ Classifier: Operating System :: Unix
23
23
  Classifier: Operating System :: POSIX :: Linux
24
24
  Classifier: Operating System :: MacOS
25
25
  Classifier: Programming Language :: Python :: 3
26
- Classifier: Programming Language :: Python :: 3.9
27
26
  Classifier: Programming Language :: Python :: 3.10
28
27
  Classifier: Programming Language :: Python :: 3.11
29
28
  Classifier: Programming Language :: Python :: 3.12
@@ -37,7 +36,7 @@ Project-URL: Homepage, https://github.com/hydrocouple/openswmm.engine/python
37
36
  Project-URL: Repository, https://github.com/hydrocouple/openswmm.engine
38
37
  Project-URL: Bug Tracker, https://github.com/hydrocouple/openswmm.engine/issues
39
38
  Project-URL: Changelog, https://github.com/hydrocouple/openswmm.engine/blob/main/CHANGELOG.md
40
- Requires-Python: >=3.9
39
+ Requires-Python: >=3.10
41
40
  Requires-Dist: numpy>=1.21.0
42
41
  Provides-Extra: dev
43
42
  Requires-Dist: pytest>=8.3; extra == "dev"
@@ -256,6 +256,21 @@ Threading & multiprocessing
256
256
  * **Multiple threads, one Solver per thread**: supported. The C
257
257
  engine is reentrant; two threads each holding their own Solver do
258
258
  not interact.
259
+
260
+ As of OpenSWMM 6.0, the following Cython entry points release the
261
+ GIL while inside the C engine, so two such threads execute their
262
+ C work truly in parallel rather than serialising on the interpreter:
263
+
264
+ * :meth:`Solver.step`, :meth:`Solver.stride`
265
+ * Every ``*_bulk`` getter / setter on :class:`Nodes`,
266
+ :class:`Links`, and :class:`Subcatchments`
267
+ (:meth:`get_depths_bulk`, :meth:`get_flows_bulk`,
268
+ :meth:`get_quality_bulk`, etc.)
269
+
270
+ Registered step-begin / step-end callbacks remain safe: their
271
+ Cython trampolines reacquire the GIL via ``noexcept with gil:``
272
+ before invoking the user's Python callable.
273
+
259
274
  * **Multiple threads, one shared Solver**: **not** supported. The
260
275
  Solver and its domain classes assume a single-threaded caller. If
261
276
  you need shared state, drive a single Solver from one thread and
@@ -138,6 +138,41 @@ Pump-specific
138
138
  * - :meth:`get_pump_init_state` / :meth:`set_pump_init_state`
139
139
  - Initial on/off state.
140
140
 
141
+ Pump utilization statistics
142
+ ---------------------------
143
+
144
+ Accumulated during a running simulation. Read either per-link with the
145
+ scalar accessors, or — for whole-network summaries — in one shot with
146
+ :meth:`get_pump_stats_bulk`, which performs a single C ABI crossing
147
+ instead of ``3 * n_links`` and releases the GIL during the call.
148
+
149
+ .. list-table::
150
+ :header-rows: 1
151
+ :widths: 45 55
152
+
153
+ * - Method
154
+ - Returns
155
+ * - :meth:`get_stat_pump_cycles(idx)`
156
+ - Pump on/off cycle count (``int``).
157
+ * - :meth:`get_stat_pump_on_time(idx)`
158
+ - Total pump on-time in seconds (``float``).
159
+ * - :meth:`get_stat_pump_volume(idx)`
160
+ - Total volume pumped in ft³ (``float``).
161
+ * - :meth:`get_pump_stats_bulk()`
162
+ - ``dict`` of three ``np.ndarray`` columns — ``cycles``
163
+ (``int32``), ``on_time`` (``float64``), ``volume`` (``float64``);
164
+ non-pump links carry ``cycles == -1``.
165
+
166
+ .. code-block:: python
167
+
168
+ # Whole-network pump summary in one call.
169
+ stats = links.get_pump_stats_bulk()
170
+ pumps = stats["cycles"] >= 0 # filter to pump links
171
+ total_pumped_ft3 = stats["volume"][pumps].sum()
172
+ total_run_time_h = stats["on_time"][pumps].sum() / 3600.0
173
+ print(f"{pumps.sum()} pumps, {total_pumped_ft3:.1f} ft³ pumped, "
174
+ f"{total_run_time_h:.1f} pump-hours")
175
+
141
176
  Weir / orifice
142
177
  --------------
143
178
 
@@ -301,10 +336,51 @@ Bulk arrays
301
336
  - All link mid-point depths.
302
337
  * - :meth:`get_quality_bulk(p)`
303
338
  - Pollutant ``p`` concentration per link.
339
+ * - :meth:`get_pump_stats_bulk`
340
+ - All pump statistics in a single C call —
341
+ ``{"cycles": ndarray[int32], "on_time": ndarray[float64],
342
+ "volume": ndarray[float64]}``. Non-pump links carry
343
+ ``cycles == -1`` as a sentinel.
344
+ * - :meth:`get_velocities_bulk`
345
+ - Cross-sectional velocity per link *(added 6.0.0)*.
346
+ * - :meth:`get_capacities_bulk`
347
+ - Capacity ratio ``q / q_full`` per link *(added 6.0.0)*.
348
+ * - :meth:`get_volumes_bulk`
349
+ - Stored volume per link *(added 6.0.0)*.
350
+ * - :meth:`get_control_settings_bulk`
351
+ - Active control setting (0..1) per link *(added 6.0.0)*.
352
+ * - :meth:`get_target_settings_bulk`
353
+ - Target control setting per link *(added 6.0.0)*.
354
+ * - :meth:`get_hyd_powers_bulk`
355
+ - Hydraulic power per link in ft-lb/s
356
+ (``gamma * |Q| * |hL|``) *(added 6.0.0)*.
357
+ * - :meth:`get_ids_bulk`
358
+ - ``list[str]`` of every link's id in one C call
359
+ *(added 6.0.0; stride-packed UTF-8)*.
360
+
361
+ Memory-aliasing note: ``get_flows_bulk`` and ``get_depths_bulk`` return
362
+ arrays that share memory with engine scratch space — ``.copy()`` if you
363
+ keep them past the next call. The other bulk getters (``get_pump_stats_bulk``
364
+ and every Phase 3 addition) return freshly allocated arrays, so the
365
+ result is yours to retain.
366
+
367
+ Whole-network reporting pattern (mirrors the Nodes example):
368
+
369
+ .. code-block:: python
304
370
 
305
- Same memory-aliasing rule as :class:`Nodes`: the returned array shares
306
- memory with engine scratch space; ``.copy()`` if you keep it past the
307
- next call.
371
+ ids = links.get_ids_bulk() # list[str]
372
+ flows = links.get_flows_bulk() # np.ndarray[float64]
373
+ velocities = links.get_velocities_bulk()
374
+ capacities = links.get_capacities_bulk()
375
+ powers = links.get_hyd_powers_bulk()
376
+ stats = links.get_pump_stats_bulk()
377
+ pumps = stats["cycles"] >= 0 # boolean mask
378
+
379
+ # Pump-energy summary in 3 lines:
380
+ pump_run_hours = float(stats["on_time"][pumps].sum() / 3600.0)
381
+ pump_ft_lb_s = float(powers[pumps].sum())
382
+ pump_hp = pump_ft_lb_s / 550.0
383
+ print(f"{pumps.sum()} pumps ran {pump_run_hours:.1f} h ~{pump_hp:.1f} hp avg")
308
384
 
309
385
  Vectorised peak detection across all links:
310
386
 
@@ -316,7 +316,7 @@ want vectorised. Each returns or accepts a contiguous
316
316
 
317
317
  .. list-table::
318
318
  :header-rows: 1
319
- :widths: 35 65
319
+ :widths: 40 60
320
320
 
321
321
  * - Method
322
322
  - Returns / accepts
@@ -327,13 +327,33 @@ want vectorised. Each returns or accepts a contiguous
327
327
  * - :meth:`set_depths_bulk(arr)`
328
328
  - Force depths for every node from ``arr``.
329
329
  * - :meth:`get_inflows_bulk`
330
- - Total inflow per node.
330
+ - **Lateral** inflow per node (see naming note below).
331
331
  * - :meth:`get_overflows_bulk`
332
332
  - Overflow (flooding) per node.
333
333
  * - :meth:`set_lat_inflows_bulk(arr)`
334
334
  - Lateral inflow per node.
335
335
  * - :meth:`get_quality_bulk(p)`
336
336
  - Concentration of pollutant ``p`` per node.
337
+ * - :meth:`get_volumes_bulk`
338
+ - Stored volume per node *(added 6.0.0)*.
339
+ * - :meth:`get_outflows_bulk`
340
+ - Total outflow per node *(added 6.0.0)*.
341
+ * - :meth:`get_losses_bulk`
342
+ - Per-node losses (evaporation + seepage) *(added 6.0.0)*.
343
+ * - :meth:`get_lateral_inflows_bulk`
344
+ - Lateral inflow per node — explicitly named successor to
345
+ :meth:`get_inflows_bulk` *(added 6.0.0)*.
346
+ * - :meth:`get_ids_bulk`
347
+ - ``list[str]`` of every node's id in one C call
348
+ *(added 6.0.0; stride-packed UTF-8)*.
349
+
350
+ .. note::
351
+
352
+ Naming caveat: :meth:`get_inflows_bulk` reads the *lateral* inflow
353
+ column on the C side despite its generic name; it is retained for
354
+ backward compatibility, but new code should prefer
355
+ :meth:`get_lateral_inflows_bulk`. Both methods return the same
356
+ values.
337
357
 
338
358
  Memory-aliasing rule: the array returned by a ``get_*_bulk`` method
339
359
  shares memory with an internal scratch buffer that the engine reuses
@@ -351,6 +371,35 @@ keep the array (e.g. across a step), call ``.copy()``:
351
371
  history.append(nodes.get_depths_bulk().copy()) # detach from scratch
352
372
  H = np.stack(history) # shape (T, n_nodes)
353
373
 
374
+ Whole-network reporting with the Phase 3 bulk accessors:
375
+
376
+ .. code-block:: python
377
+
378
+ # Single C call per quantity — replaces N round-trips through
379
+ # the scalar getters. Useful when building post-run summaries,
380
+ # MCP / GUI dataframes, or input to a downstream tool.
381
+ ids = nodes.get_ids_bulk() # list[str]
382
+ depths = nodes.get_depths_bulk() # np.ndarray[float64]
383
+ volumes = nodes.get_volumes_bulk()
384
+ outflows = nodes.get_outflows_bulk()
385
+ losses = nodes.get_losses_bulk()
386
+ lat = nodes.get_lateral_inflows_bulk()
387
+
388
+ # Build a single DataFrame-shaped dict in one shot:
389
+ summary = {
390
+ "id": ids,
391
+ "depth": depths,
392
+ "volume": volumes,
393
+ "outflow": outflows,
394
+ "losses": losses,
395
+ "lateral_inflow": lat,
396
+ }
397
+
398
+ # Find the most-flooded outfall, e.g.:
399
+ flooded = nodes.get_overflows_bulk()
400
+ worst = int(flooded.argmax())
401
+ print(f"max overflow at {ids[worst]}: {flooded[worst]:.3f}")
402
+
354
403
  ----
355
404
 
356
405
  EngineState requirements & exceptions
@@ -409,6 +409,69 @@ For the full list see :class:`~openswmm.engine.ErrorCode`.
409
409
 
410
410
  ----
411
411
 
412
+ Runoff interface file (Phase 1b)
413
+ ================================
414
+
415
+ Persists per-subcatchment runoff snapshots to a binary file matching
416
+ the legacy SWMM-5 ``Frunoff`` format. Useful when a slow-running
417
+ runoff phase needs to be cached and replayed against a downstream
418
+ routing-only run (e.g. design-storm sensitivity analyses).
419
+
420
+ .. list-table::
421
+ :header-rows: 1
422
+ :widths: 40 60
423
+
424
+ * - Method
425
+ - Description
426
+ * - :meth:`open_runoff_iface_write(path)`
427
+ - Open the file in SAVE mode. The engine then auto-emits one
428
+ record per runoff substep until :meth:`close_runoff_iface`
429
+ is called.
430
+ * - :meth:`open_runoff_iface_read(path)`
431
+ - Open the file in USE mode. Currently exposes the file but
432
+ does **not** yet skip the engine's runoff computation —
433
+ see the note below.
434
+ * - :meth:`save_runoff_step(dt)`
435
+ - Manually force one snapshot. Normally unnecessary because the
436
+ engine auto-saves; provided for plugin authors and tests.
437
+ * - :meth:`read_runoff_step()`
438
+ - Read one record from the open USE file into the current
439
+ subcatchment runoff/quality vectors. Returns ``False`` on EOF.
440
+ * - :meth:`close_runoff_iface()`
441
+ - Close the file (idempotent). Called automatically when the
442
+ solver is closed.
443
+
444
+ .. note::
445
+
446
+ USE-mode auto-skip — making the engine bypass its own runoff
447
+ computation when a USE file is open — is a follow-up to Phase 1b.
448
+ Today's USE mode is an advanced manual feature: callers must invoke
449
+ :meth:`read_runoff_step` between :meth:`Solver.step` calls *and*
450
+ understand that the engine will overwrite the loaded state when it
451
+ runs its own runoff phase.
452
+
453
+ End-to-end SAVE example:
454
+
455
+ .. code-block:: python
456
+
457
+ from openswmm.engine import EngineState, Solver
458
+
459
+ with Solver("design_storm.inp", "design_storm.rpt", "design_storm.out") as s:
460
+ s.open()
461
+ s.initialize()
462
+ s.start()
463
+ s.open_runoff_iface_write("design_storm.rfi")
464
+ while s.state == EngineState.RUNNING:
465
+ if s.step() != 0:
466
+ break
467
+ s.end()
468
+ s.close_runoff_iface()
469
+ # design_storm.rfi now contains one record per runoff substep and
470
+ # can be reopened by a downstream routing-only run via
471
+ # ``s.open_runoff_iface_read(...)``.
472
+
473
+ ----
474
+
412
475
  See also
413
476
  ========
414
477
 
@@ -99,6 +99,10 @@ Per-subcatchment
99
99
  Bulk variants
100
100
  -------------
101
101
 
102
+ Each bulk method makes a single C call and returns a contiguous
103
+ ``np.ndarray[float64]``. The GIL is released for the duration of the
104
+ C call.
105
+
102
106
  .. list-table::
103
107
  :header-rows: 1
104
108
  :widths: 50 50
@@ -111,9 +115,46 @@ Bulk variants
111
115
  - All-link peak flows.
112
116
  * - :meth:`subcatch_runoff_vol_bulk()`
113
117
  - All-subcatchment runoff volumes.
118
+ * - :meth:`node_max_overflow_bulk()`
119
+ - All-node peak overflow rate *(added 6.0.0)*.
120
+ * - :meth:`node_vol_flooded_bulk()`
121
+ - All-node total flooded volume *(added 6.0.0)*.
122
+ * - :meth:`node_time_flooded_bulk()`
123
+ - All-node cumulative time-flooded *(added 6.0.0)*.
124
+ * - :meth:`subcatch_max_runoff_bulk()`
125
+ - All-subcatchment peak runoff *(added 6.0.0)*.
126
+ * - :meth:`link_max_velocity_bulk()`
127
+ - All-link peak velocity *(added 6.0.0)*.
128
+ * - :meth:`link_max_filling_bulk()`
129
+ - All-link peak depth/full-depth ratio *(added 6.0.0)*.
130
+ * - :meth:`link_vol_flow_bulk()`
131
+ - All-link cumulative flow volume *(added 6.0.0)*.
132
+ * - :meth:`link_surcharge_time_bulk()`
133
+ - All-link cumulative surcharge time *(added 6.0.0)*.
134
+
135
+ Whole-network flooding summary in 4 C calls (replaces a ``4 * n_nodes``
136
+ Python loop):
137
+
138
+ .. code-block:: python
139
+
140
+ from openswmm.engine import Nodes, Statistics
141
+
142
+ stats = Statistics(solver)
143
+ nodes = Nodes(solver)
144
+
145
+ ids = nodes.get_ids_bulk()
146
+ max_over = stats.node_max_overflow_bulk()
147
+ vol_flood = stats.node_vol_flooded_bulk()
148
+ t_flood = stats.node_time_flooded_bulk()
149
+
150
+ # Worst-flooded node by cumulative volume:
151
+ worst = int(vol_flood.argmax())
152
+ print(f"{ids[worst]}: vol={vol_flood[worst]:.1f}, "
153
+ f"peak overflow={max_over[worst]:.3f}, hours={t_flood[worst]:.2f}")
114
154
 
115
155
  The standard memory-aliasing rule applies — ``.copy()`` if you need
116
- to keep the array.
156
+ to keep the array (the four pre-6.0 bulk getters share scratch
157
+ buffers; the 6.0 additions return freshly allocated arrays).
117
158
 
118
159
  ----
119
160
 
@@ -214,7 +255,9 @@ Compute surcharge fraction across the network
214
255
  Bulk arrays
215
256
  ===========
216
257
 
217
- The ``*_bulk`` family is the vectorised path:
258
+ The ``*_bulk`` family is the vectorised path. Each call returns a
259
+ contiguous ``np.ndarray[float64]`` of the indicated shape. GIL is
260
+ released during the underlying C call.
218
261
 
219
262
  .. list-table::
220
263
  :header-rows: 1
@@ -228,10 +271,27 @@ The ``*_bulk`` family is the vectorised path:
228
271
  - ``(n_links,)``
229
272
  * - :meth:`subcatch_runoff_vol_bulk`
230
273
  - ``(n_subcatch,)``
231
-
232
- Same memory-aliasing semantics as the bulk methods on :class:`Nodes`
233
- and :class:`Links` — ``.copy()`` if you keep the array past the next
234
- call.
274
+ * - :meth:`node_max_overflow_bulk`
275
+ - ``(n_nodes,)`` *(added 6.0.0)*
276
+ * - :meth:`node_vol_flooded_bulk`
277
+ - ``(n_nodes,)`` *(added 6.0.0)*
278
+ * - :meth:`node_time_flooded_bulk`
279
+ - ``(n_nodes,)`` *(added 6.0.0)*
280
+ * - :meth:`subcatch_max_runoff_bulk`
281
+ - ``(n_subcatch,)`` *(added 6.0.0)*
282
+ * - :meth:`link_max_velocity_bulk`
283
+ - ``(n_links,)`` *(added 6.0.0)*
284
+ * - :meth:`link_max_filling_bulk`
285
+ - ``(n_links,)`` *(added 6.0.0)*
286
+ * - :meth:`link_vol_flow_bulk`
287
+ - ``(n_links,)`` *(added 6.0.0)*
288
+ * - :meth:`link_surcharge_time_bulk`
289
+ - ``(n_links,)`` *(added 6.0.0)*
290
+
291
+ Memory-aliasing rule: the three pre-6.0 bulk methods share scratch
292
+ buffers with engine state — ``.copy()`` if you need to retain them
293
+ past the next call. The 6.0 additions return freshly allocated
294
+ arrays.
235
295
 
236
296
  ----
237
297
 
@@ -297,24 +297,57 @@ Per-subcatchment runoff coefficient (post-run summary)
297
297
  Bulk arrays
298
298
  ===========
299
299
 
300
- The :class:`Subcatchments` class does not (yet) expose bulk-array
301
- accessors. Vectorise across the population manually:
300
+ Each bulk method makes a single C call and returns a contiguous
301
+ ``np.ndarray[float64]`` of shape ``(n_subcatchments,)`` (or a
302
+ ``list[str]`` for ids). The GIL is released for the duration of the C
303
+ call, so multi-threaded consumers can read from independent solvers
304
+ in parallel.
302
305
 
303
- .. code-block:: python
306
+ .. list-table::
307
+ :header-rows: 1
308
+ :widths: 40 60
304
309
 
305
- import numpy as np
310
+ * - Method
311
+ - Returns / accepts
312
+ * - :meth:`get_runoff_bulk`
313
+ - Runoff rate per subcatchment (project flow units).
314
+ * - :meth:`get_quality_bulk(p)`
315
+ - Concentration of pollutant ``p`` per subcatchment.
316
+ * - :meth:`get_rainfall_bulk`
317
+ - Rainfall rate per subcatchment *(added 6.0.0)*.
318
+ * - :meth:`get_evap_bulk`
319
+ - Evaporation loss per subcatchment *(added 6.0.0)*.
320
+ * - :meth:`get_infil_bulk`
321
+ - Infiltration loss per subcatchment *(added 6.0.0)*.
322
+ * - :meth:`get_snow_depth_bulk`
323
+ - Snow depth per subcatchment *(added 6.0.0; placeholder zeros
324
+ pending full snow-state integration)*.
325
+ * - :meth:`get_ids_bulk`
326
+ - ``list[str]`` of every subcatchment's id in one C call
327
+ *(added 6.0.0; stride-packed UTF-8)*.
328
+
329
+ Whole-network water-balance pattern using the Phase 3 accessors:
306
330
 
307
- runoff = np.zeros(sc.count())
308
- while s.state == EngineState.RUNNING:
309
- if s.step() != 0:
310
- break
311
- for i in range(sc.count()):
312
- runoff[i] += sc.get_runoff(i)
331
+ .. code-block:: python
313
332
 
314
- If you need a strictly faster path, fall back to the
315
- :class:`OutputReader` after the run and use the bulk subcatchment
316
- methods (:doc:`output_reader`) — that's typically fastest for
317
- post-processing.
333
+ ids = sc.get_ids_bulk()
334
+ rain = sc.get_rainfall_bulk()
335
+ infil = sc.get_infil_bulk()
336
+ evap = sc.get_evap_bulk()
337
+ runoff = sc.get_runoff_bulk()
338
+
339
+ # Per-subcatch instantaneous residual (storage / snow can make this
340
+ # noisy step-by-step but it should integrate near zero over a long
341
+ # simulation if the model is well-balanced).
342
+ residual = rain - infil - evap - runoff
343
+ for i, name in enumerate(ids):
344
+ print(f" {name:<12} R={rain[i]:.3f} I={infil[i]:.3f} "
345
+ f"E={evap[i]:.3f} Q={runoff[i]:.3f} resid={residual[i]:+.3f}")
346
+
347
+ For *cumulative* (post-run) statistics, prefer the bulk accessors on
348
+ :class:`Statistics` (``subcatch_runoff_vol_bulk`` etc.) or the
349
+ :class:`OutputReader` — those are denser and pull from the report
350
+ file rather than recomputing from the live state.
318
351
 
319
352
  ----
320
353
 
@@ -13,7 +13,8 @@ cdef extern from "openswmm_2d.h":
13
13
  int swmm_2d_vertex_get_xyz(void* engine, int idx,
14
14
  double* x, double* y, double* z)
15
15
  int swmm_2d_vertex_get_xyz_bulk(void* engine,
16
- double* x, double* y, double* z)
16
+ double* x, double* y, double* z) nogil
17
+ int swmm_2d_set_vertex_z(void* engine, int idx, double z)
17
18
  int swmm_2d_triangle_get_vertices(void* engine, int idx,
18
19
  int* v0, int* v1, int* v2)
19
20
  int swmm_2d_triangle_get_area(void* engine, int idx, double* area)
@@ -23,7 +24,7 @@ cdef extern from "openswmm_2d.h":
23
24
  int swmm_2d_triangle_get_neighbours(void* engine, int idx,
24
25
  int* n0, int* n1, int* n2)
25
26
  int swmm_2d_edge_get_geometry_bulk(void* engine,
26
- double* length, double* nx, double* ny)
27
+ double* length, double* nx, double* ny) nogil
27
28
 
28
29
  # Coupling
29
30
  int swmm_2d_vertex_coupling_count(void* engine, int* count)
@@ -37,14 +38,14 @@ cdef extern from "openswmm_2d.h":
37
38
  int swmm_2d_get_coupling_flux(void* engine, int idx, double* flux)
38
39
  int swmm_2d_get_rainfall(void* engine, int idx, double* rainfall)
39
40
  int swmm_2d_get_net_source(void* engine, int idx, double* net_source)
40
- int swmm_2d_get_depths_bulk(void* engine, double* depths)
41
- int swmm_2d_get_heads_bulk(void* engine, double* heads)
42
- int swmm_2d_get_coupling_fluxes_bulk(void* engine, double* fluxes)
43
- int swmm_2d_get_edge_flux_bulk(void* engine, double* flux)
41
+ int swmm_2d_get_depths_bulk(void* engine, double* depths) nogil
42
+ int swmm_2d_get_heads_bulk(void* engine, double* heads) nogil
43
+ int swmm_2d_get_coupling_fluxes_bulk(void* engine, double* fluxes) nogil
44
+ int swmm_2d_get_edge_flux_bulk(void* engine, double* flux) nogil
44
45
 
45
46
  # State — per vertex
46
47
  int swmm_2d_vertex_get_head(void* engine, int idx, double* head)
47
- int swmm_2d_vertex_get_heads_bulk(void* engine, double* heads)
48
+ int swmm_2d_vertex_get_heads_bulk(void* engine, double* heads) nogil
48
49
 
49
50
  # Statistics
50
51
  int swmm_2d_get_max_depth(void* engine, double* max_depth)
@@ -92,7 +92,8 @@ class Surface2D:
92
92
  npt.NDArray[np.float64],
93
93
  npt.NDArray[np.float64],
94
94
  ]:
95
- """Return (x, y, z) NumPy arrays for all vertices.
95
+ """Return (x, y, z) NumPy arrays for all vertices. GIL is released
96
+ during the C call.
96
97
 
97
98
  @return: Tuple C{(x, y, z)}, each of shape C{(n_vertices,)} with
98
99
  dtype C{float64}.
@@ -101,6 +102,23 @@ class Surface2D:
101
102
  """
102
103
  ...
103
104
 
105
+ def set_vertex_z(self, idx: int, z: float) -> None:
106
+ """Set the ground elevation of a mesh vertex.
107
+
108
+ Updates derived geometry for every triangle incident to this
109
+ vertex (centroid Z, per-edge midpoint Z). XY-derived fields are
110
+ unaffected. When called during a running simulation, solver
111
+ state (head, depth) is intentionally not rewritten — the implied
112
+ depth = head - bed therefore changes by the same amount as bed.
113
+
114
+ @param idx: Vertex index (0-based).
115
+ @type idx: int
116
+ @param z: New ground elevation (project vertical units).
117
+ @type z: float
118
+ @raise RuntimeError: If the C API call fails.
119
+ """
120
+ ...
121
+
104
122
  def get_triangle_vertices(self, idx: int) -> tuple[int, int, int]:
105
123
  """Return the (v0, v1, v2) vertex indices for a triangle.
106
124
 
@@ -205,10 +223,13 @@ class Surface2D:
205
223
 
206
224
  # ====================================================================
207
225
  # State (depth/velocity) - per triangle bulk arrays
226
+ #
227
+ # Every bulk getter in this section releases the GIL for the C call.
208
228
  # ====================================================================
209
229
 
210
230
  def get_depths(self) -> npt.NDArray[np.float64]:
211
- """Return depths for all triangles as a NumPy array.
231
+ """Return depths for all triangles as a NumPy array. GIL is
232
+ released during the C call.
212
233
 
213
234
  @return: Array of shape C{(n_triangles,)} with dtype C{float64}.
214
235
  @rtype: np.ndarray
@@ -217,7 +238,8 @@ class Surface2D:
217
238
  ...
218
239
 
219
240
  def get_heads(self) -> npt.NDArray[np.float64]:
220
- """Return total heads for all triangles as a NumPy array.
241
+ """Return total heads for all triangles as a NumPy array. GIL is
242
+ released during the C call.
221
243
 
222
244
  @return: Array of shape C{(n_triangles,)} with dtype C{float64}.
223
245
  @rtype: np.ndarray
@@ -226,7 +248,8 @@ class Surface2D:
226
248
  ...
227
249
 
228
250
  def get_coupling_fluxes(self) -> npt.NDArray[np.float64]:
229
- """Return coupling fluxes for all triangles as a NumPy array.
251
+ """Return coupling fluxes for all triangles as a NumPy array. GIL
252
+ is released during the C call.
230
253
 
231
254
  @return: Array of shape C{(n_triangles,)} with dtype C{float64}.
232
255
  Positive values denote flux into the 2D surface.
@@ -236,7 +259,8 @@ class Surface2D:
236
259
  ...
237
260
 
238
261
  def get_edge_flux_bulk(self) -> npt.NDArray[np.float64]:
239
- """Return normal edge fluxes for all triangle edges.
262
+ """Return normal edge fluxes for all triangle edges. GIL is
263
+ released during the C call.
240
264
 
241
265
  Indexed as C{[tri*3 + localEdge]}.
242
266
  @return: Array of shape C{(n_triangles*3,)} with dtype C{float64}.
@@ -245,6 +269,7 @@ class Surface2D:
245
269
 
246
270
  def get_edge_geometry_bulk(self) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64], npt.NDArray[np.float64]]:
247
271
  """Return time-invariant edge lengths and outward unit normal components.
272
+ GIL is released during the C call.
248
273
 
249
274
  Returns C{(length, nx, ny)}, each indexed as C{[tri*3 + localEdge]}.
250
275
 
@@ -317,6 +342,7 @@ class Surface2D:
317
342
 
318
343
  def get_vertex_heads(self) -> npt.NDArray[np.float64]:
319
344
  """Return reconstructed heads at all vertices as a NumPy array.
345
+ GIL is released during the C call.
320
346
 
321
347
  @return: Array of shape C{(n_vertices,)} with dtype C{float64}.
322
348
  @rtype: np.ndarray