森林火灾模拟

之前我们已经构建好了一些基础,但是还没有开始对火灾进行模拟。

随机生长

  • 在原来的基础上,我们要先让树生长,即定义 grow_trees() 方法
  • 定义方法之前,我们要先指定两个属性:
    • 每个位置随机生长出树木的概率
    • 每个位置随机被闪电击中的概率
  • 为了方便,我们定义一个辅助函数来生成随机 bool 矩阵,大小与森林大小一致
  • 按照给定的生长概率生成生长的位置,将 trees 中相应位置设为 True

In [1]:

  1. import numpy as np
  2.  
  3. class Forest(object):
  4. """ Forest can grow trees which eventually die."""
  5. def __init__(self, size=(150,150), p_sapling=0.0025, p_lightning=5.0e-6):
  6. self.size = size
  7. self.trees = np.zeros(self.size, dtype=bool)
  8. self.fires = np.zeros((self.size), dtype=bool)
  9. self.p_sapling = p_sapling
  10. self.p_lightning = p_lightning
  11.  
  12. def __repr__(self):
  13. my_repr = "{}(size={})".format(self.__class__.__name__, self.size)
  14. return my_repr
  15.  
  16. def __str__(self):
  17. return self.__class__.__name__
  18.  
  19. @property
  20. def num_cells(self):
  21. """Number of cells available for growing trees"""
  22. return np.prod(self.size)
  23.  
  24. @property
  25. def tree_fraction(self):
  26. """
  27. Fraction of trees
  28. """
  29. num_trees = self.trees.sum()
  30. return float(num_trees) / self.num_cells
  31.  
  32. @property
  33. def fire_fraction(self):
  34. """
  35. Fraction of fires
  36. """
  37. num_fires = self.fires.sum()
  38. return float(num_fires) / self.num_cells
  39.  
  40. def _rand_bool(self, p):
  41. """
  42. Random boolean distributed according to p, less than p will be True
  43. """
  44. return np.random.uniform(size=self.trees.shape) < p
  45.  
  46. def grow_trees(self):
  47. """
  48. Growing trees.
  49. """
  50. growth_sites = self._rand_bool(self.p_sapling)
  51. self.trees[growth_sites] = True

测试:

In [2]:

  1. forest = Forest()
  2. print forest.tree_fraction
  3.  
  4. forest.grow_trees()
  5. print forest.tree_fraction
  1. 0.0
  2. 0.00293333333333

火灾模拟

  • 定义 start_fires()
    • 按照给定的概率生成被闪电击中的位置
    • 如果闪电击中的位置有树,那么将其设为着火点
  • 定义 burn_trees()
    • 如果一棵树的上下左右有火,那么这棵树也会着火
  • 定义 advance_one_step()
    • 进行一次生长,起火,燃烧

In [3]:

  1. import numpy as np
  2.  
  3. class Forest(object):
  4. """ Forest can grow trees which eventually die."""
  5. def __init__(self, size=(150,150), p_sapling=0.0025, p_lightning=5.0e-6):
  6. self.size = size
  7. self.trees = np.zeros(self.size, dtype=bool)
  8. self.fires = np.zeros((self.size), dtype=bool)
  9. self.p_sapling = p_sapling
  10. self.p_lightning = p_lightning
  11.  
  12. def __repr__(self):
  13. my_repr = "{}(size={})".format(self.__class__.__name__, self.size)
  14. return my_repr
  15.  
  16. def __str__(self):
  17. return self.__class__.__name__
  18.  
  19. @property
  20. def num_cells(self):
  21. """Number of cells available for growing trees"""
  22. return np.prod(self.size)
  23.  
  24. @property
  25. def tree_fraction(self):
  26. """
  27. Fraction of trees
  28. """
  29. num_trees = self.trees.sum()
  30. return float(num_trees) / self.num_cells
  31.  
  32. @property
  33. def fire_fraction(self):
  34. """
  35. Fraction of fires
  36. """
  37. num_fires = self.fires.sum()
  38. return float(num_fires) / self.num_cells
  39.  
  40. def _rand_bool(self, p):
  41. """
  42. Random boolean distributed according to p, less than p will be True
  43. """
  44. return np.random.uniform(size=self.trees.shape) < p
  45.  
  46. def grow_trees(self):
  47. """
  48. Growing trees.
  49. """
  50. growth_sites = self._rand_bool(self.p_sapling)
  51. self.trees[growth_sites] = True
  52.  
  53. def start_fires(self):
  54. """
  55. Start of fire.
  56. """
  57. lightning_strikes = (self._rand_bool(self.p_lightning) &
  58. self.trees)
  59. self.fires[lightning_strikes] = True
  60.  
  61. def burn_trees(self):
  62. """
  63. Burn trees.
  64. """
  65. fires = np.zeros((self.size[0] + 2, self.size[1] + 2), dtype=bool)
  66. fires[1:-1, 1:-1] = self.fires
  67. north = fires[:-2, 1:-1]
  68. south = fires[2:, 1:-1]
  69. east = fires[1:-1, :-2]
  70. west = fires[1:-1, 2:]
  71. new_fires = (north | south | east | west) & self.trees
  72. self.trees[self.fires] = False
  73. self.fires = new_fires
  74.  
  75. def advance_one_step(self):
  76. """
  77. Advance one step
  78. """
  79. self.grow_trees()
  80. self.start_fires()
  81. self.burn_trees()

In [4]:

  1. forest = Forest()
  2.  
  3. for i in range(100):
  4. forest.advance_one_step()

使用 matshow() 显示树木图像:

In [5]:

  1. import matplotlib.pyplot as plt
  2. from matplotlib import cm
  3.  
  4. %matplotlib inline
  5.  
  6. plt.matshow(forest.trees, cmap=cm.Greens)
  7.  
  8. plt.show()

08.07 森林火灾模拟 - 图1

查看不同着火概率下的森林覆盖率趋势变化:

In [6]:

  1. forest = Forest()
  2. forest2 = Forest(p_lightning=5e-4)
  3.  
  4. tree_fractions = []
  5.  
  6. for i in range(2500):
  7. forest.advance_one_step()
  8. forest2.advance_one_step()
  9. tree_fractions.append((forest.tree_fraction, forest2.tree_fraction))
  10.  
  11. plt.plot(tree_fractions)
  12.  
  13. plt.show()

08.07 森林火灾模拟 - 图2

原文: https://nbviewer.jupyter.org/github/lijin-THU/notes-python/blob/master/08-object-oriented-programming/08.07-forest-fire-simulation.ipynb