Simpatico  v1.10
mcMd/neighbor/PairList.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 "PairList.h"
9 #include "PairIterator.h"
10 #include <mcMd/chemistry/Atom.h>
11 #include <util/space/Vector.h>
12 #include <util/global.h>
13 
14 namespace McMd
15 {
16 
17  using namespace Util;
18 
19  /*
20  * Default constructor.
21  */
23  :
24  atom1Ptrs_(),
25  atom2Ptrs_(),
26  first_(),
27  oldPositions_(),
28  skin_(-1.0),
29  cutoff_(-1.0),
30  atomCapacity_(0),
31  pairCapacity_(0),
32  nAtom1_(0),
33  nAtom2_(0),
34  nAtom_(0),
35  tList1_(0),
36  maxNAtom_(0),
37  maxNAtom2_(0),
38  buildCounter_(0),
39  isInitialized_(false)
40  { setClassName("PairList"); }
41 
42  /*
43  * Destructor.
44  */
46  {}
47 
48  /*
49  * Read atomCapacity and pairCapacity from file.
50  */
51  void PairList::readParameters(std::istream& in)
52  {
53  read<int>(in, "atomCapacity", atomCapacity_);
54  read<int>(in, "pairCapacity", pairCapacity_);
55  read<double>(in, "skin", skin_);
56  }
57 
58  /*
59  * Load parameters an archive.
60  */
62  {
63  loadParameter<int>(ar, "atomCapacity", atomCapacity_);
64  loadParameter<int>(ar, "pairCapacity", pairCapacity_);
65  loadParameter<double>(ar, "skin", skin_);
66  ar >> cutoff_;
67  ar >> cellList_;
68 
69  allocate();
70  cellList_.clear();
71  }
72 
73  /*
74  * Save parameters an archive.
75  */
77  {
78  ar << atomCapacity_;
79  ar << pairCapacity_;
80  ar << skin_;
81  ar << cutoff_;
82  ar << cellList_;
83  }
84 
85  /*
86  * Allocate CellList and PairList arrays, initialize to empty state.
87  */
88  void PairList::initialize(int atomIdEnd, double potentialCutoff)
89  {
90  // Preconditions
91  if (skin_ <= 0.0) {
92  UTIL_THROW("skin must be set before PairList::initialize");
93  }
94 
95  // PairList cutoff = cutoff for potential + a "skin"
96  cutoff_ = potentialCutoff + skin_;
97 
98  // Set atom capacity for cell list.
99  cellList_.setAtomCapacity(atomIdEnd);
100 
101  allocate();
102  }
103 
104  /*
105  * Allocate CellList and PairList arrays, initialize to empty state.
106  */
107  void PairList::allocate()
108  {
109  // Precondition
110  if (atomCapacity_ <= 0 ) {
111  UTIL_THROW("atomCapacity_ not set in PairList::allocate");
112  }
113  if (pairCapacity_ <= 0 ) {
114  UTIL_THROW("pairCapacity_ not set in PairList::allocate");
115  }
116 
117  // Allocate arrays
118  atom1Ptrs_.allocate(atomCapacity_);
119  atom2Ptrs_.allocate(pairCapacity_);
120  first_.allocate(atomCapacity_ + 1);
121  oldPositions_.allocate(atomCapacity_);
122 
123  // Initialize array elements to null values
124  for (int i=0; i < atomCapacity_; ++i) {
125  atom1Ptrs_[i] = 0;
126  first_[i] = PairList::NullIndex;
127  oldPositions_[i].zero();
128  }
129  first_[atomCapacity_] = PairList::NullIndex;
130  for (int i=0; i < pairCapacity_; ++i) {
131  atom2Ptrs_[i] = 0;
132  }
133 
134  // Clear pair list counters
135  nAtom1_ = 0;
136  nAtom2_ = 0;
137  nAtom_ = 0;
138  tList1_ = atomCapacity_ - 1;
139  first_[0] = 0;
140 
141  isInitialized_ = true;
142  }
143 
144  /*
145  * Setup an empty pair list ready for addition of atoms.
146  */
147  void PairList::setup(const Boundary& boundary)
148  {
149  cellList_.setup(boundary, cutoff_);
150  nAtom1_ = 0;
151  nAtom2_ = 0;
152  nAtom_ = 0;
153  tList1_ = atomCapacity_ - 1;
154  first_[0] = 0;
155  }
156 
157  /*
158  * Clear the CellList and PairList.
159  */
161  {
162  cellList_.clear();
163  nAtom1_ = 0;
164  nAtom2_ = 0;
165  nAtom_ = 0;
166  tList1_ = atomCapacity_ - 1;
167  first_[0] = 0;
168  }
169 
170  /*
171  * Build the PairList, i.e., populate it with atom pairs.
172  */
173  void PairList::build(const Boundary& boundary)
174  {
175  CellList::NeighborArray cellNeighbor;
176  Vector iPos, jPos;
177  Atom *iAtomPtr, *jAtomPtr;
178  double dRSq, cutoffSq;
179  int nCellNeighbor, nCellAtom, totCells;
180  int ic, ip, iAtomId, jp, jAtomId;
181  bool foundNeighbor;
182 
183  // Precondition
184  assert(isInitialized());
185 
186  // Set maximum squared-separation for pairs in Pairlist
187  cutoffSq = cutoff_*cutoff_;
188 
189  // Initialize counters for primary atoms and neighbors
190  nAtom1_ = 0; // Number of primary atoms with neighbors
191  nAtom2_ = 0; // Number of secondary atoms (2nd in pair), or pairs
192  nAtom_ = 0; // Number of atoms, with or without neighbors
193  tList1_ = atomCapacity_ - 1;
194  first_[0] = 0;
195 
196  // Loop over cells containing primary atom. ic = cell index
197  totCells = cellList_.totCells();
198  for (ic = 0; ic < totCells; ++ic) {
199 
200  // Get Array cellNeighbor of Ids of neighbor atoms for cell ic.
201  // Elements 0,..., nCellAtom - 1 contain Ids for atoms in cell ic.
202  // Elements nCellAtom,..., nCellNeighbor-1 are from neighboring cells.
203  cellList_.getCellNeighbors(ic, cellNeighbor, nCellAtom);
204  nCellNeighbor = cellNeighbor.size();
205 
206  // Loop over atoms in cell ic
207  for (ip = 0; ip < nCellAtom; ++ip) {
208  iAtomPtr = cellNeighbor[ip];
209  iPos = iAtomPtr->position();
210  iAtomId = iAtomPtr->id();
211  ++nAtom_;
212  if (nAtom_ > atomCapacity_) {
213  UTIL_THROW("Overflow: nAtom_ > atomCapacity_ in PairList");
214  }
215 
216  // Indicate that no neighbors have been found yet
217  foundNeighbor = false;
218 
219  // Loop over atoms in all neighboring cells, including cell ic.
220  for (jp = 0; jp < nCellNeighbor; ++jp) {
221  jAtomPtr = cellNeighbor[jp];
222  jPos = jAtomPtr->position();
223  jAtomId = jAtomPtr->id();
224 
225  // Avoid double counting: only count pairs with jAtomId > iAtomId
226  if ( jAtomId > iAtomId ) {
227 
228  // Exclude bonded pairs
229  if (!iAtomPtr->mask().isMasked(*jAtomPtr)) {
230 
231  // Calculate distance between atoms i and j
232  dRSq = boundary.distanceSq(iPos, jPos);
233 
234  if (dRSq < cutoffSq) {
235 
236  // Check for overflow of atom2Ptrs_
237  if (nAtom2_ >= pairCapacity_) {
238  UTIL_THROW("Overflow: # pairs > pairCapacity_");
239  }
240 
241  // If first_ neighbor, record iAtomId in atom1Ptrs_
242  if (!foundNeighbor) {
243 
244  assert(nAtom1_ < atomCapacity_);
245  assert(nAtom1_ >= 0);
246  assert(tList1_ >= nAtom1_);
247 
248  atom1Ptrs_[nAtom1_] = iAtomPtr;
249  oldPositions_[nAtom1_] = iPos;
250  foundNeighbor = true;
251  }
252 
253  // Append Id of 2nd atom in pair to atom2Ptrs_[]
254  assert(tList1_ < atomCapacity_);
255  atom2Ptrs_[nAtom2_] = jAtomPtr;
256  ++nAtom2_;
257 
258  }
259  }
260 
261  } // end if jAtomId > iAtomId
262 
263  } // end for jp (j atom)
264 
265  if (foundNeighbor) {
266  // Update counter first_[nAtom1_]
267  ++nAtom1_;
268  first_[nAtom1_] = nAtom2_;
269  } else {
270  // Add atom with no neighbors to top of atom1Ptrs_
271  assert(tList1_ >= nAtom1_);
272  assert(tList1_ < atomCapacity_);
273  assert(tList1_ >= 0);
274  atom1Ptrs_[tList1_] = iAtomPtr;
275  oldPositions_[tList1_] = iPos;
276  --tList1_;
277  }
278 
279  } // end for ip (i atom)
280 
281  } // end for ic (i cell)
282 
283  // Increment buildCounter_= number of times the list has been built.
284  ++buildCounter_;
285 
286  // Increment maximum
287  if (nAtom_ > maxNAtom_) maxNAtom_ = nAtom_;
288  if (nAtom2_ > maxNAtom2_) maxNAtom2_ = nAtom2_;
289 
290  }
291 
292  /*
293  * Initialize a pair iterator.
294  */
295  void PairList::begin(PairIterator& iterator) const
296  {
297  iterator.atom1Ptrs_ = &atom1Ptrs_[0];
298  iterator.atom2Ptrs_ = &atom2Ptrs_[0];
299  iterator.first_ = &first_[0];
300  iterator.nAtom1_ = nAtom1_;
301  iterator.nAtom2_ = nAtom2_;
302  iterator.atom1Id_ = 0;
303  iterator.atom2Id_ = 0;
304  }
305 
306 
307  /*
308  * Return false if any atom has moved a distance greater than skin/2,
309  * or if the PairList has never been built. Return true otherwise.
310  */
311  bool PairList::isCurrent(const Boundary& boundary) const
312  {
313  // Precondition
314  assert(isInitialized());
315 
316  double dRSq, dRSqMax;
317  int ip;
318 
319  // If the list has never been built, it is not current.
320  if (buildCounter_ == 0) return false;
321 
322  dRSqMax = 0.25*skin_*skin_;
323 
324  // Loop over atoms with neighbors (increment from bottom)
325  for (ip = 0; ip < nAtom1_; ++ip) {
326  dRSq = boundary.distanceSq(atom1Ptrs_[ip]->position(),
327  oldPositions_[ip]);
328  if (dRSq > dRSqMax) {
329  return false;
330  }
331  }
332 
333  // Loop over atoms with no neighbors (decrement from top)
334  for (ip = atomCapacity_ - 1; ip > tList1_; --ip) {
335  dRSq = boundary.distanceSq(atom1Ptrs_[ip]->position(),
336  oldPositions_[ip]);
337  if (dRSq > dRSqMax) {
338  return false;
339  }
340  }
341 
342  return true;
343  }
344 
345  /*
346  * Clear all statistics.
347  */
349  {
350  maxNAtom_ = 0;
351  maxNAtom2_ = 0;
352  buildCounter_ = 0;
353  }
354 
355 
356  /*
357  * Return true if valid, or throw Exception.
358  */
359  bool PairList::isValid() const
360  {
361  if (isInitialized()) {
362 
363  // Check for null pointers to allocated arrays
364 
365  if (atomCapacity_ <= 0) UTIL_THROW("atomCapacity_ <= 0");
366  if (pairCapacity_ <= 0) UTIL_THROW("atomCapacity_ <= 0");
367 
368  //if (atom1Ptrs_ == 0) UTIL_THROW("Null atom1Ptrs_");
369  //if (atom2Ptrs_ == 0) UTIL_THROW("Null atom2Ptrs_");
370  //if (first_ == 0) UTIL_THROW("Null first_");
371  //if (oldPositions_ == 0) UTIL_THROW("Null oldPositions_");
372 
373  if (nAtom_ > 0) {
374  if (nAtom_ != nAtom1_ + atomCapacity_ - 1 - tList1_) {
375  UTIL_THROW("Inconsistent innAtom_, nAtom1_, tList1");
376  }
377  cellList_.isValid(nAtom_);
378  if (nAtom_ != cellList_.nAtom()) {
379  UTIL_THROW("Inconsistent values of nAtom_");
380  }
381  } else
382  if (nAtom_ == 0) {
383  if (nAtom1_ != 0) UTIL_THROW("nAtom_ ==0 and nAtom1 != 0");
384  if (nAtom2_ != 0) UTIL_THROW("nAtom_ ==0 and nAtom2 != 0");
385  cellList_.isValid();
386  } else {
387  UTIL_THROW("nAtom_ < 0");
388  }
389  }
390 
391  return true;
392  }
393 
394 }
void initialize(int atomIdEnd, double potentialCutoff)
Allocate memory and initialize.
A Vector is a Cartesian vector.
Definition: Vector.h:75
bool isValid(int nAtom=-1) const
Return true if valid, or throw Exception.
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.
void build(const Boundary &boundary)
Use a complete CellList to build a new PairList.
bool isValid() const
Return true if valid, or throw Exception.
An orthorhombic periodic unit cell.
PairList()
Default constructor.
Mask & mask()
Get the associated Mask by reference.
File containing preprocessor macros for error handling.
void clear()
Sets all Cell objects to empty state (no Atoms).
bool isInitialized() const
Has the initialize function been called?
Saving / output archive for binary ostream.
bool isMasked(const Atom &atom) const
True if the atom is in the masked set for the target Atom.
virtual ~PairList()
Destructor.
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
void getCellNeighbors(int ic, NeighborArray &neighbors, int &nInCell) const
Fill an array with pointers to atoms in a cell and neighboring cells.
void setup(const Boundary &boundary)
Setup an empty grid of cells for the internal cell list.
int nAtom() const
Get total number of atoms in this CellList.
A point particle within a Molecule.
Utility classes for scientific computation.
Definition: accumulators.mod:1
void setup(const Boundary &boundary, double cutoff)
Setup grid of empty cells.
int id() const
Get global index for this Atom within the Simulation.
int totCells() const
Get total number of cells in this CellList.
Iterator for pairs in a PairList.
void begin(PairIterator &iterator) const
Initialize a PairIterator.
void clearStatistics()
Clear statistical accumulators (maxNAtom, maxNPair, buildCounter).
Saving archive for binary istream.
Single-processor Monte Carlo (MC) and molecular dynamics (MD).
void setClassName(const char *className)
Set class name string.
bool isCurrent(const Boundary &boundary) const
Returns true if PairList is current, false otherwise.
void setAtomCapacity(int atomCapacity)
Set atom capacity.
void clear()
Clear the PairList and CellList.
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 size() const
Return logical size of this array (i.e., number of elements).
Definition: FSArray.h:207
void readParameters(std::istream &in)
Read atomCapacity and pairCapacity (maximum numbers of atoms and pairs).
virtual void save(Serializable::OArchive &ar)
Save internal state to an archive.