Path Integral Quantum Monte Carlo
lookuptable.cpp
Go to the documentation of this file.
1 
8 #include "lookuptable.h"
9 #include "communicator.h"
10 #include "path.h"
11 
12 // ---------------------------------------------------------------------------
13 // ---------------------------------------------------------------------------
14 // LOOKUP TABLE CLASS --------------------------------------------------------
15 // ---------------------------------------------------------------------------
16 // ---------------------------------------------------------------------------
17 
18 /**************************************************************************/
26 LookupTable::LookupTable(const Container *_boxPtr, const int _numLookupTimeSlices,
27  const int _numParticles) :
28  boxPtr(_boxPtr),
29  numLookupTimeSlices(_numLookupTimeSlices)
30 {
31  /* Setup the nearest neighbor grid list */
32  setupNNGrid();
33 
34  /* We begin with the assumption of evenly distributed particles, therefore
35  * there could be numLabels in each cell, allowing for some breathing room */
36  for (int i = 0; i < NDIM; i++)
37  hashSize[i] = numNNGrid[i];
38  hashSize[NDIM] = numLookupTimeSlices;
39  hashSize[NDIM+1] = static_cast<int>(_numParticles/totNumGridBoxes) + 5;
40 
41  /* Resize and initialize the main hash array */
42  hash.resize(hashSize);
43  hash = XXX;
44 
45  /* Resize and initialize the grid and bead label and list arrays */
46  resizeList(_numParticles);
47  grid = XXX;
48  beadLabel= XXX;
49  beadList = XXX;
50  fullBeadList = XXX;
51  beadSep = 0.0;
52 
53  /* Initialize the cutoff^2 */
54  rc2 = constants()->rc2();
55 }
56 
57 /**************************************************************************/
61  gridNN.free();
62  gridNNReduced.free();
63  beadList.free();
64  fullBeadList.free();
65  beadSep.free();
66  hash.free();
67  grid.free();
68  beadLabel.free();
69  numLabels.free();
70 }
71 
72 /**************************************************************************/
76 void LookupTable::setupNNGrid() {
77 
78  /* We determine the number of grid boxes in each dimension and compute
79  * their size */
80  totNumGridBoxes = 1;
81  for (int i = 0; i < NDIM; i++) {
82  numNNGrid[i] = static_cast<int>(floor((boxPtr->side[i] / constants()->rc()) + EPS));
83 
84  /* Make sure we have at least one grid box */
85  if (numNNGrid[i] < 1)
86  numNNGrid[i] = 1;
87 
88  /* Compute the actual size of the grid */
89  sizeNNGrid[i] = boxPtr->side[i] / (1.0 * numNNGrid[i]);
90 
91  /* Determine the total number of grid boxes */
92  totNumGridBoxes *= numNNGrid[i];
93  }
94 
95  /* Resize and initialize the numLabels array*/
96  TinyVector <int,NDIM+1> initNumLabels;
97  for (int i = 0; i < NDIM; i++)
98  initNumLabels[i] = numNNGrid[i];
99  initNumLabels[NDIM] = constants()->numTimeSlices();
100  numLabels.resize(initNumLabels);
101  numLabels= 0;
102 
103  /* Now we set the array which holds the nearest neighbors of each
104  * grid box which will be used in calculating the potential. We need
105  * to take into account that we may have periodic boundary conditions */
106  numNN = ipow(3,NDIM); // The total number of NN
107  numUniqueNN = (int) floor(0.5*(numNN-1) + EPS); // The unique NN
108  TinyVector <int,NDIM+1> init;
109 
110  /* Get the init vector used to resize data structures */
111  for (int i = 0; i < NDIM; i++)
112  init[i] = numNNGrid[i];
113  init[NDIM] = numNN;
114 
115  /* The truncated list of NN indices with no double back references and the
116  * full list of NN indices */
117  gridNNReduced.resize(init);
118  gridNN.resize(init);
119 
120  /* This is somewhat complicated. Basically we want to construct the list of
121  * nearest neighbors of a given grid box for general dimension. This consists
122  * of moving 'forward', 'zero' and 'back' in each dimension */
123  Array <iVec,1> nnShift(numNN);
124  nnShift = 0;
125  /* The shift vector */
126  TinyVector<int,3> shift;
127  shift = -1,0,1;
128 
129  /* For each of the unique nearest neighbors, we construct shift vectors
130  * this includes all redundancies and even a zero shift, this is taken
131  * into account later */
132  int m = 0;
133  for (int n = 0; n < numNN; n++) {
134  for (int i = 0; i < NDIM; i++) {
135  int index = ((int) floor(1.0*n/pow(3.0,1.0*(NDIM-1-i)) + EPS)) % 3;
136  nnShift(m)[i] = shift[index];
137  }
138  m++;
139  }
140 
141  /* We loop over each grid box, constructing the nearest neighbor list */
142  for (int n = 0; n < totNumGridBoxes; n++) {
143 
144  /* Get the NDIM-vec coordiantes of the box n */
145  gIndex = gridIndex(n);
146 
147  /* Copy over into the nn index */
148  for (int i = 0; i < NDIM; i++)
149  nnIndex[i] = gIndex[i];
150 
151  /* Now we go through the nnShift array, and find the nearest neighbor
152  * coordinates of each grid box */
153  for (m = 0; m < numNN; m++) {
154  nnIndex[NDIM] = m;
155  gridNN(nnIndex) = gIndex + nnShift(m);
156 
157  /* Here we enforce periodic boundary conditions where applicable,
158  * otherwise we set the outlier to -1 */
159  for (int i = 0; i < NDIM; i++) {
160  if (gridNN(nnIndex)[i] == numNNGrid[i])
161  gridNN(nnIndex)[i] = static_cast<int>(boxPtr->periodic[i]-1);
162  else if (gridNN(nnIndex)[i] == -1)
163  gridNN(nnIndex)[i] = static_cast<int>(boxPtr->periodic[i]*numNNGrid[i] - 1);
164  } // end i
165 
166  } // end m
167 
168  } // end n
169 
170  /* For small grid boxes, we need to make sure that periodic boundary conditions
171  * don't cause double counting by having nearest neighbors to one side and the
172  * other corresponding to the same box. We simply set such neighbors to -1 and
173  * have logic in the potential class to skip these. */
174  iVec neg,dup;
175  neg = -1;
176  /* We go through each grid box */
177  for (int n = 0; n < totNumGridBoxes; n++) {
178  gIndex = gridIndex(n);
179  for (int i = 0; i < NDIM; i++)
180  nnIndex[i] = gIndex[i];
181 
182  /* Now, for each grid box, we start from the end of the NN list
183  * and work backwards, setting any duplicates to -1 */
184  for (m = numNN-1; m >= 0; m--) {
185  nnIndex[NDIM] = m;
186  dup = gridNN(nnIndex);
187  for (int p = m-1; p >= 0; p--) {
188  nnIndex[NDIM] = p;
189  /* Check for a duplicate */
190  if (all(gridNN(nnIndex)==dup))
191  gridNN(nnIndex) = neg;
192  } // end p
193  } // end m
194  } //end n
195 
196  /* Now we copy over the NN indices to the reduced list before we remove the
197  * possibility of double counting */
198  gridNNReduced = gridNN;
199 
200  /* This is more complicated. We need to eliminate any double counting. We do
201  * this by following all links in the gridNN table one at a time, and making
202  * sure that we never have a back link. i.e. if (10)->(01) then we can't allow
203  * an entry for (01) which points back to (10). One needs to used gridNNReduced,
204  * if you wish to compute some quantity by summing over all grid boxes. */
205 
206  /* We go through each grid box one at a time */
207  for (int n = 0; n < totNumGridBoxes; n++) {
208  gIndex = gridIndex(n);
209 
210  /* We only consider the 'unique' nearest neighbors */
211  for (m = (numUniqueNN+1); m < numNN; m++) {
212 
213  for (int i = 0; i < NDIM; i++)
214  nnIndex[i] = gIndex[i];
215  nnIndex[NDIM] = m;
216 
217  /* Get the coordinate of the nearest neighbor grid box */
218  dup = gridNNReduced(nnIndex);
219 
220  /* We only follow links for real grid boxes */
221  if (!any(dup == -1)) {
222 
223  for (int i = 0; i < NDIM; i++)
224  nnIndex[i] = dup[i];
225 
226  /* Go through the unique nn of the target box and make sure
227  * we don't have any entries pointing back to the reference
228  * box */
229  for (int p = (numUniqueNN+1); p < numNN; p++) {
230  nnIndex[NDIM] = p;
231  if (all(gridNNReduced(nnIndex) == gIndex))
232  gridNNReduced(nnIndex) = neg;
233  } // end p
234 
235  } // end any
236 
237  } // end m
238  } // end n
239 
240 
241 }
242 
243 /**************************************************************************/
247 
248  /* This outputs the NN grid table */
249  for (int n = 0; n < totNumGridBoxes; n++) {
250  iVec tIndex;
251  tIndex = gridIndex(n);
252  for (int i = 0; i < NDIM; i++)
253  cout << tIndex[i];
254  cout << " ";
255  }
256  cout << endl;
257 
258  for (int n = 0; n < totNumGridBoxes; n++)
259  cout << "=== ";
260  cout << endl;
261 
262  for (int m = 0; m < numNN; m++) {
263  nnIndex[NDIM] = m;
264  for (int n = 0; n < totNumGridBoxes; n++) {
265  iVec tIndex;
266  tIndex = gridIndex(n);
267  for (int i = 0; i < NDIM; i++)
268  nnIndex[i] = tIndex[i];
269 
270  for (int i = 0; i < NDIM; i++) {
271  if (gridNNReduced(nnIndex)[i] == -1)
272  cout << "x";
273  else
274  cout << gridNNReduced(nnIndex)[i];
275  }
276  cout << " ";
277  }
278  cout << endl;
279  }
280 }
281 
282 /**************************************************************************/
286 void LookupTable::updateGrid(const Array <dVec,1> &fixedPos) {
287 
288  numLabels = 0;
289  beadLocator beadIndex;
290  beadIndex[0] = 0;
291  for (int n = 0; n < fixedPos.extent(firstDim); ++n) {
292  beadIndex[1] = n;
293 
294  /* First we figure out which grid box the particle is currently in */
295  grid(beadIndex) = gridIndex(fixedPos(n));
296 
297  /* Get the current number of bead labels */
298  int label = numLabels(numLabelIndex(beadIndex));
299 
300  /* We need to resize the hash array if we have too many beads in a single
301  * grid box */
302  if (hashSize[NDIM+1]==label) {
303  hashSize[NDIM+1]++;
304  hash.resizeAndPreserve(hashSize);
305  }
306 
307  /* Update the hash table */
308  hash(hashIndex(beadIndex,label)) = beadIndex[1];
309 
310  /* Assign the reverse lookup */
311  beadLabel(beadIndex) = label;
312 
313  /* Increment the number of labels */
314  numLabels(numLabelIndex(beadIndex))++;
315 
316  } // n
317 }
318 
319 /**************************************************************************/
323 void LookupTable::updateGrid(const Path &path) {
324 
325  numLabels = 0;
326  beadLocator beadIndex;
327  for (beadIndex[0] = 0; beadIndex[0] < constants()->numTimeSlices(); ++beadIndex[0]) {
328  for (beadIndex[1] = 0; beadIndex[1] < path.getNumParticles(); ++beadIndex[1]) {
329 
330  if (path.worm.beadOn(beadIndex)) {
331 
332  /* First we figure out which grid box the particle is currently in */
333  grid(beadIndex) = gridIndex(path(beadIndex));
334 
335  /* Get the current number of bead labels */
336  int label = numLabels(numLabelIndex(beadIndex));
337 
338  /* We need to resize the hash array if we have too many beads in a single
339  * grid box */
340  if (hashSize[NDIM+1]==label) {
341  hashSize[NDIM+1]++;
342  hash.resizeAndPreserve(hashSize);
343  }
344 
345  /* Update the hash table */
346  hash(hashIndex(beadIndex,label)) = beadIndex[1];
347 
348  /* Assign the reverse lookup */
349  beadLabel(beadIndex) = label;
350 
351  /* Increment the number of labels */
352  numLabels(numLabelIndex(beadIndex))++;
353 
354  } //beadOn
355  } // ptcl
356  } // slice
357 
358 }
359 
360 
361 /**************************************************************************/
364 void LookupTable::updateBead(const beadLocator &beadIndex, const dVec &pos) {
365 
366  /* Find out the new grid index */
367  gIndex = gridIndex(pos);
368 
369  /* If the new position, is in the same grid box, we don't have to do anything */
370  if (!all(gIndex==grid(beadIndex))) {
371 
372  /* Delete the current bead from the grid */
373  delBead(beadIndex);
374 
375  /* Add the new bead to the grid, using the already computed grid index. */
376 
377  /* Update the grid index */
378  grid(beadIndex) = gIndex;
379 
380  /* Get the numLabel index */
381  nI = numLabelIndex(beadIndex);
382 
383  /* Get the current number of bead labels */
384  int label = numLabels(nI);
385 
386  /* We need to resize the hash array if we have too many beads in a single
387  * grid box */
388  if (hashSize[NDIM+1]==label) {
389  hashSize[NDIM+1]++;
390  hash.resizeAndPreserve(hashSize);
391  }
392 
393  /* Update the hash table */
394  hash(hashIndex(beadIndex,label)) = beadIndex[1];
395 
396  /* Assign the reverse lookup */
397  beadLabel(beadIndex) = label;
398 
399  /* Increment the number of labels */
400  numLabels(nI)++;
401  }
402 }
403 
404 /**************************************************************************/
407 void LookupTable::addBead(const beadLocator &beadIndex, const dVec &pos) {
408 
409  /* First we figure out which grid box the particle is located in */
410 
411  grid(beadIndex) = gridIndex(pos);
412 
413  /* Get the numLabel index */
414  nI = numLabelIndex(beadIndex);
415 
416  /* Get the current number of bead labels */
417  int label = numLabels(nI);
418 
419  /* We need to resize the hash array if we have too many beads in a single
420  * grid box */
421  if (hashSize[NDIM+1]==label) {
422  hashSize[NDIM+1]++;
423  hash.resizeAndPreserve(hashSize);
424  }
425 
426  /* Update the hash table */
427  hash(hashIndex(beadIndex,label)) = beadIndex[1];
428 
429  /* Assign the reverse lookup */
430  beadLabel(beadIndex) = label;
431 
432  /* Increment the number of labels */
433  numLabels(nI)++;
434 }
435 
436 /**************************************************************************/
439 void LookupTable::delBead(const beadLocator &beadIndex) {
440 
441  swap[0] = beadIndex[0];
442 
443  /* Get the current label of beadIndex, and the label of the last bead in
444  * the grid box. */
445  int label = beadLabel(beadIndex);
446  nI = numLabelIndex(beadIndex);
447  int lastLabel = numLabels(nI)-1;
448 
449  /* Swap the last bead in the box, with the bead to be removed */
450  hI = hashIndex(beadIndex,lastLabel);
451  if (label < lastLabel) {
452  swap[1] = hash(hI);
453  hash(hI) = XXX;
454  hI[NDIM+1] = label;
455  hash(hI) = swap[1];
456  beadLabel(swap) = label;
457  }
458  else
459  hash(hI) = XXX;
460 
461  /* Reset the label and grid */
462  beadLabel(beadIndex) = XXX;
463  grid(beadIndex) = XXX;
464 
465  /* Decrement the number of labels */
466  numLabels(nI)--;
467 }
468 
469 /**************************************************************************/
473 void LookupTable::updateInteractionList(const Path &path, const beadLocator &bead1) {
474 
475  dVec sep;
476 
477  /* Reset the number of beads */
478  numBeads = 0;
479 
480  /* Get the NDIM-vec coordiantes of the box where the bead resides */
481  for (int i = 0; i < NDIM; i++)
482  nnIndex[i] = grid(bead1)[i];
483 
484  /* We go through all the neighbouring grid boxes of grid(bead1) and
485  * assemble the interaction list */
486  beadLocator bead2;
487  bead2[0] = bead1[0];
488  for (int n = 0; n < numNN; n++) {
489  nnIndex[NDIM] = n;
490 
491  /* Get the grid index of the interacting box */
492  gIndex = gridNN(nnIndex);
493 
494  /* Make sure we don't access any illegal grid boxes */
495  if (!any(gIndex == -1)) {
496 
497  int maxNL = numLabels(numLabelIndex(gIndex,bead1[0]));
498  hI = hashIndex(gIndex,bead1[0],0);
499 
500  for (int label = 0; label < maxNL; label++) {
501 
502  /* Get the interacting bead */
503  hI[NDIM+1] = label;
504  bead2[1] = hash(hI);
505 
506  /* Eliminate self-interactions */
507  if (!all(bead1 == bead2)) {
508 
509  sep = path.getSeparation(bead2,bead1);
510 
511  /* If we are within the cutoff distance, add the bead to the list,
512  * and store their separation.*/
513  if (dot(sep,sep) < rc2) {
514  beadList(numBeads) = bead2;
515  beadSep(numBeads) = sep;
516  numBeads++;
517  }
518  } // bead2 != bead1
519 
520  } // label
521 
522  } // skip any illegal grid boxes
523 
524  } // end n
525 }
526 
527 /**************************************************************************/
532 void LookupTable::updateFullInteractionList(const beadLocator &beadIndex, const int slice) {
533 
534  /* Copy over the location of the central grid box */
535  for (int i = 0; i < NDIM; i++)
536  nnIndex[i] = grid(beadIndex)[i];
537 
538  /* Now we loop over the central box, plus all nearest neighbors, filling
539  * up the beadList and incrementing the numListBeads counter */
540  fullBeadList = XXX;
541  fullNumBeads = 0;
542  for (int nn = 0; nn < numNN; nn++) {
543  nnIndex[NDIM] = nn;
544 
545  /* Get the grid index of the nearest neighbor box */
546  gIndex = gridNN(nnIndex);
547 
548  if (!any(gIndex == -1)) {
549 
550  /* Get the hash table index, and max number of labels*/
551  int maxNL = numLabels(numLabelIndex(gIndex,slice));
552  hI = hashIndex(gIndex,slice,0);
553 
554  for (int label = 0; label < maxNL; label++) {
555 
556  /* Get the interacting bead */
557  hI[NDIM+1] = label;
558  fullBeadList(fullNumBeads) = slice,hash(hI);
559  fullNumBeads++;
560 
561  } // label
562 
563  } // skip out of bounds grid boxes
564 
565  } // end nn
566 }
567 
568 /**************************************************************************/
573 void LookupTable::updateFullInteractionList(const int gNumber, const int slice) {
574 
575  gIndex = gridIndex(gNumber);
576 
577  /* Copy over the location of the central grid box */
578  for (int i = 0; i < NDIM; i++)
579  nnIndex[i] = gIndex[i];
580 
581  /* Now we loop over the central box, plus all nearest neighbors, filling
582  * up the beadList and incrementing the numListBeads counter */
583  fullBeadList = XXX;
584  fullNumBeads = 0;
585  for (int nn = 0; nn < numNN; nn++) {
586  nnIndex[NDIM] = nn;
587 
588  /* Get the grid index of the nearest neighbor box */
589  gIndex = gridNN(nnIndex);
590 
591  if (!any(gIndex == -1)) {
592 
593  /* Get the hash table index, and max number of labels*/
594  int maxNL = numLabels(numLabelIndex(gIndex,slice));
595  hI = hashIndex(gIndex,slice,0);
596 
597  for (int label = 0; label < maxNL; label++) {
598 
599  /* Get the interacting bead */
600  hI[NDIM+1] = label;
601  fullBeadList(fullNumBeads) = slice,hash(hI);
602  fullNumBeads++;
603 
604  } // label
605 
606  } // skip out of bounds grid boxes
607 
608  } // end nn
609 }
610 
611 /**************************************************************************/
615 bool LookupTable::gridNeighbors(const beadLocator &bead1, const beadLocator &bead2) {
616 
617  /* Copy over the bead1 grid index coordinates */
618  for (int i = 0; i < NDIM; i++)
619  nnIndex[i] = grid(bead1)[i];
620 
621  /* Get the bead2 grid index */
622  gIndex = grid(bead2);
623 
624  /* Run over all nearest neighbors of bead1 and see if we have found bead2's
625  * grid */
626  for (int nn = 0; nn < numNN; nn++) {
627  nnIndex[NDIM] = nn;
628  if (all(gIndex == gridNN(nnIndex))) {
629  return true;
630  }
631  }
632 
633  return false;
634 }
int numTimeSlices()
Get number of time slices.
Definition: constants.h:99
double rc2() const
Get potential cutoff squared.
Definition: constants.h:48
The base class which holds details on the generalized box that our system will be simulated inside of...
Definition: container.h:24
TinyVector< unsigned int, NDIM > periodic
Determines which dimensions have periodic bc.
Definition: container.h:29
dVec side
The linear dimensions of the box.
Definition: container.h:31
int fullNumBeads
The full number of active beads in beadList;.
Definition: lookuptable.h:44
int numUniqueNN
The number of unique nearest neighbors of each box.
Definition: lookuptable.h:37
int numNN
The total number of nearest neighbors of each box.
Definition: lookuptable.h:38
iVec gridIndex(const dVec &)
Given a particle position, return the grid index for the nearest neighbor lookup table.
Definition: lookuptable.h:139
void updateGrid(const Path &)
We update the full nearest neighbor grid by filling up all data arrays at all time slices.
Array< beadLocator, 1 > beadList
The cutoff dynamic list of interacting beads.
Definition: lookuptable.h:40
void updateFullInteractionList(const beadLocator &, const int)
Fill up the fullBeadList array with a list of beads in the same grid box as the supplied beadIndex an...
void updateInteractionList(const Path &, const beadLocator &)
Update the NN lookup table and the array of beadLocators containing all beads which 'interact' with t...
void resizeList(int _numParticles)
Resize the bead and grid lists.
Definition: lookuptable.h:78
LookupTable(const Container *, const int, const int)
Initilialize the nearest neighbor lookup table.
Definition: lookuptable.cpp:26
void addBead(const beadLocator &, const dVec &)
Add a single bead to the NN grid and position pos.
Array< dVec, 1 > beadSep
The separation between beads.
Definition: lookuptable.h:42
bool gridNeighbors(const beadLocator &, const beadLocator &)
Given two beadIndices, determine if the beads lie in neighboring grid boxes.
int numBeads
The cutoff number of active beads in beadList;.
Definition: lookuptable.h:43
~LookupTable()
Free all blitz arrays.
Definition: lookuptable.cpp:60
Array< beadLocator, 1 > fullBeadList
The full dynamic list of interacting beads.
Definition: lookuptable.h:41
const Container * boxPtr
The simulation cell.
Definition: lookuptable.h:35
void updateBead(const beadLocator &, const dVec &)
Update the NN grid with a new bead position.
void delBead(const beadLocator &)
Remove a single bead from the NN grid.
void printGrid()
Print the NN Lookup table.
The space-time trajectories.
Definition: path.h:29
int getNumParticles() const
Get the size of the worldline array.
Definition: path.h:51
dVec getSeparation(const beadLocator &, const beadLocator &) const
Return the separation vector between two particles in the same timeslice.
Definition: path.h:173
Worm worm
Details on the worm.
Definition: path.h:44
int beadOn(int, int) const
Safely get a bead (int indexed)
Definition: worm.h:148
#define NDIM
Number of spatial dimnsions.
Definition: common.h:71
int ipow(int base, int power)
Return the integer value of a number raised to a power.
Definition: common.h:136
TinyVector< int, 2 > beadLocator
time-slice,bead-number world line index
Definition: common.h:117
#define EPS
A small number.
Definition: common.h:94
TinyVector< double, NDIM > dVec
A NDIM-vector of type double.
Definition: common.h:111
TinyVector< int, NDIM > iVec
A NDIM-vector of type integer.
Definition: common.h:114
#define XXX
Used to refer to a nonsense beadIndex.
Definition: common.h:98
Class definitions for all file input/output.
ConstantParameters * constants()
Global public access to the constants.
Definition: constants.h:201
LookupTable class definition.
Path class definition.