元胞自动机:森林火灾模拟(Matlab:heatmap、colormap)

目录

1.元胞自动机(Cellular Automation,CA)

2.森林火灾

3.伪代码

4.元胞自动机模拟森林火灾(Matlab实现)

(1)定义森林火灾函数

①空位生长树木 (0 --> 1)

②周围树木燃烧 (1-->-1)

③燃烧树木清除(-1-->0)

④雷电击中正常树木 (1-->-1)

(2)定义主函数

①遍历部分

②趋势曲线绘制部分

(3)执行命令

5.森林火灾动态仿真


1.元胞自动机(Cellular Automation,CA)

该部分详细内容请参考如下链接:

元胞自动机:森林火灾模拟(Python:numpy、seaborn)_Destiny坠明的博客-CSDN博客


2.森林火灾

该部分详细内容请参考如下链接:

元胞自动机:森林火灾模拟(Python:numpy、seaborn)_Destiny坠明的博客-CSDN博客


3.伪代码

该部分详细内容请参考如下链接:

元胞自动机:森林火灾模拟(Python:numpy、seaborn)_Destiny坠明的博客-CSDN博客


4.元胞自动机模拟森林火灾(Matlab实现)

(1)定义森林火灾函数

Forest_Fire函数如下,传入参数为:

(1)上一时刻的燃烧矩阵;

(2)空格位 树的生长概率p;

(3)正常位 树的燃烧概率f;

假定:空格位 --> 0 正常位 --> 1 燃烧位 --> -1

总量:空格位 --> C 正常位 --> G 燃烧位 --> R

输出参数为:规则演化后的燃烧矩阵;

该函数可分为4个操作部分:

function matrix=Forest_Fire(current_matrix,p,f)

    global area;
    
    matrix=current_matrix;
    
    % (1)空位生长树木 (0 --> 1)   储存位置
    i_C_indexes = [];
    j_C_indexes = [];

    for i = 1:1:area   % 行循环
        for j = 1:1:area   % 列循环
            if (matrix(i, j) == 0 & rand() -1)   储存位置,并存储上一时刻的燃烧数据
    fire_memory=find(matrix==-1);
    i_indexes=[];
    j_indexes=[];

    for i = 1:1:area   % 行循环
        for j = 1:1:area   % 列循环
            if (matrix(i,j)==-1)
                
                if((1<=i-1) & (i-1<=area) & (1<=j) & (j<= area))
                    if (matrix(i-1,j)==1)
                        i_indexes(end+1)=i-1;
                        j_indexes(end+1)=j;
                    end
                end
                
                if((1<=i+1) & (i+1<=area) & (1<=j) & (j<= area))
                    if (matrix(i+1,j)==1)
                        i_indexes(end+1)=i+1;
                        j_indexes(end+1)=j;
                    end
                end
                
                if((1<=i) & (i<=area) & (1<=j-1) & (j-1<= area))
                    if (matrix(i,j-1)==1)
                        i_indexes(end+1)=i;
                        j_indexes(end+1)=j-1;
                    end
                end

                if((1<=i) & (i<=area) & (1<=j+1) & (j+1<= area))
                    if (matrix(i,j+1)==1)
                        i_indexes(end+1)=i;
                        j_indexes(end+1)=j+1;
                    end
                end
            end
        end
    end
    
    for k = 1:1: length(i_indexes)
        matrix(i_indexes(k),j_indexes(k))=-1;
    end
    

    % (3)燃烧树木清除 (-1 --> 0)
    matrix(fire_memory)=0;

    
    % (4)雷电击中正常树木 (1 --> -1)    储存位置
    i_indexes = [];
    j_indexes = [];
    
    for i = 1:1:area   % 行循环
        for j = 1:1:area   % 列循环
            if matrix(i, j) == 1
                if(1<=i-1 & i-1<=area & 1<=j & j<= area)
                    if(matrix(i-1, j) == -1)
                        continue
                    end
                end
                
                if(1<=i+1 & i+1<=area & 1<=j & j<= area)
                    if(matrix(i+1, j) == -1)
                        continue
                    end
                end
                
                if(1<=i & i<=area & 1<=j-1 & j-1<= area)
                    if(matrix(i, j-1) == -1)
                        continue
                    end
                end
                
                if(1<=i & i<=area & 1<=j+1 & j+1<= area)
                    if(matrix(i, j+1) == -1)
                        continue
                    end
                end
            
                if rand()

 

area为全局变量。(森林的边长)

function matrix=Forest_Fire(current_matrix,p,f)

    global area;
    
    matrix=current_matrix;

全局变量声明规则:

如在主函数中,你要设置n为全局变量则需声明 global n;
然后在子函数里面你用到了n这个全局变量,则需在子函数中再次声明 global n;
这样在子函数中,就可以使用n这个全局变量了。

 


①空位生长树木 (0 --> 1)

    % (1)空位生长树木 (0 --> 1)   储存位置
    i_C_indexes = [];
    j_C_indexes = [];

    for i = 1:1:area   % 行循环
        for j = 1:1:area   % 列循环
            if (matrix(i, j) == 0 & rand()

        每当一个新的演化时间点到来时,首先要执行 空位生长树木 (0 --> 1) 的操作。若这一操作滞后,则会导致前一时刻燃烧的树木在这一时刻烧尽后重新生长为树木,故这一演化的优先级较高。并且需要将符合条件的坐标存储(而不是直接将矩阵元素更改),若不如此处理,则会导致中心灰烬点重焕生机后再次被周围的余火吞噬,无法达到 空位生长树木 (0 --> 1) 的效果。

        综上,该演化优先级最高并且需要储存符合要求的坐标位置。
 


②周围树木燃烧 (1-->-1)

    % (2)周围树木燃烧   (1 --> -1)   储存位置,并存储上一时刻的燃烧数据
    fire_memory=find(matrix==-1);
    i_indexes=[];
    j_indexes=[];

    for i = 1:1:area   % 行循环
        for j = 1:1:area   % 列循环
            if (matrix(i,j)==-1)
                
                if((1<=i-1) & (i-1<=area) & (1<=j) & (j<= area))
                    if (matrix(i-1,j)==1)
                        i_indexes(end+1)=i-1;
                        j_indexes(end+1)=j;
                    end
                end
                
                if((1<=i+1) & (i+1<=area) & (1<=j) & (j<= area))
                    if (matrix(i+1,j)==1)
                        i_indexes(end+1)=i+1;
                        j_indexes(end+1)=j;
                    end
                end
                
                if((1<=i) & (i<=area) & (1<=j-1) & (j-1<= area))
                    if (matrix(i,j-1)==1)
                        i_indexes(end+1)=i;
                        j_indexes(end+1)=j-1;
                    end
                end

                if((1<=i) & (i<=area) & (1<=j+1) & (j+1<= area))
                    if (matrix(i,j+1)==1)
                        i_indexes(end+1)=i;
                        j_indexes(end+1)=j+1;
                    end
                end
            end
        end
    end
    
    for k = 1:1: length(i_indexes)
        matrix(i_indexes(k),j_indexes(k))=-1;
    end

        在这一部分需要注意边界特殊情况导致的矩阵索引越界报错。

        存储上一时刻的燃烧数据 fire_memory 的目的是为了在之后的树木烧尽操作中区分出上一时刻燃烧的树木,避免与当前时刻新燃烧的树木产生混淆。

        储存符合条件坐标的原因是避免当前时刻新燃烧的树木引燃树木(这是一个很严重的bug),所以需要先存储所有坐标信息,再统一赋新值处理。
 

注意:Matlab在判断一个标量是否在一个区间内,要将两个边界的条件拆开写!


③燃烧树木清除(-1-->0)

    % (3)燃烧树木清除 (-1 --> 0)
    matrix(fire_memory)=0;

        直接将上一操作存储的燃烧数据坐标 fire_memory 对应位置的元素归零,实现燃烧树木清除 (-1 --> 0)效果。

注:fire_memory存储的是一个向量(而非矩阵),

每一个数值标量对应着一个索引(Matlab的存储结构特性)。


④雷电击中正常树木 (1-->-1)

    % (4)雷电击中正常树木 (1 --> -1)    储存位置
    i_indexes = [];
    j_indexes = [];
    
    for i = 1:1:area   % 行循环
        for j = 1:1:area   % 列循环
            if matrix(i, j) == 1
                if(1<=i-1 & i-1<=area & 1<=j & j<= area)
                    if(matrix(i-1, j) == -1)
                        continue
                    end
                end
                
                if(1<=i+1 & i+1<=area & 1<=j & j<= area)
                    if(matrix(i+1, j) == -1)
                        continue
                    end
                end
                
                if(1<=i & i<=area & 1<=j-1 & j-1<= area)
                    if(matrix(i, j-1) == -1)
                        continue
                    end
                end
                
                if(1<=i & i<=area & 1<=j+1 & j+1<= area)
                    if(matrix(i, j+1) == -1)
                        continue
                    end
                end
            
                if rand()

        这一部分的算法实现过程与操作2类似,不再赘述。


    % 完成空位生长树木的操作
    for k = 1:1: length(i_C_indexes)
        matrix(i_C_indexes(k),j_C_indexes(k))=1;
    end

        函数的最后完成第一步 空位生长树木 (0 --> 1) 的操作,最终返回一个矩阵(二维数组)。


(2)定义主函数

main函数如下,传入参数为:

(1)森林边长area;

(2)演替次数N;

(3)空格位 树的生长概率p;

(4)正常位 树的燃烧概率f;

输出参数为:最终的燃烧矩阵;

该函数可分为2个操作部分:

function matrix=main(area,N,p,f)
    C_count=[];
    G_count=[];
    R_count=[];
    
    map = [239/255,29/255,31/255;
            165/255,165/255,165/255;
            28/255,172/255,76/255];
    
    matrix=ones(area,area);
    
    for time=1:1:N
        matrix=Forest_Fire(matrix,p,f);
        
        C_count(end+1)=length(find(matrix==0));
        G_count(end+1)=length(find(matrix==1));
        R_count(end+1)=length(find(matrix==-1));
    
   
        hfig=figure(1);
        set(hfig, 'position', get(0,'ScreenSize'));
        h=heatmap(matrix);
        colormap(map);
        %h.CellLabelFormat = '%d';
        %h.Title = 'Forest Fire';
        %h.XLabel = 'X';
        %h.YLabel = 'Y';
        h.CellLabelColor = 'none';

    end
    
        
    T=1:1:N;
    hfig=figure(2);
    set(hfig, 'position', get(0,'ScreenSize'));
    hold on;
    plot(T,C_count,'LineWidth',2,'Color',[165/255,165/255,165/255]);
    plot(T,G_count,'LineWidth',2,'Color',[28/255,172/255,76/255]);
    plot(T,R_count,'LineWidth',2,'Color',[239/255,29/255,31/255]);
    
    grid on;
    
    legend('Vacancy','Trees','Burning');
    
    hold off;
    

 

热力图自定义颜色:

map= [239/255,29/255,31/255;
           165/255,165/255,165/255;
           28/255,172/255,76/255
];

colormap(map);

function matrix=main(area,N,p,f)
    C_count=[];
    G_count=[];
    R_count=[];
    
    map = [239/255,29/255,31/255;
            165/255,165/255,165/255;
            28/255,172/255,76/255];

    matrix=ones(area,area);


①遍历部分

    for time=1:1:N
        matrix=Forest_Fire(matrix,p,f);
        
        C_count(end+1)=length(find(matrix==0));
        G_count(end+1)=length(find(matrix==1));
        R_count(end+1)=length(find(matrix==-1));
    
        hfig=figure(1);
        set(hfig, 'position', get(0,'ScreenSize'));
        h=heatmap(matrix);
        colormap(map);
        %h.CellLabelFormat = '%d';
        %h.Title = 'Forest Fire';
        %h.XLabel = 'X';
        %h.YLabel = 'Y';
        h.CellLabelColor = 'none';

    end

调整figure尺寸(铺满屏幕)

hfig=figure(1);
set(hfig, 'position', get(0,'ScreenSize'));


②趋势曲线绘制部分

    T=1:1:N;
    hfig=figure(2);
    set(hfig, 'position', get(0,'ScreenSize'));
    hold on;
    plot(T,C_count,'LineWidth',2,'Color',[165/255,165/255,165/255]);
    plot(T,G_count,'LineWidth',2,'Color',[28/255,172/255,76/255]);
    plot(T,R_count,'LineWidth',2,'Color',[239/255,29/255,31/255]);
    
    grid on;
    
    legend('Vacancy','Trees','Burning');
    
    hold off;

        这一段代码负责绘制出树木三种状态的数量变化趋势图。

元胞自动机:森林火灾模拟(Matlab:heatmap、colormap)_第1张图片

 


(3)执行命令

global area;
area=100;

final_matrix=main(area,100,0.25,0.01);


% figure(2);
% 
% h=heatmap(final_matrix);
% 
% h.CellLabelFormat = '%d';
% h.Title = 'Forest Fire';
% h.XLabel = 'X';
% h.YLabel = 'Y';
% 
% %h.CellLabelColor = 'none';
% 
% map = [239/255,29/255,31/255;
%     165/255,165/255,165/255;
%     28/255,172/255,76/255];
% 
% colormap(map)

 


5.森林火灾动态仿真

Matlab森林火灾仿真

你可能感兴趣的:(北师大,数学模型,算法,matlab)