chython 2.4__cp312-cp312-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 +31 -0
- chython/_functions.py +69 -0
- chython/algorithms/__init__.py +18 -0
- chython/algorithms/_isomorphism.cp312-win_amd64.pyd +0 -0
- chython/algorithms/_isomorphism.pyx +189 -0
- chython/algorithms/aromatics/__init__.py +27 -0
- chython/algorithms/aromatics/_rules.py +124 -0
- chython/algorithms/aromatics/kekule.py +530 -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 +226 -0
- chython/algorithms/calculate2d/__init__.py +23 -0
- chython/algorithms/calculate2d/clean2d.js +1 -0
- chython/algorithms/calculate2d/molecule.py +149 -0
- chython/algorithms/calculate2d/reaction.py +80 -0
- chython/algorithms/depict.py +523 -0
- chython/algorithms/fingerprints/__init__.py +48 -0
- chython/algorithms/fingerprints/linear.py +208 -0
- chython/algorithms/fingerprints/morgan.py +137 -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/isomorphism.py +667 -0
- chython/algorithms/mapping/__init__.py +28 -0
- chython/algorithms/mapping/_groups.py +94 -0
- chython/algorithms/mapping/_reactions.py +72 -0
- chython/algorithms/mapping/attention.py +216 -0
- chython/algorithms/mapping/fixmapper.py +84 -0
- chython/algorithms/mapping/groups.py +137 -0
- chython/algorithms/mcs.py +202 -0
- chython/algorithms/morgan.py +82 -0
- chython/algorithms/rings.py +551 -0
- chython/algorithms/smiles.py +556 -0
- chython/algorithms/standardize/__init__.py +30 -0
- chython/algorithms/standardize/_charged.py +115 -0
- chython/algorithms/standardize/_groups.py +926 -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 +479 -0
- chython/algorithms/standardize/reaction.py +429 -0
- chython/algorithms/standardize/resonance.py +196 -0
- chython/algorithms/standardize/salts.py +128 -0
- chython/algorithms/standardize/saturation.py +378 -0
- chython/algorithms/standardize/test/__init__.py +18 -0
- chython/algorithms/standardize/test/test_groups.py +118 -0
- chython/algorithms/stereo.py +1222 -0
- chython/algorithms/tautomers/__init__.py +171 -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 +214 -0
- chython/algorithms/tautomers/heteroarenes.py +108 -0
- chython/algorithms/tautomers/keto_enol.py +148 -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 +355 -0
- chython/containers/__init__.py +43 -0
- chython/containers/_pack_v2.cp312-win_amd64.pyd +0 -0
- chython/containers/_pack_v2.pyx +271 -0
- chython/containers/_unpack_v0v2.cp312-win_amd64.pyd +0 -0
- chython/containers/_unpack_v0v2.pyx +300 -0
- chython/containers/bonds.py +255 -0
- chython/containers/cgr.py +115 -0
- chython/containers/graph.py +200 -0
- chython/containers/molecule.py +695 -0
- chython/containers/query.py +66 -0
- chython/containers/reaction.py +324 -0
- chython/exceptions.py +114 -0
- chython/files/MRVrw.py +523 -0
- chython/files/PDBrw.py +257 -0
- chython/files/RDFrw.py +298 -0
- chython/files/SDFrw.py +221 -0
- chython/files/__init__.py +29 -0
- chython/files/_convert.py +207 -0
- chython/files/_mapping.py +117 -0
- chython/files/_xyz.cp312-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 +245 -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 +555 -0
- chython/files/mdl/__init__.py +25 -0
- chython/files/mdl/emol.py +209 -0
- chython/files/mdl/erxn.py +67 -0
- chython/files/mdl/mol.py +144 -0
- chython/files/mdl/read.py +225 -0
- chython/files/mdl/rxn.py +67 -0
- chython/files/mdl/stereo.py +63 -0
- chython/files/mdl/write.py +165 -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 +452 -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/reactor/__init__.py +24 -0
- chython/reactor/base.py +212 -0
- chython/reactor/deprotection.py +565 -0
- chython/reactor/groups.py +128 -0
- chython/reactor/reactions/__init__.py +157 -0
- chython/reactor/reactions/_amidation.py +58 -0
- chython/reactor/reactions/_amine_isocyanate.py +52 -0
- chython/reactor/reactions/_buchwald_hartwig.py +50 -0
- chython/reactor/reactions/_esterification.py +49 -0
- chython/reactor/reactions/_macmillan.py +43 -0
- chython/reactor/reactions/_reductive_amination.py +50 -0
- chython/reactor/reactions/_sonogashira.py +49 -0
- chython/reactor/reactions/_sulfonamidation.py +52 -0
- chython/reactor/reactions/_suzuki_miyaura.py +88 -0
- chython/reactor/reactions/ufe.py +99 -0
- chython/reactor/reactor.py +170 -0
- chython/reactor/retro/__init__.py +77 -0
- chython/reactor/retro/_amidation.py +39 -0
- chython/reactor/retro/_aryl_amination.py +32 -0
- chython/reactor/retro/_mitsunobu.py +49 -0
- chython/reactor/retro/_sonogashira.py +49 -0
- chython/reactor/retro/_suzuki_miyaura.py +54 -0
- chython/reactor/scaffold.py +122 -0
- chython/reactor/test/__init__.py +18 -0
- chython/reactor/test/test_deprotection.py +57 -0
- chython/reactor/test/test_reactor.py +40 -0
- chython/reactor/test/test_scaffold.py +57 -0
- chython/reactor/test/test_transformer.py +40 -0
- chython/reactor/transformer.py +62 -0
- chython/utils/__init__.py +57 -0
- chython/utils/free_wilson.py +114 -0
- chython/utils/grid.py +130 -0
- chython/utils/rdkit.py +165 -0
- chython/utils/retro.py +139 -0
- chython/utils/svg.py +57 -0
- chython/utils/test/__init__.py +18 -0
- chython/utils/test/test_rdkit.py +71 -0
- chython-2.4.dist-info/LICENSE +165 -0
- chython-2.4.dist-info/METADATA +101 -0
- chython-2.4.dist-info/RECORD +171 -0
- chython-2.4.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2024 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 typing import Iterator
|
|
20
|
+
from ._amidation import template as amidation_template
|
|
21
|
+
from ._amine_isocyanate import template as amine_isocyanate_template
|
|
22
|
+
from ._buchwald_hartwig import template as buchwald_hartwig_template
|
|
23
|
+
from ._esterification import template as esterification_template
|
|
24
|
+
from ._macmillan import template as macmillan_template
|
|
25
|
+
from ._reductive_amination import template as reductive_amination_template
|
|
26
|
+
from ._sonogashira import template as sonogashira_template
|
|
27
|
+
from ._sulfonamidation import template as sulfonamidation_template
|
|
28
|
+
from ._suzuki_miyaura import template as suzuki_miyaura_template
|
|
29
|
+
from ..transformer import Transformer
|
|
30
|
+
from ... import MoleculeContainer, smarts
|
|
31
|
+
from ...periodictable import At
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
__all__ = ['PreparedUFE']
|
|
35
|
+
__all__.extend(k[:-9] for k, v in globals().items() if k.endswith('_template') and isinstance(v, dict) and v)
|
|
36
|
+
_cache = {}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class TransformerWrapper:
|
|
40
|
+
def __init__(self, query, transformation, name):
|
|
41
|
+
if isinstance(transformation, str):
|
|
42
|
+
self.transformer = Transformer(smarts(query), smarts(transformation), copy_metadata=True,
|
|
43
|
+
fix_aromatic_rings=False, fix_tautomers=False)
|
|
44
|
+
else:
|
|
45
|
+
self.query = smarts(query)
|
|
46
|
+
self.mapping = transformation
|
|
47
|
+
self.transformer = None
|
|
48
|
+
self.name = name
|
|
49
|
+
|
|
50
|
+
def __call__(self, molecule: MoleculeContainer) -> Iterator[MoleculeContainer]:
|
|
51
|
+
if self.transformer is None:
|
|
52
|
+
for mapping in self.query.get_mapping(molecule):
|
|
53
|
+
n = mapping[self.mapping]
|
|
54
|
+
copy = molecule.copy()
|
|
55
|
+
copy._atoms[n].__class__ = At # ad-hoc for masking leaving group
|
|
56
|
+
copy._hydrogens[n] = 0
|
|
57
|
+
copy.meta[self.name] = n
|
|
58
|
+
yield copy
|
|
59
|
+
else:
|
|
60
|
+
for copy in self.transformer(molecule):
|
|
61
|
+
copy.meta[self.name] = max(copy)
|
|
62
|
+
yield copy
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class PreparedUFE:
|
|
66
|
+
def __init__(self, rules, name):
|
|
67
|
+
self.name = name
|
|
68
|
+
self.rules = rules
|
|
69
|
+
self.transformations = []
|
|
70
|
+
|
|
71
|
+
for n, rule in enumerate(rules['templates']):
|
|
72
|
+
for g in 'AB':
|
|
73
|
+
for s in rule[g]:
|
|
74
|
+
t = TransformerWrapper(s, rule['ufe'][g], f'{name}_{g}{n}')
|
|
75
|
+
self.transformations.append(t)
|
|
76
|
+
|
|
77
|
+
def __call__(self, molecule: MoleculeContainer) -> Iterator[MoleculeContainer]:
|
|
78
|
+
for transformer in self.transformations:
|
|
79
|
+
yield from transformer(molecule)
|
|
80
|
+
|
|
81
|
+
def __repr__(self):
|
|
82
|
+
return f'{__name__}.{self.name}'
|
|
83
|
+
|
|
84
|
+
def __str__(self):
|
|
85
|
+
return f'UFE<{self.rules["name"]}>'
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def __getattr__(name):
|
|
89
|
+
try:
|
|
90
|
+
return _cache[name]
|
|
91
|
+
except KeyError:
|
|
92
|
+
if name in __all__:
|
|
93
|
+
_cache[name] = t = PreparedUFE(globals()[f'{name}_template'], name)
|
|
94
|
+
return t
|
|
95
|
+
raise AttributeError
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def __dir__():
|
|
99
|
+
return __all__
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2019-2025 Ramil Nugmanov <nougmanoff@protonmail.com>
|
|
4
|
+
# Copyright 2019 Adelia Fatykhova <adelik21979@gmail.com>
|
|
5
|
+
# This file is part of chython.
|
|
6
|
+
#
|
|
7
|
+
# chython is free software; you can redistribute it and/or modify
|
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
|
9
|
+
# the Free Software Foundation; either version 3 of the License, or
|
|
10
|
+
# (at your option) any later version.
|
|
11
|
+
#
|
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
# GNU Lesser General Public License for more details.
|
|
16
|
+
#
|
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
18
|
+
# along with this program; if not, see <https://www.gnu.org/licenses/>.
|
|
19
|
+
#
|
|
20
|
+
from collections import deque
|
|
21
|
+
from functools import reduce
|
|
22
|
+
from itertools import count, permutations, combinations
|
|
23
|
+
from logging import getLogger, INFO
|
|
24
|
+
from operator import or_
|
|
25
|
+
from typing import List, Iterator, Tuple, Union
|
|
26
|
+
from .base import BaseReactor
|
|
27
|
+
from .._functions import lazy_product
|
|
28
|
+
from ..containers import QueryContainer, MoleculeContainer, ReactionContainer
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
logger = getLogger('chython.reactor')
|
|
32
|
+
logger.setLevel(INFO)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class Reactor(BaseReactor):
|
|
36
|
+
"""
|
|
37
|
+
Reactor for molecules transformations.
|
|
38
|
+
Generates reaction from input molecules using transformation template.
|
|
39
|
+
|
|
40
|
+
Reactor calling transforms reactants to products and
|
|
41
|
+
returns generator of reaction transformations with all
|
|
42
|
+
possible reactions.
|
|
43
|
+
"""
|
|
44
|
+
def __init__(self, patterns: Tuple[QueryContainer, ...],
|
|
45
|
+
products: Tuple[Union[MoleculeContainer, QueryContainer], ...], *,
|
|
46
|
+
delete_atoms: bool = True, one_shot: bool = True, polymerise_limit: int = 10,
|
|
47
|
+
automorphism_filter: bool = True, fix_aromatic_rings: bool = True, fix_tautomers: bool = True):
|
|
48
|
+
"""
|
|
49
|
+
:param patterns: Search patterns for each reactant.
|
|
50
|
+
:param products: Resulted structures.
|
|
51
|
+
:param delete_atoms: If True atoms exists in reactants but not exists in products will be removed.
|
|
52
|
+
:param one_shot: Do only single reaction center then True, else do all possible combinations of reactions.
|
|
53
|
+
:param polymerise_limit: Limit of self reactions. Make sense than one_shot = False.
|
|
54
|
+
:param fix_aromatic_rings: Proceed kekule and thiele on products.
|
|
55
|
+
:param fix_tautomers: See `thiele()` docs.
|
|
56
|
+
:param automorphism_filter: Skip matches to same atoms.
|
|
57
|
+
"""
|
|
58
|
+
if not patterns or not products:
|
|
59
|
+
raise ValueError('empty template')
|
|
60
|
+
|
|
61
|
+
if not all(isinstance(x, QueryContainer) for x in patterns):
|
|
62
|
+
raise TypeError('invalid params')
|
|
63
|
+
elif not all(isinstance(x, (QueryContainer, MoleculeContainer)) for x in products):
|
|
64
|
+
raise TypeError('invalid params')
|
|
65
|
+
self._patterns = patterns
|
|
66
|
+
self._products = products
|
|
67
|
+
|
|
68
|
+
self._one_shot = one_shot
|
|
69
|
+
self._polymerise_limit = polymerise_limit
|
|
70
|
+
self._products_atoms = tuple(set(m) for m in products)
|
|
71
|
+
self._automorphism_filter = automorphism_filter
|
|
72
|
+
super().__init__(reduce(or_, patterns), reduce(or_, products), delete_atoms, fix_aromatic_rings, fix_tautomers)
|
|
73
|
+
|
|
74
|
+
def __call__(self, *structures: MoleculeContainer):
|
|
75
|
+
if any(not isinstance(structure, MoleculeContainer) for structure in structures):
|
|
76
|
+
raise TypeError('only list of Molecules possible')
|
|
77
|
+
|
|
78
|
+
len_patterns = len(self._patterns)
|
|
79
|
+
structures = fix_mapping_overlap(structures)
|
|
80
|
+
s_nums = set(range(len(structures)))
|
|
81
|
+
seen = set()
|
|
82
|
+
if self._one_shot:
|
|
83
|
+
for chosen in permutations(s_nums, len_patterns):
|
|
84
|
+
ignored = [structures[x] for x in s_nums.difference(chosen)]
|
|
85
|
+
chosen = [structures[x] for x in chosen]
|
|
86
|
+
for new in self._single_stage(chosen, {x for x in ignored for x in x}):
|
|
87
|
+
# store reacted molecules in same order as matched pattern
|
|
88
|
+
r = ReactionContainer([x.copy() for x in chosen] + [x.copy() for x in ignored],
|
|
89
|
+
new + [x.copy() for x in ignored])
|
|
90
|
+
if len(new) > 1: # try to keep salts
|
|
91
|
+
r.contract_ions()
|
|
92
|
+
if str(r) in seen:
|
|
93
|
+
continue
|
|
94
|
+
seen.add(str(r))
|
|
95
|
+
yield r
|
|
96
|
+
else:
|
|
97
|
+
queue = deque(([structures[x] for x in chosen], [structures[x] for x in s_nums.difference(chosen)], 0)
|
|
98
|
+
for chosen in permutations(s_nums, len_patterns))
|
|
99
|
+
while queue:
|
|
100
|
+
chosen, ignored, depth = queue.popleft()
|
|
101
|
+
depth += 1
|
|
102
|
+
for new in self._single_stage(chosen, {x for x in ignored for x in x}):
|
|
103
|
+
r = ReactionContainer([x.copy() for x in structures], new + [x.copy() for x in ignored])
|
|
104
|
+
if len(new) > 1:
|
|
105
|
+
r.contract_ions() # try to keep salts
|
|
106
|
+
if str(r) in seen:
|
|
107
|
+
continue
|
|
108
|
+
seen.add(str(r))
|
|
109
|
+
if len(r.products) != len(ignored) + len(self._products_atoms):
|
|
110
|
+
logger.info('ambiguous multicomponent structures. skip multistage processing')
|
|
111
|
+
yield r
|
|
112
|
+
continue
|
|
113
|
+
elif str(r) in seen:
|
|
114
|
+
continue
|
|
115
|
+
else:
|
|
116
|
+
seen.add(str(r))
|
|
117
|
+
|
|
118
|
+
if depth < self._polymerise_limit:
|
|
119
|
+
prod = r.products
|
|
120
|
+
if len_patterns == 1: # simple case. only products or ignored can be transformed.
|
|
121
|
+
for i in range(len(prod)):
|
|
122
|
+
queue.append(([prod[i]], [*prod[:i], *prod[i + 1:]], depth))
|
|
123
|
+
else: # one of products molecule combined with previously chosen
|
|
124
|
+
for chp in combinations(chosen, len_patterns - 1):
|
|
125
|
+
for i in range(len(prod)):
|
|
126
|
+
for ch in permutations(fix_mapping_overlap((prod[i], *chp)), len_patterns):
|
|
127
|
+
queue.append((ch, [*prod[:i], *prod[i + 1:]], depth))
|
|
128
|
+
yield r
|
|
129
|
+
|
|
130
|
+
def _single_stage(self, chosen, ignored) -> Iterator[List[MoleculeContainer]]:
|
|
131
|
+
max_ignored_number = united_chosen = None
|
|
132
|
+
split = len(self._products_atoms) > 1
|
|
133
|
+
for match in lazy_product(*(x.get_mapping(y, automorphism_filter=self._automorphism_filter) for x, y in
|
|
134
|
+
zip(self._patterns, chosen))):
|
|
135
|
+
mapping = match[0].copy()
|
|
136
|
+
for m in match[1:]:
|
|
137
|
+
mapping.update(m)
|
|
138
|
+
if united_chosen is None:
|
|
139
|
+
united_chosen = reduce(or_, chosen)
|
|
140
|
+
max_ignored_number = max(ignored, default=0)
|
|
141
|
+
new = self._patcher(united_chosen, mapping)
|
|
142
|
+
collision = set(new).intersection(ignored)
|
|
143
|
+
if collision:
|
|
144
|
+
new.remap(dict(zip(collision, count(max(max_ignored_number, max(new)) + 1))))
|
|
145
|
+
|
|
146
|
+
if split:
|
|
147
|
+
yield new.split()
|
|
148
|
+
else:
|
|
149
|
+
yield [new]
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def fix_mapping_overlap(structures) -> List[MoleculeContainer]:
|
|
153
|
+
if len(structures) == 1:
|
|
154
|
+
return list(structures)
|
|
155
|
+
checked = []
|
|
156
|
+
checked_atoms = set()
|
|
157
|
+
for structure in structures:
|
|
158
|
+
intersection = set(structure).intersection(checked_atoms)
|
|
159
|
+
if intersection:
|
|
160
|
+
mapping = dict(zip(intersection, count(max(max(checked_atoms), max(structure)) + 1)))
|
|
161
|
+
structure = structure.copy()
|
|
162
|
+
structure.remap(mapping)
|
|
163
|
+
logger.info('some atoms in input structures had the same numbers.\n'
|
|
164
|
+
f'atoms {list(mapping)} were remapped to {list(mapping.values())}')
|
|
165
|
+
checked_atoms.update(structure)
|
|
166
|
+
checked.append(structure)
|
|
167
|
+
return checked
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
__all__ = ['Reactor', 'fix_mapping_overlap']
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2024 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 chython import Reactor, ReactionContainer, smarts
|
|
20
|
+
from typing import Iterator
|
|
21
|
+
from ._amidation import template as amidation_template
|
|
22
|
+
from ._aryl_amination import template as aryl_amination_template
|
|
23
|
+
from ._mitsunobu import template as mitsunobu_template
|
|
24
|
+
from ._sonogashira import template as sonogashira_template
|
|
25
|
+
from ._suzuki_miyaura import template as suzuki_miyaura_template
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
__all__ = ['PreparedReactor']
|
|
29
|
+
__all__.extend(k[:-9] for k, v in globals().items() if k.endswith('_template') and isinstance(v, dict) and v)
|
|
30
|
+
_cache = {}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class PreparedReactor:
|
|
34
|
+
"""
|
|
35
|
+
Prepared retrosynthetic reactors with predefined sets of templates.
|
|
36
|
+
"""
|
|
37
|
+
def __init__(self, rules, name):
|
|
38
|
+
self.name = name
|
|
39
|
+
self.rules = rules
|
|
40
|
+
|
|
41
|
+
self.rxn = rxn = []
|
|
42
|
+
for tmp in rules['templates']:
|
|
43
|
+
p = smarts(tmp['product'])
|
|
44
|
+
rs = [smarts(x) for x in tmp['reactants']]
|
|
45
|
+
rxn.append(Reactor([p], rs, automorphism_filter=False)) # noqa
|
|
46
|
+
|
|
47
|
+
def __repr__(self):
|
|
48
|
+
return f'{__name__}.{self.name}'
|
|
49
|
+
|
|
50
|
+
def __str__(self):
|
|
51
|
+
return f'RetroReactor<{self.rules["name"]}>'
|
|
52
|
+
|
|
53
|
+
def __call__(self, molecule) -> Iterator[ReactionContainer]:
|
|
54
|
+
"""
|
|
55
|
+
:param molecule: Product molecule
|
|
56
|
+
"""
|
|
57
|
+
seen = set()
|
|
58
|
+
for rx in self.rxn:
|
|
59
|
+
for r in rx(molecule):
|
|
60
|
+
if str(r) in seen:
|
|
61
|
+
continue
|
|
62
|
+
seen.add(str(r))
|
|
63
|
+
yield r
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def __getattr__(name):
|
|
67
|
+
try:
|
|
68
|
+
return _cache[name]
|
|
69
|
+
except KeyError:
|
|
70
|
+
if name in __all__:
|
|
71
|
+
_cache[name] = t = PreparedReactor(globals()[f'{name}_template'], name)
|
|
72
|
+
return t
|
|
73
|
+
raise AttributeError
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def __dir__():
|
|
77
|
+
return __all__
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2024 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
|
+
|
|
20
|
+
template = {
|
|
21
|
+
'name': 'Amidation reaction',
|
|
22
|
+
'description': 'Amide Coupling with Amines and Acids/Halo-Anhydrides',
|
|
23
|
+
'templates': [
|
|
24
|
+
{
|
|
25
|
+
'product': '[N;D2,D3;z1:1]-;!@[C;x2;z2:2]=[O;M]', # any SP3 nitrogen with carboxy
|
|
26
|
+
'reactants': [
|
|
27
|
+
'[A:1]',
|
|
28
|
+
'[A:2]-[O;M]'
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
'product': '[N;D2;z2;x0:1]-;!@[C;x2;z2:2]=[O;M]', # C=N-C(=O)R
|
|
33
|
+
'reactants': [
|
|
34
|
+
'[A:1]',
|
|
35
|
+
'[A:2]-[O;M]'
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2024 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
|
+
|
|
20
|
+
template = {
|
|
21
|
+
'name': 'Aryl amination reaction',
|
|
22
|
+
'description': 'C-N coupling of halo-aryles and amines',
|
|
23
|
+
'templates': [
|
|
24
|
+
{
|
|
25
|
+
'product': '[N;D2,D3;z1:1]-;!@[C;a:2]',
|
|
26
|
+
'reactants': [
|
|
27
|
+
'[A:1]',
|
|
28
|
+
'[A:2]-[Br;M]'
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2024 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
|
+
|
|
20
|
+
template = {
|
|
21
|
+
'name': 'Mitsunobu reaction',
|
|
22
|
+
'description': 'Phenol-Alcohol Phenol-Acid Acid-Alcohol couplings',
|
|
23
|
+
'templates': [
|
|
24
|
+
{
|
|
25
|
+
# Ph-O-Alk
|
|
26
|
+
'product': '[O;D2;x0;z1:1](-;!@[C;a;M])[C;z1;x1:2]',
|
|
27
|
+
'reactants': [
|
|
28
|
+
'[A:1]',
|
|
29
|
+
'[A:2]-[O;M]'
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
# Ac-O-Alk
|
|
34
|
+
'product': '[O;D2;x0;z1:1](-;!@[C;x2;z2;M]=[O;M])[C;z1;x1:2]',
|
|
35
|
+
'reactants': [
|
|
36
|
+
'[A:1]',
|
|
37
|
+
'[A:2]-[O;M]'
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
# Ph-O-Ac
|
|
42
|
+
'product': '[O;D2;x0;z1:1](-;!@[C;D3;x2;z2:2]=[O;M])[C;a;M]',
|
|
43
|
+
'reactants': [
|
|
44
|
+
'[A:1]',
|
|
45
|
+
'[A:2]-[O;M]'
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2024 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
|
+
|
|
20
|
+
template = {
|
|
21
|
+
'name': 'Sonogashira reaction',
|
|
22
|
+
'description': 'Alkyne Ar-X CSP2-X Ac-X couplings',
|
|
23
|
+
'templates': [
|
|
24
|
+
{
|
|
25
|
+
# Ar
|
|
26
|
+
'product': '[C;D2;x0;z3:1](-;!@[C;a:2])#[C;D2;x0;M]',
|
|
27
|
+
'reactants': [
|
|
28
|
+
'[A:1]',
|
|
29
|
+
'[A:2]-[Br;M]'
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
# Ac
|
|
34
|
+
'product': '[C;D2;x0;z3:1](-;!@[C;D3;x1;z2:2]=[O;M])#[C;D2;x0;M]',
|
|
35
|
+
'reactants': [
|
|
36
|
+
'[A:1]',
|
|
37
|
+
'[A:2]-[Cl;M]'
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
# CSP2
|
|
42
|
+
'product': '[C;D2;x0;z3:1](-;!@[C;x0;z2:2])#[C;D2;x0;M]',
|
|
43
|
+
'reactants': [
|
|
44
|
+
'[A:1]',
|
|
45
|
+
'[A:2]-[Br;M]'
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2024 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
|
+
|
|
20
|
+
template = {
|
|
21
|
+
'name': 'Suzuki-Miyaura reaction',
|
|
22
|
+
'description': 'Ar-Ar Ar-CSP2 CSP2-CSP2 couplings',
|
|
23
|
+
'templates': [
|
|
24
|
+
{
|
|
25
|
+
'product': '[C;a;D3:1]-;!@[C;a:2]',
|
|
26
|
+
'reactants': [
|
|
27
|
+
'[A:1]-[B;M]([O;M])[O;M]',
|
|
28
|
+
'[A:2]-[Br;M]'
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
'product': '[C;a;D3:1]-;!@[C;z2:2]=[C;M]',
|
|
33
|
+
'reactants': [
|
|
34
|
+
'[A:1]-[B;M]([O;M])[O;M]',
|
|
35
|
+
'[A:2]-[Br;M]'
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
# reverse
|
|
40
|
+
'product': '[C;a;D3:1]-;!@[C;z2:2]=[C;M]',
|
|
41
|
+
'reactants': [
|
|
42
|
+
'[A:1]-[Br;M]',
|
|
43
|
+
'[A:2]-[B;M]([O;M])[O;M]'
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
'product': '[C;D2,D3;z2:1](-;!@[C;z2:2]=[C;M])=[C;M]',
|
|
48
|
+
'reactants': [
|
|
49
|
+
'[A:1]-[B;M]([O;M])[O;M]',
|
|
50
|
+
'[A:2]-[Br;M]'
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|