Source code for packing_defect.core.grid

import numpy as np
import math
from packing_defect.core.cluster import DefectClustering

[docs] def cluster_sizes(self, leaflet): mask = self._binary_mask(leaflet) return DefectClustering.cluster_sizes_from_mask(mask)
# def _make_graph(matrix): # graph = {} # nx, ny = matrix.shape # for (i, j), val in np.ndenumerate(matrix): # if val == 0: # continue # idx = i * ny + j # neighbors = [] # for di in (-1, 0, 1): # for dj in (-1, 0, 1): # ni, nj = (i + di) % nx, (j + dj) % ny # if (di or dj) and matrix[ni, nj]: # neighbors.append(ni * ny + nj) # graph[idx] = set(neighbors) # return graph # def _dfs(graph, start): # visited, stack = set(), [start] # while stack: # v = stack.pop() # if v not in visited: # visited.add(v) # stack.extend(graph[v] - visited) # return visited
[docs] class DefectGrid: def __init__(self, box_xy, dx=1.0, dy=1.0, hz=None): self.dx = dx self.dy = dy self.Lx, self.Ly = box_xy self.hz = hz self.nx = int(np.ceil(self.Lx / self.dx)) self.ny = int(np.ceil(self.Ly / self.dy)) self.xbins = self.nx self.ybins = self.ny self.xx, self.yy = np.meshgrid( np.linspace(0, self.Lx, self.nx), np.linspace(0, self.Ly, self.ny), indexing='ij' ) self.grid = { 'up': np.zeros((self.nx, self.ny), dtype=int), 'dw': np.zeros((self.nx, self.ny), dtype=int) } self.zdepth = { 'up': np.full((self.nx, self.ny), -np.inf), 'dw': np.full((self.nx, self.ny), np.inf) }
[docs] def get_binary_mask(self, leaflet: str, threshold: int) -> np.ndarray: """ Return a binary mask where the defect grid matches the given threshold. """ return (self.grid[leaflet] == threshold).astype(int)
# def update(self, x, y, z, r, code, leaflet): # if leaflet not in ['up', 'dw']: # return # i = int(round(x / self.dx)) # j = int(round(y / self.dy)) # if 0 <= i < self.xbins and 0 <= j < self.ybins: # if leaflet == 'up': # if z > self.zdepth['up'][i, j]: # self.grid['up'][i, j] = code # self.zdepth['up'][i, j] = z # elif leaflet == 'dw': # if z < self.zdepth['dw'][i, j]: # self.grid['dw'][i, j] = code # self.zdepth['dw'][i, j] = z
[docs] def update(self, x, y, z, r, code, leaflet): # only up or dw matter if leaflet not in ('up','dw'): return r_eff = r + math.sqrt(self.dx**2 + self.dy**2)/2.0 i0 = int(round(x / self.dx)) j0 = int(round(y / self.dy)) max_bin = int(math.ceil(r_eff / self.dx)) for di in range(-max_bin, max_bin+1): ii = i0 + di if not (0 <= ii < self.xbins): continue x_c = (ii + 0.5) * self.dx for dj in range(-max_bin, max_bin+1): jj = j0 + dj if not (0 <= jj < self.ybins): continue y_c = (jj + 0.5) * self.dy if (x_c - x)**2 + (y_c - y)**2 > r_eff**2: continue if leaflet == 'up': if z > self.zdepth['up'][ii, jj]: self.zdepth['up'][ii, jj] = z self.grid ['up'][ii, jj] = code else: # leaflet == 'dw' if z < self.zdepth['dw'][ii, jj]: self.zdepth['dw'][ii, jj] = z self.grid ['dw'][ii, jj] = code
[docs] def get_coordinates(self, leaflet, code): mask = self.grid[leaflet] == code x_coords = self.xx[mask] y_coords = self.yy[mask] return x_coords, y_coords
def _binary_mask(self, leaflet): return self.grid[leaflet] # def detect_clusters(self, leaflet): # mask = self._binary_mask(leaflet) # graph = _make_graph(mask) # visited = set() # clusters = [] # for node in graph: # if node not in visited: # component = _dfs(graph, node) # clusters.append(component) # visited.update(component) # return clusters
[docs] def cluster_sizes(self, leaflet): return [len(c) for c in self.detect_clusters(leaflet)]