/* * 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 }
void NphIntegrator::step() { System::MoleculeIterator molIter; double prefactor; int iSpecies, nSpecies; nSpecies = simulation().nSpecies(); /* perform the first half step of the explicitly reversible NPH integration scheme. This follows from operator factorization - orthorhombic case: 1) eta_alpha(t+dt/2) = eta_alpha(t) + dt/2 * V/L_alpha * ( P_{alpha,alpha}(t) - P_ext) 2) v' = v(t) + (1/2)a(t)*dt 3) L(t+dt/2) = L(t) + dt*eta(t+dt/2)/(2*W) 4) r'_alpha = r(t) + v'*dt* (L_{alpha}^2(t)/L_{alpha}^2(t+dt/2)) 5a) L(t+dt) = L(t+dt/2) + dt*eta(t+dt/2)/2/W 5b) r_alpha(t+dt) = L_alpha(t+dt)/L_alpha(t)*r'_alpha 5c) v''_alpha = L_alpha(t)/L_alpha(t+dt) * v'_alpha alpha denotes a cartesian index. - isotropic case: only eta_x := eta is used and instead of step 1) we have 1') eta(t+dt/2) = eta(t) + dt/2 * (1/3*Tr P(t) - P_ext) furthermore, in step 3) and 5a) L is replaced with V=L^3 - tetragonal case: Lx := L_perp, Ly = Lz := L_par eta_x := eta_perp, etay := eta_par, etaz unused instead of step 1) we have 1'a) eta_perp(t+dt/2) = eta_perp + dt/2 * V/L_perp * ( P_xx(t) - P_ext) 1'b) eta_par(t+dt/2) = eta_par + dt/2 * V/L_par * ( P_yy(t) + P_zz(t) - 2*P_ext) steps 3) and 5a) are split into two sub-steps L_perp(i+1) = L_perp(i) + dt/(2*W)*eta_perp L_par(i+1) = L_par(i) + dt/(4*W)*eta_par */ // obtain current stress tensor (diagonal components) system().computeStress(currP_); // obtain current box lengths Vector lengths = system().boundary().lengths(); double volume = lengths[0]*lengths[1]*lengths[2]; double extP = system().boundaryEnsemble().pressure(); // advance eta(t)->eta(t+dt/2) (step one) if (mode_ == Orthorhombic) { double Vdthalf = 1.0/2.0 * volume * dt_; eta_[0] += Vdthalf/lengths[0] * (currP_[0] - extP); eta_[1] += Vdthalf/lengths[1] * (currP_[1] - extP); eta_[2] += Vdthalf/lengths[2] * (currP_[2] - extP); } else if (mode_ == Tetragonal) { double Vdthalf = 1.0/2.0* volume * dt_; eta_[0] += Vdthalf/lengths[0]*(currP_[0] - extP); eta_[1] += Vdthalf/lengths[1]*(currP_[1] + currP_[2] - 2.0*extP); } else if (mode_ == Cubic) { eta_[0] += 1.0/2.0*dt_*(1.0/3.0*(currP_[0]+currP_[1]+currP_[2]) - extP); } // update the box length L(t) -> L(t+dt/2) (step three) // (since we still keep the accelerations a(t) computed for box length L_alpha(t) in memory, // needed in step two, we can exchange the order of the two steps) // also pre-calculate L(t+dt) (step 5a, only depends on eta(t) of step one) Vector lengthsOld = lengths; Vector lengthsFinal; double volumeFinal = 0.0; double dthalfoverW = 1.0/2.0*dt_/W_; if (mode_ == Orthorhombic) { lengths[0] += dthalfoverW*eta_[0]; lengths[1] += dthalfoverW*eta_[1]; lengths[2] += dthalfoverW*eta_[2]; lengthsFinal[0] = lengths[0] + dthalfoverW*eta_[0]; lengthsFinal[1] = lengths[1] + dthalfoverW*eta_[1]; lengthsFinal[2] = lengths[2] + dthalfoverW*eta_[2]; volumeFinal = lengthsFinal[0]*lengthsFinal[1]*lengthsFinal[2]; } else if (mode_ == Tetragonal) { lengths[0] += dthalfoverW*eta_[0]; lengths[1] += (1.0/2.0)*dthalfoverW*eta_[1]; lengths[2] = lengths[1]; lengthsFinal[0] = lengths[0] + dthalfoverW*eta_[0]; lengthsFinal[1] = lengths[1] + (1.0/2.0)*dthalfoverW*eta_[1]; lengthsFinal[2] = lengthsFinal[1]; volumeFinal = lengthsFinal[0]*lengthsFinal[1]*lengthsFinal[2]; } else if (mode_ == Cubic) { volume += dthalfoverW*eta_[0]; lengths[0] = pow(volume,1.0/3.0); // Lx = Ly = Lz = V^(1/3) lengths[1] = lengths[0]; lengths[2] = lengths[0]; volumeFinal = volume + dthalfoverW*eta_[0]; lengthsFinal[0] = pow(volumeFinal,1./3.); lengthsFinal[1] = lengthsFinal[0]; lengthsFinal[2] = lengthsFinal[0]; } // update simulation box system().boundary().setOrthorhombic(lengthsFinal); // update particles Atom* atomPtr; int ia; Vector vtmp, dr, rtmp, dv; Vector lengthsFac, dtLengthsFac2; for (int i=0; i<3; i++) { lengthsFac[i] = lengthsFinal[i]/lengthsOld[i]; dtLengthsFac2[i] = dt_ * lengthsOld[i]*lengthsOld[i]/lengths[i]/lengths[i]; } 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); vtmp.add(atomPtr->velocity(),dv); dr[0] = vtmp[0] * dtLengthsFac2[0]; dr[1] = vtmp[1] * dtLengthsFac2[1]; dr[2] = vtmp[2] * dtLengthsFac2[2]; rtmp.add(atomPtr->position(), dr); rtmp[0] *= lengthsFac[0]; rtmp[1] *= lengthsFac[1]; rtmp[2] *= lengthsFac[2]; atomPtr->position() = rtmp; vtmp[0] /= lengthsFac[0]; vtmp[1] /= lengthsFac[1]; vtmp[2] /= lengthsFac[2]; atomPtr->velocity() = vtmp; } } } #ifndef INTER_NOPAIR if (!system().pairPotential().isPairListCurrent()) { system().pairPotential().buildPairList(); } #endif system().calculateForces(); /* the second step of the explicitly reversible integrator consists of the following to sub-steps 6) v(t+dt) = v'' + 1/2 * a(t+dt)*dt 7) eta(t+dt/2) -> eta(t+dt) */ // v(t+dt) = v'' + 1/2 * a(t+dt)*dt 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; } } } // now compute pressure tensor with updated virial and velocities system().computeStress(currP_); // advance eta(t+dt/2) -> eta(t+dt) if (mode_ == Orthorhombic) { double Vdthalf = 1.0/2.0 * volumeFinal * dt_; eta_[0] += Vdthalf/lengthsFinal[0] * (currP_[0] - extP); eta_[1] += Vdthalf/lengthsFinal[1] * (currP_[1] - extP); eta_[2] += Vdthalf/lengthsFinal[2] * (currP_[2] - extP); } else if (mode_ == Tetragonal) { double Vdthalf = 1.0/2.0 * volumeFinal * dt_; eta_[0] += Vdthalf/lengthsFinal[0]*(currP_[0] - extP); eta_[1] += Vdthalf/lengthsFinal[1]*(currP_[1] + currP_[2] - 2.0*extP); } else if (mode_ == Cubic) { eta_[0] += 1.0/2.0*dt_*(1.0/3.0*(currP_[0]+currP_[1]+currP_[2]) - extP); } #ifndef INTER_NOPAIR if (!system().pairPotential().isPairListCurrent()) { system().pairPotential().buildPairList(); } #endif /* // debug output double P; system().computeStress(P); std::cout << system().boundary() << std::endl; std::cout << "P = " << P << " "; std::cout << "Ekin = " << system().kineticEnergy() << " "; std::cout << "Epot = " << system().potentialEnergy() << " "; std::cout << "PV = " << extP * system().boundary().volume() << " "; std::cout << "Ebaro = " << barostatEnergy() << " "; std::cout << "H = " << system().potentialEnergy() + system().kineticEnergy() + extP * system().boundary().volume() + barostatEnergy() << std::endl; */ }
// Create links and print. void Crosslinker::sample(long iStep) { if (isAtInterval(iStep)) { // Clear the cellList cellList_.clear(); // Add every atom in this System to the CellList System::MoleculeIterator molIter; Atom* atomPtr; for (int iSpec=0; iSpec < system().simulation().nSpecies(); ++iSpec) { for (system().begin(iSpec, molIter); molIter.notEnd(); ++molIter) { for (int ia=0; ia < molIter->nAtom(); ++ia) { atomPtr = &molIter->atom(ia); system().boundary().shift(atomPtr->position()); cellList_.addAtom(*atomPtr); } } } //Use the cell list to find neighbours and create links CellList::NeighborArray cellNeighbor; Vector iPos, jPos; Atom *iAtomPtr, *jAtomPtr; double dRSq, cutoffSq=cutoff_*cutoff_; int nCellNeighbor, nCellAtom, totCells; int ic, ip, iAtomId, jp, jAtomId; // Loop over cells containing primary atom. ic = cell index totCells = cellList_.totCells(); for (ic = 0; ic < totCells; ++ic) { // Get Array cellNeighbor of Ids of neighbor atoms for cell ic. // Elements 0,..., nCellAtom - 1 contain Ids for atoms in cell ic. // Elements nCellAtom,..., nCellNeighbor-1 are from neighboring cells. cellList_.getCellNeighbors(ic, cellNeighbor, nCellAtom); nCellNeighbor = cellNeighbor.size(); // Loop over atoms in cell ic for (ip = 0; ip < nCellAtom; ++ip) { iAtomPtr = cellNeighbor[ip]; iPos = iAtomPtr->position(); iAtomId = iAtomPtr->id(); // Loop over atoms in all neighboring cells, including cell ic. for (jp = 0; jp < nCellNeighbor; ++jp) { jAtomPtr = cellNeighbor[jp]; jPos = jAtomPtr->position(); jAtomId = jAtomPtr->id(); // Avoid double counting: only count pairs with jAtomId > iAtomId if ( jAtomId > iAtomId ) { // Exclude bonded pairs if (!iAtomPtr->mask().isMasked(*jAtomPtr)) { // Calculate distance between atoms i and j dRSq = system().boundary().distanceSq(iPos, jPos); if (dRSq < cutoffSq) { if(system().simulation().random().uniform(0.0, 1.0) < probability_){ //create a link between i and j atoms system().linkMaster().addLink(*iAtomPtr, *jAtomPtr, 0); } } } } // end if jAtomId > iAtomId } // end for jp (j atom) } // end for ip (i atom) } // end for ic (i cell) // Construct a string representation of integer nSample std::stringstream ss; std::string nSampleString; ss << nSample_; nSampleString = ss.str(); // Construct new fileName: outputFileName + char(nSample) std::string filename; filename = outputFileName(); filename += nSampleString; // Open output file, write data, and close file fileMaster().openOutputFile(filename, outputFile_); system().writeConfig(outputFile_); outputFile_.close(); nSample_++; // Clear the LinkMaster system().linkMaster().clear(); } // end isAtInterval }
/* * Evaluate change in energy, add Boltzmann factor to accumulator. */ void McMuExchange::sample(long iStep) { if (isAtInterval(iStep)) { // Preconditions if (!system().energyEnsemble().isIsothermal()) { UTIL_THROW("EnergyEnsemble is not isothermal"); } if (nMolecule_ != system().nMolecule(speciesId_)) { UTIL_THROW("nMolecule has changed since setup"); } McPairPotential& potential = system().pairPotential(); const CellList& cellList = potential.cellList(); System::MoleculeIterator molIter; Atom* ptr0 = 0; // Pointer to first atom in molecule Atom* ptr1 = 0; // Pointer to flipped atom Atom* ptr2 = 0; // Pointer to neighboring atom Mask* maskPtr = 0; // Mask of flipped atom double rsq, dE, beta, boltzmann; int j, k, nNeighbor, nFlip; int i1, i2, id1, id2, t1, t2, t1New, iMol; beta = system().energyEnsemble().beta(); nFlip = flipAtomIds_.size(); // Loop over molecules in species iMol = 0; system().begin(speciesId_, molIter); for ( ; molIter.notEnd(); ++molIter) { dE = 0.0; ptr0 = &molIter->atom(0); // Loop over flipped atoms for (j = 0; j < nFlip; ++j) { i1 = flipAtomIds_[j]; t1New = newTypeIds_[i1]; ptr1 = &molIter->atom(i1); id1 = ptr1->id(); t1 = ptr1->typeId(); maskPtr = &(ptr1->mask()); // Loop over neighboring atoms cellList.getNeighbors(ptr1->position(), neighbors_); nNeighbor = neighbors_.size(); for (k = 0; k < nNeighbor; ++k) { ptr2 = neighbors_[k]; id2 = ptr2->id(); // Check if atoms are identical if (id2 != id1) { // Check if pair is masked if (!maskPtr->isMasked(*ptr2)) { rsq = boundary().distanceSq(ptr1->position(), ptr2->position()); t2 = ptr2->typeId(); if (&(ptr1->molecule()) != &(ptr2->molecule())) { // Intermolecular atom pair dE -= potential.energy(rsq, t1, t2); dE += potential.energy(rsq, t1New, t2); } else { // Intramolecular atom pair if (id2 > id1) { dE -= potential.energy(rsq, t1, t2); i2 = (int)(ptr2 - ptr0); t2 = newTypeIds_[i2]; dE += potential.energy(rsq, t1New, t2); } else { i2 = (int)(ptr2 - ptr0); if (!isAtomFlipped_[i2]) { dE -= potential.energy(rsq, t1, t2); t2 = newTypeIds_[i2]; dE += potential.energy(rsq, t1New, t2); } } } } } } // end loop over neighbors } // end loop over flipped atoms boltzmann = exp(-beta*dE); accumulators_[iMol].sample(boltzmann); ++iMol; } // end loop over molecules } }