Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #1912 +/- ##
==========================================
- Coverage 71.12% 71.09% -0.04%
==========================================
Files 149 149
Lines 14166 14300 +134
Branches 1879 1891 +12
==========================================
+ Hits 10075 10166 +91
- Misses 3555 3593 +38
- Partials 536 541 +5 🚀 New features to boost your workflow:
|
…nd state and only rely on GlobalConfig
| """Return if area has a heat pump strategy without tanks.""" | ||
| return isinstance( | ||
| area.strategy, | ||
| (HeatPumpStrategyWithoutTanks), |
There was a problem hiding this comment.
I think that brackets can be omitted here
There was a problem hiding this comment.
Ah yes, will fix it.
| target_temp_C_profile: Optional[Union[str, float, Dict]] = None, | ||
| target_temp_C_profile_uuid: Optional[str] = None, |
There was a problem hiding this comment.
Is the target temperature really needed here ? I would expect that the target temperature could be calculated and does not need to be an input here
There was a problem hiding this comment.
Please see comment below.
| self._update_last_time_slot_data(time_slot) | ||
|
|
||
| if not self._heat_demand_Q_J: | ||
| produced_heat_energy_kJ = self._calc_Q_kJ_from_energy_kWh( |
There was a problem hiding this comment.
Ok, now I see that the target temperature is only used to calculate the heat demand from electricity demand. In this case, I would prefer to use a constant value as a target temperature, rather than expect a profile, to uncomplicate the class constructor. This depends of course from the input data that we have from installations, however I somehow suspect that we will have trouble to find target temperature profiles. If we do have such data, then ignore this comment.
There was a problem hiding this comment.
We do not have a target temperatures as profile , yet. Indeed I was thinking of a constant value for now but wanted to be future prove and enabled providing a profile. I thought that we prepare the profile beforehand with simply filling the constant value to all timeslots.
In the case of the chiller this has to be a profile anyway (we received a temperature profile of the underground water basin.
In general, both temperature profiles are used to derive the COP and the heat demand. Which is the main task of this new strategy. Without it, it is just a load. This is why I vote for keeping profiles as input.
What do you think?
There was a problem hiding this comment.
Thanks for the explanation! I agree in general, however I am also thinking whether it makes sense to provide an option for a constant temperature, so that the user avoids this:
I thought that we prepare the profile beforehand with simply filling the constant value to all timeslots.
Thinking about it a second time though, it makes sense to implement it when we need it and not now. Therefore it is fine to leave as is.
There was a problem hiding this comment.
Just FYI, thanks to our magnificent implementation of StrategyProfile, we do not have to construct a profile beforehand but can simply pass the constant value:
strategy=HeatPumpStrategyWithoutTanks(
target_temp_C_profile=42, ...)|
|
||
|
|
||
| class MultipleTankHeatPumpStrategy(TradingStrategyBase): | ||
| class HeatPumpStrategyBase(TradingStrategyBase): |
There was a problem hiding this comment.
I assume that this class is only refactoring to a base class with no edits, right? If yes then I will not review it in detail.
| return self.__class__.__name__ | ||
|
|
||
|
|
||
| class HeatPumpStateWithoutTanks(HeatPumpStateBase): |
There was a problem hiding this comment.
I think that this class is not needed, and the methods can be integrated in the base class (HeatPumpStateBase). That way, the caller code could instantiate the base class (or an alias name of the base class for readability) and avoid having to maintain this class.
There was a problem hiding this comment.
Now that I look at it, I agree. Will do
spyrostz
left a comment
There was a problem hiding this comment.
Some comments, will LGTM once replied / fixed. Thanks!
| def get_state(self) -> Dict: | ||
| return { | ||
| "cop": convert_pendulum_to_str_in_dict(self._cop), | ||
| "heat_demand_kJ": convert_pendulum_to_str_in_dict(self._heat_demand_kJ), | ||
| } | ||
|
|
||
| def restore_state(self, state_dict: Dict): | ||
| self._cop = convert_str_to_pendulum_in_dict(state_dict["cop"]) | ||
| self._heat_demand_kJ = convert_str_to_pendulum_in_dict(state_dict["heat_demand_kJ"]) | ||
|
|
||
| def get_results_dict(self, current_time_slot: DateTime) -> Dict: | ||
| retval = { | ||
| "cop": self.get_cop(current_time_slot), | ||
| "heat_demand_kJ": self.get_heat_demand_kJ(current_time_slot), | ||
| } | ||
| return retval |
There was a problem hiding this comment.
Sorry for the nit, however I think that it would be better to reuse these methods from the superclass. Essentially, instead of duplicating these lines here, IMO it would be better to call super().get_state() from the HeatPumpState.get_state() method. That way any new attributes that we might add in the base class in the future will end up in the dicts of the superclass.
spyrostz
left a comment
There was a problem hiding this comment.
One last comment, will LGTM once resolved.
Reason for the proposed changes
Please describe what we want to achieve and why.
Proposed changes
INTEGRATION_TESTS_BRANCH=master
GSY_FRAMEWORK_BRANCH=master
SCM_ENGINE_BRANCH=master