pipedream

🚰 Interactive hydrodynamic solver for pipe and channel networks

View the Project on GitHub mdbartos/pipedream

Overview

    â€¢ Governing equations
    â€¢ Model structure

Examples

    â€¢ Flow on hillslope
    â€¢ Simulation context manager
    â€¢ Contaminant transport on hillslope
    â€¢ Uncoupled overland flow
    â€¢ Coupled overland flow
    â€¢ Simple dynamic control example
    â€¢ Adaptive step size control
    â€¢ Validation with real-world network
    â€¢ Kalman filtering with holdout analysis

Reference

    â€¢ Hydraulic solver API reference
    â€¢ Infiltration solver API reference
    â€¢ Water quality solver API reference
    â€¢ Model inputs
    â€¢ Hydraulic geometry reference

The simulation context manager

This tutorial shows how to use the simulation context manager to handle model forcing data and record simulation outputs.

Import modules

import numpy as np
import pandas as pd
from pipedream_solver.hydraulics import SuperLink
from pipedream_solver.simulation import Simulation

import matplotlib.pyplot as plt
import seaborn as sns

Load model data

input_path = '../data/hillslope'
superjunctions = pd.read_csv(f'{input_path}/hillslope_superjunctions.csv')
superlinks = pd.read_csv(f'{input_path}/hillslope_superlinks.csv')

Instantiate model

dt = 10
internal_links = 24

model = SuperLink(superlinks, superjunctions, 
                  internal_links=internal_links)

Create tables of input data

Q_in = pd.DataFrame.from_dict(
    {
        0 :  np.zeros(model.M),
        3600: np.zeros(model.M),
        3601: 1e-3 * np.ones(model.M),
        18000 : 1e-3 * np.ones(model.M),
        18001 : np.zeros(model.M),
        28000 : np.zeros(model.M)
    }, orient='index')

Q_Ik = pd.DataFrame.from_dict(
    {
        0 :  np.zeros(model.NIk),
        3600: np.zeros(model.NIk),
        3601: 1e-3 * np.ones(model.NIk),
        18000 : 1e-3 * np.ones(model.NIk),
        18001 : np.zeros(model.NIk),
        28000 : np.zeros(model.NIk)
    }, orient='index'
)

Inspecting the table of superjunction inflows:

Q_in
0 1
0 0.000 0.000
3600 0.000 0.000
3601 0.001 0.001
18000 0.001 0.001
18001 0.000 0.000
28000 0.000 0.000

We can visualize the inflows to the system as well:

fig, ax = plt.subplots(2)

Q_in.sum(axis=1).plot(ax=ax[0], title='Superjunction inflow', c='k')
Q_Ik.sum(axis=1).plot(ax=ax[1], title='Internal junction inflow', c='k')
ax[0].set_ylabel('Inflow (cms)')
ax[1].set_ylabel('Inflow (cms)')
ax[1].set_xlabel('Time (s)')
plt.tight_layout()

png

Run simulation using context manager

The simulation context manager provides a convenient tool for running simulations. It provides a systematic way to:

In this case, we will use the simulation context manager to read and parse our flow input tables, print the simulation progress, and record the internal depths and flows in the system.

# Create simulation context manager
with Simulation(model, Q_in=Q_in, Q_Ik=Q_Ik) as simulation:
    # While simulation time has not expired...
    while simulation.t <= simulation.t_end:
        # Step model forward in time
        simulation.step(dt=dt)
        # Record internal depth and flow states
        simulation.record_state()
        # Print progress bar
        simulation.print_progress()
[==================================================] 100.0% [2.37 s]

We can see the end state of the system by plotting the model profile.

sns.set_palette('cool')
_ = model.plot_profile([0, 1], width=100)

png

Visualize simulation results

The simulation context manager makes it easy to access and visualize model outputs. We can access any outputs recorded by simulation.record_state by accessing the simulation.states attribute. By default, simulation.states contains the following states:

Plot hydraulic head at superjunctions

The hydraulic heads at each superjunction can be plotted by accessing the simulation.states.H_j dataframe. Note that superjunction 0 corresponds to the uphill superjunction, and superjunction 1 corresponds to the downhill superjunction.

sns.set_palette('husl', 2)
simulation.states.H_j.plot()

plt.title('Hydraulic head at superjunctions')
plt.xlabel('Time (s)')
plt.ylabel('Head (m)')

png

The flows in each internal link can be plotted by accessing the simulation.states.Q_ik dataframe. Note that the colormap goes from red (uphill) to violet (downhill).

sns.set_palette('husl', internal_links)
simulation.states.Q_ik.plot(legend=False)

plt.title('Flow in internal links')
plt.xlabel('Time (s)')
plt.ylabel('Flow (cms)')

png

Plot water depth at internal junctions

The water depth in each internal junction can be plotted by accessing the simulation.states.h_Ik dataframe.

sns.set_palette('husl', internal_links + 1)
simulation.states.h_Ik.plot(legend=False)

plt.title('Depth in internal junctions')
plt.xlabel('Time (s)')
plt.ylabel('Depth (m)')

png