1 /**********************************************************************
2 generic.cpp - Handle OBGenericData classes.
3
4 Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
5 Some portions Copyright (C) 2001-2006 by Geoffrey R. Hutchison
6 Some portions Copyright (C) 2010 by David Lonie
7
8 This file is part of the Open Babel project.
9 For more information, see <http://openbabel.org/>
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation version 2 of the License.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19 ***********************************************************************/
20 #include <openbabel/babelconfig.h>
21
22 #include <string>
23 #include <set>
24
25 #include <openbabel/mol.h>
26 #include <openbabel/atom.h>
27 #include <openbabel/bond.h>
28 #include <openbabel/ring.h>
29 #include <openbabel/obiter.h>
30 #include <openbabel/generic.h>
31 #include <openbabel/math/matrix3x3.h>
32 #include <openbabel/elements.h>
33
34 // needed for msvc to have at least one reference to AtomClass, AliasData in openbabel library
35 #include <openbabel/alias.h>
36
37 using namespace std;
38
39 namespace OpenBabel
40 {
41
42 /** \class OBGenericData generic.h <openbabel/generic.h>
43
44 OBGenericData is an abstract base class which defines an interface for
45 storage, retrieval, and indexing of arbitrary generic data.
46 Subclasses of OBGenericData can be used to store custom data
47 on a per-atom, per-bond, per-molecule, or per-residue basis.
48 Open Babel currently supports a small subset of chemical functionality
49 as OBGenericData types, which will expand over time to support additional
50 interconversion (e.g., spectroscopy, dynamics, surfaces...)
51
52 For more information on currently supported types, please see
53 the developer wiki:
54 http://openbabel.org/wiki/Generic_Data
55
56 For your own custom data, either define a custom subclass using
57 an id from the OBGenericDataType::CustomData0 to
58 OBGenericDataType::CustomData15 slots,
59 or store your data as a string and use OBPairData for key/value access.
60 The latter is <strong>highly</strong> recommended for various text
61 descriptors
62 e.g., in QSAR, atom or bond labels, or other textual data.
63
64 <strong>New in Open Babel, version 2.1</strong>
65 is the template-based OBPairTemplate,
66 which can be used to store arbitrary data types. There are predefined
67 types OBPairInteger and OBPairFloatingPoint for storing integers and
68 floating-point values without converting to a string representation.
69
70 Also <strong>new</strong> is the "source" or "origin" of a data
71 entry, enumerated by DataOrigin. This can be accessed by
72 SetOrigin() and GetOrigin(), as well as via "filtering" methods
73 in OBBase, allowing you to separate data read in from a file,
74 added by a user, or assigned by Open Babel internally.
75
76 While the library and import routines will set DataOrigin correctly,
77 you should try to annotate data added by your code. Typically this would
78 either be userAdded or external. The former refers to something the
79 user requested as an annotation, while the latter refers to annotations
80 your code adds automatically.
81
82 Example code using OBGenericData:
83
84 @code
85 if (mol.HasData(OBGenericDataType::UnitCell))
86 {
87 uc = (OBUnitCell*)mol.GetData(OBGenericDataType::UnitCell);
88 sprintf(buffer,
89 "%10.5f%10.5f%10.5f%10.5f%10.5f%10.5f",
90 uc->GetA(), uc->GetB(), uc->GetC(),
91 uc->GetAlpha() , uc->GetBeta(), uc->GetGamma());
92 ofs << buffer << endl;
93 }
94
95 ...
96
97 vector<OBGenericData*>::iterator k;
98 vector<OBGenericData*> vdata = mol.GetData();
99 for (k = vdata.begin();k != vdata.end();++k)
100 if ((*k)->GetDataType() == OBGenericDataType::PairData)
101 {
102 ofs << "> <" << (*k)->GetAttribute() << ">" << endl;
103 ofs << ((OBPairData*)(*k))->GetValue() << endl << endl;
104 }
105 @endcode
106
107 Similar code also works for OBGenericData stored in an OBAtom or
108 OBBond or OBResidue. These examples show use of DataOrigin outside
109 of the Open Babel library.
110
111 @code
112 string atomLabel; // e.g., from the user adding annotation to an atom
113 if (!atom.HasData("UserLabel")) // stored textual data as an OBPairData
114 {
115 OBPairData *label = new OBPairData;
116 label->SetAttribute("UserLabel");
117 label->SetValue(atomLabel);
118 label->SetOrigin(userInput); // set by user, not by Open Babel
119
120 atom.SetData(label);
121 }
122
123 ...
124
125 if (bond.HasData("DisplayType")) // e.g. in a visualization tool
126 {
127 OBPairData *display = dynamic_cast<OBPairData *> bond.GetData("DisplayType");
128 if (display->GetValue() == "wireframe")
129 {
130 ... // display a wireframe view
131 }
132 }
133 @endcode
134
135 When designing a class derived from OBGenericData you must add a
136 Clone() function. For classes used with OBMol this is used when
137 an OBMol object is copied. If your class member variables contain
138 pointers to atoms or bonds then it will be necessary to ensure
139 that these are updated in Clone() to refer to the new molecule. Without
140 these and similar pointers it is more likely that the very simple
141 clone function
142 @code
143 virtual OBGenericData* Clone(OBBase* parent) const
144 {return new MyNewClass(*this);}
145 @endcode
146 and the compiler generated copy constructor would be sufficient.
147
148 It is recommended that, if possible, OBGenericData classes do not
149 store atom and bond pointers. Using atom and bond indices instead
150 would allow the simple version of Clone() above. See
151 OBRotameterData::Clone for an example of a more complicated version.
152 For classes which are not intended to support copying, Clone() can
153 return nullptr
154 @code
155 virtual OBGenericData* Clone(OBBase* parent) const
156 {return nullptr;}
157 @endcode
158 Clone() is a pure virtual function so that you need to decide what
159 kind of function you need and include it explicitly.
160 **/
161
162 //
163 //member functions for OBGenericData class
164 //
165
OBGenericData(const std::string attr,const unsigned int type,const DataOrigin source)166 OBGenericData::OBGenericData(const std::string attr, const unsigned int type,
167 const DataOrigin source):
168 _attr(attr), _type(type), _source(source)
169 { }
170
171 /* Use default copy constructor and assignment operators
172 OBGenericData::OBGenericData(const OBGenericData &src)
173 {
174 _type = src.GetDataType();
175 _attr = src.GetAttribute();
176 }
177
178
179 OBGenericData& OBGenericData::operator = (const OBGenericData &src)
180 {
181 if(this == &src)
182 return(*this);
183
184 _type = src._type;
185 _attr = src._attr;
186
187 return(*this);
188 }
189 */
190
191 //
192 //member functions for OBCommentData class
193 //
194
OBCommentData()195 OBCommentData::OBCommentData():
196 OBGenericData("Comment", OBGenericDataType::CommentData)
197 { }
198
OBCommentData(const OBCommentData & src)199 OBCommentData::OBCommentData(const OBCommentData &src) :
200 OBGenericData(src), _data(src._data)
201 { }
202
203 //
204 //member functions for OBExternalBond class
205 //
OBExternalBond(OBAtom * atom,OBBond * bond,int idx)206 OBExternalBond::OBExternalBond(OBAtom *atom,OBBond *bond,int idx):
207 _idx(idx), _atom(atom), _bond(bond)
208 { }
209
OBExternalBond(const OBExternalBond & src)210 OBExternalBond::OBExternalBond(const OBExternalBond &src):
211 _idx(src._idx), _atom(src._atom), _bond(src._bond)
212 { }
213
214 //
215 //member functions for OBExternalBondData class
216 //
217
OBExternalBondData()218 OBExternalBondData::OBExternalBondData():
219 OBGenericData("ExternalBondData", OBGenericDataType::ExternalBondData,
220 perceived)
221 { }
222
SetData(OBAtom * atom,OBBond * bond,int idx)223 void OBExternalBondData::SetData(OBAtom *atom,OBBond *bond,int idx)
224 {
225 OBExternalBond xb(atom,bond,idx);
226 _vexbnd.push_back(xb);
227 }
228
229 //
230 //member functions for OBPairData class
231 //
232
OBPairData()233 OBPairData::OBPairData() :
234 OBGenericData("PairData", OBGenericDataType::PairData)
235 { }
236
237 //
238 //member functions for OBVirtualBond class
239 //
240
OBVirtualBond()241 OBVirtualBond::OBVirtualBond():
242 OBGenericData("VirtualBondData", OBGenericDataType::VirtualBondData, perceived),
243 _bgn(0), _end(0), _ord(0), _stereo(0)
244 { }
245
OBVirtualBond(unsigned int bgn,unsigned int end,unsigned int ord,int stereo)246 OBVirtualBond::OBVirtualBond(unsigned int bgn, unsigned int end, unsigned int ord, int stereo):
247 OBGenericData("VirtualBondData", OBGenericDataType::VirtualBondData, perceived),
248 _bgn(bgn), _end(end), _ord(ord), _stereo(stereo)
249 { }
250
251 //
252 // member functions for OBUnitCell class
253 //
OBUnitCell()254 OBUnitCell::OBUnitCell():
255 OBGenericData("UnitCell", OBGenericDataType::UnitCell),
256 _mOrtho(matrix3x3()),
257 _mOrient(matrix3x3()),
258 _offset(vector3()),
259 _spaceGroupName(""), _spaceGroup(nullptr),
260 _lattice(Undefined)
261 { }
262
OBUnitCell(const OBUnitCell & src)263 OBUnitCell::OBUnitCell(const OBUnitCell &src) :
264 OBGenericData("UnitCell", OBGenericDataType::UnitCell),
265 _mOrtho(src._mOrtho),
266 _mOrient(src._mOrient),
267 _offset(src._offset),
268 _spaceGroupName(src._spaceGroupName), _spaceGroup(src._spaceGroup),
269 _lattice(src._lattice)
270 { }
271
operator =(const OBUnitCell & src)272 OBUnitCell & OBUnitCell::operator=(const OBUnitCell &src)
273 {
274 if(this == &src)
275 return(*this);
276
277 _mOrtho = src._mOrtho;
278 _mOrient = src._mOrient;
279 _offset = src._offset;
280
281 _spaceGroup = src._spaceGroup;
282 _spaceGroupName = src._spaceGroupName;
283 _lattice = src._lattice;
284
285 return(*this);
286 }
287
288 //! Implements <a href="http://qsar.sourceforge.net/dicts/blue-obelisk/index.xhtml#calculateOrthogonalisationMatrix">blue-obelisk:calculateOrthogonalisationMatrix</a>
SetData(const double a,const double b,const double c,const double alpha,const double beta,const double gamma)289 void OBUnitCell::SetData(const double a, const double b, const double c,
290 const double alpha, const double beta, const double gamma)
291 {
292 _mOrtho.FillOrth(alpha, beta, gamma, a, b, c);
293 _mOrient = matrix3x3(1);
294 _spaceGroup = nullptr;
295 _spaceGroupName = "";
296 _lattice = OBUnitCell::Undefined;
297 }
298
299 //! Implements <a href="http://qsar.sourceforge.net/dicts/blue-obelisk/index.xhtml#calculateOrthogonalisationMatrix">blue-obelisk:calculateOrthogonalisationMatrix</a>
SetData(const vector3 v1,const vector3 v2,const vector3 v3)300 void OBUnitCell::SetData(const vector3 v1, const vector3 v2, const vector3 v3)
301 {
302 matrix3x3 m (v1, v2, v3);
303 _mOrtho.FillOrth(vectorAngle(v2,v3), // alpha
304 vectorAngle(v1,v3), // beta
305 vectorAngle(v1,v2), // gamma
306 v1.length(), // a
307 v2.length(), // b
308 v3.length()); // c
309 _mOrient = m.transpose() * _mOrtho.inverse();
310 _spaceGroup = nullptr;
311 _spaceGroupName = "";
312 _lattice = OBUnitCell::Undefined;
313 }
314
315 //! Implements <a href="http://qsar.sourceforge.net/dicts/blue-obelisk/index.xhtml#calculateOrthogonalisationMatrix">blue-obelisk:calculateOrthogonalisationMatrix</a>
SetData(const matrix3x3 m)316 void OBUnitCell::SetData(const matrix3x3 m)
317 {
318 SetData(m.GetRow(0), m.GetRow(1), m.GetRow(2));
319 }
320
SetOffset(const vector3 v1)321 void OBUnitCell::SetOffset(const vector3 v1)
322 {
323 _offset = v1;
324 }
325
326 //! Implements <a href="http://qsar.sourceforge.net/dicts/blue-obelisk/index.xhtml#convertNotionalIntoCartesianCoordinates">blue-obelisk:convertNotionalIntoCartesianCoordinates</a>
GetCellVectors() const327 vector<vector3> OBUnitCell::GetCellVectors() const
328 {
329 vector<vector3> v;
330 v.reserve(3);
331
332 matrix3x3 m = GetCellMatrix();
333
334 v.push_back(m.GetRow(0));
335 v.push_back(m.GetRow(1));
336 v.push_back(m.GetRow(2));
337
338 return v;
339 }
340
GetCellMatrix() const341 matrix3x3 OBUnitCell::GetCellMatrix() const
342 {
343 return (_mOrient * _mOrtho).transpose();
344 }
345
GetOrthoMatrix() const346 matrix3x3 OBUnitCell::GetOrthoMatrix() const
347 {
348 return _mOrtho;
349 }
350
GetOrientationMatrix() const351 matrix3x3 OBUnitCell::GetOrientationMatrix() const
352 {
353 return _mOrient;
354 }
355
GetFractionalMatrix() const356 matrix3x3 OBUnitCell::GetFractionalMatrix() const
357 {
358 return _mOrtho.inverse();
359 }
360
FractionalToCartesian(vector3 frac) const361 vector3 OBUnitCell::FractionalToCartesian(vector3 frac) const
362 {
363 return _mOrient * _mOrtho * frac + _offset;
364 }
365
CartesianToFractional(vector3 cart) const366 vector3 OBUnitCell::CartesianToFractional(vector3 cart) const
367 {
368 return _mOrtho.inverse() * _mOrient.inverse() * (cart - _offset);
369 }
370
WrapCartesianCoordinate(vector3 cart) const371 vector3 OBUnitCell::WrapCartesianCoordinate(vector3 cart) const
372 {
373 vector3 v = CartesianToFractional(cart);
374 v = WrapFractionalCoordinate(v);
375 return FractionalToCartesian(v);
376 }
377
WrapFractionalCoordinate(vector3 frac) const378 vector3 OBUnitCell::WrapFractionalCoordinate(vector3 frac) const
379 {
380 double x = fmod(frac.x(), 1);
381 double y = fmod(frac.y(), 1);
382 double z = fmod(frac.z(), 1);
383 if (x < 0) x += 1;
384 if (y < 0) y += 1;
385 if (z < 0) z += 1;
386
387 #define LIMIT 0.999999
388 if (x > LIMIT)
389 x -= 1;
390 if (y > LIMIT)
391 y -= 1;
392 if (z > LIMIT)
393 z -= 1;
394 #undef LIMIT
395
396 // Fuzzy logic from Francois-Xavier
397 #define EPSILON 1.0e-6
398 if (x > 1 - EPSILON || x < EPSILON)
399 x = 0.0;
400 if (y > 1 - EPSILON || y < EPSILON)
401 y = 0.0;
402 if (z > 1 - EPSILON || z < EPSILON)
403 z = 0.0;
404 #undef EPSILON
405
406 return vector3(x, y, z);
407 }
408
UnwrapCartesianNear(vector3 new_loc,vector3 ref_loc) const409 vector3 OBUnitCell::UnwrapCartesianNear(vector3 new_loc, vector3 ref_loc) const
410 {
411 vector3 bond_dir = MinimumImageCartesian(new_loc - ref_loc);
412 return ref_loc + bond_dir;
413 }
414
UnwrapFractionalNear(vector3 new_loc,vector3 ref_loc) const415 vector3 OBUnitCell::UnwrapFractionalNear(vector3 new_loc, vector3 ref_loc) const
416 {
417 vector3 bond_dir = MinimumImageFractional(new_loc - ref_loc);
418 return ref_loc + bond_dir;
419 }
420
MinimumImageCartesian(vector3 cart) const421 vector3 OBUnitCell::MinimumImageCartesian(vector3 cart) const
422 {
423 vector3 frac = CartesianToFractional(cart);
424 frac = MinimumImageFractional(frac);
425 return FractionalToCartesian(frac);
426 }
427
MinimumImageFractional(vector3 frac) const428 vector3 OBUnitCell::MinimumImageFractional(vector3 frac) const
429 {
430 double x = frac.x() - round(frac.x());
431 double y = frac.y() - round(frac.y());
432 double z = frac.z() - round(frac.z());
433 return vector3(x, y, z);
434 }
435
GetLatticeType(int spacegroup) const436 OBUnitCell::LatticeType OBUnitCell::GetLatticeType( int spacegroup ) const
437 {
438 // 1-2 Triclinic
439 // 3-15 Monoclinic
440 // 16-74 Orthorhombic
441 // 75-142 Tetragonal
442 // 143-167 Rhombohedral
443 // 168-194 Hexagonal
444 // 195-230 Cubic
445
446 if ( spacegroup == 0 && _spaceGroup)
447 spacegroup = _spaceGroup->GetId();
448
449 if ( spacegroup <= 0 )
450 return OBUnitCell::Undefined;
451
452 else if ( spacegroup == 1 ||
453 spacegroup == 2 )
454 return OBUnitCell::Triclinic;
455
456 else if ( spacegroup >= 3 &&
457 spacegroup <= 15 )
458 return OBUnitCell::Monoclinic;
459
460 else if ( spacegroup >= 16 &&
461 spacegroup <= 74 )
462 return OBUnitCell::Orthorhombic;
463
464 else if ( spacegroup >= 75 &&
465 spacegroup <= 142 )
466 return OBUnitCell::Tetragonal;
467
468 else if ( spacegroup >= 143 &&
469 spacegroup <= 167 )
470 return OBUnitCell::Rhombohedral;
471
472 else if ( spacegroup >= 168 &&
473 spacegroup <= 194 )
474 return OBUnitCell::Hexagonal;
475
476 else if ( spacegroup >= 195 &&
477 spacegroup <= 230 )
478 return OBUnitCell::Cubic;
479
480 //just to be extra sure
481 else // ( spacegroup > 230 )
482 return OBUnitCell::Undefined;
483 }
484
GetLatticeType() const485 OBUnitCell::LatticeType OBUnitCell::GetLatticeType() const
486 {
487 if (_lattice != Undefined)
488 return _lattice;
489 else if (_spaceGroup != nullptr)
490 return GetLatticeType(_spaceGroup->GetId());
491
492 double a = GetA();
493 double b = GetB();
494 double c = GetC();
495 double alpha = GetAlpha();
496 double beta = GetBeta();
497 double gamma = GetGamma();
498
499 unsigned int rightAngles = 0;
500 if (IsApprox(alpha, 90.0, 1.0e-3)) rightAngles++;
501 if (IsApprox(beta, 90.0, 1.0e-3)) rightAngles++;
502 if (IsApprox(gamma, 90.0, 1.0e-3)) rightAngles++;
503
504 // recast cache member "_lattice" as mutable
505 OBUnitCell::LatticeType *lattice =
506 const_cast<OBUnitCell::LatticeType*>(&_lattice);
507
508 switch (rightAngles)
509 {
510 case 3:
511 if (IsApprox(a, b, 1.0e-4) && IsApprox(b, c, 1.0e-4))
512 *lattice = Cubic;
513 else if (IsApprox(a, b, 1.0e-4) || IsApprox(b, c, 1.0e-4))
514 *lattice = Tetragonal;
515 else
516 *lattice = Orthorhombic;
517 break;
518 case 2:
519 if ( (IsApprox(alpha, 120.0, 1.0e-3)
520 || IsApprox(beta, 120.0, 1.0e-3)
521 || IsApprox(gamma, 120.0f, 1.0e-3))
522 && (IsApprox(a, b, 1.0e-4) || IsApprox(b, c, 1.0e-4)) )
523 *lattice = Hexagonal;
524 else
525 *lattice = Monoclinic;
526 break;
527 default:
528 if (IsApprox(a, b, 1.0e-4) && IsApprox(b, c, 1.0e-4))
529 *lattice = Rhombohedral;
530 else
531 *lattice = Triclinic;
532 }
533
534 return *lattice;
535 }
536
GetSpaceGroupNumber(std::string name) const537 int OBUnitCell::GetSpaceGroupNumber( std::string name) const
538 {
539 static const char * const spacegroups[] = {
540 "P1", "P-1", "P2", "P2(1)", "C2", "Pm", "Pc", "Cm", "Cc", "P2/m",
541 "P2(1)/m", "C2/m", "P2/c", "P2(1)/c", "C2/c", "P222", "P222(1)",
542 "P2(1)2(1)2", "P2(1)2(1)2(1)", "C222(1)", "C222", "F222", "I222",
543 "I2(1)2(1)2(1)", "Pmm2", "Pmc2(1)", "Pcc2", "Pma2", "Pca2(1)", "Pnc2",
544 "Pmn2(1)", "Pba2", "Pna2(1)", "Pnn2", "Cmm2", "Cmc2(1)", "Ccc2", "Amm2",
545 "Abm2", "Ama2", "Aba2", "Fmm2", "Fdd2", "Imm2", "Iba2", "Ima2", "Pmmm",
546 "Pnnn", "Pccm", "Pban", "Pmma", "Pnna", "Pmna", "Pcca", "Pbam", "Pccn",
547 "Pbcm", "Pnnm", "Pmmn", "Pbcn", "Pbca", "Pnma", "Cmcm", "Cmca", "Cmmm",
548 "Cccm", "Cmma", "Ccca", "Fmmm", "Fddd", "Immm", "Ibam", "Ibca", "Imma",
549 "P4", "P4(1)", "P4(2)", "P4(3)", "I4", "I4(1)", "P-4", "I-4", "P4/m",
550 "P4(2)/m", "P4/n", "P4(2)/n", "I4/m", "I4(1)/a", "P422", "P42(1)2",
551 "P4(1)22", "P4(1)2(1)2", "P4(2)22", "P4(2)2(1)2", "P4(3)22", "P4(3)2(1)2",
552 "I422", "I4(1)22", "P4mm", "P4bm", "P4(2)cm", "P4(2)nm", "P4cc", "P4nc",
553 "P4(2)mc", "P4(2)bc", "I4mm", "I4cm", "I4(1)md", "I4(1)cd", "P-42m",
554 "P-42c", "P-42(1)m", "P-42(1)c", "P-4m2", "P-4c2", "P-4b2", "P-4n2",
555 "I-4m2", "I-4c2", "I-42m", "I-42d", "P4/mmm", "P4/mcc", "P4/nbm",
556 "P4/nnc", "P4/mbm", "P4/mnc", "P4/nmm", "P4/ncc", "P4(2)/mmc",
557 "P4(2)/mcm", "P4(2)/nbc", "P4(2)/nnm", "P4(2)/mbc", "P4(2)/mnm",
558 "P4(2)/nmc", "P4(2)/ncm", "I4/mmm", "I4/mcm", "I4(1)/amd", "I4(1)/acd",
559 "P3", "P3(1)", "P3(2)", "R3", "P-3", "R-3", "P312", "P321", "P3(1)12",
560 "P3(1)21", "P3(2)12", "P3(2)21", "R32", "P3m1", "P31m", "P3c1", "P31c",
561 "R3m", "R3c", "P-31m", "P-31c", "P-3m1", "P-3c1", "R-3m", "R-3c", "P6",
562 "P6(1)", "P6(5)", "P6(2)", "P6(4)", "P6(3)", "P-6", "P6/m", "P6(3)/m",
563 "P622", "P6(1)22", "P6(5)22", "P6(2)22", "P6(4)22", "P6(3)22", "P6mm",
564 "P6cc", "P6(3)cm", "P6(3)mc", "P-6m2", "P-6c2", "P-62m", "P-62c",
565 "P6/mmm", "P6/mcc", "P6(3)/mcm", "P6(3)/mmc", "P23", "F23", "I23",
566 "P2(1)3", "I2(1)3", "Pm-3", "Pn-3", "Fm-3", "Fd-3", "Im-3", "Pa-3",
567 "Ia-3", "P432", "P4(2)32", "F432", "F4(1)32", "I432", "P4(3)32",
568 "P4(1)32", "I4(1)32", "P-43m", "F4-3m", "I-43m", "P-43n", "F-43c",
569 "I-43d", "Pm-3m", "Pn-3n", "Pm-3n", "Pn-3m", "Fm-3m", "Fm-3c",
570 "Fd-3m", "Fd-3c", "Im-3m", "Ia-3d"
571 };
572
573 if (name.length () == 0)
574 {
575 if (_spaceGroup != nullptr)
576 return _spaceGroup->GetId();
577 else
578 name = _spaceGroupName;
579 }
580 static const int numStrings = sizeof( spacegroups ) / sizeof( spacegroups[0] );
581 for ( int i = 0; i < numStrings; ++i ) {
582 if (name == spacegroups[i] ) {
583 return i+1;
584 }
585 }
586 return 0; //presumably never reached
587 }
588
589 // Whether two points (given in fractional coordinates) are close enough
590 // to be considered duplicates.
areDuplicateAtoms(vector3 v1,vector3 v2)591 bool areDuplicateAtoms (vector3 v1, vector3 v2)
592 {
593 vector3 dr = v2 - v1;
594 if (dr.x() < -0.5)
595 dr.SetX(dr.x() + 1);
596 if (dr.x() > 0.5)
597 dr.SetX(dr.x() - 1);
598 if (dr.y() < -0.5)
599 dr.SetY(dr.y() + 1);
600 if (dr.y() > 0.5)
601 dr.SetY(dr.y() - 1);
602 if (dr.z() < -0.5)
603 dr.SetZ(dr.z() + 1);
604 if (dr.z() > 0.5)
605 dr.SetZ(dr.z() - 1);
606
607 return (dr.length_2() < 1e-6);
608 }
609
FillUnitCell(OBMol * mol)610 void OBUnitCell::FillUnitCell(OBMol *mol)
611 {
612 const SpaceGroup *sg = GetSpaceGroup(); // the actual space group and transformations for this unit cell
613
614 if (sg == nullptr)
615 return ;
616
617 // For each atom, we loop through: convert the coords back to inverse space, apply the transformations and create new atoms
618 vector3 baseV, uniqueV, updatedCoordinate;
619 list<vector3> transformedVectors; // list of symmetry-defined copies of the atom
620 list<vector3>::iterator transformIter;
621 list<OBAtom*>::iterator deleteIter, atomIter;
622 OBAtom *newAtom;
623 list<OBAtom*> atoms, atomsToDelete;
624 char hash[22];
625 set<string> coordinateSet;
626
627 // Check original mol for duplicates
628 FOR_ATOMS_OF_MOL(atom, *mol) {
629 baseV = atom->GetVector();
630 baseV = CartesianToFractional(baseV);
631 baseV = WrapFractionalCoordinate(baseV);
632 snprintf(hash, 22, "%03d,%.3f,%.3f,%.3f", atom->GetAtomicNum(), baseV.x(), baseV.y(), baseV.z());
633 if (coordinateSet.insert(hash).second) { // True if new entry
634 atoms.push_back(&(*atom));
635 } else {
636 atomsToDelete.push_back(&(*atom));
637 }
638 }
639 for (deleteIter = atomsToDelete.begin(); deleteIter != atomsToDelete.end(); ++deleteIter) {
640 mol->DeleteAtom(*deleteIter);
641 }
642
643 // Cross-check all transformations for duplicity
644 for (atomIter = atoms.begin(); atomIter != atoms.end(); ++atomIter) {
645 uniqueV = (*atomIter)->GetVector();
646 uniqueV = CartesianToFractional(uniqueV);
647 uniqueV = WrapFractionalCoordinate(uniqueV);
648
649 transformedVectors = sg->Transform(uniqueV);
650 for (transformIter = transformedVectors.begin();
651 transformIter != transformedVectors.end(); ++transformIter) {
652 updatedCoordinate = WrapFractionalCoordinate(*transformIter);
653
654 // Check if the transformed coordinate is a duplicate of an atom
655 snprintf(hash, 22, "%03d,%.3f,%.3f,%.3f", (*atomIter)->GetAtomicNum(), updatedCoordinate.x(),
656 updatedCoordinate.y(), updatedCoordinate.z());
657 if (coordinateSet.insert(hash).second) {
658 newAtom = mol->NewAtom();
659 newAtom->Duplicate(*atomIter);
660 newAtom->SetVector(FractionalToCartesian(updatedCoordinate));
661 }
662 } // end loop of transformed atoms
663 } // end loop of atoms
664 SetSpaceGroup(1); // We've now applied the symmetry, so we should act like a P1 unit cell
665 }
666
667 /// @todo Remove nonconst overloads in OBUnitCell on next version bump.
668 #define OBUNITCELL_CALL_CONST_OVERLOAD(_type, _name) \
669 _type OBUnitCell::_name() \
670 { \
671 return const_cast<const OBUnitCell*>(this)->_name(); \
672 }
673 #define OBUNITCELL_CALL_CONST_OVERLOAD_ARG(_type, _name, _argsig) \
674 _type OBUnitCell::_name( _argsig arg1 ) \
675 { \
676 return const_cast<const OBUnitCell*>(this)->_name(arg1); \
677 }
678 OBUNITCELL_CALL_CONST_OVERLOAD(double, GetA);
679 OBUNITCELL_CALL_CONST_OVERLOAD(double, GetB);
680 OBUNITCELL_CALL_CONST_OVERLOAD(double, GetC);
681 OBUNITCELL_CALL_CONST_OVERLOAD(double, GetAlpha);
682 OBUNITCELL_CALL_CONST_OVERLOAD(double, GetBeta);
683 OBUNITCELL_CALL_CONST_OVERLOAD(double, GetGamma);
684 OBUNITCELL_CALL_CONST_OVERLOAD(vector3, GetOffset);
685 OBUNITCELL_CALL_CONST_OVERLOAD_ARG(OBUnitCell::LatticeType,
686 GetLatticeType, int);
687 OBUNITCELL_CALL_CONST_OVERLOAD(OBUnitCell::LatticeType, GetLatticeType);
688 OBUNITCELL_CALL_CONST_OVERLOAD(std::vector<vector3>, GetCellVectors);
689 OBUNITCELL_CALL_CONST_OVERLOAD(matrix3x3, GetCellMatrix );
690 OBUNITCELL_CALL_CONST_OVERLOAD(matrix3x3, GetOrthoMatrix );
691 OBUNITCELL_CALL_CONST_OVERLOAD(matrix3x3, GetOrientationMatrix );
692 OBUNITCELL_CALL_CONST_OVERLOAD(matrix3x3, GetFractionalMatrix );
693 OBUNITCELL_CALL_CONST_OVERLOAD_ARG(vector3, FractionalToCartesian, vector3);
694 OBUNITCELL_CALL_CONST_OVERLOAD_ARG(vector3, CartesianToFractional, vector3);
695 OBUNITCELL_CALL_CONST_OVERLOAD_ARG(vector3, WrapCartesianCoordinate, vector3);
696 OBUNITCELL_CALL_CONST_OVERLOAD_ARG(vector3, WrapFractionalCoordinate, vector3);
697 OBUNITCELL_CALL_CONST_OVERLOAD_ARG(vector3, MinimumImageCartesian, vector3);
698 OBUNITCELL_CALL_CONST_OVERLOAD_ARG(vector3, MinimumImageFractional, vector3);
699 OBUNITCELL_CALL_CONST_OVERLOAD_ARG(int, GetSpaceGroupNumber, std::string);
700 OBUNITCELL_CALL_CONST_OVERLOAD(double, GetCellVolume);
701 // Based on OBUNITCELL_CALL_CONST_OVERLOAD_ARG above
702 #define OBUNITCELL_CALL_CONST_OVERLOAD_ARG2(_type, _name, _argsig, _argsig2) \
703 _type OBUnitCell::_name( _argsig arg1, _argsig2 arg2 ) \
704 { \
705 return const_cast<const OBUnitCell*>(this)->_name(arg1, arg2); \
706 }
707 OBUNITCELL_CALL_CONST_OVERLOAD_ARG2(vector3, UnwrapCartesianNear, vector3, vector3);
708 OBUNITCELL_CALL_CONST_OVERLOAD_ARG2(vector3, UnwrapFractionalNear, vector3, vector3);
709
GetA() const710 double OBUnitCell::GetA() const
711 {
712 return _mOrtho.GetColumn(0).length();
713 }
714
GetB() const715 double OBUnitCell::GetB() const
716 {
717 return _mOrtho.GetColumn(1).length();
718 }
719
GetC() const720 double OBUnitCell::GetC() const
721 {
722 return _mOrtho.GetColumn(2).length();
723 }
724
GetAlpha() const725 double OBUnitCell::GetAlpha() const
726 {
727 return vectorAngle(_mOrtho.GetColumn(1), _mOrtho.GetColumn(2));
728 }
729
GetBeta() const730 double OBUnitCell::GetBeta() const
731 {
732 return vectorAngle(_mOrtho.GetColumn(0), _mOrtho.GetColumn(2));
733 }
734
GetGamma() const735 double OBUnitCell::GetGamma() const
736 {
737 return vectorAngle(_mOrtho.GetColumn(0), _mOrtho.GetColumn(1));
738 }
739
GetOffset() const740 vector3 OBUnitCell::GetOffset() const
741 {
742 return _offset;
743 }
744
GetCellVolume() const745 double OBUnitCell::GetCellVolume() const
746 {
747 return fabs(GetCellMatrix().determinant());
748 }
749
750 //
751 // member functions for OBSymmetryData class
752 //
OBSymmetryData()753 OBSymmetryData::OBSymmetryData():
754 OBGenericData("Symmetry", OBGenericDataType::SymmetryData)
755 { }
756
OBSymmetryData(const OBSymmetryData & src)757 OBSymmetryData::OBSymmetryData(const OBSymmetryData &src) :
758 OBGenericData(src._attr, src._type, src._source),
759 _spaceGroup(src._spaceGroup),
760 _pointGroup(src._pointGroup)
761 { }
762
operator =(const OBSymmetryData & src)763 OBSymmetryData & OBSymmetryData::operator=(const OBSymmetryData &src)
764 {
765 if(this == &src)
766 return(*this);
767
768 _pointGroup = src._pointGroup;
769 _spaceGroup = src._spaceGroup;
770 _source = src._source;
771
772 return(*this);
773 }
774
OBConformerData()775 OBConformerData::OBConformerData() :
776 OBGenericData("Conformers", OBGenericDataType::ConformerData)
777 { }
778
OBConformerData(const OBConformerData & src)779 OBConformerData::OBConformerData(const OBConformerData &src) :
780 OBGenericData("Conformers", OBGenericDataType::ConformerData),
781 _vDimension(src._vDimension),
782 _vEnergies(src._vEnergies), _vForces(src._vForces),
783 _vVelocity(src._vVelocity), _vDisplace(src._vDisplace),
784 _vData(src._vData)
785 { }
786
operator =(const OBConformerData & src)787 OBConformerData & OBConformerData::operator=(const OBConformerData &src)
788 {
789 if(this == &src)
790 return(*this);
791
792 _source = src._source;
793
794 _vDimension = src._vDimension;
795 _vEnergies = src._vEnergies;
796 _vForces = src._vForces;
797 _vVelocity = src._vVelocity;
798 _vDisplace = src._vDisplace;
799 _vData = src._vData;
800
801 return(*this);
802 }
803
804 //
805 //member functions for OBRingData class
806 //
807
OBRingData()808 OBRingData::OBRingData() :
809 OBGenericData("RingData", OBGenericDataType::RingData)
810 {
811 _vr.clear();
812 }
813
814 /*!
815 **\brief OBRingData copy constructor
816 **\param src reference to original OBRingData object (rhs)
817 */
OBRingData(const OBRingData & src)818 OBRingData::OBRingData(const OBRingData &src)
819 : OBGenericData(src), //chain to base class
820 _vr(src._vr) //chain to member classes
821 {
822 //no other memeber data
823 //memory management
824
825 vector<OBRing*>::iterator ring;
826
827 for(ring = _vr.begin();ring != _vr.end();++ring)
828 {
829 OBRing *newring = new OBRing;
830 (*newring) = (**ring); //copy data to new object
831 (*ring) = newring; //repoint new pointer to new copy of data
832 }
833 }
834
~OBRingData()835 OBRingData::~OBRingData()
836 {
837 vector<OBRing*>::iterator ring;
838 for (ring = _vr.begin();ring != _vr.end();++ring)
839 {
840 delete *ring;
841 }
842 }
843
844 /*!
845 **\brief OBRingData assignment operator
846 **\param src reference to original OBRingData object (rhs)
847 **\return reference to changed OBRingData object (lhs)
848 */
operator =(const OBRingData & src)849 OBRingData& OBRingData::operator =(const OBRingData &src)
850 {
851 //on identity, return
852 if(this == &src)
853 return(*this);
854
855 //chain to base class
856 OBGenericData::operator =(src);
857
858 //member data
859
860 //memory management
861 vector<OBRing*>::iterator ring;
862 for(ring = _vr.begin();ring != _vr.end();++ring)
863 {
864 delete &*ring; //deallocate old rings to prevent memory leak
865 }
866
867 _vr.clear();
868 _vr = src._vr; //copy vector properties
869
870 for(ring = _vr.begin();ring != _vr.end();++ring)
871 {
872 if(*ring == 0)
873 continue;
874
875 //allocate and copy ring data
876 OBRing *newring = new OBRing;
877 (*newring) = (**ring);
878 (*ring) = newring; //redirect pointer
879 }
880 return(*this);
881 }
882
BeginRing(std::vector<OBRing * >::iterator & i)883 OBRing *OBRingData::BeginRing(std::vector<OBRing*>::iterator &i)
884 {
885 i = _vr.begin();
886 return i == _vr.end() ? nullptr : (OBRing*)*i;
887 }
888
NextRing(std::vector<OBRing * >::iterator & i)889 OBRing *OBRingData::NextRing(std::vector<OBRing*>::iterator &i)
890 {
891 ++i;
892 return i == _vr.end() ? nullptr : (OBRing*)*i;
893 }
894
895 //
896 //member functions for OBAngle class - stores all angles
897 //
898
899 /*!
900 **\brief Angle default constructor
901 */
OBAngle()902 OBAngle::OBAngle():
903 _vertex(nullptr), _termini(nullptr, nullptr), _radians(0.0)
904 { }
905
906 /*!
907 **\brief Angle constructor
908 */
OBAngle(OBAtom * vertex,OBAtom * a,OBAtom * b)909 OBAngle::OBAngle(OBAtom *vertex,OBAtom *a,OBAtom *b):
910 _vertex(vertex), _termini(a, b)
911 {
912 SortByIndex();
913 }
914
915 /*!
916 **\brief OBAngle copy constructor
917 */
OBAngle(const OBAngle & src)918 OBAngle::OBAngle(const OBAngle &src):
919 _vertex(src._vertex), _termini(src._termini), _radians(src._radians)
920 { }
921
922 /*!
923 **\brief OBAngle assignment operator
924 */
operator =(const OBAngle & src)925 OBAngle& OBAngle::operator = (const OBAngle &src)
926 {
927 if (this == &src)
928 return(*this);
929
930 _vertex = src._vertex;
931 _termini.first = src._termini.first;
932 _termini.second = src._termini.second;
933 _radians = src._radians;
934
935 return(*this);
936 }
937
938 /*!
939 **\brief Return OBAngle to its original state
940 */
Clear()941 void OBAngle::Clear()
942 {
943 _vertex = nullptr;
944 _termini.first = 0;
945 _termini.second = 0;
946 _radians = 0.0;
947 return;
948 }
949
950 /*!
951 **\brief Sets the 3 atoms in the angle
952 ** Parameters are pointers to each OBAtom
953 */
SetAtoms(OBAtom * vertex,OBAtom * a,OBAtom * b)954 void OBAngle::SetAtoms(OBAtom *vertex,OBAtom *a,OBAtom *b)
955 {
956 _vertex = vertex;
957 _termini.first = a;
958 _termini.second = b;
959 SortByIndex();
960 return;
961 }
962
963 /*!
964 **\brief Sets the 3 atoms in the angle
965 **\param atoms a triple of OBAtom pointers, the first must be the vertex
966 */
SetAtoms(triple<OBAtom *,OBAtom *,OBAtom * > & atoms)967 void OBAngle::SetAtoms(triple<OBAtom*,OBAtom*,OBAtom*> &atoms)
968 {
969 _vertex = atoms.first;
970 _termini.first = atoms.second;
971 _termini.second = atoms.third;
972 SortByIndex();
973 return;
974 }
975
976 /*!
977 **\brief Retrieves the 3 atom pointer for the angle (vertex first)
978 **\return triple of OBAtom pointers
979 */
GetAtoms()980 triple<OBAtom*,OBAtom*,OBAtom*> OBAngle::GetAtoms()
981 {
982 triple<OBAtom*,OBAtom*,OBAtom*> atoms;
983 atoms.first = _vertex;
984 atoms.second = _termini.first;
985 atoms.third = _termini.second;
986 return(atoms);
987 }
988
989 /*!
990 **\brief sorts atoms in angle by order of indices
991 */
SortByIndex()992 void OBAngle::SortByIndex()
993 {
994 OBAtom *tmp;
995
996 if(_termini.first->GetIdx() > _termini.second->GetIdx())
997 {
998 tmp = _termini.first;
999 _termini.first = _termini.second;
1000 _termini.second = tmp;
1001 }
1002 }
1003
1004 /*!
1005 **\brief OBAngle equality operator, is same angle, NOT same value
1006 **\return boolean equality
1007 */
operator ==(const OBAngle & other)1008 bool OBAngle::operator ==(const OBAngle &other)
1009 {
1010 return ((_vertex == other._vertex) &&
1011 (_termini.first == other._termini.first) &&
1012 (_termini.second == other._termini.second));
1013 }
1014
1015 //
1016 //member functions for OBAngleData class - stores OBAngle set
1017 //
1018
1019 /*!
1020 **\brief OBAngleData constructor
1021 */
OBAngleData()1022 OBAngleData::OBAngleData()
1023 : OBGenericData("AngleData", OBGenericDataType::AngleData)
1024 { }
1025
1026 /*!
1027 **\brief OBAngleData copy constructor
1028 */
OBAngleData(const OBAngleData & src)1029 OBAngleData::OBAngleData(const OBAngleData &src)
1030 : OBGenericData(src), _angles(src._angles)
1031 { }
1032
1033 /*!
1034 **\brief OBAngleData assignment operator
1035 */
operator =(const OBAngleData & src)1036 OBAngleData& OBAngleData::operator =(const OBAngleData &src)
1037 {
1038 if (this == &src)
1039 return(*this);
1040
1041 _source = src._source;
1042 _angles = src._angles;
1043
1044 return(*this);
1045 }
1046
1047 /*!
1048 **\brief sets OBAngleData to its original state
1049 */
Clear()1050 void OBAngleData::Clear()
1051 {
1052 _angles.clear();
1053 return;
1054 }
1055
1056 /*!
1057 **\brief Adds a new angle to OBAngleData
1058 */
SetData(OBAngle & angle)1059 void OBAngleData::SetData(OBAngle &angle)
1060 {
1061 _angles.push_back(angle);
1062 return;
1063 }
1064
1065 /*!
1066 **\brief Fills an array with the indices of the atoms in the angle (vertex first)
1067 **\param angles pointer to the pointer to an array of angles atom indices
1068 **\return True if successful
1069 */
FillAngleArray(std::vector<std::vector<unsigned int>> & angles)1070 bool OBAngleData::FillAngleArray(std::vector<std::vector<unsigned int> > &angles)
1071 {
1072 if(_angles.empty())
1073 return(false);
1074
1075 vector<OBAngle>::iterator angle;
1076
1077 angles.clear();
1078 angles.resize(_angles.size());
1079
1080 unsigned int ct = 0;
1081
1082 for( angle=_angles.begin(); angle!=_angles.end(); ++angle,ct++)
1083 {
1084 angles[ct].resize(3);
1085 angles[ct][0] = angle->_vertex->GetIdx() - 1;
1086 angles[ct][1] = angle->_termini.first->GetIdx() - 1;
1087 angles[ct][2] = angle->_termini.second->GetIdx() - 1;
1088 }
1089
1090 return(true);
1091 }
1092
1093 /*!
1094 **\brief Fills an array with the indices of the atoms in the angle (vertex first)
1095 **\param angles pointer to the pointer to an array of angles atom indices
1096 **\param size the current number of rows in the array
1097 **\return int The number of angles
1098 */
FillAngleArray(int ** angles,unsigned int & size)1099 unsigned int OBAngleData::FillAngleArray(int **angles, unsigned int &size)
1100 {
1101 if(_angles.size() > size)
1102 {
1103 delete [] *angles;
1104 *angles = new int[_angles.size()*3];
1105 size = (unsigned int)_angles.size();
1106 }
1107
1108 vector<OBAngle>::iterator angle;
1109 int angleIdx = 0;
1110 for( angle=_angles.begin(); angle!=_angles.end(); ++angle)
1111 {
1112 *angles[angleIdx++] = angle->_vertex->GetIdx();
1113 *angles[angleIdx++] = angle->_termini.first->GetIdx();
1114 *angles[angleIdx++] = angle->_termini.second->GetIdx();
1115 }
1116 return (unsigned int)_angles.size();
1117 }
1118
1119 //
1120 //member functions for OBAngleData class - stores OBAngle set
1121 //
1122
1123 /*!
1124 **\brief OBTorsion constructor
1125 */
OBTorsion(OBAtom * a,OBAtom * b,OBAtom * c,OBAtom * d)1126 OBTorsion::OBTorsion(OBAtom *a,OBAtom *b, OBAtom *c,OBAtom *d)
1127 {
1128 triple<OBAtom*,OBAtom*,double> ad(a,d,0.0);
1129 _ads.push_back(ad);
1130
1131 _bc.first = b;
1132 _bc.second = c;
1133 }
1134
1135 /*!
1136 **\brief OBTorsion copy constructor
1137 */
OBTorsion(const OBTorsion & src)1138 OBTorsion::OBTorsion(const OBTorsion &src)
1139 : _bc(src._bc), _ads(src._ads)
1140 {}
1141
1142 /*!
1143 **\brief Returns all the 4 atom sets in OBTorsion
1144 */
GetTorsions()1145 vector<quad<OBAtom*,OBAtom*,OBAtom*,OBAtom*> > OBTorsion::GetTorsions()
1146 {
1147 quad<OBAtom*,OBAtom*,OBAtom*,OBAtom*> abcd;
1148
1149 abcd.second = _bc.first;
1150 abcd.third = _bc.second;
1151
1152 vector<quad<OBAtom*,OBAtom*,OBAtom*,OBAtom*> > torsions;
1153 vector<triple<OBAtom*,OBAtom*,double> >::iterator ad;
1154
1155 for(ad = _ads.begin();ad != _ads.end();++ad)
1156 {
1157 abcd.first = ad->first;
1158 abcd.fourth = ad->second;
1159 torsions.push_back(abcd);
1160 }
1161
1162 return(torsions);
1163 }
1164
1165 /*!
1166 **\brief OBTorsion assignment operator
1167 */
operator =(const OBTorsion & src)1168 OBTorsion& OBTorsion::operator =(const OBTorsion &src)
1169 {
1170 if (this == &src)
1171 return(*this);
1172
1173 _bc = src._bc;
1174 _ads = src._ads;
1175
1176 return(*this);
1177 }
1178
1179 /*!
1180 **\brief Returns the OBTorsion to its original state
1181 */
Clear()1182 void OBTorsion::Clear()
1183 {
1184 _bc.first = 0;
1185 _bc.second = 0;
1186 _ads.erase(_ads.begin(),_ads.end());
1187 }
1188
1189 /*!
1190 **\brief Sets the angle of a torsion in OBTorsion
1191 **\param radians the value to assign to the torsion
1192 **\param index the index into the torsion of the OBTorsion
1193 **\return boolean success
1194 */
SetAngle(double radians,unsigned int index)1195 bool OBTorsion::SetAngle(double radians,unsigned int index)
1196 {
1197 if(index >= _ads.size())
1198 return(false);
1199
1200 _ads[index].third = radians;
1201
1202 return(true);
1203 }
1204
1205 /*!
1206 **\brief Obtains the angle of a torsion in OBTorsion
1207 **\param radians the value of the angle is set here
1208 **\param index the index into the torsion of the OBTorsion
1209 **\return boolean success
1210 */
GetAngle(double & radians,unsigned int index)1211 bool OBTorsion::GetAngle(double &radians, unsigned int index)
1212 {
1213 if(index >= _ads.size())
1214 return false;
1215 radians = _ads[index].third;
1216 return true;
1217 }
1218
GetBondIdx()1219 unsigned int OBTorsion::GetBondIdx()
1220 {
1221 return(_bc.first->GetBond(_bc.second)->GetIdx());
1222 }
1223
1224 /*!
1225 **\brief determines if torsion has only protons on either the a or d end
1226 **\return boolean
1227 */
IsProtonRotor()1228 bool OBTorsion::IsProtonRotor()
1229 {
1230 bool Aprotor = true;
1231 bool Dprotor = true;
1232 vector<triple<OBAtom*,OBAtom*,double> >::iterator ad;
1233 for(ad = _ads.begin();ad != _ads.end() && (Aprotor || Dprotor);++ad)
1234 {
1235 if (ad->first->GetAtomicNum() != OBElements::Hydrogen)
1236 Aprotor = false;
1237 if (ad->second->GetAtomicNum() != OBElements::Hydrogen)
1238 Dprotor = false;
1239 }
1240 return (Aprotor || Dprotor);
1241 }
1242
1243 /*!
1244 **\brief adds a new torsion to the OBTorsion object
1245 */
AddTorsion(OBAtom * a,OBAtom * b,OBAtom * c,OBAtom * d)1246 bool OBTorsion::AddTorsion(OBAtom *a,OBAtom *b, OBAtom *c,OBAtom *d)
1247 {
1248 if(!Empty() && (b != _bc.first || c != _bc.second))
1249 return(false);
1250
1251 if(Empty())
1252 {
1253 _bc.first = b;
1254 _bc.second = c;
1255 }
1256
1257 triple<OBAtom*,OBAtom*,double> ad(a,d,0.0);
1258 _ads.push_back(ad);
1259
1260 return(true);
1261 }
1262
1263 /*!
1264 **\brief adds a new torsion to the OBTorsion object
1265 */
AddTorsion(quad<OBAtom *,OBAtom *,OBAtom *,OBAtom * > & atoms)1266 bool OBTorsion::AddTorsion(quad<OBAtom*,OBAtom*,OBAtom*,OBAtom*> &atoms)
1267 {
1268 if(!Empty() && (atoms.second != _bc.first || atoms.third != _bc.second))
1269 return(false);
1270
1271 if(Empty())
1272 {
1273 _bc.first = atoms.second;
1274 _bc.second = atoms.third;
1275 }
1276
1277 triple<OBAtom*,OBAtom*,double> ad(atoms.first,atoms.fourth,0.0);
1278 _ads.push_back(ad);
1279
1280 return(true);
1281 }
1282
1283 //\!brief OBTorsionData ctor
OBTorsionData()1284 OBTorsionData::OBTorsionData()
1285 : OBGenericData("TorsionData", OBGenericDataType::TorsionData)
1286 { }
1287
1288 //
1289 //member functions for OBTorsionData class - stores OBTorsion set
1290 //
OBTorsionData(const OBTorsionData & src)1291 OBTorsionData::OBTorsionData(const OBTorsionData &src)
1292 : OBGenericData(src), _torsions(src._torsions)
1293 { }
1294
operator =(const OBTorsionData & src)1295 OBTorsionData& OBTorsionData::operator =(const OBTorsionData &src)
1296 {
1297 if (this == &src)
1298 return(*this);
1299
1300 OBGenericData::operator =(src);
1301
1302 _source = src._source;
1303 _torsions = src._torsions;
1304
1305 return(*this);
1306 }
1307
Clear()1308 void OBTorsionData::Clear()
1309 {
1310 _torsions.clear();
1311 }
1312
SetData(OBTorsion & torsion)1313 void OBTorsionData::SetData(OBTorsion &torsion)
1314 {
1315 _torsions.push_back(torsion);
1316 }
1317
1318 /*!
1319 **\brief Fills a vector with the indices of the atoms in torsions (ordered abcd)
1320 **\param torsions reference to the vector of abcd atom sets
1321 **\return boolean success
1322 */
FillTorsionArray(std::vector<std::vector<unsigned int>> & torsions)1323 bool OBTorsionData::FillTorsionArray(std::vector<std::vector<unsigned int> > &torsions)
1324 {
1325 if(_torsions.empty())
1326 return(false);
1327
1328 vector<quad<OBAtom*,OBAtom*,OBAtom*,OBAtom*> > tmpquads,quads;
1329 vector<quad<OBAtom*,OBAtom*,OBAtom*,OBAtom*> >::iterator thisQuad;
1330 vector<OBTorsion>::iterator torsion;
1331
1332 //generate set of all 4 atom abcd's from torsion structure
1333 for (torsion = _torsions.begin();torsion != _torsions.end();++torsion)
1334 {
1335 tmpquads = torsion->GetTorsions();
1336 for(thisQuad = tmpquads.begin();thisQuad != tmpquads.end();++thisQuad)
1337 quads.push_back(*thisQuad);
1338 }
1339
1340 //fill array of torsion atoms
1341
1342 torsions.clear();
1343 torsions.resize(quads.size());
1344
1345 unsigned int ct = 0;
1346
1347 for (thisQuad = quads.begin();thisQuad != quads.end();++thisQuad,++ct)
1348 {
1349 torsions[ct].resize(4);
1350 torsions[ct][0] = thisQuad->first->GetIdx()-1;
1351 torsions[ct][1] = thisQuad->second->GetIdx()-1;
1352 torsions[ct][2] = thisQuad->third->GetIdx()-1;
1353 torsions[ct][3] = thisQuad->fourth->GetIdx()-1;
1354 }
1355
1356 return(true);
1357 }
1358
1359
1360 //
1361 //member functions for OBDOSData class
1362 //
1363
1364 /*!
1365 **\brief Assign the data
1366 **\param fermi The Fermi energy in eV
1367 **\param vEnergies Energy levels in eV
1368 **\param vDensities Density of states in (number of states) / (unit cell)
1369 **\param vIntegration Integrated DOS
1370 */
SetData(double fermi,const std::vector<double> & vEnergies,const std::vector<double> & vDensities,const std::vector<double> & vIntegration)1371 void OBDOSData::SetData(double fermi,
1372 const std::vector<double> & vEnergies,
1373 const std::vector<double> & vDensities,
1374 const std::vector<double> & vIntegration)
1375 {
1376 this->_fermi = fermi;
1377 this->_vEnergies = vEnergies;
1378 this->_vIntegration = vIntegration;
1379 this->_vDensities = vDensities;
1380 }
1381
1382 // member functions for OBOrbitalData
1383
LoadClosedShellOrbitals(std::vector<double> energies,std::vector<std::string> symmetries,unsigned int alphaHOMO)1384 void OBOrbitalData::LoadClosedShellOrbitals(std::vector<double> energies, std::vector<std::string> symmetries, unsigned int alphaHOMO)
1385 {
1386 if (energies.size() < symmetries.size())
1387 return; // something is very weird -- it's OK to pass no symmetries (we'll assume "A")
1388 if (energies.size() == 0)
1389 return;
1390 if (alphaHOMO > energies.size())
1391 return;
1392
1393 _alphaHOMO = alphaHOMO;
1394 _alphaOrbitals.clear();
1395 _betaHOMO = 0;
1396 _betaOrbitals.clear();
1397 _openShell = false;
1398
1399 if (symmetries.size() < energies.size()) // pad with "A" symmetry
1400 for (unsigned int i = symmetries.size(); i < energies.size(); ++i)
1401 symmetries.push_back("A");
1402
1403 OBOrbital currentOrbital;
1404 for (unsigned int i = 0; i < energies.size(); ++i)
1405 {
1406 if (i < alphaHOMO)
1407 currentOrbital.SetData(energies[i], 2.0, symmetries[i]);
1408 else
1409 currentOrbital.SetData(energies[i], 0.0, symmetries[i]);
1410
1411 _alphaOrbitals.push_back(currentOrbital);
1412 }
1413 }
1414
LoadAlphaOrbitals(std::vector<double> energies,std::vector<std::string> symmetries,unsigned int alphaHOMO)1415 void OBOrbitalData::LoadAlphaOrbitals(std::vector<double> energies, std::vector<std::string> symmetries, unsigned int alphaHOMO)
1416 {
1417 if (energies.size() < symmetries.size())
1418 return; // something is very weird -- it's OK to pass no symmetries (we'll assume "A")
1419 if (energies.size() == 0)
1420 return;
1421 if (alphaHOMO > energies.size())
1422 return;
1423
1424 _alphaHOMO = alphaHOMO;
1425 _alphaOrbitals.clear();
1426 _openShell = true;
1427
1428 if (symmetries.size() < energies.size()) // pad with "A" symmetry
1429 for (unsigned int i = symmetries.size(); i < energies.size(); ++i)
1430 symmetries.push_back("A");
1431
1432 OBOrbital currentOrbital;
1433 for (unsigned int i = 0; i < energies.size(); ++i)
1434 {
1435 if (i < alphaHOMO)
1436 currentOrbital.SetData(energies[i], 2.0, symmetries[i]);
1437 else
1438 currentOrbital.SetData(energies[i], 0.0, symmetries[i]);
1439
1440 _alphaOrbitals.push_back(currentOrbital);
1441 }
1442 }
1443
LoadBetaOrbitals(std::vector<double> energies,std::vector<std::string> symmetries,unsigned int betaHOMO)1444 void OBOrbitalData::LoadBetaOrbitals(std::vector<double> energies, std::vector<std::string> symmetries, unsigned int betaHOMO)
1445 {
1446 if (energies.size() < symmetries.size())
1447 return; // something is very weird -- it's OK to pass no symmetries (we'll assume "A")
1448 if (energies.size() == 0)
1449 return;
1450 if (betaHOMO > energies.size())
1451 return;
1452
1453 _betaHOMO = betaHOMO;
1454 _betaOrbitals.clear();
1455 _openShell = true;
1456
1457 if (symmetries.size() < energies.size()) // pad with "A" symmetry
1458 for (unsigned int i = symmetries.size(); i < energies.size(); ++i)
1459 symmetries.push_back("A");
1460
1461 OBOrbital currentOrbital;
1462 for (unsigned int i = 0; i < energies.size(); ++i)
1463 {
1464 if (i < betaHOMO)
1465 currentOrbital.SetData(energies[i], 2.0, symmetries[i]);
1466 else
1467 currentOrbital.SetData(energies[i], 0.0, symmetries[i]);
1468
1469 _betaOrbitals.push_back(currentOrbital);
1470 }
1471 }
1472
1473 //
1474 //member functions for OBElectronicTransitionData class
1475 //
1476
1477 /*!
1478 **\brief Assign the basic excitation data
1479 **\param vWavelengths Wavelengths in nm
1480 **\param vForces Oscillator strengths
1481 */
SetData(const std::vector<double> & vWavelengths,const std::vector<double> & vForces)1482 void OBElectronicTransitionData::SetData(const std::vector<double> & vWavelengths,
1483 const std::vector<double> & vForces)
1484 {
1485 this->_vWavelengths = vWavelengths;
1486 this->_vForces = vForces;
1487 }
1488
1489 /*!
1490 **\brief Assign the electronic dipole strengths
1491 **\param vEDipole Electronic dipole moment strength
1492 */
SetEDipole(const std::vector<double> & vEDipole)1493 void OBElectronicTransitionData::SetEDipole(const std::vector<double> & vEDipole)
1494 {
1495 this->_vEDipole = vEDipole;
1496 }
1497
1498 /*!
1499 **\brief Assign the rotatory strengths (velocity)
1500 **\param vRotatoryStrengthsVelocity Vector containing the rotatory strengths
1501 */
SetRotatoryStrengthsVelocity(const std::vector<double> & vRotatoryStrengthsVelocity)1502 void OBElectronicTransitionData::SetRotatoryStrengthsVelocity(const std::vector<double> & vRotatoryStrengthsVelocity)
1503 {
1504 this->_vRotatoryStrengthsVelocity = vRotatoryStrengthsVelocity;
1505 }
1506
1507 /*!
1508 **\brief Assign the rotatory strengths (length)
1509 **\param vRotatoryStrengthsLength Vector containing the rotatory strengths
1510 */
SetRotatoryStrengthsLength(const std::vector<double> & vRotatoryStrengthsLength)1511 void OBElectronicTransitionData::SetRotatoryStrengthsLength(const std::vector<double> & vRotatoryStrengthsLength)
1512 {
1513 this->_vRotatoryStrengthsLength = vRotatoryStrengthsLength;
1514 }
1515
1516 //
1517 //member functions for OBVibrationData class
1518 //
1519
1520 /*!
1521 **\brief Assign the data
1522 **\param vLx Normal modes in 1/sqrt(a.u.)
1523 **\param vFrequencies Harmonic frequencies in inverse centimeters
1524 **\param vIntensities Infrared absorption intensities in KM/Mole
1525 */
SetData(const std::vector<std::vector<vector3>> & vLx,const std::vector<double> & vFrequencies,const std::vector<double> & vIntensities)1526 void OBVibrationData::SetData(const std::vector< std::vector< vector3 > > & vLx,
1527 const std::vector<double> & vFrequencies,
1528 const std::vector<double> & vIntensities)
1529 {
1530 this->_vLx = vLx;
1531 this->_vFrequencies = vFrequencies;
1532 this->_vIntensities = vIntensities;
1533 }
1534
1535 /*!
1536 **\brief Assign the data
1537 **\param vLx Normal modes in 1/sqrt(a.u.)
1538 **\param vFrequencies Harmonic frequencies in inverse centimeters
1539 **\param vIntensities Infrared absorption intensities in KM/Mole
1540 **\param vRamanActivities Raman activities
1541 */
SetData(const std::vector<std::vector<vector3>> & vLx,const std::vector<double> & vFrequencies,const std::vector<double> & vIntensities,const std::vector<double> & vRamanActivities)1542 void OBVibrationData::SetData(const std::vector< std::vector< vector3 > > & vLx,
1543 const std::vector<double> & vFrequencies,
1544 const std::vector<double> & vIntensities,
1545 const std::vector<double> & vRamanActivities)
1546 {
1547 this->_vLx = vLx;
1548 this->_vFrequencies = vFrequencies;
1549 this->_vIntensities = vIntensities;
1550 this->_vRamanActivities = vRamanActivities;
1551 }
1552
1553
1554 /*!
1555 **\brief Get the number of frequencies
1556 */
GetNumberOfFrequencies() const1557 unsigned int OBVibrationData::GetNumberOfFrequencies() const
1558 {
1559 return this->_vFrequencies.size();
1560 }
1561
Clear()1562 void OBFreeGrid::Clear()
1563 {
1564 _points.clear();
1565 }
1566
1567 } //end namespace OpenBabel
1568
1569 //! \file generic.cpp
1570 //! \brief Handle OBGenericData classes. Custom data for atoms, bonds, etc.
1571