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 }