Source code for glycosylator.optimizers.utils
"""
This module contains additional utility functions for the optimizers that are Glycosylator specific.
"""
import buildamol.graphs.residue_graph as residue_graph
import buildamol.structural as structural
import numpy as np
[docs]
def make_scaffold_graph(
scaffold,
only_clashing_glycans: bool = True,
slice: int = 0,
include_root: bool = False,
include_n_ancestors: int = 0,
) -> tuple["residue_graph.ResidueGraph", list]:
"""
Make a ResidueGraph from a glycosylated scaffold in order to optimize the conformations of the attached glycans.
Parameters
----------
scaffold: Scaffold
The glycosylated scaffold to optimize
only_clashing_glycans: bool
If True, only glycans that clash with the protein or each other will will contribute rotatable edges.
slice: int
The number of residue connections to slice from each glycan. This will sub-sample the rotatable edges of the glycans. At 0 all rotatable edges are included.
Set to -1 to exclude all glycan-internal rotatable edges. This is useful for glycans that are already optimized. And only their placement relative to the scaffold
needs to be optimized (i.e. you only want to optimize the root connections).
include_root: bool
If True, the root connection (to the scaffold) will always be included in the rotatable edges.
include_n_ancestors: int
If > 0, the n ancestor atoms (upstream of the scaffold anchor atom) will also be included in the rotatable edges.
This will allow for a more versatile placement of glycans as it allows partial movement of the scaffold rather than just the glycan.
This requires `include_root` to be True.
Returns
-------
ResidueGraph
The graph of the glycosylated scaffold
list
The rotatable edges of the graph
"""
G = scaffold.make_residue_graph()
if only_clashing_glycans:
glycan_gen = (
(root, glycan)
for (root, glycan) in scaffold.get_glycans().items()
if (glycan.count_clashes() > 0 or glycan.clashes_with_scaffold())
)
else:
glycan_gen = scaffold.get_glycans().items()
_atoms_to_fill_in = []
_rotatable_edges = []
_flat_residues = list(scaffold.get_residues())
_res_coords = [res.coord for res in _flat_residues]
dists = structural.cdist(_res_coords, _res_coords) < 8.0
for root, glycan in glycan_gen:
if glycan.count_residues() > 1:
g = glycan.get_residue_graph()
g.make_detailed(include_clashes=True)
if slice >= 0:
_rotatable_edges.extend(
glycan.get_residue_connections(direct_by="root")
)
else:
g = glycan.get_residue_graph(detailed=True)
root_residue = root.parent
neighboring_residues = (
_flat_residues[idx]
for idx in np.where(dists[_flat_residues.index(root_residue)])[0]
)
neighboring_atoms = (
atom for res in neighboring_residues for atom in res.child_list
)
_atoms_to_fill_in.extend(g.nodes)
_atoms_to_fill_in.extend(neighboring_atoms)
G.remove_nodes_from(g.residues)
G.add_nodes_from(_atoms_to_fill_in)
G.add_edges_from(g.edges)
if slice > 0:
_rotatable_edges = G.sample_edges(
_rotatable_edges, len(scaffold.glycans), slice
)
if include_root:
incoming = scaffold.get_glycan_root_connections(
glycan=glycan,
include_scaffold_ancestors=include_n_ancestors,
)
_rotatable_edges.extend(incoming)
G.add_edges_from(incoming)
_atoms_to_fill_in.clear()
return G, _rotatable_edges
if __name__ == "__main__":
import glycosylator as gl
glycan = gl.glycan(
"Gal(b1-4)GlcNAc(b1-3)[Gal(b1-4)[Fuc(a1-3)]GlcNAc(b1-6)]Gal(b1-4)Glc"
)
scaf = gl.Protein.from_pdb(
"/Users/noahhk/GIT/glycosylator/__projects__/SOLF/solf.pdb"
)
sites = [
scaf.get_residue(179, chain="A"),
scaf.get_residue(141, chain="A"),
scaf.get_residue(179, chain="C"),
scaf.get_residue(179, chain="E"),
]
scaf.apply_standard_bonds_for(*sites)
scaf.add_hydrogens(*[i.get_atom("ND2") for i in sites])
scaf.rename_atoms("HND22", "HD22").rename_atoms("HND21", "HD21")
scaf.glycosylate(glycan, residues=sites)
# scaf = gl.utils.load_pickle(
# "//Users/noahhk/GIT/glycosylator/__projects__/solf3/solF_plus_3G_rsr017_coot_30_man5.pdb_glycosylated_optimized.pkl"
# )
# scaf.apply_standard_bonds_for(*[i.parent for i in scaf.get_glycans().keys()])
graph, rotatable_edges = make_scaffold_graph(
scaf,
only_clashing_glycans=True,
slice=5,
include_root=True,
include_n_ancestors=2,
)
rotatron = gl.optimizers.DistanceRotatron(
graph,
rotatable_edges,
pushback=1.5,
)
# scaf_opt = gl.optimizers.optimize(scaf.copy(), rotatron)
# scaf_opt.to_pdb("scaf_opt_new_slice_graph.pdb")
split = gl.optimizers.split_environment(rotatron, 4)
split = [gl.optimizers.ScaffoldRotatron(i) for i in split]
scaf_opt = gl.optimizers.parallel_optimize(scaf, split)
scaf_opt.to_pdb("scaf_opt_new_slice_parallel.pdb")