mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-04 21:54:27 +08:00
* atoms: radical electrons and presence of a chiral tag * bonds: presence of stereo * add new atom queries to python wrapper * add queries for missing atom chiral tags
504 lines
14 KiB
C++
504 lines
14 KiB
C++
// $Id$
|
|
//
|
|
// Copyright (C) 2003-2008 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.
|
|
//
|
|
#include "QueryOps.h"
|
|
#include <algorithm>
|
|
#include <RDGeneral/types.h>
|
|
|
|
namespace RDKit {
|
|
|
|
// common general queries
|
|
|
|
//! returns a Query for matching atoms with a particular number of ring bonds
|
|
ATOM_EQUALS_QUERY *makeAtomRingBondCountQuery(int what) {
|
|
ATOM_EQUALS_QUERY *res = new AtomRingQuery(what);
|
|
res->setDescription("AtomRingBondCount");
|
|
res->setDataFunc(queryAtomRingBondCount);
|
|
return res;
|
|
};
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomInRingOfSizeQuery(int tgt) {
|
|
RANGE_CHECK(3, tgt, 20);
|
|
ATOM_EQUALS_QUERY *res = new ATOM_EQUALS_QUERY;
|
|
res->setVal(tgt);
|
|
switch (tgt) {
|
|
case 3:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<3>);
|
|
break;
|
|
case 4:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<4>);
|
|
break;
|
|
case 5:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<5>);
|
|
break;
|
|
case 6:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<6>);
|
|
break;
|
|
case 7:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<7>);
|
|
break;
|
|
case 8:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<8>);
|
|
break;
|
|
case 9:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<9>);
|
|
break;
|
|
case 10:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<10>);
|
|
break;
|
|
case 11:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<11>);
|
|
break;
|
|
case 12:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<12>);
|
|
break;
|
|
case 13:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<13>);
|
|
break;
|
|
case 14:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<14>);
|
|
break;
|
|
case 15:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<15>);
|
|
break;
|
|
case 16:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<16>);
|
|
break;
|
|
case 17:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<17>);
|
|
break;
|
|
case 18:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<18>);
|
|
break;
|
|
case 19:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<19>);
|
|
break;
|
|
case 20:
|
|
res->setDataFunc(queryAtomIsInRingOfSize<20>);
|
|
break;
|
|
}
|
|
|
|
res->setDescription("AtomRingSize");
|
|
return res;
|
|
}
|
|
BOND_EQUALS_QUERY *makeBondInRingOfSizeQuery(int tgt) {
|
|
RANGE_CHECK(3, tgt, 20);
|
|
BOND_EQUALS_QUERY *res = new BOND_EQUALS_QUERY;
|
|
res->setVal(tgt);
|
|
switch (tgt) {
|
|
case 3:
|
|
res->setDataFunc(queryBondIsInRingOfSize<3>);
|
|
break;
|
|
case 4:
|
|
res->setDataFunc(queryBondIsInRingOfSize<4>);
|
|
break;
|
|
case 5:
|
|
res->setDataFunc(queryBondIsInRingOfSize<5>);
|
|
break;
|
|
case 6:
|
|
res->setDataFunc(queryBondIsInRingOfSize<6>);
|
|
break;
|
|
case 7:
|
|
res->setDataFunc(queryBondIsInRingOfSize<7>);
|
|
break;
|
|
case 8:
|
|
res->setDataFunc(queryBondIsInRingOfSize<8>);
|
|
break;
|
|
case 9:
|
|
res->setDataFunc(queryBondIsInRingOfSize<9>);
|
|
break;
|
|
case 10:
|
|
res->setDataFunc(queryBondIsInRingOfSize<10>);
|
|
break;
|
|
case 11:
|
|
res->setDataFunc(queryBondIsInRingOfSize<11>);
|
|
break;
|
|
case 12:
|
|
res->setDataFunc(queryBondIsInRingOfSize<12>);
|
|
break;
|
|
case 13:
|
|
res->setDataFunc(queryBondIsInRingOfSize<13>);
|
|
break;
|
|
case 14:
|
|
res->setDataFunc(queryBondIsInRingOfSize<14>);
|
|
break;
|
|
case 15:
|
|
res->setDataFunc(queryBondIsInRingOfSize<15>);
|
|
break;
|
|
case 16:
|
|
res->setDataFunc(queryBondIsInRingOfSize<16>);
|
|
break;
|
|
case 17:
|
|
res->setDataFunc(queryBondIsInRingOfSize<17>);
|
|
break;
|
|
case 18:
|
|
res->setDataFunc(queryBondIsInRingOfSize<18>);
|
|
break;
|
|
case 19:
|
|
res->setDataFunc(queryBondIsInRingOfSize<19>);
|
|
break;
|
|
case 20:
|
|
res->setDataFunc(queryBondIsInRingOfSize<20>);
|
|
break;
|
|
}
|
|
res->setDescription("BondRingSize");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomMinRingSizeQuery(int tgt) {
|
|
RANGE_CHECK(3, tgt, 20);
|
|
ATOM_EQUALS_QUERY *res = new ATOM_EQUALS_QUERY;
|
|
res->setVal(tgt);
|
|
res->setDataFunc(queryAtomMinRingSize);
|
|
res->setDescription("AtomMinRingSize");
|
|
return res;
|
|
}
|
|
BOND_EQUALS_QUERY *makeBondMinRingSizeQuery(int tgt) {
|
|
RANGE_CHECK(3, tgt, 20);
|
|
BOND_EQUALS_QUERY *res = new BOND_EQUALS_QUERY;
|
|
res->setVal(tgt);
|
|
res->setDataFunc(queryBondMinRingSize);
|
|
res->setDescription("BondMinRingSize");
|
|
return res;
|
|
}
|
|
|
|
unsigned int queryAtomBondProduct(Atom const *at) {
|
|
ROMol::OEDGE_ITER beg, end;
|
|
boost::tie(beg, end) = at->getOwningMol().getAtomBonds(at);
|
|
unsigned int prod = 1;
|
|
while (beg != end) {
|
|
prod *= static_cast<unsigned int>(
|
|
firstThousandPrimes[at->getOwningMol()[*beg]->getBondType()]);
|
|
++beg;
|
|
}
|
|
return prod;
|
|
}
|
|
unsigned int queryAtomAllBondProduct(Atom const *at) {
|
|
ROMol::OEDGE_ITER beg, end;
|
|
|
|
boost::tie(beg, end) = at->getOwningMol().getAtomBonds(at);
|
|
unsigned int prod = 1;
|
|
while (beg != end) {
|
|
prod *= static_cast<unsigned int>(
|
|
firstThousandPrimes[at->getOwningMol()[*beg]->getBondType()]);
|
|
++beg;
|
|
}
|
|
for (unsigned int i = 0; i < at->getTotalNumHs(); i++) {
|
|
prod *= static_cast<unsigned int>(firstThousandPrimes[Bond::SINGLE]);
|
|
}
|
|
return prod;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomImplicitValenceQuery(int what) {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(what, queryAtomImplicitValence);
|
|
res->setDescription("AtomImplicitValence");
|
|
return res;
|
|
}
|
|
ATOM_EQUALS_QUERY *makeAtomExplicitValenceQuery(int what) {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(what, queryAtomExplicitValence);
|
|
res->setDescription("AtomExplicitValence");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomTotalValenceQuery(int what) {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(what, queryAtomTotalValence);
|
|
res->setDescription("AtomTotalValence");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomNumQuery(int what) {
|
|
return makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(what, queryAtomNum,
|
|
"AtomAtomicNum");
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomExplicitDegreeQuery(int what) {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(what, queryAtomExplicitDegree);
|
|
res->setDescription("AtomExplicitDegree");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomTotalDegreeQuery(int what) {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(what, queryAtomTotalDegree);
|
|
res->setDescription("AtomTotalDegree");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomHCountQuery(int what) {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(what, queryAtomHCount);
|
|
res->setDescription("AtomHCount");
|
|
return res;
|
|
}
|
|
ATOM_EQUALS_QUERY *makeAtomImplicitHCountQuery(int what) {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(what, queryAtomImplicitHCount);
|
|
res->setDescription("AtomImplicitHCount");
|
|
return res;
|
|
}
|
|
ATOM_EQUALS_QUERY *makeAtomHasImplicitHQuery() {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(true, queryAtomHasImplicitH);
|
|
res->setDescription("AtomHasImplicitH");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomAromaticQuery() {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(true, queryAtomAromatic);
|
|
res->setDescription("AtomIsAromatic");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomAliphaticQuery() {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(true, queryAtomAliphatic);
|
|
res->setDescription("AtomIsAliphatic");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomUnsaturatedQuery() {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(true, queryAtomUnsaturated);
|
|
res->setDescription("AtomUnsaturated");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomMassQuery(int what) {
|
|
ATOM_EQUALS_QUERY *res = makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(
|
|
massIntegerConversionFactor * what, queryAtomMass);
|
|
res->setDescription("AtomMass");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomIsotopeQuery(int what) {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(what, queryAtomIsotope);
|
|
res->setDescription("AtomIsotope");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomFormalChargeQuery(int what) {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(what, queryAtomFormalCharge);
|
|
res->setDescription("AtomFormalCharge");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomHybridizationQuery(int what) {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(what, queryAtomHybridization);
|
|
res->setDescription("AtomHybridization");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomNumRadicalElectronsQuery(int what) {
|
|
ATOM_EQUALS_QUERY *res = makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(
|
|
what, queryAtomNumRadicalElectrons);
|
|
res->setDescription("AtomNumRadicalElectrons");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomHasChiralTagQuery() {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(true, queryAtomHasChiralTag);
|
|
res->setDescription("AtomHasChiralTag");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomMissingChiralTagQuery() {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(true, queryAtomMissingChiralTag);
|
|
res->setDescription("AtomMissingChiralTag");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomInRingQuery() {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(true, queryIsAtomInRing);
|
|
res->setDescription("AtomInRing");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomHasRingBondQuery() {
|
|
ATOM_EQUALS_QUERY *res =
|
|
makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(true, queryAtomHasRingBond);
|
|
res->setDescription("AtomHasRingBond");
|
|
return res;
|
|
}
|
|
|
|
ATOM_EQUALS_QUERY *makeAtomInNRingsQuery(int what) {
|
|
ATOM_EQUALS_QUERY *res;
|
|
res = makeAtomSimpleQuery<ATOM_EQUALS_QUERY>(what, queryIsAtomInNRings);
|
|
res->setDescription("AtomInNRings");
|
|
return res;
|
|
}
|
|
|
|
BOND_EQUALS_QUERY *makeBondOrderEqualsQuery(Bond::BondType what) {
|
|
BOND_EQUALS_QUERY *res = new BOND_EQUALS_QUERY;
|
|
res->setVal(what);
|
|
res->setDataFunc(queryBondOrder);
|
|
res->setDescription("BondOrder");
|
|
return res;
|
|
}
|
|
|
|
BOND_EQUALS_QUERY *makeBondDirEqualsQuery(Bond::BondDir what) {
|
|
BOND_EQUALS_QUERY *res = new BOND_EQUALS_QUERY;
|
|
res->setVal(what);
|
|
res->setDataFunc(queryBondDir);
|
|
res->setDescription("BondDir");
|
|
return res;
|
|
}
|
|
|
|
BOND_EQUALS_QUERY *makeBondHasStereoQuery() {
|
|
BOND_EQUALS_QUERY *res = new BOND_EQUALS_QUERY;
|
|
res->setVal(true);
|
|
res->setDataFunc(queryBondHasStereo);
|
|
res->setDescription("BondStereo");
|
|
return res;
|
|
}
|
|
|
|
BOND_EQUALS_QUERY *makeBondIsInRingQuery() {
|
|
BOND_EQUALS_QUERY *res = new BOND_EQUALS_QUERY;
|
|
res->setVal(true);
|
|
res->setDataFunc(queryIsBondInRing);
|
|
res->setDescription("BondInRing");
|
|
return res;
|
|
}
|
|
|
|
BOND_EQUALS_QUERY *makeBondInNRingsQuery(int what) {
|
|
BOND_EQUALS_QUERY *res = new BOND_EQUALS_QUERY;
|
|
res->setVal(what);
|
|
res->setDataFunc(queryIsBondInNRings);
|
|
res->setDescription("BondInNRings");
|
|
return res;
|
|
}
|
|
|
|
BOND_NULL_QUERY *makeBondNullQuery() {
|
|
BOND_NULL_QUERY *res = new BOND_NULL_QUERY;
|
|
res->setDataFunc(nullDataFun);
|
|
res->setMatchFunc(nullQueryFun);
|
|
res->setDescription("BondNull");
|
|
return res;
|
|
}
|
|
|
|
ATOM_NULL_QUERY *makeAtomNullQuery() {
|
|
ATOM_NULL_QUERY *res = new ATOM_NULL_QUERY;
|
|
res->setDataFunc(nullDataFun);
|
|
res->setMatchFunc(nullQueryFun);
|
|
res->setDescription("AtomNull");
|
|
return res;
|
|
}
|
|
|
|
bool isComplexQuery(const Bond *b) {
|
|
if (!b->hasQuery()) return false;
|
|
// negated things are always complex:
|
|
if (b->getQuery()->getNegation()) return true;
|
|
std::string descr = b->getQuery()->getDescription();
|
|
if (descr == "BondOrder") return false;
|
|
if (descr == "BondAnd" || descr == "BondXor") return true;
|
|
if (descr == "BondOr") {
|
|
// detect the types of queries that appear for unspecified bonds in SMARTS:
|
|
if (b->getQuery()->endChildren() - b->getQuery()->beginChildren() == 2) {
|
|
for (Bond::QUERYBOND_QUERY::CHILD_VECT_CI child =
|
|
b->getQuery()->beginChildren();
|
|
child != b->getQuery()->endChildren(); ++child) {
|
|
if ((*child)->getDescription() != "BondOrder" ||
|
|
(*child)->getNegation())
|
|
return true;
|
|
if (static_cast<BOND_EQUALS_QUERY *>(child->get())->getVal() !=
|
|
Bond::SINGLE &&
|
|
static_cast<BOND_EQUALS_QUERY *>(child->get())->getVal() !=
|
|
Bond::AROMATIC)
|
|
return true;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool _complexQueryHelper(Atom::QUERYATOM_QUERY const *query, bool &hasAtNum) {
|
|
if (!query) return false;
|
|
if (query->getNegation()) return true;
|
|
std::string descr = query->getDescription();
|
|
// std::cerr<<" |"<<descr;
|
|
if (descr == "AtomAtomicNum") {
|
|
hasAtNum = true;
|
|
return false;
|
|
}
|
|
if (descr == "AtomOr" || descr == "AtomXor") return true;
|
|
if (descr == "AtomAnd") {
|
|
Queries::Query<int, Atom const *, true>::CHILD_VECT_CI childIt =
|
|
query->beginChildren();
|
|
while (childIt != query->endChildren()) {
|
|
if (_complexQueryHelper(childIt->get(), hasAtNum)) return true;
|
|
++childIt;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
bool isComplexQuery(const Atom *a) {
|
|
if (!a->hasQuery()) return false;
|
|
// std::cerr<<"\n"<<a->getIdx();
|
|
// negated things are always complex:
|
|
if (a->getQuery()->getNegation()) return true;
|
|
std::string descr = a->getQuery()->getDescription();
|
|
// std::cerr<<" "<<descr;
|
|
if (descr == "AtomAtomicNum") return false;
|
|
if (descr == "AtomOr" || descr == "AtomXor") return true;
|
|
if (descr == "AtomAnd") {
|
|
bool hasAtNum = false;
|
|
if (_complexQueryHelper(a->getQuery(), hasAtNum)) return true;
|
|
if (hasAtNum)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
bool isAtomAromatic(const Atom *a) {
|
|
bool res = false;
|
|
if (!a->hasQuery()) {
|
|
res = a->getIsAromatic();
|
|
} else {
|
|
std::string descr = a->getQuery()->getDescription();
|
|
if (descr == "AtomAtomicNum") {
|
|
res = a->getIsAromatic();
|
|
} else if (descr == "AtomIsAromatic") {
|
|
res = true;
|
|
if (a->getQuery()->getNegation()) res = !res;
|
|
} else if (descr == "AtomIsAliphatic") {
|
|
res = false;
|
|
if (a->getQuery()->getNegation()) res = !res;
|
|
} else if (descr == "AtomAnd") {
|
|
Queries::Query<int, Atom const *, true>::CHILD_VECT_CI childIt =
|
|
a->getQuery()->beginChildren();
|
|
if ((*childIt)->getDescription() == "AtomAtomicNum") {
|
|
if (a->getQuery()->getNegation()) {
|
|
res = false;
|
|
} else if ((*(childIt + 1))->getDescription() == "AtomIsAliphatic") {
|
|
res = false;
|
|
} else if ((*(childIt + 1))->getDescription() == "AtomIsAromatic") {
|
|
res = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
};
|