-
Notifications
You must be signed in to change notification settings - Fork 10
Usage: 4.2. Using Network: Road Pricing
This page goes through the process of generating a road pricing MATSim file. Available as a jupyter notebook or wiki page.
Let's read an example MATSim network to work with.
from genet import read_matsim
import pandas as pd
import os
path_to_matsim_network = '../example_data/pt2matsim_network'
network = os.path.join(path_to_matsim_network, 'network.xml')
schedule = os.path.join(path_to_matsim_network, 'schedule.xml')
vehicles = os.path.join(path_to_matsim_network, 'vehicles.xml')
n = read_matsim(
path_to_network=network,
epsg='epsg:27700',
path_to_schedule=schedule,
path_to_vehicles=vehicles
)
# you don't need to read the vehicles file, but doing so ensures all vehicles
# in the schedule are of the expected type and the definition of the vehicle
# is preserved
n.link_attribute_summary()
attribute
├── id
├── from
├── to
├── freespeed
├── capacity
├── permlanes
├── oneway
├── modes
├── s2_from
├── s2_to
├── attributes
│ ├── osm:way:access
│ ├── osm:way:highway
│ ├── osm:way:id
│ ├── osm:way:name
│ ├── osm:relation:route
│ ├── osm:way:lanes
│ ├── osm:way:oneway
│ ├── osm:way:tunnel
│ ├── osm:way:psv
│ ├── osm:way:vehicle
│ ├── osm:way:traffic_calming
│ ├── osm:way:junction
│ └── osm:way:service
└── length
Our current workflow relies on OSM way ids being saved to the network in the nested 'attributes' dictionary. We query OSM to extract those OSM ids and find them in the network.
attribute
├── id
├── from
├── to
...
├── attributes
...
│ ├── osm:way:id
...
Of course this can be streamlined by just reading and saving the toll
tag when creating a network from OSM. For more info see Usage: 2.2. Reading Data: OSM. This would manifest itself in the following way in the links data:
attribute
├── id
├── from
├── to
...
├── attributes
...
│ ├── osm:way:toll
...
where you would look for 'osm:way:toll':'yes'
To do this via OSM ids, you can head over to https://overpass-turbo.eu/, use the quiery Wizard to find toll=yes
zooming into the right place on the map. You can then grab the relevant OSM data by clicking Export
. Under Data
tab, you can click on download/copy as raw OSM data
. This will copy the data into clipboard. Below I paste a small example:
osm_data = {
"version": 0.6,
"generator": "Overpass API 0.7.56.8 7d656e78",
"osm3s": {
"timestamp_osm_base": "2020-12-16T15:46:02Z",
"copyright": "The data included in this document is from www.openstreetmap.org. The data is made available under ODbL."
},
"elements": [
{
"type": "way",
"id": 26997928,
"nodes": [
107790,
1102995756,
5479634639,
5364578862,
21665585,
5479634644,
107791
],
"tags": {
"highway": "primary",
"lit": "yes",
"maxspeed": "20 mph",
"maxspeed:type": "GB:zone20",
"name": "Charing Cross Road",
"ref": "A400",
"sidewalk": "both",
"surface": "asphalt",
"toll": "yes",
"wikidata": "Q1063230"
}
},
{
"type": "way",
"id": 546461337,
"nodes": [
1556097185,
1951372935,
1951372927
],
"tags": {
"foot": "no",
"highway": "primary",
"lit": "yes",
"maxspeed": "20 mph",
"name": "Byward Street",
"oneway": "yes",
"operator": "Transport for London",
"postal_code": "EC3",
"ref": "A3211",
"sidewalk": "none",
"surface": "asphalt",
"toll": "yes"
}},
{
"type": "node",
"id": 107790,
"lat": 51.511322,
"lon": -0.1283895
},
{
"type": "node",
"id": 107791,
"lat": 51.5118562,
"lon": -0.1283797
},
{
"type": "node",
"id": 21665585,
"lat": 51.5116901,
"lon": -0.1283715
},
{
"type": "node",
"id": 1102995756,
"lat": 51.511415,
"lon": -0.1283857
},
{
"type": "node",
"id": 5364578862,
"lat": 51.511599,
"lon": -0.1283762
},
{
"type": "node",
"id": 5479634639,
"lat": 51.5114884,
"lon": -0.1283819
},
{
"type": "node",
"id": 5479634644,
"lat": 51.5117331,
"lon": -0.1283705
}
]
}
All that is left is extracting the OSM way IDs of interest. In the case above it's just a couple.
It is also useful to record the ref
and name
or any other data that may relate to a dataset you have for tolls to make it human readable or to be able to join the two datasets. This will make it easier to decide on how much the toll should be.
def extract_data(d, key):
try:
return d[key]
except KeyError:
return float('nan')
osm_id = []
osm_ref = []
osm_name = []
for element in osm_data['elements']:
if element['type']=='way':
# what you get from overpass should all just be tolls but let's
# put an extra condition here anyway
if ('toll' in element['tags']) and (element['tags']['toll'] == 'yes'):
osm_id.append(element['id'])
osm_ref.append(extract_data(element['tags'], 'ref'))
osm_name.append(extract_data(element['tags'], 'name'))
df_tolls = pd.DataFrame(
{'osm_id': osm_id,
'osm_ref': osm_ref,
'osm_name': osm_name})
# the osm IDs in our network are of float type. Make sure you search for data with matching data types
df_tolls['osm_id'] = df_tolls['osm_id'].astype(float)
df_tolls.head()
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
osm_id | osm_ref | osm_name | |
---|---|---|---|
0 | 26997928.0 | A400 | Charing Cross Road |
1 | 546461337.0 | A3211 | Byward Street |
We now write this to a csv file.
df_tolls.to_csv('../example_data/pt2matsim_network/road_pricing/osm_toll_id_ref.csv',
index=False)
We can now use GeNet's road pricing methods to map the OSM ids in df_tolls
to network links.
from genet.use import road_pricing
road_pricing.extract_network_id_from_osm_csv(
network=n,
attribute_name='osm:way:id',
osm_csv_path='../example_data/pt2matsim_network/road_pricing/osm_toll_id_ref.csv',
outpath='../example_data/pt2matsim_network/road_pricing',
osm_dtype=float # the osm IDs in our network are of float type. Make sure you search for data with matching data types
)
100%|██████████| 2/2 [00:00<00:00, 37.33it/s]
( osm_id osm_ref osm_name network_id
0 26997928.0 A400 Charing Cross Road True
1 546461337.0 A3211 Byward Street True,
{26997928.0: ['1', '2', '3', '4'], 546461337.0: ['998', '999']})
This step can take a long time because the relationship between OSM ways and MATSim network links is rarely 1-to-1. For a given OSM way, there can be multiple network links (i.e. multiple links sharing the same osm:way:id
) or no network links at all (i.e. during network creation/manipulation some OSM links were deleted or merged). Therefore, the matching OSM ways to network links has to be done on a case-by-case basis.
Upon completion, there will be two new files in the output folder ../example_data/pt2matsim_network/road_pricing
specified above:
-
osm_tolls_with_network_ids.csv
: this file will be a copy of the inputosm_toll_id_ref.csv
but augmented with aTrue
/False
value indicating whether each OSM way id was successfully matched with one of more network link ids. -
osm_to_network_ids.json
: this file contains a mapping of each OSM way id inosm_toll_id_ref.csv
with one or more network link ids.
The next step is to decide on the vehicle_type
, toll_amount
, start_time
and end_time
for the toll. You may have other data that you can join onto osm_tolls_with_network_ids.csv
. In the example below, we make it up.
df_tolls = pd.read_csv(
'../example_data/pt2matsim_network/road_pricing/osm_tolls_with_network_ids.csv')
df_tolls.head()
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
osm_id | osm_ref | osm_name | network_id | |
---|---|---|---|---|
0 | 26997928.0 | A400 | Charing Cross Road | True |
1 | 546461337.0 | A3211 | Byward Street | True |
df_tolls['vehicle_type'] = 'type2'
df_tolls['toll_amount'] = '2.9'
df_tolls['start_time'] = '00:00'
df_tolls['end_time'] = '23:59'
df_tolls.head()
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
osm_id | osm_ref | osm_name | network_id | vehicle_type | toll_amount | start_time | end_time | |
---|---|---|---|---|---|---|---|---|
0 | 26997928.0 | A400 | Charing Cross Road | True | type2 | 2.9 | 00:00 | 23:59 |
1 | 546461337.0 | A3211 | Byward Street | True | type2 | 2.9 | 00:00 | 23:59 |
df_tolls.to_csv(
'../example_data/pt2matsim_network/road_pricing/osm_tolls_with_network_ids.csv')
Next we can generate the road pricing file.
xml_tree = road_pricing.build_tree_from_csv_json(
'../example_data/pt2matsim_network/road_pricing/osm_tolls_with_network_ids.csv',
'../example_data/pt2matsim_network/road_pricing/osm_to_network_ids.json')
road_pricing.write_xml(xml_tree, '../example_data/pt2matsim_network/road_pricing')