void setBondDirRelativeToAtom(Bond *bond, Atom *atom, Bond::BondDir dir, bool reverse, boost::dynamic_bitset<> &needsDir) { PRECONDITION(bond, "bad bond"); PRECONDITION(atom, "bad atom"); PRECONDITION(dir == Bond::ENDUPRIGHT || dir == Bond::ENDDOWNRIGHT, "bad dir"); PRECONDITION(atom == bond->getBeginAtom() || atom == bond->getEndAtom(), "atom doesn't belong to bond"); // std::cerr<<"\t\t>sbdra : bond "<<bond->getIdx()<<" atom // "<<atom->getIdx()<<" dir: " << dir << " reverse: "<<reverse<<std::endl; Atom *oAtom; if (bond->getBeginAtom() != atom) { reverse = !reverse; oAtom = bond->getBeginAtom(); } else { oAtom = bond->getEndAtom(); } if (reverse) { dir = (dir == Bond::ENDUPRIGHT ? Bond::ENDDOWNRIGHT : Bond::ENDUPRIGHT); } // to ensure maximum compatibility, even when a bond has unknown stereo (set // explicitly and recorded in _UnknownStereo property), I will still let a // direction to be computed. You must check the _UnknownStereo property to // make sure whether this bond is explictly set to have no direction info. // This makes sense because the direction info are all derived from // coordinates, the _UnknownStereo property is like extra metadata to be // used with the direction info. bond->setBondDir(dir); // std::cerr<<"\t\t\t\t -> dir "<<dir<<std::endl; // check for other single bonds around the other atom who need their // direction set and set it as demanded by the direction of this one: ROMol::OEDGE_ITER beg, end; boost::tie(beg, end) = oAtom->getOwningMol().getAtomBonds(oAtom); while (beg != end) { Bond *nbrBond = oAtom->getOwningMol()[*beg].get(); if (nbrBond != bond && needsDir[nbrBond->getIdx()]) { Bond::BondDir nbrDir = Bond::NONE; if ((nbrBond->getBeginAtom() == oAtom && bond->getBeginAtom() == oAtom) || (nbrBond->getEndAtom() == oAtom && bond->getEndAtom() == oAtom)) { // both bonds either start or end here; they *must* have different // directions: nbrDir = (dir == Bond::ENDUPRIGHT ? Bond::ENDDOWNRIGHT : Bond::ENDUPRIGHT); } else { // one starts here, the other ends here, they need to have the same // direction: nbrDir = dir; } nbrBond->setBondDir(nbrDir); needsDir[nbrBond->getIdx()] = 0; // std::cerr<<"\t\t\t\t update bond "<<nbrBond->getIdx()<<" to dir "<< // nbrDir<<std::endl; } ++beg; } }
void StandardPDBResidueBondOrders(RWMol *mol) { RWMol::BondIterator bondIt; for (bondIt=mol->beginBonds(); bondIt!=mol->endBonds(); ++bondIt) { Bond *bond = *bondIt; if (bond->getBondType() == Bond::SINGLE) { Atom *beg = bond->getBeginAtom(); Atom *end = bond->getEndAtom(); if (StandardPDBDoubleBond(mol,beg,end)) bond->setBondType(Bond::DOUBLE); } } }
RWMOL_SPTR convertTemplateToMol(const ROMOL_SPTR prodTemplateSptr) { const ROMol *prodTemplate = prodTemplateSptr.get(); auto *res = new RWMol(); // --------- --------- --------- --------- --------- --------- // Initialize by making a copy of the product template as a normal molecule. // NOTE that we can't just use a normal copy because we do not want to end up // with query atoms or bonds in the product. // copy in the atoms: ROMol::ATOM_ITER_PAIR atItP = prodTemplate->getVertices(); while (atItP.first != atItP.second) { const Atom *oAtom = (*prodTemplate)[*(atItP.first++)]; auto *newAtom = new Atom(*oAtom); res->addAtom(newAtom, false, true); int mapNum; if (newAtom->getPropIfPresent(common_properties::molAtomMapNumber, mapNum)) { // set bookmarks for the mapped atoms: res->setAtomBookmark(newAtom, mapNum); // now clear the molAtomMapNumber property so that it doesn't // end up in the products (this was bug 3140490): newAtom->clearProp(common_properties::molAtomMapNumber); newAtom->setProp<int>(common_properties::reactionMapNum, mapNum); } newAtom->setChiralTag(Atom::CHI_UNSPECIFIED); // if the product-template atom has the inversion flag set // to 4 (=SET), then bring its stereochem over, otherwise we'll // ignore it: int iFlag; if (oAtom->getPropIfPresent(common_properties::molInversionFlag, iFlag)) { if (iFlag == 4) newAtom->setChiralTag(oAtom->getChiralTag()); } // check for properties we need to set: int val; if (newAtom->getPropIfPresent(common_properties::_QueryFormalCharge, val)) { newAtom->setFormalCharge(val); } if (newAtom->getPropIfPresent(common_properties::_QueryHCount, val)) { newAtom->setNumExplicitHs(val); newAtom->setNoImplicit(true); // this was github #1544 } if (newAtom->getPropIfPresent(common_properties::_QueryMass, val)) { // FIX: technically should do something with this // newAtom->setMass(val); } if (newAtom->getPropIfPresent(common_properties::_QueryIsotope, val)) { newAtom->setIsotope(val); } } // and the bonds: ROMol::BOND_ITER_PAIR bondItP = prodTemplate->getEdges(); while (bondItP.first != bondItP.second) { const Bond *oldB = (*prodTemplate)[*(bondItP.first++)]; unsigned int bondIdx; bondIdx = res->addBond(oldB->getBeginAtomIdx(), oldB->getEndAtomIdx(), oldB->getBondType()) - 1; // make sure we don't lose the bond dir information: Bond *newB = res->getBondWithIdx(bondIdx); newB->setBondDir(oldB->getBondDir()); // Special case/hack: // The product has been processed by the SMARTS parser. // The SMARTS parser tags unspecified bonds as single, but then adds // a query so that they match single or double // This caused Issue 1748846 // http://sourceforge.net/tracker/index.php?func=detail&aid=1748846&group_id=160139&atid=814650 // We need to fix that little problem now: if (oldB->hasQuery()) { // remember that the product has been processed by the SMARTS parser. std::string queryDescription = oldB->getQuery()->getDescription(); if (queryDescription == "BondOr" && oldB->getBondType() == Bond::SINGLE) { // We need to fix that little problem now: if (newB->getBeginAtom()->getIsAromatic() && newB->getEndAtom()->getIsAromatic()) { newB->setBondType(Bond::AROMATIC); newB->setIsAromatic(true); } else { newB->setBondType(Bond::SINGLE); newB->setIsAromatic(false); } } else if (queryDescription == "BondNull") { newB->setProp(common_properties::NullBond, 1); } } // copy properties over: bool preserveExisting = true; newB->updateProps(*static_cast<const RDProps *>(oldB), preserveExisting); } return RWMOL_SPTR(res); } // end of convertTemplateToMol()