📚 The CoCalc Library - books, templates and other resources
License: OTHER
import itertools12import numpy as np3import matplotlib.pyplot as plt45from Cell2D import Cell2D, Cell2DViewer6from scipy.signal import correlate2d789class SandPile(Cell2D):10"""Diffusion Cellular Automaton."""1112kernel = np.array([[0, 1, 0],13[1,-4, 1],14[0, 1, 0]], dtype=np.int32)1516def __init__(self, n, m=None, level=9):17"""Initializes the attributes.1819n: number of rows20m: number of columns21level: starting value for all cells22"""23m = n if m is None else m24self.array = np.ones((n, m), dtype=np.int32) * level25self.reset()2627def reset(self):28"""Start keeping track of the number of toppled cells.29"""30self.toppled_seq = []3132def step(self, K=3):33"""Executes one time step.3435returns: number of cells that toppled36"""37toppling = self.array > K38num_toppled = np.sum(toppling)39self.toppled_seq.append(num_toppled)4041c = correlate2d(toppling, self.kernel, mode='same')42self.array += c43return num_toppled4445def drop(self):46"""Increments a random cell."""47a = self.array48n, m = a.shape49index = np.random.randint(n), np.random.randint(m)50a[index] += 15152def run(self):53"""Runs until equilibrium.5455returns: duration, total number of topplings56"""57total = 058for i in itertools.count(1):59num_toppled = self.step()60total += num_toppled61if num_toppled == 0:62return i, total6364def drop_and_run(self):65"""Drops a random grain and runs to equilibrium.6667returns: duration, total_toppled68"""69self.drop()70duration, total_toppled = self.run()71return duration, total_toppled727374class SandPileViewer(Cell2DViewer):75cmap = plt.get_cmap('YlOrRd')76options = dict(interpolation='nearest', alpha=0.8,77vmin=0, vmax=5)7879def __init__(self, viewee, drop_flag=True):80"""Initializes the attributes.8182drop_flag: determines whether `step` drops a grain83"""84Cell2DViewer.__init__(self, viewee)85self.drop_flag = drop_flag8687def step(self):88"""Advances the viewee one step."""89if self.drop_flag:90self.viewee.drop_and_run()91else:92self.viewee.step()939495def single_source(pile, height=1024):96"""Adds a tower to the center cell.9798height: value assigned to the center cell99"""100a = pile.array101n, m = a.shape102a[:, :] = 0103a[n//2, m//2] = height104105106def main():107n = 101108pile = SandPile(n)109single_source(pile, height=2**14)110viewer = SandPileViewer(pile, drop_flag=False)111anim = viewer.animate(interval=0)112plt.subplots_adjust(left=0.01, right=0.99, bottom=0.01, top=0.99)113plt.show()114115116if __name__ == '__main__':117main()118119120