From 34c69e114c2b8abcf147b1aa4fbfdac1cb7f7f81 Mon Sep 17 00:00:00 2001 From: Martin Moraga Date: Thu, 19 Oct 2023 12:35:50 +0200 Subject: [PATCH 1/5] fix small error in cimexport.py Signed-off-by: Martin Moraga --- cimpy/cimexport.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cimpy/cimexport.py b/cimpy/cimexport.py index ce0802b7..faca28d1 100644 --- a/cimpy/cimexport.py +++ b/cimpy/cimexport.py @@ -202,7 +202,7 @@ def _sort_classes_to_profile(class_attributes_list, activeProfileList): if 'class' in possibleProfileList[klass['name']].keys(): possibleProfileList[klass['name']]['class'].sort() for klass_profile in possibleProfileList[klass['name']]['class']: - if Profile(klass_profile).name in activeProfileList: + if Profile(klass_profile) in activeProfileList: # active profile for class export found class_serializationProfile = Profile(klass_profile).name break From 1d2357d828258a979b3ac2d31586c09ffd02af9b Mon Sep 17 00:00:00 2001 From: Martin Moraga Date: Tue, 10 Oct 2023 10:34:24 +0200 Subject: [PATCH 2/5] Update SynchronousMachineTimeConstantReactance.py initialize dynamic parameters of class SynchronousMachineTimeConstantReactance as float Signed-off-by: Martin Moraga --- cimpy/cgmes_v2_4_15/SynchronousMachineTimeConstantReactance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 8a6ddc5739b350361b465881f313895118b09e78 Mon Sep 17 00:00:00 2001 From: Martin Moraga Date: Tue, 10 Oct 2023 10:35:40 +0200 Subject: [PATCH 3/5] Update RotatingMachineDynamics.py initialize parameter 'inertia' of class RotatingMachineDynamics as float Signed-off-by: Martin Moraga --- cimpy/cgmes_v2_4_15/RotatingMachineDynamics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 37bab231516fd7cbed52ee1cafd39a8bb27bc7f0 Mon Sep 17 00:00:00 2001 From: Canfirat98 Date: Wed, 25 Oct 2023 13:39:21 +0200 Subject: [PATCH 4/5] added new functions to utils.py Signed-off-by: Canfirat98 --- cimpy/utils.py | 858 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 858 insertions(+) diff --git a/cimpy/utils.py b/cimpy/utils.py index e9cfea3b..c1ccbf1b 100644 --- a/cimpy/utils.py +++ b/cimpy/utils.py @@ -1,4 +1,7 @@ import importlib +import uuid +import datetime +import cimpy.cgmes_v2_4_15 def node_breaker_to_bus_branch(import_result): """TODO: Add documentation @@ -130,9 +133,864 @@ def add_external_network_injection(import_result, version, mRID, voltage_set_poi 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 Date: Wed, 25 Oct 2023 14:47:54 +0200 Subject: [PATCH 5/5] rename file utils.py Signed-off-by: Canfirat98 --- cimpy/__init__.py | 2 +- cimpy/{utils.py => cimedit.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename cimpy/{utils.py => cimedit.py} (100%) 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/utils.py b/cimpy/cimedit.py similarity index 100% rename from cimpy/utils.py rename to cimpy/cimedit.py