This tutorial demonstrates how quasi-stationary time series analysis can be done with pandapipes. In the following, an already existing net is loaded from a json file. The prerequisites for a successful execution of a time series simulation are:
In this example, the following pandapipes network is loaded:
The following modules are imported first
import os
import pandas as pd
import pandapower.control as control
from pandapower.timeseries import DFData
from pandapower.timeseries import OutputWriter
from pandapipes.timeseries import run_timeseries
Not that the time series functionality is provided by the pandapower module. But because the structure of pandapipes is similar to the one of pandapower, we can use the same functions here.
With the following import statement, stored networks can be loaded.
from pandapipes import networks
The loading procedure is started with this function call:
net = networks.simple_gas_networks.gas_meshed_delta()
This is the delta STANET network from the chapter Meshed Networks with the medium gas.
In this example, time series data for the sink and source components is added. For every provided data point, an own pandapipes calculation will be executed. This is of course done automatically. Thus, the number of time steps in this case is 10. Since there is only one sink and one source, the respective csv file only consists of one column.
With the code
profiles_sink = pd.read_csv(os.path.join('files',
'simple_time_series_example_sink_profiles.csv'),
index_col=0)
profiles_source = pd.read_csv(os.path.join('files',
'simple_time_series_example_source_profiles.csv'),
index_col=0)
ds_sink = DFData(profiles_sink)
ds_source = DFData(profiles_source)
const_sink = control.ConstControl(net, element='sink', variable='mdot_kg_per_s',
element_index=net.sink.index.values, data_source=ds_sink,
profile_name=net.sink.index.values.astype(str))
const_source = control.ConstControl(net, element='source', variable='mdot_kg_per_s',
element_index=net.source.index.values,
data_source=ds_source,
profile_name=net.source.index.values.astype(str))
the corresponding csv-file is read out, prepared as data sources (ds) for the controllers and the resulting DataFrames are written into the network with the help of the controller ConstControl. Then the desired time steps for which the network is to be calculated must be specified. In the present case, these can be defined from 1 to 10 at most, since only 10 time steps are specified for the sink and source. Likewise, for example, a range of 3 to 6 can be specified. Here the time steps from 1 to 10 are defined with
time_steps = range(10)
Furthermore an OuputWriter must be created, which is defined as ow
using
log_variables = [('res_junction', 'p_bar'), ('res_pipe', 'v_mean_m_per_s'),
('res_pipe', 'reynolds'), ('res_pipe', 'lambda'),
('res_sink', 'mdot_kg_per_s'), ('res_source', 'mdot_kg_per_s'),
('res_ext_grid', 'mdot_kg_per_s')]
ow = OutputWriter(net, time_steps, output_path=None, log_variables=log_variables)
In the output writer the results of the simulation are stored. Finally, the main function can be called to run the time series simulation:
run_timeseries(net, time_steps)
Progress: |██████████████████████████████████████████████████| 100.0% Complete
The results of the simulation can be accessed via the OutputWriter as follows:
print("pressure:")
print(ow.np_results["res_junction.p_bar"])
print("mean velocity:")
print(ow.np_results["res_pipe.v_mean_m_per_s"])
print("reynolds number:")
print(ow.np_results["res_pipe.reynolds"])
print("lambda:")
print(ow.np_results["res_pipe.lambda"])
print("mass flow sink:")
print(ow.np_results["res_sink.mdot_kg_per_s"])
print("mass flow source:")
print(ow.np_results["res_source.mdot_kg_per_s"])
print("mass flow ext. grid:")
print(ow.np_results["res_ext_grid.mdot_kg_per_s"])
pressure: [[3.49975257 3.5 3.49961173] [3.49973649 3.5 3.49949785] [3.49972162 3.5 3.49936071] [3.49970758 3.5 3.49920016] [3.49969414 3.5 3.4990161 ] [3.49968112 3.5 3.49880846] [3.49966839 3.5 3.49857714] [3.49965585 3.5 3.4983221 ] [3.49964345 3.5 3.49804329] [3.49963112 3.5 3.49774068]] mean velocity: [[-0.57651001 -0.49611582 -0.21696278] [-0.76534799 -0.51363216 -0.25383547] [-0.95276066 -0.5293793 -0.2932576 ] [-1.13916058 -0.54386481 -0.33449866] [-1.32480882 -0.55740925 -0.37709744] [-1.5099034 -0.57025531 -0.42070489] [-1.69457795 -0.58256615 -0.46508642] [-1.87893324 -0.59446437 -0.51006588] [-2.06302946 -0.60602249 -0.55553927] [-2.24692628 -0.61731235 -0.60140351]] reynolds number: [[17616.51199081 13644.68760488 4971.54745982] [23386.16464632 14126.19817054 5816.74628673] [29112.07624708 14559.10756425 6720.26651999] [34807.4075172 14958.03881282 7664.56052742] [40478.68817099 15330.24715434 8640.92202331] [46132.73805781 15683.31019923 9640.25787515] [51773.58389153 16021.70207401 10657.19913113] [57404.8788946 16349.48191474 11686.87482796] [63026.79298166 16666.83851545 12729.05841282] [68641.89412809 16976.62518213 13780.32591852]] lambda: [[0.02324864 0.02481883 0.03393751] [0.02235235 0.02465895 0.03206697] [0.02181409 0.02452424 0.03058769] [0.02145438 0.024407 0.02941438] [0.02119677 0.02430312 0.02847087] [0.02100299 0.02420913 0.02770308] [0.02085184 0.02412294 0.02706959] [0.02073058 0.02404286 0.02654048] [0.02063113 0.02396832 0.02609212] [0.02054806 0.02389825 0.02570856]] mass flow sink: [[0.02 ] [0.026] [0.032] [0.038] [0.044] [0.05 ] [0.056] [0.062] [0.068] [0.074]] mass flow source: [[0.005] [0.01 ] [0.015] [0.02 ] [0.025] [0.03 ] [0.035] [0.04 ] [0.045] [0.05 ]] mass flow ext. grid: [[-0.015] [-0.016] [-0.017] [-0.018] [-0.019] [-0.02 ] [-0.021] [-0.022] [-0.023] [-0.024]]
To view the results more clearly, they can be displayed with matplotlib.pyplot
in a diagram with the time steps as x-axis.The time curve for the mass flow in the External Grid looks as follows:
The figure can be created by the following lines:
import matplotlib.pyplot as plt
x = time_steps
y = ow.np_results["res_ext_grid.mdot_kg_per_s"]
plt.xlabel("time step")
plt.ylabel("mass flow [kg/s]")
plt.title("External Grid Mass Flow Profile")
plt.plot(x, y, "r-o")
plt.grid()
plt.show()
In addition, the pressure curves for the individual junctions can be plotted with this code block:
import matplotlib.pyplot as plt
x = time_steps
y = ow.np_results["res_junction.p_bar"]
plt.xlabel("time step")
plt.ylabel("pressure [bar]")
plt.title("Pressure Profile")
plt.plot(x, y[:,0], "g-o")
plt.plot(x, y[:,1], "r-o")
plt.plot(x, y[:,2], "y-o")
plt.legend(["Source", "External Grid", "Sink"], loc='lower left')
plt.grid()
plt.show()
As a final example to illustrate the results, the flow velocities of the three pipes are plotted:
For this purpose, the following code must be executed:
import matplotlib.pyplot as plt
x = time_steps
y = ow.np_results["res_pipe.v_mean_m_per_s"]
plt.xlabel("time step")
plt.ylabel("v_mean [m/s]")
plt.title("Velocity Profile")
plt.plot(x, y[:,0], "g-o")
plt.plot(x, y[:,1], "r-o")
plt.plot(x, y[:,2], "y-o")
plt.legend(["Pipe 1", "Pipe 2", "Pipe 3"], loc='lower left')
plt.grid()
plt.show()