Tutorial 8: Miscellaneous
This Tutorial demonstrates miscellaneous functions of the SIR3S_Model() class that cannot be assigned to one of the previous Tutorial topics.
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 (SirGraf) installation.
[5]:
wrapper.Initialize_Toolkit(SIR3S_SIRGRAF_DIR)
[2026-10-14 14:12:11,368] INFO in sir3stoolkit.core.wrapper: [Initialization] Using provided SirGraf path: C:\3S\SIR 3S\SirGraf-90-15-00-24_Quebec-Upd2
[2026-10-14 14:12:11,368] INFO in sir3stoolkit.core.wrapper: [Initialization] Using provided SirGraf path: C:\3S\SIR 3S\SirGraf-90-15-00-24_Quebec-Upd2
[2026-10-14 14:12:11,427] INFO in sir3stoolkit.core.wrapper: [Initialization] Initializing toolkit with SirGraf path: C:\3S\SIR 3S\SirGraf-90-15-00-24_Quebec-Upd2
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()
[2026-10-14 14:12:12,146] INFO in sir3stoolkit.core.wrapper: [Model Class Initialization] Initialization complete
[7]:
s3s_view = wrapper.SIR3S_View()
[2026-10-14 14:12:12,347] INFO in sir3stoolkit.core.wrapper: Initialization complete
Open Model
[8]:
dbFilePath=r"Toolkit_Tutorial8_Model.db3"
[9]:
s3s.OpenModel(dbName=dbFilePath,
providerType=s3s.ProviderTypes.SQLite,
Mid="M-1-0-1",
saveCurrentlyOpenModel=False,
namedInstance="",
userID="",
password="")
[2026-10-14 14:12:24,998] INFO in sir3stoolkit.core.wrapper: Model is open for further operation
Now the model has been opened and the previous one has been closed without saving it. All SIR 3S Toolkit commands now apply to this model until another one is opened.
[10]:
print(s3s.GetNetworkType()) # to check that the model is responsive
NetworkType.DistrictHeating
GetHydraulicProfileObjectString()
We can use the function GetHydraulicProfileObjectString() to obtain a string containing all pipe tks part of the longitudinal section.
[11]:
s3s.GetTksofElementType(s3s.ObjectTypes.AGSN_HydraulicProfile)
[11]:
['4999575369425665759']
[12]:
s3s.GetHydraulicProfileObjectString(tkAgsn="4999575369425665759")
[12]:
(True, '\tROHR~5222487322443009246\tROHR~5354178785470006283\n')
We can us regex to get clean list of the pipe tks.
[13]:
import re
[14]:
text = s3s.GetHydraulicProfileObjectString(tkAgsn="4999575369425665759")[1]
[15]:
tks = re.findall(r'ROHR~(\d+)', text)
[16]:
tks
[16]:
['5222487322443009246', '5354178785470006283']
GetCourseOfHydraulicProfile()
We can use the function GetCourseOfHydraulicProfile() to obtain a detailed output for longitudinal sections including branch considerations.
[17]:
hydraulicProfile = s3s.GetCourseOfHydraulicProfile(tkAgsn="4999575369425665759", uid="0")
[18]:
hydraulicProfile
[18]:
hydraulicProfile(childrenUID=<System.Collections.Generic.List[String] object at 0x0000029CF78D82C0>, nodesVL=<System.Collections.Generic.List[String] object at 0x0000029CF78D8200>, linksVL=<System.Collections.Generic.List[String] object at 0x0000029CF78D81C0>, xVL=<System.Collections.Generic.List[Double] object at 0x0000029CF78DBC00>, nodesRL=<System.Collections.Generic.List[String] object at 0x0000029CF78DBC80>, linksRL=<System.Collections.Generic.List[String] object at 0x0000029CF78DBD00>, xRL=<System.Collections.Generic.List[Double] object at 0x0000029CF78DBD80>, nrOfBranches=0, xOffSet=0.0, xOffsetRelativeToParent=0.0, length=493.5, tkArticulationNode='-1')
If we have more than one branch in our section we can use the uid parameter to differentiate between them. Otherwise “0” is sufficient.
As the lists that are part of the returned tuple remain NET objets we have to turn them into python lists.
[19]:
nodesVL = list(hydraulicProfile.nodesVL)
[20]:
nodesVL
[20]:
['4905524959962565243', '5517957656259932533', '4852293679410056753']
[21]:
linksVL = list(hydraulicProfile.linksVL)
[22]:
linksVL
[22]:
['5222487322443009246', '5354178785470006283']
[23]:
xVL = list(hydraulicProfile.xVL)
[24]:
xVL
[24]:
[0.0, 316.43719482421875, 493.4965362548828]
[25]:
hydraulicProfile.nrOfBranches
[25]:
0
[26]:
hydraulicProfile.length
[26]:
493.5
SetLogFilePath()
We can use the function SetLogFilePath() to change where the log file, created when SIR 3S executes calculations, is saved. It takes the full path of the log file, including the file name.
[27]:
import os
s3s.SetLogFilePath(os.path.join(os.getcwd(), "Tutorial8.log"))
[27]:
True
Set_Raise_On_Error()
When the SIR 3S Toolkit is used from a standalone Python process (like this notebook), errors reported by SIR 3S raise a SIR3S_ToolkitError. Inside SIR Graf they are only logged and the function returns a value indicating the failure (e.g. False, ‘-1’ or (‘’, ‘’)). Let’s try to set the log file path to a directory that does not exist.
[28]:
try:
s3s.SetLogFilePath("C:/does/not/exist/Tutorial8.log")
except wrapper.SIR3S_ToolkitError as e:
print(f"Caught: {e}")
[2026-10-14 14:12:25,778] ERROR in sir3stoolkit.core.wrapper: Error: DirectoryNotFoundException: Ein Teil des Pfades "C:\does\not\exist\Tutorial8.log" konnte nicht gefunden werden.
Caught: Error: DirectoryNotFoundException: Ein Teil des Pfades "C:\does\not\exist\Tutorial8.log" konnte nicht gefunden werden.
We can use the function Set_Raise_On_Error() to change this behavior: False only logs errors (the behavior inside SIR Graf), True always raises, None restores the default.
[29]:
wrapper.Set_Raise_On_Error(False)
s3s.SetLogFilePath("C:/does/not/exist/Tutorial8.log")
[2026-10-14 14:12:25,811] ERROR in sir3stoolkit.core.wrapper: Error: DirectoryNotFoundException: Ein Teil des Pfades "C:\does\not\exist\Tutorial8.log" konnte nicht gefunden werden.
[29]:
False
[30]:
wrapper.Set_Raise_On_Error(None)
Errors of core calls made inside mantle methods are always only logged, as the mantle handles them itself.
Note that not every invalid input is reported as an error by SIR 3S. Check the stored values with GetValue() (Tutorial 2) and run ExecuteModelValidation() (Tutorial 9) before relying on a model you built or changed.
EnableOrDisableOutputComments()
We can use the function EnableOrDisableOutputComments() to turn output comments on or off. Default is True.
[31]:
s3s.EnableOrDisableOutputComments(outputComments=True)
[32]:
print(s3s.InsertElement(s3s.ObjectTypes.Node, "-1"))
[2026-10-14 14:12:26,095] INFO in sir3stoolkit.core.wrapper: Element inserted successfully into the model with Tk: 5443648786860568132
5443648786860568132
[33]:
s3s.EnableOrDisableOutputComments(outputComments=False)
[34]:
print(s3s.InsertElement(s3s.ObjectTypes.Node, "-1"))
5663454685669646552
As you can see, after the output comments were disabled the function does not print an output. The printed tk is the return value of the function that is displayed in Jupyter Notebooks.
[35]:
s3s.EnableOrDisableOutputComments(outputComments=True)
AllowSirMessageBox()
We can use the function AllowSirMessageBox() to allow or diallow SIR DB Messages to pop up. Default is True. Generally, not recommeded to turn off, as it could mean missing out on deep error messages.
[36]:
s3s.AllowSirMessageBox(bAllow=True)
[37]:
dbFilePath2=r"Toolkit_Tutorial8_PotsdamVersionModel.db3"
We will try to open a model created in Potsdam Version of SIR 3S. A message window should pop up that asks whether you want the model to be migrated to your current SIR 3S version. Please choose to not migrate. The cell will fail to execute.
[38]:
s3s.OpenModel(dbName=dbFilePath2,
providerType=s3s.ProviderTypes.SQLite,
Mid="M-1-0-1",
saveCurrentlyOpenModel=False,
namedInstance="",
userID="",
password="")
---------------------------------------------------------------------------
SQLiteException Traceback (most recent call last)
Cell In[38], line 1
----> 1 s3s.OpenModel(dbName=dbFilePath2,
2 providerType=s3s.ProviderTypes.SQLite,
3 Mid="M-1-0-1",
4 saveCurrentlyOpenModel=False,
5 namedInstance="",
6 userID="",
7 password="")
File ~\3S\sir3stoolkit\src\sir3stoolkit\core\wrapper.py:671, in SIR3S_Model.OpenModel(self, dbName, providerType, Mid, saveCurrentlyOpenModel, namedInstance, userID, password)
647 """
648 Opens a model from a database file.
649
(...)
668 :description: This is a wrapper method for OpenModel() from toolkit; Watch out for errors for more information.
669 """
670 providerType_net = self.to_dotnet_enum(providerType)
--> 671 result, error = self.toolkit.OpenModel(dbName, providerType_net, Mid, saveCurrentlyOpenModel,
672 namedInstance, userID, password)
673 if result:
674 if self.outputComments:
SQLiteException: code = Error (1), message = System.Data.SQLite.SQLiteException (0x800007BF): SQL logic error
no such table: USCH
bei System.Data.SQLite.SQLite3.Prepare(SQLiteConnection cnn, String strSql, SQLiteStatement previous, UInt32 timeoutMS, String& strRemain)
bei System.Data.SQLite.SQLiteCommand.BuildNextCommand()
bei System.Data.SQLite.SQLiteDataReader.NextResult()
bei System.Data.SQLite.SQLiteDataReader..ctor(SQLiteCommand cmd, CommandBehavior behave)
bei System.Data.SQLite.SQLiteCommand.ExecuteReader(CommandBehavior behavior)
bei System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, DataTable[] datatables, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)
bei System.Data.Common.DbDataAdapter.Fill(DataSet dataSet, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)
bei System.Data.Common.DbDataAdapter.Fill(DataSet dataSet, String srcTable)
bei Sir3S_Repository.DataBaseModel.CDbTableTypeA.FillDataSet(DbDataAdapter dbDataAdapter, String fkBa, String fkVa, String fkBz, Int32& iTables)
bei Sir3S_Repository.DataBaseModel.CDataBase.FillDataSet(DbDataAdapter dbDataAdapter, IModel iModel)
bei Sir3S_Repository.DataSetModel.CModelDs.Open(IModel iModel, Boolean& modelWasInUse)
bei Sir3S_Repository.ModelManager.CModelManagerModelListEvents.OpenModel(IDialog iDialog, IModelInfo iModelInfo, Boolean& modelWasInUse)
bei Sir3S_Repository.ModelManager.CModelManager.OpenModel(IModel Model, Boolean& modelWasInUse)
bei Sir3S_Toolkit.Model.CSir3SToolkitModel.OpenModel(String dbName, SirDBProviderType providerType, String Mid, Boolean saveCurrentlyOpenModel, String namedInstance, String userID, String password, String& error)
Now we will attempt the same but with message boxes turned off.
[39]:
s3s.AllowSirMessageBox(bAllow=False)
[40]:
s3s.OpenModel(dbName=dbFilePath2,
providerType=s3s.ProviderTypes.SQLite,
Mid="M-1-0-1",
saveCurrentlyOpenModel=False,
namedInstance="",
userID="",
password="")
[2026-10-14 14:14:06,187] INFO in sir3stoolkit.core.wrapper: Model is open for further operation
As you can see in your file explorer this time the model was migrated without asking. In general during model creation/opening the message boxes should be left on.
This method also works if you want to open a model just to view it, while it is already open in SIR Graf.