diff --git a/Code/MinimalLib/CMakeLists.txt b/Code/MinimalLib/CMakeLists.txt index 889c562cf..21cc55d02 100644 --- a/Code/MinimalLib/CMakeLists.txt +++ b/Code/MinimalLib/CMakeLists.txt @@ -10,7 +10,9 @@ if(RDK_BUILD_MINIMAL_LIB) endif() endif() add_executable(RDKit_minimal jswrapper.cpp minilib.cpp) - target_link_libraries(RDKit_minimal MolInterchange_static Abbreviations_static CIPLabeler_static MolDraw2D_static Depictor_static RDInchiLib_static SubstructMatch_static FileParsers_static + target_link_libraries(RDKit_minimal MolInterchange_static Abbreviations_static + CIPLabeler_static MolDraw2D_static Depictor_static RDInchiLib_static + SubstructMatch_static SubstructLibrary_static FileParsers_static SmilesParse_static GraphMol_static RDGeometryLib_static RDGeneral_static) set_target_properties(RDKit_minimal PROPERTIES LINK_FLAGS "--bind") diff --git a/Code/MinimalLib/common.h b/Code/MinimalLib/common.h index e0da48947..957c8101c 100755 --- a/Code/MinimalLib/common.h +++ b/Code/MinimalLib/common.h @@ -68,7 +68,9 @@ static constexpr unsigned int d_defaultHeight = 200; RWMol *mol_from_input(const std::string &input, const std::string &details_json = "") { bool sanitize = true; + bool kekulize = true; bool removeHs = true; + bool mergeQueryHs = false; RWMol *res = nullptr; boost::property_tree::ptree pt; if (!details_json.empty()) { @@ -76,7 +78,9 @@ RWMol *mol_from_input(const std::string &input, ss.str(details_json); boost::property_tree::read_json(ss, pt); LPT_OPT_GET(sanitize); + LPT_OPT_GET(kekulize); LPT_OPT_GET(removeHs); + LPT_OPT_GET(mergeQueryHs); } try { if (input.find("M END") != std::string::npos) { @@ -109,9 +113,17 @@ RWMol *mol_from_input(const std::string &input, if (res) { try { if (sanitize) { - MolOps::sanitizeMol(*res); + unsigned int failedOp; + unsigned int sanitizeOps = MolOps::SANITIZE_ALL; + if (!kekulize) { + sanitizeOps ^= MolOps::SANITIZE_KEKULIZE; + } + MolOps::sanitizeMol(*res, failedOp, sanitizeOps); } MolOps::assignStereochemistry(*res, true, true, true); + if (mergeQueryHs) { + MolOps::mergeQueryHs(*res); + } } catch (...) { delete res; res = nullptr; @@ -130,7 +142,6 @@ RWMol *mol_from_input(const std::string &input, const char *details_json) { RWMol *qmol_from_input(const std::string &input, const std::string &details_json = "") { RWMol *res = nullptr; - bool sanitize = false; bool removeHs = true; boost::property_tree::ptree pt; if (!details_json.empty()) { @@ -138,7 +149,6 @@ RWMol *qmol_from_input(const std::string &input, std::istringstream ss; ss.str(details_json); boost::property_tree::read_json(ss, pt); - LPT_OPT_GET(sanitize); LPT_OPT_GET(removeHs); } if (input.find("M END") != std::string::npos) { diff --git a/Code/MinimalLib/docs/GettingStartedInJS.html b/Code/MinimalLib/docs/GettingStartedInJS.html index 05688b7d2..8bf5511c0 100644 --- a/Code/MinimalLib/docs/GettingStartedInJS.html +++ b/Code/MinimalLib/docs/GettingStartedInJS.html @@ -156,6 +156,7 @@ The currently supported options are: atomLabelDeuteriumTritium, dummiesAreAttachments, circleAtoms, +splitBonds, continuousHighlight, fillHighlights, highlightRadius, @@ -170,6 +171,7 @@ fontFile, multipleBondOffset, padding, additionalAtomLabelPadding, +noAtomLabels, bondLineWidth, scaleBondWidth, scaleHighlightBondWidth, @@ -180,21 +182,24 @@ fixedBondLength, rotate, addAtomIndices, addBondIndices, +isotopeLabels, +dummyIsotopeLabels, addStereoAnnotation, atomHighlightsAreCircles, centreMoleculesBeforeDrawing, explicitMethyl, includeMetadata, includeRadicals, -highlightColour, -backgroundColour, -legendColour, -symbolColour, -atomLabels +comicMode, +variableBondWidthMultiplier, +variableAtomRadius, +includeChiralFlagLabel, +simplifiedStereoGroupLabel, +singleColourWedgeBonds -

It's often useful to generate molecule renderings where the coordinates of a core is constrained. +

It's often useful to generate molecule renderings where the coordinates of a core are constrained.

+
+
+
+ + +
+
+

+ +

The SubstructLibrary functionality is exposed to enable running fast substructure searches +taking advantage of pre-filtering through pattern fingerprints: +

+
+ +
+
+
+ + + + + + +
+
+

diff --git a/Code/MinimalLib/jswrapper.cpp b/Code/MinimalLib/jswrapper.cpp index a3738fd8f..59db65bbc 100644 --- a/Code/MinimalLib/jswrapper.cpp +++ b/Code/MinimalLib/jswrapper.cpp @@ -88,6 +88,10 @@ std::string draw_to_canvas_with_highlights(JSMol &self, emscripten::val canvas, return ""; } +JSMol *get_mol_no_details(const std::string &input) { + return get_mol(input, std::string()); +} + } // namespace using namespace emscripten; @@ -138,6 +142,9 @@ EMSCRIPTEN_BINDINGS(RDKit_minimal) { .function("generate_aligned_coords", select_overload( &JSMol::generate_aligned_coords)) + .function("generate_aligned_coords", + select_overload( + &JSMol::generate_aligned_coords)) .function("condense_abbreviations", select_overload(&JSMol::condense_abbreviations)) .function("condense_abbreviations", @@ -146,9 +153,34 @@ EMSCRIPTEN_BINDINGS(RDKit_minimal) { .function("add_hs", &JSMol::add_hs) .function("remove_hs", &JSMol::remove_hs); + class_("SubstructLibrary") + .constructor<>() + .constructor() + .function("add_mol", &JSSubstructLibrary::add_mol) + .function("add_smiles", &JSSubstructLibrary::add_smiles) + .function("add_trusted_smiles", &JSSubstructLibrary::add_trusted_smiles) + .function("get_mol", &JSSubstructLibrary::get_mol, allow_raw_pointers()) + .function( + "get_matches", + select_overload( + &JSSubstructLibrary::get_matches)) + .function("get_matches", + select_overload( + &JSSubstructLibrary::get_matches)) + .function("get_matches", + select_overload( + &JSSubstructLibrary::get_matches)) + .function("count_matches", + select_overload( + &JSSubstructLibrary::count_matches)) + .function("count_matches", + select_overload( + &JSSubstructLibrary::count_matches)); + function("version", &version); function("prefer_coordgen", &prefer_coordgen); function("get_inchikey_for_inchi", &get_inchikey_for_inchi); function("get_mol", &get_mol, allow_raw_pointers()); + function("get_mol", &get_mol_no_details, allow_raw_pointers()); function("get_qmol", &get_qmol, allow_raw_pointers()); } diff --git a/Code/MinimalLib/minilib.cpp b/Code/MinimalLib/minilib.cpp index 3cc4fe6cd..aa29d3856 100644 --- a/Code/MinimalLib/minilib.cpp +++ b/Code/MinimalLib/minilib.cpp @@ -17,12 +17,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include #include @@ -287,7 +287,8 @@ std::string JSMol::condense_abbreviations_from_defs( std::string JSMol::generate_aligned_coords(const JSMol &templateMol, bool useCoordGen, - bool allowRGroups) { + bool allowRGroups, + bool acceptFailure) { std::string res; if (!d_mol || !templateMol.d_mol || !templateMol.d_mol->getNumConformers()) return res; @@ -297,7 +298,6 @@ std::string JSMol::generate_aligned_coords(const JSMol &templateMol, RDDepict::preferCoordGen = useCoordGen; #endif RDKit::ROMol *refPattern = nullptr; - bool acceptFailure = true; int confId = -1; RDKit::MatchVectType match = RDDepict::generateDepictionMatching2DStructure( *d_mol, *(templateMol.d_mol), confId, refPattern, acceptFailure, false, @@ -310,6 +310,8 @@ std::string JSMol::generate_aligned_coords(const JSMol &templateMol, rj::Writer writer(buffer); doc.Accept(writer); res = buffer.GetString(); + } else { + res = "{}"; } #ifdef RDK_BUILD_COORDGEN_SUPPORT RDDepict::preferCoordGen = oprefer; @@ -317,12 +319,86 @@ std::string JSMol::generate_aligned_coords(const JSMol &templateMol, return res; }; +JSSubstructLibrary::JSSubstructLibrary(unsigned int num_bits) + : d_sslib(new SubstructLibrary( + boost::shared_ptr( + new CachedTrustedSmilesMolHolder()), + boost::shared_ptr(new PatternHolder()))), + d_num_bits(num_bits) { + d_molHolder = dynamic_cast( + d_sslib->getMolHolder().get()); + d_fpHolder = dynamic_cast(d_sslib->getFpHolder().get()); +} + +int JSSubstructLibrary::add_trusted_smiles(const std::string &smi) { + std::unique_ptr mol(SmilesToMol(smi, 0, false)); + if (!mol) { + return -1; + } + mol->updatePropertyCache(); + ExplicitBitVect *bv = PatternFingerprintMol(*mol, d_num_bits); + if (!bv) { + return -1; + } + d_fpHolder->addFingerprint(bv); + auto ret = d_molHolder->addSmiles(smi); + return ret; +} + +inline int JSSubstructLibrary::add_mol_helper(const ROMol &mol) { + std::string smi = MolToSmiles(mol); + return add_trusted_smiles(smi); +} + +int JSSubstructLibrary::add_mol(const JSMol &m) { + return add_mol_helper(*m.d_mol); +} + +int JSSubstructLibrary::add_smiles(const std::string &smi) { + std::unique_ptr mol(SmilesToMol(smi)); + if (!mol) { + return -1; + } + return add_mol_helper(*mol); +} + +JSMol *JSSubstructLibrary::get_mol(unsigned int i) { + return new JSMol(new RWMol(*d_sslib->getMol(i))); +} + +std::string JSSubstructLibrary::get_matches(const JSMol &q, bool useChirality, + int numThreads, + int maxResults) const { + if (!d_sslib->size()) { + return "[]"; + } + std::vector indices = d_sslib->getMatches( + *q.d_mol, true, useChirality, false, numThreads, maxResults); + rj::Document doc; + doc.SetArray(); + auto &alloc = doc.GetAllocator(); + for (const auto &i : indices) { + doc.PushBack(i, alloc); + } + rj::StringBuffer buffer; + rj::Writer writer(buffer); + doc.Accept(writer); + std::string res = buffer.GetString(); + return res; +} + +unsigned int JSSubstructLibrary::count_matches(const JSMol &q, + bool useChirality, + int numThreads) const { + return d_sslib->countMatches(*q.d_mol, true, useChirality, false, 1); +} + std::string get_inchikey_for_inchi(const std::string &input) { return InchiToInchiKey(input); } -JSMol *get_mol(const std::string &input) { - RWMol *mol = MinimalLib::mol_from_input(input); +JSMol *get_mol(const std::string &input, const std::string &details_json) { + RWMol *mol = MinimalLib::mol_from_input(input, details_json); return new JSMol(mol); } diff --git a/Code/MinimalLib/minilib.h b/Code/MinimalLib/minilib.h index 9ce969e09..30bd77e16 100644 --- a/Code/MinimalLib/minilib.h +++ b/Code/MinimalLib/minilib.h @@ -10,6 +10,7 @@ // #include #include +#include class JSMol { public: @@ -38,13 +39,17 @@ class JSMol { double maxCoverage, bool areLinkers); std::string generate_aligned_coords(const JSMol &templateMol, - bool useCoordGen, bool allowRGroups); + bool useCoordGen, bool allowOptionalAttachments, bool acceptFailure); + std::string generate_aligned_coords(const JSMol &templateMol, + bool useCoordGen, bool allowOptionalAttachments) { + return generate_aligned_coords(templateMol, useCoordGen, allowOptionalAttachments, true); + }; std::string generate_aligned_coords(const JSMol &templateMol, bool useCoordGen) { - return generate_aligned_coords(templateMol, useCoordGen, false); + return generate_aligned_coords(templateMol, useCoordGen, false, true); }; std::string generate_aligned_coords(const JSMol &templateMol) { - return generate_aligned_coords(templateMol, false, false); + return generate_aligned_coords(templateMol, false, false, true); }; bool is_valid() const { return d_mol.get() != nullptr; }; @@ -63,8 +68,45 @@ class JSMol { static constexpr unsigned int d_defaultHeight = 200; }; +class JSSubstructLibrary { + public: + JSSubstructLibrary(unsigned int num_bits); + JSSubstructLibrary() : JSSubstructLibrary(d_defaultNumBits) {} + int add_mol(const JSMol &m); + int add_smiles(const std::string &smi); + int add_trusted_smiles(const std::string &smi); + JSMol *get_mol(unsigned int i); + std::string get_matches(const JSMol &q, bool useChirality, int numThreads, + int maxResults) const; + std::string get_matches(const JSMol &q, int maxResults) const { + return get_matches(q, d_defaultUseChirality, d_defaultNumThreads, + maxResults); + } + std::string get_matches(const JSMol &q) const { + return get_matches(q, d_defaultUseChirality, d_defaultNumThreads, + d_defaultMaxResults); + } + unsigned int count_matches(const JSMol &q, bool useChirality, + int numThreads) const; + unsigned int count_matches(const JSMol &q) const { + return count_matches(q, d_defaultUseChirality, d_defaultNumThreads); + } + + std::unique_ptr d_sslib; + RDKit::CachedTrustedSmilesMolHolder *d_molHolder; + RDKit::PatternHolder *d_fpHolder; + unsigned int d_num_bits; + static constexpr unsigned int d_defaultNumBits = 2048; + static constexpr bool d_defaultUseChirality = true; + static constexpr int d_defaultNumThreads = -1; + static constexpr int d_defaultMaxResults = 1000; + + private: + inline int add_mol_helper(const RDKit::ROMol &mol); +}; + std::string get_inchikey_for_inchi(const std::string &input); -JSMol *get_mol(const std::string &input); +JSMol *get_mol(const std::string &input, const std::string &details_json); JSMol *get_qmol(const std::string &input); std::string version(); void prefer_coordgen(bool prefer); diff --git a/Code/MinimalLib/tests/tests.js b/Code/MinimalLib/tests/tests.js index d44476a0a..fc84b4e33 100644 --- a/Code/MinimalLib/tests/tests.js +++ b/Code/MinimalLib/tests/tests.js @@ -10,12 +10,17 @@ // const assert = require('assert'); +const { + performance + } = require('perf_hooks'); var initRDKitModule = require("../demo/RDKit_minimal.js"); var RDKitModule; +const fs = require('fs'); +const readline = require('readline'); // the goal here isn't to be comprehensive (the RDKit has tests for that), // just to make sure that the wrappers are working as expected -function test_basics(){ +function test_basics() { var bmol = RDKitModule.get_mol("c1ccccc"); assert.equal(bmol.is_valid(),0); @@ -58,7 +63,7 @@ function test_basics(){ assert(svg2.search("#FF7F7F")>0); } -function test_molblock_nostrict(){ +function test_molblock_nostrict() { var molblock = ` MJ201100 @@ -99,14 +104,43 @@ M END`; assert.equal(qmb.includes("M SAP 1 1 8 6"), true); } -function test_sketcher_services(){ +function test_molblock_rgp() { + var molblock = ` + MJ190400 + + 9 9 0 0 0 0 0 0 0 0999 V2000 + -6.5623 0.3105 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0 + -5.8478 -0.1019 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -5.1333 0.3105 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + -4.4188 -0.1019 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + -4.4188 -0.9269 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -5.1333 -1.3394 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -5.8478 -0.9269 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -3.7043 -1.3394 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + -2.9898 -0.9268 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0 + 3 4 4 0 0 0 0 + 4 5 4 0 0 0 0 + 5 6 4 0 0 0 0 + 6 7 4 0 0 0 0 + 2 3 4 0 0 0 0 + 2 7 4 0 0 0 0 + 5 8 1 0 0 0 0 + 8 9 1 0 0 0 0 + 1 2 1 0 0 0 0 +M RGP 2 1 2 9 1 +M END`; + var mol = RDKitModule.get_mol(molblock); + assert.equal(mol.is_valid(),1); +} + +function test_sketcher_services() { var mol = RDKitModule.get_mol("C[C@](F)(Cl)/C=C/C(F)Br"); assert.equal(mol.is_valid(),1); var tags = mol.get_stereo_tags(); assert.equal(tags,'{"CIP_atoms":[[1,"(S)"],[6,"(?)"]],"CIP_bonds":[[4,5,"(E)"]]}'); } -function test_sketcher_services2(){ +function test_sketcher_services2() { var mol = RDKitModule.get_mol("c1ccccc1"); assert.equal(mol.is_valid(),1); var molb = mol.add_hs(); @@ -124,7 +158,7 @@ function test_sketcher_services2(){ } -function test_abbreviations(){ +function test_abbreviations() { var bmol = RDKitModule.get_mol("C1CCC1C(F)(F)F"); assert.equal(bmol.is_valid(),1); bmol.condense_abbreviations(); @@ -133,8 +167,92 @@ function test_abbreviations(){ assert.equal(bmol.get_cxsmiles(),"*C1CCC1 |$CF3;;;;$|"); } +function test_substruct_library(done) { + done.test_substruct_library = false; + var smiReader = readline.createInterface({ + input: fs.createReadStream(__dirname + '/../../GraphMol/test_data/compounds.smi') + }); + var sslib = new RDKitModule.SubstructLibrary(); + // var t0 = performance.now() + // console.log('Started adding trusted SMILES'); + smiReader.on('line', (smi) => { + sslib.add_trusted_smiles(smi); + }); + smiReader.on('close', () => { + var query = RDKitModule.get_qmol("N"); + // var t1 = performance.now(); + // console.log('Finished adding trusted SMILES took ' + (t1 - t0) / 1000 + ' seconds'); + assert.equal(sslib.count_matches(query), 52); + assert.equal(sslib.get_matches(query), JSON.stringify([ + 12,13,19,22,24,30,31,32,35,36,39,41,43,44,55,56,58,64,72,80, + 85,95,96,101,105,113,124,127,128,131,143,150,151,185,201,202, + 203,214,215,223,232,234,238,240,241,246,258,261,263,265,266,284 + ])); + done.test_substruct_library = true; + }); +} -function test_generate_aligned_coords(){ +function test_substruct_library_merge_hs() { + var sslib = new RDKitModule.SubstructLibrary(); + var mol1 = RDKitModule.get_mol("c1ccccc1"); + var mol2 = RDKitModule.get_mol("Cc1ccccc1"); + sslib.add_trusted_smiles(mol1.get_smiles()); + sslib.add_trusted_smiles(mol2.get_smiles()); + var query = RDKitModule.get_mol(` + MJ201100 2D + + 6 6 0 0 0 0 0 0 0 0999 V2000 + -1.0491 0.7134 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.7635 0.3009 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.7635 -0.5241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -1.0491 -0.9366 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.3346 -0.5241 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.3346 0.3009 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 2 3 1 0 0 0 0 + 5 6 2 0 0 0 0 + 1 2 2 0 0 0 0 + 6 1 1 0 0 0 0 + 3 4 2 0 0 0 0 + 4 5 1 0 0 0 0 +M END`); + assert.equal(sslib.get_matches(query), JSON.stringify([0, 1])); + var query_hs = RDKitModule.get_mol(query.add_hs()); + assert.equal(sslib.get_matches(query_hs), JSON.stringify([])); + query_hs = RDKitModule.get_mol(query_hs.get_molblock(), JSON.stringify({ mergeQueryHs: true })); + assert.equal(sslib.get_matches(query_hs), JSON.stringify([0])); +} + +function test_substruct_library_empty_mols() { + var sslib = new RDKitModule.SubstructLibrary(); + var mol1 = RDKitModule.get_mol(""); + var mol2 = RDKitModule.get_mol(""); + sslib.add_trusted_smiles(mol1.get_smiles()); + sslib.add_trusted_smiles(mol2.get_smiles()); + var query = RDKitModule.get_mol("C"); + assert.equal(sslib.get_matches(query), JSON.stringify([])); + var empty_query = RDKitModule.get_mol(""); + assert.equal(sslib.get_matches(empty_query), JSON.stringify([])); +} + +function test_substruct_library_empty_query() { + var sslib = new RDKitModule.SubstructLibrary(); + var mol1 = RDKitModule.get_mol("C"); + var mol2 = RDKitModule.get_mol("CC"); + sslib.add_trusted_smiles(mol1.get_smiles()); + sslib.add_trusted_smiles(mol2.get_smiles()); + var query = RDKitModule.get_mol(""); + assert.equal(sslib.get_matches(query), JSON.stringify([])); +} + +function test_substruct_library_empty_lib() { + var sslib = new RDKitModule.SubstructLibrary(); + var query = RDKitModule.get_mol("C"); + assert.equal(sslib.get_matches(query), JSON.stringify([])); + var empty_query = RDKitModule.get_mol(""); + assert.equal(sslib.get_matches(empty_query), JSON.stringify([])); +} + +function test_generate_aligned_coords() { var smiles = "CCC"; var mol = RDKitModule.get_mol(smiles); var template = "CC"; @@ -143,7 +261,7 @@ function test_generate_aligned_coords(){ } -function test_isotope_labels(){ +function test_isotope_labels() { var mol = RDKitModule.get_mol("[1*]c1cc([2*])c([3*])c[14c]1"); assert.equal(mol.is_valid(), 1); @@ -165,7 +283,8 @@ function test_isotope_labels(){ assert.ok(res.every((resItem, i) => (resItem === resSorted[i]))); } -function test_generate_aligned_coords_allow_rgroups(){ + +function test_generate_aligned_coords_allow_rgroups() { var template_molblock = ` RDKit 2D @@ -214,16 +333,107 @@ M END`; } +function test_accept_failure() { + var template_molblock = ` + RDKit 2D + + 9 9 0 0 0 0 0 0 0 0999 V2000 + -0.8929 1.0942 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -2.1919 0.3442 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -2.1919 -1.1558 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.8929 -1.9059 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.4060 -1.1558 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.4060 0.3442 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -3.4910 1.0942 0.0000 R1 0 0 0 0 0 0 0 0 0 0 0 0 + 1.7051 1.0942 0.0000 R2 0 0 0 0 0 0 0 0 0 0 0 0 + -3.4910 -1.9059 0.0000 R3 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 2 0 + 2 3 1 0 + 3 4 2 0 + 4 5 1 0 + 5 6 2 0 + 6 1 1 0 + 6 8 1 0 + 3 9 1 0 + 2 7 1 0 +M RGP 3 7 1 8 2 9 3 +M END +`; + var mol_molblock = ` + RDKit 2D + + 9 9 0 0 0 0 0 0 0 0999 V2000 + -0.8929 1.0942 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0 + -2.1919 0.3442 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -2.1919 -1.1558 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -0.8929 -1.9059 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.4060 -1.1558 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + 0.4060 0.3442 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0 + -3.4910 1.0942 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0 + 1.7051 1.0942 0.0000 Cl 0 0 0 0 0 0 0 0 0 0 0 0 + -3.4910 -1.9059 0.0000 Br 0 0 0 0 0 0 0 0 0 0 0 0 + 1 2 2 0 + 2 3 1 0 + 3 4 2 0 + 4 5 1 0 + 5 6 2 0 + 6 1 1 0 + 6 8 1 0 + 3 9 1 0 + 2 7 1 0 +M END +`; + var template_ref = RDKitModule.get_mol(template_molblock); + var mol = RDKitModule.get_mol(mol_molblock); + var hasThrown = false; + try { + mol.generate_aligned_coords(template_ref, false, true, false); + } catch (e) { + hasThrown = true; + } + assert(hasThrown); + assert.equal(mol.get_molblock(), mol_molblock); +} + +function test_get_mol_no_kekulize() { + var mol = RDKitModule.get_mol("c"); + assert(!mol.is_valid()); + mol = RDKitModule.get_mol("c", JSON.stringify({kekulize: false})); + assert(mol.is_valid()); +} + + initRDKitModule().then(function(instance) { + var done = {}; + const waitAllTestsFinished = () => { + const poll = resolve => { + if (Object.values(done).every(v => v)) { + resolve(); + } else { + setTimeout(() => poll(resolve), 100); + } + } + return new Promise(poll); + } RDKitModule = instance; console.log(RDKitModule.version()); test_basics(); test_molblock_nostrict(); + test_molblock_rgp(); test_sketcher_services(); test_sketcher_services2(); test_abbreviations(); + test_substruct_library(done); + test_substruct_library_merge_hs(); + test_substruct_library_empty_mols(); + test_substruct_library_empty_lib(); + test_substruct_library_empty_query(); test_generate_aligned_coords(); test_isotope_labels(); test_generate_aligned_coords_allow_rgroups(); - console.log("Tests finished successfully"); + test_accept_failure(); + test_get_mol_no_kekulize(); + waitAllTestsFinished().then(() => + console.log("Tests finished successfully") + ); });