diff --git a/cimpy/__init__.py b/cimpy/__init__.py
index 15a9ab7f..49dd0d2a 100644
--- a/cimpy/__init__.py
+++ b/cimpy/__init__.py
@@ -1,6 +1,6 @@
from cimpy.cimexport import cim_export
from cimpy.cimimport import cim_import
-import cimpy.utils
+import cimpy.cimedit
from cimpy.cimexamples import import_example
from cimpy.cimexamples import export_example
from cimpy.cimexamples import addExternalNetworkInjection_example
diff --git a/cimpy/cgmes_v2_4_15/RotatingMachineDynamics.py b/cimpy/cgmes_v2_4_15/RotatingMachineDynamics.py
index bdb81b86..ca6e47fb 100644
--- a/cimpy/cgmes_v2_4_15/RotatingMachineDynamics.py
+++ b/cimpy/cgmes_v2_4_15/RotatingMachineDynamics.py
@@ -28,7 +28,7 @@ class RotatingMachineDynamics(DynamicsFunctionBlock):
__doc__ += '\n Documentation of parent class DynamicsFunctionBlock: \n' + DynamicsFunctionBlock.__doc__
- def __init__(self, damping = 0.0, inertia = 0, saturationFactor = 0.0, saturationFactor120 = 0.0, statorLeakageReactance = 0.0, statorResistance = 0.0, *args, **kw_args):
+ def __init__(self, damping = 0.0, inertia = 0.0, saturationFactor = 0.0, saturationFactor120 = 0.0, statorLeakageReactance = 0.0, statorResistance = 0.0, *args, **kw_args):
super().__init__(*args, **kw_args)
self.damping = damping
diff --git a/cimpy/cgmes_v2_4_15/SynchronousMachineTimeConstantReactance.py b/cimpy/cgmes_v2_4_15/SynchronousMachineTimeConstantReactance.py
index ef592f50..12120c08 100644
--- a/cimpy/cgmes_v2_4_15/SynchronousMachineTimeConstantReactance.py
+++ b/cimpy/cgmes_v2_4_15/SynchronousMachineTimeConstantReactance.py
@@ -44,7 +44,7 @@ class SynchronousMachineTimeConstantReactance(SynchronousMachineDetailed):
__doc__ += '\n Documentation of parent class SynchronousMachineDetailed: \n' + SynchronousMachineDetailed.__doc__
- def __init__(self, rotorType = None, modelType = None, ks = 0.0, xDirectSync = 0.0, xDirectTrans = 0.0, xDirectSubtrans = 0.0, xQuadSync = 0.0, xQuadTrans = 0.0, xQuadSubtrans = 0.0, tpdo = 0, tppdo = 0, tpqo = 0, tppqo = 0, tc = 0, *args, **kw_args):
+ def __init__(self, rotorType = None, modelType = None, ks = 0.0, xDirectSync = 0.0, xDirectTrans = 0.0, xDirectSubtrans = 0.0, xQuadSync = 0.0, xQuadTrans = 0.0, xQuadSubtrans = 0.0, tpdo = 0.0, tppdo = 0.0, tpqo = 0.0, tppqo = 0.0, tc = 0.0, *args, **kw_args):
super().__init__(*args, **kw_args)
self.rotorType = rotorType
diff --git a/cimpy/cimedit.py b/cimpy/cimedit.py
new file mode 100644
index 00000000..c1ccbf1b
--- /dev/null
+++ b/cimpy/cimedit.py
@@ -0,0 +1,996 @@
+import importlib
+import uuid
+import datetime
+import cimpy.cgmes_v2_4_15
+
+def node_breaker_to_bus_branch(import_result):
+ """TODO: Add documentation
+ """
+ res = import_result['topology']
+ breaker_list = []
+ terminals_list = []
+ operational_limit_set_list = []
+ voltage_limit_list = []
+ diagram_objects_list = []
+ diagram_object_points_list = []
+ connect_nodes = []
+ for mRID in res.keys():
+ class_name = res[mRID].__class__.__name__
+ if class_name == "Breaker":
+ breaker_list.append(mRID)
+ elif class_name == "OperationalLimitSet":
+ operational_limit_set_list.append(mRID)
+ elif class_name == "Terminal":
+ terminals_list.append(mRID)
+ elif class_name == "VoltageLimit":
+ voltage_limit_list.append(mRID)
+ elif class_name == "DiagramObject":
+ diagram_objects_list.append(mRID)
+ elif class_name == "DiagramObjectPoint":
+ diagram_object_points_list.append(mRID)
+ elif class_name == 'ConnectivityNode':
+ connect_nodes.append(mRID)
+
+ # search for open breakers
+ open_breakers = []
+ for breaker in breaker_list:
+ if res[breaker].open:
+ if not res[breaker].retained:
+ open_breakers.append(breaker)
+
+ # check terminals for reference to open breakers and delete references to Connectivity Nodes
+ del_terminals_list = []
+ for terminal in terminals_list:
+ cond_eq = res[terminal].ConductingEquipment
+ if cond_eq.mRID in open_breakers:
+ del_terminals_list.append(terminal)
+ else:
+ res[terminal].ConnectivityNode = None
+
+ # check for OperationalLimitSet with references to deleted Terminals
+ del_operationallimitset = []
+ for operational_limit in operational_limit_set_list:
+ if res[operational_limit].Terminal.mRID in del_terminals_list:
+ del_operationallimitset.append(operational_limit)
+
+ del_voltage_limit = []
+ for voltage in voltage_limit_list:
+ if res[voltage].OperationalLimitSet.mRID in del_operationallimitset:
+ del_voltage_limit.append(voltage)
+
+ del_diagram_object = []
+
+ for diagram_object in diagram_objects_list:
+ keep_diagram = []
+ if res[diagram_object].IdentifiedObject is None:
+ continue
+ if 'ConnectivityNode' in str(type(res[diagram_object].IdentifiedObject)):
+ if res[diagram_object].IdentifiedObject.TopologicalNode is not None:
+ keep_diagram.append(res[diagram_object].IdentifiedObject.TopologicalNode)
+ elif res[diagram_object].IdentifiedObject.mRID in (open_breakers + del_terminals_list):
+ del_diagram_object.append(diagram_object)
+
+ del_diagram_object_points = []
+ for diagram_point in diagram_object_points_list:
+ if res[diagram_point].DiagramObject is None:
+ continue
+ if res[diagram_point].DiagramObject.mRID in del_diagram_object:
+ del_diagram_object_points.append(diagram_point)
+
+ del_list = open_breakers + del_diagram_object_points + del_diagram_object + del_voltage_limit + \
+ del_operationallimitset + del_terminals_list + connect_nodes
+
+ for key in del_list:
+ del res[key]
+
+ import_result['topology'] = res
+
+ return import_result
+
+
+def add_external_network_injection(import_result, version, mRID, voltage_set_point):
+ """TODO: Add documentation
+ """
+ res = import_result['topology']
+ TopologicalNode = ''
+ if mRID in res:
+ if 'TopologicalNode' in str(type(res[mRID])):
+ TopologicalNode = res[mRID]
+ elif 'ConnectivityNode' in str(type(res[mRID])):
+ TopologicalNode = res[mRID].TopologicalNode.mRID
+
+ if TopologicalNode != '':
+ i = 1
+ while 'Injection ' + str(i) in res.keys():
+ i += 1
+ inj_name = 'Injection ' + str(i)
+ reg_name = 'Regulating Control ' + str(i)
+ terminal_name = 'Terminal Injection ' + str(i)
+
+ #module_name = "cimpy." + version + ".Equipment."
+ module_name = "cimpy." + version + "."
+
+ terminal_module = importlib.import_module((module_name + 'Terminal'))
+ terminal_class = getattr(terminal_module, 'Terminal')
+ res[terminal_name] = terminal_class(mRID=terminal_name,
+ name=terminal_name,
+ TopologicalNode=TopologicalNode)
+
+ regulating_control_module = importlib.import_module(module_name + 'RegulatingControl')
+ regulating_control_class = getattr(regulating_control_module, 'RegulatingControl')
+ res[reg_name] = regulating_control_class(mRID=reg_name,
+ name=reg_name,
+ targetValue=voltage_set_point,
+ Terminal=res[terminal_name])
+
+ network_injection_module = importlib.import_module(module_name + 'ExternalNetworkInjection')
+ network_injection_class = getattr(network_injection_module, 'ExternalNetworkInjection')
+ res[inj_name] = network_injection_class(mRID=inj_name,
+ name=inj_name,
+ RegulatingControl=res[reg_name],
+ Terminals=[res[terminal_name]])
+
+ res[reg_name].RegulatingCondEq = res[inj_name]
+ res[terminal_name].ConductingEquipment = res[inj_name]
+ res[terminal_name].RegulatingControl = res[reg_name]
+
+ # Append the Terminal List of the TopologicalNode
+ res[mRID].Terminal.append(res[terminal_name])
+ else:
+ print('No Terminal with mRID ', mRID, ' found in object list!')
+
+ import_result['topology'] = res
+
+ return import_result
+
+
+def add_ACLineSegment(cim_topology, version, name, mRID="", mRID_node1="", node1_name="", mRID_node2="", node2_name="", r=0, x=0, bch=0, gch=0, baseVoltage=0):
+ """
+ Function to add ACLineSegment objects to existing cim topology
+
+ ...
+
+ Parameters
+ ----------
+ cim_topology : dict
+ existing cim topology
+ version : str
+ cgmes version. Actually only version 2.4.15 is supported
+ name : str
+ name of the ACLineSegment to be added
+ mRID : str
+ uuid for the synchronous machine. If mRID=="", it will be automatically generate
+ mRID_node1 : str
+ uuid of the first node to which this ACLineSegment has to be connected
+ mRID_node2 : str
+ uuid of the second node to which this ACLineSegment machine has to be connecteds
+ r : float
+ Positive sequence series resistance of the entire line section. Unit: Ohm
+ x : float
+ Positive sequence series reactance of the entire line section. Unit: Ohm
+ bch : float
+ Positive sequence shunt (charging) susceptance, uniformly distributed, of the entire line section. This value represents the full charging over the full length of the line. Unit: S
+ gch : float
+ Positive sequence shunt (charging) conductance, uniformly distributed, of the entire line section. Unit: S
+ baseVoltage: float
+ Nominal Voltage of this line
+
+ Returns
+ -------
+ import_result
+ dict containing the modified cim topology
+ """
+
+ res = cim_topology['topology']
+
+ if name in res:
+ print('WARN: ACLineSegment mRID={} is already included in the cim topology, object will be not be addd to cim topology"', mRID)
+ return cim_topology
+
+ # Creating random mRID using uuid4()
+ if mRID == "":
+ mRID = str(uuid.uuid4())
+
+ if (mRID_node1==""):
+ for uuid_, obj in res.items():
+ if hasattr(obj, "name"):
+ if (obj.name==node1_name):
+ mRID_node1=uuid_
+ if (mRID_node2==""):
+ for uuid_, obj in res.items():
+ if hasattr(obj, "name"):
+ if (obj.name==node2_name):
+ mRID_node2=uuid_
+
+ # look for topological nodels connected to line
+ TopologicalNode1 = None
+ TopologicalNode2 = None
+ if mRID_node1 in res:
+ if 'TopologicalNode' in str(type(res[mRID_node1])):
+ TopologicalNode1 = res[mRID_node1]
+ elif 'ConnectivityNode' in str(type(res[mRID_node1])):
+ TopologicalNode1 = res[mRID_node1].TopologicalNode
+
+ if mRID_node2 in res:
+ if 'TopologicalNode' in str(type(res[mRID_node2])):
+ TopologicalNode2 = res[mRID_node2]
+ elif 'ConnectivityNode' in str(type(res[mRID_node2])):
+ TopologicalNode2 = res[mRID_node2].TopologicalNode
+
+ if (TopologicalNode1 is not None) and (TopologicalNode2 is not None):
+
+ module_name = "cimpy." + version + "."
+
+ # create terminals for this line
+ terminal1_mRID = str(uuid.uuid4())
+ terminal_module = importlib.import_module((module_name + 'Terminal'))
+ terminal_class = getattr(terminal_module, 'Terminal')
+ res[terminal1_mRID] = terminal_class(mRID=terminal1_mRID,
+ name='Terminal_1_' + name,
+ sequenceNumber=1,
+ TopologicalNode=TopologicalNode1)
+ terminal2_mRID = str(uuid.uuid4())
+ res[terminal2_mRID] = terminal_class(mRID=terminal2_mRID,
+ name='Terminal_2_' + name,
+ sequenceNumber=2,
+ TopologicalNode=TopologicalNode2)
+
+ # create object of type ACLineSegment
+ ACLineSegment_module = importlib.import_module((module_name + 'ACLineSegment'))
+ ACLineSegment_class = getattr(ACLineSegment_module, 'ACLineSegment')
+ res[mRID] = ACLineSegment_class(mRID= mRID,
+ name= name,
+ r = r,
+ x = x,
+ bch = bch,
+ gch = gch,
+ BaseVoltage = create_BaseVoltage(res, baseVoltage),
+ Terminals = [res[terminal1_mRID], res[terminal2_mRID]])
+ # Connect Equipment to Terminal
+ res[terminal1_mRID].ConductingEquipment = res[mRID]
+ res[terminal2_mRID].ConductingEquipment = res[mRID]
+
+ # Append the Terminal List of the TopologicalNodes
+ res[mRID_node1].Terminal.append(res[terminal1_mRID])
+ res[mRID_node2].Terminal.append(res[terminal2_mRID])
+
+ cim_topology['topology'] = res
+ return cim_topology
+
+ elif TopologicalNode1 is None:
+ print('WARN: No Topological with mRID={} found in cim topology, ACLineSegment name={} will be not added to cim topology!'.format(mRID_node1, name))
+
+ if TopologicalNode2 is None:
+ print('WARN: No Topological with mRID={} found in cim topology, ACLineSegment name={} will be not added to cim topology!'.format(mRID_node2, name))
+
+ cim_topology['topology'] = res
+
+ return cim_topology
+
+
+def add_Terminal(cim_topology, version, TopologicalNode, ConductingEquipment, pInjection = 0, qInjection = 0, mRID = ''):
+ res = cim_topology['topology']
+
+ if mRID == "":
+ mRID = str(uuid.uuid4())
+
+ #module_name = "cimpy." + version + ".Equipment."
+ module_name = "cimpy." + version + "."
+
+ terminal_module = importlib.import_module((module_name + 'Terminal'))
+ terminal_class = getattr(terminal_module, 'Terminal')
+ res[mRID] = terminal_class(mRID='Terminal',
+ name='Terminal',
+ TopologicalNode=TopologicalNode,
+ ConductingEquipment= ConductingEquipment,
+ pInjection= pInjection,
+ qInjection= qInjection)
+
+ cim_topology['topology'] = res
+
+ return cim_topology
+
+def add_TopologicalNode(cim_topology, version, name, mRID="", baseVoltage=0, v=0.0, angle=0.0):
+
+ res = cim_topology['topology']
+
+ if mRID in res:
+ print("mRID", mRID, "is already included")
+ return cim_topology
+
+ # Creating random mRID using uuid4()
+ if mRID == "":
+ mRID = str(uuid.uuid4())
+
+ # get module name
+ module_name = "cimpy." + version + "."
+ TopologicalNode_module = importlib.import_module((module_name + 'TopologicalNode'))
+
+ # create topological node object
+ TopologicalNode_class = getattr(TopologicalNode_module, 'TopologicalNode')
+ res[mRID] = TopologicalNode_class(mRID= mRID,
+ name= name,
+ BaseVoltage=baseVoltage,
+ Terminal = [])
+
+ # create SV object
+ if isinstance(v, float) and isinstance(angle, float):
+ SvVoltage_name = name + "-sv"
+ SvVoltage_module = importlib.import_module((module_name + 'SvVoltage'))
+ SvVoltage_class = getattr(SvVoltage_module, 'SvVoltage')
+ res[SvVoltage_name] = SvVoltage_class(v=v,
+ angle=angle,
+ TopologicalNode=res[mRID])
+ res[mRID].SvVoltage = res[SvVoltage_name]
+
+ cim_topology['topology'] = res
+ return cim_topology
+
+
+def add_SynchronousMachine(cim_topology, version, name, mRID_node="", node_name="", mRID="", ratedS=0, ratedU=0, p=0, q=0, targetValue=0, initialP=0):
+ """
+ #TODO: baseVoltage?
+ Function to add synchronous machine to existing cim topology
+
+ ...
+
+ Parameters
+ ----------
+ cim_topology : dict
+ existing cim topology
+ version : str
+ cgmes version. Actually only version 2.4.15 is supported
+ name : str
+ name of the synchronous machine to be added
+ mRID_node : str
+ uuid of the node to which this synchronous machine has to be connected
+ mRID : str
+ uuid for the synchronous machine. If mRID=="", it will be automatically generated
+ ratedS : float
+ apparent power rating for the unit. The attribute shall have a positive value. Unit: MVA
+ ratedU : float
+ Rated voltage. It is primarily used for short circuit data exchange according to IEC 60909. Unit: kV
+ p : float
+ Active power injection. Load sign convention is used, i.e. positive sign means flow out from a node. Starting value for a steady state solution. Unit: MW
+ q : float
+ Reactive power injection. Load sign convention is used, i.e. positive sign means flow out from a node. Starting value for a steady state solution. Unit: MVAr
+ targetValue : float
+ uuid for the synchronous machine. If mRID=="", it will be automatically generated. Unit: kV
+ initialP : float
+ Default initial active power which is used to store a powerflow result for the initial active power for this unit in this network configuration. Unit: MW
+
+
+ Returns
+ -------
+ import_result
+ dict containing the modified cim topology
+ """
+
+ # TODO: RotatingMachine without paramameters?
+
+ res = cim_topology['topology']
+
+ if mRID in res:
+ print('WARN: Synchronous Machine mRID="{}" is already included in the cim topology, object will be not be addd to cim topology"', mRID)
+ return cim_topology
+
+ # Creating random mRID using uuid4()
+ if mRID == "":
+ mRID = str(uuid.uuid4())
+
+ if (mRID_node==""):
+ for uuid_, obj in res.items():
+ if isinstance(obj, cimpy.cgmes_v2_4_15.TopologicalNode):
+ if (obj.name==node_name):
+ mRID_node=uuid_
+
+ TopologicalNode = None
+ if 'TopologicalNode' in str(type(res[mRID_node])):
+ TopologicalNode = res[mRID_node]
+ elif 'ConnectivityNode' in str(type(res[mRID_node])):
+ TopologicalNode = res[mRID_node].TopologicalNode.mRID
+
+ if TopologicalNode is not None:
+
+ module_name = "cimpy." + version + "."
+
+ # add terminal for this SM
+ terminal_mRID = str(uuid.uuid4())
+ terminal_module = importlib.import_module((module_name + 'Terminal'))
+ terminal_class = getattr(terminal_module, 'Terminal')
+ res[terminal_mRID] = terminal_class(mRID=terminal_mRID,
+ name='Terminal_' + name,
+ TopologicalNode=TopologicalNode)
+
+ # add terminal for this SM
+ generating_unit_mRID = str(uuid.uuid4())
+ GeneratingUnit_module = importlib.import_module((module_name + 'GeneratingUnit'))
+ GeneratingUnit_class = getattr(GeneratingUnit_module, 'GeneratingUnit')
+ res[generating_unit_mRID] = GeneratingUnit_class(mRID=generating_unit_mRID,
+ name='GeneratingUnit_' + name,
+ initialP=initialP)
+
+ # add terminal for this SM
+ regulating_control_mRID = str(uuid.uuid4())
+ RegulatingControl_module = importlib.import_module((module_name + 'RegulatingControl'))
+ RegulatingControl_class = getattr(RegulatingControl_module, 'RegulatingControl')
+ res[regulating_control_mRID] = RegulatingControl_class(mRID=regulating_control_mRID,
+ name='RegulatingControl_' + name,
+ targetValue=targetValue,
+ mode='http://iec.ch/TC57/2013/CIM-schema-cim16#RegulatingControlModeKind.voltage#')
+ # ADD targetValueUnitMultiplier --> fix class in cimpy
+
+ # create Synchronous machine object
+ SynchronousMachine_module = importlib.import_module((module_name + 'SynchronousMachine'))
+ SynchronousMachine_class = getattr(SynchronousMachine_module, 'SynchronousMachine')
+ res[mRID] = SynchronousMachine_class(mRID=mRID,
+ name=name,
+ p=p,
+ q=q,
+ ratedS=ratedS,
+ ratedU=ratedU,
+ RegulatingControl=res[regulating_control_mRID],
+ GeneratingUnit=res[regulating_control_mRID],
+ Terminals=[res[terminal_mRID]])
+
+ # connect terminal with synchronous machine
+ res[terminal_mRID].ConductingEquipment = res[mRID]
+
+ # Append the Terminal to the terminals list of the TopologicalNode
+ res[mRID_node].Terminal.append(res[terminal_mRID])
+
+ cim_topology['topology'] = res
+ return cim_topology
+
+ else:
+ print('WARN: No Topological with mRID={} found in cim topology, Synchronous Machine name={} will be not added to cim topology!'.format(mRID_node, name))
+ return cim_topology
+
+def extend_SynchronousMachineTimeConstantReactance(cim_topology, version, name="", mRID="", SynchronousMachine_mRID="",
+ damping=0, inertia=0, statorResistance=0, statorLeakageReactance=0,
+ tpdo=0, tpqo=0, tppdo=0, tppqo=0, xDirectSubtrans=0, xDirectSync=0,
+ xDirectTrans=0, xQuadSubtrans=0, xQuadSync=0, xQuadTrans=0):
+ """
+ Function to add element of type SynchronousMachineTimeConstantReactance to existing cim topology
+
+ ...
+
+ Parameters
+ ----------
+ cim_topology : dict
+ existing cim topology
+ version : str
+ cgmes version. Actually only version 2.4.15 is supported
+ name : str
+ name of the synchronous machine to be added
+ mRID : str
+ uuid for the synchronous machine. If mRID=="", it will be automatically generated
+ SynchronousMachine_mRID : str
+ uuid of the synchronous machine to which this object belongs
+
+ Returns
+ -------
+ import_result
+ dict containing the modified cim topology
+ """
+
+ res = cim_topology['topology']
+
+ if mRID in res:
+ print('WARN: SynchronousMachineTimeConstantReactance mRID="{}" is already included in the cim topology, object will be not be addd to cim topology"'.format(mRID))
+ return cim_topology
+
+ # search for the synchonous machine
+ synchronous_machine = None
+ if SynchronousMachine_mRID in res.keys():
+ synchronous_machine = res[SynchronousMachine_mRID]
+ else:
+ print('WARN: SynchronousMachine mRID={} coud not be found in the cim topology, object of type SynchronousMachineTimeConstantReactance will be not addd to cim topology'.format(SynchronousMachine_mRID))
+ return cim_topology
+
+ if name == "":
+ name = synchronous_machine.name + "_TimeConstantReactance"
+
+ if mRID == "":
+ mRID = str(uuid.uuid4())
+
+ module_name = "cimpy." + version + "."
+
+ # create object of type SynchronousMachineTimeConstantReactance
+ SynchronousMachineTCR_module = importlib.import_module((module_name + 'SynchronousMachineTimeConstantReactance'))
+ SynchronousMachineTCR_class = getattr(SynchronousMachineTCR_module, 'SynchronousMachineTimeConstantReactance')
+ res[name] = SynchronousMachineTCR_class(mRID=mRID,
+ name=name,
+ SynchronousMachine=synchronous_machine,
+ damping=damping,
+ inertia=inertia,
+ statorResistance=statorResistance,
+ statorLeakageReactance=statorLeakageReactance,
+ tpdo=tpdo,
+ tpqo=tpqo,
+ tppdo=tppdo,
+ tppqo=tppqo,
+ xDirectSubtrans=xDirectSubtrans,
+ xDirectSync=xDirectSync,
+ xDirectTrans=xDirectTrans,
+ xQuadSubtrans=xQuadSubtrans,
+ xQuadSync=xQuadSync,
+ xQuadTrans=xQuadTrans)
+ # TODO: Add
+ # TODO: Add