# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
# SPDX-License-Identifier: MPL-2.0
import numpy as np
import pandas as pd
from VeraGridEngine.Simulations.results_table import ResultsTable
from VeraGridEngine.Simulations.results_template import ResultsTemplate, ResultsProperty
from VeraGridEngine.basic_structures import IntVec, Vec, StrVec, Mat, CxVec
from VeraGridEngine.enumerations import StudyResultsType, ResultTypes, DeviceType
[docs]
class LinearAnalysisResults(ResultsTemplate):
"""
LinearAnalysisResults
"""
LOCAL_RESULTS_DECLARATIONS = (
ResultsProperty(name='branch_names', tpe=StrVec, old_names=list(), expandable=False),
ResultsProperty(name='bus_names', tpe=StrVec, old_names=list(), expandable=False),
ResultsProperty(name='hvdc_names', tpe=StrVec, old_names=list(), expandable=False),
ResultsProperty(name='vsc_names', tpe=StrVec, old_names=list(), expandable=False),
ResultsProperty(name='bus_types', tpe=IntVec, old_names=list(), expandable=False),
ResultsProperty(name='PTDF', tpe=Mat, old_names=list(), expandable=False),
ResultsProperty(name='LODF', tpe=Mat, old_names=list(), expandable=False),
ResultsProperty(name='HvdcDF', tpe=Mat, old_names=list(), expandable=False),
ResultsProperty(name='HvdcODF', tpe=Mat, old_names=list(), expandable=False),
ResultsProperty(name='VscDF', tpe=Mat, old_names=list(), expandable=False),
ResultsProperty(name='VscODF', tpe=Mat, old_names=list(), expandable=False),
ResultsProperty(name='Sf', tpe=Vec, old_names=list(), expandable=False),
ResultsProperty(name='Sbus', tpe=Vec, old_names=list(), expandable=False),
ResultsProperty(name='voltage', tpe=CxVec, old_names=list(), expandable=False),
ResultsProperty(name='loading', tpe=Vec, old_names=list(), expandable=False),
)
__slots__ = (
"branch_names",
"bus_names",
"hvdc_names",
"vsc_names",
"bus_types",
"PTDF",
"LODF",
"HvdcDF",
"HvdcODF",
"VscDF",
"VscODF",
"Sf",
"Sbus",
"voltage",
"loading",
)
def __init__(self,
br_names=(), bus_names=(), hvdc_names=(), vsc_names=(),
bus_types=()):
"""
PTDF and LODF results class
:param br_names: branch names
:param bus_names: bus names
:param hvdc_names: HVDC names
:param vsc_names: VSC names
:param bus_types: bus types array
"""
ResultsTemplate.__init__(self,
name='Linear Analysis',
available_results={
ResultTypes.BusResults: [
ResultTypes.PTDF,
ResultTypes.BusActivePower
],
ResultTypes.BranchResults: [
ResultTypes.LODF,
ResultTypes.BranchActivePowerFrom,
ResultTypes.BranchLoading],
ResultTypes.HvdcResults: [
ResultTypes.HvdcPTDF,
ResultTypes.HvdcODF,
],
ResultTypes.VscResults: [
ResultTypes.VscPTDF,
ResultTypes.VscODF,
]
},
time_array=None,
clustering_results=None,
study_results_type=StudyResultsType.LinearAnalysis)
n_br = len(bus_names)
n_bus = len(br_names)
n_hvdc = len(hvdc_names)
n_vsc = len(vsc_names)
# names of the Branches
self.branch_names: StrVec = br_names
self.bus_names: StrVec = bus_names
self.hvdc_names: StrVec = hvdc_names
self.vsc_names: StrVec = vsc_names
self.bus_types: IntVec = bus_types
self.PTDF: Mat = np.zeros((n_br, n_bus))
self.LODF: Mat = np.zeros((n_br, n_br))
self.HvdcDF: Mat = np.zeros((n_hvdc, n_bus))
self.HvdcODF: Mat = np.zeros((n_br, n_hvdc))
self.VscDF: Mat = np.zeros((n_vsc, n_bus))
self.VscODF: Mat = np.zeros((n_br, n_vsc))
self.Sf: Vec = np.zeros(self.n_br)
self.Sbus: Vec = np.zeros(self.n_bus)
self.voltage: CxVec = np.ones(self.n_bus, dtype=complex)
self.loading: Vec = np.zeros(self.n_br)
@property
def n_br(self):
"""
Branch number
:return:
"""
return self.PTDF.shape[0]
@property
def n_bus(self):
"""
Bus number
:return:
"""
return self.PTDF.shape[1]
[docs]
def get_bus_df(self) -> pd.DataFrame:
"""
Get a DataFrame with the buses results
:return: DataFrame
"""
return pd.DataFrame(data={'Vm': np.abs(self.voltage),
'Va': np.angle(self.voltage, deg=True),
'P': self.Sbus.real,
'Q': self.Sbus.imag},
index=self.bus_names)
[docs]
def get_branch_df(self) -> pd.DataFrame:
"""
Get a DataFrame with the branches results
:return: DataFrame
"""
return pd.DataFrame(data={'Pf': self.Sf.real,
'loading': self.loading.real * 100.0},
index=self.branch_names)
[docs]
def mdl(self, result_type: ResultTypes) -> ResultsTable:
"""
Plot the results.
Arguments:
**result_type**: ResultTypes
Returns: ResultsModel
"""
if result_type == ResultTypes.PTDF:
title = 'Branches sensitivity'
return ResultsTable(data=self.PTDF,
index=self.branch_names,
idx_device_type=DeviceType.BranchDevice,
columns=self.bus_names,
cols_device_type=DeviceType.BusDevice,
title=title,
ylabel='(p.u.)',
units='(p.u.)')
elif result_type == ResultTypes.LODF:
title = 'Branch failure sensitivity'
return ResultsTable(data=self.LODF,
index=self.branch_names,
idx_device_type=DeviceType.BranchDevice,
columns=self.branch_names,
cols_device_type=DeviceType.BranchDevice,
title=title,
ylabel='(p.u.)',
units='(p.u.)')
elif result_type == ResultTypes.HvdcPTDF:
return ResultsTable(data=self.HvdcDF,
index=self.branch_names,
idx_device_type=DeviceType.BranchDevice,
columns=self.hvdc_names,
cols_device_type=DeviceType.HVDCLineDevice,
title=result_type.value,
ylabel='(p.u.)',
units='(p.u.)')
elif result_type == ResultTypes.HvdcODF:
return ResultsTable(data=self.HvdcODF,
index=self.branch_names,
idx_device_type=DeviceType.BranchDevice,
columns=self.hvdc_names,
cols_device_type=DeviceType.HVDCLineDevice,
title=result_type.value,
ylabel='(p.u.)',
units='(p.u.)')
elif result_type == ResultTypes.VscPTDF:
return ResultsTable(data=self.VscDF,
index=self.branch_names,
idx_device_type=DeviceType.BranchDevice,
columns=self.vsc_names,
cols_device_type=DeviceType.VscDevice,
title=result_type.value,
ylabel='(p.u.)',
units='(p.u.)')
elif result_type == ResultTypes.VscODF:
return ResultsTable(data=self.VscODF,
index=self.branch_names,
idx_device_type=DeviceType.BranchDevice,
columns=self.vsc_names,
cols_device_type=DeviceType.VscDevice,
title=result_type.value,
ylabel='(p.u.)',
units='(p.u.)')
elif result_type == ResultTypes.BranchActivePowerFrom:
return ResultsTable(data=self.Sf,
index=self.branch_names,
idx_device_type=DeviceType.BranchDevice,
columns=[result_type.value],
cols_device_type=DeviceType.NoDevice,
title=result_type.value,
ylabel='(MW)',
units='(MW)')
elif result_type == ResultTypes.BranchLoading:
return ResultsTable(data=self.loading * 100.0,
index=self.branch_names,
idx_device_type=DeviceType.BranchDevice,
columns=[result_type.value],
cols_device_type=DeviceType.NoDevice,
title=result_type.value,
ylabel='(%)',
units='(%)')
elif result_type == ResultTypes.BusActivePower:
return ResultsTable(data=self.Sbus,
index=self.bus_names,
idx_device_type=DeviceType.BusDevice,
columns=[result_type.value],
cols_device_type=DeviceType.NoDevice,
title=result_type.value,
ylabel='(MW)',
units='(MW)')
else:
raise Exception('Result type not understood:' + str(result_type))