Source code for oemof.demand.particular_profiles

# -*- coding: utf-8 -*-
"""
Implementation of industrial step load profiles.

"""

from datetime import time as settime

import pandas as pd

from .tools import add_weekdays2df


[docs] class IndustrialLoadProfile: """Generate an industrial heat or electricity load profile.""" def __init__(self, dt_index, holidays=None, holiday_is_sunday=False): """ Initialize the industrial load profile. Parameters ---------- dt_index : pandas.DatetimeIndex Datetime index for the load profile. holidays : dict Dictionary with keys of type datetime and values with holiday name as str, e.g. {datetime.date(2010, 1, 1): "New year"}. See the electricity_demand_example in the examples directory for information on how to obtain holidays using workalender. Per default, no holidays are used. Default: None. holiday_is_sunday : bool If True, holidays are treated as Sundays. If False, holidays are assigned weekday 0 and separate holiday scaling factors are applied in method simple_profile(). Default: False. """ self.dataframe = pd.DataFrame(index=dt_index) self.dataframe = add_weekdays2df( self.dataframe, holiday_is_sunday=holiday_is_sunday, holidays=holidays, )
[docs] def simple_profile(self, annual_demand, **kwargs): """ Create industrial step load profile. Parameters ---------- annual_demand : float Total demand over the period given upon initialisation of IndustrialLoadProfile through parameter `dt_index`. This is actually only the annual demand, if an entire year was given. Other Parameters ---------------- am : datetime.time Defines the beginning of the workday. Times between `am` and `pm`, including the start and end time defined by `am` and `pm`, are assigned "day" factors from `profile_factors`. Other times are assigned "night" factors. Default: 7 a.m. pm : datetime.time Defines the end of the workday. Times between `am` and `pm`, including the start and end time defined by `am` and `pm`, are assigned "day" factors from `profile_factors`. Other times are assigned "night" factors. Default: 11:30 p.m. week : list(int) List of weekdays, where 1 corresponds to Monday, 2 to Tuesday, etc. Weekdays are assigned "week" factors from `profile_factors`. Default: [1, 2, 3, 4, 5]. weekend : list(int) List of weekend days, where 1 corresponds to Monday, 2 to Tuesday, etc. Weekend days are assigned "weekend" factors from `profile_factors`. Default: [6, 7]. holiday : list(int) List of holiday days. Holidays given upon initialisation of the IndustrialLoadProfile object are tagged with weekday 0 if `holiday_is_sunday` is set to False, wherefore the default for this parameter is [0]. Holidays are assigned "holiday" factors from `profile_factors`. Default: [0]. profile_factors : dict Dictionary with load profile scaling factors for night and day of weekdays, weekend days and holidays. The dictionary must have the same form as the dictionary given as the default value. Default: .. code:: python { "week": {"day": 0.8, "night": 0.6}, "weekend": {"day": 0.9, "night": 0.7}, "holiday": {"day": 0.9, "night": 0.7}, } Returns ------- pd.Series Series with demand per time step (unit depends on the unit the `annual_demand` was provided with). Index is a DatetimeIndex containing all time steps the IndustrialLoadProfile was initialised with. """ # Define day (am to pm), night (pm to am), week day (week), # weekend day (weekend) and holiday am = kwargs.get("am", settime(7, 00, 0)) pm = kwargs.get("pm", settime(23, 30, 0)) week = kwargs.get("week", [1, 2, 3, 4, 5]) weekend = kwargs.get("weekend", [6, 7]) holiday = kwargs.get("holiday", [0]) default_factors = { "week": {"day": 0.8, "night": 0.6}, "weekend": {"day": 0.9, "night": 0.7}, "holiday": {"day": 0.9, "night": 0.7}, } profile_factors = kwargs.get("profile_factors", default_factors) # check profile factors for key in ["week", "weekend", "holiday"]: if key not in profile_factors.keys(): raise ValueError( f"Missing entry for '{key}' in profile_factors." ) else: if "day" not in profile_factors[key].keys(): raise ValueError( f"Missing entry for 'day' in profile_factors for " f"'{key}'." ) elif "night" not in profile_factors[key].keys(): raise ValueError( f"Missing entry for 'night' in profile_factors for " f"'{key}'." ) self.dataframe["ind"] = 0.0 day_mask = self.dataframe.index.indexer_between_time( am, pm, include_start=True, include_end=True ) day_filter = pd.Series(False, index=self.dataframe.index) day_filter.iloc[day_mask] = True # set up night filter as the reverse of the day filter night_filter = pd.Series(True, index=self.dataframe.index) night_filter.iloc[day_mask] = False week_filter = self.dataframe["weekday"].isin(week) weekend_filter = self.dataframe["weekday"].isin(weekend) holiday_filter = self.dataframe["weekday"].isin(holiday) # Update 'ind' column based on day/night filters and # weekday/weekend/holiday conditions self.dataframe.loc[day_filter & week_filter, "ind"] = profile_factors[ "week" ]["day"] self.dataframe.loc[night_filter & week_filter, "ind"] = ( profile_factors["week"]["night"] ) self.dataframe.loc[day_filter & weekend_filter, "ind"] = ( profile_factors["weekend"]["day"] ) self.dataframe.loc[night_filter & weekend_filter, "ind"] = ( profile_factors["weekend"]["night"] ) self.dataframe.loc[day_filter & holiday_filter, "ind"] = ( profile_factors["holiday"]["day"] ) self.dataframe.loc[night_filter & holiday_filter, "ind"] = ( profile_factors["holiday"]["night"] ) time_interval = self.dataframe.index.freq.nanos / 3.6e12 return ( self.dataframe["ind"] / self.dataframe["ind"].sum() * annual_demand / time_interval )