Skip to content
Snippets Groups Projects
Select Git revision
  • b280eef24479542f5f150e0aac13e94368e91d06
  • main default protected
  • ravaflow3g
  • docs
  • v0.1.2
  • v0.1.1
  • v0.1.0
7 results

conf.py

Blame
  • input_profile_processor.py NaN GiB
    """
    MIT License
    
    Copyright (c) 2023 RWTH Aachen University
    
    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:
    
    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.
    """
    
    from Model_Library.dynamics import Profile
    from Tooling.demand_generator.electrical_demand.ElectricalDemand import ElectricalDemand
    from Tooling.demand_generator.thermal_demand.ThermalDemand import ThermalDemand
    from Tooling.input_profile_processor.calc_irradiance import generate_g_t_series
    from Tooling.modifier import Modifier
    
    from datetime import datetime, timedelta
    import pandas as pd
    
    def process_input_profiles(input_profile_dict, t_start, dynamic):
        d_step_min = min(dynamic.step_size(index) for index in dynamic.time_steps())
        # This entire process assumes four things:
        # 1. d_step_min devides a day into an integer amount of steps
        # 2. d_step_min devides the intervall from YYYY.MM.DD 00:00:00 of the day containing t_start to t_start into an integer amount of steps
        # 3. The timestamps of the desired timeseries either line up the with timestamps provided by the profiles in the files or the other way around
        # 4. The sizes of all time steps in the given dynamic are devisible by 
        input_profiles = {}
        for input_profile_name, input_profile_config in input_profile_dict.items():
            if 'file' in input_profile_config:
                profile = load_profile(input_profile_name, input_profile_config['file'], t_start, dynamic, d_step_min)
            elif 'generate' in input_profile_config:
                profile = generate_profile(input_profile_name, input_profile_config['type'], input_profile_config['generate'], input_profiles, t_start, dynamic, d_step_min)
            elif 'modify' in input_profile_config:
                profile = modify_profile(input_profile_name, input_profile_config['type'], input_profile_config['modify'], input_profiles, t_start, dynamic, d_step_min)
            input_profiles[input_profile_name] = (input_profile_config['type'], profile)
    
        for input_profile_name, (input_profile_type, input_profile) in input_profiles.items():
            input_profile.drop(pd.date_range(input_profile.index[0], t_start - timedelta(hours = d_step_min), freq = str(d_step_min) + 'H'), inplace = True)
            input_profile.drop(pd.date_range(t_start + pd.Timedelta(hours = sum(dynamic.step_size(index) for index in dynamic.time_steps())), input_profile.index[-1], freq = str(d_step_min) + 'H'), inplace = True)
    
            if len(input_profile) != dynamic.number_of_steps():
                index = 0
                drop = []
                for index in dynamic.time_steps():
                    if dynamic.step_size(index) != d_step_min:
                        number_of_steps = int(dynamic.step_size(index) / d_step_min)
                        input_profile.iloc[index] = sum(d_step_min * input_profile.iloc[index + i] for i in range(number_of_steps)) / dynamic.step_size(index)
                        drop.extend(index + i + 1 for i in range(number_of_steps - 1))
                        index += number_of_steps
                    else:
                        index += 1
                input_profile.drop((input_profile.index[i] for i in drop), inplace = True)
    
            if input_profile_type == 'irradiance':
                lambda_1 = 14.122
                lambda_st = 15
                phi = 52.21
                psi_f = 0
                beta = 30
                input_profile = generate_g_t_series(input_profile, beta, psi_f, phi, lambda_st, lambda_1, t_start, dynamic)
    
            input_profile = input_profile.squeeze()
            input_profile.set_axis(list(range(dynamic.number_of_steps())), inplace = True)
            input_profiles[input_profile_name] = Profile(input_profile, dynamic)
        return input_profiles
    
    def resample_profile(name, profile, t_start, dynamic, d_step_min, t_last):
        profile = profile.resample(str(d_step_min) + 'H').mean().interpolate('linear')
        if t_start < profile.index[0]:
            missing_indices = pd.date_range(t_start, profile.index[0] - timedelta(hours = d_step_min), freq = str(d_step_min) + 'H')
            print(f'For input profile {name} {len(missing_indices)} {"values are" if len(missing_indices) > 1 else "value is"} extrapolated to the beginning of the profile!')
            profile = pd.concat([pd.DataFrame([profile.iloc[0]], index = missing_indices), profile])
        if profile.index[-1] < t_last:
            missing_indices = pd.date_range(profile.index[-1] + timedelta(hours = d_step_min), t_last, freq = str(d_step_min) + 'H')
            print(f'For input profile {name} {len(missing_indices)} {"values are" if len(missing_indices) > 1 else "value is"} extrapolated to the end of the profile!')
            profile = pd.concat([profile, pd.DataFrame([profile.iloc[-1]], index = missing_indices)])
        return profile
    
    def expand_profile_to_year(profile, year, t_step):
        if datetime(year, 1, 1, 0) < profile.index[0]:
            missing_indices = pd.date_range(datetime(year, 1, 1, 0), profile.index[0] - timedelta(hours = t_step), freq = str(t_step) + 'H')
            profile = pd.concat([pd.DataFrame([profile.iloc[0]], index  =missing_indices), profile])
        if profile.index[-1] < datetime(year + 1, 1, 1, 0) - timedelta(hours = t_step):
            missing_indices = pd.date_range(profile.index[-1] + timedelta(hours = t_step), datetime(year + 1, 1, 1, 0) - timedelta(hours = t_step), freq = str(t_step) + 'H')
            profile = pd.concat([profile, pd.DataFrame([profile.iloc[-1]], index = missing_indices)])
        return profile
    
    def load_profile(name, file, t_start, dynamic, d_step_min):
        t_last = t_start + pd.Timedelta(hours = sum(dynamic.step_size(index) for index in dynamic.time_steps()) - 1)
        profile = pd.read_csv(file, index_col = 0)
        try:
            file_start = pd.to_datetime(profile.index[0], format = '%d-%m-%Y %H:%M:%S')
            format = '%d-%m-%Y %H:%M:%S'
        except ValueError:
            format = '%Y-%m-%d %H:%M:%S'
        # left_index = 0
        # right_index = len(profile) - 1
        # middle_index = left_index + int((right_index - left_index) / 2)
        # middle_time = pd.to_datetime(profile.index[middle_index], format = format)
        # while True:
        #     if right_index - left_index == 1:
        #         # We now know that t_start is strictly larger than the time at left_index and smaller or equal than the time at right_index
        #         # So we have to test if t_start is equal to the time at right_index and return right_index if this is the case
        #         # Otherwise return left_index
        #         right_time = pd.to_datetime(profile.index[right_index], format = format)
        #         if right_time <= t_start:
        #             first_index = right_index
        #         else:
        #             first_index = left_index
        #         break
        #     if middle_time < t_start:
        #         left_index = middle_index
        #     else:
        #         right_index = middle_index
        #     middle_index = left_index + int((right_index - left_index) / 2)
        #     middle_time = pd.to_datetime(profile.index[middle_index], format = format)
        # left_index = 0
        # right_index = len(profile) - 1
        # middle_index = left_index + int((right_index - left_index) / 2)
        # middle_time = pd.to_datetime(profile.index[middle_index], format = format)
        # while True:
        #     if right_index - left_index == 1:
        #         # We now know that t_last is lager or equal than the time at left_index and strictly smaller than the time at right_index
        #         # So we have to test if t_last is equal to the time at left_index and return left_index if this is the case
        #         # Otherwise return right_index
        #         left_time = pd.to_datetime(profile.index[left_index], format = format)
        #         if t_last <= left_time:
        #             last_index = left_index
        #         else:
        #             last_index = right_index
        #         break
        #     if t_last < middle_time:
        #         right_index = middle_index
        #     else:
        #         left_index = middle_index
        #     middle_index = left_index + int((right_index - left_index) / 2)
        #     middle_time = pd.to_datetime(profile.index[middle_index], format = format)
        # first_index = 0
        # last_index = len(profile) - 1
        # profile = profile[first_index:last_index + 1]
        profile.index = pd.to_datetime(profile.index, format = format)
        return resample_profile(name, profile, t_start, dynamic, d_step_min, t_last)
    
    def generate_profile(name, profile_type, parameters, input_profiles, t_start, dynamic, d_step_min):
        t_last = t_start + pd.Timedelta(hours = sum(dynamic.step_size(index) for index in list(dynamic.time_steps())[:-1]))
        years = range(t_start.year, t_last.year + 1)
    
        if profile_type == 'elec_demand':
            profiles = []
            for year in years:
                year_profile = ElectricalDemand(year).get_profile(parameters['yearly_demand'], 'h0', True)  # True: with smoothing function for household profiles, False: no smoothing function for household profiles
                profiles.append(year_profile)
            profile = pd.concat(profiles)
            return resample_profile(name, profile, t_start, dynamic, d_step_min, t_last)
        elif profile_type == 'therm_demand':
            profiles = []
            for year in years:
                demand_df = pd.DataFrame(index=pd.date_range(datetime(year, 1, 1, 0),
                                                             periods=8760 / d_step_min,
                                                             freq=str(d_step_min) + 'H'))
                # Fixme: non-residential building only have building_class = 0
                # residential building could varies from 1 to 11
                # same problem for hot water demand.
                # temporary fix
                if len(input_profiles[parameters['temperature']][1]) < len(demand_df.index):
                    temp = list(input_profiles[parameters['temperature']])
                    temp[1] = expand_profile_to_year(input_profiles[parameters['temperature']][1], year, d_step_min)
                    input_profiles[parameters['temperature']] = tuple(temp)
                year_profile = ThermalDemand(demand_df.index,
                                             shlp_type='EFH',
                                             temperature=input_profiles[parameters['temperature']][1],
                                             building_class=1,
                                             wind_class=1,
                                             annual_heat_demand=parameters['yearly_demand'],
                                             name='HeatDemand_EFH',
                                             ww_incl=0).get_bdew_profile()
                profiles.append(year_profile)
            profile = pd.concat(profiles)
            return profile
        elif profile_type == 'hot_water_demand':
            profiles = []
            for year in years:
                demand_df = pd.DataFrame(index=pd.date_range(datetime(year, 1, 1, 0),
                                                             periods=8760 / d_step_min,
                                                             freq=str(d_step_min) + 'H'))
                # temporary fix
                if len(input_profiles[parameters['temperature']][1]) < len(demand_df.index):
                    temp = list(input_profiles[parameters['temperature']])
                    temp[1] = expand_profile_to_year(input_profiles[parameters['temperature']][1], year, d_step_min)
                    input_profiles[parameters['temperature']] = tuple(temp)
                year_profile = ThermalDemand(demand_df.index,
                                             shlp_type='EFH',
                                             temperature=input_profiles[parameters['temperature']][1],
                                             building_class=1,
                                             wind_class=1,
                                             annual_heat_demand=parameters['yearly_demand'],
                                             name='DomesticHotWaterDemand_EFH',
                                             ww_incl=1).get_bdew_profile()
                profiles.append(year_profile)
            profile = pd.concat(profiles)
            return profile
        else:
            raise Exception("Generator for profile type " + str(profile_type) + " is not implemented!")
    
    
    def modify_profile(name, mod_type: str, parameters, input_profiles, t_start, dynamic, d_step_min):
        # Example of the parameters for use in the runme
        # ------------------------------------------------------------------------------------------------------------------
        # 'temperature_1': ['prophet', 'modify', 'input_files/data/temperature/temperature.csv', 'temperature',
        #                       {"winter1": 0, "spring": 0, "summer": 0,"fall": 0,"winter2": 0},
        #                       "Tooling/Modifier/prophet_models/serialized_model_08032023.json", True, True]
        # ------------------------------------------------------------------------------------------------------------------
    
        if mod_type == "prophet":
            # t_start : timestamp, e.g.: pd.Timestamp("2021-01-01 00:00:00")
            # t_horizon: int, number of days that should be created, for now hardcoded to 365 due to external dependencies
            # parameters[]: array of additional parameters, should contain csv_path, season_offset, model_path, new, save.
            # For details on the specific parameters look at the documentation of the prophet_based_modification
            profile = Modifier.prophet_based_modification(csv_path = parameters[0],
                                                          feature_name = parameters[1],
                                                          season_offset = parameters[2],
                                                          start = t_start,
                                                          model_path = parameters[3],
                                                          new = parameters[4],
                                                          mod_period = 365,
                                                          save = parameters[5])
            return profile
        else:
            raise Exception("Modification for mod type " + str(mod_type) + " is not implemented!")