Special Hot Water
- heatpro.special_hot_water.special_hot_water(external_factors: ExternalFactors, total_heating_including_hotwater: MonthlyHeatDemand, monthly_hot_water_profile: DataFrame, temperature_hot_water: float, hourly_hot_water_day_profil: DataFrame, name: str = 'hot_water')[source]
Calculate the hourly energy demand for hot water considering external factors and profiles.
- Parameters:
external_factors (ExternalFactors) – Object containing external factors affecting hot water energy demand.
total_heating_including_hotwater (MonthlyHeatDemand) – Monthly total heat demand including hot water.
monthly_hot_water_profile (pd.DataFrame) – Monthly hot water profile (In term of quantity i.e. L).
temperature_hot_water (float) – The temperature of the hot water.
hourly_hot_water_day_profil (pd.DataFrame) – Hourly profile for hot water demand (In term of quantity i.e. L).
name (str, optional) – Name of the demand. Defaults to “hot_water”.
- Returns:
The hourly demand for hot water.
- Return type:
Explanation
special_hot_water function¶
This note aims to explain how heatpro.special_hot_water.special_hot_water
is working
import numpy as np
import pandas as pd
import plotly.graph_objects as go
import plotly.io as pio
pio.renderers.default='notebook'
pd.options.plotting.backend = "plotly"
Prerequisites : External Factors and Induced Factors¶
External Factors are exogenous data.
from heatpro.external_factors import ExternalFactors, EXTERNAL_TEMPERATURE_NAME
df = pd.read_csv('../external_factors.csv',parse_dates=True,index_col=0)
df.index = pd.date_range(start='2021',freq='h',periods=8760)
df2 = df.copy()
df2.index = pd.date_range(start='2022',freq='h',periods=8760)
external_factors = ExternalFactors(pd.concat((df,df2)))
external_factors.data.astype(float).plot()
Induced factor comes from External Factors processing.
Cold water temperature correspond to temparature in drinking water distribution network.
Closed heating season correspond to a period where months have at least one day in the heating season. Consumption on Closed Heating Season while be used to evaluate a normalized heat consomption for hot water.
from heatpro.external_factors import closed_heating_season, burch_cold_water, basic_temperature_departure, basic_temperature_return, kasuda_soil_temperature
induced_factors = pd.concat((
closed_heating_season(external_factors),
burch_cold_water(external_factors),
basic_temperature_departure(external_factors, T_max_HS=110,
T_max_NHS=90, T_min_HS=80, T_min_NHS=70,
T_ext_mid=15, T_ext_min=-15),
basic_temperature_return(external_factors, 70, 60),
kasuda_soil_temperature(external_factors,d=3, alpha=0.078),
),axis=1)
induced_factors.astype(float).plot().show()
fig = go.Figure(layout_title="Difference between Heating Season and Closed Heating Season")
fig.add_trace(
go.Scatter(
x = external_factors.data.index,
y = external_factors.data.heating_season,
name = "Heating Season",
)
)
fig.add_trace(
go.Scatter(
x = induced_factors.index,
y = induced_factors.closed_heating_season,
name = "Closed Heating Season",
)
)
fig.show()
Beginning with a monthly energy consumption for heating including hot water consumption.
from heatpro.temporal_demand import MonthlyHeatDemand
from heatpro.check import ENERGY_FEATURE_NAME
np.random.seed(22)
total_heating_including_hotwater = MonthlyHeatDemand(
'total_heating',
pd.DataFrame(
np.random.rand(24) * 10_000 + 60_000, # Heating demand randomly initialized
index=pd.date_range('2021',freq='MS',end='2023',inclusive='left'), #Monthly indexing
columns=[ENERGY_FEATURE_NAME],
)
)
total_heating_including_hotwater.plot()
Monthly hot water consumption (In terms of quantity of hot water and not energy) is given. Sum on each year of weights equals 1 as it is a profile (consequently normalized). $$ \forall~year, \int_{year}Q(t)dt = \sum_{month\in year}Q(month)= 1 $$
monthly_hot_water_profile = pd.DataFrame(
[1.13,1.11,1.04,1.04,1.0,0.93,0.8,0.74,0.98,1.0,1.09,1.14]*2,
columns=['weight'],
index=total_heating_including_hotwater.data.index,
) / 12 # To normalize
monthly_hot_water_profile.plot()
monthly_hot_water_profile.resample('YE').sum() #Sum over each year
weight | |
---|---|
2021-12-31 | 1.0 |
2022-12-31 | 1.0 |
Monthly profile is disaggregate into hourly profile taking into account number of day in each month and number of hour in each day
$$ \forall~year, \int_{year}Q(t)dt = \sum_{hour \in month,month\in year}Q(hour,month)= 1 $$
from heatpro.demand_profile import day_length_proportionnal_weight
hourly_hot_water_month_profile = (day_length_proportionnal_weight(monthly_hot_water_profile.index)\
/24 \
* monthly_hot_water_profile) \
.reindex(induced_factors.index).ffill()
fig = go.Figure(layout_title="Change to monthly weight to hourly weight (constant on month)")
# Add trace for previous monthly weight
fig.add_trace(
go.Scatter(
x=monthly_hot_water_profile.index,
y=monthly_hot_water_profile.weight,
name="Previous monthly weight",
yaxis="y1" # Assign to y-axis 1
)
)
# Add trace for new hourly weight
fig.add_trace(
go.Scatter(
x=hourly_hot_water_month_profile.index,
y=hourly_hot_water_month_profile.weight,
name="New hourly weight",
yaxis="y2" # Assign to y-axis 2
)
)
# Define y-axis properties
fig.update_layout(
yaxis=dict(
title="Previous monthly weight",
side="left" # Align with left side
),
yaxis2=dict(
title="New hourly weight",
overlaying="y", # Overlay on top of first y-axis
side="right" # Align with right side
),
legend=dict(
orientation="h", # Horizontal orientation
yanchor="top", # Anchor to the top
y=-0.1, # Position below the plot
x=0.5,
xanchor="center" # Anchor to the center
)
)
# Show the figure
fig.show()
Sum of hourly weights over a year equal 1.
hourly_hot_water_month_profile.resample('YE').sum()
weight | |
---|---|
2021-12-31 | 1.0 |
2022-12-31 | 1.0 |
Energy consumption on Closed Non Heating Season (supposedly equals to energy consumption for hot water production)
from heatpro.external_factors import CLOSED_HEATING_SEASON_NAME
non_heating_season_consumption = total_heating_including_hotwater.\
data[~induced_factors[CLOSED_HEATING_SEASON_NAME].\
reindex(total_heating_including_hotwater.data.index)]\
[ENERGY_FEATURE_NAME].sum()
print(f'Non heating season consumption : {non_heating_season_consumption:.0f} kWh')
print(f'Overall consumption : {total_heating_including_hotwater.data.thermal_energy_kWh.sum():.0f} kWh')
Non heating season consumption : 522462 kWh Overall consumption : 1559876 kWh
Get hourly energy consumption using gap temperature through time. For now consumption is constant on each day.
$$ \forall~day, E(day) = \frac{\int_{day}Q(t)\cdot(T^{(\text{prod})}-T_t^{(\text{Cold Water})})dt}{\int_{\text{Non Heating Season}}Q(t)\cdot(T^{(\text{prod})}-T_t^{(\text{Cold Water})})dt} \cdot \int_{\text{Non Heating Season}} E(t)dt $$
$$ \forall~hour \in~day, E(hour) = P(hour) \cdot E(day) $$ where, $$ \sum_{hour\in day}P(hour) = 1 $$
Temperature_hot_water = 60
daily_hot_water_energy_consumption = (non_heating_season_consumption *\
(hourly_hot_water_month_profile['weight'] * (Temperature_hot_water - induced_factors['cold_water_temperature']))\
.groupby(hourly_hot_water_month_profile.index.date).transform('sum')/\
(hourly_hot_water_month_profile['weight'] * (Temperature_hot_water - induced_factors['cold_water_temperature']))[~induced_factors['closed_heating_season']].sum())\
.rename(ENERGY_FEATURE_NAME)
daily_hot_water_energy_consumption.plot().update_layout(title='Daily consumption')
from heatpro.demand_profile import apply_hourly_pattern, basic_hot_water_hourly_profile, basic_hot_water_monthly_profile
hot_water_raw_profil = {
0: 0.01,
1: 0,
2: 0,
3: 0,
4: 0,
5: 4.797,
6: 3.543,
7: 0.86,
8: 0.43,
9: 0.86,
10: 1.3,
11: 0,
12: 0.43,
13: 0.43,
14: 0.43,
15: 0,
16: 1.3,
17: 0.43,
18: 3.01,
19: 4.797,
20: 1.373,
21: 0,
22: 0,
23: 0
}
hot_water_raw_profil = {key:value/24 for key,value in hot_water_raw_profil.items()}
hourly_hot_water_raw_day_profil = apply_hourly_pattern(daily_hot_water_energy_consumption.index,hot_water_raw_profil)
hourly_hot_water_day_profil = basic_hot_water_hourly_profile(
hourly_hot_water_raw_day_profil,
0.1,
0.1,
)
final_hourly_hot_water_energy_consumption = pd.DataFrame((daily_hot_water_energy_consumption * hourly_hot_water_day_profil['weight']).rename(ENERGY_FEATURE_NAME))
fig = go.Figure(layout_title="Integrating daily profile")
# Add trace for previous monthly weight
fig.add_trace(
go.Scatter(
x=final_hourly_hot_water_energy_consumption.index,
y=final_hourly_hot_water_energy_consumption[ENERGY_FEATURE_NAME],
name="Hourly consumption",
yaxis="y1" # Assign to y-axis 1
)
)
# Add trace for previous monthly weight
fig.add_trace(
go.Scatter(
x=daily_hot_water_energy_consumption.index,
y=daily_hot_water_energy_consumption/24,
name="Hourly consumption",
yaxis="y1" # Assign to y-axis 1
)
)
# Add trace for new hourly weight
fig.add_trace(
go.Scatter(
x=induced_factors.index,
y=induced_factors.cold_water_temperature,
name="Cold water temperature",
yaxis="y2" # Assign to y-axis 2
)
)
# Define y-axis properties
fig.update_layout(
yaxis=dict(
title="Hourly consumption",
side="left" # Align with left side
),
yaxis2=dict(
title="Cold water temperature",
overlaying="y", # Overlay on top of first y-axis
side="right" # Align with right side
),
legend=dict(
orientation="h", # Horizontal orientation
yanchor="top", # Anchor to the top
y=-0.1, # Position below the plot
x=0.5,
xanchor="center" # Anchor to the center
)
)
# Show the figure
fig.show()
from heatpro.temporal_demand import HourlyHeatDemand
hot_water_energy_load = HourlyHeatDemand('hot_water',final_hourly_hot_water_energy_consumption)
hot_water_energy_load.plot()
from heatpro.special_hot_water import special_hot_water
direct_hot_water_energy_load = special_hot_water(
external_factors,
total_heating_including_hotwater,
monthly_hot_water_profile,
Temperature_hot_water,
hourly_hot_water_day_profil,
name="hot_water")
direct_hot_water_energy_load.plot()