|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
""" |
|
PLEASE NOTE THIS IMPLEMENTATION INCLUDES THE ORIGINAL SOURCE CODE (AND SOME ADAPTATIONS) |
|
OF THE MHG IMPLEMENTATION OF HIROSHI KAJINO AT IBM TRL ALREADY PUBLICLY AVAILABLE. |
|
THIS MIGHT INFLUENCE THE DECISION OF THE FINAL LICENSE SO CAREFUL CHECK NEEDS BE DONE. |
|
""" |
|
|
|
""" Title """ |
|
|
|
__author__ = "Hiroshi Kajino <KAJINO@jp.ibm.com>" |
|
__copyright__ = "(c) Copyright IBM Corp. 2018" |
|
__version__ = "0.1" |
|
__date__ = "Jan 12 2018" |
|
|
|
from copy import deepcopy |
|
from rdkit import Chem |
|
from rdkit import RDLogger |
|
import networkx as nx |
|
import numpy as np |
|
from ..hypergraph import Hypergraph |
|
from ..graph_grammar.symbols import TSymbol, BondSymbol |
|
|
|
|
|
lg = RDLogger.logger() |
|
lg.setLevel(RDLogger.CRITICAL) |
|
|
|
|
|
class HGGen(object): |
|
""" |
|
load .smi file and yield a hypergraph. |
|
|
|
Attributes |
|
---------- |
|
path_to_file : str |
|
path to .smi file |
|
kekulize : bool |
|
kekulize or not |
|
add_Hs : bool |
|
add implicit hydrogens to the molecule or not. |
|
all_single : bool |
|
if True, all multiple bonds are summarized into a single bond with some attributes |
|
|
|
Yields |
|
------ |
|
Hypergraph |
|
""" |
|
def __init__(self, path_to_file, kekulize=True, add_Hs=False, all_single=True): |
|
self.num_line = 1 |
|
self.mol_gen = Chem.SmilesMolSupplier(path_to_file, titleLine=False) |
|
self.kekulize = kekulize |
|
self.add_Hs = add_Hs |
|
self.all_single = all_single |
|
|
|
def __iter__(self): |
|
return self |
|
|
|
def __next__(self): |
|
''' |
|
each_mol = None |
|
while each_mol is None: |
|
each_mol = next(self.mol_gen) |
|
''' |
|
|
|
each_mol = next(self.mol_gen) |
|
if each_mol is None: |
|
raise ValueError(f'incorrect smiles in line {self.num_line}') |
|
else: |
|
self.num_line += 1 |
|
return mol_to_hg(each_mol, self.kekulize, self.add_Hs) |
|
|
|
|
|
def mol_to_bipartite(mol, kekulize): |
|
""" |
|
get a bipartite representation of a molecule. |
|
|
|
Parameters |
|
---------- |
|
mol : rdkit.Chem.rdchem.Mol |
|
molecule object |
|
|
|
Returns |
|
------- |
|
nx.Graph |
|
a bipartite graph representing which bond is connected to which atoms. |
|
""" |
|
try: |
|
mol = standardize_stereo(mol) |
|
except KeyError: |
|
print(Chem.MolToSmiles(mol)) |
|
raise KeyError |
|
|
|
if kekulize: |
|
Chem.Kekulize(mol) |
|
|
|
bipartite_g = nx.Graph() |
|
for each_atom in mol.GetAtoms(): |
|
bipartite_g.add_node(f"atom_{each_atom.GetIdx()}", |
|
atom_attr=atom_attr(each_atom, kekulize)) |
|
|
|
for each_bond in mol.GetBonds(): |
|
bond_idx = each_bond.GetIdx() |
|
bipartite_g.add_node( |
|
f"bond_{bond_idx}", |
|
bond_attr=bond_attr(each_bond, kekulize)) |
|
bipartite_g.add_edge( |
|
f"atom_{each_bond.GetBeginAtomIdx()}", |
|
f"bond_{bond_idx}") |
|
bipartite_g.add_edge( |
|
f"atom_{each_bond.GetEndAtomIdx()}", |
|
f"bond_{bond_idx}") |
|
return bipartite_g |
|
|
|
|
|
def mol_to_hg(mol, kekulize, add_Hs): |
|
""" |
|
get a bipartite representation of a molecule. |
|
|
|
Parameters |
|
---------- |
|
mol : rdkit.Chem.rdchem.Mol |
|
molecule object |
|
kekulize : bool |
|
kekulize or not |
|
add_Hs : bool |
|
add implicit hydrogens to the molecule or not. |
|
|
|
Returns |
|
------- |
|
Hypergraph |
|
""" |
|
if add_Hs: |
|
mol = Chem.AddHs(mol) |
|
|
|
if kekulize: |
|
Chem.Kekulize(mol) |
|
|
|
bipartite_g = mol_to_bipartite(mol, kekulize) |
|
hg = Hypergraph() |
|
for each_atom in [each_node for each_node in bipartite_g.nodes() |
|
if each_node.startswith('atom_')]: |
|
node_set = set([]) |
|
for each_bond in bipartite_g.adj[each_atom]: |
|
hg.add_node(each_bond, |
|
attr_dict=bipartite_g.nodes[each_bond]['bond_attr']) |
|
node_set.add(each_bond) |
|
hg.add_edge(node_set, |
|
attr_dict=bipartite_g.nodes[each_atom]['atom_attr']) |
|
return hg |
|
|
|
|
|
def hg_to_mol(hg, verbose=False): |
|
""" convert a hypergraph into Mol object |
|
|
|
Parameters |
|
---------- |
|
hg : Hypergraph |
|
|
|
Returns |
|
------- |
|
mol : Chem.RWMol |
|
""" |
|
mol = Chem.RWMol() |
|
atom_dict = {} |
|
bond_set = set([]) |
|
for each_edge in hg.edges: |
|
atom = Chem.Atom(hg.edge_attr(each_edge)['symbol'].symbol) |
|
atom.SetNumExplicitHs(hg.edge_attr(each_edge)['symbol'].num_explicit_Hs) |
|
atom.SetFormalCharge(hg.edge_attr(each_edge)['symbol'].formal_charge) |
|
atom.SetChiralTag( |
|
Chem.rdchem.ChiralType.values[ |
|
hg.edge_attr(each_edge)['symbol'].chirality]) |
|
atom_idx = mol.AddAtom(atom) |
|
atom_dict[each_edge] = atom_idx |
|
|
|
for each_node in hg.nodes: |
|
edge_1, edge_2 = hg.adj_edges(each_node) |
|
if edge_1+edge_2 not in bond_set: |
|
if hg.node_attr(each_node)['symbol'].bond_type <= 3: |
|
num_bond = hg.node_attr(each_node)['symbol'].bond_type |
|
elif hg.node_attr(each_node)['symbol'].bond_type == 12: |
|
num_bond = 1 |
|
else: |
|
raise ValueError(f'too many bonds; {hg.node_attr(each_node)["bond_symbol"].bond_type}') |
|
_ = mol.AddBond(atom_dict[edge_1], |
|
atom_dict[edge_2], |
|
order=Chem.rdchem.BondType.values[num_bond]) |
|
bond_idx = mol.GetBondBetweenAtoms(atom_dict[edge_1], atom_dict[edge_2]).GetIdx() |
|
|
|
|
|
mol.GetBondWithIdx(bond_idx).SetStereo( |
|
Chem.rdchem.BondStereo.values[hg.node_attr(each_node)['symbol'].stereo]) |
|
bond_set.update([edge_1+edge_2]) |
|
bond_set.update([edge_2+edge_1]) |
|
mol.UpdatePropertyCache() |
|
mol = mol.GetMol() |
|
not_stereo_mol = deepcopy(mol) |
|
if Chem.MolFromSmiles(Chem.MolToSmiles(not_stereo_mol)) is None: |
|
raise RuntimeError('no valid molecule was obtained.') |
|
try: |
|
mol = set_stereo(mol) |
|
is_stereo = True |
|
except: |
|
import traceback |
|
traceback.print_exc() |
|
is_stereo = False |
|
mol_tmp = deepcopy(mol) |
|
Chem.SetAromaticity(mol_tmp) |
|
if Chem.MolFromSmiles(Chem.MolToSmiles(mol_tmp)) is not None: |
|
mol = mol_tmp |
|
else: |
|
if Chem.MolFromSmiles(Chem.MolToSmiles(mol)) is None: |
|
mol = not_stereo_mol |
|
mol.UpdatePropertyCache() |
|
Chem.GetSymmSSSR(mol) |
|
mol = Chem.MolFromSmiles(Chem.MolToSmiles(mol)) |
|
if verbose: |
|
return mol, is_stereo |
|
else: |
|
return mol |
|
|
|
def hgs_to_mols(hg_list, ignore_error=False): |
|
if ignore_error: |
|
mol_list = [] |
|
for each_hg in hg_list: |
|
try: |
|
mol = hg_to_mol(each_hg) |
|
except: |
|
mol = None |
|
mol_list.append(mol) |
|
else: |
|
mol_list = [hg_to_mol(each_hg) for each_hg in hg_list] |
|
return mol_list |
|
|
|
def hgs_to_smiles(hg_list, ignore_error=False): |
|
mol_list = hgs_to_mols(hg_list, ignore_error) |
|
smiles_list = [] |
|
for each_mol in mol_list: |
|
try: |
|
smiles_list.append( |
|
Chem.MolToSmiles( |
|
Chem.MolFromSmiles( |
|
Chem.MolToSmiles( |
|
each_mol)))) |
|
except: |
|
smiles_list.append(None) |
|
return smiles_list |
|
|
|
def atom_attr(atom, kekulize): |
|
""" |
|
get atom's attributes |
|
|
|
Parameters |
|
---------- |
|
atom : rdkit.Chem.rdchem.Atom |
|
kekulize : bool |
|
kekulize or not |
|
|
|
Returns |
|
------- |
|
atom_attr : dict |
|
"is_aromatic" : bool |
|
the atom is aromatic or not. |
|
"smarts" : str |
|
SMARTS representation of the atom. |
|
""" |
|
if kekulize: |
|
return {'terminal': True, |
|
'is_in_ring': atom.IsInRing(), |
|
'symbol': TSymbol(degree=0, |
|
|
|
is_aromatic=False, |
|
symbol=atom.GetSymbol(), |
|
num_explicit_Hs=atom.GetNumExplicitHs(), |
|
formal_charge=atom.GetFormalCharge(), |
|
chirality=atom.GetChiralTag().real |
|
)} |
|
else: |
|
return {'terminal': True, |
|
'is_in_ring': atom.IsInRing(), |
|
'symbol': TSymbol(degree=0, |
|
|
|
is_aromatic=atom.GetIsAromatic(), |
|
symbol=atom.GetSymbol(), |
|
num_explicit_Hs=atom.GetNumExplicitHs(), |
|
formal_charge=atom.GetFormalCharge(), |
|
chirality=atom.GetChiralTag().real |
|
)} |
|
|
|
def bond_attr(bond, kekulize): |
|
""" |
|
get atom's attributes |
|
|
|
Parameters |
|
---------- |
|
bond : rdkit.Chem.rdchem.Bond |
|
kekulize : bool |
|
kekulize or not |
|
|
|
Returns |
|
------- |
|
bond_attr : dict |
|
"bond_type" : int |
|
{0: rdkit.Chem.rdchem.BondType.UNSPECIFIED, |
|
1: rdkit.Chem.rdchem.BondType.SINGLE, |
|
2: rdkit.Chem.rdchem.BondType.DOUBLE, |
|
3: rdkit.Chem.rdchem.BondType.TRIPLE, |
|
4: rdkit.Chem.rdchem.BondType.QUADRUPLE, |
|
5: rdkit.Chem.rdchem.BondType.QUINTUPLE, |
|
6: rdkit.Chem.rdchem.BondType.HEXTUPLE, |
|
7: rdkit.Chem.rdchem.BondType.ONEANDAHALF, |
|
8: rdkit.Chem.rdchem.BondType.TWOANDAHALF, |
|
9: rdkit.Chem.rdchem.BondType.THREEANDAHALF, |
|
10: rdkit.Chem.rdchem.BondType.FOURANDAHALF, |
|
11: rdkit.Chem.rdchem.BondType.FIVEANDAHALF, |
|
12: rdkit.Chem.rdchem.BondType.AROMATIC, |
|
13: rdkit.Chem.rdchem.BondType.IONIC, |
|
14: rdkit.Chem.rdchem.BondType.HYDROGEN, |
|
15: rdkit.Chem.rdchem.BondType.THREECENTER, |
|
16: rdkit.Chem.rdchem.BondType.DATIVEONE, |
|
17: rdkit.Chem.rdchem.BondType.DATIVE, |
|
18: rdkit.Chem.rdchem.BondType.DATIVEL, |
|
19: rdkit.Chem.rdchem.BondType.DATIVER, |
|
20: rdkit.Chem.rdchem.BondType.OTHER, |
|
21: rdkit.Chem.rdchem.BondType.ZERO} |
|
""" |
|
if kekulize: |
|
is_aromatic = False |
|
if bond.GetBondType().real == 12: |
|
bond_type = 1 |
|
else: |
|
bond_type = bond.GetBondType().real |
|
else: |
|
is_aromatic = bond.GetIsAromatic() |
|
bond_type = bond.GetBondType().real |
|
return {'symbol': BondSymbol(is_aromatic=is_aromatic, |
|
bond_type=bond_type, |
|
stereo=int(bond.GetStereo())), |
|
'is_in_ring': bond.IsInRing()} |
|
|
|
|
|
def standardize_stereo(mol): |
|
''' |
|
0: rdkit.Chem.rdchem.BondDir.NONE, |
|
1: rdkit.Chem.rdchem.BondDir.BEGINWEDGE, |
|
2: rdkit.Chem.rdchem.BondDir.BEGINDASH, |
|
3: rdkit.Chem.rdchem.BondDir.ENDDOWNRIGHT, |
|
4: rdkit.Chem.rdchem.BondDir.ENDUPRIGHT, |
|
|
|
''' |
|
|
|
for each_bond in mol.GetBonds(): |
|
if int(each_bond.GetStereo()) in [2, 3]: |
|
begin_stereo_atom_idx = each_bond.GetBeginAtomIdx() |
|
end_stereo_atom_idx = each_bond.GetEndAtomIdx() |
|
atom_idx_1 = each_bond.GetStereoAtoms()[0] |
|
atom_idx_2 = each_bond.GetStereoAtoms()[1] |
|
if mol.GetBondBetweenAtoms(atom_idx_1, begin_stereo_atom_idx): |
|
begin_atom_idx = atom_idx_1 |
|
end_atom_idx = atom_idx_2 |
|
else: |
|
begin_atom_idx = atom_idx_2 |
|
end_atom_idx = atom_idx_1 |
|
|
|
begin_another_atom_idx = None |
|
assert len(mol.GetAtomWithIdx(begin_stereo_atom_idx).GetNeighbors()) <= 3 |
|
for each_neighbor in mol.GetAtomWithIdx(begin_stereo_atom_idx).GetNeighbors(): |
|
each_neighbor_idx = each_neighbor.GetIdx() |
|
if each_neighbor_idx not in [end_stereo_atom_idx, begin_atom_idx]: |
|
begin_another_atom_idx = each_neighbor_idx |
|
|
|
end_another_atom_idx = None |
|
assert len(mol.GetAtomWithIdx(end_stereo_atom_idx).GetNeighbors()) <= 3 |
|
for each_neighbor in mol.GetAtomWithIdx(end_stereo_atom_idx).GetNeighbors(): |
|
each_neighbor_idx = each_neighbor.GetIdx() |
|
if each_neighbor_idx not in [begin_stereo_atom_idx, end_atom_idx]: |
|
end_another_atom_idx = each_neighbor_idx |
|
|
|
''' |
|
relationship between begin_atom_idx and end_atom_idx is encoded in GetStereo |
|
''' |
|
begin_atom_rank = int(mol.GetAtomWithIdx(begin_atom_idx).GetProp('_CIPRank')) |
|
end_atom_rank = int(mol.GetAtomWithIdx(end_atom_idx).GetProp('_CIPRank')) |
|
try: |
|
begin_another_atom_rank = int(mol.GetAtomWithIdx(begin_another_atom_idx).GetProp('_CIPRank')) |
|
except: |
|
begin_another_atom_rank = np.inf |
|
try: |
|
end_another_atom_rank = int(mol.GetAtomWithIdx(end_another_atom_idx).GetProp('_CIPRank')) |
|
except: |
|
end_another_atom_rank = np.inf |
|
if begin_atom_rank < begin_another_atom_rank\ |
|
and end_atom_rank < end_another_atom_rank: |
|
pass |
|
elif begin_atom_rank < begin_another_atom_rank\ |
|
and end_atom_rank > end_another_atom_rank: |
|
|
|
if each_bond.GetStereo() == 2: |
|
|
|
each_bond.SetStereo(Chem.rdchem.BondStereo.values[3]) |
|
|
|
mol = safe_set_bond_dir(mol, begin_atom_idx, begin_stereo_atom_idx, 3) |
|
mol = safe_set_bond_dir(mol, begin_another_atom_idx, begin_stereo_atom_idx, 0) |
|
mol = safe_set_bond_dir(mol, end_atom_idx, end_stereo_atom_idx, 0) |
|
mol = safe_set_bond_dir(mol, end_another_atom_idx, end_stereo_atom_idx, 3) |
|
elif each_bond.GetStereo() == 3: |
|
|
|
each_bond.SetStereo(Chem.rdchem.BondStereo.values[2]) |
|
|
|
mol = safe_set_bond_dir(mol, begin_atom_idx, begin_stereo_atom_idx, 3) |
|
mol = safe_set_bond_dir(mol, begin_another_atom_idx, begin_stereo_atom_idx, 0) |
|
mol = safe_set_bond_dir(mol, end_atom_idx, end_stereo_atom_idx, 0) |
|
mol = safe_set_bond_dir(mol, end_another_atom_idx, end_stereo_atom_idx, 4) |
|
else: |
|
raise ValueError |
|
each_bond.SetStereoAtoms(begin_atom_idx, end_another_atom_idx) |
|
elif begin_atom_rank > begin_another_atom_rank\ |
|
and end_atom_rank < end_another_atom_rank: |
|
|
|
if each_bond.GetStereo() == 2: |
|
|
|
each_bond.SetStereo(Chem.rdchem.BondStereo.values[3]) |
|
|
|
mol = safe_set_bond_dir(mol, begin_atom_idx, begin_stereo_atom_idx, 0) |
|
mol = safe_set_bond_dir(mol, begin_another_atom_idx, begin_stereo_atom_idx, 4) |
|
mol = safe_set_bond_dir(mol, end_atom_idx, end_stereo_atom_idx, 4) |
|
mol = safe_set_bond_dir(mol, end_another_atom_idx, end_stereo_atom_idx, 0) |
|
elif each_bond.GetStereo() == 3: |
|
|
|
each_bond.SetStereo(Chem.rdchem.BondStereo.values[2]) |
|
|
|
mol = safe_set_bond_dir(mol, begin_atom_idx, begin_stereo_atom_idx, 0) |
|
mol = safe_set_bond_dir(mol, begin_another_atom_idx, begin_stereo_atom_idx, 4) |
|
mol = safe_set_bond_dir(mol, end_atom_idx, end_stereo_atom_idx, 3) |
|
mol = safe_set_bond_dir(mol, end_another_atom_idx, end_stereo_atom_idx, 0) |
|
else: |
|
raise ValueError |
|
each_bond.SetStereoAtoms(begin_another_atom_idx, end_atom_idx) |
|
elif begin_atom_rank > begin_another_atom_rank\ |
|
and end_atom_rank > end_another_atom_rank: |
|
|
|
if each_bond.GetStereo() == 2: |
|
|
|
mol = safe_set_bond_dir(mol, begin_atom_idx, begin_stereo_atom_idx, 0) |
|
mol = safe_set_bond_dir(mol, begin_another_atom_idx, begin_stereo_atom_idx, 4) |
|
mol = safe_set_bond_dir(mol, end_atom_idx, end_stereo_atom_idx, 0) |
|
mol = safe_set_bond_dir(mol, end_another_atom_idx, end_stereo_atom_idx, 3) |
|
elif each_bond.GetStereo() == 3: |
|
|
|
mol = safe_set_bond_dir(mol, begin_atom_idx, begin_stereo_atom_idx, 0) |
|
mol = safe_set_bond_dir(mol, begin_another_atom_idx, begin_stereo_atom_idx, 4) |
|
mol = safe_set_bond_dir(mol, end_atom_idx, end_stereo_atom_idx, 0) |
|
mol = safe_set_bond_dir(mol, end_another_atom_idx, end_stereo_atom_idx, 4) |
|
else: |
|
raise ValueError |
|
each_bond.SetStereoAtoms(begin_another_atom_idx, end_another_atom_idx) |
|
else: |
|
raise RuntimeError |
|
return mol |
|
|
|
|
|
def set_stereo(mol): |
|
''' |
|
0: rdkit.Chem.rdchem.BondDir.NONE, |
|
1: rdkit.Chem.rdchem.BondDir.BEGINWEDGE, |
|
2: rdkit.Chem.rdchem.BondDir.BEGINDASH, |
|
3: rdkit.Chem.rdchem.BondDir.ENDDOWNRIGHT, |
|
4: rdkit.Chem.rdchem.BondDir.ENDUPRIGHT, |
|
''' |
|
_mol = Chem.MolFromSmiles(Chem.MolToSmiles(mol)) |
|
Chem.Kekulize(_mol, True) |
|
substruct_match = mol.GetSubstructMatch(_mol) |
|
if not substruct_match: |
|
''' mol and _mol are kekulized. |
|
sometimes, the order of '=' and '-' changes, which causes mol and _mol not matched. |
|
''' |
|
Chem.SetAromaticity(mol) |
|
Chem.SetAromaticity(_mol) |
|
substruct_match = mol.GetSubstructMatch(_mol) |
|
try: |
|
atom_match = {substruct_match[_mol_atom_idx]: _mol_atom_idx for _mol_atom_idx in range(_mol.GetNumAtoms())} |
|
except: |
|
raise ValueError('two molecules obtained from the same data do not match.') |
|
|
|
for each_bond in mol.GetBonds(): |
|
begin_atom_idx = each_bond.GetBeginAtomIdx() |
|
end_atom_idx = each_bond.GetEndAtomIdx() |
|
_bond = _mol.GetBondBetweenAtoms(atom_match[begin_atom_idx], atom_match[end_atom_idx]) |
|
_bond.SetStereo(each_bond.GetStereo()) |
|
|
|
mol = _mol |
|
for each_bond in mol.GetBonds(): |
|
if int(each_bond.GetStereo()) in [2, 3]: |
|
begin_stereo_atom_idx = each_bond.GetBeginAtomIdx() |
|
end_stereo_atom_idx = each_bond.GetEndAtomIdx() |
|
begin_atom_idx_set = set([each_neighbor.GetIdx() |
|
for each_neighbor |
|
in mol.GetAtomWithIdx(begin_stereo_atom_idx).GetNeighbors() |
|
if each_neighbor.GetIdx() != end_stereo_atom_idx]) |
|
end_atom_idx_set = set([each_neighbor.GetIdx() |
|
for each_neighbor |
|
in mol.GetAtomWithIdx(end_stereo_atom_idx).GetNeighbors() |
|
if each_neighbor.GetIdx() != begin_stereo_atom_idx]) |
|
if not begin_atom_idx_set: |
|
each_bond.SetStereo(Chem.rdchem.BondStereo(0)) |
|
continue |
|
if not end_atom_idx_set: |
|
each_bond.SetStereo(Chem.rdchem.BondStereo(0)) |
|
continue |
|
if len(begin_atom_idx_set) == 1: |
|
begin_atom_idx = begin_atom_idx_set.pop() |
|
begin_another_atom_idx = None |
|
if len(end_atom_idx_set) == 1: |
|
end_atom_idx = end_atom_idx_set.pop() |
|
end_another_atom_idx = None |
|
if len(begin_atom_idx_set) == 2: |
|
atom_idx_1 = begin_atom_idx_set.pop() |
|
atom_idx_2 = begin_atom_idx_set.pop() |
|
if int(mol.GetAtomWithIdx(atom_idx_1).GetProp('_CIPRank')) < int(mol.GetAtomWithIdx(atom_idx_2).GetProp('_CIPRank')): |
|
begin_atom_idx = atom_idx_1 |
|
begin_another_atom_idx = atom_idx_2 |
|
else: |
|
begin_atom_idx = atom_idx_2 |
|
begin_another_atom_idx = atom_idx_1 |
|
if len(end_atom_idx_set) == 2: |
|
atom_idx_1 = end_atom_idx_set.pop() |
|
atom_idx_2 = end_atom_idx_set.pop() |
|
if int(mol.GetAtomWithIdx(atom_idx_1).GetProp('_CIPRank')) < int(mol.GetAtomWithIdx(atom_idx_2).GetProp('_CIPRank')): |
|
end_atom_idx = atom_idx_1 |
|
end_another_atom_idx = atom_idx_2 |
|
else: |
|
end_atom_idx = atom_idx_2 |
|
end_another_atom_idx = atom_idx_1 |
|
|
|
if each_bond.GetStereo() == 2: |
|
mol = safe_set_bond_dir(mol, begin_atom_idx, begin_stereo_atom_idx, 3) |
|
mol = safe_set_bond_dir(mol, end_atom_idx, end_stereo_atom_idx, 4) |
|
each_bond.SetStereoAtoms(begin_atom_idx, end_atom_idx) |
|
elif each_bond.GetStereo() == 3: |
|
mol = safe_set_bond_dir(mol, begin_atom_idx, begin_stereo_atom_idx, 3) |
|
mol = safe_set_bond_dir(mol, end_atom_idx, end_stereo_atom_idx, 3) |
|
each_bond.SetStereoAtoms(begin_atom_idx, end_atom_idx) |
|
else: |
|
raise ValueError |
|
return mol |
|
|
|
|
|
def safe_set_bond_dir(mol, atom_idx_1, atom_idx_2, bond_dir_val): |
|
if atom_idx_1 is None or atom_idx_2 is None: |
|
return mol |
|
else: |
|
mol.GetBondBetweenAtoms(atom_idx_1, atom_idx_2).SetBondDir(Chem.rdchem.BondDir.values[bond_dir_val]) |
|
return mol |
|
|
|
|