Palabos  Version 1.0
blockLattice3D.hh
Go to the documentation of this file.
00001 /* This file is part of the Palabos library.
00002  *
00003  * Copyright (C) 2011 FlowKit Sarl
00004  * Avenue de Chailly 23
00005  * 1012 Lausanne, Switzerland
00006  * E-mail contact: contact@flowkit.com
00007  *
00008  * The most recent release of Palabos can be downloaded at 
00009  * <http://www.palabos.org/>
00010  *
00011  * The library Palabos is free software: you can redistribute it and/or
00012  * modify it under the terms of the GNU Affero General Public License as
00013  * published by the Free Software Foundation, either version 3 of the
00014  * License, or (at your option) any later version.
00015  *
00016  * The library is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU Affero General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Affero General Public License
00022  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00023 */
00024 
00028 #ifndef BLOCK_LATTICE_3D_HH
00029 #define BLOCK_LATTICE_3D_HH
00030 
00031 #include "atomicBlock/blockLattice3D.h"
00032 #include "core/dynamics.h"
00033 #include "core/cell.h"
00034 #include "latticeBoltzmann/latticeTemplates.h"
00035 #include "latticeBoltzmann/indexTemplates.h"
00036 #include "core/util.h"
00037 #include "core/latticeStatistics.h"
00038 #include "core/dynamicsIdentifiers.h"
00039 #include "core/plbProfiler.h"
00040 #include <algorithm>
00041 #include <typeinfo>
00042 #include <cmath>
00043 
00044 namespace plb {
00045 
00046 // Class BlockLattice3D /////////////////////////
00047 
00052 template<typename T, template<typename U> class Descriptor>
00053 BlockLattice3D<T,Descriptor>::BlockLattice3D (
00054         plint nx_, plint ny_, plint nz_,
00055         Dynamics<T,Descriptor>* backgroundDynamics_ )
00056     : AtomicBlock3D(nx_, ny_, nz_),
00057       backgroundDynamics(backgroundDynamics_),
00058       dataTransfer(*this)
00059 {
00060     plint nx = this->getNx();
00061     plint ny = this->getNy();
00062     plint nz = this->getNz();
00063     // Allocate memory, and initialize dynamics.
00064     allocateAndInitialize();
00065     for (plint iX=0; iX<nx; ++iX) {
00066         for (plint iY=0; iY<ny; ++iY) {
00067             for (plint iZ=0; iZ<nz; ++iZ) {
00068                 grid[iX][iY][iZ].attributeDynamics(backgroundDynamics);
00069             }
00070         }
00071     }
00072     // Attribute default value to the standard statistics (average uSqr,
00073     //   max uSqr, average rho). These have previously been subscribed
00074     //   in the constructor of BlockLatticeBase3D.
00075     std::vector<double> average, sum, max;
00076     std::vector<plint> intSum;
00077     average.push_back(Descriptor<double>::rhoBar((T)1));
00078                             // default average rho to 1, to avoid division by
00079                             // zero in constRhoBGK and related models
00080     average.push_back(0.);  // default average uSqr to 0
00081     max.push_back(0.);      // default max uSqr to 0
00082     plint numCells = 1;     // pretend fictitious cell to evaluate statistics
00083     this->getInternalStatistics().evaluate (average, sum, max, intSum, numCells);
00084 }
00085 
00090 template<typename T, template<typename U> class Descriptor>
00091 BlockLattice3D<T,Descriptor>::~BlockLattice3D()
00092 {
00093     releaseMemory();
00094 }
00095 
00101 template<typename T, template<typename U> class Descriptor>
00102 BlockLattice3D<T,Descriptor>::BlockLattice3D(BlockLattice3D<T,Descriptor> const& rhs)
00103     : BlockLatticeBase3D<T,Descriptor>(rhs),
00104       AtomicBlock3D(rhs),
00105       backgroundDynamics(rhs.backgroundDynamics->clone()),
00106       dataTransfer(*this)
00107 {
00108     plint nx = this->getNx();
00109     plint ny = this->getNy();
00110     plint nz = this->getNz();
00111     allocateAndInitialize();
00112     for (plint iX=0; iX<nx; ++iX) {
00113         for (plint iY=0; iY<ny; ++iY) {
00114             for (plint iZ=0; iZ<nz; ++iZ) {
00115                 Cell<T,Descriptor>& cell = grid[iX][iY][iZ];
00116                 // Assign cell from rhs
00117                 cell = rhs.grid[iX][iY][iZ];
00118                 // Get an independent clone of the dynamics,
00119                 //   or assign backgroundDynamics
00120                 if (&cell.getDynamics()==rhs.backgroundDynamics) {
00121                     cell.attributeDynamics(backgroundDynamics);
00122                 }
00123                 else {
00124                     cell.attributeDynamics(cell.getDynamics().clone());
00125                 }
00126             }
00127         }
00128     }
00129 }
00130 
00137 template<typename T, template<typename U> class Descriptor>
00138 BlockLattice3D<T,Descriptor>& BlockLattice3D<T,Descriptor>::operator= (
00139         BlockLattice3D<T,Descriptor> const& rhs )
00140 {
00141     BlockLattice3D<T,Descriptor> tmp(rhs);
00142     swap(tmp);
00143     return *this;
00144 }
00145 
00149 template<typename T, template<typename U> class Descriptor>
00150 void BlockLattice3D<T,Descriptor>::swap(BlockLattice3D& rhs) {
00151     BlockLatticeBase3D<T,Descriptor>::swap(rhs);
00152     AtomicBlock3D::swap(rhs);
00153     std::swap(backgroundDynamics, rhs.backgroundDynamics);
00154     std::swap(rawData, rhs.rawData);
00155     std::swap(grid, rhs.grid);
00156 }
00157 
00158 template<typename T, template<typename U> class Descriptor>
00159 void BlockLattice3D<T,Descriptor>::specifyStatisticsStatus(Box3D domain, bool status) {
00160     // Make sure domain is contained within current lattice
00161     PLB_PRECONDITION( contained(domain, this->getBoundingBox()) );
00162 
00163     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00164         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00165             for (plint iZ=domain.z0; iZ<=domain.z1; ++iZ) {
00166                 grid[iX][iY][iZ].specifyStatisticsStatus(status);
00167             }
00168         }
00169     }
00170 }
00171 
00172 template<typename T, template<typename U> class Descriptor>
00173 void BlockLattice3D<T,Descriptor>::collide(Box3D domain) {
00174     // Make sure domain is contained within current lattice
00175     PLB_PRECONDITION( contained(domain, this->getBoundingBox()) );
00176 
00177     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00178         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00179             for (plint iZ=domain.z0; iZ<=domain.z1; ++iZ) {
00180                 grid[iX][iY][iZ].collide(this->getInternalStatistics());
00181                 grid[iX][iY][iZ].revert();
00182             }
00183         }
00184     }
00185 }
00186 
00188 template<typename T, template<typename U> class Descriptor>
00189 void BlockLattice3D<T,Descriptor>::collide() {
00190     collide(this->getBoundingBox());
00191 }
00192 
00202 template<typename T, template<typename U> class Descriptor>
00203 void BlockLattice3D<T,Descriptor>::stream(Box3D domain) {
00204     // Make sure domain is contained within current lattice
00205     PLB_PRECONDITION( contained(domain, this->getBoundingBox()) );
00206 
00207     static const plint vicinity = Descriptor<T>::vicinity;
00208 
00209     bulkStream(Box3D(domain.x0+vicinity,domain.x1-vicinity,
00210                      domain.y0+vicinity,domain.y1-vicinity,
00211                      domain.z0+vicinity,domain.z1-vicinity) );
00212 
00213     boundaryStream(domain, Box3D(domain.x0,domain.x0+vicinity-1,
00214                                  domain.y0,domain.y1,
00215                                  domain.z0,domain.z1) );
00216     boundaryStream(domain, Box3D(domain.x1-vicinity-1,domain.x1,
00217                                  domain.y0,domain.y1,
00218                                  domain.z0,domain.z1) );
00219     boundaryStream(domain, Box3D(domain.x0+vicinity,domain.x1-vicinity,
00220                                  domain.y0,domain.y0+vicinity-1,
00221                                  domain.z0,domain.z1) );
00222     boundaryStream(domain, Box3D(domain.x0+vicinity,domain.x1-vicinity,
00223                                  domain.y1-vicinity+1,domain.y1,
00224                                  domain.z0,domain.z1) );
00225     boundaryStream(domain, Box3D(domain.x0+vicinity,domain.x1-vicinity,
00226                                  domain.y0+vicinity,domain.y1-vicinity,
00227                                  domain.z0,domain.z0+vicinity-1) );
00228     boundaryStream(domain, Box3D(domain.x0+vicinity,domain.x1-vicinity,
00229                                  domain.y0+vicinity,domain.y1-vicinity,
00230                                  domain.z1-vicinity+1,domain.z1) );
00231 }
00232 
00236 template<typename T, template<typename U> class Descriptor>
00237 void BlockLattice3D<T,Descriptor>::stream()
00238 {
00239     stream(this->getBoundingBox());
00240 
00241     implementPeriodicity();
00242 
00243     this->executeInternalProcessors();
00244     this->evaluateStatistics();
00245     this->incrementTime();
00246 }
00247 
00252 template<typename T, template<typename U> class Descriptor>
00253 void BlockLattice3D<T,Descriptor>::collideAndStream(Box3D domain) {
00254     // Make sure domain is contained within current lattice
00255     PLB_PRECONDITION( contained(domain, this->getBoundingBox()) );
00256 
00257     global::profiler().start("collStream");
00258     global::profiler().increment("collStreamCells", domain.nCells());
00259 
00260     static const plint vicinity = Descriptor<T>::vicinity;
00261 
00262     // First, do the collision on cells within a boundary envelope of width
00263     // equal to the range of the lattice vectors (e.g. 1 for D3Q19)
00264     collide(Box3D(domain.x0,domain.x0+vicinity-1,
00265                   domain.y0,domain.y1,
00266                   domain.z0,domain.z1) );
00267     collide(Box3D(domain.x1-vicinity+1,domain.x1,
00268                   domain.y0,domain.y1,
00269                   domain.z0,domain.z1) );
00270     collide(Box3D(domain.x0+vicinity,domain.x1-vicinity,
00271                   domain.y0,domain.y0+vicinity-1,
00272                   domain.z0,domain.z1) );
00273     collide(Box3D(domain.x0+vicinity,domain.x1-vicinity,
00274                   domain.y1-vicinity+1,domain.y1,
00275                   domain.z0,domain.z1) );
00276     collide(Box3D(domain.x0+vicinity,domain.x1-vicinity,
00277                   domain.y0+vicinity,domain.y1-vicinity,
00278                   domain.z0,domain.z0+vicinity-1) );
00279     collide(Box3D(domain.x0+vicinity,domain.x1-vicinity,
00280                   domain.y0+vicinity,domain.y1-vicinity,
00281                   domain.z1-vicinity+1,domain.z1) );
00282 
00283     // Then, do the efficient collideAndStream algorithm in the bulk,
00284     // excluding the envelope (this is efficient because there is no
00285     // if-then-else statement within the loop, given that the boundary
00286     // region is excluded)
00287     bulkCollideAndStream(Box3D(domain.x0+vicinity,domain.x1-vicinity,
00288                                domain.y0+vicinity,domain.y1-vicinity,
00289                                domain.z0+vicinity,domain.z1-vicinity) );
00290 
00291     // Finally, do streaming in the boundary envelope to conclude the
00292     // collision-stream cycle
00293     boundaryStream(domain, Box3D(domain.x0,domain.x0+vicinity-1,
00294                                  domain.y0,domain.y1,
00295                                  domain.z0,domain.z1) );
00296     boundaryStream(domain, Box3D(domain.x1-vicinity+1,domain.x1,
00297                                  domain.y0,domain.y1,
00298                                  domain.z0,domain.z1) );
00299     boundaryStream(domain, Box3D(domain.x0+vicinity,domain.x1-vicinity,
00300                                  domain.y0,domain.y0+vicinity-1,
00301                                  domain.z0,domain.z1) );
00302     boundaryStream(domain, Box3D(domain.x0+vicinity,domain.x1-vicinity,
00303                                  domain.y1-vicinity+1,domain.y1,
00304                                  domain.z0,domain.z1) );
00305     boundaryStream(domain, Box3D(domain.x0+vicinity,domain.x1-vicinity,
00306                                  domain.y0+vicinity,domain.y1-vicinity,
00307                                  domain.z0,domain.z0+vicinity-1) );
00308     boundaryStream(domain, Box3D(domain.x0+vicinity,domain.x1-vicinity,
00309                                  domain.y0+vicinity,domain.y1-vicinity,
00310                                  domain.z1-vicinity+1,domain.z1) );
00311     global::profiler().stop("collStream");
00312 }
00313 
00317 template<typename T, template<typename U> class Descriptor>
00318 void BlockLattice3D<T,Descriptor>::collideAndStream() {
00319     collideAndStream(this->getBoundingBox());
00320 
00321     implementPeriodicity();
00322 
00323     this->executeInternalProcessors();
00324     this->evaluateStatistics();
00325     this->incrementTime();
00326 }
00327 
00328 template<typename T, template<typename U> class Descriptor>
00329 void BlockLattice3D<T,Descriptor>::incrementTime() {
00330     this->getTimeCounter().incrementTime();
00331 }
00332 
00333 template<typename T, template<typename U> class Descriptor>
00334 void BlockLattice3D<T,Descriptor>::allocateAndInitialize() {
00335     this->getInternalStatistics().subscribeAverage(); // Subscribe average rho-bar
00336     this->getInternalStatistics().subscribeAverage(); // Subscribe average uSqr
00337     this->getInternalStatistics().subscribeMax();     // Subscribe max uSqr
00338 
00339     plint nx = this->getNx();
00340     plint ny = this->getNy();
00341     plint nz = this->getNz();
00342     rawData = new Cell<T,Descriptor> [nx*ny*nz];
00343     grid    = new Cell<T,Descriptor>** [nx];
00344     for (plint iX=0; iX<nx; ++iX) {
00345         grid[iX] = new Cell<T,Descriptor>* [ny];
00346         for (plint iY=0; iY<ny; ++iY) {
00347             grid[iX][iY] = rawData + nz*(iY+ny*iX);
00348         }
00349     }
00350 }
00351 
00352 template<typename T, template<typename U> class Descriptor>
00353 void BlockLattice3D<T,Descriptor>::releaseMemory() {
00354     plint nx = this->getNx();
00355     plint ny = this->getNy();
00356     plint nz = this->getNz();
00357     for (plint iX=0; iX<nx; ++iX) {
00358         for (plint iY=0; iY<ny; ++iY) {
00359             for (plint iZ=0; iZ<nz; ++iZ) {
00360                 Dynamics<T,Descriptor>* dynamics = &grid[iX][iY][iZ].getDynamics();
00361                 if (dynamics != backgroundDynamics) {
00362                     delete dynamics;
00363                 }
00364             }
00365         }
00366     }
00367     delete backgroundDynamics;
00368     delete [] rawData;
00369     for (plint iX=0; iX<nx; ++iX) {
00370         delete [] grid[iX];
00371     }
00372     delete [] grid;
00373 }
00374 
00375 template<typename T, template<typename U> class Descriptor>
00376 void BlockLattice3D<T,Descriptor>::attributeDynamics (
00377         plint iX, plint iY, plint iZ, Dynamics<T,Descriptor>* dynamics )
00378 {
00379     Dynamics<T,Descriptor>* previousDynamics = &grid[iX][iY][iZ].getDynamics();
00380     if (previousDynamics != backgroundDynamics) {
00381         delete previousDynamics;
00382     }
00383     grid[iX][iY][iZ].attributeDynamics(dynamics);
00384 }
00385 
00386 template<typename T, template<typename U> class Descriptor>
00387 Dynamics<T,Descriptor>& BlockLattice3D<T,Descriptor>::getBackgroundDynamics() {
00388     return *backgroundDynamics;
00389 }
00390 
00391 template<typename T, template<typename U> class Descriptor>
00392 Dynamics<T,Descriptor> const& BlockLattice3D<T,Descriptor>::getBackgroundDynamics() const {
00393     return *backgroundDynamics;
00394 }
00395 
00402 template<typename T, template<typename U> class Descriptor>
00403 void BlockLattice3D<T,Descriptor>::boundaryStream(Box3D bound, Box3D domain) {
00404     // Make sure bound is contained within current lattice
00405     PLB_PRECONDITION( contained(bound, this->getBoundingBox()) );
00406     // Make sure domain is contained within bound
00407     PLB_PRECONDITION( contained(domain, bound) );
00408 
00409     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00410         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00411             for (plint iZ=domain.z0; iZ<=domain.z1; ++iZ) {
00412                 for (plint iPop=1; iPop<=Descriptor<T>::q/2; ++iPop) {
00413                     plint nextX = iX + Descriptor<T>::c[iPop][0];
00414                     plint nextY = iY + Descriptor<T>::c[iPop][1];
00415                     plint nextZ = iZ + Descriptor<T>::c[iPop][2];
00416                     if ( nextX>=bound.x0 && nextX<=bound.x1 &&
00417                          nextY>=bound.y0 && nextY<=bound.y1 &&
00418                          nextZ>=bound.z0 && nextZ<=bound.z1 )
00419                     {
00420                         std::swap(grid[iX][iY][iZ][iPop+Descriptor<T>::q/2],
00421                                   grid[nextX][nextY][nextZ][iPop]);
00422                     }
00423                 }
00424             }
00425         }
00426     }
00427 }
00428 
00434 template<typename T, template<typename U> class Descriptor>
00435 void BlockLattice3D<T,Descriptor>::bulkStream(Box3D domain) {
00436     // Make sure domain is contained within current lattice
00437     PLB_PRECONDITION( contained(domain, this->getBoundingBox()) );
00438 
00439     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00440         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00441             for (plint iZ=domain.z0; iZ<=domain.z1; ++iZ) {
00442                 for (plint iPop=1; iPop<=Descriptor<T>::q/2; ++iPop) {
00443                     plint nextX = iX + Descriptor<T>::c[iPop][0];
00444                     plint nextY = iY + Descriptor<T>::c[iPop][1];
00445                     plint nextZ = iZ + Descriptor<T>::c[iPop][2];
00446                     std::swap(grid[iX][iY][iZ][iPop+Descriptor<T>::q/2],
00447                               grid[nextX][nextY][nextZ][iPop]);
00448                 }
00449             }
00450         }
00451     }
00452 }
00453 
00459 template<typename T, template<typename U> class Descriptor>
00460 void BlockLattice3D<T,Descriptor>::bulkCollideAndStream(Box3D domain) {
00461     // Make sure domain is contained within current lattice
00462     PLB_PRECONDITION( contained(domain, this->getBoundingBox()) );
00463 
00464     if (Descriptor<T>::vicinity==1) {
00465         // On nearest-neighbor lattice, use the cache-efficient
00466         //   version of collidAndStream.
00467         blockwiseBulkCollideAndStream(domain);
00468     }
00469     else {
00470         // Otherwise, use the straightforward implementation.
00471         //   Note that at some point, we should implement the cache-efficient
00472         //   version for extended lattices as well.
00473         linearBulkCollideAndStream(domain);
00474     }
00475 }
00476 
00477 
00481 template<typename T, template<typename U> class Descriptor>
00482 void BlockLattice3D<T,Descriptor>::linearBulkCollideAndStream(Box3D domain) {
00483     // Make sure domain is contained within current lattice
00484     PLB_PRECONDITION( contained(domain, this->getBoundingBox()) );
00485 
00486     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00487         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00488             for (plint iZ=domain.z0; iZ<=domain.z1; ++iZ) {
00489                 grid[iX][iY][iZ].collide(this->getInternalStatistics());
00490                 latticeTemplates<T,Descriptor>::swapAndStream3D(grid, iX, iY, iZ);
00491             }
00492         }
00493     }
00494 }
00495 
00496 
00501 template<typename T, template<typename U> class Descriptor>
00502 void BlockLattice3D<T,Descriptor>::blockwiseBulkCollideAndStream(Box3D domain) {
00503     // Make sure domain is contained within current lattice
00504     PLB_PRECONDITION( contained(domain, this->getBoundingBox()) );
00505 
00506     // For cache efficiency, memory is traversed block-wise. The three outer loops enumerate
00507     //   the blocks, whereas the three inner loops enumerate the cells inside each block.
00508     const plint blockSize = cachePolicy().getBlockSize();
00509     // Outer loops.
00510     for (plint outerX=domain.x0; outerX<=domain.x1; outerX+=blockSize) {
00511         for (plint outerY=domain.y0; outerY<=domain.y1+blockSize-1; outerY+=blockSize) {
00512             for (plint outerZ=domain.z0; outerZ<=domain.z1+2*(blockSize-1); outerZ+=blockSize) {
00513                 // Inner loops.
00514                 plint dx = 0;
00515                 for (plint innerX=outerX;
00516                      innerX <= std::min(outerX+blockSize-1, domain.x1);
00517                      ++innerX, ++dx)
00518                 {
00519                     // Y-index is shifted in negative direction at each x-increment. to ensure
00520                     //   that only post-collision cells are accessed during the swap-operation
00521                     //   of the streaming.
00522                     plint minY = outerY-dx;
00523                     plint maxY = minY+blockSize-1;
00524                     plint dy = 0;
00525                     for (plint innerY=std::max(minY,domain.y0);
00526                          innerY <= std::min(maxY, domain.y1);
00527                          ++innerY, ++dy)
00528                     {
00529                         // Z-index is shifted in negative direction at each x-increment. and at each
00530                         //    y-increment, to ensure that only post-collision cells are accessed during
00531                         //    the swap-operation of the streaming.
00532                         plint minZ = outerZ-dx-dy;
00533                         plint maxZ = minZ+blockSize-1;
00534                         for (plint innerZ=std::max(minZ,domain.z0);
00535                              innerZ <= std::min(maxZ, domain.z1);
00536                              ++innerZ)
00537                         {
00538                             // Collide the cell.
00539                             grid[innerX][innerY][innerZ].collide (
00540                                     this->getInternalStatistics() );
00541                             // Swap the populations on the cell, and then with post-collision
00542                             //   neighboring cell, to perform the streaming step.
00543                             latticeTemplates<T,Descriptor>::swapAndStream3D (
00544                                     grid, innerX, innerY, innerZ );
00545                         }
00546                     }
00547                 }
00548             }
00549         }
00550     }
00551 }
00552 
00553 template<typename T, template<typename U> class Descriptor>
00554 void BlockLattice3D<T,Descriptor>::implementPeriodicity() {
00555     static const plint vicinity = Descriptor<T>::vicinity;
00556     plint maxX = this->getNx()-1;
00557     plint maxY = this->getNy()-1;
00558     plint maxZ = this->getNz()-1;
00559     // Periodicity of planes orthogonal to x-axis.
00560     periodicDomain(Box3D(-vicinity,-1, 0,maxY, 0,maxZ));
00561     // Periodicity of planes orthogonal to y-axis.
00562     periodicDomain(Box3D(0,maxX, -vicinity,-1, 0,maxZ));
00563     // Periodicity of planes orthogonal to z-axis.
00564     periodicDomain(Box3D(0,maxX, 0,maxY, -vicinity,-1));
00565 
00566     // Periodicity of edges in y-z plane.
00567     // Periodicity between (-y,-z) and (+y,+z) edge.
00568     periodicDomain(Box3D(0,maxX, -vicinity,-1, -vicinity,-1));
00569     // Periodicity between (-y,+z) and (+y,-z) edge.
00570     periodicDomain(Box3D(0,maxX, -vicinity,-1, maxZ+1,maxZ+vicinity));
00571 
00572     // Periodicity of edges in x-z plane.
00573     // Periodicity between (-x,-z) and (+x,+z) edge.
00574     periodicDomain(Box3D(-vicinity,-1, 0,maxY, -vicinity,-1));
00575     // Periodicity between (-x,+z) and (+x,-z) edge.
00576     periodicDomain(Box3D(maxX+1,maxX+vicinity, 0,maxY, -vicinity,-1));
00577 
00578     // Periodicity of edges in x-y plane.
00579     // Periodicity between (-x,-y) and (+x,+y) edge.
00580     periodicDomain(Box3D(-vicinity,-1, -vicinity,-1, 0,maxZ));
00581     // Periodicity between (-x,+y) and (+x,-y) edge.
00582     periodicDomain(Box3D(-vicinity,-1, maxY+1,maxY+vicinity, 0,maxZ));
00583 
00584     // Periodicity of corners.
00585     // Periodicity of (+1,+1,+1) and (-1,-1,-1)
00586     periodicDomain(Box3D(maxX+1,maxX+vicinity, maxY+1,maxY+vicinity, maxZ+1,maxZ+vicinity));
00587     // Periodicity of (+1,+1,-1) and (-1,-1,+1)
00588     periodicDomain(Box3D(maxX+1,maxX+vicinity, maxY+1,maxY+vicinity, -vicinity,-1));
00589     // Periodicity of (+1,-1,+1) and (-1,+1,-1)
00590     periodicDomain(Box3D(maxX+1,maxX+vicinity, -vicinity,-1, maxZ+1,maxZ+vicinity));
00591     // Periodicity of (+1,-1,-1) and (-1,+1,+1)
00592     periodicDomain(Box3D(maxX+1,maxX+vicinity, -vicinity,-1, -vicinity,-1));
00593 }
00594 
00595 template<typename T, template<typename U> class Descriptor>
00596 void BlockLattice3D<T,Descriptor>::periodicDomain(Box3D domain) {
00597     plint nx = this->getNx();
00598     plint ny = this->getNy();
00599     plint nz = this->getNz();
00600     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00601         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00602             for (plint iZ=domain.z0; iZ<=domain.z1; ++iZ) {
00603                 for (plint iPop=1; iPop<Descriptor<T>::q; ++iPop) {
00604                     plint prevX = iX - Descriptor<T>::c[iPop][0];
00605                     plint prevY = iY - Descriptor<T>::c[iPop][1];
00606                     plint prevZ = iZ - Descriptor<T>::c[iPop][2];
00607 
00608                     if ( (prevX>=0 && prevX<nx) &&
00609                          (prevY>=0 && prevY<ny) &&
00610                          (prevZ>=0 && prevZ<nz) )
00611                     {
00612                         plint nextX = (iX+nx)%nx;
00613                         plint nextY = (iY+ny)%ny;
00614                         plint nextZ = (iZ+nz)%nz;
00615                         std::swap (
00616                             grid[prevX][prevY][prevZ][indexTemplates::opposite<Descriptor<T> >(iPop)],
00617                             grid[nextX][nextY][nextZ][iPop] );
00618                     }
00619                 }
00620             }
00621         }
00622     }
00623 }
00624 
00625 template<typename T, template<typename U> class Descriptor>
00626 BlockLatticeDataTransfer3D<T,Descriptor>& BlockLattice3D<T,Descriptor>::getDataTransfer() {
00627     return dataTransfer;
00628 }
00629 
00630 template<typename T, template<typename U> class Descriptor>
00631 BlockLatticeDataTransfer3D<T,Descriptor> const& BlockLattice3D<T,Descriptor>::getDataTransfer() const {
00632     return dataTransfer;
00633 }
00634 
00635 
00637 
00638 template<typename T, template<typename U> class Descriptor>
00639 BlockLatticeDataTransfer3D<T,Descriptor>::BlockLatticeDataTransfer3D(BlockLattice3D<T,Descriptor>& lattice_)
00640     : lattice(lattice_)
00641 { }
00642 
00643 template<typename T, template<typename U> class Descriptor>
00644 plint BlockLatticeDataTransfer3D<T,Descriptor>::staticCellSize() const {
00645     return sizeof(T)* (Descriptor<T>::numPop + Descriptor<T>::ExternalField::numScalars);
00646 }
00647 
00648 template<typename T, template<typename U> class Descriptor>
00649 void BlockLatticeDataTransfer3D<T,Descriptor>::send (
00650         Box3D domain, std::vector<char>& buffer, modif::ModifT kind ) const
00651 {
00652     PLB_PRECONDITION(contained(domain, lattice.getBoundingBox()));
00653     // It's the responsibility of the functions called below to allocate
00654     //   the right amount of memory for the buffer.
00655     buffer.clear();
00656     switch(kind) {
00657         case modif::staticVariables:
00658             send_static(domain, buffer); break;
00659         case modif::dynamicVariables:
00660             send_dynamic(domain, buffer); break;
00661         // Serialization is the same no matter if the dynamics object
00662         //   is being regenerated or not by the recipient.
00663         case modif::allVariables:  
00664         case modif::dataStructure:
00665             send_all(domain,buffer); break;
00666         default: PLB_ASSERT(false);
00667     }
00668 }
00669 
00670 template<typename T, template<typename U> class Descriptor>
00671 void BlockLatticeDataTransfer3D<T,Descriptor>::send_static (
00672         Box3D domain, std::vector<char>& buffer ) const
00673 {
00674     plint cellSize = staticCellSize();
00675     pluint numBytes = domain.nCells()*cellSize;
00676     // Avoid dereferencing uninitialized pointer.
00677     if (numBytes==0) return;
00678     buffer.resize(numBytes);
00679 
00680     plint iData=0;
00681     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00682         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00683             for (plint iZ=domain.z0; iZ<=domain.z1; ++iZ) {
00684                 lattice.get(iX,iY,iZ).serialize(&buffer[iData]);
00685                 iData += cellSize;
00686             }
00687         }
00688     }
00689 }
00690 
00691 template<typename T, template<typename U> class Descriptor>
00692 void BlockLatticeDataTransfer3D<T,Descriptor>::send_dynamic (
00693         Box3D domain, std::vector<char>& buffer ) const
00694 {
00695     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00696         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00697             for (plint iZ=domain.z0; iZ<=domain.z1; ++iZ) {
00698                 // The serialize function automatically reallocates memory for buffer.
00699                 serialize(lattice.get(iX,iY,iZ).getDynamics(), buffer);
00700             }
00701         }
00702     }
00703 }
00704 
00705 template<typename T, template<typename U> class Descriptor>
00706 void BlockLatticeDataTransfer3D<T,Descriptor>::send_all (
00707         Box3D domain, std::vector<char>& buffer ) const
00708 {
00709     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00710         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00711             for (plint iZ=domain.z0; iZ<=domain.z1; ++iZ) {
00712                 // 1. Send dynamic info (automaic allocation of buffer memory).
00713                 serialize(lattice.get(iX,iY,iZ).getDynamics(), buffer);
00714                 pluint pos = buffer.size();
00715                 // 2. Send static info (needs manual allocation of buffer memory).
00716                 if (staticCellSize()>0) {
00717                     buffer.resize(pos+staticCellSize());
00718                     lattice.get(iX,iY,iZ).serialize(&buffer[pos]);
00719                 }
00720             }
00721         }
00722     }
00723 }
00724 
00725 template<typename T, template<typename U> class Descriptor>
00726 void BlockLatticeDataTransfer3D<T,Descriptor>::receive (
00727         Box3D domain, std::vector<char> const& buffer,
00728         modif::ModifT kind, std::map<int,std::string> const& foreignIds )
00729 {
00730     if (kind==modif::dataStructure && !foreignIds.empty()) {
00731         std::map<int,int> idIndirect;
00732         meta::createIdIndirection<T,Descriptor>(foreignIds, idIndirect);
00733         receive_regenerate(domain, buffer, idIndirect);
00734     }
00735     else {
00736         receive(domain, buffer, kind);
00737     }
00738 }
00739 
00740 template<typename T, template<typename U> class Descriptor>
00741 void BlockLatticeDataTransfer3D<T,Descriptor>::receive (
00742         Box3D domain, std::vector<char> const& buffer, modif::ModifT kind )
00743 {
00744     PLB_PRECONDITION(contained(domain, lattice.getBoundingBox()));
00745     switch(kind) {
00746         case modif::staticVariables:
00747             receive_static(domain, buffer); break;
00748         case modif::dynamicVariables:
00749             receive_dynamic(domain, buffer); break;
00750         case modif::allVariables:
00751             receive_all(domain, buffer); break;
00752         case modif::dataStructure:
00753             receive_regenerate(domain, buffer); break;
00754         default:
00755             PLB_ASSERT( false );
00756     }
00757 }
00758 
00759 template<typename T, template<typename U> class Descriptor>
00760 void BlockLatticeDataTransfer3D<T,Descriptor>::receive_static (
00761         Box3D domain, std::vector<char> const& buffer )
00762 {
00763     PLB_PRECONDITION( (plint) buffer.size() == domain.nCells()*staticCellSize() );
00764     // Avoid dereferencing uninitialized pointer.
00765     if (buffer.empty()) return;
00766     plint cellSize = staticCellSize();
00767 
00768     plint iData=0;
00769     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00770         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00771             for (plint iZ=domain.z0; iZ<=domain.z1; ++iZ) {
00772                 lattice.get(iX,iY,iZ).unSerialize(&buffer[iData]);
00773                 iData += cellSize;
00774             }
00775         }
00776     }
00777 }
00778 
00779 template<typename T, template<typename U> class Descriptor>
00780 void BlockLatticeDataTransfer3D<T,Descriptor>::receive_dynamic (
00781         Box3D domain, std::vector<char> const& buffer )
00782 {
00783     pluint serializerPos = 0;
00784     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00785         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00786             for (plint iZ=domain.z0; iZ<=domain.z1; ++iZ) {
00787                 // No assert is included here, because incompatible types of
00788                 //   dynamics are detected by asserts inside HierarchicUnserializer.
00789                 serializerPos = 
00790                     unserialize (
00791                         lattice.get(iX,iY,iZ).getDynamics(), buffer, serializerPos );
00792             }
00793         }
00794     }
00795 }
00796 
00797 template<typename T, template<typename U> class Descriptor>
00798 void BlockLatticeDataTransfer3D<T,Descriptor>::receive_all (
00799         Box3D domain, std::vector<char> const& buffer )
00800 {
00801     pluint posInBuffer = 0;
00802     plint cellSize = staticCellSize();
00803     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00804         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00805             for (plint iZ=domain.z0; iZ<=domain.z1; ++iZ) {
00806                 // 1. Unserialize dynamic data.
00807                 posInBuffer = 
00808                     unserialize (
00809                         lattice.get(iX,iY,iZ).getDynamics(), buffer, posInBuffer );
00810                 // 2. Unserialize static data.
00811                 if (staticCellSize()>0) {
00812                     lattice.get(iX,iY,iZ).unSerialize(&buffer[posInBuffer]);
00813                     posInBuffer += cellSize;
00814                 }
00815             }
00816         }
00817     }
00818 }
00819 
00820 template<typename T, template<typename U> class Descriptor>
00821 void BlockLatticeDataTransfer3D<T,Descriptor>::receive_regenerate (
00822         Box3D domain, std::vector<char> const& buffer, std::map<int,int> const& idIndirect )
00823 {
00824     pluint posInBuffer = 0;
00825     plint cellSize = staticCellSize();
00826     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00827         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00828             for (plint iZ=domain.z0; iZ<=domain.z1; ++iZ) {
00829                 // 1. Generate dynamics object, and unserialize dynamic data.
00830                 std::map<int,int> const* indirectPtr = idIndirect.empty() ? 0 : &idIndirect;
00831                 HierarchicUnserializer unserializer(buffer, posInBuffer, indirectPtr);
00832                 Dynamics<T,Descriptor>* newDynamics =
00833                     meta::dynamicsRegistration<T,Descriptor>().generate(unserializer);
00834                 posInBuffer = unserializer.getCurrentPos();
00835                 lattice.attributeDynamics(iX,iY,iZ, newDynamics);
00836 
00837                 // 2. Unserialize static data.
00838                 if (staticCellSize()>0) {
00839                     PLB_ASSERT( !buffer.empty() );
00840                     PLB_ASSERT( posInBuffer+cellSize<=buffer.size() );
00841                     lattice.get(iX,iY,iZ).unSerialize(&buffer[posInBuffer]);
00842                     posInBuffer += cellSize;
00843                 }
00844             }
00845         }
00846     }
00847 }
00848 
00849 template<typename T, template<typename U> class Descriptor>
00850 void BlockLatticeDataTransfer3D<T,Descriptor>::attribute (
00851         Box3D toDomain, plint deltaX, plint deltaY, plint deltaZ,
00852         AtomicBlock3D const& from, modif::ModifT kind )
00853 {
00854     PLB_PRECONDITION (typeid(from) == typeid(BlockLattice3D<T,Descriptor> const&));
00855     PLB_PRECONDITION(contained(toDomain, lattice.getBoundingBox()));
00856     BlockLattice3D<T,Descriptor> const& fromLattice = (BlockLattice3D<T,Descriptor> const&) from;
00857     switch(kind) {
00858         case modif::staticVariables:
00859             attribute_static(toDomain, deltaX, deltaY, deltaZ, fromLattice); break;
00860         case modif::dynamicVariables:
00861             attribute_dynamic(toDomain, deltaX, deltaY, deltaZ, fromLattice); break;
00862         case modif::allVariables:
00863             attribute_all(toDomain, deltaX, deltaY, deltaZ, fromLattice); break;
00864         case modif::dataStructure:
00865             attribute_regenerate(toDomain, deltaX, deltaY, deltaZ, fromLattice); break;
00866         default:
00867             PLB_ASSERT( false );
00868     }
00869 }
00870 
00871 template<typename T, template<typename U> class Descriptor>
00872 void BlockLatticeDataTransfer3D<T,Descriptor>::attribute_static (
00873         Box3D toDomain, plint deltaX, plint deltaY, plint deltaZ,
00874         BlockLattice3D<T,Descriptor> const& from )
00875 {
00876     for (plint iX=toDomain.x0; iX<=toDomain.x1; ++iX) {
00877         for (plint iY=toDomain.y0; iY<=toDomain.y1; ++iY) {
00878             for (plint iZ=toDomain.z0; iZ<=toDomain.z1; ++iZ) {
00879                 lattice.get(iX,iY,iZ).attributeValues (
00880                         from.get(iX+deltaX,iY+deltaY,iZ+deltaZ) );
00881             }
00882         }
00883     }
00884 }
00885 
00886 template<typename T, template<typename U> class Descriptor>
00887 void BlockLatticeDataTransfer3D<T,Descriptor>::attribute_dynamic (
00888         Box3D toDomain, plint deltaX, plint deltaY, plint deltaZ,
00889         BlockLattice3D<T,Descriptor> const& from )
00890 {
00891     std::vector<char> serializedData;
00892     for (plint iX=toDomain.x0; iX<=toDomain.x1; ++iX) {
00893         for (plint iY=toDomain.y0; iY<=toDomain.y1; ++iY) {
00894             for (plint iZ=toDomain.z0; iZ<=toDomain.z1; ++iZ) {
00895                 serializedData.clear();
00896                 serialize (
00897                     from.get(iX+deltaX,iY+deltaY,iZ+deltaZ).getDynamics(),
00898                     serializedData );
00899                 unserialize (
00900                     lattice.get(iX,iY,iZ).getDynamics(),
00901                     serializedData );
00902             }
00903         }
00904     }
00905 }
00906 
00907 template<typename T, template<typename U> class Descriptor>
00908 void BlockLatticeDataTransfer3D<T,Descriptor>::attribute_all (
00909         Box3D toDomain, plint deltaX, plint deltaY, plint deltaZ,
00910         BlockLattice3D<T,Descriptor> const& from )
00911 {
00912     std::vector<char> serializedData;
00913     for (plint iX=toDomain.x0; iX<=toDomain.x1; ++iX) {
00914         for (plint iY=toDomain.y0; iY<=toDomain.y1; ++iY) {
00915             for (plint iZ=toDomain.z0; iZ<=toDomain.z1; ++iZ) {
00916                 // 1. Attribute dynamic content.
00917                 serializedData.clear();
00918                 serialize (
00919                     from.get(iX+deltaX,iY+deltaY,iZ+deltaZ).getDynamics(),
00920                     serializedData );
00921                 unserialize (
00922                     lattice.get(iX,iY,iZ).getDynamics(),
00923                     serializedData );
00924 
00925                 // 2. Attribute static content.
00926                 lattice.get(iX,iY,iZ).attributeValues (
00927                         from.get(iX+deltaX,iY+deltaY,iZ+deltaZ) );
00928             }
00929         }
00930     }
00931 }
00932 
00933 template<typename T, template<typename U> class Descriptor>
00934 void BlockLatticeDataTransfer3D<T,Descriptor>::attribute_regenerate (
00935         Box3D toDomain, plint deltaX, plint deltaY, plint deltaZ,
00936         BlockLattice3D<T,Descriptor> const& from )
00937 {
00938     std::vector<char> serializedData;
00939     for (plint iX=toDomain.x0; iX<=toDomain.x1; ++iX) {
00940         for (plint iY=toDomain.y0; iY<=toDomain.y1; ++iY) {
00941             for (plint iZ=toDomain.z0; iZ<=toDomain.z1; ++iZ) {
00942                 // 1. Generate new dynamics and attribute dynamic content.
00943                 serializedData.clear();
00944                 serialize (
00945                     from.get(iX+deltaX,iY+deltaY,iZ+deltaZ).getDynamics(),
00946                     serializedData );
00947                 HierarchicUnserializer unserializer(serializedData, 0);
00948                 Dynamics<T,Descriptor>* newDynamics =
00949                     meta::dynamicsRegistration<T,Descriptor>().generate(unserializer);
00950                 lattice.attributeDynamics(iX,iY,iZ, newDynamics);
00951 
00952                 // 2. Attribute static content.
00953                 lattice.get(iX,iY,iZ).attributeValues (
00954                         from.get(iX+deltaX,iY+deltaY,iZ+deltaZ) );
00955             }
00956         }
00957     }
00958 }
00959 
00960 template<typename T, template<typename U> class Descriptor>
00961 CachePolicy3D& BlockLattice3D<T,Descriptor>::cachePolicy() {
00962     static CachePolicy3D cachePolicySingleton(30);
00963     return cachePolicySingleton;
00964 }
00965 
00966 
00968 
00969 template<typename T, template<typename U> class Descriptor>
00970 double getStoredAverageDensity(BlockLattice3D<T,Descriptor> const& blockLattice) {
00971     return Descriptor<T>::fullRho (
00972                blockLattice.getInternalStatistics().getAverage (
00973                   LatticeStatistics::avRhoBar ) );
00974 }
00975 
00976 template<typename T, template<typename U> class Descriptor>
00977 double getStoredAverageEnergy(BlockLattice3D<T,Descriptor> const& blockLattice) {
00978     return 0.5 * blockLattice.getInternalStatistics().getAverage (
00979                         LatticeStatistics::avUSqr );
00980 }
00981 
00982 template<typename T, template<typename U> class Descriptor>
00983 double getStoredMaxVelocity(BlockLattice3D<T,Descriptor> const& blockLattice) {
00984     return std::sqrt( blockLattice.getInternalStatistics().getMax (
00985                              LatticeStatistics::maxUSqr ) );
00986 }
00987 
00988 }  // namespace plb
00989 
00990 #endif  // BLOCK_LATTICE_3D_HH