Exemple #1
0
def map_atoms(mol_a: Mol, mol_b: Mol) -> Dict[int, int]:
    """Find all atoms in mol_a in mol_b

    Args:
        mol_a:
        mol_b:

    Returns:
        Dictionary where key are atom indices from mol_a and values are atom indices from mol_b
    """
    a_conf = mol_a.GetConformer()
    b_conf = mol_b.GetConformer()

    # find mapping of atoms from mol to parent
    a2b_atoms = {}
    b2a_atoms = {}
    for a in mol_a.GetAtoms():
        a_pos = a_conf.GetAtomPosition(a.GetIdx())
        for b in mol_b.GetAtoms():
            if b.GetIdx() in b2a_atoms:
                # Don't try to map same atom twice
                continue
            bp_pos = b_conf.GetAtomPosition(b.GetIdx())
            if b.Match(
                    a
            ) and a_pos.x == bp_pos.x and a_pos.y == bp_pos.y and a_pos.z == bp_pos.z:
                a2b_atoms[a.GetIdx()] = b.GetIdx()
                b2a_atoms[b.GetIdx()] = a.GetIdx()

    return a2b_atoms
Exemple #2
0
 def from_rdmol(cls, rdmol: Chem.Mol, atomidx2nodename=None):
     """
     :param rdmol:
     :param atomidx2nodename: the dict to convert atomidx in rdmol to graph node, atomidx2nodename[rdmolid] == nodename
     if not None then nodename will be set just based on atomidx
     :return:
     """
     g = nx.Graph()
     if atomidx2nodename:
         index_dict_no = atomidx2nodename
         for atom in rdmol.GetAtoms():
             g.add_node(
                 index_dict_no[atom.GetIdx()],
                 symbol=atom.GetSymbol(),
             )
         for bond in rdmol.GetBonds():
             g.add_edge(
                 index_dict_no[bond.GetBeginAtomIdx()],
                 index_dict_no[bond.GetEndAtomIdx()],
             )
     else:
         for atom in rdmol.GetAtoms():
             g.add_node(
                 atom.GetIdx(),
                 symbol=atom.GetSymbol(),
             )
         for bond in rdmol.GetBonds():
             g.add_edge(
                 bond.GetBeginAtomIdx(),
                 bond.GetEndAtomIdx(),
             )
     if not nx.is_connected(g):
         raise GraphError('the graph is not connected!')
     return cls(g)
Exemple #3
0
    def process(self, mol: chem.Mol, atom_map: Dict[int, int]) -> GCNGraph:
        n = mol.GetNumAtoms() + 1  # allocate a new node for graph embedding

        # all edges (including all self-loops) as index
        begin_idx = [u.GetBeginAtomIdx()
                     for u in mol.GetBonds()] + [n - 1] * (n - 1)
        end_idx = [u.GetEndAtomIdx()
                   for u in mol.GetBonds()] + list(range(n - 1))
        assert len(begin_idx) == len(end_idx)
        ran = list(range(n))
        index = [begin_idx + end_idx + ran, end_idx + begin_idx + ran]

        # construct coefficients adjacent matrix
        deg = torch.tensor(
            [sqrt(1 / (len(u.GetNeighbors()) + 2))
             for u in mol.GetAtoms()] + [sqrt(1 / n)],
            device=self.device)
        coeff = deg.reshape(-1, 1) @ deg[None, :]  # pairwise coefficients
        adj = torch.zeros((n, n), device=self.device)
        adj[index] = coeff[index]

        # node embedding
        num = torch.tensor(
            [atom_map[u.GetAtomicNum()]
             for u in mol.GetAtoms()] + [len(atom_map)],
            device=self.device)

        return GCNGraph(n, adj, num)
Exemple #4
0
    def get_conjugate_group_with_halogen(m: Mol):
        natoms = len(m.GetAtoms())
        adjmat = np.zeros((natoms, natoms), dtype=bool)
        for i in range(natoms):
            for j in range(i + 1, natoms):
                if isinstance(m.GetBondBetweenAtoms(i, j), Bond):
                    adjmat[i][j] = True
                    adjmat[j][i] = True

        supp = ResonanceMolSupplier(m, )
        # supp = ResonanceMolSupplier(m, Chem.KEKULE_ALL)
        # supp = ResonanceMolSupplier(m, Chem.ALLOW_CHARGE_SEPARATION)
        cg_dict = {}
        a: Atom
        for a in m.GetAtoms():
            aid = a.GetIdx()
            cgid = supp.GetAtomConjGrpIdx(aid)
            if cgid < 1e5:
                cg_dict[aid] = cgid
        cgids = set(cg_dict.values())
        cgs = []
        for cgid in cgids:
            cg = [i for i in cg_dict.keys() if cg_dict[i] == cgid]
            atom: Atom
            for atom in m.GetAtoms():
                if atom.GetIdx() not in cg:
                    if any(adjmat[atom.GetIdx()][cg_aid]
                           for cg_aid in cg) and atom.GetSymbol() in ("I", "F",
                                                                      "Cl",
                                                                      "Br"):
                        cg.append(atom.GetIdx())
            cgmol, old_id_2_new_id = RdFunc.get_sub_rdmol(m, cg)
            cgs.append([cgmol, old_id_2_new_id])
        return sorted(cgs, key=lambda x: x[0].GetNumAtoms(), reverse=True)
Exemple #5
0
def remap_reaction_to_canonical(input_mol: Mol,
                                target_mol: Mol) -> Tuple[Mol, Mol]:
    """
    Re-maps reaction according to order of atoms in RdKit - this makes sure that stereochemical SMILES are canonical.
    Note: this method does not transfer any information from target molecule to the input molecule
    (the input molecule is mapped according to its order of atoms in its canonical SMILES)
    """

    # converting Mol to smiles and again to Mol makes atom order canonical
    input_mol = Chem.MolFromSmiles(Chem.MolToSmiles(input_mol))
    target_mol = Chem.MolFromSmiles(Chem.MolToSmiles(target_mol))

    map2map = {}
    for i, a in enumerate(input_mol.GetAtoms()):
        map2map[int(a.GetAtomMapNum())] = i + 1
        a.SetAtomMapNum(i + 1)

    max_map = max(map2map.values())

    for i, a in enumerate(target_mol.GetAtoms()):
        old_map = int(a.GetAtomMapNum())
        if old_map in map2map:
            new_map = map2map[old_map]
        else:
            new_map = max_map + 1
            max_map += 1
        a.SetAtomMapNum(new_map)

    return input_mol, target_mol
def map_reac_to_prod(mol_reac: Chem.Mol, mol_prod: Chem.Mol):
    """
    Build a dictionary of mapping atom indices in the reactants to the products.

    :param mol_reac: An RDKit molecule of the reactants.
    :param mol_prod: An RDKit molecule of the products.
    :return: A dictionary of corresponding reactant and product atom indices.
    """
    only_prod_ids = []
    prod_map_to_id = {}
    mapnos_reac = set([atom.GetAtomMapNum() for atom in mol_reac.GetAtoms()])
    for atom in mol_prod.GetAtoms():
        mapno = atom.GetAtomMapNum()
        if mapno > 0:
            prod_map_to_id[mapno] = atom.GetIdx()
            if mapno not in mapnos_reac:
                only_prod_ids.append(atom.GetIdx())
        else:
            only_prod_ids.append(atom.GetIdx())
    only_reac_ids = []
    reac_id_to_prod_id = {}
    for atom in mol_reac.GetAtoms():
        mapno = atom.GetAtomMapNum()
        if mapno > 0:
            try:
                reac_id_to_prod_id[atom.GetIdx()] = prod_map_to_id[mapno]
            except KeyError:
                only_reac_ids.append(atom.GetIdx())
        else:
            only_reac_ids.append(atom.GetIdx())
    return reac_id_to_prod_id, only_prod_ids, only_reac_ids
def setup_relative_restraints_by_distance(mol_a: Chem.Mol,
                                          mol_b: Chem.Mol,
                                          cutoff: float = 0.1,
                                          terminal: bool = False):
    """
    Setup restraints between atoms in two molecules using
    a cutoff distance between atoms

    Parameters
    ----------
    mol_a: Chem.Mol
        First molecule

    mol_b: Chem.Mol
        Second molecule

    cutoff: float=0.1
        Distance between atoms to consider as a match

    terminal: bool=false
        Map terminal atoms

    Returns
    -------
    np.array (N, 2)
        Atom mapping between atoms in mol_a to atoms in mol_b.
    """

    ligand_coords_a = get_romol_conf(mol_a)
    ligand_coords_b = get_romol_conf(mol_b)
    core_idxs_a = []
    core_idxs_b = []

    for idx, a in enumerate(mol_a.GetAtoms()):
        if not terminal and a.GetDegree() == 1:
            continue
        for b_idx, b in enumerate(mol_b.GetAtoms()):
            if not terminal and b.GetDegree() == 1:
                continue
            if np.linalg.norm(ligand_coords_a[idx] -
                              ligand_coords_b[b_idx]) < cutoff:
                core_idxs_a.append(idx)
                core_idxs_b.append(b_idx)
    assert len(core_idxs_a) == len(core_idxs_b), "Core sizes were inconsistent"

    rij = cdist(ligand_coords_a[core_idxs_a], ligand_coords_b[core_idxs_b])

    row_idxs, col_idxs = linear_sum_assignment(rij)

    core_idxs = []

    for core_a, core_b in zip(row_idxs, col_idxs):
        core_idxs.append((core_idxs_a[core_a], core_idxs_b[core_b]))

    core_idxs = np.array(core_idxs, dtype=np.int32)

    return core_idxs
Exemple #8
0
def embed_r_groups(mol: Mol, parent: Mol):
    """Assign coordinates to R groups

    Args:
        mol: Molecule with atoms with '*' as symbol
        parent: Molecule that was used to generate `mol`

    Raises:
        LookupError: When atoms bonded to R group can not be found in parent

    """
    mol2parent_idxs = map_atoms(mol, parent)
    parent2mol_idxs = {v for v in mol2parent_idxs.values()}
    idx2parent_atom = {a.GetIdx(): a for a in parent.GetAtoms()}

    mol_conf = mol.GetConformer()
    parent_conf = parent.GetConformer()
    r_pos_cache = set()
    for r_atom in mol.GetAtoms():
        if r_atom.GetSymbol() == '*':
            for r_bond in r_atom.GetBonds():
                # atom bonded to r group in mol
                r_bonded_atom = r_bond.GetOtherAtom(r_atom)
                r_bonded_idx = r_bonded_atom.GetIdx()
                if r_bonded_idx in mol2parent_idxs:
                    # same atom in parent
                    r_bonded_atom_parent_idx = mol2parent_idxs[r_bonded_idx]
                    r_bonded_atom_parent = idx2parent_atom[
                        r_bonded_atom_parent_idx]
                    for r_bonded_atom_parent_bond in r_bonded_atom_parent.GetBonds(
                    ):
                        # Atom bonded to atom which is bonded to R group in parent
                        r_bonded_atom_parend_bonded_atom = r_bonded_atom_parent_bond.GetOtherAtom(
                            r_bonded_atom_parent)
                        r_bonded_atom_parend_bonded_atom_idx = r_bonded_atom_parend_bonded_atom.GetIdx(
                        )
                        if r_bonded_atom_parend_bonded_atom_idx not in parent2mol_idxs:
                            # atom in parent but not in mol which was replaced R group
                            point = parent_conf.GetAtomPosition(
                                r_bonded_atom_parend_bonded_atom_idx)
                            if serialize_point(point) not in r_pos_cache:
                                # Position has not been used for other R group
                                mol_conf.SetAtomPosition(
                                    r_atom.GetIdx(), point)
                                r_pos_cache.add(serialize_point(point))
                                break
                else:
                    raise LookupError(
                        'Atom bonded to R group not found in parent')
Exemple #9
0
 def get_atom(self, mol: Chem.Mol, name: str) -> Chem.Atom:
     for atom in mol.GetAtoms():
         if atom.HasProp('_AtomName') and name == atom.GetProp(
                 '_AtomName'):  # Nonstandard. do not copy
             return atom
     else:
         raise ValueError(f'Atom {name} not found')
Exemple #10
0
    def _categorise(self, mol: Chem.Mol,
                    uniques: set) -> Dict[str, Union[set, Dict]]:
        """
        What do the novel atoms do in terms of connectivity.
        Complicated dict output (called ``categories`` in the methods). Really ought to be SetProp of the atoms.

        * ``uniques`` are set of atoms to classify on
        * ``internals`` are unique atoms that are connected solely to unique atoms
        * ``attachments`` are non-unique atoms to which a unique atom connects
        * ``pairs`` is a dict of unique atom idx --> dict of ``idx`` --> attachment idx and ``type`` bond type.

        :param mol: molecule to describe
        :param uniques: set of indices that are new to this molecule
        :return:
        """
        #
        pairs = {}
        internals = set()
        attachments = set()
        dummies = set()
        for i in uniques:  # novel atoms
            unique_atom = mol.GetAtomWithIdx(i)
            if unique_atom.GetSymbol() == self.dummy_symbol:
                dummies.add(i)
            neighbours = {n.GetIdx() for n in unique_atom.GetNeighbors()}
            if len(neighbours - uniques
                   ) == 0:  # unlessone of the connections is not unique.
                internals.add(i)
            else:
                i_attached = neighbours - uniques
                attachments |= i_attached
                pairs[i] = [{
                    'idx': j,
                    'type': mol.GetBondBetweenAtoms(i, j).GetBondType()
                } for j in i_attached]
        anchors = uniques - internals
        # store for safekeeping
        for atom in mol.GetAtoms():
            i = atom.GetIdx()
            if i in internals:  # novel and not connected
                atom.SetProp('_Category', 'internal')
            elif i in attachments:  # not-novel but connected
                atom.SetProp('_Category', 'overlapping-attachment')
            elif i in pairs:  # dict not set tho
                atom.SetProp('_Category', 'internal-attachment')
            else:  # overlapping
                atom.SetProp('_Category', 'overlapping')
        # if self._debug_draw: # depracated... but this could be useful...
        #     high = list(internals) + list(attachments) + list(anchors)
        #     color = {**{i: (0, 0.8, 0) for i in internals},
        #              **{i: (0, 0, 0.8) for i in attachments},
        #              **{i: (0.8, 0, 0.8) for i in anchors}}
        #     print('Purple: anchor atoms, Blue: attachments, Green: internals')
        #     self.draw_nicely(mol, highlightAtoms=high, highlightAtomColors=color)
        #     print({atom.GetIdx(): atom.GetProp('_Category') for atom in mol.GetAtoms()})
        return dict(uniques=uniques,
                    internals=internals,
                    attachments=attachments,
                    pairs=pairs,
                    dummies=dummies)
Exemple #11
0
def rdkit_to_openbabel_mol(mol: Chem.Mol) -> openbabel.OBMol:
    """Convert a RDKit molecule to an OpenBabel molecule.

    :param mol: RDKit molecule
    """
    obmol = openbabel.OBMol()
    # Add hydrogen atoms to complete molecule if needed
    rdkitmol = Chem.Mol(mol)
    # Perceive valence and ring information before assigning hydrogens
    rdkitmol.UpdatePropertyCache(strict=False)
    rdkitmol = Chem.AddHs(rdkitmol)
    # Kekulize molecule
    Chem.rdmolops.Kekulize(rdkitmol, clearAromaticFlags=True)
    # Add atoms
    for atom in mol.GetAtoms():
        # Create new atom and assign values
        obatom = obmol.NewAtom()
        obatom.SetAtomicNum(atom.GetAtomicNum())
        obatom.SetIsotope(atom.GetIsotope())
        obatom.SetFormalCharge(atom.GetFormalCharge())
        obatom.SetPartialCharge(atom.GetDoubleProp('_PartialCharge'))
        obatom.SetSpinMultiplicity(atom.GetNumRadicalElectrons() + 1)
    for bond in mol.GetBonds():
        obmol.AddBond(bond.GetBeginAtomIdx() + 1, bond.GetEndAtomIdx() + 1, int(bond.GetBondTypeAsDouble()))
    obmol.AssignSpinMultiplicity(True)
    return obmol
Exemple #12
0
 def max_from_mol(self, mol: Chem.Mol = None):
     if mol is None:
         mol = self.positioned_mol
     return [
         atom.GetDoubleProp('_Max') if atom.HasProp('_Max') else 0
         for atom in mol.GetAtoms()
     ]
Exemple #13
0
 def assign_names(cls, mol: Chem.Mol, names: List[str]) -> None:
     """
     Stores names of atoms as given in the list.
     totally non-standard way. PDBInfo is correct way. But too much effort.
     """
     for name, atom in zip(names, mol.GetAtoms()):
         atom.SetProp('_AtomName', name)  # Nonstandard. do not copy
Exemple #14
0
def CalculateZagreb1(mol: Chem.Mol) -> float:
    """Get Zagreb index with order 1.

    Or ZM1.
    """
    deltas = [x.GetDegree() for x in mol.GetAtoms()]
    return sum(numpy.array(deltas)**2)
    def _get_new_index(self, mol: Chem.Mol, old: int, search_collapsed=True,
                       name_restriction: Optional[str] = None) -> int:
        """
        Given an old index check in ``_ori_i`` for what the current one is.
        NB. ring placeholder will be -1 and these also have ``_ori_is``. a JSON of the ori_i they summarise.

        :param mol:
        :param old: old index
        :param search_collapsed: seach also in ``_ori_is``
        :parm name_restriction: restrict to original name.
        :return:
        """
        for i, atom in enumerate(mol.GetAtoms()):
            if name_restriction is not None and atom.GetProp('_ori_name') != name_restriction:
                pass
            elif atom.GetIntProp('_ori_i') == old:
                return i
            elif search_collapsed and \
                    atom.HasProp('_ori_is') and \
                    old in json.loads(atom.GetProp('_ori_is')):
                return i
            else:
                pass
        else:
            raise ValueError(f'Cannot find {old}')
Exemple #16
0
def _CalculateMoranAutocorrelation(mol: Chem.Mol, lag: int = 1, propertylabel: str = 'm') -> float:
    """Calculate weighted Moran autocorrelation descriptors.

    :param lag: topological distance between atom i and atom j.
    :param propertylabel: type of weighted property
    """
    Natom = mol.GetNumAtoms()
    prolist = []
    for i in mol.GetAtoms():
        temp = GetRelativeAtomicProperty(i.GetSymbol(), propertyname=propertylabel)
        prolist.append(temp)
    aveweight = sum(prolist) / Natom
    tempp = [numpy.square(x - aveweight) for x in prolist]
    GetDistanceMatrix = Chem.GetDistanceMatrix(mol)
    res = 0.0
    index = 0
    for i in range(Natom):
        for j in range(Natom):
            if GetDistanceMatrix[i, j] == lag:
                atom1 = mol.GetAtomWithIdx(i)
                atom2 = mol.GetAtomWithIdx(j)
                temp1 = GetRelativeAtomicProperty(element=atom1.GetSymbol(), propertyname=propertylabel)
                temp2 = GetRelativeAtomicProperty(element=atom2.GetSymbol(), propertyname=propertylabel)
                res = res + (temp1 - aveweight) * (temp2 - aveweight)
                index += 1
            else:
                res = res + 0.0
    if sum(tempp) == 0 or index == 0:
        result = 0
    else:
        result = (res / index) / (sum(tempp) / Natom)
    return round(result, 3)
 def _prevent_allene(self, mol: Chem.Mol) -> Chem.Mol:
     if not isinstance(mol, Chem.RWMol):
         mol = Chem.RWMol(mol)
     for atom in mol.GetAtoms():
         if atom.GetAtomicNum() < 14:
             n = []
             for bond in atom.GetBonds():
                 if bond.GetBondType().name in ('DOUBLE', 'TRIPLE'):
                     n.append(bond)
                 else:
                     pass
             if len(n) > 2:
                 #this is a mess!
                 log.info(f'Allene issue: {n} double bonds on {atom.GetSymbol()} atom {atom.GetIdx()}!')
                 for bond in n:
                     bond.SetBondType(Chem.BondType().SINGLE)
             elif len(n) == 2:
                 # downgrade the higher bonded one!
                 others = [a for bond in n for a in (bond.GetBeginAtom(), bond.GetEndAtom()) if a.GetIdx() != atom.GetIdx()]
                 others = sorted(others, key=lambda atom: sum([b.GetBondTypeAsDouble() for b in atom.GetBonds()]))
                 log.info(f'Allene removed between {atom.GetIdx()} and {[a.GetIdx() for a in others]}')
                 mol.GetBondBetweenAtoms(atom.GetIdx(), others[-1].GetIdx()).SetBondType(Chem.BondType.SINGLE)
             else:
                 pass
         else:
             continue
     return mol
Exemple #18
0
    def mol_to_nx(mol: Chem.Mol):
        try:
            from tf_routes import preprocessing

            return preprocessing._mol_to_nx_full_weight(mol)
        except ModuleNotFoundError:

            G = nx.Graph()

            for atom in mol.GetAtoms():
                G.add_node(
                    atom.GetIdx(),
                    atomic_num=atom.GetAtomicNum(),
                    formal_charge=atom.GetFormalCharge(),
                    chiral_tag=atom.GetChiralTag(),
                    hybridization=atom.GetHybridization(),
                    num_explicit_hs=atom.GetNumExplicitHs(),
                    is_aromatic=atom.GetIsAromatic(),
                )

            for bond in mol.GetBonds():
                G.add_edge(
                    bond.GetBeginAtomIdx(),
                    bond.GetEndAtomIdx(),
                    bond_type=bond.GetBondType(),
                )

            return G
Exemple #19
0
def CalculateHalogenNumber(mol: Chem.Mol) -> float:
    """Calculate number of Halogens."""
    i = 0
    for atom in mol.GetAtoms():
        if atom.GetAtomicNum() in [9, 17, 35, 53]:
            i += 1
    return i
Exemple #20
0
def CalculateHeavyMolWeight(mol: Chem.Mol) -> float:
    """Calculate molecular weight of heavy atoms."""
    MolWeight = 0
    for atom in mol.GetAtoms():
        if atom.GetAtomicNum() != 1:
            MolWeight += atom.GetMass()
    return MolWeight
Exemple #21
0
def _CalculateElementNumber(mol: Chem.Mol, AtomicNumber=6) -> float:
    """Calculate number of atoms with specified element."""
    i = 0
    for atom in mol.GetAtoms():
        if atom.GetAtomicNum() == AtomicNumber:
            i += 1
    return i
Exemple #22
0
def CalculateHeteroNumber(mol: Chem.Mol) -> float:
    """Calculate number of Heteroatoms."""
    i = 0
    for atom in mol.GetAtoms():
        if atom.GetAtomicNum() not in [1, 6]:
            i += 1
    return mol.GetNumAtoms() - i
Exemple #23
0
def generate_orca_script_for_gas_phase(mol: Chem.Mol, conformer_id: int = 0) -> str:
    """Returns a psi4 Molecule object instance for a single conformer from a rdkit mol object.

    Parameters
    ----------
    mol : Chem.Mol
        rdkit mol object
    conformer_id : int
        specifies the conformer to use

    Returns
    -------
    mol : psi4.core.Molecule
        a psi4 molecule object instance
    """

    assert type(mol) == Chem.Mol or type(mol) == Chem.PropertyMol.PropertyMol
    atoms = mol.GetAtoms()

    header_str = "! B3LYP 6-31G*  \n"
    xyz_string_str = f"*xyz 0 1\n"
    for _, atom in enumerate(atoms):
        pos = mol.GetConformer(conformer_id).GetAtomPosition(atom.GetIdx())
        xyz_string_str += f"{atom.GetSymbol()} {pos.x:.7f} {pos.y:.7f} {pos.z:.7f}\n"
    xyz_string_str += "*"

    orca_input = header_str + xyz_string_str

    return orca_input
Exemple #24
0
    def find_symmetry_classes(rdkit_mol: Chem.Mol) -> Dict[int, str]:
        """
        Generate list of tuples of symmetry-equivalent (homotopic) atoms in the molecular graph
        based on: https://sourceforge.net/p/rdkit/mailman/message/27897393/
        Our thanks to Dr Michal Krompiec for the symmetrisation method and its implementation.
        :param rdkit_mol: molecule to find symmetry classes for (rdkit mol class object)
        :return: A dict where the keys are the atom indices and the values are their type
        (type is arbitrarily based on index; only consistency is needed, no specific values)
        """

        # Check CIPRank is present for first atom (can assume it is present for all afterwards)
        if not rdkit_mol.GetAtomWithIdx(0).HasProp("_CIPRank"):
            Chem.AssignStereochemistry(rdkit_mol,
                                       cleanIt=True,
                                       force=True,
                                       flagPossibleStereoCenters=True)

        # Array of ranks showing matching atoms
        cip_ranks = np.array(
            [int(atom.GetProp("_CIPRank")) for atom in rdkit_mol.GetAtoms()])

        # Map the ranks to the atoms to produce a list of symmetrical atoms
        atom_symmetry_classes = [
            np.where(cip_ranks == rank)[0].tolist()
            for rank in range(max(cip_ranks) + 1)
        ]

        # Convert from list of classes to dict where each key is an atom and each value is its class (just a str)
        atom_symmetry_classes_dict = {}
        # i will be used to define the class (just index based)
        for i, sym_class in enumerate(atom_symmetry_classes):
            for atom in sym_class:
                atom_symmetry_classes_dict[atom] = str(i)

        return atom_symmetry_classes_dict
    def _renumber_original_indices(self, mol: Chem.Mol,
                                   mapping: Dict[int, int],
                                   name_restriction: Optional[str] = None):
        """

        :param mol:
        :param mapping: old index to new index dictionary
        :param name_restriction:
        :return:
        """
        for atom in mol.GetAtoms():
            if name_restriction is not None and atom.HasProp('_ori_name') and atom.GetProp(
                    '_ori_name') != name_restriction:
                continue
            i = atom.GetIntProp('_ori_i')
            if i == -1:
                # original indices
                ori = json.loads(atom.GetProp('_ori_is'))
                alt = [dd if dd not in mapping else mapping[dd] for dd in ori]
                atom.SetProp('_ori_is', json.dumps(alt))
                # original neighbors
                ori = json.loads(atom.GetProp('_neighbors'))
                alt = [[dd if dd not in mapping else mapping[dd] for dd in inner] for inner in ori]
                atom.SetProp('_neighbors', json.dumps(alt))
            elif i in mapping:
                atom.SetIntProp('_ori_i', mapping[i])
            else:
                pass
Exemple #26
0
def to_graph(mol: Chem.Mol):
    """Convert a molecule to a network x graph. A list of properties are added
    to every nodes and edges.

    Args:
        mol (Chem.Mol): a molecule.

    Returns:
        mol_graph (networkx.Graph): a graph representing the molecule.
    """

    nx = _get_networkx()

    mol_graph = nx.Graph()
    for atom in mol.GetAtoms():
        mol_graph.add_node(
            atom.GetIdx(),
            atomic_num=atom.GetAtomicNum(),
            formal_charge=atom.GetFormalCharge(),
            chiral_tag=atom.GetChiralTag(),
            hybridization=atom.GetHybridization(),
            num_explicit_hs=atom.GetNumExplicitHs(),
            implicit_valence=atom.GetImplicitValence(),
            degree=atom.GetDegree(),
            symbol=atom.GetSymbol(),
            ring_atom=atom.IsInRing(),
            is_aromatic=atom.GetIsAromatic(),
        )
    for bond in mol.GetBonds():
        mol_graph.add_edge(
            bond.GetBeginAtomIdx(),
            bond.GetEndAtomIdx(),
            bond_type=bond.GetBondType(),
        )
    return mol_graph
    def _offset_origins(self, mol: Chem.Mol):
        """
        This is to prevent clashes.

        :param mol:
        :return:
        """
        self._collapsed_ring_offset += 100
        old2new = {}
        for atom in mol.GetAtoms():
            if atom.GetIntProp('_ori_i') != -1:
                o = atom.GetIntProp('_ori_i')
                n = o + self._collapsed_ring_offset
                atom.SetIntProp('_ori_i', n)
                old2new[o] = n
        for atom in self._get_collapsed_atoms(mol):
            old = json.loads(atom.GetProp('_ori_is'))
            new = [i + self._collapsed_ring_offset for i in old]
            atom.SetProp('_ori_is', json.dumps(new))
            old2new = {**old2new, **dict(zip(old, new))}
            if self._debug_draw:
                print('UPDATE', old2new)
            old_neighss = json.loads(atom.GetProp('_neighbors'))
            new_neighss = [[old2new[i] if i in old2new else i for i in old_neighs] for old_neighs in old_neighss]
            atom.SetProp('_neighbors', json.dumps(new_neighss))
Exemple #28
0
    def _generate_conformations_from_mol(self,
                                         mol: Chem.Mol,
                                         nr_of_conformations: int,
                                         enforceChirality: bool = True):
        """
        Helper function - does not need to be called directly.
        Generates conformations from a rdkit mol object.
        """

        charge = 0
        for at in mol.GetAtoms():
            if at.GetFormalCharge() != 0:
                charge += int(at.GetFormalCharge())

        if charge != 0:
            print(Chem.MolToSmiles(mol))
            raise NotImplementedError("Charged system")

        mol.SetProp("smiles", Chem.MolToSmiles(mol))
        mol.SetProp("charge", str(charge))
        mol.SetProp("name", str(self.name))

        # generate numConfs for the smiles string
        new_confs = Chem.rdDistGeom.EmbedMultipleConfs(
            mol,
            numConfs=nr_of_conformations,
            enforceChirality=enforceChirality,
            ignoreSmoothingFailures=True,
        )  # NOTE enforceChirality!

        # AllChem.AlignMolConformers(mol)
        assert int(mol.GetNumConformers()) != 0
        assert int(mol.GetNumConformers()) == nr_of_conformations

        return mol
Exemple #29
0
def get_node_infos(molecule: Chem.Mol) -> List[NodeInfo]:
    return [
        NodeInfo(
            symbol=ase.data.chemical_symbols[atom.GetAtomicNum()],
            chiral_tag=atom.GetChiralTag(),
        ) for atom in molecule.GetAtoms()
    ]
Exemple #30
0
def from_mol_to_ani_input(mol: Chem.Mol) -> dict:
    """
    Generates atom_list and coord_list entries from rdkit mol.
    Parameters
    ----------
    mol : rdkit.Chem.Mol

    Returns
    -------
    { 'ligand_atoms' : atoms, 'ligand_coords' : coord_list} 
    """

    atom_list = []
    coord_list = []
    for a in mol.GetAtoms():
        atom_list.append(a.GetSymbol())
        pos = mol.GetConformer().GetAtomPosition(a.GetIdx())
        coord_list.append([pos.x, pos.y, pos.z])

    _ = write_pdb(mol, 'tmp.pdb')
    topology = md.load('tmp.pdb').topology
    os.remove('tmp.pdb')

    return {
        'ligand_atoms': ''.join(atom_list),
        'ligand_coords': np.array(coord_list) * unit.angstrom,
        'ligand_topology': topology,
    }