chython 2.19__cp313-cp313-win_amd64.whl
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.
- chython/__init__.py +35 -0
- chython/_functions.py +95 -0
- chython/_java.py +57 -0
- chython/algorithms/__init__.py +18 -0
- chython/algorithms/_isomorphism.cp313-win_amd64.pyd +0 -0
- chython/algorithms/_isomorphism.pyx +189 -0
- chython/algorithms/_rings.cp313-win_amd64.pyd +0 -0
- chython/algorithms/_rings.pyx +478 -0
- chython/algorithms/aromatics/__init__.py +27 -0
- chython/algorithms/aromatics/_rules.py +124 -0
- chython/algorithms/aromatics/kekule.py +532 -0
- chython/algorithms/aromatics/test/__init__.py +18 -0
- chython/algorithms/aromatics/test/test_kekule.py +160 -0
- chython/algorithms/aromatics/test/test_thiele.py +263 -0
- chython/algorithms/aromatics/thiele.py +222 -0
- chython/algorithms/calculate2d/__init__.py +23 -0
- chython/algorithms/calculate2d/clean2d.js +1 -0
- chython/algorithms/calculate2d/molecule.py +191 -0
- chython/algorithms/calculate2d/reaction.py +75 -0
- chython/algorithms/conformers.py +106 -0
- chython/algorithms/depict.py +596 -0
- chython/algorithms/fingerprints/__init__.py +43 -0
- chython/algorithms/fingerprints/linear.py +202 -0
- chython/algorithms/fingerprints/morgan.py +132 -0
- chython/algorithms/fingerprints/test/__init__.py +18 -0
- chython/algorithms/fingerprints/test/test_linear.py +127 -0
- chython/algorithms/fingerprints/test/test_morgan.py +79 -0
- chython/algorithms/groups/__init__.py +212 -0
- chython/algorithms/groups/_functional.py +290 -0
- chython/algorithms/groups/_oxidations.py +70 -0
- chython/algorithms/groups/_protective.py +964 -0
- chython/algorithms/groups/_reactions.py +809 -0
- chython/algorithms/groups/_reductions.py +88 -0
- chython/algorithms/groups/_transformations.py +278 -0
- chython/algorithms/groups/test/__init__.py +18 -0
- chython/algorithms/groups/test/test_deprotection.py +108 -0
- chython/algorithms/groups/test/test_reactions.py +377 -0
- chython/algorithms/isomorphism.py +664 -0
- chython/algorithms/mapping/__init__.py +188 -0
- chython/algorithms/mapping/_groups.py +94 -0
- chython/algorithms/mapping/_reactions.py +72 -0
- chython/algorithms/mapping/attention.py +266 -0
- chython/algorithms/mapping/reconstruct.py +346 -0
- chython/algorithms/mcs.py +201 -0
- chython/algorithms/morgan.py +77 -0
- chython/algorithms/rings.py +178 -0
- chython/algorithms/smiles.py +597 -0
- chython/algorithms/standardize/__init__.py +30 -0
- chython/algorithms/standardize/_groups.py +958 -0
- chython/algorithms/standardize/_isomers.py +330 -0
- chython/algorithms/standardize/_metal_organics.py +189 -0
- chython/algorithms/standardize/_reagents.py +44 -0
- chython/algorithms/standardize/_salts.py +68 -0
- chython/algorithms/standardize/molecule.py +475 -0
- chython/algorithms/standardize/reaction.py +384 -0
- chython/algorithms/standardize/resonance.py +191 -0
- chython/algorithms/standardize/salts.py +128 -0
- chython/algorithms/standardize/saturation.py +373 -0
- chython/algorithms/standardize/test/__init__.py +18 -0
- chython/algorithms/standardize/test/test_canonicalize.py +66 -0
- chython/algorithms/standardize/test/test_groups.py +146 -0
- chython/algorithms/standardize/test/test_isomers.py +198 -0
- chython/algorithms/stereo.py +1215 -0
- chython/algorithms/tautomers/__init__.py +167 -0
- chython/algorithms/tautomers/_acid.py +59 -0
- chython/algorithms/tautomers/_base.py +116 -0
- chython/algorithms/tautomers/_keto_enol.py +107 -0
- chython/algorithms/tautomers/acid_base.py +208 -0
- chython/algorithms/tautomers/heteroarenes.py +103 -0
- chython/algorithms/tautomers/keto_enol.py +143 -0
- chython/algorithms/tautomers/test/__init__.py +18 -0
- chython/algorithms/tautomers/test/test_tautomers.py +80 -0
- chython/algorithms/test/__init__.py +18 -0
- chython/algorithms/test/test_isomorphism.py +58 -0
- chython/algorithms/test/test_smiles.py +76 -0
- chython/algorithms/x3dom.py +350 -0
- chython/containers/__init__.py +48 -0
- chython/containers/_pack_v2.cp313-win_amd64.pyd +0 -0
- chython/containers/_pack_v2.pyx +271 -0
- chython/containers/_unpack_v0v2.cp313-win_amd64.pyd +0 -0
- chython/containers/_unpack_v0v2.pyx +302 -0
- chython/containers/bonds.py +255 -0
- chython/containers/cgr.py +115 -0
- chython/containers/chimera.py +63 -0
- chython/containers/graph.py +199 -0
- chython/containers/molecule.py +817 -0
- chython/containers/query.py +71 -0
- chython/containers/rdkit.py +183 -0
- chython/containers/reaction.py +324 -0
- chython/containers/test/__init__.py +18 -0
- chython/containers/test/test_molecule.py +117 -0
- chython/containers/test/test_pack.py +60 -0
- chython/containers/test/test_rdkit.py +70 -0
- chython/containers/test/test_reaction.py +40 -0
- chython/exceptions.py +114 -0
- chython/files/MRVrw.py +532 -0
- chython/files/PDBrw.py +255 -0
- chython/files/RDFrw.py +309 -0
- chython/files/SDFrw.py +221 -0
- chython/files/__init__.py +30 -0
- chython/files/_convert.py +207 -0
- chython/files/_mapping.py +117 -0
- chython/files/_xyz.cp313-win_amd64.pyd +0 -0
- chython/files/_xyz.pyx +74 -0
- chython/files/daylight/__init__.py +24 -0
- chython/files/daylight/parser.py +157 -0
- chython/files/daylight/smarts.py +107 -0
- chython/files/daylight/smiles.py +260 -0
- chython/files/daylight/test/__init__.py +18 -0
- chython/files/daylight/test/test_daylight_smarts.py +289 -0
- chython/files/daylight/test/test_daylight_smiles.py +101 -0
- chython/files/daylight/test/test_parser.py +118 -0
- chython/files/daylight/test/test_tokenize.py +77 -0
- chython/files/daylight/tokenize.py +376 -0
- chython/files/libinchi/__init__.py +22 -0
- chython/files/libinchi/libinchi.dll +0 -0
- chython/files/libinchi/wrapper.py +554 -0
- chython/files/mdl/__init__.py +25 -0
- chython/files/mdl/emol.py +251 -0
- chython/files/mdl/erxn.py +67 -0
- chython/files/mdl/mol.py +186 -0
- chython/files/mdl/read.py +223 -0
- chython/files/mdl/rxn.py +67 -0
- chython/files/mdl/stereo.py +63 -0
- chython/files/mdl/write.py +201 -0
- chython/files/opsin.py +35 -0
- chython/files/test/__init__.py +0 -0
- chython/files/test/test_inchi.py +27 -0
- chython/files/test/test_mrv.py +47 -0
- chython/files/test/test_sdf_rdf.py +64 -0
- chython/files/test/test_xyz.py +20 -0
- chython/files/xyz.py +78 -0
- chython/periodictable/__init__.py +69 -0
- chython/periodictable/base/__init__.py +25 -0
- chython/periodictable/base/dynamic.py +149 -0
- chython/periodictable/base/element.py +451 -0
- chython/periodictable/base/groups.py +90 -0
- chython/periodictable/base/periods.py +46 -0
- chython/periodictable/base/query.py +473 -0
- chython/periodictable/base/vector.py +119 -0
- chython/periodictable/groupI.py +252 -0
- chython/periodictable/groupII.py +223 -0
- chython/periodictable/groupIII.py +1154 -0
- chython/periodictable/groupIV.py +210 -0
- chython/periodictable/groupIX.py +196 -0
- chython/periodictable/groupV.py +192 -0
- chython/periodictable/groupVI.py +183 -0
- chython/periodictable/groupVII.py +162 -0
- chython/periodictable/groupVIII.py +161 -0
- chython/periodictable/groupX.py +166 -0
- chython/periodictable/groupXI.py +164 -0
- chython/periodictable/groupXII.py +158 -0
- chython/periodictable/groupXIII.py +239 -0
- chython/periodictable/groupXIV.py +262 -0
- chython/periodictable/groupXV.py +276 -0
- chython/periodictable/groupXVI.py +457 -0
- chython/periodictable/groupXVII.py +324 -0
- chython/periodictable/groupXVIII.py +260 -0
- chython/periodictable/test/__init__.py +0 -0
- chython/periodictable/test/test_element.py +100 -0
- chython/reactor/__init__.py +24 -0
- chython/reactor/base.py +222 -0
- chython/reactor/reactor.py +177 -0
- chython/reactor/test/__init__.py +18 -0
- chython/reactor/test/test_reactor.py +40 -0
- chython/reactor/test/test_transformer.py +78 -0
- chython/reactor/transformer.py +72 -0
- chython/utils/__init__.py +50 -0
- chython/utils/free_wilson.py +114 -0
- chython/utils/grid.py +130 -0
- chython/utils/retro.py +139 -0
- chython-2.19.dist-info/METADATA +105 -0
- chython-2.19.dist-info/RECORD +175 -0
- chython-2.19.dist-info/WHEEL +4 -0
- chython-2.19.dist-info/licenses/LICENSE +165 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2026 Ramil Nugmanov <nougmanoff@protonmail.com>
|
|
4
|
+
# This file is part of chython.
|
|
5
|
+
#
|
|
6
|
+
# chython is free software; you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
|
8
|
+
# the Free Software Foundation; either version 3 of the License, or
|
|
9
|
+
# (at your option) any later version.
|
|
10
|
+
#
|
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU Lesser General Public License for more details.
|
|
15
|
+
#
|
|
16
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
17
|
+
# along with this program; if not, see <https://www.gnu.org/licenses/>.
|
|
18
|
+
#
|
|
19
|
+
from collections.abc import Iterator
|
|
20
|
+
from functools import cached_property
|
|
21
|
+
from itertools import permutations
|
|
22
|
+
from ._functional import rules as functional_rules
|
|
23
|
+
from ._oxidations import rules as oxidation_rules
|
|
24
|
+
from ._protective import rules as protective_rules
|
|
25
|
+
from ._reactions import rules as reaction_rules
|
|
26
|
+
from ._reductions import rules as reduction_rules
|
|
27
|
+
from ._transformations import rules as transformation_rules
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class FunctionalGroups:
|
|
31
|
+
__slots__ = ()
|
|
32
|
+
|
|
33
|
+
@cached_property
|
|
34
|
+
def functional_groups(self) -> dict[str, int]:
|
|
35
|
+
"""
|
|
36
|
+
Dict of functional group names to their count in the molecule.
|
|
37
|
+
"""
|
|
38
|
+
found = {}
|
|
39
|
+
for name, q in functional_rules.items():
|
|
40
|
+
c = sum(1 for _ in q.get_mapping(self))
|
|
41
|
+
if c:
|
|
42
|
+
found[name] = c
|
|
43
|
+
return found
|
|
44
|
+
|
|
45
|
+
@cached_property
|
|
46
|
+
def protective_groups(self) -> dict[str, int]:
|
|
47
|
+
"""
|
|
48
|
+
Dict of protective group names to their count in the molecule.
|
|
49
|
+
"""
|
|
50
|
+
found = {}
|
|
51
|
+
seen = set()
|
|
52
|
+
for name, (q, keep, *_) in protective_rules.items():
|
|
53
|
+
c = 0
|
|
54
|
+
for mp in q.get_mapping(self, automorphism_filter=False):
|
|
55
|
+
atoms = {m for n, m in mp.items() if n not in keep}
|
|
56
|
+
if seen.isdisjoint(atoms):
|
|
57
|
+
seen.update(atoms)
|
|
58
|
+
c += 1
|
|
59
|
+
if c:
|
|
60
|
+
found[name] = c
|
|
61
|
+
return found
|
|
62
|
+
|
|
63
|
+
def remove_protection(self, name=None, canonicalize=True,
|
|
64
|
+
fix_tautomers=True, ignore_pyrrole_hydrogen=False) -> bool:
|
|
65
|
+
"""
|
|
66
|
+
Remove protective groups from the given molecule if applicable.
|
|
67
|
+
|
|
68
|
+
:param name: Specific protective group name to remove (None = all).
|
|
69
|
+
:param canonicalize: Run full canonicalization after removal.
|
|
70
|
+
:param fix_tautomers: Canonicalize tautomer forms. Passed to canonicalize().
|
|
71
|
+
:param ignore_pyrrole_hydrogen: Fix invalid rings like Cn1cc[nH]c1. Passed to canonicalize().
|
|
72
|
+
"""
|
|
73
|
+
to_delete = set()
|
|
74
|
+
to_add = []
|
|
75
|
+
if name is None:
|
|
76
|
+
rules = protective_rules.values()
|
|
77
|
+
elif name in protective_rules:
|
|
78
|
+
rules = [protective_rules[name]]
|
|
79
|
+
else:
|
|
80
|
+
raise ValueError(f'Unknown protective group: {name}')
|
|
81
|
+
|
|
82
|
+
kept_atoms = set()
|
|
83
|
+
for q, keep, add, *_ in rules:
|
|
84
|
+
for mp in q.get_mapping(self, automorphism_filter=False):
|
|
85
|
+
delete = {m for n, m in mp.items() if n not in keep}
|
|
86
|
+
if not to_delete.isdisjoint(delete):
|
|
87
|
+
continue
|
|
88
|
+
to_delete.update(delete)
|
|
89
|
+
for n in keep:
|
|
90
|
+
kept_atoms.add(mp[n])
|
|
91
|
+
for n, a, b in add:
|
|
92
|
+
to_add.append((mp[n], a, b))
|
|
93
|
+
|
|
94
|
+
for n, a, b in to_add:
|
|
95
|
+
m = self.add_atom(a, _skip_calculation=True)
|
|
96
|
+
self.add_bond(m, n, b, _skip_calculation=True)
|
|
97
|
+
for n in to_delete:
|
|
98
|
+
self.delete_atom(n, _skip_calculation=True)
|
|
99
|
+
if to_delete or to_add:
|
|
100
|
+
self.fix_structure()
|
|
101
|
+
if canonicalize:
|
|
102
|
+
self.canonicalize(fix_tautomers=fix_tautomers,
|
|
103
|
+
ignore_pyrrole_hydrogen=ignore_pyrrole_hydrogen)
|
|
104
|
+
else:
|
|
105
|
+
# fix implicit H on aromatic N freed from PG
|
|
106
|
+
for n in kept_atoms:
|
|
107
|
+
a = self.atom(n)
|
|
108
|
+
if a.atomic_symbol == 'N' and a.hybridization == 4 and a.implicit_hydrogens is None:
|
|
109
|
+
a._implicit_hydrogens = 1
|
|
110
|
+
self.fix_stereo()
|
|
111
|
+
return True
|
|
112
|
+
return False
|
|
113
|
+
|
|
114
|
+
def react(self, *others, reaction=None) -> Iterator[tuple[str, 'ReactionContainer']]:
|
|
115
|
+
"""
|
|
116
|
+
Enumerate possible reaction products between molecules.
|
|
117
|
+
|
|
118
|
+
mol1.react(mol2) -> [(reaction_name, ReactionContainer), ...]
|
|
119
|
+
mol1.react(mol2, mol3) -> [(reaction_name, ReactionContainer), ...] # multi-component
|
|
120
|
+
mol1.react(mol2, reaction='suzuki') -> only suzuki coupling
|
|
121
|
+
|
|
122
|
+
:param reaction: optional reaction name to apply selectively.
|
|
123
|
+
"""
|
|
124
|
+
mols = [self, *others]
|
|
125
|
+
|
|
126
|
+
for name, fg_names, reactor in reaction_rules:
|
|
127
|
+
if reaction is not None and name != reaction:
|
|
128
|
+
continue
|
|
129
|
+
if len(fg_names) != len(mols):
|
|
130
|
+
continue
|
|
131
|
+
for perm in permutations(mols):
|
|
132
|
+
if all(fg in mol.functional_groups for mol, fg in zip(perm, fg_names)):
|
|
133
|
+
for rxn in reactor(*perm):
|
|
134
|
+
yield name, rxn
|
|
135
|
+
break
|
|
136
|
+
|
|
137
|
+
def oxidize(self, reaction=None) -> Iterator[tuple[str, 'ReactionContainer']]:
|
|
138
|
+
"""
|
|
139
|
+
Enumerate possible single-step oxidation products.
|
|
140
|
+
|
|
141
|
+
mol.oxidize() -> [(reaction_name, ReactionContainer), ...]
|
|
142
|
+
mol.oxidize(reaction='alcohol_to_aldehyde') -> only this oxidation
|
|
143
|
+
|
|
144
|
+
:param reaction: optional reaction name to apply selectively.
|
|
145
|
+
"""
|
|
146
|
+
fgs = self.functional_groups
|
|
147
|
+
for name, fg_name, _, reactor in oxidation_rules:
|
|
148
|
+
if reaction is not None and name != reaction:
|
|
149
|
+
continue
|
|
150
|
+
if fg_name in fgs:
|
|
151
|
+
for rxn in reactor(self):
|
|
152
|
+
yield name, rxn
|
|
153
|
+
|
|
154
|
+
def reduce(self, reaction=None) -> Iterator[tuple[str, 'ReactionContainer']]:
|
|
155
|
+
"""
|
|
156
|
+
Enumerate possible single-step reduction products.
|
|
157
|
+
|
|
158
|
+
mol.reduce() -> [(reaction_name, ReactionContainer), ...]
|
|
159
|
+
mol.reduce(reaction='ketone_to_alcohol') -> only this reduction
|
|
160
|
+
|
|
161
|
+
:param reaction: optional reaction name to apply selectively.
|
|
162
|
+
"""
|
|
163
|
+
fgs = self.functional_groups
|
|
164
|
+
for name, fg_name, _, reactor in reduction_rules:
|
|
165
|
+
if reaction is not None and name != reaction:
|
|
166
|
+
continue
|
|
167
|
+
if fg_name in fgs:
|
|
168
|
+
for rxn in reactor(self):
|
|
169
|
+
yield name, rxn
|
|
170
|
+
|
|
171
|
+
def transform(self, reaction=None) -> Iterator[tuple[str, 'ReactionContainer']]:
|
|
172
|
+
"""
|
|
173
|
+
Enumerate possible single-molecule functional group interconversions
|
|
174
|
+
(ring formations from open-chain precursors with implicit reagents).
|
|
175
|
+
|
|
176
|
+
mol.transform() -> [(reaction_name, ReactionContainer), ...]
|
|
177
|
+
mol.transform(reaction='appel') -> only Appel reaction
|
|
178
|
+
|
|
179
|
+
:param reaction: optional reaction name to apply selectively.
|
|
180
|
+
"""
|
|
181
|
+
fgs = self.functional_groups
|
|
182
|
+
for name, fg_name, _, reactor in transformation_rules:
|
|
183
|
+
if reaction is not None and name != reaction:
|
|
184
|
+
continue
|
|
185
|
+
if fg_name in fgs:
|
|
186
|
+
for rxn in reactor(self):
|
|
187
|
+
yield name, rxn
|
|
188
|
+
|
|
189
|
+
def __invert__(self):
|
|
190
|
+
"""
|
|
191
|
+
Enumerate all possible single-step molecular transformations
|
|
192
|
+
(oxidations, reductions, and functional group interconversions).
|
|
193
|
+
|
|
194
|
+
~mol -> [(reaction_name, ReactionContainer), ...]
|
|
195
|
+
"""
|
|
196
|
+
yield from self.oxidize()
|
|
197
|
+
yield from self.reduce()
|
|
198
|
+
yield from self.transform()
|
|
199
|
+
|
|
200
|
+
def __matmul__(self, other):
|
|
201
|
+
"""
|
|
202
|
+
Enumerate possible reaction products between molecules.
|
|
203
|
+
|
|
204
|
+
mol1 @ mol2 -> [(reaction_name, ReactionContainer), ...]
|
|
205
|
+
mol1 @ [mol2, mol3] -> [(reaction_name, ReactionContainer), ...] # multi-component
|
|
206
|
+
"""
|
|
207
|
+
if isinstance(other, (list, tuple)):
|
|
208
|
+
return self.react(*other)
|
|
209
|
+
return self.react(other)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
__all__ = ['FunctionalGroups']
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2024-2026 Ramil Nugmanov <nougmanoff@protonmail.com>
|
|
4
|
+
# This file is part of chython.
|
|
5
|
+
#
|
|
6
|
+
# chython is free software; you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
|
8
|
+
# the Free Software Foundation; either version 3 of the License, or
|
|
9
|
+
# (at your option) any later version.
|
|
10
|
+
#
|
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU Lesser General Public License for more details.
|
|
15
|
+
#
|
|
16
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
17
|
+
# along with this program; if not, see <https://www.gnu.org/licenses/>.
|
|
18
|
+
#
|
|
19
|
+
from lazy_object_proxy import Proxy
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _rules():
|
|
23
|
+
from ... import smarts
|
|
24
|
+
|
|
25
|
+
rules = {}
|
|
26
|
+
|
|
27
|
+
# carbohydrides
|
|
28
|
+
rules['terminal_alkene'] = smarts('[C;z2;x0;D1:1]=[C;z2;x0;D2,D3:2]')
|
|
29
|
+
rules['alkene'] = smarts('[C;z2;x0;D2,D3:1]=[C;z2;x0;D2,D3:2]')
|
|
30
|
+
rules['terminal_alkyne'] = smarts('[C;z3;x0;D1:1]#[C;x0;D2:2]')
|
|
31
|
+
rules['alkyne'] = smarts('[C;z3;x0;D2:1]#[C;x0;D2:2]')
|
|
32
|
+
|
|
33
|
+
# enamines/enol ethers: C=C bonded to N or O (for hydrogenation)
|
|
34
|
+
rules['enamine'] = smarts('[C;z2;D2,D3:1]=[C;z2;D2,D3:2]-[N;z1;D2,D3:3]')
|
|
35
|
+
rules['enol_ether'] = smarts('[C;z2;D2,D3:1]=[C;z2;D2,D3:2]-[O;D2:3]')
|
|
36
|
+
|
|
37
|
+
rules['vicinal_diol'] = smarts('[O;D1;z1;x0:1]-[C;z1;x1]-[C;z1;x1]-[O;D1;z1;x0:2]')
|
|
38
|
+
|
|
39
|
+
rules['benzylic_ch'] = smarts('[C;z1;h1,h2;D2,D3:1]-[C;a:2]')
|
|
40
|
+
|
|
41
|
+
# halides
|
|
42
|
+
rules['aryl_fluoride'] = smarts('[F;D1:100]-[C;a:1]')
|
|
43
|
+
rules['aryl_chloride'] = smarts('[Cl;D1:100]-[C;a:1]')
|
|
44
|
+
rules['aryl_bromide'] = smarts('[Br;D1:100]-[C;a:1]')
|
|
45
|
+
rules['aryl_iodide'] = smarts('[I;D1:100]-[C;a:1]')
|
|
46
|
+
|
|
47
|
+
rules['alkyl_fluoride'] = smarts('[F;D1:100][C;z1;x1:1]')
|
|
48
|
+
rules['alkyl_chloride'] = smarts('[Cl;D1:100][C;z1;x1:1]')
|
|
49
|
+
rules['alkyl_bromide'] = smarts('[Br;D1:100][C;z1;x1:1]')
|
|
50
|
+
rules['alkyl_iodide'] = smarts('[I;D1:100][C;z1;x1:1]')
|
|
51
|
+
|
|
52
|
+
rules['alkenyl_fluoride'] = smarts('[F;D1:100][C;z2;x1:1]=[C:2]')
|
|
53
|
+
rules['alkenyl_chloride'] = smarts('[Cl;D1:100][C;z2;x1:1]=[C:2]')
|
|
54
|
+
rules['alkenyl_bromide'] = smarts('[Br;D1:100][C;z2;x1:1]=[C:2]')
|
|
55
|
+
rules['alkenyl_iodide'] = smarts('[I;D1:100][C;z2;x1:1]=[C:2]')
|
|
56
|
+
|
|
57
|
+
rules['alkynyl_fluoride'] = smarts('[F;D1:100][C;z3;x1:1]')
|
|
58
|
+
rules['alkynyl_chloride'] = smarts('[Cl;D1:100][C;z3;x1:1]')
|
|
59
|
+
rules['alkynyl_bromide'] = smarts('[Br;D1:100][C;z3;x1:1]')
|
|
60
|
+
rules['alkynyl_iodide'] = smarts('[I;D1:100][C;z3;x1:1]')
|
|
61
|
+
|
|
62
|
+
# pseudohalides
|
|
63
|
+
rules['aryl_triflate'] = smarts('[S;D4](=O)(=O)(-[O:100]-;!@[C;a:1])-[C;D4](F)(F)F')
|
|
64
|
+
rules['aryl_mesylate'] = smarts('[S;D4](=O)(=O)(-[O:100]-;!@[C;a:1])-[C;D1]')
|
|
65
|
+
rules['aryl_tosylate'] = smarts('[S;D4](=O)(=O)(-[O:100]-;!@[C;a:1])-[C;a]:1:[C;D2]:[C;D2]:[C](-[C;D1]):[C;D2]:[C;D2]:1')
|
|
66
|
+
|
|
67
|
+
rules['alkyl_triflate'] = smarts('[S;D4](=O)(=O)(-[O:100]-;!@[C;z1;x1:1])-[C;D4](F)(F)F')
|
|
68
|
+
rules['alkyl_mesylate'] = smarts('[S;D4](=O)(=O)(-[O:100]-;!@[C;z1;x1:1])-[C;D1]')
|
|
69
|
+
rules['alkyl_tosylate'] = smarts('[S;D4](=O)(=O)(-[O:100]-;!@[C;z1;x1:1])-[C;a]:1:[C;D2]:[C;D2]:[C](-[C;D1]):[C;D2]:[C;D2]:1')
|
|
70
|
+
|
|
71
|
+
# boronic acids and esters
|
|
72
|
+
rules['aryl_boronic_acid'] = smarts('[B;D3;z1;x2:100](-[O;D1])(-[O;D1])-;!@[C;a:1]')
|
|
73
|
+
rules['aryl_boronic_ester'] = smarts('[B;D3;z1;x2:100](-[O;D2;x1])(-[O;D2;x1])-;!@[C;a:1]')
|
|
74
|
+
|
|
75
|
+
rules['alkyl_boronic_acid'] = smarts('[B;D3;z1;x2:100](-[O;D1])(-[O;D1])-;!@[C;z1;x1:1]')
|
|
76
|
+
rules['alkyl_boronic_ester'] = smarts('[B;D3;z1;x2:100](-[O;D2;x1])(-[O;D2;x1])-;!@[C;z1;x1:1]')
|
|
77
|
+
|
|
78
|
+
rules['alkenyl_boronic_acid'] = smarts('[B;D3;z1;x2:100](-[O;D1])(-[O;D1])-;!@[C;z2;x1:1]=[C:2]')
|
|
79
|
+
rules['alkenyl_boronic_ester'] = smarts('[B;D3;z1;x2:100](-[O;D2;x1])(-[O;D2;x1])-;!@[C;z2;x1:1]=[C:2]')
|
|
80
|
+
|
|
81
|
+
rules['alkynyl_boronic_acid'] = smarts('[B;D3;z1;x2:100](-[O;D1])(-[O;D1])-;!@[C;z3;x1:1]')
|
|
82
|
+
rules['alkynyl_boronic_ester'] = smarts('[B;D3;z1;x2:100](-[O;D2;x1])(-[O;D2;x1])-;!@[C;z3;x1:1]')
|
|
83
|
+
|
|
84
|
+
# molander salts (trifluoroborates)
|
|
85
|
+
rules['aryl_molander_salt'] = smarts('[B;D4;z1;x3;-:100](F)(F)(F)-;!@[C;a:1]')
|
|
86
|
+
rules['alkyl_molander_salt'] = smarts('[B;D4;z1;x3;-:100](F)(F)(F)-;!@[C;z1:1]')
|
|
87
|
+
rules['alkenyl_molander_salt'] = smarts('[B;D4;z1;x3;-:100](F)(F)(F)-;!@[C;z2:1]=[C:2]')
|
|
88
|
+
rules['alkynyl_molander_salt'] = smarts('[B;D4;z1;x3;-:100](F)(F)(F)-;!@[C;z3;x1:1]')
|
|
89
|
+
|
|
90
|
+
# alcohols and phenols
|
|
91
|
+
rules['primary_alcohol'] = smarts('[O;D1;z1;x0:1][C;D2;x1;z1:2]')
|
|
92
|
+
rules['secondary_alcohol'] = smarts('[O;D1;z1;x0:1][C;D3;x1;z1:2]')
|
|
93
|
+
rules['tertiary_alcohol'] = smarts('[O;D1;z1;x0:1][C;D4;x1;z1:2]')
|
|
94
|
+
# tertiary alcohol with adjacent sp3 CH (eliminable): for dehydration
|
|
95
|
+
rules['tertiary_alcohol_with_alpha_h'] = smarts('[O;D1;z1;x0:1]-[C;D4;x1;z1:2]-[C;z1;h1,h2:3]')
|
|
96
|
+
rules['phenol'] = smarts('[O;D1;z1;x0:1]-[C;a:2]')
|
|
97
|
+
|
|
98
|
+
# aldehydes and ketones
|
|
99
|
+
rules['aldehyde'] = smarts('[O;z2;x0:2]=[C;D2;x1;z2:1]')
|
|
100
|
+
rules['ketone'] = smarts('[O;z2;x0:2]=[C;D3;x1;z2:1]')
|
|
101
|
+
# enal: alpha,beta-unsaturated aldehyde (for Doebner-Miller)
|
|
102
|
+
rules['enal'] = smarts('[O;z2;x0:2]=[C;D2;x1;z2:1]-[C;z2;x0:3]=[C;x0:4]')
|
|
103
|
+
# fisher, friedlander
|
|
104
|
+
rules['alpha_ketone'] = smarts('[O;z2;x0:2]=[C;D3;x1:1]-[C;z1;D1,D2;x0:3]')
|
|
105
|
+
# hantzsch thiazole, imidazo[1,2-a]pyridine
|
|
106
|
+
rules['alpha_haloketone'] = smarts('[O;z2;x0:2]=[C;D3;x1:1]-[C;z1;D2,D3;x1:3]([Cl,Br,I;D1:100])')
|
|
107
|
+
# imidazo[1,2-a]pyridine from alpha-haloester (ester O masked, carbonyl O deleted)
|
|
108
|
+
rules['alpha_haloester'] = smarts('[O;D2;x0;M]-[C;D3;x2;z2:1](=[O:2])-[C;z1;D2,D3;x1:3]([Cl,Br,I;D1:100])')
|
|
109
|
+
|
|
110
|
+
rules['1_2_diketone'] = smarts('[O;z2;x0:2]=[C;D3;x1:1]-[C;z2;x1;D3:3]=[O:4]')
|
|
111
|
+
rules['1_3_diketone'] = smarts('[O;z2;x0:2]=[C;D3;x1:1]-[C;z1;D2,D3:5]-[C;z2;x1;D3:3]=[O:4]')
|
|
112
|
+
rules['1_4_diketone'] = smarts('[O;z2;x0:2]=[C;D3;x1:1]-[C;z1;D2,D3:5]-[C;z1;D2,D3:6]-[C;z2;x1;D3:3]=[O:4]')
|
|
113
|
+
rules['beta_ketoester'] = smarts('[O;z2;x0:2]=[C;D3;x1:1]-[C;z1;D2;x0:5]-[C;z2;x2;D3:3](=[O:4])[O;D2:100]')
|
|
114
|
+
|
|
115
|
+
# acids
|
|
116
|
+
rules['alkyl_carboxylic_acid'] = smarts('[O;D1;z1;x0:100][C;z2;x2;D3:1](=[O:2])[C;z1:3]')
|
|
117
|
+
rules['aryl_carboxylic_acid'] = smarts('[O;D1;z1;x0:100][C;z2;x2;D3:1](=[O:2])[C;a:3]')
|
|
118
|
+
rules['carboxylic_acid'] = smarts('[O;D1;z1;x0:100][C;z2;x2;D3:1]=[O:2]')
|
|
119
|
+
rules['acyl_chloride'] = smarts('[Cl:100][C;z2;x2;D3:1]=[O:2]')
|
|
120
|
+
rules['acyl_fluoride'] = smarts('[F:100][C;z2;x2;D3:1]=[O:2]')
|
|
121
|
+
rules['chloroformate'] = smarts('[Cl:100][C;z2;x3;D3:1](=[O:2])-[O;D2:3]')
|
|
122
|
+
rules['fluoroformate'] = smarts('[F:100][C;z2;x3;D3:1](=[O:2])-[O;D2:3]')
|
|
123
|
+
rules['carbamoyl_chloride'] = smarts('[Cl:100][C;z2;x3;D3:1](=[O:2])-[N;D2,D3:3]')
|
|
124
|
+
rules['carbamoyl_fluoride'] = smarts('[F:100][C;z2;x3;D3:1](=[O:2])-[N;D2,D3:3]')
|
|
125
|
+
|
|
126
|
+
# amines
|
|
127
|
+
rules['primary_amine'] = smarts('[N;D1;z1;x0:1][C;z1:2]')
|
|
128
|
+
rules['primary_aniline'] = smarts('[N;D1;z1;x0:1][C;a:2]')
|
|
129
|
+
# NH2 on sp2 C=N (e.g. pyrazoline, amidine-like)
|
|
130
|
+
rules['primary_amidine_amine'] = smarts('[N;D1;z1;x0:1]-[C;z2:2]=[N;M]')
|
|
131
|
+
rules['secondary_amine'] = smarts('[N;D2;z1;x0:1]([C;z1:2])[C;z1:3]')
|
|
132
|
+
rules['secondary_aniline'] = smarts('[N;D2;z1;x0:1]([C;a:2])[C;z1:3]')
|
|
133
|
+
rules['biaryl_aniline'] = smarts('[N;D2;z1;x0:1]([C;a:2])[C;a:3]')
|
|
134
|
+
|
|
135
|
+
# esters and amides
|
|
136
|
+
rules['ester'] = smarts('[O;z2;x0:2]=[C;D3;x2;z2:1]-[O;D2;x0:100]')
|
|
137
|
+
rules['primary_amide'] = smarts('[N;D1;z1;x0:1][C;z2;x2;D3:2]=[O:3]')
|
|
138
|
+
rules['secondary_amide'] = smarts('[N;D2;z1;x0:1][C;z2;x2;D3:2]=[O:3]')
|
|
139
|
+
|
|
140
|
+
# sulfonyl
|
|
141
|
+
rules['sulfonyl_chloride'] = smarts('[S;D4:1](=[O:2])(=[O:3])[Cl;D1:100]')
|
|
142
|
+
rules['sulfonyl_fluoride'] = smarts('[S;D4:1](=[O:2])(=[O:3])[F;D1:100]')
|
|
143
|
+
rules['sulfonamide'] = smarts('[S;x3;D4:1](=[O:2])(=[O:3])-[N;z1:100]')
|
|
144
|
+
rules['sulfonyl_anhydride'] = smarts('[S;x3;D4:1](=[O:2])(=[O:3])-[O:100]-[S;x3;D4](=O)(=O)')
|
|
145
|
+
|
|
146
|
+
# nitrogen functional groups
|
|
147
|
+
rules['nitrile'] = smarts('[N;D1;z3;x0:2]#[C;D2;x1:1]')
|
|
148
|
+
rules['azide'] = smarts('[N;x1;D2:1]=[N+:2]=[N-:3]')
|
|
149
|
+
rules['isocyanate'] = smarts('[N;z2;x0;D2:1]=[C:2]=[O:3]')
|
|
150
|
+
rules['isocyano'] = smarts('[N;D2;x0;+:1]#[C;-:2]')
|
|
151
|
+
rules['guanidine'] = smarts('[N;z1;x0:1][C;!R:2]([N;z1;x0:3])=[N;x0:4]')
|
|
152
|
+
rules['nitro'] = smarts('[N;D3;x2;+:1]([O;-:2])=[O:3]')
|
|
153
|
+
|
|
154
|
+
# grignard reagents (RMgX)
|
|
155
|
+
rules['alkyl_grignard'] = smarts('[Mg;D2:100](-[F,Cl,Br,I])-[C;z1:1]')
|
|
156
|
+
rules['aryl_grignard'] = smarts('[Mg;D2:100](-[F,Cl,Br,I])-[C;a:1]')
|
|
157
|
+
rules['alkenyl_grignard'] = smarts('[Mg;D2:100](-[F,Cl,Br,I])-[C;z2:1]=[C:2]')
|
|
158
|
+
|
|
159
|
+
# organozinc reagents (RZnX)
|
|
160
|
+
rules['alkyl_zinc'] = smarts('[Zn;D2:100](-[F,Cl,Br,I])-[C;z1:1]')
|
|
161
|
+
rules['aryl_zinc'] = smarts('[Zn;D2:100](-[F,Cl,Br,I])-[C;a:1]')
|
|
162
|
+
rules['alkenyl_zinc'] = smarts('[Zn;D2:100](-[F,Cl,Br,I])-[C;z2:1]=[C:2]')
|
|
163
|
+
|
|
164
|
+
# boronate alkyl halides: B-CH2-X (one-carbon, for SN2)
|
|
165
|
+
rules['boronate_alkyl_chloride'] = smarts('[Cl;D1:100]-[C;z1;D2;x2:1]-[B;M]')
|
|
166
|
+
rules['boronate_alkyl_bromide'] = smarts('[Br;D1:100]-[C;z1;D2;x2:1]-[B;M]')
|
|
167
|
+
rules['boronate_alkyl_iodide'] = smarts('[I;D1:100]-[C;z1;D2;x2:1]-[B;M]')
|
|
168
|
+
|
|
169
|
+
# stannanes (R-SnR3)
|
|
170
|
+
rules['aryl_stannane'] = smarts('[Sn;D4;z1:100]-;!@[C;a:1]')
|
|
171
|
+
rules['alkenyl_stannane'] = smarts('[Sn;D4;z1:100]-;!@[C;z2:1]=[C:2]')
|
|
172
|
+
rules['alkyl_stannane'] = smarts('[Sn;D4;z1:100]-;!@[C;z1;D2,D3,D4:1]')
|
|
173
|
+
|
|
174
|
+
# silanes (R-SiR3, for Hiyama coupling)
|
|
175
|
+
rules['aryl_silane'] = smarts('[Si;D4:100]-;!@[C;a:1]')
|
|
176
|
+
rules['alkenyl_silane'] = smarts('[Si;D4:100]-;!@[C;z2:1]=[C:2]')
|
|
177
|
+
|
|
178
|
+
# phosphorus ylides and phosphonates
|
|
179
|
+
rules['phosphonium_ylide'] = smarts('[P;D4;z2;x0:100]=[C:1]')
|
|
180
|
+
rules['phosphonate'] = smarts('[P;D4;x3:100](=O)([O;D2;x1])([O;D2;x1])-[C:1]')
|
|
181
|
+
|
|
182
|
+
# weinreb amide
|
|
183
|
+
rules['weinreb_amide'] = smarts('[O:2]=[C;D3;x2:1]-[N;D3;x1:100][O;D2;x1]')
|
|
184
|
+
|
|
185
|
+
# arene C-H (for electrophilic aromatic substitution)
|
|
186
|
+
rules['arene_ch'] = smarts('[C;a;D2:1]')
|
|
187
|
+
|
|
188
|
+
# sulfur
|
|
189
|
+
rules['thiol'] = smarts('[S;x0;D1;z1:1][C;z1:2]')
|
|
190
|
+
rules['thioether'] = smarts('[S;D2;z1;x0:1]([C:2])[C:3]')
|
|
191
|
+
rules['sulfoxide'] = smarts('[S;D3;z2:1](=[O:2])([C:3])[C:4]')
|
|
192
|
+
rules['sulfone'] = smarts('[S;D4:1](=[O:2])(=[O:3])([C:4])[C:5]')
|
|
193
|
+
|
|
194
|
+
# lactam halides: ring-closure patterns for activated C(sp2)-X in 6-membered lactam rings
|
|
195
|
+
# covers pyridone, pyridazinone, quinazolinone, pyrimidinone, benzo-fused lactams
|
|
196
|
+
# 6 positional patterns per halide (all relative positions of X to N-C=O in ring)
|
|
197
|
+
for _x, _name in (('F', 'fluoride'), ('Cl', 'chloride'), ('Br', 'bromide'), ('I', 'iodide')):
|
|
198
|
+
# X=C-C/N-C(=O)-N-C/N e.g. CN1C=CC(Br)=CC1=O
|
|
199
|
+
rules[f'lactam_1_{_name}'] = smarts(f'[{_x};D1:100]-[C;z2;r6:1]1=[C,N;z2;M]-[C;D3;z2;M]-[N;D3;M]-[C,N;z2,z4;M]=,:[C,N;z2,z4;M]1')
|
|
200
|
+
# X=C-N-C(=O)-C/N-C/N e.g. CN1C(Br)=CC=CC1=O
|
|
201
|
+
rules[f'lactam_2_{_name}'] = smarts(f'[{_x};D1:100]-[C;z2;r6:1]=1-[N;D3;M]-[C;D3;z2;M]-[C,N;z2,z4;M]=,:[C,N;z2,z4;M]-[C,N;z2;M]=1')
|
|
202
|
+
# X=C-N-C/N-C/N-C(=O) e.g. CN1C=CC(=O)C=C1Br
|
|
203
|
+
rules[f'lactam_3_{_name}'] = smarts(f'[{_x};D1:100]-[C;z2;r6:1]=1-[N;D3;M]-[C,N;z2,z4;M]=,:[C,N;z2,z4;M]-[C;D3;z2;M]-[C,N;z2;M]=1')
|
|
204
|
+
# X=C-C(=O)-N-C/N-C/N e.g. CN1C=CC=C(Br)C1=O
|
|
205
|
+
rules[f'lactam_4_{_name}'] = smarts(f'[{_x};D1:100]-[C;z2;r6:1]=1-[C;D3;z2;M]-[N;D3;M]-[C,N;z2,z4;M]=,:[C,N;z2,z4;M]-[C,N;z2;M]=1')
|
|
206
|
+
# X=C-C/N-C/N-N-C(=O) e.g. CN1C=CC(=O)C(Br)=C1
|
|
207
|
+
rules[f'lactam_5_{_name}'] = smarts(f'[{_x};D1:100]-[C;z2;r6:1]1=[C,N;z2;M]-[N;D3;M]-[C,N;z2,z4;M]=,:[C,N;z2,z4;M]-[C;D3;z2;M]1')
|
|
208
|
+
# X=C-C/N-N-C(=O)-C/N e.g. CN1C=C(Br)C=CC1=O
|
|
209
|
+
rules[f'lactam_6_{_name}'] = smarts(f'[{_x};D1:100]-[C;z2;r6:1]1=[C,N;z2;M]-[N;D3;M]-[C;D3;z2;M]-[C,N;z2,z4;M]=,:[C,N;z2,z4;M]1')
|
|
210
|
+
|
|
211
|
+
# pyrrole. for tautomerism handling H not in template.
|
|
212
|
+
rules['pyrrole'] = smarts('[N;h1;D2;a;r5:1]')
|
|
213
|
+
rules['pyrazole'] = smarts('[N;h1;D2;a;r5:1]:[N;h0;D2;r5:2]')
|
|
214
|
+
rules['imidazole'] = smarts('[N;h1;D2;a;r5:1]:[A:2]:[N;h0;D2;r5:3]')
|
|
215
|
+
|
|
216
|
+
# heterocycles (for screening)
|
|
217
|
+
rules['isoxazole'] = smarts('[O;a;D2;r5:1]:[N;a;D2;r5:2]')
|
|
218
|
+
rules['pyridazine'] = smarts('[N;a;D2;r6:1]:[N;a;D2;r6:2]')
|
|
219
|
+
|
|
220
|
+
# hydrazines
|
|
221
|
+
rules['alkyl_hydrazine'] = smarts('[N;D1;z1;x1:2]-[N;D2;z1;x1:1]-[C;z1:3]')
|
|
222
|
+
rules['aryl_hydrazine'] = smarts('[N;D1;z1;x1:2]-[N;D2;z1;x1:1]-[C;a:3]:[C;a;D2:4]')
|
|
223
|
+
|
|
224
|
+
# hydrazone (C=N-NH-R, product of carbonyl + hydrazine condensation)
|
|
225
|
+
rules['hydrazone'] = smarts('[C;z2:1]=[N;D2;z2;x1:2]-[N;D2;z1;x1:3]')
|
|
226
|
+
|
|
227
|
+
# thioamide (for Hantzsch thiazole)
|
|
228
|
+
rules['thioamide'] = smarts('[S;z2;x0;D1:2]=[C;D3;x2:1]-[N;D1:3]')
|
|
229
|
+
|
|
230
|
+
# ortho-bifunctional arenes
|
|
231
|
+
rules['o_diaminoarene'] = smarts('[N;D1;z1;x0:1]-[C;a:3]:[C;a:4]-[N;D1,D2;z1;x0:2]')
|
|
232
|
+
rules['o_aminophenol'] = smarts('[N;D1;z1;x0:1]-[C;a:3]:[C;a:4]-[O;D1:2]')
|
|
233
|
+
rules['o_aminothiophenol'] = smarts('[N;D1;z1;x0:1]-[C;a:3]:[C;a:4]-[S;D1:2]')
|
|
234
|
+
rules['o_aminobenzaldehyde'] = smarts('[N;D1;z1;x0:1]-[C;a:3]:[C;a:4]-[C;D2;z2;x1:5]=[O:6]')
|
|
235
|
+
rules['anthranilic_acid'] = smarts('[N;D1;z1;x0:1]-[C;a:3]:[C;a:4]-[C;z2;x2;D3:5](=[O:6])[O;D1:100]')
|
|
236
|
+
|
|
237
|
+
# amidoxime: RC(=NH)NHOH canonical form (for 1,2,4-oxadiazole)
|
|
238
|
+
rules['amidoxime'] = smarts('[N;D1;z2;x0:3]=[C;D3;x2:1]-[N;D2;z1;x1:2]-[O;D1:4]')
|
|
239
|
+
|
|
240
|
+
# amidine: RC(=NH)NH2 (for pyrimidine)
|
|
241
|
+
rules['amidine'] = smarts('[N;D1;z1;x0:3]-[C;D3;z2;x2:1]=[N;D1:2]')
|
|
242
|
+
# urea/thiourea (for Biginelli)
|
|
243
|
+
rules['urea'] = smarts('[N;D1;z1;x0:1]-[C;D3;z2;x3:2](=[O:3])-[N;D1:4]')
|
|
244
|
+
rules['thiourea'] = smarts('[N;D1;z1;x0:1]-[C;D3;z2;x3:2](=[S;D1:3])-[N;D1:4]')
|
|
245
|
+
|
|
246
|
+
# beta-arylethylamine (for Pictet-Spengler)
|
|
247
|
+
rules['beta_arylethylamine'] = smarts('[N;D1;z1;x0:1]-[C;z1:2]-[C;z1:3]-[C;a:4]:[C;a;D2:5]')
|
|
248
|
+
# 2-aminopyridine / 2-aminoazine (for GBB, imidazo[1,2-a]pyridine)
|
|
249
|
+
rules['aminopyridine'] = smarts('[N;D1;z1;x0:1]-[C;a:2]:[N;a;h0;D2:3]')
|
|
250
|
+
|
|
251
|
+
# amino alcohol (for oxazoline formation): H2N-C-C-OH
|
|
252
|
+
rules['amino_alcohol'] = smarts('[N;D1;z1;x0:1]-[C;z1:2]-[C;z1:3]-[O;D1:4]')
|
|
253
|
+
|
|
254
|
+
# hydroxamic acid: R-C(=O)-NH-OH
|
|
255
|
+
rules['hydroxamic_acid'] = smarts('[O;D1;z1;x1:1]-[N;D2;z1;x1:2]-[C;z2;x2:3]=[O:4]')
|
|
256
|
+
|
|
257
|
+
# oxime: C=N-OH
|
|
258
|
+
rules['oxime'] = smarts('[O;D1;z1;x1:1]-[N;D2;z2;x1:2]=[C:3]')
|
|
259
|
+
|
|
260
|
+
# O-alkylhydroxylamine: R-O-NH2 (for oxime ether formation)
|
|
261
|
+
rules['O_alkylhydroxylamine'] = smarts('[N;D1;z1;x1:1]-[O;D2;z1;x1:2]-[C:3]')
|
|
262
|
+
|
|
263
|
+
# alpha-isocyano (for Van Leusen oxazole)
|
|
264
|
+
rules['tosyl_isocyanide'] = smarts('[C;-;D1:2]#[N;+;D2:1]-[C;D2,D3;z1;x2:3]-[S;D4;x2:100](=O)=O')
|
|
265
|
+
|
|
266
|
+
# thioester (for Liebeskind-Srogl): R-C(=O)-S-R'
|
|
267
|
+
rules['thioester'] = smarts('[O;z2;x0:2]=[C;D3;x2;z2:1]-[S;D2;z1;x0:100]')
|
|
268
|
+
|
|
269
|
+
# active methylene (for Knoevenagel): CH flanked by 2 EWGs
|
|
270
|
+
rules['active_methylene'] = smarts('[C;z1;D2,D3;x0:1](-[C;z2,z3;x1,x2:2])-[C;z2,z3;x1,x2:3]')
|
|
271
|
+
|
|
272
|
+
# aniline with ortho C-H (for Doebner-Miller)
|
|
273
|
+
rules['aniline_ortho_ch'] = smarts('[N;D1;z1;x0:1]-[C;a:2]:[C;a;D2:3]')
|
|
274
|
+
|
|
275
|
+
# ortho-haloaniline (for Larock indole)
|
|
276
|
+
rules['o_haloaniline'] = smarts('[N;D1;z1;x0:1]-[C;a:2]:[C;a:3]-[Cl,Br,I;D1:100]')
|
|
277
|
+
|
|
278
|
+
# tertiary amine (for N-oxidation): NR3 where all substituents are C
|
|
279
|
+
rules['tertiary_amine'] = smarts('[N;D3;z1;x0:1]')
|
|
280
|
+
|
|
281
|
+
# pyridine-like nitrogen (for N-oxidation): aromatic N with no H, degree 2
|
|
282
|
+
rules['pyridine_n'] = smarts('[N;a;D2;h0:1]')
|
|
283
|
+
|
|
284
|
+
return rules
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
rules = Proxy(_rules)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
__all__ = ['rules']
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2026 Ramil Nugmanov <nougmanoff@protonmail.com>
|
|
4
|
+
# This file is part of chython.
|
|
5
|
+
#
|
|
6
|
+
# chython is free software; you can redistribute it and/or modify
|
|
7
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
|
8
|
+
# the Free Software Foundation; either version 3 of the License, or
|
|
9
|
+
# (at your option) any later version.
|
|
10
|
+
#
|
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
# GNU Lesser General Public License for more details.
|
|
15
|
+
#
|
|
16
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
17
|
+
# along with this program; if not, see <https://www.gnu.org/licenses/>.
|
|
18
|
+
#
|
|
19
|
+
from lazy_object_proxy import Proxy
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _make_reactor(rxn_name, fg_name, output_fg, product_smarts):
|
|
23
|
+
from ._functional import rules
|
|
24
|
+
from ...reactor import Reactor
|
|
25
|
+
from ... import smarts
|
|
26
|
+
|
|
27
|
+
q = rules[fg_name]
|
|
28
|
+
product = smarts(product_smarts)
|
|
29
|
+
return rxn_name, fg_name, output_fg, Reactor((q,), (product,),
|
|
30
|
+
delete_atoms=True, one_shot=True, ignore_pyrrole_hydrogen=True)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _rules():
|
|
34
|
+
rules = []
|
|
35
|
+
|
|
36
|
+
# primary_alcohol → aldehyde (Swern, Dess-Martin, PCC)
|
|
37
|
+
rules.append(_make_reactor('alcohol_to_aldehyde', 'primary_alcohol', 'aldehyde', '[A:1]=[A:2]'))
|
|
38
|
+
|
|
39
|
+
# secondary_alcohol → ketone (Dess-Martin, Jones, PCC)
|
|
40
|
+
rules.append(_make_reactor('alcohol_to_ketone', 'secondary_alcohol', 'ketone', '[A:1]=[A:2]'))
|
|
41
|
+
|
|
42
|
+
# aldehyde → carboxylic_acid (Pinnick, Jones, KMnO4)
|
|
43
|
+
rules.append(_make_reactor('aldehyde_to_acid', 'aldehyde', 'carboxylic_acid', '[A:2]=[A:1]-[O:20]'))
|
|
44
|
+
|
|
45
|
+
# alkene → 1,2-diol (Sharpless dihydroxylation, OsO4/KMnO4)
|
|
46
|
+
rules.append(_make_reactor('dihydroxylation', 'terminal_alkene', 'vicinal_diol', '[A:1](-[O:20])-[A:2](-[O:21])'))
|
|
47
|
+
rules.append(_make_reactor('dihydroxylation', 'alkene', 'vicinal_diol', '[A:1](-[O:20])-[A:2](-[O:21])'))
|
|
48
|
+
|
|
49
|
+
# thioether → sulfoxide (mCPBA, H2O2, NaIO4)
|
|
50
|
+
rules.append(_make_reactor('thioether_to_sulfoxide', 'thioether', 'sulfoxide', '[A:1](=[O:20])(-[A:2])-[A:3]'))
|
|
51
|
+
|
|
52
|
+
# thioether → sulfone (excess mCPBA, H2O2/AcOH, Oxone)
|
|
53
|
+
rules.append(_make_reactor('thioether_to_sulfone', 'thioether', 'sulfone', '[A:1](=[O:20])(=[O:21])(-[A:2])-[A:3]'))
|
|
54
|
+
|
|
55
|
+
# sulfoxide → sulfone
|
|
56
|
+
rules.append(_make_reactor('sulfoxide_to_sulfone', 'sulfoxide', 'sulfone', '[A:1](=[A:2])(=[O:20])(-[A:3])-[A:4]'))
|
|
57
|
+
|
|
58
|
+
# tertiary amine → N-oxide (mCPBA, H2O2)
|
|
59
|
+
rules.append(_make_reactor('nitrogen_oxidation', 'tertiary_amine', None, '[N;+:1]([O;-:20])'))
|
|
60
|
+
|
|
61
|
+
# pyridine → N-oxide (mCPBA, H2O2)
|
|
62
|
+
rules.append(_make_reactor('nitrogen_oxidation', 'pyridine_n', None, '[N;+:1]([O;-:20])'))
|
|
63
|
+
|
|
64
|
+
return rules
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
rules = Proxy(_rules)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
__all__ = ['rules']
|