Chaste Release::3.1
BoxCollection.cpp
00001 /*
00002 
00003 Copyright (c) 2005-2012, University of Oxford.
00004 All rights reserved.
00005 
00006 University of Oxford means the Chancellor, Masters and Scholars of the
00007 University of Oxford, having an administrative office at Wellington
00008 Square, Oxford OX1 2JD, UK.
00009 
00010 This file is part of Chaste.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014  * Redistributions of source code must retain the above copyright notice,
00015    this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright notice,
00017    this list of conditions and the following disclaimer in the documentation
00018    and/or other materials provided with the distribution.
00019  * Neither the name of the University of Oxford nor the names of its
00020    contributors may be used to endorse or promote products derived from this
00021    software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 #include "BoxCollection.hpp"
00036 #include "Exception.hpp"
00037 
00039 // Box methods
00041 
00042 
00043 template<unsigned DIM>
00044 Box<DIM>::Box(c_vector<double, 2*DIM>& rMinAndMaxValues)
00045 {
00046     mMinAndMaxValues = rMinAndMaxValues;
00047 }
00048 
00049 template<unsigned DIM>
00050 c_vector<double, 2*DIM>& Box<DIM>::rGetMinAndMaxValues()
00051 {
00052     return mMinAndMaxValues;
00053 }
00054 
00055 template<unsigned DIM>
00056 void Box<DIM>::AddNode(Node<DIM>* pNode)
00057 {
00058     mNodesContained.insert(pNode);
00059 }
00060 
00061 template<unsigned DIM>
00062 void Box<DIM>::RemoveNode(Node<DIM>* pNode)
00063 {
00064     mNodesContained.erase(pNode);
00065 }
00066 
00067 template<unsigned DIM>
00068 std::set< Node<DIM>* >& Box<DIM>::rGetNodesContained()
00069 {
00070     return mNodesContained;
00071 }
00072 
00073 template<unsigned DIM>
00074 void Box<DIM>::AddElement(Element<DIM,DIM>* pElement)
00075 {
00076     mElementsContained.insert(pElement);
00077 }
00078 
00079 template<unsigned DIM>
00080 std::set< Element<DIM,DIM>* >& Box<DIM>::rGetElementsContained()
00081 {
00082     return mElementsContained;
00083 }
00084 
00085 
00087 // BoxCollection methods
00089 
00090 
00091 template<unsigned DIM>
00092 BoxCollection<DIM>::BoxCollection(double boxWidth, c_vector<double, 2*DIM> domainSize)
00093     : mDomainSize(domainSize),
00094       mBoxWidth(boxWidth)
00095 {
00096     /*
00097      * Start by calculating the number of boxes in each direction and total number of boxes.
00098      * Also create a helper vector of coefficients, whose first entry is 1 and whose i-th
00099      * entry (for i>1) is the i-th partial product of the vector mNumBoxesEachDirection. This
00100      * vector of coefficients will be used in the next code block to compute how many boxes
00101      * along in each dimension each box, given its index.
00102      */
00103     unsigned num_boxes = 1;
00104     std::vector<unsigned> coefficients;
00105     coefficients.push_back(1);
00106 
00107     for (unsigned i=0; i<DIM; i++)
00108     {
00109         mNumBoxesEachDirection(i) = floor((domainSize(2*i+1) - domainSize(2*i))/boxWidth + mFudge) + 1;
00110         num_boxes *= mNumBoxesEachDirection(i);
00111         coefficients.push_back(coefficients[i]*mNumBoxesEachDirection(i));
00112     }
00113 
00114     for (unsigned box_index=0; box_index<num_boxes; box_index++)
00115     {
00116         /*
00117          * The code block below computes how many boxes along in each dimension the
00118          * current box is and stores this information in the second, ..., (DIM+1)th
00119          * entries of the vector current_box_indices. The first entry of
00120          * current_box_indices is zero to ensure that the for loop works correctly.
00121          *
00122          * Our convention is that in 3D the index of each box, box_index, is related
00123          * to its indices (i,j,k) by
00124          *
00125          * box_index = i + mNumBoxesEachDirection(0)*j
00126          *               + mNumBoxesEachDirection(0)*mNumBoxesEachDirection(1)*k,
00127          *
00128          * while in 2D, box_index is related to (i,j) by
00129          *
00130          * box_index = i + mNumBoxesEachDirection(0)*j
00131          *
00132          * and in 1D we simply have box_index = i.
00133          */
00134         c_vector<unsigned, DIM+1> current_box_indices;
00135         current_box_indices[0] = 0;
00136 
00137         for (unsigned i=0; i<DIM; i++)
00138         {
00139             unsigned temp = 0;
00140             for (unsigned j=1; j<i; j++)
00141             {
00142                 temp += coefficients[j]*current_box_indices[j-1];
00143             }
00144             current_box_indices[i+1] = (box_index%coefficients[i+1] - temp)/coefficients[i];
00145         }
00146 
00147         /*
00148          * We now use the information stores in current_box_indices to construct the
00149          * Box, which we add to mBoxes.
00150          */
00151         c_vector<double, 2*DIM> box_coords;
00152         for (unsigned l=0; l<DIM; l++)
00153         {
00154             box_coords(2*l) = domainSize(2*l) + current_box_indices(l+1)*boxWidth;
00155             box_coords(2*l+1) = domainSize(2*l) + (current_box_indices(l+1)+1)*boxWidth;
00156         }
00157 
00158         Box<DIM> new_box(box_coords);
00159         mBoxes.push_back(new_box);
00160     }
00161 
00162     // Check that we have the correct number of boxes
00163     assert(num_boxes == mBoxes.size());
00164 }
00165 
00166 template<unsigned DIM>
00167 unsigned BoxCollection<DIM>::CalculateContainingBox(Node<DIM>* pNode)
00168 {
00169     // Get the location of the node
00170     c_vector<double, DIM> location = pNode->rGetLocation();
00171     return CalculateContainingBox(location);
00172 }
00173 
00174 
00175 template<unsigned DIM>
00176 unsigned BoxCollection<DIM>::CalculateContainingBox(c_vector<double, DIM>& rLocation)
00177 {
00178     // The node must lie inside the boundary of the box collection
00179     for (unsigned i=0; i<DIM; i++)
00180     {
00181         if ( (rLocation[i] < mDomainSize(2*i)) || (rLocation[i] > mDomainSize(2*i+1)) )
00182         {
00183             EXCEPTION("The point provided is outside all of the boxes");
00184         }
00185     }
00186 
00187     // Compute the containing box index in each dimension
00188     c_vector<unsigned, DIM> containing_box_indices;
00189     for (unsigned i=0; i<DIM; i++)
00190     {
00191         containing_box_indices[i] = (unsigned) floor((rLocation[i] - mDomainSize(2*i) + mFudge)/mBoxWidth);
00192     }
00193 
00194     // Use these to compute the index of the containing box
00195     unsigned containing_box_index = 0;
00196     for (unsigned i=0; i<DIM; i++)
00197     {
00198         unsigned temp = 1;
00199         for (unsigned j=0; j<i; j++)
00200         {
00201             temp *= mNumBoxesEachDirection(j);
00202         }
00203         containing_box_index += temp*containing_box_indices[i];
00204     }
00205 
00206     // This index must be less than the number of boxes
00207     assert(containing_box_index < mBoxes.size());
00208 
00209     return containing_box_index;
00210 }
00211 
00212 template<unsigned DIM>
00213 Box<DIM>& BoxCollection<DIM>::rGetBox(unsigned boxIndex)
00214 {
00215     assert(boxIndex < mBoxes.size());
00216     return mBoxes[boxIndex];
00217 }
00218 
00219 template<unsigned DIM>
00220 unsigned BoxCollection<DIM>::GetNumBoxes()
00221 {
00222     return mBoxes.size();
00223 }
00224 
00225 template<unsigned DIM>
00226 void BoxCollection<DIM>::SetupLocalBoxesHalfOnly()
00227 {
00228     switch (DIM)
00229     {
00230         case 1:
00231         {
00232             // We only need to look for neighbours in the current and successive boxes
00233             mLocalBoxes.clear();
00234             for (unsigned box_index=0; box_index<mBoxes.size(); box_index++)
00235             {
00236                 std::set<unsigned> local_boxes;
00237 
00238                 // Insert the current box
00239                 local_boxes.insert(box_index);
00240 
00241                 // If we're not at the right-most box, then insert the box to the right
00242                 if (box_index < mNumBoxesEachDirection(0)-1)
00243                 {
00244                     local_boxes.insert(box_index+1);
00245                 }
00246                 mLocalBoxes.push_back(local_boxes);
00247             }
00248             break;
00249         }
00250         case 2:
00251         {
00252             // We only need to look for neighbours in the current box and half the neighbouring boxes
00253             mLocalBoxes.clear();
00254             for (unsigned box_index=0; box_index<mBoxes.size(); box_index++)
00255             {
00256                 std::set<unsigned> local_boxes;
00257 
00258                 // Insert the current box
00259                 local_boxes.insert(box_index);
00260 
00261                 // If we're not on the top-most row, then insert the box above
00262                 if (box_index < mBoxes.size() - mNumBoxesEachDirection(0))
00263                 {
00264                     local_boxes.insert(box_index + mNumBoxesEachDirection(0));
00265 
00266                     // If we're also not on the left-most column, then insert the box above-left
00267                     if (box_index % mNumBoxesEachDirection(0) != 0)
00268                     {
00269                         local_boxes.insert(box_index + mNumBoxesEachDirection(0) - 1);
00270                     }
00271                 }
00272                 // If we're not on the right-most column, then insert the box to the right
00273                 if (box_index % mNumBoxesEachDirection(0) != mNumBoxesEachDirection(0)-1)
00274                 {
00275                     local_boxes.insert(box_index + 1);
00276 
00277                     // If we're also not on the top-most row, then insert the box above-right
00278                     if (box_index < mBoxes.size() - mNumBoxesEachDirection(0))
00279                     {
00280                         local_boxes.insert(box_index + mNumBoxesEachDirection(0) + 1);
00281                     }
00282                 }
00283 
00284                 mLocalBoxes.push_back(local_boxes);
00285             }
00286             break;
00287         }
00288         case 3:
00289         {
00290             // We only need to look for neighbours in the current box and half the neighbouring boxes
00291             mLocalBoxes.clear();
00292             unsigned num_boxes_xy = mNumBoxesEachDirection(0)*mNumBoxesEachDirection(1);
00293 
00294             for (unsigned box_index=0; box_index<mBoxes.size(); box_index++)
00295             {
00296                 std::set<unsigned> local_boxes;
00297 
00298                 // Insert the current box
00299                 local_boxes.insert(box_index);
00300 
00301                 // If we're not on the far face (y max), then insert the far box
00302                 if (box_index % num_boxes_xy < num_boxes_xy - mNumBoxesEachDirection(0))
00303                 {
00304                     local_boxes.insert(box_index + mNumBoxesEachDirection(0));
00305 
00306                     // If we're also not on the left face (x min), then insert the box to the left
00307                     if (box_index % mNumBoxesEachDirection(0) != 0)
00308                     {
00309                         local_boxes.insert(box_index + mNumBoxesEachDirection(0) - 1);
00310                     }
00311                 }
00312                 // If we're not on the right face (x max), then insert the box to the right
00313                 if (box_index % mNumBoxesEachDirection(0) != mNumBoxesEachDirection(0)-1)
00314                 {
00315                     local_boxes.insert(box_index + 1);
00316 
00317                     // If we're also not on the far face (y max) row, then insert the box to the far-right
00318                     if (box_index % num_boxes_xy < num_boxes_xy - mNumBoxesEachDirection(0))
00319                     {
00320                         local_boxes.insert(box_index + mNumBoxesEachDirection(0) + 1);
00321                     }
00322                 }
00323                 // If we're not on the top face (z max), then insert the box above
00324                 if (box_index < mBoxes.size() - num_boxes_xy)
00325                 {
00326                     local_boxes.insert(box_index + num_boxes_xy);
00327 
00328                     // If we're also not on the far face (y max), then insert the above-far box
00329                     if (box_index % num_boxes_xy < num_boxes_xy - mNumBoxesEachDirection(0))
00330                     {
00331                         local_boxes.insert(box_index + num_boxes_xy + mNumBoxesEachDirection(0));
00332 
00333                         // If we're also not on the left face (x min), then insert the box to the above-left
00334                         if (box_index % mNumBoxesEachDirection(0) != 0)
00335                         {
00336                             local_boxes.insert(box_index + num_boxes_xy + mNumBoxesEachDirection(0) - 1);
00337                         }
00338                     }
00339                     // If we're also not on the right face (x max), then insert the box to the above-right
00340                     if (box_index % mNumBoxesEachDirection(0) != mNumBoxesEachDirection(0)-1)
00341                     {
00342                         local_boxes.insert(box_index + num_boxes_xy + 1);
00343 
00344                         // If we're also not on the far face (y max) row, then insert the box to the above-far-right
00345                         if (box_index % num_boxes_xy < num_boxes_xy - mNumBoxesEachDirection(0))
00346                         {
00347                             local_boxes.insert(box_index + num_boxes_xy + mNumBoxesEachDirection(0) + 1);
00348                         }
00349                     }
00350                 }
00351                 // If we're not on the bottom face (z min), then insert the box above
00352                 if (box_index >= num_boxes_xy)
00353                 {
00354                     local_boxes.insert(box_index - num_boxes_xy);
00355 
00356                     // If we're also not on the far face (y max), then insert the below-far box
00357                     if (box_index % num_boxes_xy < num_boxes_xy - mNumBoxesEachDirection(0))
00358                     {
00359                         local_boxes.insert(box_index - num_boxes_xy + mNumBoxesEachDirection(0));
00360 
00361                         // If we're also not on the left face (x min), then insert the box to the below-left
00362                         if (box_index % mNumBoxesEachDirection(0) != 0)
00363                         {
00364                             local_boxes.insert(box_index - num_boxes_xy + mNumBoxesEachDirection(0) - 1);
00365                         }
00366                     }
00367                     // If we're also not on the right face (x max), then insert the box to the below-right
00368                     if (box_index % mNumBoxesEachDirection(0) != mNumBoxesEachDirection(0)-1)
00369                     {
00370                         local_boxes.insert(box_index - num_boxes_xy + 1);
00371 
00372                         // If we're also not on the far face (y max) row, then insert the box to the below-far-right
00373                         if (box_index % num_boxes_xy < num_boxes_xy - mNumBoxesEachDirection(0))
00374                         {
00375                             local_boxes.insert(box_index - num_boxes_xy + mNumBoxesEachDirection(0) + 1);
00376                         }
00377                     }
00378                 }
00379                 mLocalBoxes.push_back(local_boxes);
00380             }
00381             break;
00382         }
00383         default:
00384             NEVER_REACHED;
00385     }
00386 }
00387 
00388 
00389 
00390 template<unsigned DIM>
00391 void BoxCollection<DIM>::SetupAllLocalBoxes()
00392 {
00393     switch (DIM)
00394     {
00395         case 1:
00396         {
00397             for (unsigned i=0; i<mBoxes.size(); i++)
00398             {
00399                 std::set<unsigned> local_boxes;
00400 
00401                 local_boxes.insert(i);
00402 
00403                 // add the two neighbours
00404                 if (i!=0)
00405                 {
00406                     local_boxes.insert(i-1);
00407                 }
00408                 if (i+1 != mNumBoxesEachDirection(0))
00409                 {
00410                     local_boxes.insert(i+1);
00411                 }
00412 
00413                 mLocalBoxes.push_back(local_boxes);
00414             }
00415             break;
00416         }
00417         case 2:
00418         {
00419             mLocalBoxes.clear();
00420 
00421             unsigned M = mNumBoxesEachDirection(0);
00422             unsigned N = mNumBoxesEachDirection(1);
00423 
00424             std::vector<bool> is_xmin(N*M); // far left
00425             std::vector<bool> is_xmax(N*M); // far right
00426             std::vector<bool> is_ymin(N*M); // bottom
00427             std::vector<bool> is_ymax(N*M); // top
00428 
00429             for (unsigned i=0; i<M*N; i++)
00430             {
00431                 is_xmin[i] = (i%M==0);
00432                 is_xmax[i] = ((i+1)%M==0);
00433                 is_ymin[i] = (i%(M*N)<M);
00434                 is_ymax[i] = (i%(M*N)>=(N-1)*M);
00435             }
00436 
00437             for (unsigned i=0; i<mBoxes.size(); i++)
00438             {
00439                 std::set<unsigned> local_boxes;
00440 
00441                 local_boxes.insert(i);
00442 
00443                 // add the box to the left
00444                 if (!is_xmin[i])
00445                 {
00446                     local_boxes.insert(i-1);
00447                 }
00448 
00449                 // add the box to the right
00450                 if (!is_xmax[i])
00451                 {
00452                     local_boxes.insert(i+1);
00453                 }
00454 
00455                 // add the one below
00456                 if (!is_ymin[i])
00457                 {
00458                     local_boxes.insert(i-M);
00459                 }
00460 
00461                 // add the one above
00462                 if (!is_ymax[i])
00463                 {
00464                     local_boxes.insert(i+M);
00465                 }
00466 
00467                 // add the four corner boxes
00468 
00469                 if ( (!is_xmin[i]) && (!is_ymin[i]) )
00470                 {
00471                     local_boxes.insert(i-1-M);
00472                 }
00473 
00474                 if ( (!is_xmin[i]) && (!is_ymax[i]) )
00475                 {
00476                     local_boxes.insert(i-1+M);
00477                 }
00478 
00479                 if ( (!is_xmax[i]) && (!is_ymin[i]) )
00480                 {
00481                     local_boxes.insert(i+1-M);
00482                 }
00483 
00484                 if ( (!is_xmax[i]) && (!is_ymax[i]) )
00485                 {
00486                     local_boxes.insert(i+1+M);
00487                 }
00488 
00489                 mLocalBoxes.push_back(local_boxes);
00490             }
00491             break;
00492         }
00493         case 3:
00494         {
00495             mLocalBoxes.clear();
00496 
00497             unsigned M = mNumBoxesEachDirection(0);
00498             unsigned N = mNumBoxesEachDirection(1);
00499             unsigned P = mNumBoxesEachDirection(2);
00500 
00501             std::vector<bool> is_xmin(N*M*P); // far left
00502             std::vector<bool> is_xmax(N*M*P); // far right
00503             std::vector<bool> is_ymin(N*M*P); // nearest
00504             std::vector<bool> is_ymax(N*M*P); // furthest
00505             std::vector<bool> is_zmin(N*M*P); // bottom layer
00506             std::vector<bool> is_zmax(N*M*P); // top layer
00507 
00508             for (unsigned i=0; i<M*N*P; i++)
00509             {
00510                 is_xmin[i] = (i%M==0);
00511                 is_xmax[i] = ((i+1)%M==0);
00512                 is_ymin[i] = (i%(M*N)<M);
00513                 is_ymax[i] = (i%(M*N)>=(N-1)*M);
00514                 is_zmin[i] = (i<M*N);
00515                 is_zmax[i] = (i>=M*N*(P-1));
00516             }
00517 
00518             for (unsigned i=0; i<mBoxes.size(); i++)
00519             {
00520                 std::set<unsigned> local_boxes;
00521 
00522                 // add itself as a local box
00523                 local_boxes.insert(i);
00524 
00525                 // now add all 26 other neighbours.....
00526 
00527                 // add the box left
00528                 if (!is_xmin[i])
00529                 {
00530                     local_boxes.insert(i-1);
00531 
00532                     // plus some others towards the left
00533                     if (!is_ymin[i])
00534                     {
00535                         local_boxes.insert(i-1-M);
00536                     }
00537 
00538                     if (!is_ymax[i])
00539                     {
00540                         local_boxes.insert(i-1+M);
00541                     }
00542 
00543                     if (!is_zmin[i])
00544                     {
00545                         local_boxes.insert(i-1-M*N);
00546                     }
00547 
00548                     if (!is_zmax[i])
00549                     {
00550                         local_boxes.insert(i-1+M*N);
00551                     }
00552                 }
00553 
00554                 // add the box to the right
00555                 if (!is_xmax[i])
00556                 {
00557                     local_boxes.insert(i+1);
00558 
00559                     // plus some others towards the right
00560                     if (!is_ymin[i])
00561                     {
00562                         local_boxes.insert(i+1-M);
00563                     }
00564 
00565                     if (!is_ymax[i])
00566                     {
00567                         local_boxes.insert(i+1+M);
00568                     }
00569 
00570                     if (!is_zmin[i])
00571                     {
00572                         local_boxes.insert(i+1-M*N);
00573                     }
00574 
00575                     if (!is_zmax[i])
00576                     {
00577                         local_boxes.insert(i+1+M*N);
00578                     }
00579                 }
00580 
00581                 // add the boxes next along the y axis
00582                 if (!is_ymin[i])
00583                 {
00584                     local_boxes.insert(i-M);
00585 
00586                     // and more in this plane
00587                     if (!is_zmin[i])
00588                     {
00589                         local_boxes.insert(i-M-M*N);
00590                     }
00591 
00592                     if (!is_zmax[i])
00593                     {
00594                         local_boxes.insert(i-M+M*N);
00595                     }
00596                 }
00597 
00598                 // add the boxes next along the y axis
00599                 if (!is_ymax[i])
00600                 {
00601                     local_boxes.insert(i+M);
00602 
00603                     // and more in this plane
00604                     if (!is_zmin[i])
00605                     {
00606                         local_boxes.insert(i+M-M*N);
00607                     }
00608 
00609                     if (!is_zmax[i])
00610                     {
00611                         local_boxes.insert(i+M+M*N);
00612                     }
00613                 }
00614 
00615                 // add the box directly above
00616                 if (!is_zmin[i])
00617                 {
00618                     local_boxes.insert(i-N*M);
00619                 }
00620 
00621                 // add the box directly below
00622                 if (!is_zmax[i])
00623                 {
00624                     local_boxes.insert(i+N*M);
00625                 }
00626 
00627                 // finally, the 8 corners are left
00628 
00629                 if ( (!is_xmin[i]) && (!is_ymin[i]) && (!is_zmin[i]) )
00630                 {
00631                     local_boxes.insert(i-1-M-M*N);
00632                 }
00633 
00634                 if ( (!is_xmin[i]) && (!is_ymin[i]) && (!is_zmax[i]) )
00635                 {
00636                     local_boxes.insert(i-1-M+M*N);
00637                 }
00638 
00639                 if ( (!is_xmin[i]) && (!is_ymax[i]) && (!is_zmin[i]) )
00640                 {
00641                     local_boxes.insert(i-1+M-M*N);
00642                 }
00643 
00644                 if ( (!is_xmin[i]) && (!is_ymax[i]) && (!is_zmax[i]) )
00645                 {
00646                     local_boxes.insert(i-1+M+M*N);
00647                 }
00648 
00649                 if ( (!is_xmax[i]) && (!is_ymin[i]) && (!is_zmin[i]) )
00650                 {
00651                     local_boxes.insert(i+1-M-M*N);
00652                 }
00653 
00654                 if ( (!is_xmax[i]) && (!is_ymin[i]) && (!is_zmax[i]) )
00655                 {
00656                     local_boxes.insert(i+1-M+M*N);
00657                 }
00658 
00659                 if ( (!is_xmax[i]) && (!is_ymax[i]) && (!is_zmin[i]) )
00660                 {
00661                     local_boxes.insert(i+1+M-M*N);
00662                 }
00663 
00664                 if ( (!is_xmax[i]) && (!is_ymax[i]) && (!is_zmax[i]) )
00665                 {
00666                     local_boxes.insert(i+1+M+M*N);
00667                 }
00668 
00669                 mLocalBoxes.push_back(local_boxes);
00670             }
00671             break;
00672         }
00673         default:
00674             NEVER_REACHED;
00675     }
00676 }
00677 
00678 template<unsigned DIM>
00679 std::set<unsigned> BoxCollection<DIM>::GetLocalBoxes(unsigned boxIndex)
00680 {
00681     assert(boxIndex < mLocalBoxes.size());
00682     return mLocalBoxes[boxIndex];
00683 }
00684 
00685 template<unsigned DIM>
00686 void BoxCollection<DIM>::CalculateNodePairs(std::vector<Node<DIM>*>& rNodes, std::set<std::pair<Node<DIM>*, Node<DIM>*> >& rNodePairs, std::map<unsigned, std::set<unsigned> >& rNodeNeighbours)
00687 {
00688     rNodePairs.clear();
00689     rNodeNeighbours.clear();
00690 
00691     // Create an empty set of neighbours for each node
00692     for (unsigned node_index=0; node_index<rNodes.size(); node_index++)
00693     {
00694         rNodeNeighbours[node_index] = std::set<unsigned>();
00695     }
00696 
00697     for (unsigned node_index=0; node_index<rNodes.size(); node_index++)
00698         {
00699         // Get the box containing this node
00700         unsigned box_index = CalculateContainingBox(rNodes[node_index]);
00701 
00702         // Get the local boxes to this node
00703         std::set<unsigned> local_boxes_indices = GetLocalBoxes(box_index);
00704 
00705         // Loop over all the local boxes
00706         for (std::set<unsigned>::iterator box_iter = local_boxes_indices.begin();
00707              box_iter != local_boxes_indices.end();
00708              box_iter++)
00709         {
00710             // Get the set of nodes contained in this box
00711             std::set< Node<DIM>* >& r_contained_nodes = mBoxes[*box_iter].rGetNodesContained();
00712 
00713             // Loop over these nodes
00714             for (typename std::set<Node<DIM>*>::iterator node_iter = r_contained_nodes.begin();
00715                  node_iter != r_contained_nodes.end();
00716                  ++node_iter)
00717             {
00718                 // Get the index of the other node
00719                 unsigned other_node_index = (*node_iter)->GetIndex();
00720 
00721                 // If we're in the same box, then take care not to store the node pair twice
00722                 if (*box_iter == box_index)
00723                 {
00724                     if (other_node_index > node_index)
00725                     {
00726                         rNodePairs.insert(std::pair<Node<DIM>*, Node<DIM>*>(rNodes[node_index], rNodes[other_node_index]));
00727                         rNodeNeighbours[node_index].insert(other_node_index);
00728                         rNodeNeighbours[other_node_index].insert(node_index);
00729                     }
00730                 }
00731                 else
00732                 {
00733                     rNodePairs.insert(std::pair<Node<DIM>*, Node<DIM>*>(rNodes[node_index], rNodes[other_node_index]));
00734                     rNodeNeighbours[node_index].insert(other_node_index);
00735                     rNodeNeighbours[other_node_index].insert(node_index);
00736                 }
00737             }
00738         }
00739     }
00740 }
00741 
00743 // Explicit instantiation
00745 
00746 template class Box<1>;
00747 template class Box<2>;
00748 template class Box<3>;
00749 template class BoxCollection<1>;
00750 template class BoxCollection<2>;
00751 template class BoxCollection<3>;