Compare commits

...

13 Commits

11 changed files with 1586244 additions and 62 deletions

1585013
input_files/roads.json Normal file

File diff suppressed because it is too large Load Diff

116
main.py
View File

@ -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}")

View File

@ -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,

View 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)

View 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.")

View File

@ -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()

View 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

View 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

View 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

View File

@ -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
View 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
}