Skip to content
Snippets Groups Projects
Commit 71a5a3a3 authored by Ubuntu's avatar Ubuntu
Browse files

added branch reading functions, but somehow I have to add directly to 'venv'...

added branch reading functions, but somehow I have to add directly to 'venv' evnironment 'lib'. Guess that's my side issues. Still updating at  as well

Signed-off-by: default avatarUbuntu <ubuntu@ty-beflex.osc.eonerc.rwth-aachen.de>
parent b19c6427
Branches
Tags 9.3.6
No related merge requests found
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python Debugger: Current File",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"justMyCode": false,
"console": "integratedTerminal"
}
]
}
\ No newline at end of file
This diff is collapsed.
import logging
import numpy as np
from enum import Enum
import os
import hdf5storage
class BusType(Enum):
SLACK = 1
slack = 1
PV = 2
pv = 2
PQ = 3
pq = 3
class Node():
def __init__(self, uuid='', name='', base_voltage=1.0, base_apparent_power=1.0, v_mag=0.0,
v_phase=0.0, p=0.0, q=0.0, index=0, ideal_connected_with=''):
self.uuid = uuid
self.name = name
self.index = index
self.baseVoltage = base_voltage
self.base_apparent_power = base_apparent_power
self.base_current = self.base_apparent_power / self.baseVoltage / np.sqrt(3)
self.type = BusType["PQ"]
self.voltage = complex(v_mag * np.cos(np.radians(v_phase)), v_mag * np.sin(np.radians(v_phase)))
self.power = complex(p, q)
self.power_pu = complex(p, q) / self.base_apparent_power
self.voltage_pu = self.voltage / self.baseVoltage
self.ideal_connected_with = ideal_connected_with
def __str__(self):
string = 'class=Node\n'
attributes = self.__dict__
for key in attributes.keys():
string = string + key + '={}\n'.format(attributes[key])
return string
class Branch():
def __init__(self, uuid='', r=0.0, x=0.0, start_node=None, end_node=None,
base_voltage=1.0, base_apparent_power=1.0):
self.uuid = uuid
self.baseVoltage = base_voltage
self.base_apparent_power = base_apparent_power
self.base_current = self.base_apparent_power / self.baseVoltage / np.sqrt(3)
self.base_impedance = base_voltage ** 2 / self.base_apparent_power
self.start_node = start_node
self.end_node = end_node
self.r = r
self.x = x
self.z = self.r + 1j * self.x
self.y = 1 / self.z if (self.z != 0) else float("inf")
self.r_pu = r / self.base_impedance
self.x_pu = x / self.base_impedance
self.z_pu = self.r_pu + 1j * self.x_pu
self.y_pu = 1 / self.z_pu if (self.z_pu != 0) else float("inf")
def __str__(self):
string = 'class=Branch\n'
attributes = self.__dict__
for key in attributes.keys():
string = string + key + '={}\n'.format(attributes[key])
return string
class Breaker():
def __init__(self, from_node, to_node, is_open=True):
"""
:param from_node:
:param to_node:
:param is_open: True if the breaker is considered open and False if the broker is closed
"""
self.from_node = from_node
self.to_node = to_node
self.is_open = is_open
def __str__(self):
string = 'class=Breaker\n'
attributes = self.__dict__
for key in attributes.keys():
string = string + key + '={}\n'.format(attributes[key])
return string
def open_breaker(self):
self.is_open = True
self.to_node.ideal_connected_with = ''
def close_breaker(self):
self.is_open = False
self.to_node.ideal_connected_with = self.from_node.uuid
class System():
def __init__(self):
self.nodes = []
self.branches = []
self.breakers = []
self.Ymatrix = np.zeros([], dtype=complex)
self.Bmatrix = np.zeros([], dtype=complex)
def get_node_by_uuid(self, node_uuid):
for node in self.nodes:
if node.uuid == node_uuid:
return node
return None
def get_node_by_index(self, index):
"""
Return the node with node.index == index
"""
for node in self.nodes:
if (node.index == index) and (node.ideal_connected_with == ''):
return node
return None
def get_nodes_num(self):
"""
Return the number of nodes in the list system.nodes
Warning: if any node is ideally connected to another node,
the counter is increased only one time
"""
nodes_num = 0
for node in self.nodes:
if node.ideal_connected_with == '':
nodes_num += 1
return nodes_num
def reindex_nodes_list(self):
"""
Re-enumerate the nodes in system.nodes
If any node is ideally connected to another node,
both receive the same index
"""
index = 0
remaining_nodes_list = []
for node in self.nodes:
if node.ideal_connected_with == '':
node.index = index
index += 1
else:
remaining_nodes_list.append(node)
for node in remaining_nodes_list:
node.index = self.get_node_by_uuid(node.ideal_connected_with).index
def load_cim_data(self, res, base_apparent_power):
"""
fill the vectors node, branch and breakers
"""
self.nodes = []
self.branches = []
self.breakers = []
index = 0
list_TPNode = [elem for elem in res.values() if elem.__class__.__name__ == "TopologicalNode"]
list_SvVoltage = [elem for elem in res.values() if elem.__class__.__name__ == "SvVoltage"]
list_SvPowerFlow = [elem for elem in res.values() if elem.__class__.__name__ == "SvPowerFlow"]
list_EnergySources = [elem for elem in res.values() if elem.__class__.__name__ == "EnergySource"]
list_EnergyConsumer = [elem for elem in res.values() if elem.__class__.__name__ == "EnergyConsumer"]
list_ACLineSegment = [elem for elem in res.values() if elem.__class__.__name__ == "ACLineSegment"]
list_PowerTransformer = [elem for elem in res.values() if elem.__class__.__name__ == "PowerTransformer"]
list_Terminals = [elem for elem in res.values() if elem.__class__.__name__ == "Terminal"]
list_Terminals_ES = [elem for elem in list_Terminals if
elem.ConductingEquipment.__class__.__name__ == "EnergySource"]
list_Terminals_EC = [elem for elem in list_Terminals if
elem.ConductingEquipment.__class__.__name__ == "EnergyConsumer"]
list_PowerTransformerEnds = [elem for elem in res.values() if elem.__class__.__name__ == "PowerTransformerEnd"]
list_Breakers = [elem for elem in res.values() if elem.__class__.__name__ == "Breaker"]
#create nodes
for TPNode in list_TPNode:
uuid_TPNode = TPNode.mRID
name = TPNode.name
vmag = 0.0
vphase = 0.0
pInj = 0.0
qInj = 0.0
for obj_SvVoltage in list_SvVoltage:
if obj_SvVoltage.TopologicalNode.mRID == uuid_TPNode:
vmag = obj_SvVoltage.v
vphase = obj_SvVoltage.angle
break
for obj_SvPowerFlow in list_SvPowerFlow:
if obj_SvPowerFlow.Terminal.TopologicalNode.mRID == uuid_TPNode:
pInj -= obj_SvPowerFlow.p
qInj -= obj_SvPowerFlow.q
for obj_Terminal in list_Terminals_ES:
if obj_Terminal.TopologicalNode.mRID == uuid_TPNode:
for obj_EnergySource in list_EnergySources:
if obj_EnergySource.mRID == obj_Terminal.ConductingEquipment.mRID:
pInj += obj_EnergySource.activePower
qInj += obj_EnergySource.reactivePower
for obj_Terminal in list_Terminals_EC:
if obj_Terminal.TopologicalNode.mRID == uuid_TPNode:
for obj_EnergyConsumer in list_EnergyConsumer:
if obj_EnergyConsumer.mRID == obj_Terminal.ConductingEquipment.mRID:
pInj -= obj_EnergyConsumer.p
qInj -= obj_EnergyConsumer.q
base_voltage = TPNode.BaseVoltage.nominalVoltage
self.nodes.append(Node(name=name, uuid=uuid_TPNode, base_voltage=base_voltage, v_mag=vmag,
base_apparent_power=base_apparent_power, v_phase=vphase,
p=pInj, q=qInj, index=index))
index = index + 1
self._setNodeType(list_Terminals)
#create branches type ACLineSegment
for ACLineSegment in list_ACLineSegment:
uuid_ACLineSegment = ACLineSegment.mRID
nodes = self._get_nodes(list_Terminals, uuid_ACLineSegment)
start_node = nodes[0]
end_node = nodes[1]
base_voltage = ACLineSegment.BaseVoltage.nominalVoltage
self.branches.append(Branch(uuid=uuid_ACLineSegment, r=ACLineSegment.r, x=ACLineSegment.x,
start_node=start_node, end_node=end_node,
base_voltage=base_voltage, base_apparent_power=base_apparent_power))
#create branches type powerTransformer
for power_transformer in list_PowerTransformer:
uuid_power_transformer = power_transformer.mRID
nodes = self._get_nodes(list_Terminals, uuid_power_transformer)
start_node = nodes[0]
end_node = nodes[1]
# base voltage = high voltage side (=primaryConnection)
primary_connection = self._get_primary_connection(list_PowerTransformerEnds, uuid_power_transformer)
base_voltage = primary_connection.BaseVoltage.nominalVoltage
self.branches.append(Branch(uuid=uuid_power_transformer, r=primary_connection.r, x=primary_connection.x,
start_node=start_node, end_node=end_node, base_voltage=base_voltage,
base_apparent_power=base_apparent_power))
#create breakers
for obj_Breaker in list_Breakers:
is_open = obj_Breaker.normalOpen
nodes = self._get_nodes(list_Terminals, obj_Breaker.mRID)
self.breakers.append(Breaker(from_node=nodes[0], to_node=nodes[1], is_open=is_open))
#if the breaker is open == closed --> close broker
if is_open is False:
self.breakers[-1].close_breaker()
else:
self.breakers[-1].ideal_connected_with = ''
#calculate admitance matrix
self.Ymatrix_calc()
def _get_nodes(self, list_Terminals, elem_uuid):
"""
get the the start and end node of the element with uuid=elem_uuid
This function can used only with element which are connected
to 2 topologicalNodes, for example: ACLineSegment, PowerTransformer and Breaker
:param list_Terminals: list of all elements of type Terminal
:param elem_uuid: uuid of the element for which the start and end node ID are searched
:return list: [startNodeID, endNodeID]
"""
start_node_uuid = None
end_node_uuid = None
for terminal in list_Terminals:
if terminal.ConductingEquipment.mRID != elem_uuid:
continue
sequence_number = terminal.sequenceNumber
if sequence_number == 1:
start_node_uuid = terminal.TopologicalNode.mRID
elif sequence_number == 2:
end_node_uuid = terminal.TopologicalNode.mRID
start_node = None
end_node = None
if start_node_uuid is None:
print('WARNING: It could not find a start node for the element with uuid={}'.format(elem_uuid))
else:
start_node = self.get_node_by_uuid(start_node_uuid)
if end_node_uuid is None:
print('WARNING: It could not find a end node for the element with uuid={}'.format(elem_uuid))
else:
end_node = self.get_node_by_uuid(end_node_uuid)
return [start_node, end_node]
def _get_primary_connection(self, list_PowerTransformerEnds, elem_uuid):
"""
get primaryConnection of the powertransformer with uuid = elem_uuid
:param list_PowerTransformerEnds: list of all elements of type PowerTransformerEnd
:param elem_uuid: uuid of the power transformer for which the primary connection is searched
:return: primary_connection
"""
primary_connection = None
power_transformer_ends = []
#search for two elements of class powertransformerend that point to the powertransformer with ID == elem_uuid
for power_transformer_end in list_PowerTransformerEnds:
power_transformer = None
if isinstance(power_transformer_end.PowerTransformer, list):
if len(power_transformer_end.PowerTransformer) != 1:
print('WARNING: len(power_transformer_end.PowerTransformer)!=1 for the element with uuid={}. \
The first element will be used'.format(power_transformer_end.mRID))
power_transformer = power_transformer_end.PowerTransformer[0]
else:
power_transformer = power_transformer_end.PowerTransformer
if power_transformer.mRID == elem_uuid:
power_transformer_ends.append(power_transformer_end)
if power_transformer_ends[0].BaseVoltage.nominalVoltage >= \
power_transformer_ends[1].BaseVoltage.nominalVoltage:
primary_connection=power_transformer_ends[0]
elif power_transformer_ends[1].BaseVoltage.nominalVoltage >= \
power_transformer_ends[0].BaseVoltage.nominalVoltage:
primary_connection=power_transformer_ends[1]
return primary_connection
def _setNodeType(self, list_Terminals):
"""
set the parameter "type" of all elements of the list self.nodes
:param list_Terminals: list of all elements of type Terminal
:return None
"""
#get a list of Terminals for which the ConductingEquipment is a element of class ExternalNetworkInjection
list_Terminals_ENI = [elem for elem in list_Terminals if
elem.ConductingEquipment.__class__.__name__ == "ExternalNetworkInjection"]
for terminal in list_Terminals_ENI:
node_uuid = terminal.TopologicalNode.mRID
for node in self.nodes:
if node.uuid == node_uuid:
node.type = BusType["SLACK"]
#get a list of Terminals for which the ConductingEquipment is a element of class SynchronousMachine
list_Terminals_SM = [elem for elem in list_Terminals
if elem.ConductingEquipment.__class__.__name__ == "SynchronousMachine"]
for terminal in list_Terminals_SM:
node_uuid = terminal.TopologicalNode.mRID
for node in self.nodes:
if node.uuid == node_uuid:
node.type = BusType["PV"]
def Ymatrix_calc(self):
self.reindex_nodes_list()
nodes_num = self.get_nodes_num()
self.Ymatrix = np.zeros((nodes_num, nodes_num), dtype=complex)
self.Bmatrix = np.zeros((nodes_num, nodes_num), dtype=complex)
for branch in self.branches:
fr = branch.start_node.index
to = branch.end_node.index
self.Ymatrix[fr][to] -= branch.y_pu
self.Ymatrix[to][fr] -= branch.y_pu
self.Ymatrix[fr][fr] += branch.y_pu
self.Ymatrix[to][to] += branch.y_pu
#testing functions
def print_nodes_names(self):
for node in self.nodes:
print('{} {}'.format(node.name, node.index))
def print_node_types(self):
for node in self.nodes:
print('{} {}'.format(node.name, node.type))
def print_power(self):
for node in self.nodes:
print('{} {}'.format(node.name, node.power))
def print_branch(self):
for branch in self.branches:
print('{}'.format(branch.uuid))
print('bus{} to bus{}'.format(branch.start_node, branch.end_node))
print('---')
def load_from_m_file(self, file_path):
"""
Load network data from a MATLAB file (v7.3 supported) and populate nodes and branches.
Expects the file to contain at least 'bus' and 'branch' keys.
"""
if not os.path.exists(file_path):
raise FileNotFoundError(f"File {file_path} not found.")
# Use hdf5storage to load the file
mat_data = hdf5storage.loadmat(file_path)
if 'bus' not in mat_data or 'branch' not in mat_data:
raise ValueError("MATLAB file must contain 'bus' and 'branch' data.")
bus_data = mat_data['bus']
branch_data = mat_data['branch']
self.nodes = []
# Create nodes (example for MATPOWER bus format)
for i, bus in enumerate(bus_data):
# Update indices based on your MAT file structure.
bus_id = str(int(bus[0]))
name = f"Bus_{bus[0]}"
p = bus[2] # Active power demand (MW)
q = bus[3] # Reactive power demand (MVAr)
v_mag = bus[7] # Voltage magnitude
v_phase = bus[8] # Voltage angle in degrees
base_voltage = bus[9] # Base voltage (kV)
base_apparent_power = 100.0 # Example default; adjust as necessary.
self.nodes.append(
Node(
uuid=bus_id,
name=name,
base_voltage=base_voltage,
base_apparent_power=base_apparent_power,
v_mag=v_mag,
v_phase=v_phase,
p=p,
q=q,
index=i
)
)
self.reindex_nodes_list()
self.branches = []
# Create branches (example for MATPOWER branch format)
for branch in branch_data:
fbus = str(int(branch[0]))
tbus = str(int(branch[1]))
start_node = self.get_node_by_uuid(fbus)
end_node = self.get_node_by_uuid(tbus)
# Check if nodes are missing
if start_node is None or end_node is None:
print(f"WARNING: Branch {fbus} -> {tbus} skipped due to missing node.")
continue
base_voltage = start_node.baseVoltage
self.branches.append(
Branch(
uuid=f"{fbus}_{tbus}",
r=branch[2],
x=branch[3],
start_node=start_node,
end_node=end_node,
base_voltage=base_voltage,
base_apparent_power=start_node.base_apparent_power
)
)
self.Ymatrix_calc()
\ No newline at end of file
import numpy as np
from .network import BusType
from .results import Results
def solve(system):
"""It performs powerflow by using rectangular node voltage state variables and considering the current mismatch
function.
Solve the non-linear powerflow problem stated by
r = z-h(state) = 0
following the Newton-Raphson approach
delta_state = H^-1 * r
new_state = old_state + delta_state
r: residual function (current mismatch)
z: expected currents
state: rectangular voltages (i.e. [V0_re, V1_re, ..., VN_re, V0_im, V1_im, ... , VN_im])
h: currents calculated from state
H: Jacobian matrix
V: same as state but with complex numbers (i.e. [V0_re+j*V0_im, V1_re+j*V1_im, ...])
"""
nodes_num = system.get_nodes_num()
z = np.zeros(2 * nodes_num)
h = np.zeros(2 * nodes_num)
H = np.zeros((2 * nodes_num, 2 * nodes_num))
for node in system.nodes:
if node.ideal_connected_with == '':
i = node.index
m = 2 * i
i2 = i + nodes_num
node_type = node.type
if node_type == BusType.SLACK:
z[m] = np.real(node.voltage_pu)
z[m + 1] = np.imag(node.voltage_pu)
H[m][i] = 1
H[m + 1][i2] = 1
elif node_type is BusType.PQ:
H[m][:nodes_num] = np.real(system.Ymatrix[i])
H[m][nodes_num:] = - np.imag(system.Ymatrix[i])
H[m+1][:nodes_num] = np.imag(system.Ymatrix[i])
H[m+1][nodes_num:] = np.real(system.Ymatrix[i])
elif node_type is BusType.PV:
z[m] = np.real(node.power_pu)
z[m + 1] = np.abs(node.voltage_pu)
epsilon = 10 ** (-10)
diff = 5
V = np.ones(nodes_num) + 1j * np.zeros(nodes_num)
num_iter = 0
state = np.concatenate((np.ones(nodes_num), np.zeros(nodes_num)), axis=0)
while diff > epsilon:
for node in system.nodes:
if node.ideal_connected_with == '':
i = node.index
m = 2 * i
i2 = i + nodes_num
node_type = node.type
if node_type is BusType.SLACK:
h[m] = np.inner(H[m], state)
h[m + 1] = np.inner(H[m + 1], state)
elif node_type is BusType.PQ:
z[m] = (np.real(node.power_pu) * np.real(V[i]) +
np.imag(node.power_pu) * np.imag(V[i])) / (np.abs(V[i]) ** 2)
z[m + 1] = (np.real(node.power_pu) * np.imag(V[i]) -
np.imag(node.power_pu) * np.real(V[i])) / (np.abs(V[i]) ** 2)
h[m] = np.inner(H[m], state)
h[m + 1] = np.inner(H[m + 1], state)
elif node_type is BusType.PV:
h[m] = np.real(V[i]) * (np.inner(np.real(system.Ymatrix[i]), np.real(V)) -
np.inner(np.imag(system.Ymatrix[i]), np.imag(V))) + \
np.imag(V[i]) * (np.inner(np.real(system.Ymatrix[i]), np.imag(V)) +
np.inner(np.imag(system.Ymatrix[i]), np.real(V)))
h[m + 1] = np.abs(V[i])
H[m][:nodes_num] = np.real(V) * np.real(system.Ymatrix[i]) + np.imag(V) * np.imag(system.Ymatrix[i])
H[m][i] = H[m][i] + np.inner(np.real(system.Ymatrix[i]), np.real(V)) - \
np.inner(np.imag(system.Ymatrix[i]), np.imag(V))
H[m][nodes_num:] = np.imag(V) * np.real(system.Ymatrix[i]) - np.real(V) * np.imag(system.Ymatrix[i])
H[m][i2] = H[m][i2] + np.inner(np.real(system.Ymatrix[i]), np.imag(V)) + \
np.inner(np.imag(system.Ymatrix[i]), np.real(V))
H[m + 1][i] = np.cos(np.angle(V[i]))
H[m + 1][i2] = np.sin(np.angle(V[i]))
r = np.subtract(z, h)
Hinv = np.linalg.inv(H)
delta_state = np.inner(Hinv, r)
state = state + delta_state
diff = np.amax(np.absolute(delta_state))
V = state[:nodes_num] + 1j * state[nodes_num:]
num_iter = num_iter + 1
# calculate all the other quantities of the grid
powerflow_results = Results(system)
powerflow_results.load_voltages(V)
powerflow_results.calculate_all()
print (powerflow_results)
return powerflow_results, num_iter
This diff is collapsed.
import cmath
import numpy as np
import pandas as pd
class ResultsNode:
def __init__(self, topo_node):
self.topology_node = topo_node
self.voltage = complex(0, 0)
self.current = complex(0, 0)
self.power = complex(0, 0)
self.voltage_pu = complex(1, 0)
self.current_pu = complex(0, 0)
self.power_pu = complex(0, 0)
def __str__(self):
str = 'class=Node\n'
attributes = self.__dict__
for key in attributes.keys():
str = str + key + '={}\n'.format(attributes[key])
return str
class ResultsBranch:
def __init__(self, topo_branch):
self.topology_branch = topo_branch
self.current = complex(0, 0)
self.power = complex(0, 0)
self.power2 = complex(0, 0)
self.current_pu = complex(0, 0)
self.power_pu = complex(0, 0)
self.power2_pu = complex(0, 0)
def __str__(self):
str = 'class=Branch\n'
attributes = self.__dict__
for key in attributes.keys():
str = str + key + '={}\n'.format(attributes[key])
return str + key + '={}\n'.format(attributes[key])
return str
class TimeSeries:
""" A TimeSeries object always consists of timestamps and datapoints.
"""
def __init__(self, name, time, values, label=""):
self.time = np.array(time)
self.values = np.array(values)
self.name = name
self.label = name
class Results():
def __init__(self, system):
self.nodes = []
self.branches = []
self.Ymatrix = system.Ymatrix
self.Bmatrix = system.Bmatrix
for node in system.nodes:
if node.ideal_connected_with == '':
self.nodes.append(ResultsNode(topo_node=node))
for branch in system.branches:
self.branches.append(ResultsBranch(topo_branch=branch))
def get_node_by_index(self, index):
"""
return the node with node.index==index
"""
for node in self.nodes:
if (node.topology_node.index==index):
return node
return None
def read_timeseries_csv(self, filename, timeseries_names=None, print_status=True):
"""Reads complex time series data from a CSV file. Real and
imaginary part are stored in one complex variable.
:param filename: name of the csv file that has the data
:param timeseries_names: column name which should be read
:return: list of Timeseries objects
"""
pd_df = pd.read_csv(filename)
timeseries_list = {}
cmpl_result_columns = []
real_result_columns = []
if timeseries_names is None:
# No column names specified, thus read in all and strip off spaces
pd_df.rename(columns=lambda x: x.strip(), inplace=True)
column_names = list(pd_df.columns.values)
# Remove timestamps column name and store separately
column_names.remove('time')
timestamps = pd_df.iloc[:, 0]
# Find real and complex variable names
suffixes = [ ('_re', '_im'), ('.re', '.im'), ('.real', '.imag') ]
for column in column_names:
is_complex = False
for suffix in suffixes:
real_suffix = suffix[0]
imag_suffix = suffix[1]
if column.endswith(imag_suffix):
is_complex = True
break # Ignore imag columns
if column.endswith(real_suffix):
is_complex = True
column_base = column.replace(real_suffix, '')
if column_base + imag_suffix not in column_names:
continue
cmpl_result_columns.append(column_base)
timeseries_list[column_base] = TimeSeries(column_base, timestamps,
np.vectorize(complex)(
pd_df[column_base + real_suffix],
pd_df[column_base + imag_suffix]
)
)
break
if is_complex:
continue
real_result_columns.append(column)
timeseries_list[column] = TimeSeries(column, timestamps, pd_df[column])
else:
# Read in specified time series
print('cannot read specified columns yet')
if print_status :
print('column number: ' + str(len(timeseries_list)))
print('results length: ' + str(len(timestamps)))
print('real column names: ' + str(real_result_columns))
print('complex column names: ' + str(cmpl_result_columns))
return timeseries_list
def read_data(self, file_name, pu=False):
"""
read the voltages from a CSV input file
@param file_name
@param pu: - True if voltages are expressed in per unit system
"""
loadflow_results = self.read_timeseries_csv(file_name, print_status=False)
if pu == True:
for node in self.nodes:
node.voltage_pu = loadflow_results[node.topology_node.uuid].values[0]
node.voltage = node.voltage_pu * node.topology_node.baseVoltage
elif pu == False:
for node in self.nodes:
node.voltage = loadflow_results[node.topology_node.uuid].values[0]
node.voltage_pu = node.voltage / node.topology_node.baseVoltage
def load_voltages(self, V):
"""
Load the voltages of V-array (result of powerflow_cim.solve)
"""
for index in range(len(V)):
node = self.get_node_by_index(index)
node.voltage_pu = V[index]
node.voltage = node.voltage_pu * node.topology_node.baseVoltage
def load_currents(self, I_est):
"""
Load estimated branch currents into Results.
@param I_est: Array of complex currents (per-unit) from state estimation
"""
if len(I_est) != len(self.branches):
raise ValueError("Length of I_est must match number of branches.")
for i, branch in enumerate(self.branches):
branch.current_pu = I_est[i]
branch.current = branch.current_pu * branch.topology_branch.base_current
def calculate_all(self):
"""Calculate all quantities of the grid from currents or voltages."""
# If currents are loaded, compute voltages first
if any(branch.current_pu != 0 for branch in self.branches):
Yinv = np.linalg.pinv(self.Ymatrix)
I_inj = np.zeros(len(self.nodes), dtype=complex)
for branch in self.branches:
I_inj[branch.topology_branch.start_node.index] -= branch.current_pu
I_inj[branch.topology_branch.end_node.index] += branch.current_pu
V = Yinv @ I_inj
for i, node in enumerate(self.nodes):
node.voltage_pu = V[i]
node.voltage = node.voltage_pu * node.topology_node.baseVoltage
# Then calculate other quantities
self.calculateI()
self.calculateIinj()
self.calculateSinj()
self.calculateS1()
self.calculateS2()
def calculateI(self):
"""
To calculate the branch currents
Note: branch current flowing into start node coming from end node
"""
for branch in self.branches:
fr = branch.topology_branch.start_node.index
to = branch.topology_branch.end_node.index
branch.current_pu = - (self.nodes[fr].voltage_pu - self.nodes[to].voltage_pu) * self.Ymatrix[fr][to] + 1j*self.Bmatrix[fr][to] * self.nodes[fr].voltage_pu
branch.current = branch.current_pu * branch.topology_branch.base_current
def calculateIinj(self):
"""
Calculate current injections at a node
Note: node current flowing into the node
"""
for node in self.nodes:
to = complex(0, 0) # sum of the currents flowing to the node
fr = complex(0, 0) # sum of the currents flowing from the node
for branch in self.branches:
if node.topology_node.index == branch.topology_branch.start_node.index:
fr = fr + branch.current_pu
if node.topology_node.index == branch.topology_branch.end_node.index:
to = to + branch.current_pu
node.current_pu = fr - to
node.current = node.current_pu * node.topology_node.base_current
def calculateSinj(self):
"""
calculate power injection at a node
"""
for node in self.nodes:
node.power_pu = node.voltage_pu * np.conj(node.current_pu)
node.power = node.power_pu * node.topology_node.base_apparent_power
def calculateS1(self):
"""
calculate complex power flow at branch, measured at initial node
"""
for branch in self.branches:
branch_index = branch.topology_branch.start_node.index
for node in self.nodes:
if branch_index == node.topology_node.index:
branch.power_pu = node.voltage_pu * (np.conj(branch.current_pu))
branch.power = branch.power_pu * branch.topology_branch.base_apparent_power
def calculateS2(self):
"""
calculate complex ower flow at branch, measured at final node
"""
for branch in self.branches:
branch_index = branch.topology_branch.end_node.index
for node in self.nodes:
if branch_index == node.topology_node.index:
branch.power2_pu = -node.voltage_pu * (np.conj(branch.current_pu))
branch.power2 = branch.power2_pu * branch.topology_branch.base_apparent_power
def get_node(self, index=None, uuid=None):
"""
returns a PowerflowNode with a certain uuid or a certain index (not both!):
- if index in not None --> return the PowerflowNode with PowerflowNode.topology_node.index == index
- if uuid in not None --> return the PowerflowNode with PowerflowNode.topology_node.uuid == uuid
"""
if index is not None:
for node in self.nodes:
if index == node.topology_node.index:
return node
elif uuid is not None:
for node in self.nodes:
if uuid == node.topology_node.uuid:
return node
def get_branch(self, uuid):
"""
returns a PowerflowBranch with a certain uuid
"""
for branch in self.branches:
if uuid == branch.topology_branch.uuid:
return branch
def get_voltages(self, pu=True):
"""
get node voltages
- if pu==True --> voltages are expressed as per-unit
"""
voltages = np.zeros(len(self.nodes), dtype=complex)
if pu == True:
for node in self.nodes:
voltages[node.topology_node.index] = node.voltage_pu
elif pu == False:
for node in self.nodes:
voltages[node.topology_node.index] = node.voltage
return voltages
def get_branch_powers(self, pu=True):
"""
get branch powers
- if pu==True --> branch powers are expressed as per-unit
"""
#branch_powers = np.zeros(len(self.branches), dtype=np.complex_)
branch_powers = []
if pu == True:
for branch in self.branches:
branch_powers.append(branch.power_pu)
elif pu == False:
for branch in self.branches:
branch_powers.append(branch.power)
return branch_powers
def get_Iinj(self, pu=True):
"""
get node currents
- if pu==True --> voltages are expressed as per-unit
"""
Iinj = np.zeros(len(self.nodes), dtype=complex)
if pu == True:
for node in self.nodes:
Iinj[node.topology_node.index] = node.current_pu
elif pu == False:
for node in self.nodes:
Iinj[node.topology_node.index] = node.current
return Iinj
def get_Sinj(self, pu=True):
"""
get node power
- if pu==True --> voltages are expressed as per-unit
"""
Sinj = np.zeros(len(self.nodes), dtype=complex)
if pu == True:
for node in self.nodes:
Sinj[node.topology_node.index] = node.power_pu
elif pu == False:
for node in self.nodes:
Sinj[node.topology_node.index] = node.power
return Sinj
def getI(self, pu=True):
"""Get branch currents."""
I = np.zeros(len(self.branches), dtype=complex)
if pu:
for i, branch in enumerate(self.branches):
I[i] = branch.current_pu
else:
for i, branch in enumerate(self.branches):
I[i] = branch.current
return I
def get_S1(self, pu=True):
"""
get complex Power flow at branch, measured at initial node
- if pu==True --> voltages are expressed as per-unit
"""
S1 = np.zeros(len(self.branches), dtype=complex)
if pu == True:
for branch_idx in range(len(self.branches)):
S1[branch_idx] = self.branches[branch_idx].power_pu
elif pu == False:
for branch_idx in range(len(self.branches)):
S1[branch_idx] = self.branches[branch_idx].power
return S1
def get_S2(self, pu=True):
"""
get complex Power flow at branch, measured at final node
- if pu==True --> voltages are expressed as per-unit
"""
S2 = np.zeros(len(self.branches), dtype=complex)
if pu == True:
for branch_idx in range(len(self.branches)):
S2[branch_idx] = self.branches[branch_idx].power2_pu
elif pu == False:
for branch_idx in range(len(self.branches)):
S2[branch_idx] = self.branches[branch_idx].power2
return S2
def print_voltages_polar(self):
"""
for test purposes
"""
for node in self.nodes:
print(node.topology_node.uuid + " = " + str(cmath.polar(node.voltage)))
INFO:cimpy.cimimport:START of parsing file "/home/ubuntu/code/CIM_Read/pyvolt-docker/examples/sample_data/AD102425N.xml"
INFO:cimpy.cimimport:START of parsing file "/home/ubuntu/code/CIM_Read/pyvolt-docker/examples/sample_data/AD106025N.xml"
INFO:cimpy.cimimport:END of parsing file "/home/ubuntu/code/CIM_Read/pyvolt-docker/examples/sample_data/AD102425N.xml"
INFO:cimpy.cimimport:END of parsing file "/home/ubuntu/code/CIM_Read/pyvolt-docker/examples/sample_data/AD106025N.xml"
WARNING:cimpy.cimimport:Package information not found for class type : 275 times
WARNING:cimpy.cimimport:Package information not found for class SvPowerFlow, attribute p : 11 times
WARNING:cimpy.cimimport:Package information not found for class SvPowerFlow, attribute q : 11 times
WARNING:cimpy.cimimport:Package information not found for class SvPowerFlow, attribute Terminal : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute name : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute x : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute r : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute gch : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute bch : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute length : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute BaseVoltage : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute aggregate : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute EquipmentContainer : 11 times
WARNING:cimpy.cimimport:Package information not found for class Terminal, attribute ConductingEquipment : 95 times
WARNING:cimpy.cimimport:'Terminal' has not attribute 'ConnectivityNode' : 95 times
WARNING:cimpy.cimimport:Package information not found for class Terminal, attribute name : 95 times
WARNING:cimpy.cimimport:Package information not found for class Terminal, attribute connected : 95 times
WARNING:cimpy.cimimport:Package information not found for class Terminal, attribute sequenceNumber : 95 times
WARNING:cimpy.cimimport:Referenced Terminal [PhaseCode.ABC] object missing. : 95 times
WARNING:cimpy.cimimport:Package information not found for class Terminal, attribute TopologicalNode : 51 times
WARNING:cimpy.cimimport:'ConnectivityNode' has not attribute 'name' : 35 times
WARNING:cimpy.cimimport:'ConnectivityNode' has not attribute 'ConnectivityNodeContainer' : 35 times
WARNING:cimpy.cimimport:Package information not found for class Disconnector, attribute name : 25 times
WARNING:cimpy.cimimport:Package information not found for class Disconnector, attribute BaseVoltage : 25 times
WARNING:cimpy.cimimport:Package information not found for class Disconnector, attribute EquipmentContainer : 25 times
WARNING:cimpy.cimimport:Package information not found for class Disconnector, attribute normalOpen : 25 times
WARNING:cimpy.cimimport:Package information not found for class SvVoltage, attribute v : 13 times
WARNING:cimpy.cimimport:Package information not found for class SvVoltage, attribute angle : 13 times
WARNING:cimpy.cimimport:Package information not found for class SvVoltage, attribute TopologicalNode : 13 times
WARNING:cimpy.cimimport:Package information not found for class ExternalNetworkInjection, attribute aggregate : 2 times
WARNING:cimpy.cimimport:Package information not found for class ExternalNetworkInjection, attribute name : 2 times
WARNING:cimpy.cimimport:Package information not found for class ExternalNetworkInjection, attribute EquipmentContainer : 2 times
WARNING:cimpy.cimimport:Package information not found for class TopologicalNode, attribute name : 13 times
WARNING:cimpy.cimimport:Package information not found for class TopologicalNode, attribute ConnectivityNodeContainer : 13 times
WARNING:cimpy.cimimport:Package information not found for class TopologicalNode, attribute TopologicalIsland : 13 times
WARNING:cimpy.cimimport:Package information not found for class TopologicalNode, attribute BaseVoltage : 13 times
WARNING:cimpy.cimimport:Package information not found for class VoltageLevel, attribute BaseVoltage : 14 times
WARNING:cimpy.cimimport:Package information not found for class VoltageLevel, attribute name : 14 times
WARNING:cimpy.cimimport:Package information not found for class VoltageLevel, attribute Substation : 14 times
WARNING:cimpy.cimimport:Package information not found for class BaseVoltage, attribute nominalVoltage : 2 times
WARNING:cimpy.cimimport:Package information not found for class BaseVoltage, attribute name : 2 times
WARNING:cimpy.cimimport:Package information not found for class EnergyConsumer, attribute name : 11 times
WARNING:cimpy.cimimport:Package information not found for class EnergyConsumer, attribute EquipmentContainer : 11 times
WARNING:cimpy.cimimport:Package information not found for class EnergyConsumer, attribute aggregate : 11 times
WARNING:cimpy.cimimport:'EnergyConsumer' has not attribute 'pfixed' : 11 times
WARNING:cimpy.cimimport:'EnergyConsumer' has not attribute 'qfixed' : 11 times
WARNING:cimpy.cimimport:Package information not found for class GeographicalRegion, attribute name : 2 times
WARNING:cimpy.cimimport:Package information not found for class Substation, attribute name : 13 times
WARNING:cimpy.cimimport:Package information not found for class Substation, attribute Region : 13 times
WARNING:cimpy.cimimport:Package information not found for class Line, attribute name : 11 times
WARNING:cimpy.cimimport:Package information not found for class Line, attribute Region : 11 times
WARNING:cimpy.cimimport:Package information not found for class SubGeographicalRegion, attribute name : 2 times
WARNING:cimpy.cimimport:Package information not found for class SubGeographicalRegion, attribute Region : 2 times
WARNING:cimpy.cimimport:Package information not found for class BusbarSection, attribute name : 13 times
WARNING:cimpy.cimimport:Package information not found for class BusbarSection, attribute EquipmentContainer : 13 times
WARNING:cimpy.cimimport:Package information not found for class BusbarSection, attribute BaseVoltage : 13 times
WARNING:cimpy.cimimport:Package information not found for class TopologicalIsland, attribute name : 2 times
INFO:cimpy.cimimport:CIM object SvPowerFlow created : 11 times
INFO:cimpy.cimimport:CIM object ACLineSegment created : 11 times
INFO:cimpy.cimimport:CIM object Terminal created : 95 times
INFO:cimpy.cimimport:CIM object ConnectivityNode created : 35 times
INFO:cimpy.cimimport:CIM object Disconnector created : 25 times
INFO:cimpy.cimimport:CIM object SvVoltage created : 13 times
INFO:cimpy.cimimport:CIM object ExternalNetworkInjection created : 2 times
INFO:cimpy.cimimport:CIM object TopologicalNode created : 13 times
INFO:cimpy.cimimport:CIM object VoltageLevel created : 14 times
INFO:cimpy.cimimport:CIM object BaseVoltage created : 2 times
INFO:cimpy.cimimport:CIM object EnergyConsumer created : 11 times
INFO:cimpy.cimimport:CIM object GeographicalRegion created : 2 times
INFO:cimpy.cimimport:CIM object Substation created : 13 times
INFO:cimpy.cimimport:CIM object Line created : 11 times
INFO:cimpy.cimimport:CIM object SubGeographicalRegion created : 2 times
INFO:cimpy.cimimport:CIM object BusbarSection created : 13 times
INFO:cimpy.cimimport:CIM object TopologicalIsland created : 2 times
INFO:cimpy.cimimport:Created totally 275 CIM objects in 0.020636320114135742s
...@@ -7,17 +7,18 @@ import cimpy ...@@ -7,17 +7,18 @@ import cimpy
import os import os
logging.basicConfig(filename='run_nv_powerflow.log', level=logging.INFO, filemode='w') logging.basicConfig(filename='run_nv_powerflow.log', level=logging.INFO, filemode='w')
#python starts as module in subdirectory, 2 folders up to set the new path #python starts as module in subdirectory, 2 folders up to set the new path
this_file_folder = Path(__file__).parents[2] this_file_folder = Path(__file__).parents[2]
p = str(this_file_folder)+"/examples/sample_data/areti" p = str(this_file_folder)+"/examples/sample_data"
xml_path = Path(p) xml_path = Path(p)
xml_files = [os.path.join(xml_path, "1.xml"), xml_files = [os.path.join(xml_path, "AD102425N.xml"),
os.path.join(xml_path, "2.xml"), os.path.join(xml_path, "AD106025N.xml")
os.path.join(xml_path, "3.xml")
] ]
# Read cim files and create new network.System object # Read cim files and create new network.System object
...@@ -25,7 +26,7 @@ res = cimpy.cim_import(xml_files, "cgmes_v2_4_15") ...@@ -25,7 +26,7 @@ res = cimpy.cim_import(xml_files, "cgmes_v2_4_15")
system = network.System() system = network.System()
base_apparent_power = 25 # MW base_apparent_power = 25 # MW
system.load_cim_data(res['topology'], base_apparent_power) system.load_cim_data(res['topology'], base_apparent_power)
# system.print_branch()
# Execute power flow analysis # Execute power flow analysis
results_pf, num_iter = nv_powerflow.solve(system) results_pf, num_iter = nv_powerflow.solve(system)
......
This diff is collapsed.
This diff is collapsed.
...@@ -369,7 +369,25 @@ class System(): ...@@ -369,7 +369,25 @@ class System():
for node in self.nodes: for node in self.nodes:
print('{} {}'.format(node.name, node.power)) print('{} {}'.format(node.name, node.power))
def print_branch_names(self):
for branch in self.branches:
print('{}'.format(branch.uuid))
# startNode= branch.start_node
# endNode= branch.end_node
print('from bus {} to bus {}'.format(branch.start_node.name, branch.end_node.name))
print('---------------------------------------------------------')
def print_branch_index(self):
for branch in self.branches:
print('{}'.format(branch.uuid))
# startNode= branch.start_node
# endNode= branch.end_node
print('from bus {} to bus {}'.format(branch.start_node.index, branch.end_node.index))
print('---------------------------------------------------------')
def print_breaker_names(self):
for breaker in self.breakers:
print('{} {}'.format(breaker.name, breaker.index))
def load_from_m_file(self, file_path): def load_from_m_file(self, file_path):
""" """
......
INFO:cimpy.cimimport:START of parsing file "/home/ubuntu/code/CIM_Read/pyvolt-docker/examples/sample_data/AD102425N.xml"
INFO:cimpy.cimimport:START of parsing file "/home/ubuntu/code/CIM_Read/pyvolt-docker/examples/sample_data/AD106025N.xml"
INFO:cimpy.cimimport:END of parsing file "/home/ubuntu/code/CIM_Read/pyvolt-docker/examples/sample_data/AD102425N.xml"
INFO:cimpy.cimimport:END of parsing file "/home/ubuntu/code/CIM_Read/pyvolt-docker/examples/sample_data/AD106025N.xml"
WARNING:cimpy.cimimport:Package information not found for class type : 275 times
WARNING:cimpy.cimimport:Package information not found for class SvPowerFlow, attribute p : 11 times
WARNING:cimpy.cimimport:Package information not found for class SvPowerFlow, attribute q : 11 times
WARNING:cimpy.cimimport:Package information not found for class SvPowerFlow, attribute Terminal : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute name : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute x : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute r : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute gch : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute bch : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute length : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute BaseVoltage : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute aggregate : 11 times
WARNING:cimpy.cimimport:Package information not found for class ACLineSegment, attribute EquipmentContainer : 11 times
WARNING:cimpy.cimimport:Package information not found for class Terminal, attribute ConductingEquipment : 95 times
WARNING:cimpy.cimimport:'Terminal' has not attribute 'ConnectivityNode' : 95 times
WARNING:cimpy.cimimport:Package information not found for class Terminal, attribute name : 95 times
WARNING:cimpy.cimimport:Package information not found for class Terminal, attribute connected : 95 times
WARNING:cimpy.cimimport:Package information not found for class Terminal, attribute sequenceNumber : 95 times
WARNING:cimpy.cimimport:Referenced Terminal [PhaseCode.ABC] object missing. : 95 times
WARNING:cimpy.cimimport:Package information not found for class Terminal, attribute TopologicalNode : 51 times
WARNING:cimpy.cimimport:'ConnectivityNode' has not attribute 'name' : 35 times
WARNING:cimpy.cimimport:'ConnectivityNode' has not attribute 'ConnectivityNodeContainer' : 35 times
WARNING:cimpy.cimimport:Package information not found for class Disconnector, attribute name : 25 times
WARNING:cimpy.cimimport:Package information not found for class Disconnector, attribute BaseVoltage : 25 times
WARNING:cimpy.cimimport:Package information not found for class Disconnector, attribute EquipmentContainer : 25 times
WARNING:cimpy.cimimport:Package information not found for class Disconnector, attribute normalOpen : 25 times
WARNING:cimpy.cimimport:Package information not found for class SvVoltage, attribute v : 13 times
WARNING:cimpy.cimimport:Package information not found for class SvVoltage, attribute angle : 13 times
WARNING:cimpy.cimimport:Package information not found for class SvVoltage, attribute TopologicalNode : 13 times
WARNING:cimpy.cimimport:Package information not found for class ExternalNetworkInjection, attribute aggregate : 2 times
WARNING:cimpy.cimimport:Package information not found for class ExternalNetworkInjection, attribute name : 2 times
WARNING:cimpy.cimimport:Package information not found for class ExternalNetworkInjection, attribute EquipmentContainer : 2 times
WARNING:cimpy.cimimport:Package information not found for class TopologicalNode, attribute name : 13 times
WARNING:cimpy.cimimport:Package information not found for class TopologicalNode, attribute ConnectivityNodeContainer : 13 times
WARNING:cimpy.cimimport:Package information not found for class TopologicalNode, attribute TopologicalIsland : 13 times
WARNING:cimpy.cimimport:Package information not found for class TopologicalNode, attribute BaseVoltage : 13 times
WARNING:cimpy.cimimport:Package information not found for class VoltageLevel, attribute BaseVoltage : 14 times
WARNING:cimpy.cimimport:Package information not found for class VoltageLevel, attribute name : 14 times
WARNING:cimpy.cimimport:Package information not found for class VoltageLevel, attribute Substation : 14 times
WARNING:cimpy.cimimport:Package information not found for class BaseVoltage, attribute nominalVoltage : 2 times
WARNING:cimpy.cimimport:Package information not found for class BaseVoltage, attribute name : 2 times
WARNING:cimpy.cimimport:Package information not found for class EnergyConsumer, attribute name : 11 times
WARNING:cimpy.cimimport:Package information not found for class EnergyConsumer, attribute EquipmentContainer : 11 times
WARNING:cimpy.cimimport:Package information not found for class EnergyConsumer, attribute aggregate : 11 times
WARNING:cimpy.cimimport:'EnergyConsumer' has not attribute 'pfixed' : 11 times
WARNING:cimpy.cimimport:'EnergyConsumer' has not attribute 'qfixed' : 11 times
WARNING:cimpy.cimimport:Package information not found for class GeographicalRegion, attribute name : 2 times
WARNING:cimpy.cimimport:Package information not found for class Substation, attribute name : 13 times
WARNING:cimpy.cimimport:Package information not found for class Substation, attribute Region : 13 times
WARNING:cimpy.cimimport:Package information not found for class Line, attribute name : 11 times
WARNING:cimpy.cimimport:Package information not found for class Line, attribute Region : 11 times
WARNING:cimpy.cimimport:Package information not found for class SubGeographicalRegion, attribute name : 2 times
WARNING:cimpy.cimimport:Package information not found for class SubGeographicalRegion, attribute Region : 2 times
WARNING:cimpy.cimimport:Package information not found for class BusbarSection, attribute name : 13 times
WARNING:cimpy.cimimport:Package information not found for class BusbarSection, attribute EquipmentContainer : 13 times
WARNING:cimpy.cimimport:Package information not found for class BusbarSection, attribute BaseVoltage : 13 times
WARNING:cimpy.cimimport:Package information not found for class TopologicalIsland, attribute name : 2 times
INFO:cimpy.cimimport:CIM object SvPowerFlow created : 11 times
INFO:cimpy.cimimport:CIM object ACLineSegment created : 11 times
INFO:cimpy.cimimport:CIM object Terminal created : 95 times
INFO:cimpy.cimimport:CIM object ConnectivityNode created : 35 times
INFO:cimpy.cimimport:CIM object Disconnector created : 25 times
INFO:cimpy.cimimport:CIM object SvVoltage created : 13 times
INFO:cimpy.cimimport:CIM object ExternalNetworkInjection created : 2 times
INFO:cimpy.cimimport:CIM object TopologicalNode created : 13 times
INFO:cimpy.cimimport:CIM object VoltageLevel created : 14 times
INFO:cimpy.cimimport:CIM object BaseVoltage created : 2 times
INFO:cimpy.cimimport:CIM object EnergyConsumer created : 11 times
INFO:cimpy.cimimport:CIM object GeographicalRegion created : 2 times
INFO:cimpy.cimimport:CIM object Substation created : 13 times
INFO:cimpy.cimimport:CIM object Line created : 11 times
INFO:cimpy.cimimport:CIM object SubGeographicalRegion created : 2 times
INFO:cimpy.cimimport:CIM object BusbarSection created : 13 times
INFO:cimpy.cimimport:CIM object TopologicalIsland created : 2 times
INFO:cimpy.cimimport:Created totally 275 CIM objects in 0.040792226791381836s
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment