|
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import pandas as pd\n",
|
|
"import numpy as np\n",
|
|
"import os\n",
|
|
"import sumolib\n",
|
|
"import copy\n",
|
|
"import json\n",
|
|
"from tqdm import tqdm\n",
|
|
"from datetime import datetime"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"m = 105\n",
|
|
"midnight = int(datetime(2024, 1, 5, 0, 0, 0).timestamp())\n",
|
|
"next_day = int(datetime(2024, 1, 6, 0, 0, 0).timestamp())\n",
|
|
"fmins = range(midnight, next_day, 300)\n",
|
|
"\n",
|
|
"# 현재시각\n",
|
|
"present_time = fmins[m]\n",
|
|
"sim_start = fmins[m] - 300\n",
|
|
"\n",
|
|
"# network and dataframes\n",
|
|
"net = sumolib.net.readNet('../Data/networks/sn.net.xml')\n",
|
|
"inter_node = pd.read_csv('../Data/tables/inter_node.csv', index_col=0)\n",
|
|
"plan = pd.read_csv('../Data/tables/plan.csv', index_col=0)\n",
|
|
"match6 = pd.read_csv('../Intermediates/match6.csv', index_col=0)\n",
|
|
"match6 = match6[['node_id', 'phase_no', 'ring_type', 'inc_edge', 'out_edge']].reset_index(drop=True)\n",
|
|
"histid = pd.read_csv(f'../Intermediates/histid/histid_{present_time}.csv', index_col=0)\n",
|
|
"histid = histid.reset_index(drop=True).drop(columns=['inter_no'])\n",
|
|
"\n",
|
|
"# helper dictionaries and lists\n",
|
|
"inter_node_p = inter_node[inter_node.inter_type=='parent']\n",
|
|
"inter2node = dict(zip(inter_node_p['inter_no'], inter_node_p['node_id']))\n",
|
|
"node2inter = dict(zip(inter_node['node_id'], inter_node['inter_no']))\n",
|
|
"pa2ch = {'i0':['u00'], 'i1':[], 'i2':['u20'], 'i3':['c30', 'u30', 'u31', 'u32'], 'i6':['u60'], 'i7':[], 'i8':[], 'i9':[]}\n",
|
|
"node_ids = sorted(inter_node.node_id.unique())\n",
|
|
"parent_ids = sorted(inter_node[inter_node.inter_type=='parent'].node_id.unique())\n",
|
|
"nodes = [net.getNode(node_id) for node_id in node_ids]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def attach_children(histid, match6, parent_ids, pa2ch):\n",
|
|
" '''\n",
|
|
" 자식교차로에 대한 진입·진출 엣지 정보를 붙여주는 함수\n",
|
|
"\n",
|
|
" input :\n",
|
|
" (1) histid\n",
|
|
" - 각 교차로에 대한 (시작유닉스, A현시, B현시)별 현시시간, 진입·진출엣지\n",
|
|
" - 부모교차로(주교차로)에 대해서만 값이 지정되어 있음\n",
|
|
" (2) match6\n",
|
|
" - (현시, 링)별 진입·진출엣지\n",
|
|
" - 자식교차로(유턴 및 연동교차로)에 대해서도 값이 지정되어 있음\n",
|
|
" (3) parent_ids : 부모교차로 목록\n",
|
|
" (4) pa2ch : 각 부모교차로id를 부모교차로가 포함하고 있는 자식교차로들의 id들의 리스트로 대응시키는 딕셔너리\n",
|
|
"\n",
|
|
" output : histids\n",
|
|
" - 모든(부모 및 자식) 교차로에 대한 시작유닉스 (시작유닉스, A현시, B현시)별 현시시간, 진입·진출엣지\n",
|
|
" '''\n",
|
|
" new_histids = []\n",
|
|
" for parent_id in parent_ids:\n",
|
|
" for child_id in pa2ch[parent_id]:\n",
|
|
" new_histid = histid.copy()[histid.node_id==parent_id]\n",
|
|
" new_histid[['inc_edge_A', 'out_edge_A', 'inc_edge_B', 'out_edge_B']] = np.nan\n",
|
|
" for i, row in new_histid.iterrows():\n",
|
|
" phas_A = row.phas_A\n",
|
|
" phas_B = row.phas_B\n",
|
|
" new_match = match6[match6.node_id==child_id]\n",
|
|
" Arow = new_match[(new_match.phase_no==phas_A) & (new_match.ring_type=='A')]\n",
|
|
" if ~ Arow[['inc_edge', 'out_edge']].isna().all().all():\n",
|
|
" inc_edge = Arow.iloc[0].inc_edge\n",
|
|
" out_edge = Arow.iloc[0].out_edge\n",
|
|
" new_histid.loc[i, ['inc_edge_A', 'out_edge_A']] = [inc_edge, out_edge]\n",
|
|
" Brow = new_match[(new_match.phase_no==phas_B) & (new_match.ring_type=='B')]\n",
|
|
" if ~ Brow[['inc_edge', 'out_edge']].isna().all().all():\n",
|
|
" inc_edge = Brow.iloc[0].inc_edge\n",
|
|
" out_edge = Brow.iloc[0].out_edge\n",
|
|
" new_histid.loc[i, ['inc_edge_B', 'out_edge_B']] = [inc_edge, out_edge]\n",
|
|
" new_histid.loc[i, 'node_id'] = child_id\n",
|
|
" new_histids.append(new_histid)\n",
|
|
" new_histids = pd.concat(new_histids)\n",
|
|
" histids = pd.concat([histid.copy(), new_histids])\n",
|
|
" histids = histids.sort_values(by=['start_unix', 'node_id', 'phas_A', 'phas_B']).reset_index(drop=True)\n",
|
|
" return histids\n",
|
|
"histids = attach_children(histid, match6, parent_ids, pa2ch)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def initialize_states(net, nodes, histids):\n",
|
|
" '''\n",
|
|
" 신호 초기화\n",
|
|
"\n",
|
|
" input :\n",
|
|
" (1) net : 네트워크\n",
|
|
" (2) nodes : 노드 목록\n",
|
|
" (3) histids : 모든 교차로에 대한 시작유닉스 (시작유닉스, A현시, B현시)별 현시시간, 진입·진출엣지\n",
|
|
"\n",
|
|
" output : node2init\n",
|
|
" - 각 노드를 초기화된 신호로 맵핑하는 딕셔너리\n",
|
|
" - 초기화된 신호란, 우회전을 g로 나머지는 r로 지정한 신호를 말함.\n",
|
|
" '''\n",
|
|
" node2init = {}\n",
|
|
" for node in nodes:\n",
|
|
" node_id = node.getID()\n",
|
|
" conns = [(c.getJunctionIndex(), c) for c in node.getConnections()]\n",
|
|
" conns = [c for c in conns if c[0] >= 0]\n",
|
|
" conns = sorted(conns, key=lambda x: x[0])\n",
|
|
" state = []\n",
|
|
" for i, ci in conns:\n",
|
|
" if ci.getTLLinkIndex() < 0:\n",
|
|
" continue\n",
|
|
" are_foes = False\n",
|
|
" for j, cj in conns:\n",
|
|
" if ci.getTo() == cj.getTo():\n",
|
|
" continue\n",
|
|
" if node.areFoes(i, j):\n",
|
|
" are_foes = True\n",
|
|
" break\n",
|
|
" state.append('r' if are_foes else 'g')\n",
|
|
" node2init[node_id] = state\n",
|
|
"\n",
|
|
" # 어떤 연결과도 상충이 일어나지는 않지만, 신호가 부여되어 있는 경우에는 r을 부여\n",
|
|
" for _, row in histids.iterrows():\n",
|
|
" node_id = row['node_id']\n",
|
|
" inc_edge_A = row.inc_edge_A\n",
|
|
" inc_edge_B = row.inc_edge_B\n",
|
|
" out_edge_A = row.out_edge_A\n",
|
|
" out_edge_B = row.out_edge_B\n",
|
|
"\n",
|
|
" if pd.isna(inc_edge_A) or pd.isna(out_edge_A):\n",
|
|
" pass\n",
|
|
" else:\n",
|
|
" inc_edge_A = net.getEdge(inc_edge_A)\n",
|
|
" out_edge_A = net.getEdge(out_edge_A)\n",
|
|
" for conn in inc_edge_A.getConnections(out_edge_A):\n",
|
|
" index = conn.getTLLinkIndex()\n",
|
|
" if index >= 0:\n",
|
|
" node2init[node_id][index] = 'r'\n",
|
|
"\n",
|
|
" if pd.isna(inc_edge_B) or pd.isna(out_edge_B):\n",
|
|
" pass\n",
|
|
" else:\n",
|
|
" inc_edge_B = net.getEdge(inc_edge_B)\n",
|
|
" out_edge_B = net.getEdge(out_edge_B)\n",
|
|
" for conn in inc_edge_B.getConnections(out_edge_B):\n",
|
|
" index = conn.getTLLinkIndex()\n",
|
|
" if index >= 0:\n",
|
|
" node2init[node_id][index] = 'r'\n",
|
|
" return node2init\n",
|
|
"node2init = initialize_states(net, nodes, histids)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def assign_signals(histids, node2init, net):\n",
|
|
" '''\n",
|
|
" 진입·진출엣지를 신호문자열로 배정\n",
|
|
"\n",
|
|
" input :\n",
|
|
" (1) histids : 모든 교차로에 대한 (시작유닉스, A현시, B현시)별 현시시간, 진입·진출엣지\n",
|
|
" (2) node2init : 각 노드를 초기화된 신호로 맵핑하는 딕셔너리\n",
|
|
" (3) net : 네트워크\n",
|
|
"\n",
|
|
" output : sigtable\n",
|
|
" - 모든 교차로에 대한 (시작유닉스, A현시, B현시)별 현시시간, 신호문자열\n",
|
|
" - 황색 및 적색신호는 아직 반영되지 않았음.\n",
|
|
" '''\n",
|
|
" sigtable = histids.copy()\n",
|
|
" sigtable['init_state'] = sigtable['node_id'].map(node2init)\n",
|
|
" sigtable['state'] = sigtable['init_state'].map(lambda x:''.join(x))\n",
|
|
" for i, row in sigtable.iterrows():\n",
|
|
" node_id = row.node_id\n",
|
|
" inc_edge_A = row.inc_edge_A\n",
|
|
" inc_edge_B = row.inc_edge_B\n",
|
|
" out_edge_A = row.out_edge_A\n",
|
|
" out_edge_B = row.out_edge_B\n",
|
|
" state = copy.deepcopy(node2init)[node_id]\n",
|
|
" if pd.isna(inc_edge_A) or pd.isna(out_edge_A):\n",
|
|
" pass\n",
|
|
" else:\n",
|
|
" inc_edge_A = net.getEdge(inc_edge_A)\n",
|
|
" out_edge_A = net.getEdge(out_edge_A)\n",
|
|
" for conn in inc_edge_A.getConnections(out_edge_A):\n",
|
|
" index = conn.getTLLinkIndex()\n",
|
|
" if index >= 0:\n",
|
|
" state[index] = 'G'\n",
|
|
" sigtable.at[i, 'state'] = ''.join(state)\n",
|
|
"\n",
|
|
" if pd.isna(inc_edge_B) or pd.isna(out_edge_B):\n",
|
|
" pass\n",
|
|
" else:\n",
|
|
" inc_edge_B = net.getEdge(inc_edge_B)\n",
|
|
" out_edge_B = net.getEdge(out_edge_B)\n",
|
|
" for conn in inc_edge_B.getConnections(out_edge_B):\n",
|
|
" index = conn.getTLLinkIndex()\n",
|
|
" if index >= 0:\n",
|
|
" state[index] = 'G'\n",
|
|
" sigtable.at[i, 'state'] = ''.join(state)\n",
|
|
" sigtable = sigtable.dropna(subset='state')\n",
|
|
" sigtable = sigtable.reset_index(drop=True)\n",
|
|
" sigtable['phase_sumo'] = sigtable.groupby(['node_id', 'start_unix']).cumcount()\n",
|
|
" sigtable = sigtable[['node_id', 'start_unix', 'phase_sumo', 'duration', 'state']]\n",
|
|
" sigtable = sigtable.sort_values(by=['start_unix', 'node_id'])\n",
|
|
" sigtable['start_dt'] = sigtable['start_unix'].apply(lambda x:datetime.fromtimestamp(x))\n",
|
|
" return sigtable\n",
|
|
"sigtable = assign_signals(histids, node2init, net)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"image/png": "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4qBCRET0o+HDh2PZsmUer7t06RJ+9atf4YEHHgj49oqLi93+vf7669A0Dbfddptrm7y8PHz11Vf4/PPPsXr1amzatAn33Xdfvduqrq7GxIkTce2113q9v2+//Ra/+93vPG5z7tw5DB06FPPmzQu4v65FixZh5syZePrpp/HVV19h9uzZeOihh/Dhhx8GfZt+Neh9bImIiJqw6667zu9bvC9dulQkJSUFdftjx44V119/vevrgwcPCgBi165drss++eQToWmaOHnypNv3/v73vxd33HGH1/uvqakR2dnZ4rXXXhP5+fli7NixHhucHymyd+/eetedPXtW3HPPPaJ169YiISFBjBgxQhQWFrquHzx4sPjd737n9j1Tp04VQ4YMCWDvg8NHVIiIiEKgtLQUH330Ee655x7XZdu2bUNycjL69+/vuiwnJwcRERHYsWOH67L169fjvffew8KFC73e/jPPPIOUlBS322+oX/3qVygrK8Mnn3yCgoIC9O3bFyNHjsSZM2cAADabrd4nRMfGxmLnzp1un7quJw4qREREIbB8+XIkJCTg1ltvdV1WUlKClJQUt+2ioqLQsmVLlJSUAAB++OEHTJo0CcuWLUNiYqLH296yZQv+/ve/49VXXw26b8uWLdi5cyfee+899O/fH1lZWfjzn/+M5ORk/Otf/wIAjB49Gq+99hoKCgoghMDu3bvx2muvobq6Gt9//33Q9+0LBxUiIgpbzz//PJo3b+76t3nzZtx///1ul504cUKX+3r99deRl5dX7xEJf+699178+te/xrBhwzxeX1lZiTvvvBOvvvoqWrduHXTfvn37UFVVhVatWrntf1FREY4ePQoAePLJJ3HDDTfgmmuuQbNmzTB27Fjk5+cDACIijBkpogy5VSIiIgXcf//9GD9+vOvrvLw83HbbbW6PeqSnpzf6fjZv3oxDhw7hnXfecbs8LS0NZWVlbpfV1NTgzJkzSEtLA3D5aZ9Vq1bhz3/+MwBACAGHw4GoqCgsWbIEffv2xbfffoubbrrJdRsOhwPA5UdnDh06hE6dOvltrKqqQtu2bbFx48Z61znPMoqNjcXrr7+OxYsXo7S0FG3btsWSJUuQkJCANm3aBLweDcFBhYiIwlbLli3RsmVL19exsbFISUlB586ddb2fv//97+jXrx969+7tdvngwYNRXl6OgoIC9OvXD8DlwcThcGDQoEEALr+OxW63u77ngw8+wLx587B161a0a9cOsbGx2L9/v9vtPvHEE6isrMSCBQuQkZERUGPfvn1RUlKCqKgoXHHFFT63bdasGdq3bw/g8unQN954Ix9RISIiMtOJEydw5swZnDhxAna73fU+JJ07d0bz5s0BAF27dsWcOXNwyy23uL7ParXivffew1/+8pd6t9mtWzfk5ubi3nvvxSuvvILq6mpMnjwZEyZMcD2S061bN7fv2b17NyIiItCzZ0/XZbX/f+CnR0BqX+5sP3XqFADg0KFDAC4/qpOWloacnBwMHjwY48aNw5/+9CdcddVVOHXqFD766CPccsst6N+/P7755hvs3LkTgwYNwtmzZzF//nwcOHAAy5cvD2ZJA8LXqBAREQXgqaeeQp8+fTBr1ixUVVWhT58+6NOnD3bv3u3a5tChQ6ioqHD7vrfffhtCCEycONHj7b755pvo2rUrRo4ciV/84hcYOnQolixZonv/qlWr0KdPH4wZMwYAMGHCBPTp0wevvPIKgMtvTvfxxx9j2LBhuOuuu3DVVVdhwoQJOH78OFJTUwEAdrsdf/nLX9C7d2/8/Oc/x8WLF7F161a/j8A0hiaEEIbdOhEREVEj8BEVIiIikhYHFSIiIpIWBxUiIiKSFgcVIiIikhYHFSIiIpIWBxUiIiKSFgcVIiIikhYHFSIiIpIWBxUiIiKSFgcVIiIikhYHFSIiIpIWBxUiIiKS1v8H0D5RGzTHKFUAAAAASUVORK5CYII=",
|
|
"text/plain": [
|
|
"<Figure size 640x480 with 1 Axes>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"import matplotlib.pyplot as plt\n",
|
|
"k = 0\n",
|
|
"for node_id, group in sigtable.groupby('node_id'):\n",
|
|
" k += 1\n",
|
|
" plt.plot(group.start_unix.unique(), [k] * len(group.start_unix.unique()), marker='o')\n",
|
|
" plt.axvline(present_time - 300, c='r', linewidth=.5)\n",
|
|
" plt.axvline(present_time, c='r', linewidth=.5)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# node2num_cycles : A dictionary that maps a node_id to the number of cycles\n",
|
|
"def get_node2num_cycles(plan, node_ids):\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",
|
|
"\n",
|
|
" return node2numcycles\n",
|
|
"node2num_cycles = get_node2num_cycles(plan, node_ids)\n",
|
|
"node2num_cycles"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def set_timepoints(sigtable, node2num_cycles, present_time):\n",
|
|
" offsets = {}\n",
|
|
" Sigtable = []\n",
|
|
" sim_start = present_time - 300\n",
|
|
" for node_id, group in sigtable.groupby('node_id'):\n",
|
|
" lsbs = group[group['start_unix'] < sim_start]['start_unix'].max() # the last start_unix before sim_start\n",
|
|
" offsets[node_id] = lsbs - sim_start\n",
|
|
" group = group[group.start_unix >= lsbs]\n",
|
|
" start_unixes = np.array(group.start_unix)\n",
|
|
" start_unixes = np.sort(np.unique(start_unixes))[:node2num_cycles[node_id]]\n",
|
|
" group = group[group.start_unix.isin(start_unixes)]\n",
|
|
" Sigtable.append(group)\n",
|
|
" Sigtable = pd.concat(Sigtable)\n",
|
|
" return Sigtable, offsets\n",
|
|
"Sigtable, offsets = set_timepoints(sigtable, node2num_cycles, present_time)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": []
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"1 c30 4\n",
|
|
"2 i0 3\n",
|
|
"3 i1 4\n",
|
|
"4 i2 4\n",
|
|
"5 i3 4\n",
|
|
"6 i6 4\n",
|
|
"7 i7 4\n",
|
|
"8 i8 4\n",
|
|
"9 i9 4\n",
|
|
"10 u00 3\n",
|
|
"11 u20 4\n",
|
|
"12 u30 4\n",
|
|
"13 u31 4\n",
|
|
"14 u32 4\n",
|
|
"15 u60 4\n"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"image/png": "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8GVf1GLfvn1mw4YNZsOGDUaSmTlzptmwYYPZvn272bdvn7njjjvMypUrzbZt28yHH35oBg4caHr16mUOHDgQWUdeXp4ZMGCAWb16tfn4449Nr169zLXXXhu5v7S01GRlZZnrr7/ebNy40bz22msmPT3dzJkzJxEvOWZ1bRtjjHnzzTdNixYtzNy5c83WrVvN008/bVJTU83y5csj67j55pvNCSecYBYtWmTWrVtnhg4daoYOHRq5/9ChQ6Zfv35m5MiRpqCgwCxcuNB07tzZTJ06tdlfb0PVt32MMaasrMykp6eb2bNn17oOr753zj//fHPaaaeZxYsXm6+//tq89NJLplWrVuaZZ56JrMPL753XX3/dLF682Hz11Vfmr3/9q+nevbu54oorotbh1u1zyy23mGAwaJYsWWIKCwsjfxUVFZE2Trz2r7/+2qSnp5s777zTfPHFF2bWrFkmNTXVLFy4sFlfb0PFsn0KCwvNhg0bzHPPPWckmWXLlpkNGzaY7777LtKmOfY9FChNdPg0rKP/xo8fbyoqKszIkSNN586dTYsWLUz37t3NjTfeGHXqmjHGfPfdd+baa681bdu2NYFAwPziF78w+/bti2rzySefmHPOOcf4/X7TtWtXM3369OZ8mY1S17Y57IUXXjAnn3yyadWqlenfv7/561//GrWO77//3tx6662mffv2Jj093Vx++eWmsLAwqs0333xjLrnkEtO6dWvTqVMn85vf/MZUVlY2x0tskli2z5w5c0zr1q1NaWlprevw6nunsLDQTJgwweTk5JhWrVqZ3r17myeeeMJUV1dH1uHl985TTz1lunXrZlq0aGFOOOEEc++99x5zarBbt09t20WSeemllyJtnHrtixcvNmeeeaZp2bKlOemkk6Kew1axbJ8HHnig3jbNse/x/dBhAAAAa/AdFAAAYB0KFAAAYB0KFAAAYB0KFAAAYB0KFAAAYB0KFAAAYB0KFAAAYB0KFAAAYvDII49o2LBhSk9PP+bXkI/H5/PV+vf4449H2uzZs0fjxo1TIBBQRkaGbrjhBpWXl9e6vi+//FLt2rWr8/lfe+01+Xw+jR07Nmr5m2++qZEjR6pjx47y+XwqKCiI6TUcbdasWTr11FPVunVr9e7dW3/84x8btZ76UKAAAPCDCy64QPPmzav1voMHD+rnP/+5brnllpjXV1hYGPX34osvyufz6corr4y0GTdunD7//HN98MEHevvtt7Vs2TLddNNNx6yrsrJS1157rc4999zjPt8333yjO+64o9Y2+/fv1znnnKMZM2bE3P+jzZ49W1OnTtWDDz6ozz//XA899JAmTpyot956q9HrPK7GXzAXAAB3Of/88+u9ZP1LL71kgsFgo9Y/ZswYc9FFF0Vub9q0yUgya9eujSx79913jc/nMzt37ox67G9/+1tz3XXXHff5Dx06ZIYNG2aef/55M378eDNmzJha+7Bt2zYjyWzYsOGY+/bu3WtuuOEG06lTJ9OuXTtz4YUXmoKCgsj9Q4cONXfccUfUY6ZMmWKGDx8ew6tvGI6gAADQDIqLi/XOO+/ohhtuiCxbuXKlMjIyNHjw4MiyESNGKCUlRatXr44sW7Rokd544w3NmjXruOt/+OGHlZmZGbX+hvr5z3+ukpISvfvuu8rPz9fAgQN18cUXa8+ePZKkcDisVq1aRT2mdevWWrNmTdQvFzuBAgUAgGbw8ssvq127drriiisiy4qKipSZmRnVLi0tTR06dFBRUZEk6bvvvtOECRM0b948BQKBWtf98ccf64UXXtBzzz3X6P59/PHHWrNmjd544w0NHjxYvXr10u9//3tlZGTof/7nfyRJo0aN0vPPP6/8/HwZY7Ru3To9//zzqqys1D//+c9GP3dtKFAAAJ716KOPqm3btpG/5cuX6+abb45atmPHDkee68UXX9S4ceOOOQJRnxtvvFH/9m//pvPOO6/W+/ft26frr79ezz33nDp16tTo/n3yyScqLy9Xx44do17/tm3b9NVXX0mS7rvvPl1yySX6yU9+ohYtWmjMmDEaP368JCklxdmSIs3RtQEAkERuvvlmXXXVVZHb48aN05VXXhl1lCMnJ6fJz7N8+XJt3rxZf/nLX6KWZ2dnq6SkJGrZoUOHtGfPHmVnZ0uqmd5ZsGCBfv/730uSjDGqrq5WWlqa5s6dq4EDB+qbb77RpZdeGllHdXW1pJqjMZs3b1bPnj3r7WN5ebm6dOmiJUuWHHPf4bOGWrdurRdffFFz5sxRcXGxunTporlz56pdu3bq3LlzzNsjFhQoAADP6tChgzp06BC53bp1a2VmZurkk0929HleeOEFDRo0SP37949aPnToUJWWlio/P1+DBg2SVFOQVFdXa8iQIZJqvqdSVVUVeczf/vY3zZgxQytWrFDXrl3VunVrffbZZ1Hrvffee7Vv3z499dRTys3NjamPAwcOVFFRkdLS0nTiiSfW2bZFixbq1q2bpJrTmn/2s59xBAUAgETYsWOH9uzZox07dqiqqipyHZGTTz5Zbdu2lST16dNH06ZN0+WXXx55XCgU0htvvKEnnnjimHWeeuqpysvL04033qhnn31WlZWVmjRpkq655prIkZtTTz016jHr1q1TSkqK+vXrF1l25L+lH494HLn8cN937dolSdq8ebOkmqM42dnZGjFihIYOHaqxY8fqscce0ymnnKJdu3bpnXfe0eWXX67Bgwdry5YtWrNmjYYMGaK9e/dq5syZ2rhxo15++eXGbNI68R0UAABicP/992vAgAF64IEHVF5ergEDBmjAgAFat25dpM3mzZtVVlYW9bjXXntNxhhde+21ta731VdfVZ8+fXTxxRfrX/7lX3TOOedo7ty5jvd/wYIFGjBggEaPHi1JuuaaazRgwAA9++yzkmouKvf3v/9d5513nn7xi1/olFNO0TXXXKPt27crKytLklRVVaUnnnhC/fv3109/+lMdOHBAK1asqPeIS2P4jDHG8bUCAAA0AUdQAACAdShQAACAdShQAACAdShQAACAdShQAACAdShQAACAdShQAACAdShQAACAdShQAACAdShQAACAdShQAACAdShQAACAdf5/efe8nZG0xXQAAAAASUVORK5CYII=",
|
|
"text/plain": [
|
|
"<Figure size 640x480 with 1 Axes>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"import matplotlib.pyplot as plt\n",
|
|
"k = 0\n",
|
|
"for node_id, group in Sigtable.groupby('node_id'):\n",
|
|
" k += 1\n",
|
|
" print(k, node_id, node2num_cycles[node_id])\n",
|
|
" plt.plot(group.start_unix.unique(), [k] * len(group.start_unix.unique()), marker='o')\n",
|
|
" plt.axvline(present_time - 300, c='r', linewidth=.5)\n",
|
|
" plt.axvline(present_time, c='r', linewidth=.5)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 10,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def assign_red_yellow(Sigtable):\n",
|
|
" '''\n",
|
|
" 적색, 황색신호를 반영한 신호문자열 배정\n",
|
|
"\n",
|
|
" input : Sigtable\n",
|
|
" - 모든 교차로에 대한 (시작유닉스, 세부현시번호)별 현시시간, 신호문자열, 진입·진출엣지\n",
|
|
" * 세부현시란 오버랩을 반영한 현시번호를 뜻함.\n",
|
|
"\n",
|
|
" output : SIGTABLE\n",
|
|
" - 모든 교차로에 대한 (시작유닉스, 녹황적세부현시번호)별 현시시간, (황·적색신호가 포함된) 신호문자열\n",
|
|
" * 녹황적세부현시번호란 세부현시번호에 r, g, y 옵션까지 포함된 현시번호를 뜻함.\n",
|
|
" '''\n",
|
|
" SIGTABLE = []\n",
|
|
" for node_id, group in Sigtable.groupby('node_id'):\n",
|
|
" new_rows_list = []\n",
|
|
" for i in range(1, len(group)):\n",
|
|
" prev_row = group.iloc[i-1:i].copy()\n",
|
|
" next_row = group.iloc[i:i+1].copy()\n",
|
|
" new_rows = pd.concat([prev_row, prev_row, next_row]).reset_index(drop=True)\n",
|
|
" new_rows.loc[0, 'phase_sumo'] = str(prev_row.phase_sumo.iloc[0]) + '_g'\n",
|
|
" new_rows.loc[0, 'duration'] = new_rows.loc[0, 'duration'] - 5\n",
|
|
" new_rows.loc[1, 'phase_sumo'] = str(prev_row.phase_sumo.iloc[0]) + '_y'\n",
|
|
" new_rows.loc[1, 'duration'] = 4\n",
|
|
" yellow_state = ''\n",
|
|
" red_state = ''\n",
|
|
" for a, b in zip(prev_row.state.iloc[0], next_row.state.iloc[0]):\n",
|
|
" if a == 'G' and b == 'r':\n",
|
|
" yellow_state += 'y'\n",
|
|
" red_state += 'r'\n",
|
|
" else:\n",
|
|
" yellow_state += a\n",
|
|
" red_state += a\n",
|
|
" new_rows.loc[2, 'phase_sumo'] = str(next_row.phase_sumo.iloc[0]) + '__r'\n",
|
|
" new_rows.loc[2, 'duration'] = 1\n",
|
|
" new_rows.loc[1, 'state'] = yellow_state\n",
|
|
" new_rows.loc[2, 'state'] = red_state\n",
|
|
" new_rows_list.append(new_rows)\n",
|
|
" next_row['phase_sumo'] = str(next_row.phase_sumo.iloc[0]) + '_g'\n",
|
|
" next_row['duration'] -= 5\n",
|
|
" # next_row.loc['duration'] -= 5\n",
|
|
" new_rows_list.append(next_row)\n",
|
|
" new_rows = pd.concat(new_rows_list)\n",
|
|
" SIGTABLE.append(new_rows)\n",
|
|
" SIGTABLE = pd.concat(SIGTABLE).sort_values(by=['node_id', 'start_unix', 'phase_sumo']).reset_index(drop=True)\n",
|
|
" return SIGTABLE\n",
|
|
"SIGTABLE = assign_red_yellow(Sigtable)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 11,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def make_tl_file(SIGTABLE, offsets, present_time):\n",
|
|
" strings = ['<additional>\\n']\n",
|
|
" for node_id, group in SIGTABLE.groupby('node_id'):\n",
|
|
" strings.append(f' <tlLogic id=\"{node_id}\" type=\"static\" programID=\"{node_id}_prog\" offset=\"{offsets[node_id]}\">\\n')\n",
|
|
" for i, row in group.iterrows():\n",
|
|
" duration = row.duration\n",
|
|
" state = row.state\n",
|
|
" strings.append(f' <phase duration=\"{duration}\" state=\"{state}\"/>\\n')\n",
|
|
" strings.append(' </tlLogic>\\n')\n",
|
|
" strings.append('</additional>')\n",
|
|
" strings = ''.join(strings)\n",
|
|
" # 저장\n",
|
|
" path_output = f'../Results/sn_{present_time}.add.xml'\n",
|
|
" with open(path_output, 'w') as f:\n",
|
|
" f.write(strings)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 12,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def generate_signals(m):\n",
|
|
" midnight = int(datetime(2024, 1, 5, 0, 0, 0).timestamp())\n",
|
|
" next_day = int(datetime(2024, 1, 6, 0, 0, 0).timestamp())\n",
|
|
" fmins = range(midnight, next_day, 300)\n",
|
|
"\n",
|
|
" # 현재시각\n",
|
|
" present_time = fmins[m]\n",
|
|
" sim_start = fmins[m] - 300\n",
|
|
" \n",
|
|
" # network and dataframes\n",
|
|
" net = sumolib.net.readNet('../Data/networks/sn.net.xml')\n",
|
|
" inter_node = pd.read_csv('../data/tables/inter_node.csv', index_col=0)\n",
|
|
" plan = pd.read_csv('../Data/tables/plan.csv', index_col=0)\n",
|
|
" match6 = pd.read_csv('../Intermediates/match6.csv', index_col=0)\n",
|
|
" match6 = match6[['node_id', 'phase_no', 'ring_type', 'inc_edge', 'out_edge']].reset_index(drop=True)\n",
|
|
" histid = pd.read_csv(f'../Intermediates/histid/histid_{present_time}.csv', index_col=0)\n",
|
|
" histid = histid.reset_index(drop=True).drop(columns=['inter_no'])\n",
|
|
" \n",
|
|
" # helper dictionaries and lists\n",
|
|
" inter_node_p = inter_node[inter_node.inter_type=='parent']\n",
|
|
" inter2node = dict(zip(inter_node_p['inter_no'], inter_node_p['node_id']))\n",
|
|
" node2inter = dict(zip(inter_node['node_id'], inter_node['inter_no']))\n",
|
|
" pa2ch = {'i0':['u00'], 'i1':[], 'i2':['u20'], 'i3':['c30', 'u30', 'u31', 'u32'], 'i6':['u60'], 'i7':[], 'i8':[], 'i9':[]}\n",
|
|
" node_ids = sorted(inter_node.node_id.unique())\n",
|
|
" parent_ids = sorted(inter_node[inter_node.inter_type=='parent'].node_id.unique())\n",
|
|
" nodes = [net.getNode(node_id) for node_id in node_ids]\n",
|
|
"\n",
|
|
" # histids\n",
|
|
" histids = attach_children(histid, match6, parent_ids, pa2ch)\n",
|
|
"\n",
|
|
" # node2init\n",
|
|
" node2init = initialize_states(net, nodes, histids)\n",
|
|
"\n",
|
|
" # sigtable\n",
|
|
" sigtable = assign_signals(histids, node2init, net)\n",
|
|
"\n",
|
|
" with open('../Intermediates/node2numcycles.json', 'r') as file:\n",
|
|
" node2numcycles = json.load(file)\n",
|
|
"\n",
|
|
" # Sigtable\n",
|
|
" Sigtable, offsets = set_timepoints(sigtable, node2num_cycles, present_time)\n",
|
|
"\n",
|
|
" # SIGTABLE\n",
|
|
" SIGTABLE = assign_red_yellow(Sigtable)\n",
|
|
"\n",
|
|
" make_tl_file(SIGTABLE, offsets, present_time)\n",
|
|
" print(f'A signal file (add.xml) has been created for the timeslot between {datetime.fromtimestamp(sim_start)} and {datetime.fromtimestamp(present_time)} ({sim_start} ~ {present_time})')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 13,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"A signal file (add.xml) has been created for the timeslot between 2024-01-05 08:40:00 and 2024-01-05 08:45:00 (1704411600 ~ 1704411900)\n",
|
|
"A signal file (add.xml) has been created for the timeslot between 2024-01-05 08:45:00 and 2024-01-05 08:50:00 (1704411900 ~ 1704412200)\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"for m in range(105, 107):\n",
|
|
" generate_signals(m)"
|
|
]
|
|
}
|
|
],
|
|
"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
|
|
}
|