Select Git revision
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
test_esipp_converter.py 8.35 KiB
# imports
# standard
import random
# local, external
import numpy as np
# local, internal
import src.topupopt.problems.esipp.dynsys as dynsys
import src.topupopt.problems.esipp.converter as cvn
import src.topupopt.problems.esipp.signal as sgn
# ******************************************************************************
# ******************************************************************************
class TestConverter:
# **************************************************************************
# **************************************************************************
# test converters
# 1) regular and irregular time steps
# 2) time invariant and time varying models
# 3) integrate and do not integrate outputs
# 4) generate coefficients
# test creating a stateless converter without outputs
# test creating a stateless converter with 1 output
# test creating a stateless converter with 2 output
# test creating a converter based on a single ODE system without outputs
# test creating a converter based on a single ODE system with 1 output
# test creating a converter based on a single ODE system with 2 output
# test creating a converter based on a multiple ODE system without outputs
# test creating a converter based on a multiple ODE system with 1 output
# test creating a converter based on a multiple ODE multi-output system
# **************************************************************************
# **************************************************************************
def test_full_converter_regular(self):
time_step_durations = [1, 1, 1, 1]
method_full_converter(time_step_durations)
# **************************************************************************
# **************************************************************************
def test_full_converter_irregular(self):
time_step_durations = [1, 1.5, 0.5, 1]
method_full_converter(time_step_durations)
# **************************************************************************
# **************************************************************************
# ******************************************************************************
# ******************************************************************************
def get_stateless_model_data(relative_amplitude_variation: float = 0.0):
mrh_deviation = random.random() - 0.5
Aw = 6.22 # original: 6.22 m2
min_rel_heat = 0.2 * (1 + relative_amplitude_variation * mrh_deviation)
return Aw, min_rel_heat
# ******************************************************************************
# ******************************************************************************
def get_single_ode_model_data(relative_amplitude_variation: float = 0.0):
# define how the coefficients change
Ria_deviation = random.random() - 0.5
# define the (A, B, C and D) matrices
# A: n*n
# B: n*m
# C: r*n
# D: r*m
Ci = 1.360 * 3600000
Ria = (1 + relative_amplitude_variation * Ria_deviation) * 5.31 / 3600000
Aw = 6.22
min_rel_heat = 0.2
x0 = np.array([20])
return Ci, Ria, Aw, min_rel_heat, x0
# *****************************************************************************
# *****************************************************************************
def get_multi_ode_model_data(relative_amplitude_variation: float = 0.0):
# define how the coefficients change
Rih_deviation = random.random() - 0.5
Ria_deviation = random.random() - 0.5
# define the (A, B, C and D) matrices
# A: n*n
# B: n*m
# C: r*n
# D: r*m
# from Bacher and Madsen (2011): model TiTh
Ci = 1.360 * 3600000 # original: 1.36 kWh/ºC
Ch = 0.309 * 3600000 # original: 0.309 kWh/ºC
Ria = (
(1 + relative_amplitude_variation * Ria_deviation) * 5.31 / 3600000
) # original: 5.31 ºC/kWh
Rih = (
(1 + relative_amplitude_variation * Rih_deviation) * 0.639 / 3600000
) # original: 0.639 ºC/kWh
Aw = 6.22 # original: 6.22 m2
Pw = 5000 # 5 kW
min_rel_heat = 0.2
x0 = np.array([20, 20])
return Ci, Ch, Ria, Rih, Aw, min_rel_heat, Pw, x0
# ******************************************************************************
# ******************************************************************************
def stateless_model(Aw, min_rel_heat):
# inputs: Ta, phi_s, phi_h above the minimum, phi_h status
# outputs: solar irradiance, heat
d = np.array([[0, Aw, 0, 0], [0, 0, (1 - min_rel_heat), min_rel_heat]])
return None, None, None, d
# ******************************************************************************
# ******************************************************************************
def single_node_model(Ci, Ria, Aw, min_rel_heat, Pw):
# states: Ti and Th
# inputs: Ta, phi_s, phi_h above the minimum, phi_h status
# outputs: solar irradiance, heat
a = np.array([[-1 / (Ria * Ci)]])
b = np.array(
[
[
1 / (Ci * Ria),
Aw / Ci,
Pw * (1 - min_rel_heat) / Ci,
Pw * min_rel_heat / Ci,
]
]
)
c = np.array([[0], [0]])
d = np.array([[0, Aw, 0, 0], [0, 0, Pw * (1 - min_rel_heat), Pw * min_rel_heat]])
return a, b, c, d
# ******************************************************************************
# ******************************************************************************
def two_node_model(Ci, Ch, Ria, Rih, Aw, min_rel_heat, Pw):
# states: Ti and Th
# inputs: Ta, phi_s, phi_h above the minimum, phi_h status
# outputs: solar irradiance, heat
a = np.array(
[[-(1 / Rih + 1 / Ria) / Ci, 1 / (Ci * Rih)], [1 / (Ch * Rih), -1 / (Ch * Rih)]]
)
b = np.array(
[
[1 / (Ci * Ria), Aw / Ci, 0, 0],
[0, 0, Pw * (1 - min_rel_heat) / Ch, Pw * min_rel_heat / Ch],
]
)
c = np.array([[0, 0], [0, 0]])
d = np.array([[0, Aw, 0, 0], [0, 0, Pw * (1 - min_rel_heat), Pw * min_rel_heat]])
return a, b, c, d
# ******************************************************************************
# ******************************************************************************
def get_two_node_model_signals(number_samples):
# signals
# inputs:
# 1) ambient temperature (real, can be fixed later)
# 2) solar irradiation (real, can be fixed later)
# 3) relative heat above minimum (nnr)
# 4) heater status (binary)
list_inputs = [
sgn.FreeUnboundedSignal(number_samples),
sgn.FreeUnboundedSignal(number_samples),
sgn.NonNegativeRealSignal(number_samples),
sgn.BinarySignal(number_samples),
]
# states
# 1) indoor temperature (real)
# 2) heater temperature (real)
list_states = [
sgn.FreeUnboundedSignal(number_samples),
sgn.FreeUnboundedSignal(number_samples),
]
# outputs:
# 1) solar gain (nnr)
# 2) heat input (nnr)
list_outputs = [
sgn.NonNegativeRealSignal(number_samples),
sgn.NonNegativeRealSignal(number_samples),
]
return list_inputs, list_states, list_outputs
# ******************************************************************************
# ******************************************************************************
def method_full_converter(time_step_durations: list):
# number of samples
number_time_steps = len(time_step_durations)
# get the coefficients
Ci, Ch, Ria, Rih, Aw, min_rel_heat, Pw, x0 = get_multi_ode_model_data()
# get the model
a, b, c, d = two_node_model(Ci, Ch, Ria, Rih, Aw, min_rel_heat, Pw)
# get the signals
inputs, states, outputs = get_two_node_model_signals(number_time_steps)
# create a dynamic system
ds = dynsys.DynamicSystem(
time_interval_durations=time_step_durations, A=a, B=b, C=c, D=d
)
# create a converter
cvn1 = cvn.Converter(
sys=ds,
time_frame=None,
initial_states=x0,
turn_key_cost=3,
inputs=inputs,
states=states,
outputs=outputs,
)
# get the dictionaries
(a_innk, b_inmk, c_irnk, d_irmk, e_x_ink, e_y_irk) = cvn1.matrix_dictionaries()
# TODO: check the dicts
# ******************************************************************************
# ******************************************************************************