// // 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 #include #include #include #include #include #include #include #include #include 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 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 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 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 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 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 ranks; Canon::rankMolAtoms(*mol, ranks, breakTies); std::copy(ranks.begin(), ranks.end(), std::ostream_iterator(std::cerr, " ")); std::cerr << std::endl; mol->getBondWithIdx(1)->setStereo(Bond::BondStereo::STEREOCIS); mol->getBondWithIdx(7)->setStereo(Bond::BondStereo::STEREOTRANS); std::vector ranks2; Canon::rankMolAtoms(*mol, ranks2, breakTies); std::copy(ranks2.begin(), ranks2.end(), std::ostream_iterator(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 ranks3; Canon::rankMolAtoms(*mol, ranks3, breakTies); std::copy(ranks3.begin(), ranks3.end(), std::ostream_iterator(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 ranks; Canon::rankMolAtoms(*mol, ranks, breakTies); std::copy(ranks.begin(), ranks.end(), std::ostream_iterator(std::cerr, " ")); std::cerr << std::endl; CHECK(ranks[0] < ranks[9]); } }