1 /*
2  *  sketcherMinimizerAtom.h
3  *
4  *  Created by Nicola Zonta on 13/04/2010.
5  *   Copyright Schrodinger, LLC. All rights reserved.
6  *
7  */
8 
9 #ifndef sketcherMINIMIZERATOM_H
10 #define sketcherMINIMIZERATOM_H
11 
12 // #include <sketcherMinimizerPointF>
13 #include "CoordgenConfig.hpp"
14 #include "sketcherMinimizerMaths.h"
15 #include <iostream>
16 #include <map>
17 #include <vector>
18 
19 static const int COORDINATES_LIMIT = 10000000;
20 static const int INVALID_COORDINATES = COORDINATES_LIMIT + 1;
21 
22 class sketcherMinimizerBond;
23 
24 class sketcherMinimizerFragment;
25 class sketcherMinimizerRing;
26 class sketcherMinimizerMolecule;
27 
28 class sketcherMinimizerAtom;
29 typedef struct {
30     sketcherMinimizerAtom* a;
31     unsigned int priority;
32 } sketcherMinimizerAtomPriority;
33 
34 struct sketcherMinimizerAtomChiralityInfo {
35     enum sketcherMinimizerChirality {
36         clockwise,
37         counterClockwise,
38         unspecified
39     };
40 
41     sketcherMinimizerAtom* lookingFrom = nullptr;
42     sketcherMinimizerAtom* atom1 = nullptr;
43     sketcherMinimizerAtom* atom2 = nullptr;
44     sketcherMinimizerChirality direction = unspecified;
45 };
46 
47 /* structure to represent an atom in Cahn–Ingold–Prelog priorities assignment */
48 struct CIPAtom {
CIPAtomCIPAtom49     CIPAtom(std::vector<std::pair<int, sketcherMinimizerAtom*>> us,
50             sketcherMinimizerAtom* dad,
51             std::vector<sketcherMinimizerAtom*> allPars,
52             std::map<sketcherMinimizerAtom*, int>* scors,
53             std::map<sketcherMinimizerAtom*, std::vector<int>>* meds,
54             std::map<sketcherMinimizerAtom*, int>* visits
55 
56             )
57         : theseAtoms(std::move(us)), parent(dad),
58           allParents(std::move(allPars)), scores(scors), visited(visits),
59           medals(meds)
60     {
61     }
62     bool operator<(const CIPAtom& rhs) const;
63     bool operator==(const CIPAtom& rhs) const;
64     bool isBetter(CIPAtom& rhs,
65                   std::map<sketcherMinimizerAtom*, unsigned int>* m) const;
66 
67     std::vector<std::pair<int, sketcherMinimizerAtom*>>
68         theseAtoms; // NULL if dummy
69     sketcherMinimizerAtom* parent;
70     std::vector<sketcherMinimizerAtom*> allParents;
71     std::map<sketcherMinimizerAtom*, int>* scores;
72     std::map<sketcherMinimizerAtom*, int>* visited;
73     std::map<sketcherMinimizerAtom*, std::vector<int>>* medals;
74 
75   private:
76     friend std::ostream& operator<<(std::ostream& os, const CIPAtom& a);
77 };
78 
79 /* class to represent an atom */
80 class EXPORT_COORDGEN sketcherMinimizerAtom
81 {
82   public:
83     sketcherMinimizerAtom();
84     virtual ~sketcherMinimizerAtom();
85 
86     bool crossLayout; // atoms with 4 substituents displayed in a cross style
87                       // (such as S in sulphate)
88     bool fixed, constrained, rigid;
89     bool isSharedAndInner; // shared by two rings and needs to be drawn inside a
90                            // ring
91     bool hidden;
92     int atomicNumber, charge, _valence, _generalUseN, _generalUseN2;
93     int m_chmN; // idx of the corresponding ChmAtom if molecule comes from 3d
94 
95     bool _generalUseVisited, _generalUseVisited2;
96     bool m_clockwiseInvert;
97     bool m_ignoreRingChirality;
98     std::vector<int> m_RSPriorities;
99     int _implicitHs = -1;
100     sketcherMinimizerMolecule* molecule;
101     sketcherMinimizerFragment* fragment;
setFragment(sketcherMinimizerFragment * fragmentToSet)102     void setFragment(sketcherMinimizerFragment* fragmentToSet)
103     {
104         fragment = fragmentToSet;
105     }
getFragment()106     sketcherMinimizerFragment* getFragment() const { return fragment; }
getBonds()107     const std::vector<sketcherMinimizerBond*>& getBonds() const
108     {
109         return bonds;
110     }
getRings()111     const std::vector<sketcherMinimizerRing*>& getRings() const
112     {
113         return rings;
114     }
115 
getMolecule()116     sketcherMinimizerMolecule* getMolecule() const { return molecule; }
117 
118     /*
119      Find all connected atoms, pruning the search at the excludedAtom."
120      This function assumes that the bond between this atom and excludedAtom
121      is not part of a ring.
122      */
123     std::vector<sketcherMinimizerAtom*>
124     getSubmolecule(sketcherMinimizerAtom* excludedAtom);
125     std::vector<sketcherMinimizerAtom*> neighbors;
126     std::vector<sketcherMinimizerBond*> bonds;
127     std::vector<sketcherMinimizerAtom*> residueInteractionPartners;
128     std::vector<sketcherMinimizerBond*> residueInteractions;
129     std::vector<sketcherMinimizerRing*> rings;
130     float m_pseudoZ;
131 
132     float m_x3D;
133     float m_y3D;
134     float m_z3D;
135 
136     bool m_isClashing, m_isWaterMap;
137     float m_pocketDistance;
138 
139     bool needsCheckForClashes;
140     bool m_isLigand;
141     bool visited, coordinatesSet;
142     bool isR; // stereochemistry
143     bool hasStereochemistrySet, m_isStereogenic;
144     bool _hasRingChirality; // used to keep track of cyclohexane cis/trans
145                             // chirality
146 
147     /* write coordinates to atom */
148     void setCoordinates(sketcherMinimizerPointF coords);
149 
150     /* check that the atom has no double bonds possibly involved in E/Z
151      * stereochemistry */
152     bool hasNoStereoActiveBonds() const;
153 
getCoordinates()154     const sketcherMinimizerPointF& getCoordinates() const
155     {
156         return coordinates;
157     }
getAtomicNumber()158     int getAtomicNumber() const { return atomicNumber; }
159 
setAtomicNumber(int number)160     void setAtomicNumber(int number) { atomicNumber = number; }
161 
setStereoChemistry(sketcherMinimizerAtomChiralityInfo info)162     void setStereoChemistry(sketcherMinimizerAtomChiralityInfo info)
163     {
164         m_chiralityInfo = info;
165     }
166 
167     /* write template coordinates to atom */
setCoordinatesToTemplate()168     void setCoordinatesToTemplate() { setCoordinates(templateCoordinates); }
169     sketcherMinimizerPointF coordinates;
170     sketcherMinimizerPointF templateCoordinates;
171     sketcherMinimizerPointF force;
172 
173     /* return the expected valence for the atom */
174     unsigned int expectedValence(unsigned int atomicNumber) const;
175 
176     bool canBeChiral() const; // checks if the atom can have 4 substituents (one
177                               // can be implicit H). Doesn't actually check if
178                               // two of them are the same, so can return true
179                               // for achiral centers
180 
181     /* return true if this and at2 share a bond */
isNeighborOf(sketcherMinimizerAtom * at2)182     bool isNeighborOf(sketcherMinimizerAtom* at2) const
183     {
184         for (auto& neighbor : at2->neighbors) {
185             if (neighbor == this) {
186                 return true;
187             }
188         }
189         return false;
190     }
191 
192     sketcherMinimizerAtomChiralityInfo::sketcherMinimizerChirality
193     getRelativeStereo(sketcherMinimizerAtom* lookingFrom,
194                       sketcherMinimizerAtom* atom1,
195                       sketcherMinimizerAtom* atom2);
196     bool setAbsoluteStereoFromChiralityInfo();
197 
198     /* if this atom and the given one share a bond, return it */
199     sketcherMinimizerBond* bondTo(sketcherMinimizerAtom* at) const;
200 
201     /* return all bonded atoms, ordered as they appear clockwise around this */
202     std::vector<sketcherMinimizerAtom*> clockwiseOrderedNeighbors() const;
203     int findHsNumber() const;
204 
205     void writeStereoChemistry(); // assigns up-down bond flags based on isR and
206                                  // hasStereochemistrySet
207 
208     /* return true if the two sequences represent the same isomer */
209     static bool matchCIPSequence(std::vector<int>& v1, std::vector<int>& v2);
210 
211     /* calculate CIP priorities and assign them */
212     static bool
213     setCIPPriorities(std::vector<sketcherMinimizerAtomPriority>& atomPriorities,
214                      sketcherMinimizerAtom* center);
215 
216     static void orderAtomPriorities(
217         std::vector<sketcherMinimizerAtomPriority>& atomPriorities,
218         sketcherMinimizerAtom* center); // orders trying to keep long chains in
219                                         // position 2 and 3 and side
220                                         // substituents in 1 and 4
221 
222     /* return which between at1 and at2 has higher CIP priority. Returns NULL if
223      * they have the same */
224     static sketcherMinimizerAtom* CIPPriority(sketcherMinimizerAtom* at1,
225                                               sketcherMinimizerAtom* at2,
226                                               sketcherMinimizerAtom* center);
227 
228     /* consider one additional level of bound atoms in the CIP algorithm to
229      * break a tie */
230     static std::vector<CIPAtom> expandOneLevel(std::vector<CIPAtom>& oldV);
231 
232     /* if any ties between parent atoms was solved, assign two different scores
233      to them. Also clear the medals for the next iteration */
234     static void finalizeScores(std::vector<CIPAtom>& v);
235 
236     /* medals are used to mark parent atoms according to the priorities of their
237      children and also their numbers. */
238     static void assignMedals(std::vector<CIPAtom>& v);
239 
240     /* first atom will be the highest priority, subsequent will be based on
241      * atoms that have already been picked, giving priorities to branches that
242      * have been already been visited. friendsMask keeps track of parents that
243      * have a child that has been already selected */
244     static void chooseFirstAndSortAccordingly(std::vector<CIPAtom>& V);
245 
246     /* if the two atoms share a ring, return it */
247     static sketcherMinimizerRing*
248     shareARing(const sketcherMinimizerAtom* atom1,
249                const sketcherMinimizerAtom* atom2);
250 
251     /* mirror the coordinates of at wrt bond */
252     static void mirrorCoordinates(sketcherMinimizerAtom* at,
253                                   const sketcherMinimizerBond* bond);
254 
255     /* return the stereochemistry set in the wedges around the atom.  0 if not
256      * assigned, 1 if R, -1 if S */
257     int readStereochemistry(bool readOnly = false);
258 
259     /* return a direction perpendicular to the atom's bonds average */
260     sketcherMinimizerPointF getSingleAdditionVector() const;
261 
262     static sketcherMinimizerPointF
263     getSingleAdditionVector(const std::vector<sketcherMinimizerAtom*>& ats);
264 
265     /* return true if the atom  has valid 3d coordinates */
266     bool hasValid3DCoordinates() const;
267 
268     /* return true if the atom is a residue */
269     virtual bool isResidue() const;
270 
271     /* return true if atomicNumber represents a metal */
272     static bool isMetal(const unsigned int atomicNumber);
273 
274     sketcherMinimizerAtomChiralityInfo m_chiralityInfo;
275 };
276 
277 #endif // sketcherMINIMIZERATOM_H
278