mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-04 21:54:27 +08:00
2526 lines
98 KiB
C++
2526 lines
98 KiB
C++
//
|
|
// Copyright (C) 2021-2025 Greg Landrum and other RDKit contributors
|
|
//
|
|
// @@ All Rights Reserved @@
|
|
// This file is part of the RDKit.
|
|
// The contents are covered by the terms of the BSD license
|
|
// which is included in the file license.txt, found at the root
|
|
// of the RDKit source tree.
|
|
//
|
|
|
|
#include <ranges>
|
|
#include <catch2/catch_all.hpp>
|
|
#include <GraphMol/MolAlign/AlignMolecules.h>
|
|
#include <GraphMol/RDKitBase.h>
|
|
#include <GraphMol/Chirality.h>
|
|
#include "RDDepictor.h"
|
|
#include "DepictUtils.h"
|
|
#include <GraphMol/SmilesParse/SmilesParse.h>
|
|
#include <GraphMol/SmilesParse/SmilesWrite.h>
|
|
#include <GraphMol/FileParsers/FileParsers.h>
|
|
#include <GraphMol/FileParsers/MolFileStereochem.h>
|
|
#include <GraphMol/MolTransforms/MolTransforms.h>
|
|
#include <GraphMol/test_fixtures.h>
|
|
|
|
using namespace RDKit;
|
|
|
|
TEST_CASE(
|
|
"github #4504: overlapping coordinates with 1,1-disubstituted "
|
|
"cyclobutanes") {
|
|
SECTION("basics") {
|
|
auto m = "CCC1(CCC1)CC1CCCCC1"_smiles;
|
|
REQUIRE(m);
|
|
CHECK(RDDepict::compute2DCoords(*m) == 0);
|
|
auto &conf = m->getConformer();
|
|
auto v = conf.getAtomPos(1) - conf.getAtomPos(3);
|
|
CHECK(v.length() > 0.1);
|
|
v = conf.getAtomPos(1) - conf.getAtomPos(5);
|
|
CHECK(v.length() > 0.1);
|
|
}
|
|
SECTION("this one was ok") {
|
|
auto m = "CCC1(CCC1)C1CCCCC1"_smiles;
|
|
REQUIRE(m);
|
|
CHECK(RDDepict::compute2DCoords(*m) == 0);
|
|
auto &conf = m->getConformer();
|
|
auto v = conf.getAtomPos(1) - conf.getAtomPos(3);
|
|
CHECK(v.length() > 0.1);
|
|
v = conf.getAtomPos(1) - conf.getAtomPos(5);
|
|
CHECK(v.length() > 0.1);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("square planar", "[nontetrahedral]") {
|
|
SECTION("cis-platin") {
|
|
auto m = "Cl[Pt@SP1](Cl)(<-[NH3])<-[NH3]"_smiles;
|
|
REQUIRE(m);
|
|
CHECK(RDDepict::compute2DCoords(*m) == 0);
|
|
auto &conf = m->getConformer();
|
|
auto v1 = conf.getAtomPos(0) - conf.getAtomPos(2);
|
|
auto v2 = conf.getAtomPos(0) - conf.getAtomPos(3);
|
|
CHECK(v1.length() < v2.length());
|
|
}
|
|
SECTION("trans-platin") {
|
|
auto m = "Cl[Pt@SP2](Cl)(<-[NH3])<-[NH3]"_smiles;
|
|
REQUIRE(m);
|
|
CHECK(RDDepict::compute2DCoords(*m) == 0);
|
|
auto &conf = m->getConformer();
|
|
auto v1 = conf.getAtomPos(0) - conf.getAtomPos(2);
|
|
auto v2 = conf.getAtomPos(0) - conf.getAtomPos(3);
|
|
CHECK(v1.length() > v2.length());
|
|
}
|
|
SECTION("trans-metal in a ring") {
|
|
auto m = "C1[Pt@SP2](CCC1)(<-[NH3])<-[NH3]"_smiles;
|
|
REQUIRE(m);
|
|
CHECK(RDDepict::compute2DCoords(*m) == 0);
|
|
// std::cerr << MolToV3KMolBlock(*m) << std::endl;
|
|
auto &conf = m->getConformer();
|
|
auto v1 = conf.getAtomPos(0) - conf.getAtomPos(2);
|
|
auto v2 = conf.getAtomPos(0) - conf.getAtomPos(5);
|
|
CHECK(v1.length() > v2.length());
|
|
}
|
|
SECTION("cis-metal in a ring") {
|
|
auto m = "C1[Pt@SP1](CCC1)(<-[NH3])<-[NH3]"_smiles;
|
|
REQUIRE(m);
|
|
CHECK(RDDepict::compute2DCoords(*m) == 0);
|
|
// std::cerr << MolToV3KMolBlock(*m) << std::endl;
|
|
auto &conf = m->getConformer();
|
|
auto v1 = conf.getAtomPos(0) - conf.getAtomPos(2);
|
|
auto v2 = conf.getAtomPos(0) - conf.getAtomPos(5);
|
|
CHECK(v1.length() < v2.length());
|
|
}
|
|
}
|
|
|
|
TEST_CASE("trigonal bipyramidal", "[nontetrahedral]") {
|
|
SECTION("TB1") {
|
|
auto m = "S[As@TB1](F)(Cl)(Br)N"_smiles;
|
|
REQUIRE(m);
|
|
CHECK(RDDepict::compute2DCoords(*m) == 0);
|
|
auto &conf = m->getConformer();
|
|
auto v1 = conf.getAtomPos(0) - conf.getAtomPos(5); // ax - ax
|
|
auto v2 = conf.getAtomPos(0) - conf.getAtomPos(4); // ax - eq
|
|
auto v3 = conf.getAtomPos(2) - conf.getAtomPos(4); // eq - eq long
|
|
auto v4 = conf.getAtomPos(2) - conf.getAtomPos(3); // eq - eq short
|
|
CHECK(v1.length() > v2.length());
|
|
CHECK(v1.length() > v3.length());
|
|
CHECK(v3.length() > v2.length());
|
|
CHECK(v3.length() > v4.length());
|
|
CHECK(v2.length() > v4.length());
|
|
}
|
|
SECTION("TB3") {
|
|
auto m = "S[As@TB3](F)(Cl)(N)Br"_smiles;
|
|
REQUIRE(m);
|
|
CHECK(RDDepict::compute2DCoords(*m) == 0);
|
|
auto &conf = m->getConformer();
|
|
auto v1 = conf.getAtomPos(0) - conf.getAtomPos(4); // ax - ax
|
|
auto v2 = conf.getAtomPos(0) - conf.getAtomPos(5); // ax - eq
|
|
auto v3 = conf.getAtomPos(2) - conf.getAtomPos(5); // eq - eq long
|
|
auto v4 = conf.getAtomPos(2) - conf.getAtomPos(3); // eq - eq short
|
|
CHECK(v1.length() > v2.length());
|
|
CHECK(v1.length() > v3.length());
|
|
CHECK(v3.length() > v2.length());
|
|
CHECK(v3.length() > v4.length());
|
|
CHECK(v2.length() > v4.length());
|
|
}
|
|
SECTION("TB1 missing ax") {
|
|
// // S[As@TB1](F)(Cl)(Br)* => S[As@TB7](*)(F)(Cl)Br
|
|
auto m = "S[As@TB7](F)(Cl)Br"_smiles;
|
|
REQUIRE(m);
|
|
|
|
CHECK_THAT(
|
|
Chirality::getIdealAngleBetweenLigands(
|
|
m->getAtomWithIdx(1), m->getAtomWithIdx(0), m->getAtomWithIdx(2)),
|
|
Catch::Matchers::WithinAbs(90, 0.001));
|
|
CHECK_THAT(
|
|
Chirality::getIdealAngleBetweenLigands(
|
|
m->getAtomWithIdx(1), m->getAtomWithIdx(0), m->getAtomWithIdx(3)),
|
|
Catch::Matchers::WithinAbs(90, 0.001));
|
|
CHECK_THAT(
|
|
Chirality::getIdealAngleBetweenLigands(
|
|
m->getAtomWithIdx(1), m->getAtomWithIdx(0), m->getAtomWithIdx(4)),
|
|
Catch::Matchers::WithinAbs(90, 0.001));
|
|
CHECK_THAT(
|
|
Chirality::getIdealAngleBetweenLigands(
|
|
m->getAtomWithIdx(1), m->getAtomWithIdx(2), m->getAtomWithIdx(3)),
|
|
Catch::Matchers::WithinAbs(120, 0.001));
|
|
|
|
CHECK(RDDepict::compute2DCoords(*m) == 0);
|
|
auto &conf = m->getConformer();
|
|
auto v2 = conf.getAtomPos(0) - conf.getAtomPos(4); // ax - eq
|
|
auto v3 = conf.getAtomPos(2) - conf.getAtomPos(4); // eq - eq long
|
|
auto v4 = conf.getAtomPos(2) - conf.getAtomPos(3); // eq - eq short
|
|
CHECK(v3.length() > v2.length());
|
|
CHECK(v3.length() > v4.length());
|
|
CHECK(v2.length() > v4.length());
|
|
}
|
|
}
|
|
|
|
TEST_CASE("octahedral", "[nontetrahedral]") {
|
|
SECTION("OH1") {
|
|
auto m = "O[Co@OH1](Cl)(C)(N)(F)P"_smiles;
|
|
REQUIRE(m);
|
|
CHECK(RDDepict::compute2DCoords(*m) == 0);
|
|
// std::cerr << MolToV3KMolBlock(*m) << std::endl;
|
|
auto &conf = m->getConformer();
|
|
auto v1 = conf.getAtomPos(3) - conf.getAtomPos(5); // ax - ax
|
|
auto v2 = conf.getAtomPos(3) - conf.getAtomPos(4); // ax - eq
|
|
auto v3 = conf.getAtomPos(3) - conf.getAtomPos(0); // ax - eq
|
|
auto v4 = conf.getAtomPos(0) - conf.getAtomPos(4); // eq - eq nbr
|
|
auto v5 = conf.getAtomPos(0) - conf.getAtomPos(6); // eq - eq cross
|
|
auto v6 = conf.getAtomPos(0) - conf.getAtomPos(2); // eq - eq longnbr
|
|
|
|
CHECK(v1.length() > v2.length());
|
|
CHECK(v1.length() > v3.length());
|
|
CHECK(v1.length() > v4.length());
|
|
CHECK(v1.length() > v6.length());
|
|
CHECK(v5.length() > v4.length());
|
|
CHECK(v5.length() > v6.length());
|
|
}
|
|
SECTION("OH3") {
|
|
auto m = "O[Co@OH3](Cl)(C)(N)(P)F"_smiles;
|
|
REQUIRE(m);
|
|
CHECK(RDDepict::compute2DCoords(*m) == 0);
|
|
// std::cerr << MolToV3KMolBlock(*m) << std::endl;
|
|
auto &conf = m->getConformer();
|
|
auto v1 = conf.getAtomPos(3) - conf.getAtomPos(6); // ax - ax
|
|
auto v2 = conf.getAtomPos(3) - conf.getAtomPos(4); // ax - eq
|
|
auto v3 = conf.getAtomPos(3) - conf.getAtomPos(0); // ax - eq
|
|
auto v4 = conf.getAtomPos(0) - conf.getAtomPos(4); // eq - eq nbr
|
|
auto v5 = conf.getAtomPos(0) - conf.getAtomPos(5); // eq - eq cross
|
|
auto v6 = conf.getAtomPos(0) - conf.getAtomPos(2); // eq - eq longnbr
|
|
|
|
CHECK(v1.length() > v2.length());
|
|
CHECK(v1.length() > v3.length());
|
|
CHECK(v1.length() > v4.length());
|
|
CHECK(v1.length() > v6.length());
|
|
CHECK(v5.length() > v4.length());
|
|
CHECK(v5.length() > v6.length());
|
|
}
|
|
SECTION("OH1 missing one ligand") {
|
|
// O[Co@OH1](Cl)(C)(N)(F)* => O[Co@OH25](*)(Cl)(C)(N)F
|
|
auto m = "O[Co@OH25](Cl)(C)(N)F"_smiles;
|
|
REQUIRE(m);
|
|
CHECK(RDDepict::compute2DCoords(*m) == 0);
|
|
// std::cerr << MolToV3KMolBlock(*m) << std::endl;
|
|
auto &conf = m->getConformer();
|
|
auto v1 = conf.getAtomPos(3) - conf.getAtomPos(5); // ax - ax
|
|
auto v2 = conf.getAtomPos(3) - conf.getAtomPos(4); // ax - eq
|
|
auto v3 = conf.getAtomPos(3) - conf.getAtomPos(0); // ax - eq
|
|
auto v4 = conf.getAtomPos(0) - conf.getAtomPos(4); // eq - eq nbr
|
|
auto v6 = conf.getAtomPos(0) - conf.getAtomPos(2); // eq - eq longnbr
|
|
|
|
CHECK(v1.length() > v2.length());
|
|
CHECK(v1.length() > v3.length());
|
|
CHECK(v1.length() > v4.length());
|
|
CHECK(v1.length() > v6.length());
|
|
}
|
|
}
|
|
|
|
TEST_CASE("use ring system templates") {
|
|
SECTION("in compute2DCoords") {
|
|
auto mol = "C1CCC2C(C1)C1CCN2NN1"_smiles;
|
|
RDDepict::Compute2DCoordParameters params;
|
|
RDDepict::compute2DCoords(*mol, params);
|
|
auto diff =
|
|
mol->getConformer().getAtomPos(10) - mol->getConformer().getAtomPos(11);
|
|
// when templates are not used, bond from 10-11 is very short
|
|
TEST_ASSERT(RDKit::feq(diff.length(), 0.116, .1));
|
|
|
|
params.useRingTemplates = true;
|
|
RDDepict::compute2DCoords(*mol, params);
|
|
diff =
|
|
mol->getConformer().getAtomPos(10) - mol->getConformer().getAtomPos(11);
|
|
TEST_ASSERT(RDKit::feq(diff.length(), 1.0, .1))
|
|
}
|
|
SECTION("in generateDepictionMatching2DStructure") {
|
|
auto align_ref_mol = R"CTAB(
|
|
RDKit 2D
|
|
|
|
0 0 0 0 0 0 0 0 0 0999 V3000
|
|
M V30 BEGIN CTAB
|
|
M V30 COUNTS 6 6 0 0 0
|
|
M V30 BEGIN ATOM
|
|
M V30 1 N -5.242424 0.787879 0.000000 0
|
|
M V30 2 C -4.492420 2.086915 0.000000 0
|
|
M V30 3 C -2.992419 2.086916 0.000000 0
|
|
M V30 4 C -2.242418 0.787879 0.000000 0
|
|
M V30 5 C -2.992416 -0.511157 0.000000 0
|
|
M V30 6 C -4.492420 -0.511158 0.000000 0
|
|
M V30 END ATOM
|
|
M V30 BEGIN BOND
|
|
M V30 1 1 2 3
|
|
M V30 2 2 3 4
|
|
M V30 3 1 4 5
|
|
M V30 4 2 5 6
|
|
M V30 5 2 2 1
|
|
M V30 6 1 1 6
|
|
M V30 END BOND
|
|
M V30 END CTAB
|
|
M END
|
|
$$$$
|
|
)CTAB"_ctab;
|
|
|
|
auto mol = "CC1=CC(C23C4C5C6C4C2C6C53)=CN=C1"_smiles;
|
|
|
|
REQUIRE(align_ref_mol);
|
|
REQUIRE(mol);
|
|
|
|
const auto &ref_coords = align_ref_mol->getConformer().getPositions();
|
|
|
|
// coordinates of the matched atoms must match the reference
|
|
auto check_match_coords = [](const auto &mol, const auto &ref_coords,
|
|
const MatchVectType &match) {
|
|
const auto &coords = mol.getConformer().getPositions();
|
|
return std::ranges::all_of(
|
|
match,
|
|
[&coords, &ref_coords](const auto &match_pair) {
|
|
auto diff =
|
|
ref_coords[match_pair.first] - coords[match_pair.second];
|
|
return RDKit::feq(diff.length(), 0.);
|
|
}
|
|
|
|
);
|
|
};
|
|
|
|
// whether the molecule has too long or too short bonds (thresholds are
|
|
// arbitrary)
|
|
auto has_weird_bonds = [](const auto &mol) {
|
|
const auto &coords = mol.getConformer().getPositions();
|
|
for (auto bond : mol.bonds()) {
|
|
auto diff =
|
|
coords[bond->getBeginAtomIdx()] - coords[bond->getEndAtomIdx()];
|
|
if (auto length = diff.length(); length < 1.0 || length > 2.0) {
|
|
return true;
|
|
}
|
|
};
|
|
return false;
|
|
};
|
|
|
|
RDDepict::ConstrainedDepictionParams params;
|
|
|
|
// without ring templates
|
|
params.useRingTemplates = false;
|
|
|
|
auto match = RDDepict::generateDepictionMatching2DStructure(
|
|
*mol, *align_ref_mol, -1, nullptr, params);
|
|
REQUIRE(match.size() == 6);
|
|
|
|
CHECK(check_match_coords(*mol, ref_coords, match) == true);
|
|
|
|
// by default, RDkit's coordinate generation creates some
|
|
// weird bonds for cubane
|
|
CHECK(has_weird_bonds(*mol) == true);
|
|
|
|
// with ring templates
|
|
params.useRingTemplates = true;
|
|
|
|
match = RDDepict::generateDepictionMatching2DStructure(*mol, *align_ref_mol,
|
|
-1, nullptr, params);
|
|
REQUIRE(match.size() == 6);
|
|
CHECK(check_match_coords(*mol, ref_coords, match) == true);
|
|
|
|
// when using ring templates, cubane bonds are all approximately
|
|
// the same length, which is reasonable
|
|
CHECK(has_weird_bonds(*mol) == false);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("find core rings") {
|
|
// perhydroanthracene and perhydrophenalene, and their
|
|
// expected number of core rings
|
|
std::map<std::string, unsigned int> examples = {
|
|
{"C1CCC2CC3CCCCC3CC2C1", 1u}, {"C1CC2CCCC3C2C(C1)CCC3", 3u}};
|
|
for (auto example : examples) {
|
|
auto mol = v2::SmilesParse::MolFromSmiles(example.first);
|
|
RDKit::VECT_INT_VECT arings;
|
|
bool includeDativeBonds = true;
|
|
RDKit::MolOps::symmetrizeSSSR(*mol, arings, includeDativeBonds);
|
|
CHECK(arings.size() == 3);
|
|
RDKit::INT_VECT coreRingsIds;
|
|
auto coreRings = RDDepict::findCoreRings(arings, coreRingsIds, *mol);
|
|
CHECK(coreRings.size() == example.second);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("match template with added rings") {
|
|
// this is a molecule we have a template for
|
|
auto mol1 = "C1C2CC3CC1CC3C2"_smiles;
|
|
// and this is the same molecule with an extra ring added
|
|
auto mol2 = "C1C2CC3C1CC1(C2)NC31"_smiles;
|
|
// generate coordinates
|
|
RDDepict::Compute2DCoordParameters params;
|
|
params.useRingTemplates = true;
|
|
RDDepict::compute2DCoords(*mol1, params);
|
|
RDDepict::compute2DCoords(*mol2, params);
|
|
|
|
// align the two molecules
|
|
auto rmsd = MolAlign::getBestRMS(*mol1, *mol2);
|
|
CHECK(rmsd < 0.2);
|
|
}
|
|
|
|
TEST_CASE("templates are aware of E/Z stereochemistry") {
|
|
// this is a molecule we have a template for
|
|
auto mol1 =
|
|
"CCC1C2=N[C@@](C)(C3N/C(=C(/C)C4=N/C(=C\\C5=N/C(=C\\2C)[C@@](C)(CC(N)=O)C5CCC(N)=O)C(C)(C)C4CCC(N)=O)[C@](C)(CCC(=O)NC)C3C)C1(C)C"_smiles;
|
|
// and this is the same molecule with different stereochemistry on double
|
|
// bonds
|
|
auto mol2 =
|
|
"CCC1C2=N[C@@](C)(C3N/C(=C(\\C)C4=N/C(=C/C5=N/C(=C/2C)[C@@](C)(CC(N)=O)C5CCC(N)=O)C(C)(C)C4CCC(N)=O)[C@](C)(CCC(=O)NC)C3C)C1(C)C"_smiles;
|
|
|
|
// generate coordinates for the two molecules, they should be different
|
|
// because only the first one matches the template
|
|
RDDepict::Compute2DCoordParameters params;
|
|
params.useRingTemplates = true;
|
|
RDDepict::compute2DCoords(*mol1, params);
|
|
RDDepict::compute2DCoords(*mol2, params);
|
|
auto rmsd = MolAlign::getBestRMS(*mol1, *mol2);
|
|
CHECK(rmsd > 0.58);
|
|
}
|
|
|
|
TEST_CASE("dative bonds and rings") {
|
|
auto mol = "O->[Pt]1(<-O)<-NC2CCC2N->1"_smiles;
|
|
REQUIRE(mol);
|
|
auto rings = mol->getRingInfo();
|
|
CHECK(rings->numRings() == 1); // the dative bonds are ignored
|
|
RDDepict::compute2DCoords(*mol);
|
|
CHECK(rings->numRings() == 1); // ensure the ring count hasn't changed
|
|
auto conf = mol->getConformer();
|
|
auto v1 = conf.getAtomPos(1) - conf.getAtomPos(3);
|
|
auto v2 = conf.getAtomPos(1) - conf.getAtomPos(8);
|
|
CHECK_THAT(v1.length(), Catch::Matchers::WithinAbs(v2.length(), 0.01));
|
|
}
|
|
|
|
TEST_CASE("vicinal R groups can match an aromatic ring") {
|
|
auto benzene = R"CTAB(
|
|
MJ201100
|
|
|
|
8 8 0 0 0 0 0 0 0 0999 V2000
|
|
-1.0263 -0.3133 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-2.4553 0.5116 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.7408 -0.7258 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.7408 -1.5509 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-2.4553 -1.9633 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-3.1698 -1.5509 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-3.1698 -0.7258 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-2.4553 -0.3133 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
3 1 1 0 0 0 0
|
|
8 2 1 0 0 0 0
|
|
4 3 2 0 0 0 0
|
|
5 4 1 0 0 0 0
|
|
6 5 2 0 0 0 0
|
|
7 6 1 0 0 0 0
|
|
8 3 1 0 0 0 0
|
|
8 7 2 0 0 0 0
|
|
M RGP 2 1 2 2 1
|
|
M END)CTAB"_ctab;
|
|
REQUIRE(benzene);
|
|
auto biphenyl = R"CTAB(
|
|
MJ201100
|
|
|
|
14 15 0 0 0 0 0 0 0 0999 V2000
|
|
-0.6027 2.4098 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.3171 1.9973 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.3171 1.1722 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.6027 0.7597 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.1117 1.1722 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.1117 1.9973 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.6027 -0.0652 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.3171 -0.4777 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.3171 -1.3028 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.6028 -1.7153 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.1117 -1.3028 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.1117 -0.4777 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-2.0316 0.7597 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-2.0316 -0.0652 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1 2 2 0 0 0 0
|
|
2 3 1 0 0 0 0
|
|
3 4 2 0 0 0 0
|
|
4 5 1 0 0 0 0
|
|
5 6 2 0 0 0 0
|
|
6 1 1 0 0 0 0
|
|
4 7 1 0 0 0 0
|
|
8 9 1 0 0 0 0
|
|
9 10 2 0 0 0 0
|
|
10 11 1 0 0 0 0
|
|
11 12 2 0 0 0 0
|
|
7 8 2 0 0 0 0
|
|
12 7 1 0 0 0 0
|
|
3 13 1 0 0 0 0
|
|
8 14 1 0 0 0 0
|
|
M RGP 2 13 1 14 2
|
|
M END)CTAB"_ctab;
|
|
REQUIRE(biphenyl);
|
|
SECTION("R groups on benzene match quinoxaline") {
|
|
auto quinoxaline = "c1ccc2nccnc2c1"_smiles;
|
|
REQUIRE(quinoxaline);
|
|
auto match = RDDepict::generateDepictionMatching2DStructure(
|
|
*quinoxaline, *benzene, -1, nullptr, false, false, true);
|
|
CHECK(match.size() == 8);
|
|
}
|
|
SECTION("R groups on benzene match tetralin") {
|
|
auto tetralin = "c1cccc2CCCCc12"_smiles;
|
|
REQUIRE(tetralin);
|
|
auto match = RDDepict::generateDepictionMatching2DStructure(
|
|
*tetralin, *benzene, -1, nullptr, false, false, true);
|
|
CHECK(match.size() == 8);
|
|
}
|
|
SECTION("R groups on biphenyl match phenantridine") {
|
|
auto phenantridine = "c1cccc2ncc3ccccc3c12"_smiles;
|
|
REQUIRE(phenantridine);
|
|
auto match = RDDepict::generateDepictionMatching2DStructure(
|
|
*phenantridine, *biphenyl, -1, nullptr, false, false, true);
|
|
CHECK(match.size() == 14);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("trans bonds in large rings") {
|
|
// In large rings, we need to retain a trans geometry for double bonds.
|
|
// This simulates the case where we write to SDF and read again.
|
|
auto mol = "C1=C/CCCCCCCCCCCCC/1"_smiles;
|
|
RDDepict::compute2DCoords(*mol);
|
|
// simulate writing to SDF and reading again:
|
|
RDKit::MolOps::removeStereochemistry(*mol);
|
|
mol->getConformer().set3D(true);
|
|
RDKit::MolOps::assignStereochemistryFrom3D(*mol);
|
|
CHECK(RDKit::MolToSmiles(*mol) == "C1=C/CCCCCCCCCCCCC/1");
|
|
}
|
|
|
|
TEST_CASE("generate aligned coords accept failure") {
|
|
auto template_ref_molblock = R"CTAB(
|
|
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
|
|
)CTAB";
|
|
std::unique_ptr<RWMol> template_ref(MolBlockToMol(template_ref_molblock));
|
|
REQUIRE(template_ref);
|
|
auto mol_molblock = R"CTAB(
|
|
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 1 0
|
|
2 3 2 0
|
|
3 4 1 0
|
|
4 5 2 0
|
|
5 6 1 0
|
|
6 1 2 0
|
|
6 8 1 0
|
|
3 9 1 0
|
|
2 7 1 0
|
|
M END
|
|
)CTAB";
|
|
std::unique_ptr<RWMol> mol(MolBlockToMol(mol_molblock));
|
|
REQUIRE(mol);
|
|
SECTION("acceptFailure false, existing coords preserved") {
|
|
REQUIRE_THROWS_AS(RDDepict::generateDepictionMatching2DStructure(
|
|
*mol, *template_ref, -1, nullptr, false, false, true),
|
|
RDDepict::DepictException);
|
|
CHECK(MolToMolBlock(*mol) == mol_molblock);
|
|
}
|
|
SECTION("acceptFailure true, existing coords overwritten") {
|
|
CHECK(RDDepict::generateDepictionMatching2DStructure(
|
|
*mol, *template_ref, -1, nullptr, true, false, true)
|
|
.empty());
|
|
CHECK(MolToMolBlock(*mol) != mol_molblock);
|
|
}
|
|
SECTION("acceptFailure false, no existing coords") {
|
|
mol->removeConformer(0);
|
|
RDDepict::ConstrainedDepictionParams p;
|
|
p.allowRGroups = true;
|
|
p.acceptFailure = false;
|
|
CHECK(mol->getNumConformers() == 0);
|
|
REQUIRE_THROWS_AS(RDDepict::generateDepictionMatching2DStructure(
|
|
*mol, *template_ref, -1, nullptr, p),
|
|
RDDepict::DepictException);
|
|
CHECK(mol->getNumConformers() == 0);
|
|
}
|
|
SECTION("acceptFailure true, no existing coords") {
|
|
mol->removeConformer(0);
|
|
RDDepict::ConstrainedDepictionParams p;
|
|
p.allowRGroups = true;
|
|
p.acceptFailure = true;
|
|
CHECK(mol->getNumConformers() == 0);
|
|
CHECK(RDDepict::generateDepictionMatching2DStructure(*mol, *template_ref,
|
|
-1, nullptr, p)
|
|
.empty());
|
|
CHECK(mol->getNumConformers() == 1);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("generate aligned coords alignOnly") {
|
|
auto template_ref_molblock = R"CTAB(
|
|
RDKit 2D
|
|
|
|
6 6 0 0 0 0 0 0 0 0999 V2000
|
|
-13.7477 6.3036 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-13.7477 4.7567 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-12.6540 3.6628 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-13.7477 2.5691 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-14.8414 3.6628 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-11.1071 3.6628 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1 2 1 0
|
|
2 3 1 0
|
|
3 4 1 0
|
|
4 5 1 0
|
|
2 5 1 0
|
|
3 6 1 0
|
|
M RGP 2 1 1 6 2
|
|
M END
|
|
)CTAB";
|
|
std::unique_ptr<RWMol> template_ref(MolBlockToMol(template_ref_molblock));
|
|
REQUIRE(template_ref);
|
|
auto mol_molblock = R"CTAB(
|
|
RDKit 2D
|
|
|
|
18 22 0 0 0 0 0 0 0 0999 V2000
|
|
4.3922 -1.5699 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2.9211 -2.0479 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2.5995 -0.5349 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
3.3731 0.8046 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
4.8441 1.2825 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
4.0704 -0.0568 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1.8666 0.7748 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.7736 -0.3197 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.7749 -1.8666 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.7718 -1.8679 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.7731 -0.3208 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.8679 0.7718 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-4.0718 -0.0598 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-4.3933 -1.5729 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-2.9222 -2.0509 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-2.6008 -0.5379 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-3.3744 0.8016 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-4.8454 1.2795 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
9 10 1 0
|
|
11 10 1 0
|
|
11 8 1 0
|
|
8 9 1 0
|
|
4 5 1 0
|
|
6 5 1 0
|
|
7 6 1 0
|
|
3 4 1 0
|
|
3 7 1 0
|
|
1 6 1 0
|
|
2 3 1 0
|
|
2 1 1 0
|
|
17 18 1 0
|
|
13 18 1 0
|
|
12 13 1 0
|
|
16 17 1 0
|
|
16 12 1 0
|
|
14 13 1 0
|
|
15 16 1 0
|
|
15 14 1 0
|
|
12 11 1 0
|
|
8 7 1 0
|
|
M END
|
|
)CTAB";
|
|
std::unique_ptr<RWMol> mol(MolBlockToMol(mol_molblock));
|
|
REQUIRE(mol);
|
|
auto bondLength11_12 =
|
|
MolTransforms::getBondLength(mol->getConformer(), 11, 12);
|
|
auto bondLength5_6 = MolTransforms::getBondLength(mol->getConformer(), 5, 6);
|
|
REQUIRE(fabs(bondLength11_12 - bondLength5_6) < 1.e-4);
|
|
REQUIRE(bondLength11_12 > 2.3);
|
|
SECTION("alignOnly false/true") {
|
|
for (auto alignOnly : {false, true}) {
|
|
mol.reset(MolBlockToMol(mol_molblock));
|
|
REQUIRE(mol);
|
|
RDDepict::ConstrainedDepictionParams p;
|
|
p.allowRGroups = true;
|
|
p.alignOnly = alignOnly;
|
|
auto res = RDDepict::generateDepictionMatching2DStructure(
|
|
*mol, *template_ref, -1, nullptr, p);
|
|
std::vector<int> expectedMolIndices{11, 10, 7, 8, 9, 6};
|
|
auto sameIndices = std::all_of(
|
|
res.begin(), res.end(), [&expectedMolIndices](const auto &pair) {
|
|
return pair.second == expectedMolIndices.at(pair.first);
|
|
});
|
|
CHECK(sameIndices);
|
|
CHECK(MolToSmiles(*mol) == "C1CC2CCC1N2C1CNC1N1C2CCC1CC2");
|
|
auto samePositions = std::all_of(
|
|
res.begin(), res.end(), [&mol, &template_ref](const auto &pair) {
|
|
return (mol->getConformer().getAtomPos(pair.second) -
|
|
template_ref->getConformer().getAtomPos(pair.first))
|
|
.lengthSq() < 1.e-4;
|
|
});
|
|
CHECK(samePositions);
|
|
auto bondLengthAli11_12 =
|
|
MolTransforms::getBondLength(mol->getConformer(), 11, 12);
|
|
auto bondLengthAli5_6 =
|
|
MolTransforms::getBondLength(mol->getConformer(), 5, 6);
|
|
CHECK(fabs(bondLengthAli11_12 - bondLengthAli5_6) < 1.e-4);
|
|
if (alignOnly) {
|
|
CHECK(bondLengthAli11_12 > 2.3);
|
|
} else {
|
|
CHECK(bondLengthAli11_12 < 1.6);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("generate aligned coords and wedging") {
|
|
auto wedgedMol = R"CTAB(
|
|
RDKit 2D
|
|
|
|
29 34 0 0 1 0 0 0 0 0999 V2000
|
|
1.3719 5.1304 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.5985 3.7907 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.9482 3.7907 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.7216 5.1304 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-3.2685 5.1304 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-3.8994 3.5835 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-2.5597 4.3569 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-2.5597 5.9038 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-3.8994 6.6771 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-5.2389 5.9038 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-6.5784 6.6771 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-5.2389 4.3569 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1.3719 2.4510 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.5985 1.1115 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1.3719 -0.2276 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2.9188 -0.2276 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
3.6921 1.1115 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2.9188 2.4510 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
5.2389 1.1115 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
6.0124 -0.2276 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
5.2389 -1.5673 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
3.6921 -1.5673 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
3.8996 -5.0201 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
5.2391 -4.2467 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
3.5777 -6.5331 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
4.9909 -5.9040 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
6.0124 -2.9070 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
6.3306 -6.6772 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
6.5784 -5.0201 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2 1 1 1
|
|
2 3 1 0
|
|
3 4 1 0
|
|
5 4 1 6
|
|
5 6 1 0
|
|
6 7 1 0
|
|
7 8 1 0
|
|
9 8 1 1
|
|
5 9 1 0
|
|
9 10 1 0
|
|
10 11 1 1
|
|
10 12 1 0
|
|
6 12 1 1
|
|
2 13 1 0
|
|
13 14 2 0
|
|
14 15 1 0
|
|
15 16 2 0
|
|
16 17 1 0
|
|
17 18 2 0
|
|
13 18 1 0
|
|
17 19 1 0
|
|
19 20 1 0
|
|
20 21 1 0
|
|
21 22 1 0
|
|
16 22 1 0
|
|
23 24 1 0
|
|
23 25 1 0
|
|
25 26 1 0
|
|
24 27 1 0
|
|
27 26 1 0
|
|
26 28 1 0
|
|
24 29 1 0
|
|
28 29 1 0
|
|
21 27 1 0
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(wedgedMol);
|
|
auto invertedWedges = R"CTAB( 2 1 1 6
|
|
2 3 1 0
|
|
3 4 1 0
|
|
5 4 1 1
|
|
5 6 1 0
|
|
6 7 1 0
|
|
7 8 1 0
|
|
9 8 1 6
|
|
5 9 1 0
|
|
9 10 1 0
|
|
10 11 1 6
|
|
10 12 1 0
|
|
6 12 1 6
|
|
2 13 1 0
|
|
13 14 2 0
|
|
14 15 1 0
|
|
15 16 2 0
|
|
16 17 1 0
|
|
17 18 2 0
|
|
13 18 1 0
|
|
17 19 1 0
|
|
19 20 1 0
|
|
20 21 1 0
|
|
21 22 1 0
|
|
16 22 1 0
|
|
23 24 1 0
|
|
23 25 1 0
|
|
25 26 1 0
|
|
24 27 1 0
|
|
27 26 1 0
|
|
26 28 1 0
|
|
24 29 1 0
|
|
28 29 1 0
|
|
21 27 1 0
|
|
)CTAB";
|
|
const std::vector<std::pair<unsigned int, unsigned int>> wedgePairs = {
|
|
{1, 0}, {4, 3}, {8, 7}, {9, 10}, {5, 11}, {1, 12}};
|
|
|
|
auto invertBondDir = [](Bond::BondDir dir) {
|
|
switch (dir) {
|
|
case Bond::BEGINWEDGE:
|
|
return Bond::BEGINDASH;
|
|
case Bond::BEGINDASH:
|
|
return Bond::BEGINWEDGE;
|
|
default:
|
|
return dir;
|
|
}
|
|
};
|
|
|
|
ROMol baseMol(*wedgedMol);
|
|
Chirality::reapplyMolBlockWedging(baseMol);
|
|
|
|
auto getBondDirBetween = [](const ROMol &mol, unsigned int a1,
|
|
unsigned int a2) {
|
|
const auto bond = mol.getBondBetweenAtoms(a1, a2);
|
|
REQUIRE(bond);
|
|
return bond->getBondDir();
|
|
};
|
|
SECTION("wedging all within scaffold") {
|
|
auto scaffold = R"CTAB(
|
|
RDKit 2D
|
|
|
|
13 14 0 0 1 0 0 0 0 0999 V2000
|
|
-1.6549 2.5755 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.8814 1.2358 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.6653 1.2358 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1.4385 2.5755 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2.9854 2.5755 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
3.6161 1.0286 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2.2766 1.8019 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2.2766 3.3487 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
3.6161 4.1222 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
4.9558 3.3487 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
6.2953 4.1222 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0
|
|
4.9558 1.8019 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.6549 -0.1037 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2 1 1 0
|
|
2 3 1 0
|
|
3 4 1 0
|
|
5 4 1 1
|
|
5 6 1 0
|
|
6 7 1 6
|
|
7 8 1 0
|
|
9 8 1 6
|
|
5 9 1 0
|
|
9 10 1 0
|
|
10 11 1 6
|
|
10 12 1 0
|
|
6 12 1 0
|
|
2 13 1 6
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(scaffold);
|
|
// the "alignOnly" alignment should succeed and preserve molblock wedging
|
|
// (inverted with respect to the original molecule)
|
|
// it should feature a narrow angle between the bridge bonds
|
|
// as the original geometry of the bridge is preserved
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
RDDepict::ConstrainedDepictionParams p;
|
|
p.alignOnly = true;
|
|
REQUIRE(!RDDepict::generateDepictionMatching2DStructure(
|
|
wedgedMolCopy, *scaffold, -1, nullptr, p)
|
|
.empty());
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto angle =
|
|
MolTransforms::getAngleDeg(wedgedMolCopy.getConformer(), 23, 26, 25);
|
|
CHECK((angle > 10. && angle < 15.));
|
|
for (const auto &p : wedgePairs) {
|
|
CHECK(getBondDirBetween(wedgedMolCopy, p.first, p.second) ==
|
|
invertBondDir(getBondDirBetween(baseMol, p.first, p.second)));
|
|
}
|
|
}
|
|
// the "alignOnly" alignment should succeed and preserve molblock wedging
|
|
// (same as original molecule)
|
|
// it should feature a narrow angle between the bridge bonds
|
|
// as the original geometry of the bridge is preserved
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
RDDepict::ConstrainedDepictionParams p;
|
|
p.alignOnly = true;
|
|
p.adjustMolBlockWedging = false;
|
|
REQUIRE(!RDDepict::generateDepictionMatching2DStructure(
|
|
wedgedMolCopy, *scaffold, -1, nullptr, p)
|
|
.empty());
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto angle =
|
|
MolTransforms::getAngleDeg(wedgedMolCopy.getConformer(), 23, 26, 25);
|
|
CHECK((angle > 10. && angle < 15.));
|
|
for (const auto &p : wedgePairs) {
|
|
CHECK(getBondDirBetween(wedgedMolCopy, p.first, p.second) ==
|
|
getBondDirBetween(baseMol, p.first, p.second));
|
|
}
|
|
}
|
|
// the "rebuild" alignment should succeed and preserve molblock wedging
|
|
// (inverted with respect to the original molecule)
|
|
// it should feature a much wider angle between the bridge bonds as the
|
|
// bridged system is entirely rebuilt since it is not part of the scaffold
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
REQUIRE(!RDDepict::generateDepictionMatching2DStructure(wedgedMolCopy,
|
|
*scaffold)
|
|
.empty());
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto angle =
|
|
MolTransforms::getAngleDeg(wedgedMolCopy.getConformer(), 23, 26, 25);
|
|
CHECK((angle > 105. && angle < 110.));
|
|
for (const auto &p : wedgePairs) {
|
|
CHECK(getBondDirBetween(wedgedMolCopy, p.first, p.second) ==
|
|
invertBondDir(getBondDirBetween(baseMol, p.first, p.second)));
|
|
}
|
|
}
|
|
// the "rebuild" alignment should succeed and preserve molblock wedging
|
|
// (same as the original molecule)
|
|
// it should feature a much wider angle between the bridge bonds as the
|
|
// bridged system is entirely rebuilt since it is not part of the scaffold
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
RDDepict::ConstrainedDepictionParams p;
|
|
p.adjustMolBlockWedging = false;
|
|
REQUIRE(!RDDepict::generateDepictionMatching2DStructure(
|
|
wedgedMolCopy, *scaffold, -1, nullptr, p)
|
|
.empty());
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto angle =
|
|
MolTransforms::getAngleDeg(wedgedMolCopy.getConformer(), 23, 26, 25);
|
|
CHECK((angle > 105. && angle < 110.));
|
|
for (const auto &p : wedgePairs) {
|
|
CHECK(getBondDirBetween(wedgedMolCopy, p.first, p.second) ==
|
|
getBondDirBetween(baseMol, p.first, p.second));
|
|
}
|
|
}
|
|
#ifdef RDK_BUILD_COORDGEN_SUPPORT
|
|
// the "rebuildCoordGen" alignment should succeed and clear original wedging
|
|
// it should feature an even wider angle between the bridge bonds as
|
|
// CoordGen has a template for the bridged system. Additionally, CoordGen
|
|
// also rebuilds the scaffold, therefore original wedging should be cleared
|
|
RDDepict::preferCoordGen = true;
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
REQUIRE(!RDDepict::generateDepictionMatching2DStructure(wedgedMolCopy,
|
|
*scaffold)
|
|
.empty());
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto angle =
|
|
MolTransforms::getAngleDeg(wedgedMolCopy.getConformer(), 23, 26, 25);
|
|
CHECK((angle > 145. && angle < 150.));
|
|
for (const auto &p : wedgePairs) {
|
|
CHECK(getBondDirBetween(wedgedMolCopy, p.first, p.second) == Bond::NONE);
|
|
}
|
|
}
|
|
// the "rebuildCoordGen" alignment should succeed and keep original wedging
|
|
// unaltered.
|
|
// it should feature an even wider angle between the bridge bonds as
|
|
// CoordGen has a template for the bridged system.
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
RDDepict::ConstrainedDepictionParams p;
|
|
p.adjustMolBlockWedging = false;
|
|
REQUIRE(!RDDepict::generateDepictionMatching2DStructure(
|
|
wedgedMolCopy, *scaffold, -1, nullptr, p)
|
|
.empty());
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto angle =
|
|
MolTransforms::getAngleDeg(wedgedMolCopy.getConformer(), 23, 26, 25);
|
|
CHECK((angle > 145. && angle < 150.));
|
|
for (const auto &p : wedgePairs) {
|
|
CHECK(getBondDirBetween(wedgedMolCopy, p.first, p.second) ==
|
|
getBondDirBetween(baseMol, p.first, p.second));
|
|
}
|
|
}
|
|
RDDepict::preferCoordGen = false;
|
|
#endif
|
|
}
|
|
SECTION("wedging outside scaffold") {
|
|
auto scaffold = R"CTAB(
|
|
RDKit 2D
|
|
|
|
9 10 0 0 1 0 0 0 0 0999 V2000
|
|
-0.8816 0.5663 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.6651 0.5663 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1.2958 -0.9804 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.0435 -0.2072 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.0435 1.3395 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1.2958 2.1129 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2.6355 1.3395 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
3.9750 2.1129 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2.6355 -0.2072 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2 1 1 1
|
|
2 3 1 0
|
|
3 4 1 6
|
|
4 5 1 0
|
|
6 5 1 6
|
|
2 6 1 0
|
|
6 7 1 0
|
|
7 8 1 6
|
|
7 9 1 0
|
|
3 9 1 0
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(scaffold);
|
|
// the "alignOnly" alignment should succeed and preserve molblock wedging
|
|
// (inverted with respect to the original molecule)
|
|
// it should feature a narrow angle between the bridge bonds
|
|
// as the original geometry of the bridge is preserved
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
RDDepict::ConstrainedDepictionParams p;
|
|
p.alignOnly = true;
|
|
REQUIRE(!RDDepict::generateDepictionMatching2DStructure(
|
|
wedgedMolCopy, *scaffold, -1, nullptr, p)
|
|
.empty());
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto angle =
|
|
MolTransforms::getAngleDeg(wedgedMolCopy.getConformer(), 23, 26, 25);
|
|
CHECK((angle > 10. && angle < 15.));
|
|
for (const auto &p : wedgePairs) {
|
|
CHECK(getBondDirBetween(wedgedMolCopy, p.first, p.second) ==
|
|
invertBondDir(getBondDirBetween(baseMol, p.first, p.second)));
|
|
}
|
|
}
|
|
// the "alignOnly" alignment should succeed and preserve molblock wedging
|
|
// (same as original molecule)
|
|
// it should feature a narrow angle between the bridge bonds
|
|
// as the original geometry of the bridge is preserved
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
RDDepict::ConstrainedDepictionParams p;
|
|
p.alignOnly = true;
|
|
p.adjustMolBlockWedging = false;
|
|
REQUIRE(!RDDepict::generateDepictionMatching2DStructure(
|
|
wedgedMolCopy, *scaffold, -1, nullptr, p)
|
|
.empty());
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto angle =
|
|
MolTransforms::getAngleDeg(wedgedMolCopy.getConformer(), 23, 26, 25);
|
|
CHECK((angle > 10. && angle < 15.));
|
|
for (const auto &p : wedgePairs) {
|
|
CHECK(getBondDirBetween(wedgedMolCopy, p.first, p.second) ==
|
|
getBondDirBetween(baseMol, p.first, p.second));
|
|
}
|
|
}
|
|
// the "rebuild" alignment should succeed and clear original wedging
|
|
// it should feature a much wider angle between the bridge bonds as the
|
|
// bridged system is entirely rebuilt since it is not part of the scaffold
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
REQUIRE(!RDDepict::generateDepictionMatching2DStructure(wedgedMolCopy,
|
|
*scaffold)
|
|
.empty());
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto angle =
|
|
MolTransforms::getAngleDeg(wedgedMolCopy.getConformer(), 23, 26, 25);
|
|
CHECK((angle > 105. && angle < 110.));
|
|
for (const auto &p : wedgePairs) {
|
|
CHECK(getBondDirBetween(wedgedMolCopy, p.first, p.second) == Bond::NONE);
|
|
}
|
|
}
|
|
// the "rebuild" alignment should succeed and preserve molblock wedging
|
|
// (same as the original molecule)
|
|
// it should feature a much wider angle between the bridge bonds as the
|
|
// bridged system is entirely rebuilt since it is not part of the scaffold
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
RDDepict::ConstrainedDepictionParams p;
|
|
p.adjustMolBlockWedging = false;
|
|
REQUIRE(!RDDepict::generateDepictionMatching2DStructure(
|
|
wedgedMolCopy, *scaffold, -1, nullptr, p)
|
|
.empty());
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto angle =
|
|
MolTransforms::getAngleDeg(wedgedMolCopy.getConformer(), 23, 26, 25);
|
|
CHECK((angle > 105. && angle < 110.));
|
|
for (const auto &p : wedgePairs) {
|
|
CHECK(getBondDirBetween(wedgedMolCopy, p.first, p.second) ==
|
|
getBondDirBetween(baseMol, p.first, p.second));
|
|
}
|
|
}
|
|
#ifdef RDK_BUILD_COORDGEN_SUPPORT
|
|
// the "rebuildCoordGen" alignment should succeed and clear original wedging
|
|
// it should feature an even wider angle between the bridge bonds as
|
|
// CoordGen has a template for the bridged system. Additionally, CoordGen
|
|
// also rebuilds the scaffold, therefore original wedging should be cleared
|
|
RDDepict::preferCoordGen = true;
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
REQUIRE(!RDDepict::generateDepictionMatching2DStructure(wedgedMolCopy,
|
|
*scaffold)
|
|
.empty());
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto angle =
|
|
MolTransforms::getAngleDeg(wedgedMolCopy.getConformer(), 23, 26, 25);
|
|
CHECK((angle > 145. && angle < 150.));
|
|
for (const auto &p : wedgePairs) {
|
|
CHECK(getBondDirBetween(wedgedMolCopy, p.first, p.second) == Bond::NONE);
|
|
}
|
|
}
|
|
// the "rebuildCoordGen" alignment should succeed and keep original wedging
|
|
// unaltered.
|
|
// it should feature an even wider angle between the bridge bonds as
|
|
// CoordGen has a template for the bridged system.
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
RDDepict::ConstrainedDepictionParams p;
|
|
p.adjustMolBlockWedging = false;
|
|
REQUIRE(!RDDepict::generateDepictionMatching2DStructure(
|
|
wedgedMolCopy, *scaffold, -1, nullptr, p)
|
|
.empty());
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto angle =
|
|
MolTransforms::getAngleDeg(wedgedMolCopy.getConformer(), 23, 26, 25);
|
|
CHECK((angle > 145. && angle < 150.));
|
|
for (const auto &p : wedgePairs) {
|
|
CHECK(getBondDirBetween(wedgedMolCopy, p.first, p.second) ==
|
|
getBondDirBetween(baseMol, p.first, p.second));
|
|
}
|
|
}
|
|
RDDepict::preferCoordGen = false;
|
|
#endif
|
|
}
|
|
SECTION("wedging no match") {
|
|
auto scaffoldNoMatch = R"CTAB(
|
|
RDKit 2D
|
|
|
|
13 14 0 0 1 0 0 0 0 0999 V2000
|
|
-1.6549 2.5755 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.8814 1.2358 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.6653 1.2358 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1.4385 2.5755 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2.9854 2.5755 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
3.6161 1.0286 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2.2766 1.8019 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2.2766 3.3487 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
3.6161 4.1222 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
4.9558 3.3487 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
6.2953 4.1222 0.0000 Cl 0 0 0 0 0 0 0 0 0 0 0 0
|
|
4.9558 1.8019 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.6549 -0.1037 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2 1 1 0
|
|
2 3 1 0
|
|
3 4 1 0
|
|
5 4 1 1
|
|
5 6 1 0
|
|
6 7 1 6
|
|
7 8 1 0
|
|
9 8 1 6
|
|
5 9 1 0
|
|
9 10 1 0
|
|
10 11 1 6
|
|
10 12 1 0
|
|
6 12 1 0
|
|
2 13 1 6
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(scaffoldNoMatch);
|
|
std::string origMolBlock;
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
origMolBlock = MolToMolBlock(wedgedMolCopy);
|
|
}
|
|
REQUIRE(!origMolBlock.empty());
|
|
// the "alignOnly" alignment should throw if acceptFailure is false
|
|
// and preserve the original coordinates
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
RDDepict::ConstrainedDepictionParams p;
|
|
p.alignOnly = true;
|
|
REQUIRE_THROWS_AS(RDDepict::generateDepictionMatching2DStructure(
|
|
wedgedMolCopy, *scaffoldNoMatch, -1, nullptr, p),
|
|
RDDepict::DepictException);
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto currMolBlock = MolToMolBlock(wedgedMolCopy);
|
|
CHECK(currMolBlock == origMolBlock);
|
|
CHECK(currMolBlock.find(invertedWedges) == std::string::npos);
|
|
}
|
|
// the "alignOnly" alignment should return an empty MatchVect if
|
|
// acceptFailure is true and generate new coordinates, hence wedging should
|
|
// be cleared
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
RDDepict::ConstrainedDepictionParams p;
|
|
p.alignOnly = true;
|
|
p.acceptFailure = true;
|
|
REQUIRE(RDDepict::generateDepictionMatching2DStructure(
|
|
wedgedMolCopy, *scaffoldNoMatch, -1, nullptr, p)
|
|
.empty());
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto currMolBlock = MolToMolBlock(wedgedMolCopy);
|
|
CHECK(currMolBlock != origMolBlock);
|
|
CHECK(currMolBlock.find(invertedWedges) == std::string::npos);
|
|
}
|
|
// the "rebuild" alignment should throw if acceptFailure is false
|
|
// and preserve the original coordinates
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
REQUIRE_THROWS_AS(RDDepict::generateDepictionMatching2DStructure(
|
|
wedgedMolCopy, *scaffoldNoMatch),
|
|
RDDepict::DepictException);
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto currMolBlock = MolToMolBlock(wedgedMolCopy);
|
|
CHECK(currMolBlock == origMolBlock);
|
|
CHECK(currMolBlock.find(invertedWedges) == std::string::npos);
|
|
}
|
|
// the "rebuild" alignment should return an empty MatchVect if acceptFailure
|
|
// is true and generate new coordinates, hence wedging should be cleared
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
RDDepict::ConstrainedDepictionParams p;
|
|
p.acceptFailure = true;
|
|
REQUIRE(RDDepict::generateDepictionMatching2DStructure(
|
|
wedgedMolCopy, *scaffoldNoMatch, -1, nullptr, p)
|
|
.empty());
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto currMolBlock = MolToMolBlock(wedgedMolCopy);
|
|
CHECK(currMolBlock != origMolBlock);
|
|
CHECK(currMolBlock.find(invertedWedges) == std::string::npos);
|
|
}
|
|
#ifdef RDK_BUILD_COORDGEN_SUPPORT
|
|
// the "rebuildCoordGen" alignment should throw if acceptFailure is false
|
|
// and preserve the original coordinates
|
|
RDDepict::preferCoordGen = true;
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
REQUIRE_THROWS_AS(RDDepict::generateDepictionMatching2DStructure(
|
|
wedgedMolCopy, *scaffoldNoMatch),
|
|
RDDepict::DepictException);
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto currMolBlock = MolToMolBlock(wedgedMolCopy);
|
|
CHECK(currMolBlock == origMolBlock);
|
|
CHECK(currMolBlock.find(invertedWedges) == std::string::npos);
|
|
}
|
|
// the "rebuildCoordGen" alignment should return an empty MatchVect if
|
|
// acceptFailure is true and generate new coordinates, hence wedging should
|
|
// be cleared
|
|
{
|
|
ROMol wedgedMolCopy(*wedgedMol);
|
|
RDDepict::ConstrainedDepictionParams p;
|
|
p.acceptFailure = true;
|
|
REQUIRE(RDDepict::generateDepictionMatching2DStructure(
|
|
wedgedMolCopy, *scaffoldNoMatch, -1, nullptr, p)
|
|
.empty());
|
|
Chirality::reapplyMolBlockWedging(wedgedMolCopy);
|
|
auto currMolBlock = MolToMolBlock(wedgedMolCopy);
|
|
CHECK(currMolBlock != origMolBlock);
|
|
CHECK(currMolBlock.find(invertedWedges) == std::string::npos);
|
|
}
|
|
RDDepict::preferCoordGen = false;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
TEST_CASE("generate aligned coords R group match") {
|
|
auto templateRef = R"CTAB(
|
|
MJ201100
|
|
|
|
7 7 0 0 0 0 0 0 0 0999 V2000
|
|
-0.5804 1.2045 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.2948 0.7920 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.2948 -0.0330 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.5804 -0.4455 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.1340 -0.0330 0.0000 A 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.1340 0.7920 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.8485 -0.4455 0.0000 R# 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1 2 2 0 0 0 0
|
|
2 3 1 0 0 0 0
|
|
3 4 2 0 0 0 0
|
|
6 1 1 0 0 0 0
|
|
4 5 1 0 0 0 0
|
|
5 6 2 0 0 0 0
|
|
5 7 1 0 0 0 0
|
|
M RGP 1 7 1
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(templateRef);
|
|
RDDepict::ConstrainedDepictionParams p;
|
|
p.allowRGroups = true;
|
|
SECTION("heavy") {
|
|
for (auto alignOnly : {true, false}) {
|
|
p.alignOnly = alignOnly;
|
|
auto mol = "Cc1ccccc1"_smiles;
|
|
REQUIRE(mol);
|
|
REQUIRE(mol->getNumAtoms() == 7);
|
|
CHECK(RDDepict::generateDepictionMatching2DStructure(*mol, *templateRef,
|
|
-1, nullptr, p)
|
|
.size() == 7);
|
|
}
|
|
}
|
|
SECTION("implicit hydrogen") {
|
|
for (auto alignOnly : {true, false}) {
|
|
p.alignOnly = alignOnly;
|
|
auto mol = "c1ccccc1"_smiles;
|
|
REQUIRE(mol);
|
|
REQUIRE(mol->getNumAtoms() == 6);
|
|
CHECK(RDDepict::generateDepictionMatching2DStructure(*mol, *templateRef,
|
|
-1, nullptr, p)
|
|
.size() == 6);
|
|
}
|
|
}
|
|
SECTION("explicit hydrogen") {
|
|
auto smi = "[H]c1ccccc1";
|
|
SmilesParserParams smilesParams;
|
|
smilesParams.removeHs = false;
|
|
for (auto alignOnly : {true, false}) {
|
|
p.alignOnly = alignOnly;
|
|
std::unique_ptr<RWMol> mol(SmilesToMol(smi, smilesParams));
|
|
REQUIRE(mol);
|
|
REQUIRE(mol->getNumAtoms() == 7);
|
|
CHECK(RDDepict::generateDepictionMatching2DStructure(*mol, *templateRef,
|
|
-1, nullptr, p)
|
|
.size() == 7);
|
|
}
|
|
}
|
|
SECTION("no atom") {
|
|
for (auto alignOnly : {true, false}) {
|
|
p.alignOnly = alignOnly;
|
|
auto mol = "n1ccccc1"_smiles;
|
|
REQUIRE(mol);
|
|
REQUIRE(mol->getNumAtoms() == 6);
|
|
CHECK(RDDepict::generateDepictionMatching2DStructure(*mol, *templateRef,
|
|
-1, nullptr, p)
|
|
.size() == 6);
|
|
}
|
|
}
|
|
SECTION("charged") {
|
|
for (auto alignOnly : {true, false}) {
|
|
p.alignOnly = alignOnly;
|
|
auto mol = "C[n+]1ccccc1"_smiles;
|
|
REQUIRE(mol);
|
|
REQUIRE(mol->getNumAtoms() == 7);
|
|
CHECK(RDDepict::generateDepictionMatching2DStructure(*mol, *templateRef,
|
|
-1, nullptr, p)
|
|
.size() == 7);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("test GitHub6816") {
|
|
SECTION("double-2000") {
|
|
auto mol = R"CTAB(double-2000.mol
|
|
ChemDraw10192311132D
|
|
|
|
4 3 0 0 0 0 0 0 0 0999 V2000
|
|
-0.7145 0.2062 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.0000 0.6188 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.7145 0.2062 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.7145 -0.6188 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1 2 2 0 0
|
|
2 3 1 4 0
|
|
1 4 1 4 0
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(mol);
|
|
CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::NONE);
|
|
CHECK(mol->getBondWithIdx(1)->getProp<int>(
|
|
common_properties::_MolFileBondStereo) == 4);
|
|
CHECK(!mol->getBondWithIdx(1)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(mol->getBondWithIdx(1)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::NONE);
|
|
CHECK(mol->getBondWithIdx(2)->getProp<int>(
|
|
common_properties::_MolFileBondStereo) == 4);
|
|
CHECK(!mol->getBondWithIdx(2)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(mol->getBondWithIdx(2)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
Chirality::reapplyMolBlockWedging(*mol);
|
|
CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
|
|
|
|
CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::UNKNOWN);
|
|
|
|
CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::UNKNOWN);
|
|
}
|
|
SECTION("double-3000") {
|
|
auto mol = R"CTAB(double-3000.mol
|
|
ChemDraw10232310312D
|
|
|
|
0 0 0 0 0 0 V3000
|
|
M V30 BEGIN CTAB
|
|
M V30 COUNTS 4 3 0 0 0
|
|
M V30 BEGIN ATOM
|
|
M V30 1 C -0.714435 0.206182 0.000000 0
|
|
M V30 2 C 0.000000 0.618744 0.000000 0
|
|
M V30 3 F 0.714435 0.206182 0.000000 0
|
|
M V30 4 O -0.714435 -0.618744 0.000000 0
|
|
M V30 END ATOM
|
|
M V30 BEGIN BOND
|
|
M V30 1 2 1 2
|
|
M V30 2 1 2 3 CFG=2
|
|
M V30 3 1 1 4 CFG=2
|
|
M V30 END BOND
|
|
M V30 END CTAB
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(mol);
|
|
CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(1)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(mol->getBondWithIdx(1)->getProp<int>(
|
|
common_properties::_MolFileBondCfg) == 2);
|
|
CHECK(mol->getBondWithIdx(1)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(2)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(mol->getBondWithIdx(2)->getProp<int>(
|
|
common_properties::_MolFileBondCfg) == 2);
|
|
CHECK(mol->getBondWithIdx(2)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
Chirality::reapplyMolBlockWedging(*mol);
|
|
CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
|
|
|
|
CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::UNKNOWN);
|
|
|
|
CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::UNKNOWN);
|
|
}
|
|
SECTION("double-explicit-crossed-2000") {
|
|
auto mol = R"CTAB(double-explicit-crossed-2000.mol
|
|
ChemDraw10232310432D
|
|
|
|
4 3 0 0 0 0 0 0 0 0999 V2000
|
|
-0.7144 0.2062 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.0000 0.6187 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.7144 0.2062 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.7144 -0.6187 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1 2 2 3
|
|
2 3 1 4
|
|
1 4 1 4
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(mol);
|
|
CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
|
|
CHECK(mol->getBondWithIdx(0)->getProp<int>(
|
|
common_properties::_MolFileBondStereo) == 3);
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::NONE);
|
|
CHECK(mol->getBondWithIdx(1)->getProp<int>(
|
|
common_properties::_MolFileBondStereo) == 4);
|
|
CHECK(!mol->getBondWithIdx(1)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(mol->getBondWithIdx(1)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::NONE);
|
|
CHECK(mol->getBondWithIdx(2)->getProp<int>(
|
|
common_properties::_MolFileBondStereo) == 4);
|
|
CHECK(!mol->getBondWithIdx(2)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(mol->getBondWithIdx(2)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
Chirality::reapplyMolBlockWedging(*mol);
|
|
CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::EITHERDOUBLE);
|
|
|
|
CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::UNKNOWN);
|
|
|
|
CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::UNKNOWN);
|
|
}
|
|
SECTION("double-explicit-crossed-3000") {
|
|
auto mol = R"CTAB(double-explicit-crossed-3000.mol
|
|
ChemDraw10232310422D
|
|
|
|
0 0 0 0 0 0 V3000
|
|
M V30 BEGIN CTAB
|
|
M V30 COUNTS 4 3 0 0 0
|
|
M V30 BEGIN ATOM
|
|
M V30 1 C -0.714435 0.206182 0.000000 0
|
|
M V30 2 C 0.000000 0.618744 0.000000 0
|
|
M V30 3 F 0.714435 0.206182 0.000000 0
|
|
M V30 4 O -0.714435 -0.618744 0.000000 0
|
|
M V30 END ATOM
|
|
M V30 BEGIN BOND
|
|
M V30 1 2 1 2 CFG=2
|
|
M V30 2 1 2 3 CFG=2
|
|
M V30 3 1 1 4 CFG=2
|
|
M V30 END BOND
|
|
M V30 END CTAB
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(mol);
|
|
CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(mol->getBondWithIdx(0)->getProp<int>(
|
|
common_properties::_MolFileBondCfg) == 2);
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(1)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(mol->getBondWithIdx(1)->getProp<int>(
|
|
common_properties::_MolFileBondCfg) == 2);
|
|
CHECK(mol->getBondWithIdx(1)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(2)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(mol->getBondWithIdx(2)->getProp<int>(
|
|
common_properties::_MolFileBondCfg) == 2);
|
|
CHECK(mol->getBondWithIdx(2)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
Chirality::reapplyMolBlockWedging(*mol);
|
|
CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::EITHERDOUBLE);
|
|
|
|
CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::UNKNOWN);
|
|
|
|
CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::UNKNOWN);
|
|
}
|
|
SECTION("double-2-2000") {
|
|
auto mol = R"CTAB(double-2-2000.mol
|
|
ChemDraw10192311332D
|
|
|
|
4 3 0 0 0 0 0 0 0 0999 V2000
|
|
-0.3572 -0.2062 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.3572 0.2062 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1.0717 0.6188 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.0717 -0.6188 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1 2 2 0 0
|
|
2 3 1 4 0
|
|
1 4 1 4 0
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(mol);
|
|
CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::NONE);
|
|
CHECK(mol->getBondWithIdx(1)->getProp<int>(
|
|
common_properties::_MolFileBondStereo) == 4);
|
|
CHECK(!mol->getBondWithIdx(1)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(mol->getBondWithIdx(1)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::NONE);
|
|
CHECK(mol->getBondWithIdx(2)->getProp<int>(
|
|
common_properties::_MolFileBondStereo) == 4);
|
|
CHECK(!mol->getBondWithIdx(2)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(mol->getBondWithIdx(2)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
Chirality::reapplyMolBlockWedging(*mol);
|
|
CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
|
|
|
|
CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::UNKNOWN);
|
|
|
|
CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::UNKNOWN);
|
|
}
|
|
SECTION("double-2-3000") {
|
|
auto mol = R"CTAB(double-2-3000.mol
|
|
ChemDraw10232310312D
|
|
|
|
0 0 0 0 0 0 V3000
|
|
M V30 BEGIN CTAB
|
|
M V30 COUNTS 4 3 0 0 0
|
|
M V30 BEGIN ATOM
|
|
M V30 1 C -0.357168 -0.206181 0.000000 0
|
|
M V30 2 C 0.357167 0.206182 0.000000 0
|
|
M V30 3 F 1.071603 0.618744 0.000000 0
|
|
M V30 4 O -1.071603 -0.618744 0.000000 0
|
|
M V30 END ATOM
|
|
M V30 BEGIN BOND
|
|
M V30 1 2 1 2
|
|
M V30 2 1 2 3 CFG=2
|
|
M V30 3 1 1 4 CFG=2
|
|
M V30 END BOND
|
|
M V30 END CTAB
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(mol);
|
|
CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(1)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(mol->getBondWithIdx(1)->getProp<int>(
|
|
common_properties::_MolFileBondCfg) == 2);
|
|
CHECK(mol->getBondWithIdx(1)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(2)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(mol->getBondWithIdx(2)->getProp<int>(
|
|
common_properties::_MolFileBondCfg) == 2);
|
|
CHECK(mol->getBondWithIdx(2)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
Chirality::reapplyMolBlockWedging(*mol);
|
|
CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
|
|
|
|
CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::UNKNOWN);
|
|
|
|
CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::UNKNOWN);
|
|
}
|
|
SECTION("double-2-explicit-crossed-2000") {
|
|
auto mol = R"CTAB(double-2-explicit-crossed-2000.mol
|
|
ChemDraw10232310432D
|
|
|
|
4 3 0 0 0 0 0 0 0 0999 V2000
|
|
-0.3572 -0.2062 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.3572 0.2062 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1.0716 0.6187 0.0000 F 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.0716 -0.6187 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1 2 2 3
|
|
2 3 1 4
|
|
1 4 1 4
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(mol);
|
|
CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
|
|
CHECK(mol->getBondWithIdx(0)->getProp<int>(
|
|
common_properties::_MolFileBondStereo) == 3);
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::NONE);
|
|
CHECK(mol->getBondWithIdx(1)->getProp<int>(
|
|
common_properties::_MolFileBondStereo) == 4);
|
|
CHECK(!mol->getBondWithIdx(1)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(mol->getBondWithIdx(1)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::NONE);
|
|
CHECK(mol->getBondWithIdx(2)->getProp<int>(
|
|
common_properties::_MolFileBondStereo) == 4);
|
|
CHECK(!mol->getBondWithIdx(2)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(mol->getBondWithIdx(2)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
Chirality::reapplyMolBlockWedging(*mol);
|
|
CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::EITHERDOUBLE);
|
|
|
|
CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::UNKNOWN);
|
|
|
|
CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::UNKNOWN);
|
|
}
|
|
SECTION("double-2-explicit-crossed-3000") {
|
|
auto mol = R"CTAB(double-2-explicit-crossed-3000.mol
|
|
ChemDraw10232310422D
|
|
|
|
0 0 0 0 0 0 V3000
|
|
M V30 BEGIN CTAB
|
|
M V30 COUNTS 4 3 0 0 0
|
|
M V30 BEGIN ATOM
|
|
M V30 1 C -0.357168 -0.206181 0.000000 0
|
|
M V30 2 C 0.357167 0.206182 0.000000 0
|
|
M V30 3 F 1.071603 0.618744 0.000000 0
|
|
M V30 4 O -1.071603 -0.618744 0.000000 0
|
|
M V30 END ATOM
|
|
M V30 BEGIN BOND
|
|
M V30 1 2 1 2 CFG=2
|
|
M V30 2 1 2 3 CFG=2
|
|
M V30 3 1 1 4 CFG=2
|
|
M V30 END BOND
|
|
M V30 END CTAB
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(mol);
|
|
CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(mol->getBondWithIdx(0)->getProp<int>(
|
|
common_properties::_MolFileBondCfg) == 2);
|
|
CHECK(!mol->getBondWithIdx(0)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(1)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(mol->getBondWithIdx(1)->getProp<int>(
|
|
common_properties::_MolFileBondCfg) == 2);
|
|
CHECK(mol->getBondWithIdx(1)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(2)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(mol->getBondWithIdx(2)->getProp<int>(
|
|
common_properties::_MolFileBondCfg) == 2);
|
|
CHECK(mol->getBondWithIdx(2)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
Chirality::reapplyMolBlockWedging(*mol);
|
|
CHECK(mol->getBondWithIdx(0)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(0)->getBondDir() == Bond::EITHERDOUBLE);
|
|
|
|
CHECK(mol->getBondWithIdx(1)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(1)->getBondDir() == Bond::UNKNOWN);
|
|
|
|
CHECK(mol->getBondWithIdx(2)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(2)->getBondDir() == Bond::UNKNOWN);
|
|
}
|
|
SECTION("di-imine-2-2000") {
|
|
auto mol = R"CTAB(di-imine-2-2000.mol
|
|
ChemDraw10192311522D
|
|
|
|
8 7 0 0 0 0 0 0 0 0999 V2000
|
|
-0.9959 -1.0600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.4125 -0.4767 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.4125 -0.4767 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.9959 -1.0600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.7282 0.2855 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.9971 1.0600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.7282 0.2855 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.9971 1.0270 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1 2 1 0 0
|
|
2 3 1 0 0
|
|
3 4 1 0 0
|
|
2 5 2 0 0
|
|
5 6 1 4 0
|
|
3 7 2 0 0
|
|
7 8 1 4 0
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(mol);
|
|
CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(3)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::NONE);
|
|
CHECK(mol->getBondWithIdx(4)->getProp<int>(
|
|
common_properties::_MolFileBondStereo) == 4);
|
|
CHECK(!mol->getBondWithIdx(4)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(mol->getBondWithIdx(4)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::NONE);
|
|
CHECK(mol->getBondWithIdx(6)->getProp<int>(
|
|
common_properties::_MolFileBondStereo) == 4);
|
|
CHECK(!mol->getBondWithIdx(6)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(mol->getBondWithIdx(6)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
Chirality::reapplyMolBlockWedging(*mol);
|
|
CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::NONE);
|
|
|
|
CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::UNKNOWN);
|
|
|
|
CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
|
|
|
|
CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::UNKNOWN);
|
|
}
|
|
SECTION("di-imine-2-3000") {
|
|
auto mol = R"CTAB(di-imine-2-3000.mol
|
|
ChemDraw10232310302D
|
|
|
|
0 0 0 0 0 0 V3000
|
|
M V30 BEGIN CTAB
|
|
M V30 COUNTS 8 7 0 0 0
|
|
M V30 BEGIN ATOM
|
|
M V30 1 C -0.995922 -1.060024 0.000000 0
|
|
M V30 2 C -0.412509 -0.476711 0.000000 0
|
|
M V30 3 C 0.412509 -0.476711 0.000000 0
|
|
M V30 4 C 0.995923 -1.060024 0.000000 0
|
|
M V30 5 N -0.728217 0.285506 0.000000 0
|
|
M V30 6 C -0.997122 1.060024 0.000000 0
|
|
M V30 7 N 0.728216 0.285506 0.000000 0
|
|
M V30 8 C 0.997122 1.027023 0.000000 0
|
|
M V30 END ATOM
|
|
M V30 BEGIN BOND
|
|
M V30 1 1 1 2
|
|
M V30 2 1 2 3
|
|
M V30 3 1 3 4
|
|
M V30 4 2 2 5
|
|
M V30 5 1 5 6 CFG=2
|
|
M V30 6 2 3 7
|
|
M V30 7 1 7 8 CFG=2
|
|
M V30 END BOND
|
|
M V30 END CTAB
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(mol);
|
|
CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(3)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(4)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(mol->getBondWithIdx(4)->getProp<int>(
|
|
common_properties::_MolFileBondCfg) == 2);
|
|
CHECK(mol->getBondWithIdx(4)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(6)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(mol->getBondWithIdx(6)->getProp<int>(
|
|
common_properties::_MolFileBondCfg) == 2);
|
|
CHECK(mol->getBondWithIdx(6)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
Chirality::reapplyMolBlockWedging(*mol);
|
|
CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::NONE);
|
|
|
|
CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::UNKNOWN);
|
|
|
|
CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
|
|
|
|
CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::UNKNOWN);
|
|
}
|
|
SECTION("di-imine-2-explicit-crossed-2000") {
|
|
auto mol = R"CTAB(di-imine-2-explicit-crossed-2000.mol
|
|
ChemDraw10232310432D
|
|
|
|
8 7 0 0 0 0 0 0 0 0999 V2000
|
|
-0.9959 -1.0600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.4125 -0.4767 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.4125 -0.4767 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.9959 -1.0600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.7282 0.2855 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.9971 1.0600 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.7282 0.2855 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.9971 1.0270 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1 2 1 0
|
|
2 3 1 0
|
|
3 4 1 0
|
|
2 5 2 3
|
|
5 6 1 4
|
|
3 7 2 0
|
|
7 8 1 4
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(mol);
|
|
CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::NONE);
|
|
CHECK(mol->getBondWithIdx(3)->getProp<int>(
|
|
common_properties::_MolFileBondStereo) == 3);
|
|
CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::NONE);
|
|
CHECK(mol->getBondWithIdx(4)->getProp<int>(
|
|
common_properties::_MolFileBondStereo) == 4);
|
|
CHECK(!mol->getBondWithIdx(4)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(mol->getBondWithIdx(4)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::NONE);
|
|
CHECK(mol->getBondWithIdx(6)->getProp<int>(
|
|
common_properties::_MolFileBondStereo) == 4);
|
|
CHECK(!mol->getBondWithIdx(6)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(mol->getBondWithIdx(6)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
Chirality::reapplyMolBlockWedging(*mol);
|
|
CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::EITHERDOUBLE);
|
|
|
|
CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::UNKNOWN);
|
|
|
|
CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
|
|
|
|
CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::UNKNOWN);
|
|
}
|
|
SECTION("di-imine-2-explicit-crossed-3000") {
|
|
auto mol = R"CTAB(di-imine-2-explicit-crossed-3000.mol
|
|
ChemDraw10232310432D
|
|
|
|
0 0 0 0 0 0 V3000
|
|
M V30 BEGIN CTAB
|
|
M V30 COUNTS 8 7 0 0 0
|
|
M V30 BEGIN ATOM
|
|
M V30 1 C -0.995922 -1.060024 0.000000 0
|
|
M V30 2 C -0.412509 -0.476711 0.000000 0
|
|
M V30 3 C 0.412509 -0.476711 0.000000 0
|
|
M V30 4 C 0.995923 -1.060024 0.000000 0
|
|
M V30 5 N -0.728217 0.285506 0.000000 0
|
|
M V30 6 C -0.997122 1.060024 0.000000 0
|
|
M V30 7 N 0.728216 0.285506 0.000000 0
|
|
M V30 8 C 0.997122 1.027023 0.000000 0
|
|
M V30 END ATOM
|
|
M V30 BEGIN BOND
|
|
M V30 1 1 1 2
|
|
M V30 2 1 2 3
|
|
M V30 3 1 3 4
|
|
M V30 4 2 2 5 CFG=2
|
|
M V30 5 1 5 6 CFG=2
|
|
M V30 6 2 3 7
|
|
M V30 7 1 7 8 CFG=2
|
|
M V30 END BOND
|
|
M V30 END CTAB
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(mol);
|
|
CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(3)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(mol->getBondWithIdx(3)->getProp<int>(
|
|
common_properties::_MolFileBondCfg) == 2);
|
|
CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(4)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(mol->getBondWithIdx(4)->getProp<int>(
|
|
common_properties::_MolFileBondCfg) == 2);
|
|
CHECK(mol->getBondWithIdx(4)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(6)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(mol->getBondWithIdx(6)->getProp<int>(
|
|
common_properties::_MolFileBondCfg) == 2);
|
|
CHECK(mol->getBondWithIdx(6)->getProp<int>(
|
|
common_properties::_UnknownStereo));
|
|
|
|
Chirality::reapplyMolBlockWedging(*mol);
|
|
CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::EITHERDOUBLE);
|
|
|
|
CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::UNKNOWN);
|
|
|
|
CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
|
|
|
|
CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::UNKNOWN);
|
|
}
|
|
|
|
SECTION("di-imine-cross-2000") {
|
|
auto mol = R"CTAB(di-imine-cross-2000.mol
|
|
ChemDraw10192311582D
|
|
|
|
8 7 0 0 0 0 0 0 0 0999 V2000
|
|
-1.0099 -1.1129 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.5974 -0.3984 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.2276 -0.3984 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.6401 -1.1129 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-0.8109 0.3984 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.6401 0.3160 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.2234 1.1129 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1.2234 0.8994 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1 2 1 0 0
|
|
2 3 1 0 0
|
|
3 4 1 0 0
|
|
2 5 2 3 0
|
|
3 6 2 3 0
|
|
5 7 1 0 0
|
|
6 8 1 0 0
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(mol);
|
|
CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::NONE);
|
|
CHECK(mol->getBondWithIdx(3)->getProp<int>(
|
|
common_properties::_MolFileBondStereo) == 3);
|
|
CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::NONE);
|
|
CHECK(mol->getBondWithIdx(4)->getProp<int>(
|
|
common_properties::_MolFileBondStereo) == 3);
|
|
CHECK(!mol->getBondWithIdx(4)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(4)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(6)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(!mol->getBondWithIdx(6)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(6)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
Chirality::reapplyMolBlockWedging(*mol);
|
|
CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::EITHERDOUBLE);
|
|
|
|
CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::EITHERDOUBLE);
|
|
|
|
CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
|
|
|
|
CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::NONE);
|
|
}
|
|
SECTION("di-imine-cross-3000") {
|
|
auto mol = R"CTAB(di-imine-cross-3000.mol
|
|
ChemDraw10232310302D
|
|
|
|
0 0 0 0 0 0 V3000
|
|
M V30 BEGIN CTAB
|
|
M V30 COUNTS 8 7 0 0 0
|
|
M V30 BEGIN ATOM
|
|
M V30 1 C -1.009900 -1.112900 0.000000 0
|
|
M V30 2 C -0.597400 -0.398400 0.000000 0
|
|
M V30 3 C 0.227600 -0.398400 0.000000 0
|
|
M V30 4 C 0.640100 -1.112900 0.000000 0
|
|
M V30 5 N -0.810900 0.398400 0.000000 0
|
|
M V30 6 N 0.640100 0.316000 0.000000 0
|
|
M V30 7 C -1.223400 1.112900 0.000000 0
|
|
M V30 8 C 1.223400 0.899400 0.000000 0
|
|
M V30 END ATOM
|
|
M V30 BEGIN BOND
|
|
M V30 1 1 1 2
|
|
M V30 2 1 2 3
|
|
M V30 3 1 3 4
|
|
M V30 4 2 2 5 CFG=2
|
|
M V30 5 2 3 6 CFG=2
|
|
M V30 6 1 5 7
|
|
M V30 7 1 6 8
|
|
M V30 END BOND
|
|
M V30 END CTAB
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(mol);
|
|
CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(3)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(mol->getBondWithIdx(3)->getProp<int>(
|
|
common_properties::_MolFileBondCfg) == 2);
|
|
CHECK(!mol->getBondWithIdx(3)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(4)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(mol->getBondWithIdx(4)->getProp<int>(
|
|
common_properties::_MolFileBondCfg) == 2);
|
|
CHECK(!mol->getBondWithIdx(4)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(5)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::NONE);
|
|
CHECK(!mol->getBondWithIdx(6)->hasProp(
|
|
common_properties::_MolFileBondStereo));
|
|
CHECK(!mol->getBondWithIdx(6)->hasProp(common_properties::_MolFileBondCfg));
|
|
CHECK(!mol->getBondWithIdx(6)->hasProp(common_properties::_UnknownStereo));
|
|
|
|
Chirality::reapplyMolBlockWedging(*mol);
|
|
CHECK(mol->getBondWithIdx(3)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(3)->getBondDir() == Bond::EITHERDOUBLE);
|
|
|
|
CHECK(mol->getBondWithIdx(4)->getStereo() == Bond::STEREOANY);
|
|
CHECK(mol->getBondWithIdx(4)->getBondDir() == Bond::EITHERDOUBLE);
|
|
|
|
CHECK(mol->getBondWithIdx(5)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(5)->getBondDir() == Bond::NONE);
|
|
|
|
CHECK(mol->getBondWithIdx(6)->getStereo() == Bond::STEREONONE);
|
|
CHECK(mol->getBondWithIdx(6)->getBondDir() == Bond::NONE);
|
|
}
|
|
SECTION(
|
|
"roundtripping molblock with cis double bond should not change it into crosssed") {
|
|
auto molblockIn = R"CTAB(
|
|
RDKit 2D
|
|
|
|
5 4 0 0 0 0 0 0 0 0999 V2000
|
|
-2.4998 2.4772 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-3.2142 2.0647 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-2.4998 3.3022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-3.2142 3.7147 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-3.9287 3.3022 0.0000 Cl 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2 1 1 0
|
|
1 3 2 0
|
|
3 4 1 0
|
|
4 5 1 0
|
|
M END
|
|
)CTAB";
|
|
{
|
|
std::unique_ptr<RWMol> mol(MolBlockToMol(molblockIn, false));
|
|
auto molblockOut = MolToMolBlock(*mol);
|
|
CHECK(molblockIn == molblockOut);
|
|
}
|
|
{
|
|
std::unique_ptr<RWMol> mol(MolBlockToMol(molblockIn, false));
|
|
RDKit::Chirality::reapplyMolBlockWedging(*mol);
|
|
auto molblockOut = MolToMolBlock(*mol);
|
|
CHECK(molblockIn == molblockOut);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("test GitHub6952") {
|
|
auto methotrexate = R"CTAB(
|
|
RDKit 2D
|
|
|
|
33 35 0 0 0 0 0 0 0 0999 V2000
|
|
9.6907 -4.0059 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
9.7594 -1.2647 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
7.3558 -2.5828 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
8.1529 -1.2392 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
8.1064 -3.9607 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
10.5157 -2.6141 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
5.7874 -2.5470 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-3.6071 0.3538 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
7.4061 0.1262 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-4.3656 1.7364 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
5.0321 -1.1768 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-6.7519 0.4301 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2.6721 0.2392 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-5.9466 1.7689 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-9.0366 4.5624 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-2.0167 0.3375 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
3.4339 -1.1557 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1.0736 0.2603 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-4.4076 -0.9769 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-10.9286 4.6884 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-5.9966 -0.9397 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
5.8226 0.1920 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-8.2221 5.9171 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
7.3253 -5.3137 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.2570 -1.0243 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.2450 1.6744 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.3066 -1.0682 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.3566 1.6406 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
12.1001 -2.6593 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-6.6878 3.1631 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-8.2654 3.1830 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-8.3214 0.4451 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
3.4912 1.6022 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2 6 2 0
|
|
3 5 1 0
|
|
4 2 1 0
|
|
5 1 2 0
|
|
6 1 1 0
|
|
7 3 2 0
|
|
8 16 1 0
|
|
9 4 2 0
|
|
10 8 1 0
|
|
11 7 1 0
|
|
14 12 1 0
|
|
13 17 1 0
|
|
14 10 1 0
|
|
15 31 1 0
|
|
16 26 2 0
|
|
17 11 1 0
|
|
18 13 1 0
|
|
19 8 2 0
|
|
20 15 1 0
|
|
21 12 2 0
|
|
22 9 1 0
|
|
23 15 2 0
|
|
24 5 1 0
|
|
25 27 2 0
|
|
26 28 1 0
|
|
27 18 1 0
|
|
28 18 2 0
|
|
29 6 1 0
|
|
14 30 1 6
|
|
31 30 1 0
|
|
32 12 1 0
|
|
33 13 1 0
|
|
4 3 1 0
|
|
22 11 2 0
|
|
16 25 1 0
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(methotrexate);
|
|
auto methotrexateAnalog = R"CTAB(
|
|
RDKit 2D
|
|
|
|
33 35 0 0 1 0 0 0 0 0999 V2000
|
|
-4.0189 0.3866 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-2.6792 -0.3866 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-2.6792 -1.9335 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-4.0189 -2.7069 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-4.0189 -4.2538 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-5.3584 -5.0273 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-6.6981 -4.2538 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-8.0378 -5.0273 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-9.3773 -4.2538 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-10.7169 -5.0273 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-9.3773 -2.7069 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-8.0378 -1.9335 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-8.0378 -0.3866 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-6.6981 -2.7069 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-5.3584 -1.9335 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.3395 0.3866 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
-1.3395 1.9335 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.0000 2.7069 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1.3395 1.9335 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
2.6792 2.7069 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
4.0189 1.9335 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
5.3584 2.7069 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
6.6981 1.9335 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
8.0378 2.7069 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
9.3773 1.9335 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
10.7169 2.7069 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
9.3773 0.3866 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
5.3584 4.2538 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
6.6981 5.0273 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
4.0189 5.0273 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1.3395 0.3866 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
0.0000 -0.3866 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
4.0189 0.3866 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1 2 2 0
|
|
2 3 1 0
|
|
3 4 1 0
|
|
4 5 2 0
|
|
5 6 1 0
|
|
6 7 2 0
|
|
7 8 1 0
|
|
8 9 2 0
|
|
9 10 1 0
|
|
9 11 1 0
|
|
11 12 2 0
|
|
12 13 1 0
|
|
12 14 1 0
|
|
7 14 1 0
|
|
14 15 2 0
|
|
4 15 1 0
|
|
2 16 1 0
|
|
16 17 2 0
|
|
17 18 1 0
|
|
18 19 2 0
|
|
22 23 1 0
|
|
23 24 1 0
|
|
24 25 1 0
|
|
25 26 2 0
|
|
25 27 1 0
|
|
22 28 1 0
|
|
28 29 2 0
|
|
28 30 1 0
|
|
19 31 1 0
|
|
31 32 2 0
|
|
16 32 1 0
|
|
19 20 1 0
|
|
22 21 1 0
|
|
20 21 1 0
|
|
21 33 2 0
|
|
M END
|
|
)CTAB"_ctab;
|
|
REQUIRE(methotrexateAnalog);
|
|
auto refPatt =
|
|
"[#7]1:[#6](:[#7]:[#6](:[#6]2:[#6]:1:[#7]:[#6]:[#6](:[#7]:2)-[#6])-[#7])-[#7]"_smarts;
|
|
REQUIRE(refPatt);
|
|
MatchVectType expected{{1, 7}, {5, 8}, {0, 10}, {4, 11}, {2, 13},
|
|
{3, 6}, {8, 5}, {21, 4}, {10, 3}, {6, 14},
|
|
{16, 2}, {23, 12}, {28, 9}};
|
|
RDDepict::ConstrainedDepictionParams p;
|
|
p.alignOnly = true;
|
|
auto match = RDDepict::generateDepictionMatching2DStructure(
|
|
*methotrexateAnalog, *methotrexate, -1, refPatt.get(), p);
|
|
CHECK(match == expected);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Normalize should always center in centroid, irrespective of canonicalize parameter") {
|
|
auto m = R"CTAB(
|
|
RDKit 2D
|
|
|
|
25 27 0 0 0 0 0 0 0 0999 V2000
|
|
18.2425 6.6594 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
16.8948 6.0009 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
16.3808 7.4101 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
14.8817 7.3567 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
14.4692 5.9146 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
15.7134 5.0766 0.0000 S 0 0 0 0 0 0 0 0 0 0 0 0
|
|
13.0271 6.3270 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
13.4395 7.7692 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
12.7114 9.0806 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
11.7156 5.5989 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
10.4294 6.3705 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
10.4545 7.8703 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
9.1179 5.6424 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
7.8316 6.4141 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
7.8568 7.9139 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
6.5705 8.6855 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
5.2591 7.9574 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
5.2339 6.4576 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
6.5202 5.6860 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
3.9728 8.7291 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
9.0928 4.1426 0.0000 N 0 0 0 0 0 0 0 0 0 0 0 0
|
|
17.2187 8.6543 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
16.5602 10.0020 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
18.7151 8.5507 0.0000 O 0 0 0 0 0 0 0 0 0 0 0 0
|
|
17.6905 4.7294 0.0000 C 0 0 0 0 0 0 0 0 0 0 0 0
|
|
1 2 1 0
|
|
2 3 1 0
|
|
3 4 1 0
|
|
4 5 1 0
|
|
5 6 1 6
|
|
5 7 1 0
|
|
7 8 1 0
|
|
8 9 2 0
|
|
7 10 1 6
|
|
10 11 1 0
|
|
11 12 2 0
|
|
11 13 1 0
|
|
13 14 1 0
|
|
14 15 2 0
|
|
15 16 1 0
|
|
16 17 2 0
|
|
17 18 1 0
|
|
18 19 2 0
|
|
17 20 1 0
|
|
13 21 1 6
|
|
3 22 1 1
|
|
22 23 2 0
|
|
22 24 1 0
|
|
2 25 1 0
|
|
6 2 1 0
|
|
8 4 1 0
|
|
19 14 1 0
|
|
M END)CTAB"_ctab;
|
|
REQUIRE(m);
|
|
RDDepict::normalizeDepiction(*m, -1, 0);
|
|
auto ctd = MolTransforms::computeCentroid(m->getConformer());
|
|
CHECK_THAT(ctd.x, Catch::Matchers::WithinAbs(0.0, 1.0e-4));
|
|
CHECK_THAT(ctd.y, Catch::Matchers::WithinAbs(0.0, 1.0e-4));
|
|
}
|
|
|
|
#ifdef RDK_BUILD_COORDGEN_SUPPORT
|
|
TEST_CASE(
|
|
"CoordGen should not segfault when bond has stereo spec but no stereo atoms") {
|
|
auto m = "C=C1C=CC(=O)CC1"_smiles;
|
|
REQUIRE(m);
|
|
CHECK(m->getNumBonds() == 8);
|
|
auto b = m->getBondWithIdx(0);
|
|
CHECK(b->getBondType() == Bond::DOUBLE);
|
|
b->setStereo(Bond::STEREOZ);
|
|
CHECK(b->getStereoAtoms().empty());
|
|
RDDepict::preferCoordGen = true;
|
|
RDDepict::compute2DCoords(*m);
|
|
RDDepict::preferCoordGen = false;
|
|
CHECK(m->getNumConformers() == 1);
|
|
}
|
|
#endif
|
|
|
|
TEST_CASE("canonical ordering") {
|
|
auto useLegacy = GENERATE(true, false);
|
|
CAPTURE(useLegacy);
|
|
UseLegacyStereoPerceptionFixture useLegacyFixture(useLegacy);
|
|
auto m = "CN2C3CC(OC(=O)C(CO)c1ccccc1)CC2CC3"_smiles;
|
|
REQUIRE(m);
|
|
RDDepict::compute2DCoords(*m);
|
|
auto conf = m->getConformer();
|
|
for (auto i = 0u; i < m->getNumAtoms(); ++i) {
|
|
for (auto j = i + 1; j < m->getNumAtoms(); ++j) {
|
|
auto pos = conf.getAtomPos(i) - conf.getAtomPos(j);
|
|
auto dist = pos.length();
|
|
CHECK(dist > 0.35);
|
|
INFO("i " << i << " " << j);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("macrocycle templating") {
|
|
// Helper function to test if templates are used for a ring of size n.
|
|
// We generate a ring of that size, generate 2D coordinates with and without
|
|
// templates enabled, and compare the results. If the coordinates are the
|
|
// same, we assume no template was used. If they differ, a template was used.
|
|
auto templates_are_used_for_ring_size_n = [](int ringSize) -> bool {
|
|
// Build SMILES for n-membered ring: C1 + (n-2) C's + C1
|
|
std::string smiles = "C1";
|
|
for (int i = 0; i < ringSize - 2; ++i) {
|
|
smiles += "C";
|
|
}
|
|
smiles += "C1";
|
|
|
|
auto mol = SmilesToMol(smiles);
|
|
if (!mol) {
|
|
return false;
|
|
}
|
|
|
|
// Generate coordinates WITHOUT templates
|
|
RDDepict::Compute2DCoordParameters params;
|
|
params.useRingTemplates = false;
|
|
RDDepict::compute2DCoords(*mol, params);
|
|
|
|
auto withoutTemplates =
|
|
mol->getConformer().getAtomPos(0) -
|
|
mol->getConformer().getAtomPos(ringSize / 2);
|
|
|
|
// Generate coordinates WITH templates
|
|
params.useRingTemplates = true;
|
|
RDDepict::compute2DCoords(*mol, params);
|
|
|
|
auto withTemplates = mol->getConformer().getAtomPos(0) -
|
|
mol->getConformer().getAtomPos(ringSize / 2);
|
|
|
|
delete mol;
|
|
|
|
// Return true if coordinates differ (templates were used)
|
|
return !RDKit::feq(withoutTemplates.length(), withTemplates.length(), 0.01);
|
|
};
|
|
|
|
SECTION("template usage threshold at ring size 8") {
|
|
// Test that templates are used only for rings with size > 8
|
|
for (int i = 4; i <= 14; ++i) {
|
|
CAPTURE(i);
|
|
bool templatesUsed = templates_are_used_for_ring_size_n(i);
|
|
bool expectedTemplatesUsed = (i > 8);
|
|
CHECK(templatesUsed == expectedTemplatesUsed);
|
|
}
|
|
}
|
|
} |