東名高速 大和トンネルの渋滞を再現する【交通流シミュレータSUMO】

##はじめに
2019年は<font color="Silver">（カレンダー通りであれば）</font>GWが10連休です．高速道路の渋滞もきっと例年より酷いものになるでしょう．

そこで，本稿では交通流シミュレータSUMOを使って東名高速上り大和トンネル付近を先頭とする渋滞を再現します．
自然発生する渋滞のモデルは既に存在しますが，本稿ではシミュレータの利便性を活かして**数学的ことは考えずに**渋滞を発生させます．

##環境
- Windows10 64bit
- SUMO version 1.1.0
- Python 3.7.3 

SUMOの基本的な操作は[こちらの記事](https://qiita.com/nattof/items/d198557126b7d3636f10)が参考になると思います．

##大和トンネルはなぜ渋滞するのか（上り線）
大和トンネルは言わずと知れた渋滞の名所で，土休日の酷いときや，GWや盆正月のUターンラッシュに限らず数十km/h単位の渋滞が発生します．今年のGWもサンデードライバが大挙して押し寄せ，多くの人が渋滞に苦しめられるでしょう，

さて，国交省の資料を確認してまとめると，渋滞の原因として以下の4点が考えられます．

- 交通量が多い
- 綾瀬バス停手前にサグ部がある
- 綾瀬バス停通過後 4車線→3車線になる
- 大和トンネルが上り坂

特にサグ部や上り坂ではドライバが意識せず速度が低下してしまい，後続車との車間が詰まってブレーキをペコペコ踏んでしまうので，渋滞の原因となります．自然発生する渋滞のほとんどがサグ部によるものと考えられています．

今回はこれらの条件をシミュレータで再現して渋滞する様子を観察します．

![yamatoTN.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366359/d9992878-049e-3cfe-d6e5-0d44cc84e6be.png)
出典: 国土交通省関東地方整備局 横浜国道事務所 神奈川県東名軸渋滞ボトルネック検討ワーキンググループ 第１回ワーキンググループ資料pp.21（http://www.ktr.mlit.go.jp/yokohama/06data/plan/jyutai/）

##交通流シミュレータSUMOを使って再現する

###地図を準備する

####OpenStreetMapから地図を取り込む

[過去の記事](https://qiita.com/jagimo/items/5581ac3cc02356911c85)と同様に**日本向けの速度設定を実施したうえで**，SUMOに付属のNETCONVETを用いてOpenStreetMapの地図を取り込みます．今回は横浜町田ICから大井松井ICまでの範囲が入るようにOSMから地図をエクスポートします．

下記設定ファイルを準備し，NETCONVERTを実行します．今回は高速道路のみ使用するので，*highway.motorway, highway.motorway_link*クラスのみ読み込みます．また，綾瀬BSと大和BSも目印にしたいので，*highway.service*クラスも読み込みます．

``` expressway.netcfg
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/netconvertConfiguration.xsd">

    <input>
        <osm-files value="kanagawa.osm"/>
    </input>

    <output>
        <output-file value="tomei_expressway.net.xml"/>
        <output.street-names value="true"/>
    </output>
    
    <edge_removal>
        <keep-edges.by-type value="highway.motorway, highway.motorway_link, highway.service"/>
    </edge_removal>

    <projection>
        <proj.utm value="true"/>
        <proj.plain-geo value="true"/>
    </projection>
    

    <junctions>
        <no-internal-links value="true"/>
    </junctions>

    <report>
        <verbose value="true"/>
        <xml-validation value="never"/>
    </report>

</configuration>

```
`$ netconvert -c expressway.netcfg`

####地図の微修正を行う
NETCONVERTで地図をそのまま読み込むと，デフォルトの設定では全区間3車線で道路が生成されます．しかし，実際には海老名JCTから綾瀬BSまでの区間は4車線ですので，<font color="Silver">（泥臭いですが）</font>SUMOに付属の地図編集ソフトNETEDITを使って手動で微修正を行います．

![netedit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366359/1cb9e1d0-b105-9fb1-0feb-8708c09e1e57.png)

また，今回の制限速度は基本的には100 km/h（27.78 m/s）で設定していますが，渋滞を発生させるために，大和トンネルと綾瀬BS付近のサグ部のみは制限速度を80 km/h（22.22 m/s）に書き換え，細工を施します．この書き換えもNETEDITから操作できます．

そして，SUMOの欠点として加速車線があまり考慮されない点があります．なので，NETEDITで合流部の本線は1車線追加しておかないと，いつまでたっても車両が本線に合流しないという事象が発生するので注意が必要です．

編集結果は *map/tomei_expressway_edit.net.xml* としてファイル名を変えて保存しておきます．以後編集後のnet.xmlファイルを使います．

###シミュレーション上の交通量を定義する

####交通センサスデータをもとにflowを定義する

日本国内の交通流の全容をざっくり知りたい場合，参考になる情報として**全国道路・街路交通情勢調査 一般交通量調査**（交通センサス）の集計表がありあます．5年ごとに調査結果が更新されています．今回は[平成27年度のデータ](http://www.mlit.go.jp/road/census/h27/)をもとにして交通流を生成します．

交通センサスの時間帯別交通量表では，各ICやJCT間の1時間ごとの交通量が確認できます．例えば，大井松田ICから横浜町田ICまでの交通量は以下のようになっています．<font color="Silver">（国交省の書式では7:00始まりですが，今回は後述の実装のために0:00始まりに読み替えています．）</font>

|単区間番号|起点|終点|車種区分|0時台|1時台|2時台|…|
|:---|:---|:---|:---|:---|:---|:---|:---|
|70|大井松田IC|秦野中井IC|小型車|300|224|214|…|
|60|秦野中井IC|厚木IC|小型車|394|221|247|…|
|50|厚木IC|海老名JCT|小型車|512|295|329|…|
|60|海老名JCT|横浜町田IC|小型車|507|314|310|…|
|70|大井松田IC|秦野中井IC|大型車|1407|1484|1852|…|
|…||||||||

今回は，時間帯ごとに交通量を順々に累算し，前区間よりも交通量が減少する場合はICで流出，増加する場合はICから流入するようにします．<font color="Silver">（ただし，海老名JCTの流出する場合は，厚木ICの集散路で本線から離脱するものとします．）</font>
各IC・JCTの流入・流出台数は以下のようになります．<font color="Silver">（流入edgeと流出edgeはNETEDITで地図を目視しながら決めました．）</font>

|流入edgeID|流出edgeID|IC・JCT|流入出台数|車種区分|0時台|1時台|2時台|…|
|:---|:---|:---|:---|:---|:---|:---|:---|:---|
|33809839#1|なし|大井松田IC|300|小型車|300|224|214|…|
|50867656|407660409#0|秦野中井IC|94|小型車|94|-13|33|…|
|571990950#0|429427367|厚木IC|118|小型車|118|94|82|…|
|51335836|429427367|海老名JCT|-5|小型車|-5|19|-19|…|
|…||||大型車も同様|||||

また，実際の交通事情とは異なる点として，シミュレーション上では大井松田ICと厚木ICにおいては，流入車両は本線上に初速22.22 m/s（80 km/h）で車両を出現させるものとします．<font color="Silver">（交通量に対してシミュレータ上のICのループ路の容量が大幅に不足するため．）</font>

以上の交通量を，SUMOに入力するO/D（出発地・目的地）のflowのファイルに記述すると以下のようになります．

```tomei_census.flows.xml
<flowdefs>
    <!--0時台 小型車 大井松田IC-海老名JCT-->
    <flow id="flow0standard" from="33809839#1" to="429427367" begin="0" end="3599" number="5" />
    <!--0時台 小型車 大井松田IC-横浜町田IC-->
    <flow id="flow1standard" from="33809839#1" to="384983605#0" begin="0" end="3599" number="295" />
    <!--0時台 小型車 秦野中井IC-横浜町田IC-->
    <flow id="flow2standard" from="50867656" to="384983605#0" begin="0" end="3599" number="94" />
    <!--0時台 小型車 厚木IC-横浜町田IC-->
    <flow id="flow3standard" from="571990950#0" to="384983605#0" begin="0" end="3599" number="118" />
    <!--0時台 大型車 大井松田IC-海老名JCT-->
    <flow id="flow4large" from="33809839#1" to="429427367" begin="0" end="3599" number="112" />
    …
```

作成した *tomei_census.flows.xml* をもとに，SUMO付属のDUAROUTERを使って個々の車両の定義を出力します．
下記の設定ファイルを作成し，DUAROUTERを実行します．

```tomei.duarcfg
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/duarouterConfiguration.xsd">

    <input>
        <net-file value="../map/tomei_expressway_edit.net.xml"/>
        <route-files value="tomei_census.flows.xml"/>
    </input>

    <output>
        <output-file value="tomei.rou.xml"/>
    </output>

    <defaults>
        <departspeed value="22.22"/>
        <departlane value="random"/>
        <departpos value="random"/>
    </defaults>

    <report>
        <xml-validation value="never"/>
        <no-step-log value="true"/>
    </report>

</configuration>
```

`
$ duarouter -c tomei.duarcfg
`

####トラヒックデマンドファイル（rou.xml）の車両定義を行う
DUAROUTERで生成されたrou.xmlファイルは車両の細かな設定がなされていないので，ファイルに直接追記します．

追記部分は以下のようになります．
vTypeの *sigma* は運転の上手さのパラメータで，0-1.0を指定できます．今回は大型車は職業ドライバを想定，小型車はサンデードライバを想定して *sigma* を設定しています．

```tomei_edit.rou.xml
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://sumo.dlr.de/xsd/routes_file.xsd">
    <!--vType追記-->
    <vType id="standard" maxSpeed="30.56" vClass="private" sigma="0.2"/>
    <vType id="large" maxSpeed="25" vClass="trailer" sigma="0.8" color="#ff0000"/>
    <!--ここまで追記-->

    <!--以下，各vehicleでtype="standard"もしくはtype="large"を追記-->
    <vehicle id="flow0standard.0" depart="0.00" departLane="random" departPos="random" departSpeed="22.22" type="standard">
        <route edges="33809839#1 285333494 379537552 379537555 285333467 34000115 34000116#0 34000116#1 571925282 571925289 407660406 50873070 50873069 50867665 407660405#0 407660405#1 22735936 33811279 33811285 33811287 158813023 22735937 33811713 33811714 33811715 33811716 33811764 33811765 575950287 575950297 285333488 285333479#0 285333479#1 33811914 571956614#0 571956614#1 571957332 571957330 571958023 571958025 285333486 285333443 36982381 36982383 571969729 26416199 429427367"/>
    </vehicle>
…
    <vehicle id="flow4large.0" depart="0.00" departLane="random" departPos="random" departSpeed="22.22" type="large">
        <route edges="33809839#1 285333494 379537552 379537555 285333467 34000115 34000116#0 34000116#1 571925282 571925289 407660406 50873070 50873069 50867665 407660405#0 407660405#1 22735936 33811279 33811285 33811287 158813023 22735937 33811713 33811714 33811715 33811716 33811764 33811765 575950287 575950297 285333488 285333479#0 285333479#1 33811914 571956614#0 571956614#1 571957332 571957330 571958023 571958025 285333486 285333443 36982381 36982383 571969729 26416199 429427367"/>
    </vehicle>
…
```

東名高速の大井松田-横浜町田を通過する車両は1日の交通量が7万台以上あり，手動でファイルに手を加えるのは骨が折れるので，pythonスクリプトで書き換えてしまします．

```vehicletype.py
def main(read_file_name, write_file_name):
    edit_xml = edit_xml_lines(read_file_name)
    print_edited_xml(write_file_name, edit_xml)


def edit_xml_lines(read_file_name):
    edit = []
    file = open(read_file_name + '.rou.xml', 'r')
    lines = file.readlines()

    for line in lines:
        if 'standard' in line:
            edit.append(line[:len(line) - 2]
                        + ' type="standard">')
        elif 'large' in line:
            edit.append(line[:len(line) - 2]
                        + ' type="large">')
        elif '<routes' in line:
            edit.append(line[:len(line) - 1])
            edit.append('    <vType id="standard" maxSpeed="30.56" vClass="private" sigma=0.2/>')
            edit.append('    <vType id="large" maxSpeed="25" vClass="trailer" sigma=0.8 color="#ff0000"/>')
        else:
            edit.append(line[:len(line) - 1])

    file.close()
    return edit


def print_edited_xml(write_file_name, edit_xml):
    file = open(write_file_name + '.rou.xml', 'w')
    for line in edit_xml:
        file.write(line + '\n')
    file.close()


main('tomei', 'tomei_edit')
```

####シミュレーションの実行ファイルを作る
地図ファイル（*net.xml*）とトラヒックデマンドファイル（rou.xml）が揃ったので，基本的にはシミュレーションを実行できる状態になりました．ここで下記のようなSUMOの実行ファイルを作成します．

特筆すべき設定は *max-depart-delay* です．これは，車両を挿入する場所が渋滞で埋められてて新たに車両を挿入できない場合，何秒まで待つかの設定です．ここでは15分で車両の挿入をキャンセルする設定にしていますが，これを設定しない場合は挿入待ちの車両が溜まりつづけて渋滞がいつまで経っても解消されない場合があります．

```tomei.sumocfg
<configuration>
	<input>
		<net-file value="map/tomei_expressway_edit.net.xml"/>
		<route-files value="trip/tomei_edit.rou.xml"/>
	</input>
	<time>
		<begin value="0"/>
		<end value="86400"/>
	</time>
	<processing>
		<max-depart-delay value="900"/>
	</processing>
</configuration>

```

上記のsumocfgファイルを実行してシミュレーションを観察していても**渋滞はほとんど発生しません**．これは，サグ部で車両が減速する挙動を十分に再現できていないからです．<font color="Silver">（つまり，ACC等が普及してサグ部で全く減速しない世界が来たら，ほとんど渋滞しない．）</font>

ここからのシミュレーションでいかに再現するかというのは，チューニングでゴリゴリ泥臭くやる世界です…（今回はそこまでこだわってチューニングはしません．）

###TraCIを使い，SUMO実行中に裏側から動的に制御し，ブレーキをパカパカ踏ませる

SUMOにはTraCIというシミュレーション実行中に車両の挙動等を裏側から制御するためのI/Fが用意されています．
Windows版のSUMOをインストーラを使ってインストールしていれば，基本的にpythonでtraciライブラリをimportできるようになっているはずです．例えば以下のようにして使います．

```tracisample.py
import traci

traci.start(sumoCmd) #SUMOを起動しシミュレーションを開始する

for step in range(1000):
    traci.simulationStep() #シミュレーションを1step進める
    traci.vehicle.getSpeed('hoge') #車両hogeの速度を取得する（一例）

traci.close() #SUMOを終了する
```

TraCIを使って，大和TNおよび綾瀬BSサグ部を通過中の車両に対して減速指示を送るpythonスクリプトを作成します．
動作の概要は以下のようになります．

- 5秒に1回 走行中の車両の一覧を取得し，走行位置と速度を取得する
- 走行位置が大和TNか綾瀬BSサグ部であった場合，減速指示を行う
    - <font color="Red">当該地点走行中の車両全てが 10% 減速する（今回は決め打ち）</font>
    - 大和TNで一度減速した車両は，もう一度大和TNで原則指示を受けることはない（綾瀬BSでも同様）
- 毎秒走行が終了した車両を監視し，終了した車両は監視対象から外す

以上の挙動をtraciとpythonを使って書くとこうなります．

```trafficjam.py
import traci

YAMATO_TN = '31887784'
AYASE_BT_SAG = '37038705'
DECELERATION_RATE = 0.9
DECELERATION_DURATION = 3


def main(sumocfg):
    sumoCmd = ['sumo-gui', '-c', sumocfg]

    traci.start(sumoCmd)
    step = 0
    accident = False

    slow_down_yamato = []
    slow_down_ayase = []

    while step < 60 * 60 * 24: # 1day
        traci.simulationStep()

        # arrived vehicle
        arrive_list = traci.simulation.getArrivedIDList()
        for v in arrive_list:
            if v in slow_down_ayase:
                slow_down_ayase.remove(v)
            if v in slow_down_yamato:
                slow_down_yamato.remove(v)

        if step % 5 == 0:
            v_list = traci.vehicle.getIDList()
            for v in v_list:
                speed = traci.vehicle.getSpeed(v)

                # slow down at sag
                current_edge = traci.vehicle.getRoadID(v)
                if current_edge == YAMATO_TN and v not in slow_down_yamato:
                    traci.vehicle.slowDown(
                        v,
                        speed * DECELERATION_RATE,
                        DECELERATION_DURATION
                        )
                    slow_down_yamato.append(v)
                elif current_edge == AYASE_BT_SAG and v not in slow_down_ayase:
                    traci.vehicle.slowDown(
                        v,
                        speed * DECELERATION_RATE,
                        DECELERATION_DURATION
                        )
                    slow_down_ayase.append(v)
        step += 1
    traci.close()


sumocfg = 'tomei.sumocfg'
main(sumocfg)
```

##シミュレーション結果（平日）
簡単にビジュアライゼーションしてみました．

赤い部分が渋滞個所（40km/h以下で流れている場所）です．
元々の交通センサスデータが平日のなので，朝に少し綾瀬BS付近で渋滞します．
夕方は大和TNを先頭に厚木ICまで渋滞が続く結果となりました．

![ave10_5.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366359/aecd0d2d-dd62-9b9d-8a50-67b54bcab349.gif)


##GWの渋滞らしきものを再現（番外編）
交通センサスの平日のデータを改変して，GWのデータらしきものを作ってみます．
今回は決め打ちで，大型車の交通量0.5倍にする代わりに，9:00～21:00の小型車のデータを2倍にしてみます．

![ave10_gw_noaccident.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366359/2d83855f-814e-228b-5874-6d8c22787160.gif)

少々大げさに渋滞を作ってしまった感じは否めませんが，夕方前には綾瀬BSと大和TNで渋滞し始め，ピーク時には秦野中井ICまで渋滞します．

##おわりに
大和トンネルをはじめとする東名高速のサグ部を交通流シミュレータSUMOで設定し，実際の交通量に近いデータを流して渋滞を再現しました．渋滞の程度はチューニング不足で実際のとは多少異なるでしょうが，おおよその傾向としては再現できたのではないでしょうか．

GWは大変な渋滞が予想されます．少しでも渋滞緩和のため，車間距離はある程度取り，<font color="Red">**サグ部では減速しないように**</font>心がけましょう．<font color="Silver">（私が少しでも快適に実家に帰省できることを願います．）</font>

あとは，くれぐれも事故には気を付けてください．


##参考ページ
- 国土交通省関東地方整備局 横浜国道事務所 神奈川県東名軸渋滞ボトルネック検討ワーキンググループ 第１回ワーキンググループ資料: http://www.ktr.mlit.go.jp/yokohama/06data/plan/jyutai/
(accessed: 2019/04/26).
- 平成27年度　全国道路・街路交通情勢調査 一般交通量調査 集計表: http://www.mlit.go.jp/road/census/h27/
(accessed: 2019/04/26).
- SUMO NETCONVERT（英語）, ドイツ航空宇宙センター: https://sumo.dlr.de/wiki/NETCONVERT
(accessed: 2019/04/27).
- SUMO Definition of Vehicles, Vehicle Types, and Routes（英語）, ドイツ航空宇宙センター: https://sumo.dlr.de/wiki/Definition_of_Vehicles,_Vehicle_Types,_and_Routes
(accessed: 2019/04/27).
- SUMO DUAROUTER（英語）, ドイツ航空宇宙センター: https://sumo.dlr.de/wiki/DUAROUTER
(accessed: 2019/04/27).
- SUMO SUMO（英語）, ドイツ航空宇宙センター: https://sumo.dlr.de/wiki/SUMO
(accessed: 2019/04/27).
- SUMO TraCI（英語）,ドイツ航空宇宙センター:  https://sumo.dlr.de/wiki/TraCI
(accessed: 2019/04/27).