1 //
2 //
3 // Copyright (C) 2020 Schrödinger, LLC
4 //
5 // @@ All Rights Reserved @@
6 // This file is part of the RDKit.
7 // The contents are covered by the terms of the BSD license
8 // which is included in the file license.txt, found at the root
9 // of the RDKit source tree.
10 //
11 #include <GraphMol/Chirality.h>
12
13 #include "Sp2Bond.h"
14 #include "../Sort.h"
15 #include "../rules/Rules.h"
16
17 namespace RDKit {
18 namespace CIPLabeler {
19
Sp2Bond(const CIPMol & mol,Bond * bond,Atom * startAtom,Atom * endAtom,Bond::BondStereo cfg)20 Sp2Bond::Sp2Bond(const CIPMol &mol, Bond *bond, Atom *startAtom, Atom *endAtom,
21 Bond::BondStereo cfg)
22 : Configuration(mol, {startAtom, endAtom}), dp_bond{bond}, d_cfg{cfg} {
23 CHECK_INVARIANT(startAtom && endAtom, "bad foci")
24 CHECK_INVARIANT(d_cfg == Bond::STEREOTRANS || d_cfg == Bond::STEREOCIS,
25 "bad config")
26
27 auto stereo_atoms = Chirality::findStereoAtoms(bond);
28 CHECK_INVARIANT(stereo_atoms.size() == 2, "incorrect number of stereo atoms")
29
30 std::vector<Atom *> anchors{
31 {mol.getAtom(stereo_atoms[0]), mol.getAtom(stereo_atoms[1])}};
32
33 setCarriers(std::move(anchors));
34 }
35
setPrimaryLabel(Descriptor desc)36 void Sp2Bond::setPrimaryLabel(Descriptor desc) {
37 switch (desc) {
38 case Descriptor::seqTrans:
39 case Descriptor::E:
40 case Descriptor::seqCis:
41 case Descriptor::Z: {
42 auto carriers = getCarriers();
43 dp_bond->setStereoAtoms(carriers[0]->getIdx(), carriers[1]->getIdx());
44 dp_bond->setStereo(d_cfg);
45 dp_bond->setProp(common_properties::_CIPCode, to_string(desc));
46 return;
47 }
48 case Descriptor::R:
49 case Descriptor::S:
50 case Descriptor::r:
51 case Descriptor::s:
52 case Descriptor::SP_4:
53 case Descriptor::TBPY_5:
54 case Descriptor::OC_6:
55 throw std::runtime_error(
56 "Received a Descriptor that is not supported for bonds");
57 default:
58 throw std::runtime_error("Received an invalid Bond Descriptor");
59 }
60 }
61
label(const Rules & comp)62 Descriptor Sp2Bond::label(const Rules &comp) {
63 auto &digraph = getDigraph();
64 auto root1 = digraph.getOriginalRoot();
65 if (digraph.getCurrentRoot() != root1) {
66 digraph.changeRoot(root1);
67 }
68
69 return label(root1, digraph, comp);
70 }
71
label(Node * root1,Digraph & digraph,const Rules & comp)72 Descriptor Sp2Bond::label(Node *root1, Digraph &digraph, const Rules &comp) {
73 const auto &focus1 = getFoci()[0];
74 const auto &focus2 = getFoci()[1];
75
76 const auto &internal = findInternalEdge(root1->getEdges(), focus1, focus2);
77 if (internal == nullptr) {
78 return Descriptor::UNKNOWN;
79 }
80 const auto &root2 = internal->getOther(root1);
81
82 auto edges1 = root1->getEdges();
83 auto edges2 = root2->getEdges();
84 removeInternalEdges(edges1, focus1, focus2);
85 removeInternalEdges(edges2, focus1, focus2);
86
87 auto carriers = std::vector<Atom *>(getCarriers());
88 auto config = d_cfg;
89
90 if (root1->getAtom() == focus2) {
91 std::swap(carriers[0], carriers[1]);
92 }
93
94 digraph.changeRoot(root1);
95 const auto &priority1 = comp.sort(root1, edges1);
96 if (!priority1.isUnique()) {
97 return Descriptor::UNKNOWN;
98 }
99 // swap
100 if (edges1.size() > 1 && carriers[0] == edges1[1]->getEnd()->getAtom()) {
101 if (config == Bond::STEREOCIS) {
102 config = Bond::STEREOTRANS;
103 } else {
104 config = Bond::STEREOCIS;
105 }
106 }
107 digraph.changeRoot(root2);
108 const auto &priority2 = comp.sort(root2, edges2);
109 if (!priority2.isUnique()) {
110 return Descriptor::UNKNOWN;
111 }
112 // swap
113 if (edges2.size() > 1 && carriers[1] == edges2[1]->getEnd()->getAtom()) {
114 if (config == Bond::STEREOCIS) {
115 config = Bond::STEREOTRANS;
116 } else {
117 config = Bond::STEREOCIS;
118 }
119 }
120
121 if (config == Bond::STEREOCIS) {
122 if (priority1.isPseudoAsymetric() != priority2.isPseudoAsymetric()) {
123 return Descriptor::seqCis;
124 } else {
125 return Descriptor::Z;
126 }
127 } else if (config == Bond::STEREOTRANS) {
128 if (priority1.isPseudoAsymetric() != priority2.isPseudoAsymetric()) {
129 return Descriptor::seqTrans;
130 } else {
131 return Descriptor::E;
132 }
133 }
134 return Descriptor::UNKNOWN;
135 }
136
137 } // namespace CIPLabeler
138 } // namespace RDKit