root/src/xtalopt/structures/molecularxtal.cpp @ 765823687709e2ae5f572a5c5ad94322a045998f

Revision 765823687709e2ae5f572a5c5ad94322a045998f, 23.4 KB (checked in by David C. Lonie <loniedavid@…>, 13 months ago)

Initial version of MolecularXtal?, SubMolecule?, and SMSource.

  • Property mode set to 100644
Line 
1/**********************************************************************
2  MolecularXtal - Molecular-crystal themed subclass to Xtal
3
4  Copyright (C) 2011 by David C. Lonie
5
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation version 2 of the License.
9
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  GNU General Public License for more details.
14 ***********************************************************************/
15
16#include <xtalopt/structures/molecularxtal.h>
17
18#include <xtalopt/structures/submolecule.h>
19
20#include <globalsearch/macros.h>
21#include <globalsearch/obeigenconv.h>
22
23#include <avogadro/atom.h>
24#include <avogadro/bond.h>
25
26extern "C" {
27#include <spglib/spglib.h>
28}
29
30#include <xtalcomp/xtalcomp.h>
31
32using namespace Avogadro;
33
34namespace XtalOpt {
35
36  MolecularXtal::MolecularXtal(QObject *parent) :
37    Xtal(parent)
38  {
39  }
40
41  MolecularXtal::MolecularXtal(double A, double B, double C,
42                               double Alpha, double Beta, double Gamma,
43                               QObject *parent) :
44    Xtal(A, B, C, Alpha, Beta, Gamma, parent)
45  {
46  }
47
48  MolecularXtal::MolecularXtal(const MolecularXtal &other) :
49    Xtal(other.parent()),
50    m_preOptStepCount(0),
51    m_preOptStep(0),
52    m_needsPreOpt(false),
53    m_mxtalOpt(NULL)
54  {
55    *this = other;
56  }
57
58  MolecularXtal::~MolecularXtal()
59  {
60    for (int i = 0; i < this->m_subMolecules.size(); ++i) {
61      delete this->m_subMolecules.at(i);
62      this->m_subMolecules[i] = NULL;
63    }
64    this->m_subMolecules.clear();
65  }
66
67  GlobalSearch::Structure& MolecularXtal::copyStructure(
68      const GlobalSearch::Structure &other)
69  {
70    this->Xtal::copyStructure(other);
71
72    const MolecularXtal *otherMXtal =
73        qobject_cast<const MolecularXtal*>(&other);
74    if (otherMXtal == NULL) {
75      qWarning() << Q_FUNC_INFO << "Other structure is not a MolecularXtal.";
76      return *this;
77    }
78
79    // Remove existing submolecules
80    for (int i = 0; i < this->m_subMolecules.size(); ++i) {
81      delete this->m_subMolecules[i];
82      this->m_subMolecules[i] = NULL;
83    }
84    m_subMolecules.clear();
85    m_subMolecules.reserve(otherMXtal->m_subMolecules.size());
86
87    // Copy the submolecules from other to this
88    for (QList<SubMolecule*>::const_iterator
89         it = otherMXtal->m_subMolecules.constBegin(),
90         it_end = otherMXtal->m_subMolecules.constEnd(); it != it_end; ++it) {
91
92      SubMolecule *sub = new SubMolecule ();
93      sub->m_sourceId = (*it)->m_sourceId;
94      sub->m_mxtal = this;
95      sub->m_atoms.reserve((*it)->m_atoms.size());
96
97      for (QList<Atom*>::const_iterator ait = (*it)->m_atoms.constBegin(),
98           ait_end = (*it)->m_atoms.constEnd(); ait != ait_end; ++ait) {
99        sub->m_atoms.append(this->atomById((*ait)->id()));
100      }
101
102      sub->m_bonds.reserve((*it)->m_bonds.size());
103      for (QList<Bond*>::const_iterator bit = (*it)->m_bonds.constBegin(),
104           bit_end = (*it)->m_bonds.constEnd(); bit != bit_end; ++bit) {
105        sub->m_bonds.append(this->bondById((*bit)->id()));
106      }
107
108      this->m_subMolecules.append(sub);
109    }
110
111    return *this;
112  }
113
114  bool MolecularXtal::operator ==(const MolecularXtal &other) const
115  {
116    // Compare coordinates using the default tolerances
117    if (!this->MolecularXtal::compareCoordinates(other))
118      return false;
119
120    return true;
121  }
122
123  bool MolecularXtal::compareCoordinates(const MolecularXtal &other,
124                                         const double lengthTol,
125                                         const double angleTol) const
126  {
127    // Cell matrices as row vectors
128    const OpenBabel::matrix3x3 thisCellOB (this->cell()->GetCellMatrix());
129    const OpenBabel::matrix3x3 otherCellOB (other.cell()->GetCellMatrix());
130    XcMatrix thisCell (thisCellOB(0,0), thisCellOB(0,1), thisCellOB(0,2),
131                       thisCellOB(1,0), thisCellOB(1,1), thisCellOB(1,2),
132                       thisCellOB(2,0), thisCellOB(2,1), thisCellOB(2,2));
133    XcMatrix otherCell(otherCellOB(0,0), otherCellOB(0,1), otherCellOB(0,2),
134                       otherCellOB(1,0), otherCellOB(1,1), otherCellOB(1,2),
135                       otherCellOB(2,0), otherCellOB(2,1), otherCellOB(2,2));
136
137    // vectors of fractional coordinates and atomic numbers
138    std::vector<XcVector> thisCoords;
139    std::vector<XcVector> otherCoords;
140    std::vector<unsigned int> thisTypes;
141    std::vector<unsigned int> otherTypes;
142    thisCoords.reserve(this->numAtoms());
143    thisTypes.reserve(this->numAtoms());
144    otherCoords.reserve(other.numAtoms());
145    otherTypes.reserve(other.numAtoms());
146    Eigen::Vector3d pos;
147    for (QList<Atom*>::const_iterator it = this->m_atomList.constBegin(),
148           it_end = this->m_atomList.constEnd(); it != it_end; ++it) {
149      // Don't compare hydrogens -- too floppy.
150      if ((*it)->isHydrogen()) {
151        continue;
152      }
153      pos = this->cartToFrac(*(*it)->pos());
154      thisCoords.push_back(XcVector(pos.x(), pos.y(), pos.z()));
155      thisTypes.push_back((*it)->atomicNumber());
156    }
157    for (QList<Atom*>::const_iterator it = other.m_atomList.constBegin(),
158           it_end = other.m_atomList.constEnd(); it != it_end; ++it) {
159      // Don't compare hydrogens -- too floppy.
160      if ((*it)->isHydrogen()) {
161        continue;
162      }
163      pos = other.cartToFrac(*(*it)->pos());
164      otherCoords.push_back(XcVector(pos.x(), pos.y(), pos.z()));
165      otherTypes.push_back((*it)->atomicNumber());
166    }
167
168    return XtalComp::compare(thisCell,  thisTypes,  thisCoords,
169                             otherCell, otherTypes, otherCoords,
170                             NULL, lengthTol, angleTol);
171  }
172
173  int MolecularXtal::numSubMolecules() const
174  {
175    return m_subMolecules.size();
176  }
177
178  QList<SubMolecule*> MolecularXtal::subMolecules() const
179  {
180    return m_subMolecules;
181  }
182
183  SubMolecule * MolecularXtal::subMolecule(int index)
184  {
185    return this->m_subMolecules.at(index);
186  }
187
188  const SubMolecule * MolecularXtal::subMolecule(int index) const
189  {
190    return this->m_subMolecules.at(index);
191  }
192
193  bool MolecularXtal::verifySubMolecules() const
194  {
195    // Cache and pass the cell matrix to each submolecule
196    const Eigen::Matrix3d cellRowMatrix =
197        OB2Eigen(this->cell()->GetCellMatrix());
198
199    // Verify bonds in submolecules
200    for (QList<SubMolecule*>::const_iterator it = m_subMolecules.constBegin(),
201         it_end = m_subMolecules.constEnd(); it != it_end; ++it) {
202      if (!(*it)->verifyBonds(cellRowMatrix)) {
203        return false;
204      }
205    }
206
207    return true;
208  }
209
210  // helper function. Returns -1 if the atom is not "between" the bonded atoms
211  inline double squaredDistanceToBond(const Eigen::Vector3d &bondVec,
212                                      const Eigen::Vector3d &startAtomPos,
213                                      const Eigen::Vector3d &testPos,
214                                      const double bondLengthSquared)
215  {
216    const Eigen::Vector3d beginToPos (testPos - startAtomPos);
217    const Eigen::Vector3d proj
218        ((bondVec.dot(beginToPos) / bondVec.squaredNorm()) * bondVec);
219
220    // If the dot product of the projection and the bond vector is negative,
221    // then the test point is on the other side of startAtom than the bond.
222    if (proj.dot(bondVec) < 0.0) {
223      return -1.0;
224    }
225
226    // If the projection vector is larger than the bond, then the atom is on
227    // the other side of the endAtom.
228    if (proj.squaredNorm() > bondLengthSquared) {
229      return -1.0;
230    }
231
232    return (proj - beginToPos).squaredNorm();
233  }
234
235  bool MolecularXtal::checkAtomToBondDistances(double minDistance)
236  {
237    const double r2 = minDistance * minDistance;
238
239    // Cache list of translations
240    Eigen::Vector3d translations[27];
241    std::vector<OpenBabel::vector3> obvecs
242        (this->OBUnitCell()->GetCellVectors());
243    const Eigen::Vector3d v1 (obvecs[0].AsArray());
244    const Eigen::Vector3d v2 (obvecs[1].AsArray());
245    const Eigen::Vector3d v3 (obvecs[2].AsArray());
246
247    int transIndex = -1;
248    for (double x = -1.0; x < 1.5; ++x) {
249      for (double y = -1.0; y < 1.5; ++y) {
250        for (double z = -1.0; z < 1.5; ++z) {
251          translations[++transIndex] = x * v1 + y * v2 + z * v3;
252        }
253      }
254    }
255
256    // For each submolecule:
257    for (QList<SubMolecule*>::const_iterator it = m_subMolecules.constBegin(),
258         it_end = m_subMolecules.constEnd(); it != it_end; ++it) {
259
260      // Get the coherent coordinates
261      const QVector<Eigen::Vector3d> cohVecs ((*it)->getCoherentCoordinates());
262      Q_ASSERT(cohVecs.size() == (*it)->m_atoms.size());
263
264      // For each bond in current submolecule
265      for (QList<Bond*>::const_iterator bit = (*it)->m_bonds.constBegin(),
266           bit_end = (*it)->m_bonds.constEnd(); bit != bit_end; ++bit) {
267
268        // Cache the bondVector and the start atom position
269        Atom *begin = (*bit)->beginAtom();
270        Atom *end = (*bit)->endAtom();
271        const Eigen::Vector3d &beginPos = cohVecs[(*it)->m_atoms.indexOf(begin)];
272        const Eigen::Vector3d &endPos   = cohVecs[(*it)->m_atoms.indexOf(end)];
273        const Eigen::Vector3d bondVec (endPos - beginPos);
274        const double bondLengthSquared = bondVec.squaredNorm();
275
276        // For each atom in mxtal
277        for (QList<Atom*>::const_iterator ait = m_atomList.constBegin(),
278             ait_end = m_atomList.constEnd(); ait != ait_end; ++ait) {
279
280          // Skip the atoms in the current bond
281          if ((*ait) == begin || (*ait) == end)
282            continue;
283
284          // Cache a reference to this atom's original position
285          const Eigen::Vector3d &testPos (*(*ait)->pos());
286
287          // Test each translated position.
288          for (int i = 0; i < 27; ++i) {
289
290            // Calculate the distance from the atom to the bond
291            const double dist = squaredDistanceToBond(
292                  bondVec, beginPos, testPos + translations[i],
293                  bondLengthSquared);
294
295            // If dist is less than 0, then the test atom is not between the
296            // bonded atoms ( and thus ok )
297            if (dist < 0.0)
298              continue;
299
300            // If the distance is too small, return false
301            if (dist < r2) {
302              return false;
303
304            } // if (distance < r2)
305          } // For each translation
306        } // For each atom
307      } // foreach bond
308    } // foreach submolecule
309
310    // If all atoms pass, return true
311    return true;
312  }
313
314  void MolecularXtal::findSpaceGroup(double prec)
315  {
316    // Check that the precision is reasonable
317    if (prec < 1e-5) {
318      qWarning() << "MolecularXtal::findSpaceGroup called with a precision of"
319                 << prec << ". This is likely an error. Resetting prec to"
320                 << 0.05 << ".";
321      prec = 0.05;
322    }
323
324    // reset space group to 0 so we can exit if needed
325    m_spgNumber = 0;
326    m_spgSymbol = "Unknown";
327    int num = this->numAtoms();
328    // Remove hydrogens from count
329    foreach (const Atom *a, this->m_atomList) {
330      if (a->isHydrogen())
331        --num;
332    }
333
334    // if no unit cell or atoms, exit
335    if (!cell() || num == 0) {
336      qWarning() << "MolecularXtal::findSpaceGroup(" << prec << ") called on "
337                    "atom with no cell or atoms!";
338      return;
339    }
340
341    // get lattice matrix
342    std::vector<OpenBabel::vector3> vecs = cell()->GetCellVectors();
343    OpenBabel::vector3 obU1 = vecs[0];
344    OpenBabel::vector3 obU2 = vecs[1];
345    OpenBabel::vector3 obU3 = vecs[2];
346    double lattice[3][3] = {
347      {obU1.x(), obU2.x(), obU3.x()},
348      {obU1.y(), obU2.y(), obU3.y()},
349      {obU1.z(), obU2.z(), obU3.z()}
350    };
351
352    // Get atom info
353    double (*positions)[3] = new double[num][3];
354    int *types = new int[num];
355    Eigen::Vector3d fracCoord;
356    int ind = 0;
357    foreach (const Atom *a, this->m_atomList) {
358      if (a->isHydrogen())
359        continue;
360      types[ind] = a->atomicNumber();
361      fracCoord = this->cartToFrac(*a->pos());
362      positions[ind][0] = fracCoord.x();
363      positions[ind][1] = fracCoord.y();
364      positions[ind][2] = fracCoord.z();
365      ++ind;
366    }
367
368    // find spacegroup
369    char symbol[21];
370    m_spgNumber = spg_get_international(symbol,
371                                        lattice,
372                                        positions,
373                                        types,
374                                        num, prec);
375
376    delete [] positions;
377    delete [] types;
378
379    // Update the OBUnitCell object.
380    cell()->SetSpaceGroup(m_spgNumber);
381
382    // Fail if m_spgNumber is still 0
383    if (m_spgNumber == 0) {
384      return;
385    }
386
387    // Set and clean up the symbol string
388    m_spgSymbol = QString(symbol);
389    m_spgSymbol.remove(" ");
390    return;
391  }
392
393  void MolecularXtal::setVolume(double Volume)
394  {
395    // Get scaling factor
396    double factor = pow(Volume/cell()->GetCellVolume(), 1.0/3.0); // Cube root
397
398    // Store submolecule centers in fractional units
399    QList<SubMolecule*> submols = this->subMolecules();
400    QList<Eigen::Vector3d> fracCenterList;
401    for (int i = 0; i < submols.size(); i++)
402      fracCenterList.append(cartToFrac(submols.at(i)->center()));
403
404    // Scale cell
405    setCellInfo(factor * cell()->GetA(),
406                factor * cell()->GetB(),
407                factor * cell()->GetC(),
408                cell()->GetAlpha(),
409                cell()->GetBeta(),
410                cell()->GetGamma());
411
412    // Recalculate coordinates:
413    for (int i = 0; i < submols.size(); i++)
414      submols.at(i)->setCenter(fracToCart(fracCenterList.at(i)));
415  }
416
417  void MolecularXtal::rescaleCell(double a, double b, double c,
418                                  double alpha, double beta, double gamma)
419  {
420    if (!a && !b && !c && !alpha && !beta && !gamma) {
421      return;
422    }
423
424    this->rotateCellAndCoordsToStandardOrientation();
425
426    // Store position of atoms in fractional units
427    QList<SubMolecule*> submols = this->subMolecules();
428    QList<Eigen::Vector3d> fracCoordsList;
429    for (int i = 0; i < submols.size(); i++)
430      fracCoordsList.append(cartToFrac(submols.at(i)->center()));
431
432    double nA = getA();
433    double nB = getB();
434    double nC = getC();
435    double nAlpha = getAlpha();
436    double nBeta = getBeta();
437    double nGamma = getGamma();
438
439    // Set angles and reset volume
440    if (alpha || beta || gamma) {
441      double volume = getVolume();
442      if (alpha) nAlpha = alpha;
443      if (beta) nBeta = beta;
444      if (gamma) nGamma = gamma;
445      setCellInfo(nA,
446                  nB,
447                  nC,
448                  nAlpha,
449                  nBeta,
450                  nGamma);
451      setVolume(volume);
452    }
453
454    if (a || b || c) {
455      // Initialize variables
456      double scale_primary, scale_secondary, scale_tertiary;
457
458      // Set lengths while preserving volume
459      // Case one length is static
460      if (a && !b && !c) {        // A
461        scale_primary = a / nA;
462        scale_secondary = pow(scale_primary, 0.5);
463        nA = a;
464        nB *= scale_secondary;
465        nC *= scale_secondary;
466      }
467      else if (!a && b && !c) {   // B
468        scale_primary = b / nB;
469        scale_secondary = pow(scale_primary, 0.5);
470        nB = b;
471        nA *= scale_secondary;
472        nC *= scale_secondary;
473      }
474      else if (!a && !b && c) {   // C
475        scale_primary = c / nC;
476        scale_secondary = pow(scale_primary, 0.5);
477        nC = c;
478        nA *= scale_secondary;
479        nB *= scale_secondary;
480      }
481      // Case two lengths are static
482      else if (a && b && !c) {    // AB
483        scale_primary   = a / nA;
484        scale_secondary = b / nB;
485        scale_tertiary  = scale_primary * scale_secondary;
486        nA = a;
487        nB = b;
488        nC *= scale_tertiary;
489      }
490      else if (a && !b && c) {    // AC
491        scale_primary   = a / nA;
492        scale_secondary = c / nC;
493        scale_tertiary  = scale_primary * scale_secondary;
494        nA = a;
495        nC = c;
496        nB *= scale_tertiary;
497      }
498      else if (!a && b && c) {    // BC
499        scale_primary   = c / nC;
500        scale_secondary = b / nB;
501        scale_tertiary  = scale_primary * scale_secondary;
502        nC = c;
503        nB = b;
504        nA *= scale_tertiary;
505      }
506      // Case three lengths are static
507      else if (a && b && c) {     // ABC
508        nA = a;
509        nB = b;
510        nC = c;
511      }
512
513      // Update unit cell
514      setCellInfo(nA,
515                  nB,
516                  nC,
517                  nAlpha,
518                  nBeta,
519                  nGamma);
520    }
521
522    // Recalculate coordinates:
523    for (int i = 0; i < submols.size(); i++)
524      submols.at(i)->setCenter(fracToCart(fracCoordsList.at(i)));
525  }
526
527  void MolecularXtal::addSubMolecule(SubMolecule *sub)
528  {
529    // Is the handle/submolecule valid?
530    if (!sub || sub->numAtoms() == 0) {
531      qWarning() << Q_FUNC_INFO << "Attempt to add NULL/empty submolecule?";
532      return;
533    }
534
535    // Do we already own this subMolecule?
536    if (m_subMolecules.contains(sub)) {
537      qWarning() << "Attempting to add SubMolecule @" << sub
538                 << " twice. Aborting.";
539      return;
540    }
541
542    // Create atoms and bonds for the subMolecule to use
543    QList<Atom*> atoms;
544    QList<Bond*> bonds;
545#if QT_VERSION >= 0x040700
546    atoms.reserve(sub->numAtoms());
547    atoms.reserve(sub->numBonds());
548#endif
549
550    for (int i = 0; i < sub->numAtoms(); ++i) {
551      atoms.append(this->addAtom());
552    }
553    for (int i = 0; i < sub->numBonds(); ++i) {
554      bonds.append(this->addBond());
555    }
556
557    // Take ownership of the submolecule:
558    sub->takeOwnership(this, atoms, bonds);
559
560    m_subMolecules.append(sub);
561  }
562
563  void MolecularXtal::removeSubMolecule(SubMolecule *sub)
564  {
565    // Is the handle/submolecule valid?
566    if (!sub) {
567      qWarning() << Q_FUNC_INFO << "Attempt to remove NULL submolecule?";
568      return;
569    }
570
571    if (!m_subMolecules.contains(sub)) {
572      qWarning() << "Attempting to remove SubMolecule @" << sub
573                 << ", which does not belong to this MolecularXtal ("
574                 << this->getIDString() << " @" << this << ". Aborting.";
575      return;
576    }
577
578    // Cache list of atoms and bonds owned by submolecule
579    QList<Atom*> atoms = sub->atoms();
580    QList<Bond*> bonds = sub->bonds();
581
582    m_subMolecules.removeAll(sub);
583    sub->releaseOwnership();
584
585    // Remove atoms and bonds previously held by submolecule.
586    // Take out bonds first.
587    for (QList<Bond*>::const_iterator it = bonds.constBegin(),
588         it_end = bonds.constEnd(); it != it_end; ++it) {
589      this->removeBond(*it);
590    }
591    for (QList<Atom*>::const_iterator it = atoms.constBegin(),
592         it_end = atoms.constEnd(); it != it_end; ++it) {
593      this->removeAtom(*it);
594    }
595
596  }
597
598  void MolecularXtal::replaceSubMolecule(int i, SubMolecule *newSub)
599  {
600    SubMolecule *oldSub = m_subMolecules.at(i);
601    this->removeSubMolecule(oldSub);
602    this->addSubMolecule(newSub);
603
604    // Move the new submol to position i
605    m_subMolecules.insert(i, m_subMolecules.takeLast());
606
607    // Clean up the old submol
608    oldSub->deleteLater();
609  }
610
611  void MolecularXtal::readMolecularXtalSettings(const QString &filename)
612  {
613    SETTINGS(filename);
614
615    if (!settings->value("molecularxtal/mxtalIsValid", false).toBool()) {
616      qWarning() << "Cannot read invalid mxtal settings for mxtal"
617                 << this->getIDString();
618      return;
619    }
620
621    // Clear existing bonds. These will be recreated below
622    while (m_bondList.size() != 0) {
623      this->removeBond(m_bondList.first());
624    }
625
626    int lengSubMoleculeArr =
627        settings->beginReadArray("molecularxtal/submolecules");
628    for (int i = 0; i < lengSubMoleculeArr; ++i) {
629      settings->setArrayIndex(i);
630
631      // Create empty submolecule data
632      SubMolecule *sub = new SubMolecule(this);
633
634      sub->setSourceId(static_cast<unsigned long>(
635                         settings->value("sourceId", -1).toULongLong()));
636
637      // Read atom indices
638      int lenAtomArr = settings->beginReadArray("atoms");
639      for (int j = 0; j < lenAtomArr; ++j) {
640        settings->setArrayIndex(j);
641        int ind = settings->value("ind", -1).toInt();
642        if (ind < 0 || ind > this->numAtoms() - 1) {
643          qFatal(QString("Invalid atom index %1 for Structure %2 in %3.")
644                 .arg(ind).arg(this->getIDString()).arg(filename)
645                 .toStdString().c_str());
646        }
647        sub->m_atoms.append(this->atom(ind));
648      }
649      settings->endArray();
650
651      // Read bond info
652      int lenBondArr = settings->beginReadArray("bonds");
653      for (int j = 0; j < lenBondArr; ++j) {
654        settings->setArrayIndex(j);
655        int begInd = settings->value("begInd", -1).toInt();
656        int endInd = settings->value("endInd", -1).toInt();
657        short order = static_cast<short>(settings->value("order", -1).toInt());
658        if (begInd < 0 || begInd > this->numAtoms() - 1) {
659          qFatal(QString("Invalid atom index %1 for Structure %2 in %3.")
660                 .arg(begInd).arg(this->getIDString()).arg(filename)
661                 .toStdString().c_str());
662        }
663        if (endInd < 0 || endInd > this->numAtoms() - 1) {
664          qFatal(QString("Invalid atom index %1 for Structure %2 in %3.")
665                 .arg(endInd).arg(this->getIDString()).arg(filename)
666                 .toStdString().c_str());
667        }
668        Bond *bond = this->addBond();
669        bond->setBegin(m_atomList[begInd]);
670        bond->setEnd(m_atomList[endInd]);
671        bond->setOrder(order);
672        sub->m_bonds.append(bond);
673      }
674      settings->endArray();
675
676      // Add submolecule to this
677      sub->m_mxtal = this;
678      m_subMolecules.append(sub);
679
680    }
681    settings->endArray();
682  }
683
684  void MolecularXtal::writeMolecularXtalSettings(const QString &filename) const
685  {
686    SETTINGS(filename);
687
688<<<<<<< HEAD
689    settings->beginWriteArray("submolecules");
690=======
691    if (this->m_optimizerLookup.isEmpty()) {
692      settings->setValue("molecularxtal/mxtalIsValid", false);
693      return; // Cannot serialize yet
694    }
695    settings->setValue("molecularxtal/mxtalIsValid", true);
696
697    settings->beginWriteArray("molecularxtal/submolecules");
698>>>>>>> 902ab7c... f structures
699    for (int i = 0; i < this->numSubMolecules(); ++i) {
700      settings->setArrayIndex(i);
701
702      // cache submolecule data
703      const SubMolecule *sub = this->subMolecule(i);
704      settings->setValue("sourceId", static_cast<unsigned long long>(
705                           sub->sourceId()));
706      const QList<Atom*> atoms = sub->atoms();
707      const QList<Bond*> bonds = sub->bonds();
708
709      // Write atom ids
710      settings->beginWriteArray("atoms");
711      for (int j = 0; j < atoms.size(); ++j) {
712        settings->setArrayIndex(j);
713<<<<<<< HEAD
714        settings->setValue("ind",static_cast<unsigned long long>(
715                             atoms.at(j)->index()));
716=======
717        settings->setValue("ind", static_cast<int>(atoms.at(j)->index()));
718>>>>>>> 902ab7c... f structures
719      }
720      settings->endArray();
721
722      // Write bond ids
723      settings->beginWriteArray("bonds");
724      for (int j = 0; j < bonds.size(); ++j) {
725        settings->setArrayIndex(j);
726<<<<<<< HEAD
727        settings->setValue("ind",static_cast<unsigned long long>(
728                             bonds.at(j)->index()));
729=======
730        Bond *curbond = bonds[j];
731        int begIndex = static_cast<int>(curbond->beginAtom()->index());
732        int endIndex = static_cast<int>(curbond->endAtom()->index());
733        settings->setValue("begInd", begIndex);
734        settings->setValue("endInd", endIndex);
735        settings->setValue("order", static_cast<int>(curbond->order()));
736>>>>>>> 902ab7c... f structures
737      }
738      settings->endArray();
739    }
740    settings->endArray();
741  }
742
743
744
745} // end namespace XtalOpt
Note: See TracBrowser for help on using the browser.