Chaste  Release::3.4
BoxCollection.cpp
1 /*
2 
3 Copyright (c) 2005-2016, University of Oxford.
4 All rights reserved.
5 
6 University of Oxford means the Chancellor, Masters and Scholars of the
7 University of Oxford, having an administrative office at Wellington
8 Square, Oxford OX1 2JD, UK.
9 
10 This file is part of Chaste.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are met:
14  * Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16  * Redistributions in binary form must reproduce the above copyright notice,
17  this list of conditions and the following disclaimer in the documentation
18  and/or other materials provided with the distribution.
19  * Neither the name of the University of Oxford nor the names of its
20  contributors may be used to endorse or promote products derived from this
21  software without specific prior written permission.
22 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 */
35 
36 #include "BoxCollection.hpp"
37 #include "Exception.hpp"
38 #include "Debug.hpp"
39 
41 // BoxCollection methods
43 
44 // Static member for "fudge factor" is instantiated here
45 template<unsigned DIM>
46 const double BoxCollection<DIM>::msFudge = 5e-14;
47 
48 template<unsigned DIM>
49 BoxCollection<DIM>::BoxCollection(double boxWidth, c_vector<double, 2 * DIM> domainSize, bool isPeriodicInX,
50  bool isPeriodicInY, bool isPeriodicInZ)
51  : mDomainSize(domainSize),
52  mBoxWidth(boxWidth)
53 {
54  // Populate mIsDomainPeriodic
55  switch (DIM)
56  {
57  case 1:
58  {
59  mIsDomainPeriodic[0] = isPeriodicInX;
60  break;
61  }
62  case 2:
63  {
64  mIsDomainPeriodic[0] = isPeriodicInX;
65  mIsDomainPeriodic[1] = isPeriodicInY;
66  break;
67  }
68  case 3:
69  {
70  mIsDomainPeriodic[0] = isPeriodicInX;
71  mIsDomainPeriodic[1] = isPeriodicInY;
72  mIsDomainPeriodic[2] = isPeriodicInZ;
73  break;
74  }
75  default:
76  {
78  }
79  }
80 
81  /*
82  * Start by calculating the number of boxes in each direction and total number of boxes.
83  * Also create a helper vector of coefficients, whose first entry is 1 and whose i-th
84  * entry (for i>1) is the i-th partial product of the vector mNumBoxesEachDirection. This
85  * vector of coefficients will be used in the next code block to compute how many boxes
86  * along in each dimension each box is, given its index.
87  */
88  unsigned num_boxes = 1;
89  std::vector<unsigned> coefficients;
90  coefficients.push_back(1);
91 
92  for (unsigned i = 0; i < DIM; i++)
93  {
95  mNumBoxesEachDirection(i) = (unsigned) floor((domainSize(2 * i + 1) - domainSize(2 * i)) / boxWidth + msFudge) + 1;
96  num_boxes *= mNumBoxesEachDirection(i);
97  coefficients.push_back(coefficients[i] * mNumBoxesEachDirection(i));
98  }
99 
100  for (unsigned box_index = 0 ; box_index < num_boxes ; box_index++)
101  {
102  /*
103  * The code block below computes how many boxes along in each dimension the
104  * current box is and stores this information in the second, ..., (DIM+1)th
105  * entries of the vector current_box_indices. The first entry of
106  * current_box_indices is zero to ensure that the for loop works correctly.
107  *
108  * Our convention is that in 3D the index of each box, box_index, is related
109  * to its indices (i,j,k) by
110  *
111  * box_index = i + mNumBoxesEachDirection(0)*j
112  * + mNumBoxesEachDirection(0)*mNumBoxesEachDirection(1)*k,
113  *
114  * while in 2D, box_index is related to (i,j) by
115  *
116  * box_index = i + mNumBoxesEachDirection(0)*j
117  *
118  * and in 1D we simply have box_index = i.
119  */
120  c_vector<unsigned, DIM + 1> current_box_indices;
121  current_box_indices[0] = 0;
122 
123  for (unsigned i = 0; i < DIM; i++)
124  {
125  unsigned temp = 0;
126  for (unsigned j = 1; j < i; j++)
127  {
128  temp += coefficients[j] * current_box_indices[j - 1];
129  }
130  current_box_indices[i + 1] = (box_index % coefficients[i + 1] - temp) / coefficients[i];
131  }
132 
133  /*
134  * We now use the information stores in current_box_indices to construct the
135  * Box, which we add to mBoxes.
136  */
137  c_vector<double, 2 * DIM> box_coords;
138  for (unsigned l = 0; l < DIM; l++)
139  {
140  box_coords(2 * l) = domainSize(2 * l) + current_box_indices(l + 1) * boxWidth;
141  box_coords(2 * l + 1) = domainSize(2 * l) + (current_box_indices(l + 1) + 1) * boxWidth;
142  }
143 
144  Box<DIM> new_box(box_coords);
145  mBoxes.push_back(new_box);
146  }
147 
148  // Check that we have the correct number of boxes
149  assert(num_boxes == mBoxes.size());
150 }
151 
152 template<unsigned DIM>
154 {
155  for (unsigned i = 0; i < mBoxes.size(); i++)
156  {
157  mBoxes[i].ClearNodes();
158  }
159 }
160 
161 template<unsigned DIM>
163 {
164  // Get the location of the node
165  c_vector<double, DIM> location = pNode->rGetLocation();
166  return CalculateContainingBox(location);
167 }
168 
169 template<unsigned DIM>
170 unsigned BoxCollection<DIM>::CalculateContainingBox(c_vector<double, DIM>& rLocation)
171 {
172  // Compute the containing box index in each dimension
173  c_vector<int, DIM> containing_box_indices;
174  for (unsigned i = 0; i < DIM; i++)
175  {
176  containing_box_indices[i] = (int) floor((rLocation[i] - mDomainSize(2 * i) + msFudge) / mBoxWidth);
177  }
178 
179  if(!IsBoxInDomain(containing_box_indices))
180  {
181  EXCEPTION("Location does not correspond to any box.");
182  }
183 
184  return GetLinearIndex(containing_box_indices);
185 }
186 
187 template<unsigned DIM>
189 {
190  assert(boxIndex < mBoxes.size());
191  return mBoxes[boxIndex];
192 }
193 
194 template<unsigned DIM>
196 {
197  return mBoxes.size();
198 }
199 
200 template<unsigned DIM>
201 unsigned BoxCollection<DIM>::GetLinearIndex(c_vector<int, DIM> gridIndices)
202 {
203  /*
204  * This function may be passed values outside the range in one or more
205  * dimensions in the case of a periodic domain. We therefore assume that
206  * these values represent a situation with periodicity and adjust them
207  * accordingly before calculating the linear index.
208  */
209 
210  // Adjust for periodicity if necessary
211  for (unsigned dim = 0; dim < DIM; dim++)
212  {
213  // Check for values too large
214  if (gridIndices(dim) >= (int)mNumBoxesEachDirection(dim))
215  {
216  assert(mIsDomainPeriodic(dim));
217  gridIndices(dim) -= (int)mNumBoxesEachDirection(dim);
218  }
219 
220  // Check for negative values
221  else if (gridIndices(dim) < 0)
222  {
223  assert(mIsDomainPeriodic(dim));
224  gridIndices(dim) += (int)mNumBoxesEachDirection(dim);
225  }
226  }
227 
228  // Calculate linear index
229  unsigned linear_index;
230 
231  switch (DIM)
232  {
233  case 1:
234  {
235  linear_index = gridIndices(0);
236  break;
237  }
238  case 2:
239  {
240  linear_index = gridIndices(0) +
241  gridIndices(1) * mNumBoxesEachDirection(0);
242  break;
243  }
244  case 3:
245  {
246  linear_index = gridIndices(0) +
247  gridIndices(1) * mNumBoxesEachDirection(0) +
248  gridIndices(2) * mNumBoxesEachDirection(0) * mNumBoxesEachDirection(1);
249  break;
250  }
251  default:
252  {
254  }
255  }
256 
257  return linear_index;
258 }
259 
260 template<unsigned DIM>
261 c_vector<int,DIM> BoxCollection<DIM>::GetGridIndices(unsigned linearIndex)
262 {
263  c_vector<int,DIM> grid_indices;
264 
265  switch (DIM)
266  {
267  case 1:
268  {
269  grid_indices(0) = linearIndex;
270  break;
271  }
272  case 2:
273  {
274  unsigned num_x = mNumBoxesEachDirection(0);
275  grid_indices(0) = linearIndex % num_x;
276  grid_indices(1) = (linearIndex - grid_indices(0)) / num_x;
277  break;
278  }
279  case 3:
280  {
281  unsigned num_x = mNumBoxesEachDirection(0);
282  unsigned num_xy = mNumBoxesEachDirection(0)*mNumBoxesEachDirection(1);
283  grid_indices(0) = linearIndex % num_x;
284  grid_indices(1) = (linearIndex % num_xy - grid_indices(0)) / num_x;
285  grid_indices(2) = linearIndex / num_xy;
286  break;
287  }
288  default:
289  {
291  }
292  }
293 
294  return grid_indices;
295 }
296 
297 template<unsigned DIM>
298 bool BoxCollection<DIM>::IsBoxInDomain(c_vector<int, DIM> gridIndices)
299 {
300  /*
301  * We assume that, for a given dimension, any location is in the domain
302  * if the domain is periodic in that dimension.
303  *
304  * This method can only return false in the case of one or more
305  * dimensions being aperiodic and a location in one of those dimensions
306  * being outside the range.
307  */
308 
309  bool is_in_domain = true;
310 
311  for (unsigned dim = 0; dim < DIM; dim++)
312  {
313  if (!mIsDomainPeriodic(dim))
314  {
315  if (gridIndices(dim) < 0 || gridIndices(dim) >= (int)mNumBoxesEachDirection(dim))
316  {
317  is_in_domain = false;
318  }
319  }
320  }
321 
322  return is_in_domain;
323 }
324 
325 template<unsigned DIM>
326 c_vector<bool,DIM> BoxCollection<DIM>::IsIndexPenultimate(c_vector<int,DIM> gridIndices)
327 {
328  c_vector<bool,DIM> is_penultimate;
329 
330  for (unsigned dim = 0 ; dim < DIM ; dim++)
331  {
332  is_penultimate(dim) = (gridIndices(dim) == (int)mNumBoxesEachDirection(dim) - 2);
333  }
334 
335  return is_penultimate;
336 }
337 
338 template<unsigned DIM>
340 {
341  // Populate a list of half the neighbours in this number of dimensions
342  std::vector<c_vector<int,DIM> > neighbours;
343 
344  switch (DIM)
345  {
346  case 1:
347  {
348  // Just one neighbour, plus the current box (zero vector)
349  neighbours = std::vector<c_vector<int,DIM> >(2);
350 
351  neighbours[0](0) = 0; // current box
352  neighbours[1](0) = 1; // right
353 
354  break;
355  }
356  case 2:
357  {
358  // Four neighbours, plus the current box (zero vector)
359  neighbours = std::vector<c_vector<int,DIM> >(5);
360 
361  neighbours[0](0) = 0; neighbours[0](1) = 1; // up
362  neighbours[1](0) = 1; neighbours[1](1) = 1; // up right
363  neighbours[2](0) = 1; neighbours[2](1) = 0; // right
364  neighbours[3](0) = 1; neighbours[3](1) =-1; // down right
365  neighbours[4](0) = 0; neighbours[4](1) = 0; // current box
366 
367  break;
368  }
369  case 3:
370  {
371  /*
372  * We need to pick 13 neighbours in such a way as to ensure all interactions are captured,
373  * in addition to the current box.
374  *
375  * The 26 cubes on the outside of a 3x3 arrangement either adjacent to a whole face of
376  * the central cube, only an edge of the central cube, or only a vertex of the central
377  * cube:
378  *
379  * 6 contact faces, and come in the following 3 pairs:
380  * +x -x (1, 0, 0)
381  * +y -y (0, 1, 0)
382  * +z -z (0, 0, 1)
383  *
384  * 12 contact edges, and come in the following 6 pairs:
385  * +x+y -x-y (1, 1, 0)
386  * +x+z -x-z (1, 0, 1)
387  * +x-y -x+y (1,-1, 0)
388  * +x-z -x+z (1, 0,-1)
389  * +y+z -y-z (0, 1, 1)
390  * +y-z -y+z (0, 1,-1)
391  *
392  * 8 contact vertices, and come in the following 4 pairs:
393  * +x+y+z -x-y-z (1, 1, 1)
394  * +x+y-z -x-y+z (1, 1,-1)
395  * +x-y+z -x+y-z (1,-1, 1)
396  * +x-y-z -x+y+z (1,-1,-1)
397  *
398  * We will simply pick the 13 from the left-hand column above, which can be represented
399  * as an integer offset in three dimensions from the middle cube, as shown in the third
400  * column above.
401  */
402 
403  neighbours = std::vector<c_vector<int,DIM> >(14);
404 
405  neighbours[0](0) = 1; neighbours[0](1) = 0; neighbours[0](2) = 0;
406  neighbours[1](0) = 0; neighbours[1](1) = 1; neighbours[1](2) = 0;
407  neighbours[2](0) = 0; neighbours[2](1) = 0; neighbours[2](2) = 1;
408  neighbours[3](0) = 1; neighbours[3](1) = 1; neighbours[3](2) = 0;
409  neighbours[4](0) = 1; neighbours[4](1) = 0; neighbours[4](2) = 1;
410  neighbours[5](0) = 1; neighbours[5](1) =-1; neighbours[5](2) = 0;
411  neighbours[6](0) = 1; neighbours[6](1) = 0; neighbours[6](2) =-1;
412  neighbours[7](0) = 0; neighbours[7](1) = 1; neighbours[7](2) = 1;
413  neighbours[8](0) = 0; neighbours[8](1) = 1; neighbours[8](2) =-1;
414  neighbours[9](0) = 1; neighbours[9](1) = 1; neighbours[9](2) = 1;
415  neighbours[10](0) = 1; neighbours[10](1) = 1; neighbours[10](2) =-1;
416  neighbours[11](0) = 1; neighbours[11](1) =-1; neighbours[11](2) = 1;
417  neighbours[12](0) = 1; neighbours[12](1) =-1; neighbours[12](2) =-1;
418 
419  neighbours[13](0) = 0; neighbours[13](1) = 0; neighbours[13](2) = 0; // current box
420 
421  break;
422  }
423  default:
424  {
426  }
427  }
428 
429  // Pass the list of possible neighbours to SetupLocalBoxes()
430  SetupLocalBoxes(neighbours);
431 }
432 
433 template<unsigned DIM>
435 {
436  // Populate a list of all neighbours in this number of dimensions
437  std::vector<c_vector<int,DIM> > neighbours;
438 
439  switch (DIM)
440  {
441  case 1:
442  {
443  // 3 neighbours
444  neighbours.clear();
445 
446  for (int x_dim = -1 ; x_dim < 2 ; x_dim++)
447  {
448  c_vector<int,DIM> neighbour;
449  neighbour(0) = x_dim;
450 
451  neighbours.push_back(neighbour);
452  }
453 
454  break;
455  }
456  case 2:
457  {
458  // 3x3 neighbours
459  neighbours.clear();
460 
461  for (int x_dim = -1 ; x_dim < 2 ; x_dim++)
462  {
463  for (int y_dim = -1 ; y_dim < 2 ; y_dim++)
464  {
465  c_vector<int,DIM> neighbour;
466  neighbour(0) = x_dim;
467  neighbour(1) = y_dim;
468 
469  neighbours.push_back(neighbour);
470  }
471  }
472 
473  break;
474  }
475  case 3:
476  {
477  // 3x3x3 neighbours
478  neighbours.clear();
479 
480  for (int x_dim = -1 ; x_dim < 2 ; x_dim++)
481  {
482  for (int y_dim = -1 ; y_dim < 2 ; y_dim++)
483  {
484  for (int z_dim = -1 ; z_dim < 2 ; z_dim++)
485  {
486  c_vector<int,DIM> neighbour;
487  neighbour(0) = x_dim;
488  neighbour(1) = y_dim;
489  neighbour(2) = z_dim;
490 
491  neighbours.push_back(neighbour);
492  }
493  }
494  }
495 
496  break;
497  }
498  default:
499  {
501  }
502  }
503 
504  // Pass the list of possible neighbours to SetupLocalBoxes()
505  SetupLocalBoxes(neighbours);
506 }
507 
508 template<unsigned DIM>
509 void BoxCollection<DIM>::SetupLocalBoxes(std::vector<c_vector<int, DIM> > neighbours)
510 {
511  mLocalBoxes.clear();
512 
513  // Loop over all boxes and add all necessary local boxes
514  for (unsigned box_idx = 0 ; box_idx < mBoxes.size() ; box_idx++)
515  {
516  std::set<unsigned> local_boxes;
517 
518  // The grid indices (i), (i,j) or (i,j,k) depending on DIM, corresponding to box_idx
519  c_vector<int, DIM> grid_indices = GetGridIndices(box_idx);
520 
521  // Check all neighbours (1 or 2 in 1D, 4 or 8 in 2D, 13 or 26 in 3D) and add them as local
522  // boxes if they are in the domain
523  for (unsigned neighbour = 0 ; neighbour < neighbours.size() ; neighbour++)
524  {
525  if (IsBoxInDomain(grid_indices + neighbours[neighbour]))
526  {
527  local_boxes.insert(GetLinearIndex(grid_indices + neighbours[neighbour]));
528  }
529  }
530 
531  /*
532  * If we are in a periodic domain, we need to add additional boxes if the
533  * current box is in the penultimate position of any dimension.
534  *
535  * The additional boxes we need to add are just all the neighbours of the box
536  * in the final position in that dimension. Because we use set::insert, it
537  * doesn't matter if we try and add the same box multiple times (only one
538  * copy of the index will be included).
539  */
540 
541  // Find if the current indices are penultimate in any dimension in which collection is periodic
542  c_vector<bool,DIM> is_penultimate_periodic = IsIndexPenultimate(grid_indices);
543  unsigned num_penultimate_periodic_dimensions = 0;
544 
545  for (unsigned dim = 0 ; dim < DIM ; dim++)
546  {
547  is_penultimate_periodic(dim) = is_penultimate_periodic(dim) && mIsDomainPeriodic(dim);
548  if (is_penultimate_periodic(dim))
549  {
550  num_penultimate_periodic_dimensions++;
551  }
552  }
553 
554  // First, deal with at least one penultimate dimension
555  if (num_penultimate_periodic_dimensions > 0)
556  {
557  // Loop over each dimension. If penultimate in dimension DIM move one box and add all neighbours
558  for (unsigned dim = 0 ; dim < DIM ; dim++)
559  {
560  if (is_penultimate_periodic(dim))
561  {
562  // If we're penultimate in dimension dim, move to the final location and add each neighbour as before.
563  // The call to IsBoxInDomain() will handle periodicity.
564  // Note that we define this vector before setting it as otherwise the profiling build will break (see #2367)
565  c_vector<int, DIM> ultimate_indices; // Initialisation on next line for profile compiler
566  ultimate_indices = grid_indices;
567  ultimate_indices(dim) ++;
568 
569  for (unsigned neighbour = 0 ; neighbour < neighbours.size() ; neighbour++)
570  {
571  if (IsBoxInDomain(ultimate_indices + neighbours[neighbour]))
572  {
573  local_boxes.insert(GetLinearIndex(ultimate_indices + neighbours[neighbour]));
574  }
575  }
576  }
577  }
578  }
579 
580  // The final consideration is cases of multiple dimensions of periodicity.
581  if (num_penultimate_periodic_dimensions > 1)
582  {
583  switch (DIM)
584  {
585  case 2:
586  {
587  // Must have x and y periodicity - just have to add one extra box
588  assert(mIsDomainPeriodic(0) && mIsDomainPeriodic(1));
589 
590  local_boxes.insert(0);
591 
592  break;
593  }
594  case 3:
595  {
596  // Could have X and Y, X and Z, Y and Z, or X, Y and Z periodicity
597 
598  // X and Y
599  if (is_penultimate_periodic(0) && is_penultimate_periodic(1))
600  {
601  c_vector<int,DIM> ultimate_indices = grid_indices;
602  ultimate_indices(0) ++;
603  ultimate_indices(1) ++;
604 
605  for (unsigned neighbour = 0 ; neighbour < neighbours.size() ; neighbour++)
606  {
607  if (IsBoxInDomain(ultimate_indices + neighbours[neighbour]))
608  {
609  local_boxes.insert(GetLinearIndex(ultimate_indices + neighbours[neighbour]));
610  }
611  }
612  }
613 
614  // X and Z
615  if (is_penultimate_periodic(0) && is_penultimate_periodic(2))
616  {
617  c_vector<int,DIM> ultimate_indices = grid_indices;
618  ultimate_indices(0) ++;
619  ultimate_indices(2) ++;
620 
621  for (unsigned neighbour = 0 ; neighbour < neighbours.size() ; neighbour++)
622  {
623  if (IsBoxInDomain(ultimate_indices + neighbours[neighbour]))
624  {
625  local_boxes.insert(GetLinearIndex(ultimate_indices + neighbours[neighbour]));
626  }
627  }
628  }
629 
630  // Y and Z
631  if (is_penultimate_periodic(1) && is_penultimate_periodic(2))
632  {
633  c_vector<int,DIM> ultimate_indices = grid_indices;
634  ultimate_indices(1) ++;
635  ultimate_indices(2) ++;
636 
637  for (unsigned neighbour = 0 ; neighbour < neighbours.size() ; neighbour++)
638  {
639  if (IsBoxInDomain(ultimate_indices + neighbours[neighbour]))
640  {
641  local_boxes.insert(GetLinearIndex(ultimate_indices + neighbours[neighbour]));
642  }
643  }
644  }
645 
646  // X Y and Z
647  if (num_penultimate_periodic_dimensions == 3)
648  {
649  assert(mIsDomainPeriodic(0) && mIsDomainPeriodic(1) && mIsDomainPeriodic(1));
650  local_boxes.insert(0);
651  }
652 
653  break;
654  }
655  default:
656  {
658  }
659  }
660  }
661 
662  // Add the local boxes to the member vector
663  mLocalBoxes.push_back(local_boxes);
664  }
665 }
666 
667 template<unsigned DIM>
668 std::set<unsigned> BoxCollection<DIM>::GetLocalBoxes(unsigned boxIndex)
669 {
670  assert(boxIndex < mLocalBoxes.size());
671  return mLocalBoxes[boxIndex];
672 }
673 
674 template<unsigned DIM>
675 const c_vector<double, 2 * DIM>& BoxCollection<DIM>::rGetDomainSize() const
676 {
677  return mDomainSize;
678 }
679 
680 template<unsigned DIM>
682  std::vector<std::pair<Node<DIM>*, Node<DIM>*> >& rNodePairs,
683  std::map<unsigned, std::set<unsigned> >& rNodeNeighbours)
684 {
685  rNodePairs.clear();
686  rNodeNeighbours.clear();
687 
688  // Ensure all boxes are empty
689  EmptyBoxes();
690 
691  // Create an empty set of neighbours for each node, and add each node to its correct box
692  for (unsigned node_index = 0; node_index < rNodes.size(); node_index++)
693  {
694  rNodeNeighbours[node_index] = std::set<unsigned>();
695 
696  unsigned box_index = CalculateContainingBox(rNodes[node_index]);
697  mBoxes[box_index].AddNode(rNodes[node_index]);
698  }
699 
700  for (unsigned i = 0; i < rNodes.size(); i++)
701  {
702  Node<DIM>* this_node = rNodes[i];
703  unsigned node_index = this_node->GetIndex();
704 
705  // Get the box containing this node
706  unsigned this_node_box_index = CalculateContainingBox(this_node);
707 
708  // Get the local boxes to this node
709  std::set<unsigned> local_boxes_indices = GetLocalBoxes(this_node_box_index);
710 
711  // Loop over all the local boxes
712  for (std::set<unsigned>::iterator box_iter = local_boxes_indices.begin(); box_iter != local_boxes_indices.end();
713  box_iter++)
714  {
715  // Get the set of nodes contained in this box
716  std::set<Node<DIM>*>& r_contained_nodes = mBoxes[*box_iter].rGetNodesContained();
717 
718  // Loop over these nodes
719  for (typename std::set<Node<DIM>*>::iterator node_iter = r_contained_nodes.begin();
720  node_iter != r_contained_nodes.end(); ++node_iter)
721  {
722  // Get the index of the other node
723  unsigned other_node_index = (*node_iter)->GetIndex();
724 
725  // If we're in the same box, then take care not to store the node pair twice
726  if (*box_iter == this_node_box_index)
727  {
728  if (other_node_index > this_node->GetIndex())
729  {
730  rNodePairs.push_back(std::pair<Node<DIM>*, Node<DIM>*>(this_node, (*node_iter)));
731  rNodeNeighbours[node_index].insert(other_node_index);
732  rNodeNeighbours[other_node_index].insert(node_index);
733  }
734  }
735  else
736  {
737  rNodePairs.push_back(std::pair<Node<DIM>*, Node<DIM>*>(this_node, (*node_iter)));
738  rNodeNeighbours[node_index].insert(other_node_index);
739  rNodeNeighbours[other_node_index].insert(node_index);
740  }
741  }
742  }
743  }
744 }
745 
747 // Explicit instantiation
749 
750 template class BoxCollection<1>;
751 template class BoxCollection<2>;
752 template class BoxCollection<3>;
Definition: Node.hpp:58
c_vector< int, DIM > GetGridIndices(unsigned linearIndex)
#define EXCEPTION(message)
Definition: Exception.hpp:143
std::vector< Box< DIM > > mBoxes
#define NEVER_REACHED
Definition: Exception.hpp:206
std::set< unsigned > GetLocalBoxes(unsigned boxIndex)
unsigned GetLinearIndex(c_vector< int, DIM > gridIndices)
unsigned GetNumBoxes()
c_vector< bool, DIM > IsIndexPenultimate(c_vector< int, DIM > gridIndices)
bool IsBoxInDomain(c_vector< int, DIM > gridIndices)
unsigned CalculateContainingBox(Node< DIM > *pNode)
Definition: Box.hpp:50
const c_vector< double, 2 *DIM > & rGetDomainSize() const
const c_vector< double, SPACE_DIM > & rGetLocation() const
Definition: Node.cpp:140
void SetupAllLocalBoxes()
BoxCollection(double boxWidth, c_vector< double, 2 *DIM > domainSize, bool isPeriodicInX=false, bool isPeriodicInY=false, bool isPeriodicInZ=false)
Box< DIM > & rGetBox(unsigned boxIndex)
c_vector< unsigned, DIM > mNumBoxesEachDirection
void SetupLocalBoxesHalfOnly()
void CalculateNodePairs(std::vector< Node< DIM > * > &rNodes, std::vector< std::pair< Node< DIM > *, Node< DIM > * > > &rNodePairs, std::map< unsigned, std::set< unsigned > > &rNodeNeighbours)
static const double msFudge
unsigned GetIndex() const
Definition: Node.cpp:159
void SetupLocalBoxes(std::vector< c_vector< int, DIM > > neighbours)
c_vector< bool, DIM > mIsDomainPeriodic