Support atropisomers in the conformer generator (#7098)

* change a define to a "using"

* basic atropiosomer support for confgen

currently only supports bonds with two exo substituents on each end

* support systems with two exo bonds

* cleanup

* add test for #7109

Fixes #7109

* clean the tests up a bit
This commit is contained in:
Greg Landrum
2024-02-06 15:48:25 +01:00
committed by GitHub
parent b5a301a5df
commit 6bede685e0
8 changed files with 623 additions and 15 deletions

View File

@@ -17,10 +17,9 @@
#include <string>
#include <stdexcept>
#define AtropAtomAndBondVec std::pair<Atom *, std::vector<Bond *>>
namespace RDKit {
namespace Atropisomers {
using AtropAtomAndBondVec = std::pair<Atom *, std::vector<Bond *>>;
RDKIT_GRAPHMOL_EXPORT void detectAtropisomerChirality(ROMol &mol,
const Conformer *conf);
RDKIT_GRAPHMOL_EXPORT void wedgeBondsFromAtropisomers(

View File

@@ -26,7 +26,7 @@ AtropisomerBond::AtropisomerBond(const CIPMol &mol, Bond *bond, Atom *startAtom,
CHECK_INVARIANT(d_cfg == Bond::STEREOATROPCW || d_cfg == Bond::STEREOATROPCCW,
"bad config")
AtropAtomAndBondVec atomAndBondVecs[2];
Atropisomers::AtropAtomAndBondVec atomAndBondVecs[2];
if (!Atropisomers::getAtropisomerAtomsAndBonds(bond, atomAndBondVecs,
bond->getOwningMol())) {
return; // not an atropisomer

View File

@@ -19,6 +19,7 @@
#include <GraphMol/Atom.h>
#include <GraphMol/AtomIterators.h>
#include <GraphMol/RingInfo.h>
#include <GraphMol/Atropisomers.h>
#include <GraphMol/Conformer.h>
#include <RDGeneral/types.h>
@@ -543,8 +544,8 @@ bool checkChiralCenters(const RDGeom::PointPtrVect *positions,
chiralSet->d_idx4, *positions);
double lb = chiralSet->getLowerVolumeBound();
double ub = chiralSet->getUpperVolumeBound();
if ((lb > 0 && vol < lb && (lb - vol) / lb > .2) ||
(ub < 0 && vol > ub && (vol - ub) / ub > .2)) {
if ((lb > 0 && vol < lb && ((lb - vol) / lb > .2 || vol * lb < 0)) ||
(ub < 0 && vol > ub && ((vol - ub) / ub > .2 || vol * ub < 0))) {
#ifdef DEBUG_EMBEDDING
std::cerr << " fail! (" << chiralSet->d_idx0 << ") iter: "
<< " " << vol << " " << lb << "-" << ub << std::endl;
@@ -733,6 +734,17 @@ bool doubleBondStereoChecks(const RDGeom::PointPtrVect &positions,
bool finalChiralChecks(RDGeom::PointPtrVect *positions,
const detail::EmbedArgs &eargs,
EmbedParameters &embedParams) {
// confirm chiral volumes
if (!checkChiralCenters(positions, eargs, embedParams)) {
if (embedParams.trackFailures) {
#ifdef RDK_BUILD_THREADSAFE_SSS
std::lock_guard<std::mutex> lock(GetFailMutex());
#endif
embedParams.failures[EmbedFailureCauses::CHECK_CHIRAL_CENTERS2]++;
}
return false;
}
// "distance matrix" chirality test
std::set<int> atoms;
for (const auto &chiralSet : *eargs.chiralCenters) {
@@ -780,6 +792,8 @@ bool finalChiralChecks(RDGeom::PointPtrVect *positions,
return false;
}
}
// FIX: do we need some kind of sanity check here for the non-atomic
// situations (e.g. atropisomers)?
return true;
}
@@ -1054,7 +1068,63 @@ void findChiralSets(const ROMol &mol, DistGeom::VECT_CHIRALSET &chiralCenters,
} // if block -chirality check
} // if block - heavy atom check
} // for loop over atoms
} // end of _findChiralSets
// now do atropisomers
for (const auto &bond : mol.bonds()) {
if (bond->getStereo() != Bond::BondStereo::STEREOATROPCCW &&
bond->getStereo() != Bond::BondStereo::STEREOATROPCW) {
continue;
}
Atropisomers::AtropAtomAndBondVec atomsAndBonds[2];
Atropisomers::getAtropisomerAtomsAndBonds(bond, atomsAndBonds, mol);
// make a chiral set for the atropisomeric bond
// we start with only managing cases where there are two exo-substituents on
// at least one side
if (atomsAndBonds[0].second.size() != 2 &&
atomsAndBonds[1].second.size() != 2) {
BOOST_LOG(rdWarningLog)
<< "Atropisomer bond stereochemistry not used for bond "
<< bond->getIdx()
<< ", which does not have two exo substituents on at least one side."
<< std::endl;
continue;
}
int idx0 = atomsAndBonds[0].first->getIdx();
int idx1 = atomsAndBonds[1].first->getIdx();
int nbr1 = atomsAndBonds[0].second[0]->getOtherAtomIdx(idx0);
int nbr2 = 0;
int nbr3 = 0;
int nbr4 = 0;
if (atomsAndBonds[0].second.size() == 2) {
nbr2 = atomsAndBonds[0].second[1]->getOtherAtomIdx(idx0);
nbr3 = atomsAndBonds[1].second[0]->getOtherAtomIdx(idx1);
if (atomsAndBonds[1].second.size() == 2) {
nbr4 = atomsAndBonds[1].second[1]->getOtherAtomIdx(idx1);
} else {
nbr4 = idx0;
}
} else {
nbr2 = atomsAndBonds[1].second[0]->getOtherAtomIdx(idx1);
nbr3 = atomsAndBonds[1].second[1]->getOtherAtomIdx(idx1);
nbr4 = idx0;
}
INT_VECT nbrs = {nbr1, nbr2, nbr3, nbr4};
// FIX: these numbers are empirical and should be revisited
double volLowerBound = 1.0;
double volUpperBound = 100.0;
if (bond->getStereo() == Bond::BondStereo::STEREOATROPCCW) {
std::swap(volLowerBound, volUpperBound);
volLowerBound *= -1;
volUpperBound *= -1;
}
auto *cset = new DistGeom::ChiralSet(idx0, nbrs[0], nbrs[1], nbrs[2],
nbrs[3], volLowerBound, volUpperBound);
DistGeom::ChiralSetPtr cptr(cset);
chiralCenters.push_back(cptr);
}
}
void adjustBoundsMatFromCoordMap(
DistGeom::BoundsMatPtr mmat, unsigned int,

View File

@@ -33,6 +33,7 @@ enum EmbedFailureCauses {
FINAL_CENTER_IN_VOLUME = 7,
LINEAR_DOUBLE_BOND = 8,
BAD_DOUBLE_BOND_STEREO = 9,
CHECK_CHIRAL_CENTERS2 = 10,
};
//! Parameter object for controlling embedding
@@ -287,10 +288,10 @@ inline int EmbedMolecule(ROMol &mol, EmbedParameters &params) {
\param useSmallRingTorsions optional torsions to improve small ring
conformer sampling
\param useMacrocycleTorsions optional torsions to improve macrocycle
conformer sampling
\param useMacrocycle14config If 1-4 distances bound heuristics for macrocycles
is used
conformer sampling
\param useMacrocycle14config If 1-4 distances bound heuristics for
macrocycles is used
\return ID of the conformer added to the molecule, -1 if the emdedding failed
*/
inline int EmbedMolecule(
@@ -386,9 +387,9 @@ inline int EmbedMolecule(
\param useSmallRingTorsions optional torsions to improve small ring
conformer sampling
\param useMacrocycleTorsions optional torsions to improve macrocycle
conformer sampling
\param useMacrocycle14config If 1-4 distances bound heuristics for macrocycles
is used
conformer sampling
\param useMacrocycle14config If 1-4 distances bound heuristics for
macrocycles is used
*/
inline void EmbedMultipleConfs(

View File

@@ -453,6 +453,8 @@ BOOST_PYTHON_MODULE(rdDistGeom) {
RDKit::DGeomHelpers::EmbedFailureCauses::LINEAR_DOUBLE_BOND)
.value("BAD_DOUBLE_BOND_STEREO",
RDKit::DGeomHelpers::EmbedFailureCauses::BAD_DOUBLE_BOND_STEREO)
.value("CHECK_CHIRAL_CENTERS2",
RDKit::DGeomHelpers::EmbedFailureCauses::CHECK_CHIRAL_CENTERS2)
.export_values();
python::class_<PyEmbedParameters, boost::noncopyable>(

View File

@@ -1,5 +1,5 @@
//
// Copyright (C) 2021 Greg Landrum and other RDKit contributors
// Copyright (C) 2021-2024 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
@@ -13,15 +13,19 @@
#include <RDGeneral/RDLog.h>
#include <GraphMol/test_fixtures.h>
#include <GraphMol/RDKitBase.h>
#include <GraphMol/Atropisomers.h>
#include <GraphMol/Chirality.h>
#include <GraphMol/Substruct/SubstructMatch.h>
#include <GraphMol/ForceFieldHelpers/UFF/UFF.h>
#include <GraphMol/FileParsers/FileParsers.h>
#include <GraphMol/FileParsers/MolSupplier.h>
#include <GraphMol/SmilesParse/SmilesParse.h>
#include <GraphMol/ForceFieldHelpers/CrystalFF/TorsionPreferences.h>
#include "Embedder.h"
#include "BoundsMatrixBuilder.h"
#include <tuple>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/trim.hpp>
using namespace RDKit;
@@ -773,3 +777,157 @@ TEST_CASE("Macrocycle bounds matrix") {
CHECK((pos_1 - pos_4).length() > 3.5);
}
}
TEST_CASE("atropisomers and embedding") {
SECTION("basics") {
auto mol =
"Cc1cccc(O)c1-c1c(N)cccc1Cl |(-8.88571,2.09707,;-8.17143,3.33425,;-6.74286,3.33425,;-6.02857,4.57143,;-6.74286,5.80861,;-8.17143,5.80861,;-8.88571,7.04579,;-8.88571,4.57143,;-10.3143,4.57143,;-11.0286,5.80861,;-10.3143,7.04579,;-12.4571,5.80861,;-13.1714,4.57143,;-12.4571,3.33425,;-11.0286,3.33425,;-10.3143,2.09707,),wU:8.15|"_smiles;
REQUIRE(mol);
REQUIRE(mol->getBondWithIdx(7)->getBondType() == Bond::BondType::SINGLE);
REQUIRE(mol->getBondWithIdx(7)->getStereo() ==
Bond::BondStereo::STEREOATROPCCW);
MolOps::addHs(*mol);
// mol->debugMol(std::cerr);
DGeomHelpers::EmbedParameters ps = DGeomHelpers::ETKDGv3;
ps.randomSeed = 0xf00d;
{
auto cid = DGeomHelpers::EmbedMolecule(*mol, ps);
REQUIRE(cid >= 0);
const auto conf = mol->getConformer(cid);
Atropisomers::AtropAtomAndBondVec abvs[2];
REQUIRE(Atropisomers::getAtropisomerAtomsAndBonds(mol->getBondWithIdx(7),
abvs, *mol));
auto pos_1 = conf.getAtomPos(7);
auto pos_2 = conf.getAtomPos(8);
auto pos_3 = conf.getAtomPos(1);
auto pos_4 = conf.getAtomPos(9);
auto v2 = pos_2 - pos_1;
auto v3 = pos_3 - pos_1;
auto v4 = pos_4 - pos_1;
auto chiralVol = v3.crossProduct(v4).dotProduct(v2);
CHECK(chiralVol < 0);
}
{
RWMol mol2(*mol);
mol2.getBondWithIdx(7)->setStereo(Bond::BondStereo::STEREOATROPCW);
auto cid = DGeomHelpers::EmbedMolecule(mol2, ps);
REQUIRE(cid >= 0);
const auto conf = mol2.getConformer(cid);
Atropisomers::AtropAtomAndBondVec abvs[2];
REQUIRE(Atropisomers::getAtropisomerAtomsAndBonds(mol2.getBondWithIdx(7),
abvs, mol2));
auto pos_1 = conf.getAtomPos(7);
auto pos_2 = conf.getAtomPos(8);
auto pos_3 = conf.getAtomPos(1);
auto pos_4 = conf.getAtomPos(9);
auto v2 = pos_2 - pos_1;
auto v3 = pos_3 - pos_1;
auto v4 = pos_4 - pos_1;
auto chiralVol = v3.crossProduct(v4).dotProduct(v2);
CHECK(chiralVol > 0);
}
}
}
TEST_CASE("atropisomers bulk") {
std::string rdbase = getenv("RDBASE");
std::string fname =
rdbase + "/Code/GraphMol/DistGeomHelpers/test_data/atropisomers.sdf";
SDMolSupplier sdsup(fname);
auto params = DGeomHelpers::ETKDGv3;
params.randomSeed = 0xf00d + 1;
for (auto i = 0u; i < sdsup.length(); ++i) {
std::unique_ptr<RWMol> mol(static_cast<RWMol *>(sdsup[i]));
REQUIRE(mol);
auto bondIdx = mol->getProp<unsigned int>("atrop bond");
REQUIRE((mol->getBondWithIdx(bondIdx)->getStereo() ==
Bond::BondStereo::STEREOATROPCCW ||
mol->getBondWithIdx(bondIdx)->getStereo() ==
Bond::BondStereo::STEREOATROPCW));
auto atropInfo = mol->getProp<std::string>("atrop volume");
std::vector<std::string> tokens;
boost::split(tokens, atropInfo, boost::is_any_of(" \t"));
REQUIRE(tokens.size() == 5);
std::vector<unsigned int> atropAtoms(4);
for (auto j = 0u; j < 4u; ++j) {
atropAtoms[j] = std::stol(tokens[j]);
}
int vol = std::stol(tokens[4]);
MolOps::addHs(*mol);
unsigned int nconfs = 20;
{
auto cids = DGeomHelpers::EmbedMultipleConfs(*mol, nconfs, params);
CHECK(cids.size() == nconfs);
for (auto cid : cids) {
const auto conf = mol->getConformer(cid);
std::vector<RDGeom::Point3D> pts;
for (auto idx : atropAtoms) {
pts.push_back(conf.getAtomPos(idx));
}
auto v2 = pts[1] - pts[0];
auto v3 = pts[2] - pts[0];
auto v4 = pts[3] - pts[0];
auto chiralVol = v3.crossProduct(v4).dotProduct(v2);
INFO(cid << MolToV3KMolBlock(*mol, true, cid));
CHECK(chiralVol * vol > 0);
}
} // now swap the stereo and see if it still works
mol->getBondWithIdx(bondIdx)->setStereo(
mol->getBondWithIdx(bondIdx)->getStereo() ==
Bond::BondStereo::STEREOATROPCCW
? Bond::BondStereo::STEREOATROPCW
: Bond::BondStereo::STEREOATROPCCW);
{
auto cids = DGeomHelpers::EmbedMultipleConfs(*mol, nconfs, params);
CHECK(cids.size() == nconfs);
for (auto cid : cids) {
const auto conf = mol->getConformer(cid);
std::vector<RDGeom::Point3D> pts;
for (auto idx : atropAtoms) {
pts.push_back(conf.getAtomPos(idx));
}
auto v2 = pts[1] - pts[0];
auto v3 = pts[2] - pts[0];
auto v4 = pts[3] - pts[0];
auto chiralVol = v3.crossProduct(v4).dotProduct(v2);
INFO(cid << MolToV3KMolBlock(*mol, true, cid));
CHECK(chiralVol * vol < 0);
}
}
}
}
TEST_CASE(
"Github #7109: wrong stereochemistry in ring from stereospecific SMILES") {
SECTION("basics") {
auto m = "C1[C@H](C#CC#C)CC[C@H](C#CC#C)C1"_smiles;
REQUIRE(m);
MolOps::addHs(*m);
REQUIRE(m->getAtomWithIdx(1)->getChiralTag() == Atom::CHI_TETRAHEDRAL_CCW);
REQUIRE(m->getAtomWithIdx(8)->getChiralTag() == Atom::CHI_TETRAHEDRAL_CCW);
DGeomHelpers::EmbedParameters ps = DGeomHelpers::KDG;
{ // this always worked
ps.randomSeed = 0xC0FFEE;
auto cid = DGeomHelpers::EmbedMolecule(*m, ps);
CHECK(cid >= 0);
MolOps::assignStereochemistryFrom3D(*m, cid);
CHECK(m->getAtomWithIdx(1)->getChiralTag() == Atom::CHI_TETRAHEDRAL_CCW);
CHECK(m->getAtomWithIdx(8)->getChiralTag() == Atom::CHI_TETRAHEDRAL_CCW);
}
{ // this failed
ps.randomSeed = 0xC0FFEE + 123;
auto cid = DGeomHelpers::EmbedMolecule(*m, ps);
CHECK(cid >= 0);
MolOps::assignStereochemistryFrom3D(*m, cid);
CHECK(m->getAtomWithIdx(1)->getChiralTag() == Atom::CHI_TETRAHEDRAL_CCW);
CHECK(m->getAtomWithIdx(8)->getChiralTag() == Atom::CHI_TETRAHEDRAL_CCW);
}
}
}

View File

@@ -0,0 +1,378 @@
voxelotor
RDKit 2D
0 0 0 0 0 0 0 0 0 0999 V3000
M V30 BEGIN CTAB
M V30 COUNTS 26 28 0 0 0
M V30 BEGIN ATOM
M V30 1 C 4.522893 -2.428571 0.000000 0
M V30 2 C 5.760073 -1.714286 0.000000 0
M V30 3 C 5.760073 -0.285714 0.000000 0
M V30 4 C 4.522893 0.428571 0.000000 0
M V30 5 C 3.285714 -0.285714 0.000000 0
M V30 6 N 3.285714 -1.714286 0.000000 0
M V30 7 C 4.522893 -3.857143 0.000000 0
M V30 8 N 3.367155 -4.696836 0.000000 0
M V30 9 N 3.808608 -6.055488 0.000000 0
M V30 10 C 5.237179 -6.055488 0.000000 0
M V30 11 C 5.678632 -4.696836 0.000000 0
M V30 12 C 6.997252 -2.428571 0.000000 0
M V30 13 O 8.234431 -1.714286 0.000000 0
M V30 14 C 9.471610 -2.428571 0.000000 0
M V30 15 C 9.471610 -3.857143 0.000000 0
M V30 16 C 10.708789 -4.571429 0.000000 0
M V30 17 C 11.945968 -3.857143 0.000000 0
M V30 18 C 11.945968 -2.428571 0.000000 0
M V30 19 C 10.708789 -1.714286 0.000000 0
M V30 20 C 10.708789 -0.285714 0.000000 0
M V30 21 O 11.945968 0.428571 0.000000 0
M V30 22 C 9.471610 0.428571 0.000000 0
M V30 23 O 13.183147 -1.714286 0.000000 0
M V30 24 C 2.008503 -4.255383 0.000000 0
M V30 25 C 1.711486 -2.858030 0.000000 0
M V30 26 C 0.946867 -5.211284 0.000000 0
M V30 END ATOM
M V30 BEGIN BOND
M V30 1 1 1 2
M V30 2 2 2 3
M V30 3 1 3 4
M V30 4 2 4 5
M V30 5 1 5 6
M V30 6 2 6 1
M V30 7 1 1 7
M V30 8 1 8 9
M V30 9 2 9 10
M V30 10 1 10 11
M V30 11 2 11 7
M V30 12 1 7 8 CFG=1
M V30 13 1 2 12
M V30 14 1 12 13
M V30 15 1 13 14
M V30 16 1 15 16
M V30 17 2 16 17
M V30 18 1 17 18
M V30 19 2 18 19
M V30 20 1 19 14
M V30 21 2 14 15
M V30 22 1 19 20
M V30 23 2 20 21
M V30 24 1 20 22
M V30 25 1 18 23
M V30 26 1 8 24
M V30 27 1 24 25
M V30 28 1 24 26
M V30 END BOND
M V30 END CTAB
M END
> <atrop bond>
6
> <atrop volume>
6 7 1 5 1
$$$$
trifarotene
Mrv2211 01272406202D
0 0 0 0 0 999 V3000
M V30 BEGIN CTAB
M V30 COUNTS 34 37 0 0 0
M V30 BEGIN ATOM
M V30 1 C -10.4702 -6.275 0 0
M V30 2 C -9.1366 -5.505 0 0
M V30 3 C -8.3666 -6.8387 0 0
M V30 4 C -9.9066 -4.1713 0 0
M V30 5 C -7.8029 -4.735 0 0
M V30 6 C -7.8029 -3.195 0 0
M V30 7 C -6.4692 -2.425 0 0
M V30 8 C -6.4692 -0.885 0 0
M V30 9 C -7.8029 -0.115 0 0
M V30 10 C -7.8029 1.425 0 0
M V30 11 C -9.1366 2.195 0 0
M V30 12 C -10.4702 1.425 0 0
M V30 13 C -11.8039 2.195 0 0
M V30 14 C -11.8039 3.735 0 0
M V30 15 C -13.1376 4.505 0 0
M V30 16 O -13.1376 6.045 0 0
M V30 17 O -14.4713 3.735 0 0
M V30 18 C -10.4702 4.505 0 0
M V30 19 C -9.1366 3.735 0 0
M V30 20 C -6.4692 2.195 0 0
M V30 21 C -5.1355 1.425 0 0
M V30 22 C -5.1355 -0.115 0 0
M V30 23 O -3.8019 -0.885 0 0
M V30 24 C -3.8019 -2.425 0 0
M V30 25 C -2.4682 -3.195 0 0
M V30 26 O -2.4682 -4.735 0 0
M V30 27 C -5.1355 -3.195 0 0
M V30 28 C -5.1355 -4.735 0 0
M V30 29 C -6.4692 -5.505 0 0
M V30 30 N -6.4692 -7.045 0 0
M V30 31 C -5.2233 -7.9502 0 0
M V30 32 C -5.6992 -9.4148 0 0
M V30 33 C -7.2392 -9.4148 0 0
M V30 34 C -7.7151 -7.9502 0 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 2 4
M V30 4 1 2 5
M V30 5 2 5 6
M V30 6 1 7 8
M V30 7 2 8 9
M V30 8 1 9 10
M V30 9 1 10 11
M V30 10 2 11 12
M V30 11 1 12 13
M V30 12 2 13 14
M V30 13 1 14 15
M V30 14 2 15 16
M V30 15 1 15 17
M V30 16 1 14 18
M V30 17 2 18 19
M V30 18 1 11 19
M V30 19 2 10 20
M V30 20 1 20 21
M V30 21 2 21 22
M V30 22 1 8 22
M V30 23 1 22 23
M V30 24 1 23 24
M V30 25 1 24 25
M V30 26 1 25 26
M V30 27 2 7 27
M V30 28 1 27 28
M V30 29 2 28 29
M V30 30 1 5 29
M V30 31 1 29 30
M V30 32 1 30 31
M V30 33 1 31 32
M V30 34 1 32 33
M V30 35 1 33 34
M V30 36 1 30 34
M V30 37 1 7 6 CFG=1
M V30 END BOND
M V30 END CTAB
M END
> <atrop bond>
5
> <atrop volume>
6 5 21 8 1
$$$$
M4076 https://doi.org/10.1016/j.xphs.2021.10.011
Mrv2211 01272406282D
0 0 0 0 0 999 V3000
M V30 BEGIN CTAB
M V30 COUNTS 33 37 0 0 0
M V30 BEGIN ATOM
M V30 1 C -14.75 -0.6266 0 0
M V30 2 C -16.0837 -1.3966 0 0
M V30 3 N -16.0837 -2.9367 0 0
M V30 4 C -14.75 -3.7067 0 0
M V30 5 C -13.4163 -2.9367 0 0
M V30 6 C -13.4163 -1.3966 0 0
M V30 7 C -16.0837 1.6834 0 0
M V30 8 C -17.4173 0.9134 0 0
M V30 9 C -17.4173 -0.6266 0 0
M V30 10 C -14.75 0.9134 0 0
M V30 11 N -11.9436 -0.9464 0 0
M V30 12 N -11.9871 -3.4377 0 0
M V30 13 C -11.0604 -2.2079 0 0
M V30 14 O -9.5206 -2.2348 0 0
M V30 15 C -11.4423 0.5097 0 0
M V30 16 C -11.5409 -4.9117 0 0
M V30 17 O -18.751 1.6834 0 0
M V30 18 C -16.0837 3.2234 0 0
M V30 19 N -17.2149 5.4436 0 0
M V30 20 C -17.4557 3.9225 0 0
M V30 21 C -14.9947 4.3124 0 0
M V30 22 N -15.6938 5.6844 0 0
M V30 23 C -13.4737 4.0715 0 0
M V30 24 C -18.3038 6.5325 0 0
M V30 25 C -20.0847 0.9134 0 0
M V30 26 C -11.8135 3.1512 0 0
M V30 27 C -12.3904 1.7233 0 0
M V30 28 C -9.9172 0.724 0 0
M V30 29 C -9.3404 2.1519 0 0
M V30 30 N -10.2885 3.3655 0 0
M V30 31 F -13.9154 1.509 0 0
M V30 32 O -8.9691 -0.4895 0 0
M V30 33 C -7.4816 -0.0909 0 0
M V30 END ATOM
M V30 BEGIN BOND
M V30 1 2 1 2
M V30 2 1 2 3
M V30 3 2 3 4
M V30 4 1 4 5
M V30 5 2 5 6
M V30 6 1 1 6
M V30 7 1 7 8
M V30 8 2 8 9
M V30 9 2 7 10
M V30 10 1 9 2
M V30 11 1 1 10
M V30 12 1 12 13
M V30 13 1 11 13
M V30 14 1 11 6
M V30 15 1 5 12
M V30 16 2 13 14
M V30 17 1 11 15
M V30 18 1 12 16
M V30 19 1 8 17
M V30 20 1 7 18
M V30 21 1 19 20
M V30 22 1 19 22
M V30 23 1 18 21
M V30 24 1 21 23
M V30 25 1 19 24
M V30 26 2 21 22
M V30 27 2 20 18
M V30 28 1 17 25
M V30 29 1 26 27
M V30 30 2 28 29
M V30 31 1 29 30
M V30 32 2 26 30
M V30 33 2 27 15
M V30 34 1 15 28 CFG=1
M V30 35 1 27 31
M V30 36 1 28 32
M V30 37 1 32 33
M V30 END BOND
M V30 END CTAB
M END
> <atrop bond>
16
> <atrop volume>
10 5 27 26 1
$$$$
triclabendazole wedge in ring
Mrv2211 01272406512D
0 0 0 0 0 999 V3000
M V30 BEGIN CTAB
M V30 COUNTS 21 23 0 0 0
M V30 BEGIN ATOM
M V30 1 C -1.0896 0.0309 0 0
M V30 2 S -0.3196 -1.3028 0 0
M V30 3 C 1.2204 -1.3028 0 0
M V30 4 N 2.1256 -0.0569 0 0
M V30 5 C 3.5902 -0.5328 0 0
M V30 6 C 4.9239 0.2372 0 0
M V30 7 C 6.2576 -0.5328 0 0
M V30 8 Cl 7.5913 0.2372 0 0
M V30 9 C 6.2576 -2.0728 0 0
M V30 10 O 7.5913 -2.8428 0 0
M V30 11 C 7.5913 -4.3828 0 0
M V30 12 C 8.925 -5.1528 0 0
M V30 13 C 8.925 -6.6928 0 0
M V30 14 C 7.5913 -7.4628 0 0
M V30 15 C 6.2576 -6.6928 0 0
M V30 16 Cl 4.9239 -7.4628 0 0
M V30 17 C 6.2576 -5.1528 0 0
M V30 18 Cl 4.9239 -4.3828 0 0
M V30 19 C 4.9239 -2.8428 0 0
M V30 20 C 3.5902 -2.0728 0 0
M V30 21 N 2.1256 -2.5487 0 0
M V30 END ATOM
M V30 BEGIN BOND
M V30 1 1 1 2
M V30 2 1 2 3
M V30 3 2 3 4
M V30 4 1 4 5
M V30 5 2 5 6
M V30 6 1 6 7
M V30 7 1 7 8
M V30 8 2 7 9
M V30 9 1 9 10
M V30 10 1 10 11
M V30 11 2 11 12
M V30 12 1 12 13
M V30 13 2 13 14
M V30 14 1 14 15
M V30 15 1 15 16
M V30 16 2 15 17
M V30 17 1 11 17
M V30 18 1 17 18
M V30 19 2 19 20
M V30 20 1 5 20
M V30 21 1 20 21
M V30 22 1 3 21
M V30 23 1 9 19 CFG=1
M V30 END BOND
M V30 END CTAB
M END
> <atrop bond>
8
> <atrop volume>
8 18 6 10 1
$$$$
triclabendazole wedge on O
Mrv2211 01272406512D
0 0 0 0 0 999 V3000
M V30 BEGIN CTAB
M V30 COUNTS 21 23 0 0 0
M V30 BEGIN ATOM
M V30 1 C -1.0896 0.0309 0 0
M V30 2 S -0.3196 -1.3028 0 0
M V30 3 C 1.2204 -1.3028 0 0
M V30 4 N 2.1256 -0.0569 0 0
M V30 5 C 3.5902 -0.5328 0 0
M V30 6 C 4.9239 0.2372 0 0
M V30 7 C 6.2576 -0.5328 0 0
M V30 8 Cl 7.5913 0.2372 0 0
M V30 9 C 6.2576 -2.0728 0 0
M V30 10 O 7.5913 -2.8428 0 0
M V30 11 C 7.5913 -4.3828 0 0
M V30 12 C 8.925 -5.1528 0 0
M V30 13 C 8.925 -6.6928 0 0
M V30 14 C 7.5913 -7.4628 0 0
M V30 15 C 6.2576 -6.6928 0 0
M V30 16 Cl 4.9239 -7.4628 0 0
M V30 17 C 6.2576 -5.1528 0 0
M V30 18 Cl 4.9239 -4.3828 0 0
M V30 19 C 4.9239 -2.8428 0 0
M V30 20 C 3.5902 -2.0728 0 0
M V30 21 N 2.1256 -2.5487 0 0
M V30 END ATOM
M V30 BEGIN BOND
M V30 1 1 1 2
M V30 2 1 2 3
M V30 3 2 3 4
M V30 4 1 4 5
M V30 5 2 5 6
M V30 6 1 6 7
M V30 7 1 7 8
M V30 8 2 7 9
M V30 9 1 9 10
M V30 10 1 10 11 CFG=1
M V30 11 2 11 12
M V30 12 1 12 13
M V30 13 2 13 14
M V30 14 1 14 15
M V30 15 1 15 16
M V30 16 2 15 17
M V30 17 1 11 17
M V30 18 1 17 18
M V30 19 2 19 20
M V30 20 1 5 20
M V30 21 1 20 21
M V30 22 1 3 21
M V30 23 1 9 19
M V30 END BOND
M V30 END CTAB
M END
> <atrop bond>
8
> <atrop volume>
9 10 6 18 1
$$$$

View File

@@ -434,7 +434,7 @@ bondholder makeBondHolder(const Bond *bond, unsigned int otherIdx,
if (res.stype == Bond::BondStereo::STEREOATROPCCW ||
res.stype == Bond::BondStereo::STEREOATROPCW) {
AtropAtomAndBondVec atropAtomAndBondVecs[2];
Atropisomers::AtropAtomAndBondVec atropAtomAndBondVecs[2];
CHECK_INVARIANT(Atropisomers::getAtropisomerAtomsAndBonds(
bond, atropAtomAndBondVecs, bond->getOwningMol()),
"Could not find atropisomer controlling atoms")