Source code for waterEntropy.analysis.shells

"""Store shell information here"""


[docs] class Shell: """Represent a single atom shell with dynamic properties, which are set in the ShellCollection class."""
[docs] def __init__(self, atom_idx): object.__setattr__(self, "atom_idx", atom_idx) # Store atom index directly object.__setattr__(self, "properties", {}) # Internal dictionary
[docs] def __getattr__(self, key: str): """Allow dot notation access to stored properties. :param key: name of the property in the properties dictionary """ if key in self.properties: return self.properties[key] raise AttributeError(f"Property '{key}' not found for atom {self.atom_idx}")
[docs] def __setattr__(self, key: str, value): """Allow adding properties dynamically, except for 'atom_idx'. :param key: name of the property being added to the properties dictionary :param value: value for the key being added to the properties dictionary """ if key == "atom_idx": # Ensure atom index remains immutable object.__setattr__(self, key, value) else: self.properties[key] = value # Store additional properties
[docs] def __repr__(self): """Print the atom and its properties.""" return f"Shell(atom_idx={self.atom_idx}, properties={self.properties})"
[docs] class ShellCollection: """Manage multiple atom shells and allow adding/updating properties."""
[docs] def __init__(self): self.shells = {} # Dictionary storing Shell objects indexed by atom index
[docs] def add_data(self, atom_idx: int, UA_shell: list[int]): """Add a new atom shell to the collection if it doesn't exist and set various properties used to describe the class. :param atom_idx: the heavy atom index of the central atom in a shell :param UA_shell: the list of heavy atom indices in the shell of atom_idx """ if atom_idx not in self.shells: self.shells[atom_idx] = Shell(atom_idx) self.set_property(atom_idx, "atom_idx", atom_idx) self.set_property(atom_idx, "UA_shell", UA_shell) self.set_property(atom_idx, "nearest_nonlike_idx", None) self.set_property(atom_idx, "labels", None) self.set_property(atom_idx, "donates_to_labels", None) self.set_property(atom_idx, "accepts_from_labels", None) self.set_property(atom_idx, "N_w", None)
[docs] def set_property(self, atom_idx, key: str, value): """Set a property for a specific atom shell, ensuring it exists first. :param atom_idx: the heavy atom index of the central atom in a shell :param key: the name of the key being added to the shells dictionary :param value: the value of the key being added to the shells dictionary """ if atom_idx not in self.shells: self.shells[atom_idx] = Shell(atom_idx) # Auto-create atom if missing setattr(self.shells[atom_idx], key, value)
[docs] def find_shell(self, atom_idx: int): """ Get the shell instance if atom_idx is a key in shells dictionary :param atom_idx: index of central atom in shell """ return self.shells.get(atom_idx, None)
[docs] def __repr__(self): """Return a dictionary-like representation of stored atoms.""" return repr(self.shells)