Showing posts with label PYSWMM simulation.py Summary. Show all posts
Showing posts with label PYSWMM simulation.py Summary. Show all posts

Monday, December 30, 2024

PYSWMM simulation.py Summary

 Below is an extended summary of the code, highlighting its purpose, key components, and how it fits into a broader PySWMM workflow.


Overview

This module expands upon PySWMM’s functionality by introducing higher-level classes to manage SWMM (Storm Water Management Model) simulations. Specifically, it provides a new Simulation class (and a complementary SimulationPreConfig class) that streamline how users can configure, run, and interact with SWMM simulations in Python. It also includes safety mechanisms and convenience features like callback registration and multi-simulation guards.

The primary class—Simulation—is designed to handle everything from opening a SWMM model and iterating through time steps, to finalizing and closing the model. Additionally, the module addresses real-time simulation control, hotstart file usage, and advanced model editing capabilities via a SimulationPreConfig class.


Core Classes

1. _SimulationStateManager

  • Purpose: Maintains a global state to ensure only one SWMM simulation instance is active at a time in a given Python process.
  • Why: USEPA-SWMM isn’t thread-safe or reentrant, so multiple concurrent SWMM instances can cause crashes or data corruption.
  • Usage: When a Simulation is instantiated, _SimulationStateManager is used to guard against a second simulation being opened concurrently.

2. Simulation

Purpose

  • Wraps the lower-level PySWMM class to provide a more intuitive, Pythonic interface for setting up, running, and finalizing a SWMM simulation.
  • Supports context-manager usage (with Simulation(...) as sim:) to automatically handle opening and closing.

Key Attributes

  • _model: An instance of PySWMM that manages the actual SWMM engine calls (opening files, stepping through time, closing).
  • _is_open: Indicates if the SWMM model is currently open.
  • _is_started: Tracks whether the simulation has started stepping through time.
  • _advance_seconds: If set, the simulation will “stride” in user-defined increments rather than at every SWMM routing step.
  • _terminate_request: A flag to gracefully stop the simulation loop when conditions are met (e.g., flooding threshold).
  • _callbacks: A dictionary of callbacks (function hooks) that can be invoked at various simulation events (e.g., before start, after step, after close).

Core Methods

  1. __init__

    • Manages opening the input file via PySWMM and ensures single-instance constraints via _SimulationStateManager.
    • Optionally uses a SimulationPreConfig object (if provided) to apply dynamic changes to the SWMM input file.
  2. Context Management:

    • __enter__: Enters the context, disabling a warning about context usage.
    • __exit__: Completes the simulation if it hasn’t ended, closes the SWMM file, and triggers “after_close” callbacks.
  3. Iteration:

    • __iter__ and __next__:
      • Allows Python’s for step in sim: pattern.
      • Calls swmm_step or swmm_stride until the simulation ends or a termination is requested.
      • Handles pre-step and post-step callbacks.
  4. Simulation Lifecycle:

    • start(): Officially starts the simulation in manual stepping mode, calling any “before_start”/“after_start” callbacks.
    • execute(): Runs the simulation in a single call (no stepping iteration). This is a simpler approach but prevents interactive changes mid-run.
  5. Callbacks:

    • Provides methods like add_before_start, add_after_start, add_before_step, add_after_step, add_before_end, add_after_end, and add_after_close.
    • Each accepts a callable that’s triggered at that point in the simulation lifecycle.
  6. Hotstart File Support:

    • use_hotstart(file): Load a hotstart file at the beginning of the simulation.
    • save_hotstart(file): Save the current state mid-run for later usage or branching scenarios.
  7. Runoff/Routing/Quality Error Tracking:

    • Properties like runoff_error, flow_routing_error, quality_error return mass balance error percentages at the end of a run.
  8. Time Controls:

    • Properties like start_time, end_time, and report_start allow dynamic read/write of the SWMM simulation’s time boundaries.
    • current_time returns the current simulation time at each iteration.
    • percent_complete estimates progress by comparing current_time to start_time and end_time.
  9. Other Features:

    • terminate_simulation(): Gracefully requests a simulation stop.
    • report(): Writes final report file data.

3. SimulationPreConfig

Purpose

  • Allows a user to programmatically modify a SWMM input file prior to running the simulation.
  • Useful for batch processing, scenario testing, or automated parameter calibration.
  • Can handle changes like subcatchment property adjustments, timeseries data updates, or other [SECTION] manipulations.

Workflow:

  1. Add Updates:
    • add_update_by_token(section, obj_id, index, new_val, row_num=0)
      • Defines a single change to apply to the input file at a specific row and column (parameter index).
      • Example: Changing a subcatchment’s outlet from “J1” to “J2.”
  2. Apply Changes:
    • apply_changes() reads the original .inp file, edits the specified lines, and writes out a new .inp with a customizable suffix.
    • The resulting file is used by the Simulation object if passed to sim_preconfig.

Typical Usage Patterns

A. Simple Simulation with Context Manager

from pyswmm import Simulation

with Simulation('model.inp') as sim:
    for step in sim:
        # Access real-time data or adjust parameters
        pass

B. Manual Execution

sim = Simulation('model.inp')
sim.execute()  # Runs start -> simulation -> end -> close

C. Using Callbacks

def print_time():
    print("Current time:", sim.current_time)

with Simulation('model.inp') as sim:
    sim.add_before_step(print_time)
    for step in sim:
        pass

D. Applying Pre-Run Modifications

from pyswmm import Simulation, SimulationPreConfig

preconf = SimulationPreConfig()
preconf.add_update_by_token("SUBCATCHMENTS", "S1", 2, "J2")  # E.g., change the outlet

with Simulation('model.inp', sim_preconfig=preconf) as sim:
    for step in sim:
        # The sim runs with a newly saved "model_mod.inp"
        pass

Key Benefits

  1. Thread-Safety and Single-Instance Guard:

    • _SimulationStateManager ensures that even novice users don’t inadvertently run multiple SWMM instances simultaneously.
  2. Callbacks:

    • Flexible insertion points for user-defined functions at each major lifecycle stage (before/after start, each step, end, close).
  3. Hotstart Integration:

    • Simplifies saving/loading intermediate states for subsequent runs or scenario branching.
  4. Programmatic Pre-Configuration:

    • SimulationPreConfig eliminates manual editing of .inp files, enabling rapid scenario testing or parameter updates.
  5. Seamless Scripting:

    • The context-manager approach (with Simulation(...) as sim:) handles cleanup automatically, preventing accidental resource leaks and ensuring complete finalization.

Conclusion

Overall, this module substantially enhances the user experience for running SWMM simulations in Python. It offers:

  • Robust lifecycle management (open, iterate, close).
  • Convenient callback hooks for real-time control or logging.
  • Safeguards against common misuse (like multiple simulations at once).
  • Dynamic model editing (SimulationPreConfig) for advanced scenario setups.

Thus, it provides a powerful foundation for developing interactive, automation-friendly SWMM workflows in Python, from simple one-shot runs to complex real-time control and calibration tasks.

Banach-Tarski paradox and SWMM5 modeling.

Banach-Tarski paradox and SWMM5 modeling.  Let's elaborate on how the principles underlying Banach-Tarski could inspire practical hydrau...