Palabos  Version 1.0
blockLattice2D.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_2D_HH
00029 #define BLOCK_LATTICE_2D_HH
00030 
00031 #include "atomicBlock/blockLattice2D.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 
00047 
00051 template<typename T, template<typename U> class Descriptor>
00052 BlockLattice2D<T,Descriptor>::BlockLattice2D (
00053         plint nx_, plint ny_,
00054         Dynamics<T,Descriptor>* backgroundDynamics_ )
00055     : AtomicBlock2D(nx_, ny_),
00056       backgroundDynamics(backgroundDynamics_),
00057       dataTransfer(*this)
00058 {
00059     plint nx = this->getNx();
00060     plint ny = this->getNy();
00061     // Allocate memory and attribute dynamics.
00062     allocateAndInitialize();
00063     for (plint iX=0; iX<nx; ++iX) {
00064         for (plint iY=0; iY<ny; ++iY) {
00065             grid[iX][iY].attributeDynamics(backgroundDynamics);
00066        }
00067     }
00068     // Attribute default value to the standard statistics (average uSqr,
00069     //   max uSqr, average rho). These have previously been subscribed
00070     //   in the constructor of BlockLatticeBase2D.
00071     std::vector<double> average, sum, max;
00072     std::vector<plint> intSum;
00073     average.push_back(Descriptor<double>::rhoBar((T)1));
00074                              // default average rho to 1, to avoid division by
00075                              // zero in constRhoBGK and related models
00076     average.push_back(0.);  // default average uSqr to 0
00077     max.push_back(0.);      // default max uSqr to 0
00078     plint numCells = 1;       // pretend fictitious cell to evaluate statistics
00079     this->getInternalStatistics().evaluate (average, sum, max, intSum, numCells);
00080 }
00081 
00086 template<typename T, template<typename U> class Descriptor>
00087 BlockLattice2D<T,Descriptor>::~BlockLattice2D()
00088 {
00089     releaseMemory();
00090 }
00091 
00097 template<typename T, template<typename U> class Descriptor>
00098 BlockLattice2D<T,Descriptor>::BlockLattice2D(BlockLattice2D<T,Descriptor> const& rhs)
00099     : BlockLatticeBase2D<T,Descriptor>(rhs),
00100       AtomicBlock2D(rhs),
00101       backgroundDynamics(rhs.backgroundDynamics->clone()),
00102       dataTransfer(*this)
00103 {
00104     plint nx = this->getNx();
00105     plint ny = this->getNy();
00106     allocateAndInitialize();
00107     for (plint iX=0; iX<nx; ++iX) {
00108         for (plint iY=0; iY<ny; ++iY) {
00109             Cell<T,Descriptor>& cell = grid[iX][iY];
00110             // Assign cell from rhs
00111             cell = rhs.grid[iX][iY];
00112             // Get an independent clone of the dynamics,
00113             //   or assign backgroundDynamics
00114             if (&cell.getDynamics()==rhs.backgroundDynamics) {
00115                 cell.attributeDynamics(backgroundDynamics);
00116             }
00117             else {
00118                 cell.attributeDynamics(cell.getDynamics().clone());
00119             }
00120         }
00121     }
00122 }
00123 
00130 template<typename T, template<typename U> class Descriptor>
00131 BlockLattice2D<T,Descriptor>& BlockLattice2D<T,Descriptor>::operator= (
00132         BlockLattice2D<T,Descriptor> const& rhs )
00133 {
00134     BlockLattice2D<T,Descriptor> tmp(rhs);
00135     swap(tmp);
00136     return *this;
00137 }
00138 
00142 template<typename T, template<typename U> class Descriptor>
00143 void BlockLattice2D<T,Descriptor>::swap(BlockLattice2D& rhs) {
00144     BlockLatticeBase2D<T,Descriptor>::swap(rhs);
00145     AtomicBlock2D::swap(rhs);
00146     std::swap(backgroundDynamics, rhs.backgroundDynamics);
00147     std::swap(rawData, rhs.rawData);
00148     std::swap(grid, rhs.grid);
00149 }
00150 
00151 template<typename T, template<typename U> class Descriptor>
00152 void BlockLattice2D<T,Descriptor>::specifyStatisticsStatus (
00153         Box2D domain, bool status )
00154 {
00155     // Make sure domain is contained within current lattice
00156     PLB_PRECONDITION( contained(domain, this->getBoundingBox()) );
00157 
00158     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00159         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00160             grid[iX][iY].specifyStatisticsStatus(status);
00161         }
00162     }
00163 }
00164 
00165 template<typename T, template<typename U> class Descriptor>
00166 void BlockLattice2D<T,Descriptor>::collide(Box2D domain) {
00167     PLB_PRECONDITION( (plint)Descriptor<T>::q==(plint)Descriptor<T>::numPop );
00168     // Make sure domain is contained within current lattice
00169     PLB_PRECONDITION( contained(domain, this->getBoundingBox()) );
00170 
00171     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00172         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00173             grid[iX][iY].collide(this->getInternalStatistics());
00174             grid[iX][iY].revert();
00175         }
00176     }
00177 }
00178 
00180 template<typename T, template<typename U> class Descriptor>
00181 void BlockLattice2D<T,Descriptor>::collide() {
00182     collide(this->getBoundingBox());
00183 }
00184 
00194 template<typename T, template<typename U> class Descriptor>
00195 void BlockLattice2D<T,Descriptor>::stream(Box2D domain) {
00196     // Make sure domain is contained within current lattice
00197     PLB_PRECONDITION( contained(domain, this->getBoundingBox()) );
00198 
00199     static const plint vicinity = Descriptor<T>::vicinity;
00200 
00201     bulkStream( Box2D(domain.x0+vicinity,domain.x1-vicinity,
00202                       domain.y0+vicinity,domain.y1-vicinity) );
00203 
00204     boundaryStream(domain, Box2D(domain.x0,domain.x0+vicinity-1,
00205                                  domain.y0,domain.y1));
00206     boundaryStream(domain, Box2D(domain.x1-vicinity+1,domain.x1,
00207                                  domain.y0,domain.y1));
00208     boundaryStream(domain, Box2D(domain.x0+vicinity,domain.x1-vicinity,
00209                                  domain.y0,domain.y0+vicinity-1));
00210     boundaryStream(domain, Box2D(domain.x0+vicinity,domain.x1-vicinity,
00211                                  domain.y1-vicinity+1,domain.y1));
00212 }
00213 
00218 template<typename T, template<typename U> class Descriptor>
00219 void BlockLattice2D<T,Descriptor>::stream()
00220 {
00221     stream(this->getBoundingBox());
00222 
00223     implementPeriodicity();
00224 
00225     this->executeInternalProcessors();
00226     this->evaluateStatistics();
00227     this->incrementTime();
00228 }
00229 
00239 template<typename T, template<typename U> class Descriptor>
00240 void BlockLattice2D<T,Descriptor>::collideAndStream(Box2D domain)
00241 {
00242     PLB_PRECONDITION( (plint)Descriptor<T>::q==(plint)Descriptor<T>::numPop );
00243     // Make sure domain is contained within current lattice
00244     PLB_PRECONDITION( contained(domain, this->getBoundingBox()) );
00245 
00246     global::profiler().start("collStream");
00247     global::profiler().increment("collStreamCells", domain.nCells());
00248 
00249     static const plint vicinity = Descriptor<T>::vicinity;
00250 
00251     // First, do the collision on cells within a boundary envelope of width
00252     // equal to the range of the lattice vectors (e.g. 1 for D2Q9)
00253     collide(Box2D(domain.x0,domain.x0+vicinity-1, domain.y0,domain.y1));
00254     collide(Box2D(domain.x1-vicinity+1,domain.x1, domain.y0,domain.y1));
00255     collide(Box2D(domain.x0+vicinity,domain.x1-vicinity, domain.y0,domain.y0+vicinity-1));
00256     collide(Box2D(domain.x0+vicinity,domain.x1-vicinity, domain.y1-vicinity+1,domain.y1));
00257 
00258     // Then, do the efficient collideAndStream algorithm in the bulk,
00259     // excluding the envelope (this is efficient because there is no
00260     // if-then-else statement within the loop, given that the boundary
00261     // region is excluded)
00262     bulkCollideAndStream(Box2D(domain.x0+vicinity,domain.x1-vicinity,
00263                                domain.y0+vicinity,domain.y1-vicinity));
00264 
00265     // Finally, do streaming in the boundary envelope to conclude the
00266     // collision-stream cycle
00267     boundaryStream(domain, Box2D(domain.x0,domain.x0+vicinity-1,
00268                                  domain.y0,domain.y1));
00269     boundaryStream(domain, Box2D(domain.x1-vicinity+1,domain.x1,
00270                                  domain.y0,domain.y1));
00271     boundaryStream(domain, Box2D(domain.x0+vicinity,domain.x1-vicinity,
00272                                  domain.y0,domain.y0+vicinity-1));
00273     boundaryStream(domain, Box2D(domain.x0+vicinity,domain.x1-vicinity,
00274                                  domain.y1-vicinity+1,domain.y1));
00275     global::profiler().stop("collStream");
00276 }
00277 
00281 template<typename T, template<typename U> class Descriptor>
00282 void BlockLattice2D<T,Descriptor>::collideAndStream() {
00283     collideAndStream(this->getBoundingBox());
00284     
00285     implementPeriodicity();
00286 
00287     this->executeInternalProcessors();
00288     this->evaluateStatistics();
00289     this->incrementTime();
00290 }
00291 
00292 template<typename T, template<typename U> class Descriptor>
00293 void BlockLattice2D<T,Descriptor>::incrementTime() {
00294     this->getTimeCounter().incrementTime();
00295 }
00296 
00297 template<typename T, template<typename U> class Descriptor>
00298 void BlockLattice2D<T,Descriptor>::allocateAndInitialize() {
00299     this->getInternalStatistics().subscribeAverage(); // Subscribe average rho-bar
00300     this->getInternalStatistics().subscribeAverage(); // Subscribe average uSqr
00301     this->getInternalStatistics().subscribeMax();     // Subscribe max uSqr
00302     plint nx = this->getNx();
00303     plint ny = this->getNy();
00304     rawData = new Cell<T,Descriptor> [nx*ny];
00305     grid    = new Cell<T,Descriptor>* [nx];
00306     for (plint iX=0; iX<nx; ++iX) {
00307         grid[iX] = rawData + iX*ny;
00308     }
00309 }
00310 
00311 template<typename T, template<typename U> class Descriptor>
00312 void BlockLattice2D<T,Descriptor>::releaseMemory() {
00313     plint nx = this->getNx();
00314     plint ny = this->getNy();
00315     for (plint iX=0; iX<nx; ++iX) {
00316         for (plint iY=0; iY<ny; ++iY) {
00317             Dynamics<T,Descriptor>* dynamics = &grid[iX][iY].getDynamics();
00318             if (dynamics != backgroundDynamics) {
00319                 delete dynamics;
00320             }
00321         }
00322     }
00323     delete backgroundDynamics;
00324     delete [] rawData;
00325     delete [] grid;
00326 }
00327 
00328 template<typename T, template<typename U> class Descriptor>
00329 void BlockLattice2D<T,Descriptor>::attributeDynamics(plint iX, plint iY, Dynamics<T,Descriptor>* dynamics) {
00330     Dynamics<T,Descriptor>* previousDynamics = &grid[iX][iY].getDynamics();
00331     if (previousDynamics != backgroundDynamics) {
00332         delete previousDynamics;
00333     }
00334     grid[iX][iY].attributeDynamics(dynamics);
00335 }
00336 
00337 template<typename T, template<typename U> class Descriptor>
00338 Dynamics<T,Descriptor>& BlockLattice2D<T,Descriptor>::getBackgroundDynamics() {
00339     return *backgroundDynamics;
00340 }
00341 
00342 template<typename T, template<typename U> class Descriptor>
00343 Dynamics<T,Descriptor> const& BlockLattice2D<T,Descriptor>::getBackgroundDynamics() const {
00344     return *backgroundDynamics;
00345 }
00346 
00353 template<typename T, template<typename U> class Descriptor>
00354 void BlockLattice2D<T,Descriptor>::boundaryStream(Box2D bound, Box2D domain) {
00355     // Make sure bound is contained within current lattice
00356     PLB_PRECONDITION( contained(bound, this->getBoundingBox()) );
00357     // Make sure domain is contained within bound
00358     PLB_PRECONDITION( contained(domain, bound) );
00359 
00360     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00361         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00362             for (plint iPop=1; iPop<=Descriptor<T>::q/2; ++iPop) {
00363                 plint nextX = iX + Descriptor<T>::c[iPop][0];
00364                 plint nextY = iY + Descriptor<T>::c[iPop][1];
00365                 if (nextX>=bound.x0 && nextX<=bound.x1 && nextY>=bound.y0 && nextY<=bound.y1) {
00366                     std::swap(grid[iX][iY][iPop+Descriptor<T>::q/2],
00367                               grid[nextX][nextY][iPop]);
00368                 }
00369             }
00370         }
00371     }
00372 }
00373 
00379 template<typename T, template<typename U> class Descriptor>
00380 void BlockLattice2D<T,Descriptor>::bulkStream(Box2D domain) {
00381     // Make sure domain is contained within current lattice
00382     PLB_PRECONDITION( contained(domain, this->getBoundingBox()) );
00383 
00384     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00385         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00386             for (plint iPop=1; iPop<=Descriptor<T>::q/2; ++iPop) {
00387                 plint nextX = iX + Descriptor<T>::c[iPop][0];
00388                 plint nextY = iY + Descriptor<T>::c[iPop][1];
00389                 std::swap(grid[iX][iY][iPop+Descriptor<T>::q/2],
00390                           grid[nextX][nextY][iPop]);
00391             }
00392         }
00393     }
00394 }
00395 
00401 template<typename T, template<typename U> class Descriptor>
00402 void BlockLattice2D<T,Descriptor>::bulkCollideAndStream(Box2D domain) {
00403     // Make sure domain is contained within current lattice
00404     PLB_PRECONDITION( contained(domain, this->getBoundingBox()) );
00405 
00406     if (Descriptor<T>::vicinity==1) {
00407         // On nearest-neighbor lattice, use the cache-efficient
00408         //   version of collidAndStream.
00409         blockwiseBulkCollideAndStream(domain);
00410     }
00411     else {
00412         // Otherwise, use the straightforward implementation.
00413         //   Note that at some point, we should implement the cache-efficient
00414         //   version for extended lattices as well.
00415         linearBulkCollideAndStream(domain);
00416     }
00417 }
00418 
00419 
00423 template<typename T, template<typename U> class Descriptor>
00424 void BlockLattice2D<T,Descriptor>::linearBulkCollideAndStream(Box2D domain) {
00425     // Make sure domain is contained within current lattice
00426     PLB_PRECONDITION( contained(domain, this->getBoundingBox()) );
00427 
00428     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00429         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00430             grid[iX][iY].collide(this->getInternalStatistics());
00431             latticeTemplates<T,Descriptor>::swapAndStream2D(grid, iX, iY);
00432         }
00433     }
00434 }
00435 
00436 
00441 template<typename T, template<typename U> class Descriptor>
00442 void BlockLattice2D<T,Descriptor>::blockwiseBulkCollideAndStream(Box2D domain) {
00443     // Make sure domain is contained within current lattice
00444     PLB_PRECONDITION( contained(domain, this->getBoundingBox()) );
00445 
00446     // For cache efficiency, memory is traversed block-wise. The two outer loops enumerate
00447     //   the blocks, whereas the two inner loops enumerate the cells inside each block.
00448     const plint blockSize = cachePolicy().getBlockSize();
00449     // Outer loops.
00450     for (plint outerX=domain.x0; outerX<=domain.x1; outerX+=blockSize) {
00451         for (plint outerY=domain.y0; outerY<=domain.y1+blockSize-1; outerY+=blockSize) {
00452             // Inner loops.
00453             plint dx = 0;
00454             for (plint innerX=outerX;
00455                  innerX <= std::min(outerX+blockSize-1, domain.x1);
00456                  ++innerX, ++dx)
00457             {
00458                 // Y-index is shifted in negative direction at each x-increment. to ensure
00459                 //   that only post-collision cells are accessed during the swap-operation
00460                 //   of the streaming.
00461                 plint minY = outerY-dx;
00462                 plint maxY = minY+blockSize-1;
00463                 for (plint innerY=std::max(minY,domain.y0);
00464                      innerY <= std::min(maxY, domain.y1);
00465                      ++innerY)
00466                 {
00467                     // Collide the cell.
00468                     grid[innerX][innerY].collide (
00469                             this->getInternalStatistics() );
00470                     // Swap the populations on the cell, and then with post-collision
00471                     //   neighboring cell, to perform the streaming step.
00472                     latticeTemplates<T,Descriptor>::swapAndStream2D (
00473                             grid, innerX, innerY );
00474                 }
00475             }
00476         }
00477     }
00478 }
00479 
00480 template<typename T, template<typename U> class Descriptor>
00481 void BlockLattice2D<T,Descriptor>::periodicDomain(Box2D domain) {
00482     plint nx = this->getNx();
00483     plint ny = this->getNy();
00484     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00485         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00486             for (plint iPop=1; iPop<Descriptor<T>::q; ++iPop) {
00487                 plint prevX = iX - Descriptor<T>::c[iPop][0];
00488                 plint prevY = iY - Descriptor<T>::c[iPop][1];
00489                 if ( (prevX>=0 && prevX<nx) &&
00490                      (prevY>=0 && prevY<ny) )
00491                 {
00492                     plint nextX = (iX+nx)%nx;
00493                     plint nextY = (iY+ny)%ny;
00494                     std::swap (
00495                         grid[prevX][prevY][indexTemplates::opposite<Descriptor<T> >(iPop)],
00496                         grid[nextX][nextY][iPop] );
00497                 }
00498             }
00499         }
00500     }
00501 }
00502 
00503 template<typename T, template<typename U> class Descriptor>
00504 void BlockLattice2D<T,Descriptor>::implementPeriodicity() {
00505     static const plint vicinity = Descriptor<T>::vicinity;
00506     plint maxX = this->getNx()-1;
00507     plint maxY = this->getNy()-1;
00508     // Periodicity of edges orthogonal to x-axis.
00509     periodicDomain(Box2D(-vicinity,-1,0,maxY));
00510     // Periodicity of edges orthogonal to y-axis.
00511     periodicDomain(Box2D(0,maxX,-vicinity,-1));
00512     // Periodicity between (-1,-1) and (+1,+1) corner.
00513     periodicDomain(Box2D(-vicinity,-1,-vicinity,-1));
00514     // Periodicity between (-1,+1) and (+1,-1) corner.
00515     periodicDomain(Box2D(-vicinity,-1,maxY+1,maxY+vicinity));
00516 }
00517 
00518 template<typename T, template<typename U> class Descriptor>
00519 BlockLatticeDataTransfer2D<T,Descriptor>& BlockLattice2D<T,Descriptor>::getDataTransfer() {
00520     return dataTransfer;
00521 }
00522 
00523 template<typename T, template<typename U> class Descriptor>
00524 BlockLatticeDataTransfer2D<T,Descriptor> const& BlockLattice2D<T,Descriptor>::getDataTransfer() const {
00525     return dataTransfer;
00526 }
00527 
00528 
00530 
00531 template<typename T, template<typename U> class Descriptor>
00532 BlockLatticeDataTransfer2D<T,Descriptor>::BlockLatticeDataTransfer2D(BlockLattice2D<T,Descriptor>& lattice_)
00533     : lattice(lattice_)
00534 { }
00535 
00536 template<typename T, template<typename U> class Descriptor>
00537 plint BlockLatticeDataTransfer2D<T,Descriptor>::staticCellSize() const {
00538     return sizeof(T)* (Descriptor<T>::numPop + Descriptor<T>::ExternalField::numScalars);
00539 }
00540 
00541 template<typename T, template<typename U> class Descriptor>
00542 void BlockLatticeDataTransfer2D<T,Descriptor>::send (
00543         Box2D domain, std::vector<char>& buffer, modif::ModifT kind ) const
00544 {
00545     PLB_PRECONDITION(contained(domain, lattice.getBoundingBox()));
00546     // It's the responsibility of the functions called below to allocate
00547     //   the right amount of memory for the buffer.
00548     buffer.clear();
00549     switch(kind) {
00550         case modif::staticVariables:
00551             send_static(domain, buffer); break;
00552         case modif::dynamicVariables:
00553             send_dynamic(domain, buffer); break;
00554         // Serialization is the same no matter if the dynamics object
00555         //   is being regenerated or not by the recipient.
00556         case modif::allVariables:  
00557         case modif::dataStructure:
00558             send_all(domain,buffer); break;
00559         default: PLB_ASSERT(false);
00560     }
00561 }
00562 
00563 template<typename T, template<typename U> class Descriptor>
00564 void BlockLatticeDataTransfer2D<T,Descriptor>::send_static (
00565         Box2D domain, std::vector<char>& buffer ) const
00566 {
00567     plint cellSize = staticCellSize();
00568     pluint numBytes = domain.nCells()*cellSize;
00569     // Avoid dereferencing uninitialized pointer.
00570     if (numBytes==0) return;
00571     buffer.resize(numBytes);
00572 
00573     plint iData=0;
00574     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00575         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00576             lattice.get(iX,iY).serialize(&buffer[iData]);
00577             iData += cellSize;
00578         }
00579     }
00580 }
00581 
00582 template<typename T, template<typename U> class Descriptor>
00583 void BlockLatticeDataTransfer2D<T,Descriptor>::send_dynamic (
00584         Box2D domain, std::vector<char>& buffer ) const
00585 {
00586     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00587         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00588             // The serialize function automatically reallocates memory for buffer.
00589             serialize(lattice.get(iX,iY).getDynamics(), buffer);
00590         }
00591     }
00592 }
00593 
00594 template<typename T, template<typename U> class Descriptor>
00595 void BlockLatticeDataTransfer2D<T,Descriptor>::send_all (
00596         Box2D domain, std::vector<char>& buffer ) const
00597 {
00598     plint cellSize = staticCellSize();
00599     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00600         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00601             // 1. Send dynamic info (automaic allocation of buffer memory).
00602             serialize(lattice.get(iX,iY).getDynamics(), buffer);
00603             pluint pos = buffer.size();
00604             // 2. Send static info (needs manual allocation of buffer memory).
00605             if (staticCellSize()>0) {
00606                 buffer.resize(pos+cellSize);
00607                 lattice.get(iX,iY).serialize(&buffer[pos]);
00608             }
00609         }
00610     }
00611 }
00612 
00613 template<typename T, template<typename U> class Descriptor>
00614 void BlockLatticeDataTransfer2D<T,Descriptor>::receive (
00615         Box2D domain, std::vector<char> const& buffer,
00616         modif::ModifT kind, std::map<int,std::string> const& foreignIds )
00617 {
00618     if (kind==modif::dataStructure && !foreignIds.empty()) {
00619         std::map<int,int> idIndirect;
00620         meta::createIdIndirection<T,Descriptor>(foreignIds, idIndirect);
00621         receive_regenerate(domain, buffer, idIndirect);
00622     }
00623     else {
00624         receive(domain, buffer, kind);
00625     }
00626 }
00627 
00628 template<typename T, template<typename U> class Descriptor>
00629 void BlockLatticeDataTransfer2D<T,Descriptor>::receive (
00630         Box2D domain, std::vector<char> const& buffer, modif::ModifT kind )
00631 {
00632     PLB_PRECONDITION(contained(domain, lattice.getBoundingBox()));
00633     switch(kind) {
00634         case modif::staticVariables:
00635             receive_static(domain, buffer); break;
00636         case modif::dynamicVariables:
00637             receive_dynamic(domain, buffer); break;
00638         case modif::allVariables:
00639             receive_all(domain, buffer); break;
00640         case modif::dataStructure:
00641             receive_regenerate(domain, buffer); break;
00642         default:
00643             PLB_ASSERT( false );
00644     }
00645 }
00646 
00647 template<typename T, template<typename U> class Descriptor>
00648 void BlockLatticeDataTransfer2D<T,Descriptor>::receive_static (
00649         Box2D domain, std::vector<char> const& buffer )
00650 {
00651     PLB_PRECONDITION( (plint) buffer.size() == domain.nCells()*staticCellSize() );
00652     // Avoid dereferencing uninitialized pointer.
00653     if (buffer.empty()) return;
00654     plint cellSize = staticCellSize();
00655 
00656     // All serialized data if of type T; therefore, buffer is considered
00657     //   as being a T-array right away.
00658     plint iData=0;
00659     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00660         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00661             lattice.get(iX,iY).unSerialize(&buffer[iData]);
00662             iData += cellSize;
00663         }
00664     }
00665 }
00666 
00667 template<typename T, template<typename U> class Descriptor>
00668 void BlockLatticeDataTransfer2D<T,Descriptor>::receive_dynamic (
00669         Box2D domain, std::vector<char> const& buffer )
00670 {
00671     pluint serializerPos = 0;
00672     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00673         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00674             // No assert is included here, because incompatible types of
00675             //   dynamics are detected by asserts inside HierarchicUnserializer.
00676             serializerPos = 
00677                 unserialize (
00678                     lattice.get(iX,iY).getDynamics(), buffer, serializerPos );
00679         }
00680     }
00681 }
00682 
00683 template<typename T, template<typename U> class Descriptor>
00684 void BlockLatticeDataTransfer2D<T,Descriptor>::receive_all (
00685         Box2D domain, std::vector<char> const& buffer )
00686 {
00687     pluint posInBuffer = 0;
00688     plint cellSize = staticCellSize();
00689     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00690         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00691             // 1. Unserialize dynamic data.
00692             posInBuffer = 
00693                 unserialize (
00694                     lattice.get(iX,iY).getDynamics(), buffer, posInBuffer );
00695             // 2. Unserialize static data.
00696             if (staticCellSize()>0) {
00697                 lattice.get(iX,iY).unSerialize(&buffer[posInBuffer]);
00698                 posInBuffer += cellSize;
00699             }
00700         }
00701     }
00702 }
00703 
00704 template<typename T, template<typename U> class Descriptor>
00705 void BlockLatticeDataTransfer2D<T,Descriptor>::receive_regenerate (
00706         Box2D domain, std::vector<char> const& buffer, std::map<int,int> const& idIndirect )
00707 {
00708     pluint posInBuffer = 0;
00709     plint cellSize = staticCellSize();
00710     for (plint iX=domain.x0; iX<=domain.x1; ++iX) {
00711         for (plint iY=domain.y0; iY<=domain.y1; ++iY) {
00712             // 1. Generate dynamics object, and unserialize dynamic data.
00713             std::map<int,int> const* indirectPtr = idIndirect.empty() ? 0 : &idIndirect;
00714             HierarchicUnserializer unserializer(buffer, posInBuffer, indirectPtr);
00715             Dynamics<T,Descriptor>* newDynamics =
00716                 meta::dynamicsRegistration<T,Descriptor>().generate(unserializer);
00717             posInBuffer = unserializer.getCurrentPos();
00718             lattice.attributeDynamics(iX,iY, newDynamics);
00719 
00720             // 2. Unserialize static data.
00721             if (staticCellSize()>0) {
00722                 PLB_ASSERT( !buffer.empty() );
00723                 PLB_ASSERT( posInBuffer+staticCellSize()<=buffer.size() );
00724                 lattice.get(iX,iY).unSerialize(&buffer[posInBuffer]);
00725                 posInBuffer += cellSize;
00726             }
00727         }
00728     }
00729 }
00730 
00731 template<typename T, template<typename U> class Descriptor>
00732 void BlockLatticeDataTransfer2D<T,Descriptor>::attribute (
00733         Box2D toDomain, plint deltaX, plint deltaY,
00734         AtomicBlock2D const& from, modif::ModifT kind )
00735 {
00736     PLB_PRECONDITION (typeid(from) == typeid(BlockLattice2D<T,Descriptor> const&));
00737     PLB_PRECONDITION(contained(toDomain, lattice.getBoundingBox()));
00738     BlockLattice2D<T,Descriptor> const& fromLattice = (BlockLattice2D<T,Descriptor> const&) from;
00739     switch(kind) {
00740         case modif::staticVariables:
00741             attribute_static(toDomain, deltaX, deltaY, fromLattice); break;
00742         case modif::dynamicVariables:
00743             attribute_dynamic(toDomain, deltaX, deltaY, fromLattice); break;
00744         case modif::allVariables:
00745             attribute_all(toDomain, deltaX, deltaY, fromLattice); break;
00746         case modif::dataStructure:
00747             attribute_regenerate(toDomain, deltaX, deltaY, fromLattice); break;
00748         default:
00749             PLB_ASSERT( false );
00750     }
00751 }
00752 
00753 template<typename T, template<typename U> class Descriptor>
00754 void BlockLatticeDataTransfer2D<T,Descriptor>::attribute_static (
00755         Box2D toDomain, plint deltaX, plint deltaY,
00756         BlockLattice2D<T,Descriptor> const& from )
00757 {
00758     for (plint iX=toDomain.x0; iX<=toDomain.x1; ++iX) {
00759         for (plint iY=toDomain.y0; iY<=toDomain.y1; ++iY) {
00760             lattice.get(iX,iY).attributeValues (
00761                     from.get(iX+deltaX,iY+deltaY) );
00762         }
00763     }
00764 }
00765 
00766 template<typename T, template<typename U> class Descriptor>
00767 void BlockLatticeDataTransfer2D<T,Descriptor>::attribute_dynamic (
00768         Box2D toDomain, plint deltaX, plint deltaY,
00769         BlockLattice2D<T,Descriptor> const& from )
00770 {
00771     std::vector<char> serializedData;
00772     for (plint iX=toDomain.x0; iX<=toDomain.x1; ++iX) {
00773         for (plint iY=toDomain.y0; iY<=toDomain.y1; ++iY) {
00774             serializedData.clear();
00775             serialize (
00776                 from.get(iX+deltaX,iY+deltaY).getDynamics(),
00777                 serializedData );
00778             unserialize (
00779                 lattice.get(iX,iY).getDynamics(),
00780                 serializedData );
00781         }
00782     }
00783 }
00784 
00785 template<typename T, template<typename U> class Descriptor>
00786 void BlockLatticeDataTransfer2D<T,Descriptor>::attribute_all (
00787         Box2D toDomain, plint deltaX, plint deltaY,
00788         BlockLattice2D<T,Descriptor> const& from )
00789 {
00790     std::vector<char> serializedData;
00791     for (plint iX=toDomain.x0; iX<=toDomain.x1; ++iX) {
00792         for (plint iY=toDomain.y0; iY<=toDomain.y1; ++iY) {
00793             // 1. Attribute dynamic content.
00794             serializedData.clear();
00795             serialize (
00796                 from.get(iX+deltaX,iY+deltaY).getDynamics(),
00797                 serializedData );
00798             unserialize (
00799                 lattice.get(iX,iY).getDynamics(),
00800                 serializedData );
00801 
00802             // 2. Attribute static content.
00803             lattice.get(iX,iY).attributeValues (
00804                     from.get(iX+deltaX,iY+deltaY) );
00805         }
00806     }
00807 }
00808 
00809 template<typename T, template<typename U> class Descriptor>
00810 void BlockLatticeDataTransfer2D<T,Descriptor>::attribute_regenerate (
00811         Box2D toDomain, plint deltaX, plint deltaY,
00812         BlockLattice2D<T,Descriptor> const& from )
00813 {
00814     std::vector<char> serializedData;
00815     for (plint iX=toDomain.x0; iX<=toDomain.x1; ++iX) {
00816         for (plint iY=toDomain.y0; iY<=toDomain.y1; ++iY) {
00817             // 1. Generate new dynamics and attribute dynamic content.
00818             serializedData.clear();
00819             serialize (
00820                 from.get(iX+deltaX,iY+deltaY).getDynamics(),
00821                 serializedData );
00822             HierarchicUnserializer unserializer(serializedData, 0);
00823             Dynamics<T,Descriptor>* newDynamics =
00824                 meta::dynamicsRegistration<T,Descriptor>().generate(unserializer);
00825             lattice.attributeDynamics(iX,iY, newDynamics);
00826 
00827             // 2. Attribute static content.
00828             lattice.get(iX,iY).attributeValues (
00829                     from.get(iX+deltaX,iY+deltaY) );
00830         }
00831     }
00832 }
00833 
00834 template<typename T, template<typename U> class Descriptor>
00835 CachePolicy2D& BlockLattice2D<T,Descriptor>::cachePolicy() {
00836     static CachePolicy2D cachePolicySingleton(200);
00837     return cachePolicySingleton;
00838 }
00839 
00840 
00842 
00843 template<typename T, template<typename U> class Descriptor>
00844 double getStoredAverageDensity(BlockLattice2D<T,Descriptor> const& blockLattice) {
00845     return Descriptor<T>::fullRho (
00846                blockLattice.getInternalStatistics().getAverage (
00847                   LatticeStatistics::avRhoBar ) );
00848 }
00849 
00850 template<typename T, template<typename U> class Descriptor>
00851 double getStoredAverageEnergy(BlockLattice2D<T,Descriptor> const& blockLattice) {
00852     return 0.5 * blockLattice.getInternalStatistics().getAverage (
00853                         LatticeStatistics::avUSqr );
00854 }
00855 
00856 template<typename T, template<typename U> class Descriptor>
00857 double getStoredMaxVelocity(BlockLattice2D<T,Descriptor> const& blockLattice) {
00858     return std::sqrt( blockLattice.getInternalStatistics().getMax (
00859                              LatticeStatistics::maxUSqr ) );
00860 }
00861 
00862 }  // namespace plb
00863 
00864 #endif  // BLOCK_LATTICE_2D_HH