00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00019
00041
00042
00043
00045
00046
00047 #include <cmath>
00048
00049
00050 #include <algorithm>
00051
00052
00053 #include <qcolor.h>
00054 #include <qdom.h>
00055 #include <qstring.h>
00056 #include <qstringlist.h>
00057
00058 #include <qdatetime.h>
00059
00060
00061 #include "atomset.h"
00062 #include "domutils.h"
00063 #include "vector3d.h"
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();
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;
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();
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);
00371 else
00372 newPosition.changeLength(amount);
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
00586
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)
00608 {
00609
00610 bonds1.reserve(numAtoms);
00611 bonds2.reserve(numAtoms);
00612
00613 updateBoxDimensions();
00614
00615
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
00624 vector< vector<unsigned int> > atomCell(totalCells);
00625 for(unsigned int i = 0; i < numAtoms; i++)
00626 {
00627 if(coords[i].id() != 0)
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
00633 atomCell[planeX + numCells.x()*planeY + cellsXY*planeZ].push_back(i);
00634 }
00635 }
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646 unsigned int cellIndex = 0;
00647 vector<unsigned int>* atomList;
00648
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;
00662
00663 addBonds(atomList, atomList);
00664
00665 if(cellX != (numCells.x() - 1))
00666 addBonds(atomList, &atomCell[cellX+1 + numCells.x()*cellY + cellsXY*cellZ]);
00667
00668 if(cellY != (numCells.y() - 1))
00669 addBonds(atomList, &atomCell[cellX + numCells.x()*(cellY+1) + cellsXY*cellZ]);
00670
00671 if(cellZ != (numCells.z() - 1))
00672 addBonds(atomList, &atomCell[cellX + numCells.x()*cellY + cellsXY*(cellZ+1)]);
00673
00674 if(cellX != (numCells.x() - 1) && cellY != (numCells.y() - 1))
00675 addBonds(atomList, &atomCell[(cellX+1) + numCells.x()*(cellY+1) + cellsXY*cellZ]);
00676
00677 if(cellX != (numCells.x() - 1) && cellZ != (numCells.z() - 1))
00678 addBonds(atomList, &atomCell[(cellX+1) + numCells.x()*cellY + cellsXY*(cellZ+1)]);
00679
00680 if(cellY != (numCells.y() - 1) && cellZ != (numCells.z() - 1))
00681 addBonds(atomList, &atomCell[cellX + numCells.x()*(cellY+1) + cellsXY*(cellZ+1)]);
00682
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
00686 if(cellX != 0 && cellZ != (numCells.z() - 1))
00687 addBonds(atomList, &atomCell[(cellX-1) + numCells.x()*cellY + cellsXY*(cellZ+1)]);
00688
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
00692 if(cellY != (numCells.y() - 1) && cellZ != 0)
00693 addBonds(atomList, &atomCell[cellX + numCells.x()*(cellY+1) + cellsXY*(cellZ-1)]);
00694
00695 if(cellX != 0 && cellY != (numCells.y() - 1) && cellZ != 0)
00696 addBonds(atomList, &atomCell[(cellX-1) + numCells.x()*(cellY+1) + cellsXY*(cellZ-1)]);
00697
00698 if(cellX != 0 && cellY != (numCells.y() - 1))
00699 addBonds(atomList, &atomCell[(cellX-1) + numCells.x()*(cellY+1) + cellsXY*cellZ]);
00700
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
00709
00710
00711
00712
00713
00714
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
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;
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
00802
00803
00804
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
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
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
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
01186
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
01253
01254 return "?";
01255 }
01256
01258 float AtomSet::vanderWaals(const unsigned int atom)
01261 {
01262 switch(atom)
01263 {
01264 case 1: return 0.40f;
01265 case 2: return 0.30f;
01266 case 3: return 1.25f;
01267 case 4: return 0.97f;
01268 case 5: return 0.82f;
01269 case 6: return 0.75f;
01270 case 7: return 0.69f;
01271 case 8: return 0.68f;
01272 case 9: return 0.64f;
01273 case 10: return 0.40f;
01274 case 11: return 1.70f;
01275 case 12: return 1.60f;
01276 case 13: return 1.20f;
01277 case 14: return 1.05f;
01278 case 15: return 1.00f;
01279 case 16: return 0.80f;
01280 case 17: return 1.00f;
01281 case 18: return 3.00f;
01282 case 19: return 2.00f;
01283 case 20: return 0.99f;
01284 case 21: return 1.44f;
01285 case 22: return 1.47f;
01286 case 23: return 1.33f;
01287 case 24: return 1.35f;
01288 case 25: return 1.35f;
01289 case 26: return 1.34f;
01290 case 27: return 1.33f;
01291 case 28: return 1.50f;
01292 case 29: return 1.52f;
01293 case 30: return 1.45f;
01294 case 31: return 1.22f;
01295 case 32: return 1.17f;
01296 case 33: return 1.21f;
01297 case 34: return 1.22f;
01298 case 35: return 1.21f;
01299 case 36: return 3.00f;
01300 case 37: return 0.00f;
01301 case 38: return 0.00f;
01302 case 39: return 1.78f;
01303 case 40: return 1.56f;
01304 case 41: return 1.48f;
01305 case 42: return 1.47f;
01306 case 43: return 1.35f;
01307 case 44: return 1.40f;
01308 case 45: return 1.45f;
01309 case 46: return 1.50f;
01310 case 47: return 1.59f;
01311 case 48: return 1.69f;
01312 case 49: return 1.63f;
01313 case 50: return 1.46f;
01314 case 51: return 1.46f;
01315 case 52: return 1.47f;
01316 case 53: return 1.40f;
01317 case 54: return 3.00f;
01318 }
01319
01320
01321
01322 return 0.30f;
01323 }
01324
01326 QColor AtomSet::stdColor(const unsigned int atom)
01329
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
01389
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();
01410
01411 clearProperties();
01412
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;
01433 if(numBonds == 1)
01434 {
01435
01436 if(callingAtom == startAtom)
01437 return false;
01438 else
01439 return true;
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
01450 if(*it2 == endAtom1 || *it2 == endAtom2)
01451 {
01452 if(callingAtom != startAtom)
01453 return false;
01454 }
01455 else if(*it2 != startAtom)
01456 {
01457
01458 if(std::find(result->begin(), result->end(), *it2) == result->end())
01459 {
01460
01461 result->push_back(*it2);
01462
01463
01464
01465 if(!addBondList(*it2, startAtom, endAtom1, endAtom2, result))
01466 return false;
01467 }
01468 }
01469 }
01470 else if(*it2 == callingAtom)
01471 {
01472
01473 if(*it1 == endAtom1 || *it1 == endAtom2)
01474 {
01475 if(callingAtom != startAtom)
01476 return false;
01477 }
01478 else if(*it1 != startAtom)
01479 {
01480
01481 if(std::find(result->begin(), result->end(), *it1) == result->end())
01482 {
01483
01484 result->push_back(*it1);
01485
01486
01487
01488 if(!addBondList(*it1, startAtom, endAtom1, endAtom2, result))
01489 return false;
01490 }
01491 }
01492 }
01493 it1++;
01494 it2++;
01495 }
01496 return true;
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
01572
01573 if(atomList2->size() == 0)
01574 return;
01575
01576
01577 float distance2, refdistance, dx, dy, dz;
01578 unsigned int atomIndex1, atomIndex2, atomNum1;
01579
01583 unsigned int limit = atomList2->size();
01584 for(unsigned int i = 0; i < atomList1->size(); i++)
01585 {
01586 atomIndex1 = atomList1->operator[](i);
01587 atomNum1 = coords[atomIndex1].id();
01588 if(atomList1 == atomList2)
01589 limit = i;
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