8 #include "NptIntegrator.h" 9 #include <ddMd/simulation/Simulation.h> 10 #include <ddMd/storage/AtomStorage.h> 11 #include <ddMd/storage/AtomIterator.h> 12 #include <ddMd/communicate/Exchanger.h> 13 #include <ddMd/potentials/pair/PairPotential.h> 14 #include <simp/ensembles/EnergyEnsemble.h> 15 #include <simp/ensembles/BoundaryEnsemble.h> 16 #include <util/mpi/MpiLoader.h> 17 #include <util/space/Vector.h> 18 #include <util/format/Dbl.h> 47 read<double>(in,
"dt", dt_);
48 read<double>(in,
"tauT", tauT_);
49 read<double>(in,
"tauP", tauP_);
50 read<LatticeSystem>(in,
"mode", mode_);
66 loadParameter<double>(ar,
"dt", dt_);
67 loadParameter<double>(ar,
"tauT", tauT_);
68 loadParameter<double>(ar,
"tauP", tauP_);
69 loadParameter<LatticeSystem>(ar,
"mode", mode_);
105 nu_ =
Vector(0.0, 0.0, 0.0);
120 double dtHalf = 0.5*dt_;
125 prefactors_[i] = dtHalf/mass;
133 if (
domain().isMaster()) {
165 P_curr_diag_ =
Vector(stress(0, 0), stress(1,1), stress(2,2));
166 double P_curr = (1.0/3.0)*stress.
trace();
168 double W = (1.0/2.0)*ndof_*T_target_*tauP_*tauP_;
169 double mtk_term = (1.0/2.0)*dt_*T_kinetic_/W;
173 if (mode_ == Cubic) {
174 nu_[0] += (1.0/2.0)*dt_*V/W*(P_curr - P_target_) + mtk_term;
175 nu_[1] = nu_[2] = nu_[0];
176 }
else if (mode_ == Tetragonal) {
177 nu_[0] += (1.0/2.0)*dt_*V/W*(P_curr_diag_[0] - P_target_) + mtk_term;
178 nu_[1] += (1.0/2.0)*dt_*V/W*((1.0/2.0)*(P_curr_diag_[1] + P_curr_diag_[2]) - P_target_)
181 }
else if (mode_ == Orthorhombic) {
182 nu_[0] += (1.0/2.0)*dt_*V/W*(P_curr_diag_[0] - P_target_) + mtk_term;
183 nu_[1] += (1.0/2.0)*dt_*V/W*(P_curr_diag_[1] - P_target_) + mtk_term;
184 nu_[2] += (1.0/2.0)*dt_*V/W*(P_curr_diag_[2] - P_target_) + mtk_term;
188 xi_prime = xi_ + (1.0/4.0)*dt_/tauT_/tauT_*(T_kinetic_/T_target_ - 1.0);
189 xi_ = xi_prime + (1.0/4.0)*dt_/tauT_/tauT_*(T_kinetic_/T_target_*exp(-xi_prime*dt_) - 1.0);
190 eta_ += (1.0/2.0)*xi_prime*dt_;
200 mtk_term_2_ = (nu_[0]+nu_[1]+nu_[2])/ndof_;
202 (1.0/4.0)*(nu_[1]+mtk_term_2_),
203 (1.0/4.0)*(nu_[2]+mtk_term_2_));
204 exp_v_fac_ =
Vector(exp(-v_fac[0]*dt_),
207 Vector exp_v_fac_2 =
Vector(exp(-(2.0*v_fac[0]+(1.0/2.0)*xi_prime)*dt_),
208 exp(-(2.0*v_fac[1]+(1.0/2.0)*xi_prime)*dt_),
209 exp(-(2.0*v_fac[2]+(1.0/2.0)*xi_prime)*dt_));
218 const double a[] = { double(1.0), double(1.0/6.0), double(1.0/120.0),
219 double(1.0/5040.0), double(1.0/362880.0), double(1.0/39916800.0)};
221 Vector arg_v =
Vector(v_fac[0]*dt_, v_fac[1]*dt_, v_fac[2]*dt_);
222 Vector arg_r =
Vector(r_fac[0]*dt_, r_fac[1]*dt_, r_fac[2]*dt_);
224 sinhx_fac_v_ =
Vector(0.0, 0.0, 0.0);
230 for (
unsigned int i = 0; i < 6; i++) {
231 sinhx_fac_v_ +=
Vector(a[i]*term_v[0],
234 sinhx_fac_r +=
Vector(a[i]*term_r[0],
237 term_v =
Vector(term_v[0] * arg_v[0] * arg_v[0],
238 term_v[1] * arg_v[1] * arg_v[1],
239 term_v[2] * arg_v[2] * arg_v[2]);
240 term_r =
Vector(term_r[0] * arg_r[0] * arg_r[0],
241 term_r[1] * arg_r[1] * arg_r[1],
242 term_r[2] * arg_r[2] * arg_r[2]);
248 for ( ; atomIter.
notEnd(); ++atomIter) {
249 prefactor = prefactors_[atomIter->typeId()];
251 dv.
multiply(atomIter->force(), prefactor);
252 dv[0] = dv[0] * exp_v_fac_[0]*sinhx_fac_v_[0];
253 dv[1] = dv[1] * exp_v_fac_[1]*sinhx_fac_v_[1];
254 dv[2] = dv[2] * exp_v_fac_[2]*sinhx_fac_v_[2];
256 Vector& v = atomIter->velocity();
257 v[0] = v[0] * exp_v_fac_2[0] + dv[0];
258 v[1] = v[1] * exp_v_fac_2[1] + dv[1];
259 v[2] = v[2] * exp_v_fac_2[2] + dv[2];
261 vtmp[0] = v[0]*exp_r_fac[0] *sinhx_fac_r[0];
262 vtmp[1] = v[1]*exp_r_fac[1] *sinhx_fac_r[1];
263 vtmp[2] = v[2]*exp_r_fac[2] *sinhx_fac_r[2];
265 Vector& r = atomIter->position();
266 r[0] = r[0]*exp_r_fac[0]*exp_r_fac[0] + vtmp[0]*dt_;
267 r[1] = r[1]*exp_r_fac[1]*exp_r_fac[1] + vtmp[1]*dt_;
268 r[2] = r[2]*exp_r_fac[2]*exp_r_fac[2] + vtmp[2]*dt_;
277 L[0] *= box_len_scale[0];
278 L[1] *= box_len_scale[1];
279 L[2] *= box_len_scale[2];
293 (1.0/2.0)*(nu_[1]+mtk_term_2_),
294 (1.0/2.0)*(nu_[2]+mtk_term_2_));
296 exp(-v_fac_2[1]*dt_),
297 exp(-v_fac_2[2]*dt_));
303 for ( ; atomIter.
notEnd(); ++atomIter) {
304 prefactor = prefactors_[atomIter->typeId()];
305 dv.
multiply(atomIter->force(), prefactor);
306 dv[0] = dv[0] * exp_v_fac_[0]*sinhx_fac_v_[0];
307 dv[1] = dv[1] * exp_v_fac_[1]*sinhx_fac_v_[1];
308 dv[2] = dv[2] * exp_v_fac_[2]*sinhx_fac_v_[2];
310 Vector& v = atomIter->velocity();
311 v[0] = v[0] * exp_v_fac_2[0] + dv[0];
312 v[1] = v[1] * exp_v_fac_2[1] + dv[1];
313 v[2] = v[2] * exp_v_fac_2[2] + dv[2];
317 v2_sum += v.
dot(v)*mass;
328 if (
domain().isMaster()) {
330 xi_prime = xi_ + (1.0/4.0)*dt_/tauT_/tauT_*(T_prime/T_target_ - 1.0);
331 xi_ = xi_prime + (1.0/4.0)*dt_/tauT_/tauT_*(T_prime/T_target_*exp(-xi_prime*dt_) - 1.0);
332 eta_ += (1.0/2.0)*xi_prime*dt_;
340 double exp_v_fac_thermo = exp(-(1.0/2.0)*xi_prime*dt_);
342 for ( ; atomIter.
notEnd(); ++atomIter) {
343 atomIter->velocity().multiply(atomIter->velocity(), exp_v_fac_thermo);
357 P_curr_diag_ =
Vector(stress(0,0), stress(1,1), stress(2,2));
358 double P_curr = (1.0/3.0)*stress.
trace();
360 double W = (1.0/2.0)*ndof_*T_target_*tauP_*tauP_;
361 double mtk_term = (1.0/2.0)*dt_*T_kinetic_/W;
364 if (mode_ == Cubic) {
365 nu_[0] += (1.0/2.0)*dt_*V/W*(P_curr - P_target_) + mtk_term;
366 nu_[1] = nu_[2] = nu_[0];
367 }
else if (mode_ == Tetragonal) {
368 nu_[0] += (1.0/2.0)*dt_*V/W*(P_curr_diag_[0] - P_target_) + mtk_term;
369 nu_[1] += (1.0/2.0)*dt_*V/W*((1.0/2.0)*(P_curr_diag_[1]+P_curr_diag_[2]) - P_target_) + mtk_term;
371 }
else if (mode_ == Orthorhombic) {
372 nu_[0] += (1.0/2.0)*dt_*V/W*(P_curr_diag_[0] - P_target_) + mtk_term;
373 nu_[1] += (1.0/2.0)*dt_*V/W*(P_curr_diag_[1] - P_target_) + mtk_term;
374 nu_[2] += (1.0/2.0)*dt_*V/W*(P_curr_diag_[2] - P_target_) + mtk_term;
383 file.open(
"NPT.log", std::ios::out | std::ios::app);
384 double thermostat_energy = ndof_ * T_target_ * (eta_ + tauT_*tauT_*xi_*xi_/2.0);
385 double W = (1.0/2.0)*ndof_*T_target_*tauP_*tauP_;
387 double barostat_energy = W*(nu_[0]*nu_[0]+ nu_[1]*nu_[1] + nu_[2]*nu_[2]);
393 <<
Dbl(barostat_energy,20)
394 <<
Dbl(thermostat_energy,20)
void loadParameters(Serializable::IArchive &ar)
Load saveInterval and saveFileName from restart archive.
Signal & velocitySignal()
Signal to indicate change in atomic velocities.
A Vector is a Cartesian vector.
int nAtomTotal() const
Get total number of atoms on all processors.
virtual void integrateStep2()
Execute secodn step of two-step integrator.
double kineticEnergy()
Return precomputed total kinetic energy.
double pressure() const
Get the target pressure.
double volume() const
Return unit cell volume.
double dot(const Vector &v) const
Return dot product of this vector and vector v.
void setOrthorhombic(const Vector &lengths)
Set unit cell dimensions for orthorhombic boundary.
const Vector & lengths() const
Get Vector of unit cell lengths by const reference.
Vector & multiply(const Vector &v, double s)
Multiply a vector v by a scalar s.
void readParameters(std::istream &in)
Read saveInterval and saveFileName.
BoundaryEnsemble & boundaryEnsemble()
Get the BoundaryEnsemble by reference.
void setIsSetup()
Mark the integrator as having been setup at least once.
double mass() const
Get the mass.
virtual void integrateStep1()
Execute first step of two-step integrator.
Wrapper for a double precision number, for formatted ostream output.
File containing preprocessor macros for error handling.
Parallel domain decomposition (DD) MD simulation.
Classes used by all simpatico molecular simulations.
double trace() const
Return the trace of this tensor.
Main object for a domain-decomposition MD simulation.
A Tensor represents a Cartesian tensor.
MPI::Intracomm & communicator() const
Return Cartesian communicator by reference.
AtomType & atomType(int i)
Get an AtomType descriptor by reference.
Saving / output archive for binary ostream.
~NptIntegrator()
Destructor.
void setupAtoms()
Setup state of atoms just before integration.
void bcast(MPI::Intracomm &comm, T &data, int root)
Broadcast a single T value.
void computePotentialEnergies()
Calculate and store total potential energy on all processors.
void notify(const T &t)
Notify all observers.
bool notEnd() const
Is the current pointer not at the end of the PArray?
Utility classes for scientific computation.
void load(Data &value)
Load and broadcast a single Data value.
NptIntegrator(Simulation &simulation)
Constructor.
Domain & domain()
Get the Domain.
Tensor kineticStress() const
Return total kinetic stress.
bool isAllocated() const
Return true if the DArray has been allocated, false otherwise.
bool isSetup() const
Has the setup() method been called at least once previously?
AtomStorage & atomStorage()
Get the AtomStorage.
void save(Serializable::OArchive &ar)
Save saveInterval and saveFileName from restart archive.
void computeNAtomTotal(MPI::Intracomm &communicator)
Compute the total number of local atoms on all processors.
bool isMaster() const
Is this the master processor (gridRank == 0) ?
void computeVirialStress()
Calculate and store all virial stress contributions.
Simulation & simulation()
Get the parent simulation.
void readParameters(std::istream &in)
Read required parameters.
double potentialEnergy() const
Return sum of precomputed total potential energies.
int nAtomType()
Get maximum number of atom types.
Saving archive for binary istream.
Provides methods for MPI-aware loading of data from input archive.
A two-step velocity-Verlet style integrator.
void setClassName(const char *className)
Set class name string.
int nAtomType()
Get maximum number of atom types.
Boundary & boundary()
Get the Boundary by reference.
int capacity() const
Return allocated size.
void allocate(int capacity)
Allocate the underlying C array.
virtual void loadParameters(Serializable::IArchive &ar)
Load internal state from an archive.
double temperature() const
Return the temperature.
void computeKineticEnergy()
Compute total kinetic energy.
Domain & domain()
Get the Domain by reference.
virtual void save(Serializable::OArchive &ar)
Save internal state to an archive.
void setup()
Setup state just before main loop.
Tensor virialStress() const
Return total virial stress.
Iterator for all atoms owned by an AtomStorage.
void computeKineticStress()
Calculate and store kinetic stress.
virtual void clear()
Set integrator to initial state and clears all statistics.
void begin(AtomIterator &iterator)
Set iterator to beginning of the set of atoms.
virtual void initDynamicalState()
Initialize internal state variables xi, eta, and nu to zero.
EnergyEnsemble & energyEnsemble()
Get the EnergyEnsemble by reference.