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.
Files changed (87) hide show
  1. {rdworks-0.51.1 → rdworks-0.53.1}/PKG-INFO +1 -1
  2. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/__init__.py +3 -3
  3. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/conf.py +9 -0
  4. rdworks-0.53.1/src/rdworks/microstates.py +138 -0
  5. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/mol.py +32 -1
  6. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/readin.py +1 -0
  7. rdworks-0.53.1/src/rdworks/stereoisomers.py +67 -0
  8. rdworks-0.53.1/src/rdworks/workflow.py +85 -0
  9. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/xtb/wrapper.py +94 -124
  10. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks.egg-info/PKG-INFO +1 -1
  11. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks.egg-info/SOURCES.txt +2 -1
  12. {rdworks-0.51.1 → rdworks-0.53.1}/tests/test_basics.py +75 -29
  13. {rdworks-0.51.1 → rdworks-0.53.1}/tests/test_qupkake.py +5 -2
  14. {rdworks-0.51.1 → rdworks-0.53.1}/tests/test_xtb.py +3 -3
  15. rdworks-0.51.1/src/rdworks/stereoisomers.py +0 -127
  16. rdworks-0.51.1/src/rdworks/tautomers.py +0 -20
  17. {rdworks-0.51.1 → rdworks-0.53.1}/LICENSE +0 -0
  18. {rdworks-0.51.1 → rdworks-0.53.1}/README.md +0 -0
  19. {rdworks-0.51.1 → rdworks-0.53.1}/pyproject.toml +0 -0
  20. {rdworks-0.51.1 → rdworks-0.53.1}/setup.cfg +0 -0
  21. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/autograph/__init__.py +0 -0
  22. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/autograph/autograph.py +0 -0
  23. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/autograph/centroid.py +0 -0
  24. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/autograph/dynamictreecut.py +0 -0
  25. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/autograph/nmrclust.py +0 -0
  26. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/autograph/rckmeans.py +0 -0
  27. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/bitqt/__init__.py +0 -0
  28. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/bitqt/bitqt.py +0 -0
  29. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/descriptor.py +0 -0
  30. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/display.py +0 -0
  31. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/ionized.py +0 -0
  32. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/matchedseries.py +0 -0
  33. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/mollibr.py +0 -0
  34. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/pka.py +0 -0
  35. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Asinex_fragment.xml +0 -0
  36. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Astex_RO3.xml +0 -0
  37. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Baell2010_PAINS/Baell2010A.xml +0 -0
  38. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Baell2010_PAINS/Baell2010B.xml +0 -0
  39. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Baell2010_PAINS/Baell2010C.xml +0 -0
  40. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Baell2010_PAINS/PAINS-less-than-015-hits.xml +0 -0
  41. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Baell2010_PAINS/PAINS-less-than-150-hits.xml +0 -0
  42. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Baell2010_PAINS/PAINS-more-than-150-hits.xml +0 -0
  43. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Baell2010_PAINS/makexml.py +0 -0
  44. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Brenk2008_Dundee/makexml.py +0 -0
  45. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/CNS.xml +0 -0
  46. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/BMS.xml +0 -0
  47. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/Dundee.xml +0 -0
  48. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/Glaxo.xml +0 -0
  49. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/Inpharmatica.xml +0 -0
  50. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/LINT.xml +0 -0
  51. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/MLSMR.xml +0 -0
  52. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/PAINS.xml +0 -0
  53. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/SureChEMBL.xml +0 -0
  54. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ChEMBL_Walters/makexml.py +0 -0
  55. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999.xml +0 -0
  56. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999Acid.xml +0 -0
  57. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999Base.xml +0 -0
  58. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999ElPh.xml +0 -0
  59. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Hann1999_Glaxo/Hann1999NuPh.xml +0 -0
  60. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Hann1999_Glaxo/makexml.py +0 -0
  61. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Kazius2005/Kazius2005.xml +0 -0
  62. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/Kazius2005/makexml.py +0 -0
  63. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ZINC_druglike.xml +0 -0
  64. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ZINC_fragment.xml +0 -0
  65. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ZINC_leadlike.xml +0 -0
  66. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/fragment.xml +0 -0
  67. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ionized/simple_smarts_pattern.csv +0 -0
  68. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/ionized/smarts_pattern.csv +0 -0
  69. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/misc/makexml.py +0 -0
  70. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/misc/reactive-part-2.xml +0 -0
  71. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/misc/reactive-part-3.xml +0 -0
  72. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/predefined/misc/reactive.xml +0 -0
  73. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/rgroup.py +0 -0
  74. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/scaffold.py +0 -0
  75. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/std.py +0 -0
  76. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/testdata.py +0 -0
  77. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/torsion.py +0 -0
  78. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/units.py +0 -0
  79. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/utils.py +0 -0
  80. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/xml.py +0 -0
  81. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks/xtb/__init__.py +0 -0
  82. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks.egg-info/dependency_links.txt +0 -0
  83. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks.egg-info/requires.txt +0 -0
  84. {rdworks-0.51.1 → rdworks-0.53.1}/src/rdworks.egg-info/top_level.txt +0 -0
  85. {rdworks-0.51.1 → rdworks-0.53.1}/tests/test_ionized.py +0 -0
  86. {rdworks-0.51.1 → rdworks-0.53.1}/tests/test_round.py +0 -0
  87. {rdworks-0.51.1 → rdworks-0.53.1}/tests/test_torsion.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rdworks
3
- Version: 0.51.1
3
+ Version: 0.53.1
4
4
  Summary: Routine tasks built on RDKit and other tools
5
5
  Author-email: Sung-Hun Bae <sunghun.bae@gmail.com>
6
6
  Maintainer-email: Sung-Hun Bae <sunghun.bae@gmail.com>
@@ -1,11 +1,11 @@
1
- __version__ = '0.51.1'
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.stereoisomers import complete_stereoisomers
8
- from rdworks.tautomers import complete_tautomers
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)