{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import os\n",
    "import json\n",
    "import sumolib\n",
    "from tqdm import tqdm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "loading_dtype = {\n",
    "            'inter_no':'int', 'start_hour':'int', 'start_minute':'int', 'cycle':'int','offset':'int',\n",
    "            'node_id':'str', 'inter_type':'str', 'parent_id':'str','child_id':'str',\n",
    "            'direction':'str', 'condition':'str', 'inc_edge':'str', 'out_edge':'str',\n",
    "            'end_unix':'int', 'inter_name':'str', 'inter_lat':'float', 'inter_lon':'float',\n",
    "            'group_no':'int', 'main_phase_no':'int', 'phase_no':'int','ring_type':'str'\n",
    "            }\n",
    "for alph in ['A', 'B']:\n",
    "    for j in range(1,9):\n",
    "        loading_dtype[f'angle_{alph}{j}'] = 'str'\n",
    "        loading_dtype[f'dura_{alph}{j}'] = 'int'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['match1.csv', 'match6.csv', 'matching.csv', 'movement', 'node2num_cycles.json']\n"
     ]
    }
   ],
   "source": [
    "path_intermediates = '../../Intermediates'\n",
    "files = os.listdir(path_intermediates)\n",
    "print(files)\n",
    "\n",
    "match1 = pd.read_csv(os.path.join(path_intermediates, 'match1.csv'), index_col=0)\n",
    "match6 = pd.read_csv(os.path.join(path_intermediates, 'match6.csv'), index_col=0)\n",
    "matching = pd.read_csv(os.path.join(path_intermediates, 'matching.csv'), index_col=0)\n",
    "nema = pd.read_csv(os.path.join('../../Data/tables', 'nema.csv'), encoding='cp949')\n",
    "plan = pd.read_csv(os.path.join('../../Data/tables', 'plan.csv'), index_col=0)\n",
    "angle = pd.read_csv(os.path.join('../../Data/tables', 'angle.csv'), index_col=0, dtype = loading_dtype)\n",
    "inter_node = pd.read_csv(os.path.join('../../Data/tables', 'inter_node.csv'), index_col=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>inter_no</th>\n",
       "      <th>node_id</th>\n",
       "      <th>inter_type</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>175</td>\n",
       "      <td>i0</td>\n",
       "      <td>parent</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>175</td>\n",
       "      <td>u00</td>\n",
       "      <td>child</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>176</td>\n",
       "      <td>i1</td>\n",
       "      <td>parent</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>177</td>\n",
       "      <td>i2</td>\n",
       "      <td>parent</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>177</td>\n",
       "      <td>u20</td>\n",
       "      <td>child</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>178</td>\n",
       "      <td>i3</td>\n",
       "      <td>parent</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>178</td>\n",
       "      <td>u30</td>\n",
       "      <td>child</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>178</td>\n",
       "      <td>u31</td>\n",
       "      <td>child</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>178</td>\n",
       "      <td>u32</td>\n",
       "      <td>child</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>201</td>\n",
       "      <td>i8</td>\n",
       "      <td>parent</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>202</td>\n",
       "      <td>i9</td>\n",
       "      <td>parent</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>206</td>\n",
       "      <td>i7</td>\n",
       "      <td>parent</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>210</td>\n",
       "      <td>i6</td>\n",
       "      <td>parent</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>210</td>\n",
       "      <td>u60</td>\n",
       "      <td>child</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>178</td>\n",
       "      <td>c30</td>\n",
       "      <td>child</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    inter_no node_id inter_type\n",
       "0        175      i0     parent\n",
       "1        175     u00      child\n",
       "2        176      i1     parent\n",
       "3        177      i2     parent\n",
       "4        177     u20      child\n",
       "5        178      i3     parent\n",
       "6        178     u30      child\n",
       "7        178     u31      child\n",
       "8        178     u32      child\n",
       "9        201      i8     parent\n",
       "10       202      i9     parent\n",
       "11       206      i7     parent\n",
       "12       210      i6     parent\n",
       "13       210     u60      child\n",
       "14       178     c30      child"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "inter_node[]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>move_no</th>\n",
       "      <th>inc_dir</th>\n",
       "      <th>out_dir</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>동</td>\n",
       "      <td>남</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2</td>\n",
       "      <td>서</td>\n",
       "      <td>동</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>3</td>\n",
       "      <td>남</td>\n",
       "      <td>서</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>4</td>\n",
       "      <td>북</td>\n",
       "      <td>남</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>5</td>\n",
       "      <td>서</td>\n",
       "      <td>북</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>6</td>\n",
       "      <td>동</td>\n",
       "      <td>서</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>7</td>\n",
       "      <td>북</td>\n",
       "      <td>동</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>8</td>\n",
       "      <td>남</td>\n",
       "      <td>북</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>9</td>\n",
       "      <td>북동</td>\n",
       "      <td>남동</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>10</td>\n",
       "      <td>남서</td>\n",
       "      <td>북동</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>11</td>\n",
       "      <td>남동</td>\n",
       "      <td>남서</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>12</td>\n",
       "      <td>북서</td>\n",
       "      <td>남동</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>13</td>\n",
       "      <td>남서</td>\n",
       "      <td>북서</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>14</td>\n",
       "      <td>북동</td>\n",
       "      <td>남서</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>15</td>\n",
       "      <td>북서</td>\n",
       "      <td>북동</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>16</td>\n",
       "      <td>남동</td>\n",
       "      <td>북서</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>17</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>18</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>21</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    move_no inc_dir out_dir\n",
       "0         1       동       남\n",
       "1         2       서       동\n",
       "2         3       남       서\n",
       "3         4       북       남\n",
       "4         5       서       북\n",
       "5         6       동       서\n",
       "6         7       북       동\n",
       "7         8       남       북\n",
       "8         9      북동      남동\n",
       "9        10      남서      북동\n",
       "10       11      남동      남서\n",
       "11       12      북서      남동\n",
       "12       13      남서      북서\n",
       "13       14      북동      남서\n",
       "14       15      북서      북동\n",
       "15       16      남동      북서\n",
       "16       17     NaN     NaN\n",
       "17       18     NaN     NaN\n",
       "18       21     NaN     NaN"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>inter_no</th>\n",
       "      <th>start_hour</th>\n",
       "      <th>start_minute</th>\n",
       "      <th>dura_A1</th>\n",
       "      <th>dura_A2</th>\n",
       "      <th>dura_A3</th>\n",
       "      <th>dura_A4</th>\n",
       "      <th>dura_A5</th>\n",
       "      <th>dura_A6</th>\n",
       "      <th>dura_A7</th>\n",
       "      <th>dura_A8</th>\n",
       "      <th>dura_B1</th>\n",
       "      <th>dura_B2</th>\n",
       "      <th>dura_B3</th>\n",
       "      <th>dura_B4</th>\n",
       "      <th>dura_B5</th>\n",
       "      <th>dura_B6</th>\n",
       "      <th>dura_B7</th>\n",
       "      <th>dura_B8</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>176</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>37</td>\n",
       "      <td>73</td>\n",
       "      <td>40</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>37</td>\n",
       "      <td>73</td>\n",
       "      <td>40</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>176</td>\n",
       "      <td>7</td>\n",
       "      <td>0</td>\n",
       "      <td>37</td>\n",
       "      <td>93</td>\n",
       "      <td>40</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>37</td>\n",
       "      <td>93</td>\n",
       "      <td>40</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>176</td>\n",
       "      <td>9</td>\n",
       "      <td>0</td>\n",
       "      <td>37</td>\n",
       "      <td>103</td>\n",
       "      <td>40</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>37</td>\n",
       "      <td>103</td>\n",
       "      <td>40</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>176</td>\n",
       "      <td>18</td>\n",
       "      <td>30</td>\n",
       "      <td>37</td>\n",
       "      <td>113</td>\n",
       "      <td>40</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>37</td>\n",
       "      <td>113</td>\n",
       "      <td>40</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   inter_no  start_hour  start_minute  dura_A1  dura_A2  dura_A3  dura_A4  \\\n",
       "4       176           0             0       37       73       40        0   \n",
       "5       176           7             0       37       93       40        0   \n",
       "6       176           9             0       37      103       40        0   \n",
       "7       176          18            30       37      113       40        0   \n",
       "\n",
       "   dura_A5  dura_A6  dura_A7  dura_A8  dura_B1  dura_B2  dura_B3  dura_B4  \\\n",
       "4        0        0        0        0       37       73       40        0   \n",
       "5        0        0        0        0       37       93       40        0   \n",
       "6        0        0        0        0       37      103       40        0   \n",
       "7        0        0        0        0       37      113       40        0   \n",
       "\n",
       "   dura_B5  dura_B6  dura_B7  dura_B8  \n",
       "4        0        0        0        0  \n",
       "5        0        0        0        0  \n",
       "6        0        0        0        0  \n",
       "7        0        0        0        0  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>inter_no</th>\n",
       "      <th>angle_A1</th>\n",
       "      <th>angle_A2</th>\n",
       "      <th>angle_A3</th>\n",
       "      <th>angle_A4</th>\n",
       "      <th>angle_A5</th>\n",
       "      <th>angle_A6</th>\n",
       "      <th>angle_A7</th>\n",
       "      <th>angle_A8</th>\n",
       "      <th>angle_B1</th>\n",
       "      <th>angle_B2</th>\n",
       "      <th>angle_B3</th>\n",
       "      <th>angle_B4</th>\n",
       "      <th>angle_B5</th>\n",
       "      <th>angle_B6</th>\n",
       "      <th>angle_B7</th>\n",
       "      <th>angle_B8</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>176</td>\n",
       "      <td>180000</td>\n",
       "      <td>180000</td>\n",
       "      <td>270356</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>359180</td>\n",
       "      <td>180270</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   inter_no angle_A1 angle_A2 angle_A3 angle_A4 angle_A5 angle_A6 angle_A7  \\\n",
       "1       176   180000   180000   270356      NaN      NaN      NaN      NaN   \n",
       "\n",
       "  angle_A8 angle_B1 angle_B2 angle_B3 angle_B4 angle_B5 angle_B6 angle_B7  \\\n",
       "1      NaN   359180   180270      NaN      NaN      NaN      NaN      NaN   \n",
       "\n",
       "  angle_B8  \n",
       "1      NaN  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>inter_no</th>\n",
       "      <th>node_id</th>\n",
       "      <th>inter_type</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>176</td>\n",
       "      <td>i1</td>\n",
       "      <td>parent</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   inter_no node_id inter_type\n",
       "2       176      i1     parent"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>inter_no</th>\n",
       "      <th>phas_A</th>\n",
       "      <th>phas_B</th>\n",
       "      <th>move_A</th>\n",
       "      <th>move_B</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>176</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>8</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>176</td>\n",
       "      <td>2</td>\n",
       "      <td>2</td>\n",
       "      <td>8</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>176</td>\n",
       "      <td>3</td>\n",
       "      <td>3</td>\n",
       "      <td>5</td>\n",
       "      <td>18</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   inter_no  phas_A  phas_B  move_A  move_B\n",
       "5       176       1       1       8       4\n",
       "6       176       2       2       8       3\n",
       "7       176       3       3       5      18"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>inter_no</th>\n",
       "      <th>phase_no</th>\n",
       "      <th>ring_type</th>\n",
       "      <th>move_no</th>\n",
       "      <th>inc_dir</th>\n",
       "      <th>out_dir</th>\n",
       "      <th>inc_angle</th>\n",
       "      <th>out_angle</th>\n",
       "      <th>inc_edge</th>\n",
       "      <th>out_edge</th>\n",
       "      <th>node_id</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>176</td>\n",
       "      <td>1</td>\n",
       "      <td>A</td>\n",
       "      <td>8</td>\n",
       "      <td>남</td>\n",
       "      <td>북</td>\n",
       "      <td>180.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>-571542810_01</td>\n",
       "      <td>-571542797_02.99</td>\n",
       "      <td>i1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>176</td>\n",
       "      <td>1</td>\n",
       "      <td>B</td>\n",
       "      <td>4</td>\n",
       "      <td>북</td>\n",
       "      <td>남</td>\n",
       "      <td>359.0</td>\n",
       "      <td>180.0</td>\n",
       "      <td>571542797_02.99</td>\n",
       "      <td>571542810_01</td>\n",
       "      <td>i1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>176</td>\n",
       "      <td>2</td>\n",
       "      <td>A</td>\n",
       "      <td>8</td>\n",
       "      <td>남</td>\n",
       "      <td>북</td>\n",
       "      <td>180.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>-571542810_01</td>\n",
       "      <td>-571542797_02.99</td>\n",
       "      <td>i1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>176</td>\n",
       "      <td>2</td>\n",
       "      <td>B</td>\n",
       "      <td>3</td>\n",
       "      <td>남</td>\n",
       "      <td>서</td>\n",
       "      <td>180.0</td>\n",
       "      <td>270.0</td>\n",
       "      <td>-571542810_01</td>\n",
       "      <td>571543469_01</td>\n",
       "      <td>i1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>176</td>\n",
       "      <td>3</td>\n",
       "      <td>A</td>\n",
       "      <td>5</td>\n",
       "      <td>서</td>\n",
       "      <td>북</td>\n",
       "      <td>270.0</td>\n",
       "      <td>356.0</td>\n",
       "      <td>571543469_02</td>\n",
       "      <td>-571542797_02.99</td>\n",
       "      <td>i1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>176</td>\n",
       "      <td>3</td>\n",
       "      <td>B</td>\n",
       "      <td>18</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>i1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    inter_no  phase_no ring_type  move_no inc_dir out_dir  inc_angle  \\\n",
       "8        176         1         A        8       남       북      180.0   \n",
       "9        176         1         B        4       북       남      359.0   \n",
       "10       176         2         A        8       남       북      180.0   \n",
       "11       176         2         B        3       남       서      180.0   \n",
       "12       176         3         A        5       서       북      270.0   \n",
       "13       176         3         B       18     NaN     NaN        NaN   \n",
       "\n",
       "    out_angle         inc_edge          out_edge node_id  \n",
       "8         0.0    -571542810_01  -571542797_02.99      i1  \n",
       "9       180.0  571542797_02.99      571542810_01      i1  \n",
       "10        0.0    -571542810_01  -571542797_02.99      i1  \n",
       "11      270.0    -571542810_01      571543469_01      i1  \n",
       "12      356.0     571543469_02  -571542797_02.99      i1  \n",
       "13        NaN              NaN               NaN      i1  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>inter_no</th>\n",
       "      <th>move_no</th>\n",
       "      <th>inc_dir</th>\n",
       "      <th>out_dir</th>\n",
       "      <th>inc_edge</th>\n",
       "      <th>out_edge</th>\n",
       "      <th>node_id</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>176</td>\n",
       "      <td>3</td>\n",
       "      <td>남</td>\n",
       "      <td>서</td>\n",
       "      <td>-571542810_01</td>\n",
       "      <td>571543469_01</td>\n",
       "      <td>i1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>176</td>\n",
       "      <td>4</td>\n",
       "      <td>북</td>\n",
       "      <td>남</td>\n",
       "      <td>571542797_02.99</td>\n",
       "      <td>571542810_01</td>\n",
       "      <td>i1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>176</td>\n",
       "      <td>5</td>\n",
       "      <td>서</td>\n",
       "      <td>북</td>\n",
       "      <td>571543469_02</td>\n",
       "      <td>-571542797_02.99</td>\n",
       "      <td>i1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>176</td>\n",
       "      <td>8</td>\n",
       "      <td>남</td>\n",
       "      <td>북</td>\n",
       "      <td>-571542810_01</td>\n",
       "      <td>-571542797_02.99</td>\n",
       "      <td>i1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>176</td>\n",
       "      <td>21</td>\n",
       "      <td>북</td>\n",
       "      <td>서</td>\n",
       "      <td>571542797_02.99</td>\n",
       "      <td>571543469_01</td>\n",
       "      <td>i1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>176</td>\n",
       "      <td>21</td>\n",
       "      <td>서</td>\n",
       "      <td>남</td>\n",
       "      <td>571543469_02</td>\n",
       "      <td>571542810_01</td>\n",
       "      <td>i1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    inter_no  move_no inc_dir out_dir         inc_edge          out_edge  \\\n",
       "13       176        3       남       서    -571542810_01      571543469_01   \n",
       "14       176        4       북       남  571542797_02.99      571542810_01   \n",
       "15       176        5       서       북     571543469_02  -571542797_02.99   \n",
       "16       176        8       남       북    -571542810_01  -571542797_02.99   \n",
       "17       176       21       북       서  571542797_02.99      571543469_01   \n",
       "18       176       21       서       남     571543469_02      571542810_01   \n",
       "\n",
       "   node_id  \n",
       "13      i1  \n",
       "14      i1  \n",
       "15      i1  \n",
       "16      i1  \n",
       "17      i1  \n",
       "18      i1  "
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "inter_no = 176\n",
    "display(nema)\n",
    "display(plan[plan.inter_no==inter_no].iloc[:,:-2])\n",
    "display(angle[angle.inter_no==inter_no])\n",
    "display(inter_node[inter_node.inter_no==inter_no])\n",
    "display(match1[match1.inter_no==inter_no])\n",
    "display(match6[match6.inter_no==inter_no])\n",
    "display(matching[matching.inter_no==inter_no])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_match1(path_move):\n",
    "    '''\n",
    "    신호 DB에는 매 초마다 이동류정보가 업데이트 된다. 그리고 이 이동류정보를 매 5초마다 불러와서 사용하게 된다.\n",
    "    '../Data/tables/move/'에는 5초마다의 이동류정보가 저장되어 있다.\n",
    "\n",
    "    return : 통합된 이동류정보\n",
    "     - 모든 inter_no(교차로번호)에 대한 A, B링 현시별 이동류정보\n",
    "\n",
    "    match1을 만드는 데 시간이 소요되므로 한 번 만들어서 저장해두고 저장해둔 것을 쓴다.\n",
    "    '''\n",
    "    # [이동류번호] 불러오기 (약 1분의 소요시간)\n",
    "    csv_moves = os.listdir(path_move)\n",
    "    moves = [pd.read_csv(path_move + csv_move, index_col=0) for csv_move in tqdm(csv_moves)]\n",
    "    match1 = pd.concat(moves).drop_duplicates().sort_values(by=['inter_no','phas_A','phas_B']).reset_index(drop=True)\n",
    "    match1.to_csv('../Intermediates/match1.csv')\n",
    "    return match1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_match2(match1):\n",
    "    '''\n",
    "    match1을 계층화함.\n",
    "     - match1의 컬럼 : inter_no, phas_A, phas_B, move_A, move_B\n",
    "     - match2의 컬럼 : inter_no, phase_no, ring_type, move_no\n",
    "    '''\n",
    "    # 계층화 (inter_no, phas_A, phas_B, move_A, move_B) -> ('inter_no', 'phase_no', 'ring_type', 'move_no')\n",
    "    matchA = match1[['inter_no', 'phas_A', 'move_A']].copy()\n",
    "    matchA.columns = ['inter_no', 'phase_no', 'move_no']\n",
    "    matchA['ring_type'] = 'A'\n",
    "    matchB = match1[['inter_no', 'phas_B', 'move_B']].copy()\n",
    "    matchB.columns = ['inter_no', 'phase_no', 'move_no']\n",
    "    matchB['ring_type'] = 'B'\n",
    "    match2 = pd.concat([matchA, matchB]).drop_duplicates()\n",
    "    match2 = match2[['inter_no', 'phase_no', 'ring_type', 'move_no']]\n",
    "    match2 = match2.sort_values(by=list(match2.columns))\n",
    "    return match2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_match3(match2, nema):\n",
    "    '''\n",
    "    각 movement들에 방향(진입방향, 진출방향)을 매칭시켜 추가함.\n",
    "     - match2의 컬럼 : inter_no, phase_no, ring_type, move_no\n",
    "     - match3의 컬럼 : inter_no, phase_no, ring_type, move_no, inc_dir, out_dir\n",
    "\n",
    "    nema : \n",
    "     - 컬럼 : move_no, inc_dir, out_dir\n",
    "     - 모든 종류의 이동류번호에 대하여 진입방향과 진출방향을 매칭시키는 테이블\n",
    "     - 이동류번호 : 1 ~ 16, 17, 18, 21\n",
    "     - 진입, 진출방향(8방위) : 동, 서, 남, 북, 북동, 북서, 남동, 남서\n",
    "    '''\n",
    "    # nema 정보 불러오기 및 병합\n",
    "    match3 = pd.merge(match2, nema, how='left', on='move_no').drop_duplicates()\n",
    "    return match3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_match4(match3, angle):\n",
    "    '''\n",
    "    방위각 정보를 매칭시켜 추가함.\n",
    "     - match3의 컬럼 : inter_no, phase_no, ring_type, move_no, inc_dir, out_dir\n",
    "     - match4의 컬럼 : inter_no, phase_no, ring_type, move_no, inc_dir, out_dir, inc_angle, out_angle\n",
    "\n",
    "    angle_original : \n",
    "     - 컬럼 : inter_no, angle_Aj, angle_Bj (j : 1 ~ 8)\n",
    "     - 모든 종류의 이동류번호에 대하여 진입방향과 진출방향을 매칭시키는 테이블\n",
    "     - 이동류번호 : 1 ~ 16, 17, 18, 21\n",
    "     - 진입, 진출방향(8방위) : 동, 서, 남, 북, 북동, 북서, 남동, 남서\n",
    "    '''\n",
    "\n",
    "    # 계층화\n",
    "    angles = []\n",
    "    for i, row in angle.iterrows():\n",
    "        angle_codes = row[[f'angle_{alph}{j}' for alph in ['A', 'B'] for j in range(1,9)]]\n",
    "        new = pd.DataFrame({'inter_no':[row.inter_no] * 16, 'phase_no':list(range(1, 9))*2, 'ring_type':['A'] * 8 + ['B'] * 8, 'angle_code':angle_codes.to_list()})\n",
    "        angles.append(new)\n",
    "    angles = pd.concat(angles)\n",
    "    angles = angles.dropna().reset_index(drop=True)\n",
    "\n",
    "    # 병합\n",
    "    six_chars = angles.angle_code.apply(lambda x:len(x)==6)\n",
    "    angles.loc[six_chars,'inc_angle'] = angles.angle_code.apply(lambda x:x[:3])\n",
    "    angles.loc[six_chars,'out_angle'] = angles.angle_code.apply(lambda x:x[3:])\n",
    "    angles = angles.drop('angle_code', axis=1)\n",
    "    match4 = pd.merge(match3, angles, how='left', left_on=['inter_no', 'phase_no', 'ring_type'],\n",
    "                    right_on=['inter_no', 'phase_no', 'ring_type']).drop_duplicates()\n",
    "    return match4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_match5(match4, net, inter_node, inter_info):\n",
    "    '''\n",
    "    진입엣지id, 진출엣지id, 노드id를 추가함 (주교차로).\n",
    "     - match4의 컬럼 : inter_no, phase_no, ring_type, move_no, inc_dir, out_dir, inc_angle, out_angle\n",
    "     - match5의 컬럼 : inter_no, phase_no, ring_type, move_no, inc_dir, out_dir, inc_angle, out_angle, inc_edge, out_edge, node_id\n",
    "    \n",
    "    사용된 데이터 : \n",
    "    (1) net\n",
    "     - 성남시 정자동 부근의 샘플 네트워크\n",
    "    (2) inter_node\n",
    "     - 교차로번호와 노드id를 매칭시키는 테이블.\n",
    "     - parent/child 정보도 포함되어 있음\n",
    "     - 컬럼 : inter_no, node_id, inter_type\n",
    "    (3) inter_info\n",
    "     - 교차로 정보. 여기에서는 위도와 경도가 쓰임.\n",
    "     - 컬럼 : inter_no, inter_name, inter_lat, inter_lon, group_no, main_phase_no\n",
    "\n",
    "    진입엣지id, 진출엣지id를 얻는 과정 :\n",
    "     - match5 = match4.copy()의 각 열을 순회하면서 아래 과정을 반복함.\n",
    "     * 진입에 대해서만 서술하겠지만 진출도 마찬가지로 설명될 수 있음\n",
    "     - 해당 행의 교차로정보로부터 노드ID를 얻어내고, 해당 노드에 대한 모든 진출엣지id를 inc_edges에 저장.\n",
    "     * inc_edge(진입엣지) : incoming edge, out_edge(진출엣지) : outgoing_edge\n",
    "     - inc_edges의 모든 진입엣지에 대하여 진입방향(inc_dires, 2차원 단위벡터)을 얻어냄.\n",
    "     - 해당 행의 진입각으로부터 그에 대응되는 진입각방향(단위벡터)를 얻어냄.\n",
    "     - 주어진 진입각방향에 대하여 내적이 가장 작은 진입방향에 대한 진입엣지를 inc_edge_id로 지정함.\n",
    "    '''\n",
    "\n",
    "    # parent node만 가져옴.\n",
    "    inter_node1 = inter_node[inter_node.inter_type == 'parent'].drop('inter_type', axis=1)\n",
    "    inter_info1 = inter_info[['inter_no', 'inter_lat', 'inter_lon']]\n",
    "    inter = pd.merge(inter_node1, inter_info1, how='left', left_on=['inter_no'],\n",
    "                    right_on=['inter_no']).drop_duplicates()\n",
    "\n",
    "    inter2node = dict(zip(inter['inter_no'], inter['node_id']))\n",
    "\n",
    "    match5 = match4.copy()\n",
    "    # 진입진출ID 매칭\n",
    "    for index, row in match5.iterrows():\n",
    "        node_id = inter2node[row.inter_no]\n",
    "        node = net.getNode(node_id)\n",
    "        # 교차로의 모든 (from / to) edges\n",
    "        inc_edges = [edge for edge in node.getIncoming() if edge.getFunction() == ''] # incoming edges\n",
    "        out_edges = [edge for edge in node.getOutgoing() if edge.getFunction() == ''] # outgoing edges\n",
    "        # 교차로의 모든 (from / to) directions\n",
    "        inc_dirs = []\n",
    "        for inc_edge in inc_edges:\n",
    "            start = inc_edge.getShape()[-2]\n",
    "            end = inc_edge.getShape()[-1]\n",
    "            inc_dir = np.array(end) - np.array(start)\n",
    "            inc_dir = inc_dir / (inc_dir ** 2).sum() ** 0.5\n",
    "            inc_dirs.append(inc_dir)\n",
    "        out_dirs = []\n",
    "        for out_edge in out_edges:\n",
    "            start = out_edge.getShape()[0]\n",
    "            end = out_edge.getShape()[1]\n",
    "            out_dir = np.array(end) - np.array(start)\n",
    "            out_dir = out_dir / (out_dir ** 2).sum() ** 0.5\n",
    "            out_dirs.append(out_dir)\n",
    "        # 진입각, 진출각 불러오기\n",
    "        if not pd.isna(row.inc_angle):\n",
    "            inc_angle = int(row.inc_angle)\n",
    "            out_angle = int(row.out_angle)\n",
    "            # 방위각을 일반각으로 가공, 라디안 변환, 단위벡터로 변환\n",
    "            inc_angle = (-90 - inc_angle) % 360\n",
    "            inc_angle = inc_angle * np.pi / 180.\n",
    "            inc_dir_true = np.array([np.cos(inc_angle), np.sin(inc_angle)])\n",
    "            out_angle = (90 - out_angle) % 360\n",
    "            out_angle = out_angle * np.pi / 180.\n",
    "            out_dir_true = np.array([np.cos(out_angle), np.sin(out_angle)])\n",
    "            # 매칭 엣지 반환\n",
    "            inc_index = np.array([np.dot(inc_dir, inc_dir_true) for inc_dir in inc_dirs]).argmax()\n",
    "            out_index = np.array([np.dot(out_dir, out_dir_true) for out_dir in out_dirs]).argmax()\n",
    "            inc_edge_id = inc_edges[inc_index].getID()\n",
    "            out_edge_id = out_edges[out_index].getID()\n",
    "            match5.at[index, 'inc_edge'] = inc_edge_id\n",
    "            match5.at[index, 'out_edge'] = out_edge_id\n",
    "    match5['node_id'] = match5['inter_no'].map(inter2node)\n",
    "    match5 = match5.sort_values(by=['inter_no','phase_no','ring_type']).reset_index(drop=True)\n",
    "    return match5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_match6(match5, inter_node, uturn, coord):\n",
    "    '''\n",
    "    진입엣지id, 진출엣지id, 노드id를 추가함 (부교차로).\n",
    "     - match6의 컬럼 : inter_no, phase_no, ring_type, move_no, inc_dir, out_dir, inc_angle, out_angle, inc_edge, out_edge, node_id\n",
    "    \n",
    "    사용된 데이터 : \n",
    "    (1) inter_node\n",
    "     - 교차로번호와 노드id를 매칭시키는 테이블.\n",
    "     - parent/child 정보도 포함되어 있음\n",
    "     - 컬럼 : inter_no, node_id, inter_type\n",
    "    (2) uturn (유턴정보)\n",
    "     - 컬럼 : parent_id, child_id, direction, condition, inc_edge, out_edge\n",
    "     - parent_id, child_id : 주교차로id, 유턴교차로id\n",
    "     - direction : 주교차로에 대한 유턴노드의 상대적인 위치(방향)\n",
    "     - condition : 좌회전시, 직진시, 직좌시, 보행신호시 중 하나\n",
    "     - inc_edge, out_edge : 유턴에 대한 진입진출엣지\n",
    "    (3) coord (연동교차로정보)\n",
    "     - 컬럼 : parent_id, child_id, phase_no, ring_type, inc_edge, out_edge\n",
    "     - parent_id, child_id : 주교차로id, 연동교차로id\n",
    "     - 나머지 컬럼 : 각 (현시, 링)별 진입진출엣지\n",
    "\n",
    "    설명 :\n",
    "     - match5는 주교차로에 대해서만 진입엣지id, 진출엣지id, 노드id를 추가했었음.\n",
    "       여기에서 uturn, coord를 사용해서 부교차로들(유턴교차로, 연동교차로)에 대해서도 해당 값들을 부여함.\n",
    "    유턴교차로 :\n",
    "     - directions를 정북기준 시계방향의 8방위로 정함.\n",
    "        - 이를 통해 진입방향이 주어진 경우에 좌회전, 직진, 보행 등에 대한 (진입방향, 진출방향)을 얻어낼 수 있음.\n",
    "        - 예) 진입방향(direction)이 '북'일 때, \n",
    "        - 직진 : (북, 남)\n",
    "            * 남 : directions[(ind + 4) % len(directions)]\n",
    "        - 좌회전 : (북, 동)\n",
    "            * 동 : directions[(ind + 2) % len(directions)]\n",
    "        - 보행 : (서, 동)\n",
    "            * 서 : directions[(ind - 2) % len(directions)]\n",
    "     - uturn의 각 행을 순회하면서 아래 과정을 반복함\n",
    "        - match5에서 parent_id에 해당하는 행들을 가져옴(cmatch).\n",
    "        - condition 별로 진입방향, 진출방향A, 진출방향B 정함.\n",
    "            - 상술한 directions를 활용하여 정함.\n",
    "        - (진입방향, 진출방향A, 진출방향B)을 고려하여 (현시, 링) 별로 진입엣지id, 진출엣지id를 정함.\n",
    "            - ex) cmatch.loc[(cmatch.inc_dir==inc_dire) & (cmatch.out_dir==out_dire_A), ['inc_edge', 'out_edge']] = [inc_edge_id, out_edge_id]\n",
    "     - 순회하면서 만든 cmatch를 cmatchs라는 리스트에 저장함.\n",
    "\n",
    "    연동교차로 :\n",
    "     - 연동교차로의 경우 coord에 (현시, 링)별 진입엣지ID, 진출엣지ID가 명시되어 있음.\n",
    "     - 'inc_dir', 'out_dir', 'inc_angle','out_angle'와 같은 열들은 np.nan을 지정해놓음.\n",
    "     - 이 열들은, 사실상 다음 스텝부터는 사용되지 않는 열들이기 때문에 np.nan으로 지정해놓아도 문제없음.\n",
    "\n",
    "    match6 :\n",
    "     - 이렇게 얻은 match5, cmatchs, coord를 모두 pd.concat하여 match6을 얻어냄.\n",
    "    '''\n",
    "\n",
    "    node2inter = dict(zip(inter_node['node_id'], inter_node['inter_no']))\n",
    "\n",
    "    child_ids = inter_node[inter_node.inter_type=='child'].node_id.unique()\n",
    "    ch2pa = {} # child to parent\n",
    "    for child_id in child_ids:\n",
    "        parent_no = inter_node[inter_node.node_id==child_id].inter_no.iloc[0]\n",
    "        sub_inter_node = inter_node[inter_node.inter_no==parent_no]\n",
    "        ch2pa[child_id] = sub_inter_node[sub_inter_node.inter_type=='parent'].iloc[0].node_id\n",
    "    directions = ['북', '북동', '동', '남동', '남', '남서', '서', '북서'] # 정북기준 시계방향으로 8방향\n",
    "\n",
    "    # 각 uturn node에 대하여 (inc_edge_id, out_edge_id) 부여\n",
    "    cmatches = []\n",
    "    for _, row in uturn.iterrows():\n",
    "        child_id = row.child_id\n",
    "        parent_id = row.parent_id\n",
    "        direction = row.direction\n",
    "        condition = row.condition\n",
    "        inc_edge_id = row.inc_edge\n",
    "        out_edge_id = row.out_edge\n",
    "        # match5에서 parent_id에 해당하는 행들을 가져옴\n",
    "        cmatch = match5.copy()[match5.node_id==parent_id] # match dataframe for a child node\n",
    "        cmatch = cmatch.sort_values(by=['phase_no', 'ring_type']).reset_index(drop=True)\n",
    "        cmatch['node_id'] = child_id\n",
    "        cmatch[['inc_edge', 'out_edge']] = np.nan\n",
    "\n",
    "        # condition 별로 inc_dire, out_dire_A, out_dire_B를 정함\n",
    "        ind = directions.index(direction)\n",
    "        if condition == \"좌회전시\":\n",
    "            inc_dire = direction\n",
    "            out_dire_A = out_dire_B = directions[(ind + 2) % len(directions)]\n",
    "        elif condition == \"직진시\":\n",
    "            inc_dire = direction\n",
    "            out_dire_A = out_dire_B = directions[(ind + 4) % len(directions)]\n",
    "        elif condition == \"보행신호시\":\n",
    "            inc_dire = directions[(ind + 2) % len(directions)]\n",
    "            out_dire_A = directions[(ind - 2) % len(directions)]\n",
    "            out_dire_B = directions[(ind - 2) % len(directions)]\n",
    "\n",
    "        # (inc_dire, out_dire_A, out_dire_B) 별로 inc_edge_id, out_edge_id를 정함\n",
    "        if condition == '보행신호시':\n",
    "            cmatch.loc[(cmatch.inc_dir==inc_dire) & (cmatch.out_dir==out_dire_A), ['inc_edge', 'out_edge']] = [inc_edge_id, out_edge_id]\n",
    "            cmatch.loc[(cmatch.inc_dir==inc_dire) & (cmatch.out_dir==out_dire_B), ['inc_edge', 'out_edge']] = [inc_edge_id, out_edge_id]\n",
    "            # 이동류번호가 17(보행신호)이면서 유턴노드방향으로 가는 신호가 없으면 (inc_edge_id, out_edge_id)를 부여한다.\n",
    "            cmatch.loc[(cmatch.move_no==17) & (cmatch.out_dir!=direction), ['inc_edge', 'out_edge']] = [inc_edge_id, out_edge_id]\n",
    "        else: # '직진시', '좌회전시'\n",
    "            cmatch.loc[(cmatch.inc_dir==inc_dire) & (cmatch.out_dir==out_dire_A), ['inc_edge', 'out_edge']] = [inc_edge_id, out_edge_id]\n",
    "            cmatch.loc[(cmatch.inc_dir==inc_dire) & (cmatch.out_dir==out_dire_B), ['inc_edge', 'out_edge']] = [inc_edge_id, out_edge_id]\n",
    "        # 유턴신호의 이동류번호를 19로 부여한다.\n",
    "        cmatch.loc[(cmatch.inc_dir==inc_dire) & (cmatch.out_dir==out_dire_A), 'move_no'] = 19\n",
    "        cmatch.loc[(cmatch.inc_dir==inc_dire) & (cmatch.out_dir==out_dire_B), 'move_no'] = 19\n",
    "        cmatches.append(cmatch)\n",
    "\n",
    "    # 각 coordination node에 대하여 (inc_edge_id, out_edge_id) 부여\n",
    "    coord['inter_no'] = coord['parent_id'].map(node2inter)\n",
    "    coord = coord.rename(columns={'child_id':'node_id'})\n",
    "    coord[['inc_dir', 'out_dir', 'inc_angle','out_angle']] = np.nan\n",
    "    coord['move_no'] = 20\n",
    "    coord = coord[['inter_no', 'phase_no', 'ring_type', 'move_no', 'inc_dir', 'out_dir', 'inc_angle','out_angle', 'inc_edge', 'out_edge', 'node_id']]\n",
    "    \n",
    "    # display(coord)\n",
    "    cmatches = pd.concat(cmatches)\n",
    "    match6 = pd.concat([match5, cmatches, coord]).drop_duplicates().sort_values(by=['inter_no', 'node_id', 'phase_no', 'ring_type'])\n",
    "    match6.to_csv('../Intermediates/match6.csv')\n",
    "    return match6"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_matching(match6, inter_node, nema):\n",
    "    '''\n",
    "    이동류 매칭 : 각 교차로에 대하여, 가능한 모든 이동류 (1~18, 21)에 대한 진입·진출엣지ID를 지정한다.\n",
    "    모든 이동류에 대해 지정하므로, 시차제시 이전과 다른 이동류가 등장하더라도 항상 진입·진출 엣지 ID를 지정할 수 있다.    \n",
    "     - matching의 컬럼 : inter_no, move_no, inc_dir, out_dir, inc_edge, out_edge, node_id\n",
    "    \n",
    "    설명 : \n",
    "     - 필요한 리스트, 딕셔너리 등을 정의\n",
    "        (1) 가능한 (진입방향, 진출방향) 목록 [리스트]\n",
    "        (2) 각 교차로별 방향 목록 : pdires (possible directions) [딕셔너리]\n",
    "        (3) 각 (교차로, 진입방향) 별 진입id 목록 : inc2id (incoming direction to incoming edge_id) [딕셔너리]\n",
    "        (4) 각 (교차로, 진출방향) 별 진출id 목록 : out2id (outgoing direction to outgoing edge_id) [딕셔너리]\n",
    "        (5) 각 교차로별 가능한 (진입방향, 진출방향) 목록 : pflow (possible flows) [딕셔너리]\n",
    "     - matching은 빈 리스트로 지정.\n",
    "     - 모든 노드id에 대하여 다음 과정을 반복\n",
    "     - 해당 노드id에 대한 모든 가능한 (진입방향, 진출방향)에 대하여 다음 과정을 반복\n",
    "     - (노드id, 진입방향)으로부터 진입엣지id를 얻어냄. 마찬가지로 진출엣지id도 얻어냄\n",
    "     - 얻어낸 정보를 바탕으로 한 행(new_row)을 만들고 이것을 matching에 append\n",
    "     '''\n",
    "\n",
    "    match7 = match6.copy()\n",
    "    match7 = match7[['inter_no', 'move_no', 'inc_dir', 'out_dir', 'inc_edge', 'out_edge', 'node_id']]\n",
    "\n",
    "    parent_ids = sorted(inter_node[inter_node.inter_type=='parent'].node_id.unique())\n",
    "    child_ids = sorted(inter_node[inter_node.inter_type=='child'].node_id.unique())\n",
    "\n",
    "    # (1) 가능한 (진입방향, 진출방향) 목록 \n",
    "    flows = nema.dropna().apply(lambda row: (row['inc_dir'], row['out_dir']), axis=1).tolist()\n",
    "    # (2) 각 교차로별 방향 목록 : pdires (possible directions)\n",
    "    pdires = {}\n",
    "    for node_id in parent_ids:\n",
    "        dires = match7[match7.node_id == node_id][['inc_dir','out_dir']].values.flatten()\n",
    "        dires = {dire for dire in dires if type(dire)==str}\n",
    "        pdires[node_id] = dires\n",
    "    # (3) 각 (교차로, 진입방향) 별 진입id 목록 : inc2id (incoming direction to incoming edge_id)\n",
    "    inc2id = {}\n",
    "    for node_id in parent_ids:\n",
    "        for inc_dir in pdires[node_id]:\n",
    "            df = match7[(match7.node_id==node_id) & (match7.inc_dir==inc_dir)]\n",
    "            inc2id[(node_id, inc_dir)] = df.inc_edge.iloc[0]\n",
    "    # (4) 각 (교차로, 진출방향) 별 진출id 목록 : out2id (outgoing direction to outgoing edge_id)\n",
    "    out2id = {}\n",
    "    for node_id in parent_ids:\n",
    "        for out_dir in pdires[node_id]:\n",
    "            df = match7[(match7.node_id==node_id) & (match7.out_dir==out_dir)]\n",
    "            out2id[(node_id, out_dir)] = df.out_edge.iloc[0]\n",
    "    # (5) 각 교차로별 가능한 (진입방향, 진출방향) 목록 : pflow (possible flows)\n",
    "    pflow = {}\n",
    "    for node_id in parent_ids:\n",
    "        pflow[node_id] = [flow for flow in flows if set(flow).issubset(pdires[node_id])]\n",
    "    # (6) 가능한 이동류에 대하여 진입id, 진출id 배정 : matching\n",
    "    node2inter = dict(zip(match7['node_id'], match7['inter_no']))\n",
    "    dires_right = ['북', '서', '남', '동', '북'] # ex (북, 서), (서, 남) 등은 우회전 flow\n",
    "    matching = []\n",
    "    for node_id in parent_ids:\n",
    "        inter_no = node2inter[node_id]\n",
    "        # 좌회전과 직진(1 ~ 16)\n",
    "        for (inc_dir, out_dir) in pflow[node_id]:\n",
    "            move_no = nema[(nema.inc_dir==inc_dir) & (nema.out_dir==out_dir)].move_no.iloc[0]\n",
    "            inc_edge = inc2id[(node_id, inc_dir)]\n",
    "            out_edge = out2id[(node_id, out_dir)]\n",
    "            new_row = pd.DataFrame({'inter_no':[inter_no], 'move_no':[move_no],\n",
    "                                    'inc_dir':[inc_dir], 'out_dir':[out_dir],\n",
    "                                    'inc_edge':[inc_edge], 'out_edge':[out_edge], 'node_id':[node_id]})\n",
    "            matching.append(new_row)\n",
    "        # 보행신호(17), 전적색(18)\n",
    "        new_row = pd.DataFrame({'inter_no':[inter_no] * 2, 'move_no':[17, 18],\n",
    "                                'inc_dir':[None]*2, 'out_dir':[None]*2,\n",
    "                                'inc_edge':[None]*2, 'out_edge':[None]*2, 'node_id':[node_id]*2})\n",
    "        matching.append(new_row)\n",
    "        # 신호우회전(21)\n",
    "        for d in range(len(dires_right)-1):\n",
    "            inc_dir = dires_right[d]\n",
    "            out_dir = dires_right[d+1]\n",
    "            if {inc_dir, out_dir}.issubset(pdires[node_id]):\n",
    "                inc_edge = inc2id[(node_id, inc_dir)]\n",
    "                out_edge = out2id[(node_id, out_dir)]\n",
    "                new_row = pd.DataFrame({'inter_no':[inter_no], 'move_no':[21],\n",
    "                                        'inc_dir':[inc_dir], 'out_dir':[out_dir],\n",
    "                                        'inc_edge':[inc_edge], 'out_edge':[out_edge], 'node_id':[node_id]})\n",
    "                matching.append(new_row)\n",
    "    matching.append(match7[match7.node_id.isin(child_ids)])\n",
    "    matching = pd.concat(matching)\n",
    "    matching = matching.dropna().sort_values(by=['inter_no', 'node_id', 'move_no']).reset_index(drop=True)\n",
    "    matching['move_no'] = matching['move_no'].astype(int)\n",
    "    matching.to_csv('../Intermediates/matching.csv')\n",
    "    return matching"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_movements():\n",
    "    movements_path = '../Intermediates/movement/'\n",
    "    movements_list = [pd.read_csv(movements_path + file, index_col=0) for file in tqdm(os.listdir(movements_path))]\n",
    "    movements = pd.concat(movements_list)\n",
    "    movements = movements.drop(columns=['start_unix'])\n",
    "    movements = movements.drop_duplicates()\n",
    "    movements = movements.sort_values(by=['inter_no', 'phas_A', 'phas_B'])\n",
    "    movements = movements.reset_index(drop=True)\n",
    "    movements.to_csv('../Intermediates/movements.csv')\n",
    "    return movements"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# node2num_cycles : A dictionary that maps a node_id to the number of cycles\n",
    "def get_node2num_cycles(plan, inter_node):\n",
    "    node2inter = dict(zip(inter_node['node_id'], inter_node['inter_no']))\n",
    "    node_ids = sorted(inter_node.node_id.unique())\n",
    "\n",
    "    Aplan = plan.copy()[['inter_no'] + [f'dura_A{j}' for j in range(1,9)] + ['cycle']]\n",
    "    grouped = Aplan.groupby('inter_no')\n",
    "    df = grouped.agg({'cycle': 'min'}).reset_index()\n",
    "    df = df.rename(columns={'cycle': 'min_cycle'})\n",
    "    df['num_cycle'] = 300 // df['min_cycle'] + 2\n",
    "    inter2num_cycles = dict(zip(df['inter_no'], df['num_cycle']))\n",
    "    node2numcycles = {node_id : inter2num_cycles[node2inter[node_id]] for node_id in node_ids}\n",
    "    with open('../Intermediates/node2numcycles.json', 'w') as file:\n",
    "        json.dump(node2numcycles, file, indent=4)\n",
    "    return node2numcycles"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def preprocess_daily():\n",
    "    path_move = '../Data/tables/move/'\n",
    "\n",
    "    inter_info = pd.read_csv('../Data/tables/inter_info.csv', index_col=0)\n",
    "    angle = pd.read_csv('../Data/tables/angle.csv', index_col=0, dtype = {f'angle_{alph}{j}':'str' for alph in ['A', 'B'] for j in range(1,9)})\n",
    "    plan = pd.read_csv('../Data/tables/plan.csv', index_col=0)\n",
    "    inter_node = pd.read_csv('../Data/tables/inter_node.csv', index_col=0)\n",
    "    uturn = pd.read_csv('../Data/tables/child_uturn.csv')\n",
    "    coord = pd.read_csv('../Data/tables/child_coord.csv')\n",
    "    nema = pd.read_csv('../Data/tables/nema.csv', encoding='cp949')\n",
    "\n",
    "    net = sumolib.net.readNet('../Data/networks/sn.net.xml')\n",
    "\n",
    "    match1 = make_match1(path_move)\n",
    "    match2 = make_match2(match1)\n",
    "    match3 = make_match3(match2, nema)\n",
    "    match4 = make_match4(match3, angle)\n",
    "    match5 = make_match5(match4, net, inter_node, inter_info)\n",
    "    match6 = make_match6(match5, inter_node, uturn, coord)\n",
    "    matching = make_matching(match6, inter_node, nema)\n",
    "    movements = make_movements()\n",
    "    node2num_cycles = get_node2num_cycles(plan, inter_node)\n",
    "    return match6, matching, movements, node2num_cycles"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "  0%|          | 0/17280 [00:00<?, ?it/s]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 17280/17280 [00:14<00:00, 1204.50it/s]\n",
      "100%|██████████| 17280/17280 [00:17<00:00, 1004.57it/s]\n"
     ]
    }
   ],
   "source": [
    "match6, matching, movements, node2num_cycles = preprocess_daily()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['Unnamed: 0', 'inter_no', 'angle_A1', 'angle_A2', 'angle_A3', 'angle_A4', 'angle_A5', 'angle_A6', 'angle_A7', 'angle_A8', 'angle_B1', 'angle_B2', 'angle_B3', 'angle_B4', 'angle_B5', 'angle_B6', 'angle_B7', 'angle_B8']\n",
      "['Unnamed: 0', 'inter_no', 'start_hour', 'start_minute', 'dura_A1', 'dura_A2', 'dura_A3', 'dura_A4', 'dura_A5', 'dura_A6', 'dura_A7', 'dura_A8', 'dura_B1', 'dura_B2', 'dura_B3', 'dura_B4', 'dura_B5', 'dura_B6', 'dura_B7', 'dura_B8', 'cycle', 'offset']\n",
      "['Unnamed: 0', 'inter_no', 'node_id', 'inter_type']\n",
      "['parent_id', 'child_id', 'direction', 'condition', 'inc_edge', 'out_edge']\n",
      "['Unnamed: 0', 'inter_no', 'end_unix', 'dura_A1', 'dura_A2', 'dura_A3', 'dura_A4', 'dura_A5', 'dura_A6', 'dura_A7', 'dura_A8', 'dura_B1', 'dura_B2', 'dura_B3', 'dura_B4', 'dura_B5', 'dura_B6', 'dura_B7', 'dura_B8', 'cycle', 'offset']\n",
      "['Unnamed: 0', 'inter_no', 'inter_name', 'inter_lat', 'inter_lon', 'group_no', 'main_phase_no']\n",
      "['parent_id', 'child_id', 'phase_no', 'ring_type', 'inc_edge', 'out_edge']\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import pandas as pd\n",
    "table_path = '../Data/tables/'\n",
    "cols = []\n",
    "for name in set(os.listdir(table_path)) - set(['move', 'nema.csv', 'raw_tables']):\n",
    "    df = pd.read_csv(table_path + name)\n",
    "    print(list(df.columns))\n",
    "#     cols.extend(list(df.columns))\n",
    "# for col in sorted(set(cols)):\n",
    "#     print(col)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'inter_no': 'int',\n",
       " 'start_hour': 'int',\n",
       " 'start_minute': 'int',\n",
       " 'cycle': 'int',\n",
       " 'offset': 'int',\n",
       " 'node_id': 'str',\n",
       " 'inter_type': 'str',\n",
       " 'parent_id': 'str',\n",
       " 'child_id': 'str',\n",
       " 'direction': 'str',\n",
       " 'condition': 'str',\n",
       " 'inc_edge': 'str',\n",
       " 'out_edge': 'str',\n",
       " 'end_unix': 'int',\n",
       " 'inter_name': 'str',\n",
       " 'inter_lat': 'float',\n",
       " 'inter_lon': 'float',\n",
       " 'group_no': 'int',\n",
       " 'main_phase_no': 'int',\n",
       " 'phase_no': 'int',\n",
       " 'ring_type': 'str',\n",
       " 'angle_A1': 'str',\n",
       " 'dura_A1': 'int',\n",
       " 'angle_A2': 'str',\n",
       " 'dura_A2': 'int',\n",
       " 'angle_A3': 'str',\n",
       " 'dura_A3': 'int',\n",
       " 'angle_A4': 'str',\n",
       " 'dura_A4': 'int',\n",
       " 'angle_A5': 'str',\n",
       " 'dura_A5': 'int',\n",
       " 'angle_A6': 'str',\n",
       " 'dura_A6': 'int',\n",
       " 'angle_A7': 'str',\n",
       " 'dura_A7': 'int',\n",
       " 'angle_A8': 'str',\n",
       " 'dura_A8': 'int',\n",
       " 'angle_B1': 'str',\n",
       " 'dura_B1': 'int',\n",
       " 'angle_B2': 'str',\n",
       " 'dura_B2': 'int',\n",
       " 'angle_B3': 'str',\n",
       " 'dura_B3': 'int',\n",
       " 'angle_B4': 'str',\n",
       " 'dura_B4': 'int',\n",
       " 'angle_B5': 'str',\n",
       " 'dura_B5': 'int',\n",
       " 'angle_B6': 'str',\n",
       " 'dura_B6': 'int',\n",
       " 'angle_B7': 'str',\n",
       " 'dura_B7': 'int',\n",
       " 'angle_B8': 'str',\n",
       " 'dura_B8': 'int'}"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dtype_loading = {\n",
    "    'inter_no':'int', 'start_hour':'int', 'start_minute':'int', 'cycle':'int','offset':'int',\n",
    "    'node_id':'str', 'inter_type':'str', 'parent_id':'str','child_id':'str',\n",
    "    'direction':'str', 'condition':'str', 'inc_edge':'str', 'out_edge':'str',\n",
    "    'end_unix':'int', 'inter_name':'str', 'inter_lat':'float', 'inter_lon':'float',\n",
    "    'group_no':'int', 'main_phase_no':'int', 'phase_no':'int','ring_type':'str'\n",
    "    }\n",
    "for alph in ['A', 'B']:\n",
    "    for j in range(1,9):\n",
    "        dtype_loading[f'angle_{alph}{j}'] = 'str'\n",
    "        dtype_loading[f'dura_{alph}{j}'] = 'int'\n",
    "dtype_loading"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[176, 202]"
      ]
     },
     "execution_count": 71,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "plan = pd.read_csv('../data/tables/plan.csv')\n",
    "durations = plan[[f'dura_{alph}{j}' for alph in ['A','B'] for j in range(1, 9)]]\n",
    "valid_indices = ((durations >= 0) & (durations <= 100)).all(axis=1)\n",
    "sorted(plan[~valid_indices].inter_no.unique())\n",
    "# durations"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "rts",
   "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.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
