Source code for pydft_qmmm.interfaces.qmmm_pme_openmm.openmm_factory

"""Functionality for building the QM/MM/PME-hacked OpenMM interface.
"""
from __future__ import annotations

from typing import TYPE_CHECKING

import openmm
from simtk.unit import femtosecond

from .openmm_interface import PMEOpenMMInterface
from pydft_qmmm.interfaces.openmm.openmm_factory import _adjust_forces
from pydft_qmmm.interfaces.openmm.openmm_factory import _build_forcefield
from pydft_qmmm.interfaces.openmm.openmm_factory import _build_modeller
from pydft_qmmm.interfaces.openmm.openmm_factory import _build_system
from pydft_qmmm.interfaces.openmm.openmm_factory import _build_topology
from pydft_qmmm.interfaces.openmm.openmm_factory import _empty_system

if TYPE_CHECKING:
    from openmm.app import Modeller
    from ..interface import MMSettings


[docs] def pme_openmm_interface_factory(settings: MMSettings) -> PMEOpenMMInterface: """Build the interface to OpenMM given the settings. Args: settings: The settings used to build the OpenMM interface. Returns: The QM/MM/PME OpenMM interface. """ if not (x := settings.pme_gridnumber) is None: for num in x: if num != x[0]: raise ValueError( ("Non-uniform number of grid points along each axis " "is not currently supported for QM/MM/PME."), ) topology = _build_topology(settings) modeller = _build_modeller(settings, topology) forcefield = _build_forcefield(settings, modeller) system = _build_system(forcefield, modeller) _adjust_forces(settings, system) base_context = _build_context( settings, system, modeller, { "ReferenceVextGrid": "true", }, ) ixn_context = _build_context(settings, _empty_system(settings), modeller) wrapper = PMEOpenMMInterface(settings, base_context, ixn_context) # Register observer functions. settings.system.charges.register_notifier(wrapper.update_charges) settings.system.positions.register_notifier(wrapper.update_positions) settings.system.box.register_notifier(wrapper.update_box) settings.system.subsystems.register_notifier(wrapper.update_subsystems) return wrapper
def _build_context( settings: MMSettings, system: openmm.System, modeller: Modeller, properties: None | dict[str, str] = None, ) -> openmm.Context: """Build the QM/MM/PME OpenMM Context object. Args: settings: The settings used to build the OpenMM interface. system: The OpenMM representation of forces, constraints, and particles. modeller: The OpenMM representation of the system. Returns: The OpenMM machinery required to perform energy and force calculations, containing the System object and the specific platform to use, which is currently just the CPU platform. """ integrator = openmm.VerletIntegrator(1. * femtosecond) platform = openmm.Platform.getPlatformByName("CPU") if properties: context = openmm.Context(system, integrator, platform, properties) else: context = openmm.Context(system, integrator, platform) context.setPositions(modeller.positions) return context