Note
Go to the end to download the full example code.
Creating external locations#
In this example, we show how to use Polaris-Studio and GeoPandas to create external locations along roads that traverse the boundary of the modelling area.
Imports#
from pathlib import Path
import geopandas as gpd
from polaris.network.consistency.network_objects.location import Location
from polaris.network.consistency.network_objects.location_links import link_types_for_ext
from polaris.network.network import Network
from polaris.utils.database.db_utils import commit_and_close
project_file = Path("/tmp/Bloomington_external_locations/Bloomington-Supply.sqlite")
net = Network.from_file(project_file, False)
Create the new model supply and open it We would normally use the national network as the source of roads entering and exiting the model area For the sake of an example, let’s use the Bloomington network itself
national_file = Path("/tmp/Bloomington_external_locations/Bloomington-Supply.sqlite")
national_net = Network.from_file(national_file, False)
Grabbing the necessary layers#
We also make sure that the layers are in the same projection
zone_layer = net.data_tables.get_geo_layer("zone")
national_links = national_net.data_tables.get_geo_layer("link").to_crs(zone_layer.crs)
We can be a little fancier and put a little buffer around all zones before we dissolve them This avoids problems with all sorts of imprecisions in the zone boundaries All Polaris models have projections in meters, so we can just go ahead and add a 10m buffer This would be a disaster if we were working in lat/lon
zone_polygon = zone_layer.buffer(10).union_all()
model_boundary = zone_polygon.boundary
Find all links that cross the zone line#
crossing_link = national_links[national_links.crosses(model_boundary)]
For each link, we add a location that is 50 meters within the model area
all_externals = []
for idx, rec in crossing_link.iterrows():
link = rec.geo
intersec = link.intersection(model_boundary)
intersec = list(intersec.geoms) if intersec.geom_type == "MultiPoint" else [intersec]
for interc_point in intersec:
projection = link.project(interc_point)
alt1 = link.interpolate(min(projection + 50, link.length))
if zone_polygon.contains(alt1):
all_externals.append(alt1)
else:
all_externals.append(link.interpolate(max(projection - 50, 0)))
Let’s make sure we don’t add locations too close to each other. Say 200 meters?
min_dist = 200
extern = gpd.GeoDataFrame({"geometry": gpd.GeoSeries(all_externals, crs=zone_layer.crs)}).set_geometry("geometry")
repeat = extern.sjoin_nearest(extern, max_distance=min_dist, rsuffix="r", exclusive=True, distance_col="dist")
repeat = repeat[repeat.index_r < repeat.index]
extern = extern.drop(repeat.index)
We also should only add locations that are close to Freeways/Expressways in the model Loading external trips in locations connected to other link types causes problems in the traffic model 3km to the closest Freeway should make for any discrepancies between the national and model networks
max_dist = 3000
print(link_types_for_ext)
model_links = net.data_tables.get_geo_layer("link")[["link", "type", "geo"]]
model_links = model_links[model_links["type"].str.upper().isin(link_types_for_ext)]
extern = extern.sjoin_nearest(model_links, max_distance=max_dist).dropna()[extern.columns]
['EXPRESSWAY', 'FREEWAY', 'EXTERNAL']
Let’s add all these locations
max_loc = net.data_tables.get_table("Location").reset_index().location.max() + 1
with commit_and_close(net.path_to_file, spatial=True) as conn:
conn.execute("DELETE FROM Location WHERE land_use='EXTERNAL'")
conn.commit()
for extern in extern.geometry.tolist():
loc = Location(max_loc, net.geotools, net.data_tables, conn)
loc.land_use = "EXTERNAL"
loc.notes = f"External location"
loc.geo = extern
loc.avg_parking_cost = loc.stop_flag = loc.dir = loc.offset = loc.setback = loc.x = loc.y = loc.tod_distance = 0
loc.truck_org = loc.truck_des = loc.auto_org = loc.auto_des = 1
loc.transit = loc.area_type = loc.lu_area = loc.census_zone = loc.anchored = 0
loc.link = net.geotools.get_link_for_point_by_mode(loc.geo, ["AUTO"])
loc.save(conn)
max_loc += 1
# Let's add a single external zone, as this is just an example
# break
DON’T FORGET TO REBUILD LOCATION-LINKS AND RUN GEO-CONSISTENCY#
from polaris.utils.database.db_utils import commit_and_close
net.geo_consistency.update_all()
net.tools.data_tables.refresh_cache()
net.tools.rebuild_location_links()
net.tools.rebuild_location_parking(maximum_distance=200)
with commit_and_close(net.path_to_file, spatial=True) as conn:
conn.execute("DELETE FROM Editing_Table")
/builds/polaris/code/polarislib/polaris/network/data/data_table_cache.py:42: UserWarning: THIS TABLE WAS CACHED, USE WITH CAUTION
warnings.warn("THIS TABLE WAS CACHED, USE WITH CAUTION")
Closes project#
net.close(False)
Total running time of the script: (0 minutes 9.313 seconds)