#
# Copyright 2015 by Justin MacCallum, Alberto Perez, Ken Dill
# All rights reserved
#
"""
A module to define MELD Systems
"""
from typing import List, Optional
import numpy as np # type: ignore
import openmm as mm # type: ignore
from openmm import app
from meld import interfaces
from meld.system import (
density,
indexing,
mapping,
param_sampling,
pdb_writer,
restraints,
state,
temperature,
)
from meld.vault import ENERGY_GROUPS
[docs]class System(interfaces.ISystem):
"""
A class representing a MELD system.
"""
restraints: restraints.RestraintManager
"""The object to handle managing restraints for the system"""
density: density.DensityManager
"""The object to handle managing densities for the system"""
index: indexing.Indexer
"""The object to lookup atom and residue indices """
temperature_scaler: Optional[temperature.TemperatureScaler]
"""The temperature scaler for the system"""
param_sampler: param_sampling.ParameterManager
"""The sampler for parameters"""
mapper: mapping.PeakMapManager
"""The peak map manager"""
_solvation: str
_openmm_system: mm.System
_openmm_topology: app.Topology
_integrator: mm.LangevinIntegrator
_barostat: Optional[mm.MonteCarloBarostat]
_template_coordinates: np.ndarray
_template_velocities: np.ndarray
_template_box_vectors: Optional[np.ndarray]
_n_atoms: int
_atom_names: List[str]
_residue_names: List[str]
_residue_numbers: List[int]
[docs] def __init__(
self,
solvation: str,
openmm_system: mm.System,
openmm_topology: app.Topology,
integrator: mm.LangevinIntegrator,
barostat: Optional[mm.MonteCarloBarostat],
template_coordinates: np.ndarray,
template_velocities: np.ndarray,
template_box_vectors: Optional[np.ndarray],
builder_info: dict,
):
"""
Initialize a MELD system
Args:
solvation: the solvation model to use
openmm_system: the OpenMM system
openmm_topology: the OpenMM topology
integrator: the OpenMM integrator
barostat: the OpenMM barostat
template_coordinates: the coordinates of the template
template_velocities: the velocities of the template
template_box_vectors: the box vectors of the template
builder_info: a dictionary of extra information from the builder/patchers
"""
self._solvation = solvation
self._openmm_system = openmm_system
self._openmm_topology = openmm_topology
self._integrator = integrator
self._barostat = barostat
self._template_coordinates = template_coordinates
self._n_atoms = self._template_coordinates.shape[0]
self._template_velocities = template_velocities
self._template_box_vectors = template_box_vectors
self.builder_info = builder_info
self.restraints = restraints.RestraintManager(self)
self.density = density.DensityManager()
self.param_sampler = param_sampling.ParameterManager()
self.mapper = mapping.PeakMapManager()
self.extra_bonds = []
self.extra_restricted_angles = []
self.extra_torsions = []
self.temperature_scaler = None
self._setup_indexing()
@property
def num_alignments(self) -> int:
return self.builder_info.get("num_alignments", 0)
@property
def solvation(self):
return self._solvation
@property
def omm_system(self):
return self._openmm_system
@property
def topology(self):
return self._openmm_topology
@property
def integrator(self):
return self._integrator
@property
def barostat(self):
return self._barostat
@property
def n_atoms(self) -> int:
"""
number of atoms
"""
return self._n_atoms
@property
def template_coordinates(self) -> np.ndarray:
"""
Get the template coordinates
"""
return self._template_coordinates
@property
def template_velocities(self) -> np.ndarray:
"""
Get the template velocities
"""
return self._template_velocities
@property
def template_box_vectors(self) -> Optional[np.ndarray]:
"""
Get the template box vectors
"""
return self._template_box_vectors
@property
def atom_names(self) -> List[str]:
"""
names for each atom
"""
return self._atom_names
@property
def residue_numbers(self) -> List[int]:
"""
residue numbers for each atom
"""
return self._residue_numbers
@property
def residue_names(self) -> List[str]:
"""
residue names for each atom
"""
return self._residue_names
[docs] def get_state_template(self) -> state.SystemState:
"""
Get a template SystemState.
"""
pos = self._template_coordinates.copy()
vel = self._template_velocities.copy()
alpha = 0.0
energy = 0.0
group_energies = np.zeros(ENERGY_GROUPS)
box_vectors = self._template_box_vectors
if box_vectors is None:
box_vectors = np.array([0.0, 0.0, 0.0])
params = self.param_sampler.get_initial_state()
mappings = self.mapper.get_initial_state()
if self.num_alignments == 0:
alignments = None
else:
alignments = np.zeros(self.num_alignments * 5)
return state.SystemState(
pos,
vel,
alpha,
energy,
group_energies,
box_vectors,
params,
mappings,
alignments,
)
[docs] def get_pdb_writer(self) -> pdb_writer.PDBWriter:
"""
Get the PDBWriter
"""
return pdb_writer.PDBWriter(
list(range(1, len(self._atom_names) + 1)),
self._atom_names,
self._residue_numbers,
self._residue_names,
)
def _setup_indexing(self):
self.index = indexing.setup_indexing(self._openmm_topology)
self._atom_names = [atom.name for atom in self._openmm_topology.atoms()]
assert len(self._atom_names) == self._n_atoms
self._residue_numbers = [
atom.residue.index for atom in self._openmm_topology.atoms()
]
assert len(self._residue_numbers) == self._n_atoms
self._residue_names = [
atom.residue.name for atom in self._openmm_topology.atoms()
]
assert len(self._residue_names) == self._n_atoms