Last active
March 28, 2023 11:36
-
-
Save IAlibay/234e8e215b7a4ee977b7cea62bebab29 to your computer and use it in GitHub Desktop.
A short script for generating networks using OpenFE
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import yaml | |
import json | |
import argparse | |
from typing import List | |
import numpy as np | |
from rdkit import Chem | |
from openfe import SmallMoleculeComponent | |
from openfe.setup import LomapAtomMapper, lomap_scorers, LigandNetwork | |
from openfe.setup.ligand_network_planning import (generate_minimal_spanning_network, | |
generate_radial_network) | |
from openmm import unit | |
from collections import OrderedDict | |
parser = argparse.ArgumentParser( | |
description="Write out a network based on a set of input molecules", | |
) | |
parser.add_argument( | |
"--mols_sdf", | |
type=str, | |
help=("Path to the input molecules SDF file. " | |
"Note: if star graph is generate, the first entry will be used as " | |
"the central ligand"), | |
) | |
parser.add_argument( | |
"--network_type", | |
type=str, | |
help=("Network to be generated, either star (star graph), " | |
"or mst (minimum spanning graph)"), | |
) | |
parser.add_argument( | |
"--outfile", | |
type=str, | |
help="Name of output yaml file", | |
) | |
parser.add_argument( | |
"--outtype", | |
type=str, | |
default="json", | |
help=("type of output file to write, " | |
"either `json` (default), `yaml` (PLB-like), or `graphml`") | |
) | |
def _load_ligands(filepath: str) -> List[SmallMoleculeComponent]: | |
""" | |
Load a list of ligands from an SDF file | |
Parameters | |
---------- | |
filepath : str | |
A str path to the SDF file to be read | |
Returns | |
------- | |
List[SmallMoleculeComponent] | |
A list of SmallMoleculeComponent objects for each molecule in the | |
SDF file. | |
""" | |
supp = Chem.SDMolSupplier(filepath, removeHs=False) | |
return [SmallMoleculeComponent(m) for m in supp] | |
def _gen_network(mols: List[SmallMoleculeComponent], | |
network_type: str) -> LigandNetwork: | |
""" | |
Generate a network (of type defined by network_type), from the input | |
mols using the LomapAtomMapper. | |
Load a list of ligands from an SDF file | |
Parameters | |
---------- | |
mols : List[SmallMoleculeComponent] | |
List of SmallMoleculeComponents to generate a network from. Please | |
note that the first molecule will be used as the central ligand | |
when building star graphs. | |
network_type : str | |
The network type to build. Currently only supports "star" (a star | |
graph), or "mst" (a minimum spanning graph). | |
Returns | |
------- | |
LigandNetwork | |
A network of ligands with each edges defining an alchemical | |
transformation. | |
""" | |
mappers = [ | |
LomapAtomMapper(time=60, threed=True, element_change=True, max3d=1), | |
] | |
if network_type == "star": | |
net = generate_radial_network( | |
ligands=mols[1:], central_ligand=mols[0], mappers=mappers, | |
scorer=lomap_scorers.default_lomap_score) | |
elif network_type == "mst": | |
net = generate_minimal_spanning_network( | |
mols, mappers, lomap_scorers.default_lomap_score) | |
else: | |
errmsg = f"{network_type} is not a currently supported network" | |
raise ValueError(errmsg) | |
return net | |
def _write_network(network: LigandNetwork, mols: List[SmallMoleculeComponent], | |
network_type: str, outfile: str, outtype: str) -> None: | |
""" | |
Write out a network to yaml. | |
Parameters | |
---------- | |
network : LigandNetwork | |
A ligand transformation network to be written out. | |
mols : List[SmallMoleculeComponent] | |
List of ligands, as ordered in the input SDF file. | |
network_type : str | |
The type of network which was created. | |
outfile : str | |
Name of the serialised network file to be written. | |
outtype : str | |
Type of file to be written out. Can either be json (default), | |
yaml, or graphml (which dumps out the network object directly). | |
""" | |
def get_index(mols, name): | |
for i, mol in enumerate(mols): | |
if mol.name == name: | |
return i | |
output = {} | |
output['mapper'] = "LOMAP (time=60, threed=True, element_change=True, max3d=1)" | |
output['planner'] = f"openfe {network_type} graph" | |
edges_dict = dict() | |
for edge in network.edges: | |
edge_name = f'edge_{edge.componentA.name}_{edge.componentB.name}' | |
mapping = [list(i) for i in edge.componentA_to_componentB.items()] | |
edges_dict[edge_name] = { | |
'ligand_a': edge.componentA.name, | |
'ligand_a_id': get_index(mols, edge.componentA.name), | |
'ligand_b': edge.componentB.name, | |
'ligand_b_id': get_index(mols, edge.componentB.name), | |
'atom mapping': edge.componentA_to_componentB, | |
'score': f"{edge.annotations['score']:.3f}",} | |
output['edges'] = edges_dict | |
if outtype == "json": | |
with open(outfile, 'w') as json_file: | |
json.dump(output, json_file) | |
elif outtype == "yaml": | |
with open(outfile, 'w') as yaml_file: | |
yaml.dump(output, yaml_file, | |
default_flow_style=None, sort_keys=False) | |
elif outtype == "graphml": | |
with open(outfile, 'w') as writer: | |
writer.write(network.to_graphml()) | |
else: | |
raise ValueError("Unknown serialisation type") | |
if __name__ == "__main__": | |
args = parser.parse_args() | |
mols = _load_ligands(args.mols_sdf) | |
network = _gen_network(mols, args.network_type) | |
_write_network(network, mols, args.network_type, args.outfile, args.outtype) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment