Compare commits
13 Commits
5b0e1ec440
...
b3ebabf6e6
Author | SHA1 | Date | |
---|---|---|---|
b3ebabf6e6 | |||
ad2d0a86d5 | |||
5205ed5ca2 | |||
797944c5bb | |||
1d93ea75f4 | |||
f7eb75159c | |||
002e59b938 | |||
db5efa92a2 | |||
6a500e10dc | |||
373d98a0d4 | |||
|
414e69a79a | ||
|
977649c5b8 | ||
08639d9dd7 |
1585013
input_files/roads.json
Normal file
1585013
input_files/roads.json
Normal file
File diff suppressed because it is too large
Load Diff
116
main.py
116
main.py
|
@ -1,4 +1,5 @@
|
|||
from pathlib import Path
|
||||
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
|
||||
|
@ -22,65 +23,68 @@ 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
|
||||
# Specify the GeoJSON file path
|
||||
data = {}
|
||||
input_files_path = (Path(__file__).parent / 'input_files')
|
||||
input_files_path.mkdir(parents=True, exist_ok=True)
|
||||
# geojson_file = process_geojson(x=-73.58001358793511, y=45.496445294438715, diff=0.0001)
|
||||
geojson_file_path = input_files_path / 'test_geojson1.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)
|
||||
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)
|
||||
|
||||
# Input files directory
|
||||
input_files_path = dir_manager.create_directory('input_files')
|
||||
geojson_file_path = input_files_path / 'output_buildings.geojson'
|
||||
|
||||
# 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')
|
||||
|
||||
# Select city area
|
||||
location = [45.53067276979674, -73.70234652694087]
|
||||
process_geojson(x=location[1], y=location[0], diff=0.001)
|
||||
|
||||
# Create city object
|
||||
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)
|
||||
# data[f'{city.buildings[0].function}'] = city.buildings[0].heating_demand[cte.YEAR][0] / 3.6e9
|
||||
# city.buildings[0].function = cte.COMMERCIAL
|
||||
# ConstructionFactory('nrcan', city).enrich()
|
||||
# UsageFactory('nrcan', city).enrich()
|
||||
# energy_plus_workflow(city, energy_plus_output_path)
|
||||
# data[f'{city.buildings[0].function}'] = city.buildings[0].heating_demand[cte.YEAR][0] / 3.6e9
|
||||
# city.buildings[0].function = cte.MEDIUM_OFFICE
|
||||
# ConstructionFactory('nrcan', city).enrich()
|
||||
# UsageFactory('nrcan', city).enrich()
|
||||
# energy_plus_workflow(city, energy_plus_output_path)
|
||||
# data[f'{city.buildings[0].function}'] = city.buildings[0].heating_demand[cte.YEAR][0] / 3.6e9
|
||||
# categories = list(data.keys())
|
||||
# values = list(data.values())
|
||||
# # Plotting
|
||||
# fig, ax = plt.subplots(figsize=(10, 6), dpi=96)
|
||||
# fig.suptitle('Impact of different usages on yearly heating demand', fontsize=16, weight='bold', alpha=.8)
|
||||
# ax.bar(categories, values, color=['#2196f3', '#ff5a5f', '#4caf50'], width=0.6, zorder=2)
|
||||
# ax.grid(which="major", axis='x', color='#DAD8D7', alpha=0.5, zorder=1)
|
||||
# ax.grid(which="major", axis='y', color='#DAD8D7', alpha=0.5, zorder=1)
|
||||
# ax.set_xlabel('Building Type', fontsize=12, labelpad=10)
|
||||
# ax.set_ylabel('Energy Consumption (MWh)', fontsize=14, labelpad=10)
|
||||
# ax.yaxis.set_major_locator(plt.MaxNLocator(integer=True))
|
||||
# ax.set_xticks(np.arange(len(categories)))
|
||||
# ax.set_xticklabels(categories, rotation=45, ha='right')
|
||||
# ax.bar_label(ax.containers[0], padding=3, color='black', fontsize=12, rotation=0)
|
||||
# ax.spines[['top', 'left', 'bottom']].set_visible(False)
|
||||
# ax.spines['right'].set_linewidth(1.1)
|
||||
# # Set a white background
|
||||
# fig.patch.set_facecolor('white')
|
||||
# # Adjust the margins around the plot area
|
||||
# plt.subplots_adjust(left=0.1, right=0.9, top=0.85, bottom=0.25)
|
||||
# # Save the plot
|
||||
# plt.savefig('plot_nrcan.png', bbox_inches='tight')
|
||||
# plt.close()
|
||||
print('test')
|
||||
|
||||
ConstructionFactory('nrcan', city).enrich()
|
||||
|
||||
UsageFactory('nrcan', city).enrich()
|
||||
|
||||
WeatherFactory('epw', city).enrich()
|
||||
|
||||
# EnergyPlus workflow
|
||||
energy_plus_workflow(city, energy_plus_output_path)
|
||||
|
||||
roads_file = road_processor(location[1], location[0], 0.001)
|
||||
|
||||
dhn_creator = DistrictHeatingNetworkCreator(geojson_file_path, roads_file)
|
||||
|
||||
network_graph = dhn_creator.run()
|
||||
|
||||
DistrictHeatingFactory(
|
||||
city,
|
||||
network_graph,
|
||||
60,
|
||||
40,
|
||||
0.8
|
||||
).enrich()
|
||||
|
||||
DistrictHeatingFactory(
|
||||
city,
|
||||
network_graph,
|
||||
60,
|
||||
40,
|
||||
0.8
|
||||
).sizing()
|
||||
|
||||
for u, v, attributes in network_graph.edges(data=True):
|
||||
print(f"Edge between {u} and {v} with attributes: {attributes}")
|
||||
|
|
|
@ -14,7 +14,7 @@ import hub.helpers.constants as cte
|
|||
from hub.exports.exports_factory import ExportsFactory
|
||||
from scripts.pv_sizing_and_simulation import PVSizingSimulation
|
||||
# Specify the GeoJSON file path
|
||||
geojson_file = process_geojson(x=-73.5681295982132, y=45.49218262677643, diff=0.0005)
|
||||
geojson_file = process_geojson(x=-73.5681295982132, y=45.49218262677643, diff=0.0001)
|
||||
file_path = (Path(__file__).parent / 'input_files' / 'output_buildings.geojson')
|
||||
# Specify the output path for the PDF file
|
||||
output_path = (Path(__file__).parent / 'out_files').resolve()
|
||||
|
@ -34,7 +34,7 @@ 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()
|
||||
energy_plus_workflow(city)
|
||||
energy_plus_workflow(city, output_path=output_path)
|
||||
solar_angles = CitySolarAngles(city.name,
|
||||
city.latitude,
|
||||
city.longitude,
|
||||
|
|
16
scripts/district_heating_network/directory_manager.py
Normal file
16
scripts/district_heating_network/directory_manager.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
from pathlib import Path
|
||||
|
||||
|
||||
class DirectoryManager:
|
||||
def __init__(self, base_path):
|
||||
self.base_path = Path(base_path)
|
||||
self.directories = {}
|
||||
|
||||
def create_directory(self, relative_path):
|
||||
full_path = self.base_path / relative_path
|
||||
full_path.mkdir(parents=True, exist_ok=True)
|
||||
self.directories[relative_path] = full_path
|
||||
return full_path
|
||||
|
||||
def get_directory(self, relative_path):
|
||||
return self.directories.get(relative_path, None)
|
79
scripts/district_heating_network/district_heating_factory.py
Normal file
79
scripts/district_heating_network/district_heating_factory.py
Normal file
|
@ -0,0 +1,79 @@
|
|||
import networkx as nx
|
||||
import logging
|
||||
import CoolProp as CP
|
||||
import math
|
||||
|
||||
|
||||
class DistrictHeatingFactory:
|
||||
"""
|
||||
DistrictHeatingFactory class
|
||||
"""
|
||||
|
||||
def __init__(self, city, graph, supply_temperature, return_temperature, simultaneity_factor):
|
||||
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"
|
||||
|
||||
def enrich(self):
|
||||
"""
|
||||
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
|
||||
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:
|
||||
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.")
|
||||
|
||||
def sizing(self):
|
||||
"""
|
||||
Calculate the diameter of the pipes in the district heating network.
|
||||
"""
|
||||
for node in self._network_graph.nodes(data=True):
|
||||
node_id, node_attrs = node
|
||||
if node_attrs.get('type') == 'building':
|
||||
heating_peak_load = node_attrs.get('heating_peak_load') # Adjusted key to match your data
|
||||
print(heating_peak_load['year'][0])
|
||||
if heating_peak_load:
|
||||
# Calculate peak mass flow rate
|
||||
peak_mass_flow_rate = heating_peak_load['year'][0] / CP.PropsSI('C',
|
||||
'T',
|
||||
(
|
||||
self._supply_temperature +
|
||||
self._return_temperature
|
||||
) / 2,
|
||||
'P',
|
||||
101325,
|
||||
self.fluid)
|
||||
print(peak_mass_flow_rate)
|
||||
# Calculate density of the fluid
|
||||
density = CP.PropsSI('D', # 'D' for density
|
||||
'T',
|
||||
(
|
||||
self._supply_temperature +
|
||||
self._return_temperature
|
||||
) / 2,
|
||||
'P',
|
||||
101325,
|
||||
self.fluid)
|
||||
|
||||
# Set the design velocity (V)
|
||||
velocity = 0.9 # m/s
|
||||
|
||||
# Calculate the diameter (D)
|
||||
D = math.sqrt((4 * peak_mass_flow_rate) / (density * velocity * math.pi)) # m
|
||||
print(D)
|
||||
# Find the edge connected to the building node
|
||||
for neighbor in self._network_graph.neighbors(node_id):
|
||||
if not self._network_graph.nodes[neighbor].get('type') == 'building': # Ensure it's a pipe connection
|
||||
self._network_graph.edges[node_id, neighbor]['diameter'] = D
|
||||
logging.info(f"Diameter for edge ({node_id}, {neighbor}) set to {D} meters.")
|
|
@ -0,0 +1,333 @@
|
|||
import json
|
||||
import math
|
||||
import logging
|
||||
import matplotlib.pyplot as plt
|
||||
import networkx as nx
|
||||
from shapely.geometry import Polygon, Point, LineString
|
||||
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)
|
||||
|
||||
|
||||
def haversine(lon1, lat1, lon2, lat2):
|
||||
"""
|
||||
Calculate the great-circle distance between two points
|
||||
on the Earth specified by their longitude and latitude.
|
||||
"""
|
||||
R = 6371000 # Radius of the Earth in meters
|
||||
phi1 = math.radians(lat1)
|
||||
phi2 = math.radians(lat2)
|
||||
delta_phi = math.radians(lat2 - lat1)
|
||||
delta_lambda = math.radians(lon2 - lon1)
|
||||
|
||||
a = math.sin(delta_phi / 2.0) ** 2 + \
|
||||
math.cos(phi1) * math.cos(phi2) * \
|
||||
math.sin(delta_lambda / 2.0) ** 2
|
||||
|
||||
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):
|
||||
"""
|
||||
Initialize the class with paths to the buildings and roads data files.
|
||||
|
||||
:param buildings_file: Path to the GeoJSON file containing building data.
|
||||
:param roads_file: Path to the GeoJSON file containing roads data.
|
||||
"""
|
||||
self.buildings_file = buildings_file
|
||||
self.roads_file = roads_file
|
||||
|
||||
def run(self) -> nx.Graph:
|
||||
"""
|
||||
Main method to execute the district heating network creation process.
|
||||
:return: NetworkX graph with nodes and edges representing the network.
|
||||
"""
|
||||
try:
|
||||
self._load_and_process_data()
|
||||
self._find_nearest_roads()
|
||||
self._find_nearest_points()
|
||||
self._break_down_roads()
|
||||
self._create_graph()
|
||||
self._create_mst()
|
||||
self._iteratively_remove_edges()
|
||||
self._add_centroids_to_mst()
|
||||
self._convert_edge_weights_to_meters()
|
||||
return self.final_mst
|
||||
except Exception as e:
|
||||
logging.error(f"Error during network creation: {e}")
|
||||
raise
|
||||
|
||||
def _load_and_process_data(self):
|
||||
"""
|
||||
Load and process the building and road data.
|
||||
"""
|
||||
try:
|
||||
# Load building data
|
||||
with open(self.buildings_file, 'r') as file:
|
||||
city = json.load(file)
|
||||
|
||||
self.centroids = []
|
||||
self.building_names = []
|
||||
buildings = city['features']
|
||||
for building in buildings:
|
||||
coordinates = building['geometry']['coordinates'][0]
|
||||
building_polygon = Polygon(coordinates)
|
||||
centroid = building_polygon.centroid
|
||||
self.centroids.append(centroid)
|
||||
self.building_names.append(str(building['id']))
|
||||
|
||||
# Load road data
|
||||
with open(self.roads_file, 'r') as file:
|
||||
roads = json.load(file)
|
||||
|
||||
line_features = [feature for feature in roads['features'] if feature['geometry']['type'] == 'LineString']
|
||||
|
||||
self.lines = [LineString(feature['geometry']['coordinates']) for feature in line_features]
|
||||
self.cleaned_lines = [LineString([line.coords[0], line.coords[-1]]) for line in self.lines]
|
||||
except Exception as e:
|
||||
logging.error(f"Error loading and processing data: {e}")
|
||||
raise
|
||||
|
||||
def _find_nearest_roads(self):
|
||||
"""
|
||||
Find the nearest road for each building centroid.
|
||||
"""
|
||||
try:
|
||||
self.closest_roads = []
|
||||
unique_roads_set = set()
|
||||
|
||||
# Create spatial index for roads
|
||||
idx = index.Index()
|
||||
for pos, line in enumerate(self.cleaned_lines):
|
||||
idx.insert(pos, line.bounds)
|
||||
|
||||
for centroid in self.centroids:
|
||||
min_distance = float('inf')
|
||||
closest_road = None
|
||||
for pos in idx.nearest(centroid.bounds, 10):
|
||||
road = self.cleaned_lines[pos]
|
||||
distance = road.distance(centroid)
|
||||
if distance < min_distance:
|
||||
min_distance = distance
|
||||
closest_road = road
|
||||
|
||||
if closest_road and closest_road.wkt not in unique_roads_set:
|
||||
unique_roads_set.add(closest_road.wkt)
|
||||
self.closest_roads.append(closest_road)
|
||||
except Exception as e:
|
||||
logging.error(f"Error finding nearest roads: {e}")
|
||||
raise
|
||||
|
||||
def _find_nearest_points(self):
|
||||
"""
|
||||
Find the nearest point on each closest road for each centroid.
|
||||
"""
|
||||
|
||||
def find_nearest_point_on_line(point: Point, line: LineString) -> Point:
|
||||
return line.interpolate(line.project(point))
|
||||
|
||||
try:
|
||||
self.nearest_points = []
|
||||
for centroid in self.centroids:
|
||||
min_distance = float('inf')
|
||||
closest_road = None
|
||||
for road in self.closest_roads:
|
||||
distance = centroid.distance(road)
|
||||
if distance < min_distance:
|
||||
min_distance = distance
|
||||
closest_road = road
|
||||
|
||||
if closest_road:
|
||||
nearest_point = find_nearest_point_on_line(centroid, closest_road)
|
||||
self.nearest_points.append(nearest_point)
|
||||
except Exception as e:
|
||||
logging.error(f"Error finding nearest points: {e}")
|
||||
raise
|
||||
|
||||
def _break_down_roads(self):
|
||||
"""
|
||||
Break down roads into segments connecting nearest points.
|
||||
"""
|
||||
|
||||
def break_down_roads(closest_roads: List[LineString], nearest_points_list: List[Point]) -> List[LineString]:
|
||||
new_segments = []
|
||||
for road in closest_roads:
|
||||
coords = list(road.coords)
|
||||
points_on_road = [point for point in nearest_points_list if road.distance(point) < 0.000000001]
|
||||
sorted_points = sorted(points_on_road, key=lambda point: road.project(point))
|
||||
sorted_points.insert(0, Point(coords[0]))
|
||||
sorted_points.append(Point(coords[-1]))
|
||||
for i in range(len(sorted_points) - 1):
|
||||
segment = LineString([sorted_points[i], sorted_points[i + 1]])
|
||||
new_segments.append(segment)
|
||||
return new_segments
|
||||
|
||||
try:
|
||||
self.new_segments = break_down_roads(self.closest_roads, self.nearest_points)
|
||||
self.cleaned_lines = [line for line in self.cleaned_lines if line not in self.closest_roads]
|
||||
self.cleaned_lines.extend(self.new_segments)
|
||||
except Exception as e:
|
||||
logging.error(f"Error breaking down roads: {e}")
|
||||
raise
|
||||
|
||||
def _create_graph(self):
|
||||
"""
|
||||
Create a NetworkX graph from the cleaned lines.
|
||||
"""
|
||||
try:
|
||||
self.G = nx.Graph()
|
||||
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])))
|
||||
except Exception as e:
|
||||
logging.error(f"Error creating graph: {e}")
|
||||
raise
|
||||
|
||||
def _create_mst(self):
|
||||
"""
|
||||
Create a Minimum Spanning Tree (MST) from the graph.
|
||||
"""
|
||||
|
||||
def find_paths_between_nearest_points(g: nx.Graph, nearest_points: List[Point]) -> List[Tuple]:
|
||||
edges = []
|
||||
for i, start_point in enumerate(nearest_points):
|
||||
start = (start_point.x, start_point.y)
|
||||
for end_point in nearest_points[i + 1:]:
|
||||
end = (end_point.x, end_point.y)
|
||||
if nx.has_path(g, start, end):
|
||||
path = nx.shortest_path(g, source=start, target=end, weight='weight')
|
||||
path_edges = list(zip(path[:-1], path[1:]))
|
||||
edges.extend((u, v, g[u][v]['weight']) for u, v in path_edges)
|
||||
return edges
|
||||
|
||||
try:
|
||||
edges = find_paths_between_nearest_points(self.G, self.nearest_points)
|
||||
h = nx.Graph()
|
||||
h.add_weighted_edges_from(edges)
|
||||
mst = nx.minimum_spanning_tree(h, weight='weight')
|
||||
final_edges = []
|
||||
for u, v in mst.edges():
|
||||
if nx.has_path(self.G, u, v):
|
||||
path = nx.shortest_path(self.G, source=u, target=v, weight='weight')
|
||||
path_edges = list(zip(path[:-1], path[1:]))
|
||||
final_edges.extend((x, y, self.G[x][y]['weight']) for x, y in path_edges)
|
||||
self.final_mst = nx.Graph()
|
||||
self.final_mst.add_weighted_edges_from(final_edges)
|
||||
except Exception as e:
|
||||
logging.error(f"Error creating MST: {e}")
|
||||
raise
|
||||
|
||||
def _iteratively_remove_edges(self):
|
||||
"""
|
||||
Iteratively remove edges that do not have any nearest points and have one end with only one connection.
|
||||
Also remove nodes that don't have any connections and street nodes with only one connection.
|
||||
"""
|
||||
nearest_points_tuples = [(point.x, point.y) for point in self.nearest_points]
|
||||
|
||||
def find_edges_to_remove(graph: nx.Graph) -> List[Tuple]:
|
||||
edges_to_remove = []
|
||||
for u, v, d in graph.edges(data=True):
|
||||
if u not in nearest_points_tuples and v not in nearest_points_tuples:
|
||||
if graph.degree(u) == 1 or graph.degree(v) == 1:
|
||||
edges_to_remove.append((u, v, d))
|
||||
return edges_to_remove
|
||||
|
||||
def find_nodes_to_remove(graph: nx.Graph) -> List[Tuple]:
|
||||
nodes_to_remove = []
|
||||
for node in graph.nodes():
|
||||
if graph.degree(node) == 0:
|
||||
nodes_to_remove.append(node)
|
||||
return nodes_to_remove
|
||||
|
||||
try:
|
||||
edges_to_remove = find_edges_to_remove(self.final_mst)
|
||||
self.final_mst_steps = [list(self.final_mst.edges(data=True))]
|
||||
|
||||
while edges_to_remove or find_nodes_to_remove(self.final_mst):
|
||||
self.final_mst.remove_edges_from(edges_to_remove)
|
||||
nodes_to_remove = find_nodes_to_remove(self.final_mst)
|
||||
self.final_mst.remove_nodes_from(nodes_to_remove)
|
||||
edges_to_remove = find_edges_to_remove(self.final_mst)
|
||||
self.final_mst_steps.append(list(self.final_mst.edges(data=True)))
|
||||
|
||||
def find_single_connection_street_nodes(graph: nx.Graph) -> List[Tuple]:
|
||||
single_connection_street_nodes = []
|
||||
for node in graph.nodes():
|
||||
if node not in nearest_points_tuples and graph.degree(node) == 1:
|
||||
single_connection_street_nodes.append(node)
|
||||
return single_connection_street_nodes
|
||||
|
||||
single_connection_street_nodes = find_single_connection_street_nodes(self.final_mst)
|
||||
|
||||
while single_connection_street_nodes:
|
||||
for node in single_connection_street_nodes:
|
||||
neighbors = list(self.final_mst.neighbors(node))
|
||||
self.final_mst.remove_node(node)
|
||||
for neighbor in neighbors:
|
||||
if self.final_mst.degree(neighbor) == 0:
|
||||
self.final_mst.remove_node(neighbor)
|
||||
single_connection_street_nodes = find_single_connection_street_nodes(self.final_mst)
|
||||
self.final_mst_steps.append(list(self.final_mst.edges(data=True)))
|
||||
except Exception as e:
|
||||
logging.error(f"Error iteratively removing edges: {e}")
|
||||
raise
|
||||
|
||||
def _add_centroids_to_mst(self):
|
||||
"""
|
||||
Add centroids to the final MST graph and connect them to their associated node on the graph.
|
||||
"""
|
||||
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)
|
||||
|
||||
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 distance < min_distance:
|
||||
min_distance = distance
|
||||
nearest_point = node
|
||||
|
||||
if nearest_point:
|
||||
self.final_mst.add_edge(centroid_tuple, nearest_point, weight=min_distance)
|
||||
except Exception as e:
|
||||
logging.error(f"Error adding centroids to MST: {e}")
|
||||
raise
|
||||
|
||||
def _convert_edge_weights_to_meters(self):
|
||||
"""
|
||||
Convert all edge weights in the final MST graph to meters using the Haversine formula.
|
||||
"""
|
||||
try:
|
||||
for u, v, data in self.final_mst.edges(data=True):
|
||||
lon1, lat1 = u
|
||||
lon2, lat2 = v
|
||||
distance = haversine(lon1, lat1, lon2, lat2)
|
||||
self.final_mst[u][v]['weight'] = distance
|
||||
except Exception as e:
|
||||
logging.error(f"Error converting edge weights to meters: {e}")
|
||||
raise
|
||||
|
||||
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')
|
||||
plt.title('District Heating Network Graph')
|
||||
plt.axis('off')
|
||||
plt.show()
|
54
scripts/district_heating_network/geojson_graph_creator.py
Normal file
54
scripts/district_heating_network/geojson_graph_creator.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
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
|
56
scripts/district_heating_network/road_processor.py
Normal file
56
scripts/district_heating_network/road_processor.py
Normal file
|
@ -0,0 +1,56 @@
|
|||
from pathlib import Path
|
||||
from shapely.geometry import Polygon, Point, shape
|
||||
import json
|
||||
|
||||
|
||||
def road_processor(x, y, diff):
|
||||
"""
|
||||
Processes a .JSON file to find roads that have at least one node within a specified polygon.
|
||||
|
||||
Parameters:
|
||||
x (float): The x-coordinate of the center of the selection box.
|
||||
y (float): The y-coordinate of the center of the selection box.
|
||||
diff (float): The half-width of the selection box.
|
||||
|
||||
Returns:
|
||||
str: The file path of the output GeoJSON file containing the selected roads.
|
||||
"""
|
||||
diff += 2 * diff
|
||||
# Define the selection polygon
|
||||
selection_box = Polygon([
|
||||
[x + diff, y - diff],
|
||||
[x - diff, y - diff],
|
||||
[x - diff, y + diff],
|
||||
[x + diff, y + diff]
|
||||
])
|
||||
|
||||
# Define input and output file paths
|
||||
geojson_file = Path("./input_files/roads.json").resolve()
|
||||
output_file = Path('./input_files/output_roads.geojson').resolve()
|
||||
|
||||
# Initialize a list to store the roads in the region
|
||||
roads_in_region = []
|
||||
|
||||
# Read the GeoJSON file
|
||||
with open(geojson_file, 'r') as file:
|
||||
roads = json.load(file)
|
||||
line_features = [feature for feature in roads['features'] if feature['geometry']['type'] == 'LineString']
|
||||
|
||||
# Check each road feature
|
||||
for feature in line_features:
|
||||
road_shape = shape(feature['geometry'])
|
||||
# Check if any node of the road is inside the selection box
|
||||
if any(selection_box.contains(Point(coord)) for coord in road_shape.coords):
|
||||
roads_in_region.append(feature)
|
||||
|
||||
# Create a new GeoJSON structure with the selected roads
|
||||
output_geojson = {
|
||||
"type": "FeatureCollection",
|
||||
"features": roads_in_region
|
||||
}
|
||||
|
||||
# Write the selected roads to the output file
|
||||
with open(output_file, 'w') as outfile:
|
||||
json.dump(output_geojson, outfile)
|
||||
|
||||
return output_file
|
80
scripts/district_heating_network/simultinity_factor.py
Normal file
80
scripts/district_heating_network/simultinity_factor.py
Normal file
|
@ -0,0 +1,80 @@
|
|||
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
|
|
@ -16,7 +16,8 @@ class Archetype1:
|
|||
self._domestic_hot_water_peak_load = building.domestic_hot_water_peak_load[cte.YEAR][0]
|
||||
self._hourly_heating_demand = [0] + [demand / 3600 for demand in building.heating_demand[cte.HOUR]]
|
||||
self._hourly_cooling_demand = [demand / 3600 for demand in building.cooling_demand[cte.HOUR]]
|
||||
self._hourly_dhw_demand = building.domestic_hot_water_heat_demand[cte.HOUR]
|
||||
self._hourly_dhw_demand = [demand / cte.WATTS_HOUR_TO_JULES for demand in
|
||||
building.domestic_hot_water_heat_demand[cte.HOUR]]
|
||||
self._output_path = output_path
|
||||
self._t_out = [0] + building.external_temperature[cte.HOUR]
|
||||
self.results = {}
|
||||
|
@ -27,9 +28,9 @@ class Archetype1:
|
|||
heat_pump = self._hvac_system.generation_systems[0]
|
||||
boiler = self._hvac_system.generation_systems[1]
|
||||
thermal_storage = heat_pump.energy_storage_systems[0]
|
||||
heat_pump.nominal_heat_output = round(0.5 * self._heating_peak_load / 3600)
|
||||
heat_pump.nominal_cooling_output = round(self._cooling_peak_load / 3600)
|
||||
boiler.nominal_heat_output = round(0.5 * self._heating_peak_load / 3600)
|
||||
heat_pump.nominal_heat_output = round(0.5 * self._heating_peak_load)
|
||||
heat_pump.nominal_cooling_output = round(self._cooling_peak_load)
|
||||
boiler.nominal_heat_output = round(0.5 * self._heating_peak_load)
|
||||
thermal_storage.volume = round(
|
||||
(self._heating_peak_load * storage_factor * cte.WATTS_HOUR_TO_JULES) /
|
||||
(cte.WATER_HEAT_CAPACITY * cte.WATER_DENSITY * 25))
|
||||
|
|
546
work_in_progress.ipynb
Normal file
546
work_in_progress.ipynb
Normal file
|
@ -0,0 +1,546 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"id": "initial_id",
|
||||
"metadata": {
|
||||
"collapsed": true,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-02T12:57:37.696565Z",
|
||||
"start_time": "2024-08-02T12:57:36.171119Z"
|
||||
}
|
||||
},
|
||||
"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": 1
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-02T12:57:39.137773Z",
|
||||
"start_time": "2024-08-02T12:57:39.125428Z"
|
||||
}
|
||||
},
|
||||
"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": 2
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-02T12:57:55.109576Z",
|
||||
"start_time": "2024-08-02T12:57:40.139063Z"
|
||||
}
|
||||
},
|
||||
"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": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"execution_count": 3
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-02T12:57:56.302754Z",
|
||||
"start_time": "2024-08-02T12:57:55.998185Z"
|
||||
}
|
||||
},
|
||||
"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": 4
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-02T12:57:57.451734Z",
|
||||
"start_time": "2024-08-02T12:57:57.072693Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": "ConstructionFactory('nrcan', city).enrich()",
|
||||
"id": "c7d73638802e40d9",
|
||||
"outputs": [],
|
||||
"execution_count": 5
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-02T12:57:59.217403Z",
|
||||
"start_time": "2024-08-02T12:57:58.188682Z"
|
||||
}
|
||||
},
|
||||
"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": 6
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-02T12:58:03.733492Z",
|
||||
"start_time": "2024-08-02T12:58:03.184816Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": "WeatherFactory('epw', city).enrich()",
|
||||
"id": "f66c01cb42c33b64",
|
||||
"outputs": [],
|
||||
"execution_count": 7
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-02T12:59:40.634144Z",
|
||||
"start_time": "2024-08-02T12:58:05.175534Z"
|
||||
}
|
||||
},
|
||||
"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_6bc439.idf\r\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 8
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-02T13:07:12.099372Z",
|
||||
"start_time": "2024-08-02T13:07:07.642747Z"
|
||||
}
|
||||
},
|
||||
"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": [],
|
||||
"execution_count": 9
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "code",
|
||||
"outputs": [],
|
||||
"execution_count": null,
|
||||
"source": "",
|
||||
"id": "fb74382fc70b6933"
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "code",
|
||||
"outputs": [],
|
||||
"execution_count": null,
|
||||
"source": "",
|
||||
"id": "9898d47485af4e62"
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "code",
|
||||
"outputs": [],
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"from scripts.district_heating_network.district_heating_factory import DistrictHeatingFactory\n",
|
||||
"\n",
|
||||
"DistrictHeatingFactory(city=city, graph=network_graph).enrich()"
|
||||
],
|
||||
"id": "1230e418a231389d"
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-02T13:08:04.652085Z",
|
||||
"start_time": "2024-08-02T13:08:04.639087Z"
|
||||
}
|
||||
},
|
||||
"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', 'name']\n",
|
||||
"Node (-73.70236957992, 45.530697070843594) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.7023772579133, 45.52982887967387) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70310348189996, 45.530242710105696) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70219141578475, 45.5309810002753) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.7015878987858, 45.53110506016847) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70197756808213, 45.531335127032875) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70171824652937, 45.53119684899265) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70181225980849, 45.53125598840158) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70212216033907, 45.53141309516707) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70224797036111, 45.531522088920134) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70319066728962, 45.53075184355254) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70309318391786, 45.53066844829803) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70326346262547, 45.53124343502157) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70289161913149, 45.53100954740511) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.7031243168426, 45.52969124795911) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70332165936908, 45.531298238343524) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70291683392738, 45.531464843960194) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70257423757026, 45.53123533603945) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70246354979903, 45.53116600989907) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70137270924536, 45.53098156462814) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70228611728258, 45.52973374332967) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70192277090158, 45.530832193189546) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70247403248253, 45.530300013163604) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70233258364674, 45.53021274328478) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70150159992788, 45.530157998392504) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70178207574742, 45.53033147043354) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70279118480165, 45.53007116190442) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70290386342012, 45.53015742711493) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70199360008198, 45.529972641218336) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.7032815855412, 45.52978985115031) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70166271484868, 45.53063422765041) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.7015006171488, 45.530550593136034) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70265213028476, 45.529962782747816) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.7029326957311, 45.53056979610127) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70166661687237, 45.5297928936099) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70193452736822, 45.53043505670828) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70320906423977, 45.53033165241546) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70242433058544, 45.531020523149344) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70229173916934, 45.53104634226288) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70164581777142, 45.53024975981883) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70181323564402, 45.52988517687263) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70207977647193, 45.53050710203167) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70180201572698, 45.53073366018695) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70260551746348, 45.53038579346295) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.7015368490746, 45.531520903846236) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70277909755795, 45.530494359508104) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.7016306503588, 45.531601992190964) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.703188128229, 45.531634438129004) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70225201894137, 45.5306050266003) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70250211711432, 45.53079519337939) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70143287673753, 45.53147394391961) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.7015564456529, 45.52971249323039) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70213321668199, 45.530060293550356) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70205098392802, 45.53092949418992) has attributes: ['type', 'name']\n",
|
||||
"Node (-73.70273955351598, 45.53092005042424) has attributes: ['type', 'name']\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 13
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T13:46:14.045488Z",
|
||||
"start_time": "2024-08-01T13:46:14.025941Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"for node in network_graph.nodes(data=True):\n",
|
||||
" node_id, node_attrs = node\n",
|
||||
" if node_attrs.get('name') == '65418':\n",
|
||||
" building_demand = node_attrs.get('_heating_demand')\n",
|
||||
" print(building_demand[\"hour\"][1])"
|
||||
],
|
||||
"id": "f7c0742941b4f2d1",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"10687074.91690603\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 24
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-01T14:02:29.592771Z",
|
||||
"start_time": "2024-08-01T14:02:29.549689Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"import CoolProp.CoolProp as CP\n",
|
||||
"\n",
|
||||
"# Define the fluid\n",
|
||||
"fluid = 'Water'\n",
|
||||
"\n",
|
||||
"# Define the state properties\n",
|
||||
"temperature = 300 # Temperature in Kelvin\n",
|
||||
"pressure = 101325 # Pressure in Pascals (1 atm)\n",
|
||||
"\n",
|
||||
"# Calculate specific heat capacity at constant pressure (Cp)\n",
|
||||
"cp = CP.PropsSI('C', 'T', temperature, 'P', pressure, fluid)\n",
|
||||
"\n",
|
||||
"print(f\"The specific heat capacity of water at {temperature} K and {pressure} Pa is {cp} J/kg.K\")"
|
||||
],
|
||||
"id": "954e9fbbfe3dbe87",
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"The specific heat capacity of water at 300 K and 101325 Pa is 4180.6357765560715 J/kg.K\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 25
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-08-02T12:47:52.738098Z",
|
||||
"start_time": "2024-08-02T12:47:52.701565Z"
|
||||
}
|
||||
},
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"import math\n",
|
||||
"import logging\n",
|
||||
"supply_temperature = 60\n",
|
||||
"return_temperature = 40\n",
|
||||
"\n",
|
||||
"for node in network_graph.nodes(data=True):\n",
|
||||
" node_id, node_attrs = node\n",
|
||||
" if node_attrs.get('type') == 'building':\n",
|
||||
" heating_peak_load = node_attrs.get('heating_peak_load') # Adjusted key to match your data\n",
|
||||
" print(heating_peak_load['year'][0])\n",
|
||||
" # if heating_peak_load:\n",
|
||||
" # # Calculate peak mass flow rate\n",
|
||||
" # peak_mass_flow_rate = heating_peak_load['year'][0] / CP.PropsSI('C',\n",
|
||||
" # 'T',\n",
|
||||
" # (\n",
|
||||
" # supply_temperature +\n",
|
||||
" # return_temperature\n",
|
||||
" # ) / 2,\n",
|
||||
" # 'P',\n",
|
||||
" # 101325,\n",
|
||||
" # fluid)\n",
|
||||
" # print(peak_mass_flow_rate)\n",
|
||||
" # # Calculate density of the fluid\n",
|
||||
" # density = CP.PropsSI('D', # 'D' for density\n",
|
||||
" # 'T',\n",
|
||||
" # (\n",
|
||||
" # supply_temperature +\n",
|
||||
" # return_temperature\n",
|
||||
" # ) / 2,\n",
|
||||
" # 'P',\n",
|
||||
" # 101325,\n",
|
||||
" # fluid)\n",
|
||||
" # \n",
|
||||
" # # Set the design velocity (V)\n",
|
||||
" # velocity = 0.9 # m/s\n",
|
||||
" # \n",
|
||||
" # # Calculate the diameter (D)\n",
|
||||
" # D = math.sqrt((4 * peak_mass_flow_rate) / (density * velocity * math.pi)) # m\n",
|
||||
" # print(D)\n",
|
||||
" # # Find the edge connected to the building node\n",
|
||||
" # for neighbor in network_graph.neighbors(node_id):\n",
|
||||
" # if not network_graph.nodes[neighbor].get('type') == 'building': # Ensure it's a pipe connection\n",
|
||||
" # network_graph.edges[node_id, neighbor]['diameter'] = D\n",
|
||||
" # logging.info(f\"Diameter for edge ({node_id}, {neighbor}) set to {D} meters.\")\n"
|
||||
],
|
||||
"id": "84557dd2ba1070e0",
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "TypeError",
|
||||
"evalue": "'NoneType' object is not subscriptable",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
|
||||
"\u001B[1;31mTypeError\u001B[0m Traceback (most recent call last)",
|
||||
"Cell \u001B[1;32mIn[28], line 10\u001B[0m\n\u001B[0;32m 8\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m node_attrs\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mtype\u001B[39m\u001B[38;5;124m'\u001B[39m) \u001B[38;5;241m==\u001B[39m \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mbuilding\u001B[39m\u001B[38;5;124m'\u001B[39m:\n\u001B[0;32m 9\u001B[0m heating_peak_load \u001B[38;5;241m=\u001B[39m node_attrs\u001B[38;5;241m.\u001B[39mget(\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mheating_peak_load\u001B[39m\u001B[38;5;124m'\u001B[39m) \u001B[38;5;66;03m# Adjusted key to match your data\u001B[39;00m\n\u001B[1;32m---> 10\u001B[0m \u001B[38;5;28mprint\u001B[39m(\u001B[43mheating_peak_load\u001B[49m\u001B[43m[\u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43myear\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m]\u001B[49m[\u001B[38;5;241m0\u001B[39m])\n",
|
||||
"\u001B[1;31mTypeError\u001B[0m: 'NoneType' object is not subscriptable"
|
||||
]
|
||||
}
|
||||
],
|
||||
"execution_count": 28
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "code",
|
||||
"outputs": [],
|
||||
"execution_count": null,
|
||||
"source": "",
|
||||
"id": "11ebedbf06ddfe38"
|
||||
}
|
||||
],
|
||||
"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
|
||||
}
|
Loading…
Reference in New Issue
Block a user