7373
7474import os
7575import pandas as pd
76+ import numpy as np
7677import functools
7778import logging
7879import pickle
@@ -99,10 +100,59 @@ def run_demandlib(weather_data, cfg):
99100 """
100101 from demandlib import vdi
101102
103+ def climate_from_dwd_weather_file (fn_weather , try_region , hoy = 8760 ):
104+ """
105+ Create a demandlib climate object from a DWD weather file.
106+
107+ The weather file must adhere to the standard of the TRY weather
108+ data published in 2016 by the German weather service DWD,
109+ available at https://kunden.dwd.de/obt/.
110+
111+ .. note::
112+
113+ ``climate_from_dwd_weather_file()`` enables users to load the
114+ most recent DWD test reference year weather files **at their
115+ own risk**. They still need to provide a TRY region number,
116+ which is required for loading the energy factors.
117+ These are used for scaling the typical days relative to each
118+ other, depending on the TRY region. But users need to be aware
119+ that they do not have the originally intended effect when
120+ used with different weather data.
121+
122+ Other file types are currently not supported. Instead, users
123+ need to create a ``Climate()`` object and provide temperature
124+ and cloud coverage time series, as well as matching energy
125+ factors.
126+
127+ Parameters
128+ ----------
129+ fn_weather : str
130+ Name of the weather data file to load.
131+ try_region : int
132+ Number of the test-reference-year region where the building
133+ is located, as defined by the German weather service DWD.
134+ The module ``dwd_try`` provides the function ``find_try_region()``
135+ to find the correct region for given coordinates.
136+ hoy : int, optional
137+ Number of hours of the year. The default is 8760.
138+ """
139+ weather = vdi .dwd_try .read_dwd_weather_file (fn_weather )
140+ weather = (
141+ weather .set_index (
142+ pd .date_range (
143+ dt .datetime (2010 , 1 , 1 , 0 ),
144+ periods = hoy ,
145+ freq = "h" ,
146+ )
147+ )
148+ .resample ("D" )
149+ .mean ()
150+ )
151+ climate = climate_from_custom_weather (weather , try_region )
152+ return climate
153+
102154 def climate_from_custom_weather (weather , try_region ):
103155 """Create a Climate object from a DataFrame with weather data."""
104- vdi .Climate ().check_try_region (try_region )
105-
106156 weather = weather .resample ("D" ).mean ()
107157
108158 weather .loc [weather ["CCOVER" ] >= 5 , "cloud_category" ] = "B"
@@ -163,6 +213,11 @@ def climate_from_custom_weather(weather, try_region):
163213 house_dict_demandlib .pop ("copies" , None )
164214 house_dict_demandlib .pop ("sigma" , None )
165215 house_dict_demandlib .pop ("Q_Kalt_a" , None )
216+ # This should not be necessary, but in demandlib v0.2.2 requries
217+ # even unused energies to be defined
218+ house_dict_demandlib .setdefault ("Q_Heiz_a" , np .nan )
219+ house_dict_demandlib .setdefault ("W_a" , np .nan )
220+ house_dict_demandlib .setdefault ("Q_TWW_a" , np .nan )
166221 my_houses .append (house_dict_demandlib )
167222
168223 if len (my_houses ) == 0 :
@@ -177,41 +232,34 @@ def climate_from_custom_weather(weather, try_region):
177232 dtype = 'float' )
178233 df_empty .columns .set_names ('name' , inplace = True )
179234
180- try :
181- if settings ['weather_file' ] is None :
182- climate = vdi .Climate ().from_try_data (int (try_region ))
183- elif isinstance (settings ['weather_file' ], vdi .Climate ):
184- climate = settings ['weather_file' ]
185- elif isinstance (settings ['weather_file' ], pd .DataFrame ):
186- climate = climate_from_custom_weather (
187- settings ['weather_file' ], try_region )
188- else :
189- climate = vdi .Climate ().from_dwd_weather_file (
190- settings ['weather_file' ], try_region )
191-
192- my_region = vdi .Region (
193- year ,
194- holidays = holidays_dict ,
195- climate = climate ,
196- houses = my_houses ,
197- resample_rule = pd .Timedelta (settings .get ('intervall' , '1 hours' )),
198- zero_summer_heat_demand = settings .get ('zero_summer_heat_demand' ),
199- )
200- except AttributeError :
201- my_region = vdi .Region (
202- year ,
203- holidays = holidays_dict ,
204- try_region = try_region ,
205- houses = my_houses ,
206- resample_rule = pd .Timedelta (settings .get ('intervall' , '1 hours' )),
207- file_weather = settings ['weather_file' ],
208- zero_summer_heat_demand = settings .get ('zero_summer_heat_demand' ),
209- )
235+ # Allow different options for creating the climate and region classes
236+ if settings ['weather_file' ] is None :
237+ climate = vdi .Climate ().from_try_data (int (try_region ))
238+ elif isinstance (settings ['weather_file' ], vdi .Climate ):
239+ climate = settings ['weather_file' ]
240+ elif isinstance (settings ['weather_file' ], pd .DataFrame ):
241+ climate = climate_from_custom_weather (
242+ settings ['weather_file' ], try_region )
243+ else :
244+ climate = climate_from_dwd_weather_file (
245+ settings ['weather_file' ], try_region )
246+
247+ my_region = vdi .Region (
248+ year ,
249+ holidays = holidays_dict ,
250+ climate = climate ,
251+ houses = my_houses ,
252+ resample_rule = pd .Timedelta (settings .get ('intervall' , '1 hours' )),
253+ zero_summer_heat_demand = settings .get ('zero_summer_heat_demand' ),
254+ )
210255
211256 # Calculate load profiles
212257 logger .info ('Create %s VDI 4655 profiles with demandlib' , len (my_houses ))
213258 lc = my_region .get_load_curve_houses ()
214259
260+ # Drop unused (nan) columns
261+ lc = lc .dropna (how = 'all' , axis = 'columns' )
262+
215263 # Demandlib uses a different time step notation then lpagg
216264 lc = lc .shift (periods = 1 , freq = "infer" ).droplevel ('house_type' ,
217265 axis = 'columns' )
0 commit comments