Tutorial 3: Calculating and Accessing results

This tutorial demonstrates how to execute calculations and access their results.

SIR 3S Installation

[1]:
SIR3S_SIRGRAF_DIR = r"C:\3S\SIR 3S\SirGraf-90-15-00-24_Quebec-Upd2" #change to local path

Imports

Note: The SIR 3S Toolkit requires the Sir3S_Toolkit.dll included in SIR 3S installations (version Quebec and higher).

[2]:
import sir3stoolkit

The core of sir3stoolkit is a Python wrapper around basic functionality of SIR 3S, offering a low-level access to the creation, modification and simulation of SIR 3S models. In the future pure python subpackages may be added.

[3]:
from sir3stoolkit.core import wrapper
[4]:
sir3stoolkit
[4]:
<module 'sir3stoolkit' from 'C:\\Users\\aUsername\\3S\\sir3stoolkit\\src\\sir3stoolkit\\__init__.py'>

The wrapper package has to be initialized with reference to a SIR 3S (SIR Graf) installation.

[5]:
wrapper.Initialize_Toolkit(SIR3S_SIRGRAF_DIR)

Initialization

The SIR 3S Toolkit contains two classes: SIR3S_Model (model and data) and SIR3S_View (depiction in SIR Graf). All SIR 3S Toolkit functionality is accessed via the methods of these classes.

[6]:
s3s = wrapper.SIR3S_Model()
Initialization complete
[7]:
s3s_view = wrapper.SIR3S_View()
Initialization complete

Open Model

[8]:
dbFilePath=r"Toolkit_Tutorial3_Model.db3"
[9]:
s3s.AllowSirMessageBox(bAllow=False) # If you encounter problems with a message box popping up when opening the model, this surpresses this
[10]:
s3s.OpenModel(dbName=dbFilePath,
              providerType=s3s.ProviderTypes.SQLite,
              Mid="M-1-0-1",
              saveCurrentlyOpenModel=False,
              namedInstance="",
              userID="",
              password="")
Model is open for further operation

Now the model has been opened. All SIR 3S Toolkit operations now apply to this model until another one is opened.

[ ]:
print(s3s.GetNetworkType()) # to check that the correct model is responsive, model we are trying to open was created with type Water
NetworkType.Water

Calculation()

We use the ExecCalculation() function to trigger a new Calculation of the SIR 3S Model using SIR Calc (version that is specfied in the components of the SIR Graf, that was used to initialize the Toolkit).

[ ]:
#s3s.ExecCalculation(waitForSirCalcToExit=True)

We can check the status of the calculation

[ ]:
Exit_status = s3s.GetResultValue(s3s.GetTksofElementType(s3s.ObjectTypes.GeneralSection)[0],"EXSTAT")[0]
[ ]:
print(Exit_status)
0

German Interpretation:

  • -1=undefiniert

  • 0=normal

  • 1=Benutzerabbruch

  • 2=fragwürdige Ergebnisse

  • 3=schlechte oder ungültige Ergebnisse

  • 100=Ergebnisse halten für Analyse

  • 101=Stopp-Signal für Analyse

English Interpretation:

  • -1=undefined

  • 0=normal

  • 1=user-interrupt

  • 2=questionable results

  • 3=bad or invald result

  • 100=holding results for analysis

  • 101=stop-signal for analysis

Our results are normal.

Automatic Parametrized Notebook Execution

The Python package Papermill allows users to parameterize Jupyter notebooks—for example by injecting different time references or simulation settings—and then execute the same notebook repeatedly with varying parameter values. Each run is saved as a separate output notebook, preserving both inputs and results. This makes Papermill an efficient tool for automating SIR 3S model calculations, enabling users to evaluate a model for multiple simulation times or scenarios without manually editing and re-running notebooks.

Get Result Values

Our goal is to find how the pressure value in Node10 changes from 12:00 to 12:05.

The GetResultValue() function requires a tk to the object and the internal SIR 3S attribute name of the value we want to obtain. This guide will walk you through how to obtain those.

SIR 3S object types

As we did with non-result values, we need to obtain the internal SIR 3S object types to be passed to our function for obtaining the attribute names.

[ ]:
node_type=s3s.ObjectTypes.Node
[ ]:
pipe_type=s3s.ObjectTypes.Pipe
[ ]:
pump_type = s3s.ObjectTypes.Pump
[ ]:
container_type = s3s.ObjectTypes.OpenContainer

Find the node of interest

As we did with non-result values, we obtain the tks of the nodes and pipes in this model.

We use GetTksofElementType() to create a list of all node tks in the model.

[ ]:
nodes=s3s.GetTksofElementType(ElementType=node_type)
[ ]:
for node in nodes:
    if(s3s.GetValue(node, 'Name')[0]=='K0011'):
        tk_of_interest=s3s.GetValue(node, 'tk')[0]
[ ]:
print(tk_of_interest)
5028478813255134383

GetResultProperties_from_elementTypes

Similar to non-result values, we use GetResultProperties_from_elementTypes() to create a list of all result properties of the different objects that exist in our model.

[ ]:
node_result_properties=s3s.GetResultProperties_from_elementType(elementType=node_type, onlySelectedVectors=False)
[ ]:
print(node_result_properties)
['BCIND', 'BCIND_CALC', 'BCIND_FLOW', 'BCIND_MODEL', 'BCIND_SOURCE', 'BCIND_TYPE', 'CHLORID', 'CP', 'DP', 'DPH', 'DYNVISKO', 'EH', 'EISENFILT', 'EISENGES', 'ESQUELLSP', 'FITT_ANGLE', 'FITT_BASTYPE', 'FITT_DP1', 'FITT_DP2', 'FITT_DP3', 'FITT_STATE', 'FITT_SUBTYPE', 'FITT_VBTYPE1', 'FITT_VBTYPE2', 'FITT_VBTYPE3', 'FITT_ZETA1', 'FITT_ZETA2', 'FITT_ZETA3', 'FSTF_NAME', 'GMIX_NAME', 'H', 'HI', 'HMAX_INST', 'HMIN_INST', 'HS', 'IAKTIV', 'INDUV', 'K', 'KP', 'KT', 'LEITFAEH', 'LFAKTAKT', 'LFKT', 'M', 'MAINELEMENT', 'MN', 'P', 'PDAMPF', 'PH', 'PH_EIN', 'PH_MIN', 'PHMINMAXDIF', 'PHWERT', 'PMAX_INST', 'PMIN_INST', 'PVAR', 'Q2', 'QM', 'QMABS', 'QVAR', 'RHO', 'RHON', 'RHONQUAL', 'SULFAT', 'T', 'TE', 'TEMP', 'TMAX_INST', 'TMIN_INST', 'TTR', 'VOLD', 'WALTER', 'ZHKNR']
[ ]:
pipe_result_properties=s3s.GetResultProperties_from_elementType(elementType=pipe_type, onlySelectedVectors=False)
[ ]:
print(pipe_result_properties)
['A', 'ACALC', 'CPI', 'CPK', 'DH', 'DP', 'DRAGRED', 'DRAKONZ', 'DSI', 'DSK', 'DTTR', 'DWVERL', 'DWVERLABS', 'ETAAV', 'FS', 'HR', 'HVEC', 'IAKTIV', 'IRTRENN', 'JV', 'JV2', 'LAMBDA', 'LECKEINAUS', 'LECKMENGE', 'LECKORT', 'LINEPACK', 'LINEPACKGEOM', 'LINEPACKRATE', 'MAINELEMENT', 'MAV', 'MI', 'MK', 'MKOND', 'MMAX_INST', 'MMIN_INST', 'MVEC', 'MVECMAX_INST', 'MVECMIN_INST', 'PAV', 'PDAMPF', 'PHR', 'PHVEC', 'PMAX', 'PMIN', 'PR', 'PVEC', 'PVECMAX_INST', 'PVECMIN_INST', 'QI2', 'QK2', 'QMAV', 'QMI', 'QMK', 'QMMAX_INST', 'QMMIN_INST', 'QMVEC', 'QSVB', 'RHOAV', 'RHOI', 'RHOK', 'RHOVEC', 'SVEC', 'TAV', 'TI', 'TK', 'TTRVEC', 'TVEC', 'TVECMAX_INST', 'TVECMIN_INST', 'VAV', 'VI', 'VK', 'VMAX_INST', 'VMIN_INST', 'VOLDA', 'WALTERI', 'WALTERK', 'WVL', 'ZAUS', 'ZEIN', 'ZHKNR', 'ZVEC']
[ ]:
pump_result_properties=s3s.GetResultProperties_from_elementType(elementType=pump_type, onlySelectedVectors=False)
[ ]:
print(pump_result_properties)
['BK', 'DH', 'DP', 'DPH', 'EINAUS', 'ETA', 'ETAW', 'IAKTIV', 'IND', 'M', 'MAINELEMENT', 'MOM', 'N', 'NMINMAXDIF', 'NPSH', 'NPSHDIF', 'NPSHMIN', 'NSOLLTURB', 'PA', 'PE', 'PE_RUECK', 'PHSOLL', 'PP', 'PUMD', 'QM', 'QMSOLL', 'QMSOLLTURB', 'QN0', 'RCPU_IND', 'RCPU_W', 'RCPU_X', 'RCPU_XD', 'RHO', 'STOERUNG', 'SWVT']
[ ]:
tank_result_properties=s3s.GetResultProperties_from_elementType(elementType=container_type, onlySelectedVectors=False)
[ ]:
print(tank_result_properties)
['DWST_DT', 'IAKTIV', 'M', 'MAINELEMENT', 'MEXT', 'QM', 'QMEXT', 'RHO', 'T', 'T0', 'V', 'VOL', 'WALTER', 'WALTER0', 'WST', 'WST0']

GetResultProperties_from_elementKey

Alternatively, we can use GetResultProperties_from_elementKey() to create a list of all result properties of one one specific object based on its tk.

[ ]:
node_result_properties_alternative=s3s.GetResultProperties_from_elementKey(elementKey=nodes[0])
[ ]:
print(node_result_properties_alternative)
['BCIND', 'FITT_BASTYPE', 'FITT_DP1', 'FITT_DP2', 'FITT_DP3', 'FITT_STATE', 'H', 'IAKTIV', 'INDUV', 'LFAKTAKT', 'P', 'PDAMPF', 'PH', 'PH_EIN', 'PH_MIN', 'PHMINMAXDIF', 'QM', 'RHO', 'T', 'TTR', 'VOLD']

Timestamps

The GetResultValue() function gives the value corresponding to the currently selected timestamp for the model. You can check the current timestamp using GetCurrentTimeStamp() and change it using SetCurrentTimeStamp().

[ ]:
s3s.GetCurrentTimeStamp()
'2025-07-18 12:00:00.000 +02:00'

We can check what Timestamps are available in this model using GetTimeStamps(). The function returns a tuple (list[str], str, str, str) with all simulation timestamps, tsStat, tsMin, tsMax.

[ ]:
available_timestamps=s3s.GetTimeStamps()
[ ]:
print(available_timestamps)
(['2025-07-18 12:00:00.000 +02:00', '2025-07-18 12:01:00.000 +02:00', '2025-07-18 12:02:00.000 +02:00', '2025-07-18 12:03:00.000 +02:00', '2025-07-18 12:04:00.000 +02:00', '2025-07-18 12:05:00.000 +02:00'], '2025-07-18 12:00:00.000 +02:00', '', '')

available_timestamps = [[simulation timestamps], static timestamp, min timestamp, max timestamp]

[ ]:
s3s.SetCurrentTimeStamp(timestamp=available_timestamps[0][1]) # second simulation step
[ ]:
s3s.GetCurrentTimeStamp() # Check whether the change worked
'2025-07-18 12:01:00.000 +02:00'

GetResultValue()

Now we can obtain the pressure value for one of our nodes at two different timestamps

[ ]:
s3s.GetCurrentTimeStamp()
'2025-07-18 12:01:00.000 +02:00'
[ ]:
pressure1=s3s.GetResultValue(elementKey=tk_of_interest, propertyName='P')[0]
[ ]:
print(pressure1)
11

Manually moving the timestamp forward by three minutes:

[ ]:
s3s.SetCurrentTimeStamp(timestamp=available_timestamps[0][4])
[ ]:
s3s.GetCurrentTimeStamp() # Check whether the change worked
'2025-07-18 12:04:00.000 +02:00'
[ ]:
pressure2=s3s.GetResultValue(elementKey=tk_of_interest, propertyName='P')[0]
[ ]:
print(pressure2)
26

Alternatively, the result can be obtained with the single, compact GetResultfortimestamp() function.

[ ]:
pressure2=s3s.GetResultfortimestamp(timestamp=available_timestamps[0][4], Tk=tk_of_interest, property='P')[0]
[ ]:
print(f"Difference in Pressure 12:01 to 12:04: {float(pressure1)-float(pressure2)} bar")
Difference in Pressure 12:01 to 12:04: -15.0 bar

We determined a pressure drop between the two timestamps.

The pressure values for the respective node for all timestamps can be obtained using the GetResultforAllTimestamp()funtion.

[ ]:
s3s.GetResultforAllTimestamp(Tk=tk_of_interest, property='P')
[('2025-07-18 12:00:00.000 +02:00', '6', 'float'),
 ('2025-07-18 12:01:00.000 +02:00', '11', 'float'),
 ('2025-07-18 12:02:00.000 +02:00', '16', 'float'),
 ('2025-07-18 12:03:00.000 +02:00', '21', 'float'),
 ('2025-07-18 12:04:00.000 +02:00', '26', 'float'),
 ('2025-07-18 12:05:00.000 +02:00', '21', 'float')]

GetMax/MinResult()

The GetMinResult() and GetMaxResult() functions return the min/max result value for a given property and element type over all timestamps.

[ ]:
s3s.GetMinResult(elementType=node_type, propertyName='P')
('2.980399', '5335506849591751028', 'float')

We can see the the minimal pressure value over all nodes and timestamps.

[ ]:
s3s.GetMaxResult(elementType=node_type, propertyName='P')
('21', '5196977599086967050', 'float')

We can see the the minimal pressure value over all nodes and timestamps.

GetMax/MinResult_for_timestamp()

The GetMinResult_for_timestamp() and GetMaxResult_for_timestamp() functions return the min/max result value for a given property, element type and timestamp.

[ ]:
s3s.GetMinResult_for_timestamp(timestamp='2025-07-18 12:01:00.000 +02:00', elementType=node_type, propertyName='P')
('2.663651', '5335506849591751028', 'float')
[ ]:
s3s.GetMinResult_for_timestamp(timestamp='2025-07-18 12:01:00.000 +02:00', elementType=node_type, propertyName='P')
('2.663651', '5335506849591751028', 'float')

We an observe that the min pressure value over all nodes stays the same from 1 to 4 minutes and occurs at the same node.

[ ]:
max_pressure1=s3s.GetMaxResult_for_timestamp(timestamp='2025-07-18 12:01:00.000 +02:00', elementType= node_type, propertyName='P')
[ ]:
max_pressure2=s3s.GetMaxResult_for_timestamp(timestamp='2025-07-18 12:04:00.000 +02:00',elementType=node_type, propertyName='P')
[ ]:
print(f"Max Pressure 12:01: {max_pressure1[0]} bar at {max_pressure1[1]} compared to 12:04: {max_pressure2[0]} bar at {max_pressure2[1]}.")
Max Pressure 12:01: 11 bar at 5196977599086967050 compared to 12:04: 26 bar at 5196977599086967050.

Next: Tutorial 4: Editing a SIR 3S model safely and effectively