Skip to content

Commit

Permalink
Fixed thermal model condition and added a unittest
Browse files Browse the repository at this point in the history
  • Loading branch information
davidusb-geek committed Jul 9, 2024
1 parent 8d4d32f commit 34302a6
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 48 deletions.
73 changes: 37 additions & 36 deletions src/emhass/optimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,42 +402,43 @@ def create_matrix(input_list, n):
rhs = 0)
for i in set_I})

elif "thermal_config" in self.optim_conf["def_load_config"][k]:
# Special case of a thermal deferrable load
def_load_config = self.optim_conf['def_load_config'][k]
if def_load_config and 'thermal_config' in def_load_config:
hc = def_load_config["thermal_config"]
start_temperature = hc["start_temperature"]
cooling_constant = hc["cooling_constant"]
heating_rate = hc["heating_rate"]
overshoot_temperature = hc["overshoot_temperature"]
outdoor_temperature_forecast = data_opt['outdoor_temperature_forecast']
desired_temperatures = hc["desired_temperatures"]
sense = hc.get('sense', 'heat')
predicted_temp = [start_temperature]
for I in set_I:
if I == 0:
continue
predicted_temp.append(
predicted_temp[I-1]
+ (P_deferrable[k][I-1] * (heating_rate * self.timeStep / self.optim_conf['P_deferrable_nom'][k]))
- (cooling_constant * (predicted_temp[I-1] - outdoor_temperature_forecast[I-1])))
if len(desired_temperatures) > I and desired_temperatures[I]:
constraints.update({"constraint_defload{}_temperature_{}".format(k, I):
plp.LpConstraint(
e = predicted_temp[I],
sense = plp.LpConstraintGE if sense == 'heat' else plp.LpConstraintLE,
rhs = desired_temperatures[I],
)
})
constraints.update({"constraint_defload{}_overshoot_temp_{}".format(k, I):
plp.LpConstraint(
e = predicted_temp[I],
sense = plp.LpConstraintLE if sense == 'heat' else plp.LpConstraintGE,
rhs = overshoot_temperature,
)
for I in set_I})
predicted_temps[k] = predicted_temp
elif "def_load_config" in self.optim_conf.keys():
if "thermal_config" in self.optim_conf["def_load_config"][k]:
# Special case of a thermal deferrable load
def_load_config = self.optim_conf['def_load_config'][k]
if def_load_config and 'thermal_config' in def_load_config:
hc = def_load_config["thermal_config"]
start_temperature = hc["start_temperature"]
cooling_constant = hc["cooling_constant"]
heating_rate = hc["heating_rate"]
overshoot_temperature = hc["overshoot_temperature"]
outdoor_temperature_forecast = data_opt['outdoor_temperature_forecast']
desired_temperatures = hc["desired_temperatures"]
sense = hc.get('sense', 'heat')
predicted_temp = [start_temperature]
for I in set_I:
if I == 0:
continue
predicted_temp.append(
predicted_temp[I-1]
+ (P_deferrable[k][I-1] * (heating_rate * self.timeStep / self.optim_conf['P_deferrable_nom'][k]))
- (cooling_constant * (predicted_temp[I-1] - outdoor_temperature_forecast[I-1])))
if len(desired_temperatures) > I and desired_temperatures[I]:
constraints.update({"constraint_defload{}_temperature_{}".format(k, I):
plp.LpConstraint(
e = predicted_temp[I],
sense = plp.LpConstraintGE if sense == 'heat' else plp.LpConstraintLE,
rhs = desired_temperatures[I],
)
})
constraints.update({"constraint_defload{}_overshoot_temp_{}".format(k, I):
plp.LpConstraint(
e = predicted_temp[I],
sense = plp.LpConstraintLE if sense == 'heat' else plp.LpConstraintGE,
rhs = overshoot_temperature,
)
for I in set_I})
predicted_temps[k] = predicted_temp

else:

Expand Down
49 changes: 37 additions & 12 deletions tests/test_optimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import numpy as np
import pathlib
import pickle
import random
from datetime import datetime, timezone

from emhass.retrieve_hass import RetrieveHass
Expand Down Expand Up @@ -265,20 +266,44 @@ def test_perform_naive_mpc_optim(self):
self.df_input_data_dayahead, self.P_PV_forecast, self.P_load_forecast, prediction_horizon,
soc_init=soc_init, soc_final=soc_final, def_total_hours=def_total_hours, def_start_timestep=def_start_timestep, def_end_timestep=def_end_timestep)
self.assertAlmostEqual(self.opt_res_dayahead.loc[self.opt_res_dayahead.index[-1],'SOC_opt'], soc_final)

def test_thermal_load_optim(self):
self.df_input_data_dayahead = self.fcst.get_load_cost_forecast(self.df_input_data_dayahead)
self.df_input_data_dayahead = self.fcst.get_prod_price_forecast(self.df_input_data_dayahead)
self.df_input_data_dayahead['outdoor_temperature_forecast'] = [random.normalvariate(10.0, 3.0) for _ in range(48)]
runtimeparams = {
'def_load_config': [
{},
{'thermal_config': {
'heating_rate': 5.0,
'cooling_constant': 0.1,
'overshoot_temperature': 24.0,
'start_temperature': 20,
'desired_temperatures': [21]*48,
}
}
]
}
self.optim_conf["def_load_config"] = runtimeparams['def_load_config']
self.opt = Optimization(self.retrieve_hass_conf, self.optim_conf, self.plant_conf,
self.fcst.var_load_cost, self.fcst.var_prod_price,
self.costfun, emhass_conf, logger)
unit_load_cost = self.df_input_data_dayahead[self.opt.var_load_cost].values # €/kWh
unit_prod_price = self.df_input_data_dayahead[self.opt.var_prod_price].values # €/kWh
self.opt_res_dayahead = self.opt.perform_optimization(self.df_input_data_dayahead,
self.P_PV_forecast.values.ravel(),
self.P_load_forecast.values.ravel(),
unit_load_cost, unit_prod_price)
self.assertIsInstance(self.opt_res_dayahead, type(pd.DataFrame()))
self.assertIsInstance(self.opt_res_dayahead.index, pd.core.indexes.datetimes.DatetimeIndex)
self.assertIsInstance(self.opt_res_dayahead.index.dtype, pd.core.dtypes.dtypes.DatetimeTZDtype)
self.assertTrue('cost_fun_'+self.costfun in self.opt_res_dayahead.columns)
self.assertTrue(self.opt.optim_status == 'Optimal')



def run_penalty_test_forecast(self):
self.opt = Optimization(
self.retrieve_hass_conf,
self.optim_conf,
self.plant_conf,
self.fcst.var_load_cost,
self.fcst.var_prod_price,
self.costfun,
emhass_conf,
logger,
)
self.opt = Optimization(self.retrieve_hass_conf, self.optim_conf, self.plant_conf,
self.fcst.var_load_cost, self.fcst.var_prod_price,
self.costfun, emhass_conf, logger)
def_total_hours = [5 * self.retrieve_hass_conf["freq"].seconds / 3600.0]
def_start_timestep = [0]
def_end_timestep = [0]
Expand Down

0 comments on commit 34302a6

Please sign in to comment.