From eb26c4862706ed9bb7b6681c1a7ea6fcff2d8008 Mon Sep 17 00:00:00 2001 From: Majid Rezaei Date: Thu, 1 Aug 2024 11:39:05 -0400 Subject: [PATCH] feature: add pipe sizing to dhn analysis --- district_heating_network.py | 111 +++ input_files/pipe_data.json | 191 +++++ main.py | 1 + .../district_heating_factory.py | 238 +++++- .../district_heating_network_creator.py | 83 ++- .../geojson_graph_creator.py | 54 -- .../simultinity_factor.py | 80 --- simulation_result_test.py | 54 -- work_in_progress.ipynb | 675 ------------------ 9 files changed, 591 insertions(+), 896 deletions(-) create mode 100644 district_heating_network.py create mode 100644 input_files/pipe_data.json delete mode 100644 scripts/district_heating_network/geojson_graph_creator.py delete mode 100644 scripts/district_heating_network/simultinity_factor.py delete mode 100644 simulation_result_test.py delete mode 100644 work_in_progress.ipynb diff --git a/district_heating_network.py b/district_heating_network.py new file mode 100644 index 00000000..66d332d4 --- /dev/null +++ b/district_heating_network.py @@ -0,0 +1,111 @@ +from scripts.district_heating_network.directory_manager import DirectoryManager +import subprocess +from scripts.ep_run_enrich import energy_plus_workflow +from hub.imports.geometry_factory import GeometryFactory +from hub.helpers.dictionaries import Dictionaries +from hub.imports.construction_factory import ConstructionFactory +from hub.imports.usage_factory import UsageFactory +from hub.imports.weather_factory import WeatherFactory +from hub.imports.results_factory import ResultFactory +from scripts.energy_system_retrofit_report import EnergySystemRetrofitReport +from scripts.geojson_creator import process_geojson +from scripts import random_assignation +from hub.imports.energy_systems_factory import EnergySystemsFactory +from scripts.energy_system_sizing import SystemSizing +from scripts.solar_angles import CitySolarAngles +from scripts.pv_sizing_and_simulation import PVSizingSimulation +from scripts.energy_system_retrofit_results import consumption_data, cost_data +from scripts.energy_system_sizing_and_simulation_factory import EnergySystemsSimulationFactory +from scripts.costs.cost import Cost +from scripts.costs.constants import SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, SYSTEM_RETROFIT_AND_PV, CURRENT_STATUS +import hub.helpers.constants as cte +from hub.exports.exports_factory import ExportsFactory +from scripts.pv_feasibility import pv_feasibility +import matplotlib.pyplot as plt +import numpy as np +from scripts.district_heating_network.district_heating_network_creator import DistrictHeatingNetworkCreator +from scripts.district_heating_network.district_heating_factory import DistrictHeatingFactory +import json + +#%% -------------------------------------------------------------------------------------------------------------------- +# Manage File Path +base_path = "./" +dir_manager = DirectoryManager(base_path) + +# Input files directory +input_files_path = dir_manager.create_directory('input_files') +geojson_file_path = input_files_path / 'output_buildings.geojson' +pipe_data_file = input_files_path / 'pipe_data.json' + +# Output files directory +output_path = dir_manager.create_directory('out_files') + +# Subdirectories for output files +energy_plus_output_path = dir_manager.create_directory('out_files/energy_plus_outputs') +simulation_results_path = dir_manager.create_directory('out_files/simulation_results') +sra_output_path = dir_manager.create_directory('out_files/sra_outputs') +cost_analysis_output_path = dir_manager.create_directory('out_files/cost_analysis') + +#%% -------------------------------------------------------------------------------------------------------------------- +# Area Under Study +location = [45.4934614681437, -73.57982834742518] + +#%% -------------------------------------------------------------------------------------------------------------------- +# Create geojson of buildings +process_geojson(x=location[1], y=location[0], diff=0.001) + +#%% -------------------------------------------------------------------------------------------------------------------- +# Create ciry and run energyplus workflow +city = GeometryFactory(file_type='geojson', + path=geojson_file_path, + height_field='height', + year_of_construction_field='year_of_construction', + function_field='function', + function_to_hub=Dictionaries().montreal_function_to_hub_function).city +ConstructionFactory('nrcan', city).enrich() +UsageFactory('nrcan', city).enrich() +WeatherFactory('epw', city).enrich() + +# SRA +ExportsFactory('sra', city, output_path).export() +sra_path = (output_path / f'{city.name}_sra.xml').resolve() +subprocess.run(['sra', str(sra_path)]) +ResultFactory('sra', city, output_path).enrich() + +# EP Workflow +energy_plus_workflow(city, energy_plus_output_path) + +#%% -------------------------------------------------------------------------------------------------------------------- +# District Heating Network Creator +central_plant_locations = [(-73.57812571080625, 45.49499447346277)] # Add at least one location + +roads_file = "./input_files/roads.json" + +dhn_creator = DistrictHeatingNetworkCreator(geojson_file_path, roads_file, central_plant_locations) + +network_graph = dhn_creator.run() + +#%% -------------------------------------------------------------------------------------------------------------------- +# Pipe and pump sizing + +with open(pipe_data_file, 'r') as f: + pipe_data = json.load(f) + +factory = DistrictHeatingFactory( + city=city, + graph=network_graph, + supply_temperature=80 + 273, # in Kelvin + return_temperature=60 + 273, # in Kelvin + simultaneity_factor=0.9 +) + +factory.enrich() +factory.sizing() +factory.calculate_diameters_and_costs(pipe_data) +pipe_groups, total_cost = factory.analyze_costs() + +# Save the pipe groups with total costs to a CSV file +factory.save_pipe_groups_to_csv('pipe_groups.csv') + +#%% -------------------------------------------------------------------------------------------------------------------- + diff --git a/input_files/pipe_data.json b/input_files/pipe_data.json new file mode 100644 index 00000000..90a53cbf --- /dev/null +++ b/input_files/pipe_data.json @@ -0,0 +1,191 @@ +[ + { + "DN": 16, + "inner_diameter": 16.1, + "outer_diameter": 21.3, + "thickness": 2.6, + "cost_per_meter": 320 + }, + { + "DN": 20, + "inner_diameter": 21.7, + "outer_diameter": 26.9, + "thickness": 2.6, + "cost_per_meter": 320 + }, + { + "DN": 25, + "inner_diameter": 27.3, + "outer_diameter": 33.7, + "thickness": 3.2, + "cost_per_meter": 320 + }, + { + "DN": 32, + "inner_diameter": 37.2, + "outer_diameter": 42.4, + "thickness": 2.6, + "cost_per_meter": 350 + }, + { + "DN": 40, + "inner_diameter": 43.1, + "outer_diameter": 48.3, + "thickness": 2.6, + "cost_per_meter": 375 + }, + { + "DN": 50, + "inner_diameter": 54.5, + "outer_diameter": 60.3, + "thickness": 2.9, + "cost_per_meter": 400 + }, + { + "DN": 65, + "inner_diameter": 70.3, + "outer_diameter": 76.1, + "thickness": 2.9, + "cost_per_meter": 450 + }, + { + "DN": 80, + "inner_diameter": 82.5, + "outer_diameter": 88.9, + "thickness": 3.2, + "cost_per_meter": 480 + }, + { + "DN": 90, + "inner_diameter": 100.8, + "outer_diameter": 108, + "thickness": 3.6, + "cost_per_meter": 480 + }, + { + "DN": 100, + "inner_diameter": 107.1, + "outer_diameter": 114.3, + "thickness": 3.6, + "cost_per_meter": 550 + }, + { + "DN": 110, + "inner_diameter": 125.8, + "outer_diameter": 133, + "thickness": 3.6, + "cost_per_meter": 550 + }, + { + "DN": 125, + "inner_diameter": 132.5, + "outer_diameter": 139.7, + "thickness": 3.6, + "cost_per_meter": 630 + }, + { + "DN": 140, + "inner_diameter": 151, + "outer_diameter": 159, + "thickness": 4, + "cost_per_meter": 700 + }, + { + "DN": 150, + "inner_diameter": 160.3, + "outer_diameter": 168.3, + "thickness": 4, + "cost_per_meter": 700 + }, + { + "DN": 180, + "inner_diameter": 184.7, + "outer_diameter": 193.7, + "thickness": 4.5, + "cost_per_meter": 700 + }, + { + "DN": 200, + "inner_diameter": 210.1, + "outer_diameter": 219.1, + "thickness": 4.5, + "cost_per_meter": 860 + }, + { + "DN": 250, + "inner_diameter": 263, + "outer_diameter": 273, + "thickness": 5, + "cost_per_meter": 860 + }, + { + "DN": 300, + "inner_diameter": 312.7, + "outer_diameter": 323.9, + "thickness": 5.6, + "cost_per_meter": 860 + }, + { + "DN": 350, + "inner_diameter": 344.4, + "outer_diameter": 355.6, + "thickness": 5.6, + "cost_per_meter": 860 + }, + { + "DN": 400, + "inner_diameter": 393.8, + "outer_diameter": 406.4, + "thickness": 6.3, + "cost_per_meter": 860 + }, + { + "DN": 450, + "inner_diameter": 444.4, + "outer_diameter": 457, + "thickness": 6.3, + "cost_per_meter": 860 + }, + { + "DN": 500, + "inner_diameter": 495.4, + "outer_diameter": 508, + "thickness": 6.3, + "cost_per_meter": 860 + }, + { + "DN": 600, + "inner_diameter": 595.8, + "outer_diameter": 610, + "thickness": 7.1, + "cost_per_meter": 860 + }, + { + "DN": 700, + "inner_diameter": 696.8, + "outer_diameter": 711, + "thickness": 7.1, + "cost_per_meter": 860 + }, + { + "DN": 800, + "inner_diameter": 797, + "outer_diameter": 813, + "thickness": 8, + "cost_per_meter": 860 + }, + { + "DN": 900, + "inner_diameter": 894, + "outer_diameter": 914, + "thickness": 10, + "cost_per_meter": 860 + }, + { + "DN": 1000, + "inner_diameter": 996, + "outer_diameter": 1016, + "thickness": 10, + "cost_per_meter": 860 + } +] \ No newline at end of file diff --git a/main.py b/main.py index 63c73fbe..312345fe 100644 --- a/main.py +++ b/main.py @@ -25,6 +25,7 @@ from scripts.pv_feasibility import pv_feasibility import matplotlib.pyplot as plt from scripts.district_heating_network.district_heating_network_creator import DistrictHeatingNetworkCreator from scripts.district_heating_network.road_processor import road_processor +from scripts.district_heating_network.district_heating_factory import DistrictHeatingFactory base_path = Path(__file__).parent dir_manager = DirectoryManager(base_path) diff --git a/scripts/district_heating_network/district_heating_factory.py b/scripts/district_heating_network/district_heating_factory.py index 55a3785a..bb362d31 100644 --- a/scripts/district_heating_network/district_heating_factory.py +++ b/scripts/district_heating_network/district_heating_factory.py @@ -1,32 +1,248 @@ -import networkx as nx +import CoolProp.CoolProp as CP +import math import logging +import numpy as np +import csv + class DistrictHeatingFactory: """ DistrictHeatingFactory class + + This class is responsible for managing the district heating network, including + enriching the network graph with building data, calculating flow rates, + sizing pipes, and analyzing costs. """ - def __init__(self, city, graph): + def __init__(self, city, graph, supply_temperature, return_temperature, simultaneity_factor): + """ + Initialize the DistrictHeatingFactory object. + + :param city: The city object containing buildings and their heating demands. + :param graph: The network graph representing the district heating network. + :param supply_temperature: The supply temperature of the heating fluid in the network (°C). + :param return_temperature: The return temperature of the heating fluid in the network (°C). + :param simultaneity_factor: The simultaneity factor used to adjust flow rates for non-building pipes. + """ self._city = city self._network_graph = graph + self._supply_temperature = supply_temperature + self._return_temperature = return_temperature + self.simultaneity_factor = simultaneity_factor + self.fluid = "Water" # The fluid used in the heating network def enrich(self): """ - Enrich the network graph nodes with attributes from the city buildings. - """ + Enrich the network graph nodes with the whole building object from the city buildings. - for node in self._network_graph.nodes(data=True): - node_id, node_attrs = node + This method associates each building node in the network graph with its corresponding + building object from the city, allowing access to heating demand data during calculations. + """ + for node_id, node_attrs in self._network_graph.nodes(data=True): if node_attrs.get('type') == 'building': building_name = node_attrs.get('name') building_found = False for building in self._city.buildings: if building.name == building_name: - building_attrs = vars(building) - for attr, value in building_attrs.items(): - if attr not in self._network_graph.nodes[node_id]: - self._network_graph.nodes[node_id][attr] = value + self._network_graph.nodes[node_id]['building_obj'] = building building_found = True break if not building_found: - logging.error(msg=f"Building with name '{building_name}' not found in city.") \ No newline at end of file + logging.error(msg=f"Building with name '{building_name}' not found in city.") + + def calculate_flow_rates(self, A, Gext): + """ + Solve the linear system to find the flow rates in each branch. + + :param A: The incidence matrix representing the network connections. + :param Gext: The external flow rates for each node in the network. + :return: The calculated flow rates for each edge, or None if an error occurs. + """ + try: + G = np.linalg.lstsq(A, Gext, rcond=None)[0] + return G + except np.linalg.LinAlgError as e: + logging.error(f"Error solving the linear system: {e}") + return None + + def switch_nodes(self, A, edge_index, node_index, edge): + """ + Switch the in and out nodes for the given edge in the incidence matrix A. + + :param A: The incidence matrix representing the network connections. + :param edge_index: The index of edges in the incidence matrix. + :param node_index: The index of nodes in the incidence matrix. + :param edge: The edge (u, v) to switch. + """ + u, v = edge + i = node_index[u] + j = node_index[v] + k = edge_index[edge] + A[i, k], A[j, k] = -A[i, k], -A[j, k] + + def sizing(self): + """ + Calculate the hourly mass flow rates, assign them to the edges, and determine the pipe diameters. + + This method generates the flow rates for each hour, adjusting the incidence matrix as needed to + ensure all flow rates are positive. It also applies the simultaneity factor to non-building pipes. + """ + num_nodes = self._network_graph.number_of_nodes() + num_edges = self._network_graph.number_of_edges() + A = np.zeros((num_nodes, num_edges)) # Initialize incidence matrix + node_index = {node: i for i, node in enumerate(self._network_graph.nodes())} + edge_index = {edge: i for i, edge in enumerate(self._network_graph.edges())} + + # Initialize mass flow rate attribute for each edge + for u, v, data in self._network_graph.edges(data=True): + self._network_graph.edges[u, v]['mass_flow_rate'] = {"hour": [], "peak": None} + + # Get the length of the hourly demand for the first building (assuming all buildings have the same length) + building = next(iter(self._city.buildings)) + num_hours = len(building.heating_demand['hour']) + + # Loop through each hour to generate Gext and solve AG = Gext + for hour in range(8760): + Gext = np.zeros(num_nodes) + + # Calculate the hourly mass flow rates for each edge and fill Gext + for edge in self._network_graph.edges(data=True): + u, v, data = edge + for node in [u, v]: + if self._network_graph.nodes[node].get('type') == 'building': + building = self._network_graph.nodes[node].get('building_obj') + if building and "hour" in building.heating_demand: + hourly_demand = building.heating_demand["hour"][hour] # Get demand for current hour + specific_heat_capacity = CP.PropsSI('C', 'T', (self._supply_temperature + self._return_temperature) / 2, + 'P', 101325, self.fluid) + mass_flow_rate = hourly_demand / 3600 / ( + specific_heat_capacity * (self._supply_temperature - self._return_temperature)) + Gext[node_index[node]] += mass_flow_rate + + # Update incidence matrix A + i = node_index[u] + j = node_index[v] + k = edge_index[(u, v)] + A[i, k] = 1 + A[j, k] = -1 + + # Solve for G (flow rates) + G = self.calculate_flow_rates(A, Gext) + if G is None: + return + + # Check for negative flow rates and adjust A accordingly + iterations = 0 + max_iterations = num_edges * 2 + while any(flow_rate < 0 for flow_rate in G) and iterations < max_iterations: + for idx, flow_rate in enumerate(G): + if flow_rate < 0: + G[idx] = -G[idx] # Invert the sign directly + iterations += 1 + + # Store the final flow rates in the edges for this hour + for idx, (edge, flow_rate) in enumerate(zip(self._network_graph.edges(), G)): + u, v = edge + if not (self._network_graph.nodes[u].get('type') == 'building' or self._network_graph.nodes[v].get( + 'type') == 'building'): + flow_rate *= self.simultaneity_factor # Apply simultaneity factor for non-building pipes + data = self._network_graph.edges[u, v] + data['mass_flow_rate']["hour"].append(flow_rate) # Append the calculated flow rate + + # Calculate the peak flow rate for each edge + for u, v, data in self._network_graph.edges(data=True): + data['mass_flow_rate']['peak'] = max(data['mass_flow_rate']['hour']) + + def calculate_diameters_and_costs(self, pipe_data): + """ + Calculate the diameter and costs of the pipes based on the maximum flow rate in each edge. + + :param pipe_data: A list of dictionaries containing pipe specifications, including inner diameters + and costs per meter for different nominal diameters (DN). + """ + for u, v, data in self._network_graph.edges(data=True): + flow_rate = data.get('mass_flow_rate', {}).get('peak') + if flow_rate is not None: + try: + # Calculate the density of the fluid + density = CP.PropsSI('D', 'T', (self._supply_temperature + self._return_temperature) / 2, 'P', 101325, + self.fluid) + velocity = 0.9 # Desired fluid velocity in m/s + # Calculate the diameter of the pipe required for the given flow rate + diameter = math.sqrt((4 * abs(flow_rate)) / (density * velocity * math.pi)) * 1000 # Convert to mm + self._network_graph.edges[u, v]['diameter'] = diameter + + # Match to the closest nominal diameter from the pipe data + closest_pipe = self.match_nominal_diameter(diameter, pipe_data) + self._network_graph.edges[u, v]['nominal_diameter'] = closest_pipe['DN'] + self._network_graph.edges[u, v]['cost_per_meter'] = closest_pipe['cost_per_meter'] + except Exception as e: + logging.error(f"Error calculating diameter or matching nominal diameter for edge ({u}, {v}): {e}") + + def match_nominal_diameter(self, diameter, pipe_data): + """ + Match the calculated diameter to the closest nominal diameter. + + :param diameter: The calculated diameter of the pipe (in mm). + :param pipe_data: A list of dictionaries containing pipe specifications, including inner diameters + and costs per meter for different nominal diameters (DN). + :return: The dictionary representing the pipe with the closest nominal diameter. + """ + closest_pipe = min(pipe_data, key=lambda x: abs(x['inner_diameter'] - diameter)) + return closest_pipe + + def analyze_costs(self): + """ + Analyze the costs based on the nominal diameters of the pipes. + + This method calculates the total cost of piping for each nominal diameter group + and returns a summary of the grouped pipes and the total cost. + + :return: A tuple containing the grouped pipe data and the total cost of piping. + """ + pipe_groups = {} + total_cost = 0 # Initialize total cost + + for u, v, data in self._network_graph.edges(data=True): + dn = data.get('nominal_diameter') + if dn is not None: + pipe_length = self._network_graph.edges[u, v].get('length', 1) * 2 # Multiply by 2 for supply and return + cost_per_meter = data.get('cost_per_meter', 0) + + if dn not in pipe_groups: + pipe_groups[dn] = { + 'DN': dn, + 'total_length': 0, + 'cost_per_meter': cost_per_meter + } + pipe_groups[dn]['total_length'] += pipe_length + group_cost = pipe_length * cost_per_meter + total_cost += group_cost # Add to total cost + + # Calculate total cost for each group + for group in pipe_groups.values(): + group['total_cost'] = group['total_length'] * group['cost_per_meter'] + + return pipe_groups, total_cost # Return both the grouped data and total cost + + def save_pipe_groups_to_csv(self, filename): + """ + Save the pipe groups and their total lengths to a CSV file. + + :param filename: The name of the CSV file to save the data to. + """ + pipe_groups, _ = self.analyze_costs() + + with open(filename, mode='w', newline='') as file: + writer = csv.writer(file) + # Write the header + writer.writerow(["Nominal Diameter (DN)", "Total Length (m)", "Cost per Meter", "Total Cost"]) + + # Write the data for each pipe group + for group in pipe_groups.values(): + writer.writerow([ + group['DN'], + group['total_length'], + group['cost_per_meter'], + group['total_cost'] + ]) diff --git a/scripts/district_heating_network/district_heating_network_creator.py b/scripts/district_heating_network/district_heating_network_creator.py index c83b3aa9..f7f5f0d4 100644 --- a/scripts/district_heating_network/district_heating_network_creator.py +++ b/scripts/district_heating_network/district_heating_network_creator.py @@ -8,9 +8,8 @@ from typing import List, Tuple from rtree import index # Configure logging -logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') -logging.getLogger('numexpr').setLevel(logging.ERROR) - +logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") +logging.getLogger("numexpr").setLevel(logging.ERROR) def haversine(lon1, lat1, lon2, lat2): """ @@ -30,17 +29,21 @@ def haversine(lon1, lat1, lon2, lat2): c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) return R * c # Output distance in meters - class DistrictHeatingNetworkCreator: - def __init__(self, buildings_file: str, roads_file: str): + def __init__(self, buildings_file: str, roads_file: str, central_plant_locations: List[Tuple[float, float]]): """ - Initialize the class with paths to the buildings and roads data files. + Initialize the class with paths to the buildings and roads data files, and central plant locations. :param buildings_file: Path to the GeoJSON file containing building data. :param roads_file: Path to the GeoJSON file containing roads data. + :param central_plant_locations: List of tuples containing the coordinates of central plant locations. """ + if len(central_plant_locations) < 1: + raise ValueError("The list of central plant locations must have at least one member.") + self.buildings_file = buildings_file self.roads_file = roads_file + self.central_plant_locations = central_plant_locations def run(self) -> nx.Graph: """ @@ -57,7 +60,8 @@ class DistrictHeatingNetworkCreator: self._iteratively_remove_edges() self._add_centroids_to_mst() self._convert_edge_weights_to_meters() - return self.final_mst + self._create_final_network_graph() + return self.network_graph except Exception as e: logging.error(f"Error during network creation: {e}") raise @@ -73,6 +77,7 @@ class DistrictHeatingNetworkCreator: self.centroids = [] self.building_names = [] + self.building_positions = [] buildings = city['features'] for building in buildings: coordinates = building['geometry']['coordinates'][0] @@ -80,6 +85,14 @@ class DistrictHeatingNetworkCreator: centroid = building_polygon.centroid self.centroids.append(centroid) self.building_names.append(str(building['id'])) + self.building_positions.append((centroid.x, centroid.y)) + + # Add central plant locations as centroids + for i, loc in enumerate(self.central_plant_locations, start=1): + centroid = Point(loc) + self.centroids.append(centroid) + self.building_names.append(f'central_plant_{i}') + self.building_positions.append((centroid.x, centroid.y)) # Load road data with open(self.roads_file, 'r') as file: @@ -184,7 +197,9 @@ class DistrictHeatingNetworkCreator: for line in self.cleaned_lines: coords = list(line.coords) for i in range(len(coords) - 1): - self.G.add_edge(coords[i], coords[i + 1], weight=Point(coords[i]).distance(Point(coords[i + 1]))) + u = coords[i] + v = coords[i + 1] + self.G.add_edge(u, v, weight=Point(coords[i]).distance(Point(coords[i + 1]))) except Exception as e: logging.error(f"Error creating graph: {e}") raise @@ -284,24 +299,22 @@ class DistrictHeatingNetworkCreator: """ try: for i, centroid in enumerate(self.centroids): - centroid_tuple = (centroid.x, centroid.y) building_name = self.building_names[i] - - # Add the centroid node with its attributes - self.final_mst.add_node(centroid_tuple, type='building', name=building_name) + pos = (centroid.x, centroid.y) + node_type = 'building' if 'central_plant' not in building_name else 'generation' + self.final_mst.add_node(pos, type=node_type, name=building_name, pos=pos) nearest_point = None min_distance = float('inf') for node in self.final_mst.nodes(): - if self.final_mst.nodes[node].get('type') != 'building': - node_point = Point(node) - distance = centroid.distance(node_point) + if self.final_mst.nodes[node].get('type') != 'building' and self.final_mst.nodes[node].get('type') != 'generation': + distance = centroid.distance(Point(node)) if distance < min_distance: min_distance = distance nearest_point = node if nearest_point: - self.final_mst.add_edge(centroid_tuple, nearest_point, weight=min_distance) + self.final_mst.add_edge(pos, nearest_point, weight=min_distance) except Exception as e: logging.error(f"Error adding centroids to MST: {e}") raise @@ -312,22 +325,48 @@ class DistrictHeatingNetworkCreator: """ try: for u, v, data in self.final_mst.edges(data=True): - lon1, lat1 = u - lon2, lat2 = v - distance = haversine(lon1, lat1, lon2, lat2) + distance = haversine(u[0], u[1], v[0], v[1]) self.final_mst[u][v]['weight'] = distance except Exception as e: logging.error(f"Error converting edge weights to meters: {e}") raise + def _create_final_network_graph(self): + """ + Create the final network graph with the required attributes from the final MST. + """ + self.network_graph = nx.Graph() + node_id = 1 + node_mapping = {} + for node in self.final_mst.nodes: + pos = node + if 'type' in self.final_mst.nodes[node]: + if self.final_mst.nodes[node]['type'] == 'building': + name = self.final_mst.nodes[node]['name'] + node_type = 'building' + elif self.final_mst.nodes[node]['type'] == 'generation': + name = self.final_mst.nodes[node]['name'] + node_type = 'generation' + else: + name = f'junction_{node_id}' + node_type = 'junction' + self.network_graph.add_node(node_id, name=name, type=node_type, pos=pos) + node_mapping[node] = node_id + node_id += 1 + for u, v, data in self.final_mst.edges(data=True): + u_new = node_mapping[u] + v_new = node_mapping[v] + length = data['weight'] + self.network_graph.add_edge(u_new, v_new, length=length) + def plot_network_graph(self): """ Plot the network graph using matplotlib and networkx. """ plt.figure(figsize=(15, 10)) - pos = {node: (node[0], node[1]) for node in self.final_mst.nodes()} - nx.draw_networkx_nodes(self.final_mst, pos, node_color='blue', node_size=50) - nx.draw_networkx_edges(self.final_mst, pos, edge_color='gray') + pos = {node: data['pos'] for node, data in self.network_graph.nodes(data=True)} + nx.draw_networkx_nodes(self.network_graph, pos, node_color='blue', node_size=50) + nx.draw_networkx_edges(self.network_graph, pos, edge_color='gray') plt.title('District Heating Network Graph') plt.axis('off') plt.show() diff --git a/scripts/district_heating_network/geojson_graph_creator.py b/scripts/district_heating_network/geojson_graph_creator.py deleted file mode 100644 index 407be813..00000000 --- a/scripts/district_heating_network/geojson_graph_creator.py +++ /dev/null @@ -1,54 +0,0 @@ -import json -from shapely import LineString, Point -import networkx as nx -from pathlib import Path - - -def networkx_to_geojson(graph: nx.Graph) -> Path: - """ - Convert a NetworkX graph to GeoJSON format. - - :param graph: A NetworkX graph. - :return: GeoJSON formatted dictionary. - """ - features = [] - - for u, v, data in graph.edges(data=True): - line = LineString([u, v]) - feature = { - "type": "Feature", - "geometry": { - "type": "LineString", - "coordinates": list(line.coords) - }, - "properties": { - "weight": data.get("weight", 1.0) - } - } - features.append(feature) - - for node, data in graph.nodes(data=True): - point = Point(node) - feature = { - "type": "Feature", - "geometry": { - "type": "Point", - "coordinates": list(point.coords)[0] - }, - "properties": { - "type": data.get("type", "unknown"), - "id": data.get("id", "N/A") - } - } - features.append(feature) - - geojson = { - "type": "FeatureCollection", - "features": features - } - - output_geojson_file = Path('./out_files/network_graph.geojson').resolve() - with open(output_geojson_file, 'w') as file: - json.dump(geojson, file, indent=4) - - return output_geojson_file diff --git a/scripts/district_heating_network/simultinity_factor.py b/scripts/district_heating_network/simultinity_factor.py deleted file mode 100644 index c97932b5..00000000 --- a/scripts/district_heating_network/simultinity_factor.py +++ /dev/null @@ -1,80 +0,0 @@ -import pandas as pd -import numpy as np - -class DemandShiftProcessor: - def __init__(self, city): - self.city = city - - def random_shift(self, series): - shift_amount = np.random.randint(0, round(0.005 * len(series))) - return series.shift(shift_amount).fillna(series.shift(shift_amount - len(series))) - - def process_demands(self): - heating_dfs = [] - cooling_dfs = [] - - for building in self.city.buildings: - heating_df = self.convert_building_to_dataframe(building, 'heating') - cooling_df = self.convert_building_to_dataframe(building, 'cooling') - heating_df.set_index('Date/Time', inplace=True) - cooling_df.set_index('Date/Time', inplace=True) - shifted_heating_demands = heating_df.apply(self.random_shift, axis=0) - shifted_cooling_demands = cooling_df.apply(self.random_shift, axis=0) - self.update_building_demands(building, shifted_heating_demands, 'heating') - self.update_building_demands(building, shifted_cooling_demands, 'cooling') - heating_dfs.append(shifted_heating_demands) - cooling_dfs.append(shifted_cooling_demands) - - combined_heating_df = pd.concat(heating_dfs, axis=1) - combined_cooling_df = pd.concat(cooling_dfs, axis=1) - self.calculate_and_set_simultaneity_factor(combined_heating_df, 'heating') - self.calculate_and_set_simultaneity_factor(combined_cooling_df, 'cooling') - - def convert_building_to_dataframe(self, building, demand_type): - if demand_type == 'heating': - data = { - "Date/Time": self.generate_date_time_index(), - "Heating_Demand": building.heating_demand["hour"] - } - else: # cooling - data = { - "Date/Time": self.generate_date_time_index(), - "Cooling_Demand": building.cooling_demand["hour"] - } - return pd.DataFrame(data) - - def generate_date_time_index(self): - # Generate hourly date time index for a full year in 2024 - date_range = pd.date_range(start="2013-01-01 00:00:00", end="2013-12-31 23:00:00", freq='H') - return date_range.strftime('%m/%d %H:%M:%S').tolist() - - def update_building_demands(self, building, shifted_demands, demand_type): - if demand_type == 'heating': - shifted_series = shifted_demands["Heating_Demand"] - building.heating_demand = self.calculate_new_demands(shifted_series) - else: # cooling - shifted_series = shifted_demands["Cooling_Demand"] - building.cooling_demand = self.calculate_new_demands(shifted_series) - - def calculate_new_demands(self, shifted_series): - new_demand = { - "hour": shifted_series.tolist(), - "month": self.calculate_monthly_demand(shifted_series), - "year": [shifted_series.sum()] - } - return new_demand - - def calculate_monthly_demand(self, series): - series.index = pd.to_datetime(series.index, format='%m/%d %H:%M:%S') - monthly_demand = series.resample('M').sum() - return monthly_demand.tolist() - - def calculate_and_set_simultaneity_factor(self, combined_df, demand_type): - total_demand_original = combined_df.sum(axis=1) - peak_total_demand_original = total_demand_original.max() - individual_peak_demands = combined_df.max(axis=0) - sum_individual_peak_demands = individual_peak_demands.sum() - if demand_type == 'heating': - self.city.simultaneity_factor_heating = peak_total_demand_original / sum_individual_peak_demands - else: # cooling - self.city.simultaneity_factor_cooling = peak_total_demand_original / sum_individual_peak_demands diff --git a/simulation_result_test.py b/simulation_result_test.py deleted file mode 100644 index 3d72ad8b..00000000 --- a/simulation_result_test.py +++ /dev/null @@ -1,54 +0,0 @@ -from pathlib import Path -import subprocess -from scripts.ep_run_enrich import energy_plus_workflow -from hub.imports.geometry_factory import GeometryFactory -from hub.helpers.dictionaries import Dictionaries -from hub.imports.construction_factory import ConstructionFactory -from hub.imports.usage_factory import UsageFactory -from hub.imports.weather_factory import WeatherFactory -from hub.imports.results_factory import ResultFactory -from scripts.energy_system_retrofit_report import EnergySystemRetrofitReport -from scripts.geojson_creator import process_geojson -from scripts import random_assignation -from hub.imports.energy_systems_factory import EnergySystemsFactory -from scripts.energy_system_sizing import SystemSizing -from scripts.solar_angles import CitySolarAngles -from scripts.pv_sizing_and_simulation import PVSizingSimulation -from scripts.energy_system_retrofit_results import consumption_data, cost_data -from scripts.energy_system_sizing_and_simulation_factory import EnergySystemsSimulationFactory -from scripts.costs.cost import Cost -from scripts.costs.constants import SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, SYSTEM_RETROFIT_AND_PV, CURRENT_STATUS -import hub.helpers.constants as cte -from hub.exports.exports_factory import ExportsFactory -from scripts.pv_feasibility import pv_feasibility - -# Specify the GeoJSON file path -input_files_path = (Path(__file__).parent / 'input_files') -input_files_path.mkdir(parents=True, exist_ok=True) -geojson_file = process_geojson(x=-73.5681295982132, y=45.49218262677643, diff=0.0001) -geojson_file_path = input_files_path / 'output_buildings.geojson' -output_path = (Path(__file__).parent / 'out_files').resolve() -output_path.mkdir(parents=True, exist_ok=True) -energy_plus_output_path = output_path / 'energy_plus_outputs' -energy_plus_output_path.mkdir(parents=True, exist_ok=True) -simulation_results_path = (Path(__file__).parent / 'out_files' / 'simulation_results').resolve() -simulation_results_path.mkdir(parents=True, exist_ok=True) -sra_output_path = output_path / 'sra_outputs' -sra_output_path.mkdir(parents=True, exist_ok=True) -cost_analysis_output_path = output_path / 'cost_analysis' -cost_analysis_output_path.mkdir(parents=True, exist_ok=True) -city = GeometryFactory(file_type='geojson', - path=geojson_file_path, - height_field='height', - year_of_construction_field='year_of_construction', - function_field='function', - function_to_hub=Dictionaries().montreal_function_to_hub_function).city -ConstructionFactory('nrcan', city).enrich() -UsageFactory('nrcan', city).enrich() -WeatherFactory('epw', city).enrich() -energy_plus_workflow(city, energy_plus_output_path) -random_assignation.call_random(city.buildings, random_assignation.residential_new_systems_percentage) -EnergySystemsFactory('montreal_future', city).enrich() -for building in city.buildings: - EnergySystemsSimulationFactory('archetype1', building=building, output_path=simulation_results_path).enrich() - diff --git a/work_in_progress.ipynb b/work_in_progress.ipynb deleted file mode 100644 index 0151fa6a..00000000 --- a/work_in_progress.ipynb +++ /dev/null @@ -1,675 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "id": "initial_id", - "metadata": { - "collapsed": true, - "ExecuteTime": { - "end_time": "2024-07-31T21:38:47.230085Z", - "start_time": "2024-07-31T21:38:47.206748Z" - } - }, - "source": [ - "from pathlib import Path\n", - "from scripts.district_heating_network.directory_manager import DirectoryManager\n", - "import subprocess\n", - "from scripts.ep_run_enrich import energy_plus_workflow\n", - "from hub.imports.geometry_factory import GeometryFactory\n", - "from hub.helpers.dictionaries import Dictionaries\n", - "from hub.imports.construction_factory import ConstructionFactory\n", - "from hub.imports.usage_factory import UsageFactory\n", - "from hub.imports.weather_factory import WeatherFactory\n", - "from hub.imports.results_factory import ResultFactory\n", - "from scripts.energy_system_retrofit_report import EnergySystemRetrofitReport\n", - "from scripts.geojson_creator import process_geojson\n", - "from scripts import random_assignation\n", - "from hub.imports.energy_systems_factory import EnergySystemsFactory\n", - "from scripts.energy_system_sizing import SystemSizing\n", - "from scripts.solar_angles import CitySolarAngles\n", - "from scripts.pv_sizing_and_simulation import PVSizingSimulation\n", - "from scripts.energy_system_retrofit_results import consumption_data, cost_data\n", - "from scripts.energy_system_sizing_and_simulation_factory import EnergySystemsSimulationFactory\n", - "from scripts.costs.cost import Cost\n", - "from scripts.costs.constants import SKIN_RETROFIT_AND_SYSTEM_RETROFIT_AND_PV, SYSTEM_RETROFIT_AND_PV, CURRENT_STATUS\n", - "import hub.helpers.constants as cte\n", - "from hub.exports.exports_factory import ExportsFactory\n", - "from scripts.pv_feasibility import pv_feasibility\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np" - ], - "outputs": [], - "execution_count": 110 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-31T21:38:47.861524Z", - "start_time": "2024-07-31T21:38:47.843529Z" - } - }, - "cell_type": "code", - "source": [ - "base_path = \"./\"\n", - "dir_manager = DirectoryManager(base_path)\n", - "\n", - "# Input files directory\n", - "input_files_path = dir_manager.create_directory('input_files')\n", - "geojson_file_path = input_files_path / 'output_buildings.geojson'\n", - "\n", - "# Output files directory\n", - "output_path = dir_manager.create_directory('out_files')\n", - "\n", - "# Subdirectories for output files\n", - "energy_plus_output_path = dir_manager.create_directory('out_files/energy_plus_outputs')\n", - "simulation_results_path = dir_manager.create_directory('out_files/simulation_results')\n", - "sra_output_path = dir_manager.create_directory('out_files/sra_outputs')\n", - "cost_analysis_output_path = dir_manager.create_directory('out_files/cost_analysis')" - ], - "id": "7d895f0e4ec2b851", - "outputs": [], - "execution_count": 111 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-31T21:39:02.661096Z", - "start_time": "2024-07-31T21:38:48.727802Z" - } - }, - "cell_type": "code", - "source": [ - "location = [45.53067276979674, -73.70234652694087]\n", - "process_geojson(x=location[1], y=location[0], diff=0.001)" - ], - "id": "20dfb8fa42189fc2", - "outputs": [ - { - "data": { - "text/plain": [ - "WindowsPath('C:/Users/ab_reza/Majid/Concordia/Repositories/energy_system_modelling_workflow/input_files/output_buildings.geojson')" - ] - }, - "execution_count": 112, - "metadata": {}, - "output_type": "execute_result" - } - ], - "execution_count": 112 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-31T21:39:02.992446Z", - "start_time": "2024-07-31T21:39:02.663422Z" - } - }, - "cell_type": "code", - "source": [ - "city = GeometryFactory(file_type='geojson',\n", - " path=geojson_file_path,\n", - " height_field='height',\n", - " year_of_construction_field='year_of_construction',\n", - " function_field='function',\n", - " function_to_hub=Dictionaries().montreal_function_to_hub_function).city" - ], - "id": "c03ae7cae09d4b21", - "outputs": [], - "execution_count": 113 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-31T21:39:03.340164Z", - "start_time": "2024-07-31T21:39:02.993466Z" - } - }, - "cell_type": "code", - "source": "ConstructionFactory('nrcan', city).enrich()", - "id": "c7d73638802e40d9", - "outputs": [], - "execution_count": 114 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-31T21:39:04.079698Z", - "start_time": "2024-07-31T21:39:03.342163Z" - } - }, - "cell_type": "code", - "source": "UsageFactory('nrcan', city).enrich()", - "id": "4a8e272413233cc9", - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Users\\ab_reza\\Majid\\Concordia\\Repositories\\energy_system_modelling_workflow\\hub\\catalog_factories\\usage\\comnet_catalog.py:193: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", - " usage_type = usage_parameters[0]\n" - ] - } - ], - "execution_count": 115 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-31T21:39:04.648022Z", - "start_time": "2024-07-31T21:39:04.081700Z" - } - }, - "cell_type": "code", - "source": "WeatherFactory('epw', city).enrich()", - "id": "f66c01cb42c33b64", - "outputs": [], - "execution_count": 116 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-31T21:40:39.688386Z", - "start_time": "2024-07-31T21:39:04.650024Z" - } - }, - "cell_type": "code", - "source": "energy_plus_workflow(city, energy_plus_output_path)", - "id": "c966b769566c173b", - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "exporting:\n", - " idf exported...\n", - "\r\n", - "C:/EnergyPlusV23-2-0\\energyplus.exe --weather C:\\Users\\ab_reza\\Majid\\Concordia\\Repositories\\energy_system_modelling_workflow\\hub\\data\\weather\\epw\\CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw --output-directory C:\\Users\\ab_reza\\Majid\\Concordia\\Repositories\\energy_system_modelling_workflow\\out_files\\energy_plus_outputs --idd C:\\Users\\ab_reza\\Majid\\Concordia\\Repositories\\energy_system_modelling_workflow\\hub\\exports\\building_energy\\idf_files\\Energy+.idd --expandobjects --readvars --output-prefix Laval_ C:\\Users\\ab_reza\\Majid\\Concordia\\Repositories\\energy_system_modelling_workflow\\out_files\\energy_plus_outputs\\Laval_602570.idf\r\n", - "\n" - ] - } - ], - "execution_count": 117 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-31T21:53:14.440222Z", - "start_time": "2024-07-31T21:53:10.290860Z" - } - }, - "cell_type": "code", - "source": [ - "from scripts.district_heating_network.district_heating_network_creator import DistrictHeatingNetworkCreator\n", - "from scripts.district_heating_network.road_processor import road_processor\n", - "from pathlib import Path\n", - "import time\n", - "from scripts.district_heating_network.geojson_graph_creator import networkx_to_geojson\n", - "roads_file = road_processor(location[1], location[0], 0.001)\n", - "\n", - "dhn_creator = DistrictHeatingNetworkCreator(geojson_file_path, roads_file)\n", - "\n", - "network_graph = dhn_creator.run()" - ], - "id": "8403846b0831b51d", - "outputs": [ - { - "ename": "AttributeError", - "evalue": "'Graph' object has no attribute 'building_names'", - "output_type": "error", - "traceback": [ - "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[1;31mAttributeError\u001B[0m Traceback (most recent call last)", - "Cell \u001B[1;32mIn[121], line 11\u001B[0m\n\u001B[0;32m 8\u001B[0m dhn_creator \u001B[38;5;241m=\u001B[39m DistrictHeatingNetworkCreator(geojson_file_path, roads_file)\n\u001B[0;32m 10\u001B[0m network_graph \u001B[38;5;241m=\u001B[39m dhn_creator\u001B[38;5;241m.\u001B[39mrun()\n\u001B[1;32m---> 11\u001B[0m \u001B[43mnetwork_graph\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mbuilding_names\u001B[49m\n", - "\u001B[1;31mAttributeError\u001B[0m: 'Graph' object has no attribute 'building_names'" - ] - } - ], - "execution_count": 121 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-31T21:43:05.521839Z", - "start_time": "2024-07-31T21:43:05.503748Z" - } - }, - "cell_type": "code", - "source": [ - "for node_id, attrs in network_graph.nodes(data=True):\n", - " print(f\"Node {node_id} has attributes: {list(attrs.keys())}\")" - ], - "id": "9c4c32ed4a5b5434", - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Node (-73.70263014634182, 45.52966550204674) has attributes: []\n", - "Node (-73.70252245592799, 45.52959782722166) has attributes: []\n", - "Node (-73.70277983402246, 45.52975956880018) has attributes: []\n", - "Node (-73.70292834674622, 45.52985289718704) has attributes: []\n", - "Node (-73.70299601156968, 45.52989541912497) has attributes: []\n", - "Node (-73.70304798829301, 45.52992808234479) has attributes: []\n", - "Node (-73.70315317772048, 45.52999418549968) has attributes: []\n", - "Node (-73.70322951375971, 45.530042156604246) has attributes: []\n", - "Node (-73.70334527410391, 45.53011490273612) has attributes: []\n", - "Node (-73.70388612860485, 45.530454786598085) has attributes: []\n", - "Node (-73.70321670301797, 45.53098320823811) has attributes: []\n", - "Node (-73.70309371940914, 45.53090572804479) has attributes: []\n", - "Node (-73.70336752508702, 45.53107818505422) has attributes: []\n", - "Node (-73.70300302780161, 45.53115122842582) has attributes: []\n", - "Node (-73.70298632291501, 45.53083806779961) has attributes: []\n", - "Node (-73.70284664272657, 45.53075006869057) has attributes: []\n", - "Node (-73.70282694240179, 45.530737657402696) has attributes: []\n", - "Node (-73.70268296446567, 45.530646950694454) has attributes: []\n", - "Node (-73.70262035905371, 45.53060750902034) has attributes: []\n", - "Node (-73.70250974072788, 45.53053781900757) has attributes: []\n", - "Node (-73.70248122664219, 45.530519855013075) has attributes: []\n", - "Node (-73.70237692791034, 45.53045414637121) has attributes: []\n", - "Node (-73.70241425825014, 45.52952983362164) has attributes: []\n", - "Node (-73.70258909924681, 45.53147671471601) has attributes: []\n", - "Node (-73.70246956317335, 45.531401341489406) has attributes: []\n", - "Node (-73.70281850395438, 45.53162108764596) has attributes: []\n", - "Node (-73.70235595692806, 45.53165968576366) has attributes: []\n", - "Node (-73.70235908646175, 45.53133168062488) has attributes: []\n", - "Node (-73.70226538550632, 45.5312725976791) has attributes: []\n", - "Node (-73.7022262934011, 45.531247948232114) has attributes: []\n", - "Node (-73.70218216283965, 45.53122012179686) has attributes: []\n", - "Node (-73.7020876584622, 45.53116053225497) has attributes: []\n", - "Node (-73.70208089954498, 45.53115627043355) has attributes: []\n", - "Node (-73.70195718026818, 45.531078259496624) has attributes: []\n", - "Node (-73.7019336727694, 45.53106343689135) has attributes: []\n", - "Node (-73.70183972286668, 45.53100419697237) has attributes: []\n", - "Node (-73.70182154258106, 45.53099273343045) has attributes: []\n", - "Node (-73.70170504466955, 45.530919275910655) has attributes: []\n", - "Node (-73.70169068527439, 45.5309102216234) has attributes: []\n", - "Node (-73.70191018896638, 45.53200952628766) has attributes: []\n", - "Node (-73.70343390828414, 45.5311199883841) has attributes: []\n", - "Node (-73.70308928370066, 45.53179149942939) has attributes: []\n", - "Node (-73.70154615235963, 45.53081908668964) has attributes: []\n", - "Node (-73.70149535566978, 45.53078705694076) has attributes: []\n", - "Node (-73.70139243548935, 45.530722160831516) has attributes: []\n", - "Node (-73.70235555653572, 45.5304406823149) has attributes: []\n", - "Node (-73.70223631048641, 45.530365556799865) has attributes: []\n", - "Node (-73.70218808966641, 45.53033517747947) has attributes: []\n", - "Node (-73.7020516180255, 45.53024919976893) has attributes: []\n", - "Node (-73.70202483520858, 45.530232326481084) has attributes: []\n", - "Node (-73.70189576536478, 45.53015101193401) has attributes: []\n", - "Node (-73.70188535693748, 45.53014445458083) has attributes: []\n", - "Node (-73.70176137113975, 45.53006634300427) has attributes: []\n", - "Node (-73.70171679336974, 45.53003825882077) has attributes: []\n", - "Node (-73.70161674578377, 45.52997522841877) has attributes: []\n", - "Node (-73.70157021391765, 45.52994591314646) has attributes: []\n", - "Node (-73.70145508528618, 45.52987338162208) has attributes: []\n", - "Node (-73.7015262783945, 45.53176766055835) has attributes: []\n", - "Node (-73.70142255824699, 45.531702316306436) has attributes: []\n", - "Node (-73.70132694890151, 45.53164208190352) has attributes: []\n", - "Node (-73.70249378379357, 45.529882494691094) has attributes: ['type', 'id']\n", - "Node (-73.70236957992, 45.530697070843594) has attributes: ['type', 'id']\n", - "Node (-73.7023772579133, 45.52982887967387) has attributes: ['type', 'id']\n", - "Node (-73.70310348189996, 45.530242710105696) has attributes: ['type', 'id']\n", - "Node (-73.70219141578475, 45.5309810002753) has attributes: ['type', 'id']\n", - "Node (-73.7015878987858, 45.53110506016847) has attributes: ['type', 'id']\n", - "Node (-73.70197756808213, 45.531335127032875) has attributes: ['type', 'id']\n", - "Node (-73.70171824652937, 45.53119684899265) has attributes: ['type', 'id']\n", - "Node (-73.70181225980849, 45.53125598840158) has attributes: ['type', 'id']\n", - "Node (-73.70212216033907, 45.53141309516707) has attributes: ['type', 'id']\n", - "Node (-73.70224797036111, 45.531522088920134) has attributes: ['type', 'id']\n", - "Node (-73.70319066728962, 45.53075184355254) has attributes: ['type', 'id']\n", - "Node (-73.70309318391786, 45.53066844829803) has attributes: ['type', 'id']\n", - "Node (-73.70326346262547, 45.53124343502157) has attributes: ['type', 'id']\n", - "Node (-73.70289161913149, 45.53100954740511) has attributes: ['type', 'id']\n", - "Node (-73.7031243168426, 45.52969124795911) has attributes: ['type', 'id']\n", - "Node (-73.70332165936908, 45.531298238343524) has attributes: ['type', 'id']\n", - "Node (-73.70291683392738, 45.531464843960194) has attributes: ['type', 'id']\n", - "Node (-73.70257423757026, 45.53123533603945) has attributes: ['type', 'id']\n", - "Node (-73.70246354979903, 45.53116600989907) has attributes: ['type', 'id']\n", - "Node (-73.70137270924536, 45.53098156462814) has attributes: ['type', 'id']\n", - "Node (-73.70228611728258, 45.52973374332967) has attributes: ['type', 'id']\n", - "Node (-73.70192277090158, 45.530832193189546) has attributes: ['type', 'id']\n", - "Node (-73.70247403248253, 45.530300013163604) has attributes: ['type', 'id']\n", - "Node (-73.70233258364674, 45.53021274328478) has attributes: ['type', 'id']\n", - "Node (-73.70150159992788, 45.530157998392504) has attributes: ['type', 'id']\n", - "Node (-73.70178207574742, 45.53033147043354) has attributes: ['type', 'id']\n", - "Node (-73.70279118480165, 45.53007116190442) has attributes: ['type', 'id']\n", - "Node (-73.70290386342012, 45.53015742711493) has attributes: ['type', 'id']\n", - "Node (-73.70199360008198, 45.529972641218336) has attributes: ['type', 'id']\n", - "Node (-73.7032815855412, 45.52978985115031) has attributes: ['type', 'id']\n", - "Node (-73.70166271484868, 45.53063422765041) has attributes: ['type', 'id']\n", - "Node (-73.7015006171488, 45.530550593136034) has attributes: ['type', 'id']\n", - "Node (-73.70265213028476, 45.529962782747816) has attributes: ['type', 'id']\n", - "Node (-73.7029326957311, 45.53056979610127) has attributes: ['type', 'id']\n", - "Node (-73.70166661687237, 45.5297928936099) has attributes: ['type', 'id']\n", - "Node (-73.70193452736822, 45.53043505670828) has attributes: ['type', 'id']\n", - "Node (-73.70320906423977, 45.53033165241546) has attributes: ['type', 'id']\n", - "Node (-73.70242433058544, 45.531020523149344) has attributes: ['type', 'id']\n", - "Node (-73.70229173916934, 45.53104634226288) has attributes: ['type', 'id']\n", - "Node (-73.70164581777142, 45.53024975981883) has attributes: ['type', 'id']\n", - "Node (-73.70181323564402, 45.52988517687263) has attributes: ['type', 'id']\n", - "Node (-73.70207977647193, 45.53050710203167) has attributes: ['type', 'id']\n", - "Node (-73.70180201572698, 45.53073366018695) has attributes: ['type', 'id']\n", - "Node (-73.70260551746348, 45.53038579346295) has attributes: ['type', 'id']\n", - "Node (-73.7015368490746, 45.531520903846236) has attributes: ['type', 'id']\n", - "Node (-73.70277909755795, 45.530494359508104) has attributes: ['type', 'id']\n", - "Node (-73.7016306503588, 45.531601992190964) has attributes: ['type', 'id']\n", - "Node (-73.703188128229, 45.531634438129004) has attributes: ['type', 'id']\n", - "Node (-73.70225201894137, 45.5306050266003) has attributes: ['type', 'id']\n", - "Node (-73.70250211711432, 45.53079519337939) has attributes: ['type', 'id']\n", - "Node (-73.70143287673753, 45.53147394391961) has attributes: ['type', 'id']\n", - "Node (-73.7015564456529, 45.52971249323039) has attributes: ['type', 'id']\n", - "Node (-73.70213321668199, 45.530060293550356) has attributes: ['type', 'id']\n", - "Node (-73.70205098392802, 45.53092949418992) has attributes: ['type', 'id']\n", - "Node (-73.70273955351598, 45.53092005042424) has attributes: ['type', 'id']\n" - ] - } - ], - "execution_count": 119 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-31T21:29:21.717811Z", - "start_time": "2024-07-31T21:29:21.697811Z" - } - }, - "cell_type": "code", - "source": [ - "from scripts.district_heating_network.district_heating_factory import DistrictHeatingFactory\n", - "\n", - "DistrictHeatingFactory(city=city, graph=network_graph)" - ], - "id": "25e14bd5433e3d95", - "outputs": [ - { - "ename": "TypeError", - "evalue": "__init__() got an unexpected keyword argument 'graph'", - "output_type": "error", - "traceback": [ - "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[1;31mTypeError\u001B[0m Traceback (most recent call last)", - "Cell \u001B[1;32mIn[94], line 3\u001B[0m\n\u001B[0;32m 1\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01mscripts\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mdistrict_heating_network\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mdistrict_heating_factory\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m DistrictHeatingFactory\n\u001B[1;32m----> 3\u001B[0m \u001B[43mDistrictHeatingFactory\u001B[49m\u001B[43m(\u001B[49m\u001B[43mcity\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mcity\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mgraph\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mnetwork_graph\u001B[49m\u001B[43m)\u001B[49m\n", - "\u001B[1;31mTypeError\u001B[0m: __init__() got an unexpected keyword argument 'graph'" - ] - } - ], - "execution_count": 94 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-31T21:18:46.818842Z", - "start_time": "2024-07-31T21:18:46.799573Z" - } - }, - "cell_type": "code", - "source": [ - "for node_id, attrs in network_graph.nodes(data=True):\n", - " print(f\"Node {node_id} has attributes: {list(attrs.keys())}\")" - ], - "id": "ad48fbc87a598b85", - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Node (-73.70263014634182, 45.52966550204674) has attributes: []\n", - "Node (-73.70252245592799, 45.52959782722166) has attributes: []\n", - "Node (-73.70277983402246, 45.52975956880018) has attributes: []\n", - "Node (-73.70292834674622, 45.52985289718704) has attributes: []\n", - "Node (-73.70299601156968, 45.52989541912497) has attributes: []\n", - "Node (-73.70304798829301, 45.52992808234479) has attributes: []\n", - "Node (-73.70315317772048, 45.52999418549968) has attributes: []\n", - "Node (-73.70322951375971, 45.530042156604246) has attributes: []\n", - "Node (-73.70334527410391, 45.53011490273612) has attributes: []\n", - "Node (-73.70388612860485, 45.530454786598085) has attributes: []\n", - "Node (-73.70321670301797, 45.53098320823811) has attributes: []\n", - "Node (-73.70309371940914, 45.53090572804479) has attributes: []\n", - "Node (-73.70336752508702, 45.53107818505422) has attributes: []\n", - "Node (-73.70300302780161, 45.53115122842582) has attributes: []\n", - "Node (-73.70298632291501, 45.53083806779961) has attributes: []\n", - "Node (-73.70284664272657, 45.53075006869057) has attributes: []\n", - "Node (-73.70282694240179, 45.530737657402696) has attributes: []\n", - "Node (-73.70268296446567, 45.530646950694454) has attributes: []\n", - "Node (-73.70262035905371, 45.53060750902034) has attributes: []\n", - "Node (-73.70250974072788, 45.53053781900757) has attributes: []\n", - "Node (-73.70248122664219, 45.530519855013075) has attributes: []\n", - "Node (-73.70237692791034, 45.53045414637121) has attributes: []\n", - "Node (-73.70241425825014, 45.52952983362164) has attributes: []\n", - "Node (-73.70258909924681, 45.53147671471601) has attributes: []\n", - "Node (-73.70246956317335, 45.531401341489406) has attributes: []\n", - "Node (-73.70281850395438, 45.53162108764596) has attributes: []\n", - "Node (-73.70235595692806, 45.53165968576366) has attributes: []\n", - "Node (-73.70235908646175, 45.53133168062488) has attributes: []\n", - "Node (-73.70226538550632, 45.5312725976791) has attributes: []\n", - "Node (-73.7022262934011, 45.531247948232114) has attributes: []\n", - "Node (-73.70218216283965, 45.53122012179686) has attributes: []\n", - "Node (-73.7020876584622, 45.53116053225497) has attributes: []\n", - "Node (-73.70208089954498, 45.53115627043355) has attributes: []\n", - "Node (-73.70195718026818, 45.531078259496624) has attributes: []\n", - "Node (-73.7019336727694, 45.53106343689135) has attributes: []\n", - "Node (-73.70183972286668, 45.53100419697237) has attributes: []\n", - "Node (-73.70182154258106, 45.53099273343045) has attributes: []\n", - "Node (-73.70170504466955, 45.530919275910655) has attributes: []\n", - "Node (-73.70169068527439, 45.5309102216234) has attributes: []\n", - "Node (-73.70191018896638, 45.53200952628766) has attributes: []\n", - "Node (-73.70343390828414, 45.5311199883841) has attributes: []\n", - "Node (-73.70308928370066, 45.53179149942939) has attributes: []\n", - "Node (-73.70154615235963, 45.53081908668964) has attributes: []\n", - "Node (-73.70149535566978, 45.53078705694076) has attributes: []\n", - "Node (-73.70139243548935, 45.530722160831516) has attributes: []\n", - "Node (-73.70235555653572, 45.5304406823149) has attributes: []\n", - "Node (-73.70223631048641, 45.530365556799865) has attributes: []\n", - "Node (-73.70218808966641, 45.53033517747947) has attributes: []\n", - "Node (-73.7020516180255, 45.53024919976893) has attributes: []\n", - "Node (-73.70202483520858, 45.530232326481084) has attributes: []\n", - "Node (-73.70189576536478, 45.53015101193401) has attributes: []\n", - "Node (-73.70188535693748, 45.53014445458083) has attributes: []\n", - "Node (-73.70176137113975, 45.53006634300427) has attributes: []\n", - "Node (-73.70171679336974, 45.53003825882077) has attributes: []\n", - "Node (-73.70161674578377, 45.52997522841877) has attributes: []\n", - "Node (-73.70157021391765, 45.52994591314646) has attributes: []\n", - "Node (-73.70145508528618, 45.52987338162208) has attributes: []\n", - "Node (-73.7015262783945, 45.53176766055835) has attributes: []\n", - "Node (-73.70142255824699, 45.531702316306436) has attributes: []\n", - "Node (-73.70132694890151, 45.53164208190352) has attributes: []\n", - "Node (-73.70249378379357, 45.529882494691094) has attributes: ['type', 'id']\n", - "Node (-73.70236957992, 45.530697070843594) has attributes: ['type', 'id']\n", - "Node (-73.7023772579133, 45.52982887967387) has attributes: ['type', 'id']\n", - "Node (-73.70310348189996, 45.530242710105696) has attributes: ['type', 'id']\n", - "Node (-73.70219141578475, 45.5309810002753) has attributes: ['type', 'id']\n", - "Node (-73.7015878987858, 45.53110506016847) has attributes: ['type', 'id']\n", - "Node (-73.70197756808213, 45.531335127032875) has attributes: ['type', 'id']\n", - "Node (-73.70171824652937, 45.53119684899265) has attributes: ['type', 'id']\n", - "Node (-73.70181225980849, 45.53125598840158) has attributes: ['type', 'id']\n", - "Node (-73.70212216033907, 45.53141309516707) has attributes: ['type', 'id']\n", - "Node (-73.70224797036111, 45.531522088920134) has attributes: ['type', 'id']\n", - "Node (-73.70319066728962, 45.53075184355254) has attributes: ['type', 'id']\n", - "Node (-73.70309318391786, 45.53066844829803) has attributes: ['type', 'id']\n", - "Node (-73.70326346262547, 45.53124343502157) has attributes: ['type', 'id']\n", - "Node (-73.70289161913149, 45.53100954740511) has attributes: ['type', 'id']\n", - "Node (-73.7031243168426, 45.52969124795911) has attributes: ['type', 'id']\n", - "Node (-73.70332165936908, 45.531298238343524) has attributes: ['type', 'id']\n", - "Node (-73.70291683392738, 45.531464843960194) has attributes: ['type', 'id']\n", - "Node (-73.70257423757026, 45.53123533603945) has attributes: ['type', 'id']\n", - "Node (-73.70246354979903, 45.53116600989907) has attributes: ['type', 'id']\n", - "Node (-73.70137270924536, 45.53098156462814) has attributes: ['type', 'id']\n", - "Node (-73.70228611728258, 45.52973374332967) has attributes: ['type', 'id']\n", - "Node (-73.70192277090158, 45.530832193189546) has attributes: ['type', 'id']\n", - "Node (-73.70247403248253, 45.530300013163604) has attributes: ['type', 'id']\n", - "Node (-73.70233258364674, 45.53021274328478) has attributes: ['type', 'id']\n", - "Node (-73.70150159992788, 45.530157998392504) has attributes: ['type', 'id']\n", - "Node (-73.70178207574742, 45.53033147043354) has attributes: ['type', 'id']\n", - "Node (-73.70279118480165, 45.53007116190442) has attributes: ['type', 'id']\n", - "Node (-73.70290386342012, 45.53015742711493) has attributes: ['type', 'id']\n", - "Node (-73.70199360008198, 45.529972641218336) has attributes: ['type', 'id']\n", - "Node (-73.7032815855412, 45.52978985115031) has attributes: ['type', 'id']\n", - "Node (-73.70166271484868, 45.53063422765041) has attributes: ['type', 'id']\n", - "Node (-73.7015006171488, 45.530550593136034) has attributes: ['type', 'id']\n", - "Node (-73.70265213028476, 45.529962782747816) has attributes: ['type', 'id']\n", - "Node (-73.7029326957311, 45.53056979610127) has attributes: ['type', 'id']\n", - "Node (-73.70166661687237, 45.5297928936099) has attributes: ['type', 'id']\n", - "Node (-73.70193452736822, 45.53043505670828) has attributes: ['type', 'id']\n", - "Node (-73.70320906423977, 45.53033165241546) has attributes: ['type', 'id']\n", - "Node (-73.70242433058544, 45.531020523149344) has attributes: ['type', 'id']\n", - "Node (-73.70229173916934, 45.53104634226288) has attributes: ['type', 'id']\n", - "Node (-73.70164581777142, 45.53024975981883) has attributes: ['type', 'id']\n", - "Node (-73.70181323564402, 45.52988517687263) has attributes: ['type', 'id']\n", - "Node (-73.70207977647193, 45.53050710203167) has attributes: ['type', 'id']\n", - "Node (-73.70180201572698, 45.53073366018695) has attributes: ['type', 'id']\n", - "Node (-73.70260551746348, 45.53038579346295) has attributes: ['type', 'id']\n", - "Node (-73.7015368490746, 45.531520903846236) has attributes: ['type', 'id']\n", - "Node (-73.70277909755795, 45.530494359508104) has attributes: ['type', 'id']\n", - "Node (-73.7016306503588, 45.531601992190964) has attributes: ['type', 'id']\n", - "Node (-73.703188128229, 45.531634438129004) has attributes: ['type', 'id']\n", - "Node (-73.70225201894137, 45.5306050266003) has attributes: ['type', 'id']\n", - "Node (-73.70250211711432, 45.53079519337939) has attributes: ['type', 'id']\n", - "Node (-73.70143287673753, 45.53147394391961) has attributes: ['type', 'id']\n", - "Node (-73.7015564456529, 45.52971249323039) has attributes: ['type', 'id']\n", - "Node (-73.70213321668199, 45.530060293550356) has attributes: ['type', 'id']\n", - "Node (-73.70205098392802, 45.53092949418992) has attributes: ['type', 'id']\n", - "Node (-73.70273955351598, 45.53092005042424) has attributes: ['type', 'id']\n" - ] - } - ], - "execution_count": 80 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-31T20:23:57.446448Z", - "start_time": "2024-07-31T20:23:57.431469Z" - } - }, - "cell_type": "code", - "source": [ - "for building in city.buildings:\n", - " print(building.name)" - ], - "id": "5b96a042e349e0eb", - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "65418\n", - "70816\n", - "73478\n", - "82649\n", - "84906\n", - "87241\n", - "87719\n", - "88675\n", - "88747\n", - "89061\n", - "89062\n", - "89251\n", - "91214\n", - "92337\n", - "92399\n", - "92520\n", - "92979\n", - "93149\n", - "95265\n", - "95266\n", - "95465\n", - "95704\n", - "96241\n", - "96579\n", - "96580\n", - "96930\n", - "96931\n", - "96996\n", - "96997\n", - "97648\n", - "98087\n", - "98666\n", - "98667\n", - "102035\n", - "103043\n", - "103740\n", - "103795\n", - "107302\n", - "108296\n", - "108297\n", - "109211\n", - "109305\n", - "109773\n", - "110561\n", - "110873\n", - "113368\n", - "116927\n", - "118062\n", - "118250\n", - "119143\n", - "120435\n", - "124177\n", - "125538\n", - "128322\n", - "129429\n", - "130498\n" - ] - } - ], - "execution_count": 75 - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-07-31T19:35:10.949715Z", - "start_time": "2024-07-31T19:35:09.846007Z" - } - }, - "cell_type": "code", - "source": "", - "id": "2bb88967eb45bcec", - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "IOPub data rate exceeded.\n", - "The Jupyter server will temporarily stop sending output\n", - "to the client in order to avoid crashing it.\n", - "To change this limit, set the config variable\n", - "`--ServerApp.iopub_data_rate_limit`.\n", - "\n", - "Current values:\n", - "ServerApp.iopub_data_rate_limit=1000000.0 (bytes/sec)\n", - "ServerApp.rate_limit_window=3.0 (secs)\n", - "\n" - ] - } - ], - "execution_count": 52 - }, - { - "metadata": {}, - "cell_type": "code", - "outputs": [], - "execution_count": null, - "source": "", - "id": "f7c0742941b4f2d1" - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -}