Source code for fast_forward.itp_to_ag
"""
Extract interactions pairs from itp and convert to atom
groups of an MDAnalysis Universe.
"""
from collections import defaultdict
import numpy as np
import networkx as nx
from fast_forward.universe_handler import res_as_mol
[docs]
def find_mol_indices(universe, atoms, moltypes):
"""
Given a universe select all atoms that belong to molecules
of the given `moltype`. Subsequently, return indices of all
multiples of the indices defined in atoms under the assumption
that all considered molecules have the same number of atoms.
Parameters
----------
universe: :class:`~MDAnalysis.core.universe.Universe`
atoms: list
moltype: str
Returns
-------
list
list of :class:`~numpy.ndarray`
"""
mol_atoms = universe.select_atoms(f'moltype {moltypes}')
n_mols = len(np.unique(mol_atoms.molnums))
try:
mol_atom_indices = mol_atoms.indices.reshape(n_mols, -1)
except ValueError:
msg = ("The target molecules passed to find_mol_indices "
"do not seem to all have the same number of atoms.")
raise IndexError(msg) from None
return list(mol_atom_indices[:, atoms])
[docs]
class ITPInteractionMapper:
"""
Class to extract interaction groups from itp files
and map them to indices in an MDAnalysis Universe.
"""
def __init__(self, universe, blocks, molnames):
"""
Parameters
----------
universe: :class:`~MDAnalysis.core.universe.Universe`
blocks: list
list of :class:`~vermouth.molecule.Block`
molnames: list
list of molecule names
"""
self.universe = universe
self.blocks = dict(zip(molnames, blocks))
# we ensure we either have molecule types, or we promote res info as such
res_as_mol(self.universe)
[docs]
def get_interactions_group(self, molname, int_mode=False):
"""
Iterate over interactions in itp file and return dict of
grouped indices corresponding to the atoms in universe.
"""
block = self.blocks[molname]
indices_dict = defaultdict(dict)
initial_parameters = defaultdict(dict)
block_indices = defaultdict(dict)
for inter_type in block.interactions:
for inter in block.interactions[inter_type]:
atoms = inter.atoms
if int_mode == "all":
atomnames=[f"{block.nodes[atom]['resid']}_{block.nodes[atom]['atomname']}" for atom in atoms]
group = "_".join(atomnames)
inter.meta["comment"] = group
else:
group = inter.meta.get("comment", None)
if group:
indices = find_mol_indices(self.universe, atoms, molname)
if inter_type == 'constraints': # treat constraints as bonds
inter_type = 'bonds'
old_indices = indices_dict[inter_type].get(group, [])
old_block_indices = block_indices[inter_type].get(group, [])
block_indices[inter_type][group] = [atoms] + old_block_indices
indices_dict[inter_type][group] = indices + old_indices
initial_parameters[inter_type][group] = inter.parameters
return indices_dict, initial_parameters, block_indices
[docs]
def get_pairwise_interaction(self, molname):
"""
Iterate over all atoms in itp file and return dict of
paired indices corresponding to all pairwise distances in universe.
group_names are given by the atomnames
"""
block = self.blocks[molname]
indices_dict = defaultdict(dict)
for node1, name1 in block.nodes(data='atomname'):
for node2, name2 in list(block.nodes(data='atomname'))[node1+1:]:
atoms = np.array([node1, node2])
group = f'{block.nodes[node1]["resid"]}_{name1}_{block.nodes[node2]["resid"]}_{name2}' # naming convention with node1 < node2
indices = find_mol_indices(self.universe, atoms, molname)
old_indices = indices_dict['distances'].get(group, [])
indices_dict['distances'][group] = indices + old_indices
return indices_dict