Пример #1
0
def _molecule_from_rdmol(
    rdmol: Chem.Mol,
    smiles: str,
    matches: Iterable[Sequence[int]],
    split: bool = True,
) -> Generator[Molecule, None, None]:
    """Construct a PLAMS molecule from the passed rdkit mol's ``MolBlock``."""
    for tup in matches:
        try:
            i, *_, j = tup  # type: int, Any, None | int
        except ValueError:
            i = tup[0]
            j = None

        # Split the capping atom (j) from the main molecule
        if j is not None and split:
            if i > j:
                i -= 1
            rdmol_edit = Chem.EditableMol(rdmol)
            rdmol_edit.RemoveAtom(j)
            rdmol_new = rdmol_edit.GetMol()
            anchor = rdmol_new.GetAtoms()[i]
            anchor.SetFormalCharge(anchor.GetFormalCharge() - 1)
        else:
            rdmol_new = rdmol

        # Parse the .mol block and convert it into a PLAMS molecule
        mol_block = Chem.MolToMolBlock(rdmol)
        iterator = _iter_mol_block(mol_block, size=len(rdmol.GetAtoms()))
        mol = Molecule()
        mol.atoms = [Atom(symbol=symbol, coords=xyz, mol=mol) for symbol, xyz in iterator]
        for bond in rdmol.GetBonds():
            at1 = mol.atoms[bond.GetBeginAtomIdx()]
            at2 = mol.atoms[bond.GetEndAtomIdx()]
            mol.add_bond(Bond(at1, at2, order=bond.GetBondTypeAsDouble()))

        # Set properties and yield
        mol.properties.smiles = smiles
        mol.properties.dummies = mol.atoms[i]
        mol.properties.anchor = f"{mol.properties.dummies.symbol}{i + 1}"
        yield mol
Пример #2
0
def from_rdmol(rdkit_mol, confid=-1):
    """
    Translate an RDKit molecule into a PLAMS molecule type.

    :parameter rdkit_mol: RDKit molecule
    :parameter int confid: conformer identifier from which to take coordinates
    :type rdkit_mol: rdkit.Chem.Mol
    :return: a PLAMS molecule
    :rtype: plams.Molecule

    """
    if isinstance(rdkit_mol, Molecule):
        return rdkit_mol
    # Create plams molecule
    plams_mol = Molecule()
    total_charge = 0
    try:
        Chem.Kekulize(rdkit_mol)
    except:
        pass
    conf = rdkit_mol.GetConformer(id=confid)
    for rd_atom in rdkit_mol.GetAtoms():
        pos = conf.GetAtomPosition(rd_atom.GetIdx())
        ch = rd_atom.GetFormalCharge()
        pl_atom = Atom(rd_atom.GetAtomicNum(),
                       coords=(pos.x, pos.y, pos.z),
                       charge=ch)
        if rd_atom.GetPDBResidueInfo():
            pl_atom.properties.pdb_info = get_PDBResidueInfo(rd_atom)
        plams_mol.add_atom(pl_atom)
        total_charge += ch
    for bond in rdkit_mol.GetBonds():
        at1 = plams_mol.atoms[bond.GetBeginAtomIdx()]
        at2 = plams_mol.atoms[bond.GetEndAtomIdx()]
        plams_mol.add_bond(Bond(at1, at2, bond.GetBondTypeAsDouble()))
    plams_mol.charge = total_charge
    for propname in rdkit_mol.GetPropNames():
        plams_mol.properties[propname] = rdkit_mol.GetProp(propname)
    return plams_mol
Пример #3
0
def run_ff_anionic(mol: Molecule, anchor: Atom, s: Settings) -> None:
    r"""Assign neutral parameters to an anionic species (*e.g.* carboxylate).

    Consists of 4 distinct steps:

    * **mol** is capped with a proton: *e.g.*
      :math:`RCO_2^- \rightarrow RCO_2H`.
    * Parameters are guessed for both fragments (using MATCH_) and then recombined into **mol**.
    * The capping proton is removed again.
    * The atomic charge of **anchor** is adjusted such that
      the total moleculair charge becomes zero.

    Performs an inplace update of **mol**.

    .. _MATCH: http://brooks.chem.lsa.umich.edu/index.php?page=match&subdir=articles/resources/software

    Parameters
    ----------
    mol : :class:`Molecule<scm.plams.mol.molecule.Molecule>`
        A cationic molecule.

    anchor : :class:`Atom<scm.plams.mol.atom.Atom>`
        The atom in **mol** with the formal negative charge.

    s : :class:`Settings<scm.plams.core.settings.Settings>`
        The job Settings to-be passed to :class:`MATCHJob<nanoCAT.ff.match_job.MATCHJob>`.

    See Also
    --------
    :func:`run_match_job()<nanoCAT.ff.ff_assignment.run_match_job>`
        Assign atom types and charges to **mol** based on the results of MATCH_.

    :func:`run_ff_cationic()<nanoCAT.ff.ff_cationic.run_ff_cationic>`
        Assign neutral parameters to a cationic species (*e.g.* ammonium).

    """  # noqa
    if anchor not in mol:
        raise MoleculeError("Passed 'anchor' is not part of 'mol'")
    anchor.properties.charge = 0

    # Cap the anion with a proton
    mol_with_h = add_Hs(mol)
    _cap_h = mol_with_h[-1]
    cap_h = Atom(atnum=_cap_h.atnum,
                 coords=_cap_h.coords,
                 mol=mol,
                 settings=mol[1].properties.copy())

    cap_h.properties.pdb_info.IsHeteroAtom = False
    cap_h.properties.pdb_info.Name = 'Hxx'
    mol.add_atom(cap_h)
    mol.add_bond(Bond(anchor, cap_h, mol=mol))

    # Guess parameters and remove the capping proton
    run_match_job(mol, s)
    mol.delete_atom(cap_h)

    # Set the total charge of the system to 0
    anchor.properties.charge_float -= sum(at.properties.charge_float
                                          for at in mol)
    return None