def categorize_residential_building(self): """ Categorizes building according to TABULA typologies. Construction year class and building type are calculated by comparing the residential building ground floor area (gfa) with the GFA of typical buildings (from TABULA). Values are adapted to building stock statistics. returns: self.class_year <tuple> (int, str) self.btype <tuple> (int, str) """ gfa = self.env_areas[2] # get size of GFA matrix rows = len(self.GFA) # construction year class cols = len(self.GFA[0]) # building type # initialize distance vectors distance = np.zeros(rows * cols) distance_inv = np.zeros(rows * cols) row_col = [[] for _ in range(rows * cols)] t_distance_inv = 0 kkk = 0 # calculate inverse of distances # 1/d is used so that the minimum distance has a higher probability for iii in range(0, rows): for jjj in range(0, cols): distance[kkk] = abs(self.GFA[iii][jjj] - gfa) + 0.01 # "+ 0.001" to avoid having x/0 distance_inv[kkk] = (1.0 / distance[kkk]) * self.STOCK_RES[iii, jjj] row_col[kkk] = [iii, jjj] t_distance_inv += distance_inv[kkk] kkk += 1 # normalize inverse distance norm_distance = distance_inv / t_distance_inv # get cumulative density function cdf = np.cumsum(norm_distance) # generate random number rnd = np.random.uniform(0, 1, 1) # check random number with cdf index = np.argmax(rnd < cdf) # Construction year class self.year_class = UrbanHeatPro.year_class_to_tuple(self.use[0], row_col[index][0]) # Building type self.btype = UrbanHeatPro.building_type_to_tuple(self.use[0], row_col[index][1])
def analyze_building_stock_per_run(self, run, result_dir_run): """ Compares the distribution of the synthetic building stock generated per run with the statistics. """ # RESIDENTIAL # total buildings count_res = len(self.my_city.energy_per_building[self.my_city.energy_per_building[:, 1] == 3]) for year_class in range(10): for btype in range(4): # extract all buildings B with specific year_class, btype and use c0 = self.my_city.energy_per_building[:, 1] == 3 # RESIDENTIAL c1 = self.my_city.energy_per_building[:, 2] == year_class c2 = self.my_city.energy_per_building[:, 3] == btype B = self.my_city.energy_per_building[c0 * c1 * c2] # add building distribution to category self.bstock_res[run][year_class][btype] = len(B)/float(count_res) # NON-RESIDENTIAL count_nres = len(self.my_city.energy_per_building[self.my_city.energy_per_building[:, 1] != 3]) for year_class in range(5): # extract all buildings B with specific year_class, btype and use c0 = self.my_city.energy_per_building[:, 1] != 3 # NON-RESIDENTIAL c1 = self.my_city.energy_per_building[:, 2] == year_class B = self.my_city.energy_per_building[c0 * c1] # add building distribution to category self.bstock_nres[run][year_class] = len(B)/float(count_nres) count_nres += 1 # Plots # Building distribution per category from statistics [%] stat_res = self.building_stock_stats[8] stat_nres = self.building_stock_stats[9] # plot imshow to compare with statistics fig_name = '{}/BuildingStock_res_{}.png'.format(result_dir_run, run) UrbanHeatPro.plot_imshow_comparison(3, self.bstock_res[run], stat_res, fig_name, cmap = 'RdBu') # fig_name = '{}/BuildingStock_nres_{}.png'.format(result_dir_run, run) UrbanHeatPro.plot_imshow_comparison(0, self.bstock_nres[run], stat_nres, fig_name, cmap = 'RdBu')
def categorize_non_residential_building(self): """ int construction year class 0 < 1918 1 1919 - 1976 2 1977 - 1983 3 1984 - 1994 4 > 1995 >>> Statistics on the non-residential buildings stock are missing """ # assign random construction year class year_class_int = randint(0, 4) self.year_class = UrbanHeatPro.year_class_to_tuple(self.use[0], year_class_int) self.btype = UrbanHeatPro.building_type_to_tuple(self.use[0], self.btype_int)
def analyze_building_stock_per_sim(self): """ Compares the MEAN distribution of the synthetic building stock generated per run with the statistics. """ # Building distribution per category from statistics [%] stat_res = self.building_stock_stats[8] stat_nres = self.building_stock_stats[9] # Simulation building stock results mean_res = self.bstock_res.mean(axis = 0) mean_nres = self.bstock_nres.mean(axis = 0) # plot imshow to compare with statistics fig_name = '{}/BuildingStock_res.png'.format(self.result_dir) UrbanHeatPro.plot_imshow_comparison(3, mean_res, stat_res, fig_name, cmap = 'RdBu') # fig_name = '{}/BuildingStock_nres.png'.format(self.result_dir) UrbanHeatPro.plot_imshow_comparison(0, mean_nres, stat_nres, fig_name, cmap = 'RdBu')
def plot_energy(self, space_heating=True, hot_water=True, total=True): """ Plots histogram of aggregated heat demand for all simulations """ if space_heating: ylabel = 'Space Heating Demand [GWh]' fig_name = '{}/SpaceHeatingDemand_hist.png'.format(self.result_dir) UrbanHeatPro.plot_histogram(self.space_heating_energy, ylabel, fig_name, factor=1e9) if hot_water: ylabel = 'Hot Water Demand [GWh]' fig_name = '{}/HotWaterDemand_hist.png'.format(self.result_dir) UrbanHeatPro.plot_histogram(self.hot_water_energy, ylabel, fig_name, factor=1e9) if total: ylabel = 'Total Heat Demand [GWh]' fig_name = '{}/TotalHeatDemand_hist.png'.format(self.result_dir) UrbanHeatPro.plot_histogram(self.total_energy, ylabel, fig_name, factor=1e9)
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)
def plot_timeseries(self, \ space_heating = True, Tb = False, \ hot_water = True, \ total = True): """ Plots heat demand timeseries """ if space_heating: fig_name = '{}/SpaceHeatingDemand_{}_{}_{}_{}.png'.format(self.result_dir, \ self.use[0], self.year_class[0], self.btype[0], self.bid) UrbanHeatPro.plot_timeseries(self.dt_vector, \ [self.space_heating_power], ['Space heating demand'], \ fig_name, xticks = ('month', 3), \ ynumticks = 'auto', ylabel = 'Power [kW]', ylim0 = True, yfactor = 1e3) if Tb: fig_name = '{}/BuildingTemperature_{}_{}_{}_{}.png'.format(self.result_dir, \ self.use[0], self.year_class[0], self.btype[0], self.bid) UrbanHeatPro.plot_timeseries(self.dt_vector, \ [self.Tamb, self.Tb], ['T_amb', 'T_b'], \ fig_name, xticks = ('month', 3), \ ynumticks = 'auto', ylabel = 'Temperature [degC]', ylim0 = False, yfactor = 1) if hot_water: fig_name = '{}/HotWaterDemand_{}_{}_{}_{}.png'.format(self.result_dir, \ self.use[0], self.year_class[0], self.btype[0], self.bid) UrbanHeatPro.plot_timeseries(self.dt_vector, \ [self.hot_water_power], ['Hot water demand'], \ fig_name, xticks = ('month', 3), \ ynumticks = 'auto', ylabel = 'Power [kW]', ylim0 = True, yfactor = 1e3) if total: fig_name = '{}/TotalHeatDemand_{}_{}_{}_{}.png'.format(self.result_dir, \ self.use[0], self.year_class[0], self.btype[0], self.bid) UrbanHeatPro.plot_stacked_timeseries(self.dt_vector, \ [self.hot_water_power, self.space_heating_power], \ ['Hot water', 'Space heating'], \ fig_name, xticks = ('month', 3), \ ynumticks = 'auto', ylabel = 'Power [kW]', ylim0 = True, yfactor = 1e3)
def plot_power(self, space_heating=True, hot_water=True, total=True): """ Plot min, max, and mean power values for each time step. """ if space_heating: min = self.space_heating_power.min(axis=1) max = self.space_heating_power.max(axis=1) mean = self.space_heating_power.mean(axis=1) fig_name = '{}/SpaceHeatingDemand_ts.png'.format(self.result_dir) UrbanHeatPro.plot_timeseries(self.dt_vector, \ [min, max, mean], ['min', 'max', 'mean'], \ fig_name, xticks = ('month', 3), \ ynumticks = 'auto', ylabel = 'Space Heating Demand [MW]', ylim0 = True, yfactor = 1e6) if hot_water: min = self.hot_water_power.min(axis=1) max = self.hot_water_power.max(axis=1) mean = self.hot_water_power.mean(axis=1) fig_name = '{}/HotWaterDemand_ts.png'.format(self.result_dir) UrbanHeatPro.plot_timeseries(self.dt_vector, \ [min, max, mean], ['min', 'max', 'mean'], \ fig_name, xticks = ('month', 3), \ ynumticks = 'auto', ylabel = 'Hot Water Demand [MW]', ylim0 = True, yfactor = 1e6) if total: min = self.total_power.min(axis=1) max = self.total_power.max(axis=1) mean = self.total_power.mean(axis=1) fig_name = '{}/TotalHeatDemand_ts.png'.format(self.result_dir) UrbanHeatPro.plot_timeseries(self.dt_vector, \ [min, max, mean], ['min', 'max', 'mean'], \ fig_name, xticks = ('month', 3), \ ynumticks = 'auto', ylabel = 'Heat Demand [MW]', ylim0 = True, yfactor = 1e6)
def calculate_building_envelope_areas(self): """ Calculates building envelope areas (wall, roof and window) depending on the building use: Residential: areas are calculated according to building typologies in TABULA. To obtain the typology (construction year class and building type) the gfa is matched to the typology GFA. Non-residential: number of floors and window-to-wall ratio are derived from statistics and used to calculate the building areas. Construction year class is also derived from statistics. An area_correction_factor is included since not the whole floor area is heated. From VDI 3807-2. returns: self.env_areas <list> [Roof, Walls, Floor (gfa), Window] in m2 self.heated_area <float> Total building heated area """ if (self.use[0] == 3): # RESIDENTIAL # Area correction factor for calculating heated areas area_correction_factor = 0.85 # Conditioned (heated) GFA self.gfa_h = self.env_areas[2] * area_correction_factor # check if building typology is given if self.building_typology: self.year_class = UrbanHeatPro.year_class_to_tuple(self.use[0], self.year_class_int) # Construction year class (int, str) self.btype = UrbanHeatPro.building_type_to_tuple(self.use[0], self.btype_int) # Building type (int, str) else: # assign building typology from statistics # check that the building data exists as C-values are not available for all buildings building_exists = False while building_exists == False: self.categorize_residential_building() a = self.C_RES[2][self.year_class[0]][self.btype[0]] # C_floor value b = self.GFA[self.year_class[0]][self.btype[0]] if (a > 0.0 and b > 0.0): building_exists = True # Floor-to-floor height # from http://www.ctbuh.org/HighRiseInfo/TallestDatabase/Criteria/HeightCalculator/tabid/1007/language/en-GB/Default.aspx # self.f2f_height = (randint(30, 32) / 10.0) # m # from TABULA self.f2f_height = 2.5 # m # Number of floors self.floors = self.FLOORS[self.year_class[0]][self.btype[0]] * (1 + (1 - area_correction_factor)) # Building areas ### Roof self.env_areas[0] = self.ARATIO[0][self.year_class[0]][self.btype[0]] * self.gfa_h ### Wall self.env_areas[1] = self.ARATIO[1][self.year_class[0]][self.btype[0]] * self.gfa_h * self.free_walls ### Window self.env_areas[3] = self.ARATIO[2][self.year_class[0]][self.btype[0]] * self.gfa_h for j in range(4): self.window_areas[j] = self.env_areas[3] * self.WRATIO_ORIENTATION[5 * j + self.btype[0]] else: # NON-RESIDENTIAL # Area correction factor for calculating heated areas area_correction_factor = (randint(6, 8) / 10.0) # Conditioned (heated) GFA self.gfa_h = self.env_areas[2] * area_correction_factor # Construction year class self.categorize_non_residential_building() # Floor-to-floor height # from http://www.ctbuh.org/HighRiseInfo/TallestDatabase/Criteria/HeightCalculator/tabid/1007/language/en-GB/Default.aspx self.f2f_height = (randint(30, 39) / 10.0) # m # Number of floors # >>> Source missing lower_limit = 1 upper_limit = 3 self.calculate_number_of_floors(lower_limit, upper_limit) # Building areas ### Roof self.env_areas[0] = self.gfa_h ### Wall width = np.sqrt(self.gfa_h) # [m] building is assumed to be a cube self.env_areas[1] = self.free_walls * self.floors * self.f2f_height * width ### Window # >>> Add Window-to-Wall ratio for the different building types # >>> Source missing self.env_areas[3] = (randint(1, 4) / 10.0) * self.env_areas[1] # Window areas oriented to [east, south, west, north] for j in range(4): self.window_areas[j] = self.env_areas[3] * self.WRATIO_ORIENTATION[5 * j + 4] # Total heated area (reference area in TABULA) in m2 self.heated_area = self.gfa_h * self.floors # Total living space self.living_area = self.gfa_h * self.floors * (1 + (1 - area_correction_factor))
def __init__(self, dt_vectors, resolution, Tamb, I, _space_heating, _hot_water, \ Tb0_str, dTset, dT_per_hour, eta, thermal_inertia, building_stock_stats, \ bid, use, gfa, free_walls, lat, lon, distance2hp, building_typology, year_class_int, btype_int, \ refurbishment_level, _active_population, _solar_gains, _internal_gains, \ _night_set_back, schedule_nsb, T_nsb, power_reduction, \ Tw, dhw_prob, hw_tank_limit, hw_flow, \ day_vector, seasonal_vector, min_vector, \ result_dir, plot, save, debug): # General data # -------------------------------------------------- # Building data self.bid = bid # Building id self.use = UrbanHeatPro.building_use_to_tuple(use) # Building use (int, str) self.free_walls = free_walls # Number of walls in contact with Tamb self.coords = (lat, lon) # Coordinates of building centroid self.building_typology = building_typology self.year_class_int = year_class_int self.btype_int = btype_int self.year_class = None # Construction year class (int, str) self.btype = None # Building type (int, str) self.env_areas = [0, 0, gfa, 0] # Envelope areas [Roof, Walls, Floor (gfa), Window] self.window_areas = [0, 0, 0, 0] # Window area oriented to the [east, south, west, north] self.floors = 0 # number of floors self.f2f_height = 0 # floor to floor height [m] self.heated_area = 0 # total heated area (reference area) [m2] self.living_area = 0 # total living area [m2] self.dwellings = 0 # number of dwellings in building self.dwelling_size_cat = 0 # dwelling size category to calculate household size # Simulation self.dt_vector = dt_vectors[0] # Vector of time steps as datetime objects self.dt_vector_excel = dt_vectors[1] # Vector of time steps as excel date self.nts = len(self.dt_vector) # Number of time steps self.resolution = resolution # Temporal resolution in min self._space_heating = _space_heating # Calculate space heating demand? self._hot_water = _hot_water # Calculate hot water demand? # External factors self.Tamb = Tamb # Ambient temperature vector in degC self.I = I # Solar radiation vector in W/m2 [I_Gh, I_Dh, I_ex, hs] self.eta = eta # Heating process efficiency self.thermal_inertia = thermal_inertia # Thermal inertia of the heating system # Result directory self.result_dir = result_dir # Directory where results are stored # Space heating demand # -------------------------------------------------- # Building stock statistics I self.GFA = building_stock_stats[0][0] # GFA of building typologies (TABULA) self.ARATIO = building_stock_stats[0][1] # Area ratio [Roof, Wall, Window] self.WRATIO_ORIENTATION = building_stock_stats[0][2] # Window ratio [East, South, West, North] self.FLOORS = building_stock_stats[0][3] # Number of floors self.U_RES = building_stock_stats[0][4] # U-values for residential buildings self.V_RES = building_stock_stats[0][5] # Air flow rate (ventilation losses) for residential self.C_RES = building_stock_stats[0][6] # Thermal cap for residential buildings self.REFURBISHED_RES = building_stock_stats[0][7] # Percentage of residential refurbished buildings self.SINGLE_DWELLING = building_stock_stats[0][8] # Percentage of single dwellings for SFH and TH self.HOUSEHOLD_SIZE = building_stock_stats[0][9] # Household size for dwelling size categories self.U_NRES = building_stock_stats[0][10] # U-values for non-residential buildings self.V_NRES = building_stock_stats[0][11] # Air flow rate (ventilation losses) for non-residential self.C_NRES = building_stock_stats[0][12] # Thermal cap for non-residential buildings self.TSET = building_stock_stats[0][13] # Target temperatures per building use self.SCHEDULE = building_stock_stats[0][14] # Active hours per building use self.STOCK_RES = building_stock_stats[0][15] # Building stock statistics for residential self.STOCK_NRES = building_stock_stats[0][16] # Building stock statistics for non-residential # Building thermal properties self.U = 0. # Transmission losses (U-value) [W/K] self.V = 0. # Ventilation losees [W/K] self.C = 0. # Thermal capacitance [J/K] self.Tau = 0. # Time constant [s] self.Tb0_str = Tb0_str # Initial building temperature as string: 'ambient' or 'Tset' self.Tb0 = 0. # Initial building temperature self.Tset = 0. # [Target temperature, dT] [degC] self.dTset = dTset # Delta temperature (for Tset_min, Tset_max) self.dT_per_hour = dT_per_hour # Maximum dT allowed in building per hour [degC] # Activity and occupancy in building self._active_population = _active_population # Consider active population for occupancy vector self.active_hours = [[0, 0], [0, 0]] # Building active hours [(start0, end0), (start1, end1)] self.activity_vector = np.ones([self.nts]) * 1. # Building activity vector self.occupancy_vector = np.ones([self.nts]) * 1. # Number of occupants in building per timestep self.household_vector = [] # Vector of households occupancy self.occupants = 0 # Number of occupants in building self.occupied = 1. # Is building occupied? self.perc_occupied = 0. # Percentage of occupied dwellings in building # Heat gains self._solar_gains = _solar_gains self._internal_gains = _internal_gains # DSM self.refurbishment_level = refurbishment_level self._night_set_back = _night_set_back # Share of buildings with nsb self.schedule_nsb = schedule_nsb # [start, end] of nsb in h self.T_nsb = T_nsb # Night set-back temperature in degC self.power_reduction = power_reduction # Percentage of power reduced (as decimal) # Results self.space_heating_power = np.zeros([self.nts]) # Power required so that Tb >= Tset in W self.solar_gains = np.zeros([self.nts]) # Power required so that Tb >= Tset in W self.internal_gains = np.zeros([self.nts]) # Power required so that Tb >= Tset in W self.Tb = np.zeros([self.nts]) # Building temp in degC self.space_heating_energy = 0. # Aggregated heating demand in Wh self.space_heating_energy_per_area = 0. # Aggregated heating demand in kWh/m2 # Hot water demand # -------------------------------------------------- # Domestic hot water consumption self.Tw = Tw # Hot water temperature in [degC] self.daily_DHW = 0. # Daily domestic hot water consumption in m3 self.dhw_prob = dhw_prob # Probabilities for dhw-loads self.hw_tank_capacity = 0. # Hot water tank capacity in m3 self.hw_tank_volume_t0 = 0. # Initial state of hot water tank in m3 self.hw_tank_limit = hw_tank_limit # Hot water tank limit as perc (decimal) self.hw_flow = hw_flow # Flow to refill hot water tank in L/min # Seasonality self.day_vector = day_vector # Vector of days in simulation time frame self.seasonal_vector = seasonal_vector # Sinusoidal function for seasonal variations of DHW consumption # Results self.hot_water_m3 = np.zeros([self.nts]) # Hot water demand in m3 (instantaneous demand) self.hot_water_tank_m3 = np.zeros([self.nts]) # Hot water demand in m3 (tank demand) self.hot_water_power = np.zeros([self.nts]) # Hot water demand in W self.hot_water_energy = 0. # Aggregated hot water demand in Wh self.dhw_debug = np.zeros([self.nts, 20]) # Hot water demand data per time step # Total heating energy demand # -------------------------------------------------- # Instantaneous demand self.total_power = np.zeros([self.nts]) # Total heat demand in W self.total_energy = 0. # Aggregated total heat demand in Wh # Delayed demand self.min_vector = min_vector # Vector of simulation time steps in minutes self.distance2hp = distance2hp # Distance to heat plant in m self.delay = 0. # Delay due to distance in min self.delayed_min_vector = np.zeros([self.nts]) # Vector of delayed time steps in min self.total_power_delayed = np.zeros([self.nts]) # Delayed total heat demand in W self.total_energy_delayed = 0. # Delayed total energy demand in Wh # Reporting # -------------------------------------------------- self.plot = plot self.save = save self.debug = debug
def calculate_typical_days(self): """ Calculates typical days based on Tamb timeseries. Based on Nahmmacher et al. (2016), Carpe diem: A novel approach to select representative days for long-term power system modeling. """ if self.debug != 0: print('Typical days: {}'.format(self.number_of_typ_days)) # 1. Divide data into days # ------------------------ ## initialize variables days_in_year = len(self.Tamb) // ((24 * 60) // self.resolution) data_in_days = np.zeros((days_in_year, (24 * 60) // self.resolution), dtype=float) row_start = np.zeros((days_in_year), dtype=int) row_end = np.zeros((days_in_year), dtype=int) ## arrange data data = self.Tamb for day in range(days_in_year): if (day == 0): row_start[day] = 0 row_end[day] = 24 * 60 / self.resolution else: row_start[day] = row_end[day - 1] row_end[day] = 24 * 60 / self.resolution + row_start[day] data_in_days[day, :] = np.reshape( data[row_start[day]:row_end[day]], (24, )) # 2. Hierarchical clustering # -------------------------- # Linkage matrix using Ward's method # Ward's algorithm groups similar days based on a dstance measure that leads to clusters with a minimum inner-cluster # variance. Z = linkage(data_in_days, 'ward') # 3. Number of clusters # ----------------------- # Number of clusters max_c = self.number_of_typ_days clusters = fcluster(Z, max_c, criterion='maxclust') # Distribution of historical days sorted by months and clusters ## Number of clusters number_of_clusters = max(clusters) ## Months month_names = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', '', 'Year' ] days_in_month = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] month_cumsum = np.cumsum(days_in_month) ## Sorted clusters by temperature ### sort clusters mean_clusters = np.zeros((number_of_clusters, 24)) max_mean_clusters = np.zeros(number_of_clusters) for c in range(1, number_of_clusters + 1): indices_in_cluster = np.where(clusters == c)[0] mean_clusters[c - 1, :] = np.mean( data_in_days[indices_in_cluster, :], axis=0) max_mean_clusters[c - 1] = np.max(mean_clusters[c - 1, :]) # sorted_clusters = np.argsort(max_mean_clusters)[::-1] # Hot days first sorted_clusters = np.argsort(max_mean_clusters) # Cold days first ### substitute ordered clusters clusters_copy = copy.deepcopy(clusters) for iii, c in enumerate(sorted_clusters): indices_in_cluster = np.where(clusters_copy == c + 1)[0] clusters[indices_in_cluster] = iii + 1 ## Annual share per cluster clusters_per_month = np.zeros((number_of_clusters, 14)) for c in range(number_of_clusters): clusters_per_month[c, 13] = np.sum(clusters == c + 1) / days_in_year for m in range(12): # month # group per month if m == 0: c_start = 0 else: c_start = month_cumsum[m - 1] c_end = month_cumsum[m] days_per_month = np.zeros(days_in_month[m]) days_per_month = clusters[c_start:c_end] clusters_per_month[c, m] = np.sum(days_per_month == c + 1) / days_in_month[m] # 4. Deriving representative days # ------------------------------- # All historical days grouped into the same cluster will be repersented by the # same representative day. The representative day for each cluster is the # historical day that with the min distance to the average day. min_distance_index_c = np.zeros(number_of_clusters, dtype=int) min_distance_index_y = np.zeros(number_of_clusters, dtype=int) min_distance_day = np.zeros((number_of_clusters, 24)) avg_day = np.zeros((number_of_clusters, 24)) for c in range(1, number_of_clusters + 1): indices_in_cluster = np.where(clusters == c)[0] if len(indices_in_cluster) > 1: # Representative day ## append average and historical days avg_day[c - 1, :] = np.mean( data_in_days[indices_in_cluster, :], axis=0) historical_days = data_in_days[indices_in_cluster, :] data_to_compare = np.append(np.array([avg_day[c - 1, :]]), historical_days, axis=0) ## calculate distance matrix (eudclidean) distance_to_avg = squareform( pdist(data_to_compare, 'euclidean'))[0, :] ## identify day with minimum distance to average day min_distance_index_c[c - 1] = np.where( distance_to_avg == np.min(distance_to_avg[ distance_to_avg > 0]))[0][0] min_distance_index_y[c - 1] = indices_in_cluster[ min_distance_index_c[c - 1] - 1] min_distance_day[c - 1, :] = historical_days[ min_distance_index_c[c - 1] - 1, :] # if there is only one day in cluster, then this is the representative day else: avg_day[c - 1, :] = data_in_days[indices_in_cluster, :] min_distance_day[c - 1, :] = data_in_days[indices_in_cluster, :] # 5. Weighting representative days # -------------------------------- # Representative days are weighten according to its cluster size to reflect # the fact that large clusters, containing many days, represent common events, # while smaller clusters represent occasional patterns. clusters_weight = np.zeros(number_of_clusters, dtype=int) for c in range(number_of_clusters): clusters_weight[c] = len(np.where(clusters == c + 1)[0]) # 6. Deriving time series with representative days # ------------------------------------------------ # A time series with the defined number of clusters is created and used for # the simulation. # Advantages: Less computational time, intraday behavior well represented # (thermal storage during the same day) # Disadvantages: Interday day behavior ist represented as representative days # are not consecutive and therefore do not represent the storage between days due to thermal capacity and/or solar gains. ## Time series timeseries_min = min_distance_day.flatten() timeseries_avg = avg_day.flatten() ## Time steps timesteps = np.array([ np.arange(row_start[d], row_end[d]) for d in min_distance_index_y ]).flatten() if self.save >= 1: UrbanHeatPro.plot_typical_days(days_in_year, data_in_days, \ Z, self.number_of_typ_days, \ min_distance_day, avg_day, clusters, \ clusters_per_month, month_names, \ timeseries_min, timeseries_avg, self.result_dir) if self.debug != 0: print(' {}\TypicalDays'.format(self.result_dir)) return timesteps, clusters_weight
### HOT_WATER = [[Tw], [hw_tank_limit, hw_flow]] # 5. REPORTING # 0 No results saved or plotted # 1 Results per simulation # 2 Results per building # 3 Results per time step plot = 0 save = 2 debug = 1 ### REPORTING = [plot, save, debug] # MAIN # -------------------------------------------------------------------------------- if __name__ == '__main__': # Simulation name NAME = region + '_' + 'CF' + str(connection_factor) + \ '_NSB' + str(_night_set_back) + '-' + str(T_nsb) + \ '_intHG' + str(_internal_gains) + '_solHG' + str(_solar_gains) + \ '_actPop' + str(_active_population) + \ '_BL' + str(base_load/1e6) + 'MW_' + \ '_dT' + str(dT_per_hour) + '_thI' + str(thermal_inertia) multiprocessing.freeze_support() my_Simulation = UrbanHeatPro.Simulation(NAME, SIMULATION, CITY, SPACE_HEATING, HOT_WATER, REPORTING) my_Simulation.run()
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
def analyze_thermal_properties_per_sim(self): """ Appends thermal properties for all runs and plot histograms """ # initialize temporal matrices U_res = [[np.array([]) for col in range(4)] for row in range(10)] C_res = [[np.array([]) for col in range(4)] for row in range(10)] TAU_res = [[np.array([]) for col in range(4)] for row in range(10)] SH_res = [[np.array([]) for col in range(4)] for row in range(10)] HW_res = [[np.array([]) for col in range(4)] for row in range(10)] HEAT_res = [[np.array([]) for col in range(4)] for row in range(10)] U_nres = [np.array([]) for col in range(5)] C_nres = [np.array([]) for col in range(5)] TAU_nres = [np.array([]) for col in range(5)] SH_nres = [np.array([]) for col in range(5)] HW_nres = [np.array([]) for col in range(5)] HEAT_nres = [np.array([]) for col in range(5)] # append simulation values for run in range(self.N): # RESIDENTIAL for year_class in range(10): for btype in range(4): U_res[year_class][btype] = np.append(U_res[year_class][btype], self.u_res[run][year_class][btype]) C_res[year_class][btype] = np.append(C_res[year_class][btype], self.c_res[run][year_class][btype]) TAU_res[year_class][btype] = np.append(TAU_res[year_class][btype], self.tau_res[run][year_class][btype]) SH_res[year_class][btype] = np.append(SH_res[year_class][btype], self.sh_per_area_res[run][year_class][btype]) HW_res[year_class][btype] = np.append(HW_res[year_class][btype], self.hw_per_area_res[run][year_class][btype]) HEAT_res[year_class][btype] = np.append(HEAT_res[year_class][btype], self.heat_per_area_res[run][year_class][btype]) # NON-RESIDENTIAL for year_class in range(5): U_nres[year_class] = np.append(U_nres[year_class], self.u_nres[run][year_class]) C_nres[year_class] = np.append(C_nres[year_class], self.c_nres[run][year_class]) TAU_nres[year_class] = np.append(TAU_nres[year_class], self.tau_nres[run][year_class]) SH_nres[year_class] = np.append(SH_nres[year_class], self.sh_per_area_nres[run][year_class]) HW_nres[year_class] = np.append(HW_nres[year_class], self.hw_per_area_nres[run][year_class]) HEAT_nres[year_class] = np.append(HEAT_nres[year_class], self.heat_per_area_nres[run][year_class]) # plot histograms ### RESIDENTIAL ###### U-value [MW/K] figname = '{}/histU_res.png'.format(self.result_dir) UrbanHeatPro.plot_histogram_table(3, U_res, 'U-value [MW/K]', figname, factor = 1e6, figsize = (30, 25)) ###### U-value [MW/K] figname = '{}/histC_res.png'.format(self.result_dir) UrbanHeatPro.plot_histogram_table(3, C_res, 'Thermal mass [GJ/K]', figname, factor = 1e9, figsize = (30, 25)) ###### Tau [h] figname = '{}/histTau_res.png'.format(self.result_dir) UrbanHeatPro.plot_histogram_table(3, TAU_res, 'Tau [h]', figname, factor = 3600, figsize = (30, 25)) ###### Space heating demand per unit area [kWh/m2] figname = '{}/histSHD_perUnitArea_res.png'.format(self.result_dir) UrbanHeatPro.plot_histogram_table(3, SH_res, 'Energy [kWh/m2]', figname, factor = 1e3, figsize = (30, 25)) ###### Hot water demand per unit area [kWh/m2] figname = '{}/histHWD_perUnitArea_res.png'.format(self.result_dir) UrbanHeatPro.plot_histogram_table(3, HW_res, 'Energy [kWh/m2]', figname, factor = 1e3, figsize = (30, 25)) ###### Total heat demand per unit area [kWh/m2] figname = '{}/histHeat_perUnitArea_res.png'.format(self.result_dir) UrbanHeatPro.plot_histogram_table(3, HEAT_res, 'Energy [kWh/m2]', figname, factor = 1e3, figsize = (30, 25)) ### NON-RESIDENTIAL ###### U-value [MW/K] figname = '{}/histU_nres.png'.format(self.result_dir) UrbanHeatPro.plot_histogram_table(0, U_nres, 'U-value [MW/K]', figname, factor = 1e6, figsize = (30, 25)) ###### U-value [MW/K] figname = '{}/histC_nres.png'.format(self.result_dir) UrbanHeatPro.plot_histogram_table(0, C_nres, 'Thermal mass [GJ/K]', figname, factor = 1e9, figsize = (30, 25)) ###### Tau [h] figname = '{}/histTau_nres.png'.format(self.result_dir) UrbanHeatPro.plot_histogram_table(0, TAU_nres, 'Tau [h]', figname, factor = 3600, figsize = (30, 25)) ###### Space heating demand per unit area [kWh/m2] figname = '{}/histSHD_perUnitArea_nres.png'.format(self.result_dir) UrbanHeatPro.plot_histogram_table(0, SH_nres, 'Energy [kWh/m2]', figname, factor = 1e3, figsize = (30, 25)) ###### Hot water demand per unit area [kWh/m2] figname = '{}/histHWD_perUnitArea_nres.png'.format(self.result_dir) UrbanHeatPro.plot_histogram_table(0, HW_nres, 'Energy [kWh/m2]', figname, factor = 1e3, figsize = (30, 25)) ###### Total heat demand per unit area [kWh/m2] figname = '{}/histHeat_perUnitArea_nres.png'.format(self.result_dir) UrbanHeatPro.plot_histogram_table(0, HEAT_nres, 'Energy [kWh/m2]', figname, factor = 1e3, figsize = (30, 25))
def analyze_thermal_properties_per_run(self, run, result_dir_run): """ Extracts data from object City and plots a histogram showing the values of the thermal properties for all buildings in the city. Buildings are classified according to year construction class and building type. Analyzed thermal parameters are: U-value [W/K] Thermal mass [J/K] Tau [s] Space heat demand per unit area [Wh/m2] Hot water demand per unit area [Wh/m2] Total heat demand per unit area [Wh/m2] """ # extract data from City object for year_class in range(10): for btype in range(4): # extract all buildings B with specific year_class, btype and use c0 = self.my_city.energy_per_building[:, 1] == 3 # RESIDENTIAL c1 = self.my_city.energy_per_building[:, 2] == year_class c2 = self.my_city.energy_per_building[:, 3] == btype B = self.my_city.energy_per_building[c0 * c1 * c2] # U-value [W/K] self.u_res[run][year_class][btype] = np.append(self.u_res[run][year_class][btype], \ B[:, 13]) # Thermal mass [J/K] self.c_res[run][year_class][btype] = np.append(self.c_res[run][year_class][btype], \ B[:, 14]) # Tau [s] self.tau_res[run][year_class][btype] = np.append(self.tau_res[run][year_class][btype], \ B[:, 15]) # Space heat demand per unit area [Wh/m2] self.sh_per_area_res[run][year_class][btype] = np.append(self.sh_per_area_res[run][year_class][btype], \ (B[:, 16] / B[:, 5])) # Hot water demand per unit area [Wh/m2] self.hw_per_area_res[run][year_class][btype] = np.append(self.hw_per_area_res[run][year_class][btype], \ (B[:, 17] / B[:, 5])) # Total heat demand per unit area [Wh/m2] self.heat_per_area_res[run][year_class][btype] = np.append(self.heat_per_area_res[run][year_class][btype], \ (B[:, 18] / B[:, 5])) for year_class in range(5): # extract all buildings B with specific year_class, btype and use C0 = self.my_city.energy_per_building[:, 1] != 3 # NON-RESIDENTIAL c1 = self.my_city.energy_per_building[:, 2] == year_class B = self.my_city.energy_per_building[c0 * c1] # U-value [W/K] self.u_nres[run][year_class] = np.append(self.u_nres[run][year_class], B[:, 13]) # Thermal mass [J/K] self.c_nres[run][year_class] = np.append(self.c_nres[run][year_class], B[:, 14]) # Tau [s] self.tau_nres[run][year_class] = np.append(self.tau_nres[run][year_class], B[:, 15]) # Space heat demand per unit area [Wh/m2] self.sh_per_area_nres[run][year_class] = np.append(self.sh_per_area_nres[run][year_class], \ (B[:, 16] / B[:, 5])) # Hot water demand per unit area [Wh/m2] self.hw_per_area_nres[run][year_class] = np.append(self.hw_per_area_nres[run][year_class], \ (B[:, 17] / B[:, 5])) # Total heat demand per unit area [Wh/m2] self.heat_per_area_nres[run][year_class] = np.append(self.heat_per_area_nres[run][year_class], \ (B[:, 18] / B[:, 5])) # plot histograms per run ### RESIDENTIAL ###### U-value [MW/K] figname = '{}/histU_res_{}.png'.format(result_dir_run, run) UrbanHeatPro.plot_histogram_table(3, self.u_res[run], 'U-value [MW/K]', figname, factor = 1e6, figsize = (30, 25)) ###### U-value [MW/K] figname = '{}/histC_res_{}.png'.format(result_dir_run, run) UrbanHeatPro.plot_histogram_table(3, self.c_res[run], 'Thermal mass [GJ/K]', figname, factor = 1e9, figsize = (30, 25)) ###### Tau [h] figname = '{}/histTau_res_{}.png'.format(result_dir_run, run) UrbanHeatPro.plot_histogram_table(3, self.tau_res[run], 'Tau [h]', figname, factor = 3600, figsize = (30, 25)) ###### Space heating demand per unit area [kWh/m2] figname = '{}/histSHD_perUnitArea_res_{}.png'.format(result_dir_run, run) UrbanHeatPro.plot_histogram_table(3, self.sh_per_area_res[run], 'Energy [kWh/m2]', figname, factor = 1e3, figsize = (30, 25)) ###### Hot water demand per unit area [kWh/m2] figname = '{}/histHWD_perUnitArea_res_{}.png'.format(result_dir_run, run) UrbanHeatPro.plot_histogram_table(3, self.hw_per_area_res[run], 'Energy [kWh/m2]', figname, factor = 1e3, figsize = (30, 25)) ###### Total heat demand per unit area [kWh/m2] figname = '{}/histHeat_perUnitArea_res_{}.png'.format(result_dir_run, run) UrbanHeatPro.plot_histogram_table(3, self.heat_per_area_res[run], 'Energy [kWh/m2]', figname, factor = 1e3, figsize = (30, 25)) ### NON-RESIDENTIAL ###### U-value [MW/K] figname = '{}/histU_nres_{}.png'.format(result_dir_run, run) UrbanHeatPro.plot_histogram_table(0, self.u_nres[run], 'U-value [MW/K]', figname, factor = 1e6, figsize = (30, 25)) ###### U-value [MW/K] figname = '{}/histC_nres_{}.png'.format(result_dir_run, run) UrbanHeatPro.plot_histogram_table(0, self.c_nres[run], 'Thermal mass [GJ/K]', figname, factor = 1e9, figsize = (30, 25)) ###### Tau [h] figname = '{}/histTau_nres_{}.png'.format(result_dir_run, run) UrbanHeatPro.plot_histogram_table(0, self.tau_nres[run], 'Tau [h]', figname, factor = 3600, figsize = (30, 25)) ###### Space heating demand per unit area [kWh/m2] figname = '{}/histSHD_perUnitArea_nres_{}.png'.format(result_dir_run, run) UrbanHeatPro.plot_histogram_table(0, self.sh_per_area_nres[run], 'Energy [kWh/m2]', figname, factor = 1e3, figsize = (30, 25)) ###### Hot water demand per unit area [kWh/m2] figname = '{}/histHWD_perUnitArea_nres_{}.png'.format(result_dir_run, run) UrbanHeatPro.plot_histogram_table(0, self.hw_per_area_nres[run], 'Energy [kWh/m2]', figname, factor = 1e3, figsize = (30, 25)) ###### Total heat demand per unit area [kWh/m2] figname = '{}/histHeat_perUnitArea_nres_{}.png'.format(result_dir_run, run) UrbanHeatPro.plot_histogram_table(0, self.heat_per_area_nres[run], 'Energy [kWh/m2]', figname, factor = 1e3, figsize = (30, 25))