Example 3: Pandapipes

This Example demonstrates how to generate a pandapipes network based on a SIR 3S model. When working with SIR 3S, pandapipes used to offer some freedom in creating simple DH models via Python, but with the introduction of the SIR 3S Toolkit, pandapipes is no longer necessary for this. Therefore the main benefit of pandapipes for SIR 3S users is for comparing calculations to SIR 3S results.

Note that the SIR 3S model we are using in this Example is quite simple.

In this Example we will first generate the pandapipes network manually by obtaining element dataframes for pipes and nodes via SIR 3S Toolkit. Then we will perform the same steps but built into one single Toolkit function.

Toolkit Release

[43]:
#pip install

Imports

SIR 3S Toolkit

Regular Import/Init

[44]:
SIR3S_SIRGRAF_DIR = r"C:\3S\SIR 3S Entwicklung\SirGraf-90-15-00-16_Quebec_x64" #change to local path
[45]:
import sir3stoolkit
[46]:
from sir3stoolkit.core import wrapper
[47]:
sir3stoolkit
[47]:
<module 'sir3stoolkit' from 'C:\\Users\\aUsername\\3S\\sir3stoolkit\\src\\sir3stoolkit\\__init__.py'>
[48]:
wrapper.Initialize_Toolkit(SIR3S_SIRGRAF_DIR)

Additional Import/Init for Alternative_Models class

[49]:
from sir3stoolkit.mantle import alternative_models
[50]:
s3s = alternative_models.Alternative_Models_SIR3S_Model()
Initialization complete

Additional

[51]:
import pandas as pd
[52]:
import pandapipes as pp
[53]:
from shapely import wkt
[54]:
import pandapipes.plotting as pp_plot

Open SIR 3S Model

[55]:
s3s.OpenModel(dbName=r"C:\Users\aUsername\3S\PT3S\PT3S\Examples\Example9_2.db3",
              providerType=s3s.ProviderTypes.SQLite,
              Mid="M-1-0-1",
              saveCurrentlyOpenModel=False,
              namedInstance="",
              userID="",
              password="")
Model is open for further operation

Generate Pandapipes network manually

Create pandapipes network

Nodes

[56]:
net = pp.create_empty_network(fluid="water")
[57]:
df_nodes_metadata = s3s.generate_element_metadata_dataframe(s3s.ObjectTypes.Node, ['Name', 'QmEin', 'bz.PhEin', 'Zkor', 'Ktyp'], geometry=True)
[2025-10-07 13:27:29,772] INFO in sir3stoolkit.mantle.dataframes: [metadata] Generating metadata dataframe for element type: ObjectTypes.Node
[2025-10-07 13:27:29,773] INFO in sir3stoolkit.mantle.dataframes: [metadata] Retrieved 9 element(s) of element type ObjectTypes.Node.
[2025-10-07 13:27:29,776] DEBUG in sir3stoolkit.mantle.dataframes: [Resolving Metadata Properties] Using 5 metadata properties.
[2025-10-07 13:27:29,777] INFO in sir3stoolkit.mantle.dataframes: [metadata] Retrieving metadata properties ['Name', 'QmEin', 'bz.PhEin', 'Zkor', 'Ktyp'], geometry...
[2025-10-07 13:27:29,777] INFO in sir3stoolkit.mantle.dataframes: [metadata] 0 non-empty end node columns were created)
[2025-10-07 13:27:29,783] INFO in sir3stoolkit.mantle.dataframes: [metadata] Done. Shape: (9, 7)
[58]:
df_nodes_results = s3s.generate_element_results_dataframe(s3s.ObjectTypes.Node, ['PH', 'T', 'QM'], s3s.GetTimeStamps()[0])
[2025-10-07 13:27:29,803] INFO in sir3stoolkit.mantle.dataframes: [results] Generating results dataframe for element type: ObjectTypes.Node
[2025-10-07 13:27:29,812] INFO in sir3stoolkit.mantle.dataframes: [Resolving Timestamps] Only static timestamp 2025-06-05 15:27:46.000 +02:00 is available
[2025-10-07 13:27:29,813] INFO in sir3stoolkit.mantle.dataframes: [results] Retrieved 9 tks.
[2025-10-07 13:27:29,816] INFO in sir3stoolkit.mantle.dataframes: [results] Using 3 result properties.
[2025-10-07 13:27:29,816] INFO in sir3stoolkit.mantle.dataframes: [results] Retrieving result properties...
[2025-10-07 13:27:29,820] INFO in sir3stoolkit.mantle.dataframes: [results] Done. Shape: (9, 5)
[59]:
df_nodes = pd.merge(df_nodes_metadata, df_nodes_results, on='tk', how='inner')
[60]:
df_nodes.head(3)
[60]:
tk Name QmEin bz.PhEin Zkor Ktyp geometry timestamp PH T QM
0 5136506604482101815 K0000 0 100 10 PKON POINT (149.99985694885254 500.00011920928955) 2025-06-05 15:27:46.000 +02:00 100 0 400
1 5174640379525019821 K0001 0 0 10 QKON POINT (349.99996423721313 600.00002384185791) 2025-06-05 15:27:46.000 +02:00 99.99306 0 0
2 5665004361761998834 K0002 0 0 10 QKON POINT (550.00007152557373 600.00002384185791) 2025-06-05 15:27:46.000 +02:00 99.86531 0 0
[61]:
js = {}

for idx, row in df_nodes.iterrows():
    geom = wkt.loads(row["geometry"])
    x, y = geom.x, geom.y

    j = pp.create_junction(
        net,
        pn_bar=1 + float(row['PH']),
        tfluid_k=273.15 + float(row['T']),
        height_m=float(row['Zkor']),
        name=f"{row['Name']}~{row['tk']}"
    )

    # Assign geodata to junction_geodata table
    net.junction_geodata.at[j, "x"] = x
    net.junction_geodata.at[j, "y"] = y

    js[row['tk']] = j
[62]:
net.junction
[62]:
name pn_bar tfluid_k height_m in_service type
0 K0000~5136506604482101815 101.00000 273.15 10.0 True junction
1 K0001~5174640379525019821 100.99306 273.15 10.0 True junction
2 K0002~5665004361761998834 100.86531 273.15 10.0 True junction
3 K0003~5185493728872360834 100.72040 273.15 10.0 True junction
4 K0004~4776931467066465913 100.72040 273.15 10.0 True junction
5 K0005~5229509832448527475 100.93705 273.15 10.0 True junction
6 K0006~5073490478136313655 100.87409 273.15 10.0 True junction
7 K0007~5417314986988666587 100.86626 273.15 10.0 True junction
8 K0008~5366461594623940805 100.86626 273.15 10.0 True junction

pipes

[63]:
df_pipes_metadata = s3s.generate_element_metadata_dataframe(s3s.ObjectTypes.Pipe, ['L', 'Di', 'Rau', 'Name'], end_nodes=True, geometry=True)
[2025-10-07 13:27:29,918] INFO in sir3stoolkit.mantle.dataframes: [metadata] Generating metadata dataframe for element type: ObjectTypes.Pipe
[2025-10-07 13:27:29,919] INFO in sir3stoolkit.mantle.dataframes: [metadata] Retrieved 9 element(s) of element type ObjectTypes.Pipe.
[2025-10-07 13:27:29,921] DEBUG in sir3stoolkit.mantle.dataframes: [Resolving Metadata Properties] Using 4 metadata properties.
[2025-10-07 13:27:29,922] INFO in sir3stoolkit.mantle.dataframes: [metadata] Retrieving metadata properties ['L', 'Di', 'Rau', 'Name'], geometry, end nodes...
[2025-10-07 13:27:29,927] INFO in sir3stoolkit.mantle.dataframes: [metadata] 2 non-empty end node columns were created)
[2025-10-07 13:27:29,927] INFO in sir3stoolkit.mantle.dataframes: [metadata] Done. Shape: (9, 8)
[64]:
for idx,row in df_pipes_metadata.iterrows():
    raw_value = row["Rau"]
    row["Rau"] = float(str(raw_value).replace(",", "."))
[65]:
df_pipes_metadata.head(3)
[65]:
tk L Di Rau Name geometry fkKI fkKK
0 4762947358005495341 1000 450 0.25 Rohr K0000 K0001 LINESTRING (149.99985694885254 500.00011920928... 5136506604482101815 5174640379525019821
1 5479123649362439650 1000 250 0.25 Rohr K0002 K0003 LINESTRING (550.00007152557373 600.00002384185... 5665004361761998834 5185493728872360834
2 5367303884852200682 1000 250 0.25 Rohr K0002 K0004 LINESTRING (550.00007152557373 600.00002384185... 5665004361761998834 4776931467066465913
[66]:
ps = {}

for idx, row in df_pipes_metadata.iterrows():
    geom = wkt.loads(row["geometry"])
    coords = list(geom.coords)

    # Create pipe
    p = pp.create_pipe_from_parameters(
        net,
        from_junction=js[row['fkKI']],
        to_junction=js[row['fkKK']],
        length_km=float(row['L']) / 1000.,
        diameter_m=float(row['Di']) / 1000.,
        k_mm=float(row['Rau']),
        name=f"{row['Name']}~{row['tk']}"
    )
    ps[row['tk']] = p

    net.pipe_geodata.at[p, "coords"] = coords
[67]:
net.pipe.head(3)
[67]:
name from_junction to_junction std_type length_km diameter_m k_mm loss_coefficient u_w_per_m2k text_k qext_w sections in_service type
0 Rohr K0000 K0001~4762947358005495341 0 1 None 1.0 0.45 0.25 0.0 0.0 NaN 0.0 1 True pipe
1 Rohr K0002 K0003~5479123649362439650 2 3 None 1.0 0.25 0.25 0.0 0.0 NaN 0.0 1 True pipe
2 Rohr K0002 K0004~5367303884852200682 2 4 None 1.0 0.25 0.25 0.0 0.0 NaN 0.0 1 True pipe

sources/sinks

[68]:
for idx, row in df_nodes.iterrows():
    ktyp = (row.get("Ktyp"))
    tk = row.get("tk")

    # Create source if Ktyp is PKON and PH > 0
    if ktyp == "PKON" and float(row.get("PH", 0)) > 0:
        pp.create_ext_grid(
            net,
            junction=js[tk],
            p_bar=1 + float(row["PH"]),
            t_k=273.15 + float(row["T"]),
            name=f"Src: {row['Name']}~{tk}"
        )

    # Create sink if Ktyp is QKON and QM < 0
    elif ktyp == "QKON" and float(row.get("QM", 0)) < 0:
        pp.create_sink(
            net,
            junction=js[tk],
            mdot_kg_per_s=abs(float(row["QM"])),
            name=f"Snk: {row['Name']}~{tk}"
        )
[69]:
net.ext_grid
[69]:
name junction p_bar t_k in_service type
0 Src: K0000~5136506604482101815 0 101.0 273.15 True pt
[70]:
net.sink
[70]:
name junction mdot_kg_per_s scaling in_service type
0 Snk: K0003~5185493728872360834 3 100.0 1.0 True sink
1 Snk: K0004~4776931467066465913 4 100.0 1.0 True sink
2 Snk: K0007~5417314986988666587 7 100.0 1.0 True sink
3 Snk: K0008~5366461594623940805 8 100.0 1.0 True sink

Calculate

[71]:
pp.pipeflow(net)

View Results

[72]:
net.res_junction
[72]:
p_bar t_k
0 101.000000 273.15
1 100.932708 273.15
2 99.491364 273.15
3 97.843832 273.15
4 97.843832 273.15
5 100.289209 273.15
6 99.578419 273.15
7 99.501563 273.15
8 99.501563 273.15
[73]:
net.res_pipe
[73]:
v_mean_m_per_s p_from_bar p_to_bar t_from_k t_to_k t_outlet_k mdot_from_kg_per_s mdot_to_kg_per_s vdot_m3_per_s reynolds lambda
0 0.587940 101.000000 100.932708 273.15 273.15 273.15 93.496673 -93.496673 0.093508 148220.775254 0.017522
1 2.037427 99.491364 97.843832 273.15 273.15 273.15 100.000000 -100.000000 0.100012 285354.955734 0.019847
2 2.037427 99.491364 97.843832 273.15 273.15 273.15 100.000000 -100.000000 0.100012 285354.955734 0.019847
3 1.927402 101.000000 100.289209 273.15 273.15 273.15 306.503327 -306.503327 0.306540 485901.348599 0.017222
4 1.927402 100.289209 99.578419 273.15 273.15 273.15 306.503327 -306.503327 0.306540 485901.348599 0.017222
5 0.628836 99.578419 99.501563 273.15 273.15 273.15 100.000000 -100.000000 0.100012 158530.530963 0.017494
6 0.628836 99.578419 99.501563 273.15 273.15 273.15 100.000000 -100.000000 0.100012 158530.530963 0.017494
7 1.904927 100.932708 99.491364 273.15 273.15 273.15 93.496673 -93.496673 0.093508 266797.395457 0.019862
8 -0.669731 99.491364 99.578419 273.15 273.15 273.15 -106.503327 106.503327 -0.106516 168840.286672 0.017470
[74]:
net.res_sink
[74]:
mdot_kg_per_s
0 100.0
1 100.0
2 100.0
3 100.0
[75]:
net.res_ext_grid
[75]:
mdot_kg_per_s
0 -400.0

Plot

[76]:
pp_plot.simple_plot(net)
../_images/examples_Toolkit_Example3_52_0.png
[76]:
<Axes: >
[77]:
import plotly.express as px

junctions = net.res_junction.copy()
junctions["x"] = net.junction_geodata["x"]
junctions["y"] = net.junction_geodata["y"]

fig = px.scatter(
    junctions,
    x="x", y="y",
    color="p_bar",
    hover_data=["p_bar"],
    title="Junctions: Pressure and Temperature",
    labels={"p_bar": "Pressure [bar]"}
)
fig.show()

Data type cannot be displayed: application/vnd.plotly.v1+json

The above depiction is not displayed in the online documentation.

Generating Pandapipes network using alternative_models() class from SIR 3S Toolkit

Create

[78]:
pp_net = s3s.SIR_3S_to_pandapipes()
[2025-10-07 13:27:30,428] INFO in sir3stoolkit.mantle.dataframes: [metadata] Generating metadata dataframe for element type: ObjectTypes.Node
[2025-10-07 13:27:30,429] INFO in sir3stoolkit.mantle.dataframes: [metadata] Retrieved 9 element(s) of element type ObjectTypes.Node.
[2025-10-07 13:27:30,430] DEBUG in sir3stoolkit.mantle.dataframes: [Resolving Metadata Properties] Using 5 metadata properties.
[2025-10-07 13:27:30,431] INFO in sir3stoolkit.mantle.dataframes: [metadata] Retrieving metadata properties ['Name', 'Zkor', 'QmEin', 'bz.PhEin', 'Ktyp'], geometry...
[2025-10-07 13:27:30,436] INFO in sir3stoolkit.mantle.dataframes: [metadata] 0 non-empty end node columns were created)
[2025-10-07 13:27:30,437] INFO in sir3stoolkit.mantle.dataframes: [metadata] Done. Shape: (9, 7)
[2025-10-07 13:27:30,483] INFO in sir3stoolkit.mantle.dataframes: [results] Generating results dataframe for element type: ObjectTypes.Node
[2025-10-07 13:27:30,501] INFO in sir3stoolkit.mantle.dataframes: [Resolving Timestamps] Only static timestamp 2025-06-05 15:27:46.000 +02:00 is available
[2025-10-07 13:27:30,503] INFO in sir3stoolkit.mantle.dataframes: [results] Retrieved 9 tks.
[2025-10-07 13:27:30,504] INFO in sir3stoolkit.mantle.dataframes: [results] Using 3 result properties.
[2025-10-07 13:27:30,504] INFO in sir3stoolkit.mantle.dataframes: [results] Retrieving result properties...
[2025-10-07 13:27:30,508] INFO in sir3stoolkit.mantle.dataframes: [results] Done. Shape: (9, 5)
[2025-10-07 13:27:30,536] INFO in sir3stoolkit.mantle.dataframes: [metadata] Generating metadata dataframe for element type: ObjectTypes.Pipe
[2025-10-07 13:27:30,537] INFO in sir3stoolkit.mantle.dataframes: [metadata] Retrieved 9 element(s) of element type ObjectTypes.Pipe.
[2025-10-07 13:27:30,539] DEBUG in sir3stoolkit.mantle.dataframes: [Resolving Metadata Properties] Using 4 metadata properties.
[2025-10-07 13:27:30,540] INFO in sir3stoolkit.mantle.dataframes: [metadata] Retrieving metadata properties ['L', 'Di', 'Rau', 'Name'], geometry, end nodes...
[2025-10-07 13:27:30,543] INFO in sir3stoolkit.mantle.dataframes: [metadata] 2 non-empty end node columns were created)
[2025-10-07 13:27:30,544] INFO in sir3stoolkit.mantle.dataframes: [metadata] Done. Shape: (9, 8)

Calculate

[79]:
pp.pipeflow(net)

View Results

[80]:
net.res_junction
[80]:
p_bar t_k
0 101.000000 273.15
1 100.932708 273.15
2 99.491364 273.15
3 97.843832 273.15
4 97.843832 273.15
5 100.289209 273.15
6 99.578419 273.15
7 99.501563 273.15
8 99.501563 273.15
[81]:
net.res_pipe
[81]:
v_mean_m_per_s p_from_bar p_to_bar t_from_k t_to_k t_outlet_k mdot_from_kg_per_s mdot_to_kg_per_s vdot_m3_per_s reynolds lambda
0 0.587940 101.000000 100.932708 273.15 273.15 273.15 93.496673 -93.496673 0.093508 148220.775254 0.017522
1 2.037427 99.491364 97.843832 273.15 273.15 273.15 100.000000 -100.000000 0.100012 285354.955734 0.019847
2 2.037427 99.491364 97.843832 273.15 273.15 273.15 100.000000 -100.000000 0.100012 285354.955734 0.019847
3 1.927402 101.000000 100.289209 273.15 273.15 273.15 306.503327 -306.503327 0.306540 485901.348599 0.017222
4 1.927402 100.289209 99.578419 273.15 273.15 273.15 306.503327 -306.503327 0.306540 485901.348599 0.017222
5 0.628836 99.578419 99.501563 273.15 273.15 273.15 100.000000 -100.000000 0.100012 158530.530963 0.017494
6 0.628836 99.578419 99.501563 273.15 273.15 273.15 100.000000 -100.000000 0.100012 158530.530963 0.017494
7 1.904927 100.932708 99.491364 273.15 273.15 273.15 93.496673 -93.496673 0.093508 266797.395457 0.019862
8 -0.669731 99.491364 99.578419 273.15 273.15 273.15 -106.503327 106.503327 -0.106516 168840.286672 0.017470
[82]:
net.res_sink
[82]:
mdot_kg_per_s
0 100.0
1 100.0
2 100.0
3 100.0
[83]:
net.res_ext_grid
[83]:
mdot_kg_per_s
0 -400.0

Plot

[84]:
import plotly.express as px

junctions = net.res_junction.copy()
junctions["x"] = net.junction_geodata["x"]
junctions["y"] = net.junction_geodata["y"]

fig = px.scatter(
    junctions,
    x="x", y="y",
    color="p_bar",
    hover_data=["p_bar"],
    title="Junctions: Pressure and Temperature",
    labels={"p_bar": "Pressure [bar]"}
)
fig.show()

Data type cannot be displayed: application/vnd.plotly.v1+json

The above depiction is not displayed in the online documentation.