Source code for molr.selection.engine

"""
Selection engine for evaluating selection expressions.

This module provides the main interface for atom selection, integrating
the expression system and parser to provide a simple API for structure
selection operations.
"""

from typing import Dict, List, Optional, Union

import numpy as np

from ..core.structure import Structure
from .expressions import SelectionExpression
from .parser import SelectionParser


[docs] class SelectionEngine: """ Engine for evaluating atom selections on structures. Provides caching and optimization for repeated selections. """
[docs] def __init__(self, cache_size: int = 100): """ Initialize selection engine. Args: cache_size: Maximum number of cached selections """ self.parser = SelectionParser() self.cache: Dict[str, SelectionExpression] = {} self.cache_size = cache_size
[docs] def select( self, structure: Structure, selection: Union[str, SelectionExpression] ) -> np.ndarray: """ Select atoms from a structure. Args: structure: The structure to select from selection: Selection string or expression Returns: Boolean array indicating selected atoms Raises: ParseException: If selection string is invalid """ if isinstance(selection, str): # Parse string to expression expr = self._get_or_parse(selection) else: expr = selection # Evaluate expression return expr.evaluate(structure)
[docs] def select_atoms( self, structure: Structure, selection: Union[str, SelectionExpression] ) -> Structure: """ Return a new Structure containing only selected atoms. Args: structure: The structure to select from selection: Selection string or expression Returns: New Structure with selected atoms """ mask = self.select(structure, selection) return structure[mask]
[docs] def count( self, structure: Structure, selection: Union[str, SelectionExpression] ) -> int: """ Count atoms matching selection. Args: structure: The structure to select from selection: Selection string or expression Returns: Number of selected atoms """ mask = self.select(structure, selection) return int(np.sum(mask))
[docs] def get_indices( self, structure: Structure, selection: Union[str, SelectionExpression] ) -> np.ndarray: """ Get indices of atoms matching selection. Args: structure: The structure to select from selection: Selection string or expression Returns: Array of atom indices """ mask = self.select(structure, selection) return np.where(mask)[0] # type: ignore[no-any-return]
def _get_or_parse(self, selection_string: str) -> SelectionExpression: """ Get expression from cache or parse it. Args: selection_string: Selection string to parse Returns: Parsed SelectionExpression """ if selection_string in self.cache: return self.cache[selection_string] # Parse expression expr = self.parser.parse(selection_string) # Add to cache (with size limit) if len(self.cache) >= self.cache_size: # Remove oldest entry (simple FIFO) oldest = next(iter(self.cache)) del self.cache[oldest] self.cache[selection_string] = expr return expr
[docs] def clear_cache(self) -> None: """Clear the selection cache.""" self.cache.clear()
# Convenience functions
[docs] def select( structure: Structure, selection: Union[str, SelectionExpression] ) -> np.ndarray: """ Select atoms from a structure. Args: structure: The structure to select from selection: Selection string or expression Returns: Boolean array indicating selected atoms """ engine = SelectionEngine() return engine.select(structure, selection)
[docs] def select_atoms( structure: Structure, selection: Union[str, SelectionExpression] ) -> Structure: """ Return a new Structure containing only selected atoms. Args: structure: The structure to select from selection: Selection string or expression Returns: New Structure with selected atoms """ engine = SelectionEngine() return engine.select_atoms(structure, selection)