/** * 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 }
/* * Generate, attempt and accept or reject a Hybrid MD/MC move. */ bool HybridNphMdMove::move() { System::MoleculeIterator molIter; Molecule::AtomIterator atomIter; double oldEnergy, newEnergy; int iSpec; int nSpec = simulation().nSpecies(); bool accept; if (nphIntegratorPtr_ == NULL) { UTIL_THROW("null integrator pointer"); } // Increment counter for attempted moves incrementNAttempt(); // Store old boundary lengths. Vector oldLengths = system().boundary().lengths(); // Store old atom positions in oldPositions_ array. for (iSpec = 0; iSpec < nSpec; ++iSpec) { mdSystemPtr_->begin(iSpec, molIter); for ( ; molIter.notEnd(); ++molIter) { for (molIter->begin(atomIter); atomIter.notEnd(); ++atomIter) { oldPositions_[atomIter->id()] = atomIter->position(); } } } // Initialize MdSystem #ifndef INTER_NOPAIR mdSystemPtr_->pairPotential().buildPairList(); #endif mdSystemPtr_->calculateForces(); mdSystemPtr_->setBoltzmannVelocities(energyEnsemble().temperature()); nphIntegratorPtr_->setup(); // generate integrator variables from a Gaussian distribution Random& random = simulation().random(); double temp = system().energyEnsemble().temperature(); double volume = system().boundary().volume(); if (mode_ == Cubic) { // one degree of freedom // barostat_energy = 1/2 (1/W) eta_x^2 double sigma = sqrt(temp/barostatMass_); nphIntegratorPtr_->setEta(0, sigma*random.gaussian()); } else if (mode_ == Tetragonal) { // two degrees of freedom // barostat_energy = 1/2 (1/W) eta_x^2 + 1/2 (1/(2W)) eta_y^2 double sigma1 = sqrt(temp/barostatMass_); nphIntegratorPtr_->setEta(0, sigma1*random.gaussian()); double sigma2 = sqrt(temp/barostatMass_/2.0); nphIntegratorPtr_->setEta(1, sigma2*random.gaussian()); } else if (mode_ == Orthorhombic) { // three degrees of freedom // barostat_energy = 1/2 (1/W) (eta_x^2 + eta_y^2 + eta_z^2) double sigma = sqrt(temp/barostatMass_); nphIntegratorPtr_->setEta(0, sigma*random.gaussian()); nphIntegratorPtr_->setEta(1, sigma*random.gaussian()); nphIntegratorPtr_->setEta(2, sigma*random.gaussian()); } // Store old energy oldEnergy = mdSystemPtr_->potentialEnergy(); oldEnergy += mdSystemPtr_->kineticEnergy(); oldEnergy += system().boundaryEnsemble().pressure()*volume; oldEnergy += nphIntegratorPtr_->barostatEnergy(); // Run a short MD simulation for (int iStep = 0; iStep < nStep_; ++iStep) { nphIntegratorPtr_->step(); } volume = system().boundary().volume(); // Calculate new energy newEnergy = mdSystemPtr_->potentialEnergy(); newEnergy += mdSystemPtr_->kineticEnergy(); newEnergy += system().boundaryEnsemble().pressure()*volume; newEnergy += nphIntegratorPtr_->barostatEnergy(); // Decide whether to accept or reject accept = random.metropolis( boltzmann(newEnergy-oldEnergy) ); // Accept move if (accept) { #ifndef INTER_NOPAIR // Rebuild the McSystem cellList using the new positions. system().pairPotential().buildCellList(); #endif // Increment counter for the number of accepted moves. incrementNAccept(); } else { // Restore old boundary lengths system().boundary().setOrthorhombic(oldLengths); // Restore old atom positions for (iSpec = 0; iSpec < nSpec; ++iSpec) { mdSystemPtr_->begin(iSpec, molIter); for ( ; molIter.notEnd(); ++molIter) { molIter->begin(atomIter); for ( ; atomIter.notEnd(); ++atomIter) { atomIter->position() = oldPositions_[atomIter->id()]; } } } } return accept; }
/* * 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; }