Tutorial 6: Insert and Connect Elements

This Tutorial demonstrates how new elements such as nodes, pipes, tanks, valves, etc. can be inserted into a SIR 3S model and connected.

SIR 3S Installation

[1]:
SIR3S_SIRGRAF_DIR = r"C:\3S\SIR 3S Entwicklung\SirGraf-90-15-00-16_Quebec_x64" #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)

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

Create Model

[8]:
dbFilePath=r"Toolkit_Tutorial6_Model.db3"
[9]:
s3s.NewModel(dbName=dbFilePath,
             providerType=s3s.ProviderTypes.SQLite,
             namedInstance="",
             netType=s3s.NetworkType.DistrictHeating,
             modelDescription="Tutorial 6 Model",
             userID="",
             password="")
New model is created with the model identifier: M-6-0-1

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 correct model is responsive, model we are trying to open was created with type Undefined
NetworkType.DistrictHeating

SIR 3S object types

[11]:
object_types = [item for item in dir(s3s.ObjectTypes) if not (item.startswith('__') and item.endswith('__'))]
print(object_types)
['AGSN_HydraulicProfile', 'AirVessel', 'Arrow', 'Atmosphere', 'BlockConnectionNode', 'CalcPari', 'CharacteristicLossTable', 'CharacteristicLossTable_Row', 'Circle', 'Compressor', 'CompressorTable', 'CompressorTable_Row', 'ControlEngineeringNexus', 'ControlMode', 'ControlPointTable', 'ControlPointTable_Row', 'ControlValve', 'ControlVariableConverter', 'ControlVariableConverterRSTE', 'CrossSectionTable', 'CrossSectionTable_Row', 'DPGR_DPKT_DatapointDpgrConnection', 'DPGR_DataPointGroup', 'DPKT_Datapoint', 'DamageRatesTable', 'DamageRatesTable_Row', 'DeadTimeElement', 'Demand', 'DifferentialRegulator', 'DirectionalArrow', 'DistrictHeatingConsumer', 'DistrictHeatingFeeder', 'Divider', 'DriveEfficiencyTable', 'DriveEfficiencyTable_Row', 'DrivePowerTable', 'DrivePowerTable_Row', 'EBES_FeederGroups', 'EfficiencyConverterTable', 'EfficiencyConverterTable_Row', 'ElementQuery', 'EnergyRecoveryTable', 'EnergyRecoveryTable_Row', 'EnvironmentTemp', 'FWBZ_DistrictHeatingReferenceValues', 'FlapValve', 'FlowControlUnit', 'FluidQualityParamSet', 'FluidQualityParamSet_OS', 'FluidThermalPropertyGroup', 'FreeDuct', 'FunctionGenerator', 'FunctionTable', 'FunctionTable_Row', 'GasComponent', 'GasMixture', 'GeneralSection', 'Gravitation', 'HeatExchanger', 'HeatFeederConsumerStation', 'HeaterCooler', 'Histeresis', 'House', 'Hydrant', 'Integrator', 'LAYR_Layer', 'LoadFactorTable', 'LoadFactorTable_Row', 'LogicalComparison', 'LogicalStorage', 'MeasuredVariableTable', 'MeasuredVariableTable_Row', 'MinMaxSelection', 'Multiplier', 'NetValve', 'Node', 'NonReturnValvesTable', 'NonReturnValvesTable_Row', 'NumericalDisplay', 'ObjectContainerSymbol', 'OpenContainer', 'Oval', 'PARZ_TransientCalculationParameters', 'PhaseSeparation', 'PidController', 'Pipe', 'PipeGroup', 'PipeTable', 'PipeTable_Row', 'PipeVertex', 'Polygon', 'Polyline', 'PressureRegulator', 'PressureZone', 'Pt1Controller', 'Pump', 'PumpCharTable', 'PumpCharTable_Row', 'PumpGroup', 'PumpOfPumpGroup', 'PumpSpeedTable', 'PumpSpeedTable_Row', 'RART_ControlMode', 'REGP_ControlParameters', 'RMES_DPTS_RmesInternalDataPoint', 'Rectangle', 'RegulatorsTable', 'RegulatorsTable_Row', 'ReturnTemperaturTable', 'ReturnTemperaturTable_Row', 'RoundRectangle', 'SIRGRAF', 'SPLZ_TimeSeries', 'SafetyValve', 'SetpointDevice', 'SolarCollector', 'StandPipe', 'Street', 'SummingPoint', 'SwitchInBlock', 'TemperatureTable', 'TemperatureTable_Row', 'Text', 'ThermalOutputTable', 'ThermalOutputTable_Row', 'ThermophysPropTable', 'ThermophysPropTable_Row', 'TransitionSymbol', 'Transmitter', 'TransportVariable', 'USCH_UserDefinedProperties', 'Unknown', 'VARA_ColorScale', 'VARA_ROWS_WidthOrScale', 'VRCT_ViewRectangle', 'Valve', 'ValveLiftTable', 'ValveLiftTable_Row', 'VarFlowTable', 'VarFlowTable_Row', 'VarPressureTable', 'VarPressureTable_Row', 'VentOpenCloseTable', 'VentOpenCloseTable_Row', 'VentValve', 'VentilatedPressureAirVessel', 'WBLZ_ThermalBalance', 'WeatherDataTable', 'WeatherDataTable_Row']

InsertElement() - Generic Element Creation

We use the InsertElement() function with the SIR 3S datatype and IdRef value (we just use default “-1”).

Let’s just create two nodes: one connected to a tank and the other for now just a free end connected via a pipe to the first node.

Containers

In SIR 3S every element exists in a specific container. If the container is not specified when creating the element it will be inserted in to the main container.

[12]:
container_A=s3s.InsertElement(s3s.ObjectTypes.ObjectContainerSymbol, IdRef="")
Element inserted successfully into the model with Tk: 5008034218814138857

Here we should define the container A using SetValue(), but for simplicity let’s leave that out.

Nodes

[13]:
nodeKI=s3s.InsertElement(ElementType=s3s.ObjectTypes.Node, IdRef ="-1")
Element inserted successfully into the model with Tk: 5370202525391386318
[14]:
nodeKK=s3s.InsertElement(ElementType=s3s.ObjectTypes.Node, IdRef ="-1")
Element inserted successfully into the model with Tk: 5217089350860543576

Pipe - Connecting Element

We again use InsertElement() function to create a new element in this case a pipe. Then we connect both nodes with the pipe using the ConnectConnectingElementWithNodes() function.

[15]:
pipe=s3s.InsertElement(ElementType=s3s.ObjectTypes.Pipe, IdRef ="-1")
Element inserted successfully into the model with Tk: 5356888914134614362
[16]:
s3s.ConnectConnectingElementWithNodes(Tk=pipe, keyOfNodeI=nodeKI, keyOfNodeK=nodeKK)
Objects connected successfully

Tank - Bypass Element

We again use InsertElement() to create a new element in this case a tank. Then we connect the KI node with the tank using the ConnectBypassElementWithNode() function.

[17]:
tank=s3s.InsertElement(ElementType=s3s.ObjectTypes.OpenContainer, IdRef ="-1")
Element inserted successfully into the model with Tk: 5372199443253516317
[18]:
s3s.ConnectBypassElementWithNode(Tk=tank, keyOfNodeI=nodeKI)
Object connected successfully

Assign Property Values

Now we have created this basic network, but it lacks defined geometry, material, supplier data. We can use the SetValue() function from Tutorial 3 to assin those values.

[19]:
s3s.SetValue(Tk=nodeKI, propertyName="Xkor", Value="100")
s3s.SetValue(Tk=nodeKI, propertyName="Ykor", Value="100")
s3s.SetValue(Tk=nodeKI, propertyName="Ktyp", Value="PKON")
s3s.SetValue(Tk=nodeKI, propertyName="Ktyp", Value="PKON")
Value is set
Value is set
Value is set
Value is set

… and so on for both nodes

[20]:
s3s.SetValue(Tk=pipe, propertyName="Kvr", Value="1")
s3s.SetValue(Tk=pipe, propertyName="L", Value="10")
Value is set
Value is set

… and so on for the pipe and also the tank

Assign to container A

The InsertElement() function inserts elements into the main container. Let’s try to move all elements created so far into the container A we created.

[21]:
s3s.SetValue(Tk=nodeKI, propertyName="fkCont", Value=container_A)
Value is set
[22]:
s3s.SetValue(Tk=nodeKK, propertyName="fkCont", Value=container_A)
Value is set
[23]:
s3s.SetValue(Tk=pipe, propertyName="fkCont", Value=container_A)
Value is set

GetMainContainer()

We can use the GetMainContainer() function to obtain the tk of the main container.

[24]:
main_container=s3s.GetMainContainer()[0]
[25]:
print(main_container)
5404784316484532375

IsMainContainer()

We can use the IsMainContainer() function to check whether the provided FkCont equals the FkCont obtained by GetMainContainer().

[26]:
s3s.IsMainContainer(fkCont=container_A)
[26]:
False
[27]:
s3s.IsMainContainer(fkCont=main_container)
[27]:
True
[28]:
s3s.IsMainContainer(s3s.GetValue(Tk=nodeKI, propertyName="fkCont")[0])
[28]:
False

We can see that nodKI is not in the main container as we moved it to the container A.

[29]:
s3s.SetValue(Tk=nodeKI, propertyName="fkCont", Value=s3s.GetMainContainer()[0])
Value is set
[30]:
s3s.IsMainContainer(s3s.GetValue(Tk=nodeKI, propertyName="fkCont")[0])
[30]:
True

But we can move it back.

GetNumberOfElements

As a side note. We can use the GetNumberOfElements() function to get the number of all elements existing in our model of a specified datatype

[31]:
print(s3s.GetNumberOfElements(ElementType=s3s.ObjectTypes.Node))
2

DeleteElement()

Let’s delete all Elements we have created so far.

[32]:
s3s.DeleteElement(Tk=nodeKI)
Element deleted successfully
[33]:
s3s.DeleteElement(Tk=nodeKK)
Element deleted successfully

Now we can check how many nodes still exist.

[34]:
print(s3s.GetNumberOfElements(ElementType=s3s.ObjectTypes.Node))
0
[35]:
s3s.DeleteElement(Tk=pipe)
Element deleted successfully
[36]:
s3s.DeleteElement(Tk=tank)
Element deleted successfully

Specific Element Creation

The approach used above is tedious. Therefore more specific functions exists for the insertion of elements of certain data types which contain specific paramters for that type.

Let’s try to build a more complex model this time. It is equivalent to Network 1. We will use template for editing models from Tutorial 5.

AddNewNode()

We use the AddNewNode() function to insert several nodes. We can already specify many properties such as geometry, node type, kvr, etc..

[37]:
s3s.StartTransaction("Inserting Nodes")

node10 = s3s.AddNewNode(tkCont="-1", name="Node10", typ="QKON", x=200, y=700, z=213, qm_PH=0, symbolFactor=1, description="DNODE 10", idRef="RefNode 10", kvr=0)
node11 = s3s.AddNewNode(tkCont="-1", name="Node11", typ="QKON", x=300, y=700, z=213, qm_PH=0, symbolFactor=1, description="DNODE 11", idRef="RefNode 11", kvr=0)
node12 = s3s.AddNewNode(tkCont="-1", name="Node12", typ="QKON", x=500, y=700, z=210, qm_PH=0, symbolFactor=1, description="DNODE 12", idRef="RefNode 12", kvr=0)
node13 = s3s.AddNewNode(tkCont="-1", name="Node13", typ="QKON", x=700, y=700, z=208.5, qm_PH=0, symbolFactor=1, description="DNODE 13", idRef="RefNode 13", kvr=0)
node21 = s3s.AddNewNode(tkCont="-1", name="Node21", typ="QKON", x=300, y=400, z=210, qm_PH=0, symbolFactor=1, description="DNODE 21", idRef="RefNode 21", kvr=0)
node22 = s3s.AddNewNode(tkCont="-1", name="Node22", typ="QKON", x=500, y=400, z=208.5, qm_PH=0, symbolFactor=1, description="DNODE 22", idRef="RefNode 22", kvr=0)
node23 = s3s.AddNewNode(tkCont="-1", name="Node23", typ="QKON", x=700, y=400, z=207, qm_PH=0, symbolFactor=1, description="DNODE 23", idRef="RefNode 23", kvr=0)
node31 = s3s.AddNewNode(tkCont="-1", name="Node31", typ="QKON", x=300, y=100, z=210, qm_PH=0, symbolFactor=1, description="DNODE 31", idRef="RefNode 31", kvr=0)
node32 = s3s.AddNewNode(tkCont="-1", name="Node32", typ="QKON", x=500, y=100, z=213, qm_PH=0, symbolFactor=1, description="DNODE 32", idRef="RefNode 32", kvr=0)
node9 = s3s.AddNewNode(tkCont="-1", name="Node9", typ="PKON", x=150, y=700, z=255, qm_PH=0, symbolFactor=1, description="PNODE 9", idRef="RefNode 9", kvr=0)
node2 = s3s.AddNewNode(tkCont="-1", name="Node2", typ="QKON", x=500, y=850, z=240, qm_PH=0, symbolFactor=1, description="Tank 2", idRef="RefNode 2", kvr=0)

s3s.EndTransaction()
s3s.SaveChanges()
s3s.RefreshViews()
Now you can make changes to the model
New node added
New node added
New node added
New node added
New node added
New node added
New node added
New node added
New node added
New node added
New node added
Transaction has ended. Please open up a new transaction if you want to make further changes
Changes saved successfully
Refresh successful

AddNewPipe()

We use the AddNewPipe() function to insert new pipes. This time there is no need for a seperate function to connect it to nodes, and many properties such as geometry, material, kvr, etc. are already set in this function.

[38]:
s3s.StartTransaction("Inserting Pipes")

pipeA = s3s.AddNewPipe(tkCont="-1", tkFrom=node10, tkTo=node11, L=3160, linestring="LINESTRING(200 700, 300, 700)", material="STDROHR", dn="450", roughness=0.25, idRef="Ref Pipe 10", description="Pipe from Pump to network", kvr=0)
pipeB = s3s.AddNewPipe(tkCont="-1", tkFrom=node11, tkTo=node12, L=1584, linestring="LINESTRING(300 700, 500, 700)", material="STDROHR", dn="350", roughness=0.25, idRef="Ref Pipe 11", description="Pipe from 11 to 12", kvr=0)
pipeC = s3s.AddNewPipe(tkCont="-1", tkFrom=node12, tkTo=node13, L=1584, linestring="LINESTRING(500 700, 700, 700)", material="STDROHR", dn="250", roughness=0.25, idRef="Ref Pipe 12", description="Pipe from 12 to 13", kvr=0)
pipeD = s3s.AddNewPipe(tkCont="-1", tkFrom=node21, tkTo=node22, L=1584, linestring="LINESTRING(300 400, 500, 400)", material="STDROHR", dn="250", roughness=0.25, idRef="Ref Pipe 21", description="Pipe from 21 to 22", kvr=0)
pipeE = s3s.AddNewPipe(tkCont="-1", tkFrom=node22, tkTo=node23, L=1584, linestring="LINESTRING(500 400, 700, 400)", material="STDROHR", dn="300", roughness=0.25, idRef="Ref Pipe 22", description="Pipe from 22 to 23", kvr=0)
pipeF = s3s.AddNewPipe(tkCont="-1", tkFrom=node31, tkTo=node32, L=1584, linestring="LINESTRING(300 100, 500, 100)", material="STDROHR", dn="150", roughness=0.25, idRef="Ref Pipe 31", description="Pipe from 31 to 32", kvr=0)
pipeG = s3s.AddNewPipe(tkCont="-1", tkFrom=node2, tkTo=node12, L=60, linestring="LINESTRING(500 850, 500, 700)", material="STDROHR", dn="450", roughness=0.25, idRef="Ref Pipe 110", description="Pipe from Tank to network", kvr=0)
pipeH = s3s.AddNewPipe(tkCont="-1", tkFrom=node11, tkTo=node21, L=1584, linestring="LINESTRING(300 700, 300, 400)", material="STDROHR", dn="250", roughness=0.25, idRef="Ref Pipee 111", description="Pipe from 11 to 21", kvr=0)
pipeI = s3s.AddNewPipe(tkCont="-1", tkFrom=node12, tkTo=node22, L=1584, linestring="LINESTRING(500 700, 500, 400)", material="STDROHR", dn="300", roughness=0.25, idRef="Ref Pipee 112", description="Pipe from 12 to 22", kvr=0)
pipeJ = s3s.AddNewPipe(tkCont="-1", tkFrom=node13, tkTo=node23, L=1584, linestring="LINESTRING(700 700, 700, 400)", material="STDROHR", dn="200", roughness=0.25, idRef="Ref Pipee 113", description="Pipe from 13 to 32", kvr=0)
pipeK = s3s.AddNewPipe(tkCont="-1", tkFrom=node21, tkTo=node31, L=1584, linestring="LINESTRING(300 400, 300, 100)", material="STDROHR", dn="200", roughness=0.25, idRef="Ref Pipee 121", description="Pipe from 21 to 31", kvr=0)
pipeL = s3s.AddNewPipe(tkCont="-1", tkFrom=node22, tkTo=node32, L=1584, linestring="LINESTRING(500 400, 500, 100)", material="STDROHR", dn="150", roughness=0.25, idRef="Ref Pipee 122", description="Pipe from 22 to 32", kvr=0)

s3s.EndTransaction()
s3s.SaveChanges()
s3s.RefreshViews()
Now you can make changes to the model
New pipe added
New pipe added
New pipe added
New pipe added
New pipe added
New pipe added
New pipe added
New pipe added
New pipe added
New pipe added
New pipe added
New pipe added
Transaction has ended. Please open up a new transaction if you want to make further changes
Changes saved successfully
Refresh successful

AddNewConnectingElement()

We use the AddNewConnectingElement() function to insert a new pump. This time there is no need for a seperate function to connect it to nodes. As this function covers more than just one element type it is not as specific as the previous two.

[39]:
s3s.StartTransaction("Insert Pump")

pump=s3s.AddNewConnectingElement(tkCont="-1", tkFrom=node9, tkTo=node10, x=175, y=700, z=0, elementType=s3s.ObjectTypes.Pump, dn=200, symbolFactor=1, angleDegree=0, idRef="Pumpe", description="standard pump")

s3s.EndTransaction()
s3s.SaveChanges()
s3s.RefreshViews()
Now you can make changes to the model
New connecting element added
Transaction has ended. Please open up a new transaction if you want to make further changes
Changes saved successfully
Refresh successful

AddNewBypassElement()

We use the AddNewBypassElement() function to insert a new tank. This time there is no need for a seperate function to connect it to a node. As this function covers more than just one element type it is not that specific just like the previous one.

[40]:
s3s.StartTransaction("Insert Pump")

tank=s3s.AddNewBypassElement(tkCont="-1", tkFrom=node2, x=500, y=850, z=255, symbolFactor=1, elementType=s3s.ObjectTypes.OpenContainer, idRef="Tank", description="Storage tank")

s3s.EndTransaction()
s3s.SaveChanges()
s3s.RefreshViews()
Now you can make changes to the model
New Bypass element added
Transaction has ended. Please open up a new transaction if you want to make further changes
Changes saved successfully
Refresh successful

GetEndNodes()

As a side note: we can use the GetEndNodes() function to get the tks of nodes an element is connected to. That works for all kinds of elements with different number of nodes. The are returned in the form tuple[str, str, str, str] = fkKI, fkKK, fkKI2, fkKK2.

It works for bypass elements with just one node.

[41]:
s3s.GetEndNodes(Tk=tank)
[41]:
('5665723676294844823', '-1', '-1', '-1')

It works for connecting elements with two nodes.

[42]:
s3s.GetEndNodes(Tk=pump)
[42]:
('5739878139344995606', '5680811754375850174', '-1', '-1')

It works for connecting elements with four nodes like heat exchangers that we have not used in this tutorial for simplicity reasons.

[43]:
s3s.GetGeometryInformation(Tk=pipeA)
[43]:
'LINESTRING Z(200 700 213, 200 700 0, 300 700 213)'

GetElementInfo()

As a side note: we can use the GetElementInfo() function to obtain a short text that tells us what kind of element we consider based on the tk given and to which elements it is connected.

[44]:
s3s.GetElementInfo(Tk=pump)
Info: Pumpe Node9 Node10
[45]:
s3s.GetElementInfo(Tk=tank)
Info: Offener Behälter Node2
[46]:
s3s.InsertElement(ElementType=s3s.ObjectTypes.Node, IdRef="A")
Element inserted successfully into the model with Tk: 5355078431502712981
[46]:
'5355078431502712981'
[47]:
s3s.GetValue('5655239364696389210', "fkCont")
[47]:
('', '')
[48]:
s3s.GetMainContainer()
[48]:
('5404784316484532375', <ObjectTypes.ObjectContainerSymbol: 44>)
[49]:
s3s.GetPropertiesofElementType(ElementType=s3s.ObjectTypes.Node)
[49]:
['Name',
 'Ktyp',
 'Zkor',
 'QmEin',
 'Lfakt',
 'Fkpzon',
 'Fkfstf',
 'Fkutmp',
 'Fkfqps',
 'Fkcont',
 'Fk2lknot',
 'Beschreibung',
 'Idreferenz',
 'Iplanung',
 'Kvr',
 'Qakt',
 'Xkor',
 'Ykor',
 'NodeNamePosition',
 'ShowNodeName',
 'KvrKlartext',
 'NumberOfVERB',
 'HasBlockConnection',
 'Tk',
 'Pk',
 'IsMarked',
 'InVariant',
 'GeometriesDiffer',
 'SymbolFactor',
 'bz.Drakonz',
 'bz.Fk',
 'bz.Fkpvar',
 'bz.Fkqvar',
 'bz.Fklfkt',
 'bz.PhEin',
 'bz.Tm',
 'bz.Te',
 'bz.PhMin']

Next: Tutorial 7: Miscellaneous