Skip to content

Commit

Permalink
filter molecule for templates
Browse files Browse the repository at this point in the history
  • Loading branch information
fgrunewald committed Aug 6, 2023
1 parent 75b892f commit b97ba71
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 25 deletions.
4 changes: 3 additions & 1 deletion polyply/src/backmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,12 @@ def _place_init_coords(self, meta_molecule):
----------
meta_molecule: :class:`polyply.src.MetaMolecule`
"""
#print(meta_molecule.templates.keys())
#print(meta_molecule.templates["PEI2"].keys())
built_nodes = []
for node in meta_molecule.nodes:
if meta_molecule.nodes[node]["backmap"]:
resname = meta_molecule.nodes[node]["resname"]
resname = meta_molecule.nodes[node]["template"]
cg_coord = meta_molecule.nodes[node]["position"]
resid = meta_molecule.nodes[node]["resid"]
high_res_atoms = meta_molecule.nodes[node]["graph"].nodes
Expand Down
5 changes: 3 additions & 2 deletions polyply/src/gen_coords.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,9 @@ def gen_coords(toppath,
grid = np.loadtxt(grid)

# do a sanity check
LOGGER.info("checking residue integrity", type="step")
check_residue_equivalence(topology)
# LOGGER.info("checking residue integrity", type="step")
# check_residue_equivalence(topology)

# Build polymer structure
LOGGER.info("generating templates", type="step")
GenerateTemplates(topology=topology, max_opt=10).run_system(topology)
Expand Down
68 changes: 50 additions & 18 deletions polyply/src/generate_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@
radius_of_gyration)
from .topology import replace_defined_interaction
from .linalg_functions import dih
from tqdm import tqdm
"""
Processor generating coordinates for all residues of a meta_molecule
matching those in the meta_molecule.molecule attribute.
"""

LOGGER = StyleAdapter(get_logger(__name__))

def _atoms_match(node1, node2):
return node1["atomname"] == node2["atomname"]

def find_atoms(molecule, attr, value):
"""
Find all nodes of a `vermouth.molecule.Molecule` that have the
Expand Down Expand Up @@ -235,7 +239,7 @@ def _relabel_interaction_atoms(interaction, mapping):
new_interaction = interaction._replace(atoms=new_atoms)
return new_interaction

def extract_block(molecule, resname, defines):
def extract_block(molecule, template_graph, defines):
"""
Given a `vermouth.molecule` and a `resname`
extract the information of a block from the
Expand All @@ -253,8 +257,8 @@ def extract_block(molecule, resname, defines):
-------
:class:vermouth.molecule.Block
"""
nodes = find_atoms(molecule, "resname", resname)
resid = molecule.nodes[nodes[0]]["resid"]
#nodes = find_atoms(molecule, "resname", resname)
#resid = molecule.nodes[nodes[0]]["resid"]
block = vermouth.molecule.Block()

# select all nodes with the same first resid and
Expand All @@ -263,11 +267,10 @@ def extract_block(molecule, resname, defines):
# label in the molecule and in the block for
# relabeling the interactions
mapping = {}
for node in nodes:
for node in template_graph.nodes:
attr_dict = molecule.nodes[node]
if attr_dict["resid"] == resid:
block.add_node(attr_dict["atomname"], **attr_dict)
mapping[node] = attr_dict["atomname"]
block.add_node(attr_dict["atomname"], **attr_dict)
mapping[node] = attr_dict["atomname"]

for inter_type in molecule.interactions:
for interaction in molecule.interactions[inter_type]:
Expand All @@ -280,14 +283,36 @@ def extract_block(molecule, resname, defines):
"virtual_sites2", "virtual_sites3", "virtual_sites4"]:
block.make_edges_from_interaction_type(inter_type)

if not nx.is_connected(block):
msg = ('\n Residue {} with id {} consistes of two disconnected parts. '
'Make sure all atoms/particles in a residue are connected by bonds,'
' constraints or virual-sites.')
raise IOError(msg.format(resname, resid))
# if not nx.is_connected(block):
# resname =
# msg = ('\n Residue {} with id {} consistes of two disconnected parts. '
# 'Make sure all atoms/particles in a residue are connected by bonds,'
# ' constraints or virual-sites.')
# raise IOError(msg.format(resname, resid))

return block

def group_by_isomorphism(meta_molecule, template_graphs={}):
"""
Extract all unique fragment graphs from meta_molecule
using the full subgraph isomorphism check.
"""
template_graphs = {}
for node in meta_molecule.nodes:
resname = meta_molecule.nodes[node]["resname"]
graph = meta_molecule.nodes[node]["graph"]
if resname in template_graphs and not nx.is_isomorphic(graph,
template_graphs[resname],
node_match=_atoms_match,
):
template_name = resname + str(len(template_graphs))
meta_molecule.nodes[node]["template"] = template_name
template_graphs[template_name] = graph

Check warning on line 310 in polyply/src/generate_templates.py

View check run for this annotation

Codecov / codecov/patch

polyply/src/generate_templates.py#L308-L310

Added lines #L308 - L310 were not covered by tests
else:
meta_molecule.nodes[node]["template"] = resname
template_graphs[resname] = graph
return template_graphs

class GenerateTemplates(Processor):
"""
This processor takes a a class:`polyply.src.MetaMolecule` and
Expand All @@ -303,7 +328,7 @@ def __init__(self, topology, max_opt, *args, **kwargs):
self.volumes = self.topology.volumes
self.templates = {}

def gen_templates(self, meta_molecule):
def gen_templates(self, meta_molecule, template_graphs):
"""
Generate blocks for each unique residue by extracting the
block information, placing initial coordinates, and geometry
Expand All @@ -314,17 +339,19 @@ class variable.
Parameters
----------
meta_molecule: :class:`polyply.src.meta_molecule.MetaMolecule`
template_graphs: dict
a dict of graphs corresponding to the templates to be generated
Updates
---------
self.templates
self.volumes
"""
resnames = set(nx.get_node_attributes(meta_molecule, "resname").values())

for resname in resnames:
#print(len(template_graphs))
for resname, template_graph in tqdm(template_graphs.items()):
if resname not in self.templates:
block = extract_block(meta_molecule.molecule, resname,
block = extract_block(meta_molecule.molecule,
template_graph,
self.topology.defines)

opt_counter = 0
Expand Down Expand Up @@ -362,7 +389,12 @@ def run_molecule(self, meta_molecule):
and volume attribute.
"""
if hasattr(meta_molecule, "templates"):
template_graphs = {res: None for res in meta_molecule.templates}
template_graphs = group_by_isomorphism(meta_molecule, template_graphs)

Check warning on line 393 in polyply/src/generate_templates.py

View check run for this annotation

Codecov / codecov/patch

polyply/src/generate_templates.py#L393

Added line #L393 was not covered by tests
self.templates.update(meta_molecule.templates)
self.gen_templates(meta_molecule)
else:
template_graphs = group_by_isomorphism(meta_molecule)

self.gen_templates(meta_molecule, template_graphs)
meta_molecule.templates = self.templates
return meta_molecule
6 changes: 3 additions & 3 deletions polyply/tests/test_backmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ def test_backmapping():
meta_molecule = MetaMolecule(graph)
meta_molecule.molecule = molecule

nx.set_node_attributes(meta_molecule, {0: {"resname": "test",
nx.set_node_attributes(meta_molecule, {0: {"resname": "test", "template": "test",
"position": np.array([0, 0, 0]),
"resid": 1, "backmap": True},
1: {"resname": "test",
1: {"resname": "test", "template": "test",
"position": np.array([0, 0, 1.0]),
"resid": 2, "backmap": True},
2: {"resname": "test",
2: {"resname": "test", "template": "test",
"position": np.array([0, 0, 2.0]),
"resid": 3, "backmap": False}})
# test if disordered template works
Expand Down
3 changes: 2 additions & 1 deletion polyply/tests/test_generate_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ def test_extract_block():
polyply.src.polyply_parser.read_polyply(lines, ff)
block = ff.blocks['test']
molecule = block.to_molecule()
new_block = extract_block(molecule, "GLY", {})
template_graph = ff.blocks['GLY'].to_molecule()
new_block = extract_block(molecule, template_graph, {})
for node in ff.blocks["GLY"]:
atomname = ff.blocks["GLY"].nodes[node]["atomname"]
assert ff.blocks["GLY"].nodes[node] == new_block.nodes[atomname]
Expand Down

0 comments on commit b97ba71

Please sign in to comment.