Skip to content
Snippets Groups Projects

Revised ResourcePrice class and methods. Added tests for problem...

15 files
+ 5728
13165
Compare changes
  • Side-by-side
  • Inline

Files

+ 231
380
# -*- coding: utf-8 -*-
"""
Created on Wed Nov 17 13:04:53 2021
@author: pmede
"""
# standard libraries
# local libraries, external
import numpy as np
# local libraries, internal
from .dynsys import DynamicSystem
from .signal import Signal, FixedSignal
from .time import TimeFrame
#******************************************************************************
#******************************************************************************
# objectives:
# 1) organise information for optimisation
# 2) upload optimisation results and compute the various objectives
# 3) retrieve information
# 4)
# *****************************************************************************
# *****************************************************************************
# TODO: create constant terms using fixed signals
class Converter:
"""A class for modular dynamic systems in an integrated energy system."""
def __init__(self,
# converter name/key
key,
# input options:
# 1) DynamicSystem object
# 2) Matrices
def __init__(
self,
# system information
sys: DynamicSystem,
# time frame
time_frame: TimeFrame,
# initial conditions
initial_states: np.array,
# optimisation-relevant parameters
@@ -47,6 +37,14 @@ class Converter:
outputs: list or Signal = None,
# information about states
states: list or Signal = None,
# final A matrix dict: a_nnk
a_nnk: dict = None,
# final B matrix dict: b_nmk
b_nmk: dict = None,
# final C matrix dict: c_rnk
c_rnk: dict = None,
# final D matrix dict: d_rmk
d_rmk: dict = None,
# input amplitude costs
input_specific_amplitude_costs: dict = None,
# output amplitude costs
@@ -57,59 +55,60 @@ class Converter:
# externalities due
input_specific_externality_costs: dict = None, # one for every input
output_specific_externality_costs: dict = None, # one for every input, then another for every time interval
state_specific_externality_costs: dict = None # one for every output, then another for every time interval
state_specific_externality_costs: dict = None, # one for every output, then another for every time interval
):
# *********************************************************************
#**********************************************************************
self.sys = sys
self.key = key
# *********************************************************************
self.sys = sys
if type(a_nnk) == dict:
self.a_nnk = a_nnk # dict(a_nnk)
if type(b_nmk) == dict:
self.b_nmk = b_nmk # dict(b_nmk)
#**********************************************************************
if type(c_rnk) == dict:
self.c_rnk = c_rnk # dict(c_rnk)
if type(d_rmk) == dict:
self.d_rmk = d_rmk # dict(d_rmk)
# *********************************************************************
# inputs
if type(inputs) == list:
self.inputs = inputs
elif isinstance(inputs, Signal):
self.inputs = [inputs]
else:
raise TypeError('Unknown format for input signals.')
raise TypeError("Unknown format for input signals.")
# outputs
if type(outputs) == list:
self.outputs = outputs
elif isinstance(outputs, Signal):
self.outputs = [outputs]
else:
raise TypeError('Unknown format for output signals.')
raise TypeError("Unknown format for output signals.")
# states
if type(states) == list:
self.states = states
elif isinstance(states, Signal):
self.states = [states]
else:
raise TypeError('Unknown format for state signals.')
raise TypeError("Unknown format for state signals.")
self.initial_states = initial_states
@@ -117,7 +116,7 @@ class Converter:
self.fixed_inputs = self.identify_fixed_signals(self.inputs)
#**********************************************************************
# *********************************************************************
# amplitude costs: one per signal
@@ -129,31 +128,23 @@ class Converter:
# externality costs: one per signal and time interval
self.input_specific_externality_costs = (
input_specific_externality_costs
)
self.input_specific_externality_costs = input_specific_externality_costs
self.state_specific_externality_costs = (
state_specific_externality_costs
)
self.state_specific_externality_costs = state_specific_externality_costs
self.output_specific_externality_costs = (
output_specific_externality_costs
)
self.output_specific_externality_costs = output_specific_externality_costs
#**********************************************************************
#**********************************************************************
# *********************************************************************
# *********************************************************************
# identify the signals with specific amplitude costs
# inputs
if type(self.input_specific_amplitude_costs) == type(None):
self.amplitude_penalised_inputs = None
else:
self.amplitude_penalised_inputs = list(
self.input_specific_amplitude_costs.keys()
)
@@ -161,11 +152,9 @@ class Converter:
# states
if type(self.state_specific_amplitude_costs) == type(None):
self.amplitude_penalised_states = None
else:
self.amplitude_penalised_states = list(
self.state_specific_amplitude_costs.keys()
)
@@ -173,28 +162,24 @@ class Converter:
# outputs
if type(self.output_specific_amplitude_costs) == type(None):
self.amplitude_penalised_outputs = None
else:
self.amplitude_penalised_outputs = list(
self.output_specific_amplitude_costs.keys()
)
#**********************************************************************
#**********************************************************************
# *********************************************************************
# *********************************************************************
# identify the signals with specific externality costs
# inputs
if type(self.input_specific_externality_costs) == type(None):
self.externality_inducing_inputs = []
else:
self.externality_inducing_inputs = [
key[0] # key is a (m, k) tuple
for key, value in self.input_specific_externality_costs.items()
@@ -204,11 +189,9 @@ class Converter:
# states
if type(self.state_specific_externality_costs) == type(None):
self.externality_inducing_states = []
else:
self.externality_inducing_states = [
key[0] # key is a (n, k) tuple
for key, value in self.state_specific_externality_costs.items()
@@ -218,18 +201,16 @@ class Converter:
# outputs
if type(self.output_specific_externality_costs) == type(None):
self.externality_inducing_outputs = []
else:
self.externality_inducing_outputs = [
key[0] # key is a (r, k) tuple
for key, value in self.output_specific_externality_costs.items()
if value != 0
]
#**********************************************************************
# *********************************************************************
# identify binary signals
@@ -249,100 +230,97 @@ class Converter:
# self.identify_amplitude_penalised_inputs()
#**********************************************************************
#**********************************************************************
# *********************************************************************
# *********************************************************************
#**************************************************************************
#**************************************************************************
# *************************************************************************
# *************************************************************************
@staticmethod
def identify_fixed_signals(signals: list):
return [u for u, sig in enumerate(signals) if isinstance(sig, FixedSignal)]
return [
u for u, sig in enumerate(signals) if isinstance(sig, FixedSignal)
]
#**************************************************************************
#**************************************************************************
# *************************************************************************
# *************************************************************************
# TODO: number of time intervals in the dynamic system class
# TODO: replace the use of the number of time intervals from signals' objects
def matrix_dictionaries(self) -> tuple:
# TODO: exclude fixed signals from the matrices
# how? skip fixed signals = the dicts do not have that information and the indexes will be correct
number_intervals = self.inputs[0].number_samples
# a_innk
# a_nnk
a_innk = {
(self.key,n1,n2,k): self.sys.A_line_k[
k if self.sys.A_line_is_time_varying else 0][n1, n2]
a_nnk = {
(n1, n2, k): self.sys.A_line_k[k if self.sys.A_line_is_time_varying else 0][
n1, n2
]
for n1 in range(self.sys.number_states) # the state being defined
for n2 in range(self.sys.number_states) # the influencing state
for k in range(number_intervals) # the time interval
}
# b_inmk
# b_nmk
b_inmk = {
(self.key,n1,m,k): self.sys.B_line_k[
k if self.sys.B_line_is_time_varying else 0][n1, m]
b_nmk = {
(n1, m, k): self.sys.B_line_k[k if self.sys.B_line_is_time_varying else 0][
n1, m
]
for n1 in range(self.sys.number_states) # the state being defined
for m in range(self.sys.number_inputs) # the influencing input
if m not in self.fixed_inputs # free inputs only
for k in range(number_intervals) # the time interval
}
# c_irnk
# c_rnk
c_irnk = {
(self.key,r,n,k): self.sys.C_line_k[
k if self.sys.C_line_is_time_varying else 0][r, n]
c_rnk = {
(r, n, k): self.sys.C_line_k[k if self.sys.C_line_is_time_varying else 0][
r, n
]
for r in range(self.sys.number_outputs) # the output being defined
for n in range(self.sys.number_states) # the influencing state
for k in range(number_intervals) # the time interval
}
# d_irmk
# d_rmk
d_irmk = {
(self.key,r,m,k): self.sys.D_line_k[
k if self.sys.D_line_is_time_varying else 0][r, m]
d_rmk = {
(r, m, k): self.sys.D_line_k[k if self.sys.D_line_is_time_varying else 0][
r, m
]
for r in range(self.sys.number_outputs) # the output being defined
for m in range(self.sys.number_inputs) # the influencing input
if m not in self.fixed_inputs # free inputs only
for k in range(number_intervals) # the time interval
}
# note: e_x_ink does not depend on the initial conditions since the
# a_innk coefficients contain the information to handle them elsewhere
# note: e_x_nk does not depend on the initial conditions since the
# a_nnk coefficients contain the information to handle them elsewhere
# e_x_ink: depends on fixed signals
# e_x_nk: depends on fixed signals
e_x_ink = {
(self.key,n,k):
sum(
self.sys.B_line_k[
k if self.sys.B_line_is_time_varying else 0][n,m]*
self.inputs[m].samples[k]
e_x_nk = {
(n, k): sum(
self.sys.B_line_k[k if self.sys.B_line_is_time_varying else 0][n, m]
* self.inputs[m].samples[k]
for m in self.fixed_inputs # b_inmk*u_imk for fixed inputs
)
for n in range(self.sys.number_states) # the state being defined
for k in range(number_intervals) # the time interval
}
# e_y_irk: depends on fixed signals
# e_y_rk: depends on fixed signals
e_y_irk = {
(self.key,r,k): sum(
self.sys.D_line_k[
k if self.sys.D_line_is_time_varying else 0][r,m]*
self.inputs[m].samples[k]
for m in self.fixed_inputs # d_irmk*u_imk for fixed inputs
e_y_rk = {
(r, k): sum(
self.sys.D_line_k[k if self.sys.D_line_is_time_varying else 0][r, m]
* self.inputs[m].samples[k]
for m in self.fixed_inputs # d_rmk*u_mk for fixed inputs
)
for r in range(self.sys.number_outputs) # the output being defined
for k in range(number_intervals) # the time interval
@@ -350,135 +328,8 @@ class Converter:
# return statement
return a_innk, b_inmk, c_irnk, d_irmk, e_x_ink, e_y_irk
# #**************************************************************************
# #**************************************************************************
# def has_dimensionable_inputs(self):
# if len(self.dimensionable_inputs) == 0:
# # the system has no dimensionable inputs
# return False
# else: # the system has dimensionable inputs
# return True
# #**************************************************************************
# #**************************************************************************
# def has_binary_inputs(self):
# if len(self.binary_inputs) == 0:
# # the system has no binary inputs
# return False
# else: # the system has binary inputs
# return True
# #**************************************************************************
# #**************************************************************************
# def has_amplitude_penalised_inputs(self):
# if len(self.amplitude_penalised_inputs) == 0:
# # the system has no amplitude-penalised inputs
# return False
# else: # the system has amplitude-penalised inputs
# return True
# #**************************************************************************
# #**************************************************************************
# def has_externality_inducing_inputs(self):
# if len(self.externality_inducing_inputs) == 0:
# # the system has no externality-inducing inputs
# return False
# else: # the system has externality-inducing inputs
# return True
# #**************************************************************************
# #**************************************************************************
# def has_externality_inducing_outputs(self):
# if len(self.externality_inducing_outputs) == 0:
# # the system has no externality-inducing outputs
# return False
# else: # the system has externality-inducing outputs
# return True
# #**************************************************************************
# #**************************************************************************
# def identify_dimensionable_inputs(self):
# self.dimensionable_inputs = [
# i
# for i, u in enumerate(self.inputs)
# if u.is_dimensionable]
# #**************************************************************************
# #**************************************************************************
# def identify_binary_inputs(self):
# self.binary_inputs = [
# i
# for i, u in enumerate(self.inputs)
# if u.is_binary]
# #**************************************************************************
# #**************************************************************************
# def identify_externality_inducing_inputs(self):
# self.externality_inducing_inputs = [
# i
# for i, c in enumerate(self.input_externalities)
# if c != 0]
# #**************************************************************************
# #**************************************************************************
# def identify_externality_inducing_outputs(self):
# self.externality_inducing_outputs = [
# i
# for i, c in enumerate(self.output_externalities)
# if c != 0]
# #**************************************************************************
# #**************************************************************************
# def identify_amplitude_penalised_inputs(self):
# self.amplitude_penalised_inputs = [
# i
# for i, c in enumerate(self.input_amplitude_costs)
# if c != 0]
return a_nnk, b_nmk, c_rnk, d_rmk, e_x_nk, e_y_rk
# #**************************************************************************
# #**************************************************************************
#******************************************************************************
#******************************************************************************
\ No newline at end of file
# *****************************************************************************
# *****************************************************************************
Loading