Simpatico  v1.10
PairPotential.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 "PairPotential.h"
9 #include <ddMd/simulation/Simulation.h>
10 #include <ddMd/storage/AtomStorage.h>
11 #include <ddMd/storage/AtomIterator.h>
12 #include <ddMd/storage/GhostIterator.h>
13 #include <ddMd/neighbor/PairIterator.h>
14 #include <ddMd/neighbor/PairList.h>
15 #include <ddMd/neighbor/CellList.h>
16 #include <ddMd/communicate/Domain.h>
17 #include <util/mpi/MpiLoader.h>
18 #include <util/space/Vector.h>
19 #include <util/global.h>
20 
21 namespace DdMd
22 {
23  using namespace Util;
24 
25  /*
26  * Default constructor (for unit testing).
27  */
29  : skin_(0.0),
30  cutoff_(0.0),
31  pairCapacity_(0),
32  domainPtr_(0),
33  boundaryPtr_(0),
34  storagePtr_(0),
35  methodId_(0),
36  nPair_(0),
37  pairEnergies_()
38  { setClassName("PairPotential"); }
39 
40  /*
41  * Constructor.
42  */
44  : skin_(0.0),
45  cutoff_(0.0),
46  pairCapacity_(0),
47  domainPtr_(&simulation.domain()),
48  boundaryPtr_(&simulation.boundary()),
49  storagePtr_(&simulation.atomStorage()),
50  methodId_(0),
51  nPair_(0),
52  pairEnergies_()
53  { setClassName("PairPotential"); }
54 
55  /*
56  * Associate with related objects. (for unit testing).
57  */
60  {
61  domainPtr_ = &domain;
62  boundaryPtr_ = &boundary;
63  storagePtr_ = &storage;
64  }
65 
66  /*
67  * Destructor.
68  */
70  {}
71 
72  /*
73  * Allocate memory for the cell list.
74  */
75  void PairPotential::initialize(const Boundary& maxBoundary, double skin,
76  int pairCapacity)
77  {
78  skin_ = skin;
79  pairCapacity_ = pairCapacity;
80  maxBoundary_ = maxBoundary;
82 
83  allocate();
84  }
85 
86  /*
87  * Read parameters for PairList and allocate memory.
88  */
89  void PairPotential::readParameters(std::istream& in)
90  {
91  read<double>(in, "skin", skin_);
92  nCellCut_ = 1; // Default value for optional parameter
93  readOptional<int>(in, "nCellCut", nCellCut_);
94  read<int>(in, "pairCapacity", pairCapacity_);
95  read<Boundary>(in, "maxBoundary", maxBoundary_);
97  allocate();
98  }
99 
100  /*
101  * Read parameters for PairList and allocate memory.
102  */
104  {
105 
106  loadParameter<double>(ar, "skin", skin_);
107  loadParameter<int>(ar, "nCellCut", nCellCut_, false);
108  loadParameter<int>(ar, "pairCapacity", pairCapacity_);
109  loadParameter<Boundary>(ar, "maxBoundary", maxBoundary_);
110 
111  MpiLoader<Serializable::IArchive> loader(*this, ar);
112  loader.load(cutoff_);
113  loader.load(methodId_);
114  allocate();
115  }
116 
117  /*
118  * Save parameters to output/saving Archive.
119  */
121  {
122  ar << skin_;
124  ar << pairCapacity_;
125  ar << maxBoundary_;
126  ar << cutoff_;
127  ar << methodId_;
128  }
129 
130  /*
131  * Allocate memory for the cell list and pair list.
132  *
133  * On entry, cutoff_, pairCapacity_, and maxBoundary_ must be defined.
134  */
135  void PairPotential::allocate()
136  {
137  // Allocate PairList
138  int localCapacity = storage().atomCapacity();
139  pairList_.allocate(localCapacity, pairCapacity_, cutoff_);
140 
141  // Calculate cell list cutoff lengths for all directions
142  Vector cutoffs;
143  Vector lower;
144  Vector upper;
145  for (int i = 0; i < Dimension; ++i) {
146  lower[i] = domain().domainBound(i, 0);
147  upper[i] = domain().domainBound(i, 1);
148  cutoffs[i] = cutoff_/maxBoundary_.length(i);
149  }
150 
151  // Allocate CellList
152  int totalCapacity = localCapacity + storage().ghostCapacity();
153  cellList_.allocate(totalCapacity, lower, upper, cutoffs, nCellCut_);
154  }
155 
156  /*
157  * Build the cell list.
158  */
160  {
161  if (storage().isCartesian()) {
162  UTIL_THROW("Coordinates are Cartesian entering buildCellList");
163  }
164 
165  // Set cutoff and domain bounds.
166  Vector cutoffs;
167  Vector lower;
168  Vector upper;
169  for (int i = 0; i < Dimension; ++i) {
170  cutoffs[i] = cutoff_/boundaryPtr_->length(i);
171  lower[i] = domain().domainBound(i, 0);
172  upper[i] = domain().domainBound(i, 1);
173  }
174  cellList_.makeGrid(lower, upper, cutoffs, nCellCut_);
175  cellList_.clear();
176 
177  // Add all atoms to the cell list.
178  AtomIterator atomIter;
179  storage().begin(atomIter);
180  for ( ; atomIter.notEnd(); ++atomIter) {
181  cellList_.placeAtom(*atomIter);
182  }
183 
184  // Add all ghosts to the cell list.
185  GhostIterator ghostIter;
186  storage().begin(ghostIter);
187  for ( ; ghostIter.notEnd(); ++ghostIter) {
188  cellList_.placeAtom(*ghostIter);
189  }
190 
191  // Finalize cell list
192  cellList_.build();
193 
194  // Postconditions
195  assert(cellList_.isValid());
196  assert(cellList_.nAtom() + cellList_.nReject()
197  == storage().nAtom() + storage().nGhost());
198  if (storage().isCartesian()) {
199  UTIL_THROW("Coordinates are Cartesian exiting buildCellList");
200  }
201  }
202 
203  /*
204  * Build the pair list.
205  */
207  {
208  if (!storage().isCartesian()) {
209  UTIL_THROW("Coordinates not Cartesian entering buildPairList");
210  }
212  }
213 
214  /*
215  * Return value of pair energies.
216  */
218  { return pairEnergies_.value(); }
219 
220  /*
221  * Set a value for pair energies.
222  */
224  { pairEnergies_.set(pairEnergies); }
225 
226  /*
227  * Mark pair energies as unknown.
228  */
230  { pairEnergies_.unset(); }
231 
232  /*
233  * Compute total pair nPair on all processors.
234  */
235  #ifdef UTIL_MPI
236  void PairPotential::computeNPair(MPI::Intracomm& communicator)
237  #else
239  #endif
240  {
241  double cut = maxPairCutoff();
242  double cutSq = cut*cut;
243  int localNPair = 0;
244  if (methodId() == 0) {
245  localNPair = nPairList(cutSq);
246  } else
247  if (methodId() == 1) {
248  localNPair = nPairCell(cutSq);
249  } else {
250  localNPair = nPairNSq(cutSq);
251  }
252  nPair_ = localNPair;
253  #ifdef UTIL_MPI
254  communicator.Reduce(&localNPair, &nPair_, 1, MPI::INT, MPI::SUM, 0);
255  #else
256  nPair_ = localNPair;
257  #endif
258  }
259 
260  /*
261  * Return twice the number of pairs within the specified cutoff.
262  *
263  * This method should only be called on the rank 0 processor. The
264  * return value is computed by a previous call to computeNPair.
265  */
267  { return nPair_; }
268 
269  /*
270  * Count number pairs using pair list (private).
271  */
272  int PairPotential::nPairList(double cutoffSq)
273  {
274  Vector f;
275  double rsq;
276  PairIterator iter;
277  Atom* atom0Ptr;
278  Atom* atom1Ptr;
279  int count = 0; // atom counter
280  if (reverseUpdateFlag()) {
281  for (pairList_.begin(iter); iter.notEnd(); ++iter) {
282  iter.getPair(atom0Ptr, atom1Ptr);
283  assert(!atom0Ptr->isGhost());
284  f.subtract(atom0Ptr->position(), atom1Ptr->position());
285  rsq = f.square();
286  if (rsq < cutoffSq) {
287  count += 2;
288  }
289  }
290  } else {
291  for (pairList_.begin(iter); iter.notEnd(); ++iter) {
292  iter.getPair(atom0Ptr, atom1Ptr);
293  assert(!atom0Ptr->isGhost());
294  f.subtract(atom0Ptr->position(), atom1Ptr->position());
295  rsq = f.square();
296  if (rsq < cutoffSq) {
297  if (!atom1Ptr->isGhost()) {
298  count += 2;
299  } else {
300  count += 1;
301  }
302  }
303  }
304  }
305  return count;
306  }
307 
308  /*
309  * Count number pairs using cell list (private).
310  */
311  int PairPotential::nPairCell(double cutoffSq)
312  {
313  // Find all neighbors (cell list)
314  Cell::NeighborArray neighbors;
315  Vector f;
316  double rsq;
317  Atom* atomPtr0;
318  Atom* atomPtr1;
319  const Cell* cellPtr;
320  int na, nn, i, j;
321  int count = 0;
322 
323  // Iterate over linked list of local cells.
324  cellPtr = cellList_.begin();
325  while (cellPtr) {
326  cellPtr->getNeighbors(neighbors, reverseUpdateFlag());
327  na = cellPtr->nAtom();
328  nn = neighbors.size();
329  for (i = 0; i < na; ++i) {
330  atomPtr0 = neighbors[i]->ptr();
331 
332  // Loop over atoms in this cell
333  for (j = 0; j < na; ++j) {
334  atomPtr1 = neighbors[j]->ptr();
335  if (atomPtr1 > atomPtr0) {
336  f.subtract(atomPtr0->position(), atomPtr1->position());
337  rsq = f.square();
338  if (rsq < cutoffSq) {
339  count += 2;
340  }
341  }
342  }
343 
344  // Loop over atoms in neighboring cells.
345  if (reverseUpdateFlag()) {
346  for (j = na; j < nn; ++j) {
347  atomPtr1 = neighbors[j]->ptr();
348  f.subtract(atomPtr0->position(), atomPtr1->position());
349  rsq = f.square();
350  if (rsq < cutoffSq) {
351  count += 2;
352  }
353  }
354  } else {
355  for (j = na; j < nn; ++j) {
356  atomPtr1 = neighbors[j]->ptr();
357  f.subtract(atomPtr0->position(), atomPtr1->position());
358  rsq = f.square();
359  if (rsq < cutoffSq) {
360  if (!atomPtr1->isGhost()) {
361  count += 2;
362  } else {
363  count += 1;
364  }
365  }
366  }
367  }
368 
369  }
370  cellPtr = cellPtr->nextCellPtr();
371  } // while (cellPtr)
372  return count;
373  }
374 
375  /*
376  * Count pairs using n-squared loop. (private)
377  */
378  int PairPotential::nPairNSq(double cutoffSq)
379  {
380  Vector f;
381  double rsq;
382  AtomIterator atomIter0, atomIter1;
383  GhostIterator ghostIter;
384  int id0, id1;
385  int count = 0;
386 
387  // Iterate over local atom 0
388  storage().begin(atomIter0);
389  for ( ; atomIter0.notEnd(); ++atomIter0) {
390  id0 = atomIter0->id();
391 
392  // Iterate over local atom 1
393  storage().begin(atomIter1);
394  for ( ; atomIter1.notEnd(); ++atomIter1) {
395  id1 = atomIter1->id();
396  if (id0 < id1) {
397  if (!atomIter0->mask().isMasked(id1)) {
398  f.subtract(atomIter0->position(), atomIter1->position());
399  rsq = f.square();
400  if (rsq < cutoffSq) {
401  count += 2;
402  }
403  }
404  }
405  }
406 
407  // Iterate over ghost atoms
408  storage().begin(ghostIter);
409  if (reverseUpdateFlag()) {
410  for ( ; ghostIter.notEnd(); ++ghostIter) {
411  id1 = ghostIter->id();
412  if (id0 < id1) {
413  if (!atomIter0->mask().isMasked(id1)) {
414  f.subtract(atomIter0->position(), ghostIter->position());
415  rsq = f.square();
416  if (rsq < cutoffSq) {
417  count += 2;
418  }
419  }
420  }
421  }
422  } else {
423  for ( ; ghostIter.notEnd(); ++ghostIter) {
424  id1 = ghostIter->id();
425  if (!atomIter0->mask().isMasked(id1)) {
426  f.subtract(atomIter0->position(), ghostIter->position());
427  rsq = f.square();
428  if (rsq < cutoffSq) {
429  count += 1;
430  }
431  }
432  }
433  }
434 
435  }
436  return count;
437  }
438 
439 }
const Cell * begin() const
Return pointer to first local cell in linked list.
void makeGrid(const Vector &lower, const Vector &upper, const Vector &cutoffs, int nCellCut=1)
Make the cell grid (using generalized coordinates).
Boundary & boundary()
Get the PairList by const reference.
const int Dimension
Dimensionality of space.
Definition: Dimension.h:19
A Vector is a Cartesian vector.
Definition: Vector.h:75
void computeNPair(MPI::Intracomm &communicator)
Compute twice the number of pairs within the force cutoff.
void placeAtom(Atom &atom)
Determine the appropriate cell for an Atom, based on its position.
int nCellCut_
Approximate number of cells per cutoff distance in each direction.
Domain & domain()
Get the PairList by const reference.
An orthorhombic periodic unit cell.
double skin_
Difference between pairlist cutoff and pair potential cutoff.
Vector & position()
Get position Vector by reference.
void buildPairList()
Build the Verlet Pair list.
double cutoff_
Minimum cell size = pair potential cutoff + skin.
void getPair(Atom *&atom1Ptr, Atom *&atom2Ptr) const
Get pointers for current pair of Atoms.
int nAtom() const
Get total number of atoms (local and ghost) in this CellList.
File containing preprocessor macros for error handling.
void begin(PairIterator &iterator) const
Initialize a PairIterator.
A point particle in an MD simulation.
Parallel domain decomposition (DD) MD simulation.
bool isValid() const
Return true if valid, or throw Exception.
Main object for a domain-decomposition MD simulation.
void buildCellList()
Build a cell list.
int pairCapacity_
Maximum number of nonbonded pairs in pair list.
int nAtom() const
Return number of local atoms on this procesor (excluding ghosts)
virtual ~PairPotential()
Destructor.
void setPairEnergies(DMatrix< double > pairEnergies)
Set values for pair energies.
Saving / output archive for binary ostream.
bool notEnd() const
Return true if not at end of PairList.
int methodId() const
Return integer id for algorithm (0=PAIR, 1=CELL, 2=NSQ)
A fixed capacity (static) contiguous array with a variable logical size.
Definition: FSArray.h:37
CellList cellList_
CellList to construct PairList or calculate nonbonded pair forces.
void unsetPairEnergies()
Mark pair energy as unknown (nullify).
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
bool isGhost() const
Is this atom a ghost?
void initialize(const Boundary &maxBoundary, double skin, int pairCapacity)
Set parameters and allocate memory.
int nGhost() const
Return current number of ghost atoms on this processor.
int nAtom() const
Number of atoms in cell.
bool notEnd() const
Is the current pointer not at the end of the PArray?
Utility classes for scientific computation.
Definition: accumulators.mod:1
virtual void save(Serializable::OArchive &ar)
Save internal state to an output archive.
void clear()
Reset the cell list to its empty state (no Atoms).
void build(CellList &cellList, bool reverseUpdateFlag=false)
Use a CellList to build a new PairList.
double length(int i) const
Get length in Cartesian direction i.
A container for all the atoms and ghost atoms on this processor.
void allocate(int atomCapacity, int pairCapacity, double cutoff)
Allocate memory and set cutoff.
bool reverseUpdateFlag() const
Get flag to identify if reverse communication is enabled.
Definition: Potential.h:228
int atomCapacity() const
Return capacity for local atoms on this processor (excluding ghosts).
PairList pairList_
Verlet pair list, to calculate nonbonded pair forces.
Decomposition of the system into domains associated with processors.
Definition: Domain.h:31
DMatrix< double > pairEnergies() const
Return total pair energies, from all processors.
Saving archive for binary istream.
Boundary maxBoundary_
Boundary used to allocate space for the cell list.
void getNeighbors(NeighborArray &neighbors, bool reverseUpdateFlag=false) const
Fill an array with pointers to atoms in a cell and neighboring cells.
AtomStorage & storage()
Get the AtomStorage by reference.
double domainBound(int i, int j) const
Get one boundary of the domain owned by this processor.
Definition: Domain.cpp:190
int nPair() const
Return twice the number of pairs within the specified force cutoff.
Provides methods for MPI-aware loading of data from input archive.
Definition: MpiLoader.h:43
int ghostCapacity() const
Return capacity for ghost atoms on this processor.
bool isCartesian() const
Are atom coordinates Cartesian (true) or generalized (false)?
Iterator for all ghost atoms owned by an AtomStorage.
Definition: GhostIterator.h:24
int nReject() const
Get number of atoms that were rejected (not placed in cells)
Vector & subtract(const Vector &v1, const Vector &v2)
Subtract vector v2 from v1.
Definition: Vector.h:672
void setClassName(const char *className)
Set class name string.
virtual void loadParameters(Serializable::IArchive &ar)
Load parameters for PairList from archive, and allocate memory.
void readParameters(std::istream &in)
Initialize, by reading parameters and allocating memory for PairList.
double skin() const
Get value of the pair list skin.
void allocate(int atomCapacity, const Vector &lower, const Vector &upper, const Vector &cutoffs, int nCellCut=1)
Allocate memory for this CellList (generalized coordinates).
Iterator for pairs in a PairList.
Iterator for all atoms owned by an AtomStorage.
Definition: AtomIterator.h:24
static void saveOptional(Serializable::OArchive &ar, Type &value, bool isActive)
Save an optional parameter value to an output archive.
Definition: Parameter.h:224
void build()
Build the cell list.
int size() const
Return logical size of this array (i.e., number of elements).
Definition: FSArray.h:207
double square() const
Return square magnitude of this vector.
Definition: Vector.h:616
void begin(AtomIterator &iterator)
Set iterator to beginning of the set of atoms.
PairPotential()
Default constructor.
const Cell * nextCellPtr() const
Return a pointer to neighbor cell i.
A single Cell in a CellList.
virtual double maxPairCutoff() const =0
Return maximum cutoff.
void associate(Domain &domain, Boundary &boundary, AtomStorage &storage)
Associate with related objects.