MOSSTOOL Demos
To run the examples provided in the mosstool
repository, you need to clone the repository and install the required dependencies.
git clone https://github.com/tsinghua-fib-lab/mosstool.git
cd mosstool
poetry install
Map-Building
Map-Builder
Build Map
python ./examples/build_map.py
Load net
files
net
is basic road net file for builder to build a map, either a GeoJSON
file or a Map
file is available. aois
, pois
and public_transport
are optional input arguments for builder.
with open("data/geojson/net.geojson", "r") as f:
net = geojson.load(f)
Initialize the builder
and build the map
builder = Builder(
net=net,
proj_str="+proj=tmerc +lat_0=33.9 +lon_0=116.4",
gen_sidewalk_speed_limit=50 / 3.6, # if the speed limit of one lane is lower than this, then sidewalks are available for thie lane
road_expand_mode="M", # in raw GeoJSON road net file, only road has a centerline geometry shape and lanes are expanded from road. "M" means that the lanes are expanded on both sides of the road centerline.
)
m = builder.build("test")
Visualize the generated map
pb = dict2pb(m, Map())
with open("data/temp/map.pb", "wb") as f: # dump as binary files
f.write(pb.SerializeToString())
vis_map = VisMap(pb) # visualization
fc = vis_map.feature_collection
with open("data/temp/map.geojson", "w") as f:
geojson.dump(fc, f, ensure_ascii=False, indent=2)
deck = vis_map.visualize()
deck.to_html("data/temp/map.html")
Add Public Transport to Map
python ./examples/add_pt_to_map.py
Load public transport JSON
data
with open(PT_PATH, "r") as f:
pt = json.load(f)
Load Map
file to add PTs
Adding PTs when generating a new map with a GeoJSON
file provided is also supported, here we use generated map as an example.
with open(ORIG_MAP_PATH, "rb") as f:
net = Map()
net.ParseFromString(f.read())
Initialize the builder
and build the map
builder = Builder(
net=net,
public_transport=pt,
proj_str=net.header.projection,
gen_sidewalk_speed_limit=50 / 3.6,
aoi_mode="append",
road_expand_mode="M",
)
m_dict = builder.build("test")
Save the dict
and Map
files
pickle.dump(m_dict, open(MAP_PKL_PATH, "wb"))
with open(MAP_PB_PATH, "wb") as f:
pb = dict2pb(m_dict, Map())
f.write(pb.SerializeToString())
Post Process of Adding Public Transport to Map
python ./examples/add_pt_post_process.py
Activate routing
service
# pre-route
# run: ./routing -map ./data/temp/srt.raw_pt_map.pb
Load the dict
and Map
files from add_pt_to_map.py
LISTENING_HOST = "http://localhost:52101"
MAP_PKL_PATH = "./data/temp/srt.raw_pt_map.pkl"
PT_MAP_PATH = f"./data/temp/srt.map_with_pt.pb"
m_dict = pickle.load(open(MAP_PKL_PATH, "rb"))
Post process and save the Map
file
new_m = public_transport_process(m_dict, LISTENING_HOST)
pb = dict2pb(new_m, Map())
with open(PT_MAP_PATH, "wb") as f:
f.write(pb.SerializeToString())
Split Map
into Multiple Map
s
split maps for more convenient manual adjustments with Web Tools/Map Editor
.
python ./examples/split_map.py
Load the bounding boxes and the map
with open("data/geojson/split_box.geojson", "r") as f:
bbox = geojson.load(f)
with open("data/map/m.pb", "rb") as f:
pb = Map()
pb.ParseFromString(f.read())
Split the map into each boxes
split_map(
geo_data=bbox,
map=pb,
output_path="data/temp",
)
Merge Split Map
s
python ./examples/merge_map.py
Load all maps
maps = []
for i in [0, 1]:
with open(f"data/temp/test_{i}.pb", "rb") as f:
pb = Map()
pb.ParseFromString(f.read())
maps.append(pb)
Merge and rebuild the map
rebuild map with basic lanes, roads, junctions, AOIs and POIs in merged_pb
. Extra AOIs and POIs can be added with aoi_mode="append"
, or use aoi_mode="overwrite"
to replace original AOIs and POIs with input AOIs and POIs.
merged_pb = merge_map(
partial_maps=maps,
output_path="data/temp/merged_m.pb",
)
if REBUILD_MAP:
builder = Builder(
net=merged_pb,
proj_str=merged_pb.header.projection,
gen_sidewalk_speed_limit=50 / 3.6,
aoi_mode="append", # keep AOIs in merged_pb
road_expand_mode="M",
)
rebuild_m = builder.build(merged_pb.header.name)
rebuild_pb = dict2pb(rebuild_m, Map())
with open("data/temp/rebuild_merged_m.pb", "wb") as f:
f.write(rebuild_pb.SerializeToString())
Visualization Map from MongoDB
python ./examples/vis_map.py
Connect to MongoDB and download the map
client = MongoClient(os.environ["MONGO_URI"])
coll = client[os.environ["MAP_DB"]][os.environ["MAP_COLL"]]
pb = Map()
pb = coll2pb(coll, pb)
Save visualization file
m = VisMap(pb)
print(m.lane_shapely_xys[0])
deck = m.visualize()
deck.to_html("map.html") # open with browser
From OpenStreetMap
Fetch RoadNet from OSM
python ./examples/map_osm2geojson.py
Set the bounding box
bbox = {
"max_lat": 40.1,
"min_lat": 39.9,
"min_lon": 116.5,
"max_lon": 116.6,
}
Fetch raw data and process
proj_str
is set to calculate the position relations more precisely between map items.
# load configs
rn = RoadNet(
proj_str="+proj=tmerc +lat_0=39.90611 +lon_0=116.3911",
max_latitude=bbox["max_lat"],
min_latitude=bbox["min_lat"],
max_longitude=bbox["max_lon"],
min_longitude=bbox["min_lon"],
)
path = "cache/topo.geojson"
rn.create_road_net(path)
Fetch AOI from OSM
python ./examples/map_aoi_geojson.py
Set the bounding box
# Beijing
bbox = {
"max_lat": 40.20836867760951,
"min_lat": 39.69203625898142,
"min_lon": 116.12174658204533,
"max_lon": 116.65141646506795,
}
Fetch raw data and process
proj_str
is set to calculate the position relations more precisely between map items.
building = Building(
proj_str="+proj=tmerc +lat_0=39.90611 +lon_0=116.3911",
max_latitude=bbox["max_lat"],
min_latitude=bbox["min_lat"],
max_longitude=bbox["max_lon"],
min_longitude=bbox["min_lon"],
)
path = "data/temp/aois.geojson"
aois = building.create_building(output_path=path)
Fetch POI from OSM
python ./examples/map_poi_geojson.py
Set the bounding box
# Beijing
bbox = {
"max_lat": 40.20836867760951,
"min_lat": 39.69203625898142,
"min_lon": 116.12174658204533,
"max_lon": 116.65141646506795,
}
Fetch raw data and process
pois = PointOfInterest(
max_latitude=bbox["max_lat"],
min_latitude=bbox["min_lat"],
max_longitude=bbox["max_lon"],
min_longitude=bbox["min_lon"],
)
path = "data/temp/pois.geojson"
pois = pois.create_pois(output_path=path)
From SUMO
Convert Map
python ./examples/sumo_map_convert.py
Initialize the MapConverter
and convert the map
s2m = MapConverter(
net_path="data/sumo/shenzhen.net.xml",
traffic_light_path="data/sumo/trafficlight.xml",
poly_path="data/sumo/poly.xml",
)
m = s2m.convert_map()
Visualization
pb = dict2pb(m, Map())
with open("data/temp/sumo_map.pb", "wb") as f:
f.write(pb.SerializeToString())
vis_map = VisMap(pb)
fc = vis_map.feature_collection
deck = vis_map.visualize()
deck.to_html("data/temp/sumo_map.html")
Trip-Generation
Trip-Generators
Generate OD-Matrix with Gravity Model
python ./examples/gravity.py
Initialize the GravityGenerator
gravity_generator = GravityGenerator(
Lambda=0.2,
Alpha=0.5,
Beta=0.5,
Gamma=0.5
)
Load the area data
area = gpd.read_file("data/gravitygenerator/Beijing-shp/beijing.shp")
Generate the O-D matrix
od_matrix = gravity_generator.generate(pops)
Generate Random Trips
python ./examples/random_persons.py
Load the map and person template
template is a Person
object with preset attributes, the generated trips are based on the template.
with open("data/temp/map.pb", "rb") as f:
m = Map()
m.ParseFromString(f.read())
template = Person()
template.CopyFrom(DEFAULT_PERSON)
template.vehicle_attribute.model = "normal"
template.pedestrian_attribute.model = "normal"
Generate random persons
persons = rg.uniform(
num=100,
first_departure_time_range=(8 * 3600, 9 * 3600),
schedule_interval_range=(5 * 60, 10 * 60),
start_id=0,
)
Fill schedules of persons with routing
service
# pre-route
# run: ./routing -map data/temp/map.pb
client = RoutingClient("http://localhost:52101")
ok_persons = []
for p in persons:
p = await pre_route(client, p)
if len(p.schedules) > 0 and len(p.schedules[0].trips) > 0:
ok_persons.append(p)
print(ok_persons)
print("final length: ", len(ok_persons))
pb = Persons(persons=ok_persons)
with open("data/temp/persons.json", "w") as f:
f.write(pb2json(pb))
Generate Trips with O-D Matrix from AigcGenerator
python ./examples/trip_generate_aigc_od.py
Initialize the AigcGenerator
and load the area data
# Initialize the generator
aigc_generator = AigcGenerator()
aigc_generator.set_satetoken(YOUR_ACCESS_TOKEN)
area = gpd.read_file("data/gravitygenerator/Beijing-shp/beijing.shp")
aigc_generator.load_area(area)
# Generate the OD matrix
od_matrix = aigc_generator.generate()
Initialize the TripGenerator
with open("data/gravitygenerator/beijing_map.pb", "rb") as f:
m = Map()
m.ParseFromString(f.read())
tg = TripGenerator(
m=m,
)
Generate persons with O-D matrix
od_persons = tg.generate_persons(
od_matrix=od_matrix,
departure_time_curve=[
1,1,1,1,2,3,
4,5,6,5,4,0.5,
1,1,0.5,1,1,0.5,
1,1,0.5,1,1,0.5,
],
areas=area,
agent_num=10000,
seed=0,
)
pb = Persons(persons=od_persons)
with open("data/temp/beijing_OD_person.pb", "wb") as f:
f.write(pb.SerializeToString())
Fill schedules of persons with routing
service
# The generated trip of the person is not guaranteed to be reachable in the map. Preroute is required.
# pre-route
# run: ./routing -map data/gravitygenerator/beijing_map.pb
client = RoutingClient("http://localhost:52101")
ok_persons = []
for p in od_persons:
p = await pre_route(client, p)
if len(p.schedules) > 0 and len(p.schedules[0].trips) > 0:
ok_persons.append(p)
print(len(ok_persons))
pb = Persons(persons=ok_persons)
with open("data/temp/beijing_OD_ok_person.pb", "wb") as f:
f.write(pb.SerializeToString())
Generate Trips with O-D Matrix from GravityGenerator
python ./examples/trip_generate_gravity_od.py
Initialize the GravityGenerator
and load the area and pop data
# Initialize the gravity generator
gravity_generator = GravityGenerator(Lambda=0.2, Alpha=0.5, Beta=0.5, Gamma=0.5)
# Load the area data
area = gpd.read_file("data/gravitygenerator/Beijing-shp/beijing.shp")
pops = np.load("data/gravitygenerator/worldpop.npy")[:, 0]
gravity_generator.load_area(area)
# Generate the OD matrix
od_matrix = gravity_generator.generate(pops)
Initialize the TripGenerator
with open("data/gravitygenerator/beijing_map.pb", "rb") as f:
m = Map()
m.ParseFromString(f.read())
tg = TripGenerator(
m=m,
)
Generate persons with O-D matrix
od_persons = tg.generate_persons(
od_matrix=od_matrix,
departure_time_curve=[
1,1,1,1,2,3,
4,5,6,5,4,0.5,
1,1,0.5,1,1,0.5,
1,1,0.5,1,1,0.5,
],
areas=area,
agent_num=10000,
seed=0,
)
pb = Persons(persons=od_persons)
with open("data/temp/beijing_OD_person.pb", "wb") as f:
f.write(pb.SerializeToString())
Fill schedules of persons with routing
service
# The generated trip of the person is not guaranteed to be reachable in the map. Preroute is required.
# pre-route
# run: ./routing -map data/gravitygenerator/beijing_map.pb
client = RoutingClient("http://localhost:52101")
ok_persons = []
for p in od_persons:
p = await pre_route(client, p)
if len(p.schedules) > 0 and len(p.schedules[0].trips) > 0:
ok_persons.append(p)
print(len(ok_persons))
pb = Persons(persons=ok_persons)
with open("data/temp/beijing_OD_ok_person.pb", "wb") as f:
f.write(pb.SerializeToString())
Generate Public Transport drivers
python ./examples/gen_pt_drivers.py
Initialize the TripGenerator
# map from `./examples/add_pt_to_map.py` and `./examples/add_pt_post_process.py`
with open("data/temp/srt.map_with_pt.pb", "rb") as f:
m = Map()
m.ParseFromString(f.read())
tg = TripGenerator(
m=m,
)
Generate the drivers
bus_drivers = tg.generate_public_transport_drivers()
persons_output_path = "data/temp/bus_drivers.pb"
pb = Persons(persons=bus_drivers)
with open(persons_output_path, "wb") as f:
f.write(pb.SerializeToString())
Static Traffic Assignment
Extra conditions are required for STA, if you want to make all driving trips to be assigned to the routes generated by the STA, you need to make sure that the following conditions are met:
- All trips' departure_time should be set.
- There must be lane connections between any in_road and out_road within any junctions.
You should also check the statistics returned by the sta.run
method to see if there are any invalid/ignored trips.
python ./examples/sta.py
Load map and trip data
from mosstool.trip.gmns import STA
from mosstool.type import Map, Persons
m = Map() # load your map
persons = Persons() # load your persons
Run STA
sta = STA(m, "data/temp/sta")
ps, stat = sta.run(persons, reset_routes=True)
print(f"STA finished, {stat}")
# Save the result
with open("data/temp/sta/sta_persons.pb", "wb") as f:
f.write(ps.SerializeToString())
From SUMO
Route Converter
python ./examples/sumo_route_convert.py
Initialize the MapConverter
and convert the map
s2m = MapConverter(
net_path="data/sumo/shenzhen.net.xml",
traffic_light_path="data/sumo/trafficlight.xml",
poly_path="data/sumo/poly.xml",
)
m = s2m.convert_map()
id2uid = s2m.get_sumo_id_mappings()
map_pb = dict2pb(m, Map())
Initialize the RouteConverter
and convert the route
s2r = RouteConverter(
converted_map=map_pb,
sumo_id_mappings=id2uid,
route_path="./data/sumo/trips.xml",
additional_path="./data/sumo/additional.xml",
)
r = s2r.convert_route()
pb = dict2pb(r, Persons())
with open("data/temp/sumo_persons.pb", "wb") as f:
f.write(pb.SerializeToString())