Source code for qmmm_pme.hamiltonians.hamiltonian
#! /usr/bin/env python3
"""A module defining the base :class:`Hamiltonian` class and derived
interface classes.
"""
from __future__ import annotations
from abc import ABC
from abc import abstractmethod
from typing import Any
from typing import TYPE_CHECKING
from qmmm_pme.interfaces import SystemTypes
if TYPE_CHECKING:
from qmmm_pme import System
from qmmm_pme.calculators.calculator import ModifiableCalculator
[docs]class Hamiltonian(ABC):
"""An abstract :class:`Hamiltonian` base class for creating the
Hamiltonian API.
"""
atoms: list[int | slice] = []
system_type: SystemTypes = SystemTypes.SYSTEM
def __getitem__(
self,
indices: int | slice | tuple[int | slice, ...],
) -> Hamiltonian:
"""Sets the indices for atoms that are treated with this
:class:`Hamiltonian`.
:return: |Hamiltonian|.
"""
indices = indices if isinstance(indices, tuple) else (indices,)
atoms = []
for i in indices:
if isinstance(i, (int, slice)):
atoms.append(i)
else:
raise TypeError("...")
self.atoms = atoms
return self
[docs] @abstractmethod
def build_calculator(self, system: System) -> ModifiableCalculator:
"""Build the :class:`Calculator` corresponding to the
:class:`Hamiltonian` object.
:param system: |system| to calculate energy and forces for.
:return: |calculator|.
"""
[docs] def parse_atoms(self, system: System) -> list[list[int]]:
"""Parse the indices provided to the :class:`Hamiltonian` object
to create the list of residue-grouped atom indices.
:param system: |system| to calculate energy and forces for.
:return: |atoms|
"""
indices = []
for i in self.atoms:
if isinstance(i, int):
indices.append(i)
else:
indices.extend(
list(
range(
i.start if i.start else 0,
i.stop if i.stop else len(system),
i.step if i.step else 1,
),
),
)
if not self.atoms:
indices = [i for i in range(len(system))]
residues = [
x for residue in system.topology.atoms()
if (x := [i for i in residue if i in indices])
]
return residues
@abstractmethod
def __add__(self, other: Any) -> Hamiltonian:
"""Add :class:`Hamiltonian` objects together.
:param other: The object being added to the
:class:`Hamiltonian`.
:return: A new :class:`Hamiltonian` object.
"""
pass
def __or__(self, other: Any) -> Hamiltonian:
"""Set the embedding distance for a :class:`QMMMHamiltonian`.
:param other: The embedding distance, in Angstroms.
:return: |hamiltonian|.
"""
return self
def __radd__(self, other: Any) -> Any:
"""Add :class:`Hamiltonian` objects together.
:param other: The object being added to the
:class:`Hamiltonian`.
:return: A new :class:`Hamiltonian` object.
"""
return self.__add__(other)
def __str__(self) -> str:
"""Create a LATEX string representation of the
:class:`Hamiltonian` object.
:return: The string representation of the :class:`Hamiltonian`
object.
"""
string = "_{"
for atom in self.atoms:
string += f"{atom}, "
string += "}"
return string
[docs]class MMHamiltonianInterface(Hamiltonian):
"""An interface for the :class:`MMHamiltonian`.
"""
[docs]class QMHamiltonianInterface(Hamiltonian):
"""An interface for the :class:`QMHamiltonian`.
"""
[docs]class QMMMHamiltonianInterface(Hamiltonian):
"""An interface for the :class:`QMMMHamiltonian`.
"""