はじめに
今回はAgents.jlの森林火災の例題を見ていきます。セルオートマトンで森林火災の様子を離散的に表現しています。
▼URL
Agentの設定
using Agents, Random
using InteractiveDynamics
using CairoMakie
@agent Automata GridAgent{2} begin end
セルオートマトンはAgentを必要とせず、空間やモデルに焦点を当てます。今後モデルステップを実行するために、ここではダミーエージェントを定義しています。
モデルの定義
function forest_fire(; density = 0.7, griddims = (100, 100), seed = 2)
space = GridSpace(griddims; periodic = false, metric = :manhattan)
rng = Random.MersenneTwister(seed)
# Empty = 0, Green = 1, Burning = 2, Burnt = 3
forest = ABM(Automata, space; rng, properties = (trees = zeros(Int, griddims),))
for I in CartesianIndices(forest.trees)
# 左端の木のおよそ7割を火状態にする
if rand(forest.rng) < density
forest.trees[I] = I[1] == 1 ? 2 : 1
end
end
return forest
end
forest = forest_fire()
グリッド空間にtreesという2次元配列を作成します。それがグリッド空間のMapを表していて、0~3の4種類の数字がそれぞれの空間の状態を表しています。metric = :manhattan
は東西南北4方向を隣接している距離と見做すことを表しています。
※GridSpaceSingleは利用できなかったので、例題と異なりますがGridSpaceを利用しています。
ステップ関数
trees配列の各要素を更新していきます。
function tree_step!(forest)
# Find trees that are burning (coded as 2)
for I in findall(isequal(2), forest.trees)
for idx in nearby_positions(I.I, forest)
# If a neighbor is Green (1), set it on fire (2)
if forest.trees[idx...] == 1
forest.trees[idx...] = 2
end
end
# Finally, any burning tree is burnt out (2)
forest.trees[I] = 3
end
end
まずtrees配列から火状態の要素を探します。次にnearby_positions
メソッドを利用し、火状態の木の四方近隣に木があったら火状態に変更します。また、火状態の木を炎症後の状態にします。
ステップの実行
ステップを任意の数だけ実行し火状態の木をカウントします。
1step実行
Agents.step!(forest, dummystep, tree_step!, 1)
count(t == 3 for t in forest.trees)
-> 70
10step実行
Agents.step!(forest, dummystep, tree_step!, 10)
count(t == 3 for t in forest.trees)
-> 560
データの収集
火状態の木の割合を計測する関数を作成し、シミュレーションを実行します。その計測結果をdataframeに格納して表示します。
forest = forest_fire(griddims = (20, 20))
burnt_percentage(f) = count(t == 3 for t in f.trees) / prod(size(f.trees))
mdata = [burnt_percentage]
_, data = run!(forest, dummystep, tree_step!, 10; mdata)
data
画像を作成
各セルの値に応じて色をつけて出力します。
forest = forest_fire()
Agents.step!(forest, dummystep, tree_step!, 1)
plotkwargs = (
add_colorbar = false,
heatarray = :trees,
heatkwargs = (
colorrange = (0, 3),
colormap = cgrad([:white, :green, :red, :darkred]; categorical = true),
),
)
fig, _ = abmplot(forest; plotkwargs...)
fig
アニメーションを作成
forest = forest_fire(density = 0.7, seed = 10)
abmvideo(
"forest.gif",
forest,
dummystep,
tree_step!;
as = 0,
framerate = 5,
frames = 20,
spf = 5,
title = "Forest Fire",
plotkwargs...,
)
5x20step分のframeを作成してアニメーションを動画に保存します。
おわりに
セルオートマトンの森林火災をagents.jlで実装しました。空間の定義や火災が広がるロジックを定義して、視覚化する流れを理解できる例題だと思います。色々ロジックやパラメータを変えたりしてみてください。