Closed sti0 closed 10 months ago
This is already possible, you can pass all these parameters at runtime: https://emhass.readthedocs.io/en/latest/intro.html#passing-other-data
But not the peak hours per deferrable load. These are not mentioned in the docs.
I think the easiest way should be if we could define a different prediction_horizon
per deferrable load
I started working on this. I'm introducing a new parameter in the optimizer, called "def_end_timestep", defined as "The timestep before which each deferrable load should consume their energy." The optimizer will get an extra constraint stating that the deferrable load should not consume any energy after the specified timestep:
# Treat deferrable loads constraints
for k in range(self.optim_conf['num_def_loads']):
# Total time of deferrable load -> unchanged
constraints.update({"constraint_defload{}_energy".format(k) :
plp.LpConstraint(
e = plp.lpSum(P_deferrable[k][i]*self.timeStep for i in set_I),
sense = plp.LpConstraintEQ,
rhs = def_total_hours[k]*self.optim_conf['P_deferrable_nom'][k])
})
# Ensure deferrable loads consume energy before def_end_timestep
constraints.update({"constraint_defload{}_end_timestep".format(k) :
plp.LpConstraint(
e = plp.lpSum(P_deferrable[k][i]*self.timeStep for i in range(def_end_timestep[k], n)),
sense = plp.LpConstraintEQ,
rhs = 0)
})
I have the "happy flow" scenario working, now working on edge cases/exception handling. Once mature enough, I'll make a pull request for this.
Thanks @michaelpiron Defined like this it is finally not a window, right? Another thing is to integrate this in a manner that by default this is deactivated, so no more constraint is added to the LP problem. And if the user need this feature then activate it somehow.
Hi @davidusb-geek, indeed, in my proposal, the user just defines the end_timestep. The start_timestep is always step 0. But I could easily allow a start_timestep parameter to be specified as well, in a second iteration.
The way I'm writing it now, is that I allow the user to specify a def_end_timestep list in the API request of the MPC optimizer.
Example: "def_end_timestep": [3,0]
This is the case of two deferrable loads, whereby the first load should operate in the first three timesteps of the optimization window. The second load can use the complete optimization window (cf the value of 0).
In code:
# Treat deferrable loads constraints
for k in range(self.optim_conf['num_def_loads']):
# Total time of deferrable load
constraints.update({"constraint_defload{}_energy".format(k) :
plp.LpConstraint(
e = plp.lpSum(P_deferrable[k][i]*self.timeStep for i in set_I),
sense = plp.LpConstraintEQ,
rhs = def_total_hours[k]*self.optim_conf['P_deferrable_nom'][k])
})
# Ensure deferrable loads consume energy before def_end_timestep
if def_end_timestep[k] > 0:
# If the available timeframe (between now and def_end_timestep) is < number of timesteps to meet the hours to operate (def_total_hours), enlarge the timeframe.
if def_end_timestep[k] < def_total_hours[k]/self.timeStep:
def_end_timestep[k] = ceil(def_total_hours[k]/self.timeStep)
self.logger.warning("Available timeframe for deferrable load %s is shorter than the specified number of hours to operate. Enlarging timeframe to def_total_hours.", k)
constraints.update({"constraint_defload{}_end_timestep".format(k) :
plp.LpConstraint(
e = plp.lpSum(P_deferrable[k][i]*self.timeStep for i in range(def_end_timestep[k], n)),
sense = plp.LpConstraintEQ,
rhs = 0)
})
I also started to foresee a corresponding field in the add-on config UI, similar to the number of operating hours:
Happy to receive your feedback.
Submitted PR #153
Comments on #153
Continued working on the PR, adding as well the start_timesteps. As such it is possible to define time windows for deferrable loads.
PR #153 just got merged into main branch. This feature request can therefore be closed
Some deferrable loads should operate in a specific time windows. E.g. a water heater should operate in the next X hours even when this is not the cost-efficient time window. Another example will be a washing machine which should operate on a sunny day in the morning so the clothes can try in the sun in the afternoon. But if its not a sunny day it should end at least on 8pm so we can hang up the clothes before we go to sleep.
To achieve this and add some more dynamic for every single deferrable load the
peak_period_hours
parameter should accessable within theruntimeparams
(or something similar).