// // Copyright (C) 2018-2025 Boran Adas and other RDKit contributors // // @@ 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 #include #include #include #include #include #include namespace RDKit { namespace TopologicalTorsion { using namespace AtomPairs; TopologicalTorsionArguments::TopologicalTorsionArguments( const bool includeChirality, const uint32_t torsionAtomCount, const bool countSimulation, const std::vector countBounds, const std::uint32_t fpSize) : FingerprintArguments(countSimulation, countBounds, fpSize, 1, includeChirality), d_torsionAtomCount(torsionAtomCount) {}; template OutputType TopologicalTorsionEnvGenerator::getResultSize() const { OutputType result = 1; return (result << (( dynamic_cast( this->dp_fingerprintArguments) ->d_torsionAtomCount * (codeSize + (dynamic_cast( this->dp_fingerprintArguments) ->df_includeChirality ? numChiralBits : 0))))); }; std::string TopologicalTorsionArguments::infoString() const { return "TopologicalTorsionArguments torsionAtomCount=" + std::to_string(d_torsionAtomCount) + " onlyShortestPaths=" + std::to_string(df_onlyShortestPaths); }; void TopologicalTorsionArguments::toJSON( boost::property_tree::ptree &pt) const { pt.put("type", "TopologicalTorsionArguments"); pt.put("torsionAtomCount", d_torsionAtomCount); pt.put("onlyShortestPaths", df_onlyShortestPaths); FingerprintArguments::toJSON(pt); } void TopologicalTorsionArguments::fromJSON( const boost::property_tree::ptree &pt) { d_torsionAtomCount = pt.get("torsionAtomCount", d_torsionAtomCount); df_onlyShortestPaths = pt.get("onlyShortestPaths", df_onlyShortestPaths); FingerprintArguments::fromJSON(pt); } template void TopologicalTorsionAtomEnv::updateAdditionalOutput( AdditionalOutput *additionalOutput, size_t bitId) const { PRECONDITION(additionalOutput, "bad output pointer"); if (additionalOutput->atomToBits || additionalOutput->atomCounts) { for (auto aid : d_atomPath) { if (additionalOutput->atomToBits) { additionalOutput->atomToBits->at(aid).push_back(bitId); } if (additionalOutput->atomCounts) { additionalOutput->atomCounts->at(aid)++; } } } if (additionalOutput->bitPaths) { (*additionalOutput->bitPaths)[bitId].push_back(d_atomPath); } if (additionalOutput->atomsPerBit) { (*additionalOutput->atomsPerBit)[bitId].push_back(d_atomPath); } } template OutputType TopologicalTorsionAtomEnv::getBitId( FingerprintArguments *, // arguments const std::vector *, // atomInvariants const std::vector *, // bondInvariants AdditionalOutput *, // additionalOutput, const bool, // hashResults const std::uint64_t // fpSize ) const { return d_bitId; }; template std::vector *> TopologicalTorsionEnvGenerator::getEnvironments( const ROMol &mol, FingerprintArguments *arguments, const std::vector *fromAtoms, const std::vector *ignoreAtoms, const int, // confId const AdditionalOutput *, // additionalOutput const std::vector *atomInvariants, const std::vector *, // bondInvariants const bool hashResults) const { auto *topologicalTorsionArguments = dynamic_cast(arguments); std::vector *> result; boost::dynamic_bitset<> *fromAtomsBV = nullptr; if (fromAtoms) { fromAtomsBV = new boost::dynamic_bitset<>(mol.getNumAtoms()); for (auto fAt : *fromAtoms) { fromAtomsBV->set(fAt); } } boost::dynamic_bitset<> *ignoreAtomsBV = nullptr; if (ignoreAtoms) { ignoreAtomsBV = new boost::dynamic_bitset<>(mol.getNumAtoms()); for (auto fAt : *ignoreAtoms) { ignoreAtomsBV->set(fAt); } } boost::dynamic_bitset<> pAtoms(mol.getNumAtoms()); bool useBonds = false; bool useHs = false; int rootedAtAtom = -1; PATH_LIST paths = findAllPathsOfLengthN( mol, topologicalTorsionArguments->d_torsionAtomCount, useBonds, useHs, rootedAtAtom, topologicalTorsionArguments->df_onlyShortestPaths); for (PATH_LIST::const_iterator pathIt = paths.begin(); pathIt != paths.end(); ++pathIt) { bool keepIt = true; if (fromAtomsBV) { keepIt = false; } std::vector pathCodes; const PATH_TYPE &path = *pathIt; if (fromAtomsBV) { if (fromAtomsBV->test(static_cast(path.front())) || fromAtomsBV->test(static_cast(path.back()))) { keepIt = true; } } if (keepIt && ignoreAtomsBV) { for (int pElem : path) { if (ignoreAtomsBV->test(pElem)) { keepIt = false; break; } } } if (keepIt) { pAtoms.reset(); for (auto pIt = path.begin(); pIt < path.end(); ++pIt) { // look for a cycle that doesn't start at the first atom // we can't effectively canonicalize these at the moment // (was github #811) if (pIt != path.begin() && *pIt != *(path.begin()) && pAtoms[*pIt]) { pathCodes.clear(); break; } pAtoms.set(*pIt); unsigned int code = (*atomInvariants)[*pIt] % ((1 << codeSize) - 1) + 1; // subtract off the branching number: if (pIt != path.begin() && pIt + 1 != path.end()) { --code; } pathCodes.push_back(code); } if (pathCodes.size()) { OutputType code; if (hashResults) { code = getTopologicalTorsionHash(pathCodes); } else { code = getTopologicalTorsionCode( pathCodes, topologicalTorsionArguments->df_includeChirality); } result.push_back(new TopologicalTorsionAtomEnv(code, path)); } } } delete fromAtomsBV; delete ignoreAtomsBV; return result; }; template std::string TopologicalTorsionEnvGenerator::infoString() const { return "TopologicalTorsionEnvGenerator"; }; template void TopologicalTorsionEnvGenerator::toJSON( boost::property_tree::ptree &pt) const { pt.put("type", "TopologicalTorsionEnvGenerator"); AtomEnvironmentGenerator::toJSON(pt); }; template void TopologicalTorsionEnvGenerator::fromJSON( const boost::property_tree::ptree &pt) { AtomEnvironmentGenerator::fromJSON(pt); }; template FingerprintGenerator *getTopologicalTorsionGenerator( const TopologicalTorsionArguments &args, AtomInvariantsGenerator *atomInvariantsGenerator, const bool ownsAtomInvGen) { auto *envGenerator = new TopologicalTorsionEnvGenerator(); bool ownsAtomInvGenerator = ownsAtomInvGen; if (!atomInvariantsGenerator) { atomInvariantsGenerator = new AtomPair::AtomPairAtomInvGenerator(args.df_includeChirality, true); ownsAtomInvGenerator = true; } return new FingerprintGenerator( envGenerator, new TopologicalTorsionArguments(args), atomInvariantsGenerator, nullptr, ownsAtomInvGenerator, false); }; template FingerprintGenerator *getTopologicalTorsionGenerator( bool includeChirality, uint32_t torsionAtomCount, AtomInvariantsGenerator *atomInvariantsGenerator, bool countSimulation, std::uint32_t fpSize, std::vector countBounds, bool ownsAtomInvGen) { TopologicalTorsionArguments arguments(includeChirality, torsionAtomCount, countSimulation, countBounds, fpSize); return getTopologicalTorsionGenerator( arguments, atomInvariantsGenerator, ownsAtomInvGen); }; // Topological torsion fingerprint does not support 32 bit output yet template RDKIT_FINGERPRINTS_EXPORT FingerprintGenerator * getTopologicalTorsionGenerator(bool includeChirality, uint32_t torsionAtomCount, AtomInvariantsGenerator *atomInvariantsGenerator, bool countSimulation, std::uint32_t fpSize, std::vector countBounds, bool ownsAtomInvGen); template RDKIT_FINGERPRINTS_EXPORT FingerprintGenerator * getTopologicalTorsionGenerator(const TopologicalTorsionArguments &, AtomInvariantsGenerator *, const bool); } // namespace TopologicalTorsion } // namespace RDKit