Simpatico  v1.10
MdEwaldPairPotentialImpl.h
1 #ifndef MCMD_MD_EWALD_PAIR_POTENTIAL_IMPL_H
2 #define MCMD_MD_EWALD_PAIR_POTENTIAL_IMPL_H
3 
4 #include <mcMd/potentials/pair/MdPairPotential.h>
5 #include <mcMd/potentials/pair/McPairPotentialImpl.h>
6 #include <mcMd/simulation/stress.h>
7 #include <mcMd/mdSimulation/MdSystem.h>
8 #include <mcMd/chemistry/AtomType.h>
9 #include <util/containers/Array.h>
10 #include <util/space/Tensor.h>
11 #include <util/misc/Setable.h>
12 #include <util/global.h>
13 
14 #include <mcMd/potentials/coulomb/EwaldRSpaceAccumulator.h>
15 #include <simp/interaction/coulomb/EwaldInteraction.h>
16 
17 namespace Util
18 {
19  class Vector;
20 }
21 
22 namespace McMd
23 {
24 
25  class MdSystem;
26 
27  using namespace Util;
28  using namespace Simp;
29 
47  template <class Interaction>
49  {
50  public:
51 
56 
60  virtual ~MdEwaldPairPotentialImpl();
61 
72  virtual void readParameters(std::istream& in);
73 
79  virtual void loadParameters(Serializable::IArchive &ar);
80 
86  virtual void save(Serializable::OArchive &ar);
87 
89 
90 
99  virtual
100  double energy(double rsq, int iAtomType, int jAtomType) const;
101 
110  virtual
111  double forceOverR(double rsq, int iAtomType, int jAtomType) const;
112 
116  virtual double maxPairCutoff() const;
117 
126  void set(std::string name, int i, int j, double value)
127  { pairPtr_->set(name, i, j, value); }
128 
136  double get(std::string name, int i, int j) const
137  { return pairPtr_->get(name, i, j); }
138 
142  virtual std::string interactionClassName() const;
143 
145 
147 
148  // Force evaluation, which adds both types of pair force.
149  virtual void addForces();
150 
154  virtual void unsetEnergy();
155 
159  virtual void computeEnergy();
160 
164  virtual void unsetStress();
165 
169  virtual void computeStress();
170 
172 
173  private:
174 
175  // Pointer to non-Coulombic pair interaction
176  Interaction* pairPtr_;
177 
178  // Pointer to Ewald Coulomb interaction (owned by MdCoulombPotential)
179  EwaldInteraction* ewaldInteractionPtr_;
180 
181  // Pointer to EwaldRSpaceAccumulator (owned by MdCoulombPotential)
182  EwaldRSpaceAccumulator* rSpaceAccumulatorPtr_;
183 
184  // Pointer to array of AtomType objects (contain mass and charge)
185  const Array<AtomType>* atomTypesPtr_;
186 
187  // True iff this is a copy of an MC pair potential (for hybrid MC).
188  bool isCopy_;
189 
190  // Get an AtomType
191  const AtomType& atomType(int i)
192  { return (*atomTypesPtr_)[i]; }
193 
194  };
195 }
196 
197 #include <mcMd/simulation/System.h>
198 #include <mcMd/simulation/Simulation.h>
199 #include <mcMd/mdSimulation/MdSystem.h>
200 #include <mcMd/simulation/stress.h>
201 #include <mcMd/neighbor/PairIterator.h>
202 #include <simp/boundary/Boundary.h>
203 #include <util/math/Constants.h>
204 #include <util/space/Dimension.h>
205 #include <util/space/Vector.h>
206 #include <util/accumulators/setToZero.h>
207 #include <mcMd/potentials/coulomb/MdCoulombPotential.h>
208 #include <mcMd/potentials/coulomb/MdEwaldPotential.h>
209 #ifdef SIMP_FFTW
210 #include <mcMd/potentials/coulomb/MdSpmePotential.h>
211 #endif
212 #include <fstream>
213 
214 namespace McMd
215 {
216 
217  using namespace Util;
218  using namespace Simp;
219 
220  /*
221  * Constructor.
222  */
223  template <class Interaction>
225  : MdPairPotential(system),
226  pairPtr_(0),
227  ewaldInteractionPtr_(0),
228  rSpaceAccumulatorPtr_(0),
229  atomTypesPtr_(&system.simulation().atomTypes()),
230  isCopy_(false)
231  {
232  // Get pointer to MdCoulombPotential.
233  MdCoulombPotential* kspacePtr;
234  kspacePtr = &system.coulombPotential();
235 
236  // Dynamic cast to a pointer to MdEwaldPotential or MdSpmePotential.
237  if (system.coulombStyle() == "Ewald"){
238  MdEwaldPotential* ewaldPtr;
239  ewaldPtr = dynamic_cast<MdEwaldPotential*>(kspacePtr);
240  ewaldInteractionPtr_ = &ewaldPtr->ewaldInteraction();
241  rSpaceAccumulatorPtr_ = &ewaldPtr->rSpaceAccumulator();
242  }
243  #ifdef SIMP_FFTW
244  else
245  if (system.coulombStyle() == "SPME"){
246  MdSpmePotential* ewaldPtr;
247  ewaldPtr = dynamic_cast<MdSpmePotential*>(kspacePtr);
248  ewaldInteractionPtr_ = &ewaldPtr->ewaldInteraction();
249  rSpaceAccumulatorPtr_ = &ewaldPtr->rSpaceAccumulator();
250  }
251  #endif
252  else {
253  UTIL_THROW("Unrecognized coulomb style");
254  }
255  UTIL_CHECK(rSpaceAccumulatorPtr_);
256  rSpaceAccumulatorPtr_->setPairPotential(*this);
257 
258  pairPtr_ = new Interaction;
259  }
260 
261  /*
262  * Destructor.
263  */
264  template <class Interaction>
266  {
267  if (pairPtr_ && !isCopy_) {
268  delete pairPtr_;
269  pairPtr_ = 0;
270  ewaldInteractionPtr_ = 0;
271  rSpaceAccumulatorPtr_ = 0;
272  }
273  }
274 
275  /*
276  * Read parameers and initialize object.
277  */
278  template <class Interaction>
280  {
281  // Read pair potential parameters only if not a copy.
282  if (!isCopy_) {
283  pairPtr_->setNAtomType(simulation().nAtomType());
284  bool nextIndent = false;
285  addParamComposite(*pairPtr_, nextIndent);
286  pairPtr_->readParameters(in);
287  }
288 
289  // Require that the Ewald rSpaceCutoff >= pair potential maxPairCutoff
290  UTIL_CHECK(ewaldInteractionPtr_->rSpaceCutoff() >= pairPtr_->maxPairCutoff())
291  //double cutoff = (ewaldInteractionPtr_->rSpaceCutoff() > pairPtr_->maxPairCutoff()) ?
292  // ewaldInteractionPtr_->rSpaceCutoff(): pairPtr_->maxPairCutoff();
293  double cutoff = ewaldInteractionPtr_->rSpaceCutoff();
294 
296 
297  // Initialize the PairList
298  pairList_.initialize(simulation().atomCapacity(), cutoff);
299 
300  }
301 
302  /*
303  * Load internal state from an archive.
304  */
305  template <class Interaction>
306  void
308  {
309  ar >> isCopy_;
310  if (!isCopy_) {
311  pairPtr_->setNAtomType(simulation().nAtomType());
312  bool nextIndent = false;
313  addParamComposite(*pairPtr_, nextIndent);
314  pairPtr_->loadParameters(ar);
315  }
316  UTIL_CHECK(ewaldInteractionPtr_->rSpaceCutoff() >=
317  pairPtr_->maxPairCutoff())
319 
320  }
321 
322  /*
323  * Save internal state to an archive.
324  */
325  template <class Interaction>
327  {
328  ar << isCopy_;
329  if (!isCopy_) {
330  pairPtr_->save(ar);
331  }
332  pairList_.save(ar);
333  }
334 
335  /*
336  * Return pair energy for a single pair.
337  */
338  template <class Interaction> double
340  int iAtomType, int jAtomType)
341  const
342  { return pairPtr_->energy(rsq, iAtomType, jAtomType); }
343 
344  /*
345  * Return force / separation for a single pair.
346  */
347  template <class Interaction> double
349  int iAtomType, int jAtomType) const
350  {
351  if (rsq < pairPtr_->cutoffSq(iAtomType, jAtomType)) {
352  return pairPtr_->forceOverR(rsq, iAtomType, jAtomType);
353  } else {
354  return 0.0;
355  }
356  }
357 
358  /*
359  * Return maximum cutoff for non-Coulomb interactions.
360  */
361  template <class Interaction>
363  { return pairPtr_->maxPairCutoff(); }
364 
365  /*
366  * Return pair interaction class name.
367  */
368  template <class Interaction>
370  { return pairPtr_->className(); }
371 
372  /*
373  * Add nonBonded pair forces to atomic forces.
374  */
375  template <class Interaction>
377  {
378  UTIL_CHECK(ewaldInteractionPtr_);
379 
380  // Update PairList if necessary
381  if (!isPairListCurrent()) {
382  buildPairList();
383  }
384 
385  PairIterator iter;
386  Vector force;
387  double forceOverR;
388  double rsq;
389  double qProduct;
390  double ewaldCutoffSq = ewaldInteractionPtr_->rSpaceCutoffSq();
391  Atom *atom0Ptr;
392  Atom *atom1Ptr;
393  int type0, type1;
394 
395  // Loop over nonbonded neighbor pairs
396  for (pairList_.begin(iter); iter.notEnd(); ++iter) {
397  iter.getPair(atom0Ptr, atom1Ptr);
398  rsq = boundary().
399  distanceSq(atom0Ptr->position(), atom1Ptr->position(),
400  force);
401  if (rsq < ewaldCutoffSq) {
402  type0 = atom0Ptr->typeId();
403  type1 = atom1Ptr->typeId();
404  qProduct = (*atomTypesPtr_)[type0].charge();
405  qProduct *= (*atomTypesPtr_)[type1].charge();
406  forceOverR = ewaldInteractionPtr_->rSpaceForceOverR(rsq, qProduct);
407  if (rsq < pairPtr_->cutoffSq(type0, type1)) {
408  forceOverR += pairPtr_->forceOverR(rsq, type0, type1);
409  }
410  force *= forceOverR;
411  atom0Ptr->force() += force;
412  atom1Ptr->force() -= force;
413  }
414  }
415 
416  }
417 
418  /*
419  * Unset both energy accumulators.
420  */
421  template <class Interaction>
423  {
424  UTIL_CHECK(rSpaceAccumulatorPtr_);
425  // Unset non-coulomb pair energy (inherited from EnergyCalculator).
426  energy_.unset();
427  // Unset coulomb r-space energy.
428  rSpaceAccumulatorPtr_->rSpaceEnergy_.unset();
429  }
430 
431  /*
432  * Compute and store pair interaction energy.
433  */
434  template <class Interaction>
436  {
437  UTIL_CHECK(ewaldInteractionPtr_);
438  UTIL_CHECK(rSpaceAccumulatorPtr_);
439 
440  // Update PairList iff necessary
441  if (!isPairListCurrent()) {
442  buildPairList();
443  }
444 
445  // Loop over pairs
446  PairIterator iter;
447  Atom *atom0Ptr;
448  Atom *atom1Ptr;
449  double rsq;
450  double qProduct;
451  double pEnergy = 0.0;
452  double cEnergy = 0.0;
453  double ewaldCutoffSq = ewaldInteractionPtr_->rSpaceCutoffSq();
454  int type0, type1;
455 
456  for (pairList_.begin(iter); iter.notEnd(); ++iter) {
457  iter.getPair(atom0Ptr, atom1Ptr);
458 
459  rsq = boundary().distanceSq(atom0Ptr->position(),
460  atom1Ptr->position());
461  if (rsq < ewaldCutoffSq) {
462  type0 = atom0Ptr->typeId();
463  type1 = atom1Ptr->typeId();
464  if (rsq < pairPtr_->cutoffSq(type0, type1)) {
465  pEnergy += pairPtr_->energy(rsq, atom0Ptr->typeId(),
466  atom1Ptr->typeId());
467  }
468  qProduct = (*atomTypesPtr_)[type0].charge();
469  qProduct *= (*atomTypesPtr_)[type1].charge();
470  cEnergy += ewaldInteractionPtr_->rSpaceEnergy(rsq, qProduct);
471  }
472  }
473 
474  // Set energy accumulators
475  energy_.set(pEnergy);
476  rSpaceAccumulatorPtr_->rSpaceEnergy_.set(cEnergy);
477  }
478 
479  /*
480  * Unset both pair and short-range coulomb stress accumulators.
481  */
482  template <class Interaction>
484  {
485  UTIL_CHECK(rSpaceAccumulatorPtr_);
486  stress_.unset();
487  rSpaceAccumulatorPtr_->rSpaceStress_.unset();
488  }
489 
490  /*
491  * Add nonBonded pair forces to atomic forces.
492  */
493  template <class Interaction>
495  {
496  UTIL_CHECK(ewaldInteractionPtr_);
497  UTIL_CHECK(rSpaceAccumulatorPtr_);
498  UTIL_CHECK(atomTypesPtr_);
499 
500  Tensor pStress; // Non-Coulombic (e.g., LJ) pair stress
501  Tensor cStress; // Short-range Coulomb pair stress
502  Vector dr;
503  Vector force;
504  double rsq;
505  double qProduct;
506  double forceOverR;
507  double ewaldCutoffSq = ewaldInteractionPtr_->rSpaceCutoffSq();
508  PairIterator iter;
509  Atom* atom1Ptr;
510  Atom* atom0Ptr;
511  int type0, type1;
512 
513  // Update PairList if necessary
514  if (!isPairListCurrent()) {
515  buildPairList();
516  }
517 
518  // Set stress accumulator tensors to zero.
519  pStress.zero();
520  cStress.zero();
521 
522  // Loop over nonbonded neighbor pairs
523  for (pairList_.begin(iter); iter.notEnd(); ++iter) {
524  iter.getPair(atom0Ptr, atom1Ptr);
525  rsq = boundary().
526  distanceSq(atom0Ptr->position(), atom1Ptr->position(), dr);
527 
528 
529  if (rsq < ewaldCutoffSq) {
530  type0 = atom0Ptr->typeId();
531  type1 = atom1Ptr->typeId();
532 
533  // Non-Coulomb stress
534  if (rsq < pairPtr_->cutoffSq(type0, type1)) {
535  force = dr;
536  force *= pairPtr_->forceOverR(rsq, type0, type1);
537  incrementPairStress(force, dr, pStress);
538  }
539 
540  // Short-range Coulomb stress
541  qProduct = (*atomTypesPtr_)[type0].charge();
542  qProduct *= (*atomTypesPtr_)[type1].charge();
543  force = dr;
544  forceOverR = ewaldInteractionPtr_->rSpaceForceOverR(rsq, qProduct);
545  force *= forceOverR;
546  incrementPairStress(force, dr, cStress);
547  }
548  }
549 
550  // Normalize by volume
551  pStress /= boundary().volume();
552  cStress /= boundary().volume();
553  normalizeStress(pStress);
554  normalizeStress(cStress);
555 
556  stress_.set(pStress);
557  rSpaceAccumulatorPtr_->rSpaceStress_.set(cStress);
558  }
559 
560 }
561 #endif
void initialize(int atomIdEnd, double potentialCutoff)
Allocate memory and initialize.
Coulomb potential for an Md simulation.
A Vector is a Cartesian vector.
Definition: Vector.h:75
virtual void loadParameters(Serializable::IArchive &ar)
Load internal state from an archive.
double distanceSq(const Vector &r1, const Vector &r2) const
Return square distance between positions r1 and r2.
Implementation of a pair potential for a charged system.
Vector & force()
Get atomic force Vector by reference.
double volume() const
Return unit cell volume.
void set(const T &value)
Set the value and mark as set.
Definition: Setable.h:107
void loadParamComposite(Serializable::IArchive &ar, ParamComposite &child, bool next=true)
Add and load a required child ParamComposite.
Tensor & zero()
Set all elements of this tensor to zero.
Definition: Tensor.h:441
double rSpaceForceOverR(double rSq, double qProduct) const
Return ratio of scalar pair interaction force to pair separation.
Array container class template.
Definition: AutoCorrArray.h:28
virtual void computeStress()
Compute and store all short-range pair stress contributions.
File containing preprocessor macros for error handling.
double rSpaceCutoffSq() const
Get real space cutoff squared.
virtual void addForces()
Calculate non-bonded pair forces for all atoms in this System.
Classes used by all simpatico molecular simulations.
virtual std::string interactionClassName() const
Return pair interaction class name (e.g., "LJPair").
A Tensor represents a Cartesian tensor.
Definition: Tensor.h:32
void getPair(Atom *&atom1Ptr, Atom *&atom2Ptr) const
Get pointers for current pair of Atoms.
virtual ~MdEwaldPairPotentialImpl()
Destructor.
virtual double forceOverR(double rsq, int iAtomType, int jAtomType) const
Return force / separation for a single pair.
Saving / output archive for binary ostream.
virtual double maxPairCutoff() const
Return maximum cutoff.
virtual void computeEnergy()
Compute and store all short-range pair energies.
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
double rSpaceEnergy(double rSq, double qProduct) const
Returns r-space interaction energy for a single pair of atoms.
Descriptor for a type of Atom.
int typeId() const
Get type index for this Atom.
std::string coulombStyle() const
Return coulomb potential style string.
Definition: System.cpp:1321
Simulation & simulation() const
Get the parent Simulation by reference.
Implementation of r-space and k-space Ewald Coulomb interactions.
A point particle within a Molecule.
Utility classes for scientific computation.
Definition: accumulators.mod:1
virtual void readParameters(std::istream &in)
Read pair potential interaction and pair list blocks.
double rSpaceCutoff() const
Get real space cutoff.
Utility class to store r-space Coulomb energy and stress.
void unset()
Unset the value (mark as unknown).
Definition: Setable.h:116
virtual void save(Serializable::OArchive &ar)
Save internal state to an archive.
Iterator for pairs in a PairList.
Smooth Particle-Mesh Ewald Coulomb potential for MD simulations.
void begin(PairIterator &iterator) const
Initialize a PairIterator.
virtual void unsetEnergy()
Unset both energy accumulators.
PairList pairList_
Verlet neighbor pair list for nonbonded interactions.
An PairPotential for MD simulation.
bool isPairListCurrent()
Return true if PairList is current, false if obsolete.
Saving archive for binary istream.
Single-processor Monte Carlo (MC) and molecular dynamics (MD).
void buildPairList()
Build the internal PairList.
void addParamComposite(ParamComposite &child, bool next=true)
Add a child ParamComposite object to the format array.
Ewald Coulomb potential class for MD simulations.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition: global.h:68
Boundary & boundary() const
Get the Boundary by reference.
bool notEnd() const
Return true if not at end of PairList.
void readParamComposite(std::istream &in, ParamComposite &child, bool next=true)
Add and read a required child ParamComposite.
A System for Molecular Dynamics simulation.
Definition: MdSystem.h:68
const Vector & position() const
Get the position Vector by const reference.
virtual void unsetStress()
Unset both stress accumulators.
double energy()
Return the energy contribution, compute if necessary.
MdCoulombPotential & coulombPotential() const
Return CoulombPotential by reference.
Definition: MdSystem.h:588
virtual void save(Serializable::OArchive &ar)
Save internal state to an archive.