Source code for qmmm_pme.plugins.pme.pme

#! /usr/bin/env python3
"""A module defining the pluggable implementation of the SETTLE
algorithm for the QM/MM/PME repository.
"""
from __future__ import annotations

from dataclasses import astuple
from typing import Any
from typing import Callable
from typing import TYPE_CHECKING

from openmm import NonbondedForce
from simtk.unit import nanometer

from .pme_utils import pme_components
from qmmm_pme.calculators.calculator import CalculatorType
from qmmm_pme.calculators.calculator import Results
from qmmm_pme.common import KJMOL_PER_EH
from qmmm_pme.plugins.plugin import QMMMCalculatorPlugin

if TYPE_CHECKING:
    from qmmm_pme.calculators import QMMMCalculator


[docs]class PME(QMMMCalculatorPlugin): """A :class:`Plugin` which implements the QM/MM/PME algorithm for energy and force calculations. """
[docs] def modify( self, calculator: QMMMCalculator, ) -> None: """Perform necessary modifications to the :class:`QMMMCalculator` object. :param calculator: The calculator to modify with the QM/MM/PME functionality. """ self._modifieds.append(type(calculator).__name__) self.system = calculator.system self.calculators = calculator.calculators interface = calculator.calculators[ CalculatorType.MM ].interface nonbonded_forces = [ force for force in interface.system.getForces() if isinstance(force, NonbondedForce) ] ( self.pme_alpha, self.pme_gridnumber, _, _, ) = nonbonded_forces[0].getPMEParameters() self.pme_alpha *= nanometer calculator.calculate = self._modify_calculate(calculator.calculate)
def _modify_calculate( self, calculate: Callable[..., tuple[Any, ...]], ) -> Callable[..., tuple[Any, ...]]: """ """ def inner(**kwargs: bool) -> tuple[Any, ...]: pme_potential = self.calculators[ CalculatorType.MM ].interface.compute_pme_potential() / KJMOL_PER_EH quadrature = self.calculators[ CalculatorType.QM ].interface.compute_quadrature() ( reciprocal_energy, quadrature_pme_potential, nuclei_pme_potential, nuclei_pme_gradient, ) = pme_components( self.system, quadrature, pme_potential, self.pme_gridnumber, self.pme_alpha, ) self.calculators[CalculatorType.QM].options.update( { "quad_extd_pot": tuple(quadrature_pme_potential), "nuc_extd_pot": tuple(nuclei_pme_potential), "nuc_extd_grad": tuple( [tuple(x) for x in nuclei_pme_gradient], ), }, ) qmmm_energy, qmmm_forces, qmmm_components = calculate(**kwargs) qmmm_energy += reciprocal_energy results = Results(qmmm_energy) if kwargs["return_forces"]: results.forces = qmmm_forces if kwargs["return_components"]: qmmm_components.update( {"Reciprocal-Space Correction Energy": reciprocal_energy}, ) results.components = qmmm_components return astuple(results) return inner