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

Add VDI profiles based on lpagg #50

Draft
wants to merge 25 commits into
base: v0.2dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/electricity_demand_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import demandlib.bdew as bdew
import demandlib.particular_profiles as profiles

# The following dictionary is create by "workalendar"
# The following dictionary has been created by "workalendar"
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
# The following dictionary has been created by "workalendar"
# The following dictionary is created by "workalendar"

I am a bit puzzled here. First, you write that the dictionary has been/ is created using workalendar but later you define the holidays yourself.

Copy link

Choose a reason for hiding this comment

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

While I am writing comments here... :-)
Since those lines are commented out, I think this is just to suggest how to use an alternative library, without creating a new dependency for the installation of demandlib. My only suggestion would be to also name https://pypi.org/project/holidays/ as another option. Personally, it took me much too long to stumble across it.

# pip3 install workalendar
# >>> from workalendar.europe import Germany
# >>> cal = Germany()
Expand Down
103 changes: 103 additions & 0 deletions examples/vdi_profile_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# -*- coding: utf-8 -*-
"""
Creating power demand profiles using bdew profiles.

Installation requirements
-------------------------
This example requires at least version v0.1.4 of the oemof demandlib. Install
by:
pip install 'demandlib>=0.1.4,<0.2'
Optional:
pip install matplotlib

SPDX-FileCopyrightText: Uwe Krien <krien@uni-bremen.de>

SPDX-License-Identifier: MIT

"""

import datetime

from matplotlib import pyplot as plt

from demandlib import vdi

# The following dictionary has been created by "workalendar"
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
# The following dictionary has been created by "workalendar"
# The following dictionary can also be created by "workalendar"

Maybe this is more clear.

# pip3 install workalendar
# from workalendar.europe import Germany
# cal = Germany()
# holidays = dict(cal.holidays(2017))

holidays = {
datetime.date(2017, 1, 1): "New year",
datetime.date(2017, 4, 14): "Good Friday",
datetime.date(2017, 4, 17): "Easter Monday",
datetime.date(2017, 5, 1): "Labour Day",
datetime.date(2017, 5, 25): "Ascension Thursday",
datetime.date(2017, 6, 5): "Whit Monday",
datetime.date(2017, 10, 3): "Day of German Unity",
datetime.date(2017, 10, 31): "Reformation Day",
datetime.date(2017, 12, 25): "Christmas Day",
datetime.date(2017, 12, 26): "Second Christmas Day",
}
p-snft marked this conversation as resolved.
Show resolved Hide resolved


my_houses = []
for n in range(2):
my_houses.append(
{
"N_Pers": 3,
"name": "EFH_{0}".format(n),
"N_WE": 1,
"Q_Heiz_a": 6000,
"copies": 24,
"house_type": "EFH",
"Q_TWW_a": 1500,
"W_a": 5250,
"summer_temperature_limit": 15,
"winter_temperature_limit": 5,
}
)
my_houses.append(
{
"N_Pers": 45,
"name": "MFH_{0}".format(n),
"N_WE": 15,
"Q_Heiz_a": 60000,
"copies": 24,
"house_type": "MFH",
"Q_TWW_a": 15000,
"W_a": 45000,
"summer_temperature_limit": 15,
"winter_temperature_limit": 5,
}
)

start = datetime.datetime.now()

# To get the DWD TRY region from coordinates the geopandas package is needed.
# pip3 install geopandas
# try_region = vdi.find_try_region(13.42, 52.82)
try_region = 4

# define the region
my_region = vdi.Region(
2017,
holidays=holidays,
try_region=try_region,
houses=my_houses,
resample_rule="15min",
)

# calculate load profiles
lc = my_region.get_load_curve_houses()

print(datetime.datetime.now() - start)
lc = lc.groupby(level=[1, 2], axis=1).sum()
lc = lc.rolling(15).mean()
print(datetime.datetime.now() - start)
print(lc)

lc.plot()
print(lc.sum())
plt.show()
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def read(*names, **kwargs):
"", read("README.rst")
)
),
long_description_content_type="text/x-rst",
author="oemof developer group",
author_email="contact@oemof.org",
url="https://github.com/oemof/demandlib",
Expand Down Expand Up @@ -75,5 +76,7 @@ def read(*names, **kwargs):
},
extras_require={
"dev": ["pytest", "sphinx", "sphinx_rtd_theme", "matplotlib"],
"examples": ["matplotlib", "workalendar"],
"geometry": ["shapely", "geopandas"],
},
)
6 changes: 3 additions & 3 deletions src/demandlib/bdew/elec_slp.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,9 @@ def create_dynamic_h0_profile(self):

# Calculate the smoothing factor of the BDEW dynamic H0 profile
smoothing_factor = (
-3.916649251 * 10 ** -10 * decimal_day ** 4
+ 3.2 * 10 ** -7 * decimal_day ** 3
- 7.02 * 10 ** -5 * decimal_day ** 2
-3.916649251 * 10**-10 * decimal_day**4
+ 3.2 * 10**-7 * decimal_day**3
- 7.02 * 10**-5 * decimal_day**2
+ 0.0021 * decimal_day
+ 1.24
)
Expand Down
2 changes: 1 addition & 1 deletion src/demandlib/bdew/heat_building.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ def get_sf_values(self, filename="shlp_hour_factors.csv"):
+ (["weekday"] if not residential else [])
)

sf_mat = sf_mat.drop(drop_cols, 1)
sf_mat = sf_mat.drop(labels=drop_cols, axis=1)

# Determine the h values
length = len(self.temperature)
Expand Down
79 changes: 79 additions & 0 deletions src/demandlib/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-

"""
Adaptable config reader.

By default the config file of the package is used. Each value can be
overwritten with a user value with a custom config file in the $HOME directory
or in the working directory. The name of the config file must be:
demandlib.ini. If there is such a file in both locations the file in the
working directory will overwrite the one in the home folder.

SPDX-FileCopyrightText: Steffen - https://github.com/steffenGit
SPDX-FileCopyrightText: 2016-2021 Uwe Krien <krien@uni-bremen.de>

SPDX-License-Identifier: MIT
"""

__all__ = [
"get",
"init",
]


import configparser as cp
import os

BLACKLIST = ["tox.ini"]

cfg = cp.RawConfigParser()
cfg.optionxform = str
_loaded = False


def get_ini_filenames():
"""Returns a list of ini files to use."""
paths = []
files = []

paths.append(os.path.join(os.path.dirname(__file__)))
paths.append(os.path.join(os.path.expanduser("~")))
paths.append(os.getcwd())

for p in paths:
if p == "": # Empty path string must be ignored
continue
for f in os.listdir(p):
if f == "demandlib.ini":
files.append(os.path.join(p, f))
return files


def init():
"""Read config file(s)."""
cfg.read(get_ini_filenames(), encoding="utf-8")
global _loaded
_loaded = True


def load():
if not _loaded:
init()


def get(section, key):
"""Returns the value of a given key in a given section."""
load()
try:
return cfg.getint(section, key)
except ValueError:
try:
return cfg.getfloat(section, key)
except ValueError:
try:
return cfg.getboolean(section, key)
except ValueError:
value = cfg.get(section, key)
if value == "None":
value = None
return value
Empty file added src/demandlib/demandlib.ini
Empty file.
3 changes: 3 additions & 0 deletions src/demandlib/vdi/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .dwd_try import find_try_region # noqa: F401
from .dwd_try import read_dwd_weather_file # noqa: F401
from .regions import Region # noqa: F401
95 changes: 95 additions & 0 deletions src/demandlib/vdi/dwd_try.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-
"""
Read DWD TRY (test reference year) data.

SPDX-FileCopyrightText: Joris Zimmermann
SPDX-FileCopyrightText: Uwe Krien

SPDX-License-Identifier: MIT
"""

import os

import pandas as pd

try:
import geopandas as gpd
from shapely.geometry import Point
except ModuleNotFoundError:
pass


def find_try_region(longitude, latitude):
"""
Find the DWD TRY region by coordinates.

Notes
-----
The packages geopandas and shapely need to be installed to use this
function.

Parameters
----------
longitude : float
latitude : float

Returns
-------
DWD TRY region. : int

"""
fn_try_map = os.path.join(
os.path.dirname(__file__), "resources_weather", "TRY_polygons.geojson"
)
try_map = gpd.read_file(fn_try_map)
my_point = Point(longitude, latitude)
return int(try_map.loc[try_map.contains(my_point), "TRY_code"])


def read_dwd_weather_file(weather_file_path=None, try_region=None):
"""Read and interpolate 'DWD Testreferenzjahr' files."""
if weather_file_path is None:
weather_file_path = os.path.join(
os.path.dirname(__file__),
"resources_weather",
"TRY2010_{:02d}_Jahr.dat".format(try_region),
)
# The comments in DWD files before the header are not commented out.
# Thus we have to search for the line with the header information:
header_row = None
with open(weather_file_path, "r") as rows:
for number, row in enumerate(rows, 1):
# The header is the row before the appearance of '***'
if "***" in row:
header_row = number - 1
break

# Plausibility check:
if header_row is None:
msg = (
"Error: Header row not found in weather file. "
'Is the data type "DWD" correct? Exiting...\nFile is: '
+ weather_file_path
)
raise TypeError(msg)

# Read the file and store it in a DataFrame
weather_data = pd.read_csv(
weather_file_path,
delim_whitespace=True,
skiprows=header_row - 1,
index_col=["MM", "DD", "HH"],
usecols=["MM", "DD", "HH", "t", "N"],
comment="*",
)

# Rename the columns
weather_data.rename(
columns={
"t": "TAMB",
"N": "CCOVER",
},
inplace=True,
)

return weather_data
Loading