Source code for cgexplore._internal.terms.bonds
# Distributed under the terms of the MIT License.
"""Module for handling bonds.
Author: Andrew Tarzia
"""
import itertools as it
import logging
from collections import abc
from dataclasses import dataclass
import stk
from openmm import openmm
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s | %(levelname)s | %(message)s",
)
logger = logging.getLogger(__name__)
_bond_k_unit = openmm.unit.kilojoules_per_mole / openmm.unit.nanometer**2
[docs]
@dataclass(frozen=True, slots=True)
class Bond:
"""Class containing bond defintion used in Forcefield.
Parameters:
atom_names:
Element and ID+1 of atoms in bond.
atom_ids:
ID of atoms in bond.
bond_r:
`r` quantity of bond force.
bond_k:
`k` quantity of bond force.
atoms:
`stk.Atom` instances of the atoms in bond.
force:
The force to apply to a bond, usually "HarmonicBondForce".
funct:
For some forcefields (e.g., Martini), this term can change the
force function. For harmonic bonds, set to `0`.
"""
atom_names: abc.Sequence[str]
atom_ids: abc.Sequence[int]
bond_r: openmm.unit.Quantity
bond_k: openmm.unit.Quantity
atoms: abc.Sequence[stk.Atom] | None
force: str
funct: int = 0
[docs]
@dataclass(frozen=True, slots=True)
class TargetBond:
"""Defines a target term to search for in a molecule.
Parameters:
type1:
Atom/bead type of atom.
type2:
Atom/bead type of atom.
element1:
Element string of atom.
element2:
Element string of atom.
bond_r:
`r` quantity of bond force.
bond_k:
`k` quantity of bond force.
funct:
For some forcefields (e.g., Martini), this term can change the
force function. For harmonic bonds, set to `0`.
"""
type1: str
type2: str
element1: str
element2: str
bond_r: openmm.unit.Quantity
bond_k: openmm.unit.Quantity
funct: int = 0
[docs]
def vector_key(self) -> str:
"""Return key for vector defining this target term."""
return f"{self.type1}{self.type2}"
[docs]
def vector(self) -> tuple[float, float]:
"""Return vector defining this target term."""
return (
self.bond_r.value_in_unit(openmm.unit.angstrom),
self.bond_k.value_in_unit(_bond_k_unit),
)
[docs]
def human_readable(self) -> str:
"""Return human-readable definition of this target term."""
return (
f"{self.__class__.__name__}("
f"{self.type1}{self.type2}, "
f"{self.element1}{self.element2}, "
f"{self.bond_r.in_units_of(openmm.unit.angstrom)}, "
f"{self.bond_k.in_units_of(_bond_k_unit)}, "
")"
)
[docs]
@dataclass(frozen=True, slots=True)
class TargetBondRange:
"""Defines a target term and ranges in parameters to search for.
Parameters:
type1:
Atom/bead type of atom.
type2:
Atom/bead type of atom.
element1:
Element string of atom.
element2:
Element string of atom.
bond_rs:
Each `r` quantity of bond force to be implemented in a forcefield
library.
bond_ks:
Each `k` quantity of bond force to be implemented in a forcefield
library.
"""
type1: str
type2: str
element1: str
element2: str
bond_rs: abc.Sequence[openmm.unit.Quantity]
bond_ks: abc.Sequence[openmm.unit.Quantity]
[docs]
def yield_bonds(self) -> abc.Iterable[TargetBond]:
"""Find interactions matching target."""
for r, k in it.product(self.bond_rs, self.bond_ks):
yield TargetBond(
type1=self.type1,
type2=self.type2,
element1=self.element1,
element2=self.element2,
bond_k=k,
bond_r=r,
)
[docs]
@dataclass(frozen=True, slots=True)
class TargetMartiniBond:
"""Defines a target angle to search for in a molecule."""
type1: str
type2: str
element1: str
element2: str
funct: int
bond_r: openmm.unit.Quantity
bond_k: openmm.unit.Quantity
[docs]
def human_readable(self) -> str:
"""Return human-readable definition of this target term."""
return (
f"{self.__class__.__name__}("
f"{self.type1}{self.type2}, "
f"{self.element1}{self.element2}, "
f"{self.funct},"
f"{self.bond_r.in_units_of(openmm.unit.angstrom)}, "
f"{self.bond_k.in_units_of(_bond_k_unit)}, "
")"
)
[docs]
@dataclass(frozen=True, slots=True)
class MartiniBondRange:
"""Defines a target bond and ranges in parameters to search for."""
type1: str
type2: str
element1: str
element2: str
funct: int
bond_rs: abc.Sequence[openmm.unit.Quantity]
bond_ks: abc.Sequence[openmm.unit.Quantity]
[docs]
def yield_bonds(self) -> abc.Iterable[TargetMartiniBond]:
"""Find bonds matching target."""
for r, k in it.product(self.bond_rs, self.bond_ks):
yield TargetMartiniBond(
type1=self.type1,
type2=self.type2,
element1=self.element1,
element2=self.element2,
funct=self.funct,
bond_k=k,
bond_r=r,
)