Source code for deepfold.eval.cell_lists
from dataclasses import dataclass, field
from typing import Any, List, Optional
import numpy as np
[docs]
@dataclass
class Particle:
pos: np.ndarray = field(default=np.zeros(3))
sig: Optional[Any] = None
[docs]
class CellLists:
def __init__(
self,
box_size: np.ndarray,
num_particles: int,
cutoff_distance: float,
) -> None:
self.box_size = np.array(box_size)
self.cell_size = self.optimal_cell_size(self.box_size, num_particles, cutoff_distance)
self.cutoff_distance = cutoff_distance
self.num_cells = (self.box_size // self.cell_size).astype(int)
self.cells = [[] for _ in range(np.prod(self.num_cells))]
self.neighbor_offsets = self.calculate_neighbor_offsets()
[docs]
@staticmethod
def optimal_cell_size(box_size, num_particles, cutoff_distance):
# Estimate volume of simulation space
volume = np.prod(box_size)
# Estimate particle density
particle_density = num_particles / volume
# Estimate average particle spacing
avg_spacing = (1 / particle_density) ** (1 / 3) # Assuming 3D
# Choose cell size slightly larger than cutoff distance
cell_size = cutoff_distance * 1.1 # Adjust multiplier as needed
# Ensure cell size is smaller than average particle spacing
cell_size = np.minimum(cell_size, avg_spacing)
return cell_size
[docs]
def clear(self):
self.cells = [[] for _ in range(np.prod(self.num_cells))]
[docs]
def calculate_neighbor_offsets(self):
max_offset = int(np.ceil(self.cutoff_distance / np.min(self.cell_size)))
offsets = []
for dz in range(-max_offset, max_offset + 1):
for dy in range(-max_offset, max_offset + 1):
for dx in range(-max_offset, max_offset + 1):
offsets.append([dx, dy, dz])
return np.array(offsets)
[docs]
def get_index(self, pos: np.ndarray):
pos = pos - self.box_size
return tuple((pos // self.cell_size).astype(int) % self.num_cells)
[docs]
def add_particle(
self,
particle: Particle,
) -> None:
index = self.get_index(particle.pos)
self.cells[np.ravel_multi_index(index, self.num_cells)].append(particle)
[docs]
def get_neighbors(self, pos: np.ndarray) -> List[Particle]:
index = self.get_index(pos)
neighbor_indices = [tuple((index + offset) % self.num_cells) for offset in self.neighbor_offsets]
neighbors = []
for neighbor_index in neighbor_indices:
cell_particles = self.cells[np.ravel_multi_index(neighbor_index, self.num_cells)]
for particle in cell_particles:
separation_squared = np.sum((pos - particle.pos) ** 2)
if separation_squared <= self.cutoff_distance**2:
neighbors.append(particle)
return neighbors