Source code for UrbanHeatPro.Classes.City

"""
City.py
A. Molar-Cruz @ TUM ENS
"""

import multiprocessing
import sys

import numpy as np
from scipy import interpolate

import UrbanHeatPro.Functions as UrbanHeatPro
from .Building import Building


# import ipdb


[docs] class City: """ City class. Note: This documentation might be incomplete or outdated, check the source code for more information. The types for the attributes might not be correct. Attributes: name (str): The name of the simulation. region (str): The region of the simulation. sce (str): The scenario of the simulation. dt_vector (list): Vector of time steps as datetime objects. dt_vector_excel (list): Vector of time steps as excel date. nts (int): Number of time steps. resolution (int): Temporal resolution in minutes. number_of_typ_days (int): Number of typical days. weights (list): Weights of typical days. processes (int): Number of parallel processes. chunk_size (int): Number of buildings in chunk to save. b_to_save_syncity (ndarray): Array to save synchronicity data. b_to_save_heat (ndarray): Array to save heat data. counter_syncity (int): Counter for synchronicity data. counter_heat (int): Counter for heat data. Tamb (list): Ambient temperature vector in degrees Celsius. I (list): Solar radiation vector in W/m2 [I_Gh, I_Dh, I_ex, hs]. buildings (list): Building data. building_stock_stats (list): Building data from statistics. nb (int): Number of buildings. connection_factor (float): Share of buildings connected to the network. _space_heating (bool): Flag to calculate space heating demand. _hot_water (bool): Flag to calculate hot water demand. _energy_only (bool): Flag to calculate only aggregated demand. base_load (ndarray): Vector of base load in W. _internal_gains (bool): Flag to consider internal gains. _solar_gains (bool): Flag to consider solar gains. _active_population (bool): Flag to consider active population for occupancy vector. _workday_weekend (bool): Flag to consider difference between workdays and weekends. _monthly_sh_prob (bool): Flag to consider monthly probability of using heating. refurbishment_level (float): Refurbishment level for all buildings. Tb0_str (str): Initial building temperature as 'ambient' or 'Tset'. dTset (float): Delta temperature (for Tset_min, Tset_max). eta (float): Heating process efficiency. dT_per_hour (float): Maximum dT allowed in building per hour in degrees Celsius. thermal_inertia (float): Thermal inertia of the heating system. _night_set_back (float): Share of buildings with night set-back. schedule_nsb (list): [start, end] of night set-back in hours. T_nsb (float): Night set-back temperature in degrees Celsius. power_reduction (float): Percentage of power reduced (as decimal). Tw (float): Hot water temperature in degrees Celsius. hw_tank_limit (float): Hot water tank limit as percentage (decimal). hw_flow (float): Flow to refill hot water tank in L/min. dhw_prob (list): Probabilities for calculation of hot water demand. rid (int): Run id. result_dir (str): Directory where results are stored. plot (int): Plot level [0, 1, 2]. save (int): Save level [0, 1, 2]. debug (int): Debug level [0, 1, 2]. """ # -------------------------------------------------------------------------------- def __init__(self, NAME, SIMULATION, CITY, SPACE_HEATING, HOT_WATER, REPORTING): """ Initializes the City object. Args: NAME (str): Name of the simulation. SIMULATION (list): List containing the parameters related to the simulation. CITY (list): List containing the parameters related to the city. SPACE_HEATING (list): List containing the parameters related to space heating demand. HOT_WATER (list): List containing the parameters related to hot water demand. REPORTING (list): List containing the parameters related to reporting. """ # SIMULATION self.name = NAME # Simulation name self.region = SIMULATION[0][0] # Region self.sce = SIMULATION[0][1] # Scenario self.dt_vector = SIMULATION[1][0] # Vector of time steps as datetime objects self.dt_vector_excel = SIMULATION[1][1] # Vector of time steps as excel date self.nts = len(self.dt_vector) # Number of time steps self.resolution = SIMULATION[2][0] # Temporal resolution in min self.number_of_typ_days = SIMULATION[4][0] # Number of typical days self.weights = SIMULATION[4][1] # Weights of typical days # PARALELLIZATION self.processes = SIMULATION[3][0] # Number of parallel processes self.chunk_size = SIMULATION[3][1] # Number of buildings in chunk to save self.b_to_save_syncity = np.zeros([self.chunk_size, 30]) self.b_to_save_heat = np.zeros([self.chunk_size, 40]) self.counter_syncity = 0 self.counter_heat = 0 # CITY ### Ambient conditions self.Tamb = CITY[0][0] # Ambient temperature vector in degC self.I = CITY[0][1] # Solar radiation vector in W/m2 [I_Gh, I_Dh, I_ex, hs] ### Building data self.buildings = CITY[1][0] # Building data self.building_stock_stats = CITY[1][1] # Building data from statistics self.nb = len(self.buildings) # Number of buildings self.connection_factor = CITY[2][0] # Share of buildings connected to the network ### Flags self._space_heating = CITY[3][0] # calculate space heating demand? self._hot_water = CITY[3][1] # calculate hot water demand? self._energy_only = CITY[3][2] # calculate only aggregated demand? ### Base load self.base_load = np.ones([self.nts]) * CITY[4][0] # Vector of base load in W # SPACE HEATING DEMAND ### Flags self._internal_gains = SPACE_HEATING[0][0] # consider internal gains? self._solar_gains = SPACE_HEATING[0][1] # consider solar gains? self._active_population = SPACE_HEATING[0][2] # consider active population for occupancy vector? self._workday_weekend = SPACE_HEATING[0][3] # consider difference between workdays and weekends? self._monthly_sh_prob = SPACE_HEATING[0][4] # consider monthly probability of using heating? ### Transmission losses self.refurbishment_level = SPACE_HEATING[1][0] # Refurbishment level for all buildings self.Tb0_str = SPACE_HEATING[2][0] # Initial building temperature as 'ambient' or 'Tset'? self.dTset = SPACE_HEATING[2][1] # Delta temperature (for Tset_min, Tset_max) ### Heating system self.eta = SPACE_HEATING[3][0] # Heating process efficiency self.dT_per_hour = SPACE_HEATING[3][1] # Maximum dT allowed in building per hour [degC] self.thermal_inertia = SPACE_HEATING[3][2] # Thermal inertia of the heating system ### DSM self._night_set_back = SPACE_HEATING[4][0] # Share of buildings with night set-back self.schedule_nsb = SPACE_HEATING[4][1] # [start, end] of nsb in h self.T_nsb = SPACE_HEATING[4][2] # Night set-back temperature in degC self.power_reduction = SPACE_HEATING[4][3] # Percentage of power reduced (as decimal) # HOT WATER DEMAND ### Calculation self.Tw = HOT_WATER[0][0] # Hot water temperature in degC self.hw_tank_limit = HOT_WATER[1][0] # Hot water tank limit as perc (decimal) self.hw_flow = HOT_WATER[1][1] # Flow to refill hot water tank in L/min self.dhw_prob = self.initialize_dhw_probabilities() # Probabilities for calculation od dhw demand # RESULTS ### Runs self.rid = SIMULATION[5][0] # Run id self.result_dir = SIMULATION[5][1] # Directory where results are stored # REPORTING self.plot = REPORTING[0] # Plot level [0, 1, 2] self.save = REPORTING[1] # Save level [0, 1, 2] self.debug = REPORTING[2] # Debug level [0, 1, 2] # Synthetic city # --------------------------------------------------------------------------------
[docs] def create_synthetic_city(self): """ Create a synthetic city representing the building stock based on statistics. """ # extract building stock statistics ## Residential self.FOOTPRINT = self.building_stock_stats[0][0] # Footprint area of building typologies (TABULA) self.FLOORS = self.building_stock_stats[0][3] # Number of floors self.CURRENT_REF_RES = self.building_stock_stats[0][7][0] # Percentage of residential refurbished buildings self.SINGLE_DWELLING = self.building_stock_stats[0][8] # Percentage of single dwellings for SFH and TH self.AVG_DWELLING_SIZE = self.building_stock_stats[0][9] # Average dwelling size in m2 self.HOUSEHOLD_SIZE = self.building_stock_stats[0][10] # Household size for dwelling size categories self.STOCK_RES = self.building_stock_stats[0][17] # Building stock statistics for residential ## Non-residential self.CURRENT_REF_NRES = self.building_stock_stats[0][14][0] # Percentage of residential refurbished buildings self.STOCK_NRES = self.building_stock_stats[0][18] # Building stock statistics for non-residential """ # DEBUG for iii in range(1000): building = self.buildings.loc[iii, :] result = self.create_synthetic_building(building) print(iii) print(result) input() """ # save synthetic city file # filename = '{}/SynCity_{}_{}_{}.csv'.format(self.result_dir, self.region, self.sce, self.rid) filename = '{}/SynCity_{}_{}.csv'.format(self.result_dir, self.name, self.rid) self.save_csv_syn_city_header(filename) # Multiprocessing if self.debug >= 1: print(' ***') print(' Creating synthetic city with {} buildings...'.format(len(self.buildings))) print(' Starting multiprocessing with {}/{} processors...'.format(self.processes, multiprocessing.cpu_count())) ### Writer queue if self.debug >= 1: print(' Starting queues...') writerQueue = multiprocessing.Queue() writeProc = multiprocessing.Process(target=self.write_to_synthetic_city, args=(writerQueue, filename)) ### Feeder queue buildings_list = range(len(self.buildings)) feederQueue = multiprocessing.Queue() feedProc = multiprocessing.Process(target=self.feed_building_to_process, args=(feederQueue, buildings_list)) ### Processes calcProc = [multiprocessing.Process(target=self.call_create_synthetic_building, args=(feederQueue, writerQueue)) for iii in range(self.processes)] ### start multiprocessing if self.debug >= 1: print(' Calculating synthetic building...') feedProc.start() for p in calcProc: p.start() if self.debug >= 1: print('\n Saving to file...') writeProc.start() feedProc.join() for p in calcProc: p.join() writeProc.join()
#
[docs] def update_synthetic_city(self, ref_matrix_res, ref_matrix_nres): """ Create a synthetic city representing the building stock based on statistics. """ # values to update self.ref_matrix_res = ref_matrix_res self.ref_matrix_nres = ref_matrix_nres """ # DEBUG for iii in range(1000): building = self.buildings.loc[iii, :] result = self.update_synthetic_building(building) print(iii) print(result) input() input() """ # save updated synthetic city file # filename = '{}/SynCity_{}_{}_{}.csv'.format(self.result_dir, self.region, self.sce, self.rid) filename = '{}/SynCity_{}_{}.csv'.format(self.result_dir, self.name, self.rid) self.save_csv_syn_city_header(filename) # Multiprocessing if self.debug >= 1: print(' ***') print(' Updating synthetic city...') print(' Starting multiprocessing with {}/{} processors...'.format(self.processes, multiprocessing.cpu_count())) ### Writer queue if self.debug >= 1: print(' Starting queues...') writerQueue = multiprocessing.Queue() writeProc = multiprocessing.Process(target=self.write_to_synthetic_city, args=(writerQueue, filename)) ### Feeder queue buildings_list = range(len(self.buildings)) feederQueue = multiprocessing.Queue() feedProc = multiprocessing.Process(target=self.feed_building_to_process, args=(feederQueue, buildings_list)) ### Processes calcProc = [multiprocessing.Process(target=self.call_update_synthetic_building, args=(feederQueue, writerQueue)) for iii in range(self.processes)] ### start multiprocessing if self.debug >= 1: print(' Updating synthetic building...') feedProc.start() for p in calcProc: p.start() if self.debug >= 1: print('\n Saving to file...') writeProc.start() feedProc.join() for p in calcProc: p.join() writeProc.join()
#
[docs] def feed_building_to_process(self, feederQueue, buildings_list): """ Feeds building data to Queue """ for iii in buildings_list: building = self.buildings.loc[iii, :] feederQueue.put((building, iii))
#
[docs] def call_create_synthetic_building(self, feederQueue, writerQueue): """ Calls function to create synthetic building """ while True: try: # get from Queue (building, iii) = feederQueue.get(block=True, timeout=10) # calculate result = self.create_synthetic_building(building) # write to Queue writerQueue.put((result, iii)) # print(' {} | bid: {}'.format(multiprocessing.current_process().name, result[0][0])) if self.debug >= 1: # Progress bar sys.stdout.write('\r') i = float((iii + 1) / len(self.buildings)) sys.stdout.write(" Calculation: [%-20s] %d%%" % ('|' * int(20 * i), 100 * i)) sys.stdout.flush() except Exception as e: # print('>>> Error: {}'.format(e)) break
#
[docs] def call_update_synthetic_building(self, feederQueue, writerQueue): """ Calls function to update synthetic building. To update: - Refurbishment level """ while True: try: # get from Queue (building, iii) = feederQueue.get(block=True, timeout=10) # calculate result = self.update_synthetic_building(building) # write to Queue writerQueue.put((result, iii)) # print(' {} | bid: {}'.format(multiprocessing.current_process().name, result[0][0])) if self.debug >= 1: # Progress bar sys.stdout.write('\r') i = float((iii + 1) / len(self.buildings)) sys.stdout.write(" Calculation: [%-20s] %d%%" % ('|' * int(20 * i), 100 * i)) sys.stdout.flush() except Exception as e: # print('>>> Error: {}'.format(e)) break
#
[docs] def create_synthetic_building(self, building): """ Creates building object and calculates missing building properties """ my_building = Building( # Building data building, self.building_stock_stats, # Simulation [None, None], None, None, None, None, None, None, None, None, # Space heating demand None, None, None, None, None, None, None, None, None, None, None, None, None, None, # Hot water demand None, self.dhw_prob, None, None, None, None, None, # Results self.result_dir, None, None, None) r = my_building.parametrize_building() result = [r.bid, r.footprint_area, r.use, r.free_walls, r.lat, r.lon, r.dist_to_heat_source, r.year_class, r.size_class, r.floors, r.storey_area, r.area_corr_factor, r.heated_area, r.window_area, r.dwellings, r.dwelling_size, r.occupants, r.ref_level_roof, r.ref_level_wall, r.ref_level_floor, r.ref_level_window, r.U, r.V, r.C, r.Tau, r.Tset, r.act_start, r.act_end, r.hw_demand_day, r.hw_tank_cap] result = np.resize(result, (1, len(result))) return result
#
[docs] def update_synthetic_building(self, building): """ Updates synthetic building. To update: - Refurbishment level """ my_building = Building( # Building data building, self.building_stock_stats, # Simulation [None, None], None, None, None, None, None, None, None, None, # Space heating demand None, None, None, None, None, None, None, None, None, None, None, None, None, None, # Hot water demand None, None, None, None, None, None, None, # Results self.result_dir, None, None, None) r = my_building.update_building_refurbishment_level(self.ref_matrix_res, self.ref_matrix_nres) result = [r.bid, r.footprint_area, r.use, r.free_walls, r.lat, r.lon, r.dist_to_heat_source, r.year_class, r.size_class, r.floors, r.storey_area, r.area_corr_factor, r.heated_area, r.window_area, r.dwellings, r.dwelling_size, r.occupants, r.ref_level_roof, r.ref_level_wall, r.ref_level_floor, r.ref_level_window, r.U, r.V, r.C, r.Tau, r.Tset, r.act_start, r.act_end, r.hw_demand_day, r.hw_tank_cap] result = np.resize(result, (1, len(result))) return result
#
[docs] def write_to_synthetic_city(self, writerQueue, filename): """ Write synthetic building results to file """ while True: try: # get from Queue (result, iii) = writerQueue.get(block=True, timeout=20) # save results once chunk size is reached if self.counter_syncity >= self.chunk_size: # save f = open(filename, 'ab') fmt = ['%d', '%.2f', '%d', '%d', '%.3f', '%.3f', '%.2f', '%d', '%d', '%d', '%.2f', '%.2f', '%.2f', '%.2f', '%d', '%.2f', '%d', '%d', '%d', '%d', '%d', '%.2f', '%.2f', '%.2f', '%.2f', '%d', '%d', '%d', '%.2f', '%.2f'] np.savetxt(f, self.b_to_save_syncity, delimiter=';', fmt=fmt) f.close() # restart counter self.counter_syncity = 0 self.b_to_save_syncity = np.zeros([self.chunk_size, 30]) # Progress bar # print(' bid: {}'.format(result[0][0])) if self.debug >= 1: sys.stdout.write('\r') i = float((iii + 1) / len(self.buildings)) sys.stdout.write("\n Saving: [%-20s] %d%%" % ('|' * int(20 * i), 100 * i)) sys.stdout.flush() # always add building to matrix to save self.b_to_save_syncity[self.counter_syncity, :] = result self.counter_syncity += 1 except Exception as e: # print('>>> Error: {}'.format(e)) # save again to not loose data f = open(filename, 'ab') fmt = ['%d', '%.2f', '%d', '%d', '%.3f', '%.3f', '%.2f', '%d', '%d', '%d', '%.2f', '%.2f', '%.2f', '%.2f', '%d', '%.2f', '%d', '%d', '%d', '%d', '%d', '%.2f', '%.2f', '%.2f', '%.2f', '%d', '%d', '%d', '%.2f', '%.2f'] # drop zero rows self.b_to_save_syncity = self.b_to_save_syncity[~np.all(self.b_to_save_syncity == 0, axis=1)] np.savetxt(f, self.b_to_save_syncity, delimiter=';', fmt=fmt) f.close() break
# City heat demand # --------------------------------------------------------------------------------
[docs] def calculate_city_heat_demand(self): """ Paralellizes the calculation of heating energy demand per building using a given number of processes. Every process modifies a shared dictionary where the heat demand is stored as power and energy. """ if self.debug >= 1: print(' ***') print(' Calculating city heat demand...') print(' Starting multiprocessing with {}/{} available processors'.format(self.processes, multiprocessing.cpu_count())) # save heat demand file # filename = '{}/EnergyPerBuilding_{}_{}_{}.csv'.format(self.result_dir, self.region, self.sce, self.rid) filename = '{}/EnergyPerBuilding_{}_{}.csv'.format(self.result_dir, self.name, self.rid) self.save_csv_energy_header(filename) # Initialize probabilities for space heating and dhw self.sh_prob = None self.day_vector = None self.seasonal_vector = None self.min_vector = self.calculate_min_vector() # Vector of minutes in time frame # if self._space_heating: if self._monthly_sh_prob: SH_PROB = self.building_stock_stats[0][19] # Monthly probability of using heating self.sh_prob = [SH_PROB[dt.month - 1] for dt in self.dt_vector] else: self.sh_prob = [1. for dt in self.dt_vector] # if self._hot_water: self.day_vector = self.calculate_day_vector() # Vector of days in time frame if not self._energy_only: self.seasonal_vector = self.calculate_seasonal_variation_vector() # Sine vector to represent seasonal variations """ # DEBUG self.sh_power = np.zeros([self.nts]) self.sh_energy = 0. self.dhw_power = np.zeros([self.nts]) self.dhw_energy = 0. self.total_power = np.zeros([self.nts]) self.total_energy = 0. for iii in range(1000): print(iii) building = self.buildings.loc[iii, :] result = self.calculate_building_heat_demand(building) print(result) input() """ # Calculation # ---------------------------------------------------------------- # City manager # this dictionary is shared with all the processes if self.debug >= 1: print(' Starting multiprocessing manager...') manager = multiprocessing.Manager() if self._energy_only: self.results = manager.dict(energy_sh=0., energy_hw=0., energy_total=0.) else: self.results = manager.dict(power_sh=np.zeros([self.nts]), energy_sh=0., power_hw=np.zeros([self.nts]), energy_hw=0., power_total=np.zeros([self.nts]), power_total_delayed=np.zeros([self.nts]), energy_total=0.) # Queues if self.debug >= 1: print(' Starting queues...') ## Feeder queue buildings_list = range(len(self.buildings)) feederQueue = multiprocessing.Queue() feedProc = multiprocessing.Process(target=self.feed_building_to_process, args=(feederQueue, buildings_list)) ## Writer queue writerQueue = multiprocessing.Queue() writeProc = multiprocessing.Process(target=self.write_to_city_heat_demand, args=(writerQueue, filename)) # Processes calcProc = [multiprocessing.Process(target=self.call_calculate_building_heat_demand, args=(feederQueue, writerQueue)) for iii in range(self.processes)] ## start # if (self.debug >= 1): # print(' Calculating building heat demand...') feedProc.start() for p in calcProc: p.start() if self.debug >= 1: print('\n Saving to file...') writeProc.start() ## join feedProc.join() for p in calcProc: p.join() writeProc.join() # add base load to timeseries if not self._energy_only: self.results['power_total'] += self.base_load self.results['energy_total'] += np.sum(self.base_load) # save results per city if self.save >= 1: if not self._energy_only: self.save_csv_power() self.save_csv_energy()
#
[docs] def call_calculate_building_heat_demand(self, feederQueue, writerQueue): """ Calls function to calculate building heat demand """ while True: try: # get from Queue (building, iii) = feederQueue.get(block=True, timeout=10) # calculate result = self.calculate_building_heat_demand(building) # write to Queue writerQueue.put((result, iii)) # print(' {} | bid: {}'.format(multiprocessing.current_process().name, result[0][0])) if self.debug >= 1: # Progress bar sys.stdout.write('\r') i = float((iii + 1) / len(self.buildings)) sys.stdout.write(" Calculation: [%-20s] %d%%" % ('|' * int(20 * i), 100 * i)) sys.stdout.flush() except Exception as e: # print('>>> Error: {}'.format(e)) break
#
[docs] def calculate_building_heat_demand(self, building): """ Extracts building information needed to create a Building object. If the building is connected to the district heating network, then a Building object is created and the heat demand is calculted. If it is not, then the heat demand is set to zero. Args: building dataframe with building information iii building counter """ # initialize results sh = np.zeros(6) hw = np.zeros(2) total = np.zeros(2) # check if building is connected to the network rand_num = np.random.uniform(0, 1, 1)[0] if rand_num < self.connection_factor: my_building = self.create_building_object(building) # Calculations ## Space heating demand if self._space_heating: sh = my_building.calculate_space_heating_demand() ### add building space heating demand to city space heating demand if not self._energy_only: # self.sh_power += my_building.space_heating_power self.results['power_sh'] += my_building.space_heating_power # self.sh_energy += my_building.space_heating_energy self.results['energy_sh'] += my_building.space_heating_energy ## Hot water demand if self._hot_water: hw = my_building.calculate_hot_water_demand() ### add building hot water demand to city hot water demand if not self._energy_only: # self.dhw_power += my_building.hot_water_power self.results['power_hw'] += my_building.hot_water_power # self.dhw_energy += my_building.dhw_energy self.results['energy_hw'] += my_building.dhw_energy ## Total heat demand total = my_building.calculate_total_heat_demand() ## add building demand to city demand if not self._energy_only: # self.total_power += my_building.total_power self.results['power_total'] += my_building.total_power # self.total_energy += my_building.total_energy self.results['energy_total'] += my_building.total_energy ## save results per building if self.save >= 2: my_building.save_csv() # my_building.save_load_duration_curve() ## save results per timestep if self.save == 3: if self._hot_water: my_building.save_dhw_debug_csv() # Plot if self.plot == 2: my_building.plot_timeseries(space_heating=self._space_heating, Tb=True, hot_water=self._hot_water, total=True, xticks=('month', 3)) r = building syn_b = [r.bid, r.footprint_area, r.use, r.free_walls, r.lat, r.lon, r.dist_to_heat_source, r.year_class, r.size_class, r.floors, r.storey_area, r.area_corr_factor, r.heated_area, r.window_area, r.dwellings, r.dwelling_size, r.occupants, r.ref_level_roof, r.ref_level_wall, r.ref_level_floor, r.ref_level_window, r.U, r.V, r.C, r.Tau, r.Tset, r.act_start, r.act_end, r.hw_demand_day, r.hw_tank_cap] result = [syn_b, sh, hw, total] # return flattened list with one row result = [item for sublist in result for item in sublist] result = np.resize(result, (1, len(result))) return result
#
[docs] def create_building_object(self, building): """ Creates instance of class Object """ # create Building object my_building = Building( # Building data building, self.building_stock_stats, # Simulation [self.dt_vector, self.dt_vector_excel], self.resolution, self.number_of_typ_days, self.weights, self.Tamb, self.I, self._space_heating, self._hot_water, self._energy_only, # Space heating demand self.Tb0_str, self.dTset, self.dT_per_hour, self.eta, self.thermal_inertia, self._active_population, self._workday_weekend, self.sh_prob, self._solar_gains, self._internal_gains, self._night_set_back, self.schedule_nsb, self.T_nsb, self.power_reduction, # Hot water demand self.Tw, self.dhw_prob, self.hw_tank_limit, self.hw_flow, self.day_vector, self.seasonal_vector, self.min_vector, # Results self.result_dir, self.plot, self.save, self.debug) return my_building
#
[docs] def write_to_city_heat_demand(self, writerQueue, filename): """ Writes building properties and heat demand to file """ while True: try: # get from Queue (result, iii) = writerQueue.get(block=True, timeout=20) # save results once chunk size is reached if self.counter_heat >= self.chunk_size: # save f = open(filename, 'ab') fmt = ['%d', '%.2f', '%d', '%d', '%.3f', '%.3f', '%.2f', '%d', '%d', '%d', '%.2f', '%.2f', '%.2f', '%.2f', '%d', '%.2f', '%d', '%d', '%d', '%d', '%d', '%.2f', '%.2f', '%.2f', '%.2f', '%d', '%d', '%d', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f'] np.savetxt(f, self.b_to_save_heat, delimiter=';', fmt=fmt) f.close() # restart counter self.counter_heat = 0 self.b_to_save_heat = np.zeros([self.chunk_size, 40]) # Progress bar # print(' bid: {}'.format(result[0][0])) if self.debug >= 1: sys.stdout.write('\r') i = float((iii + 1) / len(self.buildings)) sys.stdout.write("\n Saving: [%-20s] %d%%" % ('|' * int(20 * i), 100 * i)) sys.stdout.flush() # always add building to matrix to save self.b_to_save_heat[self.counter_heat, :] = result self.counter_heat += 1 except Exception as e: # print('>>> Error: {}'.format(e)) # save again to not loose data f = open(filename, 'ab') fmt = ['%d', '%.2f', '%d', '%d', '%.3f', '%.3f', '%.2f', '%d', '%d', '%d', '%.2f', '%.2f', '%.2f', '%.2f', '%d', '%.2f', '%d', '%d', '%d', '%d', '%d', '%.2f', '%.2f', '%.2f', '%.2f', '%d', '%d', '%d', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f'] # drop zero rows self.b_to_save_heat = self.b_to_save_heat[~np.all(self.b_to_save_heat == 0, axis=1)] np.savetxt(f, self.b_to_save_heat, delimiter=';', fmt=fmt) f.close() break
# Domestic hot water demand # --------------------------------------------------------------------------------
[docs] def initialize_dhw_probabilities(self): """ Calculates dhw probabilities (daily consumption, event loads, flow rate and duration as interpolate objects. """ # Daily specific dhw consumption [m3/m2 of living area] as cdf x = [i[0] for i in self.building_stock_stats[1][0]] p = [i[1] for i in self.building_stock_stats[1][0]] dhw_cdf = UrbanHeatPro.create_interpolated_cdf(x, p) # Probability distribution of the DHW-load happening at specific time of the day # ### Probabilities in 0.2h-steps p_shower = [i[1] for i in self.building_stock_stats[1][1]] p_bath = [i[2] for i in self.building_stock_stats[1][1]] p_med_small = [i[3] for i in self.building_stock_stats[1][1]] # ### Interpolators x_min = 0. x_max = 23.8 x_steps = 120 x = np.linspace(x_min, x_max, num=x_steps, endpoint=False) shower_ptime = interpolate.interp1d(x, p_shower) bath_ptime = interpolate.interp1d(x, p_bath) medium_ptime = interpolate.interp1d(x, p_med_small) small_ptime = medium_ptime # prob_time = [shower_ptime, bath_ptime, medium_ptime, small_ptime] # Factor for probability distribution of the DHW-load happening at specific weekday shower_pwday = [i[1] for i in self.building_stock_stats[1][2]] bath_pwday = [i[2] for i in self.building_stock_stats[1][2]] medium_pwday = [i[3] for i in self.building_stock_stats[1][2]] small_pwday = medium_pwday prob_wday = [shower_pwday, bath_pwday, medium_pwday, small_pwday] # Load flow rate CDF x_min = 3. x_max = 20. x_steps = 1000 x = np.linspace(x_min, x_max, num=x_steps, endpoint=False) ### Shower mean = self.building_stock_stats[1][3][0][0] sigma = self.building_stock_stats[1][3][1][0] norm_dist = UrbanHeatPro.create_normal_distribution(x, mean, sigma) shower_f_cdf = UrbanHeatPro.create_interpolated_cdf(x, norm_dist) # ### Bath mean = self.building_stock_stats[1][3][0][1] sigma = self.building_stock_stats[1][3][1][1] norm_dist = UrbanHeatPro.create_normal_distribution(x, mean, sigma) bath_f_cdf = UrbanHeatPro.create_interpolated_cdf(x, norm_dist) # x_min = 0. x_max = 10. x_steps = 1000 x = np.linspace(x_min, x_max, num=x_steps, endpoint=False) ### Medium mean = self.building_stock_stats[1][3][0][2] sigma = self.building_stock_stats[1][3][1][2] norm_dist = UrbanHeatPro.create_normal_distribution(x, mean, sigma) medium_f_cdf = UrbanHeatPro.create_interpolated_cdf(x, norm_dist) # ### Small mean = self.building_stock_stats[1][3][0][3] sigma = self.building_stock_stats[1][3][1][3] norm_dist = UrbanHeatPro.create_normal_distribution(x, mean, sigma) small_f_cdf = UrbanHeatPro.create_interpolated_cdf(x, norm_dist) # flowRate_cdf = [shower_f_cdf, bath_f_cdf, medium_f_cdf, small_f_cdf] # Load duration CDF x_min = 3. x_max = 15. x_steps = 1000 x = np.linspace(x_min, x_max, num=x_steps, endpoint=False) ### Shower mean = self.building_stock_stats[1][4][0][0] sigma = self.building_stock_stats[1][4][1][0] norm_dist = UrbanHeatPro.create_normal_distribution(x, mean, sigma) shower_d_cdf = UrbanHeatPro.create_interpolated_cdf(x, norm_dist) # ### Bath mean = self.building_stock_stats[1][4][0][1] sigma = self.building_stock_stats[1][4][1][1] norm_dist = UrbanHeatPro.create_normal_distribution(x, mean, sigma) bath_d_cdf = UrbanHeatPro.create_interpolated_cdf(x, norm_dist) # x_min = 0. x_max = 5. x_steps = 1000 x = np.linspace(x_min, x_max, num=x_steps, endpoint=False) ### Medium mean = self.building_stock_stats[1][4][0][2] sigma = self.building_stock_stats[1][4][1][2] norm_dist = UrbanHeatPro.create_normal_distribution(x, mean, sigma) medium_d_cdf = UrbanHeatPro.create_interpolated_cdf(x, norm_dist) # ### Small mean = self.building_stock_stats[1][4][0][3] sigma = self.building_stock_stats[1][4][1][3] norm_dist = UrbanHeatPro.create_normal_distribution(x, mean, sigma) small_d_cdf = UrbanHeatPro.create_interpolated_cdf(x, norm_dist) # duration_cdf = [shower_d_cdf, bath_d_cdf, medium_d_cdf, small_d_cdf] dhw_prob = [dhw_cdf, prob_time, prob_wday, flowRate_cdf, duration_cdf] return dhw_prob
#
[docs] def calculate_seasonal_variation_vector(self, amplitude=0.1, max_point=45): """ Creates a sine wave representing the change of the nominal consumption during the year due to the seasonal variation. Args: amplitude (float): Variation of consumption (% of nominal load) max_point (int): Day in year with the highest hot water consumption (lowest ambient temperature) Returns: seasonal_vector <numpy array> """ # initialize seasonal vector seasonal_vector = np.zeros(366) # create sine function for iii in range(1, 367): perc = float(iii) / 366. seasonal_vector[iii - 1] = np.sin(2. * np.pi * (perc + max_point / 366.)) * amplitude + 1. return seasonal_vector
#
[docs] def calculate_day_vector(self): """ Calculates a vector of the days in the year included in the simulation time frame. Maximum length is 366. Returns: list: self.day_vector, list of day numbers in simulation time frame with start and end indices """ num_days = self.number_of_typ_days # initialize day_vector day_vector = np.zeros([num_days, 3], dtype=int) # day_vector: [day in year, start time step] prev_day = 0 day_count = 0 for iii, date in enumerate(self.dt_vector): if not (date.timetuple().tm_yday == prev_day): day_vector[day_count][0] = date.timetuple().tm_yday day_vector[day_count][1] = iii # index of dt_vector where a new day starts day_count += 1 prev_day = date.timetuple().tm_yday # add end time step for iii, day in enumerate(day_vector): try: day_vector[iii][2] = day_vector[iii + 1][1] - 1 except: # last day day_vector[iii][2] = len(self.dt_vector) - 1 return day_vector
#
[docs] def calculate_min_vector(self): """ Calculates a vector of the simulation time steps in minutes of year. Maximum length is 366*24*60. Returns: list: self.min_vector, list of time steps in minutes """ # initialize min_vector min_vector = np.zeros([self.nts], dtype=int) # calculate minutes of year for iii, date in enumerate(self.dt_vector): day_in_year = date.timetuple().tm_yday hour_in_day = date.timetuple().tm_hour min_in_hour = date.timetuple().tm_min min_vector[iii] = (day_in_year - 1) * 24 * 60 + hour_in_day * 60 + min_in_hour return min_vector
# Results # --------------------------------------------------------------------------------
[docs] def plot_timeseries(self, space_heating=True, hot_water=True, total=True, xticks=('month', 3)): """ """ if space_heating: fig_name = '{}/SpaceHeatingDemand_{}.png'.format(self.result_dir, self.rid) UrbanHeatPro.plot_timeseries(self.dt_vector, [self.space_heating_power], ['Space heating demand'], fig_name, xticks=xticks, ynumticks='auto', ylabel='Power [kW]', ylim0=True, yfactor=1e3) if hot_water: fig_name = '{}/HotWaterDemand_{}.png'.format(self.result_dir, self.rid) UrbanHeatPro.plot_timeseries(self.dt_vector, [self.hot_water_power], ['Hot water demand'], fig_name, xticks=xticks, ynumticks='auto', ylabel='Power [kW]', ylim0=True, yfactor=1e3) if total: fig_name = '{}/TotalHeatDemand_{}.png'.format(self.result_dir, self.rid) UrbanHeatPro.plot_stacked_timeseries(self.dt_vector, [self.hot_water_power, self.space_heating_power], ['Hot water', 'Space heating'], fig_name, xticks=xticks, ynumticks='auto', ylabel='Power [kW]', ylim0=True, yfactor=1e3)
#
[docs] def save_csv_syn_city_header(self, filename): """ Saves key building parameters of every chunk. """ f = open(filename, 'w') # Region f.write('{};{}'.format(self.region, self.name)) # Building data f.write('\nbid;footprint_area;use;free_walls;' + \ 'lat;lon;dist_to_heat_source;' + \ 'year_class;size_class;floors;' + \ 'storey_area;area_corr_factor;heated_area;window_area;' + \ 'dwellings;dwelling_size;occupants;' + \ 'ref_level_roof;ref_level_wall;ref_level_floor;ref_level_window;' + \ 'U;V;C;Tau;' + \ 'Tset;act_start;act_end;' + \ 'hw_demand_day;hw_tank_cap\n') f.close()
#
[docs] def save_csv_energy_header(self, filename): """ Saves key building parameters of every chunk. """ f = open(filename, 'w') # Region f.write(self.region) # Building data f.write('\nbid;footprint_area;use;free_walls;' + \ 'lat;lon;dist_to_heat_source;' + \ 'year_class;size_class;floors;' + \ 'storey_area;area_corr_factor;heated_area;window_area;' + \ 'dwellings;dwelling_size;occupants;' + \ 'ref_level_roof;ref_level_wall;ref_level_floor;ref_level_window;' + \ 'U;V;C;Tau;' + \ 'Tset;act_start;act_end;' + \ 'hw_demand_day;hw_tank_cap;' + \ 'sh_demand;solar_gains;int_gains;' + \ 'sh_demand_per_h_area;solar_gains_per_h_area;int_gains_per_h_area;' + \ 'hw_demand;hw_demand_m3;' + \ 'total_demand;total_demand_per_h_area\n') f.close()
#
[docs] def save_csv_power(self): """ Saves heat demand timeseries in csv file (space heating, hot water and total). """ array_to_save = np.array([self.dt_vector_excel, self.Tamb, self.results['power_sh'], self.results['power_hw'], self.results['power_total'], self.results['power_total_delayed']]).transpose() # filename = '{}/CityHeatDemand-Profile_{}_{}_{}.csv'.format(self.result_dir, self.region, self.sce, self.rid) filename = '{}/CityHeatDemand-Profile_{}_{}.csv'.format(self.result_dir, self.name, self.rid) # Header with open(filename, 'w') as f: f.write('Run id;{};\n'.format(self.rid)) f.write('Total buildings;{};\n'.format(len(self.buildings))) f.write('Commercial;{};\n'.format(np.sum(self.buildings.use == 0))) f.write('Industrial;{};\n'.format(np.sum(self.buildings.use == 1))) f.write('Public;{};\n'.format(np.sum(self.buildings.use == 2))) f.write('Residential;{};\n'.format(np.sum(self.buildings.use == 3))) f.write('SpaceHeatingDemand_GWh;{};\n'.format(self.results['energy_sh'] / 1e9)) f.write('HotWaterDemand_GWh;{};\n'.format(self.results['energy_hw'] / 1e9)) f.write('Base Load_GWh;{};\n'.format(np.sum(self.base_load) / 1e9)) f.write('TotalHeatDemand_GWh;{};\n'.format(self.results['energy_total'] / 1e9)) f.write('\ndatenum;Tamb_degC;SpaceHeatingDemand_MW;HotWaterDemand_MW;' + 'TotalHeatDemand_MW;TotalHeatDemand_Delayed_MW\n') # Building data with open(filename, 'ab') as f: np.savetxt(f, array_to_save, delimiter=';', fmt='%.3f')
#
[docs] def save_csv_energy(self): """ Saves aggregated heat demand in csv file (space heating, hot water and total). """ array_to_save = np.array([self.results['energy_sh'], self.results['energy_hw'], self.results['energy_total']]) array_to_save = np.resize(array_to_save, (1, len(array_to_save))) # filename = '{}/CityHeatDemand-Aggregate_{}_{}_{}.csv'.format(self.result_dir, self.region, self.sce, self.rid) filename = '{}/CityHeatDemand-Aggregate_{}_{}.csv'.format(self.result_dir, self.name, self.rid) f = open(filename, 'a') # Region f.write(self.region) # Building data f.write('\nSHD_Wh;DHWD_Wh;TOTAL_Wh\n') f.close() # Building data with open(filename, 'ab') as f: np.savetxt(f, array_to_save, delimiter=';', fmt='%.3f')