Simpatico  v1.10
ddMd/potentials/angle/AnglePotentialImpl.h
1 #ifndef DDMD_ANGLE_POTENTIAL_IMPL_H
2 #define DDMD_ANGLE_POTENTIAL_IMPL_H
3 
4 /*
5 * Simpatico - Simulation Package for Polymeric and Molecular Liquids
6 *
7 * Copyright 2010 - 2017, The Regents of the University of Minnesota
8 * Distributed under the terms of the GNU General Public License.
9 */
10 
11 #include "AnglePotential.h" // base class
12 
13 namespace Util
14 {
15  class Vector;
16  class Tensor;
17 }
18 
19 namespace DdMd
20 {
21 
22  using namespace Util;
23 
24  class Simulation;
25  template <int N> class GroupStorage;
26 
32  template <class Interaction>
34  {
35 
36  public:
37 
41  AnglePotentialImpl(Simulation& simulation);
42 
47 
51  virtual ~AnglePotentialImpl();
52 
56  virtual void setNAngleType(int nAtomType);
57 
65  virtual void readParameters(std::istream& in);
66 
74  virtual void loadParameters(Serializable::IArchive &ar);
75 
81  virtual void save(Serializable::OArchive &ar);
82 
84 
85 
92  double angleEnergy(double cosTheta, int type) const;
93 
104  void angleForce(const Vector& R1, const Vector& R2,
105  Vector& F1, Vector& F2, int type) const;
106 
114  void set(std::string name, int type, double value)
115  { interactionPtr_->set(name, type, value); }
116 
123  double get(std::string name, int type) const
124  { return interactionPtr_->get(name, type); }
125 
129  virtual std::string interactionClassName() const;
130 
134  const Interaction& interaction() const;
135 
139  Interaction& interaction();
140 
142 
144 
150  virtual void computeForces();
151 
157  #ifdef UTIL_MPI
158  virtual void computeEnergy(MPI::Intracomm& communicator);
159  #else
160  virtual void computeEnergy();
161  #endif
162 
168  #ifdef UTIL_MPI
169  virtual void computeStress(MPI::Intracomm& communicator);
170  #else
171  virtual void computeStress();
172  #endif
173 
175 
176  private:
177 
181  Interaction* interactionPtr_;
182 
186  bool isInitialized_;
187 
188  };
189 
190 }
191 
192 #include "AnglePotential.h"
193 #include <ddMd/simulation/Simulation.h>
194 #include <ddMd/storage/GroupStorage.h>
195 #include <ddMd/storage/GroupIterator.h>
196 
197 #include <simp/boundary/Boundary.h>
198 #include <util/space/Dimension.h>
199 #include <util/space/Vector.h>
200 #include <util/space/Tensor.h>
201 #include <util/global.h>
202 
203 #include <fstream>
204 
205 namespace DdMd
206 {
207 
208  using namespace Util;
209  using namespace Simp;
210 
211  /*
212  * Constructor.
213  */
214  template <class Interaction>
216  : AnglePotential(simulation),
217  interactionPtr_(0),
218  isInitialized_(false)
219  {
220  interactionPtr_ = new Interaction();
221  setNAngleType(simulation.nAngleType());
222  }
223 
224  /*
225  * Default constructor.
226  */
227  template <class Interaction>
229  : AnglePotential(),
230  interactionPtr_(0),
231  isInitialized_(false)
232  { interactionPtr_ = new Interaction(); }
233 
234  /*
235  * Destructor.
236  */
237  template <class Interaction>
239  {
240  if (interactionPtr_) {
241  delete interactionPtr_;
242  }
243  }
244 
245  /*
246  * Set the maximum number of atom types.
247  */
248  template <class Interaction>
250  { interaction().setNAngleType(nAngleType); }
251 
252  /*
253  * Read angle interaction parameters.
254  */
255  template <class Interaction>
257  {
258  UTIL_CHECK(!isInitialized_);
259  bool nextIndent = false;
260  addParamComposite(interaction(), nextIndent);
261  interaction().readParameters(in);
262  isInitialized_ = true;
263  }
264 
265  /*
266  * Load internal state from an archive.
267  */
268  template <class Interaction>
269  void
271  {
272  UTIL_CHECK(!isInitialized_);
273  bool nextIndent = false;
274  addParamComposite(interaction(), nextIndent);
275  interaction().loadParameters(ar);
276  isInitialized_ = true;
277  }
278 
279  /*
280  * Save internal state to an archive.
281  */
282  template <class Interaction>
284  { interaction().save(ar); }
285 
286  /*
287  * Return energy for a single angle.
288  */
289  template <class Interaction>
290  double
291  AnglePotentialImpl<Interaction>::angleEnergy(double cosTheta, int angleTypeId)
292  const
293  { return interaction().energy(cosTheta, angleTypeId); }
294 
295  /*
296  * Return forces for a single angle.
297  */
298  template <class Interaction> void
300  const Vector& R2,
301  Vector& F1, Vector& F2,
302  int typeId) const
303  { interaction().force(R1, R2, F1, F2, typeId); }
304 
305  /*
306  * Return angle potential interaction class name.
307  */
308  template <class Interaction>
310  { return interaction().className(); }
311 
315  template <class Interaction>
317  { return *interactionPtr_; }
318 
322  template <class Interaction>
323  inline const Interaction& AnglePotentialImpl<Interaction>::interaction() const
324  { return *interactionPtr_; }
325 
326  /*
327  * Increment atomic forces, without calculating energy.
328  */
329  template <class Interaction>
331  {
332  Vector dr1; // R[1] - R[0]
333  Vector dr2; // R[2] - R[1]
334  Vector f1; // d(energy)/d(dr1)
335  Vector f2; // d(energy)/d(dr2)
336  GroupIterator<3> iter;
337  Atom* atom0Ptr;
338  Atom* atom1Ptr;
339  Atom* atom2Ptr;
340  int type;
341 
342  storage().begin(iter);
343  for ( ; iter.notEnd(); ++iter) {
344  type = iter->typeId();
345  atom0Ptr = iter->atomPtr(0);
346  atom1Ptr = iter->atomPtr(1);
347  atom2Ptr = iter->atomPtr(2);
348  // Calculate minimimum image separations
349  boundary().distanceSq(atom1Ptr->position(),
350  atom0Ptr->position(), dr1);
351  boundary().distanceSq(atom2Ptr->position(),
352  atom1Ptr->position(), dr2);
353  interaction().force(dr1, dr2, f1, f2, type);
354  if (!atom0Ptr->isGhost()) {
355  atom0Ptr->force() += f1;
356  }
357  if (!atom1Ptr->isGhost()) {
358  atom1Ptr->force() -= f1;
359  atom1Ptr->force() += f2;
360  }
361  if (!atom2Ptr->isGhost()) {
362  atom2Ptr->force() -= f2;
363  }
364  }
365  }
366 
367  /*
368  * Compute total angle energy on all processors.
369  */
370  template <class Interaction>
371  #ifdef UTIL_MPI
372  void
374  #else
376  #endif
377  {
378 
379  // Do nothing and return if energy is already set.
380  if (isEnergySet()) return;
381 
382  Vector dr1; // R[1] - R[0]
383  Vector dr2; // R[2] - R[1]
384  double rsq1, rsq2, cosTheta;
385  double angleEnergy;
386  double localEnergy = 0.0;
387  double fraction;
388  double third = 1.0/3.0;
389  GroupIterator<3> iter;
390  Atom* atom0Ptr;
391  Atom* atom1Ptr;
392  Atom* atom2Ptr;
393  int type, isLocal0, isLocal1, isLocal2;
394 
395  storage().begin(iter);
396  for ( ; iter.notEnd(); ++iter) {
397  type = iter->typeId();
398  atom0Ptr = iter->atomPtr(0);
399  atom1Ptr = iter->atomPtr(1);
400  atom2Ptr = iter->atomPtr(2);
401  isLocal0 = !(atom0Ptr->isGhost());
402  isLocal1 = !(atom1Ptr->isGhost());
403  isLocal2 = !(atom2Ptr->isGhost());
404  // Calculate minimimum image separations
405  rsq1 = boundary().distanceSq(atom1Ptr->position(),
406  atom0Ptr->position(), dr1);
407  rsq2 = boundary().distanceSq(atom2Ptr->position(),
408  atom1Ptr->position(), dr2);
409  cosTheta = dr1.dot(dr2) / sqrt(rsq1 * rsq2);
410  angleEnergy = interaction().energy(cosTheta, type);
411  fraction = (isLocal0 + isLocal1 + isLocal2)*third;
412  localEnergy += fraction*angleEnergy;
413  }
414 
415  // Add localEnergy from all nodes, set sum on master.
416  reduceEnergy(localEnergy, communicator);
417  }
418 
419  /*
420  * Compute total pair stress (Call on all processors).
421  */
422  template <class Interaction>
423  #ifdef UTIL_MPI
424  void AnglePotentialImpl<Interaction>::computeStress(MPI::Intracomm& communicator)
425  #else
427  #endif
428  {
429  // Do nothing and return if stress is already set.
430  if (isStressSet()) return;
431 
432  Tensor localStress;
433  Vector dr1, dr2;
434  Vector f1, f2;
435  double factor;
436  double prefactor = -1.0/3.0;
437  GroupIterator<3> iter;
438  Atom* atom0Ptr;
439  Atom* atom1Ptr;
440  Atom* atom2Ptr;
441  int type;
442  int isLocal0, isLocal1, isLocal2;
443 
444  // Iterate over angle groups
445  localStress.zero();
446  storage().begin(iter);
447  for ( ; iter.notEnd(); ++iter) {
448  atom0Ptr = iter->atomPtr(0);
449  atom1Ptr = iter->atomPtr(1);
450  atom2Ptr = iter->atomPtr(2);
451  type = iter->typeId();
452  boundary().distanceSq(atom1Ptr->position(),
453  atom0Ptr->position(), dr1);
454  boundary().distanceSq(atom2Ptr->position(),
455  atom1Ptr->position(), dr2);
456 
457  // Calculate derivatives f1, f2 of energy with respect to dr1, dr2
458  interaction().force(dr1, dr2, f1, f2, type);
459 
460  isLocal0 = !(atom0Ptr->isGhost());
461  isLocal1 = !(atom1Ptr->isGhost());
462  isLocal2 = !(atom2Ptr->isGhost());
463  factor = prefactor*(isLocal0 + isLocal1 + isLocal2);
464 
465  // Increment localStress tensor
466  dr1 *= factor;
467  dr2 *= factor;
468  incrementPairStress(f1, dr1, localStress);
469  incrementPairStress(f2, dr2, localStress);
470  }
471 
472  // Normalize by volume
473  localStress /= boundary().volume();
474 
475  // Add localEnergy from all nodes, set sum on master.
476  reduceStress(localStress, communicator);
477  }
478 
479 }
480 #endif
virtual void readParameters(std::istream &in)
Read potential energy parameters.
Implementation template for a AnglePotential.
A Vector is a Cartesian vector.
Definition: Vector.h:75
Abstract base class for computation of angle force and energies.
virtual void computeEnergy(MPI::Intracomm &communicator)
Compute the total angle energy for all processors.
double distanceSq(const Vector &r1, const Vector &r2) const
Return square distance between positions r1 and r2.
bool isStressSet() const
Is the stress set (known)?
Definition: Potential.cpp:94
void reduceStress(Tensor &localStress, MPI::Intracomm &communicator)
Add local stresses from all processors, set total on master.
Definition: Potential.cpp:142
double volume() const
Return unit cell volume.
double dot(const Vector &v) const
Return dot product of this vector and vector v.
Definition: Vector.h:632
Vector & position()
Get position Vector by reference.
GroupStorage< 3 > & storage() const
Return bond storage by reference.
Tensor & zero()
Set all elements of this tensor to zero.
Definition: Tensor.h:441
File containing preprocessor macros for error handling.
A point particle in an MD simulation.
Parallel domain decomposition (DD) MD simulation.
Classes used by all simpatico molecular simulations.
virtual void save(Serializable::OArchive &ar)
Save internal state to an archive.
Main object for a domain-decomposition MD simulation.
A Tensor represents a Cartesian tensor.
Definition: Tensor.h:32
double angleEnergy(double cosTheta, int type) const
Returns potential energy for one angle.
virtual void computeForces()
Compute angle forces for atoms.
Saving / output archive for binary ostream.
bool isGhost() const
Is this atom a ghost?
Iterator for all Group < N > objects owned by a GroupStorage< N >.
Definition: GroupIterator.h:25
const Interaction & interaction() const
Return angle interaction by const reference.
bool notEnd() const
Is the current pointer not at the end of the PArray?
Utility classes for scientific computation.
Definition: accumulators.mod:1
void begin(GroupIterator< N > &iterator)
Set iterator to beginning of the set of groups.
virtual void setNAngleType(int nAtomType)
Set the maximum number of atom types.
void incrementPairStress(const Vector &f, const Vector &dr, Tensor &stress) const
Add a pair contribution to the stress tensor.
Definition: Potential.h:235
Boundary & boundary() const
Return boundary by reference.
virtual std::string interactionClassName() const
Return pair interaction class name (e.g., "CosineAngle").
Saving archive for binary istream.
Vector & force()
Get force Vector by reference.
void addParamComposite(ParamComposite &child, bool next=true)
Add a child ParamComposite object to the format array.
void reduceEnergy(double localEnergy, MPI::Intracomm &communicator)
Add local energies from all processors, set energy on master.
Definition: Potential.cpp:120
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition: global.h:68
virtual void computeStress(MPI::Intracomm &communicator)
Compute the covalent bond stress.
int nAngleType()
Get maximum number of angle types.
void angleForce(const Vector &R1, const Vector &R2, Vector &F1, Vector &F2, int type) const
Returns forces along two bonds at the angle, for use in MD and stress calculation.
bool isEnergySet() const
Is the energy set (known)?
Definition: Potential.cpp:57
virtual void loadParameters(Serializable::IArchive &ar)
Load internal state from an archive.