Source code for vermouth.processors.idr_cross_domain_interaction_removal

# Copyright 2026 University of Groningen
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from itertools import compress
from .processor import Processor
from .annotate_idrs import parse_residues
from ..graph_utils import make_residue_graph
from ..rcsu.go_utils import get_go_type_from_attributes, _in_chain_and_resid_region
import numpy as np
from ..log_helpers import StyleAdapter, get_logger

LOGGER = StyleAdapter(get_logger(__name__))

[docs] class IDRCrossDomainInteractionRemoval(Processor): def __init__(self, go, elastic, id_regions): """ Parameters ---------- go: bool this system contains a go model elastic: bool this system contains an elastic network id_regions: list list of tuples of residue regions defining the IDRs """ self.go = go self.elastic = elastic self.id_regions = [] for region in id_regions: self.id_regions.append(parse_residues(region))
[docs] def remove_cross_nb_interactions(self, molecule, res_graph, nbparams): """ Remove Go interactions between folded and disordered regions of a molecule Parameters ---------- molecule: :class:`vermouth.molecule.Molecule` the molecule res_graph: :class:`networkx.Graph` the residue graph of the molecule """ #list of all the Go pairs in the molecule all_go_pairs = np.array([list(i.atoms) for i in nbparams if 'W' not in list(i.atoms)]) # list to record which items we don't want. cross = go potential between folded and disordered domain. all_cross_pairs = [] # for each IDR that we have for region in self.id_regions: # for each residue in the molecule for res_node in res_graph.nodes: # get the current resid, the original one, and the chain resid = res_graph.nodes[res_node]['resid'] _old_resid = res_graph.nodes[res_node]['stash']['resid'] chain = res_graph.nodes[res_node]['chain'] # if the region is in the original resid and chain if _in_chain_and_resid_region(region, _old_resid, chain): # get the matching virtual site from the residue attrs vs_go_node = next(get_go_type_from_attributes(res_graph.nodes[res_node]['graph'], resid=resid, chain=chain, prefix=molecule.meta.get('moltype'))) all_cross_pairs.append(np.where(all_go_pairs == vs_go_node)[0]) #just need the first one # make sure we only have one entry in case a site has more than one interaction all_cross_pairs = np.unique([x for xs in all_cross_pairs for x in xs]) return all_cross_pairs
[docs] def remove_cross_elastic(self, molecule): """ Remove elastic network bonds between folded and disordered regions of a molecule Parameters ---------- molecule: :class:`vermouth.molecule.Molecule` the molecule res_graph: :class:`networkx.Graph` the residue graph of the molecule """ # find elastic bonds by meta elastic_bonds = [list(i.atoms) for i in molecule.interactions['bonds'] if i.meta.get('group') == "Rubber band"] # list to record which items we don't want. cross = elastic bond between folded and disordered domain. all_cross_pairs = [] # make a map between bond indicies and their residues. index starts from 1 so -1 for idx nodes_map = {i: {"resid": molecule.nodes[j].get('stash').get('resid'), "chain": molecule.nodes[j].get('chain') } for i,j in enumerate(molecule.nodes, 1)} # list of bonds, but which residues they link not nodes residue_bonds = [[nodes_map[i].get('resid') for i in j] for j in elastic_bonds] # same but for chains chains = [[nodes_map[i].get('chain') for i in j] for j in elastic_bonds] for region in self.id_regions: # get info about the region lower, upper = sorted(region['resids'][0]) chain = region['chain'] # get bonds and chain in molecule which match this region bond_in_region = [any([(i>= lower) & (i<= upper) for i in j]) for j in residue_bonds] chain_in_region = [any([i == chain for i in j]) for j in chains] # list of which residue bonds meet both criteria bonds_rm_idx = [all([i,j]) for i,j in zip(bond_in_region, chain_in_region)] # get the bonds that need to be removed for_removal = compress(elastic_bonds, bonds_rm_idx) all_cross_pairs.extend(for_removal) # delete the folded-disordered elastic network bonds from the list # go backwards otherwise list order gets messed up. for i in reversed(all_cross_pairs): molecule.remove_interaction('bonds', tuple(i))
def _remove_nb_interactions(self, system, interactions_list): """ remove non bonded interactions at the system level """ # delete the folded-disordered Go interactions from the list. # go backwards otherwise list order gets messed up. for i in reversed(interactions_list): del system.gmx_topology_params["nonbond_params"][i]
[docs] def run_system(self, system): # no disordered regions, no bother if not self.id_regions: return system for molecule in system.molecules: if self.go: if hasattr(molecule, 'res_graph'): res_graph = molecule.res_graph else: res_graph = make_residue_graph(molecule) interactions_for_removal = self.remove_cross_nb_interactions(molecule=molecule, res_graph=res_graph, nbparams=system.gmx_topology_params["nonbond_params"]) self._remove_nb_interactions(system, interactions_for_removal) elif self.elastic: self.remove_cross_elastic(molecule=molecule)