{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n\n# Path and skimming\n\nIn this example, we show how to perform path computation and network skimming\nfor the Sioux Falls example model.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# Imports\nfrom uuid import uuid4\nfrom tempfile import gettempdir\nfrom os.path import join\nfrom aequilibrae.utils.create_example import create_example\n\n# We create the example project inside our temp folder\nfldr = join(gettempdir(), uuid4().hex)\n\nproject = create_example(fldr)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import logging\nimport sys\n\n# We the project opens, we can tell the logger to direct all messages to the terminal as well\nlogger = project.logger\nstdout_handler = logging.StreamHandler(sys.stdout)\nformatter = logging.Formatter(\"%(asctime)s;%(levelname)s ; %(message)s\")\nstdout_handler.setFormatter(formatter)\nlogger.addHandler(stdout_handler)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Path Computation\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "from aequilibrae.paths import PathResults"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "We build all graphs\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "project.network.build_graphs()\n# We get warnings that several fields in the project are filled with NaNs. \n# This is true, but we won't use those fields."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "We grab the graph for cars\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "graph = project.network.graphs[\"c\"]\n\n# we also see what graphs are available\n# project.network.graphs.keys()\n\n# let's say we want to minimize the distance\ngraph.set_graph(\"distance\")\n\n# And will skim time and distance while we are at it\ngraph.set_skimming([\"free_flow_time\", \"distance\"])\n\n# And we will allow paths to be computed going through other centroids/centroid connectors\n# required for the Sioux Falls network, as all nodes are centroids\n# BE CAREFUL WITH THIS SETTING\ngraph.set_blocked_centroid_flows(False)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Let's instantiate a path results object and prepare it to work with the graph\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "res = PathResults()\nres.prepare(graph)\n\n# compute a path from node 8 to 13\nres.compute_path(8, 4)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# We can get the sequence of nodes we traverse\nres.path_nodes"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# We can get the link sequence we traverse\nres.path"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# We can get the mileposts for our sequence of nodes\nres.milepost"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# If we want to compute the path for a different destination and the same origin, we can just do this\n# It is way faster when you have large networks\nres.update_trace(13)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "res.path_nodes"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "If you want to show the path in Python\nWe do NOT recommend this, though....  It is very slow for real networks\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\nfrom shapely.ops import linemerge"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "links = project.network.links\n\n# We plot the entire network\ncurr = project.conn.cursor()\ncurr.execute(\"Select link_id from links;\")\n\nfor lid in curr.fetchall():\n    geo = links.get(lid[0]).geometry\n    plt.plot(*geo.xy, color=\"red\")\n\npath_geometry = linemerge(links.get(lid).geometry for lid in res.path)\nplt.plot(*path_geometry.xy, color=\"blue\", linestyle=\"dashed\", linewidth=2)\nplt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Now to skimming\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "from aequilibrae.paths import NetworkSkimming"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "But let's say we only want a skim matrix for nodes 1, 3, 6 & 8\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import numpy as np\n\ngraph.prepare_graph(np.array([1, 3, 6, 8]))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# And run the skimming\nskm = NetworkSkimming(graph)\nskm.execute()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "The result is an AequilibraEMatrix object\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "skims = skm.results.skims\n\n# Which we can manipulate directly from its temp file, if we wish\nskims.matrices"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# Or access each matrix\nskims.free_flow_time"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# We can save it to the project if we want\nskm.save_to_project(\"base_skims\")\n\n# We can also retrieve this skim record to write something to its description\nmatrices = project.matrices\nmat_record = matrices.get_record(\"base_skims\")\nmat_record.description = \"minimized FF travel time while also skimming distance for just a few nodes\"\nmat_record.save()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "project.close()"
      ]
    }
  ],
  "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.9.16"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}