def distribuition_costs(pixT, DH_threshold, dist_grid_cost, out_raster_hdm_last_year, out_raster_maxDHdem, out_raster_invest_Euro, out_raster_coh_area_bool, out_raster_labels, struct=np.ones((3, 3))): rm_file(out_raster_coh_area_bool, out_raster_labels) invest_Euro_arr = raster_array(out_raster_invest_Euro) maxDHdem_arr = raster_array(out_raster_maxDHdem) heat_density_map_last_year, geo_transform = raster_array( out_raster_hdm_last_year, return_gt=True) rast_origin = geo_transform[0], geo_transform[3] coh_areas = np.zeros_like(maxDHdem_arr, 'int8') reg_filter = maxDHdem_arr.astype(bool).astype('int8') # DH_threshold in MWH DH_threshold_MWh = DH_threshold * 1000 for pix_threshold in pixT: # calculate coherent regions with given thresholds and cut them to # LAU2 levels # DH_Regions: boolean array showing DH regions DH_Regions, gt = DHP.DHReg(heat_density_map_last_year, pix_threshold, DH_threshold, rast_origin) # multiplication with reg_filter required to follow out_raster_maxDHdem # pattern and separate connection of regions with pixels that have # value of zero in out_raster_maxDHdem result = DH_Regions.astype(int) * reg_filter labels, nr_coherent = measurements.label(result, structure=struct) if nr_coherent == 0: break for i in range(1, nr_coherent + 1): temp = labels == i q = np.sum(maxDHdem_arr[temp]) q_inv = np.sum(invest_Euro_arr[temp]) q_spec_cost = q_inv / q if q_spec_cost <= dist_grid_cost and q >= DH_threshold_MWh: coh_areas[temp] = 1 heat_density_map_last_year[temp] = 0 labels = None nr_coherent = None labels, numLabels = measurements.label(coh_areas, structure=struct) CM19.main(out_raster_coh_area_bool, geo_transform, 'int8', coh_areas) CM19.main(out_raster_labels, geo_transform, "int16", labels) return numLabels
def distribuition_costs(invest_Euro, maxDHdem, features_path, hdm_1st, hdm_last, MS_1st, pixT, DHT, costT, coh_area_raster, hdm_dh_reg_last_year, label_raster, struct=np.ones((3, 3))): rm_file(coh_area_raster, hdm_dh_reg_last_year, label_raster) invest_Euro_arr = raster_array(invest_Euro) maxDHdem_arr = raster_array(maxDHdem) hdm_arr, geo_transform = raster_array(hdm_last, return_gt=True) rast_origin = geo_transform[0], geo_transform[3] coh_areas = np.zeros_like(maxDHdem_arr, 'int8') reg_filter = maxDHdem_arr.astype(bool).astype('int8') for pix_threshold in pixT: # calculate coherent regions with given thresholds and cut them to # LAU2 levels DH_Regions = CM4.main(hdm_arr, features_path, pix_threshold, DHT, None, rast_origin, only_return_areas=True) # multiplication with reg_filter required to follow maxDHdem # pattern and separate connection of regions with pixels that have # value of zero in maxDHdem result = DH_Regions.astype(int) * reg_filter labels, nr_coherent = measurements.label(result, structure=struct) if nr_coherent == 0: break for i in range(1, nr_coherent + 1): temp = labels == i q = np.sum(maxDHdem_arr[temp]) q_inv = np.sum(invest_Euro_arr[temp]) q_spec_cost = q_inv / q if q_spec_cost <= costT and q >= DHT: coh_areas[temp] = 1 hdm_arr[temp] = 0 labels = None nr_coherent = None hdm_last_arr = raster_array(hdm_last) hdm_1st_arr = raster_array(hdm_1st) labels, numLabels = measurements.label(coh_areas, structure=struct) if numLabels == 0: raise ValueError('For the provided grid cost ceiling, no district ' 'heating potential area can be realized!') if numLabels > 100: raise ValueError('For the given scenario, we found more than 100 ' 'coherent areas. Please reduce the size of your ' 'selection and run the scenario again!') hdm_in_dh_reg = hdm_last_arr * coh_areas CM19.main(coh_area_raster, geo_transform, 'int8', coh_areas) CM19.main(hdm_dh_reg_last_year, geo_transform, "float64", hdm_in_dh_reg) CM19.main(label_raster, geo_transform, "int16", labels) # average demand in dh regions: sum_demand/sum_area_of_dhReg # MWh/ha ave_dem_dh_reg = np.sum(hdm_in_dh_reg) / np.sum(coh_areas)
def main(investment_start_year, investment_last_year, depreciation_time, accumulated_energy_saving, dh_connection_rate_first_year, dh_connection_rate_last_year, interest_rate, grid_cost_ceiling, c1, c2, full_load_hours, mip_gap, in_raster_gfa, in_raster_hdm, out_raster_maxDHdem, out_raster_economic_maxDHdem, out_raster_invest_Euro, out_raster_hdm_last_year, out_raster_dist_pipe_length, out_raster_coh_area_bool, out_raster_labels, out_shp_prelabel, out_shp_label, out_shp_edges, out_shp_nodes, out_csv_solution, output_directory): """ Default parameters: grid_factor: grid factor of 1.05 shows the ratio of total grid costs to distribtion grid costs and is set based on previously run sensitivity analyses as well as other studies in the literature. pixT: pixel threshold in MWh/ha DH_threshold: DH area threshold in GWh/year just for filtering all the low demand pixels. trans_line_cap_cost: transmission line cost: power[MW], transmission line cost[EUR/m] """ # test input raster in_raster_hdm_arr = raster_array(in_raster_hdm) if len(np.nonzero(in_raster_hdm_arr)[0]) == 0: in_raster_hdm_arr = None covered_demand, dist_inv, dist_spec_cost, trans_inv, \ trans_spec_cost, trans_line_length, dist_pipe_len, \ heat_dem_1st, heat_dem_last, n_coh_areas, \ n_coh_areas_selected = np.zeros(11) opt_term_cond = False numLabels = 0 output_summary = summary(covered_demand, dist_inv, dist_spec_cost, trans_inv, trans_spec_cost, trans_line_length, dist_pipe_len, heat_dem_1st, heat_dem_last, n_coh_areas, n_coh_areas_selected, opt_term_cond, numLabels) return output_summary, opt_term_cond, edge_list in_raster_hdm_arr = None grid_factor = 1.05 pixT = 10 * np.arange(1, 135, 0.1) # DH Threshold in GWh/year DH_threshold = 1 trans_line_cap_cost = np.array([[0, 0], [0.2, 195], [0.3, 206], [0.6, 220], [1.2, 240], [1.9, 261], [3.6, 288], [6.1, 323], [9.8, 357], [20, 426], [45, 564], [75, 701], [125, 839], [190, 976], [400, 1418], [700, 2050], [1000, 2683]]) ''' trans_line_cap_cost = np.array([[0, 0], [0.2, 195], [0.3, 206], [0.6, 220], [1.2, 240], [1.9, 261], [3.6, 288], [6.1, 323], [9.8, 357], [20, 426], [45, 564], [75, 701], [125, 839], [190, 976], [19000, 97600]]) ''' dist_grid_cost = float(grid_cost_ceiling) / float(grid_factor) # f2: calculate pixel based values f2_output_layers = [ out_raster_maxDHdem, out_raster_invest_Euro, out_raster_hdm_last_year, out_raster_dist_pipe_length ] dh_demand(c1, c2, in_raster_gfa, in_raster_hdm, investment_start_year, investment_last_year, accumulated_energy_saving, dh_connection_rate_first_year, dh_connection_rate_last_year, depreciation_time, interest_rate, f2_output_layers) # f3: Determination of coherent areas based on the grid cost threshold. numLabels = distribuition_costs(pixT, DH_threshold, dist_grid_cost, out_raster_hdm_last_year, out_raster_maxDHdem, out_raster_invest_Euro, out_raster_coh_area_bool, out_raster_labels) edge_list = [] if numLabels > 0 and numLabels < 70: # numLabels = 0 : the grid cost ceiling is too low. # numLabels > 100: too many coherent areas were detected! # f4: pre-steps for providing input to the optimization function including # calling various functions for calculating distance between coherent # areas, optimization module, illustrating the transmission lines, # polygonize the coherent areas. (covered_demand, dist_inv, dist_spec_cost, trans_inv, trans_spec_cost, trans_line_length), dist_pipe_len, heat_dem_1st, \ heat_dem_last, n_coh_areas, \ n_coh_areas_selected, \ opt_term_cond, edge_list = pre_opt(depreciation_time, interest_rate, grid_cost_ceiling, trans_line_cap_cost, full_load_hours, mip_gap, in_raster_hdm, out_raster_coh_area_bool, out_raster_hdm_last_year, out_raster_dist_pipe_length, out_raster_maxDHdem, out_raster_economic_maxDHdem, out_raster_labels, out_raster_invest_Euro, out_shp_prelabel, out_shp_label, out_shp_edges, out_shp_nodes, out_csv_solution, output_directory, polygonize_region=True) print("pre_opt") else: covered_demand, dist_inv, dist_spec_cost, trans_inv, \ trans_spec_cost, trans_line_length, dist_pipe_len, \ heat_dem_1st, heat_dem_last, n_coh_areas, \ n_coh_areas_selected = np.zeros(11) opt_term_cond = False # f9: returns the summary of results in a dictionary format output_summary = summary(covered_demand, dist_inv, dist_spec_cost, trans_inv, trans_spec_cost, trans_line_length, dist_pipe_len, heat_dem_1st, heat_dem_last, n_coh_areas, n_coh_areas_selected, opt_term_cond, numLabels) return output_summary, opt_term_cond, edge_list
def pre_opt(depreciation_time, interest_rate, grid_cost_ceiling, trans_line_cap_cost, full_load_hours, mip_gap, in_raster_hdm, out_raster_coh_area_bool, out_raster_hdm_last_year, out_raster_dist_pipe_length, out_raster_maxDHdem, out_raster_economic_maxDHdem, out_raster_labels, out_raster_invest_Euro, out_shp_prelabel, out_shp_label, out_shp_edges, out_shp_nodes, out_csv_solution, output_directory, polygonize_region=False): hdm_arr, geoTrans = raster_array(out_raster_hdm_last_year, return_gt=True) labels = raster_array(out_raster_labels, 'int16') nr_coherent = np.max(labels) labels_copy = np.copy(labels) distance_matrix, row_from_label, col_from_label, \ row_to_label, col_to_label = feature_dist(labels) total_pipe_length_arr = raster_array(out_raster_dist_pipe_length) hdm_1st_arr = raster_array(in_raster_hdm) dist_invest_arr = raster_array(out_raster_invest_Euro) maxDHdem_arr = raster_array(out_raster_maxDHdem) # prepare dataframe for final answers. heat_dem_coh_1st = np.zeros((nr_coherent)) heat_dem_coh_last = np.zeros((nr_coherent)) heat_dem_spec_area = np.zeros((nr_coherent)) dist_pipe_len = np.zeros((nr_coherent)) q = np.zeros((nr_coherent)) q_inv = np.zeros((nr_coherent)) q_spec_cost = np.zeros((nr_coherent)) area_coh_area = np.zeros((nr_coherent)) for i in range(1, nr_coherent + 1): j = i - 1 temp = labels_copy == i # in hectare area_coh_area[j] = np.sum(temp) heat_dem_coh_1st[j] = np.sum(hdm_1st_arr[temp]) heat_dem_coh_last[j] = np.sum(hdm_arr[temp]) # pipe length raster is in m/m2 and for each pixel needs a factor 10000 # for meter and factor 1e-3 for km. Overal factor 10 to get it in km dist_pipe_len[j] = np.sum(total_pipe_length_arr[temp]) * 10 q[j] = np.sum(maxDHdem_arr[temp]) q_inv[j] = np.sum(dist_invest_arr[temp]) q_spec_cost[j] = q_inv[j] / q[j] # MWh/km2 heat_dem_spec_area[j] = heat_dem_coh_last[j] / area_coh_area[j] df = pd.DataFrame({ 'heat demand total 1st year [MWh]': heat_dem_coh_1st, 'heat demand total last year [MWh]': heat_dem_coh_last, 'max potential district heating through investment period [MWh]': q, 'specific heat demand total 1st year [MWh/ha]': heat_dem_spec_area, 'distribution line length [km]': dist_pipe_len, 'distribution costs - annualized [EUR]': q_inv, 'distribution costs [EUR/MWh]': q_spec_cost, 'area [ha]': area_coh_area }) ''' Dimension DN Water flow m/s Capacity MW Cost EUR/m Reference: GIS based analysis of future district heating in Denmark Author: Steffan Nielsen, Bernd Moeller ''' if interest_rate > 0: annuity_factor = (interest_rate * (1 + interest_rate)**depreciation_time) / ( (1 + interest_rate)**depreciation_time - 1) else: annuity_factor = 1 ''' tl_cost_copy = np.copy(trans_line_cap_cost) temp_q = np.copy(q) power_to_add = temp_q[temp_q/full_load_hours > 190]/full_load_hours for item in power_to_add: for i in range(1, 5): temp_price = i * item / 190 * 976 tl_cost_copy = np.concatenate((tl_cost_copy, [[i * item, temp_price]])) tl_cost_copy = tl_cost_copy[tl_cost_copy[:, 0].argsort()] trans_line_cap_cost = np.copy(tl_cost_copy) ''' # consideration of annuity factor trans_line_cap_cost[:, 1] = trans_line_cap_cost[:, 1] * annuity_factor cost_matrix = trans_line_cap_cost[:, 1] pow_range_matrix = trans_line_cap_cost[:, 0] term_cond, dh, edge_list = optimize_dist(grid_cost_ceiling, cost_matrix, pow_range_matrix, distance_matrix, q, q_spec_cost, mip_gap) grid_cost_header = 'Connected at %0.2f EUR/MWh' % grid_cost_ceiling df[grid_cost_header] = dh[:-6] df['label'] = df.index + 1 headers = [ 'label', 'heat demand total 1st year [MWh]', 'heat demand total last year [MWh]', 'distribution costs [EUR/MWh]', 'specific heat demand total 1st year [MWh/ha]', 'distribution costs - annualized [EUR]', 'area [ha]', 'distribution line length [km]', grid_cost_header ] df = df[headers] df.to_csv(out_csv_solution) if polygonize_region and term_cond == True: economic_bool = dh[:-6] poly(heat_dem_coh_last, heat_dem_spec_area, q, q_spec_cost, economic_bool, area_coh_area, out_raster_coh_area_bool, out_raster_labels, out_raster_maxDHdem, out_raster_economic_maxDHdem, out_shp_prelabel, out_shp_label) node_label_list = np.arange(1, nr_coherent + 1) * dh[0:-6] if term_cond == True: if len(edge_list) > 0: edge_representation(row_from_label, col_from_label, row_to_label, col_to_label, distance_matrix, node_label_list, edge_list, geoTrans, out_shp_edges, out_shp_nodes, output_directory) sum_dist_pipeline = np.sum(dist_pipe_len * dh[:-6]) return dh[-6:], sum_dist_pipeline, np.sum(hdm_1st_arr), np.sum( hdm_arr), nr_coherent, np.sum(dh[:-6]), term_cond, edge_list
def pre_opt(coh_area_raster, grid_cost, output_dir, hdm_1st, hdm_last, total_pipe_length, maxDHdem_path, inShapefile, label_raster, invest_Euro, outPolygon, depr_time, r, sol_csv, epsg=3035, struct=np.ones((3, 3)), polygonize_region=False, full_load_hours=3000): ''' ######################################################## edge_folder_name = inShapefile.split('/')[-1][:-4] edge_folder_name = 'edges' edge_folder = output_dir + os.sep + edge_folder_name rm_mk_dir(edge_folder) ######################################################## ''' hdm_arr, geoTrans = raster_array(hdm_last, return_gt=True) labels = raster_array(label_raster, 'int16') nr_coherent = np.max(labels) labels_copy = np.copy(labels) distance_matrix, row_from_label, col_from_label, \ row_to_label, col_to_label = feature_dist(labels) ''' # in case of center-to-center distance use the following: distance_matrix = 100 * cdist(coords, coords, 'euclidean') ''' ########################################################################### ########################################################################### total_pipe_length_arr = raster_array(total_pipe_length) hdm_1st_arr = raster_array(hdm_1st) dist_invest_arr = raster_array(invest_Euro) maxDHdem_arr = raster_array(maxDHdem_path) # prepare dataframe for final answers heat_dem_coh_1st = np.zeros((nr_coherent)) heat_dem_coh_last = np.zeros((nr_coherent)) heat_dem_spec_area = np.zeros((nr_coherent)) dist_pipe_len = np.zeros((nr_coherent)) q = np.zeros((nr_coherent)) q_inv = np.zeros((nr_coherent)) q_spec_cost = np.zeros((nr_coherent)) area_coh_area = np.zeros((nr_coherent)) for i in range(1, nr_coherent + 1): j = i - 1 temp = labels_copy == i # in hectare area_coh_area[j] = np.sum(temp) heat_dem_coh_1st[j] = np.sum(hdm_1st_arr[temp]) heat_dem_coh_last[j] = np.sum(hdm_arr[temp]) # pipe length raster is in m/m2 and for each pixel needs a factor 10000 # for meter and factor 1e-3 for km. Overal factor 10 to get it in km dist_pipe_len[j] = np.sum(total_pipe_length_arr[temp]) * 10 q[j] = np.sum(maxDHdem_arr[temp]) q_inv[j] = np.sum(dist_invest_arr[temp]) q_spec_cost[j] = q_inv[j] / q[j] # MWh/km2 heat_dem_spec_area[j] = heat_dem_coh_last[j] / area_coh_area[j] df = pd.DataFrame({ 'heat demand total 1st year [MWh]': heat_dem_coh_1st, 'heat demand total last year [MWh]': heat_dem_coh_last, 'potential heat demand district heating [MWh]': q, 'specific heat demand total 1st year [MWh/km2]': heat_dem_spec_area, 'distribution line length [km]': dist_pipe_len, 'distribution costs [EUR]': q_inv, 'distribution costs [EUR/MWh]': q_spec_cost, 'area [km2]': area_coh_area }) ''' Dimension DN Water flow m/s Capacity MW Cost EUR/m Reference: GIS based analysis of future district heating in Denmark Author: Steffan Nielsen, Bernd Moeller Important Note: this is a simplified method for finding the diameter of the transmission lines. The capacity and therefore, the cost of a transmission line is set only considering two coherent areas. for calculation of the cost, 3000h of full load hours has been considered. ''' annuity_factor = (r * (1 + r)**depr_time) / ((1 + r)**depr_time - 1) # power[MW], transmission line cost[EUR/m] tl_cost = np.array([[0, 0], [0.2, 195], [0.3, 206], [0.6, 220], [1.2, 240], [1.9, 261], [3.6, 288], [6.1, 323], [9.8, 357], [20, 426], [45, 564], [75, 701], [125, 839], [190, 976], [19000, 97600]]) tl_cost_copy = np.copy(tl_cost) temp_q = np.copy(q) power_to_add = temp_q[temp_q / full_load_hours > 190] / full_load_hours for item in power_to_add: for i in range(1, 5): temp_price = i * item / 190 * 976 tl_cost_copy = np.concatenate( (tl_cost_copy, [[i * item, temp_price]])) ''' for i in range(tl_cost.shape[0]): temp_pow = (item + tl_cost[i, 0])/2 temp_price = temp_pow / 190 * 976 tl_cost_copy = np.concatenate((tl_cost_copy, [[temp_pow, temp_price]])) ''' tl_cost_copy = tl_cost_copy[tl_cost_copy[:, 0].argsort()] tl_cost = np.copy(tl_cost_copy) # consideration of annuity factor tl_cost[:, 1] = tl_cost[:, 1] * annuity_factor # term_cond, dh_filtered, edge_list_filtered = optimize_dist(grid_cost, distance_matrix_filtered, trans_line_cost_filtered, q_filtered, q_spec_cost_filtered) cost_matrix = tl_cost[:, 1] pow_range_matrix = tl_cost[:, 0] term_cond, dh, edge_list = optimize_dist(grid_cost, cost_matrix, pow_range_matrix, distance_matrix, q, q_spec_cost) grid_cost_header = 'Connected at %0.2f EUR/MWh' % grid_cost df[grid_cost_header] = dh[:-6] df['label'] = df.index + 1 headers = [ 'label', 'heat demand total 1st year [MWh]', 'heat demand total last year [MWh]', 'potential heat demand district heating [MWh]', 'distribution costs [EUR/MWh]', 'specific heat demand total 1st year [MWh/km2]', 'distribution costs [EUR]', 'area [km2]', 'distribution line length [km]', grid_cost_header ] df = df[headers] df.to_csv(sol_csv) if polygonize_region and term_cond: economic = dh[:-6] poly(coh_area_raster, label_raster, outPolygon, economic, heat_dem_coh_last, heat_dem_spec_area, q, q_spec_cost, area_coh_area) node_label_list = np.arange(1, nr_coherent + 1) * dh[0:-6] if term_cond: if len(edge_list) > 0: edge_folder = output_dir + os.sep + 'edges' edge_representation(row_from_label, col_from_label, row_to_label, col_to_label, distance_matrix, node_label_list, edge_list, geoTrans, edge_folder) # for the case center-to-center use the follwoing line instead! # edge_representation(label_raster, coords, distance_matrix, # node_label_list, edge_list, # edge_folder + os.sep + str(grid_cost)) ''' ######################################################################### ######################################################################### node_label_list = np.arange(1, nr_coherent+1) * dh[0: -6] if term_cond: if len(edge_list) > 0: edge_folder = output_dir + os.sep + 'edges' edge_representation_old(label_raster, coh_area_raster, distance_matrix, node_label_list, edge_list, edge_folder) # for the case center-to-center use the follwoing line instead! # edge_representation(label_raster, coords, distance_matrix, # node_label_list, edge_list, # edge_folder + os.sep + str(grid_cost)) ######################################################################### ######################################################################### ''' sum_dist_pipeline = np.sum(dist_pipe_len * dh[:-6]) calculated_total_trans_cost = 0 return dh[-6:], sum_dist_pipeline, np.sum(hdm_1st_arr), np.sum( hdm_arr), nr_coherent, np.sum(dh[:-6])