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.

No comments:

A comprehensive explanation of how minimum travel distance relates to link length in InfoSewer

In hydraulic modeling of sewer networks, the minimum travel distance is a fundamental parameter that affects how accurately the model can si...