Example #1
0
void addReactantNeighborsToProduct(
    const ROMol &reactant, const Atom &reactantAtom, RWMOL_SPTR product,
    boost::dynamic_bitset<> &visitedAtoms,
    std::vector<const Atom *> &chiralAtomsToCheck,
    ReactantProductAtomMapping *mapping) {
  std::list<const Atom *> atomStack;
  atomStack.push_back(&reactantAtom);

  // std::cerr << "-------------------" << std::endl;
  // std::cerr << "  add reactant neighbors from: " << reactantAtom.getIdx()
  //           << std::endl;
  // #if 1
  //   product->updatePropertyCache(false);
  //   product->debugMol(std::cerr);
  //   std::cerr << "-------------------" << std::endl;
  // #endif

  while (!atomStack.empty()) {
    const Atom *lReactantAtom = atomStack.front();
    // std::cerr << "    front: " << lReactantAtom->getIdx() << std::endl;
    atomStack.pop_front();

    // each atom in the stack is guaranteed to already be in the product:
    CHECK_INVARIANT(mapping->reactProdAtomMap.find(lReactantAtom->getIdx()) !=
                        mapping->reactProdAtomMap.end(),
                    "reactant atom on traversal stack not present in product.");

    std::vector<unsigned> lReactantAtomProductIndex =
        mapping->reactProdAtomMap[lReactantAtom->getIdx()];
    unsigned lreactIdx = lReactantAtom->getIdx();
    visitedAtoms[lreactIdx] = 1;
    // Check our neighbors:
    ROMol::ADJ_ITER nbrIdx, endNbrs;
    boost::tie(nbrIdx, endNbrs) = reactant.getAtomNeighbors(lReactantAtom);
    while (nbrIdx != endNbrs) {
      // Four possibilities here. The neighbor:
      //  0) has been visited already: do nothing
      //  1) is part of the match (thus already in the product): set a bond to
      //  it
      //  2) has been added: set a bond to it
      //  3) has not yet been added: add it, set a bond to it, and push it
      //     onto the stack
      // std::cerr << "       nbr: " << *nbrIdx << std::endl;
      // std::cerr << "              visited: " << visitedAtoms[*nbrIdx]
      //           << "  skipped: " << mapping->skippedAtoms[*nbrIdx]
      //           << " mapped: " << mapping->mappedAtoms[*nbrIdx]
      //           << " mappedO: " << mapping->mappedAtoms[lreactIdx] <<
      //           std::endl;
      if (!visitedAtoms[*nbrIdx] && !mapping->skippedAtoms[*nbrIdx]) {
        if (mapping->mappedAtoms[*nbrIdx]) {
          // this is case 1 (neighbor in match); set a bond to the neighbor if
          // this atom
          // is not also in the match (match-match bonds were set when the
          // product template was
          // copied in to start things off).;
          if (!mapping->mappedAtoms[lreactIdx]) {
            CHECK_INVARIANT(mapping->reactProdAtomMap.find(*nbrIdx) !=
                                mapping->reactProdAtomMap.end(),
                            "reactant atom not present in product.");
            const Bond *origB =
                reactant.getBondBetweenAtoms(lreactIdx, *nbrIdx);
            addMissingProductBonds(*origB, product, mapping);
          } else {
            // both mapped atoms are in the match.
            // they are bonded in the reactant (otherwise we wouldn't be here),
            //
            // If they do not have already have a bond in the product and did
            // not have one in the reactant template then set one here
            // If they do have a bond in the reactant template, then we
            // assume that this is an intentional bond break, so we don't do
            // anything
            //
            // this was github #1387
            unsigned prodBeginIdx = mapping->reactProdAtomMap[lreactIdx][0];
            unsigned prodEndIdx = mapping->reactProdAtomMap[*nbrIdx][0];
            if (!product->getBondBetweenAtoms(prodBeginIdx, prodEndIdx)) {
              // They must be mapped
              CHECK_INVARIANT(
                  product->getAtomWithIdx(prodBeginIdx)
                          ->hasProp(common_properties::reactionMapNum) &&
                      product->getAtomWithIdx(prodEndIdx)
                          ->hasProp(common_properties::reactionMapNum),
                  "atoms should be mapped in product");
              int a1mapidx =
                  product->getAtomWithIdx(prodBeginIdx)
                      ->getProp<int>(common_properties::reactionMapNum);
              int a2mapidx =
                  product->getAtomWithIdx(prodEndIdx)
                      ->getProp<int>(common_properties::reactionMapNum);
              if (a1mapidx > a2mapidx) std::swap(a1mapidx, a2mapidx);
              if (mapping->reactantTemplateAtomBonds.find(
                      std::make_pair(a1mapidx, a2mapidx)) ==
                  mapping->reactantTemplateAtomBonds.end()) {
                const Bond *origB =
                    reactant.getBondBetweenAtoms(lreactIdx, *nbrIdx);
                addMissingProductBonds(*origB, product, mapping);
              }
            }
          }
        } else if (mapping->reactProdAtomMap.find(*nbrIdx) !=
                   mapping->reactProdAtomMap.end()) {
          // case 2, the neighbor has been added and we just need to set a bond
          // to it:
          const Bond *origB = reactant.getBondBetweenAtoms(lreactIdx, *nbrIdx);
          addMissingProductBonds(*origB, product, mapping);
        } else {
          // case 3, add the atom, a bond to it, and push the atom onto the
          // stack
          const Atom *neighbor = reactant.getAtomWithIdx(*nbrIdx);
          for (unsigned int i : lReactantAtomProductIndex) {
            addMissingProductAtom(*neighbor, lreactIdx, i, product, reactant,
                                  mapping);
          }
          // update the stack:
          atomStack.push_back(neighbor);
          // if the atom is chiral, we need to check its bond ordering later:
          if (neighbor->getChiralTag() != Atom::CHI_UNSPECIFIED) {
            chiralAtomsToCheck.push_back(neighbor);
          }
        }
      }
      nbrIdx++;
    }
  }  // end of atomStack traversal
}
void addReactantNeighborsToProduct(const ROMol& reactant, const Atom& reactantAtom,
                                   RWMOL_SPTR product, boost::dynamic_bitset<>& visitedAtoms,
                                   std::vector<const Atom*>& chiralAtomsToCheck,
                                   ReactantProductAtomMapping* mapping)
{
    std::list<const Atom*> atomStack;
    atomStack.push_back(&reactantAtom);
    while(!atomStack.empty()) {
        const Atom *lReactantAtom = atomStack.front();
        atomStack.pop_front();

        // each atom in the stack is guaranteed to already be in the product:
        CHECK_INVARIANT(mapping->reactProdAtomMap.find(lReactantAtom->getIdx()) !=
                        mapping->reactProdAtomMap.end(),
                        "reactant atom on traversal stack not present in product.");

        std::vector<unsigned> lReactantAtomProductIndex =
            mapping->reactProdAtomMap[lReactantAtom->getIdx()];
        unsigned lreactIdx = lReactantAtom->getIdx();
        visitedAtoms[lreactIdx] = 1;
        // Check our neighbors:
        ROMol::ADJ_ITER nbrIdx,endNbrs;
        boost::tie(nbrIdx,endNbrs) = reactant.getAtomNeighbors(lReactantAtom);
        while(nbrIdx!=endNbrs) {
            // Four possibilities here. The neighbor:
            //  0) has been visited already: do nothing
            //  1) is part of the match (thus already in the product): set a bond to it
            //  2) has been added: set a bond to it
            //  3) has not yet been added: add it, set a bond to it, and push it
            //     onto the stack
            if(!visitedAtoms[*nbrIdx] && !mapping->skippedAtoms[*nbrIdx]) {
                if(mapping->mappedAtoms[*nbrIdx]) {
                    // this is case 1 (neighbor in match); set a bond to the neighbor if this atom
                    // is not also in the match (match-match bonds were set when the product template was
                    // copied in to start things off).;
                    if(!mapping->mappedAtoms[lreactIdx]) {
                        CHECK_INVARIANT(mapping->reactProdAtomMap.find(*nbrIdx)!=mapping->reactProdAtomMap.end(),
                                        "reactant atom not present in product.");
                        const Bond *origB=reactant.getBondBetweenAtoms(lreactIdx,*nbrIdx);
                        addMissingProductBonds(*origB, product,mapping);
                    }
                }
                else if(mapping->reactProdAtomMap.find(*nbrIdx)!= mapping->reactProdAtomMap.end()) {
                    // case 2, the neighbor has been added and we just need to set a bond to it:
                    const Bond *origB=reactant.getBondBetweenAtoms(lreactIdx,*nbrIdx);
                    addMissingProductBonds(*origB, product,mapping);
                }
                else {
                    // case 3, add the atom, a bond to it, and push the atom onto the stack
                    const Atom *neighbor=reactant.getAtomWithIdx(*nbrIdx);
                    for(unsigned i = 0; i < lReactantAtomProductIndex.size(); i++) {
                        addMissingProductAtom(*neighbor, lreactIdx,lReactantAtomProductIndex[i],
                                              product, reactant, mapping);
                    }
                    // update the stack:
                    atomStack.push_back(neighbor);
                    // if the atom is chiral, we need to check its bond ordering later:
                    if(neighbor->getChiralTag()!=Atom::CHI_UNSPECIFIED) {
                        chiralAtomsToCheck.push_back(neighbor);
                    }
                }
            }
            nbrIdx++;
        }
    } // end of atomStack traversal
}