Tick when time changes rather than on event
This commit is contained in:
parent
2ab91cfaeb
commit
35ec942d94
Binary file not shown.
Binary file not shown.
10
main.py
10
main.py
|
@ -1,3 +1,4 @@
|
||||||
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from hub.imports.geometry_factory import GeometryFactory
|
from hub.imports.geometry_factory import GeometryFactory
|
||||||
|
@ -10,7 +11,7 @@ from matsim import Matsim
|
||||||
from matsim_visualizer import MatsimVisualizer
|
from matsim_visualizer import MatsimVisualizer
|
||||||
|
|
||||||
try:
|
try:
|
||||||
file_path = (Path(__file__).parent / 'input_files' / 'mtlbld_v4.geojson')
|
file_path = (Path(__file__).parent / 'input_files' / 'summerschool_all_buildings.geojson')
|
||||||
construction_format = 'nrcan'
|
construction_format = 'nrcan'
|
||||||
usage_format = 'nrcan'
|
usage_format = 'nrcan'
|
||||||
energy_systems_format = 'montreal_custom'
|
energy_systems_format = 'montreal_custom'
|
||||||
|
@ -18,7 +19,7 @@ try:
|
||||||
out_path = (Path(__file__).parent / 'output_files')
|
out_path = (Path(__file__).parent / 'output_files')
|
||||||
city = GeometryFactory('geojson',
|
city = GeometryFactory('geojson',
|
||||||
path=file_path,
|
path=file_path,
|
||||||
height_field='ETAGE_HORS',
|
height_field='citygml_me',
|
||||||
year_of_construction_field='ANNEE_CONS',
|
year_of_construction_field='ANNEE_CONS',
|
||||||
function_field='CODE_UTILI',
|
function_field='CODE_UTILI',
|
||||||
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
|
function_to_hub=Dictionaries().montreal_function_to_hub_function).city
|
||||||
|
@ -31,10 +32,13 @@ try:
|
||||||
visualizer = MatsimVisualizer(
|
visualizer = MatsimVisualizer(
|
||||||
'output_files/Montreal',
|
'output_files/Montreal',
|
||||||
'output_files',
|
'output_files',
|
||||||
(3854635.608067, 6040255.047194, 3855550.392442, 6039416.667303)
|
(3854635.608067, 6040255.047194, 3855550.392442, 6039416.667303),
|
||||||
|
True
|
||||||
)
|
)
|
||||||
visualizer.visualize()
|
visualizer.visualize()
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print('error: ', ex)
|
print('error: ', ex)
|
||||||
print('[simulation abort]')
|
print('[simulation abort]')
|
||||||
|
|
||||||
|
|
||||||
|
|
207
matsim.py
207
matsim.py
|
@ -55,60 +55,59 @@ class Matsim:
|
||||||
"""
|
"""
|
||||||
Exports the city's facilities data to XML and shapefile formats.
|
Exports the city's facilities data to XML and shapefile formats.
|
||||||
"""
|
"""
|
||||||
buildings_shape_data = {
|
|
||||||
'id': [],
|
|
||||||
'geometry': []
|
|
||||||
}
|
|
||||||
|
|
||||||
facilities_xml = etree.Element('facilities', name=self._facilities['name'])
|
facilities_xml = etree.Element('facilities', name=self._facilities['name'])
|
||||||
|
|
||||||
for building in self._city.buildings:
|
for building in self._city.buildings:
|
||||||
facility = {
|
try:
|
||||||
'id': building.name,
|
facility = {
|
||||||
'x': str(building.centroid[0]),
|
'id': building.name,
|
||||||
'y': str(building.centroid[1]),
|
'x': str(building.centroid[0]),
|
||||||
'activity': []
|
'y': str(building.centroid[1]),
|
||||||
}
|
'activity': []
|
||||||
|
}
|
||||||
|
|
||||||
if len(building.thermal_zones_from_internal_zones) > 1:
|
if len(building.thermal_zones_from_internal_zones) > 1:
|
||||||
raise NotImplementedError("multi-zone buildings aren't yet supported")
|
raise NotImplementedError("multi-zone buildings aren't yet supported")
|
||||||
|
|
||||||
building_schedules = []
|
building_schedules = []
|
||||||
|
|
||||||
capacity = 0
|
capacity = 0
|
||||||
for thermal_zone in building.thermal_zones_from_internal_zones:
|
for thermal_zone in building.thermal_zones_from_internal_zones:
|
||||||
capacity = thermal_zone.occupancy.occupancy_density * building.floor_area * building.storeys_above_ground
|
capacity = thermal_zone.occupancy.occupancy_density * building.floor_area * building.storeys_above_ground
|
||||||
for schedule in thermal_zone.occupancy.occupancy_schedules:
|
for schedule in thermal_zone.occupancy.occupancy_schedules:
|
||||||
building_schedules.append(schedule)
|
building_schedules.append(schedule)
|
||||||
|
|
||||||
activity_info = {
|
activity_info = {
|
||||||
'type': building.function,
|
'type': building.function,
|
||||||
'capacity': math.ceil(capacity),
|
'capacity': math.ceil(capacity),
|
||||||
'opentime': _convert_schedules(building_schedules)
|
'opentime': _convert_schedules(building_schedules)
|
||||||
}
|
}
|
||||||
|
|
||||||
facility_xml = etree.SubElement(facilities_xml, 'facility', {
|
facility_xml = etree.SubElement(facilities_xml, 'facility', {
|
||||||
'id': f"{facility['id']}",
|
'id': f"{facility['id']}",
|
||||||
'x': f"{facility['x']}",
|
'x': f"{facility['x']}",
|
||||||
'y': f"{facility['y']}",
|
'y': f"{facility['y']}",
|
||||||
})
|
})
|
||||||
|
|
||||||
activity_xml = etree.SubElement(facility_xml, 'activity', {
|
activity_xml = etree.SubElement(facility_xml, 'activity', {
|
||||||
'type': f"{activity_info['type']}"
|
'type': f"{activity_info['type']}"
|
||||||
})
|
})
|
||||||
|
|
||||||
etree.SubElement(activity_xml, 'capacity', {
|
etree.SubElement(activity_xml, 'capacity', {
|
||||||
'value': f"{activity_info['capacity']}"
|
'value': f"{activity_info['capacity']}"
|
||||||
})
|
})
|
||||||
|
|
||||||
etree.SubElement(activity_xml, 'opentime', {
|
etree.SubElement(activity_xml, 'opentime', {
|
||||||
'day': f"{activity_info['opentime'][0]['day']}",
|
'day': f"{activity_info['opentime'][0]['day']}",
|
||||||
'start_time': f"{activity_info['opentime'][0]['start_time']}",
|
'start_time': f"{activity_info['opentime'][0]['start_time']}",
|
||||||
'end_time': f"{activity_info['opentime'][0]['end_time']}"
|
'end_time': f"{activity_info['opentime'][0]['end_time']}"
|
||||||
})
|
})
|
||||||
|
|
||||||
facility['activity'].append(activity_info)
|
facility['activity'].append(activity_info)
|
||||||
self._facilities['facility'].append(facility)
|
self._facilities['facility'].append(facility)
|
||||||
|
except Exception as ex:
|
||||||
|
print('error: ', ex)
|
||||||
|
|
||||||
viewport = Polygon([(MONTREAL_LEFT, MONTREAL_TOP), (MONTREAL_RIGHT, MONTREAL_TOP), (MONTREAL_RIGHT, MONTREAL_BOTTOM), (MONTREAL_LEFT, MONTREAL_BOTTOM)])
|
viewport = Polygon([(MONTREAL_LEFT, MONTREAL_TOP), (MONTREAL_RIGHT, MONTREAL_TOP), (MONTREAL_RIGHT, MONTREAL_BOTTOM), (MONTREAL_LEFT, MONTREAL_BOTTOM)])
|
||||||
|
|
||||||
|
@ -142,76 +141,80 @@ class Matsim:
|
||||||
"""
|
"""
|
||||||
Generates and exports the city's population data to an XML file.
|
Generates and exports the city's population data to an XML file.
|
||||||
"""
|
"""
|
||||||
population = etree.Element("population")
|
try:
|
||||||
id = 0
|
|
||||||
|
|
||||||
# Generate work facilities
|
population = etree.Element("population")
|
||||||
work = []
|
id = 0
|
||||||
for facility in self._facilities['facility']:
|
|
||||||
if facility['activity'][0]['type'] != cte.RESIDENTIAL:
|
|
||||||
work.append({
|
|
||||||
'type': facility['activity'][0]['type'],
|
|
||||||
'capacity': int(facility['activity'][0]['capacity']),
|
|
||||||
'facility': facility['id'],
|
|
||||||
'x': facility['x'],
|
|
||||||
'y': facility['y'],
|
|
||||||
'start_time': '08:00:00',
|
|
||||||
'end_time': '18:00:00'
|
|
||||||
})
|
|
||||||
|
|
||||||
# Generate the population from residential places first
|
# Generate work facilities
|
||||||
current_work = 0
|
work = []
|
||||||
for facility in self._facilities['facility']:
|
for facility in self._facilities['facility']:
|
||||||
if facility['activity'][0]['type'] == cte.RESIDENTIAL:
|
if facility['activity'][0]['type'] != cte.RESIDENTIAL:
|
||||||
max_capacity = int(facility['activity'][0]['capacity'])
|
work.append({
|
||||||
for i in range(max_capacity):
|
'type': facility['activity'][0]['type'],
|
||||||
person = etree.SubElement(population, 'person', {
|
'capacity': int(facility['activity'][0]['capacity']),
|
||||||
'id': str(id),
|
'facility': facility['id'],
|
||||||
'sex': 'm',
|
'x': facility['x'],
|
||||||
'age': '32',
|
'y': facility['y'],
|
||||||
'car_avail': 'always',
|
'start_time': '08:00:00',
|
||||||
'employed': 'yes',
|
'end_time': '18:00:00'
|
||||||
})
|
|
||||||
plan = etree.SubElement(person, 'plan', {'selected': 'yes'})
|
|
||||||
|
|
||||||
# Residential activity
|
|
||||||
etree.SubElement(plan, 'act', {
|
|
||||||
'type': f"{facility['activity'][0]['type']}",
|
|
||||||
'facility': f"{facility['id']}",
|
|
||||||
'x': f"{facility['x']}",
|
|
||||||
'y': f"{facility['y']}",
|
|
||||||
'end_time': '7:30:00'
|
|
||||||
})
|
})
|
||||||
|
|
||||||
# Leg to work
|
# Generate the population from residential places first
|
||||||
etree.SubElement(plan, 'leg', {'mode': 'car'})
|
current_work = 0
|
||||||
|
for facility in self._facilities['facility']:
|
||||||
|
if facility['activity'][0]['type'] == cte.RESIDENTIAL:
|
||||||
|
max_capacity = int(facility['activity'][0]['capacity'])
|
||||||
|
for i in range(max_capacity):
|
||||||
|
person = etree.SubElement(population, 'person', {
|
||||||
|
'id': str(id),
|
||||||
|
'sex': 'm',
|
||||||
|
'age': '32',
|
||||||
|
'car_avail': 'always',
|
||||||
|
'employed': 'yes',
|
||||||
|
})
|
||||||
|
plan = etree.SubElement(person, 'plan', {'selected': 'yes'})
|
||||||
|
|
||||||
# Work activity
|
# Residential activity
|
||||||
etree.SubElement(plan, 'act', {
|
etree.SubElement(plan, 'act', {
|
||||||
'type': f"{work[current_work]['type']}",
|
'type': f"{facility['activity'][0]['type']}",
|
||||||
'facility': f"{work[current_work]['facility']}",
|
'facility': f"{facility['id']}",
|
||||||
'x': f"{work[current_work]['x']}",
|
'x': f"{facility['x']}",
|
||||||
'y': f"{work[current_work]['y']}",
|
'y': f"{facility['y']}",
|
||||||
'start_time': f"{work[current_work]['start_time']}",
|
'end_time': '7:30:00'
|
||||||
'end_time': f"{work[current_work]['end_time']}",
|
})
|
||||||
})
|
|
||||||
|
|
||||||
# Leg to home
|
# Leg to work
|
||||||
etree.SubElement(plan, 'leg', {'mode': 'car'})
|
etree.SubElement(plan, 'leg', {'mode': 'car'})
|
||||||
|
|
||||||
# Residential activity (return)
|
# Work activity
|
||||||
etree.SubElement(plan, 'act', {
|
etree.SubElement(plan, 'act', {
|
||||||
'type': f"{facility['activity'][0]['type']}",
|
'type': f"{work[current_work]['type']}",
|
||||||
'facility': f"{facility['id']}",
|
'facility': f"{work[current_work]['facility']}",
|
||||||
'x': f"{facility['x']}",
|
'x': f"{work[current_work]['x']}",
|
||||||
'y': f"{facility['y']}",
|
'y': f"{work[current_work]['y']}",
|
||||||
})
|
'start_time': f"{work[current_work]['start_time']}",
|
||||||
|
'end_time': f"{work[current_work]['end_time']}",
|
||||||
|
})
|
||||||
|
|
||||||
work[current_work]['capacity'] -= 1
|
# Leg to home
|
||||||
if work[current_work]['capacity'] == 0:
|
etree.SubElement(plan, 'leg', {'mode': 'car'})
|
||||||
current_work += 1
|
|
||||||
|
|
||||||
id += 1
|
# Residential activity (return)
|
||||||
|
etree.SubElement(plan, 'act', {
|
||||||
|
'type': f"{facility['activity'][0]['type']}",
|
||||||
|
'facility': f"{facility['id']}",
|
||||||
|
'x': f"{facility['x']}",
|
||||||
|
'y': f"{facility['y']}",
|
||||||
|
})
|
||||||
|
|
||||||
|
work[current_work]['capacity'] -= 1
|
||||||
|
if work[current_work]['capacity'] == 0:
|
||||||
|
current_work += 1
|
||||||
|
|
||||||
|
id += 1
|
||||||
|
except Exception as ex:
|
||||||
|
print('error: ', ex)
|
||||||
|
|
||||||
# Write xml content to file
|
# Write xml content to file
|
||||||
xml_content = etree.tostring(population, pretty_print=True, encoding='UTF-8').decode('utf-8')
|
xml_content = etree.tostring(population, pretty_print=True, encoding='UTF-8').decode('utf-8')
|
||||||
|
|
|
@ -92,11 +92,14 @@ class MatsimVisualizer:
|
||||||
with gzip.open(self._events_file_path, 'rb') as file:
|
with gzip.open(self._events_file_path, 'rb') as file:
|
||||||
events_doc = etree.parse(file)
|
events_doc = etree.parse(file)
|
||||||
|
|
||||||
|
current_time = None
|
||||||
self._tick = 0
|
self._tick = 0
|
||||||
for event in events_doc.xpath('/events/event'):
|
for event in events_doc.xpath('/events/event'):
|
||||||
link_id = event.get('link')
|
link_id = event.get('link')
|
||||||
event_type = event.get('type')
|
event_type = event.get('type')
|
||||||
time = float(event.get('time'))
|
time = float(event.get('time'))
|
||||||
|
if current_time is None:
|
||||||
|
current_time = float(event.get('time'))
|
||||||
ticked = False
|
ticked = False
|
||||||
|
|
||||||
if link_id is not None and event_type is not None and time is not None:
|
if link_id is not None and event_type is not None and time is not None:
|
||||||
|
@ -115,8 +118,9 @@ class MatsimVisualizer:
|
||||||
cumulative_traffic[link_id] -= 1
|
cumulative_traffic[link_id] -= 1
|
||||||
ticked = True
|
ticked = True
|
||||||
|
|
||||||
if ticked:
|
if ticked and current_time != time:
|
||||||
self._tick += 1
|
self._tick += 1
|
||||||
|
current_time = time
|
||||||
|
|
||||||
def _create_graph(self):
|
def _create_graph(self):
|
||||||
for node_id, coords in self._nodes.items():
|
for node_id, coords in self._nodes.items():
|
||||||
|
|
Loading…
Reference in New Issue
Block a user