mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-03 21:44:30 +08:00
* Cannot push_back std::string to boost json array `boost::json::array.push_back` expects a `value` * prefer emplace_back to avoid casting * Ensure every MINIMAL_LIB option is tested in CI Also remove Chemdraw support from the compilation. This does not change the final size of the output (not exported anyways) but it reduces the compilation time by 1 min (-10% on my local machine) * Expose MMPA with other options * Fix MMPA compilation: Implicitly binding raw pointers is illegal Applying same pattern as in `get_frags_helper`
1041 lines
32 KiB
C++
1041 lines
32 KiB
C++
//
|
|
//
|
|
// Copyright (C) 2019-2021 Greg Landrum 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 <string>
|
|
#include "minilib.h"
|
|
#include "common.h"
|
|
|
|
#include <RDGeneral/versions.h>
|
|
#include <GraphMol/RDKitBase.h>
|
|
#include <GraphMol/MolPickler.h>
|
|
#include <GraphMol/Chirality.h>
|
|
#include <GraphMol/SmilesParse/SmilesParse.h>
|
|
#include <GraphMol/SmilesParse/SmilesJSONParsers.h>
|
|
#include <GraphMol/SmilesParse/SmartsWrite.h>
|
|
#include <GraphMol/FileParsers/FileParsers.h>
|
|
#include <GraphMol/MolDraw2D/MolDraw2D.h>
|
|
#include <GraphMol/MolDraw2D/MolDraw2DSVG.h>
|
|
#include <GraphMol/MolDraw2D/MolDraw2DUtils.h>
|
|
#include <GraphMol/Substruct/SubstructMatch.h>
|
|
#ifdef RDK_BUILD_MINIMAL_LIB_SUBSTRUCTLIBRARY
|
|
#include <GraphMol/SubstructLibrary/SubstructLibrary.h>
|
|
#endif
|
|
#ifdef RDK_BUILD_MINIMAL_LIB_MCS
|
|
#include <GraphMol/FMCS/FMCS.h>
|
|
#endif
|
|
#ifdef RDK_BUILD_MINIMAL_LIB_MOLZIP
|
|
#include <GraphMol/ChemTransforms/MolFragmenterJSONParser.h>
|
|
#endif
|
|
|
|
#include <GraphMol/Descriptors/Property.h>
|
|
#include <GraphMol/Descriptors/MolDescriptors.h>
|
|
#include <GraphMol/MolInterchange/MolInterchange.h>
|
|
#include <GraphMol/CIPLabeler/CIPLabeler.h>
|
|
#include <GraphMol/Abbreviations/Abbreviations.h>
|
|
#include <GraphMol/MolTransforms/MolTransforms.h>
|
|
#include <Geometry/Transform3D.h>
|
|
#include <DataStructs/BitOps.h>
|
|
#include <DataStructs/ExplicitBitVect.h>
|
|
#ifdef RDK_BUILD_MINIMAL_LIB_RGROUPDECOMP
|
|
#include <GraphMol/RGroupDecomposition/RGroupDecompJSONParsers.h>
|
|
#endif
|
|
|
|
#ifdef RDK_BUILD_INCHI_SUPPORT
|
|
#include <INCHI-API/inchi.h>
|
|
#endif
|
|
|
|
#include <boost/json.hpp>
|
|
|
|
namespace bj = boost::json;
|
|
|
|
using namespace RDKit;
|
|
|
|
namespace {
|
|
#ifdef RDK_BUILD_MINIMAL_LIB_SUBSTRUCTLIBRARY
|
|
static const char *NO_SUPPORT_FOR_PATTERN_FPS =
|
|
"This SubstructLibrary was built without support for pattern fps";
|
|
#endif
|
|
|
|
std::string mappingToJsonArray(const ROMol &mol) {
|
|
std::vector<unsigned int> atomMapping;
|
|
std::vector<unsigned int> bondMapping;
|
|
mol.getPropIfPresent(Abbreviations::common_properties::origAtomMapping,
|
|
atomMapping);
|
|
mol.getPropIfPresent(Abbreviations::common_properties::origBondMapping,
|
|
bondMapping);
|
|
bj::object doc;
|
|
bj::array bjAtoms;
|
|
for (auto i : atomMapping) {
|
|
bjAtoms.push_back(i);
|
|
}
|
|
doc["atoms"] = bjAtoms;
|
|
|
|
bj::array bjBonds;
|
|
for (auto i : bondMapping) {
|
|
bjBonds.push_back(i);
|
|
}
|
|
doc["bonds"] = bjBonds;
|
|
std::string res = bj::serialize(doc);
|
|
return res;
|
|
}
|
|
|
|
void remove_hs_common(RWMol &mol, const std::string &details_json) {
|
|
if (details_json.empty()) {
|
|
MolOps::removeAllHs(mol);
|
|
} else {
|
|
MolOps::RemoveHsParameters ps;
|
|
bool sanitize = true;
|
|
MinimalLib::updateRemoveHsParametersFromJSON(ps, sanitize,
|
|
details_json.c_str());
|
|
MolOps::removeHs(mol, ps, sanitize);
|
|
}
|
|
}
|
|
} // end of anonymous namespace
|
|
|
|
std::string JSMolBase::get_smiles() const { return MolToSmiles(get()); }
|
|
std::string JSMolBase::get_smiles(const std::string &details) const {
|
|
SmilesWriteParams params;
|
|
updateSmilesWriteParamsFromJSON(params, details);
|
|
return MolToSmiles(get(), params);
|
|
}
|
|
std::string JSMolBase::get_cxsmiles() const { return MolToCXSmiles(get()); }
|
|
std::string JSMolBase::get_cxsmiles(const std::string &details) const {
|
|
SmilesWriteParams params;
|
|
updateSmilesWriteParamsFromJSON(params, details);
|
|
std::uint32_t cxSmilesFields = SmilesWrite::CXSmilesFields::CX_ALL;
|
|
unsigned int restoreBondDirs = RestoreBondDirOptionClear;
|
|
updateCXSmilesFieldsFromJSON(cxSmilesFields, restoreBondDirs, details);
|
|
return MolToCXSmiles(get(), params, cxSmilesFields,
|
|
static_cast<RestoreBondDirOption>(restoreBondDirs));
|
|
}
|
|
std::string JSMolBase::get_smarts() const { return MolToSmarts(get()); }
|
|
std::string JSMolBase::get_smarts(const std::string &details) const {
|
|
SmilesWriteParams params;
|
|
updateSmilesWriteParamsFromJSON(params, details);
|
|
return MolToSmarts(get(), params.doIsomericSmiles, params.rootedAtAtom);
|
|
}
|
|
std::string JSMolBase::get_cxsmarts() const { return MolToCXSmarts(get()); }
|
|
std::string JSMolBase::get_cxsmarts(const std::string &details) const {
|
|
SmilesWriteParams params;
|
|
updateSmilesWriteParamsFromJSON(params, details);
|
|
return MolToCXSmarts(get(), params.doIsomericSmiles);
|
|
}
|
|
std::string JSMolBase::get_svg(int w, int h) const {
|
|
return MinimalLib::mol_to_svg(get(), w, h);
|
|
}
|
|
std::string JSMolBase::get_svg_with_highlights(
|
|
const std::string &details) const {
|
|
int w = d_defaultWidth;
|
|
int h = d_defaultHeight;
|
|
return MinimalLib::mol_to_svg(get(), w, h, details);
|
|
}
|
|
|
|
#ifdef RDK_BUILD_INCHI_SUPPORT
|
|
std::string JSMolBase::get_inchi(const std::string &options) const {
|
|
ExtraInchiReturnValues rv;
|
|
return MolToInchi(get(), rv, !options.empty() ? options.c_str() : nullptr);
|
|
}
|
|
#endif
|
|
std::string JSMolBase::get_molblock(const std::string &details) const {
|
|
return MinimalLib::molblock_helper(get(), details.c_str(),
|
|
MinimalLib::MDLVersion::AUTO);
|
|
}
|
|
std::string JSMolBase::get_v3Kmolblock(const std::string &details) const {
|
|
return MinimalLib::molblock_helper(get(), details.c_str(),
|
|
MinimalLib::MDLVersion::V3000);
|
|
}
|
|
std::string JSMolBase::get_v2Kmolblock(const std::string &details) const {
|
|
return MinimalLib::molblock_helper(get(), details.c_str(),
|
|
MinimalLib::MDLVersion::V2000);
|
|
}
|
|
std::string JSMolBase::get_json() const {
|
|
return MolInterchange::MolToJSONData(get());
|
|
}
|
|
|
|
std::string JSMolBase::get_pickle(const std::string &details) const {
|
|
unsigned int propFlags = PicklerOps::AllProps ^ PicklerOps::ComputedProps;
|
|
MinimalLib::updatePropertyPickleOptionsFromJSON(propFlags, details.c_str());
|
|
std::string pickle;
|
|
MolPickler::pickleMol(get(), pickle, propFlags);
|
|
return pickle;
|
|
}
|
|
|
|
std::string JSMolBase::get_substruct_match(const JSMolBase &q) const {
|
|
std::string res = "{}";
|
|
|
|
MatchVectType match;
|
|
if (SubstructMatch(get(), q.get(), match)) {
|
|
bj::object doc;
|
|
MinimalLib::get_sss_json(get(), q.get(), match, doc);
|
|
res = bj::serialize(doc);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
std::string JSMolBase::get_substruct_matches(const JSMolBase &q) const {
|
|
std::string res = "{}";
|
|
|
|
auto matches = SubstructMatch(get(), q.get());
|
|
if (!matches.empty()) {
|
|
bj::array doc;
|
|
|
|
for (const auto &match : matches) {
|
|
bj::object bjMatch;
|
|
MinimalLib::get_sss_json(get(), q.get(), match, bjMatch);
|
|
doc.push_back(bjMatch);
|
|
}
|
|
|
|
res = bj::serialize(doc);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
std::string JSMolBase::get_descriptors() const {
|
|
return MinimalLib::get_descriptors(get());
|
|
}
|
|
|
|
std::string JSMolBase::get_morgan_fp(const std::string &details) const {
|
|
auto fp = MinimalLib::morgan_fp_as_bitvect(get(), details.c_str());
|
|
std::string res = BitVectToText(*fp);
|
|
return res;
|
|
}
|
|
|
|
std::string JSMolBase::get_morgan_fp_as_binary_text(
|
|
const std::string &details) const {
|
|
auto fp = MinimalLib::morgan_fp_as_bitvect(get(), details.c_str());
|
|
std::string res = BitVectToBinaryText(*fp);
|
|
return res;
|
|
}
|
|
|
|
std::string JSMolBase::get_pattern_fp(const std::string &details) const {
|
|
auto fp = MinimalLib::pattern_fp_as_bitvect(get(), details.c_str());
|
|
std::string res = BitVectToText(*fp);
|
|
return res;
|
|
}
|
|
|
|
std::string JSMolBase::get_pattern_fp_as_binary_text(
|
|
const std::string &details) const {
|
|
auto fp = MinimalLib::pattern_fp_as_bitvect(get(), details.c_str());
|
|
std::string res = BitVectToBinaryText(*fp);
|
|
return res;
|
|
}
|
|
|
|
std::string JSMolBase::get_topological_torsion_fp(
|
|
const std::string &details) const {
|
|
auto fp =
|
|
MinimalLib::topological_torsion_fp_as_bitvect(get(), details.c_str());
|
|
std::string res = BitVectToText(*fp);
|
|
return res;
|
|
}
|
|
|
|
std::string JSMolBase::get_topological_torsion_fp_as_binary_text(
|
|
const std::string &details) const {
|
|
auto fp =
|
|
MinimalLib::topological_torsion_fp_as_bitvect(get(), details.c_str());
|
|
std::string res = BitVectToBinaryText(*fp);
|
|
return res;
|
|
}
|
|
|
|
std::string JSMolBase::get_rdkit_fp(const std::string &details) const {
|
|
auto fp = MinimalLib::rdkit_fp_as_bitvect(get(), details.c_str());
|
|
std::string res = BitVectToText(*fp);
|
|
return res;
|
|
}
|
|
|
|
std::string JSMolBase::get_rdkit_fp_as_binary_text(
|
|
const std::string &details) const {
|
|
auto fp = MinimalLib::rdkit_fp_as_bitvect(get(), details.c_str());
|
|
std::string res = BitVectToBinaryText(*fp);
|
|
return res;
|
|
}
|
|
|
|
std::string JSMolBase::get_atom_pair_fp(const std::string &details) const {
|
|
auto fp = MinimalLib::atom_pair_fp_as_bitvect(get(), details.c_str());
|
|
std::string res = BitVectToText(*fp);
|
|
return res;
|
|
}
|
|
|
|
std::string JSMolBase::get_atom_pair_fp_as_binary_text(
|
|
const std::string &details) const {
|
|
auto fp = MinimalLib::atom_pair_fp_as_bitvect(get(), details.c_str());
|
|
std::string res = BitVectToBinaryText(*fp);
|
|
return res;
|
|
}
|
|
|
|
std::string JSMolBase::get_maccs_fp() const {
|
|
auto fp = MinimalLib::maccs_fp_as_bitvect(get());
|
|
std::string res = BitVectToText(*fp);
|
|
return res;
|
|
}
|
|
|
|
std::string JSMolBase::get_maccs_fp_as_binary_text() const {
|
|
auto fp = MinimalLib::maccs_fp_as_bitvect(get());
|
|
std::string res = BitVectToBinaryText(*fp);
|
|
return res;
|
|
}
|
|
|
|
#ifdef RDK_BUILD_AVALON_SUPPORT
|
|
std::string get_avalon_fp(const std::string &details) const {
|
|
auto fp = MinimalLib::avalon_fp_as_bitvect(get(), details.c_str());
|
|
std::string res = BitVectToText(*fp);
|
|
return res;
|
|
}
|
|
|
|
std::string get_avalon_fp_as_binary_text(const std::string &details) const {
|
|
auto fp = MinimalLib::avalon_fp_as_bitvect(get(), details.c_str());
|
|
std::string res = BitVectToBinaryText(*fp);
|
|
return res;
|
|
}
|
|
#endif
|
|
|
|
std::string JSMolBase::get_stereo_tags() {
|
|
bj::object doc;
|
|
|
|
bool cleanIt = true;
|
|
bool force = true;
|
|
bool flagPossibleStereocenters = true;
|
|
MolOps::assignStereochemistry(get(), cleanIt, force,
|
|
flagPossibleStereocenters);
|
|
CIPLabeler::assignCIPLabels(get());
|
|
|
|
bj::array bjAtoms;
|
|
for (const auto atom : get().atoms()) {
|
|
std::string cip;
|
|
if (!atom->getPropIfPresent(common_properties::_CIPCode, cip)) {
|
|
if (atom->hasProp(common_properties::_ChiralityPossible)) {
|
|
cip = "?";
|
|
}
|
|
}
|
|
if (!cip.empty()) {
|
|
cip = "(" + cip + ")";
|
|
bj::array entry;
|
|
entry.push_back(atom->getIdx());
|
|
entry.push_back(cip.c_str());
|
|
bjAtoms.push_back(std::move(entry));
|
|
}
|
|
}
|
|
doc["CIP_atoms"] = bjAtoms;
|
|
|
|
bj::array bjBonds;
|
|
for (const auto bond : get().bonds()) {
|
|
std::string cip;
|
|
if (bond->getPropIfPresent(common_properties::_CIPCode, cip)) {
|
|
cip = "(" + cip + ")";
|
|
bj::array entry;
|
|
entry.push_back(bond->getBeginAtomIdx());
|
|
entry.push_back(bond->getEndAtomIdx());
|
|
entry.push_back(cip.c_str());
|
|
bjBonds.push_back(std::move(entry));
|
|
}
|
|
}
|
|
|
|
doc["CIP_bonds"] = bjBonds;
|
|
|
|
return bj::serialize(doc);
|
|
}
|
|
|
|
void JSMolBase::convert_to_aromatic_form() {
|
|
get().updatePropertyCache();
|
|
MolOps::setAromaticity(get());
|
|
}
|
|
|
|
std::string JSMolBase::get_aromatic_form() const {
|
|
RWMol molCopy(get());
|
|
molCopy.updatePropertyCache();
|
|
MolOps::setAromaticity(molCopy);
|
|
|
|
bool includeStereo = true;
|
|
int confId = -1;
|
|
bool kekulize = false;
|
|
return MolToMolBlock(molCopy, includeStereo, confId, kekulize);
|
|
}
|
|
|
|
void JSMolBase::convert_to_kekule_form() { MolOps::Kekulize(get()); }
|
|
|
|
std::string JSMolBase::get_kekule_form() const {
|
|
RWMol molCopy(get());
|
|
MolOps::Kekulize(molCopy);
|
|
|
|
bool includeStereo = true;
|
|
int confId = -1;
|
|
bool kekulize = true;
|
|
return MolToMolBlock(molCopy, includeStereo, confId, kekulize);
|
|
}
|
|
|
|
bool JSMolBase::set_new_coords(bool useCoordGen) {
|
|
#ifdef RDK_BUILD_COORDGEN_SUPPORT
|
|
bool oprefer = RDDepict::preferCoordGen;
|
|
RDDepict::preferCoordGen = useCoordGen;
|
|
#endif
|
|
RDDepict::compute2DCoords(get());
|
|
#ifdef RDK_BUILD_COORDGEN_SUPPORT
|
|
RDDepict::preferCoordGen = oprefer;
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
std::string JSMolBase::get_new_coords(bool useCoordGen) const {
|
|
RWMol molCopy(get());
|
|
|
|
#ifdef RDK_BUILD_COORDGEN_SUPPORT
|
|
bool oprefer = RDDepict::preferCoordGen;
|
|
RDDepict::preferCoordGen = useCoordGen;
|
|
#endif
|
|
RDDepict::compute2DCoords(molCopy);
|
|
#ifdef RDK_BUILD_COORDGEN_SUPPORT
|
|
RDDepict::preferCoordGen = oprefer;
|
|
#endif
|
|
|
|
return MolToMolBlock(molCopy);
|
|
}
|
|
|
|
bool JSMolBase::has_prop(const std::string &key) const {
|
|
return get().hasProp(key);
|
|
}
|
|
|
|
std::vector<std::string> JSMolBase::get_prop_list(bool includePrivate,
|
|
bool includeComputed) const {
|
|
return get().getPropList(includePrivate, includeComputed);
|
|
}
|
|
|
|
bool JSMolBase::set_prop(const std::string &key, const std::string &val,
|
|
bool computed) {
|
|
get().setProp(key, val, computed);
|
|
return true;
|
|
}
|
|
|
|
std::string JSMolBase::get_prop(const std::string &key) const {
|
|
if (!get().hasProp(key)) {
|
|
return "";
|
|
}
|
|
std::string val;
|
|
get().getProp(key, val);
|
|
return val;
|
|
}
|
|
|
|
bool JSMolBase::clear_prop(const std::string &key) {
|
|
bool res = get().hasProp(key);
|
|
if (res) {
|
|
get().clearProp(key);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
std::string JSMolBase::remove_hs(const std::string &details_json) const {
|
|
RWMol molCopy(get());
|
|
remove_hs_common(molCopy, details_json);
|
|
|
|
bool includeStereo = true;
|
|
int confId = -1;
|
|
bool kekulize = true;
|
|
return MolToMolBlock(molCopy, includeStereo, confId, kekulize);
|
|
}
|
|
|
|
bool JSMolBase::remove_hs_in_place(const std::string &details_json) {
|
|
remove_hs_common(get(), details_json);
|
|
MolOps::assignStereochemistry(get(), true, true);
|
|
return true;
|
|
}
|
|
|
|
std::string JSMolBase::add_hs() const {
|
|
RWMol molCopy(get());
|
|
MolOps::addHs(molCopy);
|
|
|
|
bool includeStereo = true;
|
|
int confId = -1;
|
|
bool kekulize = true;
|
|
return MolToMolBlock(molCopy, includeStereo, confId, kekulize);
|
|
}
|
|
|
|
bool JSMolBase::add_hs_in_place() {
|
|
bool addCoords = (get().getNumConformers() > 0);
|
|
MolOps::addHs(get(), false, addCoords);
|
|
MolOps::assignStereochemistry(get(), true, true);
|
|
return true;
|
|
}
|
|
|
|
std::string JSMolBase::condense_abbreviations(double maxCoverage,
|
|
bool useLinkers) {
|
|
if (!useLinkers) {
|
|
Abbreviations::condenseMolAbbreviations(
|
|
get(), Abbreviations::Utils::getDefaultAbbreviations(), maxCoverage);
|
|
} else {
|
|
Abbreviations::condenseMolAbbreviations(
|
|
get(), Abbreviations::Utils::getDefaultLinkers(), maxCoverage);
|
|
}
|
|
return mappingToJsonArray(get());
|
|
}
|
|
|
|
std::string JSMolBase::condense_abbreviations_from_defs(
|
|
const std::string &definitions, double maxCoverage, bool areLinkers) {
|
|
static std::string lastDefs = "";
|
|
static std::vector<Abbreviations::AbbreviationDefinition> abbrevs;
|
|
if (definitions != lastDefs) {
|
|
// yes, we are making the assumption that the "areLinkers" argument remains
|
|
// the same if the definitions are the same
|
|
bool removeExtraDummies = areLinkers;
|
|
bool allowConnectionToDummies = areLinkers;
|
|
lastDefs = definitions;
|
|
try {
|
|
abbrevs = Abbreviations::Utils::parseAbbreviations(
|
|
definitions, removeExtraDummies, allowConnectionToDummies);
|
|
} catch (...) {
|
|
return "cannot parse abbreviations";
|
|
}
|
|
}
|
|
Abbreviations::condenseMolAbbreviations(get(), abbrevs, maxCoverage);
|
|
return mappingToJsonArray(get());
|
|
}
|
|
|
|
std::string JSMolBase::generate_aligned_coords(const JSMolBase &templateMol,
|
|
const std::string &details) {
|
|
if (!templateMol.get().getNumConformers()) {
|
|
return "";
|
|
}
|
|
return MinimalLib::generate_aligned_coords(get(), templateMol.get(),
|
|
details.c_str());
|
|
}
|
|
|
|
int JSMolBase::has_coords() const {
|
|
if (!get().getNumConformers()) {
|
|
return 0;
|
|
}
|
|
return (get().getConformer().is3D() ? 3 : 2);
|
|
}
|
|
|
|
const RDGeom::POINT3D_VECT &JSMolBase::get_coords() const {
|
|
static const RDGeom::POINT3D_VECT empty;
|
|
return (get().getNumConformers() ? get().getConformer().getPositions()
|
|
: empty);
|
|
}
|
|
|
|
double JSMolBase::normalize_depiction(int canonicalize, double scaleFactor) {
|
|
if (!get().getNumConformers()) {
|
|
return -1.;
|
|
}
|
|
return RDDepict::normalizeDepiction(get(), -1, canonicalize, scaleFactor);
|
|
}
|
|
|
|
void JSMolBase::straighten_depiction(bool minimizeRotation) {
|
|
if (!get().getNumConformers()) {
|
|
return;
|
|
}
|
|
RDDepict::straightenDepiction(get(), -1, minimizeRotation);
|
|
}
|
|
|
|
bool JSMolBase::is_valid() const { return true; }
|
|
|
|
std::pair<JSMolList *, std::string> JSMolBase::get_frags(
|
|
const std::string &details_json) const {
|
|
std::vector<int> frags;
|
|
std::vector<std::vector<int>> fragsMolAtomMapping;
|
|
bool sanitizeFrags = true;
|
|
bool copyConformers = true;
|
|
MinimalLib::get_mol_frags_details(details_json, sanitizeFrags,
|
|
copyConformers);
|
|
auto molFrags = MolOps::getMolFrags(get(), sanitizeFrags, &frags,
|
|
&fragsMolAtomMapping, copyConformers);
|
|
return std::make_pair(
|
|
new JSMolList(molFrags),
|
|
MinimalLib::get_mol_frags_mappings(frags, fragsMolAtomMapping));
|
|
}
|
|
|
|
unsigned int JSMolBase::get_num_atoms(bool heavyOnly) const {
|
|
return heavyOnly ? get().getNumHeavyAtoms() : get().getNumAtoms();
|
|
}
|
|
|
|
unsigned int JSMolBase::get_num_bonds() const { return get().getNumBonds(); }
|
|
|
|
#ifdef RDK_BUILD_MINIMAL_LIB_MMPA
|
|
namespace {
|
|
bool mmpaFragmentMol(const ROMol &mol, std::vector<RDKit::ROMOL_SPTR> &cores,
|
|
std::vector<RDKit::ROMOL_SPTR> &sidechains,
|
|
unsigned int minCuts, unsigned int maxCuts,
|
|
unsigned int maxCutBonds) {
|
|
std::vector<std::pair<RDKit::ROMOL_SPTR, RDKit::ROMOL_SPTR>> mmpaFrags;
|
|
if (!RDKit::MMPA::fragmentMol(mol, mmpaFrags, minCuts, maxCuts,
|
|
maxCutBonds)) {
|
|
return false;
|
|
}
|
|
auto numEntries = mmpaFrags.size();
|
|
cores.clear();
|
|
cores.reserve(numEntries);
|
|
sidechains.clear();
|
|
sidechains.reserve(numEntries);
|
|
for (const auto &mmpaFrag : mmpaFrags) {
|
|
cores.push_back(mmpaFrag.first);
|
|
sidechains.push_back(mmpaFrag.second);
|
|
}
|
|
return true;
|
|
}
|
|
} // end of anonymous namespace
|
|
|
|
std::pair<JSMolList *, JSMolList *> JSMolBase::get_mmpa_frags(
|
|
unsigned int minCuts, unsigned int maxCuts,
|
|
unsigned int maxCutBonds) const {
|
|
std::vector<RDKit::ROMOL_SPTR> cores;
|
|
std::vector<RDKit::ROMOL_SPTR> sidechains;
|
|
if (!mmpaFragmentMol(get(), cores, sidechains, minCuts, maxCuts,
|
|
maxCutBonds)) {
|
|
return std::make_pair(nullptr, nullptr);
|
|
}
|
|
return std::make_pair(new JSMolList(std::move(cores)),
|
|
new JSMolList(std::move(sidechains)));
|
|
}
|
|
#endif
|
|
|
|
std::string JSMolBase::add_to_png_blob(const std::string &pngString,
|
|
const std::string &details) const {
|
|
PNGMetadataParams params;
|
|
std::string res;
|
|
try {
|
|
MinimalLib::updatePNGMetadataParamsFromJSON(params, details.c_str());
|
|
res = addMolToPNGString(get(), pngString, params);
|
|
} catch (...) {
|
|
}
|
|
return res;
|
|
}
|
|
|
|
std::string JSMolBase::combine_with(const JSMolBase &other,
|
|
const std::string &details) {
|
|
std::unique_ptr<ROMol> combinedMol;
|
|
auto res = MinimalLib::combine_mols_internal(get(), other.get(), combinedMol,
|
|
details.c_str());
|
|
if (res.empty() && combinedMol) {
|
|
reset(static_cast<RWMol *>(combinedMol.release()));
|
|
}
|
|
return "";
|
|
}
|
|
|
|
#ifdef RDK_BUILD_MINIMAL_LIB_RXN
|
|
std::string JSReaction::get_svg(int w, int h) const {
|
|
assert(d_rxn);
|
|
return MinimalLib::rxn_to_svg(*d_rxn, w, h);
|
|
}
|
|
std::string JSReaction::get_svg_with_highlights(
|
|
const std::string &details) const {
|
|
assert(d_rxn);
|
|
|
|
int w = d_defaultWidth;
|
|
int h = d_defaultHeight;
|
|
return MinimalLib::rxn_to_svg(*d_rxn, w, h, details);
|
|
}
|
|
bool JSReaction::is_valid() const { return true; }
|
|
|
|
std::vector<JSMolList *> JSReaction::run_reactants(
|
|
const JSMolList &reactants, unsigned int maxProducts) const {
|
|
d_rxn->initReactantMatchers();
|
|
RDKit::MOL_SPTR_VECT reactant_vec;
|
|
|
|
for (const auto &reactant : reactants.mols()) {
|
|
if (!reactant) {
|
|
throw ValueErrorException("Reactant must not be null");
|
|
}
|
|
reactant_vec.push_back(reactant);
|
|
}
|
|
|
|
std::vector<RDKit::MOL_SPTR_VECT> prods;
|
|
prods = d_rxn->runReactants(reactant_vec, maxProducts);
|
|
std::vector<JSMolList *> newResults;
|
|
for (auto &mol_array : prods) {
|
|
newResults.push_back(new JSMolList(mol_array));
|
|
}
|
|
return newResults;
|
|
}
|
|
#endif
|
|
|
|
JSMolBase *JSMolList::next() {
|
|
JSMolBase *res = nullptr;
|
|
if (d_idx < d_mols.size()) {
|
|
res = at(d_idx++);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
JSMolBase *JSMolList::at(size_t idx) const {
|
|
JSMolBase *res = nullptr;
|
|
if (idx < d_mols.size()) {
|
|
const auto &molSptr = d_mols.at(idx);
|
|
if (molSptr) {
|
|
res = new JSMolShared(molSptr);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
JSMolBase *JSMolList::pop(size_t idx) {
|
|
JSMolBase *res = nullptr;
|
|
if (idx < d_mols.size()) {
|
|
res = at(idx);
|
|
d_mols.erase(d_mols.begin() + idx);
|
|
if (d_idx > idx) {
|
|
--d_idx;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
size_t JSMolList::append(const JSMolBase &mol) {
|
|
d_mols.emplace_back(new ROMol(mol.get()));
|
|
return d_mols.size();
|
|
}
|
|
|
|
size_t JSMolList::insert(size_t idx, const JSMolBase &mol) {
|
|
idx = std::min(idx, d_mols.size());
|
|
d_mols.emplace(d_mols.begin() + idx, new ROMol(mol.get()));
|
|
return d_mols.size();
|
|
}
|
|
|
|
#ifdef RDK_BUILD_MINIMAL_LIB_SUBSTRUCTLIBRARY
|
|
JSSubstructLibrary::JSSubstructLibrary(unsigned int num_bits)
|
|
: d_fpHolder(nullptr) {
|
|
boost::shared_ptr<CachedTrustedSmilesMolHolder> molHolderSptr(
|
|
new CachedTrustedSmilesMolHolder());
|
|
boost::shared_ptr<PatternHolder> fpHolderSptr;
|
|
d_molHolder = molHolderSptr.get();
|
|
if (num_bits) {
|
|
fpHolderSptr.reset(new PatternHolder(num_bits));
|
|
d_fpHolder = fpHolderSptr.get();
|
|
d_sslib.reset(new SubstructLibrary(molHolderSptr, fpHolderSptr));
|
|
} else {
|
|
d_sslib.reset(new SubstructLibrary(molHolderSptr));
|
|
}
|
|
}
|
|
|
|
int JSSubstructLibrary::add_trusted_smiles(const std::string &smi) {
|
|
SmilesParserParams ps;
|
|
ps.sanitize = false;
|
|
ps.removeHs = false;
|
|
std::unique_ptr<RWMol> mol(SmilesToMol(smi, ps));
|
|
if (!mol) {
|
|
return -1;
|
|
}
|
|
mol->updatePropertyCache();
|
|
MolOps::fastFindRings(*mol);
|
|
int smiIdx;
|
|
if (d_fpHolder) {
|
|
auto fp = d_fpHolder->makeFingerprint(*mol);
|
|
if (!fp) {
|
|
return -1;
|
|
}
|
|
int fpIdx = d_fpHolder->addFingerprint(fp);
|
|
smiIdx = d_molHolder->addSmiles(smi);
|
|
CHECK_INVARIANT(fpIdx == smiIdx, "");
|
|
} else {
|
|
smiIdx = d_molHolder->addSmiles(smi);
|
|
}
|
|
return smiIdx;
|
|
}
|
|
|
|
int JSSubstructLibrary::add_trusted_smiles_and_pattern_fp(
|
|
const std::string &smi, const std::string &patternFp) {
|
|
if (!d_fpHolder) {
|
|
throw ValueErrorException(NO_SUPPORT_FOR_PATTERN_FPS);
|
|
}
|
|
auto bitVect = new ExplicitBitVect(patternFp);
|
|
if (!bitVect) {
|
|
return -1;
|
|
}
|
|
int fpIdx = d_fpHolder->addFingerprint(bitVect);
|
|
int smiIdx = d_molHolder->addSmiles(smi);
|
|
CHECK_INVARIANT(fpIdx == smiIdx, "");
|
|
return smiIdx;
|
|
}
|
|
|
|
std::string JSSubstructLibrary::get_trusted_smiles(unsigned int i) const {
|
|
return d_molHolder->getMols().at(i);
|
|
}
|
|
|
|
std::string JSSubstructLibrary::get_pattern_fp(unsigned int i) const {
|
|
if (!d_fpHolder) {
|
|
throw ValueErrorException(NO_SUPPORT_FOR_PATTERN_FPS);
|
|
}
|
|
return d_fpHolder->getFingerprints().at(i)->toString();
|
|
}
|
|
|
|
inline int JSSubstructLibrary::add_mol_helper(const ROMol &mol) {
|
|
std::string smi = MolToSmiles(mol);
|
|
return add_trusted_smiles(smi);
|
|
}
|
|
|
|
int JSSubstructLibrary::add_mol(const JSMolBase &m) {
|
|
return add_mol_helper(m.get());
|
|
}
|
|
|
|
int JSSubstructLibrary::add_smiles(const std::string &smi) {
|
|
std::unique_ptr<RWMol> mol(SmilesToMol(smi));
|
|
if (!mol) {
|
|
return -1;
|
|
}
|
|
return add_mol_helper(*mol);
|
|
}
|
|
|
|
JSMolBase *JSSubstructLibrary::get_mol(unsigned int i) {
|
|
return new JSMolShared(d_sslib->getMol(i));
|
|
}
|
|
|
|
std::string JSSubstructLibrary::get_matches(const JSMolBase &q,
|
|
bool useChirality, int numThreads,
|
|
int maxResults) const {
|
|
if (!d_sslib->size()) {
|
|
return "[]";
|
|
}
|
|
auto indices = d_sslib->getMatches(q.get(), true, useChirality, false,
|
|
numThreads, maxResults);
|
|
bj::array doc;
|
|
for (const auto &i : indices) {
|
|
doc.push_back(i);
|
|
}
|
|
std::string res = bj::serialize(doc);
|
|
return res;
|
|
}
|
|
|
|
unsigned int JSSubstructLibrary::count_matches(const JSMolBase &q,
|
|
bool useChirality,
|
|
int numThreads) const {
|
|
return d_sslib->size() ? d_sslib->countMatches(q.get(), true, useChirality,
|
|
false, numThreads)
|
|
: 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef RDK_BUILD_INCHI_SUPPORT
|
|
std::string get_inchikey_for_inchi(const std::string &input) {
|
|
return InchiToInchiKey(input);
|
|
}
|
|
#endif
|
|
|
|
JSMolBase *get_mol_copy(const JSMolBase &other) {
|
|
return new JSMol(new RWMol(other.get()));
|
|
}
|
|
|
|
JSMolBase *get_mol(const std::string &input, const std::string &details_json) {
|
|
auto mol = MinimalLib::mol_from_input(input, details_json);
|
|
return mol ? new JSMol(mol) : nullptr;
|
|
}
|
|
|
|
JSMolBase *get_mol_from_pickle(const std::string &pkl) {
|
|
RWMol *mol = nullptr;
|
|
if (!pkl.empty()) {
|
|
mol = new RWMol();
|
|
try {
|
|
MolPickler::molFromPickle(pkl, mol);
|
|
} catch (...) {
|
|
delete mol;
|
|
mol = nullptr;
|
|
}
|
|
}
|
|
return mol ? new JSMol(mol) : nullptr;
|
|
}
|
|
|
|
JSMolBase *get_qmol(const std::string &input) {
|
|
auto mol = MinimalLib::qmol_from_input(input);
|
|
return mol ? new JSMol(mol) : nullptr;
|
|
}
|
|
|
|
#ifdef RDK_BUILD_MINIMAL_LIB_RXN
|
|
JSReaction *get_rxn(const std::string &input, const std::string &details_json) {
|
|
auto rxn = MinimalLib::rxn_from_input(input, details_json);
|
|
return rxn ? new JSReaction(rxn) : nullptr;
|
|
}
|
|
#endif
|
|
|
|
std::string version() { return std::string(rdkitVersion); }
|
|
|
|
void prefer_coordgen(bool useCoordGen) {
|
|
#ifdef RDK_BUILD_COORDGEN_SUPPORT
|
|
RDDepict::preferCoordGen = useCoordGen;
|
|
#endif
|
|
}
|
|
|
|
bool use_legacy_stereo_perception(bool value) {
|
|
bool was = Chirality::getUseLegacyStereoPerception();
|
|
Chirality::setUseLegacyStereoPerception(value);
|
|
return was;
|
|
}
|
|
|
|
bool allow_non_tetrahedral_chirality(bool value) {
|
|
bool was = Chirality::getAllowNontetrahedralChirality();
|
|
Chirality::setAllowNontetrahedralChirality(value);
|
|
return was;
|
|
}
|
|
|
|
#ifdef RDK_BUILD_MINIMAL_LIB_MCS
|
|
namespace {
|
|
MCSResult getMcsResult(const JSMolList &molList,
|
|
const std::string &details_json) {
|
|
MCSParameters p;
|
|
if (!details_json.empty()) {
|
|
parseMCSParametersJSON(details_json.c_str(), &p);
|
|
}
|
|
return RDKit::findMCS(molList.mols(), &p);
|
|
}
|
|
} // namespace
|
|
|
|
std::string get_mcs_as_json(const JSMolList &molList,
|
|
const std::string &details_json) {
|
|
auto mcsResult = getMcsResult(molList, details_json);
|
|
bj::object doc;
|
|
bj::value bjSmarts;
|
|
if (!mcsResult.DegenerateSmartsQueryMolDict.empty()) {
|
|
bj::array smartsArray;
|
|
for (const auto &pair : mcsResult.DegenerateSmartsQueryMolDict) {
|
|
smartsArray.emplace_back(pair.first);
|
|
}
|
|
bjSmarts = smartsArray;
|
|
} else {
|
|
bjSmarts = mcsResult.SmartsString;
|
|
}
|
|
doc["smarts"] = bjSmarts;
|
|
doc["canceled"] = mcsResult.Canceled;
|
|
doc["numAtoms"] = mcsResult.NumAtoms;
|
|
doc["numBonds"] = mcsResult.NumBonds;
|
|
std::string res = bj::serialize(doc);
|
|
return res;
|
|
}
|
|
|
|
std::string get_mcs_as_smarts(const JSMolList &molList,
|
|
const std::string &details_json) {
|
|
auto res = getMcsResult(molList, details_json);
|
|
return res.SmartsString;
|
|
}
|
|
|
|
JSMolBase *get_mcs_as_mol(const JSMolList &molList,
|
|
const std::string &details_json) {
|
|
auto res = getMcsResult(molList, details_json);
|
|
return new JSMolShared(res.QueryMol);
|
|
}
|
|
#endif
|
|
|
|
std::unique_ptr<MinimalLib::LoggerStateSingletons>
|
|
MinimalLib::LoggerStateSingletons::d_instance;
|
|
|
|
JSLog::JSLog(MinimalLib::LogHandle *logHandle) : d_logHandle(logHandle) {
|
|
assert(d_logHandle);
|
|
}
|
|
|
|
JSLog::~JSLog() { delete d_logHandle; }
|
|
|
|
std::string JSLog::get_buffer() const { return d_logHandle->getBuffer(); }
|
|
|
|
void JSLog::clear_buffer() const { d_logHandle->clearBuffer(); }
|
|
|
|
JSLog *set_log_tee(const std::string &log_name) {
|
|
auto logHandle = MinimalLib::LogHandle::setLogTee(log_name.c_str());
|
|
return logHandle ? new JSLog(logHandle) : nullptr;
|
|
}
|
|
|
|
JSLog *set_log_capture(const std::string &log_name) {
|
|
auto logHandle = MinimalLib::LogHandle::setLogCapture(log_name.c_str());
|
|
return logHandle ? new JSLog(logHandle) : nullptr;
|
|
}
|
|
|
|
bool enable_logging(const std::string &logName) {
|
|
return MinimalLib::LogHandle::enableLogging(logName.c_str());
|
|
}
|
|
|
|
bool disable_logging(const std::string &logName) {
|
|
return MinimalLib::LogHandle::disableLogging(logName.c_str());
|
|
}
|
|
|
|
void disable_logging() { RDKit::MinimalLib::LogHandle::disableLogging(); }
|
|
|
|
JSMolBase *get_mol_from_png_blob(const std::string &pngString,
|
|
const std::string &details) {
|
|
auto mols = MinimalLib::get_mols_from_png_blob_internal(pngString, true,
|
|
details.c_str());
|
|
if (mols.empty()) {
|
|
return nullptr;
|
|
}
|
|
return new JSMol(new RWMol(*mols.front()));
|
|
}
|
|
|
|
JSMolList *get_mols_from_png_blob(const std::string &pngString,
|
|
const std::string &details) {
|
|
auto mols = MinimalLib::get_mols_from_png_blob_internal(pngString, false,
|
|
details.c_str());
|
|
if (mols.empty()) {
|
|
return nullptr;
|
|
}
|
|
return new JSMolList(mols);
|
|
}
|
|
|
|
#ifdef RDK_BUILD_MINIMAL_LIB_RGROUPDECOMP
|
|
JSRGroupDecomposition::JSRGroupDecomposition(const JSMolBase &core,
|
|
const std::string &details_json) {
|
|
RGroupDecompositionParameters params;
|
|
updateRGroupDecompositionParametersFromJSON(params, details_json);
|
|
d_decomp.reset(new RGroupDecomposition(core.get(), params));
|
|
}
|
|
|
|
JSRGroupDecomposition::JSRGroupDecomposition(const JSMolList &cores,
|
|
const std::string &details_json) {
|
|
RGroupDecompositionParameters params;
|
|
updateRGroupDecompositionParametersFromJSON(params, details_json);
|
|
d_decomp.reset(new RGroupDecomposition(cores.mols(), params));
|
|
}
|
|
|
|
int JSRGroupDecomposition::add(const JSMolBase &mol) {
|
|
return d_decomp->add(mol.get());
|
|
}
|
|
|
|
bool JSRGroupDecomposition::process() { return d_decomp->process(); }
|
|
|
|
std::map<std::string, std::unique_ptr<JSMolList>>
|
|
JSRGroupDecomposition::getRGroupsAsColumns() const {
|
|
auto cols = d_decomp->getRGroupsAsColumns();
|
|
std::map<std::string, std::unique_ptr<JSMolList>> res;
|
|
std::transform(
|
|
cols.begin(), cols.end(), std::inserter(res, res.begin()),
|
|
[](const auto &keyValuePair) {
|
|
return std::make_pair(
|
|
std::move(keyValuePair.first),
|
|
std::unique_ptr<JSMolList>(new JSMolList(keyValuePair.second)));
|
|
});
|
|
return res;
|
|
}
|
|
|
|
std::vector<std::map<std::string, std::unique_ptr<JSMolBase>>>
|
|
JSRGroupDecomposition::getRGroupsAsRows() const {
|
|
auto rows = d_decomp->getRGroupsAsRows();
|
|
std::vector<std::map<std::string, std::unique_ptr<JSMolBase>>> res;
|
|
res.reserve(rows.size());
|
|
std::transform(
|
|
rows.begin(), rows.end(), std::back_inserter(res),
|
|
[](const auto &originalMap) {
|
|
std::map<std::string, std::unique_ptr<JSMolBase>> transformedMap;
|
|
std::transform(originalMap.begin(), originalMap.end(),
|
|
std::inserter(transformedMap, transformedMap.begin()),
|
|
[](const auto &keyValuePair) {
|
|
CHECK_INVARIANT(keyValuePair.second,
|
|
"ROMOL_SPTR must not be null");
|
|
return std::make_pair(
|
|
std::move(keyValuePair.first),
|
|
std::unique_ptr<JSMolBase>(
|
|
new JSMolShared(keyValuePair.second)));
|
|
});
|
|
return transformedMap;
|
|
});
|
|
return res;
|
|
}
|
|
#endif
|
|
#ifdef RDK_BUILD_MINIMAL_LIB_MOLZIP
|
|
JSMolBase *molzip(const JSMolBase &a, const JSMolBase &b,
|
|
const std::string &details_json) {
|
|
MolzipParams params;
|
|
parseMolzipParametersJSON(params, details_json.c_str());
|
|
auto out = molzip(a.get(), b.get(), params);
|
|
return new JSMol(new RDKit::RWMol(*out));
|
|
}
|
|
#endif
|