{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "0807871a",
   "metadata": {},
   "source": [
    "# Pre-set networks\n",
    "\n",
    "To speed up experimentation, but above all to ensure better reproducibility of experiments, pre-designed networks have been implemented in sumo-experiments. There are currently three types of pre-designed network :\n",
    "- A network composed with only one intersection (OneCrossroadNetwork)\n",
    "- A network composed of $x$ intersections arranged in a line (LineNetwork)\n",
    "- A network composed of $x \\times y$ crossroads arranged in a square (GridNetwork)\n",
    "\n",
    "Each network is represented by a class in the `preset_networks` package. The classes contains methods that generates infrastructures, flows, and all add-ons that can be added to a network.\n",
    "\n",
    "***Note :** For now, only detectors can be added to a pre-set network. Adding new features is one of our priority.*\n",
    "\n",
    "Let's see how we create a simulation with a pre-set network. We will use the `OneCrossroadNetwork` to do this.\n",
    "\n",
    "First, we must instantiate the preset network."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "08b949b7",
   "metadata": {},
   "outputs": [],
   "source": [
    "from sumo_experiments.preset_networks import OneCrossroadNetwork\n",
    "\n",
    "network = OneCrossroadNetwork()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fa0c956b",
   "metadata": {},
   "source": [
    "## Methods"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8a36a736",
   "metadata": {},
   "source": [
    "### Infrastructures\n",
    "\n",
    "Each class contains one method that generates infrastructures (`generate_infrastructures`). It is the function that you must use to create an Experiment. This function return an `InfrastructureBuilder` object, containing all the infrastructures needed for the definition of the network (nodes, edges, connections, traffic light programs). Thus, in this example with the `OneCrossroadNetwork`, the function will return an object containing 5 nodes (including 1 traffic light), 8 edges (4 * 2 directions), and 12 connections.\n",
    "\n",
    "The method `generate_infrastructures` has multiple parameters that allows to custom the network. The `lane_length` is the length of all edges of the network, in meters. The `green_time` and the `yellow_time` are respectively the duration of the green and yellow phases, in seconds. The `max_speed` is the maximum speed allowed on the network.\n",
    "\n",
    "***Note :** The SquareNetwork class also implements a `generate_random_infrastructures` method. It also implements a square network, but with random road length (between the config parameters `minimum_edge_length` and `maximum_edge_length`).*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "b4e6997e",
   "metadata": {},
   "outputs": [],
   "source": [
    "infrastructures = network.generate_infrastructures(\n",
    "    lane_length = 200,\n",
    "    green_time = 60,\n",
    "    yellow_time = 3,\n",
    "    max_speed = 50\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "167f4aa7",
   "metadata": {},
   "source": [
    "### Flows\n",
    "\n",
    "Each class contains three methods to define flows for the network :\n",
    "- The `generate_flows_only_ahead` method generates flows of vehicles that enter from an entry and can only leave the network by the opposite exit. This makes the vehicles unable to turn at intersections. The parameters `stop_generation_time` and `flow_frequency` set the simulation step when flows will end and the vehicle generation frequency, in vehicle/hour/entry (and not routes). Vehicles are generated following a distribution law, which can be 'binomial' (default) or 'uniform'.\n",
    "- The `generate_flows_all_directions` method generates flows for each entry, and the vehicles can leave the network by any exit (except the one that is related to the entry). Vehicles can then turn at intersections. The parameters are the exact same as `generate_flows_only_ahead`.\n",
    "- The `generate_flows_with_matrix` method generate variable flows over time that can go anywhere in the intersections. We'll see this in a future section.\n",
    "\n",
    "Each method returns a `FlowBuilder` object containing all the flows and informations about it (flow entry, exit, frequency, vehicle type)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b76c3d3d",
   "metadata": {},
   "source": [
    "Let's do some graphical experiments to show you the difference between the `generate_flows_only_ahead` and the `generate_flows_all_directions`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "bff4e451",
   "metadata": {},
   "outputs": [],
   "source": [
    "flows_only_ahead = network.generate_flows_only_ahead(\n",
    "    stop_generation_time=600,\n",
    "    flow_frequency=300,\n",
    "    distribution='binomial'\n",
    ")\n",
    "\n",
    "flows_all_direction = network.generate_flows_all_directions(\n",
    "    stop_generation_time=600,\n",
    "    flow_frequency=300,\n",
    "    distribution='binomial'\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "bffab841",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Success.\n",
      "Success.\n",
      "Success.\n",
      "Success.\n"
     ]
    }
   ],
   "source": [
    "from sumo_experiments import Experiment\n",
    "\n",
    "exp_only_ahead = Experiment(\n",
    "    name = 'only_ahead',\n",
    "    infrastructures = infrastructures,\n",
    "    flows = flows_only_ahead\n",
    ")\n",
    "\n",
    "exp_all_directions = Experiment(\n",
    "    name = 'all_directions',\n",
    "    infrastructures = infrastructures,\n",
    "    flows = flows_all_direction\n",
    ")\n",
    "\n",
    "exp_only_ahead.run(\n",
    "    simulation_duration=600, \n",
    "    gui=True\n",
    ")\n",
    "\n",
    "exp_all_directions.run(\n",
    "    simulation_duration=600, \n",
    "    gui=True\n",
    ")\n",
    "\n",
    "exp_only_ahead.clean_files()\n",
    "exp_all_directions.clean_files()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12eba27a",
   "metadata": {},
   "source": [
    "### Detectors\n",
    "\n",
    "Optionally, you can add detectors to the intersections of a network to adapt their operation to the traffic. While detectors can be added when generating the pre-set network, adapting the behavior of traffic lights is more complex and will be the subject of another tutorial. Detectors' range appears in blue in SUMO GUI.\n",
    "\n",
    "Each pre-set network has three methods to generate detectors :\n",
    "- `generate_boolean_detectors` generates short-range detectors that check if a car is its range or not. You can set the range of the detector with the parameter `boolean_detector_length`.\n",
    "- `generate_numerical_detectors` generates long-range detectors (all of the edge) that are supposed to count vehicles that are on its range. The range of numerical detectors is all the length of the edge it observes.\n",
    "- `generate_all_detectors` generates the boolean and the numerical detectors for each traffic light.\n",
    "\n",
    "The detectors generates data that can be used by the TraCi library to modify the traffic lights behaviour.\n",
    "\n",
    "To add detectors to a network, just add the `detectors` parameter to an experiment, with the right function to use to generate it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "93090536",
   "metadata": {},
   "outputs": [],
   "source": [
    "boolean_detectors = network.generate_boolean_detectors(\n",
    "    boolean_detector_length=20\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "c6a8e435",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Success.\n",
      "Success.\n"
     ]
    }
   ],
   "source": [
    "exp_detectors = Experiment(\n",
    "    name = 'detectors',\n",
    "    infrastructures = infrastructures,\n",
    "    flows = flows_only_ahead,\n",
    "    detectors = boolean_detectors\n",
    ")\n",
    "\n",
    "exp_detectors.run(\n",
    "    simulation_duration=600,\n",
    "    gui=True\n",
    ")\n",
    "\n",
    "exp_detectors.clean_files()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee0ea11b",
   "metadata": {},
   "source": [
    "***Note :** Some other features should be added in the future, like pedestrians, bicycles, etc.*"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4115eec",
   "metadata": {},
   "source": [
    "**In the next tutorial, we'll see how to create experiments with variable flows, using the `generate_flows_with_matrix` from a pre-set network object.**"
   ]
  }
 ],
 "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.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
