diff --git a/chython/algorithms/fingerprints/morgan.py b/chython/algorithms/fingerprints/morgan.py index 9f8d0ab5..9cec29fe 100644 --- a/chython/algorithms/fingerprints/morgan.py +++ b/chython/algorithms/fingerprints/morgan.py @@ -40,7 +40,7 @@ def morgan_fingerprint(self, min_radius: int = 1, max_radius: int = 4, :param min_radius: minimal radius of EC :param max_radius: maximum radius of EC :param length: bit string's length. Should be power of 2 - :param number_active_bits: number of active bits for each hashed tuple + :param number_active_bits: number of active bits for each hashed tuple (int or 'auto'). For 'auto' option, number of bits is count of each hash + 1. :return: array(n_features) """ @@ -57,20 +57,30 @@ def morgan_bit_set(self, min_radius: int = 1, max_radius: int = 4, :param min_radius: minimal radius of EC :param max_radius: maximum radius of EC :param length: bit string's length. Should be power of 2 - :param number_active_bits: number of active bits for each hashed tuple + :param number_active_bits: number of active bits for each hashed tuple (int or 'auto'). For 'auto' option, number of bits is count of each hash + 1. """ mask = length - 1 log = int(log2(length)) active_bits = set() - for tpl in self.morgan_hash_set(min_radius, max_radius): - active_bits.add(tpl & mask) - if number_active_bits == 2: - active_bits.add(tpl >> log & mask) - elif number_active_bits > 2: - for _ in range(1, number_active_bits): - tpl >>= log - active_bits.add(tpl & mask) + + if number_active_bits == 'auto': + for hsh, cnt in self.morgan_hash_counts(min_radius, max_radius): + active_bits.add(hsh & mask) + active_bits.add(hsh >> log & mask) + for _ in range(cnt-1): + hsh >>= log + active_bits.add(hsh & mask) + + else: + for tpl in self.morgan_hash_set(min_radius, max_radius): + active_bits.add(tpl & mask) + if number_active_bits == 2: + active_bits.add(tpl >> log & mask) + elif number_active_bits > 2: + for _ in range(1, number_active_bits): + tpl >>= log + active_bits.add(tpl & mask) return active_bits def morgan_hash_set(self: 'MoleculeContainer', min_radius: int = 1, max_radius: int = 4) -> Set[int]: @@ -129,6 +139,38 @@ def _morgan_hash_dict(self: 'MoleculeContainer', min_radius: int = 1, max_radius out.append(identifiers) return out[-(max_radius - min_radius + 1):] # slice [min, max] radii range + def morgan_hash_counts(self, min_radius: int = 1, max_radius: int = 4) -> List[tuple]: + """ + Count occurrences of each hash from _morgan_hash_dict. + + :param min_radius: minimal radius of EC + :param max_radius: maximum radius of EC + :return: list of (hash, count) tuples + """ + counts = defaultdict(int) + for hash_dict in self._morgan_hash_dict(min_radius, max_radius): + for h in hash_dict.values(): + counts[h] += 1 + return list(counts.items()) + + def morgan_count_fingerprint(self, min_radius: int = 1, max_radius: int = 4, length: int = 256): + """ + Transform structures into array of integer features, where each feature is the count of its corresponding hash. + Each fragment (hash) contributes only one positional bit in the fingerprint. + + :param min_radius: minimal radius of EC + :param max_radius: maximum radius of EC + :param length: fingerprint length. Should be power of 2 + :return: array(n_features) of counts + """ + mask = length - 1 + fingerprint = zeros(length, dtype=int) + for hsh, cnt in self.morgan_hash_counts(min_radius, max_radius): + fingerprint[hsh & mask] += cnt + return fingerprint + + + @property def _atom_identifiers(self) -> Dict[int, int]: raise NotImplementedError diff --git a/chython/containers/reaction.py b/chython/containers/reaction.py index 92c3f3cb..67c2d260 100644 --- a/chython/containers/reaction.py +++ b/chython/containers/reaction.py @@ -29,6 +29,7 @@ from ..algorithms.depict import DepictReaction from ..algorithms.mapping import Mapping from ..algorithms.standardize import StandardizeReaction +from numpy import zeros class ReactionContainer(StandardizeReaction, Mapping, Calculate2DReaction, DepictReaction): @@ -321,4 +322,33 @@ def __len__(self): return len(self.reactants) + len(self.products) + len(self.reagents) + def diff_fingerprint(self, min_radius: int = 1, max_radius: int = 4, length: int = 1024, number_active_bits: int = 2, count_fp: bool = False): + """ + Calculate the difference fingerprint for a reaction: products minus reactants. + + :param reaction: ReactionContainer object + :param min_radius: minimal radius of EC + :param max_radius: maximum radius of EC + :param length: fingerprint length. Should be power of 2 + :param number_active_bits: number of active bits for each hashed tuple (int or 'auto'). For 'auto' option, number of bits is count of each hash + 1. + + :return: array(n_features) of difference counts + """ + reactant_fp = zeros(length, dtype=uint8) + product_fp = zeros(length, dtype=uint8) + + if count_fp: + for mol in self.reactants: + reactant_fp += mol.morgan_count_fingerprint(min_radius, max_radius, length) + for mol in self.products: + product_fp += mol.morgan_count_fingerprint(min_radius, max_radius, length) + r_fp = product_fp - reactant_fp + else: + for mol in self.reactants: + reactant_fp |= mol.morgan_fingerprint(min_radius, max_radius, length, number_active_bits) + for mol in self.products: + product_fp |= mol.morgan_fingerprint(min_radius, max_radius, length, number_active_bits) + r_fp = product_fp & ~reactant_fp + return r_fp + __all__ = ['ReactionContainer'] diff --git a/chython/reactor/reactions/__init__.py b/chython/reactor/reactions/__init__.py index 78e2f9e9..0640c5ad 100644 --- a/chython/reactor/reactions/__init__.py +++ b/chython/reactor/reactions/__init__.py @@ -29,6 +29,13 @@ from ._sonogashira import template as songashira_template from ._sulfonamidation import template as sulfonamidation_template from ._suzuki_miyaura import template as suzuki_miyaura_template +from ._xec_sp2_sp3 import template as xec_sp2_sp3_template +from ._aromatic_C_O import template as aromatic_C_O_template +from ._aliphatic_C_O import template as aliphatic_C_O_template +from ._aliphatic_C_N import template as aliphatic_C_N_template +from ._mitsunobu import template as mitsunobu_template +from ._decarboxylative_xec import template as decarboxylative_xec_template +from ._negishi import template as negishi_template from ..reactor import Reactor, fix_mapping_overlap from ... import smarts, ReactionContainer, MoleculeContainer diff --git a/chython/reactor/reactions/_aliphatic_C_N.py b/chython/reactor/reactions/_aliphatic_C_N.py new file mode 100644 index 00000000..6e6dc779 --- /dev/null +++ b/chython/reactor/reactions/_aliphatic_C_N.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2022-2024 Ramil Nugmanov +# Copyright 2023 Timur Gimadiev +# This file is part of chython. +# +# chython is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, see . +# + + +template = { + 'name': 'Aliphatic C-N coupling reaction', + 'description': 'Nucleophilic substitution of aliphatic chlorides, bromides, iodides, sulfonates and sulfates with nitrogen nucleophiles such as amines, amides, hydrazines, hydrazones, N-H-aromatic heterocycles, etc.', + 'templates': [ + { + 'A': [ + # Hal-Alk + '[Cl,Br,I;D1:1]-[C;z1:2]', + # Alk-Sulfonate, i.e. mesylates, tosylates, triflates, nosylates, brosylates, etc. + '[C;z1:2]-[O:1]-[S;D4:4](=[O:5])(=[O:6])-[C:7]', + # Dimethyl sulfate, diethyl sulfate, etc. + '[C;z1:2]-[O:1]-[S;D4:4](=[O:5])(=[O:6])-[O:7]-[C:8]', + ], + 'B': [ + # Very generic nitrogen nucleophile, can be amine, amide, hydrazine, hydrazone, N-H-aromatic heterocycle, etc. + # The only requirement is that nitrogen has at least one hydrogen attached to it + '[N;h1,h2,h3:3]', + '[N:3]-[H:9]' + ], + 'product': '[A:2]-[A:3]', + 'alerts': [], + 'ufe': { + 'A': 1, + 'B': '[A:3][At;M]' + } + } + ], + 'alerts': [] +} diff --git a/chython/reactor/reactions/_aliphatic_C_O.py b/chython/reactor/reactions/_aliphatic_C_O.py new file mode 100644 index 00000000..bee82b61 --- /dev/null +++ b/chython/reactor/reactions/_aliphatic_C_O.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2022-2024 Ramil Nugmanov +# Copyright 2023 Timur Gimadiev +# This file is part of chython. +# +# chython is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, see . +# + + +template = { + 'name': 'Aliphatic C-O coupling reaction', + 'description': 'Nucleophilic substitution of aliphatic chlorides, bromides, iodides, sulfonates and sulfates with alcohols and phenols. Williamson ether synthesis or whatever is your preferred name for this type of reaction', + 'templates': [ + { + 'A': [ + # Hal-Alk + '[Cl,Br,I;D1:1]-[C;z1:2]', + # Alk-Sulfonate, i.e. mesylates, tosylates, triflates, nosylates, brosylates, etc. + '[C;z1:2]-[O:1]-[S;D4:4](=[O:5])(=[O:6])-[C:7]', + # Dimethyl sulfate, diethyl sulfate, etc. + '[C;z1:2]-[O:1]-[S;D4:4](=[O:5])(=[O:6])-[O:7]-[C:8]', + ], + 'B': [ + # Ar-OH + '[O;D1;x0;z1:3][C;a;M]', + # Alk-OH + '[O;D1;x0;z1:3][C;z1;x1;M]', + ], + 'product': '[A:2]-[A:3]', + 'alerts': [], + 'ufe': { + 'A': 1, + 'B': '[A:3][At;M]' + } + } + ], + 'alerts': [] +} diff --git a/chython/reactor/reactions/_aromatic_C_O.py b/chython/reactor/reactions/_aromatic_C_O.py new file mode 100644 index 00000000..bcd961c4 --- /dev/null +++ b/chython/reactor/reactions/_aromatic_C_O.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2022-2024 Ramil Nugmanov +# Copyright 2023 Timur Gimadiev +# This file is part of chython. +# +# chython is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, see . +# + + +template = { + 'name': 'Aromatic C-O coupling reaction', + 'description': 'Aromatic C-O coupling reaction of aryl chlorides, bromides, and iodides with with alcohols and phenols', + 'templates': [ + { + 'A': [ + # Hal-Ar + '[Cl,Br,I;D1:1]-[C;a:2]' + ], + 'B': [ + # Ar-OH + '[O;D1;x0;z1:3][C;a;M]', + # Alk-OH + '[O;D1;x0;z1:3][C;z1;x1;M]', + ], + 'product': '[A:2]-[A:3]', + 'alerts': [], + 'ufe': { + 'A': 1, + 'B': '[A:3][At;M]' + } + } + ], + 'alerts': [] +} diff --git a/chython/reactor/reactions/_buchwald_hartwig.py b/chython/reactor/reactions/_buchwald_hartwig.py index 552a7d6d..370e074b 100644 --- a/chython/reactor/reactions/_buchwald_hartwig.py +++ b/chython/reactor/reactions/_buchwald_hartwig.py @@ -26,7 +26,9 @@ { 'A': [ # Hal-Ar - '[Cl,Br,I;D1:1]-[C;a:2]' + '[Cl,Br,I;D1:1]-[C;a:2]', + # Ar triflate + '[C;a:2]-[O;D2;x1:1]-[S;x3;D4:10](=[O:11])(=[O:12])-[C;D4;z1:13](-[F;D1:14])(-[F;D1:15])-[F;D1:16]' ], 'B': [ # Ar-NH2 diff --git a/chython/reactor/reactions/_decarboxylative_xec.py b/chython/reactor/reactions/_decarboxylative_xec.py new file mode 100644 index 00000000..5b4756c8 --- /dev/null +++ b/chython/reactor/reactions/_decarboxylative_xec.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2024 Ramil Nugmanov +# This file is part of chython. +# +# chython is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, see . +# + + +template = { + 'name': 'Macmillan', + 'description': 'Deoxygenative C-C coupling reaction', + 'templates': [ + { + 'A': [ + # Hal-Ar + '[Cl,Br,I;D1:1]-[C;a:2]' + ], + 'B': [ + # AlkCOOH + '[C;z1:3]-[C;x2;z2:4](=[O:5])-[O;D1;x0;z1:6]', + # Redox ester + '[C;z1:3]-[C;x2;z2:4](=[O:5])-[O;D2;x1;z1:6]-[N;z1;x1;D3:7]1-[C;x2;z2:8](=[O:9])-[C;x0;z2,z4:10]!#[C;x0;z2,z4:11]-[C;x2;z2:12](=[O:13])-1' + ], + 'product': '[A:2]-[A:3]', + 'alerts': [], + 'ufe': { + 'A': 1, + 'B': 3 + } + } + ], + 'alerts': [] +} diff --git a/chython/reactor/reactions/_mitsunobu.py b/chython/reactor/reactions/_mitsunobu.py new file mode 100644 index 00000000..f4a1ab30 --- /dev/null +++ b/chython/reactor/reactions/_mitsunobu.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2022-2024 Ramil Nugmanov +# Copyright 2023 Timur Gimadiev +# This file is part of chython. +# +# chython is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, see . +# + +template = { + 'name': 'Mitsunobu reaction', + 'description': 'Mitsunobu coupling of aliphatic alcohols and various acidic nucleophiles such as phenols, carboxylic acids, thiols, etc.', + 'templates': [ + { + 'A': [ + # Chiral alcohol + '[O;D1:1]-[C;@@;z1:2](-[C;M])-[C;M]', + ], + 'B': [ + # Ar-OH + '[O;D1;x0;z1:3][C;a;M]', + # COOH + '[O;D1;x0;z1:3]-[C;x2;z2;M](=[O;M])-[C;M]', + # Thiol + '[S;D1;x0;z1:3][C;M]', + # Imides + '[N;D2;x0;z1:3](-[C;x2,x3;z2;M](=[O;M]))-[C;x2,x3;z2;M](=[O;M])', + # Sulfonamides + '[N;D1,D2;z1:3]-[S;x3;M](=[O;M])(=[O;M])-[C;M]', + # Azide anion + '[N;-1:3]=[N;+1;M]=[N;-1;M]', + # N-H heterocycles + '[N;D2;a;h1:3](:[C,N,S;a;M]):[C,N;a;M]', + '[H:4][N;D3:3](:[C,N,S;a;M]):[C,N;a;M]', + ], + 'product': '[A;@@:2]-[A:3]', + 'alerts': [], + 'ufe': { + 'A': 1, + 'B': '[A:3][At;M]' + } + }, + { + 'A': [ + # OH-Alk + '[O;D1:1]-[C;z1:2]', + ], + 'B': [ + # Ar-OH + '[O;D1;x0;z1:3][C;a;M]', + # COOH + '[O;D1;x0;z1:3]-[C;x2;z2;M](=[O;M])-[C;M]', + # Thiol + '[S;D1;x0;z1:3][C;M]', + # Imides + '[N;D2;x0;z1:3](-[C;x2,x3;z2;M](=[O;M]))-[C;x2,x3;z2;M](=[O;M])', + # Sulfonamides + '[N;D1,D2;z1:3]-[S;x3;M](=[O;M])(=[O;M])-[C;M]', + # Azide anion + '[N;-1:3]=[N;+1;M]=[N;-1;M]', + # N-H heterocycles + '[N;D2;a;h1:3](:[C,N,S;a;M]):[C,N;a;M]', + '[H:4][N;D3:3](:[C,N,S;a;M]):[C,N;a;M]', + # Thiophenol + + ], + 'product': '[A:2]-[A:3]', + 'alerts': [], + 'ufe': { + 'A': 1, + 'B': '[A:3][At;M]' + } + } + ], + 'alerts': [] +} diff --git a/chython/reactor/reactions/_negishi.py b/chython/reactor/reactions/_negishi.py new file mode 100644 index 00000000..6d951cc3 --- /dev/null +++ b/chython/reactor/reactions/_negishi.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2022-2024 Ramil Nugmanov +# Copyright 2023 Timur Gimadiev +# This file is part of chython. +# +# chython is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, see . +# + + +template = { + 'name': 'Negishi coupling reaction', + 'description': 'Negishi C-C coupling reaction of sp2-C halides and organozinc reagents', + 'templates': [ + { + 'A': [ + # X-Ar + '[Cl,Br,I;D1:1]-[C;a:2]', + # X-C-sp2 + '[Cl,Br,I;D1:1]-[C;x1,x2;z2:2]=[C;x0,x1;z2;M]', + # Ar triflate + '[C;a:2]-[O;D2;x1:1]-[S;x3;D4:10](=[O:11])(=[O:12])-[C;D4;z1:13](-[F;D1:14])(-[F;D1:15])-[F;D1:16]', + # Vinyl triflates + '[C;x0,x1;z2;M]=[C;x1;z2:2]-[O;D2;x1:1]-[S;x3;D4:10](=[O:11])(=[O:12])-[C;D4;z1:13](-[F;D1:14])(-[F;D1:15])-[F;D1:16]', + ], + 'B': [ + # C-Zn + '[Zn]-[C:3]', + ], + 'product': '[A:2]-[A:3]', + 'alerts': [], + 'ufe': { + 'A': 1, + 'B': '[A:3][At;M]' + } + } + ], + 'alerts': [] +} diff --git a/chython/reactor/reactions/_suzuki_miyaura.py b/chython/reactor/reactions/_suzuki_miyaura.py index 57535a1d..d3e3b571 100644 --- a/chython/reactor/reactions/_suzuki_miyaura.py +++ b/chython/reactor/reactions/_suzuki_miyaura.py @@ -26,7 +26,9 @@ { 'A': [ # X-Ar - '[Cl,Br,I;D1:1]-[C;a:2]' + '[Cl,Br,I;D1:1]-[C;a:2]', + # Ar triflate + '[C;a:2]-[O;D2;x1:1]-[S;x3;D4:10](=[O:11])(=[O:12])-[C;D4;z1:13](-[F;D1:14])(-[F;D1:15])-[F;D1:16]' ], 'B': [ # Ar-B @@ -48,7 +50,10 @@ { 'A': [ # X-C=C - '[Cl,Br,I;D1:1]-[C;x1,x2;z2:2]=[C;x0,x1;z2;M]' + '[Cl,Br,I;D1:1]-[C;x1,x2;z2:2]=[C;x0,x1;z2;M]', + # Vinyl triflates + '[C;x0,x1;z2;M]=[C;x1;z2:2]-[O;D2;x1:1]-[S;x3;D4:10](=[O:11])(=[O:12])-[C;D4;z1:13](-[F;D1:14])(-[F;D1:15])-[F;D1:16]', + ], 'B': [ # Ar-B diff --git a/chython/reactor/reactions/_xec_sp2_sp3.py b/chython/reactor/reactions/_xec_sp2_sp3.py new file mode 100644 index 00000000..9e4c7ee9 --- /dev/null +++ b/chython/reactor/reactions/_xec_sp2_sp3.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2024 Ramil Nugmanov +# This file is part of chython. +# +# chython is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, see . +# + + +template = { + 'name': 'XEC', + 'description': 'Cross-electrophile C-sp2-X C-sp3-X coupling reaction', + 'templates': [ + { + 'A': [ + # Hal-Ar + '[Cl,Br,I;D1:1]-[C;a:2]', + # Hal-pseudoaromatic, more specifically C5, C6 vinylic + '[Cl,Br,I;D1:1]-[C;z2;r5,r6:2]', + # Ar triflate + '[C;a:2]-[O;D2;x1:1]-[S;x3;D4:10](=[O:11])(=[O:12])-[C;D4;z1:13](-[F;D1:14])(-[F;D1:15])-[F;D1:16]' + ], + 'B': [ + # sp3-C-X + '[Cl,Br,I;D1:3]-[C;z1:4]' + ], + 'product': '[A:2]-[A:4]', + 'alerts': [], + 'ufe': { + 'A': 1, + 'B': 3 + } + } + ], + 'alerts': [] +}