Simulation results

Simulation results are stored in a SimulationResults object which contains:

  • Timestamp when the results were created
  • Network name
  • Node results
  • Link results

The node and link results are dictionaries of Pandas DataFrames. Each dictionary is a key:value pair, where the key is a result attribute (e.g. node demand, link flowrate) and the value is a DataFrame. DataFrames are indexed by time step (in seconds from the start of the simulation) with columns that are labelled using node or link names. The use of Pandas facilitates a comprehensive set of time series analysis options that can be used to evaluate results. For more information on Pandas, see http://pandas.pydata.org/.

Conceptually, DataFrames can be visualized as blocks of data with 2 axis, as shown in Figure 8.

Pandas DataFrames

Figure 8 Conceptual representation of DataFrames used to store simulation results.

Node results include DataFrames for each of the following attributes:

  • Demand
  • Leak demand (only when the WNTRSimulator is used)
  • Head
  • Pressure
  • Quality (only when the EpanetSimulator is used. Water age, tracer percent, or chemical concentration is stored, depending on the mode of water quality mode)

For example, node results generated with the EpanetSimulator have the following keys:

>>> node_keys = results.node.keys()
>>> print(node_keys)
['demand', 'head', 'pressure', 'quality']

Link results include DataFrames for each of the following attributes:

  • Velocity
  • Flowrate
  • Status (0 indicates closed, 1 indicates open)
  • Headloss (only when the EpanetSimulator is used)
  • Setting (only when the EpanetSimulator is used)
  • Friction factor (only when the EpanetSimulator is used)
  • Reaction rate (only when the EpanetSimulator is used)
  • Link quality (only when the EpanetSimulator is used)

For example, link results generated with the EpanetSimulator have the following keys:

>>> link_keys = results.link.keys()
>>> print(link_keys)
['flowrate', 'frictionfact', 'headloss', 'linkquality', 'rxnrate', 'setting', 'status', 'velocity']

To access node pressure over all nodes and times:

>>> pressure = results.node['pressure']

DataFrames can be sliced to extract specific information. For example, to access the pressure at node ‘123’ over all times (the “”:”” notation returns all variables along the specified axis, “head” returns the first 5 rows, values displayed to 2 decimal places):

>>> pressure_at_node123 = pressure.loc[:,'123']
>>> print(pressure_at_node123.head())
0       47.08
900     47.13
1800    47.18
2700    47.23
3600    47.94
Name: 123, dtype: float32

To access the pressure at time 3600 over all nodes (values displayed to 2 decimal places):

>>> pressure_at_1hr = pressure.loc[3600,:]
>>> print(pressure_at_1hr.head())
name
10    28.25
15    28.89
20     9.10
35    41.52
40     4.18
Name: 3600, dtype: float32

Data can be plotted as a time-series, as shown in Figure 9:

>>> pressure_at_node123.plot() 
Time-series graph.

Figure 9 Example time-series graphic.

Data can also be plotted on the water network model, as shown in Figure 10. In this figure, the node pressure at 1 hr is plotted on the network. Link attributes can be plotted in a similar manner.

>>> wntr.graphics.plot_network(wn, node_attribute=pressure_at_1hr, node_range=[30,55]) 
Network graphic

Figure 10 Example network graphic.

Network and time-series graphics can be customized to add titles, legends, axis labels, subplots, etc.

Pandas includes methods to write DataFrames to CSV, HDF, JSON, and SQL. For example, DataFrames can be saved to Excel files using:

>>> pressure.to_excel('pressure.xlsx')