/* * Pop and process the next molecule on the workStack (private). */ void ClusterIdentifier::processNextMolecule(Cluster& cluster) { CellList::NeighborArray neighborArray; Molecule::AtomIterator atomIter; ClusterLink* thisLinkPtr; ClusterLink* otherLinkPtr; Atom* otherAtomPtr; Boundary& boundary = system().boundary(); double cutoffSq = cutoff_*cutoff_; double rsq; int thisMolId, otherMolId, otherClusterId; // Pop this molecule off the stack thisLinkPtr = &workStack_.pop(); thisMolId = thisLinkPtr->molecule().id(); if (thisLinkPtr->clusterId() != cluster.id()) { UTIL_THROW("Top ClusterLink not marked with this cluster id"); } /* * Loop over atoms of this molecule. * For each atom of type atomTypeId_, find neighboring molecules. * Add each new neighbor to the cluster, and to the workStack. */ thisLinkPtr->molecule().begin(atomIter); for ( ; atomIter.notEnd(); ++atomIter) { if (atomIter->typeId() == atomTypeId_) { cellList_.getNeighbors(atomIter->position(), neighborArray); for (int i = 0; i < neighborArray.size(); i++) { otherAtomPtr = neighborArray[i]; otherMolId = otherAtomPtr->molecule().id(); if (otherMolId != thisMolId) { rsq = boundary.distanceSq(atomIter->position(), otherAtomPtr->position()); if (rsq < cutoffSq) { otherLinkPtr = &(links_[otherMolId]); assert(&otherLinkPtr->molecule() == &otherAtomPtr->molecule()); otherClusterId = otherLinkPtr->clusterId(); if (otherClusterId == -1) { cluster.addLink(*otherLinkPtr); workStack_.push(*otherLinkPtr); } else if (otherClusterId != cluster.id()) { UTIL_THROW("Cluster Clash!"); } } } } // neighbor atoms } } // atoms }
/* * Evaluate external energy, and add to ensemble. */ void McExternalEnergyAverage::sample(long iStep) { if (!isAtInterval(iStep)) return; double energy = 0.0; System::MoleculeIterator molIter; Molecule::AtomIterator atomIter; for (int iSpec=0; iSpec < system().simulation().nSpecies(); ++iSpec){ for (system().begin(iSpec, molIter); molIter.notEnd(); ++molIter){ for (molIter->begin(atomIter); atomIter.notEnd(); ++atomIter) { energy += system().externalPotential().energy(atomIter->position(), atomIter->typeId()); } } } accumulator_.sample(energy, outputFile_); }
/* * Identify all clusters in the system. */ void ClusterIdentifier::identifyClusters() { // Initialize all data structures: // Setup a grid of empty cells cellList_.setup(system().boundary(), cutoff_); // Clear clusters array and all links clusters_.clear(); for (int i = 0; i < links_.capacity(); ++i) { links_[i].clear(); } // Build the cellList, associate Molecule with ClusterLink. // Iterate over molecules of species speciesId_ System::MoleculeIterator molIter; Molecule::AtomIterator atomIter; system().begin(speciesId_, molIter); for ( ; molIter.notEnd(); ++molIter) { // Associate this Molecule with a ClusterLink links_[molIter->id()].setMolecule(*molIter.get()); // Add atoms of type = atomTypeId_ to the CellList for (molIter->begin(atomIter); atomIter.notEnd(); ++atomIter) { if (atomIter->typeId() == atomTypeId_) { system().boundary().shift(atomIter->position()); cellList_.addAtom(*atomIter); } } } // Identify all clusters Cluster* clusterPtr; ClusterLink* linkPtr; int clusterId = 0; system().begin(speciesId_, molIter); for ( ; molIter.notEnd(); ++molIter) { // Find the link with same index as this molecule linkPtr = &(links_[molIter->id()]); assert (&(linkPtr->molecule()) == molIter.get()); // If this link is not in a cluster, begin a new cluster if (linkPtr->clusterId() == -1) { // Add a new empty cluster to clusters_ array clusters_.resize(clusterId+1); clusterPtr = &clusters_[clusterId]; clusterPtr->clear(); clusterPtr->setId(clusterId); // Identify molecules in this cluster clusterPtr->addLink(*linkPtr); workStack_.push(*linkPtr); while (workStack_.size() > 0) { processNextMolecule(*clusterPtr); } clusterId++; } } // Validity check - throws exception on failure. isValid(); }
/* * Verlet MD NVE integrator step * * This method implements the algorithm: * * vm(n) = v(n) + 0.5*a(n)*dt * x(n+1) = x(n) + vm(n)*dt * * calculate acceleration a(n+1) * * v(n+1) = vm(n) + 0.5*a(n+1)*dt * * where x is position, v is velocity, and a is acceleration. */ void NveVvIntegrator::step() { Vector dv; Vector dr; System::MoleculeIterator molIter; double prefactor; int iSpecies, nSpecies; nSpecies = simulation().nSpecies(); // 1st half velocity Verlet, loop over atoms #if USE_ITERATOR Molecule::AtomIterator atomIter; for (iSpecies=0; iSpecies < nSpecies; ++iSpecies) { system().begin(iSpecies, molIter); for ( ; molIter.notEnd(); ++molIter) { for (molIter->begin(atomIter); atomIter.notEnd(); ++atomIter) { prefactor = prefactors_[atomIter->typeId()]; dv.multiply(atomIter->force(), prefactor); atomIter->velocity() += dv; dr.multiply(atomIter->velocity(), dt_); atomIter->position() += dr; } } } #else Atom* atomPtr; int ia; for (iSpecies=0; iSpecies < nSpecies; ++iSpecies) { system().begin(iSpecies, molIter); for ( ; molIter.notEnd(); ++molIter) { for (ia=0; ia < molIter->nAtom(); ++ia) { atomPtr = &molIter->atom(ia); prefactor = prefactors_[atomPtr->typeId()]; dv.multiply(atomPtr->force(), prefactor); atomPtr->velocity() += dv; dr.multiply(atomPtr->velocity(), dt_); atomPtr->position() += dr; } } } #endif system().calculateForces(); // 2nd half velocity Verlet, loop over atoms #if USE_ITERATOR for (iSpecies=0; iSpecies < nSpecies; ++iSpecies) { system().begin(iSpecies, molIter); for ( ; molIter.notEnd(); ++molIter) { for (molIter->begin(atomIter); atomIter.notEnd(); ++atomIter) { prefactor = prefactors_[atomIter->typeId()]; dv.multiply(atomIter->force(), prefactor); atomIter->velocity() += dv; } } } #else for (iSpecies=0; iSpecies < nSpecies; ++iSpecies) { system().begin(iSpecies, molIter); for ( ; molIter.notEnd(); ++molIter) { for (ia=0; ia < molIter->nAtom(); ++ia) { atomPtr = &molIter->atom(ia); prefactor = prefactors_[atomPtr->typeId()]; dv.multiply(atomPtr->force(), prefactor); atomPtr->velocity() += dv; } } } #endif #ifndef INTER_NOPAIR if (!system().pairPotential().isPairListCurrent()) { system().pairPotential().buildPairList(); } #endif }
/** * Generate random molecules */ void Linear::generateMolecules(int nMolecule, DArray<double> exclusionRadius, System& system, BondPotential *bondPotentialPtr, const Boundary &boundary) { int iMol; // Set up a cell list with twice the maxium exclusion radius as the // cell size double maxExclusionRadius = 0.0; for (int iType = 0; iType < system.simulation().nAtomType(); iType++) { if (exclusionRadius[iType] > maxExclusionRadius) maxExclusionRadius = exclusionRadius[iType]; } // the minimum cell size is twice the maxExclusionRadius, // but to save memory, we take 2 times that value CellList cellList; cellList.allocate(system.simulation().atomCapacity(), boundary, 2.0*2.0*maxExclusionRadius); if (nMolecule > capacity()) UTIL_THROW("nMolecule > Species.capacity()!"); Simulation& sim = system.simulation(); for (iMol = 0; iMol < nMolecule; ++iMol) { // Add a new molecule to the system Molecule &newMolecule= sim.getMolecule(id()); system.addMolecule(newMolecule); // Try placing atoms bool moleculeHasBeenPlaced = false; for (int iAttempt = 0; iAttempt< maxPlacementAttempts_; iAttempt++) { // Place first atom Vector pos; system.boundary().randomPosition(system.simulation().random(),pos); Atom &thisAtom = newMolecule.atom(0); // check if the first atom can be placed at the new position CellList::NeighborArray neighbors; cellList.getNeighbors(pos, neighbors); int nNeighbor = neighbors.size(); bool canBePlaced = true; for (int j = 0; j < nNeighbor; ++j) { Atom *jAtomPtr = neighbors[j]; double r = sqrt(system.boundary().distanceSq( jAtomPtr->position(), pos)); if (r < (exclusionRadius[thisAtom.typeId()] + exclusionRadius[jAtomPtr->typeId()])) { canBePlaced = false; break; } } if (canBePlaced) { thisAtom.position() = pos; cellList.addAtom(thisAtom); // Try to recursively place other atoms if (tryPlaceAtom(newMolecule, 0, exclusionRadius, system, cellList, bondPotentialPtr, system.boundary())) { moleculeHasBeenPlaced = true; break; } else { cellList.deleteAtom(thisAtom); } } } if (! moleculeHasBeenPlaced) { std::ostringstream oss; oss << "Failed to place molecule " << newMolecule.id(); UTIL_THROW(oss.str().c_str()); } } #if 0 // Check for (int iMol =0; iMol < nMolecule; ++iMol) { Molecule::AtomIterator atomIter; system.molecule(id(),iMol).begin(atomIter); for (; atomIter.notEnd(); ++atomIter) { for (int jMol =0; jMol < nMolecule; ++jMol) { Molecule::AtomIterator atomIter2; system.molecule(id(),jMol).begin(atomIter2); for (; atomIter2.notEnd(); ++atomIter2 ) { if (atomIter2->id() != atomIter->id()) { double r = sqrt(boundary.distanceSq( atomIter->position(),atomIter2->position())); if (r < (exclusionRadius[atomIter->typeId()]+ exclusionRadius[atomIter2->typeId()])) { std::cout << r << std::endl; UTIL_THROW("ERROR"); } } } } } } #endif }
/* * Nose-Hoover integrator step. * * This implements a reversible Velocity-Verlet MD NVT integrator step. * * Reference: Winkler, Kraus, and Reineker, J. Chem. Phys. 102, 9018 (1995). */ void NvtNhIntegrator::step() { Vector dv; Vector dr; System::MoleculeIterator molIter; double dtHalf = 0.5*dt_; double prefactor; double factor; Molecule::AtomIterator atomIter; int iSpecies, nSpecies; int nAtom; T_target_ = energyEnsemblePtr_->temperature(); nSpecies = simulation().nSpecies(); nAtom = system().nAtom(); factor = exp(-dtHalf*(xi_ + xiDot_*dtHalf)); // 1st half velocity Verlet, loop over atoms for (iSpecies = 0; iSpecies < nSpecies; ++iSpecies) { system().begin(iSpecies, molIter); for ( ; molIter.notEnd(); ++molIter) { molIter->begin(atomIter); for ( ; atomIter.notEnd(); ++atomIter) { atomIter->velocity() *= factor; prefactor = prefactors_[atomIter->typeId()]; dv.multiply(atomIter->force(), prefactor); //dv.multiply(atomIter->force(), dtHalf); atomIter->velocity() += dv; dr.multiply(atomIter->velocity(), dt_); atomIter->position() += dr; } } } // First half of update of xi_ xi_ += xiDot_*dtHalf; #ifndef INTER_NOPAIR // Rebuild the pair list if necessary if (!system().pairPotential().isPairListCurrent()) { system().pairPotential().buildPairList(); } #endif system().calculateForces(); // 2nd half velocity Verlet, loop over atoms for (iSpecies=0; iSpecies < nSpecies; ++iSpecies) { system().begin(iSpecies, molIter); for ( ; molIter.notEnd(); ++molIter) { for (molIter->begin(atomIter); atomIter.notEnd(); ++atomIter) { prefactor = prefactors_[atomIter->typeId()]; dv.multiply(atomIter->force(), prefactor); atomIter->velocity() += dv; atomIter->velocity() *=factor; } } } // Update xiDot and complete update of xi_ T_kinetic_ = system().kineticEnergy()*2.0/double(3*nAtom); xiDot_ = (T_kinetic_/T_target_ -1.0)*nuT_*nuT_; xi_ += xiDot_*dtHalf; }
/* * Generate, attempt and accept or reject a Hybrid MD/MC move. */ bool HoomdMove::move() { if ((!HoomdIsInitialized_) || moleculeSetHasChanged_) { initSimulation(); moleculeSetHasChanged_ = false; } // We need to create the Integrator every time since we are starting // with new coordinates, velocities etc. // this does not seem to incur a significant performance decrease createIntegrator(); System::MoleculeIterator molIter; Molecule::AtomIterator atomIter; int nSpec = simulation().nSpecies(); // Increment counter for attempted moves incrementNAttempt(); double oldEnergy, newEnergy; { // Copy atom coordinates into HOOMD ArrayHandle<Scalar4> h_pos(particleDataSPtr_->getPositions(), access_location::host, access_mode::readwrite); ArrayHandle<Scalar4> h_vel(particleDataSPtr_->getVelocities(), access_location::host, access_mode::readwrite); ArrayHandle<unsigned int> h_tag(particleDataSPtr_->getTags(), access_location::host, access_mode::readwrite); ArrayHandle<unsigned int> h_rtag(particleDataSPtr_->getRTags(), access_location::host, access_mode::readwrite); for (int iSpec =0; iSpec < nSpec; ++iSpec) { system().begin(iSpec, molIter); for ( ; molIter.notEnd(); ++ molIter) { for (molIter->begin(atomIter); atomIter.notEnd(); ++atomIter) { unsigned int idx = (unsigned int) atomIter->id(); Vector& pos = atomIter->position(); h_pos.data[idx].x = pos[0] - lengths_[0]/2.; h_pos.data[idx].y = pos[1] - lengths_[1]/2.; h_pos.data[idx].z = pos[2] - lengths_[2]/2.; int type = atomIter->typeId(); h_vel.data[idx].w = simulation().atomType(type).mass(); h_pos.data[idx].w = __int_as_scalar(type); h_tag.data[idx] = idx; h_rtag.data[idx] = idx; } } } // Generate random velocities generateRandomVelocities(h_vel); } // Notify that the particle order has changed particleDataSPtr_->notifyParticleSort(); // Initialize integrator (calculate forces and potential energy for step 0) integratorSPtr_->prepRun(0); // Calculate oldEnergy thermoSPtr_->compute(0); oldEnergy = thermoSPtr_->getLogValue("kinetic_energy",0); oldEnergy += thermoSPtr_->getLogValue("potential_energy",0); // Integrate nStep_ steps forward for (int iStep = 0; iStep < nStep_; ++iStep) { integratorSPtr_->update(iStep); // do we need to sort the particles? // do not sort at time step 0 to speed up short runs if (! (iStep % sorterPeriod_) && iStep) sorterSPtr_->update(iStep); } // Calculate new energy thermoSPtr_->compute(nStep_); newEnergy = thermoSPtr_->getLogValue("kinetic_energy",nStep_); newEnergy += thermoSPtr_->getLogValue("potential_energy",nStep_); // Decide whether to accept or reject bool accept = random().metropolis( boltzmann(newEnergy-oldEnergy) ); if (accept) { // read back integrated positions ArrayHandle<Scalar4> h_pos(particleDataSPtr_->getPositions(), access_location::host, access_mode::read); ArrayHandle<Scalar4> h_vel(particleDataSPtr_->getVelocities(), access_location::host, access_mode::read); ArrayHandle<unsigned int> h_tag(particleDataSPtr_->getTags(), access_location::host, access_mode::read); ArrayHandle<unsigned int> h_rtag(particleDataSPtr_->getRTags(), access_location::host, access_mode::read); for (int iSpec = 0; iSpec < nSpec; ++iSpec) { system().begin(iSpec, molIter); for ( ; molIter.notEnd(); ++molIter) { for (molIter->begin(atomIter); atomIter.notEnd(); ++atomIter) { unsigned int idx = h_rtag.data[atomIter->id()]; atomIter->position() = Vector(h_pos.data[idx].x+lengths_[0]/2., h_pos.data[idx].y+lengths_[1]/2., h_pos.data[idx].z+lengths_[2]/2.); } } } system().pairPotential().buildCellList(); incrementNAccept(); } else { // not accepted, do nothing } return accept; }