Building a model from GMNS

Contents

Building a model from GMNS#

In this example we create a model for Marshalltown, Iowa, from GMNS data generated from OSM data.

To create a network file from OSM, you can either use AequilibraE or OSM2GMNS

Imports#

from pathlib import Path
from tempfile import mkdtemp

import pandas as pd

# Figure out where our polaris directory is (so we can get some test data)
from polaris import __file__ as polaris_dir
from polaris.network.create.triggers import create_network_triggers, delete_network_triggers
from polaris.network.network import Network
from polaris.utils.database.db_utils import commit_and_close

polaris_dir = Path(polaris_dir).parent.parent
/venv-py312/lib/python3.12/site-packages/geopandas/_compat.py:7: DeprecationWarning: The 'shapely.geos' module is deprecated, and will be removed in a future version. All attributes of 'shapely.geos' are available directly from the top-level 'shapely' namespace (since shapely 2.0.0).
  import shapely.geos

Creates a new supply file with the chosen SRID sphinx_gallery_thumbnail_path = ‘../../examples/model_building/marshalltown.png’

data_folder = polaris_dir / "tests" / "data" / "docs" / "marshalltown"
srid = 3857

project_dir = mkdtemp(prefix="polaris_marshalltown_from_gmns")

Network.create(Path(project_dir) / "Marshalltown-Supply.sqlite", srid=srid, jumpstart=True)
2025-05-09 02:18:51 UTC+0000 - Creating file at /tmp/polaris_marshalltown_from_gmns_d3aggje/Marshalltown-Supply.sqlite
2025-05-09 02:18:51 UTC+0000 - Adding Spatialite infrastructure to the database
2025-05-09 02:18:51 UTC+0000 - Creating Tables
2025-05-09 02:18:52 UTC+0000 - Replacing existing values in Land_Use with standard default set
  land_use  is_home  is_work  is_school  is_discretionary notes
0      ALL        1        1          1                 1  None
2025-05-09 02:18:53 UTC+0000 -   Creating triggers

Opens the newly-created network and import the GMNS network into it

network = Network()
network.open(Path(project_dir) / "Marshalltown-Supply.sqlite")

network.ie.from_gmns(str(data_folder), "epsg:4326")
2025-05-09 02:18:53 UTC+0000 - Working with file on /tmp/polaris_marshalltown_from_gmns_d3aggje/Marshalltown-Supply.sqlite
2025-05-09 02:18:53 UTC+0000 - Creating active links for your network
2025-05-09 02:18:53 UTC+0000 - Importing Nodes
2025-05-09 02:19:14 UTC+0000 - Importing Links
/builds/polaris/code/polarislib/polaris/network/ie/gmns/importer/import_links.py:95: PerformanceWarning: indexing past lexsort depth may impact performance.
  links.loc[:, "use"] = links.use.str.upper()
/builds/polaris/code/polarislib/polaris/network/ie/gmns/importer/import_links.py:96: PerformanceWarning: indexing past lexsort depth may impact performance.
  links.loc[:, "type"] = links["type"].str.upper()
2025-05-09 02:19:17 UTC+0000 - Importing Zones
2025-05-09 02:19:17 UTC+0000 - Importing Locations
2025-05-09 02:19:17 UTC+0000 - No location file to import from GMNS
2025-05-09 02:19:17 UTC+0000 - Finished GMNS import

Unfortunately, Polaris still does not support arbitrary link types due to hard coded parameters in the simulator, so we will have to map them manually.

crosswalk = {
    "WALK": "WALKWAY",
    "TRANSIT": "BUSWAY",
    "RESIDENTIAL": "LOCAL",
    "SERVICE": "OTHER",
    "SECONDARY": "MINOR",
    "CYCLEWAY": "BIKEWAY",  # In Polaris, we do not have a type for both bike and walk
    "TERTIARY": "COLLECTOR",
    "PATH": "WALKWAY",
    "UNCLASSIFIED": "OTHER",
    "PRIMARY": "MAJOR",
    "TRUNK": "PRINCIPAL",
    "MOTORWAY": "EXPRESSWAY",
    "TRACK": "WALKWAY",
}

with commit_and_close(network.path_to_file, spatial=True) as conn:
    for k, v in crosswalk.items():
        conn.execute("""UPDATE Link SET "type"=? WHERE "type"=?;""", [v, k])
        conn.commit()
        conn.execute("DELETE FROM Link_type WHERE link_type=?;", [k])

We also did not did the necessary data imputation into this GMNS network before importing into Polaris, so let’s do it now. Let’s also turn off all triggers while we do that, as it makes it easier to avoid them to complain This adds a free-flow speed of 10 m/s and 1 lane per direction for most links, which is a TERRIBLE data imputation practice, but suffices for the purpose of an example

sqls = [
    """UPDATE Link SET lanes_ab=min(1, lanes_ab) where "type" !='EXPRESSWAY';""",
    """UPDATE Link SET lanes_ba=min(1, lanes_ba) where "type" !='EXPRESSWAY';""",
    """UPDATE Link SET  fspd_ab=min(10, fspd_ab) where lanes_ab>0;""",
    """UPDATE Link SET  fspd_ba=min(10, fspd_ba) where lanes_ba>0;""",
]
with commit_and_close(network.path_to_file, spatial=True) as conn:
    delete_network_triggers(conn)

    for sql in sqls:
        conn.execute(sql)
    conn.commit()

    create_network_triggers(conn)
2025-05-09 02:19:17 UTC+0000 -   Deleting triggers
2025-05-09 02:19:18 UTC+0000 -   Creating triggers
transit = network.transit
transit.purge()

feed = transit.new_gtfs(
    file_path=data_folder / "marshalltownmunicipaltransit-ia-us.zip",
    description="Marshalltown impressive PT system",
    agency="MTPT",
)

feed.set_allow_map_match(True)
feed.set_date("2019-10-08")  # We should be a pick date very carefully
feed.path_store.threshold = 5000  # Let's assume we are on a machine with little memory
feed.set_do_raw_shapes(True)

transit.fix_connections_table()
2025-05-09 02:19:18 UTC+0000 - Clearing transit tables
2025-05-09 02:19:18 UTC+0000 - Table "TRANSIT_RAW_SHAPES" does not exist in the network
2025-05-09 02:19:19 UTC+0000 - Creating GTFS feed object for /builds/polaris/code/polarislib/tests/data/docs/marshalltown/marshalltownmunicipaltransit-ia-us.zip

We can also set a maximum speed to fix possible GTFS nonsense

max_speeds = pd.read_csv(data_folder / "transit_max_speeds.csv")
feed.set_maximum_speeds(max_speeds)
max_speeds.head()
city mode min_distance max_distance speed
0 marshalltown 0 0 2500 6.8
1 marshalltown 0 2500 5000 7.4
2 marshalltown 0 5000 10000 14.7
3 marshalltown 0 10000 1000000 17.3
4 marshalltown 3 0 600 9.6


We do the transit import

feed.doWork()
2025-05-09 02:19:19 UTC+0000 - Loading data for 2019-10-08 from the MTPT GTFS feed. This may take some time
2025-05-09 02:19:19 UTC+0000 - Starting deconflict_stop_times
2025-05-09 02:19:19 UTC+0000 - There were a total of 301 segments that were too fast and were corrected
2025-05-09 02:19:19 UTC+0000 -   Building data structures
2025-05-09 02:19:20 UTC+0000 - Creating map-matching graph from scratch for mode_id=3
/venv-py312/lib/python3.12/site-packages/geopandas/geodataframe.py:2391: UserWarning: CRS mismatch between the CRS of left geometries and the CRS of right geometries.
Use `to_crs()` to reproject one of the input geometries to match the CRS of the other.

Left CRS: EPSG:3857
Right CRS: None

  return geopandas.sjoin(left_df=self, right_df=df, *args, **kwargs)  # noqa: B026
2025-05-09 02:19:20 UTC+0000 - Could not rebuild path for pattern 2000100010000
/venv-py312/lib/python3.12/site-packages/geopandas/geodataframe.py:2391: UserWarning: CRS mismatch between the CRS of left geometries and the CRS of right geometries.
Use `to_crs()` to reproject one of the input geometries to match the CRS of the other.

Left CRS: EPSG:3857
Right CRS: None

  return geopandas.sjoin(left_df=self, right_df=df, *args, **kwargs)  # noqa: B026
2025-05-09 02:19:20 UTC+0000 - Could not rebuild path for pattern 2000200010000
/venv-py312/lib/python3.12/site-packages/geopandas/geodataframe.py:2391: UserWarning: CRS mismatch between the CRS of left geometries and the CRS of right geometries.
Use `to_crs()` to reproject one of the input geometries to match the CRS of the other.

Left CRS: EPSG:3857
Right CRS: None

  return geopandas.sjoin(left_df=self, right_df=df, *args, **kwargs)  # noqa: B026
2025-05-09 02:19:20 UTC+0000 - Could not rebuild path for pattern 2000400010000
/venv-py312/lib/python3.12/site-packages/geopandas/geodataframe.py:2391: UserWarning: CRS mismatch between the CRS of left geometries and the CRS of right geometries.
Use `to_crs()` to reproject one of the input geometries to match the CRS of the other.

Left CRS: EPSG:3857
Right CRS: None

  return geopandas.sjoin(left_df=self, right_df=df, *args, **kwargs)  # noqa: B026
2025-05-09 02:19:20 UTC+0000 - Could not rebuild path for pattern 2000500010000
/venv-py312/lib/python3.12/site-packages/geopandas/geodataframe.py:2391: UserWarning: CRS mismatch between the CRS of left geometries and the CRS of right geometries.
Use `to_crs()` to reproject one of the input geometries to match the CRS of the other.

Left CRS: EPSG:3857
Right CRS: None

  return geopandas.sjoin(left_df=self, right_df=df, *args, **kwargs)  # noqa: B026
2025-05-09 02:19:20 UTC+0000 - Map-matched pattern 2000700010000
/venv-py312/lib/python3.12/site-packages/geopandas/geodataframe.py:2391: UserWarning: CRS mismatch between the CRS of left geometries and the CRS of right geometries.
Use `to_crs()` to reproject one of the input geometries to match the CRS of the other.

Left CRS: EPSG:3857
Right CRS: None

  return geopandas.sjoin(left_df=self, right_df=df, *args, **kwargs)  # noqa: B026
2025-05-09 02:19:20 UTC+0000 - Could not rebuild path for pattern 2000800010000
2025-05-09 02:19:20 UTC+0000 -   Importing feed for agency MTPT on 2019-10-08
2025-05-09 02:19:20 UTC+0000 - Creating transit raw shapes for agency ID: 2
2025-05-09 02:19:20 UTC+0000 -    Finished creating raw shapes
2025-05-09 02:19:21 UTC+0000 - 27 paths requested. 11 objects created

We create the walk/bike networks for this network

network.active.build()
2025-05-09 02:19:21 UTC+0000 - Creating active links for your network
2025-05-09 02:19:21 UTC+0000 -   Deleting triggers
2025-05-09 02:19:21 UTC+0000 - Clearing Transit_walk table and synthetic active nodes from Transit_Stops
2025-05-09 02:19:21 UTC+0000 - Copying links from road network
2025-05-09 02:19:21 UTC+0000 -   Creating triggers
2025-05-09 02:19:23 UTC+0000 -    Reading walk links
2025-05-09 02:19:23 UTC+0000 -    Reading walk links
2025-05-09 02:19:23 UTC+0000 -    Loading Transit stops and mobility nodes
2025-05-09 02:19:23 UTC+0000 -        Reading stops/docks and projecting onto links
2025-05-09 02:19:23 UTC+0000 -        Reading stops/docks and projecting onto links
2025-05-09 02:19:23 UTC+0000 - Breaking active links at stops
2025-05-09 02:19:23 UTC+0000 -    Building direct transfer links
2025-05-09 02:19:24 UTC+0000 -      0 direct connections added between stops

The network still doesn’t have zones, locations or other things, so we won’t bother about running consistency checks

network.close(clear_issues=False)
2025-05-09 02:19:26 UTC+0000 - Creating active links for your network
2025-05-09 02:19:26 UTC+0000 - Network closed at /tmp/polaris_marshalltown_from_gmns_d3aggje/Marshalltown-Supply.sqlite

Total running time of the script: (0 minutes 37.137 seconds)

Gallery generated by Sphinx-Gallery