|
Palabos
Version 1.0
|
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