mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-04 21:54:27 +08:00
* stop using CIP codes in the atomic canonicalization this will change results in some cases, so lots of tests need to be updated. * stop breaking string literals... ARGH * tests now pass * update double bond canonicalization * update a python test * some cleanup * update expected results for cartridge
196 lines
7.7 KiB
C++
196 lines
7.7 KiB
C++
//
|
|
// Copyright (C) 2022 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 "catch.hpp"
|
|
|
|
#include <GraphMol/RDKitBase.h>
|
|
#include <GraphMol/StereoGroup.h>
|
|
#include <GraphMol/Chirality.h>
|
|
#include <GraphMol/new_canon.h>
|
|
#include <GraphMol/MolOps.h>
|
|
|
|
#include <GraphMol/FileParsers/FileParsers.h>
|
|
#include <GraphMol/FileParsers/MolFileStereochem.h>
|
|
#include <GraphMol/FileParsers/MolSupplier.h>
|
|
#include <GraphMol/SmilesParse/SmilesParse.h>
|
|
#include <GraphMol/SmilesParse/SmilesWrite.h>
|
|
|
|
using namespace RDKit;
|
|
|
|
TEST_CASE("chirality and canonicalization") {
|
|
SECTION("basics") {
|
|
auto mol = "F[C@](O)(Cl)C[C@](F)(O)Cl"_smiles;
|
|
REQUIRE(mol);
|
|
bool cleanIt = true;
|
|
bool force = true;
|
|
MolOps::assignStereochemistry(*mol, cleanIt, force);
|
|
std::string cip;
|
|
CHECK(mol->getAtomWithIdx(1)->getPropIfPresent(common_properties::_CIPCode,
|
|
cip));
|
|
CHECK(cip == "S");
|
|
CHECK(mol->getAtomWithIdx(5)->getPropIfPresent(common_properties::_CIPCode,
|
|
cip));
|
|
CHECK(cip == "R");
|
|
std::vector<unsigned int> ranks;
|
|
bool breakTies = false;
|
|
Canon::rankMolAtoms(*mol, ranks, breakTies);
|
|
CHECK(ranks[1] > ranks[5]);
|
|
mol->getAtomWithIdx(1)->clearProp(common_properties::_CIPCode);
|
|
mol->getAtomWithIdx(5)->clearProp(common_properties::_CIPCode);
|
|
Canon::rankMolAtoms(*mol, ranks, breakTies);
|
|
CHECK(ranks[1] > ranks[5]);
|
|
}
|
|
SECTION("same") {
|
|
auto mol = "F[C@](O)(Cl)C[C@](O)(F)Cl"_smiles;
|
|
REQUIRE(mol);
|
|
bool cleanIt = true;
|
|
bool force = true;
|
|
MolOps::assignStereochemistry(*mol, cleanIt, force);
|
|
std::string cip;
|
|
CHECK(mol->getAtomWithIdx(1)->getPropIfPresent(common_properties::_CIPCode,
|
|
cip));
|
|
CHECK(cip == "S");
|
|
CHECK(mol->getAtomWithIdx(5)->getPropIfPresent(common_properties::_CIPCode,
|
|
cip));
|
|
CHECK(cip == "S");
|
|
std::vector<unsigned int> ranks;
|
|
bool breakTies = false;
|
|
Canon::rankMolAtoms(*mol, ranks, breakTies);
|
|
CHECK(ranks[1] == ranks[5]);
|
|
mol->getAtomWithIdx(1)->clearProp(common_properties::_CIPCode);
|
|
mol->getAtomWithIdx(5)->clearProp(common_properties::_CIPCode);
|
|
Canon::rankMolAtoms(*mol, ranks, breakTies);
|
|
CHECK(ranks[1] == ranks[5]);
|
|
}
|
|
SECTION("dependent") {
|
|
auto mol = "F[C@](O)(Cl)[C@](F)(O)[C@](F)(O)Cl"_smiles;
|
|
REQUIRE(mol);
|
|
bool cleanIt = true;
|
|
bool force = true;
|
|
MolOps::assignStereochemistry(*mol, cleanIt, force);
|
|
std::string cip;
|
|
CHECK(mol->getAtomWithIdx(1)->getPropIfPresent(common_properties::_CIPCode,
|
|
cip));
|
|
CHECK(cip == "S");
|
|
CHECK(mol->getAtomWithIdx(7)->getPropIfPresent(common_properties::_CIPCode,
|
|
cip));
|
|
CHECK(cip == "R");
|
|
CHECK(mol->getAtomWithIdx(4)->getPropIfPresent(common_properties::_CIPCode,
|
|
cip));
|
|
CHECK(cip == "R");
|
|
std::vector<unsigned int> ranks;
|
|
bool breakTies = false;
|
|
Canon::rankMolAtoms(*mol, ranks, breakTies);
|
|
CHECK(ranks[1] > ranks[7]);
|
|
mol->getAtomWithIdx(1)->clearProp(common_properties::_CIPCode);
|
|
mol->getAtomWithIdx(4)->clearProp(common_properties::_CIPCode);
|
|
mol->getAtomWithIdx(7)->clearProp(common_properties::_CIPCode);
|
|
Canon::rankMolAtoms(*mol, ranks, breakTies);
|
|
CHECK(ranks[1] > ranks[7]);
|
|
}
|
|
SECTION("dependent non-chiral") {
|
|
auto mol = "F[C@](O)(Cl)[C@](F)(O)[C@](O)(F)Cl"_smiles;
|
|
REQUIRE(mol);
|
|
bool cleanIt = false;
|
|
bool force = true;
|
|
mol->getAtomWithIdx(4)->setChiralTag(Atom::ChiralType::CHI_TETRAHEDRAL_CCW);
|
|
MolOps::assignStereochemistry(*mol, cleanIt, force);
|
|
std::string cip;
|
|
CHECK(mol->getAtomWithIdx(1)->getPropIfPresent(common_properties::_CIPCode,
|
|
cip));
|
|
CHECK(cip == "S");
|
|
CHECK(mol->getAtomWithIdx(7)->getPropIfPresent(common_properties::_CIPCode,
|
|
cip));
|
|
CHECK(cip == "S");
|
|
std::vector<unsigned int> ranks;
|
|
bool breakTies = false;
|
|
Canon::rankMolAtoms(*mol, ranks, breakTies);
|
|
CHECK(ranks[1] == ranks[7]);
|
|
mol->getAtomWithIdx(1)->clearProp(common_properties::_CIPCode);
|
|
mol->getAtomWithIdx(7)->clearProp(common_properties::_CIPCode);
|
|
Canon::rankMolAtoms(*mol, ranks, breakTies);
|
|
CHECK(ranks[1] == ranks[7]);
|
|
}
|
|
|
|
SECTION("swap parity") {
|
|
auto mol = "F[C@](O)(Cl)C[C@@](O)(Cl)F"_smiles;
|
|
REQUIRE(mol);
|
|
bool cleanIt = false;
|
|
bool force = true;
|
|
MolOps::assignStereochemistry(*mol, cleanIt, force);
|
|
std::string cip;
|
|
CHECK(mol->getAtomWithIdx(1)->getPropIfPresent(common_properties::_CIPCode,
|
|
cip));
|
|
CHECK(cip == "S");
|
|
CHECK(mol->getAtomWithIdx(5)->getPropIfPresent(common_properties::_CIPCode,
|
|
cip));
|
|
CHECK(cip == "S");
|
|
std::vector<unsigned int> ranks;
|
|
bool breakTies = false;
|
|
Canon::rankMolAtoms(*mol, ranks, breakTies);
|
|
CHECK(ranks[1] == ranks[5]);
|
|
mol->getAtomWithIdx(1)->clearProp(common_properties::_CIPCode);
|
|
mol->getAtomWithIdx(5)->clearProp(common_properties::_CIPCode);
|
|
Canon::rankMolAtoms(*mol, ranks, breakTies);
|
|
CHECK(ranks[1] == ranks[5]);
|
|
}
|
|
}
|
|
TEST_CASE("double bond stereo and canonicalization") {
|
|
SECTION("basics") {
|
|
auto mol = "CC=C(F)C(B)C(F)=CC"_smiles;
|
|
REQUIRE(mol);
|
|
mol->getBondWithIdx(1)->setStereoAtoms(0, 4);
|
|
mol->getBondWithIdx(1)->setStereo(Bond::BondStereo::STEREOTRANS);
|
|
mol->getBondWithIdx(7)->setStereoAtoms(4, 9);
|
|
mol->getBondWithIdx(7)->setStereo(Bond::BondStereo::STEREOCIS);
|
|
bool breakTies = false;
|
|
std::vector<unsigned int> ranks;
|
|
Canon::rankMolAtoms(*mol, ranks, breakTies);
|
|
std::copy(ranks.begin(), ranks.end(),
|
|
std::ostream_iterator<unsigned int>(std::cerr, " "));
|
|
std::cerr << std::endl;
|
|
mol->getBondWithIdx(1)->setStereo(Bond::BondStereo::STEREOCIS);
|
|
mol->getBondWithIdx(7)->setStereo(Bond::BondStereo::STEREOTRANS);
|
|
std::vector<unsigned int> ranks2;
|
|
Canon::rankMolAtoms(*mol, ranks2, breakTies);
|
|
std::copy(ranks2.begin(), ranks2.end(),
|
|
std::ostream_iterator<unsigned int>(std::cerr, " "));
|
|
std::cerr << std::endl;
|
|
CHECK(ranks[0] == ranks2[9]);
|
|
CHECK(ranks[1] == ranks2[8]);
|
|
CHECK(ranks[2] == ranks2[6]);
|
|
CHECK(ranks[3] == ranks2[7]);
|
|
CHECK(ranks[4] == ranks2[4]);
|
|
CHECK(ranks[5] == ranks2[5]);
|
|
|
|
// same as previous example, different controlling atoms
|
|
mol->getBondWithIdx(7)->setStereoAtoms(7, 9);
|
|
mol->getBondWithIdx(7)->setStereo(Bond::BondStereo::STEREOCIS);
|
|
std::vector<unsigned int> ranks3;
|
|
Canon::rankMolAtoms(*mol, ranks3, breakTies);
|
|
std::copy(ranks3.begin(), ranks3.end(),
|
|
std::ostream_iterator<unsigned int>(std::cerr, " "));
|
|
std::cerr << std::endl;
|
|
CHECK(ranks2 == ranks3);
|
|
}
|
|
SECTION("STEREOANY is higher priority than STEREONONE") {
|
|
auto mol = "CC=C(F)C(B)C(F)=CC"_smiles;
|
|
REQUIRE(mol);
|
|
mol->getBondWithIdx(7)->setStereoAtoms(4, 9);
|
|
mol->getBondWithIdx(7)->setStereo(Bond::BondStereo::STEREOANY);
|
|
bool breakTies = false;
|
|
std::vector<unsigned int> ranks;
|
|
Canon::rankMolAtoms(*mol, ranks, breakTies);
|
|
std::copy(ranks.begin(), ranks.end(),
|
|
std::ostream_iterator<unsigned int>(std::cerr, " "));
|
|
std::cerr << std::endl;
|
|
CHECK(ranks[0] < ranks[9]);
|
|
}
|
|
} |