{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n\n# Traffic Assignment without an AequilibraE Model\n\nIn this example, we show how to perform Traffic Assignment in AequilibraE without a model.\n\nWe are using [Sioux Falls data](https://github.com/bstabler/TransportationNetworks/tree/master/SiouxFalls), from TNTP.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        ".. admonition:: References\n\n  * :doc:`../../static_traffic_assignment`\n\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        ".. seealso::\n    Several functions, methods, classes and modules are used in this example:\n\n    * :func:`aequilibrae.paths.Graph`\n    * :func:`aequilibrae.paths.TrafficClass`\n    * :func:`aequilibrae.paths.TrafficAssignment` \n    * :func:`aequilibrae.matrix.AequilibraeMatrix`\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# Imports\nimport os\nimport pandas as pd\nimport numpy as np\nfrom uuid import uuid4\nfrom tempfile import gettempdir\n\nfrom aequilibrae.matrix import AequilibraeMatrix\nfrom aequilibrae.paths import Graph\nfrom aequilibrae.paths import TrafficAssignment\nfrom aequilibrae.paths.traffic_class import TrafficClass"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "We load the example file from the GMNS GitHub repository\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "net_file = \"https://raw.githubusercontent.com/bstabler/TransportationNetworks/master/SiouxFalls/SiouxFalls_net.tntp\"\n\ndemand_file = \"https://raw.githubusercontent.com/bstabler/TransportationNetworks/master/SiouxFalls/CSV-data/SiouxFalls_od.csv\"\n\ngeometry_file = \"https://raw.githubusercontent.com/bstabler/TransportationNetworks/master/SiouxFalls/SiouxFalls_node.tntp\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Let's use a temporary folder to store our data\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "folder = os.path.join(gettempdir(), uuid4().hex)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "First we load our demand file. This file has three columns: O, D, and Ton. \nO and D stand for origin and destination, respectively, and Ton is the demand of each\nOD pair.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "dem = pd.read_csv(demand_file)\nzones = int(max(dem.O.max(), dem.D.max()))\nindex = np.arange(zones) + 1"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Since our OD-matrix is in a different shape than we expect (for Sioux Falls, that\nwould be a 24x24 matrix), we must create our matrix.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "mtx = np.zeros(shape=(zones, zones))\nfor element in dem.to_records(index=False):\n    mtx[element[0]-1][element[1]-1] = element[2]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Now let's create an AequilibraE Matrix with out data\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "aemfile = os.path.join(folder, \"demand.aem\")\naem = AequilibraeMatrix()\nkwargs = {'file_name': aemfile,\n          'zones': zones,\n          'matrix_names': ['matrix']}\n\naem.create_empty(**kwargs)\naem.matrix['matrix'][:,:] = mtx[:,:]\naem.index[:] = index[:]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Let's import information about our network. As we're loading data in TNTP format,\nwe should do these manipulations.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "net = pd.read_csv(net_file, skiprows=2, sep=\"\\t\", lineterminator=\";\", header=None)\n\nnet.columns = [\"newline\", \"a_node\", \"b_node\", \"capacity\", \"length\", \"free_flow_time\", \"b\", \"power\", \"speed\", \"toll\", \"link_type\", \"terminator\"]\n\nnet.drop(columns=[\"newline\", \"terminator\"], index=[76], inplace=True)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "network = net[['a_node', 'b_node', \"capacity\", 'free_flow_time', \"b\", \"power\"]]\nnetwork = network.assign(direction=1)\nnetwork[\"link_id\"] = network.index + 1\nnetwork = network.astype({\"a_node\":\"int64\", \"b_node\": \"int64\"})"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Now we'll import the geometry (as lon/lat) for our network, this is required if you plan to \nuse the `A*` path finding, otherwise it can safely be skipped.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "geom = pd.read_csv(geometry_file, skiprows=1, sep=\"\\t\", lineterminator=\";\", header=None)\ngeom.columns = [\"newline\", \"lon\", \"lat\", \"terminator\"]\ngeom.drop(columns=[\"newline\", \"terminator\"], index=[24], inplace=True)\ngeom[\"node_id\"] = geom.index + 1\ngeom = geom.astype({\"node_id\": \"int64\", \"lon\": \"float64\", \"lat\": \"float64\"}).set_index(\"node_id\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Let's build our Graph! In case you're in doubt about AequilibraE Graph, \n`click here <aequilibrae-graphs>` to read more about it.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "g = Graph()\ng.cost = network['free_flow_time'].values\ng.capacity = network['capacity'].values\ng.free_flow_time = network['free_flow_time'].values\n\ng.network = network\ng.prepare_graph(index)\ng.set_graph(\"free_flow_time\")\ng.cost = np.array(g.cost, copy=True)\ng.set_skimming([\"free_flow_time\"])\ng.set_blocked_centroid_flows(False)\ng.network[\"id\"] = g.network.link_id\ng.lonlat_index = geom.loc[g.all_nodes]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Let's prepare our matrix for computation\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "aem.computational_view([\"matrix\"])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Let's perform our assignment. Feel free to try different algorithms,\nas well as change the maximum number of iterations and the gap\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "assigclass = TrafficClass(\"car\", g, aem)\n\nassig = TrafficAssignment()\n\nassig.set_classes([assigclass])\nassig.set_vdf(\"BPR\")\nassig.set_vdf_parameters({\"alpha\": \"b\", \"beta\": \"power\"})\nassig.set_capacity_field(\"capacity\")\nassig.set_time_field(\"free_flow_time\")\nassig.set_algorithm(\"fw\")\nassig.max_iter = 100\nassig.rgap_target = 1e-6\nassig.execute()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Now let's take a look at the Assignment results\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "assig.results()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "And at the Assignment report\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "assig.report()"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.10.18"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}