diff --git a/.github/workflows/build_pipeline.yml b/.github/workflows/build_pipeline.yml
deleted file mode 100644
index 30562847..00000000
--- a/.github/workflows/build_pipeline.yml
+++ /dev/null
@@ -1,86 +0,0 @@
-name: CI
-
-on: [push]
-
-jobs:
- build:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- - uses: actions/setup-python@v1
- with:
- python-version: 3.11
- - uses: actions/cache@v1
- with:
- path: ~/.cache/pip
- key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
- restore-keys: |
- ${{ runner.os }}-pip-
- - name: Install dependencies
- run: |
- export ACCEPT_EULA=Y
- sudo apt-get update
- python -m pip install --upgrade pip
- sudo apt-get install -y python3-pip libgdal-dev locales
- sudo apt-get install -y libspatialindex-dev
- sudo apt-get install -y coinor-cbc
- export CPLUS_INCLUDE_PATH=/usr/include/gdal
- export C_INCLUDE_PATH=/usr/include/gdal
- sudo apt-get install ca-certificates
- export CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
- pip install GDAL==3.4.1
- pip install -e '.[dev]'
-
- - name: Install jupyter kernel
- run: python -m ipykernel install --user --name genet
-
- - name: Unit tests
- run: pytest
-
- - name: Configure AWS credentials
- uses: aws-actions/configure-aws-credentials@v1
- with:
- aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
- aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- aws-region: eu-west-1
- - name: Push zip to S3
- env:
- AWS_S3_CODE_BUCKET: ${{ secrets.AWS_S3_CODE_BUCKET }}
- run: |
- echo $GITHUB_REPOSITORY
- echo $GITHUB_SHA
- echo $GITHUB_SHA > release
- if test "$GITHUB_REF" = "refs/heads/main"; then
- echo "Branch is main - no need to make a release name..."
- else
- echo "Making a release name for non-main branch..."
- branch=`echo $GITHUB_REF | awk -F '/' '{print $3}'`
- release_name=`echo $GITHUB_ACTOR-$branch`
- echo "Release name: $release_name"
- echo $release_name > release_name
- fi
- zip -r app.zip .
- repo_slug=`echo $GITHUB_REPOSITORY | awk -F '/' '{print $2}'`
- echo $repo_slug
- aws s3 cp app.zip "s3://$AWS_S3_CODE_BUCKET/$repo_slug.zip"
- - name: Send build success notification
- if: success()
- uses: rtCamp/action-slack-notify@v2.2.0
- env:
- SLACK_MESSAGE: ${{ github.repository }} build ${{ github.run_number }} launched by ${{ github.actor }} has succeeded
- SLACK_TITLE: Build Success
- SLACK_CHANNEL: city-modelling-feeds
- SLACK_USERNAME: GitHub Build Bot
- SLACK_ICON: https://slack-files2.s3-us-west-2.amazonaws.com/avatars/2017-12-19/288981919427_f45f04edd92902a96859_512.png
- SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
- - name: Send build failure notification
- if: failure()
- uses: rtCamp/action-slack-notify@v2.2.0
- env:
- SLACK_COLOR: '#FF0000'
- SLACK_MESSAGE: ${{ github.repository }} build ${{ github.run_number }} launched by ${{ github.actor }} has failed
- SLACK_TITLE: Build Failure!
- SLACK_CHANNEL: city-modelling-feeds
- SLACK_USERNAME: GitHub Build Bot
- SLACK_ICON: https://slack-files2.s3-us-west-2.amazonaws.com/avatars/2017-12-19/288981919427_f45f04edd92902a96859_512.png
- SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
diff --git a/.github/workflows/commit-ci.yml b/.github/workflows/commit-ci.yml
new file mode 100644
index 00000000..f87bca3a
--- /dev/null
+++ b/.github/workflows/commit-ci.yml
@@ -0,0 +1,32 @@
+name: Minimal CI
+
+on:
+ push:
+ branches:
+ - "**"
+ paths-ignore:
+ - README.md
+ - CHANGELOG.md
+ - LICENSE
+ - CONTRIBUTING.md
+ - docs/**
+ - mkdocs.yml
+
+jobs:
+ test:
+ uses: arup-group/actions-city-modelling-lab/.github/workflows/python-install-lint-test.yml@main
+ with:
+ os: ubuntu-latest
+ py3version: "11"
+ notebook_kernel: genet
+ lint: false
+ additional_mamba_args: coin-or-cbc
+
+ aws-upload:
+ needs: test
+ if: needs.test.result == 'success'
+ uses: arup-group/actions-city-modelling-lab/.github/workflows/aws-upload.yml@main
+ secrets:
+ AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+ AWS_S3_CODE_BUCKET: ${{ secrets.AWS_S3_CODE_BUCKET }}
\ No newline at end of file
diff --git a/.github/workflows/daily-scheduled-ci.yml b/.github/workflows/daily-scheduled-ci.yml
index 911cd6e6..179a7935 100644
--- a/.github/workflows/daily-scheduled-ci.yml
+++ b/.github/workflows/daily-scheduled-ci.yml
@@ -1,69 +1,36 @@
-name: Daily GeNet CI Build
+name: Daily CI
on:
schedule:
- - cron: '37 14 * * 1-5'
+ - cron: '37 14 * * 1-5' # checks on the 37th minute of the 14th hour every weekday
jobs:
- build:
+ get-date:
runs-on: ubuntu-latest
-
steps:
- - name: Checkout
- uses: actions/checkout@v3
-
- - uses: actions/setup-python@v1
- with:
- python-version: 3.11
-
- - uses: actions/cache@v1
- with:
- path: ~/.cache/pip
- key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
- restore-keys: |
- ${{ runner.os }}-pip-
-
- - name: Install dependencies
- run: |
- export ACCEPT_EULA=Y
- sudo apt-get update
- python -m pip install --upgrade pip
- sudo apt-get install -y python3-pip libgdal-dev locales
- sudo apt-get install -y libspatialindex-dev
- sudo apt-get install -y coinor-cbc
- export CPLUS_INCLUDE_PATH=/usr/include/gdal
- export C_INCLUDE_PATH=/usr/include/gdal
- sudo apt-get install ca-certificates
- export CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
- pip install GDAL==3.4.1
- pip install -e '.[dev]'
-
- - name: Install jupyter kernel
- run: python -m ipykernel install --user --name genet
-
- - name: Run tests
- run: pytest
-
- - name: Send build success notification
- if: success()
- uses: rtCamp/action-slack-notify@v2.2.0
- env:
- SLACK_MESSAGE: ${{ github.repository }} Daily scheduled CI Build ${{ github.run_number }} has succeeded
- SLACK_TITLE: Daily Scheduled CI Build Success
- SLACK_CHANNEL: city-modelling-feeds
- SLACK_USERNAME: GitHub Build Bot
- SLACK_ICON: https://slack-files2.s3-us-west-2.amazonaws.com/avatars/2017-12-19/288981919427_f45f04edd92902a96859_512.png
- SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
-
- - name: Send build failure notification
- if: failure()
- uses: rtCamp/action-slack-notify@v2.2.0
- env:
- SLACK_COLOR: '#FF0000'
- SLACK_LINK_NAMES: true
- SLACK_MESSAGE: ' ${{ github.repository }} Daily scheduled CI Build ${{ github.run_number }} has failed'
- SLACK_TITLE: Daily Scheduled CI Build Failure!
- SLACK_CHANNEL: city-modelling-feeds
- SLACK_USERNAME: GitHub Build Bot
- SLACK_ICON: https://slack-files2.s3-us-west-2.amazonaws.com/avatars/2017-12-19/288981919427_f45f04edd92902a96859_512.png
- SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
+ - name: Add date to github output env
+ run: echo "DATE=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
+
+ test:
+ needs: get-date
+ uses: arup-group/actions-city-modelling-lab/.github/workflows/python-install-lint-test.yml@main
+ with:
+ os: ubuntu-latest
+ py3version: "11"
+ notebook_kernel: genet
+ pytest_args: '--no-cov' # ignore coverage
+ cache_mamba_env: false
+ lint: false
+ mamba_env_name: daily-ci
+ additional_mamba_args: coin-or-cbc
+
+ slack-notify-ci:
+ needs: test
+ if: always()
+ uses: arup-group/actions-city-modelling-lab/.github/workflows/slack-notify.yml@main
+ secrets:
+ SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
+ with:
+ result: needs.test.result
+ channel: genet-feed
+ message: Daily CI action
\ No newline at end of file
diff --git a/.github/workflows/pr-ci.yml b/.github/workflows/pr-ci.yml
new file mode 100644
index 00000000..fe54113e
--- /dev/null
+++ b/.github/workflows/pr-ci.yml
@@ -0,0 +1,48 @@
+name: Pull Request CI
+
+on:
+ pull_request:
+ branches:
+ - main
+ paths-ignore:
+ - README.md
+ - CHANGELOG.md
+ - LICENSE
+ - CONTRIBUTING.md
+ - docs/**
+ - mkdocs.yml
+
+jobs:
+ test:
+ strategy:
+ matrix:
+ os: [windows-latest, ubuntu-latest, macos-latest]
+ py3version: ["9", "11"]
+ include:
+ - os: windows-latest
+ add_args: ""
+ - os: ubuntu-latest
+ add_args: coin-or-cbc
+ - os: macos-latest
+ add_args: coin-or-cbc
+ fail-fast: false
+ uses: arup-group/actions-city-modelling-lab/.github/workflows/python-install-lint-test.yml@main
+ with:
+ os: ${{ matrix.os }}
+ py3version: ${{ matrix.py3version }}
+ notebook_kernel: genet
+ lint: false
+ pytest_args: '--no-cov' # ignore coverage
+ upload_to_codecov: false
+ additional_mamba_args: ${{ matrix.add_args }}
+
+ test-coverage:
+ uses: arup-group/actions-city-modelling-lab/.github/workflows/python-install-lint-test.yml@main
+ with:
+ os: ubuntu-latest
+ py3version: "11"
+ notebook_kernel: genet
+ lint: false
+ pytest_args: 'tests/' # ignore example notebooks
+ upload_to_codecov: true
+ additional_mamba_args: coin-or-cbc
diff --git a/Dockerfile b/Dockerfile
index 113996ab..0ba4ff60 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,13 +1,11 @@
-FROM python:3.11.4-bullseye
+FROM mambaorg/micromamba:1.5.3-bullseye-slim
-RUN apt-get update && \
-apt-get upgrade -y && \
-apt-get -y install gcc git libgdal-dev libgeos-dev libspatialindex-dev curl coinor-cbc cmake && \
-rm -rf /var/lib/apt/lists/*
+COPY --chown=$MAMBA_USER:$MAMBA_USER . ./src
-RUN python -m pip install --no-cache-dir --compile --upgrade pip
+RUN micromamba install -y -n base -c conda-forge -c city-modelling-lab python=3.11 "proj>=9.3" pip coin-or-cbc --file src/requirements/base.txt && \
+ micromamba clean --all --yes
+ARG MAMBA_DOCKERFILE_ACTIVATE=1
-COPY . ./src
-
-RUN pip3 install --no-cache-dir --compile -e ./src && pip cache purge
+RUN pip install --no-deps ./src
+ENTRYPOINT ["/usr/local/bin/_entrypoint.sh"]
\ No newline at end of file
diff --git a/README.md b/README.md
index bf5bfb77..2ac6b5ac 100644
--- a/README.md
+++ b/README.md
@@ -10,18 +10,12 @@
+ [Building the image](#build-the-image)
+ [Running GeNet from the container](#running-a-container-with-a-pre-baked-script)
* [Installation as a Python Package](#installation-as-a-python-package)
- + [Native dependencies](#native-dependencies)
+ + [Installing a development environment](#installing-a-development-environment)
+ [A note on the mathematical solver](#a-note-on-the-mathematical-solver)
- + [Installing the native dependencies](#installing-the-native-dependencies)
- + [Install dev prereqs](#install-dev-prereqs)
- + [Install Python dependencies](#install-python-dependencies)
- + [Install GeNet in to the virtual environment](#install-genet-in-to-the-virtual-environment)
- + [Install Kepler dependencies](#install-kepler-dependencies)
- [Developing GeNet](#developing-genet)
* [Unit tests](#unit-tests)
* [Code coverage report](#generate-a-unit-test-code-coverage-report)
* [Linting](#lint-the-python-code)
- * [Smoke testing Jupyter notebooks](#smoke-test-the-jupyter-notebooks)
## Overview
@@ -114,85 +108,59 @@ as part of your command:
Note, if you reference data inside your script, or pass them as arguments to the script, they need to reference the
aliased path inside the container, here: `/mnt/`, rather than the path `/local/path/`.
-### Installation as a Python Package / CLI
+### Installation as a Python Package
-You can in your base installation of python or a virtual environment.
You can use GeNet's CLI to run pre-baked modifications or checks on networks.
-You can also write your own python scripts, importing genet as a package, use IPython shell or Jupyter Notebook to load
-up a network, inspect or change it and save it out to file. Check out the
-[wiki pages](https://github.com/arup-group/genet/wiki/Functionality-and-Usage-Guide) and
-[example jupyter notebooks](https://github.com/arup-group/genet/tree/master/notebooks)
-for usage examples.
-
-**Note:** if you plan only to _use_ GeNet rather than make code changes to it, you can avoid having to perform any
-local installation by using [GeNet's Docker image](#using-docker). If you are going to make code changes or use GeNet's
-CLI locally, follow the steps below:
-
-#### Native dependencies
-GeNet uses some Python libraries that rely on underlying native libraries for things like geospatial calculations and
-linear programming solvers. Before you install GeNet's Python dependencies, you must first install these native
-libraries.
+You can also write your own python scripts, importing genet as a package, use IPython shell or Jupyter Notebook to load up a network, inspect or change it and save it out to file.
+Check out the [wiki pages](https://github.com/arup-group/genet/wiki/Functionality-and-Usage-Guide) and [example jupyter notebooks](https://github.com/arup-group/genet/tree/master/notebooks) for usage examples.
+
+**Note:** if you plan only to _use_ GeNet rather than make code changes to it, you can ignore the rest of this section and instead use [GeNet's Docker image](#using-docker).
+If you are going to make code changes or use GeNet's CLI locally, follow the steps below to [install a development environment](#installing-a-development-environment).
+
+### Installing a development environment
+
+To create a development environment for genet, with all libraries required for development and quality assurance installed, it is easiest to install genet using the [mamba](https://mamba.readthedocs.io/en/latest/index.html) package manager, as follows:
+
+1. Install mamba with the [Mambaforge](https://github.com/conda-forge/miniforge#mambaforge) executable for your operating system.
+2. Open the command line (or the "miniforge prompt" in Windows).
+3. Download (a.k.a., clone) the genet repository: `git clone git@github.com:arup-group/genet.git`
+4. Change into the `genet` directory: `cd genet`
+5. Create the genet mamba environment: `mamba create -n genet -c conda-forge -c city-modelling-lab --file requirements/base.txt --file requirements/dev.txt`
+6. Activate the genet mamba environment: `mamba activate genet`
+7. Install the genet package into the environment, in editable mode and ignoring dependencies (we have dealt with those when creating the mamba environment): `pip install --no-deps -e .`
+8. Create a jupyter kernel linked to the environment to enable example notebook testing: `ipython kernel install --user --name=genet`
+
+All together:
+``` shell
+git clone git@github.com:arup-group/genet.git
+cd genet
+mamba create -n genet -c conda-forge -c city-modelling-lab --file requirements/base.txt --file requirements/dev.txt
+mamba activate genet
+pip install --no-deps -e .
+ipython kernel install --user --name=genet
+```
#### A note on the mathematical solver
+
**Note**: The default CBC solver is pre-installed inside [GeNet's Docker image](#using-docker), which can save you some
installation effort
-To use methods which snap public transit to the graph, GeNet uses a mathematical solver. If you won't be using such
-functionality, you do not need to install this solver.
+To use methods which snap public transit to the graph, GeNet uses a mathematical solver.
+If you won't be using such functionality, you do not need to install this solver.
Methods default to [CBC](https://projects.coin-or.org/Cbc), an open source solver.
+You can install this solver (`coin-or-cbc`) along with your other requirements when creating the environment: `mamba create -n genet -c conda-forge -c city-modelling-lab coin-or-cbc --file requirements/base.txt --file requirements/dev.txt`,
+or install it after the fact `mamba install -n genet coin-or-cbc`
+
Another good open source choice is [GLPK](https://www.gnu.org/software/glpk/).
The solver you use needs to support MILP - mixed integer linear programming.
-#### Installing the native dependencies
-The commands for installing the necessary native libraries vary according to the operating system you are using, for
-example:
-
-| OS | Commands |
-|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-|Mac OS | `brew install boost` `brew install spatialindex` `brew install gdal --HEAD` `brew install gdal` `brew tap coin-or-tools/coinor` `brew install coin-or-tools/coinor/cbc` `brew install cbc` |
-|Ubuntu | `sudo apt install libspatialindex-dev` `sudo apt install libgdal-dev` `sudo apt install coinor-cbc` |
-
-#### Install dev prereqs
-(Use equivalent linux or Windows package management as appropriate for your environment)
-
- brew install python3.11
- brew install virtualenv
-
-#### Install Python dependencies
-Create and activate a Python virtual environment
-
- virtualenv -p python3.11 venv
- source venv/bin/activate
-
-#### Install GeNet in to the virtual environment
-Finally, install `GeNet`'s Python dependencies
-
- pip install -e .
-
-After installation, you should be able to successfully run the help command to see all possible commands:
-
- genet --help
-
-To inspect a specific command, run e.g.:
-
- genet simplify-network --help
-
-#### Install Kepler dependencies
-
-Please follow [kepler's installation instructions](https://docs.kepler.gl/docs/keplergl-jupyter#install) to be able to
-use the visualisation methods. To see the maps in a jupyter notebook, make sure you enable widgets.
-```
-jupyter nbextension enable --py widgetsnbextension
-```
-
## Developing GeNet
-We welcome community contributions to GeNet; please see our [guide to contributing](CONTRIBUTING.md) and our
-[community code of conduct](CODE_OF_CONDUCT.md). If you are making changes to the codebase, you should use the tools
-described below to verify that the code still works. All of the following commands assume you are in the project's root
-directory.
+We welcome community contributions to GeNet; please see our [guide to contributing](CONTRIBUTING.md) and our [community code of conduct](CODE_OF_CONDUCT.md).
+If you are making changes to the codebase, you should use the tools described below to verify that the code still works.
+All of the following commands assume you are in the project's root directory.
-### tests
+### Tests
To run unit tests within genet python environment (including testing example notebooks):
pytest
diff --git a/examples/4_3_using_network_routing.ipynb b/examples/4_3_using_network_routing.ipynb
index f30239cb..43fdd5c7 100644
--- a/examples/4_3_using_network_routing.ipynb
+++ b/examples/4_3_using_network_routing.ipynb
@@ -25,12 +25,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "Graph info: Name: \n",
- "Type: MultiDiGraph\n",
- "Number of nodes: 1662\n",
- "Number of edges: 3166\n",
- "Average in degree: 1.9049\n",
- "Average out degree: 1.9049 \n",
+ "Graph info: MultiDiGraph with 1662 nodes and 3166 edges \n",
"Schedule info: Schedule:\n",
"Number of services: 9\n",
"Number of routes: 68\n",
@@ -40,6 +35,7 @@
],
"source": [
"import os\n",
+ "import shutil\n",
"\n",
"from genet import read_matsim\n",
"\n",
@@ -267,9 +263,9 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "2022-07-14 15:40:37,681 - Checking `linkRefId`s of the Route: `VJ375a660d47a2aa570aa20a8568012da8497ffecf` are present in the graph\n",
- "2022-07-14 15:40:37,685 - Rerouting Route `VJ375a660d47a2aa570aa20a8568012da8497ffecf`\n",
- "2022-07-14 15:40:37,784 - Changed Route attributes for 1 routes\n"
+ "2023-12-08 13:44:17,450 - Checking `linkRefId`s of the Route: `VJ375a660d47a2aa570aa20a8568012da8497ffecf` are present in the graph\n",
+ "2023-12-08 13:44:17,451 - Rerouting Route `VJ375a660d47a2aa570aa20a8568012da8497ffecf`\n",
+ "2023-12-08 13:44:17,492 - Changed Route attributes for 1 routes\n"
]
}
],
@@ -298,26 +294,29 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "2022-07-14 15:40:40,387 - Routing Service 20274 with modes = {'bus'}\n",
- "2022-07-14 15:40:40,429 - Building Maximum Stable Set for PT graph with 8 stops and 6 edges\n",
- "2022-07-14 15:40:40,896 - Passing problem to solver\n",
- "2022-07-14 15:40:40,898 - Initializing ordered Set vertices with a fundamentally unordered data source (type: set). This WILL potentially lead to nondeterministic behavior in Pyomo\n",
- "2022-07-14 15:40:40,915 - Passing problem to solver\n",
- "2022-07-14 15:40:41,597 - Stop ID changes detected for Routes: {'VJ375a660d47a2aa570aa20a8568012da8497ffecf', 'VJ6c64ab7b477e201cae950efde5bd0cb4e2e8888e', 'VJ812fad65e7fa418645b57b446f00cba573f2cdaf'}\n",
- "2022-07-14 15:40:41,601 - Changed Route attributes for 3 routes\n",
- "2022-07-14 15:40:41,608 - Changed Link attributes for 41 links\n"
+ "2023-12-08 13:44:18,258 - Routing Service 20274 with modes = {'bus'}\n",
+ "2023-12-08 13:44:18,274 - Building Maximum Stable Set for PT graph with 8 stops and 6 edges\n",
+ "2023-12-08 13:44:18,338 - Passing problem to solver\n",
+ "2023-12-08 13:44:18,339 - Initializing ordered Set vertices with a fundamentally unordered data source (type: set). This WILL potentially lead to nondeterministic behavior in Pyomo\n",
+ "2023-12-08 13:44:18,343 - Passing problem to solver\n",
+ "2023-12-08 13:44:18,838 - Stop ID changes detected for Routes: {'VJ6c64ab7b477e201cae950efde5bd0cb4e2e8888e', 'VJ812fad65e7fa418645b57b446f00cba573f2cdaf', 'VJ375a660d47a2aa570aa20a8568012da8497ffecf'}\n",
+ "2023-12-08 13:44:18,841 - Changed Route attributes for 3 routes\n",
+ "2023-12-08 13:44:18,845 - Changed Link attributes for 41 links\n"
]
}
],
"source": [
- "n.route_service(\"20274\", additional_modes={\"car\"})"
+ "if shutil.which(\"cbc\"):\n",
+ " n.route_service(\"20274\", additional_modes={\"car\"})\n",
+ "else:\n",
+ " print(\"Cannot route service without a solver installed\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "If you are creating a `Network` and want to snap and route the entire `Schedule`, or a larger number of services, the method `route_schedule` is advised. Bear in mind though that it will struggle with large networks and big and complicated schedules. Similar parameters apply to this method as the one abov"
+ "If you are creating a `Network` and want to snap and route the entire `Schedule`, or a larger number of services, the method `route_schedule` is advised. Bear in mind though that it will struggle with large networks and big and complicated schedules. Similar parameters apply to this method as the one above, and a solver is needed to undertake the routing."
]
},
{
@@ -334,32 +333,35 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "2022-07-14 15:40:41,615 - Building Spatial Tree\n",
- "2022-07-14 15:40:43,833 - Extracting Modal SubTree for modes: {'bus'}\n",
- "2022-07-14 15:40:43,882 - Routing Service 15660 with modes = {'bus'}\n",
- "2022-07-14 15:40:43,884 - Building Maximum Stable Set for PT graph with 5 stops and 3 edges\n",
- "2022-07-14 15:40:44,283 - This Maximum Stable Set Problem is partially viable.\n",
- "2022-07-14 15:40:44,284 - Maximum Stable Set problem to snap the PT graph to the network is partially viable, meaning not all stops have found a link to snap to within the distance_threshold.Partial snapping is ON, this problem will proceed to the solver.\n",
- "2022-07-14 15:40:44,285 - Passing problem to solver\n",
- "2022-07-14 15:40:44,286 - Initializing ordered Set vertices with a fundamentally unordered data source (type: set). This WILL potentially lead to nondeterministic behavior in Pyomo\n",
- "2022-07-14 15:40:44,288 - Passing problem to solver\n",
- "2022-07-14 15:40:44,383 - Successfully snapped 4 stops to network links.\n",
- "2022-07-14 15:40:44,408 - Routing Service 20274 with modes = {'bus'}\n",
- "2022-07-14 15:40:44,410 - Building Maximum Stable Set for PT graph with 8 stops and 6 edges\n",
- "2022-07-14 15:40:44,673 - Passing problem to solver\n",
- "2022-07-14 15:40:44,674 - Initializing ordered Set vertices with a fundamentally unordered data source (type: set). This WILL potentially lead to nondeterministic behavior in Pyomo\n",
- "2022-07-14 15:40:44,677 - Passing problem to solver\n",
- "2022-07-14 15:40:44,790 - Stop ID changes detected for Routes: {'VJ375a660d47a2aa570aa20a8568012da8497ffecf', 'VJ6c64ab7b477e201cae950efde5bd0cb4e2e8888e', 'VJ812fad65e7fa418645b57b446f00cba573f2cdaf', 'VJ3716910ec59c370d9f5c69137df7276b68cf0a08', 'VJ1cf651142378958b52229bfe1fa552e49136e60e', 'VJf2e0de4f5dad68cb03064e6064e372dde52cc678'}\n",
- "2022-07-14 15:40:44,804 - Changed Route attributes for 6 routes\n",
- "2022-07-14 15:40:44,813 - Added 1 nodes\n",
- "2022-07-14 15:40:45,325 - Generated 0 link ids.\n",
- "2022-07-14 15:40:45,341 - Added 2 links\n",
- "2022-07-14 15:40:45,364 - Changed Link attributes for 53 links\n"
+ "2023-12-08 13:44:18,854 - Building Spatial Tree\n",
+ "2023-12-08 13:44:19,530 - Extracting Modal SubTree for modes: {'bus'}\n",
+ "2023-12-08 13:44:19,544 - Routing Service 20274 with modes = {'bus'}\n",
+ "2023-12-08 13:44:19,545 - Building Maximum Stable Set for PT graph with 8 stops and 6 edges\n",
+ "2023-12-08 13:44:19,589 - Passing problem to solver\n",
+ "2023-12-08 13:44:19,590 - Initializing ordered Set vertices with a fundamentally unordered data source (type: set). This WILL potentially lead to nondeterministic behavior in Pyomo\n",
+ "2023-12-08 13:44:19,592 - Passing problem to solver\n",
+ "2023-12-08 13:44:19,696 - Routing Service 15660 with modes = {'bus'}\n",
+ "2023-12-08 13:44:19,698 - Building Maximum Stable Set for PT graph with 5 stops and 3 edges\n",
+ "2023-12-08 13:44:19,753 - This Maximum Stable Set Problem is partially viable.\n",
+ "2023-12-08 13:44:19,754 - Maximum Stable Set problem to snap the PT graph to the network is partially viable, meaning not all stops have found a link to snap to within the distance_threshold.Partial snapping is ON, this problem will proceed to the solver.\n",
+ "2023-12-08 13:44:19,754 - Passing problem to solver\n",
+ "2023-12-08 13:44:19,755 - Initializing ordered Set vertices with a fundamentally unordered data source (type: set). This WILL potentially lead to nondeterministic behavior in Pyomo\n",
+ "2023-12-08 13:44:19,756 - Passing problem to solver\n",
+ "2023-12-08 13:44:19,821 - Successfully snapped 4 stops to network links.\n",
+ "2023-12-08 13:44:19,830 - Stop ID changes detected for Routes: {'VJf2e0de4f5dad68cb03064e6064e372dde52cc678', 'VJ6c64ab7b477e201cae950efde5bd0cb4e2e8888e', 'VJ812fad65e7fa418645b57b446f00cba573f2cdaf', 'VJ375a660d47a2aa570aa20a8568012da8497ffecf', 'VJ3716910ec59c370d9f5c69137df7276b68cf0a08', 'VJ1cf651142378958b52229bfe1fa552e49136e60e'}\n",
+ "2023-12-08 13:44:19,834 - Changed Route attributes for 6 routes\n",
+ "2023-12-08 13:44:19,838 - Added 1 nodes\n",
+ "2023-12-08 13:44:19,900 - Generated 0 link ids.\n",
+ "2023-12-08 13:44:19,903 - Added 2 links\n",
+ "2023-12-08 13:44:19,907 - Changed Link attributes for 53 links\n"
]
}
],
"source": [
- "unsnapped_service_ids = n.route_schedule(services=[\"20274\", \"15660\"])"
+ "if shutil.which(\"cbc\"):\n",
+ " unsnapped_service_ids = n.route_schedule(services=[\"20274\", \"15660\"])\n",
+ "else:\n",
+ " print(\"Cannot route schedule without a solver installed\")"
]
},
{
@@ -383,11 +385,11 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "2022-07-14 15:40:45,436 - Added 0 nodes\n",
- "2022-07-14 15:40:45,858 - Generated 0 link ids.\n",
- "2022-07-14 15:40:45,866 - Added 8 links\n",
- "2022-07-14 15:40:45,869 - Changed Stop attributes for 10 stops\n",
- "2022-07-14 15:40:45,874 - Changed Route attributes for 2 routes\n"
+ "2023-12-08 13:44:19,925 - Added 0 nodes\n",
+ "2023-12-08 13:44:19,969 - Generated 0 link ids.\n",
+ "2023-12-08 13:44:19,973 - Added 8 links\n",
+ "2023-12-08 13:44:19,975 - Changed Stop attributes for 10 stops\n",
+ "2023-12-08 13:44:19,977 - Changed Route attributes for 2 routes\n"
]
}
],
@@ -481,13 +483,20 @@
"source": [
"list(n.schedule[\"17732\"].routes())[0].route"
]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
}
],
"metadata": {
"kernelspec": {
- "display_name": "genet",
+ "display_name": "genet-new",
"language": "python",
- "name": "genet"
+ "name": "python3"
},
"language_info": {
"codemirror_mode": {
@@ -499,7 +508,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.7.7"
+ "version": "3.11.6"
},
"latex_envs": {
"LaTeX_envs_menu_present": true,
diff --git a/examples/5_2_modifying_network_pt_schedule.ipynb b/examples/5_2_modifying_network_pt_schedule.ipynb
index 0c0697ac..3a3c9c90 100644
--- a/examples/5_2_modifying_network_pt_schedule.ipynb
+++ b/examples/5_2_modifying_network_pt_schedule.ipynb
@@ -23,12 +23,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "Graph info: Name: \n",
- "Type: MultiDiGraph\n",
- "Number of nodes: 1662\n",
- "Number of edges: 3166\n",
- "Average in degree: 1.9049\n",
- "Average out degree: 1.9049 \n",
+ "Graph info: MultiDiGraph with 1662 nodes and 3166 edges \n",
"Schedule info: Schedule:\n",
"Number of services: 9\n",
"Number of routes: 68\n",
@@ -39,6 +34,7 @@
"source": [
"# read example network\n",
"import os\n",
+ "import shutil\n",
"\n",
"from genet import Route, Service, Stop, read_matsim\n",
"\n",
@@ -222,7 +218,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "2022-07-14 15:49:53,678 - Added Services with IDs `['new_service']` and Routes: [['new_route']]\n"
+ "2023-12-08 13:44:17,452 - Added Services with IDs `['new_service']` and Routes: [['new_route']]\n"
]
}
],
@@ -244,10 +240,10 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "2022-07-14 15:49:54,010 - Route with ID `new_route` for Service 20274 within already exists in the Schedule. This Route will be reindexed to `20274_4`\n",
- "2022-07-14 15:49:54,016 - Reindexed Route from new_route to 20274_4\n",
- "2022-07-14 15:49:54,018 - Added Routes with IDs ['20274_4'], to Services `['20274']` within the Schedule\n",
- "/Users/kasia.kozlowska/PycharmProjects/ABM/genet/genet/schedule_elements.py:1384: UserWarning: DataFrame columns are not unique, some columns will be omitted.\n",
+ "2023-12-08 13:44:17,570 - Route with ID `new_route` for Service 20274 within already exists in the Schedule. This Route will be reindexed to `20274_4`\n",
+ "2023-12-08 13:44:17,573 - Reindexed Route from new_route to 20274_4\n",
+ "2023-12-08 13:44:17,575 - Added Routes with IDs ['20274_4'], to Services `['20274']` within the Schedule\n",
+ "/Users/bryn.pickering/Repos/arup-group/genet/genet/schedule_elements.py:1803: UserWarning: DataFrame columns are not unique, some columns will be omitted.\n",
" self.vehicles = {**df.T.to_dict(), **self.vehicles}\n"
]
}
@@ -380,7 +376,9 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "2022-07-14 15:49:54,284 - Added Routes with IDs ['another_new_route'], to Services `['20274']` within the Schedule\n"
+ "2023-12-08 13:44:17,731 - Added Routes with IDs ['another_new_route'], to Services `['20274']` within the Schedule\n",
+ "/Users/bryn.pickering/Repos/arup-group/genet/genet/schedule_elements.py:1803: UserWarning: DataFrame columns are not unique, some columns will be omitted.\n",
+ " self.vehicles = {**df.T.to_dict(), **self.vehicles}\n"
]
}
],
@@ -448,7 +446,9 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "2022-07-14 15:49:54,612 - Added Routes with IDs ['another_new_route_2'], to Services `['20274']` within the Schedule\n"
+ "2023-12-08 13:44:17,959 - Added Routes with IDs ['another_new_route_2'], to Services `['20274']` within the Schedule\n",
+ "/Users/bryn.pickering/Repos/arup-group/genet/genet/schedule_elements.py:1803: UserWarning: DataFrame columns are not unique, some columns will be omitted.\n",
+ " self.vehicles = {**df.T.to_dict(), **self.vehicles}\n"
]
}
],
@@ -494,8 +494,10 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "2022-07-14 15:49:54,944 - The following stops will inherit the data currently stored under those Stop IDs in the Schedule: ['490000235X.link:834', '490010689KB.link:981'].\n",
- "2022-07-14 15:49:54,946 - Added Routes with IDs ['another_new_route_3'], to Services `['20274']` within the Schedule\n"
+ "2023-12-08 13:44:18,133 - The following stops will inherit the data currently stored under those Stop IDs in the Schedule: ['490000235X.link:834', '490010689KB.link:981'].\n",
+ "2023-12-08 13:44:18,135 - Added Routes with IDs ['another_new_route_3'], to Services `['20274']` within the Schedule\n",
+ "/Users/bryn.pickering/Repos/arup-group/genet/genet/schedule_elements.py:1803: UserWarning: DataFrame columns are not unique, some columns will be omitted.\n",
+ " self.vehicles = {**df.T.to_dict(), **self.vehicles}\n"
]
}
],
@@ -546,7 +548,7 @@
{
"data": {
"text/plain": [
- "13293"
+ "1566"
]
},
"execution_count": 16,
@@ -567,7 +569,16 @@
"start_time": "2022-07-14T14:49:55.186816Z"
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/Users/bryn.pickering/Repos/arup-group/genet/genet/schedule_elements.py:1803: UserWarning: DataFrame columns are not unique, some columns will be omitted.\n",
+ " self.vehicles = {**df.T.to_dict(), **self.vehicles}\n"
+ ]
+ }
+ ],
"source": [
"n.schedule.generate_vehicles()"
]
@@ -586,8 +597,8 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "2022-07-14 15:49:55,588 - The following vehicle types are missing from the `vehicle_types` attribute: {'bus'}\n",
- "2022-07-14 15:49:55,589 - Vehicles affected by missing vehicle types: {'fun_bus_1': {'type': 'bus'}, 'fun_bus_2': {'type': 'bus'}, 'some_bus_2': {'type': 'bus'}}\n"
+ "2023-12-08 13:44:18,335 - The following vehicle types are missing from the `vehicle_types` attribute: {'bus'}\n",
+ "2023-12-08 13:44:18,337 - Vehicles affected by missing vehicle types: {'fun_bus_1': {'type': 'bus'}, 'fun_bus_2': {'type': 'bus'}, 'some_bus_2': {'type': 'bus'}}\n"
]
},
{
@@ -618,7 +629,7 @@
{
"data": {
"text/plain": [
- "13293"
+ "1566"
]
},
"execution_count": 19,
@@ -674,7 +685,7 @@
"
\n",
"
\n",
"
0
\n",
- "
2022-07-14 15:49:53
\n",
+ "
2023-12-08 13:44:17
\n",
"
add
\n",
"
service
\n",
"
None
\n",
@@ -685,7 +696,7 @@
"
\n",
"
\n",
"
1
\n",
- "
2022-07-14 15:49:54
\n",
+ "
2023-12-08 13:44:17
\n",
"
add
\n",
"
route
\n",
"
None
\n",
@@ -696,7 +707,7 @@
"
\n",
"
\n",
"
2
\n",
- "
2022-07-14 15:49:54
\n",
+ "
2023-12-08 13:44:17
\n",
"
add
\n",
"
route
\n",
"
None
\n",
@@ -707,7 +718,7 @@
"
\n",
"
\n",
"
3
\n",
- "
2022-07-14 15:49:54
\n",
+ "
2023-12-08 13:44:17
\n",
"
add
\n",
"
route
\n",
"
None
\n",
@@ -718,7 +729,7 @@
"
\n",
"
\n",
"
4
\n",
- "
2022-07-14 15:49:54
\n",
+ "
2023-12-08 13:44:18
\n",
"
add
\n",
"
route
\n",
"
None
\n",
@@ -733,11 +744,11 @@
],
"text/plain": [
" timestamp change_event object_type old_id new_id \\\n",
- "0 2022-07-14 15:49:53 add service None new_service \n",
- "1 2022-07-14 15:49:54 add route None 20274_4 \n",
- "2 2022-07-14 15:49:54 add route None another_new_route \n",
- "3 2022-07-14 15:49:54 add route None another_new_route_2 \n",
- "4 2022-07-14 15:49:54 add route None another_new_route_3 \n",
+ "0 2023-12-08 13:44:17 add service None new_service \n",
+ "1 2023-12-08 13:44:17 add route None 20274_4 \n",
+ "2 2023-12-08 13:44:17 add route None another_new_route \n",
+ "3 2023-12-08 13:44:17 add route None another_new_route_2 \n",
+ "4 2023-12-08 13:44:18 add route None another_new_route_3 \n",
"\n",
" old_attributes new_attributes \\\n",
"0 None {'id': 'new_service', 'name': 'N55'} \n",
@@ -852,25 +863,28 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "2022-07-14 15:49:57,865 - Routing Service new_service with modes = {'bus'}\n",
- "2022-07-14 15:49:57,899 - Building Maximum Stable Set for PT graph with 4 stops and 3 edges\n",
- "2022-07-14 15:49:58,036 - This Maximum Stable Set Problem is partially viable.\n",
- "2022-07-14 15:49:58,037 - Maximum Stable Set problem to snap the PT graph to the network is partially viable, meaning not all stops have found a link to snap to within the distance_threshold.Partial snapping is ON, this problem will proceed to the solver.\n",
- "2022-07-14 15:49:58,038 - Passing problem to solver\n",
- "2022-07-14 15:49:58,041 - Initializing ordered Set vertices with a fundamentally unordered data source (type: set). This WILL potentially lead to nondeterministic behavior in Pyomo\n",
- "2022-07-14 15:49:58,047 - Passing problem to solver\n",
- "2022-07-14 15:49:58,374 - Successfully snapped 3 stops to network links.\n",
- "2022-07-14 15:49:58,390 - Stop ID changes detected for Routes: {'new_route'}\n",
- "2022-07-14 15:49:58,394 - Changed Route attributes for 1 routes\n",
- "2022-07-14 15:49:58,399 - Added 1 nodes\n",
- "2022-07-14 15:49:58,505 - Generated 0 link ids.\n",
- "2022-07-14 15:49:58,510 - Added 2 links\n",
- "2022-07-14 15:49:58,513 - Changed Link attributes for 4 links\n"
+ "2023-12-08 13:44:19,064 - Routing Service new_service with modes = {'bus'}\n",
+ "2023-12-08 13:44:19,077 - Building Maximum Stable Set for PT graph with 4 stops and 3 edges\n",
+ "2023-12-08 13:44:19,121 - This Maximum Stable Set Problem is partially viable.\n",
+ "2023-12-08 13:44:19,124 - Maximum Stable Set problem to snap the PT graph to the network is partially viable, meaning not all stops have found a link to snap to within the distance_threshold.Partial snapping is ON, this problem will proceed to the solver.\n",
+ "2023-12-08 13:44:19,125 - Passing problem to solver\n",
+ "2023-12-08 13:44:19,128 - Initializing ordered Set vertices with a fundamentally unordered data source (type: set). This WILL potentially lead to nondeterministic behavior in Pyomo\n",
+ "2023-12-08 13:44:19,132 - Passing problem to solver\n",
+ "2023-12-08 13:44:19,208 - Successfully snapped 3 stops to network links.\n",
+ "2023-12-08 13:44:19,217 - Stop ID changes detected for Routes: {'new_route'}\n",
+ "2023-12-08 13:44:19,218 - Changed Route attributes for 1 routes\n",
+ "2023-12-08 13:44:19,222 - Added 1 nodes\n",
+ "2023-12-08 13:44:19,266 - Generated 0 link ids.\n",
+ "2023-12-08 13:44:19,269 - Added 2 links\n",
+ "2023-12-08 13:44:19,270 - Changed Link attributes for 4 links\n"
]
}
],
"source": [
- "n.route_service(\"new_service\")"
+ "if shutil.which(\"cbc\"):\n",
+ " n.route_service(\"new_service\")\n",
+ "else:\n",
+ " print(\"Cannot route service without a solver installed\")"
]
},
{
@@ -952,7 +966,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "2022-07-14 15:49:58,565 - Reindexed Service from new_service to more_appropriate_id\n"
+ "2023-12-08 13:44:19,290 - Reindexed Service from new_service to more_appropriate_id\n"
]
}
],
@@ -974,7 +988,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "2022-07-14 15:49:58,583 - Reindexed Route from new_route to more_appropriate_route_id\n"
+ "2023-12-08 13:44:19,297 - Reindexed Route from new_route to more_appropriate_route_id\n"
]
}
],
@@ -1026,7 +1040,7 @@
"
\n",
"
\n",
"
3
\n",
- "
2022-07-14 15:49:54
\n",
+ "
2023-12-08 13:44:17
\n",
"
add
\n",
"
route
\n",
"
None
\n",
@@ -1037,7 +1051,7 @@
"
\n",
"
\n",
"
4
\n",
- "
2022-07-14 15:49:54
\n",
+ "
2023-12-08 13:44:18
\n",
"
add
\n",
"
route
\n",
"
None
\n",
@@ -1048,7 +1062,7 @@
"
\n",
"
\n",
"
5
\n",
- "
2022-07-14 15:49:58
\n",
+ "
2023-12-08 13:44:19
\n",
"
modify
\n",
"
route
\n",
"
new_route
\n",
@@ -1059,7 +1073,7 @@
"
\n",
"
\n",
"
6
\n",
- "
2022-07-14 15:49:58
\n",
+ "
2023-12-08 13:44:19
\n",
"
modify
\n",
"
service
\n",
"
new_service
\n",
@@ -1070,7 +1084,7 @@
"
\n",
"
\n",
"
7
\n",
- "
2022-07-14 15:49:58
\n",
+ "
2023-12-08 13:44:19
\n",
"
modify
\n",
"
route
\n",
"
new_route
\n",
@@ -1085,11 +1099,11 @@
],
"text/plain": [
" timestamp change_event object_type old_id \\\n",
- "3 2022-07-14 15:49:54 add route None \n",
- "4 2022-07-14 15:49:54 add route None \n",
- "5 2022-07-14 15:49:58 modify route new_route \n",
- "6 2022-07-14 15:49:58 modify service new_service \n",
- "7 2022-07-14 15:49:58 modify route new_route \n",
+ "3 2023-12-08 13:44:17 add route None \n",
+ "4 2023-12-08 13:44:18 add route None \n",
+ "5 2023-12-08 13:44:19 modify route new_route \n",
+ "6 2023-12-08 13:44:19 modify service new_service \n",
+ "7 2023-12-08 13:44:19 modify route new_route \n",
"\n",
" new_id \\\n",
"3 another_new_route_2 \n",
@@ -1150,9 +1164,9 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "/Users/kasia.kozlowska/PycharmProjects/ABM/genet/genet/schedule_elements.py:1384: UserWarning: DataFrame columns are not unique, some columns will be omitted.\n",
+ "/Users/bryn.pickering/Repos/arup-group/genet/genet/schedule_elements.py:1803: UserWarning: DataFrame columns are not unique, some columns will be omitted.\n",
" self.vehicles = {**df.T.to_dict(), **self.vehicles}\n",
- "2022-07-14 15:49:58,899 - Removed Services with IDs `more_appropriate_id`, and Routes: {'more_appropriate_route_id'}\n"
+ "2023-12-08 13:44:19,404 - Removed Services with IDs `more_appropriate_id`, and Routes: {'more_appropriate_route_id'}\n"
]
}
],
@@ -1174,9 +1188,17 @@
"name": "stderr",
"output_type": "stream",
"text": [
- "2022-07-14 15:49:59,144 - Removed Routes with IDs ['another_new_route_2'], to Services `20274`.\n",
- "2022-07-14 15:49:59,467 - Removed Routes with IDs ['another_new_route'], to Services `20274`.\n",
- "2022-07-14 15:49:59,892 - Removed Routes with IDs ['another_new_route_3'], to Services `20274`.\n"
+ "/Users/bryn.pickering/Repos/arup-group/genet/genet/schedule_elements.py:1803: UserWarning: DataFrame columns are not unique, some columns will be omitted.\n",
+ " self.vehicles = {**df.T.to_dict(), **self.vehicles}\n",
+ "2023-12-08 13:44:19,507 - Removed Routes with IDs ['another_new_route_2'], to Services `20274`.\n",
+ "2023-12-08 13:44:19,603 - Removed Routes with IDs ['another_new_route_3'], to Services `20274`.\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "2023-12-08 13:44:19,700 - Removed Routes with IDs ['another_new_route'], to Services `20274`.\n"
]
}
],
@@ -1229,7 +1251,7 @@
"