1 /*
2  *  sketcherMinimizerMolecule.cpp
3  *
4  *  Created by Nicola Zonta on 24/05/2011.
5  *   Copyright Schrodinger, LLC. All rights reserved.
6  *
7  */
8 
9 #include "sketcherMinimizerMolecule.h"
10 #include "sketcherMinimizerAtom.h"
11 #include "sketcherMinimizerMaths.h"
12 #include "sketcherMinimizerRing.h"
13 #include "sketcherMinimizerBond.h"
14 #include <queue>
15 
16 using namespace std;
17 
sketcherMinimizerMolecule()18 sketcherMinimizerMolecule::sketcherMinimizerMolecule()
19     : fixed(false),
20 
21       hasFixedFragments(false), hasConstrainedFragments(false),
22       needToAlignNonRingAtoms(false), needToAlignWholeMolecule(false),
23       isPlaced(false), m_mainFragment(nullptr), m_requireMinimization(false){};
24 
~sketcherMinimizerMolecule()25 sketcherMinimizerMolecule::~sketcherMinimizerMolecule()
26 {
27     for (auto ring : _rings) {
28         delete ring;
29     }
30 }
31 
addNewAtom()32 sketcherMinimizerAtom* sketcherMinimizerMolecule::addNewAtom()
33 {
34     auto atom = new sketcherMinimizerAtom();
35     _atoms.push_back(atom);
36     atom->molecule = this;
37     return atom;
38 }
39 
40 sketcherMinimizerBond*
addNewBond(sketcherMinimizerAtom * at1,sketcherMinimizerAtom * at2)41 sketcherMinimizerMolecule::addNewBond(sketcherMinimizerAtom* at1,
42                                       sketcherMinimizerAtom* at2)
43 {
44     auto bond = new sketcherMinimizerBond(at1, at2);
45     _bonds.push_back(bond);
46     return bond;
47 }
48 
totalCharge()49 int sketcherMinimizerMolecule::totalCharge()
50 {
51     int charge = 0;
52     for (auto& _atom : _atoms) {
53         charge += _atom->charge;
54     }
55     return charge;
56 }
57 
boundingBox(sketcherMinimizerPointF & min,sketcherMinimizerPointF & max)58 void sketcherMinimizerMolecule::boundingBox(sketcherMinimizerPointF& min,
59                                             sketcherMinimizerPointF& max)
60 {
61     min.setX(0.f);
62     min.setY(0.f);
63     max.setX(0.f);
64     max.setY(0.f);
65     if (_atoms.size()) {
66         min = _atoms[0]->coordinates;
67         max = _atoms[0]->coordinates;
68         for (auto a : _atoms) {
69             if (a->coordinates.x() < min.x()) {
70                 min.setX(a->coordinates.x());
71             }
72             if (a->coordinates.y() < min.y()) {
73                 min.setY(a->coordinates.y());
74             }
75             if (a->coordinates.x() > max.x()) {
76                 max.setX(a->coordinates.x());
77             }
78             if (a->coordinates.y() > max.y()) {
79                 max.setY(a->coordinates.y());
80             }
81         }
82     }
83 }
84 
requireMinimization()85 void sketcherMinimizerMolecule::requireMinimization()
86 {
87     m_requireMinimization = true;
88 }
89 
minimizationIsRequired()90 bool sketcherMinimizerMolecule::minimizationIsRequired()
91 {
92     return m_requireMinimization;
93 }
94 
center()95 sketcherMinimizerPointF sketcherMinimizerMolecule::center()
96 {
97     if (!_atoms.size()) {
98         return sketcherMinimizerPointF(0.f, 0.f);
99     }
100     sketcherMinimizerPointF c(.0f, .0f);
101     for (auto& _atom : _atoms) {
102         c += _atom->coordinates;
103     }
104     return c / _atoms.size();
105 }
106 
assignBondsAndNeighbors(std::vector<sketcherMinimizerAtom * > & atoms,std::vector<sketcherMinimizerBond * > & bonds)107 void sketcherMinimizerMolecule::assignBondsAndNeighbors(
108     std::vector<sketcherMinimizerAtom*>& atoms,
109     std::vector<sketcherMinimizerBond*>& bonds)
110 {
111     for (auto atom : atoms) {
112         atom->bonds.clear();
113         atom->neighbors.clear();
114         atom->residueInteractionPartners.clear();
115         atom->residueInteractions.clear();
116         atom->rings.clear();
117     }
118 
119     for (auto bond : bonds) {
120 
121         bond->rings.clear();
122 
123         if (!bond->isResidueInteraction()) {
124             //    bond->_rings.clear ();
125             bond->startAtom->bonds.push_back(bond);
126 
127             bond->endAtom->neighbors.push_back(bond->startAtom);
128 
129             bond->endAtom->bonds.push_back(bond);
130 
131             bond->startAtom->neighbors.push_back(bond->endAtom);
132         } else {
133             bond->startAtom->residueInteractions.push_back(bond);
134 
135             bond->endAtom->residueInteractionPartners.push_back(
136                 bond->startAtom);
137 
138             bond->endAtom->residueInteractions.push_back(bond);
139 
140             bond->startAtom->residueInteractionPartners.push_back(
141                 bond->endAtom);
142         }
143     }
144     for (auto& atom : atoms) {
145         if (atom->_implicitHs == -1) {
146             atom->_implicitHs = atom->findHsNumber();
147         }
148     }
149 }
150 
forceUpdateStruct(std::vector<sketcherMinimizerAtom * > & atoms,std::vector<sketcherMinimizerBond * > & bonds,std::vector<sketcherMinimizerRing * > & rings)151 void sketcherMinimizerMolecule::forceUpdateStruct(
152     std::vector<sketcherMinimizerAtom*>& atoms,
153     std::vector<sketcherMinimizerBond*>& bonds,
154     std::vector<sketcherMinimizerRing*>& rings)
155 {
156     sketcherMinimizerMolecule::assignBondsAndNeighbors(atoms, bonds);
157 
158     findRings(bonds, rings);
159     for (auto& bond : bonds) {
160         for (unsigned int j = 0; j < bond->rings.size(); j++) {
161             sketcherMinimizerRing* ring = bond->rings[j];
162             bool found = false;
163             for (auto& k : bond->startAtom->rings) {
164                 if (k == ring) {
165                     found = true;
166                     break;
167                 }
168             }
169             if (!found) {
170                 bond->startAtom->rings.push_back(ring);
171             }
172             found = false;
173             for (auto& k : bond->endAtom->rings) {
174                 if (k == ring) {
175                     found = true;
176                     break;
177                 }
178             }
179             if (!found) {
180                 bond->endAtom->rings.push_back(ring);
181             }
182         }
183     }
184 
185     for (auto& atom : atoms) {
186         for (unsigned int j = 0; j < atom->rings.size(); j++) {
187             atom->rings[j]->_atoms.push_back(atom);
188         }
189     }
190 }
191 
findRings(std::vector<sketcherMinimizerBond * > & bonds,std::vector<sketcherMinimizerRing * > & rings)192 void sketcherMinimizerMolecule::findRings(
193     std::vector<sketcherMinimizerBond*>& bonds,
194     std::vector<sketcherMinimizerRing*>& rings)
195 {
196     for (auto& ring : rings) {
197         delete ring;
198     }
199     rings.clear();
200     for (unsigned int i = 0; i < bonds.size(); i++) {
201         for (auto& bond : bonds) {
202             bond->_SSSRVisited = false;
203             bond->_SSSRParent = nullptr;
204             bond->_SSSRParentAtStart = true;
205         }
206 
207         sketcherMinimizerBond* bond = bonds[i];
208 
209         std::queue<sketcherMinimizerBond*> q;
210         bond->_SSSRVisited = true;
211         q.push(bond);
212         bool closedRing = false;
213         while (!q.empty() && !closedRing) {
214             sketcherMinimizerBond* lastBond = q.front();
215             q.pop();
216 
217             sketcherMinimizerAtom* pivotAtom = lastBond->endAtom;
218             if (!lastBond->_SSSRParentAtStart) {
219                 pivotAtom = lastBond->startAtom;
220             }
221             for (unsigned int j = 0; j < pivotAtom->bonds.size(); j++) {
222                 sketcherMinimizerBond* nextBond = pivotAtom->bonds[j];
223                 // sketcherMinimizerAtom *nextAtom = pivotAtom->neighbors[j];
224                 if (nextBond == lastBond) {
225                     continue;
226                 }
227                 if (nextBond->_SSSRVisited) {
228                     if (nextBond == bond) {
229                         addRing(closeRing(lastBond), rings);
230                         closedRing = true;
231                     }
232 
233                 } else {
234                     if (nextBond->endAtom == pivotAtom) {
235                         nextBond->_SSSRParentAtStart = false;
236                     }
237                     nextBond->_SSSRParent = lastBond;
238                     nextBond->_SSSRVisited = true;
239                     q.push(nextBond);
240                 }
241             }
242         }
243     }
244     for (auto ring : rings) {
245         for (unsigned int j = 0; j < ring->_bonds.size(); j++) {
246             sketcherMinimizerBond* bond = ring->_bonds[j];
247             bond->rings.push_back(ring);
248         }
249     }
250 }
251 
252 sketcherMinimizerRing*
closeRing(sketcherMinimizerBond * bond)253 sketcherMinimizerMolecule::closeRing(sketcherMinimizerBond* bond)
254 {
255     auto* ring = new sketcherMinimizerRing();
256     sketcherMinimizerBond* lastBond = bond;
257     while (lastBond) {
258         ring->_bonds.push_back(lastBond);
259         lastBond = lastBond->_SSSRParent;
260     }
261     return ring;
262 }
263 
addRing(sketcherMinimizerRing * ring,std::vector<sketcherMinimizerRing * > & rings)264 void sketcherMinimizerMolecule::addRing(
265     sketcherMinimizerRing* ring, std::vector<sketcherMinimizerRing*>& rings)
266 {
267     bool found = false;
268     for (auto& i : rings) {
269         if (i->sameAs(ring)) {
270             found = true;
271             break;
272         }
273     }
274     if (!found) {
275         rings.push_back(ring);
276     } else {
277         delete ring;
278     }
279 }
280