1 //
2 // Copyright (C) 2003-2021 Greg Landrum and other RDKit contributors
3 //
4 // @@ All Rights Reserved @@
5 // This file is part of the RDKit.
6 // The contents are covered by the terms of the BSD license
7 // which is included in the file license.txt, found at the root
8 // of the RDKit source tree.
9 //
10
11 //! \file QueryOps.h
12 /*!
13 \brief Includes a bunch of functionality for handling Atom and Bond queries.
14 */
15 #include <RDGeneral/export.h>
16 #ifndef RD_QUERY_OPS_H
17 #define RD_QUERY_OPS_H
18
19 #include <GraphMol/RDKitBase.h>
20 #include <Query/QueryObjects.h>
21 #include <Query/Query.h>
22 #include <DataStructs/BitVects.h>
23 #include <DataStructs/BitOps.h>
24
25 #ifdef RDK_THREADSAFE_SSS
26 #include <mutex>
27 #endif
28
29 namespace RDKit {
30 typedef Queries::Query<bool, Atom const *, true> ATOM_BOOL_QUERY;
31 typedef Queries::Query<bool, Bond const *, true> BOND_BOOL_QUERY;
32
33 typedef Queries::AndQuery<int, Atom const *, true> ATOM_AND_QUERY;
34 typedef Queries::AndQuery<int, Bond const *, true> BOND_AND_QUERY;
35
36 typedef Queries::OrQuery<int, Atom const *, true> ATOM_OR_QUERY;
37 typedef Queries::OrQuery<int, Bond const *, true> BOND_OR_QUERY;
38
39 typedef Queries::XOrQuery<int, Atom const *, true> ATOM_XOR_QUERY;
40 typedef Queries::XOrQuery<int, Bond const *, true> BOND_XOR_QUERY;
41
42 typedef Queries::EqualityQuery<int, Atom const *, true> ATOM_EQUALS_QUERY;
43 typedef Queries::EqualityQuery<int, Bond const *, true> BOND_EQUALS_QUERY;
44
45 typedef Queries::GreaterQuery<int, Atom const *, true> ATOM_GREATER_QUERY;
46 typedef Queries::GreaterQuery<int, Bond const *, true> BOND_GREATER_QUERY;
47
48 typedef Queries::GreaterEqualQuery<int, Atom const *, true>
49 ATOM_GREATEREQUAL_QUERY;
50 typedef Queries::GreaterEqualQuery<int, Bond const *, true>
51 BOND_GREATEREQUAL_QUERY;
52
53 typedef Queries::LessQuery<int, Atom const *, true> ATOM_LESS_QUERY;
54 typedef Queries::LessQuery<int, Bond const *, true> BOND_LESS_QUERY;
55
56 typedef Queries::LessEqualQuery<int, Atom const *, true> ATOM_LESSEQUAL_QUERY;
57 typedef Queries::LessEqualQuery<int, Bond const *, true> BOND_LESSEQUAL_QUERY;
58
59 typedef Queries::RangeQuery<int, Atom const *, true> ATOM_RANGE_QUERY;
60 typedef Queries::RangeQuery<int, Bond const *, true> BOND_RANGE_QUERY;
61
62 typedef Queries::SetQuery<int, Atom const *, true> ATOM_SET_QUERY;
63 typedef Queries::SetQuery<int, Bond const *, true> BOND_SET_QUERY;
64
65 typedef Queries::Query<int, Bond const *, true> BOND_NULL_QUERY;
66 typedef Queries::Query<int, Atom const *, true> ATOM_NULL_QUERY;
67
68 // -------------------------------------------------
69 // common atom queries
70
queryAtomAromatic(Atom const * at)71 static inline int queryAtomAromatic(Atom const *at) {
72 return at->getIsAromatic();
73 };
queryAtomAliphatic(Atom const * at)74 static inline int queryAtomAliphatic(Atom const *at) {
75 return !(at->getIsAromatic());
76 };
queryAtomExplicitDegree(Atom const * at)77 static inline int queryAtomExplicitDegree(Atom const *at) {
78 return at->getDegree();
79 };
queryAtomTotalDegree(Atom const * at)80 static inline int queryAtomTotalDegree(Atom const *at) {
81 return at->getTotalDegree();
82 };
83 //! D and T are treated as "non-hydrogen" here
queryAtomNonHydrogenDegree(Atom const * at)84 static inline int queryAtomNonHydrogenDegree(Atom const *at) {
85 int res = 0;
86 for (const auto &nbri :
87 boost::make_iterator_range(at->getOwningMol().getAtomNeighbors(at))) {
88 const auto nbr = at->getOwningMol()[nbri];
89 if (nbr->getAtomicNum() != 1 || nbr->getIsotope() > 1) {
90 res++;
91 }
92 }
93
94 return res;
95 };
96 //! D and T are not treated as heavy atoms here
queryAtomHeavyAtomDegree(Atom const * at)97 static inline int queryAtomHeavyAtomDegree(Atom const *at) {
98 int heavyDegree = 0;
99 for (const auto &nbri :
100 boost::make_iterator_range(at->getOwningMol().getAtomNeighbors(at))) {
101 const auto nbr = at->getOwningMol()[nbri];
102 if (nbr->getAtomicNum() > 1) {
103 heavyDegree++;
104 }
105 }
106
107 return heavyDegree;
108 };
queryAtomHCount(Atom const * at)109 static inline int queryAtomHCount(Atom const *at) {
110 return at->getTotalNumHs(true);
111 };
queryAtomImplicitHCount(Atom const * at)112 static inline int queryAtomImplicitHCount(Atom const *at) {
113 return at->getTotalNumHs(false);
114 };
queryAtomHasImplicitH(Atom const * at)115 static inline int queryAtomHasImplicitH(Atom const *at) {
116 return int(at->getTotalNumHs(false) > 0);
117 };
queryAtomImplicitValence(Atom const * at)118 static inline int queryAtomImplicitValence(Atom const *at) {
119 return at->getImplicitValence();
120 };
queryAtomExplicitValence(Atom const * at)121 static inline int queryAtomExplicitValence(Atom const *at) {
122 return at->getExplicitValence() - at->getNumExplicitHs();
123 };
queryAtomTotalValence(Atom const * at)124 static inline int queryAtomTotalValence(Atom const *at) {
125 return at->getTotalValence();
126 };
queryAtomUnsaturated(Atom const * at)127 static inline int queryAtomUnsaturated(Atom const *at) {
128 return at->getTotalDegree() < at->getTotalValence();
129 };
queryAtomNum(Atom const * at)130 static inline int queryAtomNum(Atom const *at) { return at->getAtomicNum(); };
makeAtomType(int atomic_num,bool aromatic)131 static inline int makeAtomType(int atomic_num, bool aromatic) {
132 return atomic_num + 1000 * static_cast<int>(aromatic);
133 }
parseAtomType(int val,int & atomic_num,bool & aromatic)134 static inline void parseAtomType(int val, int &atomic_num, bool &aromatic) {
135 if (val > 1000) {
136 aromatic = true;
137 atomic_num = val - 1000;
138 } else {
139 aromatic = false;
140 atomic_num = val;
141 }
142 }
getAtomTypeIsAromatic(int val)143 static inline bool getAtomTypeIsAromatic(int val) {
144 if (val > 1000) return true;
145 return false;
146 }
getAtomTypeAtomicNum(int val)147 static inline int getAtomTypeAtomicNum(int val) {
148 if (val > 1000) return val - 1000;
149 return val;
150 }
151
queryAtomType(Atom const * at)152 static inline int queryAtomType(Atom const *at) {
153 return makeAtomType(at->getAtomicNum(), at->getIsAromatic());
154 };
155 const int massIntegerConversionFactor = 1000;
queryAtomMass(Atom const * at)156 static inline int queryAtomMass(Atom const *at) {
157 return static_cast<int>(
158 std::round(massIntegerConversionFactor * at->getMass()));
159 };
queryAtomIsotope(Atom const * at)160 static inline int queryAtomIsotope(Atom const *at) {
161 return static_cast<int>(at->getIsotope());
162 };
queryAtomFormalCharge(Atom const * at)163 static inline int queryAtomFormalCharge(Atom const *at) {
164 return static_cast<int>(at->getFormalCharge());
165 };
queryAtomNegativeFormalCharge(Atom const * at)166 static inline int queryAtomNegativeFormalCharge(Atom const *at) {
167 return static_cast<int>(-1 * at->getFormalCharge());
168 };
queryAtomHybridization(Atom const * at)169 static inline int queryAtomHybridization(Atom const *at) {
170 return at->getHybridization();
171 };
queryAtomNumRadicalElectrons(Atom const * at)172 static inline int queryAtomNumRadicalElectrons(Atom const *at) {
173 return at->getNumRadicalElectrons();
174 };
queryAtomHasChiralTag(Atom const * at)175 static inline int queryAtomHasChiralTag(Atom const *at) {
176 return at->getChiralTag() != Atom::CHI_UNSPECIFIED;
177 };
queryAtomMissingChiralTag(Atom const * at)178 static inline int queryAtomMissingChiralTag(Atom const *at) {
179 return at->getChiralTag() == Atom::CHI_UNSPECIFIED &&
180 at->hasProp(common_properties::_ChiralityPossible);
181 };
182
queryAtomHasHeteroatomNbrs(Atom const * at)183 static inline int queryAtomHasHeteroatomNbrs(Atom const *at) {
184 ROMol::ADJ_ITER nbrIdx, endNbrs;
185 boost::tie(nbrIdx, endNbrs) = at->getOwningMol().getAtomNeighbors(at);
186 while (nbrIdx != endNbrs) {
187 const Atom *nbr = at->getOwningMol()[*nbrIdx];
188 if (nbr->getAtomicNum() != 6 && nbr->getAtomicNum() != 1) {
189 return 1;
190 }
191 ++nbrIdx;
192 }
193 return 0;
194 };
195
queryAtomNumHeteroatomNbrs(Atom const * at)196 static inline int queryAtomNumHeteroatomNbrs(Atom const *at) {
197 int res = 0;
198 ROMol::ADJ_ITER nbrIdx, endNbrs;
199 boost::tie(nbrIdx, endNbrs) = at->getOwningMol().getAtomNeighbors(at);
200 while (nbrIdx != endNbrs) {
201 const Atom *nbr = at->getOwningMol()[*nbrIdx];
202 if (nbr->getAtomicNum() != 6 && nbr->getAtomicNum() != 1) {
203 ++res;
204 }
205 ++nbrIdx;
206 }
207 return res;
208 };
209
queryAtomHasAliphaticHeteroatomNbrs(Atom const * at)210 static inline int queryAtomHasAliphaticHeteroatomNbrs(Atom const *at) {
211 ROMol::ADJ_ITER nbrIdx, endNbrs;
212 boost::tie(nbrIdx, endNbrs) = at->getOwningMol().getAtomNeighbors(at);
213 while (nbrIdx != endNbrs) {
214 const Atom *nbr = at->getOwningMol()[*nbrIdx];
215 if ((!nbr->getIsAromatic()) && nbr->getAtomicNum() != 6 &&
216 nbr->getAtomicNum() != 1) {
217 return 1;
218 }
219 ++nbrIdx;
220 }
221 return 0;
222 };
223
queryAtomNumAliphaticHeteroatomNbrs(Atom const * at)224 static inline int queryAtomNumAliphaticHeteroatomNbrs(Atom const *at) {
225 int res = 0;
226 ROMol::ADJ_ITER nbrIdx, endNbrs;
227 boost::tie(nbrIdx, endNbrs) = at->getOwningMol().getAtomNeighbors(at);
228 while (nbrIdx != endNbrs) {
229 const Atom *nbr = at->getOwningMol()[*nbrIdx];
230 if ((!nbr->getIsAromatic()) && nbr->getAtomicNum() != 6 &&
231 nbr->getAtomicNum() != 1) {
232 ++res;
233 }
234 ++nbrIdx;
235 }
236 return res;
237 };
238
239 RDKIT_GRAPHMOL_EXPORT unsigned int queryAtomBondProduct(Atom const *at);
240 RDKIT_GRAPHMOL_EXPORT unsigned int queryAtomAllBondProduct(Atom const *at);
241
242 // -------------------------------------------------
243 // common bond queries
244
queryBondOrder(Bond const * bond)245 static inline int queryBondOrder(Bond const *bond) {
246 return static_cast<int>(bond->getBondType());
247 };
queryBondIsSingleOrAromatic(Bond const * bond)248 static inline int queryBondIsSingleOrAromatic(Bond const *bond) {
249 return static_cast<int>(bond->getBondType() == Bond::SINGLE ||
250 bond->getBondType() == Bond::AROMATIC);
251 };
queryBondIsDoubleOrAromatic(Bond const * bond)252 static inline int queryBondIsDoubleOrAromatic(Bond const *bond) {
253 return static_cast<int>(bond->getBondType() == Bond::DOUBLE ||
254 bond->getBondType() == Bond::AROMATIC);
255 };
queryBondIsSingleOrDouble(Bond const * bond)256 static inline int queryBondIsSingleOrDouble(Bond const *bond) {
257 return static_cast<int>(bond->getBondType() == Bond::SINGLE ||
258 bond->getBondType() == Bond::DOUBLE);
259 };
queryBondIsSingleOrDoubleOrAromatic(Bond const * bond)260 static inline int queryBondIsSingleOrDoubleOrAromatic(Bond const *bond) {
261 return static_cast<int>(bond->getBondType() == Bond::SINGLE ||
262 bond->getBondType() == Bond::DOUBLE ||
263 bond->getBondType() == Bond::AROMATIC);
264 };
queryBondDir(Bond const * bond)265 static inline int queryBondDir(Bond const *bond) {
266 return static_cast<int>(bond->getBondDir());
267 };
queryIsBondInNRings(Bond const * at)268 static inline int queryIsBondInNRings(Bond const *at) {
269 return at->getOwningMol().getRingInfo()->numBondRings(at->getIdx());
270 };
queryBondHasStereo(Bond const * bnd)271 static inline int queryBondHasStereo(Bond const *bnd) {
272 return bnd->getStereo() > Bond::STEREONONE;
273 };
274
275 // -------------------------------------------------
276 // ring queries
277
queryIsAtomInNRings(Atom const * at)278 static inline int queryIsAtomInNRings(Atom const *at) {
279 return at->getOwningMol().getRingInfo()->numAtomRings(at->getIdx());
280 };
queryIsAtomInRing(Atom const * at)281 static inline int queryIsAtomInRing(Atom const *at) {
282 return at->getOwningMol().getRingInfo()->numAtomRings(at->getIdx()) != 0;
283 };
queryAtomHasRingBond(Atom const * at)284 static inline int queryAtomHasRingBond(Atom const *at) {
285 ROMol::OBOND_ITER_PAIR atomBonds = at->getOwningMol().getAtomBonds(at);
286 while (atomBonds.first != atomBonds.second) {
287 unsigned int bondIdx =
288 at->getOwningMol().getTopology()[*atomBonds.first]->getIdx();
289 if (at->getOwningMol().getRingInfo()->numBondRings(bondIdx)) {
290 return 1;
291 }
292 ++atomBonds.first;
293 }
294 return 0;
295 };
296 RDKIT_GRAPHMOL_EXPORT int queryIsAtomBridgehead(Atom const *at);
297
queryIsBondInRing(Bond const * bond)298 static inline int queryIsBondInRing(Bond const *bond) {
299 return bond->getOwningMol().getRingInfo()->numBondRings(bond->getIdx()) != 0;
300 };
queryAtomMinRingSize(Atom const * at)301 static inline int queryAtomMinRingSize(Atom const *at) {
302 return at->getOwningMol().getRingInfo()->minAtomRingSize(at->getIdx());
303 };
queryBondMinRingSize(Bond const * bond)304 static inline int queryBondMinRingSize(Bond const *bond) {
305 return bond->getOwningMol().getRingInfo()->minBondRingSize(bond->getIdx());
306 };
307
queryAtomRingBondCount(Atom const * at)308 static inline int queryAtomRingBondCount(Atom const *at) {
309 // EFF: cache this result
310 int res = 0;
311 ROMol::OBOND_ITER_PAIR atomBonds = at->getOwningMol().getAtomBonds(at);
312 while (atomBonds.first != atomBonds.second) {
313 unsigned int bondIdx =
314 at->getOwningMol().getTopology()[*atomBonds.first]->getIdx();
315 if (at->getOwningMol().getRingInfo()->numBondRings(bondIdx)) {
316 res++;
317 }
318 ++atomBonds.first;
319 }
320 return res;
321 }
322
323 template <int tgt>
queryAtomIsInRingOfSize(Atom const * at)324 int queryAtomIsInRingOfSize(Atom const *at) {
325 if (at->getOwningMol().getRingInfo()->isAtomInRingOfSize(at->getIdx(), tgt)) {
326 return tgt;
327 } else {
328 return 0;
329 }
330 };
331 template <int tgt>
queryBondIsInRingOfSize(Bond const * bond)332 int queryBondIsInRingOfSize(Bond const *bond) {
333 if (bond->getOwningMol().getRingInfo()->isBondInRingOfSize(bond->getIdx(),
334 tgt)) {
335 return tgt;
336 } else {
337 return 0;
338 }
339 };
340
341 template <class T>
342 T *makeAtomSimpleQuery(int what, int func(Atom const *),
343 const std::string &description = "Atom Simple") {
344 T *res = new T;
345 res->setVal(what);
346 res->setDataFunc(func);
347 res->setDescription(description);
348 return res;
349 }
350
351 static inline ATOM_RANGE_QUERY *makeAtomRangeQuery(
352 int lower, int upper, bool lowerOpen, bool upperOpen,
353 int func(Atom const *), const std::string &description = "Atom Range") {
354 ATOM_RANGE_QUERY *res = new ATOM_RANGE_QUERY(lower, upper);
355 res->setDataFunc(func);
356 res->setDescription(description);
357 res->setEndsOpen(lowerOpen, upperOpen);
358 return res;
359 }
360
361 //! returns a Query for matching atomic number
362 template <class T>
makeAtomNumQuery(int what,const std::string & descr)363 T *makeAtomNumQuery(int what, const std::string &descr) {
364 return makeAtomSimpleQuery<T>(what, queryAtomNum, descr);
365 }
366 //! \overload
367 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomNumQuery(int what);
368
369 //! returns a Query for matching atomic number and aromaticity
370 template <class T>
makeAtomTypeQuery(int num,int aromatic,const std::string & descr)371 T *makeAtomTypeQuery(int num, int aromatic, const std::string &descr) {
372 return makeAtomSimpleQuery<T>(makeAtomType(num, aromatic), queryAtomType,
373 descr);
374 }
375 //! \overload
376 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomTypeQuery(int num,
377 int aromatic);
378
379 //! returns a Query for matching implicit valence
380 template <class T>
makeAtomImplicitValenceQuery(int what,const std::string & descr)381 T *makeAtomImplicitValenceQuery(int what, const std::string &descr) {
382 return makeAtomSimpleQuery<T>(what, queryAtomImplicitValence, descr);
383 }
384 //! \overload
385 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomImplicitValenceQuery(int what);
386
387 //! returns a Query for matching explicit valence
388 template <class T>
makeAtomExplicitValenceQuery(int what,const std::string & descr)389 T *makeAtomExplicitValenceQuery(int what, const std::string &descr) {
390 return makeAtomSimpleQuery<T>(what, queryAtomExplicitValence, descr);
391 }
392 //! \overload
393 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomExplicitValenceQuery(int what);
394
395 //! returns a Query for matching total valence
396 template <class T>
makeAtomTotalValenceQuery(int what,const std::string & descr)397 T *makeAtomTotalValenceQuery(int what, const std::string &descr) {
398 return makeAtomSimpleQuery<T>(what, queryAtomTotalValence, descr);
399 }
400 //! \overload
401 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomTotalValenceQuery(int what);
402
403 //! returns a Query for matching explicit degree
404 template <class T>
makeAtomExplicitDegreeQuery(int what,const std::string & descr)405 T *makeAtomExplicitDegreeQuery(int what, const std::string &descr) {
406 return makeAtomSimpleQuery<T>(what, queryAtomExplicitDegree, descr);
407 }
408 //! \overload
409 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomExplicitDegreeQuery(int what);
410
411 //! returns a Query for matching atomic degree
412 template <class T>
makeAtomTotalDegreeQuery(int what,const std::string & descr)413 T *makeAtomTotalDegreeQuery(int what, const std::string &descr) {
414 return makeAtomSimpleQuery<T>(what, queryAtomTotalDegree, descr);
415 }
416 //! \overload
417 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomTotalDegreeQuery(int what);
418
419 //! returns a Query for matching heavy atom degree
420 template <class T>
makeAtomHeavyAtomDegreeQuery(int what,const std::string & descr)421 T *makeAtomHeavyAtomDegreeQuery(int what, const std::string &descr) {
422 return makeAtomSimpleQuery<T>(what, queryAtomHeavyAtomDegree, descr);
423 }
424 //! \overload
425 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHeavyAtomDegreeQuery(int what);
426
427 //! returns a Query for matching hydrogen count
428 template <class T>
makeAtomHCountQuery(int what,const std::string & descr)429 T *makeAtomHCountQuery(int what, const std::string &descr) {
430 return makeAtomSimpleQuery<T>(what, queryAtomHCount, descr);
431 }
432 //! \overload
433 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHCountQuery(int what);
434
435 //! returns a Query for matching ring atoms
436 template <class T>
makeAtomHasImplicitHQuery(const std::string & descr)437 T *makeAtomHasImplicitHQuery(const std::string &descr) {
438 return makeAtomSimpleQuery<T>(true, queryAtomHasImplicitH, descr);
439 }
440 //! \overload
441 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHasImplicitHQuery();
442
443 //! returns a Query for matching implicit hydrogen count
444 template <class T>
makeAtomImplicitHCountQuery(int what,const std::string & descr)445 T *makeAtomImplicitHCountQuery(int what, const std::string &descr) {
446 return makeAtomSimpleQuery<T>(what, queryAtomImplicitHCount, descr);
447 }
448 //! \overload
449 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomImplicitHCountQuery(int what);
450
451 //! returns a Query for matching the \c isAromatic flag
452 template <class T>
makeAtomAromaticQuery(const std::string & descr)453 T *makeAtomAromaticQuery(const std::string &descr) {
454 return makeAtomSimpleQuery<T>(true, queryAtomAromatic, descr);
455 }
456 //! \overload
457 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomAromaticQuery();
458
459 //! returns a Query for matching aliphatic atoms
460 template <class T>
makeAtomAliphaticQuery(const std::string & descr)461 T *makeAtomAliphaticQuery(const std::string &descr) {
462 return makeAtomSimpleQuery<T>(true, queryAtomAliphatic, descr);
463 }
464 //! \overload
465 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomAliphaticQuery();
466
467 //! returns a Query for matching atoms with a particular mass
468 template <class T>
makeAtomMassQuery(int what,const std::string & descr)469 T *makeAtomMassQuery(int what, const std::string &descr) {
470 return makeAtomSimpleQuery<T>(massIntegerConversionFactor * what,
471 queryAtomMass, descr);
472 }
473 //! \overload
474 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomMassQuery(int what);
475
476 //! returns a Query for matching atoms with a particular isotope
477 template <class T>
makeAtomIsotopeQuery(int what,const std::string & descr)478 T *makeAtomIsotopeQuery(int what, const std::string &descr) {
479 return makeAtomSimpleQuery<T>(what, queryAtomIsotope, descr);
480 }
481 //! \overload
482 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomIsotopeQuery(int what);
483
484 //! returns a Query for matching formal charge
485 template <class T>
makeAtomFormalChargeQuery(int what,const std::string & descr)486 T *makeAtomFormalChargeQuery(int what, const std::string &descr) {
487 return makeAtomSimpleQuery<T>(what, queryAtomFormalCharge, descr);
488 }
489 //! \overload
490 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomFormalChargeQuery(int what);
491
492 //! returns a Query for matching negative formal charges (i.e. a query val of 1
493 //! matches a formal charge of -1)
494 template <class T>
makeAtomNegativeFormalChargeQuery(int what,const std::string & descr)495 T *makeAtomNegativeFormalChargeQuery(int what, const std::string &descr) {
496 return makeAtomSimpleQuery<T>(what, queryAtomNegativeFormalCharge, descr);
497 }
498 //! \overload
499 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomNegativeFormalChargeQuery(
500 int what);
501
502 //! returns a Query for matching hybridization
503 template <class T>
makeAtomHybridizationQuery(int what,const std::string & descr)504 T *makeAtomHybridizationQuery(int what, const std::string &descr) {
505 return makeAtomSimpleQuery<T>(what, queryAtomHybridization, descr);
506 }
507 //! \overload
508 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHybridizationQuery(int what);
509
510 //! returns a Query for matching the number of radical electrons
511 template <class T>
makeAtomNumRadicalElectronsQuery(int what,const std::string & descr)512 T *makeAtomNumRadicalElectronsQuery(int what, const std::string &descr) {
513 return makeAtomSimpleQuery<T>(what, queryAtomNumRadicalElectrons, descr);
514 }
515 //! \overload
516 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomNumRadicalElectronsQuery(
517 int what);
518
519 //! returns a Query for matching whether or not chirality has been set on the
520 //! atom
521 template <class T>
makeAtomHasChiralTagQuery(const std::string & descr)522 T *makeAtomHasChiralTagQuery(const std::string &descr) {
523 return makeAtomSimpleQuery<T>(true, queryAtomHasChiralTag, descr);
524 }
525 //! \overloadquery
526 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHasChiralTagQuery();
527
528 //! returns a Query for matching whether or not a potentially chiral atom is
529 //! missing a chiral tag
530 template <class T>
makeAtomMissingChiralTagQuery(const std::string & descr)531 T *makeAtomMissingChiralTagQuery(const std::string &descr) {
532 return makeAtomSimpleQuery<T>(true, queryAtomMissingChiralTag, descr);
533 }
534 //! \overloadquery
535 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomMissingChiralTagQuery();
536
537 //! returns a Query for matching atoms with unsaturation:
538 template <class T>
makeAtomUnsaturatedQuery(const std::string & descr)539 T *makeAtomUnsaturatedQuery(const std::string &descr) {
540 return makeAtomSimpleQuery<T>(true, queryAtomUnsaturated, descr);
541 }
542 //! \overload
543 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomUnsaturatedQuery();
544
545 //! returns a Query for matching ring atoms
546 template <class T>
makeAtomInRingQuery(const std::string & descr)547 T *makeAtomInRingQuery(const std::string &descr) {
548 return makeAtomSimpleQuery<T>(true, queryIsAtomInRing, descr);
549 }
550 //! \overload
551 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomInRingQuery();
552
553 //! returns a Query for matching atoms in a particular number of rings
554 template <class T>
makeAtomInNRingsQuery(int what,const std::string & descr)555 T *makeAtomInNRingsQuery(int what, const std::string &descr) {
556 return makeAtomSimpleQuery<T>(what, queryIsAtomInNRings, descr);
557 }
558 //! \overload
559 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomInNRingsQuery(int what);
560
561 //! returns a Query for matching atoms in rings of a particular size
562 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomInRingOfSizeQuery(int tgt);
563
564 //! returns a Query for matching an atom's minimum ring size
565 template <class T>
makeAtomMinRingSizeQuery(int tgt,const std::string & descr)566 T *makeAtomMinRingSizeQuery(int tgt, const std::string &descr) {
567 return makeAtomSimpleQuery<T>(tgt, queryAtomMinRingSize, descr);
568 }
569 //! \overload
570 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomMinRingSizeQuery(int tgt);
571
572 //! returns a Query for matching atoms with a particular number of ring bonds
573 template <class T>
makeAtomRingBondCountQuery(int what,const std::string & descr)574 T *makeAtomRingBondCountQuery(int what, const std::string &descr) {
575 return makeAtomSimpleQuery<T>(what, queryAtomRingBondCount, descr);
576 }
577 //! \overload
578 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomRingBondCountQuery(int what);
579
580 //! returns a Query for matching generic A atoms (heavy atoms)
581 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAAtomQuery();
582 //! returns a Query for matching generic AH atoms (any atom)
583 RDKIT_GRAPHMOL_EXPORT ATOM_NULL_QUERY *makeAHAtomQuery();
584 //! returns a Query for matching generic Q atoms (heteroatoms)
585 RDKIT_GRAPHMOL_EXPORT ATOM_OR_QUERY *makeQAtomQuery();
586 //! returns a Query for matching generic QH atoms (heteroatom or H)
587 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeQHAtomQuery();
588 //! returns a Query for matching generic X atoms (halogens)
589 RDKIT_GRAPHMOL_EXPORT ATOM_OR_QUERY *makeXAtomQuery();
590 //! returns a Query for matching generic XH atoms (halogen or H)
591 RDKIT_GRAPHMOL_EXPORT ATOM_OR_QUERY *makeXHAtomQuery();
592 //! returns a Query for matching generic M atoms (metals)
593 RDKIT_GRAPHMOL_EXPORT ATOM_OR_QUERY *makeMAtomQuery();
594 //! returns a Query for matching generic MH atoms (metals or H)
595 RDKIT_GRAPHMOL_EXPORT ATOM_OR_QUERY *makeMHAtomQuery();
596
597 //! returns a Query for matching atoms that have ring bonds
598 template <class T>
makeAtomHasRingBondQuery(const std::string & descr)599 T *makeAtomHasRingBondQuery(const std::string &descr) {
600 return makeAtomSimpleQuery<T>(1, queryAtomHasRingBond, descr);
601 }
602 //! \overload
603 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHasRingBondQuery();
604
605 //! returns a Query for matching the number of heteroatom neighbors
606 template <class T>
makeAtomNumHeteroatomNbrsQuery(int what,const std::string & descr)607 T *makeAtomNumHeteroatomNbrsQuery(int what, const std::string &descr) {
608 return makeAtomSimpleQuery<T>(what, queryAtomNumHeteroatomNbrs, descr);
609 }
610 //! \overload
611 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomNumHeteroatomNbrsQuery(
612 int what);
613
614 //! returns a Query for matching atoms that have heteroatom neighbors
615 template <class T>
makeAtomHasHeteroatomNbrsQuery(const std::string & descr)616 T *makeAtomHasHeteroatomNbrsQuery(const std::string &descr) {
617 return makeAtomSimpleQuery<T>(1, queryAtomHasHeteroatomNbrs, descr);
618 }
619 //! \overload
620 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomHasHeteroatomNbrsQuery();
621
622 //! returns a Query for matching the number of aliphatic heteroatom neighbors
623 template <class T>
makeAtomNumAliphaticHeteroatomNbrsQuery(int what,const std::string & descr)624 T *makeAtomNumAliphaticHeteroatomNbrsQuery(int what, const std::string &descr) {
625 return makeAtomSimpleQuery<T>(what, queryAtomNumAliphaticHeteroatomNbrs,
626 descr);
627 }
628 //! \overload
629 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *
630 makeAtomNumAliphaticHeteroatomNbrsQuery(int what);
631
632 //! returns a Query for matching atoms that have heteroatom neighbors
633 template <class T>
makeAtomHasAliphaticHeteroatomNbrsQuery(const std::string & descr)634 T *makeAtomHasAliphaticHeteroatomNbrsQuery(const std::string &descr) {
635 return makeAtomSimpleQuery<T>(1, queryAtomHasAliphaticHeteroatomNbrs, descr);
636 }
637 //! \overload
638 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *
639 makeAtomHasAliphaticHeteroatomNbrsQuery();
640
641 //! returns a Query for matching the number of non-hydrogen neighbors
642 template <class T>
makeAtomNonHydrogenDegreeQuery(int what,const std::string & descr)643 T *makeAtomNonHydrogenDegreeQuery(int what, const std::string &descr) {
644 return makeAtomSimpleQuery<T>(what, queryAtomNonHydrogenDegree, descr);
645 }
646 //! \overload
647 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomNonHydrogenDegreeQuery(
648 int what);
649
650 //! returns a Query for matching bridgehead atoms
651 template <class T>
makeAtomIsBridgeheadQuery(const std::string & descr)652 T *makeAtomIsBridgeheadQuery(const std::string &descr) {
653 return makeAtomSimpleQuery<T>(true, queryIsAtomBridgehead, descr);
654 }
655 //! \overload
656 RDKIT_GRAPHMOL_EXPORT ATOM_EQUALS_QUERY *makeAtomIsBridgeheadQuery();
657
658 //! returns a Query for matching bond orders
659 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondOrderEqualsQuery(
660 Bond::BondType what);
661 //! returns a Query for unspecified SMARTS bonds
662 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeSingleOrAromaticBondQuery();
663 //! returns a Query for double|aromatic bonds
664 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeDoubleOrAromaticBondQuery();
665 //! returns a Query for single|double bonds
666 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeSingleOrDoubleBondQuery();
667 //! returns a Query for tautomeric bonds
668 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *
669 makeSingleOrDoubleOrAromaticBondQuery();
670
671 //! returns a Query for matching bond directions
672 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondDirEqualsQuery(
673 Bond::BondDir what);
674 //! returns a Query for matching bonds with stereo set
675 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondHasStereoQuery();
676 //! returns a Query for matching ring bonds
677 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondIsInRingQuery();
678 //! returns a Query for matching bonds in rings of a particular size
679 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondInRingOfSizeQuery(int what);
680 //! returns a Query for matching a bond's minimum ring size
681 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondMinRingSizeQuery(int what);
682 //! returns a Query for matching bonds in a particular number of rings
683 RDKIT_GRAPHMOL_EXPORT BOND_EQUALS_QUERY *makeBondInNRingsQuery(int tgt);
684
685 //! returns a Query for matching any bond
686 RDKIT_GRAPHMOL_EXPORT BOND_NULL_QUERY *makeBondNullQuery();
687 //! returns a Query for matching any atom
688 RDKIT_GRAPHMOL_EXPORT ATOM_NULL_QUERY *makeAtomNullQuery();
689
queryAtomRingMembership(Atom const * at)690 static inline int queryAtomRingMembership(Atom const *at) {
691 return static_cast<int>(
692 at->getOwningMol().getRingInfo()->numAtomRings(at->getIdx()));
693 }
694 // I'm pretty sure that this typedef shouldn't be necessary,
695 // but VC++ generates a warning about const Atom const * in
696 // the definition of Match, then complains about an override
697 // that differs only by const/volatile (c4301), then generates
698 // incorrect code if we don't do this... so let's do it.
699 typedef Atom const *ConstAtomPtr;
700
701 class RDKIT_GRAPHMOL_EXPORT AtomRingQuery
702 : public Queries::EqualityQuery<int, ConstAtomPtr, true> {
703 public:
AtomRingQuery()704 AtomRingQuery() : Queries::EqualityQuery<int, ConstAtomPtr, true>(-1) {
705 // default is to just do a number of rings query:
706 this->setDescription("AtomInNRings");
707 this->setDataFunc(queryAtomRingMembership);
708 };
AtomRingQuery(int v)709 explicit AtomRingQuery(int v)
710 : Queries::EqualityQuery<int, ConstAtomPtr, true>(v) {
711 // default is to just do a number of rings query:
712 this->setDescription("AtomInNRings");
713 this->setDataFunc(queryAtomRingMembership);
714 };
715
Match(const ConstAtomPtr what)716 virtual bool Match(const ConstAtomPtr what) const {
717 int v = this->TypeConvert(what, Queries::Int2Type<true>());
718 bool res;
719 if (this->d_val < 0) {
720 res = v != 0;
721 } else {
722 res = !Queries::queryCmp(v, this->d_val, this->d_tol);
723 }
724 if (this->getNegation()) {
725 res = !res;
726 }
727 return res;
728 }
729
730 //! returns a copy of this query
copy()731 Queries::Query<int, ConstAtomPtr, true> *copy() const {
732 AtomRingQuery *res = new AtomRingQuery(this->d_val);
733 res->setNegation(getNegation());
734 res->setTol(this->getTol());
735 res->d_description = this->d_description;
736 res->d_dataFunc = this->d_dataFunc;
737 return res;
738 }
739 };
740
741 //! allows use of recursive structure queries (e.g. recursive SMARTS)
742 class RDKIT_GRAPHMOL_EXPORT RecursiveStructureQuery
743 : public Queries::SetQuery<int, Atom const *, true> {
744 public:
RecursiveStructureQuery()745 RecursiveStructureQuery() : Queries::SetQuery<int, Atom const *, true>() {
746 setDataFunc(getAtIdx);
747 setDescription("RecursiveStructure");
748 };
749 //! initialize from an ROMol pointer
750 /*!
751 <b>Notes</b>
752 - this takes over ownership of the pointer
753 */
754 RecursiveStructureQuery(ROMol const *query, unsigned int serialNumber = 0)
755 : Queries::SetQuery<int, Atom const *, true>(),
756 d_serialNumber(serialNumber) {
757 setQueryMol(query);
758 setDataFunc(getAtIdx);
759 setDescription("RecursiveStructure");
760 };
761 //! returns the index of an atom
getAtIdx(Atom const * at)762 static inline int getAtIdx(Atom const *at) {
763 PRECONDITION(at, "bad atom argument");
764 return at->getIdx();
765 };
766
767 //! sets the molecule we'll use recursively
768 /*!
769 <b>Notes</b>
770 - this takes over ownership of the pointer
771 */
setQueryMol(ROMol const * query)772 void setQueryMol(ROMol const *query) { dp_queryMol.reset(query); }
773 //! returns a pointer to our query molecule
getQueryMol()774 ROMol const *getQueryMol() const { return dp_queryMol.get(); };
775
776 //! returns a copy of this query
copy()777 Queries::Query<int, Atom const *, true> *copy() const {
778 RecursiveStructureQuery *res = new RecursiveStructureQuery();
779 res->dp_queryMol.reset(new ROMol(*dp_queryMol, true));
780
781 std::set<int>::const_iterator i;
782 for (i = d_set.begin(); i != d_set.end(); i++) {
783 res->insert(*i);
784 }
785 res->setNegation(getNegation());
786 res->d_description = d_description;
787 res->d_serialNumber = d_serialNumber;
788 return res;
789 }
getSerialNumber()790 unsigned int getSerialNumber() const { return d_serialNumber; };
791
792 #ifdef RDK_THREADSAFE_SSS
793 std::mutex d_mutex;
794 #endif
795 private:
796 boost::shared_ptr<const ROMol> dp_queryMol;
797 unsigned int d_serialNumber{0};
798 };
799
800 template <typename T>
nullDataFun(T)801 int nullDataFun(T) {
802 return 1;
803 }
804 template <typename T>
nullQueryFun(T)805 bool nullQueryFun(T) {
806 return true;
807 }
808
809 typedef Bond const *ConstBondPtr;
810
811 // ! Query whether an atom has a property
812 template <class TargetPtr>
813 class HasPropQuery : public Queries::EqualityQuery<int, TargetPtr, true> {
814 std::string propname;
815
816 public:
HasPropQuery()817 HasPropQuery() : Queries::EqualityQuery<int, TargetPtr, true>(), propname() {
818 // default is to just do a number of rings query:
819 this->setDescription("AtomHasProp");
820 this->setDataFunc(0);
821 };
HasPropQuery(const std::string & v)822 explicit HasPropQuery(const std::string &v)
823 : Queries::EqualityQuery<int, TargetPtr, true>(), propname(v) {
824 // default is to just do a number of rings query:
825 this->setDescription("AtomHasProp");
826 this->setDataFunc(nullptr);
827 };
828
Match(const TargetPtr what)829 virtual bool Match(const TargetPtr what) const {
830 bool res = what->hasProp(propname);
831 if (this->getNegation()) {
832 res = !res;
833 }
834 return res;
835 }
836
837 //! returns a copy of this query
copy()838 Queries::Query<int, TargetPtr, true> *copy() const {
839 HasPropQuery *res = new HasPropQuery(this->propname);
840 res->setNegation(this->getNegation());
841 res->d_description = this->d_description;
842 return res;
843 }
844 };
845
846 typedef Queries::EqualityQuery<int, Atom const *, true> ATOM_PROP_QUERY;
847 typedef Queries::EqualityQuery<int, Bond const *, true> BOND_PROP_QUERY;
848
849 //! returns a Query for matching atoms that have a particular property
850 template <class Target>
makeHasPropQuery(const std::string & property)851 Queries::EqualityQuery<int, const Target *, true> *makeHasPropQuery(
852 const std::string &property) {
853 return new HasPropQuery<const Target *>(property);
854 }
855
856 // ! Query whether an atom has a property with a value
857 template <class TargetPtr, class T>
858 class HasPropWithValueQuery
859 : public Queries::EqualityQuery<int, TargetPtr, true> {
860 std::string propname;
861 T val;
862 T tolerance;
863
864 public:
HasPropWithValueQuery()865 HasPropWithValueQuery()
866 : Queries::EqualityQuery<int, TargetPtr, true>(), propname(), val() {
867 // default is to just do a number of rings query:
868 this->setDescription("HasPropWithValue");
869 this->setDataFunc(0);
870 };
871 explicit HasPropWithValueQuery(const std::string &prop, const T &v,
872 const T &tol = 0.0)
873 : Queries::EqualityQuery<int, TargetPtr, true>(),
874 propname(prop),
875 val(v),
876 tolerance(tol) {
877 // default is to just do a number of rings query:
878 this->setDescription("HasPropWithValue");
879 this->setDataFunc(nullptr);
880 };
881
Match(const TargetPtr what)882 virtual bool Match(const TargetPtr what) const {
883 bool res = what->hasProp(propname);
884 if (res) {
885 try {
886 T atom_val = what->template getProp<T>(propname);
887 res = Queries::queryCmp(atom_val, this->val, this->tolerance) == 0;
888 } catch (KeyErrorException &) {
889 res = false;
890 } catch (boost::bad_any_cast &) {
891 res = false;
892 }
893 #ifdef __GNUC__
894 #if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2))
895 catch (...) {
896 // catch all -- this is currently necessary to
897 // trap some bugs in boost+gcc configurations
898 // Normally, this is not the correct thing to
899 // do, but the only exception above is due
900 // to the boost any_cast which is trapped
901 // by the Boost python wrapper when it shouldn't
902 // be.
903 res = false;
904 }
905 #endif
906 #endif
907 }
908 if (this->getNegation()) {
909 res = !res;
910 }
911 return res;
912 }
913
914 //! returns a copy of this query
copy()915 Queries::Query<int, TargetPtr, true> *copy() const {
916 HasPropWithValueQuery *res =
917 new HasPropWithValueQuery(this->propname, this->val, this->tolerance);
918 res->setNegation(this->getNegation());
919 res->d_description = this->d_description;
920 return res;
921 }
922 };
923
924 template <class TargetPtr>
925 class HasPropWithValueQuery<TargetPtr, std::string>
926 : public Queries::EqualityQuery<int, TargetPtr, true> {
927 std::string propname;
928 std::string val;
929
930 public:
HasPropWithValueQuery()931 HasPropWithValueQuery()
932 : Queries::EqualityQuery<int, TargetPtr, true>(), propname(), val() {
933 // default is to just do a number of rings query:
934 this->setDescription("HasPropWithValue");
935 this->setDataFunc(0);
936 };
937 explicit HasPropWithValueQuery(const std::string &prop, const std::string &v,
938 const std::string &tol = "")
939 : Queries::EqualityQuery<int, TargetPtr, true>(), propname(prop), val(v) {
940 RDUNUSED_PARAM(tol);
941 // default is to just do a number of rings query:
942 this->setDescription("HasPropWithValue");
943 this->setDataFunc(nullptr);
944 };
945
Match(const TargetPtr what)946 virtual bool Match(const TargetPtr what) const {
947 bool res = what->hasProp(propname);
948 if (res) {
949 try {
950 std::string atom_val = what->template getProp<std::string>(propname);
951 res = atom_val == this->val;
952 } catch (KeyErrorException &) {
953 res = false;
954 } catch (boost::bad_any_cast &) {
955 res = false;
956 }
957 #ifdef __GNUC__
958 #if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2))
959 catch (...) {
960 // catch all -- this is currently necessary to
961 // trap some bugs in boost+gcc configurations
962 // Normally, this is not the correct thing to
963 // do, but the only exception above is due
964 // to the boost any_cast which is trapped
965 // by the Boost python wrapper when it shouldn't
966 // be.
967 res = false;
968 }
969 #endif
970 #endif
971 }
972 if (this->getNegation()) {
973 res = !res;
974 }
975 return res;
976 }
977
978 //! returns a copy of this query
copy()979 Queries::Query<int, TargetPtr, true> *copy() const {
980 HasPropWithValueQuery<TargetPtr, std::string> *res =
981 new HasPropWithValueQuery<TargetPtr, std::string>(this->propname,
982 this->val);
983 res->setNegation(this->getNegation());
984 res->d_description = this->d_description;
985 return res;
986 }
987 };
988
989 template <class TargetPtr>
990 class HasPropWithValueQuery<TargetPtr, ExplicitBitVect>
991 : public Queries::EqualityQuery<int, TargetPtr, true> {
992 std::string propname;
993 ExplicitBitVect val;
994 float tol{0.0};
995
996 public:
HasPropWithValueQuery()997 HasPropWithValueQuery()
998 : Queries::EqualityQuery<int, TargetPtr, true>(), propname(), val() {
999 this->setDescription("HasPropWithValue");
1000 this->setDataFunc(0);
1001 };
1002
1003 explicit HasPropWithValueQuery(const std::string &prop,
1004 const ExplicitBitVect &v, float tol = 0.0)
1005 : Queries::EqualityQuery<int, TargetPtr, true>(),
1006 propname(prop),
1007 val(v),
1008 tol(tol) {
1009 this->setDescription("HasPropWithValue");
1010 this->setDataFunc(nullptr);
1011 };
1012
Match(const TargetPtr what)1013 virtual bool Match(const TargetPtr what) const {
1014 bool res = what->hasProp(propname);
1015 if (res) {
1016 try {
1017 const ExplicitBitVect &bv =
1018 what->template getProp<const ExplicitBitVect &>(propname);
1019 const double tani = TanimotoSimilarity(val, bv);
1020 res = (1.0 - tani) <= tol;
1021 } catch (KeyErrorException &) {
1022 res = false;
1023 } catch (boost::bad_any_cast &) {
1024 res = false;
1025 }
1026 #ifdef __GNUC__
1027 #if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2))
1028 catch (...) {
1029 // catch all -- this is currently necessary to
1030 // trap some bugs in boost+gcc configurations
1031 // Normally, this is not the correct thing to
1032 // do, but the only exception above is due
1033 // to the boost any_cast which is trapped
1034 // by the Boost python wrapper when it shouldn't
1035 // be.
1036 res = false;
1037 }
1038 #endif
1039 #endif
1040 }
1041 if (this->getNegation()) {
1042 res = !res;
1043 }
1044 return res;
1045 }
1046
1047 //! returns a copy of this query
copy()1048 Queries::Query<int, TargetPtr, true> *copy() const {
1049 HasPropWithValueQuery<TargetPtr, ExplicitBitVect> *res =
1050 new HasPropWithValueQuery<TargetPtr, ExplicitBitVect>(
1051 this->propname, this->val, this->tol);
1052 res->setNegation(this->getNegation());
1053 res->d_description = this->d_description;
1054 return res;
1055 }
1056 };
1057
1058 template <class Target, class T>
1059 Queries::EqualityQuery<int, const Target *, true> *makePropQuery(
1060 const std::string &propname, const T &val, const T &tolerance = T()) {
1061 return new HasPropWithValueQuery<const Target *, T>(propname, val, tolerance);
1062 }
1063
1064 template <class Target>
1065 Queries::EqualityQuery<int, const Target *, true> *makePropQuery(
1066 const std::string &propname, const ExplicitBitVect &val,
1067 float tolerance = 0.0) {
1068 return new HasPropWithValueQuery<const Target *, ExplicitBitVect>(
1069 propname, val, tolerance);
1070 }
1071
1072 RDKIT_GRAPHMOL_EXPORT bool isComplexQuery(const Bond *b);
1073 RDKIT_GRAPHMOL_EXPORT bool isComplexQuery(const Atom *a);
1074 RDKIT_GRAPHMOL_EXPORT bool isAtomAromatic(const Atom *a);
1075 RDKIT_GRAPHMOL_EXPORT bool isAtomListQuery(const Atom *a);
1076 RDKIT_GRAPHMOL_EXPORT void getAtomListQueryVals(const Atom::QUERYATOM_QUERY *q,
1077 std::vector<int> &vals);
1078
1079 namespace QueryOps {
1080 RDKIT_GRAPHMOL_EXPORT void completeMolQueries(
1081 RWMol *mol, unsigned int magicVal = 0xDEADBEEF);
1082 RDKIT_GRAPHMOL_EXPORT Atom *replaceAtomWithQueryAtom(RWMol *mol, Atom *atom);
1083
1084 RDKIT_GRAPHMOL_EXPORT bool hasBondTypeQuery(
1085 const Queries::Query<int, Bond const *, true> &qry);
hasBondTypeQuery(const Bond & bond)1086 inline bool hasBondTypeQuery(const Bond &bond) {
1087 if (!bond.hasQuery()) {
1088 return false;
1089 }
1090 return hasBondTypeQuery(*bond.getQuery());
1091 }
1092 RDKIT_GRAPHMOL_EXPORT bool hasComplexBondTypeQuery(
1093 const Queries::Query<int, Bond const *, true> &qry);
hasComplexBondTypeQuery(const Bond & bond)1094 inline bool hasComplexBondTypeQuery(const Bond &bond) {
1095 if (!bond.hasQuery()) {
1096 return false;
1097 }
1098 return hasComplexBondTypeQuery(*bond.getQuery());
1099 }
1100
1101 } // namespace QueryOps
1102 } // namespace RDKit
1103 #endif
1104