Advanced usage
In [1]:
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"
External Factors¶
In [2]:
from heatpro.external_factors import ExternalFactors
# loading external temperature
df = pd.read_csv("../data/external_factors.csv", index_col=0, parse_dates=True).iloc[:8760]
# Seating External Factors
external_factors = ExternalFactors(df["external_temperature"], df["heating_season"])
external_factors.plot()
Induced Factors¶
In [3]:
from heatpro.external_factors import (
TemperatureThreshold,
Threshold,
closed_heating_season,
burch_cold_water,
basic_temperature_supply,
basic_temperature_return,
kasuda_soil_temperature,
)
from heatpro.external_factors.induced_factors import InducedFactors
induced_factors = InducedFactors(
basic_temperature_supply(
external_factors,
TemperatureThreshold(
Threshold(50, 90),
Threshold(48, 60),
outside_mid=15,
outside_min=-15,
),
),
basic_temperature_return(
external_factors,
T_HS=40,
T_NHS=42,
),
kasuda_soil_temperature(external_factors, d=1, alpha=2.42 * 24 * 3600 / (840 * 3200)),
closed_heating_season(external_factors),
burch_cold_water(external_factors),
)
go.Figure(
data=[
go.Scatter(
x=induced_factors.cold_water_temperature.index,
y=induced_factors.cold_water_temperature,
name="Heatpro Cold Water",
),
go.Scatter(
x=induced_factors.supply_temperature.index,
y=induced_factors.supply_temperature,
name="Heatpro Supply",
),
go.Scatter(
x=induced_factors.return_temperature.index,
y=induced_factors.return_temperature,
name="Heatpro Return",
),
go.Scatter(
x=induced_factors.soil_temperature.index,
y=induced_factors.soil_temperature,
name="Heatpro Soil",
),
]
)
Building Heating + Hot Water¶
In [4]:
from heatpro.check import ENERGY_FEATURE_NAME
monthly_residential_load = pd.Series(
50000
* np.array(
[
2068,
1696,
1268,
727,
609,
194,
164,
177,
208,
1013,
1139,
1894,
]
),
index=pd.date_range("2021", end="2022", freq="MS", inclusive="left"),
name=ENERGY_FEATURE_NAME,
)
Hot Water¶
In [5]:
from heatpro.demand_profile import apply_weekly_hourly_pattern
from heatpro.demand_profile.hot_water_profile import basic_hot_water_hourly_profile
from heatpro.special_hot_water import special_hot_water
def hourly_mapping(day: int, hour: int) -> float:
return {
# jour 0
(0, 0): 0.016999999999999998,
(0, 1): 0.009,
(0, 2): 0.005,
(0, 3): 0.004,
(0, 4): 0.007,
(0, 5): 0.014,
(0, 6): 0.028,
(0, 7): 0.039,
(0, 8): 0.043000000000000003,
(0, 9): 0.049999999999999996,
(0, 10): 0.052,
(0, 11): 0.057,
(0, 12): 0.06999999999999999,
(0, 13): 0.064,
(0, 14): 0.045000000000000005,
(0, 15): 0.04,
(0, 16): 0.04699999999999999,
(0, 17): 0.059,
(0, 18): 0.06899999999999999,
(0, 19): 0.077,
(0, 20): 0.076,
(0, 21): 0.057,
(0, 22): 0.041,
(0, 23): 0.03,
# jour 1
(1, 0): 0.016999999999999998,
(1, 1): 0.009,
(1, 2): 0.005,
(1, 3): 0.004,
(1, 4): 0.007,
(1, 5): 0.014,
(1, 6): 0.028,
(1, 7): 0.039,
(1, 8): 0.043000000000000003,
(1, 9): 0.049999999999999996,
(1, 10): 0.052,
(1, 11): 0.057,
(1, 12): 0.06999999999999999,
(1, 13): 0.064,
(1, 14): 0.045000000000000005,
(1, 15): 0.04,
(1, 16): 0.04699999999999999,
(1, 17): 0.059,
(1, 18): 0.06899999999999999,
(1, 19): 0.077,
(1, 20): 0.076,
(1, 21): 0.057,
(1, 22): 0.041,
(1, 23): 0.03,
# jour 2
(2, 0): 0.016999999999999998,
(2, 1): 0.009,
(2, 2): 0.005,
(2, 3): 0.004,
(2, 4): 0.007,
(2, 5): 0.014,
(2, 6): 0.028,
(2, 7): 0.039,
(2, 8): 0.043000000000000003,
(2, 9): 0.049999999999999996,
(2, 10): 0.052,
(2, 11): 0.057,
(2, 12): 0.06999999999999999,
(2, 13): 0.064,
(2, 14): 0.045000000000000005,
(2, 15): 0.04,
(2, 16): 0.04699999999999999,
(2, 17): 0.059,
(2, 18): 0.06899999999999999,
(2, 19): 0.077,
(2, 20): 0.076,
(2, 21): 0.057,
(2, 22): 0.041,
(2, 23): 0.03,
# jour 3
(3, 0): 0.016999999999999998,
(3, 1): 0.009,
(3, 2): 0.005,
(3, 3): 0.004,
(3, 4): 0.007,
(3, 5): 0.014,
(3, 6): 0.028,
(3, 7): 0.039,
(3, 8): 0.043000000000000003,
(3, 9): 0.049999999999999996,
(3, 10): 0.052,
(3, 11): 0.057,
(3, 12): 0.06999999999999999,
(3, 13): 0.064,
(3, 14): 0.045000000000000005,
(3, 15): 0.04,
(3, 16): 0.04699999999999999,
(3, 17): 0.059,
(3, 18): 0.06899999999999999,
(3, 19): 0.077,
(3, 20): 0.076,
(3, 21): 0.057,
(3, 22): 0.041,
(3, 23): 0.03,
# jour 4
(4, 0): 0.016999999999999998,
(4, 1): 0.009,
(4, 2): 0.005,
(4, 3): 0.004,
(4, 4): 0.007,
(4, 5): 0.014,
(4, 6): 0.028,
(4, 7): 0.039,
(4, 8): 0.043000000000000003,
(4, 9): 0.049999999999999996,
(4, 10): 0.052,
(4, 11): 0.057,
(4, 12): 0.06999999999999999,
(4, 13): 0.064,
(4, 14): 0.045000000000000005,
(4, 15): 0.04,
(4, 16): 0.04699999999999999,
(4, 17): 0.059,
(4, 18): 0.06899999999999999,
(4, 19): 0.077,
(4, 20): 0.076,
(4, 21): 0.057,
(4, 22): 0.041,
(4, 23): 0.03,
# jour 5
(5, 0): 0.018000000000000002,
(5, 1): 0.010000000000000002,
(5, 2): 0.006,
(5, 3): 0.005000000000000001,
(5, 4): 0.005000000000000001,
(5, 5): 0.008000000000000002,
(5, 6): 0.013000000000000001,
(5, 7): 0.026000000000000002,
(5, 8): 0.04100000000000001,
(5, 9): 0.059000000000000004,
(5, 10): 0.06400000000000002,
(5, 11): 0.07100000000000001,
(5, 12): 0.07500000000000001,
(5, 13): 0.07500000000000001,
(5, 14): 0.06600000000000002,
(5, 15): 0.05,
(5, 16): 0.049,
(5, 17): 0.055000000000000014,
(5, 18): 0.062000000000000006,
(5, 19): 0.06400000000000002,
(5, 20): 0.062000000000000006,
(5, 21): 0.049,
(5, 22): 0.03900000000000001,
(5, 23): 0.028000000000000008,
# jour 6
(6, 0): 0.015000000000000001,
(6, 1): 0.010000000000000002,
(6, 2): 0.006,
(6, 3): 0.004000000000000001,
(6, 4): 0.004000000000000001,
(6, 5): 0.006,
(6, 6): 0.008000000000000002,
(6, 7): 0.013000000000000001,
(6, 8): 0.026000000000000002,
(6, 9): 0.04500000000000001,
(6, 10): 0.060000000000000005,
(6, 11): 0.07100000000000001,
(6, 12): 0.07600000000000001,
(6, 13): 0.07400000000000001,
(6, 14): 0.060000000000000005,
(6, 15): 0.053000000000000005,
(6, 16): 0.05,
(6, 17): 0.060000000000000005,
(6, 18): 0.07600000000000001,
(6, 19): 0.08200000000000002,
(6, 20): 0.07800000000000001,
(6, 21): 0.057000000000000016,
(6, 22): 0.04000000000000001,
(6, 23): 0.026000000000000002,
}.get((day, hour))
hourly_hot_water_load = special_hot_water(
external_factors=external_factors,
total_heating_including_hotwater=monthly_residential_load,
monthly_hot_water_profile=pd.DataFrame( # How hot water consumption vary each month
[1.13, 1.11, 1.04, 1.04, 1.0, 0.93, 0.8, 0.74, 0.98, 1.0, 1.09, 1.14],
columns=["weight"],
index=monthly_residential_load.index,
)
/ 12,
temperature_hot_water=60,
hourly_hot_water_day_profil=basic_hot_water_hourly_profile(
raw_hourly_hotwater_profile=apply_weekly_hourly_pattern(
hourly_index=external_factors.temperature.index, hourly_mapping=hourly_mapping
),
simultaneity=0.2,
sanitary_loop_coef=0.3,
),
)
hourly_hot_water_load.plot()
Residential¶
In [6]:
go.Figure(
data=[
go.Scatter(
x=monthly_residential_load.index,
y=monthly_residential_load,
name="total building",
),
go.Scatter(
x=monthly_residential_load.index,
y=(monthly_residential_load - hourly_hot_water_load.data.resample("MS").sum())[
ENERGY_FEATURE_NAME
],
name="building without hotwater",
),
]
)
In [7]:
monthly_residential_load
Out[7]:
2021-01-01 103400000 2021-02-01 84800000 2021-03-01 63400000 2021-04-01 36350000 2021-05-01 30450000 2021-06-01 9700000 2021-07-01 8200000 2021-08-01 8850000 2021-09-01 10400000 2021-10-01 50650000 2021-11-01 56950000 2021-12-01 94700000 Freq: MS, Name: thermal_energy_kWh, dtype: int64
In [8]:
from heatpro.demand_profile import apply_weekly_hourly_pattern
from heatpro.demand_profile.building_heating_profile import (
basic_building_heating_profile,
BUILDING_FELT_TEMPERATURE_NAME,
)
from heatpro.disaggregation import weekly_weighted_disaggregate
monthly_residential_load = (
monthly_residential_load - hourly_hot_water_load.data.resample("MS").sum()[ENERGY_FEATURE_NAME]
).rename(ENERGY_FEATURE_NAME)
def hourly_mapping(day: int, hour: int) -> float:
return {
# jour 0
(0, 0): 0.005930381852781527,
(0, 1): 0.005218474124594565,
(0, 2): 0.0054559751141820215,
(0, 3): 0.005870857795240811,
(0, 4): 0.006345264533840317,
(0, 5): 0.006701218397933798,
(0, 6): 0.006938124146945847,
(0, 7): 0.007116101078992588,
(0, 8): 0.007116101078992588,
(0, 9): 0.007116101078992588,
(0, 10): 0.0069976482044865635,
(0, 11): 0.006879195329980539,
(0, 12): 0.0067601472148991065,
(0, 13): 0.006641694340393082,
(0, 14): 0.006463717408346343,
(0, 15): 0.006345264533840317,
(0, 16): 0.006167287601793576,
(0, 17): 0.005930381852781527,
(0, 18): 0.005574427988688046,
(0, 19): 0.005158950067053849,
(0, 20): 0.004684543328454343,
(0, 21): 0.004151207772889528,
(0, 22): 0.0036768010342900226,
(0, 23): 0.003617276976749307,
# jour 1
(1, 0): 0.005930381852781527,
(1, 1): 0.005218474124594565,
(1, 2): 0.0054559751141820215,
(1, 3): 0.005870857795240811,
(1, 4): 0.006345264533840317,
(1, 5): 0.006701218397933798,
(1, 6): 0.006938124146945847,
(1, 7): 0.007116101078992588,
(1, 8): 0.007116101078992588,
(1, 9): 0.007116101078992588,
(1, 10): 0.0069976482044865635,
(1, 11): 0.006879195329980539,
(1, 12): 0.0067601472148991065,
(1, 13): 0.006641694340393082,
(1, 14): 0.006463717408346343,
(1, 15): 0.006345264533840317,
(1, 16): 0.006167287601793576,
(1, 17): 0.005930381852781527,
(1, 18): 0.005574427988688046,
(1, 19): 0.005158950067053849,
(1, 20): 0.004684543328454343,
(1, 21): 0.004151207772889528,
(1, 22): 0.0036768010342900226,
(1, 23): 0.003617276976749307,
# jour 2
(2, 0): 0.005930381852781527,
(2, 1): 0.005218474124594565,
(2, 2): 0.0054559751141820215,
(2, 3): 0.005870857795240811,
(2, 4): 0.006345264533840317,
(2, 5): 0.006701218397933798,
(2, 6): 0.006938124146945847,
(2, 7): 0.007116101078992588,
(2, 8): 0.007116101078992588,
(2, 9): 0.007116101078992588,
(2, 10): 0.0069976482044865635,
(2, 11): 0.006879195329980539,
(2, 12): 0.0067601472148991065,
(2, 13): 0.006641694340393082,
(2, 14): 0.006463717408346343,
(2, 15): 0.006345264533840317,
(2, 16): 0.006167287601793576,
(2, 17): 0.005930381852781527,
(2, 18): 0.005574427988688046,
(2, 19): 0.005158950067053849,
(2, 20): 0.004684543328454343,
(2, 21): 0.004151207772889528,
(2, 22): 0.0036768010342900226,
(2, 23): 0.003617276976749307,
# jour 3
(3, 0): 0.005930381852781527,
(3, 1): 0.005218474124594565,
(3, 2): 0.0054559751141820215,
(3, 3): 0.005870857795240811,
(3, 4): 0.006345264533840317,
(3, 5): 0.006701218397933798,
(3, 6): 0.006938124146945847,
(3, 7): 0.007116101078992588,
(3, 8): 0.007116101078992588,
(3, 9): 0.007116101078992588,
(3, 10): 0.0069976482044865635,
(3, 11): 0.006879195329980539,
(3, 12): 0.0067601472148991065,
(3, 13): 0.006641694340393082,
(3, 14): 0.006463717408346343,
(3, 15): 0.006345264533840317,
(3, 16): 0.006167287601793576,
(3, 17): 0.005930381852781527,
(3, 18): 0.005574427988688046,
(3, 19): 0.005158950067053849,
(3, 20): 0.004684543328454343,
(3, 21): 0.004151207772889528,
(3, 22): 0.0036768010342900226,
(3, 23): 0.003617276976749307,
# jour 4
(4, 0): 0.005930381852781527,
(4, 1): 0.005218474124594565,
(4, 2): 0.0054559751141820215,
(4, 3): 0.005870857795240811,
(4, 4): 0.006345264533840317,
(4, 5): 0.006701218397933798,
(4, 6): 0.006938124146945847,
(4, 7): 0.007116101078992588,
(4, 8): 0.007116101078992588,
(4, 9): 0.007116101078992588,
(4, 10): 0.0069976482044865635,
(4, 11): 0.006879195329980539,
(4, 12): 0.0067601472148991065,
(4, 13): 0.006641694340393082,
(4, 14): 0.006463717408346343,
(4, 15): 0.006345264533840317,
(4, 16): 0.006167287601793576,
(4, 17): 0.005930381852781527,
(4, 18): 0.005574427988688046,
(4, 19): 0.005158950067053849,
(4, 20): 0.004684543328454343,
(4, 21): 0.004151207772889528,
(4, 22): 0.0036768010342900226,
(4, 23): 0.003617276976749307,
# jour 5
(5, 0): 0.005930381852781527,
(5, 1): 0.005218474124594565,
(5, 2): 0.0054559751141820215,
(5, 3): 0.005870857795240811,
(5, 4): 0.006345264533840317,
(5, 5): 0.006701218397933798,
(5, 6): 0.006938124146945847,
(5, 7): 0.007116101078992588,
(5, 8): 0.007116101078992588,
(5, 9): 0.007116101078992588,
(5, 10): 0.0069976482044865635,
(5, 11): 0.006879195329980539,
(5, 12): 0.0067601472148991065,
(5, 13): 0.006641694340393082,
(5, 14): 0.006463717408346343,
(5, 15): 0.006345264533840317,
(5, 16): 0.006167287601793576,
(5, 17): 0.005930381852781527,
(5, 18): 0.005574427988688046,
(5, 19): 0.005158950067053849,
(5, 20): 0.004684543328454343,
(5, 21): 0.004151207772889528,
(5, 22): 0.0036768010342900226,
(5, 23): 0.003617276976749307,
# jour 6
(6, 0): 0.005930381852781527,
(6, 1): 0.005218474124594565,
(6, 2): 0.0054559751141820215,
(6, 3): 0.005870857795240811,
(6, 4): 0.006345264533840317,
(6, 5): 0.006701218397933798,
(6, 6): 0.006938124146945847,
(6, 7): 0.007116101078992588,
(6, 8): 0.007116101078992588,
(6, 9): 0.007116101078992588,
(6, 10): 0.0069976482044865635,
(6, 11): 0.006879195329980539,
(6, 12): 0.0067601472148991065,
(6, 13): 0.006641694340393082,
(6, 14): 0.006463717408346343,
(6, 15): 0.006345264533840317,
(6, 16): 0.006167287601793576,
(6, 17): 0.005930381852781527,
(6, 18): 0.005574427988688046,
(6, 19): 0.005158950067053849,
(6, 20): 0.004684543328454343,
(6, 21): 0.004151207772889528,
(6, 22): 0.0036768010342900226,
(6, 23): 0.003617276976749307,
}.get((day, hour))
hourly_residential_profile = basic_building_heating_profile(
felt_temperature=pd.DataFrame(
external_factors.temperature.ewm(24).mean().rename(BUILDING_FELT_TEMPERATURE_NAME)
),
non_heating_temperature=18,
hourly_weight=apply_weekly_hourly_pattern(
hourly_index=external_factors.temperature.index, hourly_mapping=hourly_mapping
),
)
hourly_residential_load = weekly_weighted_disaggregate(
monthly_demand=monthly_residential_load,
weights=hourly_residential_profile,
)
In [9]:
hourly_residential_load.plot()
Industry¶
In [10]:
from heatpro.disaggregation import monthly_weighted_disaggregate
from heatpro.demand_profile import (
month_length_proportionnal_weight,
day_length_proportionnal_weight,
)
yearly_industry_load = monthly_residential_load.resample("YS").sum() * 0.1
monthly_industry_load = monthly_weighted_disaggregate(
yearly_demand=yearly_industry_load,
weights=month_length_proportionnal_weight(
pd.date_range("2021", end="2022", freq="MS", inclusive="left")
),
)
hourly_industry_load = weekly_weighted_disaggregate(
monthly_demand=monthly_industry_load,
weights=apply_weekly_hourly_pattern(
hourly_index=external_factors.temperature.index, hourly_mapping=lambda day, hour: 1 / 24
)
* day_length_proportionnal_weight(dates=external_factors.temperature.index),
)
hourly_industry_load.plot()
In [11]:
from heatpro.demand_profile.loss_profile import Y_to_H_thermal_loss_profile
from heatpro.temporal_demand import HourlyHeatDemand
yearly_heat_loss_load = monthly_residential_load.resample("YE").sum() * 0.06
hourly_heat_loss_load = HourlyHeatDemand(
"heat_loss",
(Y_to_H_thermal_loss_profile(induced_factors) * yearly_heat_loss_load.iloc[0]).rename(
columns={"weight": ENERGY_FEATURE_NAME}
),
)
In [12]:
from heatpro.district_heating_load import DistrictHeatingLoad
hourly_hot_water_load.name = "hot_water"
hourly_industry_load.name = "industry"
hourly_residential_load.name = "residential"
hourly_heat_loss_load.name = "heat_loss"
district_heating = DistrictHeatingLoad(
demands=[
hourly_hot_water_load,
hourly_industry_load,
hourly_residential_load,
hourly_heat_loss_load,
],
external_factors=external_factors,
district_network_temperature=induced_factors,
delta_temperature=7,
cp=4.18,
)
district_heating.fit()
In [13]:
district_heating.data.astype(float).plot()
Ending Vizualisation¶
In [14]:
go.Figure(
data=[
go.Scatter(
x=district_heating.data.index,
y=district_heating.data[f"{sector}_{ENERGY_FEATURE_NAME}"],
name=sector,
stackgroup="positive",
)
for sector in district_heating.demands.keys()
]
)