Source code for mdpy.recipe.charmm_recipe
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
file : charmm_recipe.py
created time : 2021/10/05
author : Zhenyu Wei
copyright : (C)Copyright 2021-present, mdpy organization
"""
import numpy as np
from mdpy.recipe import Recipe
from mdpy.core import Ensemble
from mdpy.core import Topology
from mdpy.io import CharmmTopparParser
from mdpy.utils import check_quantity_value, check_pbc_matrix
from mdpy.constraint import *
from mdpy.unit import *
from mdpy.error import *
[docs]class CharmmRecipe(Recipe):
[docs] def __init__(
self,
topology: Topology,
pbc_matrix: np.ndarray,
cutoff_radius=12,
long_range_solver="PME",
ewald_direct_sum_error=1e-6,
is_SHAKE: bool = True,
) -> None:
super().__init__(topology)
pbc_matrix = check_quantity_value(pbc_matrix, default_length_unit)
self._pbc_matrix = check_pbc_matrix(pbc_matrix)
self._cutoff_radius = check_quantity_value(cutoff_radius, default_length_unit)
self._long_range_solver = check_long_range_solver(long_range_solver)
self._ewald_direct_sum_error = ewald_direct_sum_error
self._is_SHAKE = is_SHAKE
def set_parameter_files(self, *file_pathes) -> None:
self._parameters = CharmmTopparParser(*file_pathes).parameters
def check_parameters(self):
particle_keys = self._parameters["nonbonded"].keys()
bond_keys = self._parameters["bond"].keys()
angle_keys = self._parameters["angle"].keys()
dihedral_keys = self._parameters["dihedral"].keys()
improper_keys = self._parameters["improper"].keys()
for particle in self._topology.particles:
particle_type = particle.particle_type
if not particle_type in particle_keys:
raise ParameterPoorDefinedError(
"The nonbonded parameter for particle %d (%s) can not be found"
% (particle_type)
)
for bond in self._topology.bonds:
bond_name = (
self._topology.particles[bond[0]].particle_type
+ "-"
+ self._topology.particles[bond[1]].particle_type
)
if not bond_name in bond_keys:
raise ParameterPoorDefinedError(
"The parameter for bond %d-%d (%s) can not be found"
% (*bond, bond_name)
)
for angle in self._topology.angles:
angle_name = (
self._topology.particles[angle[0]].particle_type
+ "-"
+ self._topology.particles[angle[1]].particle_type
+ "-"
+ self._topology.particles[angle[2]].particle_type
)
if not angle_name in angle_keys:
raise ParameterPoorDefinedError(
"The parameter for angle %d-%d-%d (%s) can not be found"
% (*angle, angle_name)
)
for dihedral in self._topology.dihedrals:
dihedral_name = (
self._topology.particles[dihedral[0]].particle_type
+ "-"
+ self._topology.particles[dihedral[1]].particle_type
+ "-"
+ self._topology.particles[dihedral[2]].particle_type
+ "-"
+ self._topology.particles[dihedral[3]].particle_type
)
if not dihedral_name in dihedral_keys:
raise ParameterPoorDefinedError(
"The parameter for dihedral %d-%d-%d-%d (%s) can not be found"
% (*dihedral, dihedral_name)
)
for improper in self._topology.impropers:
improper_name = (
self._topology.particles[improper[0]].particle_type
+ "-"
+ self._topology.particles[improper[1]].particle_type
+ "-"
+ self._topology.particles[improper[2]].particle_type
+ "-"
+ self._topology.particles[improper[3]].particle_type
)
if not improper_name in improper_keys:
raise ParameterPoorDefinedError(
"The parameter for improper %d-%d-%d-%d (%s) can not be found"
% (*improper, improper_name)
)
def create_ensemble(self) -> Ensemble:
self.check_parameters()
ensemble = Ensemble(self._topology, self._pbc_matrix)
constraints = []
if self._topology.num_particles != 0:
if self._long_range_solver == "CUTOFF":
constraints.append(ElectrostaticCutoffConstraint(self._cutoff_radius))
elif self._long_range_solver == "PME":
constraints.append(
ElectrostaticPMEConstraint(
self._cutoff_radius, self._ewald_direct_sum_error
)
)
constraints.append(
CharmmVDWConstraint(self._parameters["nonbonded"], self._cutoff_radius)
)
if self._topology.num_bonds != 0:
constraints.append(CharmmBondConstraint(self._parameters["bond"]))
if self._topology.num_angles != 0:
constraints.append(CharmmAngleConstraint(self._parameters["angle"]))
if self._topology.num_dihedrals != 0:
constraints.append(CharmmDihedralConstraint(self._parameters["dihedral"]))
if self._topology.num_impropers != 0:
constraints.append(CharmmImproperConstraint(self._parameters["improper"]))
ensemble.add_constraints(*constraints)
return ensemble