rdworks 0.51.1__tar.gz → 0.53.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rdworks-0.51.1 → rdworks-0.53.1}/PKG-INFO +1 -1
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/__init__.py +3 -3
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/conf.py +9 -0
- rdworks-0.53.1/src/rdworks/microstates.py +138 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/mol.py +32 -1
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/readin.py +1 -0
- rdworks-0.53.1/src/rdworks/stereoisomers.py +67 -0
- rdworks-0.53.1/src/rdworks/workflow.py +85 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/xtb/wrapper.py +94 -124
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks.egg-info/PKG-INFO +1 -1
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks.egg-info/SOURCES.txt +2 -1
- {rdworks-0.51.1 → rdworks-0.53.1}/tests/test_basics.py +75 -29
- {rdworks-0.51.1 → rdworks-0.53.1}/tests/test_qupkake.py +5 -2
- {rdworks-0.51.1 → rdworks-0.53.1}/tests/test_xtb.py +3 -3
- rdworks-0.51.1/src/rdworks/stereoisomers.py +0 -127
- rdworks-0.51.1/src/rdworks/tautomers.py +0 -20
- {rdworks-0.51.1 → rdworks-0.53.1}/LICENSE +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/README.md +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/pyproject.toml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/setup.cfg +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/autograph/__init__.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/autograph/autograph.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/autograph/centroid.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/autograph/dynamictreecut.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/autograph/nmrclust.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/autograph/rckmeans.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/bitqt/__init__.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/bitqt/bitqt.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/descriptor.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/display.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/ionized.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/matchedseries.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/mollibr.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/pka.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Asinex_fragment.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Astex_RO3.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Baell2010_PAINS/Baell2010A.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Baell2010_PAINS/Baell2010B.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Baell2010_PAINS/Baell2010C.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Baell2010_PAINS/PAINS-less-than-015-hits.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Baell2010_PAINS/PAINS-less-than-150-hits.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Baell2010_PAINS/PAINS-more-than-150-hits.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Baell2010_PAINS/makexml.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Brenk2008_Dundee/makexml.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/CNS.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/BMS.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/Dundee.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/Glaxo.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/Inpharmatica.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/LINT.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/MLSMR.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/PAINS.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/SureChEMBL.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/makexml.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999Acid.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999Base.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999ElPh.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999NuPh.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Hann1999_Glaxo/makexml.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Kazius2005/Kazius2005.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Kazius2005/makexml.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ZINC_druglike.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ZINC_fragment.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ZINC_leadlike.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/fragment.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ionized/simple_smarts_pattern.csv +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ionized/smarts_pattern.csv +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/misc/makexml.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/misc/reactive-part-2.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/misc/reactive-part-3.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/misc/reactive.xml +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/rgroup.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/scaffold.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/std.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/testdata.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/torsion.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/units.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/utils.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/xml.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/xtb/__init__.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks.egg-info/dependency_links.txt +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks.egg-info/requires.txt +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks.egg-info/top_level.txt +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/tests/test_ionized.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/tests/test_round.py +0 -0
- {rdworks-0.51.1 → rdworks-0.53.1}/tests/test_torsion.py +0 -0
@@ -1,11 +1,11 @@
|
|
1
|
-
__version__ = '0.
|
1
|
+
__version__ = '0.53.1'
|
2
2
|
|
3
3
|
from rdworks.conf import Conf
|
4
4
|
from rdworks.mol import Mol
|
5
5
|
from rdworks.mollibr import MolLibr
|
6
6
|
|
7
|
-
from rdworks.
|
8
|
-
|
7
|
+
from rdworks.workflow import complete_stereoisomers, complete_tautomers
|
8
|
+
|
9
9
|
from rdworks.ionized import IonizedStates
|
10
10
|
|
11
11
|
from rdworks.readin import read_csv, merge_csv, read_dataframe, read_smi, read_sdf, read_mae
|
@@ -355,6 +355,15 @@ class Conf:
|
|
355
355
|
return True
|
356
356
|
|
357
357
|
|
358
|
+
def charge(self) -> int:
|
359
|
+
"""Returns molecular formal charge.
|
360
|
+
|
361
|
+
Returns:
|
362
|
+
int: charge
|
363
|
+
"""
|
364
|
+
return self.charge
|
365
|
+
|
366
|
+
|
358
367
|
def positions(self) -> np.array:
|
359
368
|
"""Returns the coordinates.
|
360
369
|
|
@@ -0,0 +1,138 @@
|
|
1
|
+
import numpy as np
|
2
|
+
import math
|
3
|
+
import itertools
|
4
|
+
|
5
|
+
from types import SimpleNamespace
|
6
|
+
from rdworks import Conf, Mol
|
7
|
+
from rdworks.xtb.wrapper import GFN2xTB
|
8
|
+
|
9
|
+
|
10
|
+
kT = 0.001987 * 298.0 # (kcal/mol K), standard condition
|
11
|
+
C = math.log(10) * kT
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
class Microstates():
|
16
|
+
|
17
|
+
def __init__(self, origin: Mol, calculator: str = 'xTB'):
|
18
|
+
self.origin = origin
|
19
|
+
self.calculator = calculator
|
20
|
+
self.basic_sites = []
|
21
|
+
self.acidic_sites = []
|
22
|
+
self.states = []
|
23
|
+
self.mols = []
|
24
|
+
self.reference = None
|
25
|
+
|
26
|
+
# read QupKake results
|
27
|
+
for conf in self.origin:
|
28
|
+
print(conf.props)
|
29
|
+
pka = conf.props.get('pka', None)
|
30
|
+
if pka is None:
|
31
|
+
# no protonation/deprotonation sites
|
32
|
+
continue
|
33
|
+
if isinstance(pka, str) and pka.startswith('tensor'):
|
34
|
+
# ex. 'tensor(9.5784)'
|
35
|
+
pka = float(pka.replace('tensor(','').replace(')',''))
|
36
|
+
if conf.props.get('pka_type') == 'basic':
|
37
|
+
self.basic_sites.append(conf.props.get('idx'))
|
38
|
+
elif conf.props.get('pka_type') == 'acidic':
|
39
|
+
self.acidic_sites.append(conf.props.get('idx'))
|
40
|
+
|
41
|
+
# enumerate protonation/deprotonation sites to generate microstates
|
42
|
+
|
43
|
+
np = len(self.basic_sites)
|
44
|
+
nd = len(self.acidic_sites)
|
45
|
+
P = [c for n in range(np+1) for c in itertools.combinations(self.basic_sites, n)]
|
46
|
+
D = [c for n in range(nd+1) for c in itertools.combinations(self.acidic_sites, n)]
|
47
|
+
|
48
|
+
PD = list(itertools.product(P, D))
|
49
|
+
|
50
|
+
for (p, d) in PD:
|
51
|
+
conf = self.origin.confs[0].copy()
|
52
|
+
conf = conf.protonate(p).deprotonate(d).optimize(calculator=calculator)
|
53
|
+
charge = len(p) - len(d)
|
54
|
+
self.states.append(SimpleNamespace(
|
55
|
+
charge=charge,
|
56
|
+
protonation_sites=p,
|
57
|
+
deprotonation_sites=d,
|
58
|
+
conf=conf,
|
59
|
+
smiles=Mol(conf).smiles,
|
60
|
+
delta_m=None,
|
61
|
+
PE=None))
|
62
|
+
|
63
|
+
# sort microstates by ascending charges
|
64
|
+
self.states = sorted(self.states, key=lambda x: x.charge)
|
65
|
+
|
66
|
+
|
67
|
+
@staticmethod
|
68
|
+
def Boltzmann_weighted_average(potential_energies: list) -> float:
|
69
|
+
"""Calculate Boltzmann weighted average potential energy at pH 0.
|
70
|
+
|
71
|
+
Args:
|
72
|
+
potential_energies (list): a list of potential energies.
|
73
|
+
|
74
|
+
Returns:
|
75
|
+
float: Boltzmann weighted average potential energy.
|
76
|
+
"""
|
77
|
+
pe_array = np.array(potential_energies)
|
78
|
+
pe = pe_array - min(potential_energies)
|
79
|
+
Boltzmann_factors = np.exp(-pe/kT)
|
80
|
+
Z = np.sum(Boltzmann_factors)
|
81
|
+
p = Boltzmann_factors/Z
|
82
|
+
|
83
|
+
return float(np.dot(p, pe_array))
|
84
|
+
|
85
|
+
|
86
|
+
def potential_energy(self) -> None:
|
87
|
+
for microstate in self.states:
|
88
|
+
mol = Mol(microstate.conf).make_confs(n=4).optimize_confs()
|
89
|
+
# mol = mol.drop_confs(similar=True, similar_rmsd=0.3, verbose=True)
|
90
|
+
# mol = mol.optimize_confs(calculator=calculator)
|
91
|
+
# mol = mol.drop_confs(k=10, window=15.0, verbose=True)
|
92
|
+
PE = []
|
93
|
+
for conf in mol.confs:
|
94
|
+
conf = conf.optimize(calculator=self.calculator, verbose=True)
|
95
|
+
# GFN2xTB requires 3D coordinates
|
96
|
+
# xtb = GFN2xTB(conf.rdmol).singlepoint(water='cpcmx', verbose=True)
|
97
|
+
xtb = GFN2xTB(conf.rdmol).singlepoint(verbose=True)
|
98
|
+
PE.append(xtb.PE)
|
99
|
+
# SimpleNamespace(
|
100
|
+
# PE = datadict['total energy'] * hartree2kcalpermol,
|
101
|
+
# Gsolv = Gsolv,
|
102
|
+
# charges = datadict['partial charges'],
|
103
|
+
# wbo = Wiberg_bond_orders,
|
104
|
+
# )
|
105
|
+
print("PE=", PE)
|
106
|
+
microstate.PE = self.Boltzmann_weighted_average(PE)
|
107
|
+
print("Boltzmann weighted=", microstate.PE)
|
108
|
+
|
109
|
+
self.mols.append(mol)
|
110
|
+
print("microstate.energy", microstate)
|
111
|
+
|
112
|
+
|
113
|
+
def populations(self, pH: float) -> list[tuple]:
|
114
|
+
# set the lowest dG as the reference
|
115
|
+
self.reference = self.states[np.argmin([microstate.PE for microstate in self.states])]
|
116
|
+
for microstate in self.states:
|
117
|
+
microstate.delta_m = microstate.charge - self.reference.charge
|
118
|
+
dG = []
|
119
|
+
for microstate in self.states:
|
120
|
+
dG.append((microstate.PE - self.reference.PE) + microstate.delta_m * C * pH)
|
121
|
+
dG = np.array(dG)
|
122
|
+
|
123
|
+
print("dG=", dG)
|
124
|
+
Boltzmann_factors = np.exp(-dG/kT)
|
125
|
+
Z = np.sum(Boltzmann_factors)
|
126
|
+
p = Boltzmann_factors/Z
|
127
|
+
idx_p = sorted(list(enumerate(p)), key=lambda x: x[1], reverse=True)
|
128
|
+
# [(0, p0), (1, p1), ...]
|
129
|
+
|
130
|
+
return idx_p
|
131
|
+
|
132
|
+
|
133
|
+
def count(self) -> int:
|
134
|
+
return len(self.states)
|
135
|
+
|
136
|
+
|
137
|
+
def get_mol(self, idx: int) -> Mol:
|
138
|
+
return self.mols[idx]
|
@@ -28,7 +28,6 @@ from rdkit.Chem import (
|
|
28
28
|
Draw, rdDepictor, inchi,
|
29
29
|
rdDistGeom, rdMolAlign, rdMolTransforms, rdmolops
|
30
30
|
)
|
31
|
-
from rdkit.Chem.Draw import rdMolDraw2D
|
32
31
|
from rdkit.ML.Cluster import Butina
|
33
32
|
from PIL import Image
|
34
33
|
|
@@ -43,6 +42,8 @@ from rdworks.autograph import NMRCLUST, DynamicTreeCut, RCKmeans, AutoGraph
|
|
43
42
|
from rdworks.bitqt import BitQT
|
44
43
|
from rdworks.torsion import create_torsion_fragment, get_torsion_atoms
|
45
44
|
from rdworks.display import render_svg, render_png
|
45
|
+
from rdworks.stereoisomers import enumerate_stereoisomers, enumerate_ring_bond_stereoisomers
|
46
|
+
|
46
47
|
|
47
48
|
from scour.scour import scourString
|
48
49
|
|
@@ -329,6 +330,36 @@ class Mol:
|
|
329
330
|
return self
|
330
331
|
|
331
332
|
|
333
|
+
def count_stereoisomers(self) -> int:
|
334
|
+
"""Counts number of all possible stereoisomers ignoring the current stereochemistry.
|
335
|
+
|
336
|
+
Returns:
|
337
|
+
int: number of stereoisomers.
|
338
|
+
"""
|
339
|
+
|
340
|
+
ring_bond_stereo_info = self.get_ring_bond_stereo()
|
341
|
+
mol = self.copy()
|
342
|
+
# remove stereochemistry
|
343
|
+
mol = mol.remove_stereo()
|
344
|
+
rdmols = enumerate_stereoisomers(mol.rdmol)
|
345
|
+
# ring bond stereo is not properly enumerated
|
346
|
+
# cis/trans information is lost if stereochemistry is removed,
|
347
|
+
# which cannot be enumerated by EnumerateStereoisomers() function
|
348
|
+
# so enumerate_ring_bond_stereoisomers() is introduced
|
349
|
+
if len(ring_bond_stereo_info) > 0:
|
350
|
+
ring_cis_trans = []
|
351
|
+
for rdmol in rdmols:
|
352
|
+
ring_cis_trans += enumerate_ring_bond_stereoisomers(rdmol,
|
353
|
+
ring_bond_stereo_info,
|
354
|
+
override=True)
|
355
|
+
if len(ring_cis_trans) > 0:
|
356
|
+
rdmols = ring_cis_trans
|
357
|
+
|
358
|
+
unique_rdmols = set([Chem.MolToSmiles(rdmol) for rdmol in rdmols])
|
359
|
+
|
360
|
+
return len(unique_rdmols)
|
361
|
+
|
362
|
+
|
332
363
|
def make_confs(self, n: int = 50, method: str = 'ETKDG', **kwargs) -> Self:
|
333
364
|
"""Generates 3D conformers.
|
334
365
|
|
@@ -232,6 +232,7 @@ def read_sdf(path:str | Path, std:bool=False, confs:bool=False, props:bool=True,
|
|
232
232
|
# start a new molecule
|
233
233
|
rdmol_2d = Chem.RemoveHs(rdmol)
|
234
234
|
AllChem.Compute2DCoords(rdmol_2d)
|
235
|
+
# initialize a new molecule with the H-removed 2D
|
235
236
|
new_mol = Mol(rdmol_2d, isomer_name, std=False) # atom indices remain unchanged.
|
236
237
|
new_conf = Conf(rdmol)
|
237
238
|
new_conf.props.update(props)
|
@@ -0,0 +1,67 @@
|
|
1
|
+
from rdkit import Chem
|
2
|
+
from rdkit.Chem.EnumerateStereoisomers import EnumerateStereoisomers, StereoEnumerationOptions
|
3
|
+
|
4
|
+
|
5
|
+
def enumerate_stereoisomers(rdmol: Chem.Mol) -> list[Chem.Mol]:
|
6
|
+
"""Returns enumerated stereoisomers.
|
7
|
+
|
8
|
+
Args:
|
9
|
+
rdmol (Chem.Mol): input molecule.
|
10
|
+
|
11
|
+
Returns:
|
12
|
+
List[Chem.Mol]: a list of enumerated stereoisomers.
|
13
|
+
"""
|
14
|
+
return list(EnumerateStereoisomers(
|
15
|
+
rdmol,
|
16
|
+
options=StereoEnumerationOptions(
|
17
|
+
tryEmbedding=False,
|
18
|
+
onlyUnassigned=True,
|
19
|
+
maxIsomers=1024,
|
20
|
+
rand=None,
|
21
|
+
unique=True,
|
22
|
+
onlyStereoGroups=False,
|
23
|
+
)))
|
24
|
+
|
25
|
+
|
26
|
+
def enumerate_ring_bond_stereoisomers(rdmol: Chem.Mol,
|
27
|
+
ring_bond_stereo_info: list[tuple],
|
28
|
+
override: bool = False) -> list[Chem.Mol]:
|
29
|
+
"""Enumerates unspecified double bond stereochemistry (cis/trans).
|
30
|
+
|
31
|
+
<pre>
|
32
|
+
a1 a4 a1
|
33
|
+
\ / \
|
34
|
+
a2=a3 a2=a3
|
35
|
+
\
|
36
|
+
a4
|
37
|
+
</pre>
|
38
|
+
|
39
|
+
Args:
|
40
|
+
rdmol (Chem.Mol): input molecule.
|
41
|
+
ring_bond_stereo_info (List[Tuple]):
|
42
|
+
ring_bond_stereo_info will be set when .remove_stereo() is called.
|
43
|
+
bond_stereo_info = [(bond_idx, bond_stereo_descriptor), ..] where
|
44
|
+
bond_stereo_descriptor is `Chem.StereoDescriptor.Bond_Cis` or
|
45
|
+
`Chem.StereoDescriptor.Bond_Trans`, or `Chem.StereoDescriptor.NoValue`.
|
46
|
+
override (bool, optional): _description_. Defaults to False.
|
47
|
+
|
48
|
+
Returns:
|
49
|
+
List[Chem.Mol]: list of enumerated stereoisomers.
|
50
|
+
"""
|
51
|
+
isomers = []
|
52
|
+
for bond_idx, bond_stereo_desc in ring_bond_stereo_info:
|
53
|
+
if (bond_stereo_desc == Chem.StereoDescriptor.NoValue) or override:
|
54
|
+
bond = rdmol.GetBondWithIdx(bond_idx)
|
55
|
+
(a2,a3) = (bond.GetBeginAtom(), bond.GetEndAtom())
|
56
|
+
a2_idx = a2.GetIdx()
|
57
|
+
a3_idx = a3.GetIdx()
|
58
|
+
a1_idx = sorted([(a.GetIdx(), a.GetAtomicNum()) for a in a2.GetNeighbors() if a.GetIdx() != a3_idx], key=lambda x: x[1], reverse=True)[0][0]
|
59
|
+
a4_idx = sorted([(a.GetIdx(), a.GetAtomicNum()) for a in a3.GetNeighbors() if a.GetIdx() != a2_idx], key=lambda x: x[1], reverse=True)[0][0]
|
60
|
+
bond.SetStereoAtoms(a1_idx, a4_idx) # need to set reference atoms
|
61
|
+
# cis
|
62
|
+
bond.SetStereo(Chem.BondStereo.STEREOCIS)
|
63
|
+
isomers.append(Chem.Mol(rdmol))
|
64
|
+
# trans
|
65
|
+
bond.SetStereo(Chem.BondStereo.STEREOTRANS)
|
66
|
+
isomers.append(Chem.Mol(rdmol))
|
67
|
+
return isomers
|
@@ -0,0 +1,85 @@
|
|
1
|
+
|
2
|
+
from rdworks.stereoisomers import enumerate_stereoisomers, enumerate_ring_bond_stereoisomers
|
3
|
+
from rdworks.mol import Mol
|
4
|
+
from rdworks.mollibr import MolLibr
|
5
|
+
|
6
|
+
from rdkit import Chem
|
7
|
+
from rdkit.Chem.MolStandardize import rdMolStandardize
|
8
|
+
|
9
|
+
|
10
|
+
def complete_stereoisomers(molecular_input: str | Chem.Mol | Mol,
|
11
|
+
name: str | None = None,
|
12
|
+
std: bool = False,
|
13
|
+
override: bool = False,
|
14
|
+
**kwargs) -> MolLibr:
|
15
|
+
"""Completes stereoisomers and returns a rdworks.MolLibr.
|
16
|
+
|
17
|
+
Args:
|
18
|
+
molecular_input (Union[Mol, str, Chem.Mol]): input molecule.
|
19
|
+
name (Optional[str], optional): name of the molecule. Defaults to None.
|
20
|
+
std (bool, optional): whether to standardize the input. Defaults to False.
|
21
|
+
override (bool, optional): whether to override input stereoisomers. Defaults to False.
|
22
|
+
|
23
|
+
Raises:
|
24
|
+
TypeError: if `molecular_input` is not rdworks.Mol, SMILES, or rdkit.Chem.Mol object.
|
25
|
+
|
26
|
+
Returns:
|
27
|
+
MolLibr: a library of complete stereoisomers.
|
28
|
+
"""
|
29
|
+
if isinstance(molecular_input, Mol):
|
30
|
+
if name:
|
31
|
+
mol = molecular_input.rename(name)
|
32
|
+
else:
|
33
|
+
mol = molecular_input
|
34
|
+
elif isinstance(molecular_input, str) or isinstance(molecular_input, Chem.Mol):
|
35
|
+
mol = Mol(molecular_input, name, std)
|
36
|
+
else:
|
37
|
+
raise TypeError('complete_stereoisomers() expects rdworks.Mol, SMILES or rdkit.Chem.Mol object')
|
38
|
+
|
39
|
+
ring_bond_stereo_info = mol.get_ring_bond_stereo()
|
40
|
+
|
41
|
+
if override:
|
42
|
+
mol = mol.remove_stereo()
|
43
|
+
|
44
|
+
rdmols = enumerate_stereoisomers(mol.rdmol)
|
45
|
+
# ring bond stereo is not properly enumerated
|
46
|
+
# cis/trans information is lost if stereochemistry is removed,
|
47
|
+
# which cannot be enumerated by EnumerateStereoisomers() function
|
48
|
+
# so enumerate_ring_bond_stereoisomers() is introduced
|
49
|
+
if len(ring_bond_stereo_info) > 0:
|
50
|
+
ring_cis_trans = []
|
51
|
+
for rdmol in rdmols:
|
52
|
+
ring_cis_trans += enumerate_ring_bond_stereoisomers(rdmol,
|
53
|
+
ring_bond_stereo_info,
|
54
|
+
override=override)
|
55
|
+
if len(ring_cis_trans) > 0:
|
56
|
+
rdmols = ring_cis_trans
|
57
|
+
|
58
|
+
if len(rdmols) > 1:
|
59
|
+
libr = MolLibr(rdmols).unique().rename(mol.name, sep='.').compute(**kwargs)
|
60
|
+
else:
|
61
|
+
libr = MolLibr(rdmols).rename(mol.name).compute(**kwargs)
|
62
|
+
|
63
|
+
for _ in libr:
|
64
|
+
_.props.update(mol.props)
|
65
|
+
|
66
|
+
return libr
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
def complete_tautomers(mol: Mol, **kwargs) -> MolLibr:
|
71
|
+
"""Returns a library of enumerated tautomers.
|
72
|
+
|
73
|
+
Args:
|
74
|
+
mol (Mol): input molecule.
|
75
|
+
|
76
|
+
Returns:
|
77
|
+
MolLibr: a library of enumerated tautomers.
|
78
|
+
"""
|
79
|
+
enumerator = rdMolStandardize.TautomerEnumerator()
|
80
|
+
rdmols = list(enumerator.Enumerate(mol.rdmol))
|
81
|
+
|
82
|
+
if len(rdmols) > 1:
|
83
|
+
return MolLibr(rdmols).unique().rename(mol.name, sep='.').compute(**kwargs)
|
84
|
+
|
85
|
+
return MolLibr(rdmols).compute(**kwargs)
|