Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GSYE-645: Add loss calculation to storage state #1799

Merged
merged 7 commits into from
Oct 7, 2024

Conversation

hannesdiedrich
Copy link
Member

Reason for the proposed changes

Please describe what we want to achieve and why.

Proposed changes

INTEGRATION_TESTS_BRANCH=feature/GSYE-645
GSY_FRAMEWORK_BRANCH=master

@@ -1,3 +1,4 @@
# pylint: disable=too-many-lines
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This module has only be changed by Black because I fixed one method interface. You can ignore reviewing this. Thanks

Copy link

codecov bot commented Sep 26, 2024

Codecov Report

Attention: Patch coverage is 65.75342% with 50 lines in your changes missing coverage. Please review.

Project coverage is 69.55%. Comparing base (f442047) to head (66e2587).
Report is 9 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1799      +/-   ##
==========================================
+ Coverage   69.52%   69.55%   +0.03%     
==========================================
  Files         148      148              
  Lines       14029    14045      +16     
  Branches     2619     2618       -1     
==========================================
+ Hits         9753     9769      +16     
- Misses       3758     3759       +1     
+ Partials      518      517       -1     

BigTava
BigTava previously approved these changes Sep 26, 2024
Copy link
Contributor

@BigTava BigTava left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I am bit skeptic that charging and discharging losses are fixed values and not percentage over the charging and discharging power. But the logic seems good ! Left minor comments but looks good

"""Register energy from a bid trade event."""
assert energy >= -FLOATING_POINT_TOLERANCE
self.pledged_buy_kWh[time_slot] += energy
self.offered_buy_kWh[time_slot] -= energy
self._track_energy_bought_type(energy, energy_origin)
self._clamp_energy_to_buy_kWh([time_slot])
# if self.charging_loss_per_kWh > 0:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can remove this

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, let me remove

@@ -411,6 +484,8 @@ def get_available_energy_to_buy_kWh(self, time_slot: DateTime) -> float:

self._clamp_energy_to_buy_kWh([time_slot])
energy_kWh = self.energy_to_buy_dict[time_slot]
# if self.charging_loss_per_kWh >0 and energy_kWh:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And removing this as well

@hannesdiedrich
Copy link
Member Author

Well, I am bit skeptic that charging and discharging losses are fixed values and not percentage over the charging and discharging power.

They are indeed implemented as percentages (have a look here: https://github.com/gridsingularity/gsy-e/pull/1799/files#diff-4581ce8152beebe7aa76014b4a741adac802ef0fcd8ac7a578d7ec4aabf39dfbR362-R363)
But you are right, the names should reflect that. Will fix.


charging_loss_percent: float = 0.0
discharging_loss_percent: float = 0.0
self_discharge_per_day_kWh: float = 0.0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All good, however the unit is striking as a bit odd here. Did you find it in any spec sheet of a battery? Reason I am asking is because I have mostly seen this unit being the percentage of the total capacity of the battery, e.g. https://www.batterypowertips.com/why-self-discharge-is-important-in-batteries/ or more specifically here https://www.batterypowertips.com/wp-content/uploads/2023/02/Why-is-self-discharge-important-in-batteries-Figure-1.jpeg .

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes, it is also a percentage value. I also found the links that you shared. Let me rename. Also, I need to fix the calculation then. I don't know why I came up with the current implementation.

Comment on lines 72 to 73
losses: Optional[StorageLosses] = StorageLosses(),
):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, but since it is Optional I would prefer None as default value:

Suggested change
losses: Optional[StorageLosses] = StorageLosses(),
):
losses: Optional[StorageLosses] = None,
):
if not losses:
losses = StorageLosses()

self_discharging_kWh = (
self.losses.self_discharge_per_day_kWh * GlobalConfig.slot_length.total_days()
)
total_loss_kWh = charging_loss_kWh + discharging_loss_kWh + self_discharging_kWh
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Admittedly an overkill, but do you think that it makes sense to also keep the total_loss_kWh in the results for debugging purposes? On second thought, better to omit it and add it if necessary in the future.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is not an overkill and indeed interesting to know if you run storages with losses. Let me add it to the storage CSV file.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did add it here: 3c11349
However, there is a corner case for that last market slot. We only calculate the losses for the past market slot in the market_cycle event method. But after the last market slot this is not triggered, hence the losses are not calculated. I gave it some time to fix, but could not find a solution for this. As you named this an overkill, I left it like this now. Let us deal with the last market slot once we need it. OK?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed and thanks!

Comment on lines +78 to +83
initial_selling_rate: Union[float, dict] = StorageSettings.SELLING_RATE_RANGE.initial,
final_selling_rate: Union[float, dict] = StorageSettings.SELLING_RATE_RANGE.final,
initial_buying_rate: Union[float, dict] = StorageSettings.BUYING_RATE_RANGE.initial,
final_buying_rate: Union[float, dict] = StorageSettings.BUYING_RATE_RANGE.final,
fit_to_limit=True,
energy_rate_increase_per_update=None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely not for now, but we need to migrate these constructor arguments to OrderUpdaterParameters at some point. I will open a ticket to do this refactoring in one go for all other strategies if it does not exist.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely! IMO we should do it in the frame of https://gridsingularity.atlassian.net/browse/GSYE-769.

self.cap_price_strategy = cap_price_strategy
self.balancing_energy_ratio = BalancingRatio(*balancing_energy_ratio)

@staticmethod
def deserialize_args(constructor_args: Dict) -> Dict:
"""Deserialize the constructor arguments for the HeatPump strategy."""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor

Suggested change
"""Deserialize the constructor arguments for the HeatPump strategy."""
"""Deserialize the constructor arguments for the Storage strategy."""

energy_rate_decrease_per_update=None,
update_interval=None,
initial_energy_origin: Enum = ESSEnergyOrigin.EXTERNAL,
losses: Optional[StorageLosses] = StorageLosses(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be None here too AFAIS.

self.cap_price_strategy = cap_price_strategy
self.balancing_energy_ratio = BalancingRatio(*balancing_energy_ratio)

@staticmethod
def deserialize_args(constructor_args: Dict) -> Dict:
Copy link
Member

@spyrostz spyrostz Oct 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this method only needs to be implemented if we want to involve gsy-web. Since we do not this could be completely omitted. That said, no problem keeping it in case we need it in the future.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, let me remove it here, only to explicitly add it once/if we add the losses to the FE.

Copy link
Member

@spyrostz spyrostz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments, LGTM in general, thanks!

Copy link
Member

@spyrostz spyrostz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@hannesdiedrich hannesdiedrich merged commit d52597c into master Oct 7, 2024
3 of 4 checks passed
@hannesdiedrich hannesdiedrich deleted the feature/GSYE-645 branch January 21, 2025 07:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants