// // Copyright (C) 2003-2017 Greg Landrum and Rational Discovery LLC // // @@ All Rights Reserved @@ // This file is part of the RDKit. // The contents are covered by the terms of the BSD license // which is included in the file license.txt, found at the root // of the RDKit source tree. // //! \file QueryOps.h /*! \brief Includes a bunch of functionality for handling Atom and Bond queries. */ #include #ifndef _RD_QUERY_OPS_H #define _RD_QUERY_OPS_H #include #include #include #include #include #ifdef RDK_THREADSAFE_SSS #include #endif namespace RDKit { typedef Queries::Query ATOM_BOOL_QUERY; typedef Queries::Query BOND_BOOL_QUERY; typedef Queries::AndQuery ATOM_AND_QUERY; typedef Queries::AndQuery BOND_AND_QUERY; typedef Queries::OrQuery ATOM_OR_QUERY; typedef Queries::OrQuery BOND_OR_QUERY; typedef Queries::XOrQuery ATOM_XOR_QUERY; typedef Queries::XOrQuery BOND_XOR_QUERY; typedef Queries::EqualityQuery ATOM_EQUALS_QUERY; typedef Queries::EqualityQuery BOND_EQUALS_QUERY; typedef Queries::GreaterQuery ATOM_GREATER_QUERY; typedef Queries::GreaterQuery BOND_GREATER_QUERY; typedef Queries::GreaterEqualQuery ATOM_GREATEREQUAL_QUERY; typedef Queries::GreaterEqualQuery BOND_GREATEREQUAL_QUERY; typedef Queries::LessQuery ATOM_LESS_QUERY; typedef Queries::LessQuery BOND_LESS_QUERY; typedef Queries::LessEqualQuery ATOM_LESSEQUAL_QUERY; typedef Queries::LessEqualQuery BOND_LESSEQUAL_QUERY; typedef Queries::RangeQuery ATOM_RANGE_QUERY; typedef Queries::RangeQuery BOND_RANGE_QUERY; typedef Queries::SetQuery ATOM_SET_QUERY; typedef Queries::SetQuery BOND_SET_QUERY; typedef Queries::Query BOND_NULL_QUERY; typedef Queries::Query ATOM_NULL_QUERY; // ------------------------------------------------- // common atom queries static inline int queryAtomAromatic(Atom const *at) { return at->getIsAromatic(); }; static inline int queryAtomAliphatic(Atom const *at) { return !(at->getIsAromatic()); }; static inline int queryAtomExplicitDegree(Atom const *at) { return at->getDegree(); }; static inline int queryAtomTotalDegree(Atom const *at) { return at->getTotalDegree(); }; static inline int queryAtomNonHydrogenDegree(Atom const *at) { return at->getTotalDegree() - at->getTotalNumHs(true); } static inline int queryAtomHeavyAtomDegree(Atom const *at) { int heavyDegree = 0; ROMol::ADJ_ITER nbrIdx, endNbrs; boost::tie(nbrIdx, endNbrs) = at->getOwningMol().getAtomNeighbors(at); while (nbrIdx != endNbrs) { const Atom *nbr = at->getOwningMol()[*nbrIdx]; if (nbr->getAtomicNum() > 1) { heavyDegree++; } ++nbrIdx; } return heavyDegree; }; static inline int queryAtomHCount(Atom const *at) { return at->getTotalNumHs(true); }; static inline int queryAtomImplicitHCount(Atom const *at) { return at->getTotalNumHs(false); }; static inline int queryAtomHasImplicitH(Atom const *at) { return int(at->getTotalNumHs(false) > 0); }; static inline int queryAtomImplicitValence(Atom const *at) { return at->getImplicitValence(); }; static inline int queryAtomExplicitValence(Atom const *at) { return at->getExplicitValence() - at->getNumExplicitHs(); }; static inline int queryAtomTotalValence(Atom const *at) { return at->getExplicitValence() + at->getImplicitValence(); }; static inline int queryAtomUnsaturated(Atom const *at) { return static_cast(at->getDegree()) < at->getExplicitValence(); }; static inline int queryAtomNum(Atom const *at) { return at->getAtomicNum(); }; static inline int makeAtomType(int atomic_num, bool aromatic) { return atomic_num + 1000 * static_cast(aromatic); } static inline void parseAtomType(int val, int &atomic_num, bool &aromatic) { if (val > 1000) { aromatic = true; atomic_num = val - 1000; } else { aromatic = false; atomic_num = val; } } static inline bool getAtomTypeIsAromatic(int val) { if (val > 1000) return true; return false; } static inline int getAtomTypeAtomicNum(int val) { if (val > 1000) return val - 1000; return val; } static inline int queryAtomType(Atom const *at) { return makeAtomType(at->getAtomicNum(), at->getIsAromatic()); }; const int massIntegerConversionFactor = 1000; static inline int queryAtomMass(Atom const *at) { return static_cast(round(massIntegerConversionFactor * at->getMass())); }; static inline int queryAtomIsotope(Atom const *at) { return static_cast(at->getIsotope()); }; static inline int queryAtomFormalCharge(Atom const *at) { return static_cast(at->getFormalCharge()); }; static inline int queryAtomHybridization(Atom const *at) { return at->getHybridization(); }; static inline int queryAtomNumRadicalElectrons(Atom const *at) { return at->getNumRadicalElectrons(); }; static inline int queryAtomHasChiralTag(Atom const *at) { return at->getChiralTag() != Atom::CHI_UNSPECIFIED; }; static inline int queryAtomMissingChiralTag(Atom const *at) { return at->getChiralTag() == Atom::CHI_UNSPECIFIED && at->hasProp(common_properties::_ChiralityPossible); }; static inline int queryAtomHasHeteroatomNbrs(Atom const *at) { ROMol::ADJ_ITER nbrIdx, endNbrs; boost::tie(nbrIdx, endNbrs) = at->getOwningMol().getAtomNeighbors(at); while (nbrIdx != endNbrs) { const Atom *nbr = at->getOwningMol()[*nbrIdx]; if (nbr->getAtomicNum() != 6 && nbr->getAtomicNum() != 1) { return 1; } ++nbrIdx; } return 0; }; static inline int queryAtomNumHeteroatomNbrs(Atom const *at) { int res = 0; ROMol::ADJ_ITER nbrIdx, endNbrs; boost::tie(nbrIdx, endNbrs) = at->getOwningMol().getAtomNeighbors(at); while (nbrIdx != endNbrs) { const Atom *nbr = at->getOwningMol()[*nbrIdx]; if (nbr->getAtomicNum() != 6 && nbr->getAtomicNum() != 1) { ++res; } ++nbrIdx; } return res; }; static inline int queryAtomHasAliphaticHeteroatomNbrs(Atom const *at) { ROMol::ADJ_ITER nbrIdx, endNbrs; boost::tie(nbrIdx, endNbrs) = at->getOwningMol().getAtomNeighbors(at); while (nbrIdx != endNbrs) { const Atom *nbr = at->getOwningMol()[*nbrIdx]; if ((!nbr->getIsAromatic()) && nbr->getAtomicNum() != 6 && nbr->getAtomicNum() != 1) { return 1; } ++nbrIdx; } return 0; }; static inline int queryAtomNumAliphaticHeteroatomNbrs(Atom const *at) { int res = 0; ROMol::ADJ_ITER nbrIdx, endNbrs; boost::tie(nbrIdx, endNbrs) = at->getOwningMol().getAtomNeighbors(at); while (nbrIdx != endNbrs) { const Atom *nbr = at->getOwningMol()[*nbrIdx]; if ((!nbr->getIsAromatic()) && nbr->getAtomicNum() != 6 && nbr->getAtomicNum() != 1) { ++res; } ++nbrIdx; } return res; }; RDKIT_GRAPHMOL_EXPORT unsigned int queryAtomBondProduct(Atom const *at); RDKIT_GRAPHMOL_EXPORT unsigned int queryAtomAllBondProduct(Atom const *at); // ------------------------------------------------- // common bond queries static inline int queryBondOrder(Bond const *bond) { return static_cast(bond->getBondType()); }; static inline int queryBondIsSingleOrAromatic(Bond const *bond) { return static_cast(bond->getBondType() == Bond::SINGLE || bond->getBondType() == Bond::AROMATIC); }; static inline int queryBondDir(Bond const *bond) { return static_cast(bond->getBondDir()); }; static inline int queryIsBondInNRings(Bond const *at) { return at->getOwningMol().getRingInfo()->numBondRings(at->getIdx()); }; static inline int queryBondHasStereo(Bond const *bnd) { return bnd->getStereo() > Bond::STEREONONE; }; // ------------------------------------------------- // ring queries static inline int queryIsAtomInNRings(Atom const *at) { return at->getOwningMol().getRingInfo()->numAtomRings(at->getIdx()); }; static inline int queryIsAtomInRing(Atom const *at) { return at->getOwningMol().getRingInfo()->numAtomRings(at->getIdx()) != 0; }; static inline int queryAtomHasRingBond(Atom const *at) { ROMol::OBOND_ITER_PAIR atomBonds = at->getOwningMol().getAtomBonds(at); while (atomBonds.first != atomBonds.second) { unsigned int bondIdx = at->getOwningMol().getTopology()[*atomBonds.first]->getIdx(); if (at->getOwningMol().getRingInfo()->numBondRings(bondIdx)) { return 1; } ++atomBonds.first; } return 0; }; static inline int queryIsBondInRing(Bond const *bond) { return bond->getOwningMol().getRingInfo()->numBondRings(bond->getIdx()) != 0; }; static inline int queryAtomMinRingSize(Atom const *at) { return at->getOwningMol().getRingInfo()->minAtomRingSize(at->getIdx()); }; static inline int queryBondMinRingSize(Bond const *bond) { return bond->getOwningMol().getRingInfo()->minBondRingSize(bond->getIdx()); }; static inline int queryAtomRingBondCount(Atom const *at) { // EFF: cache this result int res = 0; ROMol::OBOND_ITER_PAIR atomBonds = at->getOwningMol().getAtomBonds(at); while (atomBonds.first != atomBonds.second) { unsigned int bondIdx = at->getOwningMol().getTopology()[*atomBonds.first]->getIdx(); if (at->getOwningMol().getRingInfo()->numBondRings(bondIdx)) { res++; } ++atomBonds.first; } return res; } template int queryAtomIsInRingOfSize(Atom const *at) { if (at->getOwningMol().getRingInfo()->isAtomInRingOfSize(at->getIdx(), tgt)) { return tgt; } else { return 0; } }; template int queryBondIsInRingOfSize(Bond const *bond) { if (bond->getOwningMol().getRingInfo()->isBondInRingOfSize(bond->getIdx(), tgt)) { return tgt; } else { return 0; } }; template T *makeAtomSimpleQuery(int what, int func(Atom const *), const std::string &description = "Atom Simple") { T *res = new T; res->setVal(what); res->setDataFunc(func); res->setDescription(description); return res; } static inline ATOM_RANGE_QUERY *makeAtomRangeQuery( int lower, int upper, bool lowerOpen, bool upperOpen, int func(Atom const *), const std::string &description = "Atom Range") { ATOM_RANGE_QUERY *res = new ATOM_RANGE_QUERY(lower, upper); res->setDataFunc(func); res->setDescription(description); res->setEndsOpen(lowerOpen, upperOpen); return res; } //! returns a Query for matching atomic number template T *makeAtomNumQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(what, queryAtomNum, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomNumQuery(int what); //! returns a Query for matching atomic number and aromaticity template T *makeAtomTypeQuery(int num, int aromatic, const std::string &descr) { return makeAtomSimpleQuery(makeAtomType(num, aromatic), queryAtomType, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomTypeQuery(int num, int aromatic); //! returns a Query for matching implicit valence template T *makeAtomImplicitValenceQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(what, queryAtomImplicitValence, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomImplicitValenceQuery(int what); //! returns a Query for matching explicit valence template T *makeAtomExplicitValenceQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(what, queryAtomExplicitValence, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomExplicitValenceQuery(int what); //! returns a Query for matching total valence template T *makeAtomTotalValenceQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(what, queryAtomTotalValence, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomTotalValenceQuery(int what); //! returns a Query for matching explicit degree template T *makeAtomExplicitDegreeQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(what, queryAtomExplicitDegree, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomExplicitDegreeQuery(int what); //! returns a Query for matching atomic degree template T *makeAtomTotalDegreeQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(what, queryAtomTotalDegree, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomTotalDegreeQuery(int what); //! returns a Query for matching heavy atom degree template T *makeAtomHeavyAtomDegreeQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(what, queryAtomHeavyAtomDegree, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHeavyAtomDegreeQuery(int what); //! returns a Query for matching hydrogen count template T *makeAtomHCountQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(what, queryAtomHCount, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHCountQuery(int what); //! returns a Query for matching ring atoms template T *makeAtomHasImplicitHQuery(const std::string &descr) { return makeAtomSimpleQuery(true, queryAtomHasImplicitH, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHasImplicitHQuery(); //! returns a Query for matching implicit hydrogen count template T *makeAtomImplicitHCountQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(what, queryAtomImplicitHCount, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomImplicitHCountQuery(int what); //! returns a Query for matching the \c isAromatic flag template T *makeAtomAromaticQuery(const std::string &descr) { return makeAtomSimpleQuery(true, queryAtomAromatic, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomAromaticQuery(); //! returns a Query for matching aliphatic atoms template T *makeAtomAliphaticQuery(const std::string &descr) { return makeAtomSimpleQuery(true, queryAtomAliphatic, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomAliphaticQuery(); //! returns a Query for matching atoms with a particular mass template T *makeAtomMassQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(massIntegerConversionFactor * what, queryAtomMass, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomMassQuery(int what); //! returns a Query for matching atoms with a particular isotope template T *makeAtomIsotopeQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(what, queryAtomIsotope, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomIsotopeQuery(int what); //! returns a Query for matching formal charge template T *makeAtomFormalChargeQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(what, queryAtomFormalCharge, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomFormalChargeQuery(int what); //! returns a Query for matching hybridization template T *makeAtomHybridizationQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(what, queryAtomHybridization, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHybridizationQuery(int what); //! returns a Query for matching the number of radical electrons template T *makeAtomNumRadicalElectronsQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(what, queryAtomNumRadicalElectrons, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomNumRadicalElectronsQuery( int what); //! returns a Query for matching whether or not chirality has been set on the //! atom template T *makeAtomHasChiralTagQuery(const std::string &descr) { return makeAtomSimpleQuery(true, queryAtomHasChiralTag, descr); } //! \overloadquery RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHasChiralTagQuery(); //! returns a Query for matching whether or not a potentially chiral atom is //! missing a chiral tag template T *makeAtomMissingChiralTagQuery(const std::string &descr) { return makeAtomSimpleQuery(true, queryAtomMissingChiralTag, descr); } //! \overloadquery RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomMissingChiralTagQuery(); //! returns a Query for matching atoms with unsaturation: template T *makeAtomUnsaturatedQuery(const std::string &descr) { return makeAtomSimpleQuery(true, queryAtomUnsaturated, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomUnsaturatedQuery(); //! returns a Query for matching ring atoms template T *makeAtomInRingQuery(const std::string &descr) { return makeAtomSimpleQuery(true, queryIsAtomInRing, descr); } RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomInRingQuery(); //! \overload //! returns a Query for matching atoms in a particular number of rings template T *makeAtomInNRingsQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(what, queryIsAtomInNRings, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomInNRingsQuery(int what); //! returns a Query for matching atoms in rings of a particular size RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomInRingOfSizeQuery(int tgt); //! returns a Query for matching an atom's minimum ring size template T *makeAtomMinRingSizeQuery(int tgt, const std::string &descr) { return makeAtomSimpleQuery(tgt, queryAtomMinRingSize, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomMinRingSizeQuery(int tgt); //! returns a Query for matching atoms with a particular number of ring bonds template T *makeAtomRingBondCountQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(what, queryAtomRingBondCount, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomRingBondCountQuery(int what); //! returns a Query for matching generic A atoms (heavy atoms) RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAAtomQuery(); //! returns a Query for matching generic AH atoms (any atom) RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAHAtomQuery(); //! returns a Query for matching generic Q atoms (heteroatoms) RDKIT_GRAPHMOL_EXPORT ATOM_OR_QUERY *makeQAtomQuery(); //! returns a Query for matching generic QH atoms (heteroatom or H) RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeQHAtomQuery(); //! returns a Query for matching generic X atoms (halogens) RDKIT_GRAPHMOL_EXPORT ATOM_OR_QUERY *makeXAtomQuery(); //! returns a Query for matching generic XH atoms (halogen or H) RDKIT_GRAPHMOL_EXPORT ATOM_OR_QUERY *makeXHAtomQuery(); //! returns a Query for matching generic M atoms (metals) RDKIT_GRAPHMOL_EXPORT ATOM_OR_QUERY *makeMAtomQuery(); //! returns a Query for matching generic MH atoms (metals or H) RDKIT_GRAPHMOL_EXPORT ATOM_OR_QUERY *makeMHAtomQuery(); //! returns a Query for matching atoms that have ring bonds template T *makeAtomHasRingBondQuery(const std::string &descr) { return makeAtomSimpleQuery(1, queryAtomHasRingBond, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHasRingBondQuery(); //! returns a Query for matching the number of heteroatom neighbors template T *makeAtomNumHeteroatomNbrsQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(what, queryAtomNumHeteroatomNbrs, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomNumHeteroatomNbrsQuery( int what); //! returns a Query for matching atoms that have heteroatom neighbors template T *makeAtomHasHeteroatomNbrsQuery(const std::string &descr) { return makeAtomSimpleQuery(1, queryAtomHasHeteroatomNbrs, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHasHeteroatomNbrsQuery(); //! returns a Query for matching the number of aliphatic heteroatom neighbors template T *makeAtomNumAliphaticHeteroatomNbrsQuery(int what, const std::string &descr) { return makeAtomSimpleQuery(what, queryAtomNumAliphaticHeteroatomNbrs, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY * makeAtomNumAliphaticHeteroatomNbrsQuery(int what); //! returns a Query for matching atoms that have heteroatom neighbors template T *makeAtomHasAliphaticHeteroatomNbrsQuery(const std::string &descr) { return makeAtomSimpleQuery(1, queryAtomHasAliphaticHeteroatomNbrs, descr); } //! \overload RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY * makeAtomHasAliphaticHeteroatomNbrsQuery(); //! returns a Query for matching bond orders RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondOrderEqualsQuery( Bond::BondType what); //! returns a Query for unspecified SMARTS bonds RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeSingleOrAromaticBondQuery(); //! returns a Query for matching bond directions RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondDirEqualsQuery( Bond::BondDir what); //! returns a Query for matching bonds with stereo set RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondHasStereoQuery(); //! returns a Query for matching ring bonds RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondIsInRingQuery(); //! returns a Query for matching bonds in rings of a particular size RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondInRingOfSizeQuery(int what); //! returns a Query for matching a bond's minimum ring size RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondMinRingSizeQuery(int what); //! returns a Query for matching bonds in a particular number of rings RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondInNRingsQuery(int tgt); //! returns a Query for matching any bond RDKIT_GRAPHMOL_EXPORT BOND_NULL_QUERY *makeBondNullQuery(); //! returns a Query for matching any atom RDKIT_GRAPHMOL_EXPORT ATOM_NULL_QUERY *makeAtomNullQuery(); static inline int queryAtomRingMembership(Atom const *at) { return static_cast( at->getOwningMol().getRingInfo()->numAtomRings(at->getIdx())); } // I'm pretty sure that this typedef shouldn't be necessary, // but VC++ generates a warning about const Atom const * in // the definition of Match, then complains about an override // that differs only by const/volatile (c4301), then generates // incorrect code if we don't do this... so let's do it. typedef Atom const *ConstAtomPtr; class RDKIT_GRAPHMOL_EXPORT AtomRingQuery : public Queries::EqualityQuery { public: AtomRingQuery() : Queries::EqualityQuery(-1) { // default is to just do a number of rings query: this->setDescription("AtomInNRings"); this->setDataFunc(queryAtomRingMembership); }; explicit AtomRingQuery(int v) : Queries::EqualityQuery(v) { // default is to just do a number of rings query: this->setDescription("AtomInNRings"); this->setDataFunc(queryAtomRingMembership); }; virtual bool Match(const ConstAtomPtr what) const { int v = this->TypeConvert(what, Queries::Int2Type()); bool res; if (this->d_val < 0) { res = v != 0; } else { res = !Queries::queryCmp(v, this->d_val, this->d_tol); } if (this->getNegation()) { res = !res; } return res; } //! returns a copy of this query Queries::Query *copy() const { AtomRingQuery *res = new AtomRingQuery(this->d_val); res->setNegation(getNegation()); res->setTol(this->getTol()); res->d_description = this->d_description; res->d_dataFunc = this->d_dataFunc; return res; } }; //! allows use of recursive structure queries (e.g. recursive SMARTS) class RDKIT_GRAPHMOL_EXPORT RecursiveStructureQuery : public Queries::SetQuery { public: RecursiveStructureQuery() : Queries::SetQuery(), d_serialNumber(0) { setDataFunc(getAtIdx); setDescription("RecursiveStructure"); }; //! initialize from an ROMol pointer /*! Notes - this takes over ownership of the pointer */ RecursiveStructureQuery(ROMol const *query, unsigned int serialNumber = 0) : Queries::SetQuery(), d_serialNumber(serialNumber) { setQueryMol(query); setDataFunc(getAtIdx); setDescription("RecursiveStructure"); }; //! returns the index of an atom static inline int getAtIdx(Atom const *at) { PRECONDITION(at, "bad atom argument"); return at->getIdx(); }; //! sets the molecule we'll use recursively /*! Notes - this takes over ownership of the pointer */ void setQueryMol(ROMol const *query) { dp_queryMol.reset(query); } //! returns a pointer to our query molecule ROMol const *getQueryMol() const { return dp_queryMol.get(); }; //! returns a copy of this query Queries::Query *copy() const { RecursiveStructureQuery *res = new RecursiveStructureQuery(); res->dp_queryMol.reset(new ROMol(*dp_queryMol, true)); std::set::const_iterator i; for (i = d_set.begin(); i != d_set.end(); i++) { res->insert(*i); } res->setNegation(getNegation()); res->d_description = d_description; res->d_serialNumber = d_serialNumber; return res; } unsigned int getSerialNumber() const { return d_serialNumber; }; #ifdef RDK_THREADSAFE_SSS std::mutex d_mutex; #endif private: boost::shared_ptr dp_queryMol; unsigned int d_serialNumber; }; template int nullDataFun(T) { return 1; } template bool nullQueryFun(T) { return true; } typedef Bond const *ConstBondPtr; // ! Query whether an atom has a property template class HasPropQuery : public Queries::EqualityQuery { std::string propname; public: HasPropQuery() : Queries::EqualityQuery(), propname() { // default is to just do a number of rings query: this->setDescription("AtomHasProp"); this->setDataFunc(0); }; explicit HasPropQuery(const std::string &v) : Queries::EqualityQuery(), propname(v) { // default is to just do a number of rings query: this->setDescription("AtomHasProp"); this->setDataFunc(0); }; virtual bool Match(const TargetPtr what) const { bool res = what->hasProp(propname); if (this->getNegation()) { res = !res; } return res; } //! returns a copy of this query Queries::Query *copy() const { HasPropQuery *res = new HasPropQuery(this->propname); res->setNegation(this->getNegation()); res->d_description = this->d_description; return res; } }; typedef Queries::EqualityQuery ATOM_PROP_QUERY; typedef Queries::EqualityQuery BOND_PROP_QUERY; //! returns a Query for matching atoms that have a particular property template Queries::EqualityQuery *makeHasPropQuery( const std::string &property) { return new HasPropQuery(property); } // ! Query whether an atom has a property with a value template class HasPropWithValueQuery : public Queries::EqualityQuery { std::string propname; T val; T tolerance; public: HasPropWithValueQuery() : Queries::EqualityQuery(), propname(), val() { // default is to just do a number of rings query: this->setDescription("HasPropWithValue"); this->setDataFunc(0); }; explicit HasPropWithValueQuery(const std::string &prop, const T &v, const T &tol = 0.0) : Queries::EqualityQuery(), propname(prop), val(v), tolerance(tol) { // default is to just do a number of rings query: this->setDescription("HasPropWithValue"); this->setDataFunc(0); }; virtual bool Match(const TargetPtr what) const { bool res = what->hasProp(propname); if (res) { try { T atom_val = what->template getProp(propname); res = Queries::queryCmp(atom_val, this->val, this->tolerance) == 0; } catch (KeyErrorException &) { res = false; } catch (boost::bad_any_cast &) { res = false; } #ifdef __GNUC__ #if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)) catch (...) { // catch all -- this is currently necessary to // trap some bugs in boost+gcc configurations // Normally, this is not the correct thing to // do, but the only exception above is due // to the boost any_cast which is trapped // by the Boost python wrapper when it shouldn't // be. res = false; } #endif #endif } if (this->getNegation()) { res = !res; } return res; } //! returns a copy of this query Queries::Query *copy() const { HasPropWithValueQuery *res = new HasPropWithValueQuery(this->propname, this->val, this->tolerance); res->setNegation(this->getNegation()); res->d_description = this->d_description; return res; } }; template class HasPropWithValueQuery : public Queries::EqualityQuery { std::string propname; std::string val; public: HasPropWithValueQuery() : Queries::EqualityQuery(), propname(), val() { // default is to just do a number of rings query: this->setDescription("HasPropWithValue"); this->setDataFunc(0); }; explicit HasPropWithValueQuery(const std::string &prop, const std::string &v, const std::string &tol = "") : Queries::EqualityQuery(), propname(prop), val(v) { RDUNUSED_PARAM(tol); // default is to just do a number of rings query: this->setDescription("HasPropWithValue"); this->setDataFunc(0); }; virtual bool Match(const TargetPtr what) const { bool res = what->hasProp(propname); if (res) { try { std::string atom_val = what->template getProp(propname); res = atom_val == this->val; } catch (KeyErrorException &) { res = false; } catch (boost::bad_any_cast &) { res = false; } #ifdef __GNUC__ #if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)) catch (...) { // catch all -- this is currently necessary to // trap some bugs in boost+gcc configurations // Normally, this is not the correct thing to // do, but the only exception above is due // to the boost any_cast which is trapped // by the Boost python wrapper when it shouldn't // be. res = false; } #endif #endif } if (this->getNegation()) { res = !res; } return res; } //! returns a copy of this query Queries::Query *copy() const { HasPropWithValueQuery *res = new HasPropWithValueQuery(this->propname, this->val); res->setNegation(this->getNegation()); res->d_description = this->d_description; return res; } }; template class HasPropWithValueQuery : public Queries::EqualityQuery { std::string propname; ExplicitBitVect val; float tol; public: HasPropWithValueQuery() : Queries::EqualityQuery(), propname(), val(), tol(0.0) { this->setDescription("HasPropWithValue"); this->setDataFunc(0); }; explicit HasPropWithValueQuery(const std::string &prop, const ExplicitBitVect &v, float tol = 0.0) : Queries::EqualityQuery(), propname(prop), val(v), tol(tol) { this->setDescription("HasPropWithValue"); this->setDataFunc(0); }; virtual bool Match(const TargetPtr what) const { bool res = what->hasProp(propname); if (res) { try { const ExplicitBitVect &bv = what->template getProp(propname); const double tani = TanimotoSimilarity(val, bv); res = (1.0 - tani) <= tol; } catch (KeyErrorException) { res = false; } catch (boost::bad_any_cast) { res = false; } #ifdef __GNUC__ #if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)) catch (...) { // catch all -- this is currently necessary to // trap some bugs in boost+gcc configurations // Normally, this is not the correct thing to // do, but the only exception above is due // to the boost any_cast which is trapped // by the Boost python wrapper when it shouldn't // be. res = false; } #endif #endif } if (this->getNegation()) { res = !res; } return res; } //! returns a copy of this query Queries::Query *copy() const { HasPropWithValueQuery *res = new HasPropWithValueQuery( this->propname, this->val, this->tol); res->setNegation(this->getNegation()); res->d_description = this->d_description; return res; } }; template Queries::EqualityQuery *makePropQuery( const std::string &propname, const T &val, const T &tolerance = T()) { return new HasPropWithValueQuery(propname, val, tolerance); } template Queries::EqualityQuery *makePropQuery( const std::string &propname, const ExplicitBitVect &val, float tolerance = 0.0) { return new HasPropWithValueQuery( propname, val, tolerance); } RDKIT_GRAPHMOL_EXPORT bool isComplexQuery(const Bond *b); RDKIT_GRAPHMOL_EXPORT bool isComplexQuery(const Atom *a); RDKIT_GRAPHMOL_EXPORT bool isAtomAromatic(const Atom *a); }; // namespace RDKit #endif