def test_change_res_sum_larger_timestep(self): input_array = [10, 10, 20, 20] output_array = chres.changeResolution(values=input_array, oldResolution=900, newResolution=3600, method="sum") assert output_array == [60]
def load_hourly_factors(filename, time_discretization=3600): """ """ # Initialization hourly_factors = {} temperature_range = [-15, -10, -5, 0, 5, 10, 15, 20, 25, 100] book_hourly = xlrd.open_workbook(filename) # Iterate over all sheets for sheetname in book_hourly.sheet_names(): sheet = book_hourly.sheet_by_name(sheetname) temp_factors = {} # Create temporary dictionary for each sheet for d in range(7): for t in range(len(temperature_range)): # Read values values = [sheet.cell_value(d*11+t+1, hour+1) for hour in range(24)] if time_discretization != 3600: values = cr.changeResolution(values, 3600, time_discretization, "sum") temp_factors[d, temperature_range[t]] = np.array(values) # Store values hourly_factors[sheetname] = temp_factors # Return final results return hourly_factors
def test_change_res_mean_larger_timestep_2(self): input_array = [10, 20, 20, 20, 20, 30] output_array = chres.changeResolution(values=input_array, oldResolution=900, newResolution=3600, method="mean") assert output_array[0] == 10 assert output_array[1] == 20
def test_change_res_sum_smaller_timestep(self): input_array = [10, 20] output_array = chres.changeResolution(values=input_array, oldResolution=3600, newResolution=900, method="sum") assert output_array[0] == 2.5 assert output_array[1] == 2.5 assert output_array[2] == 2.5 assert output_array[3] == 2.5 assert output_array[4] == 5 assert output_array[5] == 5 assert output_array[6] == 5 assert output_array[7] == 5
def get_occ_profile_in_curr_timestep(self, timestep=None, int_con=False): """ Returns occupancy profile in current timestep (as occupancy profile is saved with 600 seconds timestep, per default) Parameters ---------- timestep : int, optional Defines specific timestep to return occupancy profile in (default: None). If None is chosen, returns profile with timestep found in environment.timer int_con : bool, optional Defines, if output values should be converted into integer numbers (conversion might lead to float numbers, depending on chosen timesteps) (default: False) Returns ------- occ_profile : np.array Numpy array holding number of persons, present within zone """ occ_profile = copy.copy(self.occupancy) if timestep is None: timestep = self.environment.timer.timeDiscretization occ_profile = chres.changeResolution(values=occ_profile, oldResolution=600, newResolution=timestep) if int_con: for i in range(len(occ_profile)): occ_profile[i] = int(round(occ_profile[i])) return occ_profile
def __init__(self, environment, method=0, loadcurve=[], annualDemand=None, profileType="H0", singleFamilyHouse=True, total_nb_occupants=0, randomizeAppliances=True, lightConfiguration=0, occupancy=[], do_normalization=False, method_3_type=None, method_4_type=None, prev_heat_dev=False, app_filename=None, light_filename=None, season_light_mod=False, light_mod_fac=0.25): """ Parameters ---------- environment : Environment object Common to all other objects. Includes time and weather instances method : Integer, optional - `0` : Provide load curve directly (for all timesteps!) - `1` : Standard load profile - `2` : Stochastic electrical load model (only residential) - `3` : Annual profile based on measured weekly profiles (non-residential) - `4` : Annual profile based on measured annual profiles (non-residential) loadcurve : Array-like, optional Load curve for all investigated time steps annualDemand : Float (required for SLP and recommended for method 2) Annual electrical demand in kWh. If method 2 is chosen but no value is given, a standard value for Germany (http://www.die-stromsparinitiative.de/fileadmin/bilder/ Stromspiegel/Brosch%C3%BCre/Stromspiegel2014web_final.pdf) is used. (default: None) profileType : String (required for SLP; method=1) - H0 : Household - L0 : Farms - L1 : Farms with breeding / cattle - L2 : Farms without cattle - G0 : Business (general) - G1 : Business (workingdays 8:00 AM - 6:00 PM) - G2 : Business with high loads in the evening - G3 : Business (24 hours) - G4 : Shops / Barbers - G5 : Bakery - G6 : Weekend operation total_nb_occupants : int, optional (used in method 2) Number of people living in the household. randomizeAppliances : Boolean (only required in method 2) - True : Distribute installed appliances randomly - False : Use the standard distribution lightConfiguration : Integer (only optional in method 2) There are 100 light bulb configurations predefined for the Stochastic model. Select one by entering an integer in [0, ..., 99] occupancy : Array-like (optional, but recommended in method 2) Occupancy given at 10-minute intervals for a full year do_normalization : bool, optional Defines, if stochastic profile (method=2) should be normalized to given annualDemand value (default: False). If set to False, annual el. demand depends on stochastic el. load profile generation. If set to True, does normalization with annualDemand method_3_type : str, optional Defines type of profile for method=3 (default: None) Options: - 'food_pro': Food production - 'metal': Metal company - 'rest': Restaurant (with large cooling load) - 'sports': Sports hall - 'repair': Repair / metal shop method_4_type : str, optional Defines type of profile for method=4 (default: None) - 'metal_1' : Metal company with smooth profile - 'metal_2' : Metal company with fluctuation in profile - 'warehouse' : Warehouse prev_heat_dev : bool, optional Defines, if heating devices should be prevented within chosen appliances (default: False). If set to True, DESWH, E-INST, Electric shower, Storage heaters and Other electric space heating are set to zero. Only relevant for method == 2 app_filename : str, optional Path to Appliances file (default: None). If set to None, uses default file Appliances.csv in \inputs\stochastic_electrical_load\. Only relevant, if method == 2. light_filename : str, optional Path to Lighting configuration file (default: None). If set to None, uses default file Appliances.csv in \inputs\stochastic_electrical_load\. Only relevant, if method == 2. season_light_mod : bool, optional Defines, if cosine-wave should be used to strengthen seasonal influence on lighting (default: False). If True, enlarges lighting power demand in winter month and reduces lighting power demand in summer month light_mod_fac : float, optional Define factor, related to maximal lighting power, which is used to implement seasonal influence (default: 0.25). Only relevant, if season_light_mod == True Info ---- The standard load profile can be downloaded here: http://www.ewe-netz.de/strom/1988.php Average German electricity consumption per household can be found here: http://www.die-stromsparinitiative.de/fileadmin/bilder/Stromspiegel/ Brosch%C3%BCre/Stromspiegel2014web_final.pdf """ src_path = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) if method == 0: super(ElectricalDemand, self).__init__(environment, loadcurve) # Use standardized load profiles (SLP) elif method == 1: if not ElectricalDemand.loaded_slp: filename = os.path.join(src_path, 'inputs', 'standard_load_profile', 'slp_electrical.xlsx') ElectricalDemand.slp = slp_el.load( filename, time_discretization=environment.timer.timeDiscretization) ElectricalDemand.loaded_slp = True loadcurve = slp_el.get_demand(annualDemand, ElectricalDemand.slp[profileType], environment.timer.timeDiscretization) super(ElectricalDemand, self).__init__(environment, loadcurve) # Usage of stochastic, el. profile generator for residential buildings elif method == 2: # Extract radiation values of weather q_direct = environment.weather.qDirect q_diffuse = environment.weather.qDiffuse # Extract initial_day initial_day = environment.timer.initialDay # Get timestep timestep = environment.timer.timeDiscretization # Generate Richadsonpy el. load object instance electr_lodad = \ eload.ElectricLoad(occ_profile=occupancy, total_nb_occ=total_nb_occupants, q_direct=q_direct, q_diffuse=q_diffuse, annual_demand=annualDemand, is_sfh=singleFamilyHouse, path_app=None, path_light=None, randomize_appliances=randomizeAppliances, prev_heat_dev=prev_heat_dev, light_config=lightConfiguration, timestep=timestep, initial_day=initial_day, season_light_mod=season_light_mod, light_mod_fac=light_mod_fac, do_normalization=do_normalization, calc_profile=True, save_app_light=False) # if app_filename is None: # Use default # pathApps = os.path.join(src_path, 'inputs', # 'stochastic_electrical_load', # 'Appliances.csv') # else: # Use user defined path # pathApps = app_filename # # if light_filename is None: # Use default # pathLights = os.path.join(src_path, 'inputs', # 'stochastic_electrical_load', # 'LightBulbs.csv') # else: # Use user defined path # pathLights = light_filename # # # Initialize appliances and lights # if annualDemand == 0: # if singleFamilyHouse: # annualDemand = self.standard_consumption["SFH"][ # total_nb_occupants] # else: # annualDemand = self.standard_consumption["MFH"][ # total_nb_occupants] # # # According to http://www.die-stromsparinitiative.de/fileadmin/ # # bilder/Stromspiegel/Brosch%C3%BCre/Stromspiegel2014web_final.pdf # # roughly 9% of the electricity consumption are due to lighting. # # This has to be excluded from the appliances' demand: # appliancesDemand = 0.91 * annualDemand # # # Get appliances # self.appliances = app_model.Appliances(pathApps, # annual_consumption=appliancesDemand, # randomize_appliances=randomizeAppliances, # prev_heat_dev=prev_heat_dev) # # # Get lighting configuration # self.lights = light_model.load_lighting_profile(pathLights, # lightConfiguration) # # # Create wrapper object # timeDis = environment.timer.timeDiscretization # timestepsDay = int(86400 / timeDis) # day = environment.timer.currentWeekday # self.wrapper = wrapper.Electricity_profile(self.appliances, # self.lights) # # # Make full year simulation # demand = [] # light_load = [] # app_load = [] # # beam = environment.weather.qDirect # diffuse = environment.weather.qDiffuse # irradiance = beam + diffuse # required_timestamp = np.arange(1440) # given_timestamp = timeDis * np.arange(timestepsDay) # # # Loop over all days # for i in range(int(len(irradiance) * timeDis / 86400)): # if (i + day) % 7 in (0, 6): # weekend = True # else: # weekend = False # # irrad_day = irradiance[ # timestepsDay * i: timestepsDay * (i + 1)] # current_irradiation = np.interp(required_timestamp, # given_timestamp, irrad_day) # # current_occupancy = occupancy[144 * i: 144 * (i + 1)] # # (el_p_curve, light_p_curve, app_p_curve) = \ # self.wrapper.demands(current_irradiation, # weekend, # i, # current_occupancy) # # demand.append(el_p_curve) # light_load.append(light_p_curve) # app_load.append(app_p_curve) # # res = np.array(demand) # light_load = np.array(light_load) # app_load = np.array(app_load) # # res = np.reshape(res, res.size) # light_load = np.reshape(light_load, light_load.size) # app_load = np.reshape(app_load, app_load.size) # # if season_light_mod: # # Put cosine-wave on lighting over the year to estimate # # seasonal influence # # light_energy = sum(light_load) * 60 # # time_array = np.arange(start=0, stop=len(app_load)) # time_pi_array = time_array * 2 * np.pi / len(app_load) # # cos_array = 0.5 * np.cos(time_pi_array) + 0.5 # # ref_light_power = max(light_load) # # light_load_new = np.zeros(len(light_load)) # # for i in range(len(light_load)): # if light_load[i] == 0: # light_load_new[i] = 0 # elif light_load[i] > 0: # light_load_new[i] = light_load[i] + \ # light_mod_fac * ref_light_power \ # * cos_array[i] # # light_energy_new = sum(light_load_new) * 60 # # # Rescale to original lighting energy demand # light_load_new *= light_energy / light_energy_new # # res = light_load_new + app_load # # # Change time resolution # loadcurve = cr.changeResolution(res, 60, timeDis) # # light_load = cr.changeResolution(light_load, 60, timeDis) # # app_load = cr.changeResolution(app_load, 60, timeDis) # # # Normalize el. load profile to annualDemand # if do_normalization: # # Convert power to energy values # energy_curve = loadcurve * timeDis # in Ws # # # Sum up energy values (plus conversion from Ws to kWh) # curr_el_dem = sum(energy_curve) / (3600 * 1000) # # con_factor = annualDemand / curr_el_dem # # # Rescale load curve # loadcurve *= con_factor super(ElectricalDemand, self).__init__(environment, electr_lodad.loadcurve) # Generate el. load based on measured, weekly profile elif method == 3: assert type is not None, 'You need to define a valid type for method 3!' assert annualDemand > 0, 'annualDemand has to be larger than 0!' if not ElectricalDemand.loaded_weekly_data: fpath = os.path.join(src_path, 'inputs', 'measured_el_loads', 'Non_res_weekly_el_profiles.txt') ElectricalDemand.weekly_data = \ eloader.load_non_res_load_data_weekly(fpath) ElectricalDemand.loaded_weekly_data = True loadcurve = eloader.gen_annual_el_load( ElectricalDemand.weekly_data, type=method_3_type, start_wd=environment.timer.currentWeekday, annual_demand=annualDemand) loadcurve = cr.changeResolution( loadcurve, oldResolution=900, newResolution=environment.timer.timeDiscretization) super(ElectricalDemand, self).__init__(environment, loadcurve) # Generate el. load based on measured, annual profiles elif method == 4: assert type is not None, 'You need to define a valid type for method 4!' assert annualDemand > 0, 'annualDemand has to be larger than 0!' if not ElectricalDemand.load_ann_data: fpath = os.path.join(src_path, 'inputs', 'measured_el_loads', 'non_res_annual_el_profiles.txt') ElectricalDemand.ann_data = \ eloader.load_non_res_load_data_annual(fpath) ElectricalDemand.load_ann_data = True loadcurve = eloader.get_annual_el_load(ElectricalDemand.ann_data, type=method_4_type, annual_demand=annualDemand) loadcurve = cr.changeResolution( loadcurve, oldResolution=900, newResolution=environment.timer.timeDiscretization) super(ElectricalDemand, self).__init__(environment, loadcurve) self._kind = "electricaldemand" self.method = method
def __init__(self, environment, method=0, loadcurve=[], annualDemand=0, profileType="H0", singleFamilyHouse=True, total_nb_occupants=0, randomizeAppliances=True, lightConfiguration=0, occupancy=[], do_normalization=False, method_3_type=None, method_4_type=None): """ Parameters ---------- environment : Environment object Common to all other objects. Includes time and weather instances method : Integer, optional - `0` : Provide load curve directly (for all timesteps!) - `1` : Standard load profile - `2` : Stochastic electrical load model (only residential) - `3` : Annual profile based on measured weekly profiles (non-residential) - `4` : Annual profile based on measured annual profiles (non-residential) loadcurve : Array-like, optional Load curve for all investigated time steps annualDemand : Float (required for SLP and recommended for method 2) Annual electrical demand in kWh. If method 2 is chosen but no value is given, a standard value for Germany (http://www.die-stromsparinitiative.de/fileadmin/bilder/ Stromspiegel/Brosch%C3%BCre/Stromspiegel2014web_final.pdf) is used. profileType : String (required for SLP; method=1) - H0 : Household - L0 : Farms - L1 : Farms with breeding / cattle - L2 : Farms without cattle - G0 : Business (general) - G1 : Business (workingdays 8:00 AM - 6:00 PM) - G2 : Business with high loads in the evening - G3 : Business (24 hours) - G4 : Shops / Barbers - G5 : Bakery - G6 : Weekend operation total_nb_occupants : int, optional (used in method 2) Number of people living in the household. randomizeAppliances : Boolean (only required in method 2) - True : Distribute installed appliances randomly - False : Use the standard distribution lightConfiguration : Integer (only optional in method 2) There are 100 light bulb configurations predefined for the Stochastic model. Select one by entering an integer in [0, ..., 99] occupancy : Array-like (optional, but recommended in method 2) Occupancy given at 10-minute intervals for a full year do_normalization : bool, optional Defines, if stochastic profile (method=2) should be normalized to given annualDemand value (default: False). If set to False, annual el. demand depends on stochastic el. load profile generation. If set to True, does normalization with annualDemand method_3_type : str, optional Defines type of profile for method=3 (default: None) Options: - 'food_pro': Food production - 'metal': Metal company - 'rest': Restaurant (with large cooling load) - 'sports': Sports hall - 'repair': Repair / metal shop method_4_type : str, optional Defines type of profile for method=4 (default: None) - 'metal_1' : Metal company with smooth profile - 'metal_2' : Metal company with fluctuation in profile - 'warehouse' : Warehouse Info ---- The standard load profile can be downloaded here: http://www.ewe-netz.de/strom/1988.php Average German electricity consumption per household can be found here: http://www.die-stromsparinitiative.de/fileadmin/bilder/Stromspiegel/ Brosch%C3%BCre/Stromspiegel2014web_final.pdf """ src_path = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) if method == 0: super(ElectricalDemand, self).__init__(environment, loadcurve) # Use standardized load profiles (SLP) elif method == 1: if not ElectricalDemand.loaded_slp: filename = os.path.join(src_path, 'inputs', 'standard_load_profile', 'slp_electrical.xlsx') ElectricalDemand.slp = slp_el.load( filename, time_discretization=environment.timer.timeDiscretization) ElectricalDemand.loaded_slp = True loadcurve = slp_el.get_demand(annualDemand, ElectricalDemand.slp[profileType], environment.timer.timeDiscretization) super(ElectricalDemand, self).__init__(environment, loadcurve) # Usage of stochastic, el. profile generator for residential buildings elif method == 2: # Initialize appliances and lights if annualDemand == 0: if singleFamilyHouse: annualDemand = self.standard_consumption["SFH"][ total_nb_occupants] else: annualDemand = self.standard_consumption["MFH"][ total_nb_occupants] # According to http://www.die-stromsparinitiative.de/fileadmin/ # bilder/Stromspiegel/Brosch%C3%BCre/Stromspiegel2014web_final.pdf # roughly 9% of the electricity consumption are due to lighting. # This has to be excluded from the appliances' demand: appliancesDemand = 0.91 * annualDemand pathApps = os.path.join(src_path, 'inputs', 'stochastic_electrical_load', 'Appliances.csv') self.appliances = app_model.Appliances( pathApps, annual_consumption=appliancesDemand, randomize_appliances=randomizeAppliances) pathLights = os.path.join(src_path, 'inputs', 'stochastic_electrical_load', 'LightBulbs.csv') self.lights = light_model.load_lighting_profile( pathLights, lightConfiguration) # Create wrapper object timeDis = environment.timer.timeDiscretization timestepsDay = int(86400 / timeDis) day = environment.timer.currentWeekday self.wrapper = wrapper.Electricity_profile(self.appliances, self.lights) # Make full year simulation demand = [] beam = environment.weather.qDirect diffuse = environment.weather.qDiffuse irradiance = beam + diffuse required_timestamp = np.arange(1440) given_timestamp = timeDis * np.arange(timestepsDay) # Loop over all days for i in range(int(len(irradiance) * timeDis / 86400)): if (i + day) % 7 in (0, 6): weekend = True else: weekend = False irrad_day = irradiance[timestepsDay * i:timestepsDay * (i + 1)] current_irradiation = np.interp(required_timestamp, given_timestamp, irrad_day) current_occupancy = occupancy[144 * i:144 * (i + 1)] demand.append( self.wrapper.demands(current_irradiation, weekend, i, current_occupancy)[0]) res = np.array(demand) res = np.reshape(res, res.size) loadcurve = cr.changeResolution(res, 60, timeDis) # Normalize el. load profile to annualDemand if do_normalization: # Convert power to energy values energy_curve = loadcurve * timeDis # in Ws # Sum up energy values (plus conversion from Ws to kWh) curr_el_dem = sum(energy_curve) / (3600 * 1000) con_factor = annualDemand / curr_el_dem # Rescale load curve loadcurve *= con_factor super(ElectricalDemand, self).__init__(environment, loadcurve) # Generate el. load based on measured, weekly profile elif method == 3: assert type is not None, 'You need to define a valid type for method 3!' assert annualDemand > 0, 'annualDemand has to be larger than 0!' if not ElectricalDemand.loaded_weekly_data: fpath = os.path.join(src_path, 'inputs', 'measured_el_loads', 'Non_res_weekly_el_profiles.txt') ElectricalDemand.weekly_data = \ eloader.load_non_res_load_data_weekly(fpath) ElectricalDemand.loaded_weekly_data = True loadcurve = eloader.gen_annual_el_load( ElectricalDemand.weekly_data, type=method_3_type, start_wd=environment.timer.currentWeekday, annual_demand=annualDemand) loadcurve = cr.changeResolution( loadcurve, oldResolution=900, newResolution=environment.timer.timeDiscretization) super(ElectricalDemand, self).__init__(environment, loadcurve) # Generate el. load based on measured, annual profiles elif method == 4: assert type is not None, 'You need to define a valid type for method 4!' assert annualDemand > 0, 'annualDemand has to be larger than 0!' if not ElectricalDemand.load_ann_data: fpath = os.path.join(src_path, 'inputs', 'measured_el_loads', 'non_res_annual_el_profiles.txt') ElectricalDemand.ann_data = \ eloader.load_non_res_load_data_annual(fpath) ElectricalDemand.load_ann_data = True loadcurve = eloader.get_annual_el_load(ElectricalDemand.ann_data, type=method_4_type, annual_demand=annualDemand) loadcurve = cr.changeResolution( loadcurve, oldResolution=900, newResolution=environment.timer.timeDiscretization) super(ElectricalDemand, self).__init__(environment, loadcurve) self._kind = "electricaldemand" self.method = method
def __init__(self, environment, method=0, loadcurve=[], livingArea=0, specificDemand=0, profile_type='HEF', zoneParameters=None, T_m_init=None, ventilation=0, TCoolingSet=200, THeatingSet=-50, occupancy=0, appliances=0, lighting=0): """ Parameters ---------- environment : Environment object Common to all other objects. Includes time and weather instances method : integer, optional - `0` : Provide load curve directly - `1` : Use thermal standard load profile - `2` : Use ISO 13790 standard to compute thermal load - `3` : Use example thermal load profiles, generated with Modelica AixLib low order model (only valid for residential building and test reference year weather file for 2010, region 5!) loadcurve : Array-like, optional Load curve for all investigated time steps Requires ``method=0``. livingArea : Float, optional Living area of the apartment in m2 Requires ``method=1`` specificDemand : Float, optional Specific thermal demand of the building in kWh/(m2 a) Requires ``method=1`` profile_type : str, optional Thermal SLP profile name Requires ``method=1`` - `HEF` : Single family household - `HMF` : Multi family household - `GBA` : Bakeries - `GBD` : Other services - `GBH` : Accomodations - `GGA` : Restaurants - `GGB` : Gardening - `GHA` : Retailers - `GHD` : Summed load profile business, trade and services - `GKO` : Banks, insurances, public institutions - `GMF` : Household similar businesses - `GMK` : Automotive - `GPD` : Paper and printing - `GWA` : Laundries zoneParameters : ZoneParameters object, optional Parameters of the building (floor area, building class, etc.). Requires ``method=2``. T_m_init : Float, optional Initial temperature of the internal heat capacity. Requires ``method=2``. ventilation : Array-like, optional Ventilation rate in 1/h. Requires ``method=2``. TCoolingSet : Array-like, optional Cooling starts if the room temperature exceeds this value. Requires ``method=2``. THeatingSet : Array-like, optional Heating starts if the room temperature drops below this value. Requires ``method=2``. occupancy : Array-like, optional Full year occupancy profile. Requires ``method=2``. appliances : Array-like, optional Internal gains from electrical appliances in Watt. Requires ``method=2``. lighting : Array-like, optional Internal gains from lighting in Watt. Requires ``method=2``. Info ---- The thermal standard load profile is based on the disseratation of Mark Hellwig. "Entwicklung und Anwendung parametrisierter Standard-Lastprofile", TU München, Germany, 2003. URL : http://mediatum.ub.tum.de/doc/601557/601557.pdf """ self.method = method if method == 0: # Hand over own power curve super(SpaceHeating, self).__init__(environment, loadcurve) elif method == 1: # Generate standardized thermal load profile (SLP) timeDis = environment.timer.timeDiscretization if not SpaceHeating.loaded_slp: src_path = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) folder = os.path.join(src_path, 'inputs', 'standard_load_profile') f_hour = os.path.join(folder, 'slp_thermal_hourly_factors.xlsx') f_prof = os.path.join(folder, 'slp_thermal_profile_factors.xlsx') f_week = os.path.join(folder, 'slp_thermal_week_day_factors.xlsx') SpaceHeating.slp_hour = slp_th.load_hourly_factors(f_hour, timeDis) SpaceHeating.slp_prof = slp_th.load_profile_factors(f_prof) SpaceHeating.slp_week = slp_th.load_week_day_factors(f_week) SpaceHeating.loaded_slp = True annual_demand = livingArea * specificDemand # kWh profile = 1 fun = slp_th.calculate loadcurve = fun(environment.weather.tAmbient, environment.timer.currentDay, SpaceHeating.slp_prof[profile_type][profile], SpaceHeating.slp_week[profile_type], SpaceHeating.slp_hour[profile_type], annual_demand) super(SpaceHeating, self).__init__(environment, loadcurve) elif method == 2: # Generate thermal load with ISO model self.zoneParameters = zoneParameters # Create zoneInputs (this already creates the full year inputs!) self.zoneInputs = zi.ZoneInputs(environment, zoneParameters, T_m_init, ventilation=ventilation, occupancy=occupancy, appliances=appliances, lighting=lighting) calc = pycity_base.functions.zoneModel.calc res = calc(zoneParameters=self.zoneParameters, zoneInputs=self.zoneInputs, TCoolingSet=TCoolingSet, THeatingSet=THeatingSet, limitHeating=np.inf, limitCooling=-np.inf, beQuiet=True) self.loadcurve = res[0] self.T_op = res[1] self.T_m = res[2] self.T_i = res[3] self.T_s = res[4] elif method == 3: # Use Modelica thermal load profile for residential building if not SpaceHeating.loaded_sim_profile: src_path = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) folder = os.path.join(src_path, 'inputs', 'simulated_profiles', 'res_building') dpath = os.path.join(folder, 'res_b_modelica_th_load_try_2010_5.txt') SpaceHeating.sim_prof_data = np.genfromtxt(dpath, delimiter='\t', skip_header=2) SpaceHeating.loaded_sim_profile = True annual_demand = livingArea * specificDemand # kWh # Extract first profile loadcurve = copy.deepcopy(SpaceHeating.sim_prof_data[:, 1]) # Rescale profile to annual_demand con_factor = (1000 * annual_demand) / sum(loadcurve) loadcurve *= con_factor # Change resolution loadcurve = chres.changeResolution(loadcurve, oldResolution=3600, newResolution=environment.timer.timeDiscretization) super(SpaceHeating, self).__init__(environment, loadcurve) self._kind = "spaceheating"
if __name__ == '__main__': this_path = os.path.dirname(os.path.abspath(__file__)) search_path = os.path.join(this_path, 'profiles') # Generate ProfilePool object prof_pool = ProfilePool(path_to_npz_folder=search_path) # Get occ, el. and dhw profile (occ_profile, el_profile, dhw_profile) = \ prof_pool.get_occ_el_dhw_profile(nb_occupants=3) # Change resolution of occupancy profile from 600 to 60 seconds occ_profile = chres.changeResolution(occ_profile, oldResolution=600, newResolution=60) el_energy = sum(el_profile) * 60 / (3600 * 1000) print('El. energy in kWh: ', el_energy) dhw_energy = sum(dhw_profile) * 60 / (3600 * 1000) print('Hot water net energy in kWh: ', dhw_energy) time_array = np.arange(0, 365 * 24 * 3600, 60) time_array = time_array / 3600 fig = plt.figure() plt.subplot(311) plt.plot(time_array, occ_profile) plt.ylabel('Occupancy')
def full_year_computation(occupancy, profiles, time_dis=3600, initial_day=0, temperature_difference=35): """ Parameters ---------- occupancy : array_like Full year, 10-minute-wise sampled occupancy profile. All values have to be integers. profiles : dictionary All probability distributions. The dictionary has to have the following structure: - Top level: [`wd_mw`, `we_mw`, `wd`, `we`] (strings) - Within `we` and `wd`: [`1`, `2`, `3`, `4`, `5`, `6`] (integers) time_dis : integer Time discretization in seconds. initial_day : integer - 0 : Monday - 1 : Tuesday - 2 : Wednesday - 3 : Thursday - 4 : Friday - 5 : Saturday - 6 : Sunday temperature_difference : float How much does the tap water has to be heated up? Either enter a float or an array with the same dimension as probability_profiles. Returns ------- water : array_like Tap water volume flow in liters per hour. heat : array_like Resulting minute-wise sampled heat demand in Watt. The heat capacity of water is assumed to be 4180 J/(kg.K) and the density is assumed to be 980 kg/m3 """ # Initialization number_days = int(len(occupancy) / 144) water = np.zeros(len(occupancy) * 10) heat = np.zeros(len(occupancy) * 10) for day in range(number_days): # Is the current day on a weekend? if (day + initial_day) % 7 >= 5: probability_profiles = profiles["we"] average_profile = profiles["we_mw"] else: probability_profiles = profiles["wd"] average_profile = profiles["wd_mw"] # Get water and heat demand for the current day res = compute_daily_demand(probability_profiles, average_profile, occupancy[day * 144:(day + 1) * 144], day, temperature_difference) (current_water, current_heat) = res # Include current_water and current_heat in water and heat water[day * 1440:(day + 1) * 1440] = current_water heat[day * 1440:(day + 1) * 1440] = current_heat # Change sampling time to the given input water = cr.changeResolution(water, 60, time_dis, "sum") / time_dis * 60 heat = cr.changeResolution(heat, 60, time_dis, "sum") / time_dis * 60 # Return results return (water, heat)
# Max. occupancy is 5 people simultaneously occupancy = np.random.geometric(p=0.8, size=6 * 24 * 365) - 1 occupancy = np.minimum(5, occupancy) # Set initial_day initial_day = 0 # Run simulation (water, heat) = full_year_computation(occupancy, profiles, time_dis=60, initial_day=initial_day) # Change time resolution to 15 minutes dt = 15 hd = cr.changeResolution(heat, 60, dt * 60, "sum") / dt # Plot heat demand import matplotlib.pyplot as plt ax1 = plt.subplot(2, 1, 1) plt.plot(np.arange(len(heat)) / 60, heat, color="b", linewidth=2) plt.step((np.arange(len(hd)) * dt + dt) / 60, hd, color="r", linewidth=2) plt.ylabel("Heat demand in Watt") plt.xlim((0, 8760)) plt.subplot(2, 1, 2, sharex=ax1) plt.step((np.arange(len(occupancy)) * 10 + 10) / 60, occupancy, linewidth=2) plt.ylabel("Active occupants") offset = 0.2