Compare commits
2 Commits
main
...
feature/ma
Author | SHA1 | Date | |
---|---|---|---|
b0b5916f0b | |||
c6f6498a23 |
2
hub/data/traffic/osm/.gitignore
vendored
Normal file
2
hub/data/traffic/osm/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.gitignore
|
||||
!.gitignore
|
File diff suppressed because it is too large
Load Diff
@ -1,157 +0,0 @@
|
||||
! Minimal.idf
|
||||
! Basic file description: This is a minimal configuration necessary to run.
|
||||
! Highlights: Illustrates minimal items necessary to perform run.
|
||||
! BUILDING, SURFACEGEOMETRY, LOCATION and DESIGNDAY (or RUNPERIOD) are the absolute minimal required input objects.
|
||||
! TIME STEP IN HOUR is included so as to not get warning error.
|
||||
! Including two design days, Run Control object and RunPeriod to facilitate use.
|
||||
! Although not incredibly useful, this could be used as a weather/solar calculator.
|
||||
! Simulation Location/Run: Denver is included. Any could be used.
|
||||
! Building: None.
|
||||
!
|
||||
! Internal gains description: None.
|
||||
!
|
||||
! HVAC: None.
|
||||
!
|
||||
|
||||
Version,9.5;
|
||||
|
||||
Timestep,4;
|
||||
|
||||
Building,
|
||||
None, !- Name
|
||||
0.0000000E+00, !- North Axis {deg}
|
||||
Suburbs, !- Terrain
|
||||
0.04, !- Loads Convergence Tolerance Value {W}
|
||||
0.40, !- Temperature Convergence Tolerance Value {deltaC}
|
||||
FullInteriorAndExterior, !- Solar Distribution
|
||||
25, !- Maximum Number of Warmup Days
|
||||
6; !- Minimum Number of Warmup Days
|
||||
|
||||
GlobalGeometryRules,
|
||||
UpperLeftCorner, !- Starting Vertex Position
|
||||
CounterClockWise, !- Vertex Entry Direction
|
||||
World; !- Coordinate System
|
||||
|
||||
Site:Location,
|
||||
DENVER_STAPLETON_CO_USA_WMO_724690, !- Name
|
||||
39.77, !- Latitude {deg}
|
||||
-104.87, !- Longitude {deg}
|
||||
-7.00, !- Time Zone {hr}
|
||||
1611.00; !- Elevation {m}
|
||||
|
||||
! DENVER_STAPLETON_CO_USA Annual Heating Design Conditions Wind Speed=2.3m/s Wind Dir=180
|
||||
! Coldest Month=December
|
||||
! DENVER_STAPLETON_CO_USA Annual Heating 99.6%, MaxDB=-20°C
|
||||
|
||||
SizingPeriod:DesignDay,
|
||||
DENVER_STAPLETON Ann Htg 99.6% Condns DB, !- Name
|
||||
12, !- Month
|
||||
21, !- Day of Month
|
||||
WinterDesignDay, !- Day Type
|
||||
-20, !- Maximum Dry-Bulb Temperature {C}
|
||||
0.0, !- Daily Dry-Bulb Temperature Range {deltaC}
|
||||
, !- Dry-Bulb Temperature Range Modifier Type
|
||||
, !- Dry-Bulb Temperature Range Modifier Day Schedule Name
|
||||
Wetbulb, !- Humidity Condition Type
|
||||
-20, !- Wetbulb or DewPoint at Maximum Dry-Bulb {C}
|
||||
, !- Humidity Condition Day Schedule Name
|
||||
, !- Humidity Ratio at Maximum Dry-Bulb {kgWater/kgDryAir}
|
||||
, !- Enthalpy at Maximum Dry-Bulb {J/kg}
|
||||
, !- Daily Wet-Bulb Temperature Range {deltaC}
|
||||
83411., !- Barometric Pressure {Pa}
|
||||
2.3, !- Wind Speed {m/s}
|
||||
180, !- Wind Direction {deg}
|
||||
No, !- Rain Indicator
|
||||
No, !- Snow Indicator
|
||||
No, !- Daylight Saving Time Indicator
|
||||
ASHRAEClearSky, !- Solar Model Indicator
|
||||
, !- Beam Solar Day Schedule Name
|
||||
, !- Diffuse Solar Day Schedule Name
|
||||
, !- ASHRAE Clear Sky Optical Depth for Beam Irradiance (taub) {dimensionless}
|
||||
, !- ASHRAE Clear Sky Optical Depth for Diffuse Irradiance (taud) {dimensionless}
|
||||
0.00; !- Sky Clearness
|
||||
|
||||
! DENVER_STAPLETON Annual Cooling Design Conditions Wind Speed=4m/s Wind Dir=120
|
||||
! Hottest Month=July
|
||||
! DENVER_STAPLETON_CO_USA Annual Cooling (DB=>MWB) .4%, MaxDB=34.1°C MWB=15.8°C
|
||||
|
||||
SizingPeriod:DesignDay,
|
||||
DENVER_STAPLETON Ann Clg .4% Condns DB=>MWB, !- Name
|
||||
7, !- Month
|
||||
21, !- Day of Month
|
||||
SummerDesignDay, !- Day Type
|
||||
34.1, !- Maximum Dry-Bulb Temperature {C}
|
||||
15.2, !- Daily Dry-Bulb Temperature Range {deltaC}
|
||||
, !- Dry-Bulb Temperature Range Modifier Type
|
||||
, !- Dry-Bulb Temperature Range Modifier Day Schedule Name
|
||||
Wetbulb, !- Humidity Condition Type
|
||||
15.8, !- Wetbulb or DewPoint at Maximum Dry-Bulb {C}
|
||||
, !- Humidity Condition Day Schedule Name
|
||||
, !- Humidity Ratio at Maximum Dry-Bulb {kgWater/kgDryAir}
|
||||
, !- Enthalpy at Maximum Dry-Bulb {J/kg}
|
||||
, !- Daily Wet-Bulb Temperature Range {deltaC}
|
||||
83411., !- Barometric Pressure {Pa}
|
||||
4, !- Wind Speed {m/s}
|
||||
120, !- Wind Direction {deg}
|
||||
No, !- Rain Indicator
|
||||
No, !- Snow Indicator
|
||||
No, !- Daylight Saving Time Indicator
|
||||
ASHRAEClearSky, !- Solar Model Indicator
|
||||
, !- Beam Solar Day Schedule Name
|
||||
, !- Diffuse Solar Day Schedule Name
|
||||
, !- ASHRAE Clear Sky Optical Depth for Beam Irradiance (taub) {dimensionless}
|
||||
, !- ASHRAE Clear Sky Optical Depth for Diffuse Irradiance (taud) {dimensionless}
|
||||
1.00; !- Sky Clearness
|
||||
|
||||
RunPeriod,
|
||||
Run Period 1, !- Name
|
||||
1, !- Begin Month
|
||||
1, !- Begin Day of Month
|
||||
, !- Begin Year
|
||||
12, !- End Month
|
||||
31, !- End Day of Month
|
||||
, !- End Year
|
||||
Tuesday, !- Day of Week for Start Day
|
||||
Yes, !- Use Weather File Holidays and Special Days
|
||||
Yes, !- Use Weather File Daylight Saving Period
|
||||
No, !- Apply Weekend Holiday Rule
|
||||
Yes, !- Use Weather File Rain Indicators
|
||||
Yes; !- Use Weather File Snow Indicators
|
||||
|
||||
SimulationControl,
|
||||
No, !- Do Zone Sizing Calculation
|
||||
No, !- Do System Sizing Calculation
|
||||
No, !- Do Plant Sizing Calculation
|
||||
No, !- Run Simulation for Sizing Periods
|
||||
Yes, !- Run Simulation for Weather File Run Periods
|
||||
No, !- Do HVAC Sizing Simulation for Sizing Periods
|
||||
1; !- Maximum Number of HVAC Sizing Simulation Passes
|
||||
|
||||
Output:Table:SummaryReports, AnnualBuildingUtilityPerformanceSummary,
|
||||
DemandEndUseComponentsSummary,
|
||||
SensibleHeatGainSummary,
|
||||
InputVerificationandResultsSummary,
|
||||
AdaptiveComfortSummary,
|
||||
Standard62.1Summary,
|
||||
ClimaticDataSummary,
|
||||
EquipmentSummary,
|
||||
EnvelopeSummary,
|
||||
LightingSummary,
|
||||
HVACSizingSummary,
|
||||
SystemSummary,
|
||||
ComponentSizingSummary,
|
||||
OutdoorAirSummary,
|
||||
ObjectCountSummary,
|
||||
EndUseEnergyConsumptionOtherFuelsMonthly,
|
||||
PeakEnergyEndUseOtherFuelsMonthly;
|
||||
|
||||
|
||||
OutputControl:Table:Style, CommaAndHTML,JtoKWH;
|
||||
|
||||
Output:Meter,DISTRICTHEATING:Facility,hourly;
|
||||
Output:Meter,DISTRICTCOOLING:Facility,hourly;
|
||||
Output:Meter,InteriorEquipment:Electricity,hourly;
|
||||
Output:Meter,InteriorLights:Electricity,hourly;
|
||||
|
||||
OutputControl:IlluminanceMap:Style,
|
||||
Comma; !- Column separator
|
0
hub/exports/energy_systems/__init__.py
Normal file
0
hub/exports/energy_systems/__init__.py
Normal file
0
hub/exports/traffic/__init__.py
Normal file
0
hub/exports/traffic/__init__.py
Normal file
0
hub/exports/traffic/helpers/__init__.py
Normal file
0
hub/exports/traffic/helpers/__init__.py
Normal file
25
hub/exports/traffic/helpers/osm.py
Normal file
25
hub/exports/traffic/helpers/osm.py
Normal file
@ -0,0 +1,25 @@
|
||||
import logging
|
||||
|
||||
|
||||
class Osm:
|
||||
_osm_file = {
|
||||
'CA.02.5935': 'https://download.geofabrik.de/north-america/canada/british-columbia-latest.osm.pbf',
|
||||
'CA.10.06': 'https://download.geofabrik.de/north-america/canada/quebec-latest.osm.pbf',
|
||||
'CA.10.13': 'https://download.geofabrik.de/north-america/canada/quebec-latest.osm.pbf',
|
||||
'CA.10.14': 'https://download.geofabrik.de/north-america/canada/quebec-latest.osm.pbf',
|
||||
'CA.10.16': 'https://download.geofabrik.de/north-america/canada/quebec-latest.osm.pbf',
|
||||
'DE.01.082': 'https://download.geofabrik.de/europe/germany/baden-wuerttemberg-latest.osm.pbf',
|
||||
'US.NY.047': 'https://download.geofabrik.de/north-america/us/new-york-latest.osm.pbf',
|
||||
'CA.10.12': 'https://download.geofabrik.de/north-america/canada/quebec-latest.osm.pbf',
|
||||
'IL.01.': 'https://download.geofabrik.de/asia/israel-and-palestine-latest.osm.pbf',
|
||||
'ES.07.PM': 'https://download.geofabrik.de/europe/spain/islas-baleares-latest.osm.pbf'
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def pfb_file(self, region_code):
|
||||
if region_code in self._osm_file.keys():
|
||||
return self._osm_file[region_code]
|
||||
logging.error('Specific osm data unknown for %s', region_code)
|
||||
raise NotImplementedError('Specific osm data unknown for %s', region_code)
|
476
hub/exports/traffic/matsim.py
Normal file
476
hub/exports/traffic/matsim.py
Normal file
@ -0,0 +1,476 @@
|
||||
import gzip
|
||||
import math
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import geopandas as gpd
|
||||
import requests
|
||||
from lxml import etree
|
||||
from shapely import Polygon
|
||||
from helpers.osm import Osm
|
||||
import hub.helpers.constants as cte
|
||||
|
||||
|
||||
class Matsim:
|
||||
_x = 0
|
||||
_y = 1
|
||||
_z = 2
|
||||
|
||||
def __init__(self, city, output_file_path):
|
||||
self._city = city
|
||||
self._output_file_path = output_file_path
|
||||
self._crs = city.c
|
||||
self._facilities = {
|
||||
'name': self._city.name + ' Facilities',
|
||||
'facility': []
|
||||
}
|
||||
self._export()
|
||||
|
||||
def _export(self):
|
||||
self._export_facilities()
|
||||
self._export_network()
|
||||
self._export_population()
|
||||
self._export_config()
|
||||
|
||||
@property
|
||||
def _jar_path(self):
|
||||
"""
|
||||
Get the matsim-network-from-osm installation path
|
||||
:return: str
|
||||
"""
|
||||
return shutil.which('matsim-network-from-osm.jar')
|
||||
|
||||
@property
|
||||
def _java_path(self):
|
||||
"""
|
||||
Get the matsim-network-from-osm installation path
|
||||
:return: str
|
||||
"""
|
||||
return shutil.which('java')
|
||||
|
||||
def _export_facilities(self):
|
||||
"""
|
||||
Exports the city's facilities data to XML and shapefile formats.
|
||||
"""
|
||||
|
||||
facilities_xml = etree.Element('facilities', name=self._facilities['name'])
|
||||
|
||||
for building in self._city.buildings:
|
||||
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')
|
||||
|
||||
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': math.ceil(capacity),
|
||||
'opentime': Matsim._convert_schedules(building_schedules)
|
||||
}
|
||||
|
||||
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"]}'
|
||||
})
|
||||
|
||||
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"]}'
|
||||
})
|
||||
|
||||
facility['activity'].append(activity_info)
|
||||
self._facilities['facility'].append(facility)
|
||||
except Exception as ex:
|
||||
print('error: ', ex)
|
||||
|
||||
viewport = Polygon([
|
||||
(self._city.lower_corner[self._x], self._city.upper_corner[self._y]),
|
||||
(self._city.upper_corner[self._x], self._city.upper_corner[self._y]),
|
||||
(self._city.upper_corner[self._x], self._city.lower_corner[self._y]),
|
||||
(self._city.lower_corner[self._x], self._city.lower_corner[self._y])])
|
||||
|
||||
gdf = gpd.GeoDataFrame(
|
||||
geometry=[viewport],
|
||||
crs=self._city.srs_name
|
||||
)
|
||||
gdf.to_file(f'{self._output_file_path}/buildings_shapefile.shp')
|
||||
|
||||
# Write xml content to file
|
||||
xml_content = etree.tostring(facilities_xml, pretty_print=True, encoding='UTF-8').decode('utf-8')
|
||||
output_file = f'{self._output_file_path}/{self._city.name}_facilities.xml'
|
||||
xml_dtd = '<!DOCTYPE facilities SYSTEM "http://www.matsim.org/files/dtd/facilities_v1.dtd">\n'
|
||||
Matsim._save_xml(output_file, xml_content, xml_dtd)
|
||||
|
||||
@staticmethod
|
||||
def _convert_schedules(building_schedules):
|
||||
"""
|
||||
Converts building schedules into a format suitable for facilities.xml.
|
||||
|
||||
:param building_schedules: A list of building schedule objects to be converted.
|
||||
:return: A list of dictionaries, each representing the converted schedule for a building.
|
||||
"""
|
||||
converted_schedules = []
|
||||
opening_hour = 0
|
||||
closing_hour = 0
|
||||
schedule = building_schedules[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': f'{opening_hour:02}:00:00',
|
||||
'end_time': f'{closing_hour:02}:00:00'
|
||||
})
|
||||
|
||||
return converted_schedules
|
||||
|
||||
@staticmethod
|
||||
def _save_xml(output_file, xml_content, xml_dtd=None):
|
||||
"""
|
||||
Saves XML content to a file, optionally adding a DOCTYPE declaration and compressing the file.
|
||||
|
||||
:param output_file: The path where the XML file will be saved.
|
||||
:param xml_content: The XML content to be written to the file.
|
||||
:param xml_dtd: An optional DOCTYPE declaration to be included at the beginning of the file.
|
||||
"""
|
||||
if xml_dtd is None:
|
||||
xml_dtd = ''
|
||||
with open(output_file, 'w') as file:
|
||||
file.write('<?xml version="1.0" encoding="utf-8"?>\n')
|
||||
file.write(xml_dtd)
|
||||
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):
|
||||
"""
|
||||
Generates a transportation network file from the city's OpenStreetMap data and buildings shapefile.
|
||||
"""
|
||||
url = Osm().pfb_file(self._city.location.region_code)
|
||||
path = (Path(__file__).parent.parent.parent / f'data/weather/epw/{url.rsplit("/", 1)[1]}').resolve()
|
||||
if not path.exists():
|
||||
with open(path, 'wb') as pbf_file:
|
||||
pbf_file.write(requests.get(url, allow_redirects=True).content)
|
||||
command = [
|
||||
self._java_path,
|
||||
'-jar', self._jar_path,
|
||||
path,
|
||||
f'{self._output_file_path}/buildings_shapefile.shp',
|
||||
f'{self._output_file_path}/{self._city.name}_network.xml.gz',
|
||||
self._crs
|
||||
]
|
||||
subprocess.run(command)
|
||||
|
||||
def _export_population(self):
|
||||
"""
|
||||
Generates and exports the city's population data to an XML file.
|
||||
"""
|
||||
population = etree.Element('population')
|
||||
person_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'
|
||||
})
|
||||
|
||||
# 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(person_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'
|
||||
})
|
||||
|
||||
# Leg to work
|
||||
etree.SubElement(plan, 'leg', {'mode': 'car'})
|
||||
|
||||
# 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"]}',
|
||||
})
|
||||
# Leg to home
|
||||
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[current_work]['capacity'] -= 1
|
||||
if work[current_work]['capacity'] == 0:
|
||||
current_work += 1
|
||||
|
||||
person_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')
|
||||
output_file = f'{self._output_file_path}/{self._city.name}_population.xml'
|
||||
self._save_xml(
|
||||
output_file,
|
||||
xml_content,
|
||||
f'<!DOCTYPE population SYSTEM "http://www.matsim.org/files/dtd/population_v5.dtd">\n'
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _add_param(parent, name, value):
|
||||
"""
|
||||
Helper function to add a parameter to an XML element.
|
||||
|
||||
:param parent: The parent XML element to which the parameter should be added.
|
||||
:param name: The name of the parameter.
|
||||
:param value: The value of the parameter.
|
||||
"""
|
||||
etree.SubElement(parent, 'param', {
|
||||
'name': name,
|
||||
'value': value
|
||||
})
|
||||
|
||||
@staticmethod
|
||||
def _add_parameterset(parent, attribute_type, parameters):
|
||||
"""
|
||||
Helper function to add a set of parameters to an XML element.
|
||||
|
||||
:param parent: The parent XML element to which the parameterset should be added.
|
||||
:param attribute_type: The attribute type for the parameterset.
|
||||
:param parameters: A list of tuples, each containing the name and value of a parameter.
|
||||
"""
|
||||
parameterset = etree.SubElement(parent, 'parameterset', {
|
||||
'type': attribute_type
|
||||
})
|
||||
for name, value in parameters:
|
||||
Matsim._add_param(parameterset, name, value)
|
||||
|
||||
def _export_config(self):
|
||||
"""
|
||||
Creates and exports the simulation configuration settings to an XML file.
|
||||
"""
|
||||
root = etree.Element('config')
|
||||
|
||||
# ======== NETWORK ========= #
|
||||
network_path_module = etree.SubElement(root, 'module', {
|
||||
'name': 'network'
|
||||
})
|
||||
Matsim._add_param(network_path_module, 'inputNetworkFile', f'{self._city.name}_network.xml.gz/')
|
||||
|
||||
# ======== POPULATION ========= #
|
||||
population_path_module = etree.SubElement(root, 'module', {
|
||||
'name': 'plans'
|
||||
})
|
||||
Matsim._add_param(population_path_module, 'inputPlansFile', f'{self._city.name}_population.xml.gz')
|
||||
|
||||
# ======== FACILITIES ========= #
|
||||
facilities_path_module = etree.SubElement(root, 'module', {
|
||||
'name': 'facilities'
|
||||
})
|
||||
Matsim._add_param(facilities_path_module, 'inputFacilitiesFile', f'{self._city.name}_facilities.xml.gz')
|
||||
Matsim._add_param(facilities_path_module, 'facilitiesSource', 'fromFile')
|
||||
|
||||
# ======== CONTROLER ========= #
|
||||
controler_module = etree.SubElement(root, 'module', {
|
||||
'name': 'controler'
|
||||
})
|
||||
controler_params = [
|
||||
('writeEventsInterval', '1000'),
|
||||
('writePlansInterval', '1000'),
|
||||
('eventsFileFormat', 'xml'),
|
||||
('outputDirectory', f"{self._output_file_path}/Montreal"),
|
||||
('firstIteration', '0'),
|
||||
('lastIteration', '10'),
|
||||
('mobsim', 'qsim'),
|
||||
]
|
||||
for param in controler_params:
|
||||
Matsim._add_param(controler_module, param[0], param[1])
|
||||
|
||||
# ======== QSIM ========= #
|
||||
qsim_module = etree.SubElement(root, 'module', {
|
||||
'name': 'qsim'
|
||||
})
|
||||
qsim_params = [
|
||||
('startTime', '00:00:00'),
|
||||
('endTime', '30:00:00'),
|
||||
('flowCapacityFactor', '1.00'),
|
||||
('storageCapacityFactor', '1.00'),
|
||||
('numberOfThreads', '1'),
|
||||
('snapshotperiod', '00:00:01'),
|
||||
('removeStuckVehicles', 'false'),
|
||||
('stuckTime', '3600.0'),
|
||||
('timeStepSize', '00:00:01'),
|
||||
('trafficDynamics', 'queue'),
|
||||
]
|
||||
for param in qsim_params:
|
||||
Matsim._add_param(qsim_module, param[0], param[1])
|
||||
|
||||
# ======== SCORING ========= #
|
||||
score_module = etree.SubElement(root, 'module', {
|
||||
'name': 'planCalcScore'
|
||||
})
|
||||
Matsim._add_param(score_module, 'BrainExpBeta', '1.0')
|
||||
Matsim._add_param(score_module, 'learningRate', '1.0')
|
||||
|
||||
scoring_paramset = etree.SubElement(score_module, 'parameterset', {
|
||||
'type': 'scoringParameters'
|
||||
})
|
||||
scoring_paramset_params = [
|
||||
('earlyDeparture', '0.0'),
|
||||
('lateArrival', '0.0'),
|
||||
('marginalUtilityOfMoney', '0.062'),
|
||||
('performing', '0.96'),
|
||||
('utilityOfLineSwitch', '0.0'),
|
||||
('waitingPt', '-0.18'),
|
||||
]
|
||||
for param in scoring_paramset_params:
|
||||
Matsim._add_param(scoring_paramset, param[0], param[1])
|
||||
|
||||
mode_paramsets = [
|
||||
('car',
|
||||
[
|
||||
('marginalUtilityOfTraveling_util_hr', '0.0'),
|
||||
('constant', '-0.562'),
|
||||
('monetaryDistanceRate', '-0.0004')
|
||||
]),
|
||||
('walk',
|
||||
[
|
||||
('marginalUtilityOfTraveling_util_hr', '-1.14'),
|
||||
('constant', '0.0'),
|
||||
('marginalUtilityOfDistance_util_m', '0.0')
|
||||
])
|
||||
]
|
||||
for mode, parameters in mode_paramsets:
|
||||
Matsim._add_parameterset(scoring_paramset, 'modeParams', [('mode', mode)] + parameters)
|
||||
|
||||
activity_paramsets = [
|
||||
('residential',[
|
||||
('priority', '1'),
|
||||
('typicalDuration', '13:00:00'),
|
||||
('minimalDuration', '01:00:00'),
|
||||
]),
|
||||
]
|
||||
|
||||
for facility in self._facilities['facility']:
|
||||
if not any(activity[0] == facility['activity'][0]['type'] for activity in activity_paramsets):
|
||||
activity_paramsets.append(
|
||||
(facility['activity'][0]['type'], [
|
||||
('priority', '1'),
|
||||
('typicalDuration', '09:00:00'),
|
||||
('minimalDuration', '08:00:00'),
|
||||
('openingTime', '08:00:00'),
|
||||
('earliestEndTime', '17:00:00'),
|
||||
('latestStartTime', '09:00:00'),
|
||||
('closingTime', '18:00:00'),
|
||||
])
|
||||
)
|
||||
|
||||
for activity_type, parameters in activity_paramsets:
|
||||
Matsim._add_parameterset(scoring_paramset, "activityParams", [("activityType", activity_type)] + parameters)
|
||||
|
||||
# ======== STRATEGY ========= #
|
||||
strategy_module = etree.SubElement(root, 'module', {
|
||||
'name': 'strategy'
|
||||
})
|
||||
Matsim._add_param(strategy_module, 'maxAgentPlanMemorySize', '6')
|
||||
|
||||
strategy_paramsets = [
|
||||
('ChangeExpBeta',[
|
||||
('weight', '0.7'),
|
||||
]),
|
||||
('ReRoute',[
|
||||
('disableAfterIteration', '2900'),
|
||||
('weight', '0.01'),
|
||||
]),
|
||||
('SubtourModeChoice', [
|
||||
('disableAfterIteration', '2900'),
|
||||
('weight', '0.01'),
|
||||
]),
|
||||
('TimeAllocationMutator', [
|
||||
('disableAfterIteration', '2900'),
|
||||
('weight', '0.01'),
|
||||
]),
|
||||
]
|
||||
for name, parameters in strategy_paramsets:
|
||||
Matsim._add_parameterset(strategy_module, 'strategysettings', [("strategyName", name)] + parameters)
|
||||
|
||||
# ======== SUBTOUR MODE CHOICE ========= #
|
||||
subtour_module = etree.SubElement(root, 'module', {
|
||||
'name': 'subtourModeChoice'
|
||||
})
|
||||
# Defines the chain-based modes, seperated by commas
|
||||
Matsim._add_param(subtour_module, 'chainBasedModes', 'car')
|
||||
# Defines whether car availability must be considered or not. An agent has no car only if it has no license, or never access to a car
|
||||
Matsim._add_param(subtour_module, 'considerCarAvailability', 'true')
|
||||
# Defines all the modes available, including chain-based modes, seperated by commas
|
||||
Matsim._add_param(subtour_module, 'modes', 'car,walk')
|
||||
|
||||
# Write xml content to file
|
||||
xml_content = etree.tostring(root, pretty_print=True, encoding='UTF-8').decode('utf-8')
|
||||
output_file = f"{self._output_file_path}/{self._city.name}_config.xml"
|
||||
self._save_xml(output_file, xml_content, f'<!DOCTYPE config SYSTEM "http://www.matsim.org/files/dtd/config_v2.dtd">\n')
|
39
hub/exports/traffic_factory.py
Normal file
39
hub/exports/traffic_factory.py
Normal file
@ -0,0 +1,39 @@
|
||||
"""
|
||||
Traffic factory export a city traffic information into several formats
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from hub.exports.traffic.matsim import Matsim
|
||||
from hub.helpers.utils import validate_import_export_type
|
||||
|
||||
|
||||
class TrafficFactory:
|
||||
"""
|
||||
Exports factory class
|
||||
"""
|
||||
def __init__(self, handler, city, path):
|
||||
self._city = city
|
||||
self._handler = '_' + handler.lower()
|
||||
validate_import_export_type(TrafficFactory, handler)
|
||||
if isinstance(path, str):
|
||||
path = Path(path)
|
||||
self._path = path
|
||||
|
||||
@property
|
||||
def _matsim(self):
|
||||
"""
|
||||
Export the city traffic information to Matsim
|
||||
:return: None
|
||||
"""
|
||||
return Matsim(self._city, self._path)
|
||||
|
||||
def export(self):
|
||||
"""
|
||||
Export the city given to the class using the given export type handler
|
||||
:return: None
|
||||
"""
|
||||
return getattr(self, self._handler, lambda: None)
|
@ -23,4 +23,5 @@ geopandas
|
||||
triangle
|
||||
psycopg2-binary
|
||||
Pillow
|
||||
pathlib
|
||||
pathlib
|
||||
lxml
|
Loading…
Reference in New Issue
Block a user