-
Notifications
You must be signed in to change notification settings - Fork 297
feat: resistive_heaters and air_sourced_hp for ptes temperature boosting #1711
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
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @TomKae00 ,
first of all: Kudos to the nice mathematical description and the overall documentation of the PR. I left a couple of comments, most of them questions to better understand what is happening or stylistic remarks. Some of them might be worth discussing together with @amos-schledorn.
"central water pit discharger", | ||
"efficiency", | ||
] | ||
* ptes_supplemental_heating_required, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't we just save the variable ptes_supplemental_heating_required
in this else-clause?
] | ||
): | ||
raise ValueError( | ||
"'booster_heat_pump' is true, but 'enable' is false in 'supplemental_heating'." | ||
"Supplemental heating: 'booster_technologies' contains 'heat_pump', but 'enable' is false." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is a matter of taste: As it is, we incentivize the user to change both enable
and boosting_technologies
. Personally, I find it practical being able to switch a feature on/off by just setting the enable
parameter in the config file, especially with a cascaded config setup. Compromise would be a warning instead of an error.
"booster_technologies" | ||
] | ||
): | ||
raise ValueError( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above
@@ -153,7 +170,7 @@ def approximate_cop(self) -> Union[xr.DataArray, np.array]: | |||
Union[xr.DataArray, np.array]: The calculated COP values. | |||
""" | |||
return xr.where( | |||
self.t_source_in_kelvin >= self.t_sink_out_kelvin, | |||
(self.delta_t_lift < self.min_delta_t_lift), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means, that for the default min_delta_t_lift
of 10 K, PTES could not be discharged with heat pumps to the district heating system if the forward flow temperature is between 90 and 100 °C, right?
- Is this realistic?
- This would suppress the capacity factors of booster heat pumps further down and give another reason why there not favored for boosting applications given the higher CAPEX compared to resistive heaters.
and "heat_pump" | ||
in options["district_heating"]["ptes"]["supplemental_heating"][ | ||
"booster_technologies" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do the booster heat pumps stand in an if-else-relation with normal heat pumps (see else-clause below in L.3355 and following)? We want the latter ones to be available independent of the boosting feature.
n.add( | ||
"Link", | ||
nodes, | ||
suffix=f" {heat_system} ptes resistive heater", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe change the "ptes" part to "pits" or even "water pits" to be more consistent, avoid abbreviations and allow a more convenient filtering of links.
ptes resistive heater: '#a0e78d' | ||
residential rural resistive heater: '#bef5b5' | ||
residential urban decentral resistive heater: '#b2f1a9' | ||
services rural resistive heater: '#a5ed9d' | ||
services urban decentral resistive heater: '#98e991' | ||
urban central resistive heater: '#8cdf85' | ||
urban central ptes resistive heater: '#71c96b' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need both entries?
Changes proposed in this Pull Request
This feature introduces resistive heaters and air-sourced heat pumps as temperature boosting technologies for PTES. The boosting methodology is based on a temperature_boost_ratio, which calculates the additional temperature lift required between the store’s current top temperature and the target forward temperature. This is done relative to the lift already achieved within the store, using the return temperature of the district heating system as a reference.
1. Boosting-ratio derivation
Let
We define two heat-transfer rates:
Energy supplied by the PTES (source)
Q_source = Ṽ·ρ·cₚ·(T_max,store − T_return)
Additional energy required (boost)
Q_boost = Ṽ·ρ·cₚ·(T_forward − T_max,store)
The total heating demand is
Q_total = Q_source + Q_boost
Define the boosting ratio α as the lift-ratio between what the pump must add versus what the PTES already delivers:
α = (T_forward − T_max,store) / (T_max,store − T_return) = Q_boost / Q_source
In other words,
Q_boost = α·Q_source
Proceeding from Q_boost = P_el·η, one finds
Q_source = (P_el·η) / α
Q_total = Q_source + Q_boost = (P_el·η)/α + P_el·η = P_el·η·(1/α + 1)
Thus:
PTES output per unit electricity
Q_source / P_el = η / α
Total output per unit electricity
Q_total / P_el = η·(1/α + 1)
2. COP calculation adjustment for heat pumps
Previously, we calculated the heat-pump COP using the district heating forward/return temperatures. To accurately model air-sourced ptes heat pumps, the COP is now based on the pump’s sink inlet and outlet temperatures. This change ensures consistency whenever an external heat source (e.g., ambient air) is used for boosting.
3. Passing heat-pump parameters correctly
Prior, heat-pump parameters (set in config) were not used and default value instead. Now, all provided parameters are properly passed through the config and used.
4. Improved handling in
logarithmic_mean
The function
logarithmic_mean(t_hot, t_cold)
failed (division-by-zero) when t_hot = t_cold. It now returns t_hot in that case (L’Hôpital’s rule), instead of throwing an error. This specifically handles instances where the PTES temperature equals the forward temperature.5. @amos-schledorn discussion about heat-source flags
Because the air-sourced heat pump is now used in two contexts—
both cases would have “heat source = Air”, but this would break the logic we have at the moment. Therefore I still used “heat source = ptes” to manually distinguish the two scenarios. It might be cleaner to introduce a separate identifier for “boosting heat source.” Do you have a quick suggestion on how best to differentiate these two cases in the codebase?
Testing
Results
System cost = 141.071 trillion
System cost = 141.054 trillion
Ran the analysis for DE and PL, both of which require relatively high forward temperatures (over 90°C). Since the PTES maximum storage temperature is 90 °C, supplemental boosting is necessary whenever the forward temperature exceeds that limit.
In both countries, resistive heaters were chosen over air-sourced heat pumps for boosting. The main reasons are:
With supplemental heating and booster technologies for PL 01 (resistive heaters)
With supplemental heating and booster technologies for PL 01 (HP)
With supplemental heating and booster technologies for DE 01 (resistive heaters)
With supplemental heating and booster technologies for DE 01 (HP)
Checklist
envs/environment.yaml
.config/config.default.yaml
.doc/configtables/*.csv
.doc/data_sources.rst
.doc/release_notes.rst
is added.