From c566168b1987d68716ea1d0e66899c9a28d2c453 Mon Sep 17 00:00:00 2001 From: Ruben1729 Date: Tue, 6 Feb 2024 16:52:33 -0500 Subject: [PATCH] Matsim exporter. Generates population and config --- __pycache__/matsim.cpython-39.pyc | Bin 0 -> 6509 bytes __pycache__/matsim_engine.cpython-39.pyc | Bin 2920 -> 1004 bytes main.py | 5 +- matsim.py | 266 +++++++++++++++++++++++ matsim_engine.py | 119 +--------- 5 files changed, 272 insertions(+), 118 deletions(-) create mode 100644 __pycache__/matsim.cpython-39.pyc create mode 100644 matsim.py diff --git a/__pycache__/matsim.cpython-39.pyc b/__pycache__/matsim.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..69dfed82e9a0951a5747760ecd9790ccdce69a86 GIT binary patch literal 6509 zcmaJ_TXP)8b)NgoUa$ZG5WI>aDeJP50RmKP(X=dsBuGV0gfJwPR3?c zo?eo>HCw3&%1f$LcBS$ZLsj5Q%KihX%1a*dU9nJH`d>-^)tM*s93P5Tdenf^2JvW_Pc5KLowqWMLt`?`8Jd_$$C zZ>rStEtT57gVadew�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 Myk0eHf2B4557y>)C;$Ke literal 0 HcmV?d00001 diff --git a/__pycache__/matsim_engine.cpython-39.pyc b/__pycache__/matsim_engine.cpython-39.pyc index 2e6783ea4e01665f007dd38b74fadb386f13b847..2fc4117563c4ac98017ee3a6f18ba3cd2f4e6571 100644 GIT binary patch delta 446 zcmZ8dJ5Iwu5Zxb%?R*GA;sR8b0ErH0fi?}D1+o^e^>^1;AEU|)}KaYkN;yZD9}{9`6Jeh#ioV}lzM zB7v@ukHAqGa7{D^A;#K_xdW;G{)Su&{i|gN34YTV$bNy5bDUrT3

{cjxXtawjK(=wzMyl}Z*pDP2*B*FM_~Ea*(m(U%_)$Dt zKkN<|9R&NiCQyS^!;a zRfVe_`r)0Z??>D|NK5O3&F9!hnJMwq$Si3BEc6Ya zTjw~lQ#7;=jc4fNe`Lkf8Wz&x(B3jGinQ z-RkGYbA$|_6g5TG(lT|n41lFAV~X|O=^suXX->HUu&#HfXpUkvxt)(l&wP6b=>n#J|M$35L01i#P0z8eZo>oD- zy1xAxI>o2|PPG;P${J~dR^{f!R$6yJ&4{bjmJ8@XSXJ83grqpRoU+>$Rr!Ut)EHgm4kIdwZVDFP{LIkl4e{Fb~v z+)H(I-=eM0aCRlVa&d#M>pl7Q@OyA#1Kum2nc1fNeu_Ug=qB(&H0jnC7TuoWKW}GS z>DI*$(oKEl_fR_)yi*eyQS&|H85Y5h4V1qh0i-+GHr>s3(rtP*-J#d$dM@+&7r1X{ zyYiijAEvun4mBX3_m13h&+GbuFMTE^YY*Z`a^?klcbCLAo)kKf7c%9{Imd0RuuqlK zXK~0RAHPID;zh`M?r4AjywIR+P0Wr@C%E$ojInaOdA&~B;V6*){v?jr-pR-hs2}yk zp2u1Aj@%nFxhF+ZixYCM_8E1F<}7;1CZELo z@qUlT;eIT_gQ3S?TKfPeH!f=tGTvu&!G54Qlat=0eseBBOF!sO+HF-J+8gdFiAQo_ z1xY+P;Fh*i`$m?4ZFz&~Zs&wO+ zLzFzpgtEN^98Z;{vx4j9sZ1d`L2!o6{8w=u{#Al4mbXRMy z4~h8)K`0B{KTuYe`GG32XatIbEy~W5ODKo4GsXo2qXJ(@Rf6;(I^Bda`w4Zc_gH-B zN$)Pt3qf!}wDE3H#(CDL5`;s>+O?`UiV_cGDNE<4Dm>vn+*B5$lZ3}zCO{+~MeVD~ z5-jL}PC9yx{|}y9f1OE0%XK#fqZ6_S7=ept8RgbzGg%nxwwA%3WiX+jxpEfNJpENs zj5yrDR3Q&-UJh<^!Lt-5cvZ)@dO4QLSzc9**b}lSYqz$*AkMwmt!n$BvdJJGakttH zVzF2$@ znN8S(eY`!N%OJr49B%lwVK;FLPGe-fvI}LiVQ!;$EjWdNqB)TBwN;#~Ke+VAaj?+2 zt2^xC(S@$-Jpc9B1B9XsemF9mB5J0%Z^AE!ae>nOxj32Z&IGQNOvK=4um%5 z@597D(745artw1!?r3mV1MTw}xUVtIIfWr~^Eb57s9cyd{zqxZ_oH?}J6u-{A*xJB z80%j(z^jCuj=W&D!#@Nexy(!VIwcHtW_g#<-z!1@yW{DmV0An{W61JSJkor^8V>we{=0E56)Vx*5yrVE9Vz8Yk#SO RCbR*dJLHaosu*&q@LvE4Oi%y- diff --git a/main.py b/main.py index 70275e2..c26bfc8 100644 --- a/main.py +++ b/main.py @@ -6,7 +6,7 @@ from hub.imports.usage_factory import UsageFactory from hub.helpers.dictionaries import Dictionaries from matsim_engine import MatSimEngine -from matsim_visualizer import MatSimVisualizer +from matsim import Matsim try: file_path = (Path(__file__).parent / 'input_files' / 'summerschool_all_buildings.geojson') @@ -24,7 +24,8 @@ try: ConstructionFactory(construction_format, city).enrich() UsageFactory(usage_format, city).enrich() - MatSimEngine(city, 'output_files') + # Matsim(city, 'output_files')._export() + MatSimEngine('output_files/Montreal_config.xml').run() # visualizer = MatSimVisualizer('output_files/network.xml.gz', 'output_files/output_events.xml.gz') # visualizer.visualize() diff --git a/matsim.py b/matsim.py new file mode 100644 index 0000000..acf3fc4 --- /dev/null +++ b/matsim.py @@ -0,0 +1,266 @@ +import math +import subprocess +import xmltodict +import gzip +import shutil + +import geopandas as gpd +from shapely.geometry import Point +import hub.helpers.constants as cte +from lxml import etree + +# TODO: remove xmltodict completely and replace with lxml as it doesnt allow for repeated mixed ordered tags +class Matsim: + def __init__(self, city, output_file_path): + self.city = city + self.output_file_path = output_file_path + + self.facilities = { + '@name': self.city.name + ' Facilities', + 'facility': [] + } + + self.population = etree.Element("population") + + def _export(self): + self._export_facilities() + self._export_network() + self._export_population() + self._export_config() + + def _export_facilities(self): + buildings_shape_data = { + 'id': [], + 'geometry': [] + } + + for building in self.city.buildings: + for surface in building.grounds: + for coord in surface.solid_polygon.coordinates: + buildings_shape_data['id'].append(f"{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': [] + } + + if len(building.thermal_zones_from_internal_zones) > 1: + raise NotImplementedError("multi-zone buildings aren't yet supported") + + 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) + + activity_info = { + '@type': building.function, + 'capacity': { + '@value': math.ceil(capacity) + }, + 'opentime': _convert_schedules(building_schedules) + } + + facility['activity'].append(activity_info) + self.facilities['facility'].append(facility) + + gdf = gpd.GeoDataFrame( + buildings_shape_data, + crs=self.city.srs_name + ) + gdf.to_file("input_files/buildings_shapefile.shp") + + # Convert the Python dictionary to an XML string + xml_content = xmltodict.unparse({'facilities': self.facilities}, pretty=True, short_empty_elements=True) + + # Write the XML to the file + output_file = f"{self.output_file_path}/{self.city.name}_facilities.xml" + with open(output_file, 'w') as file: + file.write(xml_content) + + with open(output_file, 'rb') as f_in: + with gzip.open(output_file + '.gz', 'wb') as f_out: + shutil.copyfileobj(f_in, f_out) + + def _export_network(self): + 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"{self.output_file_path}/{self.city.name}_network.xml.gz" + ] + subprocess.run(command) + + def _export_population(self): + id = 0 + + # 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']['@value']), + '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 + current_work = 0 + for facility in self.facilities['facility']: + if facility['activity'][0]['@type'] == cte.RESIDENTIAL: + max_capacity = int(facility['activity'][0]['capacity']['@value']) + for _ in range(max_capacity): + person = etree.SubElement(self.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': facility['activity'][0]['@type'], + 'facility': facility['@id'], + 'x': facility['@x'], + 'y': facility['@y'], + 'end_time': '7:30:00' + }) + + # Leg to work + etree.SubElement(plan, 'leg', {'mode': 'car'}) + + # Work activity + etree.SubElement(plan, 'act', { + 'type': work[current_work]['type'], + 'facility': work[current_work]['facility'], + 'x': work[current_work]['x'], + 'y': work[current_work]['y'], + 'start_time': work[current_work]['start_time'], + 'end_time': work[current_work]['end_time'], + }) + + # Leg to home + etree.SubElement(plan, 'leg', {'mode': 'car'}) + + # Residential activity (return) + etree.SubElement(plan, 'act', { + 'type': facility['activity'][0]['@type'], + 'facility': facility['@id'], + 'x': facility['@x'], + 'y': facility['@y'], + }) + + work[current_work]['capacity'] -= 1 + if work[current_work]['capacity'] == 0: + current_work += 1 + + id += 1 + + # Convert the Python dictionary to an XML string + xml_content = etree.tostring(self.population, pretty_print=True, encoding='UTF-8', xml_declaration=True).decode('utf-8') + + # Write the XML to the file + output_file = f"{self.output_file_path}/{self.city.name}_population.xml" + with open(output_file, 'w') as file: + file.write(xml_content) + + with open(output_file, 'rb') as f_in: + with gzip.open(output_file + '.gz', 'wb') as f_out: + shutil.copyfileobj(f_in, f_out) + + def _export_config(self): + parameterset = [] + + for facility in self.facilities['facility']: + if facility['activity'][0]['@type'] == cte.RESIDENTIAL: + parameterset.append({'@type':'activityParams', 'param': [ + {'@name':'activityType','@value':facility['activity'][0]['@type']}, + {'@name':'typicalDuration', '@value' : '12:00:00'}, + {'@name':'priority','@value': '1'} + ]}) + else: + parameterset.append({'@type':'activityParams', 'param': [ + {'@name': 'activityType', '@value': facility['activity'][0]['@type']}, + {'@name':'openingTime','@value': '08:00:00'}, + {'@name':'closingTime','@value': '18:00:00'}, + {'@name':'typicalDuration','@value': '08:00:00'}, + {'@name':'priority','@value': '1'} + ] + }) + + config = { + 'module': [ + {'@name': 'network', 'param': {'@name':'inputNetworkFile', '@value': f"{self.city.name}_network.xml.gz"}}, + {'@name': 'plans', 'param': {'@name':'inputPlansFile', '@value': f"{self.city.name}_population.xml.gz"}}, + {'@name': 'facilities', 'param': {'@name':'inputFacilitiesFile', '@value': f"{self.city.name}_facilities.xml.gz"}}, + {'@name': 'controler', 'param': [ + {'@name': 'outputDirectory', '@value': '/output'}, + {'@name': 'firstIteration', '@value': '0'}, + {'@name': 'lastIteration', '@value': '10'}, + ]}, + {'@name': 'qsim', 'param': [ + {'@name': 'startTime', '@value': '00:00:00'}, + {'@name': 'endTime', '@value': '00:00:00'}, + {'@name': 'snapshotperiod', '@value': '00:00:00'}, + ]}, + {'@name':'planCalcStore','param':[ + {'@name':'learningRate', '@value':'1.0'}, + {'@name':'BrainExpBeta', '@value':'2.0'}, + {'@name':'lateArrival', '@value':'-18'}, + {'@name':'earlyDeparture', '@value':'-0'}, + {'@name':'performing', '@value':'+6'}, + {'@name':'waiting', '@value':'-0'}, + ],'parameterset': parameterset}, + {'@name':'strategy','param':[ + {'@name': 'maxAgentPlanMemorySize', '@value': '5'}, + {'@name': 'ModuleProbability_1', '@value': '0.9'}, + {'@name': 'Module_1', '@value': 'BestScore'}, + {'@name': 'ModuleProbability_2', '@value': '0.1'}, + {'@name': 'Module_2', '@value': 'ReRoute'}, + ]} + ] + } + + xml_content = xmltodict.unparse({'config': config}, pretty=True, short_empty_elements=True) + + with open(f"{self.output_file_path}/{self.city.name}_config.xml", 'w') as file: + file.write(xml_content) + +def _convert_schedules(building_schedules): + converted_schedules = [] + for schedule in building_schedules: + opening_hour = 0 + closing_hour = 0 + + for i, value in enumerate(schedule.values): + if value > 0: + opening_hour = i + break + + for i, value in reversed(list(enumerate(schedule.values))): + if value > 0: + closing_hour = i + break + + for day in schedule.day_types: + if day[0:3] != 'hol': + converted_schedules.append({ + '@day': day[0:3], + '@start_time': opening_hour, + '@end_time': closing_hour + }) + return converted_schedules diff --git a/matsim_engine.py b/matsim_engine.py index 32dc968..6df3717 100644 --- a/matsim_engine.py +++ b/matsim_engine.py @@ -9,121 +9,8 @@ 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: this should come from the factories, please check idf generation - for building in city.buildings: - activity = hub_function_to_matsim.dictionary[building.function].split(',') - - for surface in building.grounds: - for coord in surface.solid_polygon.coordinates: - buildings_shape_data['id'].append(f"{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': [] - } - - if len(building.thermal_zones_from_internal_zones) > 1: - raise NotImplementedError("multi-zone buildings aren't yet supported") - - 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) - - for new_activity in activity: - activity_info = { - '@type': new_activity, - 'capacity': { - '@value': math.ceil(capacity) - }, - 'opentime': [] - } - - for schedule in building_schedules: - opening_hour = 0 - closing_hour = 0 - - # Find opening hour (first hour > 0) - for i, value in enumerate(schedule.values): - if value > 0: - opening_hour = i - break - - for i, value in reversed(list(enumerate(schedule.values))): - if value > 0: - closing_hour = i - break - - for day in schedule.day_types: - if day[0:3] != 'hol': - activity_info['opentime'].append({ - '@day': day[0:3], - '@start_time': opening_hour, - '@end_time': closing_hour - }) - - facility['activity'].append(activity_info) - - facilities_dict['facilities']['facility'].append(facility) - - gdf = gpd.GeoDataFrame( - buildings_shape_data, - crs=city.srs_name - ) - - gdf.to_file("input_files/buildings_shapefile.shp") - - # Convert the Python dictionary to an XML string - xml_content = xmltodict.unparse(facilities_dict, pretty=True, short_empty_elements=True) - - # Write the XML to the file - with open(f"{output_file_path}/{city.name}_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 - - # 3.1 - Public Transport - - # 4- Config Generation + def __init__(self, config_file_path): + self._config_file_path = config_file_path def run(self): java_path = "java" @@ -131,6 +18,6 @@ class MatSimEngine: command = [java_path, "-jar", jar_path] # Must generate this config file first. - # command.append(config_file_path) + command.append(self._config_file_path) subprocess.run(command)