def topple_dissipate(self): """ Forest burning and turning into ash. :param p: probability of a new tree growh per empty cell, must be smaller than p :type p: float """ #Displacement from a cell to its nearest neighbours # self.new_values[...] = self.values # A to T with small probability ash_here = self.values == _ash probabilities = np.random.random(size=(self.L_with_boundary, self.L_with_boundary)) trees_grow_here = probabilities <= self.p self.new_values[common.clean_boundary_inplace( trees_grow_here & ash_here, self.BC)] = _tree # Trees start burning: T -> B self.new_values[self.values == _tree] = _tree burn_trees(self.new_values, self.values, self.f, self.BC) # B to A burning_here = self.values == _burning self.new_values[common.clean_boundary_inplace(burning_here, self.BC)] = _ash self.values, self.new_values = self.new_values, self.values self.new_values[...] = 0 number_burning = (self.values[self.BC:-self.BC, self.BC:-self.BC] == _burning).sum() return number_burning
def topple_dissipate(self) -> int: """ Forest burning and turning into ash. """ #Displacement from a cell to its nearest neighbours # self.new_values[...] = self.values # A to T with small probability ash_here = self.values == _ash probabilities = np.random.random(size=(self.L_with_boundary, self.L_with_boundary)) trees_grow_here = probabilities <= self.p self.new_values[common.clean_boundary_inplace( trees_grow_here & ash_here, self.BC)] = _tree # Trees start burning: T -> B self.new_values[self.values == _tree] = _tree burn_trees(self.new_values, self.values, self.f, self.BC) # B to A burning_here = self.values == _burning self.new_values[common.clean_boundary_inplace(burning_here, self.BC)] = _ash self.values, self.new_values = self.new_values, self.values self.new_values[...] = 0 number_burning = (self.inside(self.values) == _burning).sum() return number_burning
def topple(values: np.ndarray, visited: np.ndarray, releases: np.ndarray, critical_value_current: float, critical_value: float, conservation_lvl: float, boundary_size: int) -> int: """ Distribute material from overloaded sites to neighbors. Returns True/False: should we continue checking if something needs toppling? :param values: data array of the simulation :type values: np.ndarray :param visited: boolean array, needs to be cleaned beforehand :type visited: np.ndarray :param critical_value: nodes topple above this value :type critical_value: float # 0.25 -> full force distributed :param conservation_lvl: 0.25 by default - fraction of the force from a toppling site going to its neighbour :type conservation_lvl: float :param boundary_size: size of boundary for the array :type boundary_size: int :rtype: int """ # find a boolean array of active (overloaded) sites active_sites = common.clean_boundary_inplace( values >= critical_value_current, boundary_size) number_of_iterations = 0 while active_sites.any(): releases += active_sites indices = np.vstack(np.where(active_sites)).T # a Nx2 array of integer indices for overloaded sites N = indices.shape[0] for i in range(N): x, y = index = indices[i] if _DEBUG: width, height = values.shape assert boundary_size <= x < width assert boundary_size <= y < width neighbors = index + np.array([[0, 1], [-1, 0], [1, 0], [0, -1]]) # TODO crack model nie wraca do sąsiadów, którzy już releasowali energię for j in range(len(neighbors)): xn, yn = neighbors[j] values[xn, yn] += conservation_lvl * ( values[x, y] - critical_value_current + critical_value ) # Grassberger (1994), eqns (1) visited[xn, yn] = True values[ x, y] = critical_value_current - critical_value # Grassberger (1994), eqns (1) active_sites = common.clean_boundary_inplace( values >= critical_value_current, boundary_size) number_of_iterations += 1 return number_of_iterations
def topple(values: np.ndarray, visited: np.ndarray, releases: np.ndarray, critical_value: int, boundary_size: int) -> int: """ Distribute material from overloaded sites to neighbors. Returns True/False: should we continue checking if something needs toppling? :param values: data array of the simulation :type values: np.ndarray :param visited: boolean array, needs to be cleaned beforehand :type visited: np.ndarray :param releases: boolean array, used to evalute number of sandpiles activations :type releases: np.ndarray :param critical_value: nodes topple above this value :type critical_value: int :param boundary_size: size of boundary for the array :type boundary_size: int :rtype: int """ # find a boolean array of active (overloaded) sites number_of_iterations = 0 active_sites = common.clean_boundary_inplace(values > critical_value, boundary_size) while active_sites.any(): releases += active_sites indices = np.vstack(np.where(active_sites)).T # a Nx2 array of integer indices for overloaded sites N = indices.shape[0] for i in range(N): x, y = indices[i] values[x, y] -= critical_value + 1 neighbors = np.array([(x - 1, y), (x, y - 1), (x + 1, y), (x, y + 1)]) # TODO try moving update: here visited[x, y] = True for j in range(len(neighbors)): xn, yn = neighbors[j] values[xn, yn] += 1 visited[xn, yn] = True number_of_iterations += 1 active_sites = common.clean_boundary_inplace(values > critical_value, boundary_size) return number_of_iterations
def __init__(self, p: float = 0.05, f: float = 0, *args, **kwargs): super().__init__(*args, **kwargs) shape = (self.L_with_boundary, self.L_with_boundary) self.values = common.clean_boundary_inplace( np.random.choice([_ash, _tree, _burning], shape, p=[0.99, 0.01, 0]), self.BC) self.new_values = np.zeros_like(self.values) self.p = p self.f = f
def topple(values: np.ndarray, visited: np.ndarray, critical_value: int, boundary_size: int) -> bool: """ Distribute material from overloaded sites to neighbors. Returns True/False: should we continue checking if something needs toppling? :param values: data array of the simulation :type values: np.ndarray :param visited: boolean array, needs to be cleaned beforehand :type visited: np.ndarray :param critical_value: nodes topple above this value :type critical_value: int :param boundary_size: size of boundary for the array :type boundary_size: int :rtype: bool """ # find a boolean array of active (overloaded) sites active_sites = common.clean_boundary_inplace(values > critical_value, boundary_size) if active_sites.any(): indices = np.vstack(np.where(active_sites)).T # a Nx2 array of integer indices for overloaded sites N = indices.shape[0] for i in range(N): x, y = index = indices[i] if _DEBUG: width, height = values.shape assert boundary_size <= x < width assert boundary_size <= y < width assert values[x, y] >= 0 values[x, y] -= 2 # randomly and independently pick two neighbors of the current site neighbors = index + np.random.choice( np.array((-1, 1)), # ugly but numba broke otherwise size=(2, 2)) for j in range(2): xn, yn = neighbors[j] values[xn, yn] += 1 visited[xn, yn] = True return True else: return False # nothing happened, we can stop toppling
def __init__(self, p=0.05, f: float = 0, *args, **kwargs): """ :param f: probability of thunder setting a tree on fire; set 0 to disable lighting """ super().__init__(*args, **kwargs) self.values = np.zeros((self.L_with_boundary, self.L_with_boundary), dtype=int) # probabilities = np.random.random(size=(self.L, self.L)) # trees_here = probabilities <= p # self.values[self.BC:self.L_with_boundary - self.BC, # self.BC:self.L_with_boundary - self.BC, # ][trees_here] = _tree self.values = common.clean_boundary_inplace( np.random.choice([_ash, _tree, _burning], self.values.shape, p=[0.99, 0.01, 0]), self.BC) self.new_values = np.zeros_like(self.values) self.p = p self.f = f
def topple_dissipate(values: np.ndarray, visited: np.ndarray, critical_value: int, abelian: bool, boundary_size: int) -> int: """ Distribute material from overloaded sites to neighbors. Returns True/False: should we continue checking if something needs toppling? :param values: data array of the simulation :type values: np.ndarray :param visited: boolean array, needs to be cleaned beforehand :type visited: np.ndarray :param critical_value: nodes topple above this value :type critical_value: int :param abelian: True by default - abelian, False - nonabelian :type abelian: bool :param boundary_size: size of boundary for the array :type boundary_size: int :return: Number of steps it took stuff to topple :rtype: int """ number_of_topple_iterations = 0 # find a boolean array of active (overloaded) sites active_sites = common.clean_boundary_inplace( values > critical_value, boundary_size) # TODO speedup? # odrzucam while active_sites.any(): # TODO speedup? indices = np.vstack(np.where(active_sites)).T # TODO speedup? # a Nx2 array of integer indices for overloaded sites N = indices.shape[0] for i in range(N): x, y = index = indices[i] if _DEBUG: width, height = values.shape assert boundary_size <= x < width assert boundary_size <= y < width assert values[x, y] >= 0 if abelian: n_to_distribute = 2 # number of particles to distribute from the active site values[x, y] -= n_to_distribute else: n_to_distribute = values[x, y] values[x, y] = 0 # randomly and independently pick neighbors of the current site neighbors = index + np.random.choice( np.array((-1, 1)), # ugly but numba broke otherwise size=(n_to_distribute, 2)) # TODO speedup? # to byśmy podmieniali gdybyśmy zmieniali model najbliższych sąsiadów for j in range(len(neighbors)): xn, yn = neighbors[j] values[xn, yn] += 1 visited[xn, yn] = True number_of_topple_iterations += 1 active_sites = common.clean_boundary_inplace(values > critical_value, boundary_size) # dissipate would be here, after the while loop # but it's not necessary so we skip it return number_of_topple_iterations