import subprocess import xmltodict import geopandas as gpd from shapely.geometry import Point from matsim_activity_to_matsim_schedule import MatsimActivityToMatsimSchedule from hub_function_to_matsim_activity import HubFunctionToMatsimActivity class MatSimEngine: def __init__(self, city, output_file_path): self._city = city self._output_file_path = output_file_path facilities_dict = { 'facilities': { '@name': 'Montreal Facilities', 'facility': [] } } hub_function_to_matsim = HubFunctionToMatsimActivity() matsim_schedule = MatsimActivityToMatsimSchedule() buildings_shape_data = { 'id': [], 'geometry': [] } # 1- Facilities # TODO: Add the ability for a building to have multiple activities for building in city.buildings: activity = hub_function_to_matsim.dictionary[building.function] schedule = matsim_schedule.dictionary[activity] start_time, end_time = schedule.split('-') new_id = 0 for surface in building.surfaces: for coord in surface.solid_polygon.coordinates: new_id += 1 buildings_shape_data['id'].append(f"{new_id}_building.name") buildings_shape_data['geometry'].append(Point(coord[0], coord[1])) facility = { '@id': building.name, '@x': str(building.centroid[0]), '@y': str(building.centroid[1]), 'activity': { '@type': activity, 'capacity': { '@value': '4.0' # TODO: Replace with a proper value taken from function }, 'opentime': { '@day': 'wkday', '@start_time': start_time, '@end_time': end_time } } } facilities_dict['facilities']['facility'].append(facility) gdf = gpd.GeoDataFrame( buildings_shape_data, crs="EPSG:26911" ) gdf.to_file("input_files/buildings_shapefile.shp") # Convert the Python dictionary to an XML string xml_content = xmltodict.unparse(facilities_dict, pretty=True) # Write the XML to the file with open(f"{output_file_path}/montreal_facilities.xml", 'w') as file: file.write(xml_content) # 2- Network # First get only the part of the network necessary for the simulation java_path = "java" jar_path = "matsim-network-from-osm.jar" command = [java_path, "-jar", jar_path, "input_files/merged-network.osm.pbf", "input_files/buildings_shapefile.shp", f"{output_file_path}/network.xml.gz"] subprocess.run(command) # 3- Population # 4- Config Generation def run(self): java_path = "java" jar_path = "matsim.jar" command = [java_path, "-jar", jar_path] # Must generate this config file first. # command.append(config_file_path) subprocess.run(command)