Source code for water_packer.distance_manager

"""Distance constraint management for water packing."""

from typing import Dict, Optional, Tuple


[docs] class DistanceManager: """ Manage species-specific minimum distances. Default distances are based on typical vdW radii sums, with values appropriate for MD simulations. """ # Default minimum distances based on vdW radii sums # These are contact distances, not equilibrium distances DEFAULT_DISTANCES: Dict[Tuple[str, str], float] = { # Water-water (inter-molecular) ('O', 'O'): 2.4, # O-O water-water relaxed to 2.4A per user request ('O', 'H'): 1.6, # O-H non-bonded ('H', 'H'): 1.5, # H-H non-bonded # Water with common substrate atoms ('O', 'Mg'): 2.0, # O-Mg (updated for realistic solvation) ('H', 'Mg'): 2.0, # H-Mg ('O', 'Ca'): 2.4, # O-Ca ('H', 'Ca'): 2.2, # H-Ca ('O', 'Si'): 2.6, # O-Si (silica) ('H', 'Si'): 2.2, # H-Si ('O', 'Al'): 2.4, # O-Al ('H', 'Al'): 2.0, # H-Al ('O', 'Fe'): 2.3, # O-Fe ('H', 'Fe'): 2.0, # H-Fe ('O', 'Na'): 2.3, # O-Na ('H', 'Na'): 2.0, # H-Na ('O', 'K'): 2.6, # O-K ('H', 'K'): 2.2, # H-K ('O', 'C'): 2.6, # O-C ('H', 'C'): 2.2, # H-C ('O', 'N'): 2.6, # O-N ('H', 'N'): 2.0, # H-N }
[docs] def __init__( self, default_distance: float = 2.0, pairwise_distances: Optional[Dict[Tuple[str, str], float]] = None, ): """ Initialize distance manager. Parameters ---------- default_distance : float Fallback minimum distance for pairs not in lookup tables. pairwise_distances : dict, optional User-specified distances that override defaults. Keys are (species1, species2) tuples (order doesn't matter). """ self.default_distance = default_distance self.user_distances = pairwise_distances or {}
def _normalize_pair(self, species1: str, species2: str) -> Tuple[str, str]: """Normalize species pair to canonical order (alphabetical).""" return tuple(sorted([species1, species2]))
[docs] def get_min_distance(self, species1: str, species2: str) -> float: """ Get minimum distance for a species pair. Priority: user-specified > defaults > fallback Parameters ---------- species1, species2 : str Element symbols. Returns ------- float Minimum allowed distance in Angstrom. """ pair = self._normalize_pair(species1, species2) # Check user overrides first if pair in self.user_distances: return self.user_distances[pair] # Also check reverse order in user distances reverse_pair = (pair[1], pair[0]) if reverse_pair in self.user_distances: return self.user_distances[reverse_pair] # Check defaults if pair in self.DEFAULT_DISTANCES: return self.DEFAULT_DISTANCES[pair] if reverse_pair in self.DEFAULT_DISTANCES: return self.DEFAULT_DISTANCES[reverse_pair] # Fallback return self.default_distance
[docs] def get_exclusion_radius(self, species: str) -> float: """ Get the half-distance exclusion radius for substrate atom. This is half the typical water-O to substrate distance, representing the substrate's "share" of the interface exclusion. Parameters ---------- species : str Element symbol of substrate atom. Returns ------- float Exclusion radius in Angstrom. """ # Use O-species distance as reference (O is the water center) full_distance = self.get_min_distance('O', species) return full_distance / 2.0