小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

[計算模擬]森林火災模擬.3:ABM建模流程以及模擬代碼解析

 godxiasad 2024-12-20 發(fā)布于北京

很長,反著你也不看,點個贊意思下就行

上一節(jié)我們介紹了元胞自動機的基礎知識,這一節(jié)我們就來看看agentpy是如何實現(xiàn)森林火災的模型的。大部分的流程與上一節(jié)的生命游戲是一樣的,只是有一些細節(jié)不太一樣。

建模過程:

ABM的建模過程如下所示:

大致上,也可以對應到元胞自動機的四大要素,但是為了不混淆,也為了不讓大家產生負面的學習遷移,所以我們這里直接用ABM的建模規(guī)則來進行說明。

agent結構

首先需要設計一個合理的agent結構,因為我們這里的模型非常簡單,也就是代表樹木的有三種狀態(tài),0代表存活的樹木,1代表燃燒中的樹木,2代表燒完了的白地。

環(huán)境結構

用于存儲環(huán)境狀態(tài)的數(shù)據(jù)結構,也就是元胞里面的空間網(wǎng)絡,ABM可以支持各種復雜類型的空間結構,包括三角網(wǎng)、矩形網(wǎng)、蜂窩網(wǎng)、網(wǎng)絡模型、多邊形區(qū)域等,但是我們這里的空間結構比較簡單,就是一個二維的網(wǎng)格,每個格網(wǎng)代表一個位置。這里與上一節(jié)生命游戲的空間網(wǎng)格定義方式是一樣的。
——說到空間這個東西,雖然是space,不是spatial,但是我們做GIS的就沒有怕過誰……任意不規(guī)則的地理建模對我們來說都是一盤菜而已,不過這里不用那么麻煩,用agentpy自帶的Grid就可以了。

個體的行為規(guī)則

abm里面的agent結構 + 個體行為規(guī)則,實際上就等于了元胞里面的狀態(tài)集合。也就是個體有幾種型態(tài)可以變化,生命游戲里面是兩種:0和1,代表死亡和存活。而森林火災的模型是三種:0代表樹木,1代表燃燒,2代表燒完了的白地。
與生命游戲不同,生命游戲的死亡和存活是可以相互轉換的,而森林火災的模型中,燃燒的樹木是不會恢復的,也就是說在這里的規(guī)則是單向的。

個體與環(huán)境的交互規(guī)則

這個是abm特有的核心,也是與元胞最大的不同,元胞的個體和空間是融為一體的,而abm的個體和空間是分開的,環(huán)境是個體的承載物,也是個體的行為約束,個體通過認知和因對認證之后的行為,來與環(huán)境進行交互。
森林火災的模型中,個體與環(huán)境的交互規(guī)則是:燒完之后,把代表環(huán)境的網(wǎng)格賦值為2.

環(huán)境的行動規(guī)則

    環(huán)境的行動規(guī)則指的是環(huán)境的狀態(tài)如何隨著時間的推移而變化。一般情況下,環(huán)境會和個體相互進行影響,不過我們這里沒有用到這個規(guī)則,直接略過。

個體與個體之間的互動規(guī)則

這個就是元胞里面的演化規(guī)則,只是可以更加詳細和復雜一些,元胞里面不考慮環(huán)境、個體的問題,二者是合一的,所以環(huán)境的變化就是個體的變化,而這里把個體與環(huán)境獨立開了,所以定義的就是個體與個體之間的影響。
另外,元胞里面,每個網(wǎng)格或者說細胞是沒有狀態(tài)的,隨生隨死,沒有記憶,沒有狀態(tài),但是在abm里面,個體本身是可以有狀態(tài)的,特別是在一些更復雜的模擬中,例如生態(tài)模型里面,捕食者可以通過交流,對獵物進行圍獵。
森林火災的模型中,個體與個體之間的互動規(guī)則就是:對于每棵正在燃燒的樹,檢查它的鄰居是否有樹可以燃燒,如果有的話,讓他燒起來。
題外話:簡單建模情況下,個體與個體之間互動,一般是依賴于環(huán)境約束的,也就是空間統(tǒng)計學里面的空間關系概念化,比如我們現(xiàn)在這個例子。
但是復雜情況下就另說了,因為個體與個體之間的聯(lián)系有可能不用通過環(huán)境,特別是真實仿真的情況下,例如設計了廣播機制。
以上六種要素就是abm建模的主要步驟,可以看出,元胞的四大要素,在abm里面都有對應的體現(xiàn)。
下面來看看代碼實現(xiàn):

import agentpy as ap

# 下面幾個包用于可視化
import matplotlib.pyplot as plt
import seaborn as sns
import IPython

# 解決繪圖中的中文亂碼問題
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
class ForestModel(ap.Model):
# 初始化設定,里面的具體參數(shù)都是通過外部傳遞進來的
def setup(self):
# 創(chuàng)建agent
# 根據(jù)給定的樹密度和網(wǎng)格大小計算出需要創(chuàng)建的樹的數(shù)量,并將結果轉換為整數(shù)
n_trees = int(self.p['Tree density'] * (self.p.size**2))
trees = self.agents = ap.AgentList(self, n_trees)

# 創(chuàng)建網(wǎng)格,也就是我們的森林,每個網(wǎng)格上可以有樹也可以沒有樹
self.forest = ap.Grid(self, [self.p.size]*2, track_empty=True)
# 將樹添加到森林中,其中樹的位置是隨機的,并且空的網(wǎng)格也會被樹占據(jù)
# 這一塊是與前面生命游戲中最大的不同,
# 生命游戲中沒有獨立agent,也可以看成所有的網(wǎng)格都是agent,
# 也就是運算單元與網(wǎng)格一一對應的
# 而在森林火災模型中,樹是agent,森林是網(wǎng)格,森林只是一個承載物
self.forest.add_agents(trees, random=True, empty=True)

# 初始將所有樹的初始狀態(tài)設置為 0,表示它們都是活著的
# 在本模型中,三種狀態(tài):0 表示樹是活著的,1 表示樹正在燃燒,2 表示樹已經(jīng)燃燒完畢
self.agents.condition = 0

# 選擇網(wǎng)格左側的兩列樹作為著火點的樹,它們將首先被點燃
# 選擇兩列的目的是防止第一列出現(xiàn)沒有樹木的情況,導致模擬無法進行
unfortunate_trees = self.forest.agents[0:self.p.size, 0:2]
unfortunate_trees.condition = 1

# 每個時間步長的具體操作,也就是模擬的每一步
def step(self):

# 選擇所有正在燃燒的樹
burning_trees = self.agents.select(self.agents.condition == 1)

# 對于每棵正在燃燒的樹,檢查它的鄰居是否有樹可以燃燒
for tree in burning_trees:
for neighbor in self.forest.neighbors(tree):
# 如果鄰居是樹,并且它還沒有燃燒,那么將它設置為正在燃燒的狀態(tài)
if neighbor.condition == 0:
neighbor.condition = 1
# 將正在燃燒的樹設置為已經(jīng)燃燒完畢的狀態(tài)
tree.condition = 2

# 停止條件:如果沒有樹正在燃燒,那么模擬就結束了
if len(burning_trees) == 0:
self.stop()

def end(self):
# 在模擬結束時,打印出已經(jīng)燃燒完畢的樹的數(shù)量和總樹的數(shù)量
burned_trees = len(self.agents.select(self.agents.condition == 2))
self.report('Percentage of burned trees',
burned_trees / len(self.agents))
# 定義各項參數(shù)

parameters = {
'Tree density': 0.4, # 定義森林的密度
'size': 50, # 定義森林的大小
'steps': 100, # 定義模擬的步數(shù)(每一步代表一個時間單位,如果沒有滿足條件,到達這個時間就會停止)
}
# 可視化的過程

def animation_plot(model, ax):
# 繪制森林的狀態(tài),定義不同樹木狀態(tài)下的顏色
attr_grid = model.forest.attr_grid('condition')
color_dict = {0:'#7FC97F', 1:'#d62c2c', 2:'#e5e5e5', None:'#d5e5d5'}
ap.gridplot(attr_grid, ax=ax, color_dict=color_dict, convert=True)
ax.set_title(f"森林火災模擬\n"
f"模擬步數(shù): {model.t}, 樹木存活數(shù)量: "
f"{len(model.agents.select(model.agents.condition == 0))}")

fig, ax = plt.subplots()
model = ForestModel(parameters)
# 生成動畫和html的控件
animation = ap.animate(model, fig, ax, animation_plot)
IPython.display.HTML(animation.to_jshtml(fps=15))
# 設置參數(shù)
parameters = {
# 森林的密度,設置為一個0.2到0.7之間的范圍
'Tree density': ap.Range(0.2, 0.7),
'size': 100
}
# 生成30組參數(shù)組合
sample = ap.Sample(parameters, n=30)
# 批處理運行,迭代運行40次,也就是整體會運行1200個模擬
exp = ap.Experiment(ForestModel, sample, iterations=40)
results = exp.run()
# 把執(zhí)行結果保存到文件中
results.save()
results = ap.DataDict.load('ForestModel')
# 繪制出森林燒毀的百分比的變化趨勢
sns.set_theme()
ax = sns.lineplot(
data=results.arrange_reporters(),
x='Tree density',
y='Percentage of burned trees'
)
fontdict = {'family': 'SimHei', 'size': 12}
ax.set_xlabel('森林密度', fontdict=fontdict)
ax.set_ylabel('森林燒毀的百分比', fontdict=fontdict)
我們手動設置幾個參數(shù)來運行一下,例如我先把森林的密度設置為0.4,森林的大小設置為50,模擬的步數(shù)設置為100,運行結果如下:
在密度為0.4的情況下,森林燒毀的百分比是474 / 950 * 100% = 49.89%
然后設置密度為0.6,大小和步數(shù)不變,運行結果如下:
在密度為0.6的情況下,森林燒毀的百分比是 3 / 1445 * 100% = 0.21%
幾乎燒光……
后面通過30組,每組40次的迭代,一共運行了1200次,得到了最終的結果:

發(fā)現(xiàn)只要密度超過50%,那么損毀的比例就接近100%。
可見,如果沒有外界因素干預的話,森林大火基本上是一發(fā)不可收拾的……
每次運行的結果可能不同,但是多次的運行結果是有一定的規(guī)律的,也就是森林的密度越大,森林燒毀的百分比越高,這是符合我們的預期的。
大家有興趣的可以自己嘗試一下。

記得用jupyter。

 




今日福利

——為了防止有同學上班的時候學習被領導看見……
所以福利見推文的第二條

    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多