RDKit
Open-source cheminformatics and machine learning.
Loading...
Searching...
No Matches
Configuration.h
Go to the documentation of this file.
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#pragma once
12
13#include <memory>
14#include <vector>
15
16#include "../Descriptor.h"
17#include "../Digraph.h"
18#include "../CIPMol.h"
19
20namespace RDKit {
21
22class Atom;
23class Bond;
24
25namespace CIPLabeler {
26
27class Rules;
28
30 public:
31 template <typename T>
32 static int parity4(const std::vector<T> &trg, const std::vector<T> &ref) {
33 if (ref.size() != 4 || trg.size() != ref.size()) {
34 throw std::runtime_error("Parity vectors must have size 4.");
35 }
36
37 if (ref[0] == trg[0]) {
38 if (ref[1] == trg[1]) {
39 // a,b,c,d -> a,b,c,d
40 if (ref[2] == trg[2] && ref[3] == trg[3]) {
41 return 2;
42 }
43 // a,b,c,d -> a,b,d,c
44 if (ref[2] == trg[3] && ref[3] == trg[2]) {
45 return 1;
46 }
47 } else if (ref[1] == trg[2]) {
48 // a,b,c,d -> a,c,b,d
49 if (ref[2] == trg[1] && ref[3] == trg[3]) {
50 return 1;
51 }
52 // a,b,c,d -> a,c,d,b
53 if (ref[2] == trg[3] && ref[3] == trg[1]) {
54 return 2;
55 }
56 } else if (ref[1] == trg[3]) {
57 // a,b,c,d -> a,d,c,b
58 if (ref[2] == trg[2] && ref[3] == trg[1]) {
59 return 1;
60 }
61 // a,b,c,d -> a,d,b,c
62 if (ref[2] == trg[1] && ref[3] == trg[2]) {
63 return 2;
64 }
65 }
66 } else if (ref[0] == trg[1]) {
67 if (ref[1] == trg[0]) {
68 // a,b,c,d -> b,a,c,d
69 if (ref[2] == trg[2] && ref[3] == trg[3]) {
70 return 1;
71 }
72 // a,b,c,d -> b,a,d,c
73 if (ref[2] == trg[3] && ref[3] == trg[2]) {
74 return 2;
75 }
76 } else if (ref[1] == trg[2]) {
77 // a,b,c,d -> b,c,a,d
78 if (ref[2] == trg[0] && ref[3] == trg[3]) {
79 return 2;
80 }
81 // a,b,c,d -> b,c,d,a
82 if (ref[2] == trg[3] && ref[3] == trg[0]) {
83 return 1;
84 }
85 } else if (ref[1] == trg[3]) {
86 // a,b,c,d -> b,d,c,a
87 if (ref[2] == trg[2] && ref[3] == trg[0]) {
88 return 2;
89 }
90 // a,b,c,d -> b,d,a,c
91 if (ref[2] == trg[0] && ref[3] == trg[2]) {
92 return 1;
93 }
94 }
95 } else if (ref[0] == trg[2]) {
96 if (ref[1] == trg[1]) {
97 // a,b,c,d -> c,b,a,d
98 if (ref[2] == trg[0] && ref[3] == trg[3]) {
99 return 1;
100 }
101 // a,b,c,d -> c,b,d,a
102 if (ref[2] == trg[3] && ref[3] == trg[0]) {
103 return 2;
104 }
105 } else if (ref[1] == trg[0]) {
106 // a,b,c,d -> c,a,b,d
107 if (ref[2] == trg[1] && ref[3] == trg[3]) {
108 return 2;
109 }
110 // a,b,c,d -> c,a,d,b
111 if (ref[2] == trg[3] && ref[3] == trg[1]) {
112 return 1;
113 }
114 } else if (ref[1] == trg[3]) {
115 // a,b,c,d -> c,d,a,b
116 if (ref[2] == trg[0] && ref[3] == trg[1]) {
117 return 2;
118 }
119 // a,b,c,d -> c,d,b,a
120 if (ref[2] == trg[1] && ref[3] == trg[0]) {
121 return 1;
122 }
123 }
124 } else if (ref[0] == trg[3]) {
125 if (ref[1] == trg[1]) {
126 // a,b,c,d -> d,b,c,a
127 if (ref[2] == trg[2] && ref[3] == trg[0]) {
128 return 1;
129 }
130 // a,b,c,d -> d,b,a,c
131 if (ref[2] == trg[0] && ref[3] == trg[2]) {
132 return 2;
133 }
134 } else if (ref[1] == trg[2]) {
135 // a,b,c,d -> d,c,b,a
136 if (ref[2] == trg[1] && ref[3] == trg[0]) {
137 return 2;
138 }
139 // a,b,c,d -> d,c,a,b
140 if (ref[2] == trg[0] && ref[3] == trg[1]) {
141 return 1;
142 }
143 } else if (ref[1] == trg[0]) {
144 // a,b,c,d -> d,a,c,b
145 if (ref[2] == trg[2] && ref[3] == trg[1]) {
146 return 2;
147 }
148 // a,b,c,d -> d,a,b,c
149 if (ref[2] == trg[1] && ref[3] == trg[2]) {
150 return 1;
151 }
152 }
153 }
154
155 // We should never hit this, but the compiler still complains
156 // about a missing return statement.
157 return 0;
158 }
159
160 Configuration() = delete;
161
163
164 Configuration(const CIPMol &mol, std::vector<Atom *> &&foci,
165 bool atropisomerMode = false);
166
167 virtual ~Configuration();
168
169 Atom *getFocus() const;
170
171 const std::vector<Atom *> &getFoci() const;
172
173 const std::vector<Atom *> &getCarriers() const;
174
176
178
179 virtual Descriptor label(const Rules &comp) = 0;
180
181 virtual void setPrimaryLabel(Descriptor desc) = 0;
182
183 protected:
184 Edge *findInternalEdge(const std::vector<Edge *> &edges, Atom *f1, Atom *f2);
185
187
188 void removeInternalEdges(std::vector<Edge *> &edges, Atom *f1, Atom *f2);
189
190 void setCarriers(std::vector<Atom *> &&carriers);
191
192 private:
193 /**
194 * Foci are the atoms on which the configuration is based,
195 * and which will carry the label. E.g., the chiral atom in
196 * a tetrahedral chirality, or the bond ends in a double bond.
197 */
198 std::vector<Atom *> d_foci;
199
200 /**
201 * Carriers are the atoms neighboring the foci that define the
202 * configuration. E.g., for a chiral atom, its four neighbors
203 * define a parity; for a double bond, one neighbor on each
204 * side of the bond defines it as Cis or Trans.
205 */
206 std::vector<Atom *> d_carriers;
207
208 Digraph d_digraph;
209
210}; // namespace CIPLabeler
211
212} // namespace CIPLabeler
213} // namespace RDKit
The class for representing atoms.
Definition Atom.h:75
void setCarriers(std::vector< Atom * > &&carriers)
virtual Descriptor label(Node *node, Digraph &digraph, const Rules &comp)
const std::vector< Atom * > & getFoci() const
const std::vector< Atom * > & getCarriers() const
Edge * findInternalEdge(const std::vector< Edge * > &edges, Atom *f1, Atom *f2)
virtual void setPrimaryLabel(Descriptor desc)=0
void removeInternalEdges(std::vector< Edge * > &edges, Atom *f1, Atom *f2)
bool isInternalEdge(const Edge *edge, Atom *f1, Atom *f2)
Configuration(const CIPMol &mol, Atom *focus)
virtual Descriptor label(const Rules &comp)=0
Configuration(const CIPMol &mol, std::vector< Atom * > &&foci, bool atropisomerMode=false)
static int parity4(const std::vector< T > &trg, const std::vector< T > &ref)
Std stuff.
bool rdvalue_is(const RDValue_cast_t)