diff --git a/__pycache__/matsim.cpython-39.pyc b/__pycache__/matsim.cpython-39.pyc index 0a7fc62..0c7f12c 100644 Binary files a/__pycache__/matsim.cpython-39.pyc and b/__pycache__/matsim.cpython-39.pyc differ diff --git a/__pycache__/matsim_visualizer.cpython-39.pyc b/__pycache__/matsim_visualizer.cpython-39.pyc index ec8867f..d0798ab 100644 Binary files a/__pycache__/matsim_visualizer.cpython-39.pyc and b/__pycache__/matsim_visualizer.cpython-39.pyc differ diff --git a/main.py b/main.py index 2a5ae59..c145760 100644 --- a/main.py +++ b/main.py @@ -1,3 +1,4 @@ +import json from pathlib import Path from hub.imports.geometry_factory import GeometryFactory @@ -10,7 +11,7 @@ from matsim import Matsim from matsim_visualizer import MatsimVisualizer 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' usage_format = 'nrcan' energy_systems_format = 'montreal_custom' @@ -18,7 +19,7 @@ try: out_path = (Path(__file__).parent / 'output_files') city = GeometryFactory('geojson', path=file_path, - height_field='ETAGE_HORS', + height_field='citygml_me', year_of_construction_field='ANNEE_CONS', function_field='CODE_UTILI', function_to_hub=Dictionaries().montreal_function_to_hub_function).city @@ -31,10 +32,13 @@ try: visualizer = MatsimVisualizer( 'output_files/Montreal', 'output_files', - (3854635.608067, 6040255.047194, 3855550.392442, 6039416.667303) + (3854635.608067, 6040255.047194, 3855550.392442, 6039416.667303), + True ) visualizer.visualize() except Exception as ex: print('error: ', ex) print('[simulation abort]') + + diff --git a/matsim.py b/matsim.py index f08cced..b11eede 100644 --- a/matsim.py +++ b/matsim.py @@ -55,60 +55,59 @@ class Matsim: """ 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']) for building in self._city.buildings: - facility = { - 'id': building.name, - 'x': str(building.centroid[0]), - 'y': str(building.centroid[1]), - 'activity': [] - } + try: + facility = { + 'id': building.name, + 'x': str(building.centroid[0]), + 'y': str(building.centroid[1]), + 'activity': [] + } - if len(building.thermal_zones_from_internal_zones) > 1: - raise NotImplementedError("multi-zone buildings aren't yet supported") + if len(building.thermal_zones_from_internal_zones) > 1: + raise NotImplementedError("multi-zone buildings aren't yet supported") - building_schedules = [] + building_schedules = [] - capacity = 0 - for thermal_zone in building.thermal_zones_from_internal_zones: - capacity = thermal_zone.occupancy.occupancy_density * building.floor_area * building.storeys_above_ground - for schedule in thermal_zone.occupancy.occupancy_schedules: - building_schedules.append(schedule) + capacity = 0 + for thermal_zone in building.thermal_zones_from_internal_zones: + capacity = thermal_zone.occupancy.occupancy_density * building.floor_area * building.storeys_above_ground + for schedule in thermal_zone.occupancy.occupancy_schedules: + building_schedules.append(schedule) - activity_info = { - 'type': building.function, - 'capacity': math.ceil(capacity), - 'opentime': _convert_schedules(building_schedules) - } + activity_info = { + 'type': building.function, + 'capacity': math.ceil(capacity), + 'opentime': _convert_schedules(building_schedules) + } - facility_xml = etree.SubElement(facilities_xml, 'facility', { - 'id': f"{facility['id']}", - 'x': f"{facility['x']}", - 'y': f"{facility['y']}", - }) + facility_xml = etree.SubElement(facilities_xml, 'facility', { + 'id': f"{facility['id']}", + 'x': f"{facility['x']}", + 'y': f"{facility['y']}", + }) - activity_xml = etree.SubElement(facility_xml, 'activity', { - 'type': f"{activity_info['type']}" - }) + activity_xml = etree.SubElement(facility_xml, 'activity', { + 'type': f"{activity_info['type']}" + }) - etree.SubElement(activity_xml, 'capacity', { - 'value': f"{activity_info['capacity']}" - }) + etree.SubElement(activity_xml, 'capacity', { + 'value': f"{activity_info['capacity']}" + }) - etree.SubElement(activity_xml, 'opentime', { - 'day': f"{activity_info['opentime'][0]['day']}", - 'start_time': f"{activity_info['opentime'][0]['start_time']}", - 'end_time': f"{activity_info['opentime'][0]['end_time']}" - }) + etree.SubElement(activity_xml, 'opentime', { + 'day': f"{activity_info['opentime'][0]['day']}", + 'start_time': f"{activity_info['opentime'][0]['start_time']}", + 'end_time': f"{activity_info['opentime'][0]['end_time']}" + }) - facility['activity'].append(activity_info) - self._facilities['facility'].append(facility) + facility['activity'].append(activity_info) + 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)]) @@ -142,76 +141,80 @@ class Matsim: """ Generates and exports the city's population data to an XML file. """ - population = etree.Element("population") - id = 0 + try: - # Generate work facilities - work = [] - 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' - }) + population = etree.Element("population") + id = 0 - # Generate the population from residential places first - 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'}) - - # 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' + # Generate work facilities + work = [] + 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' }) - # Leg to work - etree.SubElement(plan, 'leg', {'mode': 'car'}) + # Generate the population from residential places first + 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 - etree.SubElement(plan, 'act', { - 'type': f"{work[current_work]['type']}", - 'facility': f"{work[current_work]['facility']}", - 'x': f"{work[current_work]['x']}", - 'y': f"{work[current_work]['y']}", - 'start_time': f"{work[current_work]['start_time']}", - 'end_time': f"{work[current_work]['end_time']}", - }) + # 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 home - etree.SubElement(plan, 'leg', {'mode': 'car'}) + # Leg to work + etree.SubElement(plan, 'leg', {'mode': 'car'}) - # 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 activity + etree.SubElement(plan, 'act', { + 'type': f"{work[current_work]['type']}", + 'facility': f"{work[current_work]['facility']}", + 'x': f"{work[current_work]['x']}", + '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 - if work[current_work]['capacity'] == 0: - current_work += 1 + # Leg to home + etree.SubElement(plan, 'leg', {'mode': 'car'}) - 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 xml_content = etree.tostring(population, pretty_print=True, encoding='UTF-8').decode('utf-8') diff --git a/matsim_visualizer.py b/matsim_visualizer.py index 501688f..d5b87f8 100644 --- a/matsim_visualizer.py +++ b/matsim_visualizer.py @@ -92,11 +92,14 @@ class MatsimVisualizer: with gzip.open(self._events_file_path, 'rb') as file: events_doc = etree.parse(file) + current_time = None self._tick = 0 for event in events_doc.xpath('/events/event'): link_id = event.get('link') event_type = event.get('type') time = float(event.get('time')) + if current_time is None: + current_time = float(event.get('time')) ticked = False 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 ticked = True - if ticked: + if ticked and current_time != time: self._tick += 1 + current_time = time def _create_graph(self): for node_id, coords in self._nodes.items():