/src/openbabel/src/rotor.cpp
Line | Count | Source |
1 | | /********************************************************************** |
2 | | rotor.cpp - Rotate dihedral angles according to rotor rules. |
3 | | |
4 | | Copyright (C) 1998-2000 by OpenEye Scientific Software, Inc. |
5 | | Some portions Copyright (C) 2001-2006 by Geoffrey R. Hutchison |
6 | | |
7 | | This file is part of the Open Babel project. |
8 | | For more information, see <http://openbabel.org/> |
9 | | |
10 | | This program is free software; you can redistribute it and/or modify |
11 | | it under the terms of the GNU General Public License as published by |
12 | | the Free Software Foundation version 2 of the License. |
13 | | |
14 | | This program is distributed in the hope that it will be useful, |
15 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | GNU General Public License for more details. |
18 | | ***********************************************************************/ |
19 | | |
20 | | #include <openbabel/babelconfig.h> |
21 | | |
22 | | #include <openbabel/mol.h> |
23 | | #include <openbabel/bond.h> |
24 | | #include <openbabel/ring.h> |
25 | | #include <openbabel/obiter.h> |
26 | | #include <openbabel/oberror.h> |
27 | | #include <openbabel/rotor.h> |
28 | | #include <openbabel/graphsym.h> |
29 | | #include <openbabel/elements.h> |
30 | | |
31 | | #include <set> |
32 | | #include <cassert> |
33 | | |
34 | | // private data headers with default parameters |
35 | | #include "torlib.h" |
36 | | |
37 | | #ifndef M_PI |
38 | | #define M_PI 3.14159265358979323846 |
39 | | #endif |
40 | | |
41 | | |
42 | | using namespace std; |
43 | | namespace OpenBabel |
44 | | { |
45 | | |
46 | | //! Default step resolution for a dihedral angle (in degrees) |
47 | 0 | #define OB_DEFAULT_DELTA 15.0 |
48 | | static bool GetDFFVector(OBMol&,vector<int>&,OBBitVec&); |
49 | | static bool CompareRotor(const pair<OBBond*,int>&,const pair<OBBond*,int>&); |
50 | | |
51 | | |
52 | | //************************************** |
53 | | //**** OBRotorList Member Functions **** |
54 | | //************************************** |
55 | | |
56 | | bool OBRotorList::Setup(OBMol &mol, bool sampleRingBonds) |
57 | 0 | { |
58 | 0 | Clear(); |
59 | | // find the rotatable bonds |
60 | 0 | FindRotors(mol, sampleRingBonds); |
61 | 0 | if (!Size()) |
62 | 0 | return(false); |
63 | | |
64 | | // set the atoms that should be evaluated when this rotor changes |
65 | 0 | SetEvalAtoms(mol); |
66 | 0 | AssignTorVals(mol); |
67 | |
|
68 | 0 | OBRotor *rotor; |
69 | 0 | vector<OBRotor*>::iterator i; |
70 | 0 | for (rotor = BeginRotor(i);rotor;rotor = NextRotor(i)) |
71 | 0 | if (!rotor->Size()) |
72 | 0 | { |
73 | 0 | int ref[4]; |
74 | 0 | rotor->GetDihedralAtoms(ref); |
75 | 0 | char buffer[BUFF_SIZE]; |
76 | 0 | snprintf(buffer, BUFF_SIZE, "The rotor has no associated torsion values -> %d %d %d %d", |
77 | 0 | ref[0],ref[1],ref[2],ref[3]); |
78 | 0 | obErrorLog.ThrowError(__FUNCTION__, buffer, obDebug); |
79 | 0 | } |
80 | | |
81 | | // Reduce the number of torsions to be checked through symmetry considerations |
82 | 0 | if (_removesym) |
83 | 0 | RemoveSymVals(mol); |
84 | |
|
85 | 0 | return(true); |
86 | 0 | } |
87 | | |
88 | | bool OBRotorList::FindRotors(OBMol &mol, bool sampleRingBonds) |
89 | 0 | { |
90 | | // Find ring atoms & bonds |
91 | | // This function will set OBBond::IsRotor(). |
92 | 0 | mol.FindRingAtomsAndBonds(); |
93 | |
|
94 | 0 | obErrorLog.ThrowError(__FUNCTION__, |
95 | 0 | "Ran OpenBabel::FindRotors", obAuditMsg); |
96 | | |
97 | | // |
98 | | // Score the bonds using the graph theoretical distance (GTD). |
99 | | // The GTD is the distance from atom i to every other atom j. |
100 | | // Atoms on the "inside" of the molecule will have a lower GTD |
101 | | // value than atoms on the "outside" |
102 | | // |
103 | | // The scoring will rank "inside" bonds first. |
104 | | // |
105 | 0 | vector<int> gtd; |
106 | 0 | mol.GetGTDVector(gtd); |
107 | | // compute the scores |
108 | 0 | vector<OBBond*>::iterator i; |
109 | 0 | vector<pair<OBBond*,int> > vtmp; |
110 | 0 | for (OBBond *bond = mol.BeginBond(i);bond;bond = mol.NextBond(i)) { |
111 | | // check if the bond is "rotatable" |
112 | 0 | if (bond->IsRotor(sampleRingBonds)) { |
113 | | // check if the bond is fixed (using deprecated fixed atoms or new fixed bonds) |
114 | 0 | if ((HasFixedAtoms() || HasFixedBonds()) && IsFixedBond(bond)) |
115 | 0 | continue; |
116 | | |
117 | 0 | if (bond->IsInRing()) { |
118 | | //otherwise mark that we have them and add it to the pile |
119 | 0 | _ringRotors = true; |
120 | 0 | } |
121 | |
|
122 | 0 | int score = gtd[bond->GetBeginAtomIdx()-1] + gtd[bond->GetEndAtomIdx()-1]; |
123 | | // compute the GTD bond score as sum of atom GTD scores |
124 | 0 | vtmp.push_back(pair<OBBond*,int> (bond,score)); |
125 | 0 | } |
126 | 0 | } |
127 | | |
128 | | // sort the rotatable bonds by GTD score |
129 | 0 | sort(vtmp.begin(),vtmp.end(),CompareRotor); |
130 | | |
131 | | // create rotors for the bonds |
132 | 0 | int count = 0; |
133 | 0 | vector<pair<OBBond*,int> >::iterator j; |
134 | 0 | for (j = vtmp.begin(); j != vtmp.end(); ++j, ++count) { |
135 | 0 | OBRotor *rotor = new OBRotor; |
136 | 0 | rotor->SetBond((*j).first); |
137 | 0 | rotor->SetIdx(count); |
138 | 0 | rotor->SetNumCoords(mol.NumAtoms()*3); |
139 | 0 | _rotor.push_back(rotor); |
140 | 0 | } |
141 | |
|
142 | 0 | return true; |
143 | 0 | } |
144 | | |
145 | | bool OBRotorList::IsFixedBond(OBBond *bond) |
146 | 0 | { |
147 | 0 | if (_fixedatoms.IsEmpty() && _fixedbonds.IsEmpty()) |
148 | 0 | return false; |
149 | | |
150 | | // new fixed bonds |
151 | 0 | if (!_fixedbonds.IsEmpty()) { |
152 | 0 | return _fixedbonds.BitIsSet(bond->GetIdx()); |
153 | 0 | } |
154 | | |
155 | 0 | if (_fixedatoms.IsEmpty()) |
156 | 0 | return false; |
157 | | |
158 | | // deprecated fixed atoms |
159 | 0 | OBAtom *a1,*a2,*a3; |
160 | 0 | vector<OBBond*>::iterator i; |
161 | |
|
162 | 0 | a1 = bond->GetBeginAtom(); |
163 | 0 | a2 = bond->GetEndAtom(); |
164 | 0 | if (!_fixedatoms[a1->GetIdx()] || !_fixedatoms[a2->GetIdx()]) |
165 | 0 | return(false); |
166 | | |
167 | 0 | bool isfixed=false; |
168 | 0 | for (a3 = a1->BeginNbrAtom(i);a3;a3 = a1->NextNbrAtom(i)) |
169 | 0 | if (a3 != a2 && _fixedatoms[a3->GetIdx()]) |
170 | 0 | { |
171 | 0 | isfixed = true; |
172 | 0 | break; |
173 | 0 | } |
174 | |
|
175 | 0 | if (!isfixed) |
176 | 0 | return(false); |
177 | | |
178 | 0 | isfixed = false; |
179 | 0 | for (a3 = a2->BeginNbrAtom(i);a3;a3 = a2->NextNbrAtom(i)) |
180 | 0 | if (a3 != a1 && _fixedatoms[a3->GetIdx()]) |
181 | 0 | { |
182 | 0 | isfixed = true; |
183 | 0 | break; |
184 | 0 | } |
185 | |
|
186 | 0 | return(isfixed); |
187 | 0 | } |
188 | | |
189 | | bool GetDFFVector(OBMol &mol,vector<int> &dffv,OBBitVec &bv) |
190 | 0 | { |
191 | 0 | dffv.clear(); |
192 | 0 | dffv.resize(mol.NumAtoms()); |
193 | |
|
194 | 0 | int dffcount,natom; |
195 | 0 | OBBitVec used,curr,next; |
196 | 0 | OBAtom *atom,*atom1; |
197 | 0 | OBBond *bond; |
198 | 0 | vector<OBAtom*>::iterator i; |
199 | 0 | vector<OBBond*>::iterator j; |
200 | |
|
201 | 0 | next.Clear(); |
202 | |
|
203 | 0 | for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) |
204 | 0 | { |
205 | 0 | if (bv[atom->GetIdx()]) |
206 | 0 | { |
207 | 0 | dffv[atom->GetIdx()-1] = 0; |
208 | 0 | continue; |
209 | 0 | } |
210 | | |
211 | 0 | dffcount = 0; |
212 | 0 | used.Clear(); |
213 | 0 | curr.Clear(); |
214 | 0 | used.SetBitOn(atom->GetIdx()); |
215 | 0 | curr.SetBitOn(atom->GetIdx()); |
216 | |
|
217 | 0 | while (!curr.IsEmpty() && (bv&curr).IsEmpty()) |
218 | 0 | { |
219 | 0 | next.Clear(); |
220 | 0 | for (natom = curr.NextBit(-1);natom != curr.EndBit();natom = curr.NextBit(natom)) |
221 | 0 | { |
222 | 0 | atom1 = mol.GetAtom(natom); |
223 | 0 | for (bond = atom1->BeginBond(j);bond;bond = atom1->NextBond(j)) |
224 | 0 | if (!used.BitIsSet(bond->GetNbrAtomIdx(atom1)) && |
225 | 0 | !curr.BitIsSet(bond->GetNbrAtomIdx(atom1))) |
226 | 0 | if (bond->GetNbrAtom(atom1)->GetAtomicNum() != OBElements::Hydrogen) |
227 | 0 | next.SetBitOn(bond->GetNbrAtomIdx(atom1)); |
228 | 0 | } |
229 | |
|
230 | 0 | used |= next; |
231 | 0 | curr = next; |
232 | 0 | dffcount++; |
233 | 0 | } |
234 | |
|
235 | 0 | dffv[atom->GetIdx()-1] = dffcount; |
236 | 0 | } |
237 | |
|
238 | 0 | return(true); |
239 | 0 | } |
240 | | |
241 | | void OBRotorList::RemoveSymVals(OBMol &mol) |
242 | 0 | { |
243 | 0 | OBGraphSym gs(&mol); |
244 | 0 | vector<unsigned int> sym_classes; |
245 | 0 | gs.GetSymmetry(sym_classes); |
246 | |
|
247 | 0 | OBRotor *rotor; |
248 | 0 | vector<OBRotor*>::iterator i; |
249 | 0 | std::set<unsigned int> syms; |
250 | 0 | for (rotor = BeginRotor(i);rotor;rotor = NextRotor(i)) { |
251 | 0 | OBBond* bond = rotor->GetBond(); |
252 | 0 | OBAtom* end = bond->GetEndAtom(); |
253 | 0 | OBAtom* begin = bond->GetBeginAtom(); |
254 | 0 | int N_fold_symmetry = 1; |
255 | 0 | for (int here=0; here <= 1; ++here) { // Try each side of the bond in turn |
256 | |
|
257 | 0 | OBAtom *this_side, *other_side; |
258 | 0 | if (here == 0) { |
259 | 0 | this_side = begin; other_side = end; |
260 | 0 | } |
261 | 0 | else { |
262 | 0 | this_side = end; other_side = begin; |
263 | 0 | } |
264 | |
|
265 | 0 | for (unsigned int hyb=2; hyb<=3; ++hyb) { // sp2 and sp3 carbons, with explicit Hs |
266 | 0 | if (this_side->GetAtomicNum() == 6 && this_side->GetHyb() == hyb && this_side->GetExplicitDegree() == (hyb + 1) ) { |
267 | 0 | syms.clear(); |
268 | 0 | FOR_NBORS_OF_ATOM(nbr, this_side) { |
269 | 0 | if ( &(*nbr) == other_side ) continue; |
270 | 0 | syms.insert(sym_classes[nbr->GetIdx() - 1]); |
271 | 0 | } |
272 | 0 | if (syms.size() == 1) // All of the rotated atoms have the same symmetry class |
273 | 0 | N_fold_symmetry *= hyb; |
274 | 0 | } |
275 | 0 | } |
276 | 0 | } |
277 | |
|
278 | 0 | if (N_fold_symmetry > 1) { |
279 | 0 | size_t old_size = rotor->Size(); |
280 | 0 | rotor->RemoveSymTorsionValues(N_fold_symmetry); |
281 | 0 | if (!_quiet) { |
282 | 0 | cout << "...." << N_fold_symmetry << "-fold symmetry at rotor between " << |
283 | 0 | begin->GetIdx() << " and " << end->GetIdx(); |
284 | 0 | cout << " - reduced from " << old_size << " to " << rotor->Size() << endl; |
285 | 0 | } |
286 | 0 | } |
287 | 0 | } |
288 | 0 | } |
289 | | |
290 | | bool OBRotorList::SetEvalAtoms(OBMol &mol) |
291 | 0 | { |
292 | 0 | int j; |
293 | 0 | OBBond *bond; |
294 | 0 | OBAtom *a1,*a2; |
295 | 0 | OBRotor *rotor; |
296 | 0 | vector<OBRotor*>::iterator i; |
297 | 0 | OBBitVec eval,curr,next; |
298 | 0 | vector<OBBond*>::iterator k; |
299 | |
|
300 | 0 | for (rotor = BeginRotor(i);rotor;rotor = NextRotor(i)) |
301 | 0 | { |
302 | 0 | bond = rotor->GetBond(); |
303 | 0 | curr.Clear(); |
304 | 0 | eval.Clear(); |
305 | 0 | curr.SetBitOn(bond->GetBeginAtomIdx()); |
306 | 0 | curr.SetBitOn(bond->GetEndAtomIdx()); |
307 | 0 | eval |= curr; |
308 | | |
309 | | //follow all non-rotor bonds and add atoms to eval list |
310 | 0 | for (;!curr.IsEmpty();) |
311 | 0 | { |
312 | 0 | next.Clear(); |
313 | 0 | for (j = curr.NextBit(0);j != curr.EndBit();j = curr.NextBit(j)) |
314 | 0 | { |
315 | 0 | a1 = mol.GetAtom(j); |
316 | 0 | for (a2 = a1->BeginNbrAtom(k);a2;a2 = a1->NextNbrAtom(k)) |
317 | 0 | if (!eval[a2->GetIdx()]) |
318 | 0 | if (!((OBBond*)*k)->IsRotor(_ringRotors)||((HasFixedAtoms()||HasFixedBonds())&&IsFixedBond((OBBond*)*k))) |
319 | 0 | { |
320 | 0 | next.SetBitOn(a2->GetIdx()); |
321 | 0 | eval.SetBitOn(a2->GetIdx()); |
322 | 0 | } |
323 | 0 | } |
324 | 0 | curr = next; |
325 | 0 | } |
326 | | |
327 | | //add atoms alpha to eval list |
328 | 0 | next.Clear(); |
329 | 0 | for (j = eval.NextBit(0);j != eval.EndBit();j = eval.NextBit(j)) |
330 | 0 | { |
331 | 0 | a1 = mol.GetAtom(j); |
332 | 0 | for (a2 = a1->BeginNbrAtom(k);a2;a2 = a1->NextNbrAtom(k)) |
333 | 0 | next.SetBitOn(a2->GetIdx()); |
334 | 0 | } |
335 | 0 | eval |= next; |
336 | 0 | rotor->SetEvalAtoms(eval); |
337 | 0 | } |
338 | |
|
339 | 0 | return(true); |
340 | 0 | } |
341 | | |
342 | | bool OBRotorList::AssignTorVals(OBMol &mol) |
343 | 0 | { |
344 | 0 | vector<OBRotor*>::iterator i; |
345 | 0 | for (i = _rotor.begin(); i != _rotor.end(); ++i) { |
346 | 0 | OBRotor *rotor = *i; |
347 | 0 | OBBond *bond = rotor->GetBond(); |
348 | | |
349 | | // query the rotor database |
350 | 0 | int ref[4]; |
351 | 0 | vector<double> angles; |
352 | 0 | double delta; |
353 | 0 | _rr.GetRotorIncrements(mol, bond, ref, angles, delta); |
354 | 0 | rotor->SetTorsionValues(angles); |
355 | 0 | rotor->SetDelta(delta); |
356 | | |
357 | | // Find the smallest set of atoms to rotate. There are two candidate sets, |
358 | | // one on either side of the bond. If the first tried set size plus one is |
359 | | // larger than half of the number of atoms, the other set is smaller and the |
360 | | // rotor atom indexes are inverted (.i.e. a-b-c-d -> d-c-b-a). |
361 | 0 | vector<int> atoms; |
362 | 0 | vector<int>::iterator j; |
363 | | // find all atoms for which there is a path to ref[2] without goinf through ref[1] |
364 | 0 | mol.FindChildren(atoms, ref[1], ref[2]); |
365 | 0 | if (atoms.size() + 1 > mol.NumAtoms() / 2) { |
366 | 0 | atoms.clear(); |
367 | | // select the other smaller set |
368 | 0 | mol.FindChildren(atoms, ref[2], ref[1]); |
369 | | // invert the rotor |
370 | 0 | swap(ref[0],ref[3]); |
371 | 0 | swap(ref[1],ref[2]); |
372 | 0 | } |
373 | | |
374 | | // translate the rotate atom indexes to coordinate indexes (i.e. from 0, multiplied by 3) |
375 | 0 | for (j = atoms.begin(); j != atoms.end(); ++j) |
376 | 0 | *j = ((*j) - 1) * 3; |
377 | | // set the rotate atoms and dihedral atom indexes |
378 | 0 | rotor->SetRotAtoms(atoms); |
379 | 0 | rotor->SetDihedralAtoms(ref); |
380 | 0 | } |
381 | |
|
382 | 0 | return true; |
383 | 0 | } |
384 | | |
385 | | bool OBRotorList::SetRotAtoms(OBMol &mol) |
386 | 0 | { |
387 | 0 | OBRotor *rotor; |
388 | 0 | vector<int> rotatoms; |
389 | 0 | vector<OBRotor*>::iterator i; |
390 | |
|
391 | 0 | int ref[4]; |
392 | 0 | vector<int>::iterator j; |
393 | 0 | for (rotor = BeginRotor(i);rotor;rotor = NextRotor(i)) |
394 | 0 | { |
395 | 0 | rotor->GetDihedralAtoms(ref); |
396 | |
|
397 | 0 | mol.FindChildren(rotatoms,ref[1],ref[2]); |
398 | 0 | if (rotatoms.size()+1 > mol.NumAtoms()/2) |
399 | 0 | { |
400 | 0 | rotatoms.clear(); |
401 | 0 | mol.FindChildren(rotatoms,ref[2],ref[1]); |
402 | 0 | swap(ref[0],ref[3]); |
403 | 0 | swap(ref[1],ref[2]); |
404 | 0 | } |
405 | |
|
406 | 0 | for (j = rotatoms.begin();j != rotatoms.end();++j) |
407 | 0 | *j = ((*j)-1)*3; |
408 | 0 | rotor->SetRotAtoms(rotatoms); |
409 | 0 | rotor->SetDihedralAtoms(ref); |
410 | 0 | } |
411 | |
|
412 | 0 | return(true); |
413 | 0 | } |
414 | | |
415 | | void OBRotorList::SetRotAtomsByFix(OBMol &mol) |
416 | 0 | { |
417 | 0 | int ref[4]; |
418 | 0 | OBRotor *rotor; |
419 | 0 | vector<int> rotatoms; |
420 | 0 | vector<int>::iterator j; |
421 | 0 | vector<OBRotor*>::iterator i; |
422 | |
|
423 | 0 | GetDFFVector(mol,_dffv,_fixedatoms); |
424 | |
|
425 | 0 | for (rotor = BeginRotor(i);rotor;rotor = NextRotor(i)) |
426 | 0 | { |
427 | 0 | rotatoms.clear(); |
428 | 0 | rotor->GetDihedralAtoms(ref); |
429 | |
|
430 | 0 | if (_fixedatoms[ref[1]] && _fixedatoms[ref[2]]) |
431 | 0 | { |
432 | 0 | if (!_fixedatoms[ref[0]]) |
433 | 0 | { |
434 | 0 | swap(ref[0],ref[3]); |
435 | 0 | swap(ref[1],ref[2]); |
436 | 0 | mol.FindChildren(rotatoms,ref[1],ref[2]); |
437 | 0 | for (j = rotatoms.begin();j != rotatoms.end();++j) |
438 | 0 | *j = ((*j)-1)*3; |
439 | 0 | rotor->SetRotAtoms(rotatoms); |
440 | 0 | rotor->SetDihedralAtoms(ref); |
441 | 0 | } |
442 | 0 | } |
443 | 0 | else |
444 | 0 | if (_dffv[ref[1]-1] > _dffv[ref[2]-1]) |
445 | 0 | { |
446 | 0 | swap(ref[0],ref[3]); |
447 | 0 | swap(ref[1],ref[2]); |
448 | 0 | mol.FindChildren(rotatoms,ref[1],ref[2]); |
449 | 0 | for (j = rotatoms.begin();j != rotatoms.end();++j) |
450 | 0 | *j = ((*j)-1)*3; |
451 | 0 | rotor->SetRotAtoms(rotatoms); |
452 | 0 | rotor->SetDihedralAtoms(ref); |
453 | 0 | } |
454 | 0 | } |
455 | 0 | } |
456 | | |
457 | | OBRotorList::OBRotorList() |
458 | 0 | { |
459 | 0 | _rotor.clear(); |
460 | 0 | _quiet = true; |
461 | 0 | _removesym = true; |
462 | 0 | _ringRotors = false; |
463 | 0 | } |
464 | | |
465 | | OBRotorList::~OBRotorList() |
466 | 0 | { |
467 | 0 | vector<OBRotor*>::iterator i; |
468 | 0 | for (i = _rotor.begin();i != _rotor.end();++i) |
469 | 0 | delete *i; |
470 | 0 | } |
471 | | |
472 | | void OBRotorList::Clear() |
473 | 0 | { |
474 | 0 | vector<OBRotor*>::iterator i; |
475 | 0 | for (i = _rotor.begin();i != _rotor.end();++i) |
476 | 0 | delete *i; |
477 | 0 | _rotor.clear(); |
478 | 0 | _ringRotors = false; |
479 | | //_fix.Clear(); |
480 | 0 | } |
481 | | |
482 | | bool CompareRotor(const pair<OBBond*,int> &a,const pair<OBBond*,int> &b) |
483 | 0 | { |
484 | | //return(a.second > b.second); //outside->in |
485 | 0 | return(a.second < b.second); //inside->out |
486 | 0 | } |
487 | | |
488 | | //********************************** |
489 | | //**** OBRotor Member Functions **** |
490 | | //********************************** |
491 | | |
492 | | OBRotor::OBRotor() |
493 | 0 | { |
494 | 0 | } |
495 | | |
496 | | void OBRotor::SetRings() |
497 | 0 | { |
498 | 0 | _rings.clear(); |
499 | 0 | if (_bond == nullptr) |
500 | 0 | return; // nothing to do |
501 | | |
502 | 0 | vector<OBRing*> rlist; |
503 | 0 | vector<OBRing*>::iterator i; |
504 | |
|
505 | 0 | OBMol *mol = _bond->GetParent(); |
506 | |
|
507 | 0 | if (mol == nullptr) |
508 | 0 | return; // nothing to do |
509 | | |
510 | 0 | rlist = mol->GetSSSR(); |
511 | 0 | for (i = rlist.begin();i != rlist.end();++i) { |
512 | 0 | if ((*i)->IsMember(_bond)) |
513 | 0 | _rings.push_back(*i); |
514 | 0 | } |
515 | 0 | } |
516 | | |
517 | | double OBRotor::CalcTorsion(double *c) |
518 | 0 | { |
519 | 0 | double v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z; |
520 | 0 | double c1x,c1y,c1z,c2x,c2y,c2z,c3x,c3y,c3z; |
521 | 0 | double c1mag,c2mag,ang,costheta; |
522 | | |
523 | | // |
524 | | //calculate the torsion angle |
525 | | // |
526 | 0 | v1x = c[_torsion[0]] - c[_torsion[1]]; |
527 | 0 | v1y = c[_torsion[0]+1] - c[_torsion[1]+1]; |
528 | 0 | v1z = c[_torsion[0]+2] - c[_torsion[1]+2]; |
529 | 0 | v2x = c[_torsion[1]] - c[_torsion[2]]; |
530 | 0 | v2y = c[_torsion[1]+1] - c[_torsion[2]+1]; |
531 | 0 | v2z = c[_torsion[1]+2] - c[_torsion[2]+2]; |
532 | 0 | v3x = c[_torsion[2]] - c[_torsion[3]]; |
533 | 0 | v3y = c[_torsion[2]+1] - c[_torsion[3]+1]; |
534 | 0 | v3z = c[_torsion[2]+2] - c[_torsion[3]+2]; |
535 | |
|
536 | 0 | c1x = v1y*v2z - v1z*v2y; |
537 | 0 | c2x = v2y*v3z - v2z*v3y; |
538 | 0 | c1y = -v1x*v2z + v1z*v2x; |
539 | 0 | c2y = -v2x*v3z + v2z*v3x; |
540 | 0 | c1z = v1x*v2y - v1y*v2x; |
541 | 0 | c2z = v2x*v3y - v2y*v3x; |
542 | 0 | c3x = c1y*c2z - c1z*c2y; |
543 | 0 | c3y = -c1x*c2z + c1z*c2x; |
544 | 0 | c3z = c1x*c2y - c1y*c2x; |
545 | |
|
546 | 0 | c1mag = SQUARE(c1x)+SQUARE(c1y)+SQUARE(c1z); |
547 | 0 | c2mag = SQUARE(c2x)+SQUARE(c2y)+SQUARE(c2z); |
548 | 0 | if (c1mag*c2mag < 0.01) |
549 | 0 | costheta = 1.0; //avoid div by zero error |
550 | 0 | else |
551 | 0 | costheta = (c1x*c2x + c1y*c2y + c1z*c2z)/(sqrt(c1mag*c2mag)); |
552 | |
|
553 | 0 | if (costheta < -0.9999999) |
554 | 0 | costheta = -0.9999999; |
555 | 0 | if (costheta > 0.9999999) |
556 | 0 | costheta = 0.9999999; |
557 | |
|
558 | 0 | if ((v2x*c3x + v2y*c3y + v2z*c3z) > 0.0) |
559 | 0 | ang = -acos(costheta); |
560 | 0 | else |
561 | 0 | ang = acos(costheta); |
562 | |
|
563 | 0 | return(ang); |
564 | 0 | } |
565 | | |
566 | | double OBRotor::CalcBondLength(double *c) |
567 | 0 | { |
568 | | // compute the difference |
569 | 0 | double dx, dy, dz; |
570 | 0 | dx = c[_torsion[1] ] - c[_torsion[2] ]; |
571 | 0 | dy = c[_torsion[1]+1] - c[_torsion[2]+1]; |
572 | 0 | dz = c[_torsion[1]+2] - c[_torsion[2]+2]; |
573 | | // compute the length |
574 | 0 | return sqrt(SQUARE(dx) + SQUARE(dy) + SQUARE(dz)); |
575 | 0 | } |
576 | | |
577 | | |
578 | | void OBRotor::SetRotor(double *c,int idx,int prev) |
579 | 0 | { |
580 | 0 | double ang,sn,cs,t,dx,dy,dz,mag; |
581 | |
|
582 | 0 | if (prev == -1) |
583 | 0 | ang = _torsionAngles[idx] - CalcTorsion(c); |
584 | 0 | else |
585 | 0 | ang = _torsionAngles[idx] - _torsionAngles[prev]; |
586 | |
|
587 | 0 | sn = sin(ang); |
588 | 0 | cs = cos(ang); |
589 | 0 | t = 1 - cs; |
590 | |
|
591 | 0 | dx = c[_torsion[1]] - c[_torsion[2]]; |
592 | 0 | dy = c[_torsion[1]+1] - c[_torsion[2]+1]; |
593 | 0 | dz = c[_torsion[1]+2] - c[_torsion[2]+2]; |
594 | 0 | mag = sqrt(SQUARE(dx) + SQUARE(dy) + SQUARE(dz)); |
595 | |
|
596 | 0 | Set(c,sn,cs,t,1.0/mag); |
597 | 0 | } |
598 | | |
599 | | // used in combination with Set(double *coordinates, int idx) |
600 | | void OBRotor::Precompute(double *coordinates) |
601 | 0 | { |
602 | 0 | _imag = 1.0 / CalcBondLength(coordinates); |
603 | 0 | _refang = CalcTorsion(coordinates); |
604 | 0 | } |
605 | | |
606 | | // used in combination with Precompute(double *coordinates) |
607 | | void OBRotor::Set(double *coordinates, int idx) |
608 | 0 | { |
609 | 0 | double ang,sn,cs,t; |
610 | | |
611 | | // compute the rotation angle |
612 | 0 | ang = _torsionAngles[idx] - _refang; |
613 | | // compute some values for the rotation matrix |
614 | 0 | sn = sin(ang); |
615 | 0 | cs = cos(ang); |
616 | 0 | t = 1 - cs; |
617 | |
|
618 | 0 | double x,y,z,tx,ty,tz,m[9]; |
619 | | |
620 | | // compute the bond vector |
621 | 0 | x = coordinates[_torsion[1]] - coordinates[_torsion[2]]; |
622 | 0 | y = coordinates[_torsion[1]+1] - coordinates[_torsion[2]+1]; |
623 | 0 | z = coordinates[_torsion[1]+2] - coordinates[_torsion[2]+2]; |
624 | | |
625 | | // normalize the bond vector |
626 | 0 | x *= _imag; |
627 | 0 | y *= _imag; |
628 | 0 | z *= _imag; |
629 | | |
630 | | // set up the rotation matrix |
631 | 0 | tx = t*x; |
632 | 0 | ty = t*y; |
633 | 0 | tz = t*z; |
634 | 0 | m[0]= tx*x + cs; |
635 | 0 | m[1] = tx*y + sn*z; |
636 | 0 | m[2] = tx*z - sn*y; |
637 | 0 | m[3] = tx*y - sn*z; |
638 | 0 | m[4] = ty*y + cs; |
639 | 0 | m[5] = ty*z + sn*x; |
640 | 0 | m[6] = tx*z + sn*y; |
641 | 0 | m[7] = ty*z - sn*x; |
642 | 0 | m[8] = tz*z + cs; |
643 | | |
644 | | // |
645 | | //now the matrix is set - time to rotate the atoms |
646 | | // |
647 | 0 | tx = coordinates[_torsion[1]]; |
648 | 0 | ty = coordinates[_torsion[1]+1]; |
649 | 0 | tz = coordinates[_torsion[1]+2]; |
650 | 0 | unsigned int i, j; |
651 | 0 | for (i = 0; i < _rotatoms.size(); ++i) |
652 | 0 | { |
653 | 0 | j = _rotatoms[i]; |
654 | 0 | coordinates[j] -= tx; |
655 | 0 | coordinates[j+1] -= ty; |
656 | 0 | coordinates[j+2]-= tz; |
657 | 0 | x = coordinates[j]*m[0] + coordinates[j+1]*m[1] + coordinates[j+2]*m[2]; |
658 | 0 | y = coordinates[j]*m[3] + coordinates[j+1]*m[4] + coordinates[j+2]*m[5]; |
659 | 0 | z = coordinates[j]*m[6] + coordinates[j+1]*m[7] + coordinates[j+2]*m[8]; |
660 | 0 | coordinates[j] = x+tx; |
661 | 0 | coordinates[j+1] = y+ty; |
662 | 0 | coordinates[j+2] = z+tz; |
663 | 0 | } |
664 | 0 | } |
665 | | |
666 | | // used in combination with Set |
667 | | void OBRotor::Precalc(vector<double*> &cv) |
668 | 0 | { |
669 | 0 | double *c,ang; |
670 | 0 | vector<double*>::iterator i; |
671 | 0 | vector<double>::iterator j; |
672 | 0 | vector<double> cs,sn,t; |
673 | 0 | for (i = cv.begin();i != cv.end();++i) |
674 | 0 | { |
675 | 0 | c = *i; |
676 | 0 | cs.clear(); |
677 | 0 | sn.clear(); |
678 | 0 | t.clear(); |
679 | 0 | ang = CalcTorsion(c); |
680 | |
|
681 | 0 | for (j = _torsionAngles.begin();j != _torsionAngles.end();++j) |
682 | 0 | { |
683 | 0 | cs.push_back(cos(*j-ang)); |
684 | 0 | sn.push_back(sin(*j-ang)); |
685 | 0 | t.push_back(1 - cos(*j-ang)); |
686 | 0 | } |
687 | |
|
688 | 0 | _cs.push_back(cs); |
689 | 0 | _sn.push_back(sn); |
690 | 0 | _t.push_back(t); |
691 | 0 | _invmag.push_back(1.0/CalcBondLength(c)); |
692 | 0 | } |
693 | 0 | } |
694 | | |
695 | | |
696 | | void OBRotor::Set(double *c,double sn,double cs,double t,double invmag) |
697 | 0 | { |
698 | 0 | double x,y,z,tx,ty,tz,m[9]; |
699 | |
|
700 | 0 | x = c[_torsion[1]] - c[_torsion[2]]; |
701 | 0 | y = c[_torsion[1]+1] - c[_torsion[2]+1]; |
702 | 0 | z = c[_torsion[1]+2] - c[_torsion[2]+2]; |
703 | | |
704 | | //normalize the rotation vector |
705 | |
|
706 | 0 | x *= invmag; |
707 | 0 | y *= invmag; |
708 | 0 | z *= invmag; |
709 | | |
710 | | //set up the rotation matrix |
711 | 0 | tx = t*x; |
712 | 0 | ty = t*y; |
713 | 0 | tz = t*z; |
714 | 0 | m[0]= tx*x + cs; |
715 | 0 | m[1] = tx*y + sn*z; |
716 | 0 | m[2] = tx*z - sn*y; |
717 | 0 | m[3] = tx*y - sn*z; |
718 | 0 | m[4] = ty*y + cs; |
719 | 0 | m[5] = ty*z + sn*x; |
720 | 0 | m[6] = tx*z + sn*y; |
721 | 0 | m[7] = ty*z - sn*x; |
722 | 0 | m[8] = tz*z + cs; |
723 | | |
724 | | // |
725 | | //now the matrix is set - time to rotate the atoms |
726 | | // |
727 | 0 | tx = c[_torsion[1]]; |
728 | 0 | ty = c[_torsion[1]+1]; |
729 | 0 | tz = c[_torsion[1]+2]; |
730 | 0 | unsigned int i, j; |
731 | 0 | for (i = 0; i < _rotatoms.size(); ++i) |
732 | 0 | { |
733 | 0 | j = _rotatoms[i]; |
734 | 0 | c[j] -= tx; |
735 | 0 | c[j+1] -= ty; |
736 | 0 | c[j+2]-= tz; |
737 | 0 | x = c[j]*m[0] + c[j+1]*m[1] + c[j+2]*m[2]; |
738 | 0 | y = c[j]*m[3] + c[j+1]*m[4] + c[j+2]*m[5]; |
739 | 0 | z = c[j]*m[6] + c[j+1]*m[7] + c[j+2]*m[8]; |
740 | 0 | c[j] = x+tx; |
741 | 0 | c[j+1] = y+ty; |
742 | 0 | c[j+2] = z+tz; |
743 | 0 | } |
744 | 0 | } |
745 | | |
746 | | //! Remove all torsions angles between 0 and 360/fold |
747 | | void OBRotor::RemoveSymTorsionValues(int fold) |
748 | 0 | { |
749 | 0 | vector<double>::iterator i; |
750 | 0 | vector<double> tv; |
751 | 0 | if (_torsionAngles.size() == 1) |
752 | 0 | return; |
753 | | |
754 | 0 | for (i = _torsionAngles.begin();i != _torsionAngles.end();++i) |
755 | 0 | if (*i >= 0.0 && *i < 2.0*M_PI / fold) |
756 | 0 | tv.push_back(*i); |
757 | |
|
758 | 0 | if (tv.empty()) |
759 | 0 | return; |
760 | 0 | _torsionAngles = tv; |
761 | 0 | } |
762 | | |
763 | | void OBRotor::SetDihedralAtoms(std::vector<int> &ref) |
764 | 0 | { |
765 | 0 | if (ref.size() != 4) |
766 | 0 | return; |
767 | | // copy indexes starting from 1 |
768 | 0 | _ref.resize(4); |
769 | 0 | for (int i = 0;i < 4;++i) |
770 | 0 | _ref[i] = ref[i]; |
771 | 0 | _torsion.resize(4); |
772 | | // convert the indexes (start from 0, multiplied by 3) for easy access to coordinates |
773 | 0 | _torsion[0] = (ref[0]-1)*3; |
774 | 0 | _torsion[1] = (ref[1]-1)*3; |
775 | 0 | _torsion[2] = (ref[2]-1)*3; |
776 | 0 | _torsion[3] = (ref[3]-1)*3; |
777 | 0 | } |
778 | | |
779 | | void OBRotor::SetDihedralAtoms(int ref[4]) |
780 | 0 | { |
781 | | // copy indexes starting from 1 |
782 | 0 | _ref.resize(4); |
783 | 0 | for (int i = 0;i < 4;++i) |
784 | 0 | _ref[i] = ref[i]; |
785 | 0 | _torsion.resize(4); |
786 | | // convert the indexes (start from 0, multiplied by 3) for easy access to coordinates |
787 | 0 | _torsion[0] = (ref[0]-1)*3; |
788 | 0 | _torsion[1] = (ref[1]-1)*3; |
789 | 0 | _torsion[2] = (ref[2]-1)*3; |
790 | 0 | _torsion[3] = (ref[3]-1)*3; |
791 | 0 | } |
792 | | |
793 | | void OBRotor::SetRotAtoms(vector<int> &vi) |
794 | 0 | { |
795 | 0 | _rotatoms = vi; |
796 | 0 | } |
797 | | |
798 | | //*************************************** |
799 | | //**** OBRotorRules Member functions **** |
800 | | //*************************************** |
801 | | OBRotorRules::OBRotorRules() |
802 | 0 | { |
803 | 0 | _quiet=false; |
804 | 0 | _init = false; |
805 | 0 | _dir = BABEL_DATADIR; |
806 | 0 | _envvar = "BABEL_DATADIR"; |
807 | 0 | _filename = "torlib.txt"; |
808 | 0 | _subdir = "data"; |
809 | 0 | _dataptr = TorsionDefaults; |
810 | 0 | } |
811 | | |
812 | | void OBRotorRules::ParseLine(const char *buffer) |
813 | 0 | { |
814 | 0 | int i; |
815 | 0 | int ref[4]; |
816 | 0 | double delta; |
817 | 0 | vector<double> vals; |
818 | 0 | vector<string> vs; |
819 | 0 | vector<string>::iterator j; |
820 | 0 | char temp_buffer[BUFF_SIZE]; |
821 | |
|
822 | 0 | if (buffer[0] == '#') |
823 | 0 | return; |
824 | 0 | tokenize(vs,buffer); |
825 | 0 | if (vs.empty()) |
826 | 0 | return; |
827 | | |
828 | 0 | if (EQn(buffer,"SP3-SP3",7)) |
829 | 0 | { |
830 | 0 | _sp3sp3.clear(); |
831 | | // assert (vs.size() > 1); |
832 | 0 | for (j = vs.begin(),++j;j != vs.end();++j) |
833 | 0 | _sp3sp3.push_back(DEG_TO_RAD*atof(j->c_str())); |
834 | 0 | return; |
835 | 0 | } |
836 | | |
837 | 0 | if (EQn(buffer,"SP3-SP2",7)) |
838 | 0 | { |
839 | 0 | _sp3sp2.clear(); |
840 | | // assert(vs.size() > 1); |
841 | 0 | for (j = vs.begin(),++j;j != vs.end();++j) |
842 | 0 | _sp3sp2.push_back(DEG_TO_RAD*atof(j->c_str())); |
843 | 0 | return; |
844 | 0 | } |
845 | | |
846 | 0 | if (EQn(buffer,"SP2-SP2",7)) |
847 | 0 | { |
848 | 0 | _sp2sp2.clear(); |
849 | | // assert(vs.size() > 1); |
850 | 0 | for (j = vs.begin(),++j;j != vs.end();++j) |
851 | 0 | _sp2sp2.push_back(DEG_TO_RAD*atof(j->c_str())); |
852 | 0 | return; |
853 | 0 | } |
854 | | |
855 | 0 | if (vs.size() > 5) |
856 | 0 | { |
857 | 0 | strncpy(temp_buffer,vs[0].c_str(), sizeof(temp_buffer) - 1); |
858 | 0 | temp_buffer[sizeof(temp_buffer) - 1] = '\0'; |
859 | | //reference atoms |
860 | 0 | for (i = 0;i < 4;++i) |
861 | 0 | ref[i] = atoi(vs[i+1].c_str())-1; |
862 | | //possible torsions |
863 | 0 | vals.clear(); |
864 | 0 | delta = OB_DEFAULT_DELTA; |
865 | 0 | for (i = 5;(unsigned)i < vs.size();++i) |
866 | 0 | { |
867 | 0 | if (i == (signed)(vs.size()-2) && vs[i] == "Delta") |
868 | 0 | { |
869 | 0 | delta = atof(vs[i+1].c_str()); |
870 | 0 | i += 2; |
871 | 0 | } |
872 | 0 | else |
873 | 0 | vals.push_back(DEG_TO_RAD*atof(vs[i].c_str())); |
874 | 0 | } |
875 | |
|
876 | 0 | if (vals.empty()) |
877 | 0 | { |
878 | 0 | string err = "The following rule has no associated torsions: "; |
879 | 0 | err += vs[0]; |
880 | 0 | obErrorLog.ThrowError(__FUNCTION__, err, obDebug); |
881 | 0 | } |
882 | 0 | OBRotorRule *rr = new OBRotorRule (temp_buffer,ref,vals,delta); |
883 | 0 | if (rr->IsValid()) |
884 | 0 | _vr.push_back(rr); |
885 | 0 | else |
886 | 0 | delete rr; |
887 | 0 | } |
888 | |
|
889 | 0 | } |
890 | | |
891 | | void OBRotorRules::GetRotorIncrements(OBMol &mol,OBBond *bond, |
892 | | int ref[4],vector<double> &vals,double &delta) |
893 | 0 | { |
894 | 0 | if (!_init) |
895 | 0 | Init(); |
896 | |
|
897 | 0 | vals.clear(); |
898 | 0 | vector<pair<int,int> > vpr; |
899 | 0 | vpr.push_back(pair<int,int> (0,bond->GetBeginAtomIdx())); |
900 | 0 | vpr.push_back(pair<int,int> (0,bond->GetEndAtomIdx())); |
901 | |
|
902 | 0 | delta = OB_DEFAULT_DELTA; |
903 | |
|
904 | 0 | int j; |
905 | 0 | OBSmartsPattern *sp; |
906 | 0 | vector<vector<int> > map; |
907 | 0 | vector<OBRotorRule*>::iterator i; |
908 | 0 | for (i = _vr.begin();i != _vr.end();++i) |
909 | 0 | { |
910 | 0 | sp = (*i)->GetSmartsPattern(); |
911 | 0 | (*i)->GetReferenceAtoms(ref); |
912 | 0 | vpr[0].first = ref[1]; |
913 | 0 | vpr[1].first = ref[2]; |
914 | |
|
915 | 0 | if (!sp->RestrictedMatch(mol,vpr,true)) |
916 | 0 | { |
917 | 0 | swap(vpr[0].first,vpr[1].first); |
918 | 0 | if (!sp->RestrictedMatch(mol,vpr,true)) |
919 | 0 | continue; |
920 | 0 | } |
921 | | |
922 | 0 | map = sp->GetMapList(); |
923 | 0 | for (j = 0;j < 4;++j) |
924 | 0 | ref[j] = map[0][ref[j]]; |
925 | 0 | vals = (*i)->GetTorsionVals(); |
926 | 0 | delta = (*i)->GetDelta(); |
927 | |
|
928 | 0 | OBAtom *a1,*a2,*a3,*a4,*r; |
929 | 0 | a1 = mol.GetAtom(ref[0]); |
930 | 0 | a4 = mol.GetAtom(ref[3]); |
931 | 0 | if (a1->GetAtomicNum() == OBElements::Hydrogen && a4->GetAtomicNum() == OBElements::Hydrogen) |
932 | 0 | continue; //don't allow hydrogens at both ends |
933 | 0 | if (a1->GetAtomicNum() == OBElements::Hydrogen || a4->GetAtomicNum() == OBElements::Hydrogen) //need a heavy atom reference - can use hydrogen |
934 | 0 | { |
935 | 0 | bool swapped = false; |
936 | 0 | a2 = mol.GetAtom(ref[1]); |
937 | 0 | a3 = mol.GetAtom(ref[2]); |
938 | 0 | if (a4->GetAtomicNum() == OBElements::Hydrogen) |
939 | 0 | { |
940 | 0 | swap(a1,a4); |
941 | 0 | swap(a2,a3); |
942 | 0 | swapped = true; |
943 | 0 | } |
944 | |
|
945 | 0 | vector<OBBond*>::iterator k; |
946 | 0 | for (r = a2->BeginNbrAtom(k);r;r = a2->NextNbrAtom(k)) |
947 | 0 | if (r->GetAtomicNum() != OBElements::Hydrogen && r != a3) |
948 | 0 | break; |
949 | |
|
950 | 0 | if (!r) |
951 | 0 | continue; //unable to find reference heavy atom |
952 | | // cerr << "r = " << r->GetIdx() << endl; |
953 | | |
954 | 0 | double t1 = mol.GetTorsion(a1,a2,a3,a4); |
955 | 0 | double t2 = mol.GetTorsion(r,a2,a3,a4); |
956 | 0 | double diff = t2 - t1; |
957 | 0 | if (diff > 180.0) |
958 | 0 | diff -= 360.0; |
959 | 0 | if (diff < -180.0) |
960 | 0 | diff += 360.0; |
961 | 0 | diff *= DEG_TO_RAD; |
962 | |
|
963 | 0 | vector<double>::iterator m; |
964 | 0 | for (m = vals.begin();m != vals.end();++m) |
965 | 0 | { |
966 | 0 | *m += diff; |
967 | 0 | if (*m < M_PI) |
968 | 0 | *m += 2.0*M_PI; |
969 | 0 | if (*m > M_PI) |
970 | 0 | *m -= 2.0*M_PI; |
971 | 0 | } |
972 | |
|
973 | 0 | if (swapped) |
974 | 0 | ref[3] = r->GetIdx(); |
975 | 0 | else |
976 | 0 | ref[0] = r->GetIdx(); |
977 | | |
978 | | /* |
979 | | mol.SetTorsion(r,a2,a3,a4,vals[0]); |
980 | | cerr << "test = " << (vals[0]-diff)*RAD_TO_DEG << ' '; |
981 | | cerr << mol.GetTorsion(a1,a2,a3,a4) << ' '; |
982 | | cerr << mol.GetTorsion(r,a2,a3,a4) << endl; |
983 | | */ |
984 | 0 | } |
985 | | |
986 | 0 | char buffer[BUFF_SIZE]; |
987 | 0 | if (!_quiet) |
988 | 0 | { |
989 | 0 | snprintf(buffer,BUFF_SIZE,"%3d%3d%3d%3d %s", |
990 | 0 | ref[0],ref[1],ref[2],ref[3], |
991 | 0 | ((*i)->GetSmartsString()).c_str()); |
992 | 0 | obErrorLog.ThrowError(__FUNCTION__, buffer, obDebug); |
993 | 0 | } |
994 | 0 | return; |
995 | 0 | } |
996 | | |
997 | | //***didn't match any rules - assign based on hybridization*** |
998 | 0 | OBAtom *a1,*a2,*a3,*a4; |
999 | 0 | a2 = bond->GetBeginAtom(); |
1000 | 0 | a3 = bond->GetEndAtom(); |
1001 | 0 | vector<OBBond*>::iterator k; |
1002 | |
|
1003 | 0 | for (a1 = a2->BeginNbrAtom(k);a1;a1 = a2->NextNbrAtom(k)) |
1004 | 0 | if (a1->GetAtomicNum() != OBElements::Hydrogen && a1 != a3) |
1005 | 0 | break; |
1006 | 0 | for (a4 = a3->BeginNbrAtom(k);a4;a4 = a3->NextNbrAtom(k)) |
1007 | 0 | if (a4->GetAtomicNum() != OBElements::Hydrogen && a4 != a2) |
1008 | 0 | break; |
1009 | |
|
1010 | 0 | ref[0] = a1->GetIdx(); |
1011 | 0 | ref[1] = a2->GetIdx(); |
1012 | 0 | ref[2] = a3->GetIdx(); |
1013 | 0 | ref[3] = a4->GetIdx(); |
1014 | |
|
1015 | 0 | if (a2->GetHyb() == 3 && a3->GetHyb() == 3) //sp3-sp3 |
1016 | 0 | { |
1017 | 0 | vals = _sp3sp3; |
1018 | |
|
1019 | 0 | if (!_quiet) |
1020 | 0 | { |
1021 | 0 | char buffer[BUFF_SIZE]; |
1022 | 0 | snprintf(buffer,BUFF_SIZE,"%3d%3d%3d%3d %s", |
1023 | 0 | ref[0],ref[1],ref[2],ref[3],"sp3-sp3"); |
1024 | 0 | obErrorLog.ThrowError(__FUNCTION__, buffer, obDebug); |
1025 | 0 | } |
1026 | 0 | } |
1027 | 0 | else |
1028 | 0 | if (a2->GetHyb() == 2 && a3->GetHyb() == 2) //sp2-sp2 |
1029 | 0 | { |
1030 | 0 | vals = _sp2sp2; |
1031 | |
|
1032 | 0 | if (!_quiet) |
1033 | 0 | { |
1034 | 0 | char buffer[BUFF_SIZE]; |
1035 | 0 | snprintf(buffer,BUFF_SIZE,"%3d%3d%3d%3d %s", |
1036 | 0 | ref[0],ref[1],ref[2],ref[3],"sp2-sp2"); |
1037 | 0 | obErrorLog.ThrowError(__FUNCTION__, buffer, obDebug); |
1038 | 0 | } |
1039 | 0 | } |
1040 | 0 | else //must be sp2-sp3 |
1041 | 0 | { |
1042 | 0 | vals = _sp3sp2; |
1043 | |
|
1044 | 0 | if (!_quiet) |
1045 | 0 | { |
1046 | 0 | char buffer[BUFF_SIZE]; |
1047 | 0 | snprintf(buffer,BUFF_SIZE,"%3d%3d%3d%3d %s", |
1048 | 0 | ref[0],ref[1],ref[2],ref[3],"sp2-sp3"); |
1049 | 0 | obErrorLog.ThrowError(__FUNCTION__, buffer, obDebug); |
1050 | 0 | } |
1051 | 0 | } |
1052 | 0 | } |
1053 | | |
1054 | | OBRotorRules::~OBRotorRules() |
1055 | 0 | { |
1056 | 0 | vector<OBRotorRule*>::iterator i; |
1057 | 0 | for (i = _vr.begin();i != _vr.end();++i) |
1058 | 0 | delete (*i); |
1059 | 0 | } |
1060 | | |
1061 | | #undef OB_DEFAULT_DELTA |
1062 | | } |
1063 | | |
1064 | | //! \file rotor.cpp |
1065 | | //! \brief Rotate dihedral angles according to rotor rules. |