{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "fe37ddd6",
   "metadata": {},
   "source": [
    "# Experiments with variable flows"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "016cc777",
   "metadata": {},
   "source": [
    "We saw in the previous tutorials how to run simulations with pre-set networks. Pre-set networks can also be runned with flows defined in a matrix, and evolving during the simulation. In this tutorial, we're going to see how to run this simulations. We will use the `OneCrossroadNetwork` to show this."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "9a68f2b1",
   "metadata": {},
   "outputs": [],
   "source": [
    "from sumo_experiments import Experiment\n",
    "from sumo_experiments.preset_networks import OneCrossroadNetwork\n",
    "\n",
    "network = OneCrossroadNetwork()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e695bfb3",
   "metadata": {},
   "source": [
    "## Generate variable flows with a matrix\n",
    "\n",
    "For every pre-set network, three flows functions are implemented : \n",
    "- `generate_flows_only_ahead` defines flows where vehicles can only go ahead at intersections.\n",
    "- `generate_flows_all_directions` defines flows where vehicles can go to every direction at intersections.\n",
    "- `generate_flows_with_matrix` defines flows following a schema described in a matrix.\n",
    "\n",
    "The first two functions implements the parameters `stop_generation_time` and `flow_frequency` that define the flow frequency and the simulation step when flows will end. This setting is set __only one time__. It's impossible to change this parameters during the simulation.\n",
    "\n",
    "As it can be useful to change flows during a simulation, to experiment the adaptation of traffic light behaviour for example, the library implements the `generate_flow_with_matrix` that creates flows evolving over time. Let's see how to use it.\n",
    "\n",
    "The function works as following. We declare matrix whose first line is the **load vector** for all the network, and the other lines are the **proportion of flows that are using a specific route** (between 0 and 1). Thus, each column of the matrix is the setting for a part of the simulation (a period), a load of vehicle for the network, and the proportion of frequency using each route. The time of a period is defined as a **period time**, and is the same for each period of the simulation.\n",
    "\n",
    "The routes of a network are defined as couple entry-exit. In the pre-set networks, a vehicle can enter the network from each entry and leave it by any exit (except the one it has entered). For example, the `OneCrossroadNetwork`, which is the simpliest pre-set network, has 4 entry and 4 exit. Then, the total number of routes is 12 (4\\*3). For a SquareNetwork with a side length of 5 entries, this number rise to 380.\n",
    "\n",
    "The order of the routes in the matrix is as following : the first line represents the most north-west entry, and the exit is the first exit clockwise. We then iterate over all exits clockwise. The next entry is the next entry clockwise, and we restart to iterate over all exits from the most north-west. For exemple, for the `OneCrossroadNetwork`, the 12 lines matrix must have the following order (entry / exit):\n",
    "1) North / East\n",
    "2) North / South\n",
    "3) North / West\n",
    "4) East / North\n",
    "5) East / South\n",
    "6) East / Wes\n",
    "7) South / North\n",
    "8) South / East\n",
    "9) South / West\n",
    "10) West / North\n",
    "11) West / East\n",
    "12) West / South\n",
    "\n",
    "The code below shows an implementation of an Experiment where flows are defined by a load vector and a matrix of coefficient. We define 3 period of time. A period last 300 simulation steps. For the first period, the flows are distributed equally between each route. For the second period, only routes that start by the north entry or the south entry are activated. The repartition of flows between routes is set equally. Then, in the third and last period, we set behaviour as previously, but with the west and east entries. The frequency of vehicles will start at 900 vehicles per hour per entry for the first period, and will evolve to 600 for the last two periods."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "74c9096c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Success.\n",
      "Success.\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "period_time = 300\n",
    "\n",
    "load_vector = np.array([900, 600, 600]) # Load vector : each value represents a frequency for a period, for all the network\n",
    "\n",
    "coeff_matrix = np.array([\n",
    "    # P1      P2      P3\n",
    "    [0.0833, 0.1666, 0.0001], # Proportion of frequency for the route North / East\n",
    "    [0.0833, 0.1666, 0.0001], # Proportion of frequency for the route North / South\n",
    "    [0.0833, 0.1666, 0.0001], # Proportion of frequency for the route North / West\n",
    "    [0.0833, 0.0001, 0.1666], # Proportion of frequency for the route East / North\n",
    "    [0.0833, 0.0001, 0.1666], # Proportion of frequency for the route East / South\n",
    "    [0.0833, 0.0001, 0.1666], # Proportion of frequency for the route East / West\n",
    "    [0.0833, 0.1666, 0.0001], # Proportion of frequency for the route South / North\n",
    "    [0.0833, 0.1666, 0.0001], # Proportion of frequency for the route South / East\n",
    "    [0.0833, 0.1666, 0.0001], # Proportion of frequency for the route South / West\n",
    "    [0.0833, 0.0001, 0.1666], # Proportion of frequency for the route West / North\n",
    "    [0.0833, 0.0001, 0.1666], # Proportion of frequency for the route West / East\n",
    "    [0.0833, 0.0001, 0.1666], # Proportion of frequency for the route West / South\n",
    "])\n",
    "\n",
    "infrastructures = network.generate_infrastructures(\n",
    "    lane_length=200,\n",
    "    green_time=60,\n",
    "    yellow_time=3,\n",
    "    max_speed=50\n",
    ")\n",
    "\n",
    "flows = network.generate_flows_with_matrix(\n",
    "    period_time=period_time,\n",
    "    load_vector=load_vector,\n",
    "    coeff_matrix=coeff_matrix,\n",
    "    distribution='binomial'\n",
    ")\n",
    "\n",
    "exp_matrix = Experiment(\n",
    "    name = 'matrix',\n",
    "    infrastructures = infrastructures,\n",
    "    flows = flows\n",
    ")\n",
    "\n",
    "exp_matrix.run(\n",
    "    simulation_duration=(period_time*3),\n",
    "    gui=True\n",
    ")\n",
    "\n",
    "exp_matrix.clean_files()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "56cc360a",
   "metadata": {},
   "source": [
    "***Note :** SUMO doesn't allow to modify flows when they are defined. To solve this problem, sumo-experiments generates flows for each period, that start at the beginning and last until the the end of the period. Although there are 12 routes in the previous example, sumo-experiments generates actually 36 routes for the entire simulation.*\n",
    "\n",
    "***Note :** As Sumo doesn't accept to create flows with a number of vehicles set to 0, we have to set the flows to a low frequency to make them unused. This flows can then generate a car sometimes.*"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "35868f29",
   "metadata": {},
   "source": [
    "## Generate flows with a CSV file\n",
    "\n",
    "We saw previously how to define variable flows with matrices, with numpy.array objects. This allows to generate matrices and use it. But, in some case, you may want to save persistent flow data, in a CSV file for example, and use it in different experiments. In order to use persistant data, sumo-experiments implements a function `import_flows_parameters_from_csv` that read a CSV file with flow data, and returns a load vector and a coefficient matrix. The function is located in the `util` subpackage.\n",
    "\n",
    "The CSV file must be in that shape :\n",
    "- The first line is the load vector, of size $x$.\n",
    "- The rest of the file is the coeff matrix, of shape ($y$, $x$).\n",
    "- No other data in the file.\n",
    "\n",
    "The default separator for the data is the comma, but another one can be set using the function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "4a07be41",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "from sumo_experiments.util import import_flows_parameters_from_csv\n",
    "\n",
    "load_vector = np.array([300, 200, 200]) # Load vector : each value represents a frequency for a period\n",
    "\n",
    "coeff_matrix = np.array([\n",
    "    # P1      P2      P3\n",
    "    [0.0833, 0.1666, 0.0001], # Proportion of frequency for the route North / East\n",
    "    [0.0833, 0.1666, 0.0001], # Proportion of frequency for the route North / South\n",
    "    [0.0833, 0.1666, 0.0001], # Proportion of frequency for the route North / West\n",
    "    [0.0833, 0.0001, 0.1666], # Proportion of frequency for the route East / North\n",
    "    [0.0833, 0.0001, 0.1666], # Proportion of frequency for the route East / South\n",
    "    [0.0833, 0.0001, 0.1666], # Proportion of frequency for the route East / West\n",
    "    [0.0833, 0.1666, 0.0001], # Proportion of frequency for the route South / North\n",
    "    [0.0833, 0.1666, 0.0001], # Proportion of frequency for the route South / East\n",
    "    [0.0833, 0.1666, 0.0001], # Proportion of frequency for the route South / West\n",
    "    [0.0833, 0.0001, 0.1666], # Proportion of frequency for the route West / North\n",
    "    [0.0833, 0.0001, 0.1666], # Proportion of frequency for the route West / East\n",
    "    [0.0833, 0.0001, 0.1666], # Proportion of frequency for the route West / South\n",
    "])\n",
    "\n",
    "to_csv = np.vstack((load_vector, coeff_matrix))\n",
    "np.savetxt(\"tuto_4.csv\", to_csv, delimiter=\",\")\n",
    "\n",
    "load_vector_2, coeff_matrix_2 = import_flows_parameters_from_csv('tuto_4.csv')\n",
    "\n",
    "print((load_vector == load_vector_2).all())\n",
    "print((coeff_matrix == coeff_matrix_2).all())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f51a287",
   "metadata": {},
   "source": [
    "The load vector and the coefficient matrix extracted from the `import_flows_parameters_from_csv` can then be used to custom an experiment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "7d63a118",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Success.\n",
      "Success.\n"
     ]
    }
   ],
   "source": [
    "period_time = 300\n",
    "\n",
    "flows = network.generate_flows_with_matrix(\n",
    "    period_time=period_time,\n",
    "    load_vector=load_vector_2,\n",
    "    coeff_matrix=coeff_matrix_2\n",
    ")\n",
    "\n",
    "exp_matrix = Experiment(\n",
    "    name = 'matrix_2',\n",
    "    infrastructures = infrastructures,\n",
    "    flows = flows\n",
    ")\n",
    "\n",
    "exp_matrix.run(\n",
    "    simulation_duration=(period_time*3),\n",
    "    gui=True\n",
    ")\n",
    "\n",
    "exp_matrix.clean_files()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "4d696be9",
   "metadata": {},
   "outputs": [],
   "source": [
    "!rm tuto_4.csv"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cb481c2d",
   "metadata": {},
   "source": [
    "**You know now how to create simulations with variable flows. This allows you to create traffic scenarios to test traffic management systems in different conditions. However, this method can only be used with pre-set networks. If you want to reproduce this behaviour with a custom network, you must redefine a similar function, specific to this network. Custom networks are the subject of the next tutorial.**"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
