Ejemplo n.º 1
0
FragCatalogEntry::FragCatalogEntry(const ROMol *omol, const PATH_TYPE &path,
                                   const MatchVectType &aidToFid) {
  PRECONDITION(omol, "bad mol");
  // start with the assumption that this entry is not participating in
  //  any find of fingerprinting
  d_aToFmap.clear();
  setBitId(-1);
  INT_MAP_INT aIdxMap;  // a map from atom id in omol to the new atoms id in mol
  dp_mol = Subgraphs::pathToSubmol(*omol, path, false,
                                   aIdxMap);  // Using Subgraphs functionality
  d_order = path.size();

  // using aIdxMap initialize the location (and their IDs) of the
  // functional groups on dp_mol
  for (const auto &mvtci : aidToFid) {
    int oldAid = mvtci.first;
    if (aIdxMap.find(oldAid) != aIdxMap.end()) {
      int newAid = aIdxMap[oldAid];
      if (d_aToFmap.find(newAid) != d_aToFmap.end()) {
        d_aToFmap[newAid].push_back(mvtci.second);
      } else {
        INT_VECT tmpVect;
        tmpVect.clear();
        tmpVect.push_back(mvtci.second);
        d_aToFmap[newAid] = tmpVect;
      }
    }
  }
  dp_props = new Dict();

  d_descrip = "";
}
Ejemplo n.º 2
0
//
// Determine bond wedge state
///
Bond::BondDir DetermineBondWedgeState(const Bond *bond,
                                      const INT_MAP_INT &wedgeBonds,
                                      const Conformer *conf) {
    PRECONDITION(bond, "no bond");
    PRECONDITION(bond->getBondType() == Bond::SINGLE,
                 "bad bond order for wedging");
    const ROMol *mol = &(bond->getOwningMol());
    PRECONDITION(mol, "no mol");

    Bond::BondDir res = bond->getBondDir();
    if (!conf) {
        return res;
    }

    int bid = bond->getIdx();
    INT_MAP_INT_CI wbi = wedgeBonds.find(bid);
    if (wbi == wedgeBonds.end()) {
        return res;
    }

    unsigned int waid = wbi->second;

    Atom *atom, *bondAtom;  // = bond->getBeginAtom();
    if (bond->getBeginAtom()->getIdx() == waid) {
        atom = bond->getBeginAtom();
        bondAtom = bond->getEndAtom();
    } else {
        atom = bond->getEndAtom();
        bondAtom = bond->getBeginAtom();
    }

    Atom::ChiralType chiralType = atom->getChiralTag();
    CHECK_INVARIANT(chiralType == Atom::CHI_TETRAHEDRAL_CW ||
                    chiralType == Atom::CHI_TETRAHEDRAL_CCW,
                    "");

    // if we got this far, we really need to think about it:
    INT_LIST neighborBondIndices;
    DOUBLE_LIST neighborBondAngles;
    RDGeom::Point3D centerLoc, tmpPt;
    centerLoc = conf->getAtomPos(atom->getIdx());
    tmpPt = conf->getAtomPos(bondAtom->getIdx());
    centerLoc.z = 0.0;
    tmpPt.z = 0.0;
    RDGeom::Point3D refVect = centerLoc.directionVector(tmpPt);

    neighborBondIndices.push_back(bond->getIdx());
    neighborBondAngles.push_back(0.0);

    ROMol::OEDGE_ITER beg, end;
    boost::tie(beg, end) = mol->getAtomBonds(atom);
    while (beg != end) {
        Bond *nbrBond = (*mol)[*beg].get();
        Atom *otherAtom = nbrBond->getOtherAtom(atom);
        if (nbrBond != bond) {
            tmpPt = conf->getAtomPos(otherAtom->getIdx());
            tmpPt.z = 0.0;
            RDGeom::Point3D tmpVect = centerLoc.directionVector(tmpPt);
            double angle = refVect.signedAngleTo(tmpVect);
            if (angle < 0.0) angle += 2. * M_PI;
            INT_LIST::iterator nbrIt = neighborBondIndices.begin();
            DOUBLE_LIST::iterator angleIt = neighborBondAngles.begin();
            // find the location of this neighbor in our angle-sorted list
            // of neighbors:
            while (angleIt != neighborBondAngles.end() && angle > (*angleIt)) {
                ++angleIt;
                ++nbrIt;
            }
            neighborBondAngles.insert(angleIt, angle);
            neighborBondIndices.insert(nbrIt, nbrBond->getIdx());
        }
        ++beg;
    }

    // at this point, neighborBondIndices contains a list of bond
    // indices from the central atom.  They are arranged starting
    // at the reference bond in CCW order (based on the current
    // depiction).
    int nSwaps = atom->getPerturbationOrder(neighborBondIndices);

    // in the case of three-coordinated atoms we may have to worry about
    // the location of the implicit hydrogen - Issue 209
    // Check if we have one of these situation
    //
    //      0        1 0 2
    //      *         \*/
    //  1 - C - 2      C
    //
    // here the hydrogen will be between 1 and 2 and we need to add an additional
    // swap
    if (neighborBondAngles.size() == 3) {
        // three coordinated
        DOUBLE_LIST::iterator angleIt = neighborBondAngles.begin();
        ++angleIt;  // the first is the 0 (or reference bond - we will ignoire that
        double angle1 = (*angleIt);
        ++angleIt;
        double angle2 = (*angleIt);
        if (angle2 - angle1 >= (M_PI - 1e-4)) {
            // we have the above situation
            nSwaps++;
        }
    }

#ifdef VERBOSE_STEREOCHEM
    BOOST_LOG(rdDebugLog) << "--------- " << nSwaps << std::endl;
    std::copy(neighborBondIndices.begin(), neighborBondIndices.end(),
              std::ostream_iterator<int>(BOOST_LOG(rdDebugLog), " "));
    BOOST_LOG(rdDebugLog) << std::endl;
    std::copy(neighborBondAngles.begin(), neighborBondAngles.end(),
              std::ostream_iterator<double>(BOOST_LOG(rdDebugLog), " "));
    BOOST_LOG(rdDebugLog) << std::endl;
#endif
    if (chiralType == Atom::CHI_TETRAHEDRAL_CCW) {
        if (nSwaps % 2 == 1) {  // ^ reverse) {
            res = Bond::BEGINDASH;
        } else {
            res = Bond::BEGINWEDGE;
        }
    } else {
        if (nSwaps % 2 == 1) {  // ^ reverse) {
            res = Bond::BEGINWEDGE;
        } else {
            res = Bond::BEGINDASH;
        }
    }

    return res;
}
Ejemplo n.º 3
0
INT_MAP_INT pickBondsToWedge(const ROMol &mol) {
    // we need ring information; make sure findSSSR has been called before
    // if not call now
    if (!mol.getRingInfo()->isInitialized()) {
        MolOps::findSSSR(mol);
    }

    static int noNbrs = 100;
    INT_VECT nChiralNbrs(mol.getNumAtoms(), noNbrs);

    // start by looking for bonds that are already wedged
    for (ROMol::ConstBondIterator cbi = mol.beginBonds(); cbi != mol.endBonds();
            ++cbi) {
        const Bond *bond = *cbi;
        if (bond->getBondDir() == Bond::BEGINWEDGE ||
                bond->getBondDir() == Bond::BEGINDASH ||
                bond->getBondDir() == Bond::UNKNOWN) {
            nChiralNbrs[bond->getBeginAtomIdx()] = noNbrs + 1;
            // std::cerr<<"skip: "<<bond->getBeginAtomIdx()<<std::endl;
        }
    }

    // now rank atoms by the number of chiral neighbors or Hs they have:
    bool chiNbrs = false;
    for (ROMol::ConstAtomIterator cai = mol.beginAtoms(); cai != mol.endAtoms();
            ++cai) {
        const Atom *at = *cai;
        if (nChiralNbrs[at->getIdx()] > noNbrs) {
            // std::cerr<<" SKIPPING1: "<<at->getIdx()<<std::endl;
            continue;
        }
        Atom::ChiralType type = at->getChiralTag();
        if (type != Atom::CHI_TETRAHEDRAL_CW && type != Atom::CHI_TETRAHEDRAL_CCW)
            continue;
        nChiralNbrs[at->getIdx()] = 0;
        chiNbrs = true;
        ROMol::ADJ_ITER nbrIdx, endNbrs;
        boost::tie(nbrIdx, endNbrs) = mol.getAtomNeighbors(at);
        while (nbrIdx != endNbrs) {
            const ATOM_SPTR nat = mol[*nbrIdx];
            ++nbrIdx;
            if (nat->getAtomicNum() == 1) {
                // special case: it's an H... we weight these especially high:
                nChiralNbrs[at->getIdx()] -= 10;
                continue;
            }
            type = nat->getChiralTag();
            if (type != Atom::CHI_TETRAHEDRAL_CW && type != Atom::CHI_TETRAHEDRAL_CCW)
                continue;
            nChiralNbrs[at->getIdx()] -= 1;
        }
    }
    std::vector<unsigned int> indices(mol.getNumAtoms());
    for (unsigned int i = 0; i < mol.getNumAtoms(); ++i) indices[i] = i;
    if (chiNbrs) {
        std::sort(indices.begin(), indices.end(),
                  Rankers::argless<INT_VECT>(nChiralNbrs));
    }
#if 0
    std::cerr<<"  nbrs: ";
    std::copy(nChiralNbrs.begin(),nChiralNbrs.end(),std::ostream_iterator<int>(std::cerr," "));
    std::cerr<<std::endl;
    std::cerr<<"  order: ";
    std::copy(indices.begin(),indices.end(),std::ostream_iterator<int>(std::cerr," "));
    std::cerr<<std::endl;
#endif
    // picks a bond for each atom that we will wedge when we write the mol file
    // here is what we are going to do
    // - at each chiral center look for a bond that is begins at the atom and
    //   is not yet picked to be wedged for a different chiral center, preferring
    //   bonds to Hs
    // - if we do not find a bond that begins at the chiral center - we will take
    //   the first bond that is not yet picked by any other chiral centers
    // we use the orders calculated above to determine which order to do the
    // wedging
    INT_MAP_INT res;
    BOOST_FOREACH (unsigned int idx, indices) {
        if (nChiralNbrs[idx] > noNbrs) {
            // std::cerr<<" SKIPPING2: "<<idx<<std::endl;
            continue;  // already have a wedged bond here
        }
        const Atom *atom = mol.getAtomWithIdx(idx);
        Atom::ChiralType type = atom->getChiralTag();
        // the indices are ordered such that all chiral atoms come first. If
        // this has no chiral flag, we can stop the whole loop:
        if (type != Atom::CHI_TETRAHEDRAL_CW && type != Atom::CHI_TETRAHEDRAL_CCW)
            break;
        RDKit::ROMol::OBOND_ITER_PAIR atomBonds = mol.getAtomBonds(atom);
        std::vector<std::pair<int, int> > nbrScores;
        while (atomBonds.first != atomBonds.second) {
            const Bond *bond = mol[*atomBonds.first].get();
            ++atomBonds.first;

            // can only wedge single bonds:
            if (bond->getBondType() != Bond::SINGLE) continue;

            int bid = bond->getIdx();
            if (res.find(bid) == res.end()) {
                // very strong preference for Hs:
                if (bond->getOtherAtom(atom)->getAtomicNum() == 1) {
                    nbrScores.push_back(
                        std::make_pair(-1000, bid));  // lower than anything else can be
                    continue;
                }
                int nbrScore = 0;
                // prefer neighbors that are nonchiral or have as few chiral neighbors
                // as possible:
                int oIdx = bond->getOtherAtomIdx(idx);
                if (nChiralNbrs[oIdx] < noNbrs) {
                    // the counts are negative, so we have to subtract them off
                    nbrScore -= 10 * nChiralNbrs[oIdx];
                }
                // prefer non-ring bonds;
                nbrScore += mol.getRingInfo()->numBondRings(bid);
                nbrScores.push_back(std::make_pair(nbrScore, bid));
            }
        }
        // There's still one situation where this whole thing can fail: an unlucky
        // situation where all neighbors of all neighbors of an atom are chiral and
        // that atom ends up being the last one picked for stereochem assignment.
        //
        // We'll catch that as an error here and hope that it's as unlikely to occur
        // as it seems like it is. (I'm going into this knowing that it's bound to
        // happen; I'll kick myself and do the hard solution at that point.)
        CHECK_INVARIANT(nbrScores.size(),
                        "no eligible neighbors for chiral center");
        std::sort(nbrScores.begin(), nbrScores.end(),
                  Rankers::pairLess<int, int>());
        res[nbrScores[0].second] = idx;
    }
    return res;
}