Example 5: Loop over multiple SIR 3S calculations

This example demonstrates how to modify the SirCalcXmlFile, perform calculations on its state, and plot the results. These steps are executed in a loop over several different SIR 3S calculations.

SIR 3S provides a C# .NET adapter for carrying out loops over multiple calculations. With the C# .NET adapter, SIR 3S calculations can be integrated directly into other software. In SIR 3S itself, the C# .NET adapter is used to implement calculation loops such as n-1 calculations.

In addition, SIR 3S provides connections to control systems via OPC and other interfaces such as Kafka. The SIR 3S software component for these connections is called - for historical reasons - SirOPC. SirIPC (Inter Process Communication) is a more suitable name for SirOPC. SirOPC is used for e.g. control system integrated SIR 3S simulations such as cyclic look-ahead calculations.

Regardless of the topic of interprocess communication SIR 3S offers the option to perform several steady state calculations one after the other in one SIR 3S calculation run as quasi steady state calculations. The sequence of calculations is done out over a pseudo time step, e.g. 1 hour with 60 calculations or 1 year with 8760 calculations. Whether individual calculations or a sequence over a pseudo-time in one run is the better choice depends on the task.

Despite the aforementioned options, it can be helpful to control or perform SIR 3S calculations calculations by script.

PT3S Release

[38]:
#pip install PT3S -U --no-deps

Necessary packages for this Example

When running this example for the first time on your machine, please execute the cell below. Afterward, you may need to restart the kernel (using the ‘fast-forward’ button).
[39]:
pip install -q ipywidgets folium ipython lxml
Note: you may need to restart the kernel to use updated packages.

Imports

[40]:
import os
import geopandas
import logging
import pandas as pd
import io
import subprocess
import numpy as np
#from PIL import Image

import ipywidgets as widgets
from IPython.display import Image, display

import matplotlib.pyplot as plt
#import matplotlib.dates as mdates

import matplotlib

import folium
from folium.plugins import HeatMap

import networkx as nx

try:
    from PT3S import dxAndMxHelperFcts
except:
    import dxAndMxHelperFcts

try:
    from PT3S import Mx
except:
    import Mx

try:
    from PT3S import Rm
except:
    import Rm


try:
    from PT3S import pNFD
except:
    import pNFD

try:
    from PT3S import ncd
except:
    import ncd
[ ]:
import importlib
from importlib import resources
[42]:
#importlib.reload(dxAndMxHelperFcts)

Logging

[ ]:
logger = logging.getLogger()

if not logger.handlers:
    logFileName = r"Example5.log"
    loglevel = logging.DEBUG

    logging.basicConfig(
        filename=logFileName,
        filemode='w',
        level=loglevel,
        format="%(asctime)s ; %(name)-60s ; %(levelname)-7s ; %(message)s"
    )

    fileHandler = logging.FileHandler(logFileName)
    logger.addHandler(fileHandler)

    consoleHandler = logging.StreamHandler()
    consoleHandler.setFormatter(logging.Formatter("%(levelname)-7s ; %(message)s"))
    consoleHandler.setLevel(logging.INFO)
    logger.addHandler(consoleHandler)

Read Model and Results

[ ]:
dbFilename="Example5"
dbFile = resources.files("PT3S").joinpath("Examples", f"{dbFilename}.db3")
[ ]:
m=dxAndMxHelperFcts.readDxAndMx(dbFile=dbFile,preventPklDump=True
                                ,maxRecords=-1
                                #,SirCalcExePath=r"C:\3S\SIR 3S\SirCalc-90-14-02-10_Potsdam\SirCalc.exe"
                                )
INFO    ; Dx.__init__: dbFile (abspath): c:\users\aUserName\3s\pt3s\Examples\Example5.db3 exists readable ...
INFO    ; Dx.__init__: dbFile (abspath): c:\users\aUserName\3s\pt3s\Examples\Example5.db3 exists readable ...
INFO    ; dxAndMxHelperFcts.readDxAndMx: Model is being recalculated using C:\3S\SIR 3S\SirCalc-90-14-02-10_Potsdam\SirCalc.exe
INFO    ; dxAndMxHelperFcts.readDxAndMx: Model is being recalculated using C:\3S\SIR 3S\SirCalc-90-14-02-10_Potsdam\SirCalc.exe
INFO    ; Mx.setResultsToMxsFile: Mxs: ..\Examples\WDExample5\B1\V0\BZ1\M-1-0-1.1.MXS reading ...
INFO    ; Mx.setResultsToMxsFile: Mxs: ..\Examples\WDExample5\B1\V0\BZ1\M-1-0-1.1.MXS reading ...
INFO    ; dxWithMx.__init__: Example5: processing dx and mx ...
INFO    ; dxWithMx.__init__: Example5: processing dx and mx ...

Plot Result

As Network Color Diagram

[46]:
def plot_Result_ncd(gdf_ROHR, gdf_FWVB, axTitle='initial condition'):

    fig, ax = plt.subplots(figsize=Rm.DINA3q)

    nodes_patches_1 = ncd.pNcd_nodes(ax=ax
                                    ,gdf=gdf_FWVB
                                    ,attribute='QM'
                                    ,colors = ['cyan','teal']
                                    ,norm_max=100
                                    ,marker_style='p'
                                    ,legend_fmt = '{:4.0f} t/h'
                                    ,legend_values = [0,25,50,75,100]
                                    ,zorder=1)

    pipes_patches_2 = ncd.pNcd_pipes(ax=ax
                                     ,gdf=gdf_ROHR
                                     ,attribute='DI'
                                     ,colors = ['lightgray', 'dimgray']
                                     ,legend_fmt = '{:4.0f} mm'
                                     ,line_width_factor=20
                                     ,legend_values = [0,250,500,750]
                                     ,zorder=2)


    pipes_patches_3 = ncd.pNcd_pipes(ax=ax
                                     ,gdf=gdf_ROHR
                                     ,attribute='QMAVAbs'
                                     ,colors = ['darkgreen', 'magenta']
                                     ,legend_fmt = '{:4.0f} t/h'
                                     ,line_width_factor=20
                                     ,legend_values = [0,500,1000,1500,2000]
                                     ,zorder=3)
    all_patches = nodes_patches_1 + pipes_patches_2 + pipes_patches_3
    ax.legend(handles=all_patches, loc='best')

    plt.title(axTitle)
    plt.show()
[47]:
plot_Result_ncd(m.gdf_ROHR, m.gdf_FWVB)
_images/Example5_19_0.png

As Longitudinal Section

[48]:
def fyPH(ax,offset=0):
    ax.spines["left"].set_position(("outward", offset))
    ax.set_ylabel('PH Druck in bar')
    ax.set_ylim(0,21)
    ax.set_yticks(sorted(np.append(np.linspace(0,21, 22),[])))
    ax.yaxis.set_ticks_position('left')
    ax.yaxis.set_label_position('left')

def fyPH_d(ax,offset=0):
    ax.spines["left"].set_position(("outward", offset))
    ax.set_ylabel('PH Druck in bar')
    ax.set_ylim(0,20)
    ax.set_yticks(sorted(np.append(np.linspace(-5,21,27),[])))
    ax.yaxis.set_ticks_position('left')
    ax.yaxis.set_label_position('left')

def fymlc(ax,offset=60):
    ax.spines["left"].set_position(("outward", offset))
    ax.set_ylabel('mlc Druckhöhe in mlc')
    #ax.set_ylim(1,6)
    #ax.set_yticks(sorted(np.append(np.linspace(1,6,11),[])))
    ax.yaxis.set_ticks_position('left')
    ax.yaxis.set_label_position('left')

def fybarBzg(ax,offset=120):
    ax.spines["left"].set_position(("outward", offset))
    ax.set_ylabel('H Druck in barBzg')
    #ax.set_ylim(1,6)
    #ax.set_yticks(sorted(np.append(np.linspace(1,6,11),[])))
    ax.yaxis.set_ticks_position('left')
    ax.yaxis.set_label_position('left')

#def fyM(ax,offset=180):
#    Rm.pltLDSHelperY(ax)
#    ax.spines["left"].set_position(("outward",offset))
#    ax.set_ylabel('QM Massenstrom in t/h')
    #ax.set_ylim(500,550)
    #ax.set_yticks(sorted(np.append(np.linspace(500,550,11),[])))
#    ax.yaxis.set_ticks_position('left')
#    ax.yaxis.set_label_position('left')

def fyT(ax,offset=180):
    Rm.pltLDSHelperY(ax)
    ax.spines["left"].set_position(("outward",offset))
    ax.set_ylabel('T Tempertatur in °C')
    ax.set_ylim(55,95)
    #ax.set_yticks(sorted(np.append(np.linspace(0,95,11),[])))
    ax.yaxis.set_ticks_position('left')
    ax.yaxis.set_label_position('left')
[49]:
def plot_Result_ls(V3_AGSN):

    PHCol='PH_n'
    mlcCol='mlc_n'
    zKoorCol='ZKOR_n'
    barBzgCol='H_n'
    QMCol='QM'
    TCol='T_n'
    xCol='LSum'

    dfAGSN = V3_AGSN[
        (V3_AGSN['LFDNR'] == 1) &
        (V3_AGSN['XL'] == 1)
    ]
    dfAGSNRL=V3_AGSN[
    (V3_AGSN['LFDNR']==1)
    &
    (V3_AGSN['XL']==2)
    ]

    fig, ax0 = plt.subplots(figsize=Rm.DINA3q)

    ax0.grid()

    #PH
    fyPH(ax0)
    PH_SL=ax0.plot(dfAGSN[xCol], dfAGSN[PHCol], color='red', label='PH SL',ls='dotted')
    PH_RL=ax0.plot(dfAGSNRL[xCol], dfAGSNRL[PHCol], color='blue', label='PH RL',ls='dotted')

    #mlc
    ax11 = ax0.twinx()
    fymlc(ax11)
    mlc_SL=ax11.plot(dfAGSN[xCol], dfAGSN[mlcCol], color='red', label='mlc SL')
    mlc_RL=ax11.plot(dfAGSNRL[xCol], dfAGSNRL[mlcCol], color='blue', label='mlc RL')

    z=ax11.plot(dfAGSN[xCol], dfAGSN[zKoorCol], color='black', label='z',ls='dashed',alpha=.5)

    #barBZG
    ax12 = ax0.twinx()
    fybarBzg(ax12)
    barB_SL=ax12.plot(dfAGSN[xCol], dfAGSN[barBzgCol], color='red', label='H SL',ls='dashdot')
    barB_RL=ax12.plot(dfAGSNRL[xCol], dfAGSNRL[barBzgCol], color='blue', label='H RL',ls='dashdot')

    #M
    #ax2 = ax0.twinx()
    #fyM(ax2)
    #QM_SL=ax2.step(dfAGSN[xCol], dfAGSN[QMCol]*dfAGSN['direction'], color='orange', label='M SL')
    #QM_RL=ax2.step(dfAGSNRL[xCol], dfAGSNRL[QMCol]*dfAGSNRL['direction'], color='cyan', label='M RL',ls='--')

    #T
    ax3 = ax0.twinx()
    fyT(ax3)
    T_SL=ax3.plot(dfAGSN[xCol], dfAGSN[TCol], color='pink', label='T SL')
    T_RL=ax3.plot(dfAGSNRL[xCol], dfAGSNRL[TCol], color='lavender', label='T RL')

    ax0.set_xlim(dfAGSN['LSum'].min(), 25000)

    ax0.set_title('Longitudinal Section for '+dbFilename)

    # added these three lines
    lns =  PH_SL+ PH_RL+ T_SL+ T_RL + mlc_SL+ mlc_RL + barB_SL+ barB_RL
    labs = [l.get_label() for l in lns]
    ax0.legend(lns, labs)#, loc=0)

    plt.show()
[50]:
plot_Result_ls(m.V3_AGSN)
_images/Example5_23_0.png

Show Network Graph

[51]:
netNodes=[n for (n,data) in m.G.nodes(data=True) if data['ID_CONT']==data['IDPARENT_CONT']] # nur das Netz
[52]:
GNet=m.G.subgraph(netNodes)
[53]:
nx.number_connected_components(GNet)
[53]:
1
[54]:
nx.draw_networkx(GNet,with_labels = False,node_size=3,pos=m.nodeposDctNx)
_images/Example5_28_0.png

Decomposition into Areas

In the network, areas can be separated by valves in the sense of an emergency concept. In this way, leaks can be isolated while maintaining supply in the other areas. All seperating valves are located in the SIR 3S Block “TS”. So the network graph without the content of “TS” must be decomposed into areas.

[55]:
netEdgesWithoutTS=[(i,k) for i,k,data in GNet.edges(data=True) if data['NAME_CONT'] not in ['TS']]
[56]:
GNetWithoutTS=GNet.edge_subgraph(netEdgesWithoutTS)
[57]:
nOfCC=nx.number_connected_components(GNetWithoutTS)
nOfCC
[57]:
25
[58]:
GNetWithoutTSAreas=[GNet.subgraph(c).copy() for c in sorted(nx.connected_components(GNetWithoutTS), key=len, reverse=True)]

Read SirCalc’s XmlFile

[59]:
from lxml import etree
tree = etree.parse(m.SirCalcXmlFile) # ElementTree
root = tree.getroot() # Element
[60]:
print(m.SirCalcXmlFile)
c:\users\jablonski\3s\pt3s\Examples\WDExample5\B1\V0\BZ1\M-1-0-1.XML
[61]:
print(m.SirCalcExeFile)
C:\3S\SIR 3S\SirCalc-90-14-02-10_Potsdam\SirCalc.exe

Function to edit SirCalcXmlFile

[62]:
def close_valves(df, root, tree):
    for index, row in df.iterrows():
        vent_bz_elements = root.xpath(f"//VENT_BZ[@fk='{row['OBJID']}']")
        for el in vent_bz_elements:
            el.set('INDPHI', '-1')
            global BESCHREIBUNG
            BESCHREIBUNG = row['BESCHREIBUNG']
    tree.write(m.SirCalcXmlFile)
[63]:
def reopen_valves(df, root):
    for index, row in df.iterrows():
        vent_bz_elements = root.xpath(f"//VENT_BZ[@fk='{row['OBJID']}']")
        for el in vent_bz_elements:
            el.set('INDPHI', '0')

Function to calculate SirCalcXmlFile

[64]:
def calculate(m):
    with subprocess.Popen([m.SirCalcExeFile, m.SirCalcXmlFile]) as process:
        process.wait()
        print(f'Command {process.args} exited with {process.returncode}.')

Loop over all Areas

[65]:
max_dfAGSN_SL = None
max_dfAGSN_RL = None
min_dfAGSN_SL = None
min_dfAGSN_RL = None
cols_to_track = ['PH_n', 'mlc_n', 'T_n']
V3_AGSN_list = []
[66]:
for idx, G in enumerate(GNetWithoutTSAreas):
    # Determine separating Valves to close
    trennNodes = []
    for n, data in G.nodes(data=True):
        if data['NAME_CONT_VKNO'] == 'TS':
            trennNodes.append(n)

    trennNodes = sorted(trennNodes)

    if 'V-A1' in G.nodes:
        print("Gebiet um Erzeuger H - keine Trennung")
        continue

    if 'V-A2' in G.nodes:
        print("Gebiet um Erzeuger H - keine Trennung")
        continue

    if 'V-B' in G.nodes:
        print("Gebiet um Erzeuger R - keine Trennung")
        continue

    df = m.V3_VBEL.reset_index()

    df = df[
        (
            (df['NAME_i'].isin(trennNodes))
            |
            (df['NAME_k'].isin(trennNodes))
        )
        &
        df['OBJTYPE'].isin(['VENT'])
        &
        df['NAME_CONT'].isin(['TS'])
    ]

    # Call the function to close the valves
    close_valves(df, root, tree)

    # Call the function to perform calculation
    calculate(m)

    # Read the results
    mx = Mx.Mx(m.mx.mx1File)
    mTmp = dxAndMxHelperFcts.dxWithMx(m.dx, mx)

    axTitle = f"{idx+1}/{nOfCC}- Exemplarisch die BESCHREIBUNG einer Trennstelle: {BESCHREIBUNG}"
    plot_index = int(axTitle.split('/')[0])
    V3_AGSN_list.insert(plot_index, mTmp.V3_AGSN.copy())

    # Plot Result as ncd
    plot_Result_ncd(mTmp.gdf_ROHR, mTmp.gdf_FWVB, axTitle=axTitle)

    # Plot Result as Longitudinal Sections
    plot_Result_ls(mTmp.V3_AGSN)

    # Update the maximum values DataFrames for SL and RL
    if max_dfAGSN_SL is None:
        max_dfAGSN_SL = mTmp.V3_AGSN[mTmp.V3_AGSN['XL'] == 1].copy()
        max_dfAGSN_RL = mTmp.V3_AGSN[mTmp.V3_AGSN['XL'] == 2].copy()
    else:
        for col in cols_to_track:
            max_dfAGSN_SL.loc[max_dfAGSN_SL['XL'] == 1, col] = np.maximum(max_dfAGSN_SL[col], mTmp.V3_AGSN[mTmp.V3_AGSN['XL'] == 1][col])
            max_dfAGSN_RL.loc[max_dfAGSN_RL['XL'] == 2, col] = np.maximum(max_dfAGSN_RL[col], mTmp.V3_AGSN[mTmp.V3_AGSN['XL'] == 2][col])

    # Update the minimal values DataFrames for SL and RL
    if min_dfAGSN_SL is None:
        min_dfAGSN_SL = mTmp.V3_AGSN[mTmp.V3_AGSN['XL'] == 1].copy()
        min_dfAGSN_RL = mTmp.V3_AGSN[mTmp.V3_AGSN['XL'] == 2].copy()
    else:
        for col in cols_to_track:
            min_dfAGSN_SL.loc[min_dfAGSN_SL['XL'] == 1, col] = np.minimum(min_dfAGSN_SL[col], mTmp.V3_AGSN[mTmp.V3_AGSN['XL'] == 1][col])
            min_dfAGSN_RL.loc[min_dfAGSN_RL['XL'] == 2, col] = np.minimum(min_dfAGSN_RL[col], mTmp.V3_AGSN[mTmp.V3_AGSN['XL'] == 2][col])

    # Call the function to reopen the valves
    reopen_valves(df, root)

    if idx > 4:
        break
INFO    ; Mx.setResultsToMxsFile: Mxs: ..\Examples\WDExample5\B1\V0\BZ1\M-1-0-1.1.MXS reading ...
INFO    ; Mx.setResultsToMxsFile: Mxs: ..\Examples\WDExample5\B1\V0\BZ1\M-1-0-1.1.MXS reading ...
Command ['C:\\3S\\SIR 3S\\SirCalc-90-14-02-10_Potsdam\\SirCalc.exe', 'c:\\users\\jablonski\\3s\\pt3s\\Examples\\WDExample5\\B1\\V0\\BZ1\\M-1-0-1.XML'] exited with 0.
INFO    ; dxWithMx.__init__: Example5: processing dx and mx ...
INFO    ; dxWithMx.__init__: Example5: processing dx and mx ...
_images/Example5_46_3.png
_images/Example5_46_4.png
INFO    ; Mx.setResultsToMxsFile: Mxs: ..\Examples\WDExample5\B1\V0\BZ1\M-1-0-1.1.MXS reading ...
INFO    ; Mx.setResultsToMxsFile: Mxs: ..\Examples\WDExample5\B1\V0\BZ1\M-1-0-1.1.MXS reading ...
Command ['C:\\3S\\SIR 3S\\SirCalc-90-14-02-10_Potsdam\\SirCalc.exe', 'c:\\users\\jablonski\\3s\\pt3s\\Examples\\WDExample5\\B1\\V0\\BZ1\\M-1-0-1.XML'] exited with 0.
INFO    ; dxWithMx.__init__: Example5: processing dx and mx ...
INFO    ; dxWithMx.__init__: Example5: processing dx and mx ...
_images/Example5_46_8.png
_images/Example5_46_9.png
INFO    ; Mx.setResultsToMxsFile: Mxs: ..\Examples\WDExample5\B1\V0\BZ1\M-1-0-1.1.MXS reading ...
INFO    ; Mx.setResultsToMxsFile: Mxs: ..\Examples\WDExample5\B1\V0\BZ1\M-1-0-1.1.MXS reading ...
Command ['C:\\3S\\SIR 3S\\SirCalc-90-14-02-10_Potsdam\\SirCalc.exe', 'c:\\users\\jablonski\\3s\\pt3s\\Examples\\WDExample5\\B1\\V0\\BZ1\\M-1-0-1.XML'] exited with 0.
INFO    ; dxWithMx.__init__: Example5: processing dx and mx ...
INFO    ; dxWithMx.__init__: Example5: processing dx and mx ...
_images/Example5_46_13.png
_images/Example5_46_14.png
Gebiet um Erzeuger H - keine Trennung
INFO    ; Mx.setResultsToMxsFile: Mxs: ..\Examples\WDExample5\B1\V0\BZ1\M-1-0-1.1.MXS reading ...
INFO    ; Mx.setResultsToMxsFile: Mxs: ..\Examples\WDExample5\B1\V0\BZ1\M-1-0-1.1.MXS reading ...
Command ['C:\\3S\\SIR 3S\\SirCalc-90-14-02-10_Potsdam\\SirCalc.exe', 'c:\\users\\jablonski\\3s\\pt3s\\Examples\\WDExample5\\B1\\V0\\BZ1\\M-1-0-1.XML'] exited with 0.
INFO    ; dxWithMx.__init__: Example5: processing dx and mx ...
INFO    ; dxWithMx.__init__: Example5: processing dx and mx ...
_images/Example5_46_19.png
_images/Example5_46_20.png
INFO    ; Mx.setResultsToMxsFile: Mxs: ..\Examples\WDExample5\B1\V0\BZ1\M-1-0-1.1.MXS reading ...
INFO    ; Mx.setResultsToMxsFile: Mxs: ..\Examples\WDExample5\B1\V0\BZ1\M-1-0-1.1.MXS reading ...
Command ['C:\\3S\\SIR 3S\\SirCalc-90-14-02-10_Potsdam\\SirCalc.exe', 'c:\\users\\jablonski\\3s\\pt3s\\Examples\\WDExample5\\B1\\V0\\BZ1\\M-1-0-1.XML'] exited with 0.
INFO    ; dxWithMx.__init__: Example5: processing dx and mx ...
INFO    ; dxWithMx.__init__: Example5: processing dx and mx ...
_images/Example5_46_24.png
_images/Example5_46_25.png

Min/Max

[67]:
def plot_Result_ls_min_max(dfAGSN1, dfAGSN2):
    PHCol = 'PH_n'
    mlcCol = 'mlc_n'
    zKoorCol = 'ZKOR_n'
    barBzgCol = 'H_n'
    QMCol = 'QM'
    TCol = 'T_n'
    xCol = 'LSum'

    # Convert columns to numeric, forcing errors to NaN
    for col in [PHCol, mlcCol, barBzgCol, TCol, xCol]:
        dfAGSN1[col] = pd.to_numeric(dfAGSN1[col], errors='coerce')
        dfAGSN2[col] = pd.to_numeric(dfAGSN2[col], errors='coerce')

    # Create checkboxes for each value pair
    PH_SL_checkbox = widgets.Checkbox(value=True, description='PH SL')
    PH_RL_checkbox = widgets.Checkbox(value=False, description='PH RL')
    mlc_SL_checkbox = widgets.Checkbox(value=False, description='mlc SL')
    mlc_RL_checkbox = widgets.Checkbox(value=False, description='mlc RL')

    def update_plot(PH_SL, PH_RL, mlc_SL, mlc_RL):

        fig, ax0 = plt.subplots(figsize=Rm.DINA3q)
        ax0.grid()

        lns = []

        # Process dfAGSN1
        name_prefix1 = dfAGSN1.name.split('_')[0]
        dfAGSN1_SL = dfAGSN1[(dfAGSN1['LFDNR'] == 1) & (dfAGSN1['XL'] == 1)]
        dfAGSN1_RL = dfAGSN1[(dfAGSN1['LFDNR'] == 1) & (dfAGSN1['XL'] == 2)]

        # Process dfAGSN2
        name_prefix2 = dfAGSN2.name.split('_')[0]
        dfAGSN2_SL = dfAGSN2[(dfAGSN2['LFDNR'] == 1) & (dfAGSN2['XL'] == 1)]
        dfAGSN2_RL = dfAGSN2[(dfAGSN2['LFDNR'] == 1) & (dfAGSN2['XL'] == 2)]

        # Create a dictionary to store axes
        axes_dict = {}

        # Function to get or create an axis
        def get_or_create_axis(ax_key):
            if ax_key not in axes_dict:
                axes_dict[ax_key] = ax0.twinx()
            return axes_dict[ax_key]

        # PH SL
        if PH_SL:
            fyPH(ax0)
            PH_SL1 = ax0.plot(dfAGSN1_SL[xCol], dfAGSN1_SL[PHCol], label=f'{name_prefix1} PH SL', ls='dotted', color='blue')
            PH_SL2 = ax0.plot(dfAGSN2_SL[xCol], dfAGSN2_SL[PHCol], label=f'{name_prefix2} PH SL', ls='dotted', color='red')
            lns += PH_SL1 + PH_SL2
            ax0.fill_between(dfAGSN1_SL[xCol], dfAGSN1_SL[PHCol], dfAGSN2_SL[PHCol], color='gray', alpha=0.3)
            diff_PH_SL = ax0.plot(dfAGSN1_SL[xCol], dfAGSN1_SL[PHCol] - dfAGSN2_SL[PHCol], label=f'Diff {name_prefix1} - {name_prefix2} PH SL', ls='solid', color='black')
            lns += diff_PH_SL

        # PH RL
        if PH_RL:
            fyPH(ax0)
            PH_RL1 = ax0.plot(dfAGSN1_RL[xCol], dfAGSN1_RL[PHCol], label=f'{name_prefix1} PH RL', ls='dotted', color='blue')
            PH_RL2 = ax0.plot(dfAGSN2_RL[xCol], dfAGSN2_RL[PHCol], label=f'{name_prefix2} PH RL', ls='dotted', color='red')
            lns += PH_RL1 + PH_RL2
            ax0.fill_between(dfAGSN1_RL[xCol], dfAGSN1_RL[PHCol], dfAGSN2_RL[PHCol], color='gray', alpha=0.3)
            diff_PH_RL = ax0.plot(dfAGSN1_RL[xCol], dfAGSN1_RL[PHCol] - dfAGSN2_RL[PHCol], label=f'Diff {name_prefix1} - {name_prefix2} PH RL', ls='solid', color='black')
            lns += diff_PH_RL

        # mlc SL
        if mlc_SL:
            ax11 = get_or_create_axis('mlc')
            fymlc(ax11)
            mlc_SL1 = ax11.plot(dfAGSN1_SL[xCol], dfAGSN1_SL[mlcCol], label=f'{name_prefix1} mlc SL', ls='--', color='green')
            mlc_SL2 = ax11.plot(dfAGSN2_SL[xCol], dfAGSN2_SL[mlcCol], label=f'{name_prefix2} mlc SL', ls='--', color='orange')
            lns += mlc_SL1 + mlc_SL2
            ax11.fill_between(dfAGSN1_SL[xCol], dfAGSN1_SL[mlcCol], dfAGSN2_SL[mlcCol], color='gray', alpha=0.3)
            diff_mlc_SL = ax11.plot(dfAGSN1_SL[xCol], dfAGSN1_SL[mlcCol] - dfAGSN2_SL[mlcCol], label=f'Diff {name_prefix1} - {name_prefix2} mlc SL', ls='solid', color='black')
            lns += diff_mlc_SL

        # mlc RL
        if mlc_RL:
            ax11 = get_or_create_axis('mlc')
            fymlc(ax11)
            mlc_RL1 = ax11.plot(dfAGSN1_RL[xCol], dfAGSN1_RL[mlcCol], label=f'{name_prefix1} mlc RL', ls='--', color='green')
            mlc_RL2 = ax11.plot(dfAGSN2_RL[xCol], dfAGSN2_RL[mlcCol], label=f'{name_prefix2} mlc RL', ls='--', color='orange')
            lns += mlc_RL1 + mlc_RL2
            ax11.fill_between(dfAGSN1_RL[xCol], dfAGSN1_RL[mlcCol], dfAGSN2_RL[mlcCol], color='gray', alpha=0.3)
            diff_mlc_RL = ax11.plot(dfAGSN1_RL[xCol], dfAGSN1_RL[mlcCol] - dfAGSN2_RL[mlcCol], label=f'Diff {name_prefix1} - {name_prefix2} mlc RL', ls='solid', color='black')
            lns += diff_mlc_RL

        labs = [l.get_label() for l in lns]

        ax0.set_xlim(dfAGSN1['LSum'].min(), 25000)

        ax0.legend(lns, labs)

        plt.show()

    # Create interactive plot
    interactive_plot = widgets.interactive(update_plot,
                                           PH_SL=PH_SL_checkbox,
                                           PH_RL=PH_RL_checkbox,
                                           mlc_SL=mlc_SL_checkbox,
                                           mlc_RL=mlc_RL_checkbox,)

    display(interactive_plot)
[68]:
max_dfAGSN_SL['XL'] = 1
max_dfAGSN_RL['XL'] = 2
max_dfAGSN = pd.concat([max_dfAGSN_SL, max_dfAGSN_RL])

min_dfAGSN_SL['XL'] = 1
min_dfAGSN_RL['XL'] = 2
min_dfAGSN = pd.concat([min_dfAGSN_SL, min_dfAGSN_RL])
[69]:
min_dfAGSN.name='min'
max_dfAGSN.name='max'
dfAGSN_list=(min_dfAGSN, max_dfAGSN)
plot_Result_ls_min_max(max_dfAGSN, min_dfAGSN)
The depiction of the interactive Widget plot does not work in the documentation, because a python kernel must run it. A screenshot of the interacitve plot is provided below. To interact with the plot, download and run the script.
[70]:
try:
    image = Image(filename=r"C:\Users\jablonski\3S\PT3S\Examples\Images\5_example5_minmaxplot.png")
    display(image)
except:
    print('png not displayed')
_images/Example5_52_0.png

Difference

[71]:
def plot_Result_ls_comparison(dfAGSN1, dfAGSN2):
    PHCol = 'PH_n'
    mlcCol = 'mlc_n'
    zKoorCol = 'ZKOR_n'
    barBzgCol = 'H_n'
    QMCol = 'QM'
    TCol = 'T_n'
    xCol = 'LSum'

    # Convert columns to numeric, forcing errors to NaN
    dfAGSN1[PHCol] = pd.to_numeric(dfAGSN1[PHCol], errors='coerce')
    dfAGSN1[mlcCol] = pd.to_numeric(dfAGSN1[mlcCol], errors='coerce')
    dfAGSN1[barBzgCol] = pd.to_numeric(dfAGSN1[barBzgCol], errors='coerce')
    dfAGSN1[TCol] = pd.to_numeric(dfAGSN1[TCol], errors='coerce')
    dfAGSN1[xCol] = pd.to_numeric(dfAGSN1[xCol], errors='coerce')

    dfAGSN2[PHCol] = pd.to_numeric(dfAGSN2[PHCol], errors='coerce')
    dfAGSN2[mlcCol] = pd.to_numeric(dfAGSN2[mlcCol], errors='coerce')
    dfAGSN2[barBzgCol] = pd.to_numeric(dfAGSN2[barBzgCol], errors='coerce')
    dfAGSN2[TCol] = pd.to_numeric(dfAGSN2[TCol], errors='coerce')
    dfAGSN2[xCol] = pd.to_numeric(dfAGSN2[xCol], errors='coerce')

    # Create checkboxes for each value pair
    PH_SL_checkbox = widgets.Checkbox(value=False, description='PH SL')
    PH_RL_checkbox = widgets.Checkbox(value=True, description='PH RL')
    mlc_SL_checkbox = widgets.Checkbox(value=False, description='mlc SL')
    mlc_RL_checkbox = widgets.Checkbox(value=False, description='mlc RL')

    def update_plot(PH_SL, PH_RL, mlc_SL, mlc_RL):

        fig, ax0 = plt.subplots(figsize=Rm.DINA3q)
        ax0.grid()

        lns = []

        # Process dfAGSN1
        name_prefix1 = dfAGSN1.name.split('_')[0]
        dfAGSN1_SL = dfAGSN1[(dfAGSN1['LFDNR'] == 1) & (dfAGSN1['XL'] == 1)]
        dfAGSN1_RL = dfAGSN1[(dfAGSN1['LFDNR'] == 1) & (dfAGSN1['XL'] == 2)]

        # Process dfAGSN2
        name_prefix2 = dfAGSN2.name.split('_')[0]
        dfAGSN2_SL = dfAGSN2[(dfAGSN2['LFDNR'] == 1) & (dfAGSN2['XL'] == 1)]
        dfAGSN2_RL = dfAGSN2[(dfAGSN2['LFDNR'] == 1) & (dfAGSN2['XL'] == 2)]

        # Create a dictionary to store axes
        axes_dict = {}

        # Function to get or create an axis
        def get_or_create_axis(ax_key):
            if ax_key not in axes_dict:
                axes_dict[ax_key] = ax0.twinx()
            return axes_dict[ax_key]

        # PH SL
        if PH_SL:
            fyPH_d(ax0)
            PH_SL1 = ax0.plot(dfAGSN1_SL[xCol], dfAGSN1_SL[PHCol], label=f'{name_prefix1} PH SL', ls='dotted', color='blue')
            PH_SL2 = ax0.plot(dfAGSN2_SL[xCol], dfAGSN2_SL[PHCol], label=f'{name_prefix2} PH SL', ls='dotted', color='red')
            lns += PH_SL1 + PH_SL2
            ax0.fill_between(dfAGSN1_SL[xCol], dfAGSN1_SL[PHCol], dfAGSN2_SL[PHCol], color='gray', alpha=0.3)
            diff_PH_SL = ax0.plot(dfAGSN1_SL[xCol], dfAGSN1_SL[PHCol] - dfAGSN2_SL[PHCol], label=f'Diff {name_prefix1} - {name_prefix2} PH SL', ls='solid', color='black')
            lns += diff_PH_SL

        # PH RL
        if PH_RL:
            fyPH_d(ax0)
            PH_RL1 = ax0.plot(dfAGSN1_RL[xCol], dfAGSN1_RL[PHCol], label=f'{name_prefix1} PH RL', ls='dotted', color='blue')
            PH_RL2 = ax0.plot(dfAGSN2_RL[xCol], dfAGSN2_RL[PHCol], label=f'{name_prefix2} PH RL', ls='dotted', color='red')
            lns += PH_RL1 + PH_RL2
            ax0.fill_between(dfAGSN1_RL[xCol], dfAGSN1_RL[PHCol], dfAGSN2_RL[PHCol], color='gray', alpha=0.3)
            diff_PH_RL = ax0.plot(dfAGSN1_RL[xCol], dfAGSN1_RL[PHCol] - dfAGSN2_RL[PHCol], label=f'Diff {name_prefix1} - {name_prefix2} PH RL', ls='solid', color='black')
            lns += diff_PH_RL

        # mlc SL
        if mlc_SL:
            ax11 = get_or_create_axis('mlc')
            fymlc(ax11)
            mlc_SL1 = ax11.plot(dfAGSN1_SL[xCol], dfAGSN1_SL[mlcCol], label=f'{name_prefix1} mlc SL', ls='--', color='green')
            mlc_SL2 = ax11.plot(dfAGSN2_SL[xCol], dfAGSN2_SL[mlcCol], label=f'{name_prefix2} mlc SL', ls='--', color='orange')
            lns += mlc_SL1 + mlc_SL2
            ax11.fill_between(dfAGSN1_SL[xCol], dfAGSN1_SL[mlcCol], dfAGSN2_SL[mlcCol], color='gray', alpha=0.3)
            diff_mlc_SL = ax11.plot(dfAGSN1_SL[xCol], dfAGSN1_SL[mlcCol] - dfAGSN2_SL[mlcCol], label=f'Diff {name_prefix1} - {name_prefix2} mlc SL', ls='solid', color='black')
            lns += diff_mlc_SL

        # mlc RL
        if mlc_RL:
            ax11 = get_or_create_axis('mlc')
            fymlc(ax11)
            mlc_RL1 = ax11.plot(dfAGSN1_RL[xCol], dfAGSN1_RL[mlcCol], label=f'{name_prefix1} mlc RL', ls='--', color='green')
            mlc_RL2 = ax11.plot(dfAGSN2_RL[xCol], dfAGSN2_RL[mlcCol], label=f'{name_prefix2} mlc RL', ls='--', color='orange')
            lns += mlc_RL1 + mlc_RL2
            ax11.fill_between(dfAGSN1_RL[xCol], dfAGSN1_RL[mlcCol], dfAGSN2_RL[mlcCol], color='gray', alpha=0.3)
            diff_mlc_RL = ax11.plot(dfAGSN1_RL[xCol], dfAGSN1_RL[mlcCol] - dfAGSN2_RL[mlcCol], label=f'Diff {name_prefix1} - {name_prefix2} mlc RL', ls='solid', color='black')
            lns += diff_mlc_RL

        labs = [l.get_label() for l in lns]

        ax0.set_xlim(dfAGSN1['LSum'].min(), 25000)

        ax0.legend(lns, labs)

        plt.show()

    # Create interactive plot
    interactive_plot = widgets.interactive(update_plot,
                                           PH_SL=PH_SL_checkbox,
                                           PH_RL=PH_RL_checkbox,
                                           mlc_SL=mlc_SL_checkbox,
                                           mlc_RL=mlc_RL_checkbox,)

    display(interactive_plot)
[72]:
#Indexing issue - to be fixed (JAB 01/11)
V3_AGSN_list[0].name='1'
V3_AGSN_list[2].name='3'
plot_Result_ls_comparison(V3_AGSN_list[0], V3_AGSN_list[2])
The depiction of the interactive Widget plot does not work in the documentation, because a python kernel must run it. A screenshot of the interacitve plot is provided below. To interact with the plot, download and run the script.
[73]:
try:
    image = Image(filename=os.path.dirname(os.path.abspath(dxAndMxHelperFcts.__file__))+r"\Examples\Images\6_example5_differenceplot.png")
    display(image)
except:
    print('png not displayed')
_images/Example5_57_0.png

Recalculate initial condition

[74]:
# (Re-)Calculate initial condition
tree.write(m.SirCalcXmlFile)

# Call the function to perform the calculation
calculate(m)
Command ['C:\\3S\\SIR 3S\\SirCalc-90-14-02-10_Potsdam\\SirCalc.exe', 'c:\\users\\jablonski\\3s\\pt3s\\Examples\\WDExample5\\B1\\V0\\BZ1\\M-1-0-1.XML'] exited with 0.