Skip to content

浸水データをシミュレーションで使用する方法

Mitsuo Saito edited this page Oct 15, 2018 · 5 revisions

浸水のエージェントへの影響

CrowdWalk では津波や洪水による浸水の影響をシミュレーションに反映する事が出来ます。

capture000702

冠水したエージェントは水位によって以下の影響を受けます。

歩行速度

歩行速度 = 通常の歩行速度 × (歩行不可能になる水位 - 現在水位) / 歩行不可能になる水位

※ 歩行不可能になる水位 = 1.0m
※ 歩行速度の最小値は 0

生死状態

  • 水位が 1.0m に達するとエージェントは死亡してその位置に留まります。
  • 死亡したエージェントは「歩行中」としてカウントされます。

トリアージレベル

  • 医療用語の「トリアージ」を参考にしたCrowdWalk独自の用語です。
  • エージェントの危険性のレベルを色で表します。
  • グラフィックシミュレータではエージェントの表示色に反映されます。
  • 生存しているエージェントは水位の上昇・下降に応じた状態に変化します。(水位が下がればトリアージレベルも回復します)
トリアージレベル 水位 現実での人への影響
GREEN 30cm 未満 流速がかなり速い場合や歩行者が子供以外であれば、被害の発生はない。(※)
YELLOW 30cm ~ 歩くにはかなり困難であるが、大人であれば生命の危険性は少ない。(※)
RED 80cm ~ 流速が遅く、路面の状況が良い場合には歩行が可能ではあるが、人的被害発生の可能性は非常に高い。(※)
BLACK 1.0m 以上 道路歩行中の人は、ほぼ絶望である。(木など高いものに登るしかない)(※)

※引用元: 千葉県ホームページ / 浸水深のランク分け

パラメータの調整

フォールバックファイルの設定で以下のパラメータを変更する事が可能です。

    "obstructer" : {
        "Flood" : {
            "waterDepthThreshold3" : 1.0,   ←  トリアージレベル BLACK の下限水位(m)
            "waterDepthThreshold2" : 0.8,   ←  トリアージレベル RED の下限水位(m)
            "waterDepthThreshold1" : 0.3,   ←  トリアージレベル YELLOW の下限水位(m)
            "nonAmbulatoryDepth" : 1.0      ←  歩行不可能になる水位(m)
        },

ログ出力

浸水特有の情報が individual pedestrians ログに出力されます。

カラム名 内容
current_exposure 冠水の水位(m)
amount_exposure 同上
current_status_by_exposure トリアージレベル

※amount_exposure はプロパティファイルの設定で pollution_type を Pollution にした場合に累積暴露量として出力されます。


ポリューションファイルとマップファイルの準備

浸水データをシミュレーションに反映させるためには CrowdWalk で読み込める形式に変換する必要があります。この形式のファイルを「ポリューションファイル」と呼びます。
また、マップファイルには個々の浸水領域を示す Area 要素を追加します。

これらの処理をおこなうプログラムを CrowdWalk 利用者の側で用意する必要があります。

ポリューションファイルの形式

  • カンマ区切りのCSVファイルです。
  • 1カラム目は時刻(シミュレーション開始からの経過秒数)です。
  • 2カラム目以降はその時刻におけるエリア順の水位(m)です。エリアの順番はマップファイルの Area 要素のタグに記述され、番号(1から開始)または文字列です。
  • 行頭が # ならばコメントになります。
  • 1行目の行頭が # の場合はエリア順の指定として扱われます。そのカラムに該当するエリアのタグ文字列をカンマで区切って並べます。1カラム目は無視されます。

マップファイルの浸水エリア

  • ポリューションファイルで扱っているすべての浸水領域に対応する Area 要素が必要です。
  • 浸水領域は緯線・経線に沿った直線からなる長方形でなければなりません。
  • 追加先の Group はどこでも構いません。(ただしサブグループが存在する場合はルートグループには追加できません)

Area 要素の形式

    <Area angle="0.0" id="area1" maxHeight="5.0" minHeight="-5.0" pEastX="106290.0" pNorthY="-103100.0" pSouthY="-103090.0" pWestX="106280.0">
      <tag>1</tag>
    </Area>
  • angle, maxHeight, minHeight 属性は互換性のために残してあるだけで値は利用されません。
  • id 属性にはマップファイル内の全要素の id に対してユニークな文字列を指定します。
  • pEastX 属性には浸水エリアの東端座標を指定します。
  • pNorthY 属性には浸水エリアの北端座標を指定します。
  • pSouthY 属性には浸水エリアの南端座標を指定します。
  • pWestX 属性には浸水エリアの西端座標を指定します。
  • 座標はすべて CrowdWalk 座標系の値で指定します。
  • tag 要素にはポリューションファイルの浸水領域に対応するエリア番号または文字列を指定します。

データ変換プログラムの開発

以下に Ruby スクリプトをサンプルとして示します。

入力情報として浸水データファイルが存在するディレクトリとマップファイルのパス、オプションとして時刻に加えるオフセット値を受け取ります。
出力は浸水エリアが追加されたマップファイルとポリューションファイルです。

特徴として、浸水データの利用範囲をマップデータを囲む矩形内に限定しています。浸水エリアの数が多すぎるとメモリオーバーになってしまうためです。

require 'pathname'
require 'rexml/document'

# 徳島大学の津波データを CrowdWalk の pollution ファイルに変換する
#
# 入力ファイル
# ・津波データファイル
#     指定ディレクトリ内の /.*flow_depth_(\d+)s\.xyz/
#     書式: 平面直角座標系X座標<TAB>平面直角座標系Y座標<TAB>水位(m)
# ・CrowdWalk マップファイル
#
# 出力ファイル
# ・Area タグを埋め込んだマップファイル.xml
#       元のマップファイル名の末尾 -> '_flood.xml'
# ・pollutionデータ.csv
#       元のマップファイル名の末尾 -> '_flood.csv'

MESH_WIDTH = 10
MESH_HEIGHT = 10

# CrowdWalk のマップ領域に外接する矩形を返す
def get_boundary(map_filename)
  x_array = []
  y_array = []
  map = REXML::Document.new(open(map_filename))
  map.elements.each('Group') do |group|
    group.elements.each('Node') do |node|
      x_array << node.attributes['x'].to_f
      y_array << node.attributes['y'].to_f
    end
  end
  map.elements.each('Group/Group') do |group|
    group.elements.each('Node') do |node|
      x_array << node.attributes['x'].to_f
      y_array << node.attributes['y'].to_f
    end
  end
  x_array.map! {|x| x < 0.0 ? x.floor : x.ceil }
  y_array.map! {|y| y < 0.0 ? y.floor : y.ceil }
  return x_array.min, y_array.min, x_array.max, y_array.max
end

# 座標がマップ矩形内にあるか?
def contains_coordinate?(x, y)
   return (x >= @min_x and x <= @max_x and y >= @min_y and y <= @max_y)
end

# 津波データを読み込む
def read_tsunami_data(file_path)
  flood_base = {}
  File.open(file_path) {|file|
    file.each_line do |line|
      a, b, c = line.strip.split(/\s/)
      x = a.to_i
      y = -(b.to_i)
      next if c == 'NaN' or ! contains_coordinate?(x, y)
      height = c.to_f
      flood_base[x] ||= {}
      flood_base[x][y] = height
      @coordinates[x] ||= []
      @coordinates[x] << y unless @coordinates[x].include?(y)
    end
  }
  return flood_base
end

# Area タグを埋め込んだマップファイルを出力する
def save_area_added_map(map_filename, output_map_filename)
  File.open(output_map_filename, 'w') {|output_map_file|
    File.open(map_filename) {|map_file|
      area_tag_embedded = false
      map_file.each_line do |line|
        str = line.rstrip
        if ! area_tag_embedded and str.include?('</Group>')
          # Area タグを埋め込む
          index = 1
          @coordinates.each_pair do |x, y_array|
            y_array.each do |y|
              north = y - MESH_HEIGHT / 2.0
              south = y + MESH_HEIGHT / 2.0
              west = x - MESH_WIDTH / 2.0
              east = x + MESH_WIDTH / 2.0
              output_map_file.write <<_EOL_
    <Area angle="0.0" id="area#{index}" maxHeight="5.0" minHeight="-5.0" pEastX="#{east}" pNorthY="#{north}" pSouthY="#{south}" pWestX="#{west}">
      <tag>#{index}</tag>
    </Area>
_EOL_
              index += 1
            end
          end
          $stderr.puts "max index = #{index - 1}"
          area_tag_embedded = true
        end
        output_map_file.write str
        output_map_file.write "\n"
      end
    }
  }
end

# pollutionデータ.csv を出力する
def save_flood_data(flood_data_filename)
  File.open(flood_data_filename, 'w') {|file|
    @flood_base.each_pair do |elapsed_time, flood_base|
      file.write elapsed_time
      @coordinates.each_pair do |x, y_array|
        y_array.each do |y|
          file.write ','
          if flood_base.has_key?(x) and flood_base[x].has_key?(y)
            file.write flood_base[x][y]
          else
            file.write '0.0'
          end
        end
      end
      file.write "\n"
    end
  }
end

@data_dir = Pathname.new(ARGV[0])
@map_filename = ARGV[1]
@elapsed_time_offset = ARGV[2].to_i

@flood_base = {}        # { time: { x: { y: height } } }
@coordinates = {}
@output_map_filename = @map_filename.sub(/\.xml$/i, '_flood.xml')
@flood_data_filename = @map_filename.sub(/\.xml$/i, '_flood.csv')

@min_x, @min_y, @max_x, @max_y = get_boundary(@map_filename)
$stderr.puts "Networkmap boundary: (#{@min_x}, #{@min_y}) - (#{@max_x}, #{@max_y})"

Dir.glob(@data_dir + '*').each do |filename|
  if filename =~ /flow_depth_(\d+)s\.xyz/
    $stderr.puts "Read tsunami data file: #{filename}"
    elapsed_time = $1.to_i + @elapsed_time_offset
    if elapsed_time < 0
      $stderr.puts "    Skip this file."
      next
    end
    @flood_base[elapsed_time] = read_tsunami_data(filename)
    $stderr.puts "elapsed time: #{elapsed_time}s"
  end
end

save_area_added_map(@map_filename, @output_map_filename)
save_flood_data(@flood_data_filename)

上記スクリプトのファイル名を "tsunami_conv.rb" とした場合の使い方を示します。

書式: ruby tsunami_conv.rb <浸水データディレクトリ> <マップファイル> [時刻オフセット]

最初の浸水データファイルが "0010-30.flow_depth_02400s.xyz" ならば、時刻オフセットに -2400 を指定すればシミュレーション開始と同時(0 秒後)に浸水が発生するポリューションファイルが出力されます。

例)
    ruby tsunami_conv.rb data map.xml -2400

    出力ポリューションファイル -> map_flood.csv
    出力マップファイル -> map_flood.xml

なお CrowdWalk/floodtocrowdwalk ディレクトリには、荒川の氾濫データをポリューションファイルに変換する Ruby スクリプトがあります。


プロパティファイルの設定

以下の設定項目をプロパティファイルに加えるとシミュレーションに浸水が反映される様になります。

  "pollution_file": "flood.csv",            // ポリューションファイル
      "interpolation_interval": 10,         // この間隔(秒)で pollution データを線形補間する
      "pollution_type": "Flood",            // 浸水型
      "pollution_color_saturation": 5.0,    // 彩度100%に相当する pollution level (水位 5m 以上は完全な青)
      "pollution_color": "blue",            // 'hsv', 'red', 'blue', 'orange'

設定の仕方については CrowdWalk チュートリアルプロパティファイルの作成 / 設定項目 / 災害データに関する設定 を参照してください。

Clone this wiki locally