atomset.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                          atomset.cpp  -  description
00003                              -------------------
00004     begin                : Mon Sep 9 2002
00005     copyright            : (C) 2002-2006 by Ben Swerts
00006     email                : bswerts@users.sourceforge.net
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00019 
00041 
00042 
00043 
00045 
00046 // C++ header files
00047 #include <cmath>         
00048 
00049 // STL header files
00050 #include <algorithm>
00051 
00052 // Qt header files
00053 #include <qcolor.h>
00054 #include <qdom.h>
00055 #include <qstring.h>
00056 #include <qstringlist.h>
00057 
00058 #include <qdatetime.h>
00059 
00060 // Xbrabo header files
00061 #include "atomset.h"
00062 #include "domutils.h"
00063 #include "vector3d.h" // includes the Point3D header file
00064 
00068 
00070 AtomSet::AtomSet() :
00071   numAtoms(0),
00072   forces(0),
00073   chargesMulliken(0),
00074   chargesStockholder(0),
00075   boxMax(new Point3D<double>()),
00076   boxMin(new Point3D<double>()),
00077   dirtyBox(true)
00079 {
00080 
00081 }
00082 
00084 AtomSet::~AtomSet()
00086 {
00087   clearProperties(); // releases all allocated memory
00088   delete boxMax;
00089   delete boxMin;
00090 }
00091 
00093 void AtomSet::clear()
00095 { 
00096   coords.clear();
00097   colors.clear();
00098   clearProperties();
00099   bonds1.clear();
00100   bonds2.clear();
00101   numAtoms = 0;
00102   setChanged(false);
00103 }
00104 
00106 void AtomSet::reserve(const unsigned int size)
00108 { 
00109   if(size <= coords.size())
00110     return;
00111 
00112   coords.reserve(size);
00113   colors.reserve(size);
00114   if(forces != 0)
00115     forces->reserve(size);
00116   if(chargesMulliken != 0)
00117     chargesMulliken->reserve(size);
00118   if(chargesStockholder != 0)
00119     chargesStockholder->reserve(size);
00120 }
00121 
00123 void AtomSet::addAtom(const Point3D<double>& location, const unsigned int atomicNumber, const QColor color, const int index)
00128 {
00130   if(numAtoms == coords.max_size())
00131   {
00132     qDebug("AtomSet::addAtom: the maximum number of atoms has been reached.");
00133     return;
00134   }
00135 
00137   unsigned int atomNum = atomicNumber;
00138   if(atomNum > maxElements)
00139     atomNum = 0; // the unknown element
00141   Point3D<double> newAtom(location);
00142   newAtom.setID(atomNum);
00143 
00145   if(index < 0 || static_cast<unsigned int>(index) > numAtoms)
00146   {
00148     coords.push_back(newAtom);
00149     colors.push_back(color);
00150   }
00151   else
00152   {
00153     if(static_cast<unsigned int>(index) < numAtoms - 1)
00154     {
00156       vector<Point3D<double> >::iterator it = coords.begin();
00157       it += index;
00158       coords.insert(it, newAtom);
00159       vector<QColor>::iterator it2 = colors.begin();
00160       it2 += index;
00161       colors.insert(it2, color);
00162     }
00163   }
00164   numAtoms++;
00165 
00166   setGeometryChanged(); // also calls setChanged and clearProperties
00167 }
00168 
00170 void AtomSet::addAtom(const Point3D<double>& location, const unsigned int atomicNumber, const int index)
00172 {
00173   addAtom(location, atomicNumber, stdColor(atomicNumber), index);
00174 }
00175 
00177 void AtomSet::addAtom(const double x, const double y, const double z, const unsigned int atomicNumber, const QColor color, const int index)
00179 {
00180   addAtom(Point3D<double>(x, y, z), atomicNumber, color, index);
00181 }
00182 
00184 void AtomSet::addAtom(const double x, const double y, const double z, const unsigned int atomicNumber, const int index)
00186 {
00187   addAtom(Point3D<double>(x, y, z), atomicNumber, stdColor(atomicNumber), index);
00188 }
00189 
00191 void AtomSet::removeAtom(const unsigned int index)
00194 {
00195   if((numAtoms > 0) && (index < numAtoms))
00196   {
00197     if(index == numAtoms - 1)
00198     {
00199       coords.pop_back();
00200       colors.pop_back();
00201     }
00202     else
00203     {
00204       vector<Point3D<double> >::iterator it = coords.begin();
00205       it += index;
00206       coords.erase(it);
00207       vector<QColor>::iterator it2 = colors.begin();
00208       it2 += index;
00209       colors.erase(it2);
00210     }
00211     numAtoms--;
00212     setGeometryChanged();
00213   }
00214 }
00215 
00217 void AtomSet::setX(const unsigned int index, const double x)
00220 {  
00221   if(index >= numAtoms)
00222     return;
00223   
00224   coords[index].setValues(x, coords[index].y(), coords[index].z());
00225   setGeometryChanged();
00226 }
00227 
00229 void AtomSet::setY(const unsigned int index, const double y)
00232 { 
00233   if(index >= numAtoms)
00234     return;
00235   
00236   coords[index].setValues(coords[index].x(), y, coords[index].z());
00237   setGeometryChanged();  
00238 }
00239 
00241 void AtomSet::setZ(const unsigned int index, const double z)
00244 {  
00245   if(index >= numAtoms)
00246     return;
00247   
00248   coords[index].setValues(coords[index].x(), coords[index].y(), z);
00249   setGeometryChanged();
00250 }
00251 
00253 void AtomSet::setColor(const unsigned int index, const QColor color)
00255 {
00256   if(index >= numAtoms)
00257     return;
00258   
00259   colors[index] = color;
00260   setChanged();
00261 }
00262 
00264 void AtomSet::setCharges(const vector<double>& charges, const ChargeType type, const QString scf, const QString density)
00271 {
00272   if(charges.size() != numAtoms || type == None)
00273     return;
00274   
00275   if(type == Mulliken)
00276   {
00278     if(chargesMulliken == 0)
00279     {
00280       chargesMulliken = new vector<double>();
00281       chargesMulliken->reserve(numAtoms);
00282     }
00283     chargesMulliken->assign(charges.begin(), charges.end());
00284     chargesMullikenSCF = scf;
00285     chargesMullikenDensity = density;
00286   }
00287   else
00288   {
00290     if(chargesStockholder == 0)
00291     {
00292       chargesStockholder = new vector<double>();
00293       chargesStockholder->reserve(numAtoms);
00294     }
00295     chargesStockholder->assign(charges.begin(), charges.end());
00296     chargesStockholderSCF = scf;
00297     chargesStockholderDensity = density;
00298   }
00299   setChanged();
00300 }
00301 
00303 void AtomSet::clearCharges(const ChargeType type)
00305 {
00306   if(type == None)
00307     return;
00308   else if(type == Mulliken)
00309   {
00310     if(chargesMulliken == 0)
00311       return;
00312     delete chargesMulliken;
00313     chargesMulliken = 0;
00314   }
00315   else
00316   {
00317     if(chargesStockholder == 0)
00318       return;
00319     delete chargesStockholder;
00320     chargesStockholder = 0;
00321   }
00322   setChanged();
00323 }
00324 
00326 void AtomSet::setForces(const unsigned int index, const double dx, const double dy, const double dz)
00328 {
00329   if(index >= numAtoms)
00330     return;
00331 
00332   if(forces == 0)
00333     forces = new vector<Point3D<double> >(numAtoms);
00334   
00335   forces->operator[](index) = Point3D<double>(dx, dy, dz);
00336 }
00337 
00339 void AtomSet::changeBond(const double amount, const unsigned int movingAtom, const unsigned int secondAtom, const bool includeNeighbours)
00344 {
00346   if(movingAtom >= numAtoms || secondAtom >= numAtoms)
00347     return;
00348   if(fabs(amount) < Point3D<double>::TOLERANCE)
00349     return;
00350 
00352   vector<unsigned int> moveableAtoms;
00353   if(includeNeighbours)
00354   {
00356     {
00357       vector<unsigned int>* tempBonds1, * tempBonds2;
00358       bonds(tempBonds1, tempBonds2);
00359     }
00361     if(!addBondList(movingAtom, movingAtom, secondAtom, secondAtom, &moveableAtoms))
00362       moveableAtoms.clear();
00363   }
00364   moveableAtoms.push_back(movingAtom);
00365   
00367   const Vector3D<double> oldPosition(coords[secondAtom], coords[movingAtom]);
00368   Vector3D<double> newPosition = oldPosition;
00369   if((oldPosition.length() + amount) < 0.1)
00370     newPosition.setLength(0.1); // the bond would get too small or even flip over
00371   else
00372     newPosition.changeLength(amount); // normal displacement
00373   const double dx = newPosition.x() - oldPosition.x();
00374   const double dy = newPosition.y() - oldPosition.y();
00375   const double dz = newPosition.z() - oldPosition.z();
00376 
00378   vector<unsigned int>::iterator it = moveableAtoms.begin();
00379   while(it != moveableAtoms.end())
00380     coords[*it++].add(Point3D<double>(dx, dy, dz));
00381 
00382   setGeometryChanged();
00383 }
00384 
00386 void AtomSet::changeAngle(const double amount, const unsigned int movingAtom, const unsigned int centralAtom, const unsigned int lastAtom, const bool includeNeighbours)
00392 {
00394   if(movingAtom >= numAtoms || centralAtom >= numAtoms || lastAtom >= numAtoms)
00395     return;
00396   if(fabs(amount) < Point3D<double>::TOLERANCE)
00397     return;
00398 
00400   vector<unsigned int> moveableAtoms;
00401   if(includeNeighbours)
00402   {
00404     {
00405       vector<unsigned int>* tempBonds1, * tempBonds2;
00406       bonds(tempBonds1, tempBonds2);
00407     }
00409     if(!addBondList(movingAtom, movingAtom, centralAtom, lastAtom, &moveableAtoms))
00410       moveableAtoms.clear();
00411   }
00412   moveableAtoms.push_back(movingAtom);
00413 
00415   Vector3D<double> bond1(coords[centralAtom], coords[movingAtom]);
00416   Vector3D<double> bond2(coords[centralAtom], coords[lastAtom]);
00417   Vector3D<double> axis = bond1.cross(bond2);
00418 
00420   std::vector<unsigned int>::iterator it = moveableAtoms.begin();
00421   while(it != moveableAtoms.end())
00422   {
00423     Vector3D<double> rotatebond(coords[centralAtom], coords[*it]);
00424     axis = rotatebond.cross(bond2);
00425     rotatebond.rotate(axis, amount);
00426     coords[*it].setValues(coords[centralAtom].x() + rotatebond.x(),
00427                           coords[centralAtom].y() + rotatebond.y(),
00428                           coords[centralAtom].z() + rotatebond.z());
00429     it++;
00430   }
00431   setGeometryChanged();
00432 }
00433 
00435 void AtomSet::changeTorsion(const double amount, const unsigned int movingAtom, const unsigned int secondAtom, const unsigned int thirdAtom, const unsigned int fourthAtom, const bool includeNeighbours)
00442 {
00444   if(movingAtom >= numAtoms || secondAtom >= numAtoms || thirdAtom >= numAtoms || fourthAtom >= numAtoms)
00445     return;
00446   if(fabs(amount) < Point3D<double>::TOLERANCE)
00447     return;
00448 
00450   vector<unsigned int> moveableAtoms;
00451   if(includeNeighbours)
00452   {
00454     {
00455       vector<unsigned int>* tempBonds1, * tempBonds2;
00456       bonds(tempBonds1, tempBonds2);
00457     }
00459     if(!addBondList(secondAtom, secondAtom, thirdAtom, thirdAtom, &moveableAtoms))
00460     {
00461       moveableAtoms.clear();
00462       moveableAtoms.push_back(movingAtom);
00463     }
00464     else
00465     {
00467       vector<unsigned int>::iterator it = std::find(moveableAtoms.begin(), moveableAtoms.end(), movingAtom);
00468       if(it == moveableAtoms.end())
00469         moveableAtoms.push_back(movingAtom);
00470     }
00471   }
00472   else
00473     moveableAtoms.push_back(movingAtom);
00474 
00476   Vector3D<double> centralbond(coords[secondAtom], coords[thirdAtom]);
00477 
00479   std::vector<unsigned int>::iterator it = moveableAtoms.begin();
00480   while(it != moveableAtoms.end())
00481   {
00482     Vector3D<double> rotatebond(coords[secondAtom], coords[*it]);
00483     rotatebond.rotate(centralbond, -amount);
00484     coords[*it].setValues(coords[secondAtom].x() + rotatebond.x(),
00485                           coords[secondAtom].y() + rotatebond.y(),
00486                           coords[secondAtom].z() + rotatebond.z());
00487     it++;
00488   }
00489   setGeometryChanged();
00490 }
00491 
00493 void AtomSet::transferCoordinates(const AtomSet* source)
00498 
00499 {
00500   if(count() != source->count())
00501     return;
00502 
00504   coords.assign(source->coords.begin(), source->coords.end());
00505 
00506   setGeometryChanged();
00507 }
00508 
00510 unsigned int AtomSet::count() const
00512 {
00513   return numAtoms;
00514 }
00515 
00517 Point3D<double> AtomSet::coordinates(const unsigned int index) const
00519 {
00520   if(index < numAtoms)
00521     return coords[index];
00522   else
00523     return Point3D<double>();
00524 }
00525 
00527 double AtomSet::x(const unsigned int index) const
00529 {
00530   if(index < numAtoms)
00531     return coords[index].x();
00532   else
00533     return 0.0;
00534 }
00535 
00537 double AtomSet::y(const unsigned int index) const
00539 {
00540   if(index < numAtoms)
00541     return coords[index].y();
00542   else
00543     return 0.0;
00544 }
00545 
00547 double AtomSet::z(const unsigned int index) const
00549 {
00550   if(index < numAtoms)
00551     return coords[index].z();
00552   else
00553     return 0.0;
00554 }
00555 
00557 unsigned int AtomSet::atomicNumber(const unsigned int index) const
00559 {
00560   if(index < numAtoms)
00561     return coords[index].id();
00562   else
00563     return 0;
00564 }
00565 
00567 QColor AtomSet::color(const unsigned int index) const
00569 {
00570   if(index < numAtoms)
00571     return colors[index];
00572   else
00573     return QColor(0,0,0);
00574 }
00575 
00577 vector<unsigned int> AtomSet::usedAtomicNumbers() const
00580 {
00581   vector<unsigned int> result;
00582   for(unsigned int i = 1; i <= maxElements; i++)
00583   {
00585     //if(std::find(atomicNumbers.begin(), atomicNumbers.end(), i) != atomicNumbers.end())
00586     //  result.push_back(i); // found an occurence
00587     for(unsigned int j = 0; j < numAtoms; j++)
00588     {
00589       if(coords[j].id() == i)
00590       {
00591         result.push_back(i);
00592         break;
00593       }
00594     }
00595   }
00596   return result;
00597 }
00598 
00600 void AtomSet::bonds(vector<unsigned int>*& first, vector<unsigned int>*& second)
00604 {
00605   QTime timer;
00606   timer.start();
00607   if(bonds1.empty() && numAtoms != 0) // only recalculate when necessary
00608   {
00609     // reserve some space (guesstimate of the number of bonds to be generated, normally between 0.67x and 1x the number of atoms)
00610     bonds1.reserve(numAtoms);
00611     bonds2.reserve(numAtoms);
00612     // update the dimensions of the box
00613     updateBoxDimensions();
00614     // divide it into cells of 4x4x4 Angstrom 
00615     // (4.0A because largest VdW radius = 3.0A => largest distance = 1.25*(3.0 + 3.0) = 7.5A < 2 * 4.0A)
00616     const double cellSize = 4.0;
00617     Point3D<unsigned int> numCells(static_cast<unsigned int>((boxMax->x() - boxMin->x())/cellSize) + 1,
00618                                    static_cast<unsigned int>((boxMax->y() - boxMin->y())/cellSize) + 1,
00619                                    static_cast<unsigned int>((boxMax->z() - boxMin->z())/cellSize) + 1);
00620     unsigned int cellsXY = numCells.x() * numCells.y();
00621     unsigned int totalCells = cellsXY * numCells.z();
00622 
00623     // assign all atoms to their cells
00624     vector< vector<unsigned int> > atomCell(totalCells); // each cell contains a vector of all assigned atom indices
00625     for(unsigned int i = 0; i < numAtoms; i++)
00626     {
00627       if(coords[i].id() != 0) // check for point charges, because they never have bonds
00628       {
00629         unsigned int planeX = static_cast<unsigned int>((coords[i].x() - boxMin->x())/cellSize);
00630         unsigned int planeY = static_cast<unsigned int>((coords[i].y() - boxMin->y())/cellSize);
00631         unsigned int planeZ = static_cast<unsigned int>((coords[i].z() - boxMin->z())/cellSize);
00632         // the atom belongs to the cell at the crossing of planeX, planeY and planeZ
00633         atomCell[planeX + numCells.x()*planeY + cellsXY*planeZ].push_back(i);
00634       }
00635     }
00636     /*qDebug("atoms in each cell:");
00637     for(unsigned int i = 0; i < totalCells; i++)
00638     {
00639       qDebug("cell %d: %d atoms", i, atomCell[i].size());
00640       for(unsigned int j = 0; j < atomCell[i].size(); j++)
00641         qDebug("contains atom %d", atomCell[i][j]+1);
00642     }*/
00643 
00644     // loop over combinations of all cells and calculate bonds only if the cells
00645     // are connected and cell2 has a larger index than cell1 in each direction
00646     unsigned int cellIndex = 0;
00647     vector<unsigned int>* atomList;
00648     // loop over the first set of cells
00649     for(unsigned int cellZ = 0; cellZ < numCells.z(); cellZ++)
00650     {
00651       for(unsigned int cellY = 0; cellY < numCells.y(); cellY++)
00652       {
00653         for(unsigned int cellX = 0; cellX < numCells.x(); cellX++)
00654         {
00655           atomList = &atomCell[cellIndex++];
00656           if(atomList->size() == 0)
00657             continue; // an empty cell can be skipped
00662           // X/Y/Z -> intra-cell bonds
00663           addBonds(atomList, atomList);
00664           // X+1/Y/Z
00665           if(cellX != (numCells.x() - 1))
00666             addBonds(atomList, &atomCell[cellX+1 + numCells.x()*cellY + cellsXY*cellZ]);
00667           // X/Y+1/Z
00668           if(cellY != (numCells.y() - 1))
00669            addBonds(atomList, &atomCell[cellX + numCells.x()*(cellY+1) + cellsXY*cellZ]);
00670           // X/Y/Z+1
00671           if(cellZ != (numCells.z() - 1))
00672             addBonds(atomList, &atomCell[cellX + numCells.x()*cellY + cellsXY*(cellZ+1)]);
00673           // X+1/Y+1/Z
00674           if(cellX != (numCells.x() - 1) && cellY != (numCells.y() - 1))
00675             addBonds(atomList, &atomCell[(cellX+1) + numCells.x()*(cellY+1) + cellsXY*cellZ]);
00676           // X+1/Y/Z+1
00677           if(cellX != (numCells.x() - 1) && cellZ != (numCells.z() - 1))
00678             addBonds(atomList, &atomCell[(cellX+1) + numCells.x()*cellY + cellsXY*(cellZ+1)]);
00679           // X/Y+1/Z+1
00680           if(cellY != (numCells.y() - 1) && cellZ != (numCells.z() - 1))
00681             addBonds(atomList, &atomCell[cellX + numCells.x()*(cellY+1) + cellsXY*(cellZ+1)]);
00682           // X+1/Y+1/Z+1
00683           if(cellX != (numCells.x() - 1) && cellY != (numCells.y() - 1) && cellZ != (numCells.z() - 1))
00684             addBonds(atomList, &atomCell[(cellX+1) + numCells.x()*(cellY+1) + cellsXY*(cellZ+1)]);
00685           // X-1/Y/Z+1
00686           if(cellX != 0 && cellZ != (numCells.z() - 1))
00687             addBonds(atomList, &atomCell[(cellX-1) + numCells.x()*cellY + cellsXY*(cellZ+1)]);
00688           // X+1/Y+1/Z-1
00689           if(cellX != (numCells.x() - 1) && cellY != (numCells.y() - 1) && cellZ != 0)
00690             addBonds(atomList, &atomCell[(cellX+1) + numCells.x()*(cellY+1) + cellsXY*(cellZ-1)]);
00691           // X/Y+1/Z-1
00692           if(cellY != (numCells.y() - 1) && cellZ != 0)
00693             addBonds(atomList, &atomCell[cellX + numCells.x()*(cellY+1) + cellsXY*(cellZ-1)]);
00694           // X-1/Y+1/Z-1
00695           if(cellX != 0 && cellY != (numCells.y() - 1) && cellZ != 0)
00696             addBonds(atomList, &atomCell[(cellX-1) + numCells.x()*(cellY+1) + cellsXY*(cellZ-1)]);
00697           // X-1/Y+1/Z
00698           if(cellX != 0 && cellY != (numCells.y() - 1))
00699             addBonds(atomList, &atomCell[(cellX-1) + numCells.x()*(cellY+1) + cellsXY*cellZ]);
00700           // X-1/Y+1/Z+1
00701           if(cellX != 0 && cellY != (numCells.y() - 1) && cellZ != (numCells.z() - 1))
00702             addBonds(atomList, &atomCell[(cellX-1) + numCells.x()*(cellY+1) + cellsXY*(cellZ+1)]);
00703         }
00704       }
00705     }
00706     qDebug("bonds generation took %f seconds", timer.restart()/1000.0f);
00707   }
00708   // old unoptimized code (44 times slower for 8870 atoms of acetone cluster, 25 times slower for GFP)
00709   /*if(bonds1.empty() && numAtoms != 0) // only recalculate when necessary
00710   {
00711     float distance2, refdistance, dx, dy, dz;
00712     unsigned int numBonds = 0;
00713     unsigned int atomNumI, atomNumJ;
00714 
00718     for(unsigned int i = 0; i < numAtoms; i++)
00719     {
00720       atomNumI = atomicNumbers[i];
00721       if(atomNumI == 0)
00722         continue;
00723       for(unsigned int j = 0; j < i; j++)
00724       {
00725         atomNumJ = atomicNumbers[j];
00726         if(atomNumJ == 0)
00727           continue;
00728         dx = static_cast<float>(coords[i].x() - coords[j].x());
00729         dy = static_cast<float>(coords[i].y() - coords[j].y());
00730         dz = static_cast<float>(coords[i].z() - coords[j].z());
00731         distance2 = dx*dx + dy*dy +dz*dz;
00732         refdistance = 1.25f*(vanderWaals(atomNumI) + vanderWaals(atomNumJ));
00733         if(distance2 <= refdistance*refdistance)
00734         {
00735           numBonds++;
00736           if(numBonds == bonds1.max_size())
00737           {
00738             qDebug("AtomSet::bonds: the maximum number of bonds has been reached.");
00739             first = &bonds1;
00740             second = &bonds2;
00741             return;
00742           }
00743           bonds1.push_back(i);
00744           bonds2.push_back(j);
00745         }
00746       }
00747     }
00748     qDebug("old bonds generation took %f seconds", timer.restart()/1000.0f);
00749   }
00750   */
00751 
00752   first = &bonds1;
00753   second = &bonds2;
00754 }
00755 
00757 unsigned int AtomSet::numberOfBonds(unsigned int index) const
00759 {
00760   if(index >= numAtoms || atomicNumber(index) == 0)
00761     return 0;
00762 
00763   unsigned int result = 0;
00764   float distance2, refdistance, dx, dy, dz;
00765 
00767   for(unsigned int i = 0; i < numAtoms; i++)
00768   {
00769     if(i == index || atomicNumber(i) == 0)
00770       continue;
00771 
00772     dx = static_cast<float>(coords[i].x() - coords[index].x());
00773     dy = static_cast<float>(coords[i].y() - coords[index].y());
00774     dz = static_cast<float>(coords[i].z() - coords[index].z());
00775 
00776     distance2 = dx*dx + dy*dy + dz*dz;
00777     refdistance = 1.25f*(vanderWaals(atomicNumber(i)) + vanderWaals(atomicNumber(index)));
00778     
00779     if(distance2 <= refdistance*refdistance)
00780       result++;
00781   }
00782   return result;
00783 }
00784 
00786 bool AtomSet::isLinear() const
00788 {
00789   if(numAtoms < 3)
00790     return true; // 2 atoms or less are always on a line
00791 
00795   double dx10 = coords[1].x() - coords[0].x();
00796   double dy10 = coords[1].y() - coords[0].y();
00797   double dz10 = coords[1].z() - coords[0].z();
00798 
00799   for(unsigned int i = 2; i < numAtoms; i++)
00800   {
00801     //double test1 = (x(1) - x(0)) * (y(i) - y(0));
00802     //double test2 = (y(1) - y(0)) * (x(i) - x(0));
00803     //double test3 = (y(1) - y(0)) * (z(i) - z(0));
00804     //double test4 = (z(1) - z(0)) * (y(i) - y(0));
00805     double test1 = dx10 * (coords[i].y() - coords[0].y());
00806     double test2 = dy10 * (coords[i].x() - coords[0].x());
00807     double test3 = dy10 * (coords[i].z() - coords[0].z());
00808     double test4 = dz10 * (coords[i].y() - coords[0].y());
00809     if((fabs(test1 - test2) > Point3D<double>::TOLERANCE) || (fabs(test3 - test4) > Point3D<double>::TOLERANCE))
00810       return false;
00811   }
00813   return true;
00814 }
00815 
00817 bool AtomSet::isChanged() const
00819 {
00820   return changed;
00821 }
00822 
00824 double AtomSet::dx(const unsigned int index) const
00827 {
00828   if(forces == 0 || index >= numAtoms)
00829     return 0.0;
00830   
00831   return forces->operator[](index).x();
00832 }
00833 
00835 double AtomSet::dy(const unsigned int index) const
00838 {
00839   if(forces == 0 || index >= numAtoms)
00840     return 0.0;
00841   
00842   return forces->operator[](index).y();
00843 }
00844 
00846 double AtomSet::dz(const unsigned int index) const
00849 {
00850   if(forces == 0 || index >= numAtoms)
00851     return 0.0;
00852   
00853   return forces->operator[](index).z();
00854 }
00855 
00857 double AtomSet::bond(const unsigned int atom1, const unsigned int atom2) const
00859 {
00860   Vector3D<double> bondSize(coords[atom1], coords[atom2]);
00861   return bondSize.length();
00862 }
00863 
00865 double AtomSet::angle(const unsigned int atom1, const unsigned int atom2, const unsigned int atom3) const
00867 {
00868   Vector3D<double> bond1(coords[atom2], coords[atom1]);
00869   Vector3D<double> bond2(coords[atom2], coords[atom3]);
00870   return bond1.angle(bond2);
00871 }
00872 
00874 double AtomSet::torsion(const unsigned int atom1, const unsigned int atom2, const unsigned int atom3, const unsigned int atom4) const
00876 {
00877   Vector3D<double> bond1(coords[atom2], coords[atom1]);
00878   Vector3D<double> centralbond(coords[atom2], coords[atom3]);
00879   Vector3D<double> bond2(coords[atom3], coords[atom4]);
00880   return bond1.torsion(bond2, centralbond);
00881 }
00882 
00884 double AtomSet::charge(const ChargeType type, const unsigned int index) const
00886 {
00887   if(index >= numAtoms || type == None)
00888     return 0.0;
00889 
00890   if(type == Mulliken)
00891   {
00892     if(chargesMulliken == 0)
00893       return 0.0;
00894 
00895     return chargesMulliken->operator[](index);
00896   }
00897   else
00898   {
00899     if(chargesStockholder == 0)
00900       return 0.0;
00901 
00902     return chargesStockholder->operator[](index);
00903   }
00904 }
00905 
00907 bool AtomSet::hasCharges(const ChargeType type) const
00909 {
00910   if((type == Mulliken && chargesMulliken != 0) || 
00911      (type == Stockholder && chargesStockholder != 0))
00912     return true;
00913 
00914   return false;
00915 }
00916 
00918 QString AtomSet::chargesSCF(const ChargeType type) const
00921 {
00922   if(type == Mulliken && chargesMulliken != 0)
00923       return chargesMullikenSCF;
00924   else if(type == Stockholder && chargesStockholder != 0)
00925       return chargesStockholderSCF;
00926   
00927   return QString::null;
00928 }
00929 
00931 QString AtomSet::chargesDensity(const ChargeType type) const
00934 {
00935   if(type == Mulliken && chargesMulliken != 0)
00936       return chargesMullikenDensity;
00937   else if(type == Stockholder && chargesStockholder != 0)
00938       return chargesStockholderDensity;
00939   
00940   return QString::null;
00941 }
00942 
00944 bool AtomSet::hasForces() const
00946 {
00947   return forces != 0;
00948 }
00949 
00951 Point3D<float> AtomSet::rotationCenter() const
00953 {
00954   return Point3D<float>(static_cast<float>((boxMax->x() + boxMin->x())/2.0), 
00955                         static_cast<float>((boxMax->y() + boxMin->y())/2.0), 
00956                         static_cast<float>((boxMax->z() + boxMin->z())/2.0));
00957 }
00958 
00960 bool AtomSet::needsExtendedFormat()
00964 {
00965   updateBoxDimensions();
00966   return(boxMax->x() >= 100.0 || boxMax->y() >= 100.0 || boxMax->z() >= 100.0 ||
00967          boxMin->x() <= -10.0 || boxMin->y() <= -10.0 || boxMin->z() <= -10.0);
00968 }
00969 
00971 void AtomSet::loadCML(const QDomElement* root)
00973 {
00974   clear();
00975   vector<double> mullikenCharges, stockholderCharges;
00976   QStringList newForces;
00977 
00979   QDomNode childNode = root->firstChild();  
00980   while(!childNode.isNull())
00981   {
00982     if(childNode.isElement() && childNode.toElement().tagName() == "atomArray")
00983     {
00985       QDomNode grandChildNode = childNode.firstChild();
00986       QDomElement atomElement;
00987       while(!grandChildNode.isNull())
00988       {
00989         atomElement = grandChildNode.toElement();
00990         if(!atomElement.isNull() && atomElement.tagName() == "atom")
00991         {
00993           const unsigned int atomicNumber = atomToNum(atomElement.attribute("elementType", "H"));
00994           const Point3D<double> xyz3(atomElement.attribute("x3","0.0").toDouble(), 
00995                                       atomElement.attribute("y3","0.0").toDouble(),
00996                                       atomElement.attribute("z3","0.0").toDouble());
00998           QDomNode scalarNode = atomElement.firstChild();
00999           QString color = "#000000";
01000           while(!scalarNode.isNull())
01001           {
01002             if(scalarNode.isElement())
01003             {
01004               if(scalarNode.toElement().tagName() == "scalar")
01005               { 
01006                 if(DomUtils::dictEntry(scalarNode, "atom_color"))
01007                   color = scalarNode.toElement().text();
01008                 else if(scalarNode.toElement().attribute("dictRef") == DomUtils::nsCMLM + ":mulliken" && count() == mullikenCharges.size())
01009                 {
01010                   // only save the Muliken charges if all previous atoms also have charges
01011                   double charge = scalarNode.toElement().text().toDouble();
01012                   mullikenCharges.push_back(charge);                
01013                 }
01014                 else if(scalarNode.toElement().attribute("dictRef") == DomUtils::nsCMLM + ":stockholder" && count() == stockholderCharges.size())
01015                 {
01016                   double charge = scalarNode.toElement().text().toDouble();
01017                   stockholderCharges.push_back(charge);
01018                 }
01019               }
01020               else if(scalarNode.toElement().tagName() == "vector3" && scalarNode.toElement().attribute("dictRef") == DomUtils::nsCMLM + ":dcart")
01021                 newForces += QStringList::split(" ",scalarNode.toElement().text());
01022             }
01023             scalarNode = scalarNode.nextSibling();
01024           }
01026           QColor nColor;
01027           nColor.setNamedColor(color);
01028           addAtom(xyz3, atomicNumber, nColor);
01029         }
01030         grandChildNode = grandChildNode.nextSibling();
01031       }
01032     }
01033     childNode = childNode.nextSibling();
01034   }
01035   
01037   if(mullikenCharges.size() == count())
01038     setCharges(mullikenCharges, Mulliken);
01039   if(stockholderCharges.size() == count())
01040     setCharges(stockholderCharges, Stockholder);
01041 
01043   if(newForces.size() == 3*count())
01044   {
01045     unsigned int index = 0;
01046     double dx, dy, dz;
01047     for(QStringList::Iterator it = newForces.begin(); it != newForces.end(); ++it)
01048     {
01049       dx = (*it).toDouble();
01050       dy = (*(++it)).toDouble();
01051       dz = (*(++it)).toDouble();
01052       setForces(index++, dx, dy, dz);
01053     }
01054   }
01055 }
01056 
01058 void AtomSet::saveCML(QDomElement* root)
01061 {
01062   QDomElement childNode, grandChildNode;
01063   QDomText textNode;
01064   
01066   QDomElement atomArray = root->ownerDocument().createElement("atomArray");
01067   root->appendChild(atomArray);
01068   for(unsigned int i = 0; i < count(); i++)
01069   {
01071     childNode = root->ownerDocument().createElement("atom");
01072     childNode.setAttribute("id", QString(numToAtom(atomicNumber(i)).stripWhiteSpace() + QString::number(i + 1)));
01073     childNode.setAttribute("elementType", numToAtom(atomicNumber(i)).stripWhiteSpace());
01074     childNode.setAttribute("x3", QString::number(coords[i].x(), 'f', 12));
01075     childNode.setAttribute("y3", QString::number(coords[i].y(), 'f', 12));
01076     childNode.setAttribute("z3", QString::number(coords[i].z(), 'f', 12));
01077     atomArray.appendChild(childNode);
01079     grandChildNode = root->ownerDocument().createElement("scalar");
01080     grandChildNode.setAttribute("dictRef", DomUtils::ns + ":atom_color");
01081     grandChildNode.setAttribute("dataType", DomUtils::nsXSD + ":string");
01082     childNode.appendChild(grandChildNode);
01083     textNode = root->ownerDocument().createTextNode(color(i).name());
01084     grandChildNode.appendChild(textNode);
01086     if(chargesMulliken != 0)
01087     {
01088       grandChildNode = root->ownerDocument().createElement("scalar");
01089       //grandChildNode.setAttribute("title", "Mulliken charge");
01090       grandChildNode.setAttribute("dictRef", DomUtils::nsCMLM + ":mulliken");
01091       grandChildNode.setAttribute("units", DomUtils::nsAtomic + ":elementary_charge");
01092       grandChildNode.setAttribute("dataType", DomUtils::nsXSD + ":double");
01093       childNode.appendChild(grandChildNode);
01094       textNode = root->ownerDocument().createTextNode(QString::number(chargesMulliken->operator[](i)));
01095       grandChildNode.appendChild(textNode);
01096     }
01097     if(chargesStockholder != 0)
01098     {
01099       grandChildNode = root->ownerDocument().createElement("scalar");
01100       //grandChildNode.setAttribute("title", "stockholder charge");
01101       grandChildNode.setAttribute("dictRef", DomUtils::nsCMLM + ":stockholder");
01102       grandChildNode.setAttribute("units", DomUtils::nsAtomic + ":elementary_charge");
01103       grandChildNode.setAttribute("dataType", DomUtils::nsXSD + ":double");
01104       childNode.appendChild(grandChildNode);
01105       textNode = root->ownerDocument().createTextNode(QString::number(chargesStockholder->operator[](i)));
01106       grandChildNode.appendChild(textNode);
01107     }
01109     if(forces != 0)
01110     {
01111       grandChildNode = root->ownerDocument().createElement("vector3");
01112       grandChildNode.setAttribute("dictRef", DomUtils::nsCMLM + ":dcart");
01113       grandChildNode.setAttribute("units", DomUtils::nsSI + ":newton");
01114       grandChildNode.setAttribute("multiplierToSI", "1E-8");
01115       grandChildNode.setAttribute("dataType", DomUtils::nsXSD + ":double");
01116       childNode.appendChild(grandChildNode);
01117       textNode = root->ownerDocument().createTextNode(  QString::number(forces->operator [](i).x(), 'f', 12) + " " 
01118                                                       + QString::number(forces->operator [](i).y(), 'f', 12) + " " 
01119                                                       + QString::number(forces->operator [](i).z(), 'f', 12) + " ");
01120       grandChildNode.appendChild(textNode);      
01121     }
01122   }
01123 }
01124 
01126 unsigned int AtomSet::atomToNum(const QString& atom)
01129 {
01130   QString atom2 = atom.upper().simplifyWhiteSpace();  
01131   if(atom2 == "H")  return  1;
01132   if(atom2 == "HE") return  2;
01133   if(atom2 == "LI") return  3;
01134   if(atom2 == "BE") return  4;
01135   if(atom2 == "B")  return  5;
01136   if(atom2 == "C")  return  6;
01137   if(atom2 == "N")  return  7;
01138   if(atom2 == "O")  return  8;
01139   if(atom2 == "F")  return  9;
01140   if(atom2 == "NE") return 10;
01141   if(atom2 == "NA") return 11;
01142   if(atom2 == "MG") return 12;
01143   if(atom2 == "AL") return 13;
01144   if(atom2 == "SI") return 14;
01145   if(atom2 == "P")  return 15;
01146   if(atom2 == "S")  return 16;
01147   if(atom2 == "CL") return 17;
01148   if(atom2 == "AR") return 18;
01149   if(atom2 == "K")  return 19;
01150   if(atom2 == "CA") return 20;
01151   if(atom2 == "SC") return 21;
01152   if(atom2 == "TI") return 22;
01153   if(atom2 == "V")  return 23;
01154   if(atom2 == "CR") return 24;
01155   if(atom2 == "MN") return 25;
01156   if(atom2 == "FE") return 26;
01157   if(atom2 == "CO") return 27;
01158   if(atom2 == "NI") return 28;
01159   if(atom2 == "CU") return 29;
01160   if(atom2 == "ZN") return 30;
01161   if(atom2 == "GA") return 31;
01162   if(atom2 == "GE") return 32;
01163   if(atom2 == "AS") return 33;
01164   if(atom2 == "SE") return 34;
01165   if(atom2 == "BR") return 35;
01166   if(atom2 == "KR") return 36;
01167   if(atom2 == "RB") return 37;
01168   if(atom2 == "SR") return 38;
01169   if(atom2 == "Y")  return 39;
01170   if(atom2 == "ZR") return 40;
01171   if(atom2 == "NB") return 41;
01172   if(atom2 == "MO") return 42;
01173   if(atom2 == "TC") return 43;
01174   if(atom2 == "RU") return 44;
01175   if(atom2 == "RH") return 45;
01176   if(atom2 == "PD") return 46;
01177   if(atom2 == "AG") return 47;
01178   if(atom2 == "CD") return 48;
01179   if(atom2 == "IN") return 49;
01180   if(atom2 == "SN") return 50;
01181   if(atom2 == "SB") return 51;
01182   if(atom2 == "TE") return 52;
01183   if(atom2 == "I")  return 53;
01184   if(atom2 == "XE") return 54;
01185   //qDebug("AtomSet::atomToNum: Unknown element " + atom2 + " encountered. Returning 0");
01186   // any other atom type is returned as number 0, the unknown type "?"
01187   return 0;
01188 }
01189 
01191 QString AtomSet::numToAtom(const unsigned int atom)
01194 {
01195   switch(atom)
01196   {
01197     case  1: return "H ";
01198     case  2: return "He";
01199     case  3: return "Li";
01200     case  4: return "Be";
01201     case  5: return "B ";
01202     case  6: return "C ";
01203     case  7: return "N ";
01204     case  8: return "O ";
01205     case  9: return "F ";
01206     case 10: return "Ne";
01207     case 11: return "Na";
01208     case 12: return "Mg";
01209     case 13: return "Al";
01210     case 14: return "Si";
01211     case 15: return "P ";
01212     case 16: return "S ";
01213     case 17: return "Cl";
01214     case 18: return "Ar";
01215     case 19: return "K ";
01216     case 20: return "Ca";
01217     case 21: return "Sc";
01218     case 22: return "Ti";
01219     case 23: return "V ";
01220     case 24: return "Cr";
01221     case 25: return "Mn";
01222     case 26: return "Fe";
01223     case 27: return "Co";
01224     case 28: return "Ni";
01225     case 29: return "Cu";
01226     case 30: return "Zn";
01227     case 31: return "Ga";
01228     case 32: return "Ge";
01229     case 33: return "As";
01230     case 34: return "Se";
01231     case 35: return "Br";
01232     case 36: return "Kr";
01233     case 37: return "Rb";
01234     case 38: return "Sr";
01235     case 39: return "Y ";
01236     case 40: return "Zr";
01237     case 41: return "Nb";
01238     case 42: return "Mo";
01239     case 43: return "Tc";
01240     case 44: return "Ru";
01241     case 45: return "Rh";
01242     case 46: return "Pd";
01243     case 47: return "Ag";
01244     case 48: return "Cd";
01245     case 49: return "In";
01246     case 50: return "Sn";
01247     case 51: return "Sb";
01248     case 52: return "Te";
01249     case 53: return "I ";
01250     case 54: return "Xe";
01251   }
01252   //qDebug("AtomSet::numToAtom: atomic number %d out of range. Returning 'XX'", atom);
01253   // an unknown atom number is returned as "?"
01254   return "?";
01255 }
01256 
01258 float AtomSet::vanderWaals(const unsigned int atom)
01261 {
01262   switch(atom)
01263   {                         // Accelrys ViewerLite radii
01264     case  1: return 0.40f;   // 1.10
01265     case  2: return 0.30f;   // 2.20
01266     case  3: return 1.25f;   // 1.22
01267     case  4: return 0.97f;   // 0.63
01268     case  5: return 0.82f;   // 1.75
01269     case  6: return 0.75f;   // 1.55
01270     case  7: return 0.69f;   // 1.40
01271     case  8: return 0.68f;   // 1.35
01272     case  9: return 0.64f;   // 1.30
01273     case 10: return 0.40f;   // 2.02
01274     case 11: return 1.70f;   // 2.20
01275     case 12: return 1.60f;   // 1.50
01276     case 13: return 1.20f;   // 1.50
01277     case 14: return 1.05f;   // 2.00
01278     case 15: return 1.00f;   // 1.88
01279     case 16: return 0.80f;   // 1.81
01280     case 17: return 1.00f;   // 1.75
01281     case 18: return 3.00f;   // 2.77
01282     case 19: return 2.00f;   // 2.39
01283     case 20: return 0.99f;   // 1.95
01284     case 21: return 1.44f;   // 1.32
01285     case 22: return 1.47f;   // 1.95
01286     case 23: return 1.33f;   // 1.06
01287     case 24: return 1.35f;   // 1.13
01288     case 25: return 1.35f;   // 1.19
01289     case 26: return 1.34f;   // 1.26
01290     case 27: return 1.33f;   // 1.13
01291     case 28: return 1.50f;   // 1.24
01292     case 29: return 1.52f;   // 1.15
01293     case 30: return 1.45f;   // 1.15
01294     case 31: return 1.22f;   // 1.55
01295     case 32: return 1.17f;   // 1.48
01296     case 33: return 1.21f;   // 0.83
01297     case 34: return 1.22f;   // 0.90
01298     case 35: return 1.21f;   // 1.95
01299     case 36: return 3.00f;   // 1.90
01300     case 37: return 0.00f;   // 2.65
01301     case 38: return 0.00f;   // 2.02
01302     case 39: return 1.78f;   // 1.61
01303     case 40: return 1.56f;   // 1.42
01304     case 41: return 1.48f;   // 1.33
01305     case 42: return 1.47f;   // 1.75
01306     case 43: return 1.35f;   // 1.80
01307     case 44: return 1.40f;   // 1.20
01308     case 45: return 1.45f;   // 1.22
01309     case 46: return 1.50f;   // 1.44
01310     case 47: return 1.59f;   // 1.55
01311     case 48: return 1.69f;   // 1.75
01312     case 49: return 1.63f;   // 1.46
01313     case 50: return 1.46f;   // 1.67
01314     case 51: return 1.46f;   // 1.12
01315     case 52: return 1.47f;   // 1.26
01316     case 53: return 1.40f;   // 2.15
01317     case 54: return 3.00f;   // 2.10
01318   }
01319   //qDebug("AtomSet::vanderWaals: atomic number %d out of range. Returning 0.0", atom);
01320   // the radius of an unknown atom is set to that of helium (the smallest one disregarding
01321   // the zeroes) This sort of atom does not bond at all.
01322   return 0.30f; 
01323 }
01324   
01326 QColor AtomSet::stdColor(const unsigned int atom)
01329 //  (from Accelrys ViewerLite)
01330 {
01331   switch(atom)
01332   {
01333     case  1: return QColor(255, 255, 255);
01334     case  2: return QColor(217, 255, 255);
01335     case  3: return QColor(205, 126, 255);
01336     case  4: return QColor(197, 255,   0);
01337     case  5: return QColor(255, 183, 183);
01338     case  6: return QColor(146, 146, 146);
01339     case  7: return QColor(143, 143, 255);
01340     case  8: return QColor(240,   0,   0);
01341     case  9: return QColor(179, 255, 255);
01342     case 10: return QColor(175, 227, 244);
01343     case 11: return QColor(170,  94, 242);
01344     case 12: return QColor(137, 255,   0);
01345     case 13: return QColor(210, 165, 165);
01346     case 14: return QColor(129, 154, 154);
01347     case 15: return QColor(255, 128,   0);
01348     case 16: return QColor(255, 200,  50);
01349     case 17: return QColor( 32, 240,  32);
01350     case 18: return QColor(129, 209, 228);
01351     case 19: return QColor(143,  65, 211);
01352     case 20: return QColor( 61, 255,   0);
01353     case 21: return QColor(230, 230, 228);
01354     case 22: return QColor(192, 195, 198);
01355     case 23: return QColor(167, 165, 172);
01356     case 24: return QColor(139, 153, 198);
01357     case 25: return QColor(156, 123, 198);
01358     case 26: return QColor(129, 123, 198);
01359     case 27: return QColor(112, 123, 195);
01360     case 28: return QColor( 93, 123, 195);
01361     case 29: return QColor(255, 123,  98);
01362     case 30: return QColor(124, 129, 175);
01363     case 31: return QColor(195, 146, 145);
01364     case 32: return QColor(102, 146, 146);
01365     case 33: return QColor(190, 129, 227);
01366     case 34: return QColor(255, 162,   0);
01367     case 35: return QColor(165,  42,  42);
01368     case 36: return QColor( 93, 186, 209);
01369     case 37: return QColor(113,  46, 178);
01370     case 38: return QColor(  0, 255,   0);
01371     case 39: return QColor(150, 253, 255);
01372     case 40: return QColor(150, 225, 225);
01373     case 41: return QColor(116, 195, 203);
01374     case 42: return QColor( 85, 181, 183);
01375     case 43: return QColor( 60, 159, 168);
01376     case 44: return QColor( 35, 142, 151);
01377     case 45: return QColor( 11, 124, 140);
01378     case 46: return QColor(  0, 105, 134);
01379     case 47: return QColor(153, 198, 255);
01380     case 48: return QColor(255, 216, 145);
01381     case 49: return QColor(167, 118, 115);
01382     case 50: return QColor(102, 129, 129);
01383     case 51: return QColor(159, 101, 181);
01384     case 52: return QColor(213, 123,   0);
01385     case 53: return QColor(147,   0, 147);
01386     case 54: return QColor( 66, 159, 176);
01387   }
01388   //qDebug("AtomSet::stdColor: atomic number %d out of range. Returning white", atom);
01389   // unknown atoms are intense purple so they stand out.
01390   return QColor(255, 0, 255);
01391 }
01392 
01393 
01397 
01399 void AtomSet::setChanged(const bool state)
01401 {
01402   changed = state;
01403 }
01404 
01406 void AtomSet::setGeometryChanged()
01408 {
01409   setChanged(); // something has changed
01410 
01411   clearProperties(); // properties like forces and charges do not coincide with the 
01412                      // structure anymore
01414   bonds1.clear();
01415   bonds2.clear();
01416   dirtyBox = true;
01417 }
01418 
01420 bool AtomSet::addBondList(const unsigned int callingAtom, const unsigned int startAtom, const unsigned int endAtom1, const unsigned int endAtom2, std::vector<unsigned int>* result)
01426 {
01427   qDebug("entering AtomSet::addBondList");
01429   unsigned int numBonds = std::count(bonds1.begin(), bonds1.end(), callingAtom);
01430   numBonds += std::count(bonds2.begin(), bonds2.end(), callingAtom);
01431   if(numBonds == 0)
01432     return false; // if the atom is not bonded, it is to be changed independently
01433   if(numBonds == 1)
01434   {
01435     //qDebug("atom %d has only 1 bond.", callingAtom);
01436     if(callingAtom == startAtom)
01437       return false; // if startAtom is only bonded to endAtom, it can be changed indepedently
01438     else
01439       return true; // end of list has been reached
01440   }
01441 
01443   vector<unsigned int>::iterator it1 = bonds1.begin();
01444   vector<unsigned int>::iterator it2 = bonds2.begin();
01445   while(it1 != bonds1.end() && it2 != bonds2.end())
01446   {
01447     if(*it1 == callingAtom)
01448     {
01449       // check for ring structures
01450       if(*it2 == endAtom1 || *it2 == endAtom2)
01451       {
01452         if(callingAtom != startAtom)
01453           return false;
01454       }
01455       else if(*it2 != startAtom)
01456       {
01457         // check whether the bonded atom is already in the list
01458         if(std::find(result->begin(), result->end(), *it2) == result->end())
01459         {
01460           // add the bond
01461           result->push_back(*it2);
01462           //qDebug("adding the bond between atoms %d and %d", callingAtom, *it2);
01463 
01464           // look for indirect bonds
01465           if(!addBondList(*it2, startAtom, endAtom1, endAtom2, result))
01466             return false;
01467         }
01468       }
01469     }
01470     else if(*it2 == callingAtom)
01471     {
01472       // check for ring structures
01473       if(*it1 == endAtom1 || *it1 == endAtom2)
01474       {
01475         if(callingAtom != startAtom)
01476           return false;
01477       }
01478       else if(*it1 != startAtom)
01479       {
01480         // check whether the bonded atom is already in the list
01481         if(std::find(result->begin(), result->end(), *it1) == result->end())
01482         {
01483           // add the bond
01484           result->push_back(*it1);
01485           //qDebug("adding the bond between atoms %d and %d", callingAtom, *it1);
01486 
01487           // look for indirect bonds
01488           if(!addBondList(*it1, startAtom, endAtom1, endAtom2, result))
01489             return false;
01490         }
01491       }
01492     }
01493     it1++;
01494     it2++;
01495   }
01496   return true; // surpresses a warning
01497 }
01498 
01500 void AtomSet::clearProperties()
01502 {
01503   if(forces != 0)
01504   {
01505     delete forces;
01506     forces = 0;
01507   }
01508   if(chargesMulliken != 0)
01509   {
01510     delete chargesMulliken;
01511     chargesMulliken = 0;
01512   }
01513   if(chargesStockholder != 0)
01514   {
01515     delete chargesStockholder;
01516     chargesStockholder = 0;
01517   }
01518   chargesMullikenSCF = QString::null;
01519   chargesMullikenDensity = QString::null;
01520   chargesStockholderSCF = QString::null;
01521   chargesStockholderDensity = QString::null;
01522 }
01523 
01525 void AtomSet::updateBoxDimensions()
01528 {
01529   if(!dirtyBox)
01530     return;
01531   dirtyBox = false;
01532 
01533   if(numAtoms == 0)
01534   {
01535     boxMin->setValues(0.0, 0.0, 0.0);
01536     boxMax->setValues(0.0, 0.0, 0.0);
01537   }
01538   else
01539   {
01540     double maxx = coords[0].x();
01541     double maxy = coords[0].y();
01542     double maxz = coords[0].z();
01543     double minx = maxx;
01544     double miny = maxy;
01545     double minz = maxz;
01546     for(unsigned int i = 1; i < numAtoms; i++)
01547     {
01548       if(coords[i].x() > maxx)
01549         maxx = coords[i].x();
01550       else if(coords[i].x() < minx)
01551         minx = coords[i].x();
01552       if(coords[i].y() > maxy)
01553         maxy = coords[i].y();
01554       else if(coords[i].y() < miny)
01555         miny = coords[i].y();
01556       if(coords[i].z() > maxz)
01557         maxz = coords[i].z();
01558       else if(coords[i].z() < minz)
01559         minz = coords[i].z();
01560     }
01561     boxMax->setValues(maxx, maxy, maxz);
01562     boxMin->setValues(minx, miny, minz);
01563   }
01564 }
01565 
01567 void AtomSet::addBonds(const vector<unsigned int>* atomList1, const vector<unsigned int>* atomList2)
01570 {
01571   // check whether the second list contains any atoms (the first list is already checked in the
01572   // bonds function
01573   if(atomList2->size() == 0)
01574     return;
01575 
01576   //qDebug("sizes of atomList1 and atomList2: %d and %d", atomList1->size(), atomList2->size());
01577   float distance2, refdistance, dx, dy, dz;
01578   unsigned int atomIndex1, atomIndex2, atomNum1;
01579 
01583   unsigned int limit = atomList2->size(); // normal iteration limit for different atom lists
01584   for(unsigned int i = 0; i < atomList1->size(); i++)
01585   {
01586     atomIndex1 = atomList1->operator[](i);
01587     atomNum1 = coords[atomIndex1].id(); // can never be zero as that has been checked in bonds
01588     if(atomList1 == atomList2)
01589       limit = i; // prevents bonds between same atoms or double counting of bonds between identical atom lists
01590     for(unsigned int j = 0; j < limit; j++)
01591     {
01592       atomIndex2 = atomList2->operator[](j);
01593       dx = static_cast<float>(coords[atomIndex1].x() - coords[atomIndex2].x());
01594       dy = static_cast<float>(coords[atomIndex1].y() - coords[atomIndex2].y());
01595       dz = static_cast<float>(coords[atomIndex1].z() - coords[atomIndex2].z());
01596       distance2 = dx*dx + dy*dy +dz*dz;
01597       refdistance = 1.25f*(vanderWaals(atomNum1) + vanderWaals(coords[atomIndex2].id()));
01598       if(distance2 <= refdistance*refdistance)
01599       {
01600         bonds1.push_back(atomIndex1);
01601         bonds2.push_back(atomIndex2);
01602       }
01603     }
01604   }
01605 }
01606 
01610 
01611 const unsigned int AtomSet::maxElements = 54;
01612 

Generated on Fri May 19 14:31:53 2006 for Brabosphere by  doxygen 1.4.6-NO