Example of usage of data for further modelling

In this demo we will show you how to load and use data in preheat.

[1]:
# Load packages from preheat and time management
from preheat_open import set_logging_level, test
set_logging_level("WARNING") # prevent annoying info logs from printing
from preheat_open.building import Building
from datetime import datetime, timedelta
import pandas as pd
pd.options.plotting.backend = "plotly"
2022-03-18 11:59:28,031  INFO      api                               Loading config from /home/ask/.preheat/config.json                                                                                                                .(api.py:126)

Let us consider a test-location

[2]:
building = Building(2371)

To access energy data we query for a list of heating units (there’s only one)

[3]:
heating = building.qu("heating")
print("Heating unit: ", heating)
Heating unit:  heating(heating_7252)

Let us consider the components of the heating unit

[4]:
print("The indoor climate unit has the following components: ", heating.components)
The indoor climate unit has the following components:  [Component(primaryReturnT, HEAT_RETURN_TEMP (S5))]

Unfortunately, the heating unit only has the return temperature mapped not any energy meter. We must infer the energy from the difference between main and hot water. (We could also traverse down the tree of the heating unit and check if the secondaries that belong to it have energy meters, however, we refrain from that in this tutorial.)

[5]:
main = building.qu("main")
print("Main:", main)
hot_water = building.qu("hotWater")
print("Hot water:", hot_water)
Main: [main(Hus 11 Main), main(MAIN [10+11])]
Hot water: hotWater(Hus 11 Varmt brugsvand)

It appears that this location shares its main unit with another location (the MAIN [10+11]) however, the unit Hus 11 Main provides us with information for only this location.

[6]:
main = main[0]

Let us check that these have the desired meters

[7]:
for u in [main, hot_water]:
    print(f"Components of {u.unit_type}:", u.components)
Components of main: [Component(supplyT, FLOW_TEMPERATURE), Component(returnT, RETURN_TEMPERATURE), Component(flow, VOLUME_FLOW), Component(volume, VOLUME), Component(energy, ENERGY), Component(power, POWER)]
Components of hotWater: [Component(primarySupplyT, FLOW_TEMPERATURE), Component(primaryReturnT, RETURN_TEMPERATURE), Component(primaryFlow, VOLUME_FLOW), Component(volume, VOLUME), Component(energy, ENERGY), Component(power, POWER)]

Luckily, they both provide power readings. Let us load the daily average power consumption for the past three months and approximate the consumption as the difference between the two. To avoid wasting effort on loading all available data, we restrict to the component “power” (you can leave components unspecified to load all data!)

[8]:
end = datetime.now()
start = end - timedelta(days=90)
resolution = "hour"
df = pd.DataFrame()
for u in [main, hot_water]:
    u.load_data(start,end,resolution, components=["power"])
    df[u.unit_type] = u.data["power"]
df["heating"] = df[main.unit_type] - df[hot_water.unit_type]
df.describe().transpose()
[8]:
count mean std min 25% 50% 75% max
main 2157.0 46.093011 13.453564 7.266667 39.225000 48.218182 54.916667 83.036364
hotWater 2158.0 5.766640 3.574115 1.600000 2.955492 4.713636 7.448864 25.760000
heating 2157.0 40.324532 12.962233 3.541667 34.383333 43.036364 48.063636 79.927273

While we are at it, let us load the weather information for the same period and append the data to our dataframe. Note that as a rule of thumb, the weather components begin with a capital letter. That allows us to distinguish the indoor temperature (a component of the indoor climate units) from the outdoor Temperature etc. We load the ambient temperature and the incoming sun power.

[9]:
weather = building.weather
print("Weather components:", weather.components)
weather_components = ["Temperature", "DirectSunPowerVertical", "DiffuseSunPower"]
weather.load_data(start,end,resolution, components=weather_components)
df[weather_components] = weather.data[weather_components]
df.describe().transpose()
Weather components: [Component(Temperature, None), Component(Humidity, None), Component(WindDirection, None), Component(WindSpeed, None), Component(Pressure, None), Component(LowClouds, None), Component(MediumClouds, None), Component(HighClouds, None), Component(Fog, None), Component(WindGust, None), Component(DewPointTemperature, None), Component(Cloudiness, None), Component(Precipitation, None), Component(DirectSunPower, None), Component(DiffuseSunPower, None), Component(SunAltitude, None), Component(SunAzimuth, None), Component(DirectSunPowerVertical, None)]
[9]:
count mean std min 25% 50% 75% max
main 2157.0 46.093011 13.453564 7.266667 39.225000 48.218182 54.916667 83.036364
hotWater 2158.0 5.766640 3.574115 1.600000 2.955492 4.713636 7.448864 25.760000
heating 2157.0 40.324532 12.962233 3.541667 34.383333 43.036364 48.063636 79.927273
Temperature 2159.0 3.425938 2.605860 -5.500000 1.700000 3.300000 5.500000 9.600000
DirectSunPowerVertical 2159.0 0.118278 0.207390 0.000000 0.000000 0.000000 0.156606 0.741441
DiffuseSunPower 2159.0 0.014667 0.027488 0.000000 0.000000 0.000000 0.016838 0.153348

We can use the acquired data to construct a simple linear model for the heating energy demand

[10]:
import statsmodels.formula.api as smf
res = smf.ols("heating ~ 1 + Temperature + DirectSunPowerVertical + DiffuseSunPower", df).fit()
res.summary()
[10]:
OLS Regression Results
Dep. Variable: heating R-squared: 0.479
Model: OLS Adj. R-squared: 0.479
Method: Least Squares F-statistic: 660.5
Date: Fri, 18 Mar 2022 Prob (F-statistic): 2.25e-304
Time: 11:59:29 Log-Likelihood: -7882.7
No. Observations: 2157 AIC: 1.577e+04
Df Residuals: 2153 BIC: 1.580e+04
Df Model: 3
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
Intercept 49.4827 0.341 145.220 0.000 48.814 50.151
Temperature -1.3682 0.079 -17.352 0.000 -1.523 -1.214
DirectSunPowerVertical -27.9668 1.548 -18.061 0.000 -31.003 -24.930
DiffuseSunPower -79.4236 11.723 -6.775 0.000 -102.413 -56.434
Omnibus: 9.255 Durbin-Watson: 0.777
Prob(Omnibus): 0.010 Jarque-Bera (JB): 10.786
Skew: -0.082 Prob(JB): 0.00455
Kurtosis: 3.305 Cond. No. 256.


Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

Let us investigate the quality of the fit

[ ]: