diff --git a/src/fire2a/adjacency.py b/src/fire2a/adjacency.py deleted file mode 100644 index d643cb0..0000000 --- a/src/fire2a/adjacency.py +++ /dev/null @@ -1,120 +0,0 @@ -#!python3 -"""👋🌎 🌲🔥 -This is the raster module docstring -""" -__author__ = "Rodrigo Mahaluf Recasens" -__revision__ = "$Format:%H$" - -from scipy.sparse import lil_matrix - - -def adjacent_cells(grid: lil_matrix, connectivity: int = 4) -> list: - """ - Get adjacent cells for each cell in a grid. - - Parameters: - grid (lil_matrix): Sparse matrix representing a landscape. - connectivity (int, optional): The type of connectivity (4 or 8). Defaults to 4. - - Returns: - list: List of lists containing neighbors for each cell. - """ # fmt: skip - if connectivity == 4: - adj_cells = adjacent_cells4(grid) - elif connectivity == 8: - adj_cells = adjacent_cells8(grid) - else: - raise ValueError("Invalid connectivity value. Use 4 or 8.") - - return adj_cells - - -def adjacent_cells4(grid: lil_matrix) -> list: - """ - Get 4-connected adjacent cells for each cell in the forest grid. - - Parameters: - grid (lil_matrix): Sparse matrix representing a landscape. - - Returns: - list: List of lists containing 4-connected neighbors for each cell. - """ # fmt: skip - nrows, ncols = grid.shape - AdjCells = [] - - for i in range(nrows): - for j in range(ncols): - neighbors = [] - - if i > 0: - neighbors.append(grid[i - 1, j]) # Up - - if i < nrows - 1: - neighbors.append(grid[i + 1, j]) # Down - - if j > 0: - neighbors.append(grid[i, j - 1]) # Left - - if j < ncols - 1: - neighbors.append(grid[i, j + 1]) # Right - - AdjCells.append(neighbors) - return AdjCells - - -def adjacent_cells8(grid: lil_matrix) -> list: - """ - Get 8-connected adjacent cells for each cell in the forest grid. - - Parameters: - grid (lil_matrix): Sparse matrix representing a landscape. - - Returns: - list: List of lists containing 8-connected neighbors for each cell. - """ # fmt: skip - nrows, ncols = grid.shape - AdjCells = [] - - for i in range(nrows): - for j in range(ncols): - neighbors = [] - - for x in range(max(0, i - 1), min(nrows, i + 2)): - for y in range(max(0, j - 1), min(ncols, j + 2)): - if x != i or y != j: - neighbors.append(grid[x, y]) - - AdjCells.append(neighbors) - return AdjCells - - -if __name__ == "__main__": - - # Create a sparse forest grid (5x5) with random values - nrows = 5 - ncols = 5 - ncells = nrows * ncols - id_pixel = list(range(1, ncells + 1)) - - # Create a sparse forest grid from the id_pixel list - grid = lil_matrix((nrows, ncols), dtype=int) - for idx, value in enumerate(id_pixel): - row = idx // ncols - col = idx % ncols - grid[row, col] = value - - print("grid:") - for row in grid.toarray(): - print(row) - - # Call the adjacent_cells function to get 4-connected neighbors - adj_cells_4 = adjacent_cells(grid, connectivity=4) - print("\n4-Connected Neighbors:") - for row in adj_cells_4: - print(row) - - # Call the adjacent_cells function to get 8-connected neighbors - adj_cells_8 = adjacent_cells(grid, connectivity=8) - print("\n8-Connected Neighbors:") - for row in adj_cells_8: - print(row) diff --git a/src/fire2a/cell2fire/__init__.py b/src/fire2a/cell2fire/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/fire2a/cell2fire/burn_probability.py b/src/fire2a/cell2fire/burn_probability.py new file mode 100644 index 0000000..e69de29 diff --git a/src/fire2a/cell2fire.py b/src/fire2a/cell2fire/cell2fire.py similarity index 100% rename from src/fire2a/cell2fire.py rename to src/fire2a/cell2fire/cell2fire.py diff --git a/src/fire2a/downstream_protection_value.py b/src/fire2a/cell2fire/downstream_protection_value.py similarity index 100% rename from src/fire2a/downstream_protection_value.py rename to src/fire2a/cell2fire/downstream_protection_value.py diff --git a/src/fire2a/c2f_lookup_table_colors.py b/src/fire2a/cell2fire/parse_lookup_table_colors.py similarity index 100% rename from src/fire2a/c2f_lookup_table_colors.py rename to src/fire2a/cell2fire/parse_lookup_table_colors.py diff --git a/src/fire2a/cell2fire/raster_layer_to_firebreaks_cell_ids.py b/src/fire2a/cell2fire/raster_layer_to_firebreaks_cell_ids.py new file mode 100644 index 0000000..e69de29 diff --git a/src/fire2a/cell2fire/spatial_statistics.py b/src/fire2a/cell2fire/spatial_statistics.py new file mode 100644 index 0000000..e69de29 diff --git a/src/fire2a/clustering.py b/src/fire2a/clustering.py deleted file mode 100644 index e348028..0000000 --- a/src/fire2a/clustering.py +++ /dev/null @@ -1,100 +0,0 @@ -#!python3 -"""👋🌎 🌲🔥 -This is the raster module docstring -""" -__author__ = "Rodrigo Mahaluf-Recasens" -__revision__ = "$Format:%H$" - -import numpy as np -from scipy.sparse import dok_matrix, lil_matrix -from sklearn.cluster import AgglomerativeClustering -from typing import Union - -from .adjacency import adjacent_cells - - -def raster_clusters( - stacked_rasters: np.ndarray, - cellsize: float, - min_surface: float, - max_surface: float, - distance_threshold: float = 50.0, - total_clusters: Union[int, None] = None, - connectivity: Union[int, None] = None, -) -> np.ndarray: - """ - This function receives as arguments: - 1. An array with the raster paths, e.g. raster_paths=[elevation_path,fuel_path,slope_path,...] - You can provide as many as you want, just make sure all the raster layers are numerically defined, - even if there are cathegorical variables, you can not use string, transform them into a numerical raster. - - 2. total_clusters: number of clusters defined by the user. - - 3. min_surface: minimum area to consider into the cells aggregation process. - - 4. min_surface: maximum area to condsider into the cells aggregation process. - """ # fmt: skip - if min_surface >= max_surface: - raise ValueError("min_surface must be less than max_surface.") - - else: - _, nrows, ncols = stacked_rasters.shape - ncells = nrows * ncols - cell_area = cellsize**2 - connectivity = connectivity if connectivity else 4 - assert connectivity == 4 or connectivity == 8, "Connectivity mut be either 4 or 8" - - flattened_data = stacked_rasters.T.reshape(-1, stacked_rasters.shape[0]) # validado - - id_pixel = list(range(1, ncells + 1)) # to set and id to every cell - - grid = lil_matrix((nrows, ncols), dtype=int) - for idx, value in enumerate(id_pixel): - row = idx // ncols - col = idx % ncols - grid[row, col] = value - - forest_grid_adjCells = adjacent_cells(grid, connectivity=connectivity) - - dict_forest_grid_adjCells = dict( - zip(id_pixel, forest_grid_adjCells) - ) # A dictionary of adjacents cells per id cell - - adjacency_matrix = dok_matrix((ncells, ncells)) # Create an empty matrix to save binaries adjacencies - - ## Iterate over the dictionary items and update the adjacency matrix with 1 when a cell is adjacent, 0 when is not. - for key, values in dict_forest_grid_adjCells.items(): - for value in values: - adjacency_matrix[key - 1, value - 1] = 1 - - # Create an instance for the Agglomerative Clustering Algorithm with connectivity from the adjacency matrix - clustering = AgglomerativeClustering( - n_clusters=total_clusters, connectivity=adjacency_matrix, distance_threshold=distance_threshold - ) - - # Apply the algorithm over the whole data - clustering.fit(flattened_data) - # Reshape the cluster assignments to match the original raster shape - cluster_raster = clustering.labels_.reshape((nrows, ncols)) - - counts = np.bincount(cluster_raster.flatten()) - - # Assuming square cells - min_elements = min_surface / (cell_area) - max_elements = max_surface / (cell_area) - - # Apply minimum and maximum surface filtering - smaller_clusters = np.where(counts < min_elements)[0] - larger_clusters = np.where(counts > max_elements)[0] - - for cluster in smaller_clusters: - indices = np.where(cluster_raster == cluster) - cluster_raster[indices] = -1 - - for cluster in larger_clusters: - indices = np.where(cluster_raster == cluster) - cluster_raster[indices] = -1 - - cluster_raster = cluster_raster.astype(np.int16) - - return cluster_raster