Files
rdkit/Code/GraphMol/ChemTransforms/testChemTransforms.cpp
Ric a6b26253ff Fix (most of) mem problems (#2123)
* do not use new on loggers

* del pointers in testDistGeom

* Update Dict hasNonPOD status on bulk update

* delete new Dicts in memtest1.cpp

* fixes in MolSuppliers and testFMCS

* PeriodicTable singleton as unique_ptr

* fix EEM_arrays leak

* fix leaks in testPBF

* fix ParamCollection leak in test UFF

* fix leaks in MMFF

* clear prop dict before read in in pickler

* fix leaks in testFreeSASA

* fix leaks in test3D

* modernize Dict.h & SmilesParse.cpp

* fix leaks in testQuery

* fix leaks in testCrystalFF

* fix leaks in cxsmilesTest

* fix leaks in Catalog & mol cat test

* fix leaks in ShapeUtils & tests

* fix leaks in testSubgraphs1

* fix leaks testFingerprintGenerators

* fix leaks in Catalog/FilterCatalog

* fix leaks in graphmolqueryTest

* these changes reduce bison parse leaks

* fixed leaks in testChirality.cpp

* fix leaks + 2 tests in testMolWriter

* fix 4m leaks in substructLibraryTest

* small improvements to molTautomerTest; still leaks

* fix leaks in testRGroupDecomp

* fix leaks in test; parser still leaks

* fix leaks in itertest

* fix 4m leaks in testDepictor

* fixes in smatest; still leaking due to parser

* fixes in testSLNParse; still leaking due to parser

* flex/bison: always add atoms with ownership; smarts error cleanup

* fix leaks in testReaction

* fix leaks in testSubstructMatch

* fix leaks in resMolSupplierTest

* fix leaks in testChemTransforms + bug in ChemTransforms

* fix leaks in testPickler

* fix leaks in testMolTransform

* fix leaks in testFragCatalog

* fix leak in testSLNParse. Still leaks due to Smiles

* fixed most leaks in testMolSupplier

* pre bison fix

* fix some atom & bond parse problems; others still fail

* bison smiles & smarts, atoms & bonds more or less fixed

* fix leaks in molopstest.cpp

* fix leaks in testFingerprints, MACCS.cpp & AtomPairs.cpp

* fix leaks in moldraw2Dtest1

* fix leaks in testDescriptors

* fix leaks in testInchi

* fix leaks in testUFFForceFieldHelpers

* fix leaks in hanoiTest & new_canon.h

* fix leaks in testMMFFForceField

* fix leaks in graphmolTest1

* fix leaks in testMMFFForceFieldHelpers

* fix leaks in testDistGeomHelpers

* fix leaks in testMolAlign

* initialize occupancy & temp facto with default values

* fix leak in TautomerTransform

* updated suppressions

* fix testStructChecker

* fix logging & py tests

* fix TautomerTransform class/struct issue

* remove misplaced delete in testSLNParse

* deinit in testAvalonLib1

* fix Avalon-triggered(?) bug in StructChecker/Pattern.cpp

* fix random testMolWriter/Supplier fails

- diversify output file names to avoid clashing.
- unify Writers close/destruct behavior.
- flushing/closing in tests.

* use reset in FFs Params.cpp

* comments on testMMFFForceField

* unrequired 'if's added to mol suppliers

* correct cast in FilterCatalog.h

* use unique_ptr in MACCS Patterns

* remove unrequred if in new_canon

* update & move suppressions
2018-10-29 14:33:26 +00:00

2087 lines
62 KiB
C++

//
// Copyright (C) 2006-2018 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.
//
#include <RDGeneral/test.h>
#include <RDGeneral/RDLog.h>
#include <RDGeneral/utils.h>
#include <GraphMol/RDKitBase.h>
#include <string>
#include <iostream>
#include <GraphMol/SmilesParse/SmilesParse.h>
#include <GraphMol/SmilesParse/SmilesWrite.h>
#include <GraphMol/ChemTransforms/ChemTransforms.h>
#include <GraphMol/FileParsers/FileParsers.h>
#include <GraphMol/FileParsers/MolSupplier.h>
#include <GraphMol/Substruct/SubstructMatch.h>
#include <RDGeneral/Exceptions.h>
using namespace RDKit;
void testDeleteSubstruct() {
ROMol *mol1 = nullptr, *mol2 = nullptr, *matcher1 = nullptr,
*matcher2 = nullptr, *matcher3 = nullptr;
std::string smi, sma;
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing deleteSubstruct" << std::endl;
// a lot of the seemingly repetitive stuff is here for Issue96
smi = "CCC(=O).C=O";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
TEST_ASSERT(mol1->getNumAtoms() == 6)
sma = "C=O";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
mol2 = deleteSubstructs(*mol1, *matcher1, 0);
delete mol1;
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 2)
mol1 = deleteSubstructs(*mol2, *matcher1, 0);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 2)
delete matcher1;
delete mol1;
delete mol2;
sma = "[Cl;H1&X1,-]";
matcher1 = SmartsToMol(sma);
sma = "[Na+]";
matcher2 = SmartsToMol(sma);
sma = "[O;H2,H1&-,X0&-2]";
matcher3 = SmartsToMol(sma);
mol1 = SmilesToMol("CCO.Cl");
TEST_ASSERT(mol1);
TEST_ASSERT(mol1->getNumAtoms() == 4);
mol2 = deleteSubstructs(*mol1, *matcher1, true);
delete mol1;
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 3);
mol1 = deleteSubstructs(*mol2, *matcher2, true);
delete mol1;
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 3);
mol1 = deleteSubstructs(*mol2, *matcher3, true);
delete mol1;
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 3);
delete mol2;
delete matcher3;
mol1 = SmilesToMol("CC(=O)[O-].[Na+]");
TEST_ASSERT(mol1);
TEST_ASSERT(mol1->getNumAtoms() == 5);
delete matcher1;
matcher1 = SmartsToMol("[Cl;H1&X1,-]");
delete matcher2;
matcher2 = SmartsToMol("[Na+]");
mol2 = deleteSubstructs(*mol1, *matcher1, true);
delete mol1;
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 5);
mol1 = deleteSubstructs(*mol2, *matcher2, true);
delete mol2;
TEST_ASSERT(mol1);
TEST_ASSERT(mol1->getNumAtoms() == 4);
mol2 = deleteSubstructs(*mol1, *matcher1, true);
TEST_ASSERT(mol1);
TEST_ASSERT(mol1->getNumAtoms() == 4);
delete mol2;
delete mol1;
delete matcher1;
delete matcher2;
// test chiralty
smi = "CCO[C@H](N)(P)";
mol1 = SmilesToMol(smi);
matcher1 = SmartsToMol("O[C@H](N)(P)");
mol2 = deleteSubstructs(*mol1, *matcher1, false, true);
std::string smi1 = MolToSmiles(*mol2, true);
std::cerr << "1 smi: " << smi1 << std::endl;
TEST_ASSERT(smi1 == "CC");
delete mol2;
// still matches with non-chiral
mol2 = deleteSubstructs(*mol1, *matcher1, false, false);
smi1 = MolToSmiles(*mol2, true);
std::cerr << "1 smi: " << smi1 << std::endl;
TEST_ASSERT(smi1 == "CC");
delete mol2;
delete matcher1;
matcher1 = SmartsToMol("O[C@@H](N)(P)");
mol2 = deleteSubstructs(*mol1, *matcher1, false, true);
smi1 = MolToSmiles(*mol2, true);
std::cerr << "2 smi: " << smi1 << std::endl;
TEST_ASSERT(smi1 == "CCO[C@H](N)P");
delete mol2;
// still matches with non-chiral
mol2 = deleteSubstructs(*mol1, *matcher1, false, false);
smi1 = MolToSmiles(*mol2, true);
std::cerr << "2 smi: " << smi1 << std::endl;
TEST_ASSERT(smi1 == "CC");
delete mol2;
delete mol1;
delete matcher1;
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testReplaceSubstructs() {
ROMol *mol1 = nullptr, *matcher1 = nullptr, *frag = nullptr;
std::string smi, sma;
std::vector<ROMOL_SPTR> vect;
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing replaceSubstruct" << std::endl;
smi = "CCCC";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
sma = "C(=O)O";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
smi = "N";
frag = SmilesToMol(smi);
TEST_ASSERT(frag);
vect = replaceSubstructs(*mol1, *matcher1, *frag);
TEST_ASSERT(vect.size() == 1);
TEST_ASSERT(mol1->getNumAtoms() == 4);
TEST_ASSERT(vect[0]->getNumAtoms() == 4);
delete mol1;
smi = "CCCC(=O)O";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
vect = replaceSubstructs(*mol1, *matcher1, *frag);
TEST_ASSERT(vect.size() == 1);
TEST_ASSERT(mol1->getNumAtoms() == 6);
TEST_ASSERT(vect[0]->getNumAtoms() == 4);
vect = replaceSubstructs(*mol1, *matcher1, *frag, true);
TEST_ASSERT(vect.size() == 1);
TEST_ASSERT(mol1->getNumAtoms() == 6);
TEST_ASSERT(vect[0]->getNumAtoms() == 4);
delete mol1;
smi = "OC(=O)CCCC(=O)O";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
vect = replaceSubstructs(*mol1, *matcher1, *frag);
TEST_ASSERT(vect.size() == 2);
TEST_ASSERT(mol1->getNumAtoms() == 9);
TEST_ASSERT(vect[0]->getNumAtoms() == 7);
TEST_ASSERT(vect[1]->getNumAtoms() == 7);
// use replaceAll when a single replacement is available:
vect = replaceSubstructs(*mol1, *matcher1, *frag, true);
TEST_ASSERT(vect.size() == 1);
TEST_ASSERT(mol1->getNumAtoms() == 9);
TEST_ASSERT(vect[0]->getNumAtoms() == 5);
delete matcher1;
sma = "C=O";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
delete mol1;
smi = "CC(=O)C";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
vect = replaceSubstructs(*mol1, *matcher1, *frag);
TEST_ASSERT(vect.size() == 1);
TEST_ASSERT(mol1->getNumAtoms() == 4);
TEST_ASSERT(vect[0]->getNumAtoms() == 3);
delete mol1;
smi = "C1C(=O)C1";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
vect = replaceSubstructs(*mol1, *matcher1, *frag);
TEST_ASSERT(vect.size() == 1);
TEST_ASSERT(mol1->getNumAtoms() == 4);
TEST_ASSERT(vect[0]->getNumAtoms() == 3);
TEST_ASSERT(vect[0]->getNumBonds() == 3);
// test chirality
delete mol1;
delete matcher1;
sma = "P([C@H](N)O)";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
// test stereo matching
smi = "CCP([C@H](N)O)CC";
mol1 = SmilesToMol(smi);
vect = replaceSubstructs(*mol1, *matcher1, *frag, false, 0, true);
TEST_ASSERT(vect.size() == 1);
std::string smi1 = MolToSmiles(*vect[0], true);
TEST_ASSERT(smi1 == "CCNCC");
// should also match when matching non-chiral
vect = replaceSubstructs(*mol1, *matcher1, *frag, false, 0, false);
TEST_ASSERT(vect.size() == 1);
smi1 = MolToSmiles(*vect[0], true);
TEST_ASSERT(smi1 == "CCNCC");
delete mol1;
smi = "CCP([C@@H](N)O)CC";
mol1 = SmilesToMol(smi);
vect = replaceSubstructs(*mol1, *matcher1, *frag, false, 0, true);
TEST_ASSERT(vect.size() == 1);
smi1 = MolToSmiles(*vect[0], true);
std::cerr << "replaceSub smi1:" << smi1 << std::endl;
;
// no change
TEST_ASSERT(smi1 == "CCP(CC)[C@@H](N)O");
// should also match when matching non-chiral
vect = replaceSubstructs(*mol1, *matcher1, *frag, false, 0, false);
TEST_ASSERT(vect.size() == 1);
smi1 = MolToSmiles(*vect[0], true);
std::cerr << "replaceSub smi1:" << smi1 << std::endl;
delete mol1;
delete frag;
delete matcher1;
// no change
TEST_ASSERT(smi1 == "CCNCC");
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testReplaceSubstructs2() {
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "More testing of replaceSubstruct" << std::endl;
{
std::string smi = "CCC(=O)O";
ROMol *mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
std::string sma = "[$(O-C(=O))]";
ROMol *matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
std::string repl = "NC";
ROMol *frag = SmilesToMol(repl);
TEST_ASSERT(frag);
std::vector<ROMOL_SPTR> vect = replaceSubstructs(*mol1, *matcher1, *frag);
TEST_ASSERT(vect.size() == 1);
TEST_ASSERT(mol1->getNumAtoms() == 5);
TEST_ASSERT(vect[0]->getNumAtoms() == 6);
std::string csmi1 = MolToSmiles(*vect[0], true);
repl = "CN";
delete frag;
frag = SmilesToMol(repl);
TEST_ASSERT(frag);
vect = replaceSubstructs(*mol1, *matcher1, *frag, true, 1);
TEST_ASSERT(vect.size() == 1);
TEST_ASSERT(mol1->getNumAtoms() == 5);
TEST_ASSERT(vect[0]->getNumAtoms() == 6);
std::string csmi2 = MolToSmiles(*vect[0], true);
TEST_ASSERT(csmi2 == csmi1);
delete mol1;
delete frag;
delete matcher1;
}
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testReplaceSidechains() {
ROMol *mol1 = nullptr, *mol2 = nullptr, *matcher1 = nullptr;
std::string smi, sma;
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing replaceSidechains" << std::endl;
smi = "ClC1CC(F)C1";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
sma = "C1CCC1";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
mol2 = replaceSidechains(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 6);
delete mol2;
delete mol1;
smi = "ClC1C(F)C1";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
mol2 = replaceSidechains(*mol1, *matcher1);
TEST_ASSERT(!mol2);
delete mol1;
delete mol2;
delete matcher1;
sma = "C=O";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
smi = "CC=O";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
mol2 = replaceSidechains(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 3);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(smi == "[1*]C=O");
delete mol1;
delete mol2;
smi = "CC(C)=O";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
mol2 = replaceSidechains(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 4);
smi = MolToSmiles(*mol2, true);
// there's no way to guarantee the order here:
TEST_ASSERT(smi == "[1*]C([2*])=O" || smi == "[2*]C([1*])=O");
delete mol1;
delete mol2;
delete matcher1;
sma = "P([C@H](N)O)";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
smi = "CCP([C@H](N)O)CC";
mol1 = SmilesToMol(smi);
mol2 = replaceSidechains(*mol1, *matcher1, true);
TEST_ASSERT(mol2);
smi = MolToSmiles(*mol2, true);
std::cerr << "sidechains chiral=true smi1;;; " << smi << std::endl;
delete mol2;
mol2 = replaceSidechains(*mol1, *matcher1, true);
TEST_ASSERT(mol2);
smi = MolToSmiles(*mol2, true);
std::cerr << "sidechains chiral=false smi1;;; " << smi << std::endl;
delete mol1;
delete mol2;
delete matcher1;
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testReplaceCore() {
ROMol *mol1 = nullptr, *mol2 = nullptr, *matcher1 = nullptr;
std::string smi, sma;
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing replaceCore" << std::endl;
smi = "ClC1CC(F)C1";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
sma = "C1CC1";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(!mol2);
delete mol1;
delete mol2;
delete matcher1;
smi = "ClC1CC(F)C1";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
sma = "C1CCC1";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 4);
smi = MolToSmiles(*mol2, true);
// there's no way to guarantee the order here:
TEST_ASSERT(smi == "[1*]Cl.[2*]F" || smi == "[2*]Cl.[1*]F");
delete mol1;
delete mol2;
delete matcher1;
smi = "CCC=O";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
sma = "C=O";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 3);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(smi == "[1*]CC");
delete mol1;
delete mol2;
delete matcher1;
smi = "C1C(=O)CC1";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
sma = "C=O";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 5);
smi = MolToSmiles(*mol2, true);
// there's no way to guarantee the order here:
TEST_ASSERT(smi == "[1*]CCC[2*]" || smi == "[1*]CCC[2*]");
delete mol1;
delete mol2;
delete matcher1;
smi = "CNC";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
sma = "N";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 4);
smi = MolToSmiles(*mol2, true);
// there's no way to guarantee the order here:
TEST_ASSERT(smi == "[1*]C.[2*]C" || smi == "[2*]C.[1*]C");
delete mol1;
delete mol2;
delete matcher1;
smi = "OC1CCC1";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
sma = "[CH2][CH2][CH2]";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(mol2->getNumAtoms() == 4);
smi = MolToSmiles(*mol2, true);
// there's no way to guarantee the order here:
TEST_ASSERT(smi == "[2*]C([1*])O" || smi == "[1*]C([2*])O");
delete mol1;
delete mol2;
delete matcher1;
smi = "C/C=C/CN/C=C/O";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
sma = "N";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 9);
smi = MolToSmiles(*mol2, true);
// there's no way to guarantee the order here:
TEST_ASSERT(smi == "[1*]C/C=C/C.[2*]/C=C/O" ||
smi == "[1*]/C=C/O.[2*]C/C=C/C");
delete mol1;
delete mol2;
delete matcher1;
smi = "C[C@](F)(Cl)N";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
sma = "N";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 5);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(smi == "[1*][C@@](C)(F)Cl");
delete mol1;
delete mol2;
smi = "C[C@](F)(N)Cl";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 5);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(smi == "[1*][C@](C)(F)Cl");
delete mol1;
delete mol2;
smi = "N[C@](C)(F)Cl";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 5);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(smi == "[1*][C@](C)(F)Cl");
delete mol1;
delete mol2;
delete matcher1;
smi = "C[C@@](F)(Cl)N";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
sma = "N";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 5);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(smi == "[1*][C@](C)(F)Cl");
delete mol1;
delete mol2;
smi = "C[C@@](F)(N)Cl";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 5);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(smi == "[1*][C@@](C)(F)Cl");
smi = "C[C@@](N)(Cl)F";
delete mol1;
delete mol2;
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 5);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(smi == "[1*][C@@](C)(F)Cl");
delete mol1;
delete mol2;
delete matcher1;
smi = "C[C@H](F)N";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
sma = "N";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 4);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(smi == "[1*][C@H](C)F");
delete mol1;
delete mol2;
smi = "C[C@H](N)F";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 4);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(smi == "[1*][C@@H](C)F");
delete mol1;
delete mol2;
smi = "N[C@H](C)F";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 4);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(smi == "[1*][C@H](C)F");
delete mol1;
delete mol2;
smi = "F[C@H](C)N";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 4);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(smi == "[1*][C@@H](C)F");
delete mol1;
delete mol2;
smi = "N[C@H]1CCCO1";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 6);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(smi == "[1*][C@H]1CCCO1");
delete mol1;
delete mol2;
delete matcher1;
smi = "ClC1CC(F)C1";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
sma = "*C1CC(*)C1";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
mol2 = replaceCore(*mol1, *matcher1, false);
TEST_ASSERT(mol2);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(mol2->getNumAtoms() == 4);
smi = MolToSmiles(*mol2, true);
// there's no way to guarantee the order here:
TEST_ASSERT(smi == "[1*]F.[2*]Cl" || smi == "[1*]Cl.[2*]F");
delete mol1;
delete mol2;
delete matcher1;
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
struct CoreTest {
const char *smiles;
const char *smarts;
bool replaceDummies;
bool labelByIndex;
bool requireDummyMatch;
bool useChirality;
const char *expected;
};
void testReplaceCore2() {
const CoreTest tests[] = {
{"C1O[C@@]1(OC)NC", "C1O[C@]1(*)*", false, false, false, false,
"[1*]OC.[2*]NC"},
{"C1O[C@@]1(OC)NC", "C1O[C@]1(*)*", false, false, false, true,
"[1*]NC.[2*]OC"},
{"C1O[C@@]1(OC)NC", "C1O[C@]1(*)*", false, true, false, false,
"[3*]OC.[4*]NC"},
{"C1O[C@@]1(OC)NC", "C1O[C@]1(*)*", false, true, false, true,
"[3*]NC.[4*]OC"},
{"C1O[C@@]1(OC)NC", "C1O[C@]1(*)*", true, false, false, false,
"[1*]C.[2*]C"},
{"C1O[C@@]1(OC)NC", "C1O[C@]1(*)*", true, false, false, true,
"[1*]C.[2*]C"},
{"C1O[C@@]1(OC)NC", "C1O[C@]1(*)*", true, true, false, false,
"[3*]C.[4*]C"},
{"C1O[C@@]1(OC)NC", "C1O[C@]1(*)*", true, true, false, true,
"[3*]C.[4*]C"},
{"C1O[C@]1(OC)NC", "C1O[C@]1(*)*", false, false, false, false,
"[1*]OC.[2*]NC"},
{"C1O[C@]1(OC)NC", "C1O[C@]1(*)*", false, false, false, true,
"[1*]OC.[2*]NC"},
{"C1O[C@]1(OC)NC", "C1O[C@]1(*)*", false, true, false, false,
"[3*]OC.[4*]NC"},
{"C1O[C@]1(OC)NC", "C1O[C@]1(*)*", false, true, false, true,
"[3*]OC.[4*]NC"},
{"C1O[C@]1(OC)NC", "C1O[C@]1(*)*", true, false, false, false,
"[1*]C.[2*]C"},
{"C1O[C@]1(OC)NC", "C1O[C@]1(*)*", true, false, false, true,
"[1*]C.[2*]C"},
{"C1O[C@]1(OC)NC", "C1O[C@]1(*)*", true, true, false, false,
"[3*]C.[4*]C"},
{"C1O[C@]1(OC)NC", "C1O[C@]1(*)*", true, true, false, true,
"[3*]C.[4*]C"},
{"C1O[C@@]1(OC)NCC", "C1O[C@]1(*)*", true, false, false, false,
"[1*]C.[2*]CC"},
{"C1O[C@@]1(OC)NCC", "C1O[C@]1(*)*", true, false, false, true,
"[1*]CC.[2*]C"},
{"C1O[C@@]1(OC)NCC", "C1O[C@]1(*)*", true, true, false, false,
"[3*]C.[4*]CC"},
{"C1O[C@@]1(OC)NCC", "C1O[C@]1(*)*", true, true, false, true,
"[3*]CC.[4*]C"},
{"C1O[C@]1(OC)NCC", "C1O[C@]1(*)*", true, false, false, false,
"[1*]C.[2*]CC"},
{"C1O[C@]1(OC)NCC", "C1O[C@]1(*)*", true, false, false, true,
"[1*]C.[2*]CC"},
{"C1O[C@]1(OC)NCC", "C1O[C@]1(*)*", true, true, false, false,
"[3*]C.[4*]CC"},
{"C1O[C@]1(OC)NCC", "C1O[C@]1(*)*", true, true, false, true,
"[3*]C.[4*]CC"},
{"CNOC", "CONC", false, true, false, false, ""},
{"PCNOCS", "CONC", false, true, false, false, "*S.[3*]P"},
{"PCNOCS", "CONC", false, false, false, false, "[1*]S.[2*]P"},
{"PCONCS", "CONC", false, true, false, false, "*P.[3*]S"},
{"PCONCS", "CONC", false, false, false, false, "[1*]P.[2*]S"}
};
size_t num_tests = sizeof(tests) / sizeof(CoreTest);
for (size_t i = 0; i < num_tests; ++i) {
ROMOL_SPTR mol(SmilesToMol(tests[i].smiles));
ROMOL_SPTR smarts(SmartsToMol(tests[i].smarts));
ROMOL_SPTR res(replaceCore(*mol.get(), *smarts.get(),
tests[i].replaceDummies, tests[i].labelByIndex,
tests[i].requireDummyMatch,
tests[i].useChirality));
if (tests[i].expected) {
TEST_ASSERT(res.get());
std::string smi = MolToSmiles(*res.get(), true);
if (smi != tests[i].expected) {
std::cerr << i << " " << tests[i].smiles << " " << tests[i].smarts
<< " " << (int)tests[i].replaceDummies << " "
<< (int)tests[i].labelByIndex << " "
<< (int)tests[i].requireDummyMatch << " "
<< (int)tests[i].useChirality
<< " expected:" << tests[i].expected << " got => " << smi
<< std::endl;
}
TEST_ASSERT(smi == tests[i].expected);
} else {
TEST_ASSERT(!res.get());
}
MatchVectType matchV;
// do the substructure matching and get the atoms that match the query
const bool recursionPossible = true;
bool matchFound = SubstructMatch(*mol.get(), *smarts.get(), matchV,
recursionPossible, tests[i].useChirality);
TEST_ASSERT(matchFound);
res = ROMOL_SPTR(replaceCore(*mol.get(), *smarts.get(), matchV,
tests[i].replaceDummies, tests[i].labelByIndex,
tests[i].requireDummyMatch));
if (tests[i].expected) {
TEST_ASSERT(res.get());
std::string smi = MolToSmiles(*res.get(), true);
if (smi != tests[i].expected) {
std::cerr << i << " " << tests[i].smiles << " " << tests[i].smarts
<< " " << (int)tests[i].replaceDummies << " "
<< (int)tests[i].labelByIndex << " "
<< (int)tests[i].requireDummyMatch << " "
<< (int)tests[i].useChirality
<< " expected:" << tests[i].expected << " got => " << smi
<< std::endl;
}
TEST_ASSERT(smi == tests[i].expected);
} else {
TEST_ASSERT(!res.get());
}
}
}
void testReplaceCoreLabels() {
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing replaceCore with labels" << std::endl;
{
std::string sma = "n1cocc1";
ROMol *matcher = SmartsToMol(sma);
TEST_ASSERT(matcher);
std::string smi = "n1c(CC)oc(C)c1";
ROMol *mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
ROMol *mol2 = replaceCore(*mol1, *matcher, true, true);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 5);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(smi == "[1*]CC.[3*]C");
delete mol1;
delete mol2;
delete matcher;
}
{
std::string sma = "n1cocc1";
ROMol *matcher = SmartsToMol(sma);
TEST_ASSERT(matcher);
std::string smi = "n1c(C)oc(CC)c1";
ROMol *mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
ROMol *mol2 = replaceCore(*mol1, *matcher, true, true);
TEST_ASSERT(mol2);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(smi == "[1*]C.[3*]CC");
delete mol1;
delete mol2;
delete matcher;
}
{
std::string sma = "n1cocc1";
ROMol *matcher = SmartsToMol(sma);
TEST_ASSERT(matcher);
std::string smi = "CCC1=C(OC)N=C(C)O1";
ROMol *mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
ROMol *mol2 = replaceCore(*mol1, *matcher, true, true);
TEST_ASSERT(mol2);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(smi == "[1*]C.[3*]CC.[4*]OC");
delete mol1;
delete mol2;
delete matcher;
}
{
std::string sma = "n1cocc1";
ROMol *matcher = SmartsToMol(sma);
TEST_ASSERT(matcher);
std::string smi = "C1=C(OC)N=CO1";
ROMol *mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
ROMol *mol2 = replaceCore(*mol1, *matcher, true, true);
TEST_ASSERT(mol2);
smi = MolToSmiles(*mol2, true);
TEST_ASSERT(smi == "[4*]OC");
delete mol1;
delete mol2;
delete matcher;
}
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testReplaceCoreCrash() {
ROMol *mol1 = nullptr, *mol2 = nullptr, *matcher1 = nullptr;
std::string smi, sma;
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing a former crash in replaceCore" << std::endl;
std::string pathName = getenv("RDBASE");
pathName += "/Code/GraphMol/ChemTransforms/testData/oldcrash.mol";
mol1 = MolFileToMol(pathName);
TEST_ASSERT(mol1);
sma = "N";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 6);
smi = MolToSmiles(*mol2, true);
delete mol1;
delete mol2;
delete matcher1;
// there's no way to guarantee the order here:
TEST_ASSERT(smi == "[1*]CC.[2*]CC" || smi == "[2*]CC.[1*]CC");
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testReplaceCorePositions() {
ROMol *mol1 = nullptr, *mol2 = nullptr, *matcher1 = nullptr;
std::string smi, sma;
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog)
<< "Testing that atom positions are correctly copied by replaceCore"
<< std::endl;
std::string pathName = getenv("RDBASE");
pathName += "/Code/GraphMol/ChemTransforms/testData/core_location.mol";
mol1 = MolFileToMol(pathName);
TEST_ASSERT(mol1);
TEST_ASSERT(mol1->getNumAtoms() == 8);
sma = "c1ccccc1";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
mol2 = replaceCore(*mol1, *matcher1);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 4);
RDGeom::Point3D op, np;
op = mol1->getConformer().getAtomPos(6);
np = mol2->getConformer().getAtomPos(0);
TEST_ASSERT(feq(op.x, np.x));
TEST_ASSERT(feq(op.y, np.y));
TEST_ASSERT(feq(op.z, np.z));
op = mol1->getConformer().getAtomPos(7);
np = mol2->getConformer().getAtomPos(1);
TEST_ASSERT(feq(op.x, np.x));
TEST_ASSERT(feq(op.y, np.y));
TEST_ASSERT(feq(op.z, np.z));
op = mol1->getConformer().getAtomPos(0);
np = mol2->getConformer().getAtomPos(2);
TEST_ASSERT(feq(op.x, np.x));
TEST_ASSERT(feq(op.y, np.y));
TEST_ASSERT(feq(op.z, np.z));
op = mol1->getConformer().getAtomPos(4);
np = mol2->getConformer().getAtomPos(3);
TEST_ASSERT(feq(op.x, np.x));
TEST_ASSERT(feq(op.y, np.y));
TEST_ASSERT(feq(op.z, np.z));
delete mol1;
delete mol2;
delete matcher1;
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testReplaceCoreMatchVect() {
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing replaceCore with a matchvect" << std::endl;
std::map<std::string, int> expected;
expected["[1*]N.[2*]O.[3*]P"] = 1;
expected["[1*]N.[2*]P.[3*]O"] = 1;
expected["[1*]O.[2*]N.[3*]P"] = 1;
expected["[1*]O.[2*]P.[3*]N"] = 1;
expected["[1*]P.[2*]N.[3*]O"] = 1;
expected["[1*]P.[2*]O.[3*]N"] = 1;
const char *smiles = "NC1C(O)C1P";
const char *smarts = "*C1C(*)C1*";
ROMOL_SPTR mol(SmilesToMol(smiles));
ROMOL_SPTR query(SmartsToMol(smarts));
std::vector<MatchVectType> matches;
const bool uniquify = false;
unsigned int matchCount =
SubstructMatch(*mol.get(), *query.get(), matches, uniquify);
TEST_ASSERT(matchCount);
std::map<std::string, int> results;
const bool replaceDummies = false;
for (unsigned int i = 0; i < matchCount; ++i) {
ROMOL_SPTR res(
replaceCore(*mol.get(), *query.get(), matches[i], replaceDummies));
std::string smi = MolToSmiles(*res.get(), true);
results[smi] = results[smi] + 1;
}
TEST_ASSERT(expected == results);
{
MatchVectType fake;
fake.push_back(std::make_pair(1, 100));
try {
ROMOL_SPTR res(
replaceCore(*mol.get(), *query.get(), fake, replaceDummies));
TEST_ASSERT(0);
} catch (...) {
BOOST_LOG(rdInfoLog) << "-- caught error";
}
}
{
MatchVectType fake;
fake.push_back(std::make_pair(100, 1));
try {
ROMOL_SPTR res(
replaceCore(*mol.get(), *query.get(), fake, replaceDummies));
TEST_ASSERT(0);
} catch (...) {
BOOST_LOG(rdInfoLog) << "-- caught error";
}
}
{
MatchVectType fake;
fake.push_back(std::make_pair(1, -10));
try {
ROMOL_SPTR res(
replaceCore(*mol.get(), *query.get(), fake, replaceDummies));
TEST_ASSERT(0);
} catch (...) {
BOOST_LOG(rdInfoLog) << "-- caught error";
}
}
{
MatchVectType fake;
fake.push_back(std::make_pair(-10, 1));
try {
ROMOL_SPTR res(
replaceCore(*mol.get(), *query.get(), fake, replaceDummies));
TEST_ASSERT(0);
} catch (...) {
BOOST_LOG(rdInfoLog) << "-- caught error";
}
}
}
void testMurckoDecomp() {
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing murcko decomposition" << std::endl;
const char *testMolecules[][2] = {
{"C1CC1CCC1CC(C)C1", "C1CC1CCC1CCC1"},
{"CC1CCC1", "C1CCC1"},
{"NCNCC2CC2C1CC1O", "C1CC1C1CC1"},
{"OC2C(C)C21C(N)C1C", "C2CC12CC1"}, // Spiro
{"C1CC1C(=O)OC", "C1CC1"}, // Carbonyl outside scaffold
{"C1CC1C=C", "C1CC1"}, // Double bond outside scaffold
{"C1CC1C=CC1CC1C=CNNCO", "C1CC1C=CC1CC1"}, // Double bond in scaffold
{"CC1CC1C(N)C1C(N)C1", "C1CC1CC1CC1"},
{"C1CC1S(=O)C1CC1C=CNNCO", "C1CC1S(=O)C1CC1"}, // S=O group in scaffold
{"O=SCNC1CC1S(=O)C1CC1C=CNNCO",
"C1CC1S(=O)C1CC1"}, // S=O group outside scaffold
{"C1CC1S(=O)(=O)C1CC1C=CNNCO",
"C1CC1S(=O)(=O)C1CC1"}, // SO2 group in scaffold
{"O=S(CNCNC)(=O)CNC1CC1S(=O)(=O)C1CC1C=CNNCO",
"C1CC1S(=O)(=O)C1CC1"}, // SO2 group outside scaffold
{"C1CC1C=NO", "C1CC1"}, // Hydroxamide
{"C1CC1C(C(C)C)=NC1CC1", "C1CC1C=NC1CC1"}, // Hydroxamide
{"C1CC1C#N", "C1CC1"}, // Cyano group
{"C1CC1C#CNC", "C1CC1"}, // Acetylene group
{"O=C1N(C)C(=O)N1C#CNC", "O=C1NC(=O)N1"}, // Acetylene group
{"[O-][N+](=O)c1cc(ccc1Cl)NS(=O)(=O)Cc2ccccc2",
"c1ccccc1NS(=O)(=O)Cc2ccccc2"},
{"Cn1cccc1", "c1ccc[nH]1"},
{"C1CC1[CH](C)C1CC1", "C1CC1CC1CC1"},
{"CC(C)c1c(Cl)cc(F)c(Nc2ccc(C)cc2CC(=O)O)c1F", "c1ccc(Nc2ccccc2)cc1"},
{"C1CC1C[C@](Cl)(F)C1CCC1", "C1CC1CCC1CCC1"},
{"C1CC1.C1CC1", "C1CC1.C1CC1"}, // this was a crash at one point
{"CCC", ""},
{"EOS", "EOS"}};
unsigned int i = 0;
while (1) {
std::string smi = testMolecules[i][0];
std::string tgt = testMolecules[i][1];
++i;
if (smi == "EOS") break;
ROMol *mol = SmilesToMol(smi);
ROMol *nMol = MurckoDecompose(*mol);
TEST_ASSERT(nMol);
delete mol;
if (tgt != "") {
TEST_ASSERT(nMol->getNumAtoms());
MolOps::sanitizeMol(static_cast<RWMol &>(*nMol));
smi = MolToSmiles(*nMol, true);
mol = SmilesToMol(tgt);
TEST_ASSERT(mol);
tgt = MolToSmiles(*mol, true);
delete mol;
TEST_ASSERT(smi == tgt);
} else {
TEST_ASSERT(nMol->getNumAtoms() == 0);
}
delete nMol;
}
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testReplaceCoreRequireDummies() {
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing replaceCore requiring dummy atoms"
<< std::endl;
{
std::string sma = "n1c(*)oc(*)c1";
ROMol *matcher = SmartsToMol(sma);
TEST_ASSERT(matcher);
std::string smi = "n1c(CC)oc(C)c1";
ROMol *mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
bool replaceDummies = false;
bool labelByIndex = true;
bool requireDummyMatch = false;
ROMol *mol2 = replaceCore(*mol1, *matcher, replaceDummies, labelByIndex,
requireDummyMatch);
TEST_ASSERT(mol2);
TEST_ASSERT(mol2->getNumAtoms() == 5);
smi = MolToSmiles(*mol2, true);
// If dummies existed and were replaced
// use THEIR atom indices
TEST_ASSERT(smi == "[2*]CC.[5*]C");
delete mol1;
delete mol2;
smi = "n1c(CC)oc(C)c1C";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
replaceDummies = false;
labelByIndex = true;
requireDummyMatch = true;
mol2 = replaceCore(*mol1, *matcher, replaceDummies, labelByIndex,
requireDummyMatch);
TEST_ASSERT(!mol2);
delete mol1;
smi = "n1c(CC)occ1C";
mol1 = SmilesToMol(smi);
TEST_ASSERT(mol1);
replaceDummies = false;
labelByIndex = true;
requireDummyMatch = true;
mol2 = replaceCore(*mol1, *matcher, replaceDummies, labelByIndex,
requireDummyMatch);
TEST_ASSERT(!mol2);
delete mol1;
delete matcher;
}
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testIssue3453144() {
ROMol *mol1 = nullptr, *matcher1 = nullptr, *replacement = nullptr;
std::string smi, sma;
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog)
<< "Testing that atom positions are correctly copied by replaceSubstructs"
<< std::endl;
std::string pathName = getenv("RDBASE");
pathName += "/Code/GraphMol/ChemTransforms/testData/ethanol.mol";
mol1 = MolFileToMol(pathName);
TEST_ASSERT(mol1);
TEST_ASSERT(mol1->getNumAtoms() == 3);
sma = "O";
matcher1 = SmartsToMol(sma);
TEST_ASSERT(matcher1);
smi = "N";
replacement = SmilesToMol(smi);
TEST_ASSERT(replacement);
std::vector<ROMOL_SPTR> rs;
rs = replaceSubstructs(*mol1, *matcher1, *replacement);
TEST_ASSERT(rs.size() == 1);
TEST_ASSERT(rs[0]->getNumAtoms() == 3);
TEST_ASSERT(rs[0]->getAtomWithIdx(2)->getAtomicNum() == 7);
TEST_ASSERT(rs[0]->getNumConformers() == mol1->getNumConformers());
RDGeom::Point3D op, np;
op = mol1->getConformer().getAtomPos(0);
np = rs[0]->getConformer().getAtomPos(0);
TEST_ASSERT(feq(op.x, np.x));
TEST_ASSERT(feq(op.y, np.y));
TEST_ASSERT(feq(op.z, np.z));
op = mol1->getConformer().getAtomPos(1);
np = rs[0]->getConformer().getAtomPos(1);
TEST_ASSERT(feq(op.x, np.x));
TEST_ASSERT(feq(op.y, np.y));
TEST_ASSERT(feq(op.z, np.z));
delete mol1;
delete matcher1;
delete replacement;
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testIssue3537675() {
std::string smi, sma;
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog)
<< "Testing handling of substituted non-carbon aromatic atoms"
<< std::endl;
{
std::string smi = "c1cccp1C";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
ROMol *nMol = MurckoDecompose(*mol);
TEST_ASSERT(nMol->getAtomWithIdx(4)->getNumExplicitHs());
delete mol;
delete nMol;
}
{
std::string smi = "c1cccn1C";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
ROMol *nMol = MurckoDecompose(*mol);
TEST_ASSERT(nMol->getAtomWithIdx(4)->getNumExplicitHs());
delete mol;
delete nMol;
}
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testCombineMols() {
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing combination of molecules" << std::endl;
{
std::string smi1 = "C1CCC1";
std::string smi2 = "C1CC1";
ROMol *mol1 = SmilesToMol(smi1);
ROMol *mol2 = SmilesToMol(smi2);
ROMol *mol3 = combineMols(*mol1, *mol2);
TEST_ASSERT(mol3->getNumAtoms() ==
(mol1->getNumAtoms() + mol2->getNumAtoms()));
MolOps::findSSSR(*mol3);
TEST_ASSERT(mol3->getRingInfo()->numRings() == 2);
delete mol1;
delete mol2;
delete mol3;
}
{
std::string pathName = getenv("RDBASE");
pathName += "/Code/GraphMol/ChemTransforms/testData/ethanol.mol";
ROMol *mol1 = MolFileToMol(pathName);
TEST_ASSERT(mol1);
ROMol *mol2 = MolFileToMol(pathName);
TEST_ASSERT(mol2);
TEST_ASSERT(mol1->getNumAtoms() == 3);
TEST_ASSERT(mol2->getNumAtoms() == 3);
ROMol *mol3 = combineMols(*mol1, *mol2);
TEST_ASSERT(mol3->getNumAtoms() ==
(mol1->getNumAtoms() + mol2->getNumAtoms()));
TEST_ASSERT(mol3->getNumConformers() == 1);
TEST_ASSERT(feq(mol3->getConformer().getAtomPos(0).x,
mol3->getConformer().getAtomPos(3).x));
TEST_ASSERT(feq(mol3->getConformer().getAtomPos(0).y,
mol3->getConformer().getAtomPos(3).y));
TEST_ASSERT(feq(mol3->getConformer().getAtomPos(0).z,
mol3->getConformer().getAtomPos(3).z));
delete mol3;
mol3 = combineMols(*mol1, *mol2, RDGeom::Point3D(1, 0, 0));
TEST_ASSERT(mol3->getNumAtoms() ==
(mol1->getNumAtoms() + mol2->getNumAtoms()));
TEST_ASSERT(mol3->getNumConformers() == 1);
TEST_ASSERT(!feq(mol3->getConformer().getAtomPos(0).x,
mol3->getConformer().getAtomPos(3).x));
TEST_ASSERT(feq(mol3->getConformer().getAtomPos(0).y,
mol3->getConformer().getAtomPos(3).y));
TEST_ASSERT(feq(mol3->getConformer().getAtomPos(0).z,
mol3->getConformer().getAtomPos(3).z));
delete mol1;
delete mol2;
delete mol3;
}
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testAddRecursiveQueries() {
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing adding recursive queries to a molecule"
<< std::endl;
{
std::string smi1 = "CC";
ROMol *mol1 = SmilesToMol(smi1);
std::string smi2 = "CO";
ROMOL_SPTR q1(SmilesToMol(smi2));
std::map<std::string, ROMOL_SPTR> mp;
mp["foo"] = q1;
TEST_ASSERT(!mol1->getAtomWithIdx(0)->hasQuery());
addRecursiveQueries(*mol1, mp, "replaceme");
TEST_ASSERT(!mol1->getAtomWithIdx(0)->hasQuery());
mol1->getAtomWithIdx(0)->setProp("replaceme", "foo");
addRecursiveQueries(*mol1, mp, "replaceme");
TEST_ASSERT(mol1->getAtomWithIdx(0)->hasQuery());
TEST_ASSERT(mol1->getAtomWithIdx(0)->getQuery()->getDescription() ==
"AtomAnd");
TEST_ASSERT(!mol1->getAtomWithIdx(1)->hasQuery());
mol1->getAtomWithIdx(0)->setProp("replaceme", "bar");
bool ok = false;
try {
addRecursiveQueries(*mol1, mp, "replaceme");
} catch (KeyErrorException &e) {
ok = true;
}
TEST_ASSERT(ok);
delete mol1;
}
{
std::string smi1 = "CC";
ROMol *mol1 = SmilesToMol(smi1);
std::string smi2 = "CO";
ROMOL_SPTR q1(SmilesToMol(smi2));
std::map<std::string, ROMOL_SPTR> mp;
mp["foo"] = q1;
std::vector<std::pair<unsigned int, std::string>> labels;
mol1->getAtomWithIdx(0)->setProp("replaceme", "foo");
addRecursiveQueries(*mol1, mp, "replaceme", &labels);
TEST_ASSERT(mol1->getAtomWithIdx(0)->hasQuery());
TEST_ASSERT(labels.size() == 1);
delete mol1;
}
{
std::string smi1 = "CC";
ROMol *mol1 = SmilesToMol(smi1);
std::string smi2 = "CO";
ROMOL_SPTR q1(SmilesToMol(smi2));
std::map<std::string, ROMOL_SPTR> mp;
mp["foo"] = q1;
smi2 = "OC";
ROMOL_SPTR q2(SmilesToMol(smi2));
mp["bar"] = q2;
std::vector<std::pair<unsigned int, std::string>> labels;
mol1->getAtomWithIdx(0)->setProp("replaceme", "foo");
mol1->getAtomWithIdx(1)->setProp("replaceme", "bar");
addRecursiveQueries(*mol1, mp, "replaceme", &labels);
TEST_ASSERT(mol1->getAtomWithIdx(0)->hasQuery());
TEST_ASSERT(mol1->getAtomWithIdx(1)->hasQuery());
TEST_ASSERT(mol1->getAtomWithIdx(0)->getQuery()->getDescription() ==
"AtomAnd");
TEST_ASSERT(mol1->getAtomWithIdx(1)->getQuery()->getDescription() ==
"AtomAnd");
TEST_ASSERT(labels.size() == 2);
delete mol1;
}
{
std::string smi1 = "CC";
ROMol *mol1 = SmilesToMol(smi1);
std::string smi2 = "CO";
ROMOL_SPTR q1(SmilesToMol(smi2));
std::map<std::string, ROMOL_SPTR> mp;
mp["foo"] = q1;
smi2 = "CN";
ROMOL_SPTR q2(SmilesToMol(smi2));
mp["bar"] = q2;
mol1->getAtomWithIdx(0)->setProp("replaceme", "foo,bar");
addRecursiveQueries(*mol1, mp, "replaceme");
TEST_ASSERT(mol1->getAtomWithIdx(0)->hasQuery());
TEST_ASSERT(!mol1->getAtomWithIdx(1)->hasQuery());
TEST_ASSERT(mol1->getAtomWithIdx(0)->getQuery()->getDescription() ==
"AtomAnd");
MatchVectType mv;
std::string msmi = "CCC";
ROMol *mmol = SmilesToMol(msmi);
TEST_ASSERT(mmol);
TEST_ASSERT(!SubstructMatch(*mmol, *mol1, mv));
delete mmol;
msmi = "CCO";
mmol = SmilesToMol(msmi);
TEST_ASSERT(mmol);
TEST_ASSERT(SubstructMatch(*mmol, *mol1, mv));
delete mmol;
msmi = "CCN";
mmol = SmilesToMol(msmi);
TEST_ASSERT(mmol);
TEST_ASSERT(SubstructMatch(*mmol, *mol1, mv));
delete mmol;
delete mol1;
}
// Tests smarts as props
{
std::string smi1 = "CC";
ROMol *mol1 = SmilesToMol(smi1);
std::map<std::string, ROMOL_SPTR> mp;
mol1->getAtomWithIdx(0)->setProp("replaceme", "CO");
addRecursiveQueries(*mol1, mp, "replaceme");
TEST_ASSERT(mol1->getAtomWithIdx(0)->hasQuery());
TEST_ASSERT(!mol1->getAtomWithIdx(1)->hasQuery());
TEST_ASSERT(mol1->getAtomWithIdx(0)->getQuery()->getDescription() ==
"AtomAnd");
MatchVectType mv;
std::string msmi = "CCC";
ROMol *mmol = SmilesToMol(msmi);
TEST_ASSERT(mmol);
TEST_ASSERT(!SubstructMatch(*mmol, *mol1, mv));
delete mmol;
msmi = "CCO";
mmol = SmilesToMol(msmi);
TEST_ASSERT(mmol);
TEST_ASSERT(SubstructMatch(*mmol, *mol1, mv));
delete mmol;
delete mol1;
}
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testParseQueryDefFile() {
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing parsing query definition file" << std::endl;
{
std::string pathName = getenv("RDBASE");
pathName += "/Code/GraphMol/ChemTransforms/testData/query_file1.txt";
std::map<std::string, ROMOL_SPTR> qdefs;
parseQueryDefFile(pathName, qdefs, false);
TEST_ASSERT(!qdefs.empty());
TEST_ASSERT(qdefs.size() == 7);
TEST_ASSERT(qdefs.find("AcidChloride") != qdefs.end());
TEST_ASSERT(qdefs.find("AcideChloride") == qdefs.end());
TEST_ASSERT(qdefs.find("AcidChloride.Aliphatic") != qdefs.end());
TEST_ASSERT(qdefs.find("CarboxylicAcid.AlphaAmino") != qdefs.end());
std::string msmi = "CCC(=O)Cl";
ROMol *mmol = SmilesToMol(msmi);
TEST_ASSERT(mmol);
MatchVectType mv;
TEST_ASSERT(SubstructMatch(*mmol, *(qdefs["AcidChloride"]), mv));
delete mmol;
}
{
std::string pathName = getenv("RDBASE");
pathName += "/Code/GraphMol/ChemTransforms/testData/query_file2.txt";
std::map<std::string, ROMOL_SPTR> qdefs;
parseQueryDefFile(pathName, qdefs);
TEST_ASSERT(qdefs.empty());
}
/*{
std::string pathName = getenv("RDBASE");
pathName += "/Code/GraphMol/ChemTransforms/testData/query_file1.txt";
std::map<std::string, ROMOL_SPTR> qdefs;
parseQueryDefFile(pathName, qdefs);
TEST_ASSERT(!qdefs.empty());
TEST_ASSERT(qdefs.size()==7);
TEST_ASSERT(qdefs.find("acidchloride")!=qdefs.end());
TEST_ASSERT(qdefs.find("AcidChloride")==qdefs.end());
}*/
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testIssue275() {
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog)
<< "Testing sf.net issue 275: Murcko decomposition with chiral atoms"
<< std::endl;
{
std::string smi = "CCCCC[C@H]1CC[C@H](C(=O)O)CC1";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
ROMol *nMol = MurckoDecompose(*mol);
smi = MolToSmiles(*nMol, true);
TEST_ASSERT(smi == "C1CCCCC1");
delete mol;
delete nMol;
}
{
std::string smi = "CCCCC[C@H]1CC[C@H](C(=O)O)CC1";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
ROMol *nMol = MurckoDecompose(*mol);
smi = MolToSmiles(*nMol, false);
TEST_ASSERT(smi == "C1CCCCC1");
delete mol;
delete nMol;
}
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testFragmentOnBonds() {
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing fragmentOnBonds" << std::endl;
{
std::string smi = "OCCCN";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms() == 5);
unsigned int indices[] = {0, 3};
std::vector<unsigned int> bindices(
indices, indices + (sizeof(indices) / sizeof(indices[0])));
ROMol *nmol = MolFragmenter::fragmentOnBonds(*mol, bindices, false);
TEST_ASSERT(nmol);
TEST_ASSERT(nmol->getNumAtoms() == 5);
delete mol;
delete nmol;
}
{
std::string smi = "OCCCN";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms() == 5);
unsigned int indices[] = {0, 1};
std::vector<unsigned int> bindices(
indices, indices + (sizeof(indices) / sizeof(indices[0])));
std::vector<unsigned int> cutsPerAtom(mol->getNumAtoms());
ROMol *nmol = MolFragmenter::fragmentOnBonds(*mol, bindices, false, nullptr,
nullptr, &cutsPerAtom);
TEST_ASSERT(nmol);
TEST_ASSERT(nmol->getNumAtoms() == 5);
TEST_ASSERT(cutsPerAtom[0] == 1);
TEST_ASSERT(cutsPerAtom[1] == 2);
TEST_ASSERT(cutsPerAtom[2] == 1);
TEST_ASSERT(cutsPerAtom[3] == 0);
delete mol;
delete nmol;
}
{
std::string smi = "OCCCN";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms() == 5);
TEST_ASSERT(mol->getBondBetweenAtoms(0, 1));
TEST_ASSERT(mol->getBondBetweenAtoms(3, 4));
unsigned int indices[] = {0, 3};
std::vector<unsigned int> bindices(
indices, indices + (sizeof(indices) / sizeof(indices[0])));
ROMol *nmol = MolFragmenter::fragmentOnBonds(*mol, bindices);
TEST_ASSERT(nmol);
TEST_ASSERT(nmol->getNumAtoms() == 9);
TEST_ASSERT(!nmol->getBondBetweenAtoms(0, 1));
TEST_ASSERT(!nmol->getBondBetweenAtoms(3, 4));
TEST_ASSERT(nmol->getAtomWithIdx(5)->getAtomicNum() == 0);
TEST_ASSERT(nmol->getAtomWithIdx(5)->getIsotope() == 0);
TEST_ASSERT(nmol->getBondBetweenAtoms(1, 5));
TEST_ASSERT(nmol->getAtomWithIdx(6)->getAtomicNum() == 0);
TEST_ASSERT(nmol->getAtomWithIdx(6)->getIsotope() == 1);
TEST_ASSERT(nmol->getBondBetweenAtoms(0, 6));
TEST_ASSERT(nmol->getAtomWithIdx(7)->getAtomicNum() == 0);
TEST_ASSERT(nmol->getAtomWithIdx(7)->getIsotope() == 3);
TEST_ASSERT(nmol->getBondBetweenAtoms(4, 7));
TEST_ASSERT(nmol->getAtomWithIdx(8)->getAtomicNum() == 0);
TEST_ASSERT(nmol->getAtomWithIdx(8)->getIsotope() == 4);
TEST_ASSERT(nmol->getBondBetweenAtoms(3, 8));
delete mol;
delete nmol;
}
{
std::string smi = "OCCCN";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms() == 5);
TEST_ASSERT(mol->getBondBetweenAtoms(0, 1));
TEST_ASSERT(mol->getBondBetweenAtoms(3, 4));
unsigned int indices[] = {0, 3};
std::vector<unsigned int> bindices(
indices, indices + (sizeof(indices) / sizeof(indices[0])));
std::vector<std::pair<unsigned int, unsigned int>> dummyLabels(2);
dummyLabels[0] = std::make_pair(10, 11);
dummyLabels[1] = std::make_pair(100, 110);
ROMol *nmol =
MolFragmenter::fragmentOnBonds(*mol, bindices, true, &dummyLabels);
TEST_ASSERT(nmol);
TEST_ASSERT(nmol->getNumAtoms() == 9);
TEST_ASSERT(!nmol->getBondBetweenAtoms(0, 1));
TEST_ASSERT(!nmol->getBondBetweenAtoms(3, 4));
TEST_ASSERT(nmol->getAtomWithIdx(5)->getAtomicNum() == 0);
TEST_ASSERT(nmol->getAtomWithIdx(5)->getIsotope() == 10);
TEST_ASSERT(nmol->getBondBetweenAtoms(1, 5));
TEST_ASSERT(nmol->getAtomWithIdx(6)->getAtomicNum() == 0);
TEST_ASSERT(nmol->getAtomWithIdx(6)->getIsotope() == 11);
TEST_ASSERT(nmol->getBondBetweenAtoms(0, 6));
TEST_ASSERT(nmol->getAtomWithIdx(7)->getAtomicNum() == 0);
TEST_ASSERT(nmol->getAtomWithIdx(7)->getIsotope() == 100);
TEST_ASSERT(nmol->getBondBetweenAtoms(4, 7));
TEST_ASSERT(nmol->getAtomWithIdx(8)->getAtomicNum() == 0);
TEST_ASSERT(nmol->getAtomWithIdx(8)->getIsotope() == 110);
TEST_ASSERT(nmol->getBondBetweenAtoms(3, 8));
delete mol;
delete nmol;
}
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testFragmentOnBRICSBonds() {
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing fragmentOnBRICSBonds" << std::endl;
{
std::string smi = "c1ccccc1OC";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms() == 8);
TEST_ASSERT(mol->getBondBetweenAtoms(5, 6));
TEST_ASSERT(mol->getBondBetweenAtoms(6, 7));
std::vector<MolFragmenter::FragmenterBondType> fbts;
MolFragmenter::constructBRICSBondTypes(fbts);
ROMol *nmol = MolFragmenter::fragmentOnBonds(*mol, fbts);
TEST_ASSERT(nmol);
TEST_ASSERT(nmol->getNumAtoms() == 10);
TEST_ASSERT(!nmol->getBondBetweenAtoms(5, 6));
TEST_ASSERT(nmol->getBondBetweenAtoms(6, 7));
smi = MolToSmiles(*nmol, true);
TEST_ASSERT(smi == "[16*]c1ccccc1.[3*]OC");
TEST_ASSERT(nmol->getAtomWithIdx(8)->getAtomicNum() == 0);
TEST_ASSERT(nmol->getAtomWithIdx(8)->getIsotope() == 3);
TEST_ASSERT(nmol->getBondBetweenAtoms(6, 8));
TEST_ASSERT(nmol->getAtomWithIdx(9)->getAtomicNum() == 0);
TEST_ASSERT(nmol->getAtomWithIdx(9)->getIsotope() == 16);
TEST_ASSERT(nmol->getBondBetweenAtoms(5, 9));
delete mol;
delete nmol;
}
{
std::string smi = "c1ccccc1";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms() == 6);
std::vector<MolFragmenter::FragmenterBondType> fbts;
MolFragmenter::constructBRICSBondTypes(fbts);
ROMol *nmol = MolFragmenter::fragmentOnBonds(*mol, fbts);
TEST_ASSERT(nmol);
TEST_ASSERT(nmol->getNumAtoms() == 6);
smi = MolToSmiles(*nmol, true);
TEST_ASSERT(smi == "c1ccccc1");
delete mol;
delete nmol;
}
{
std::string smi = "OC(C)=CC";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms() == 5);
std::vector<MolFragmenter::FragmenterBondType> fbts;
MolFragmenter::constructBRICSBondTypes(fbts);
ROMol *nmol = MolFragmenter::fragmentOnBonds(*mol, fbts);
TEST_ASSERT(nmol);
TEST_ASSERT(nmol->getNumAtoms() == 7);
smi = MolToSmiles(*nmol, true);
TEST_ASSERT(smi == "[7*]=C(C)O.[7*]=CC");
delete mol;
delete nmol;
}
{
std::string smi = "c1ccccc1OC";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms() == 8);
ROMol *nmol = MolFragmenter::fragmentOnBRICSBonds(*mol);
TEST_ASSERT(nmol);
TEST_ASSERT(nmol->getNumAtoms() == 10);
smi = MolToSmiles(*nmol, true);
TEST_ASSERT(smi == "[16*]c1ccccc1.[3*]OC");
delete mol;
delete nmol;
}
{
std::string smi = "OC(C)=CC";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms() == 5);
ROMol *nmol = MolFragmenter::fragmentOnBRICSBonds(*mol);
TEST_ASSERT(nmol);
TEST_ASSERT(nmol->getNumAtoms() == 7);
smi = MolToSmiles(*nmol, true);
TEST_ASSERT(smi == "[7*]=C(C)O.[7*]=CC");
delete mol;
delete nmol;
}
{
std::string smi = "CCCOCCC(=O)c1ccccc1";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms() == 14);
ROMol *nmol = MolFragmenter::fragmentOnBRICSBonds(*mol);
TEST_ASSERT(nmol);
TEST_ASSERT(nmol->getNumAtoms() == 20);
smi = MolToSmiles(*nmol, true);
TEST_ASSERT(smi == "[16*]c1ccccc1.[3*]O[3*].[4*]CCC.[4*]CCC([6*])=O");
MolOps::sanitizeMol(static_cast<RWMol &>(*nmol));
smi = MolToSmiles(*nmol, true);
TEST_ASSERT(smi == "[16*]c1ccccc1.[3*]O[3*].[4*]CCC.[4*]CCC([6*])=O");
delete mol;
delete nmol;
}
{
std::string smi = "Cl.CC(=O)O[C@]1(c2ccccc2)CCN(C)[C@H]2CCCC[C@@H]21";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms() == 22);
ROMol *nmol = MolFragmenter::fragmentOnBRICSBonds(*mol);
TEST_ASSERT(nmol);
TEST_ASSERT(nmol->getNumAtoms() == 28);
smi = MolToSmiles(*nmol, true);
// std::cerr<<smi<<std::endl;
TEST_ASSERT(smi ==
"Cl.[1*]C(C)=O.[15*]C1([15*])CCN(C)[C@H]2CCCC[C@@H]21.[16*]"
"c1ccccc1.[3*]O[3*]");
MolOps::sanitizeMol(static_cast<RWMol &>(*nmol));
smi = MolToSmiles(*nmol, true);
TEST_ASSERT(smi ==
"Cl.[1*]C(C)=O.[15*]C1([15*])CCN(C)[C@H]2CCCC[C@@H]21.[16*]"
"c1ccccc1.[3*]O[3*]");
delete mol;
delete nmol;
}
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void benchFragmentOnBRICSBonds() {
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing fragmentOnBRICSBonds" << std::endl;
{
std::string pathName = getenv("RDBASE");
pathName += "/Regress/Data/mols.1000.sdf";
SDMolSupplier suppl(pathName);
while (!suppl.atEnd()) {
ROMol *m = suppl.next();
ROMol *nmol = MolFragmenter::fragmentOnBRICSBonds(*m);
delete m;
delete nmol;
}
}
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testFragmentOnSomeBonds() {
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing fragmentOnSomeBonds" << std::endl;
{
std::string smi = "OCCCCN";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms());
unsigned int indices[] = {0, 2, 4};
std::vector<unsigned int> bindices(
indices, indices + (sizeof(indices) / sizeof(indices[0])));
std::vector<ROMOL_SPTR> frags;
MolFragmenter::fragmentOnSomeBonds(*mol, bindices, frags, 2);
TEST_ASSERT(frags.size() == 3);
std::vector<std::vector<int>> fragMap;
TEST_ASSERT(MolOps::getMolFrags(*frags[0], fragMap) == 3);
TEST_ASSERT(fragMap.size() == 3);
TEST_ASSERT(fragMap[0].size() == 2);
TEST_ASSERT(fragMap[1].size() == 4);
TEST_ASSERT(fragMap[2].size() == 4);
TEST_ASSERT(MolOps::getMolFrags(*frags[1], fragMap) == 3);
TEST_ASSERT(fragMap.size() == 3);
TEST_ASSERT(fragMap[0].size() == 2);
TEST_ASSERT(fragMap[1].size() == 6);
TEST_ASSERT(fragMap[2].size() == 2);
TEST_ASSERT(MolOps::getMolFrags(*frags[2], fragMap) == 3);
TEST_ASSERT(fragMap.size() == 3);
TEST_ASSERT(fragMap[0].size() == 4);
TEST_ASSERT(fragMap[1].size() == 4);
TEST_ASSERT(fragMap[2].size() == 2);
delete mol;
}
{
std::string smi = "OCCCCN";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms());
unsigned int indices[] = {0, 2, 4};
std::vector<unsigned int> bindices(
indices, indices + (sizeof(indices) / sizeof(indices[0])));
std::vector<ROMOL_SPTR> frags;
std::vector<std::vector<unsigned int>> cpa;
MolFragmenter::fragmentOnSomeBonds(*mol, bindices, frags, 2, false, nullptr,
nullptr, &cpa);
TEST_ASSERT(frags.size() == 3);
TEST_ASSERT(cpa.size() == 3);
TEST_ASSERT(cpa[0].size() == mol->getNumAtoms());
TEST_ASSERT(cpa[1].size() == mol->getNumAtoms());
TEST_ASSERT(cpa[2].size() == mol->getNumAtoms());
delete mol;
}
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testGithubIssue429() {
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing github issue 429: fragmentOnSomeBonds() "
"should update implicit H count on aromatic "
"heteroatoms when addDummies is False"
<< std::endl;
{
std::string smi = "c1cccn1CC1CC1";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms());
unsigned int indices[] = {4, 5};
std::vector<unsigned int> bindices(
indices, indices + (sizeof(indices) / sizeof(indices[0])));
std::vector<ROMOL_SPTR> frags;
MolFragmenter::fragmentOnSomeBonds(*mol, bindices, frags, 1, false);
TEST_ASSERT(frags.size() == 2);
std::vector<std::vector<int>> fragMap;
BOOST_FOREACH (ROMOL_SPTR romol, frags) {
RWMol *rwmol = (RWMol *)(romol.get());
MolOps::sanitizeMol(*rwmol);
}
// we actually changed fragmentOnBonds(), check that too:
RWMol *nmol =
(RWMol *)MolFragmenter::fragmentOnBonds(*mol, bindices, false);
MolOps::sanitizeMol(*nmol);
delete nmol;
delete mol;
}
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testGithubIssue430() {
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing github issue 430: fragmentOnSomeBonds() "
"crashes if bond list is empty"
<< std::endl;
{
std::string smi = "c1cccn1CC1CC1";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms());
std::vector<unsigned int> bindices;
std::vector<ROMOL_SPTR> frags;
MolFragmenter::fragmentOnSomeBonds(*mol, bindices, frags, 1, false);
TEST_ASSERT(frags.size() == 0);
delete mol;
}
{
std::string smi = "c1cccn1CC1CC1";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms());
unsigned int indices[] = {4, 5};
std::vector<unsigned int> bindices(
indices, indices + (sizeof(indices) / sizeof(indices[0])));
std::vector<ROMOL_SPTR> frags;
MolFragmenter::fragmentOnSomeBonds(*mol, bindices, frags, 0, false);
TEST_ASSERT(frags.size() == 0);
delete mol;
}
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testGithubIssue511() {
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing github issue 511: FragmentOnBonds() "
"producing incorrect chirality"
<< std::endl;
{ // start with an example with no ring bonds... just to dodge that
// complication
std::string smi = "CO[C@](CC)(C)N";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms() == 7)
std::vector<unsigned int> bindices;
bindices.push_back(1);
ROMol *frags = MolFragmenter::fragmentOnBonds(*mol, bindices, true);
TEST_ASSERT(frags->getNumAtoms() == 9);
std::string csmi1 = MolToSmiles(*mol, true);
std::cerr << csmi1 << std::endl;
TEST_ASSERT(csmi1 == "CC[C@@](C)(N)OC");
std::string csmi2 = MolToSmiles(*frags, true);
// std::cerr << csmi2 << std::endl;
TEST_ASSERT(csmi2 == "[1*][C@](C)(N)CC.[2*]OC");
delete mol;
delete frags;
}
{ // Steve's original bug report
std::string smi = "CO[C@]1(C)NCC1";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms() == 7)
std::vector<unsigned int> bindices;
bindices.push_back(1);
ROMol *frags = MolFragmenter::fragmentOnBonds(*mol, bindices, true);
TEST_ASSERT(frags->getNumAtoms() == 9);
std::string csmi1 = MolToSmiles(*mol, true);
TEST_ASSERT(csmi1 == "CO[C@@]1(C)CCN1");
std::string csmi2 = MolToSmiles(*frags, true);
// std::cerr << csmi2 << std::endl;
TEST_ASSERT(csmi2 == "[1*][C@@]1(C)CCN1.[2*]OC");
delete mol;
delete frags;
}
{ // further complicated by adding stereochem on both sides
std::string smi = "C[C@](O)(F)[C@@]1(C)CCN1";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms() == 9)
std::vector<unsigned int> bindices;
bindices.push_back(3);
ROMol *frags = MolFragmenter::fragmentOnBonds(*mol, bindices, true);
TEST_ASSERT(frags->getNumAtoms() == 11);
std::string csmi1 = MolToSmiles(*mol, true);
// std::cerr << csmi1 << std::endl;
TEST_ASSERT(csmi1 == "C[C@](O)(F)[C@@]1(C)CCN1");
std::string csmi2 = MolToSmiles(*frags, true);
// std::cerr << csmi2 << std::endl;
TEST_ASSERT(csmi2 == "[1*][C@@]1(C)CCN1.[4*][C@@](C)(O)F");
delete mol;
delete frags;
}
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
void testGithub1734() {
BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl;
BOOST_LOG(rdInfoLog) << "Testing github issue 1734: BreakBRICSBonds() not "
"preserving stereochemistry"
<< std::endl;
{ // no implicit H on chiral center
std::string smi = "c1ccccc1[C@]([I])(C)NC";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms() == 11)
ROMol *nmol = MolFragmenter::fragmentOnBRICSBonds(*mol);
TEST_ASSERT(nmol);
TEST_ASSERT(nmol->getNumAtoms() == 15);
smi = MolToSmiles(*nmol, true);
TEST_ASSERT(smi == "[16*]c1ccccc1.[4*][C@]([8*])(C)I.[5*]NC");
delete mol;
delete nmol;
}
{ // The original example
std::string smi = "c1ccccc1[C@H](C)NC";
RWMol *mol = SmilesToMol(smi);
TEST_ASSERT(mol);
TEST_ASSERT(mol->getNumAtoms() == 10)
ROMol *nmol = MolFragmenter::fragmentOnBRICSBonds(*mol);
TEST_ASSERT(nmol);
TEST_ASSERT(nmol->getNumAtoms() == 14);
smi = MolToSmiles(*nmol, true);
TEST_ASSERT(smi == "[16*]c1ccccc1.[4*][C@H]([8*])C.[5*]NC");
delete mol;
delete nmol;
}
BOOST_LOG(rdInfoLog) << "\tdone" << std::endl;
}
int main() {
RDLog::InitLogs();
BOOST_LOG(rdInfoLog)
<< "********************************************************\n";
BOOST_LOG(rdInfoLog) << "Testing Chemical Transforms \n";
#if 1
testDeleteSubstruct();
testReplaceSubstructs();
testReplaceSubstructs2();
testReplaceSidechains();
testReplaceCore();
testReplaceCoreLabels();
testReplaceCoreCrash();
testReplaceCorePositions();
testReplaceCoreMatchVect();
testMurckoDecomp();
testReplaceCoreRequireDummies();
testIssue3453144();
testIssue3537675();
testCombineMols();
testAddRecursiveQueries();
testParseQueryDefFile();
testIssue275();
testFragmentOnBonds();
testFragmentOnBRICSBonds();
testFragmentOnSomeBonds();
// benchFragmentOnBRICSBonds();
testGithubIssue429();
testGithubIssue430();
testGithubIssue511();
testReplaceCore2();
#endif
testGithub1734();
BOOST_LOG(rdInfoLog)
<< "*******************************************************\n";
return (0);
}