Simpatico  v1.10
mcMd/mdIntegrators/NphIntegrator.cpp
1 /*
2 * Simpatico - Simulation Package for Polymeric and Molecular Liquids
3 *
4 * Copyright 2010 - 2017, The Regents of the University of Minnesota
5 * Distributed under the terms of the GNU General Public License.
6 */
7 
8 #include "NphIntegrator.h"
9 #include <mcMd/mdSimulation/MdSystem.h>
10 #include <mcMd/simulation/Simulation.h>
11 #include <mcMd/potentials/pair/MdPairPotential.h>
12 #include <mcMd/chemistry/Molecule.h>
13 #include <mcMd/chemistry/Atom.h>
14 #include <simp/ensembles/EnergyEnsemble.h>
15 #include <simp/ensembles/BoundaryEnsemble.h>
16 #include <simp/boundary/Boundary.h>
17 #include <util/space/Vector.h>
18 #include <util/archives/Serializable_includes.h>
19 #include <util/crystal/LatticeSystem.h>
20 
21 namespace McMd
22 {
23 
24  using namespace Util;
25  using namespace Simp;
26 
27  /*
28  * Constructor.
29  */
31  : MdIntegrator(system),
32  W_(0.0)
33  {
34  setClassName("NphIntegrator");
35 
36  // Start with zero barostat momentum
37  eta_.zero();
38  }
39 
40  /*
41  * Destructor.
42  */
44  {}
45 
46  /*
47  * Read parameter and configuration files, initialize system.
48  */
49  void NphIntegrator::readParameters(std::istream &in)
50  {
51  read<double>(in, "dt", dt_);
52  read<double>(in, "W", W_);
53  read<LatticeSystem>(in, "mode", mode_);
54 
55  int nAtomType = simulation().nAtomType();
56  prefactors_.allocate(nAtomType);
57 
58  }
59 
64  {
65  loadParameter<double>(ar, "dt", dt_);
66  loadParameter<double>(ar, "W", W_);
67  loadParameter<LatticeSystem>(ar, "mode", mode_);
68  ar & eta_;
69  ar & currP_;
70  ar & prefactors_;
71  }
72 
73  /*
74  * Save the internal state to an archive.
75  */
77  {
78  ar & dt_;
79  ar & W_;
80  serializeEnum(ar, mode_);
81  ar & eta_;
82  ar & currP_;
83  ar & prefactors_;
84  }
85 
86  /*
87  * Initialize constants.
88  */
90  {
91  double mass;
92  int nAtomType = prefactors_.capacity();
93  for (int i = 0; i < nAtomType; ++i) {
94  mass = simulation().atomType(i).mass();
95  prefactors_[i] = 0.5*dt_/mass;
96  }
99  }
100 
102  {
103  System::MoleculeIterator molIter;
104  double prefactor;
105  int iSpecies, nSpecies;
106 
107  nSpecies = simulation().nSpecies();
108 
109  /* Perform the first half step of the explicitly reversible NPH integration scheme.
110 
111  This follows from operator factorization
112 
113  - orthorhombic case:
114 
115  1) eta_alpha(t+dt/2) = eta_alpha(t) + dt/2 * V/L_alpha * ( P_{alpha,alpha}(t) - P_ext)
116  2) v' = v(t) + (1/2)a(t)*dt
117  3) L(t+dt/2) = L(t) + dt*eta(t+dt/2)/(2*W)
118  4) r'_alpha = r(t) + v'*dt* (L_{alpha}^2(t)/L_{alpha}^2(t+dt/2))
119  5a) L(t+dt) = L(t+dt/2) + dt*eta(t+dt/2)/2/W
120  5b) r_alpha(t+dt) = L_alpha(t+dt)/L_alpha(t)*r'_alpha
121  5c) v''_alpha = L_alpha(t)/L_alpha(t+dt) * v'_alpha
122 
123  alpha denotes a cartesian index.
124 
125  - isotropic case:
126 
127  only eta_x := eta is used and instead of step 1) we have
128 
129  1') eta(t+dt/2) = eta(t) + dt/2 * (1/3*Tr P(t) - P_ext)
130 
131  furthermore, in step 3) and 5a) L is replaced with V=L^3
132 
133  - tetragonal case:
134 
135  Lx := L_perp, Ly = Lz := L_par
136  eta_x := eta_perp, etay := eta_par, etaz unused
137 
138  instead of step 1) we have
139 
140  1'a) eta_perp(t+dt/2) = eta_perp + dt/2 * V/L_perp * ( P_xx(t) - P_ext)
141  1'b) eta_par(t+dt/2) = eta_par + dt/2 * V/L_par * ( P_yy(t) + P_zz(t) - 2*P_ext)
142 
143  steps 3) and 5a) are split into two sub-steps
144 
145  L_perp(i+1) = L_perp(i) + dt/(2*W)*eta_perp
146  L_par(i+1) = L_par(i) + dt/(4*W)*eta_par
147  */
148 
149  // obtain current stress tensor (diagonal components)
150  system().computeStress(currP_);
151 
152  // obtain current box lengths
153  Vector lengths = system().boundary().lengths();
154  double volume = lengths[0]*lengths[1]*lengths[2];
155 
156  double extP = system().boundaryEnsemble().pressure();
157 
158  // Advance eta(t)->eta(t+dt/2) (step one)
159  if (mode_ == Orthorhombic) {
160  double Vdthalf = 1.0/2.0 * volume * dt_;
161  eta_[0] += Vdthalf/lengths[0] * (currP_[0] - extP);
162  eta_[1] += Vdthalf/lengths[1] * (currP_[1] - extP);
163  eta_[2] += Vdthalf/lengths[2] * (currP_[2] - extP);
164  } else if (mode_ == Tetragonal) {
165  double Vdthalf = 1.0/2.0* volume * dt_;
166  eta_[0] += Vdthalf/lengths[0]*(currP_[0] - extP);
167  eta_[1] += Vdthalf/lengths[1]*(currP_[1] + currP_[2] - 2.0*extP);
168  } else if (mode_ == Cubic) {
169  eta_[0] += 1.0/2.0*dt_*(1.0/3.0*(currP_[0]+currP_[1]+currP_[2]) - extP);
170  }
171 
172  // Update the box length L(t) -> L(t+dt/2) (step three)
173  // (Since we still keep accelerations a(t) computed for length L_alpha(t) in memory,
174  // needed in step two, we can exchange the order of the two steps.)
175  // Also pre-calculate L(t+dt) (step 5a, only depends on eta(t) of step one)
176 
177  Vector lengthsOld = lengths;
178  Vector lengthsFinal;
179  double volumeFinal = 0.0;
180 
181  double dthalfoverW = 1.0/2.0*dt_/W_;
182 
183  if (mode_ == Orthorhombic) {
184  lengths[0] += dthalfoverW*eta_[0];
185  lengths[1] += dthalfoverW*eta_[1];
186  lengths[2] += dthalfoverW*eta_[2];
187  lengthsFinal[0] = lengths[0] + dthalfoverW*eta_[0];
188  lengthsFinal[1] = lengths[1] + dthalfoverW*eta_[1];
189  lengthsFinal[2] = lengths[2] + dthalfoverW*eta_[2];
190  volumeFinal = lengthsFinal[0]*lengthsFinal[1]*lengthsFinal[2];
191  } else if (mode_ == Tetragonal) {
192  lengths[0] += dthalfoverW*eta_[0];
193  lengths[1] += (1.0/2.0)*dthalfoverW*eta_[1];
194  lengths[2] = lengths[1];
195  lengthsFinal[0] = lengths[0] + dthalfoverW*eta_[0];
196  lengthsFinal[1] = lengths[1] + (1.0/2.0)*dthalfoverW*eta_[1];
197  lengthsFinal[2] = lengthsFinal[1];
198  volumeFinal = lengthsFinal[0]*lengthsFinal[1]*lengthsFinal[2];
199  } else if (mode_ == Cubic) {
200  volume += dthalfoverW*eta_[0];
201  lengths[0] = pow(volume,1.0/3.0); // Lx = Ly = Lz = V^(1/3)
202  lengths[1] = lengths[0];
203  lengths[2] = lengths[0];
204  volumeFinal = volume + dthalfoverW*eta_[0];
205  lengthsFinal[0] = pow(volumeFinal,1./3.);
206  lengthsFinal[1] = lengthsFinal[0];
207  lengthsFinal[2] = lengthsFinal[0];
208  }
209 
210  // Update simulation box
211  system().boundary().setOrthorhombic(lengthsFinal);
212 
213  // update particles
214  Atom* atomPtr;
215  int ia;
216  Vector vtmp, dr, rtmp, dv;
217  Vector lengthsFac, dtLengthsFac2;
218 
219  for (int i=0; i<3; i++) {
220  lengthsFac[i] = lengthsFinal[i]/lengthsOld[i];
221  dtLengthsFac2[i] = dt_ * lengthsOld[i]*lengthsOld[i]/lengths[i]/lengths[i];
222  }
223 
224  for (iSpecies=0; iSpecies < nSpecies; ++iSpecies) {
225  system().begin(iSpecies, molIter);
226  for ( ; molIter.notEnd(); ++molIter) {
227  for (ia=0; ia < molIter->nAtom(); ++ia) {
228  atomPtr = &molIter->atom(ia);
229  prefactor = prefactors_[atomPtr->typeId()];
230 
231  dv.multiply(atomPtr->force(), prefactor);
232  vtmp.add(atomPtr->velocity(),dv);
233 
234  dr[0] = vtmp[0] * dtLengthsFac2[0];
235  dr[1] = vtmp[1] * dtLengthsFac2[1];
236  dr[2] = vtmp[2] * dtLengthsFac2[2];
237 
238  rtmp.add(atomPtr->position(), dr);
239 
240  rtmp[0] *= lengthsFac[0];
241  rtmp[1] *= lengthsFac[1];
242  rtmp[2] *= lengthsFac[2];
243 
244  atomPtr->position() = rtmp;
245 
246  vtmp[0] /= lengthsFac[0];
247  vtmp[1] /= lengthsFac[1];
248  vtmp[2] /= lengthsFac[2];
249 
250  atomPtr->velocity() = vtmp;
251  }
252  }
253  }
256 
257  #ifndef SIMP_NOPAIR
258  if (!system().pairPotential().isPairListCurrent()) {
260  }
261  #endif
262 
264 
265  /* Second step of the explicitly reversible integrator consists of the following sub-steps
266  *
267  * 6) v(t+dt) = v'' + 1/2 * a(t+dt)*dt
268  * 7) eta(t+dt/2) -> eta(t+dt)
269  */
270 
271  // Update velocities
272  // v(t+dt) = v'' + 1/2 * a(t+dt)*dt
273  for (iSpecies=0; iSpecies < nSpecies; ++iSpecies) {
274  system().begin(iSpecies, molIter);
275  for ( ; molIter.notEnd(); ++molIter)
276  {
277  for (ia=0; ia < molIter->nAtom(); ++ia) {
278  atomPtr = &molIter->atom(ia);
279  prefactor = prefactors_[atomPtr->typeId()];
280  dv.multiply(atomPtr->force(), prefactor);
281  atomPtr->velocity() += dv;
282  }
283  }
284  }
286 
287  // now compute pressure tensor with updated virial and velocities
288  system().computeStress(currP_);
289 
290  // Advance eta(t+dt/2) -> eta(t+dt)
291  if (mode_ == Orthorhombic) {
292  double Vdthalf = 1.0/2.0 * volumeFinal * dt_;
293  eta_[0] += Vdthalf/lengthsFinal[0] * (currP_[0] - extP);
294  eta_[1] += Vdthalf/lengthsFinal[1] * (currP_[1] - extP);
295  eta_[2] += Vdthalf/lengthsFinal[2] * (currP_[2] - extP);
296  } else if (mode_ == Tetragonal) {
297  double Vdthalf = 1.0/2.0 * volumeFinal * dt_;
298  eta_[0] += Vdthalf/lengthsFinal[0]*(currP_[0] - extP);
299  eta_[1] += Vdthalf/lengthsFinal[1]*(currP_[1] + currP_[2] - 2.0*extP);
300  } else if (mode_ == Cubic) {
301  eta_[0] += 1.0/2.0*dt_*(1.0/3.0*(currP_[0]+currP_[1]+currP_[2]) - extP);
302  }
303 
304  #ifndef SIMP_NOPAIR
305  if (!system().pairPotential().isPairListCurrent()) {
307  }
308  #endif
309 
310  /*
311  // debug output
312  double P;
313  system().computeStress(P);
314  std::cout << system().boundary() << std::endl;
315  std::cout << "P = " << P << " ";
316  std::cout << "Ekin = " << system().kineticEnergy() << " ";
317  std::cout << "Epot = " << system().potentialEnergy() << " ";
318  std::cout << "PV = " << extP * system().boundary().volume() << " ";
319  std::cout << "Ebaro = " << barostatEnergy() << " ";
320  std::cout << "H = " << system().potentialEnergy() + system().kineticEnergy() +
321  extP * system().boundary().volume() + barostatEnergy() << std::endl;
322  */
323  }
324 
325  /*
326  * Get barostat energy.
327  */
329  {
330  double barostat_energy = 0.0;
331  if (mode_ == Orthorhombic)
332  barostat_energy = (eta_[0]*eta_[0]+eta_[1]*eta_[1]+eta_[2]*eta_[2]) / 2.0 / W_;
333  else if (mode_ == Tetragonal)
334  barostat_energy = (eta_[0]*eta_[0]+eta_[1]*eta_[1]/2.0) / 2.0 / W_;
335  else if (mode_ == Cubic)
336  barostat_energy = eta_[0]*eta_[0]/2.0/W_;
337 
338  return barostat_energy;
339  }
340 
341  /*
342  * Get barostat mass.
343  */
345  { return W_; }
346 
347  /*
348  * Get mode of integrator.
349  */
351  { return mode_; }
352 
353  /*
354  * Get momentum of barostat.
355  */
356  //Vector& NphIntegrator::eta()
357  //{ return eta_; }
358 
359  /*
360  * Set momentum component of barostat.
361  */
362  void NphIntegrator::setEta(unsigned int index, double eta)
363  {
364  eta_[index] = eta;
365  }
366 
367 }
Vector & zero()
Set all elements of a 3D vector to zero.
Definition: Vector.h:514
A Vector is a Cartesian vector.
Definition: Vector.h:75
virtual void setup()
Setup private variables before main loop.
void calculateForces()
Compute all forces in this System.
Definition: MdSystem.cpp:857
void begin(int speciesId, MoleculeIterator &iterator)
Initialize an iterator for molecules of one species in this System.
Definition: System.h:1147
Vector & add(const Vector &v1, const Vector &v2)
Add vectors v1 and v2.
Definition: Vector.h:657
Vector & velocity()
Get atomic velocity Vector by reference.
double pressure() const
Get the target pressure.
Signal & positionSignal()
Signal to indicate change in atomic positions.
Definition: MdSystem.h:669
Vector & force()
Get atomic force Vector by reference.
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.
Definition: Vector.h:686
virtual double barostatEnergy()
Get the barostat energy.
virtual void step()
Take a complete NVE MD integration step.
BoundaryEnsemble & boundaryEnsemble() const
Get the BoundaryEnsemble by reference.
Definition: System.h:1104
Classes used by all simpatico molecular simulations.
Simulation & simulation()
Get parent Simulation by reference.
Definition: MdIntegrator.h:111
void computeStress(T &stress) const
Compute total pressure (T=double), xyz pressures (T=Vector) or stress (T=Tensor). ...
virtual LatticeSystem mode() const
Get the integrator mode.
Abstract base for molecular dynamics integrators.
Definition: MdIntegrator.h:30
Saving / output archive for binary ostream.
MdPairPotential & pairPotential() const
Return MdPairPotential by reference.
Definition: MdSystem.h:520
const AtomType & atomType(int i) const
Get a single AtomType object by const reference.
virtual double barostatMass() const
Get the barostat mass.
int typeId() const
Get type index for this Atom.
MdSystem & system()
Get parent MdSystem by reference.
Definition: MdIntegrator.h:105
virtual void readParameters(std::istream &in)
Read parameters from file and initialize this MdSystem.
void notify(const T &t)
Notify all observers.
Definition: Signal.cpp:22
virtual void loadParameters(Serializable::IArchive &ar)
Load the internal state to an archive.
A point particle within a Molecule.
bool notEnd() const
Is the current pointer not at the end of the PArray?
Utility classes for scientific computation.
Definition: accumulators.mod:1
void serializeEnum(Archive &ar, T &data, const unsigned int version=0)
Serialize an enumeration value.
Definition: serialize.h:42
virtual void save(Serializable::OArchive &ar)
Save the internal state to an archive.
virtual void setEta(unsigned int index, double eta)
Get the barostat momentum.
Forward iterator for a PArray.
Definition: ArraySet.h:19
double dt_
Integrator time step.
Definition: MdIntegrator.h:79
Signal & velocitySignal()
Signal to indicate change in atomic velocities.
Definition: MdSystem.h:675
Boundary & boundary() const
Get the Boundary by reference.
Definition: System.h:1064
Saving archive for binary istream.
LatticeSystem
Enumeration of the 7 possible Bravais lattice systems.
Definition: LatticeSystem.h:29
double mass() const
Get the mass.
Single-processor Monte Carlo (MC) and molecular dynamics (MD).
int nSpecies() const
Get the number of Species in this Simulation.
void buildPairList()
Build the internal PairList.
void setClassName(const char *className)
Set class name string.
NphIntegrator(MdSystem &system)
Constructor.
A System for Molecular Dynamics simulation.
Definition: MdSystem.h:68
int capacity() const
Return allocated size.
Definition: Array.h:153
void allocate(int capacity)
Allocate the underlying C array.
Definition: DArray.h:191
const Vector & position() const
Get the position Vector by const reference.
int nAtomType() const
Get the number of atom types.