📚 The CoCalc Library - books, templates and other resources
License: OTHER
""" Code example from Complexity and Computation, a book about1exploring complexity science with Python. Available free from23http://greenteapress.com/complexity45Copyright 2011 Allen B. Downey.6Distributed under the GNU General Public License at gnu.org/licenses/gpl.html.7"""89import numpy10import scipy.ndimage1112import matplotlib13matplotlib.use('TkAgg')14import matplotlib.pyplot as pyplot1516import fractal171819def vfunc(con, rand, p=0.05, f=0.005):20"""Computes an update in the forest fire model.2122con: an element from the convolution array23rand: an element from a random array2425The output is 0 for an empty cell, 1 for a tree, and 10 for26a burning tree.27"""28# tree + neighbor on fire = burning29if con >= 110:30return 103132# no tree, check for a new tree33if con < 100:34if rand < p:35return 136else:37return 03839# otherwise, tree + no neighbor on fire, check spark40if rand < f:41return 1042else:43return 14445update_func = numpy.vectorize(vfunc, [numpy.int8])464748class Forest(object):49"""Implements the Bak-Chen-Tang forest fire model.5051n: the number of rows and columns52"""5354def __init__(self, n, mode='wrap'):55"""Attributes:56n: number of rows and columns57mode: how border conditions are handled58array: the numpy array that contains the data.59weights: the kernel used for convolution60"""61self.n = n62self.mode = mode63self.array = numpy.zeros((n, n), numpy.int8)64self.weights = numpy.array([[1,1,1],65[1,100,1],66[1,1,1]])6768def get_array(self, start=0, end=None):69"""Gets a slice of columns from the CA, with slice indices70(start, end). Avoid copying if possible.71"""72if start==0 and end==None:73return self.array74else:75return self.array[:, start:end]7677def loop(self, steps=1):78"""Executes the given number of time steps."""79[self.step() for i in xrange(steps)]8081def step(self):82"""Executes one time step."""83con = scipy.ndimage.filters.convolve(self.array,84self.weights,85mode=self.mode)86rand = numpy.random.rand(self.n, self.n)87self.array = update_func(con, rand)8889def count(self):90data = []91a = numpy.int8(self.array == 1)92for i in range(self.n):93total = numpy.sum(a[:i, :i])94data.append((i+1, total))95return zip(*data)969798class ForestViewer(object):99"""Generates an animated view of the forest."""100def __init__(self, forest, cmap=matplotlib.cm.gray_r):101self.forest = forest102self.cmap = cmap103104self.fig = pyplot.figure()105pyplot.axis([0, forest.n, 0, forest.n])106pyplot.xticks([])107pyplot.yticks([])108109self.pcolor = None110self.update()111112def update(self):113"""Updates the display with the state of the forest."""114if self.pcolor:115self.pcolor.remove()116117a = self.forest.array118self.pcolor = pyplot.pcolor(a, vmax=10, cmap=self.cmap)119self.fig.canvas.draw()120121def animate(self, steps=10):122"""Creates the GUI and then invokes animate_callback.123124Generates an animation with the given number of steps.125"""126self.steps = steps127self.fig.canvas.manager.window.after(1000, self.animate_callback)128pyplot.show()129130def animate_callback(self):131"""Runs the animation."""132for i in range(self.steps):133self.forest.step()134self.update()135136137def main(script, n=50, steps=50, *args):138139n = int(n)140steps = int(steps)141142forest = Forest(n)143144for i in range(steps):145forest.step()146xs, ys = forest.count()147148slope, inter = fractal.fit_loglog(xs, ys, n/4)149print i+1, slope150151fractal.plot_loglog(xs, ys)152153import CADrawer154drawer = CADrawer.EPSDrawer()155drawer.draw(forest)156drawer.save('forest.eps')157158if __name__ == '__main__':159import sys160161profile = False162if profile:163import cProfile164cProfile.run('main(*sys.argv)')165else:166main(*sys.argv)167168169