mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-04 21:54:27 +08:00
- remove redundant #include - avoid unnecessary copy of match - expose SubstructMatchParams to JS MinimalLib - add JS SubstructMatchParams test Co-authored-by: ptosco <paolo.tosco@novartis.com>
1089 lines
33 KiB
C++
1089 lines
33 KiB
C++
//
|
|
// Copyright (C) 2021 Greg Landrum
|
|
//
|
|
// @@ 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.
|
|
//
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
#include <string>
|
|
#include <cstring>
|
|
#include <regex>
|
|
|
|
#include <RDGeneral/versions.h>
|
|
#include <atomic>
|
|
#include <GraphMol/RDKitBase.h>
|
|
#include <GraphMol/MolPickler.h>
|
|
#include <GraphMol/SmilesParse/SmilesParse.h>
|
|
#include <GraphMol/SmilesParse/SmilesWrite.h>
|
|
#include <GraphMol/SmilesParse/SmartsWrite.h>
|
|
#include <GraphMol/SmilesParse/SmilesJSONParsers.h>
|
|
#include <GraphMol/FileParsers/FileParsers.h>
|
|
#include <GraphMol/MolDraw2D/MolDraw2D.h>
|
|
#include <GraphMol/MolDraw2D/MolDraw2DSVG.h>
|
|
#include <GraphMol/MolDraw2D/MolDraw2DUtils.h>
|
|
#include <GraphMol/MolInterchange/MolInterchange.h>
|
|
#include <GraphMol/Substruct/SubstructMatch.h>
|
|
#include <GraphMol/Descriptors/Property.h>
|
|
#include <GraphMol/Descriptors/MolDescriptors.h>
|
|
#include <GraphMol/Fingerprints/MorganFingerprints.h>
|
|
#include <GraphMol/Fingerprints/Fingerprints.h>
|
|
#include <GraphMol/Fingerprints/AtomPairs.h>
|
|
#include <GraphMol/Fingerprints/MACCS.h>
|
|
#include <GraphMol/Depictor/RDDepictor.h>
|
|
#include <GraphMol/CIPLabeler/CIPLabeler.h>
|
|
#include <GraphMol/Abbreviations/Abbreviations.h>
|
|
#include <GraphMol/DistGeomHelpers/Embedder.h>
|
|
#include <GraphMol/ChemReactions/Reaction.h>
|
|
#include <GraphMol/ChemReactions/ReactionPickler.h>
|
|
#include <GraphMol/Chirality.h>
|
|
#include <DataStructs/BitOps.h>
|
|
|
|
#include "common.h"
|
|
|
|
#include <sstream>
|
|
#include <RDGeneral/BoostStartInclude.h>
|
|
#include <boost/property_tree/ptree.hpp>
|
|
#include <boost/property_tree/json_parser.hpp>
|
|
#include <RDGeneral/BoostEndInclude.h>
|
|
|
|
#ifdef RDK_BUILD_INCHI_SUPPORT
|
|
#include <INCHI-API/inchi.h>
|
|
#endif
|
|
|
|
#include <boost/json.hpp>
|
|
#include "cffiwrapper.h"
|
|
|
|
namespace bj = boost::json;
|
|
|
|
using namespace RDKit;
|
|
|
|
#if (defined(__GNUC__) || defined(__GNUG__))
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wconversion-null"
|
|
#endif
|
|
|
|
namespace {
|
|
char *str_to_c(const std::string &str, size_t *len = nullptr) {
|
|
if (len) {
|
|
*len = 0;
|
|
}
|
|
char *res;
|
|
res = (char *)malloc(str.size() + 1);
|
|
if (res) {
|
|
if (len) {
|
|
*len = str.size();
|
|
}
|
|
memcpy(res, str.c_str(), str.size());
|
|
res[str.size()] = '\0';
|
|
}
|
|
return res;
|
|
}
|
|
char *str_to_c(const char *str) {
|
|
char *res;
|
|
res = (char *)malloc(strlen(str) + 1);
|
|
if (res) {
|
|
strcpy(res, str);
|
|
}
|
|
return res;
|
|
}
|
|
} // namespace
|
|
|
|
void mol_to_pkl(
|
|
const ROMol &mol, char **mol_pkl, size_t *mol_pkl_sz,
|
|
unsigned int propFlags = PicklerOps::PropertyPickleOptions::AllProps ^
|
|
PicklerOps::PropertyPickleOptions::ComputedProps) {
|
|
std::string pkl;
|
|
MolPickler::pickleMol(mol, pkl, propFlags);
|
|
free(*mol_pkl);
|
|
*mol_pkl = str_to_c(pkl, mol_pkl_sz);
|
|
}
|
|
|
|
RWMol mol_from_pkl(const char *pkl, size_t pkl_sz) {
|
|
if (!pkl || !pkl_sz) {
|
|
return RWMol();
|
|
}
|
|
std::string mol_pkl(pkl, pkl_sz);
|
|
RWMol res(mol_pkl);
|
|
res.setProp(common_properties::_StereochemDone, 1, true);
|
|
return res;
|
|
}
|
|
|
|
ChemicalReaction rxn_from_pkl(const char *pkl, size_t pkl_sz) {
|
|
if (!pkl || !pkl_sz) {
|
|
return ChemicalReaction();
|
|
}
|
|
std::string rxn_pkl(pkl, pkl_sz);
|
|
ChemicalReaction res(rxn_pkl);
|
|
return res;
|
|
}
|
|
|
|
#ifdef PT_OPT_GET
|
|
#undef PT_OPT_GET
|
|
#endif
|
|
#define PT_OPT_GET(opt) opt = pt.get(#opt, opt);
|
|
|
|
namespace {
|
|
SmilesWriteParams smiles_helper(const char *details_json) {
|
|
SmilesWriteParams params;
|
|
updateSmilesWriteParamsFromJSON(params, details_json);
|
|
return params;
|
|
}
|
|
std::string cxsmiles_helper(const char *pkl, size_t pkl_sz,
|
|
const char *details_json) {
|
|
if (!pkl || !pkl_sz) {
|
|
return "";
|
|
}
|
|
auto params = smiles_helper(details_json);
|
|
auto mol = mol_from_pkl(pkl, pkl_sz);
|
|
std::uint32_t cxSmilesFields = SmilesWrite::CXSmilesFields::CX_ALL;
|
|
unsigned int restoreBondDirs = RestoreBondDirOptionClear;
|
|
updateCXSmilesFieldsFromJSON(cxSmilesFields, restoreBondDirs, details_json);
|
|
return MolToCXSmiles(mol, params, cxSmilesFields,
|
|
static_cast<RestoreBondDirOption>(restoreBondDirs));
|
|
}
|
|
char *get_molblock_common(const char *pkl, size_t pkl_sz,
|
|
const char *details_json,
|
|
MinimalLib::MDLVersion forceMDLVersion) {
|
|
if (!pkl || !pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
auto mol = mol_from_pkl(pkl, pkl_sz);
|
|
auto data = MinimalLib::molblock_helper(mol, details_json, forceMDLVersion);
|
|
return str_to_c(data);
|
|
}
|
|
} // namespace
|
|
extern "C" char *get_smiles(const char *pkl, size_t pkl_sz,
|
|
const char *details_json) {
|
|
if (!pkl || !pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
auto params = smiles_helper(details_json);
|
|
auto mol = mol_from_pkl(pkl, pkl_sz);
|
|
auto data = MolToSmiles(mol, params);
|
|
return str_to_c(data);
|
|
}
|
|
extern "C" char *get_smarts(const char *pkl, size_t pkl_sz,
|
|
const char *details_json) {
|
|
if (!pkl || !pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
auto params = smiles_helper(details_json);
|
|
auto mol = mol_from_pkl(pkl, pkl_sz);
|
|
auto data = MolToSmarts(mol, params.doIsomericSmiles, params.rootedAtAtom);
|
|
return str_to_c(data);
|
|
}
|
|
extern "C" char *get_cxsmiles(const char *pkl, size_t pkl_sz,
|
|
const char *details_json) {
|
|
if (!pkl || !pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
auto data = cxsmiles_helper(pkl, pkl_sz, details_json);
|
|
return str_to_c(data);
|
|
}
|
|
extern "C" char *get_cxsmarts(const char *pkl, size_t pkl_sz,
|
|
const char *details_json) {
|
|
if (!pkl || !pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
auto params = smiles_helper(details_json);
|
|
auto mol = mol_from_pkl(pkl, pkl_sz);
|
|
auto data = MolToCXSmarts(mol, params.doIsomericSmiles);
|
|
return str_to_c(data);
|
|
}
|
|
extern "C" char *get_molblock(const char *pkl, size_t pkl_sz,
|
|
const char *details_json) {
|
|
return get_molblock_common(pkl, pkl_sz, details_json,
|
|
MinimalLib::MDLVersion::AUTO);
|
|
}
|
|
extern "C" char *get_v3kmolblock(const char *pkl, size_t pkl_sz,
|
|
const char *details_json) {
|
|
return get_molblock_common(pkl, pkl_sz, details_json,
|
|
MinimalLib::MDLVersion::V3000);
|
|
}
|
|
extern "C" char *get_v2kmolblock(const char *pkl, size_t pkl_sz,
|
|
const char *details_json) {
|
|
return get_molblock_common(pkl, pkl_sz, details_json,
|
|
MinimalLib::MDLVersion::V2000);
|
|
}
|
|
extern "C" char *get_json(const char *pkl, size_t pkl_sz, const char *) {
|
|
if (!pkl || !pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
auto mol = mol_from_pkl(pkl, pkl_sz);
|
|
auto data = MolInterchange::MolToJSONData(mol);
|
|
return str_to_c(data);
|
|
}
|
|
extern "C" void free_ptr(char *ptr) {
|
|
if (ptr) {
|
|
free(ptr);
|
|
}
|
|
}
|
|
|
|
extern "C" char *get_svg(const char *pkl, size_t pkl_sz,
|
|
const char *details_json) {
|
|
if (!pkl || !pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
auto mol = mol_from_pkl(pkl, pkl_sz);
|
|
unsigned int width = MinimalLib::d_defaultWidth;
|
|
unsigned int height = MinimalLib::d_defaultHeight;
|
|
return str_to_c(MinimalLib::mol_to_svg(mol, width, height, details_json));
|
|
}
|
|
|
|
extern "C" char *get_rxn_svg(const char *pkl, size_t pkl_sz,
|
|
const char *details_json) {
|
|
if (!pkl || !pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
auto rxn = rxn_from_pkl(pkl, pkl_sz);
|
|
unsigned int width = MinimalLib::d_defaultWidth;
|
|
unsigned int height = MinimalLib::d_defaultHeight;
|
|
return str_to_c(MinimalLib::rxn_to_svg(rxn, width, height, details_json));
|
|
}
|
|
|
|
#ifdef RDK_BUILD_INCHI_SUPPORT
|
|
extern "C" char *get_inchi(const char *pkl, size_t pkl_sz,
|
|
const char *details_json) {
|
|
if (!pkl || !pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
auto mol = mol_from_pkl(pkl, pkl_sz);
|
|
ExtraInchiReturnValues rv;
|
|
auto options = MinimalLib::parse_inchi_options(details_json);
|
|
return str_to_c(
|
|
MolToInchi(mol, rv, !options.empty() ? options.c_str() : nullptr));
|
|
}
|
|
|
|
extern "C" char *get_inchi_for_molblock(const char *ctab,
|
|
const char *details_json) {
|
|
if (!ctab) {
|
|
return str_to_c("");
|
|
}
|
|
ExtraInchiReturnValues rv;
|
|
auto options = MinimalLib::parse_inchi_options(details_json);
|
|
return str_to_c(
|
|
MolBlockToInchi(ctab, rv, !options.empty() ? options.c_str() : nullptr));
|
|
}
|
|
|
|
extern "C" char *get_inchikey_for_inchi(const char *inchi) {
|
|
if (!inchi) {
|
|
return str_to_c("");
|
|
}
|
|
return str_to_c(InchiToInchiKey(inchi));
|
|
}
|
|
#endif
|
|
|
|
extern "C" char *get_mol(const char *input, size_t *pkl_sz,
|
|
const char *details_json) {
|
|
std::unique_ptr<RWMol> mol{MinimalLib::mol_from_input(input, details_json)};
|
|
if (!mol) {
|
|
*pkl_sz = 0;
|
|
return nullptr;
|
|
}
|
|
unsigned int propFlags = PicklerOps::PropertyPickleOptions::AllProps ^
|
|
PicklerOps::PropertyPickleOptions::ComputedProps;
|
|
MinimalLib::updatePropertyPickleOptionsFromJSON(propFlags, details_json);
|
|
std::string pkl;
|
|
MolPickler::pickleMol(*mol, pkl, propFlags);
|
|
return str_to_c(pkl, pkl_sz);
|
|
}
|
|
|
|
extern "C" char *get_qmol(const char *input, size_t *pkl_sz,
|
|
const char *details_json) {
|
|
std::unique_ptr<RWMol> mol{MinimalLib::qmol_from_input(input, details_json)};
|
|
if (!mol) {
|
|
*pkl_sz = 0;
|
|
return nullptr;
|
|
}
|
|
static const unsigned int propFlags =
|
|
PicklerOps::PropertyPickleOptions::AllProps ^
|
|
PicklerOps::PropertyPickleOptions::ComputedProps;
|
|
std::string pkl;
|
|
MolPickler::pickleMol(*mol, pkl, propFlags);
|
|
return str_to_c(pkl, pkl_sz);
|
|
}
|
|
|
|
extern "C" char *get_rxn(const char *input, size_t *pkl_sz,
|
|
const char *details_json) {
|
|
std::unique_ptr<ChemicalReaction> rxn{
|
|
MinimalLib::rxn_from_input(input, details_json)};
|
|
if (!rxn) {
|
|
*pkl_sz = 0;
|
|
return nullptr;
|
|
}
|
|
unsigned int propFlags = PicklerOps::PropertyPickleOptions::AllProps ^
|
|
PicklerOps::PropertyPickleOptions::ComputedProps;
|
|
std::string pkl;
|
|
ReactionPickler::pickleReaction(*rxn, pkl, propFlags);
|
|
return str_to_c(pkl, pkl_sz);
|
|
}
|
|
|
|
extern "C" char **get_mol_frags(const char *pkl, size_t pkl_sz,
|
|
size_t **frags_pkl_sz_array, size_t *num_frags,
|
|
const char *details_json,
|
|
char **mappings_json) {
|
|
if (!pkl || !pkl_sz || !frags_pkl_sz_array || !num_frags) {
|
|
return nullptr;
|
|
}
|
|
*frags_pkl_sz_array = nullptr;
|
|
*num_frags = 0;
|
|
auto mol = mol_from_pkl(pkl, pkl_sz);
|
|
std::vector<int> frags;
|
|
std::vector<std::vector<int>> fragsMolAtomMapping;
|
|
bool sanitizeFrags = true;
|
|
bool copyConformers = true;
|
|
if (details_json) {
|
|
std::string json = details_json;
|
|
MinimalLib::get_mol_frags_details(json, sanitizeFrags, copyConformers);
|
|
}
|
|
std::vector<ROMOL_SPTR> molFrags;
|
|
try {
|
|
molFrags = MolOps::getMolFrags(mol, sanitizeFrags, &frags,
|
|
&fragsMolAtomMapping, copyConformers);
|
|
} catch (...) {
|
|
}
|
|
if (molFrags.empty()) {
|
|
return nullptr;
|
|
}
|
|
char **molPklArray = (char **)malloc(sizeof(char *) * molFrags.size());
|
|
if (!molPklArray) {
|
|
return nullptr;
|
|
}
|
|
*frags_pkl_sz_array = (size_t *)malloc(sizeof(size_t) * molFrags.size());
|
|
if (!*frags_pkl_sz_array) {
|
|
free(molPklArray);
|
|
return nullptr;
|
|
}
|
|
memset(molPklArray, 0, sizeof(char *) * molFrags.size());
|
|
*num_frags = molFrags.size();
|
|
for (size_t i = 0; i < molFrags.size(); ++i) {
|
|
mol_to_pkl(*molFrags[i], &molPklArray[i], &(*frags_pkl_sz_array)[i]);
|
|
}
|
|
if (mappings_json) {
|
|
auto res = MinimalLib::get_mol_frags_mappings(frags, fragsMolAtomMapping);
|
|
*mappings_json = str_to_c(res);
|
|
}
|
|
return molPklArray;
|
|
}
|
|
|
|
extern "C" char *version() { return str_to_c(rdkitVersion); }
|
|
|
|
extern "C" char *get_substruct_match(const char *mol_pkl, size_t mol_pkl_sz,
|
|
const char *query_pkl, size_t query_pkl_sz,
|
|
const char *options_json) {
|
|
if (!mol_pkl || !mol_pkl_sz || !query_pkl || !query_pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
auto mol = mol_from_pkl(mol_pkl, mol_pkl_sz);
|
|
auto query = mol_from_pkl(query_pkl, query_pkl_sz);
|
|
|
|
SubstructMatchParameters params;
|
|
if (options_json) {
|
|
std::string json(options_json);
|
|
updateSubstructMatchParamsFromJSON(params, json);
|
|
}
|
|
params.maxMatches = 1;
|
|
|
|
std::string res = "{}";
|
|
auto matches = SubstructMatch(mol, query, params);
|
|
if (!matches.empty()) {
|
|
const auto &match = matches[0];
|
|
bj::object doc;
|
|
MinimalLib::get_sss_json(mol, query, match, doc);
|
|
res = bj::serialize(doc);
|
|
}
|
|
|
|
return str_to_c(res);
|
|
}
|
|
extern "C" char *get_substruct_matches(const char *mol_pkl, size_t mol_pkl_sz,
|
|
const char *query_pkl,
|
|
size_t query_pkl_sz,
|
|
const char *options_json) {
|
|
if (!mol_pkl || !mol_pkl_sz || !query_pkl || !query_pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
auto mol = mol_from_pkl(mol_pkl, mol_pkl_sz);
|
|
auto query = mol_from_pkl(query_pkl, query_pkl_sz);
|
|
|
|
SubstructMatchParameters params;
|
|
if (options_json) {
|
|
std::string json(options_json);
|
|
updateSubstructMatchParamsFromJSON(params, json);
|
|
}
|
|
|
|
std::string res = "{}";
|
|
auto matches = SubstructMatch(mol, query, params);
|
|
if (!matches.empty()) {
|
|
bj::array doc;
|
|
|
|
for (const auto &match : matches) {
|
|
bj::object bjMatch;
|
|
MinimalLib::get_sss_json(mol, query, match, bjMatch);
|
|
doc.push_back(bjMatch);
|
|
}
|
|
|
|
res = bj::serialize(doc);
|
|
}
|
|
|
|
return str_to_c(res);
|
|
}
|
|
|
|
extern "C" char *get_descriptors(const char *mol_pkl, size_t mol_pkl_sz) {
|
|
if (!mol_pkl || !mol_pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
auto mol = mol_from_pkl(mol_pkl, mol_pkl_sz);
|
|
return str_to_c(MinimalLib::get_descriptors(mol));
|
|
}
|
|
|
|
extern "C" char *get_morgan_fp(const char *mol_pkl, size_t mol_pkl_sz,
|
|
const char *details_json) {
|
|
if (!mol_pkl || !mol_pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
try {
|
|
auto fp = MinimalLib::morgan_fp_as_bitvect(
|
|
mol_from_pkl(mol_pkl, mol_pkl_sz), details_json);
|
|
auto res = BitVectToText(*fp);
|
|
return str_to_c(res);
|
|
} catch (...) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
extern "C" char *get_morgan_fp_as_bytes(const char *mol_pkl, size_t mol_pkl_sz,
|
|
size_t *nbytes,
|
|
const char *details_json) {
|
|
if (!mol_pkl || !mol_pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
try {
|
|
auto fp = MinimalLib::morgan_fp_as_bitvect(
|
|
mol_from_pkl(mol_pkl, mol_pkl_sz), details_json);
|
|
auto res = BitVectToBinaryText(*fp);
|
|
return str_to_c(res, nbytes);
|
|
} catch (...) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
extern "C" char *get_rdkit_fp(const char *mol_pkl, size_t mol_pkl_sz,
|
|
const char *details_json) {
|
|
if (!mol_pkl || !mol_pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
try {
|
|
auto fp = MinimalLib::rdkit_fp_as_bitvect(mol_from_pkl(mol_pkl, mol_pkl_sz),
|
|
details_json);
|
|
auto res = BitVectToText(*fp);
|
|
return str_to_c(res);
|
|
} catch (...) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
extern "C" char *get_rdkit_fp_as_bytes(const char *mol_pkl, size_t mol_pkl_sz,
|
|
size_t *nbytes,
|
|
const char *details_json) {
|
|
if (!mol_pkl || !mol_pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
try {
|
|
auto fp = MinimalLib::rdkit_fp_as_bitvect(mol_from_pkl(mol_pkl, mol_pkl_sz),
|
|
details_json);
|
|
auto res = BitVectToBinaryText(*fp);
|
|
return str_to_c(res, nbytes);
|
|
} catch (...) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
extern "C" char *get_pattern_fp(const char *mol_pkl, size_t mol_pkl_sz,
|
|
const char *details_json) {
|
|
if (!mol_pkl || !mol_pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
try {
|
|
auto fp = MinimalLib::pattern_fp_as_bitvect(
|
|
mol_from_pkl(mol_pkl, mol_pkl_sz), details_json);
|
|
auto res = BitVectToText(*fp);
|
|
return str_to_c(res);
|
|
} catch (...) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
extern "C" char *get_pattern_fp_as_bytes(const char *mol_pkl, size_t mol_pkl_sz,
|
|
size_t *nbytes,
|
|
const char *details_json) {
|
|
if (!mol_pkl || !mol_pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
try {
|
|
auto fp = MinimalLib::pattern_fp_as_bitvect(
|
|
mol_from_pkl(mol_pkl, mol_pkl_sz), details_json);
|
|
auto res = BitVectToBinaryText(*fp);
|
|
return str_to_c(res, nbytes);
|
|
} catch (...) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
extern "C" char *get_topological_torsion_fp(const char *mol_pkl,
|
|
size_t mol_pkl_sz,
|
|
const char *details_json) {
|
|
if (!mol_pkl || !mol_pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
try {
|
|
auto fp = MinimalLib::topological_torsion_fp_as_bitvect(
|
|
mol_from_pkl(mol_pkl, mol_pkl_sz), details_json);
|
|
auto res = BitVectToText(*fp);
|
|
return str_to_c(res);
|
|
} catch (...) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
extern "C" char *get_topological_torsion_fp_as_bytes(const char *mol_pkl,
|
|
size_t mol_pkl_sz,
|
|
size_t *nbytes,
|
|
const char *details_json) {
|
|
if (!mol_pkl || !mol_pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
try {
|
|
auto fp = MinimalLib::topological_torsion_fp_as_bitvect(
|
|
mol_from_pkl(mol_pkl, mol_pkl_sz), details_json);
|
|
auto res = BitVectToBinaryText(*fp);
|
|
return str_to_c(res, nbytes);
|
|
} catch (...) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
extern "C" char *get_atom_pair_fp(const char *mol_pkl, size_t mol_pkl_sz,
|
|
const char *details_json) {
|
|
if (!mol_pkl || !mol_pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
try {
|
|
auto fp = MinimalLib::atom_pair_fp_as_bitvect(
|
|
mol_from_pkl(mol_pkl, mol_pkl_sz), details_json);
|
|
auto res = BitVectToText(*fp);
|
|
return str_to_c(res);
|
|
} catch (...) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
extern "C" char *get_atom_pair_fp_as_bytes(const char *mol_pkl,
|
|
size_t mol_pkl_sz, size_t *nbytes,
|
|
const char *details_json) {
|
|
if (!mol_pkl || !mol_pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
try {
|
|
auto fp = MinimalLib::atom_pair_fp_as_bitvect(
|
|
mol_from_pkl(mol_pkl, mol_pkl_sz), details_json);
|
|
auto res = BitVectToBinaryText(*fp);
|
|
return str_to_c(res, nbytes);
|
|
} catch (...) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
extern "C" char *get_maccs_fp(const char *mol_pkl, size_t mol_pkl_sz) {
|
|
if (!mol_pkl || !mol_pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
try {
|
|
auto fp =
|
|
MinimalLib::maccs_fp_as_bitvect(mol_from_pkl(mol_pkl, mol_pkl_sz));
|
|
auto res = BitVectToText(*fp);
|
|
return str_to_c(res);
|
|
} catch (...) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
extern "C" char *get_maccs_fp_as_bytes(const char *mol_pkl, size_t mol_pkl_sz,
|
|
size_t *nbytes) {
|
|
if (!mol_pkl || !mol_pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
try {
|
|
auto fp =
|
|
MinimalLib::maccs_fp_as_bitvect(mol_from_pkl(mol_pkl, mol_pkl_sz));
|
|
auto res = BitVectToBinaryText(*fp);
|
|
return str_to_c(res, nbytes);
|
|
} catch (...) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
#ifdef RDK_BUILD_AVALON_SUPPORT
|
|
extern "C" char *get_avalon_fp(const char *mol_pkl, size_t mol_pkl_sz,
|
|
const char *details_json) {
|
|
if (!mol_pkl || !mol_pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
try {
|
|
auto fp = MinimalLib::avalon_fp_as_bitvect(
|
|
mol_from_pkl(mol_pkl, mol_pkl_sz), details_json);
|
|
auto res = BitVectToText(*fp);
|
|
return str_to_c(res);
|
|
} catch (...) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
extern "C" char *get_avalon_fp_as_bytes(const char *mol_pkl, size_t mol_pkl_sz,
|
|
size_t *nbytes,
|
|
const char *details_json) {
|
|
if (!mol_pkl || !mol_pkl_sz) {
|
|
return nullptr;
|
|
}
|
|
try {
|
|
auto fp = MinimalLib::avalon_fp_as_bitvect(
|
|
mol_from_pkl(mol_pkl, mol_pkl_sz), details_json);
|
|
auto res = BitVectToBinaryText(*fp);
|
|
return str_to_c(res, nbytes);
|
|
} catch (...) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
extern "C" void prefer_coordgen(short val) {
|
|
#ifdef RDK_BUILD_COORDGEN_SUPPORT
|
|
RDDepict::preferCoordGen = val;
|
|
#endif
|
|
};
|
|
|
|
extern "C" short has_coords(const char *mol_pkl, size_t mol_pkl_sz) {
|
|
short res = 0;
|
|
if (mol_pkl && mol_pkl_sz) {
|
|
auto mol = mol_from_pkl(mol_pkl, mol_pkl_sz);
|
|
res = (mol.getNumConformers() > 0);
|
|
if (res) {
|
|
res = mol.getConformer().is3D() ? 3 : 2;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
extern "C" short set_2d_coords(char **mol_pkl, size_t *mol_pkl_sz) {
|
|
if (!mol_pkl || !mol_pkl_sz || !*mol_pkl || !*mol_pkl_sz) {
|
|
return 0;
|
|
}
|
|
auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz);
|
|
RDDepict::compute2DCoords(mol);
|
|
|
|
mol_to_pkl(mol, mol_pkl, mol_pkl_sz);
|
|
return 1;
|
|
}
|
|
|
|
extern "C" short set_2d_coords_aligned(char **mol_pkl, size_t *mol_pkl_sz,
|
|
const char *template_pkl,
|
|
size_t template_sz,
|
|
const char *details_json,
|
|
char **match_json) {
|
|
if (match_json) {
|
|
*match_json = nullptr;
|
|
}
|
|
if (!mol_pkl || !mol_pkl_sz || !*mol_pkl || !*mol_pkl_sz || !template_pkl ||
|
|
!template_sz || !template_pkl || !template_sz) {
|
|
return 0;
|
|
}
|
|
auto templ = mol_from_pkl(template_pkl, template_sz);
|
|
if (!templ.getNumConformers()) {
|
|
return 0;
|
|
}
|
|
auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz);
|
|
auto match = MinimalLib::generate_aligned_coords(mol, templ, details_json);
|
|
if (match.empty()) {
|
|
return 0;
|
|
} else {
|
|
mol_to_pkl(mol, mol_pkl, mol_pkl_sz);
|
|
if (match_json) {
|
|
*match_json = str_to_c(match);
|
|
}
|
|
return 1;
|
|
}
|
|
};
|
|
|
|
extern "C" short set_3d_coords(char **mol_pkl, size_t *mol_pkl_sz,
|
|
const char *params_json) {
|
|
if (!mol_pkl || !mol_pkl_sz || !*mol_pkl || !*mol_pkl_sz) {
|
|
return 0;
|
|
}
|
|
auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz);
|
|
std::string json;
|
|
if (params_json) {
|
|
json = params_json;
|
|
}
|
|
DGeomHelpers::EmbedParameters ps = DGeomHelpers::srETKDGv3;
|
|
if (!json.empty()) {
|
|
DGeomHelpers::updateEmbedParametersFromJSON(ps, json);
|
|
}
|
|
int res = DGeomHelpers::EmbedMolecule(mol, ps);
|
|
if (res >= 0) {
|
|
++res;
|
|
}
|
|
// if we have a coordMap then be sure to clear up the memory that
|
|
// updateEmbedParametersFromJSON() allocated for it
|
|
if (ps.coordMap) {
|
|
delete ps.coordMap;
|
|
}
|
|
mol_to_pkl(mol, mol_pkl, mol_pkl_sz);
|
|
return (short)res;
|
|
}
|
|
|
|
extern "C" short add_hs(char **mol_pkl, size_t *mol_pkl_sz) {
|
|
if (!mol_pkl || !mol_pkl_sz || !*mol_pkl || !*mol_pkl_sz) {
|
|
return 0;
|
|
}
|
|
auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz);
|
|
MolOps::addHs(mol);
|
|
// we don't need the properties that sets:
|
|
for (auto atom : mol.atoms()) {
|
|
if (atom->getAtomicNum() == 1) {
|
|
atom->clearProp(common_properties::isImplicit);
|
|
}
|
|
}
|
|
|
|
mol_to_pkl(mol, mol_pkl, mol_pkl_sz);
|
|
return 1;
|
|
}
|
|
|
|
extern "C" short remove_all_hs(char **mol_pkl, size_t *mol_pkl_sz) {
|
|
if (!mol_pkl || !mol_pkl_sz || !*mol_pkl || !*mol_pkl_sz) {
|
|
return 0;
|
|
}
|
|
auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz);
|
|
MolOps::removeAllHs(mol);
|
|
|
|
mol_to_pkl(mol, mol_pkl, mol_pkl_sz);
|
|
return 1;
|
|
}
|
|
|
|
extern "C" short remove_hs(char **mol_pkl, size_t *mol_pkl_sz,
|
|
const char *details_json) {
|
|
if (!mol_pkl || !mol_pkl_sz || !*mol_pkl || !*mol_pkl_sz) {
|
|
return 0;
|
|
}
|
|
auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz);
|
|
MolOps::RemoveHsParameters ps;
|
|
bool sanitize = true;
|
|
MinimalLib::updateRemoveHsParametersFromJSON(ps, sanitize, details_json);
|
|
MolOps::removeHs(mol, ps, sanitize);
|
|
|
|
mol_to_pkl(mol, mol_pkl, mol_pkl_sz);
|
|
return 1;
|
|
}
|
|
|
|
// standardization
|
|
namespace {
|
|
template <typename T>
|
|
short standardize_func(char **mol_pkl, size_t *mol_pkl_sz,
|
|
const char *details_json, T func) {
|
|
if (!mol_pkl || !mol_pkl_sz || !*mol_pkl || !*mol_pkl_sz) {
|
|
return 0;
|
|
}
|
|
auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz);
|
|
std::string json;
|
|
if (details_json) {
|
|
json = details_json;
|
|
}
|
|
std::unique_ptr<RWMol> res(func(mol, json));
|
|
|
|
mol_to_pkl(*res, mol_pkl, mol_pkl_sz);
|
|
return 1;
|
|
}
|
|
} // namespace
|
|
extern "C" short cleanup(char **mol_pkl, size_t *mol_pkl_sz,
|
|
const char *details_json) {
|
|
return standardize_func(mol_pkl, mol_pkl_sz, details_json,
|
|
MinimalLib::do_cleanup);
|
|
};
|
|
extern "C" short normalize(char **mol_pkl, size_t *mol_pkl_sz,
|
|
const char *details_json) {
|
|
return standardize_func(mol_pkl, mol_pkl_sz, details_json,
|
|
MinimalLib::do_normalize);
|
|
};
|
|
extern "C" short canonical_tautomer(char **mol_pkl, size_t *mol_pkl_sz,
|
|
const char *details_json) {
|
|
return standardize_func(mol_pkl, mol_pkl_sz, details_json,
|
|
MinimalLib::do_canonical_tautomer);
|
|
};
|
|
extern "C" short charge_parent(char **mol_pkl, size_t *mol_pkl_sz,
|
|
const char *details_json) {
|
|
return standardize_func(mol_pkl, mol_pkl_sz, details_json,
|
|
MinimalLib::do_charge_parent);
|
|
};
|
|
extern "C" short reionize(char **mol_pkl, size_t *mol_pkl_sz,
|
|
const char *details_json) {
|
|
return standardize_func(mol_pkl, mol_pkl_sz, details_json,
|
|
MinimalLib::do_reionize);
|
|
};
|
|
extern "C" short neutralize(char **mol_pkl, size_t *mol_pkl_sz,
|
|
const char *details_json) {
|
|
return standardize_func(mol_pkl, mol_pkl_sz, details_json,
|
|
MinimalLib::do_neutralize);
|
|
};
|
|
extern "C" short fragment_parent(char **mol_pkl, size_t *mol_pkl_sz,
|
|
const char *details_json) {
|
|
return standardize_func(mol_pkl, mol_pkl_sz, details_json,
|
|
MinimalLib::do_fragment_parent);
|
|
};
|
|
|
|
// chirality
|
|
extern "C" short use_legacy_stereo_perception(short value) {
|
|
short was = Chirality::getUseLegacyStereoPerception();
|
|
Chirality::setUseLegacyStereoPerception(value);
|
|
return was;
|
|
}
|
|
|
|
extern "C" short allow_non_tetrahedral_chirality(short value) {
|
|
short was = Chirality::getAllowNontetrahedralChirality();
|
|
Chirality::setAllowNontetrahedralChirality(value);
|
|
return was;
|
|
}
|
|
|
|
std::unique_ptr<MinimalLib::LoggerStateSingletons>
|
|
MinimalLib::LoggerStateSingletons::d_instance;
|
|
|
|
extern "C" short enable_logging() {
|
|
return MinimalLib::LogHandle::enableLogging();
|
|
}
|
|
extern "C" short enable_logger(const char *log_name) {
|
|
return MinimalLib::LogHandle::enableLogging(log_name);
|
|
}
|
|
|
|
extern "C" short disable_logging() {
|
|
return MinimalLib::LogHandle::disableLogging();
|
|
}
|
|
extern "C" short disable_logger(const char *log_name) {
|
|
return MinimalLib::LogHandle::disableLogging(log_name);
|
|
}
|
|
|
|
extern "C" void *set_log_tee(const char *log_name) {
|
|
return MinimalLib::LogHandle::setLogTee(log_name);
|
|
}
|
|
|
|
extern "C" void *set_log_capture(const char *log_name) {
|
|
return MinimalLib::LogHandle::setLogCapture(log_name);
|
|
}
|
|
|
|
extern "C" short destroy_log_handle(void **log_handle) {
|
|
if (!log_handle || !*log_handle) {
|
|
return 0;
|
|
}
|
|
auto lh = reinterpret_cast<MinimalLib::LogHandle *>(*log_handle);
|
|
delete lh;
|
|
*log_handle = nullptr;
|
|
return 1;
|
|
}
|
|
|
|
extern "C" char *get_log_buffer(void *log_handle) {
|
|
return log_handle
|
|
? str_to_c(reinterpret_cast<MinimalLib::LogHandle *>(log_handle)
|
|
->getBuffer())
|
|
: nullptr;
|
|
}
|
|
|
|
extern "C" short clear_log_buffer(void *log_handle) {
|
|
if (log_handle) {
|
|
reinterpret_cast<MinimalLib::LogHandle *>(log_handle)->clearBuffer();
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
extern "C" short has_prop(const char *mol_pkl, size_t mol_pkl_sz,
|
|
const char *key) {
|
|
auto mol = mol_from_pkl(mol_pkl, mol_pkl_sz);
|
|
return mol.hasProp(key);
|
|
}
|
|
|
|
extern "C" char **get_prop_list(const char *mol_pkl, size_t mol_pkl_sz,
|
|
short includePrivate, short includeComputed) {
|
|
auto mol = mol_from_pkl(mol_pkl, mol_pkl_sz);
|
|
auto propList = mol.getPropList(includePrivate, includeComputed);
|
|
std::string propNames;
|
|
for (const auto &prop : propList) {
|
|
propNames += prop + ",";
|
|
}
|
|
auto resLen = sizeof(char *) * (propList.size() + 1);
|
|
char **res = (char **)malloc(resLen);
|
|
if (!res) {
|
|
return nullptr;
|
|
}
|
|
memset(res, 0, resLen);
|
|
for (size_t i = 0; i < propList.size(); ++i) {
|
|
res[i] = strdup(propList.at(i).c_str());
|
|
if (!res[i]) {
|
|
while (i--) {
|
|
free(res[i]);
|
|
}
|
|
return nullptr;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
extern "C" void set_prop(char **mol_pkl, size_t *mol_pkl_sz, const char *key,
|
|
const char *val, short computed) {
|
|
auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz);
|
|
std::string valAsString(val);
|
|
mol.setProp(key, valAsString, computed);
|
|
mol_to_pkl(mol, mol_pkl, mol_pkl_sz);
|
|
}
|
|
|
|
extern "C" char *get_prop(const char *mol_pkl, size_t mol_pkl_sz,
|
|
const char *key) {
|
|
auto mol = mol_from_pkl(mol_pkl, mol_pkl_sz);
|
|
if (!mol.hasProp(key)) {
|
|
return nullptr;
|
|
}
|
|
std::string val;
|
|
mol.getProp(key, val);
|
|
return strdup(val.c_str());
|
|
}
|
|
|
|
extern "C" short clear_prop(char **mol_pkl, size_t *mol_pkl_sz,
|
|
const char *key) {
|
|
auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz);
|
|
short res = mol.hasProp(key);
|
|
if (res) {
|
|
mol.clearProp(key);
|
|
mol_to_pkl(mol, mol_pkl, mol_pkl_sz);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
extern "C" void keep_props(char **mol_pkl, size_t *mol_pkl_sz,
|
|
const char *details_json) {
|
|
auto mol = mol_from_pkl(*mol_pkl, *mol_pkl_sz);
|
|
unsigned int propFlags = PicklerOps::PropertyPickleOptions::AllProps ^
|
|
PicklerOps::PropertyPickleOptions::ComputedProps;
|
|
MinimalLib::updatePropertyPickleOptionsFromJSON(propFlags, details_json);
|
|
mol_to_pkl(mol, mol_pkl, mol_pkl_sz, propFlags);
|
|
}
|
|
|
|
extern "C" short add_mol_to_png_blob(char **png_blob, size_t *png_blob_sz,
|
|
const char *pkl, size_t pkl_sz,
|
|
const char *details_json) {
|
|
if (!png_blob || !*png_blob || !png_blob_sz || !*png_blob_sz || !pkl ||
|
|
!pkl_sz) {
|
|
return 0;
|
|
}
|
|
PNGMetadataParams params;
|
|
MinimalLib::updatePNGMetadataParamsFromJSON(params, details_json);
|
|
std::string pngString(*png_blob, *png_blob_sz);
|
|
try {
|
|
auto mol = mol_from_pkl(pkl, pkl_sz);
|
|
auto updatedPngString = addMolToPNGString(mol, pngString, params);
|
|
auto updated_png_blob =
|
|
static_cast<char *>(malloc(updatedPngString.size()));
|
|
if (!updated_png_blob) {
|
|
return 0;
|
|
}
|
|
memcpy(updated_png_blob, updatedPngString.data(), updatedPngString.size());
|
|
free(*png_blob);
|
|
*png_blob = updated_png_blob;
|
|
*png_blob_sz = updatedPngString.size();
|
|
} catch (...) {
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
extern "C" short get_mol_from_png_blob(const char *png_blob, size_t png_blob_sz,
|
|
char **pkl, size_t *pkl_sz,
|
|
const char *details_json) {
|
|
if (!png_blob || !png_blob_sz || !pkl || !pkl_sz) {
|
|
return 0;
|
|
}
|
|
std::string pngString(png_blob, png_blob_sz);
|
|
auto mols = MinimalLib::get_mols_from_png_blob_internal(pngString, true,
|
|
details_json);
|
|
if (mols.empty()) {
|
|
return 0;
|
|
}
|
|
char *pkl_local = nullptr;
|
|
size_t pkl_sz_local = 0;
|
|
mol_to_pkl(*mols.front(), &pkl_local, &pkl_sz_local);
|
|
if (pkl_local && pkl_sz_local) {
|
|
*pkl = pkl_local;
|
|
*pkl_sz = pkl_sz_local;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
extern "C" short get_mols_from_png_blob(const char *png_blob,
|
|
size_t png_blob_sz, char ***pkl_array,
|
|
size_t **pkl_sz_array,
|
|
const char *details_json) {
|
|
if (!png_blob || !png_blob_sz || !pkl_array || !pkl_sz_array) {
|
|
return 0;
|
|
}
|
|
std::string pngString(png_blob, png_blob_sz);
|
|
auto mols = MinimalLib::get_mols_from_png_blob_internal(pngString, false,
|
|
details_json);
|
|
if (mols.empty()) {
|
|
return 0;
|
|
}
|
|
char **pkl_array_local = nullptr;
|
|
size_t *pkl_sz_array_local = nullptr;
|
|
size_t mol_array_len = mols.size() + 1;
|
|
pkl_array_local = (char **)malloc(mol_array_len * sizeof(char *));
|
|
if (pkl_array_local) {
|
|
memset(pkl_array_local, 0, mol_array_len * sizeof(char *));
|
|
pkl_sz_array_local = (size_t *)malloc(mol_array_len * sizeof(size_t));
|
|
}
|
|
if (pkl_sz_array_local) {
|
|
memset(pkl_sz_array_local, 0, mol_array_len * sizeof(size_t));
|
|
short i = 0;
|
|
for (const auto &mol : mols) {
|
|
mol_to_pkl(*mol, &pkl_array_local[i], &pkl_sz_array_local[i]);
|
|
if (pkl_array_local[i] && pkl_sz_array_local[i]) {
|
|
++i;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if (i == static_cast<short>(mols.size())) {
|
|
*pkl_array = pkl_array_local;
|
|
*pkl_sz_array = pkl_sz_array_local;
|
|
return i;
|
|
}
|
|
}
|
|
free_mol_array(&pkl_array_local, &pkl_sz_array_local);
|
|
return 0;
|
|
}
|
|
|
|
extern "C" void free_mol_array(char ***pkl_array, size_t **pkl_sz_array) {
|
|
if (pkl_array && *pkl_array) {
|
|
for (size_t i = 0; (*pkl_array)[i]; ++i) {
|
|
free((*pkl_array)[i]);
|
|
(*pkl_array)[i] = NULL;
|
|
}
|
|
free(*pkl_array);
|
|
*pkl_array = NULL;
|
|
}
|
|
if (pkl_sz_array && *pkl_sz_array) {
|
|
free(*pkl_sz_array);
|
|
*pkl_sz_array = NULL;
|
|
}
|
|
}
|
|
|
|
#if (defined(__GNUC__) || defined(__GNUG__))
|
|
#pragma GCC diagnostic pop
|
|
#endif
|