$treeview $search $mathjax
Palabos  Version 1.1
$projectbrief
$projectbrief
$searchbox

multiBlockLattice3D.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 MULTI_BLOCK_LATTICE_3D_HH
00029 #define MULTI_BLOCK_LATTICE_3D_HH
00030 
00031 #include "multiBlock/multiBlockLattice3D.h"
00032 #include "atomicBlock/blockLattice3D.h"
00033 #include "multiBlock/defaultMultiBlockPolicy3D.h"
00034 #include "multiBlock/nonLocalTransfer3D.h"
00035 #include "multiBlock/multiBlockGenerator3D.h"
00036 #include "core/latticeStatistics.h"
00037 #include "core/plbTypenames.h"
00038 #include "core/multiBlockIdentifiers3D.h"
00039 #include "core/plbProfiler.h"
00040 #include "core/dynamicsIdentifiers.h"
00041 #include "dataProcessors/metaStuffWrapper3D.h"
00042 #include "coProcessors/coProcessor3D.h"
00043 #include <algorithm>
00044 #include <limits>
00045 #include <cmath>
00046 
00047 
00048 namespace plb {
00049 
00051 
00052 template<typename T, template<typename U> class Descriptor>
00053 const int MultiBlockLattice3D<T,Descriptor>::staticId =
00054 meta::registerMultiBlock3D ( MultiBlockLattice3D<T,Descriptor>::basicType(),
00055                              MultiBlockLattice3D<T,Descriptor>::descriptorType(),
00056                              MultiBlockLattice3D<T,Descriptor>::blockName(),
00057                              defaultGenerateMultiBlockLattice3D<T,Descriptor> );
00058 
00059 template<typename T, template<typename U> class Descriptor>
00060 MultiBlockLattice3D<T,Descriptor>::MultiBlockLattice3D (
00061         MultiBlockManagement3D const& multiBlockManagement_,
00062         BlockCommunicator3D* blockCommunicator_,
00063         CombinedStatistics* combinedStatistics_,
00064         MultiCellAccess3D<T,Descriptor>* multiCellAccess_,
00065         Dynamics<T,Descriptor>* backgroundDynamics_ )
00066     : MultiBlock3D(multiBlockManagement_, blockCommunicator_, combinedStatistics_ ),
00067       backgroundDynamics(backgroundDynamics_),
00068       multiCellAccess(multiCellAccess_)
00069 {
00070     allocateAndInitialize();
00071     eliminateStatisticsInEnvelope();
00072     this->evaluateStatistics(); // Reset statistics to default.
00073 }
00074 
00075 template<typename T, template<typename U> class Descriptor>
00076 MultiBlockLattice3D<T,Descriptor>::MultiBlockLattice3D (
00077         plint nx, plint ny, plint nz,
00078         Dynamics<T,Descriptor>* backgroundDynamics_ )
00079     : MultiBlock3D(nx,ny,nz,Descriptor<T>::vicinity),
00080       backgroundDynamics(backgroundDynamics_),
00081       multiCellAccess(defaultMultiBlockPolicy3D().getMultiCellAccess<T,Descriptor>())
00082 {
00083     allocateAndInitialize();
00084     eliminateStatisticsInEnvelope();
00085     this->evaluateStatistics(); // Reset statistics to default.
00086 }
00087 
00088 template<typename T, template<typename U> class Descriptor>
00089 MultiBlockLattice3D<T,Descriptor>::~MultiBlockLattice3D() {
00090     for ( typename BlockMap::iterator it = blockLattices.begin();
00091           it != blockLattices.end(); ++it)
00092     {
00093         delete it->second;
00094     }
00095     delete backgroundDynamics;
00096     delete multiCellAccess;
00097 }
00098 
00099 template<typename T, template<typename U> class Descriptor>
00100 MultiBlockLattice3D<T,Descriptor>::MultiBlockLattice3D(MultiBlockLattice3D<T,Descriptor> const& rhs)
00101     : BlockLatticeBase3D<T,Descriptor>(rhs),
00102       MultiBlock3D(rhs),
00103       backgroundDynamics(rhs.backgroundDynamics->clone()),
00104       multiCellAccess(rhs.multiCellAccess->clone())
00105 {
00106     for ( typename  BlockMap::const_iterator it = rhs.blockLattices.begin();
00107           it != rhs.blockLattices.end(); ++it )
00108     {
00109         blockLattices[it->first] = new BlockLattice3D<T,Descriptor>(*it->second);
00110     }
00111 }
00112 
00113 template<typename T, template<typename U> class Descriptor>
00114 MultiBlockLattice3D<T,Descriptor>::MultiBlockLattice3D(MultiBlock3D const& rhs)
00115       // Use MultiBlock's sub-domain constructor to avoid that the data-processors are copied
00116     : MultiBlock3D(rhs, rhs.getBoundingBox(), false),
00117       backgroundDynamics(new NoDynamics<T,Descriptor>),
00118       multiCellAccess(defaultMultiBlockPolicy3D().getMultiCellAccess<T,Descriptor>())
00119 {
00120     allocateAndInitialize();
00121     eliminateStatisticsInEnvelope();
00122 }
00123 
00124 template<typename T, template<typename U> class Descriptor>
00125 MultiBlockLattice3D<T,Descriptor>::MultiBlockLattice3D(MultiBlock3D const& rhs, Box3D subDomain, bool crop)
00126     : MultiBlock3D(rhs, subDomain, crop),
00127       backgroundDynamics(new NoDynamics<T,Descriptor>),
00128       multiCellAccess(defaultMultiBlockPolicy3D().getMultiCellAccess<T,Descriptor>())
00129 {
00130     allocateAndInitialize();
00131     eliminateStatisticsInEnvelope();
00132 }
00133 
00134 template<typename T, template<typename U> class Descriptor>
00135 void MultiBlockLattice3D<T,Descriptor>::swap(MultiBlockLattice3D<T,Descriptor>& rhs) {
00136     BlockLatticeBase3D<T,Descriptor>::swap(rhs);
00137     MultiBlock3D::swap(rhs);
00138     std::swap(backgroundDynamics, rhs.backgroundDynamics);
00139     std::swap(multiCellAccess, rhs.multiCellAccess);
00140     blockLattices.swap(rhs.blockLattices);
00141 }
00142 
00143 template<typename T, template<typename U> class Descriptor>
00144 MultiBlockLattice3D<T,Descriptor>& MultiBlockLattice3D<T,Descriptor>::operator= (
00145         MultiBlockLattice3D<T,Descriptor> const& rhs )
00146 {
00147     MultiBlockLattice3D<T,Descriptor> tmp(rhs);
00148     swap(tmp);
00149     return *this;
00150 }
00151 
00152 template<typename T, template<typename U> class Descriptor>
00153 MultiBlockLattice3D<T,Descriptor>*
00154     MultiBlockLattice3D<T,Descriptor>::clone() const
00155 {
00156     return new MultiBlockLattice3D<T,Descriptor>(*this);
00157 }
00158 
00159 template<typename T, template<typename U> class Descriptor>
00160 MultiBlockLattice3D<T,Descriptor>*
00161     MultiBlockLattice3D<T,Descriptor>::clone(MultiBlockManagement3D const& newManagement) const
00162 {
00163     MultiBlockLattice3D<T,Descriptor>* newLattice =
00164         new MultiBlockLattice3D<T,Descriptor> (
00165                 newManagement,
00166                 this->getBlockCommunicator().clone(),
00167                 this->getCombinedStatistics().clone(),
00168                 multiCellAccess->clone(),
00169                 getBackgroundDynamics().clone() );
00170     copy(*this, this->getBoundingBox(), *newLattice, newLattice->getBoundingBox(), modif::dataStructure);
00171     return newLattice;
00172 }
00173 
00174 
00175 template<typename T, template<typename U> class Descriptor>
00176 Dynamics<T,Descriptor> const& MultiBlockLattice3D<T,Descriptor>::getBackgroundDynamics() const {
00177     return *backgroundDynamics;
00178 }
00179 
00180 template<typename T, template<typename U> class Descriptor>
00181 Cell<T,Descriptor>& MultiBlockLattice3D<T,Descriptor>::get(plint iX, plint iY, plint iZ) {
00182     return multiCellAccess -> getDistributedCell(iX,iY,iZ, this->getMultiBlockManagement(), blockLattices);
00183 }
00184 
00185 template<typename T, template<typename U> class Descriptor>
00186 Cell<T,Descriptor> const& MultiBlockLattice3D<T,Descriptor>::get(plint iX, plint iY, plint iZ) const {
00187     return multiCellAccess -> getDistributedCell(iX,iY,iZ, this->getMultiBlockManagement(), blockLattices);
00188 }
00189 
00190 template<typename T, template<typename U> class Descriptor>
00191 void MultiBlockLattice3D<T,Descriptor>::specifyStatisticsStatus (Box3D domain, bool status) {
00192     Box3D inters;
00193     for ( typename BlockMap::iterator it = blockLattices.begin();
00194           it != blockLattices.end(); ++it)
00195     {
00196         SmartBulk3D bulk(this->getMultiBlockManagement(), it->first);
00197         if (intersect(domain, bulk.getBulk(), inters ) ) {
00198             inters = bulk.toLocal(inters);
00199             it->second -> specifyStatisticsStatus(inters, status);
00200         }
00201     }
00202 }
00203 
00204 template<typename T, template<typename U> class Descriptor>
00205 void MultiBlockLattice3D<T,Descriptor>::collide(Box3D domain) {
00206     Box3D inters;
00207     for ( typename BlockMap::iterator it = blockLattices.begin();
00208           it != blockLattices.end(); ++it)
00209     {
00210         SmartBulk3D bulk(this->getMultiBlockManagement(), it->first);
00211         if (intersect(domain, bulk.computeEnvelope(), inters ) ) {
00212             inters = bulk.toLocal(inters);
00213             it->second -> collide(inters);
00214         }
00215     }
00216 }
00217 
00218 template<typename T, template<typename U> class Descriptor>
00219 void MultiBlockLattice3D<T,Descriptor>::collide() {
00220     for ( typename BlockMap::iterator it = blockLattices.begin();
00221           it != blockLattices.end(); ++it)
00222     {
00223         it->second -> collide();
00224     }
00225 }
00226 
00227 template<typename T, template<typename U> class Descriptor>
00228 void MultiBlockLattice3D<T,Descriptor>::stream(Box3D domain) {
00229     Box3D inters;
00230     for ( typename BlockMap::iterator it = blockLattices.begin();
00231           it != blockLattices.end(); ++it)
00232     {
00233         SmartBulk3D bulk(this->getMultiBlockManagement(), it->first);
00234         if (intersect(domain, bulk.computeNonPeriodicEnvelope(), inters ) ) {
00235             inters = bulk.toLocal(inters);
00236             it->second -> stream(inters);
00237         }
00238     }
00239 }
00240 
00241 template<typename T, template<typename U> class Descriptor>
00242 Box3D MultiBlockLattice3D<T,Descriptor>::extendPeriodic(Box3D const& box, plint envelopeWidth) const
00243 {
00244     Box3D boundingBox(this->getBoundingBox());
00245     Box3D periodicBox(box);
00246     bool periodicX = this->periodicity().get(0);
00247     bool periodicY = this->periodicity().get(1);
00248     bool periodicZ = this->periodicity().get(2);
00249     if (periodicX) {
00250         if (periodicBox.x0 == boundingBox.x0) {
00251             periodicBox.x0 -= envelopeWidth;
00252         }
00253         if (periodicBox.x1 == boundingBox.x1) {
00254             periodicBox.x1 += envelopeWidth;
00255         }
00256     }
00257     if (periodicY) {
00258         if (periodicBox.y0 == boundingBox.y0) {
00259             periodicBox.y0 -= envelopeWidth;
00260         }
00261         if (periodicBox.y1 == boundingBox.y1) {
00262             periodicBox.y1 += envelopeWidth;
00263         }
00264     }
00265     if (periodicZ) {
00266         if (periodicBox.z0 == boundingBox.z0) {
00267             periodicBox.z0 -= envelopeWidth;
00268         }
00269         if (periodicBox.z1 == boundingBox.z1) {
00270             periodicBox.z1 += envelopeWidth;
00271         }
00272     }
00273     return periodicBox;
00274 }
00275 
00276 template<typename T, template<typename U> class Descriptor>
00277 void MultiBlockLattice3D<T,Descriptor>::stream() {
00278     for ( typename BlockMap::iterator it = blockLattices.begin();
00279           it != blockLattices.end(); ++it)
00280     {
00281         SmartBulk3D bulk(this->getMultiBlockManagement(), it->first);
00282         // Stream must be applied to full domain, including currently active envelopes.
00283         Box3D domain = extendPeriodic(bulk.computeNonPeriodicEnvelope(),
00284                                       this->getMultiBlockManagement().getEnvelopeWidth());
00285         it->second -> stream( bulk.toLocal(domain) );
00286     }
00287     this->executeInternalProcessors();
00288     this->evaluateStatistics();
00289     this->incrementTime();
00290 }
00291 
00292 template<typename T, template<typename U> class Descriptor>
00293 void MultiBlockLattice3D<T,Descriptor>::collideAndStream(Box3D domain) {
00294     Box3D inters;
00295     for ( typename BlockMap::iterator it = blockLattices.begin();
00296           it != blockLattices.end(); ++it)
00297     {
00298         SmartBulk3D bulk(this->getMultiBlockManagement(), it->first);
00299         if (intersect(domain, bulk.computeNonPeriodicEnvelope(), inters ) ) {
00300             inters = bulk.toLocal(inters);
00301             it->second -> collideAndStream(inters);
00302         }
00303     }
00304 }
00305 
00306 template<typename T, template<typename U> class Descriptor>
00307 void MultiBlockLattice3D<T,Descriptor>::collideAndStream() {
00308     global::profiler().start("cycle");
00309     ThreadAttribution const& threadAttribution=this->getMultiBlockManagement().getThreadAttribution();
00310     if (threadAttribution.hasCoProcessors()) {
00311         for ( typename BlockMap::iterator it = blockLattices.begin();
00312               it != blockLattices.end(); ++it )
00313         {
00314             plint blockId = it->first;
00315             int handle = threadAttribution.getCoProcessorHandle(blockId);
00316             if (handle>=0) {
00317                  global::defaultCoProcessor3D<T>().collideAndStream(handle);
00318             }
00319             else {
00320                 SmartBulk3D bulk(this->getMultiBlockManagement(), blockId);
00321                 // CollideAndStream must be applied to full domain,
00322                 //   including currently active envelopes.
00323                 Box3D domain = extendPeriodic(bulk.computeNonPeriodicEnvelope(),
00324                                               this->getMultiBlockManagement().getEnvelopeWidth());
00325                 it->second -> collideAndStream( bulk.toLocal(domain) );
00326             }
00327         }
00328     }
00329     else  {
00330         for ( typename BlockMap::iterator it = blockLattices.begin();
00331               it != blockLattices.end(); ++it)
00332         {
00333             SmartBulk3D bulk(this->getMultiBlockManagement(), it->first);
00334             // CollideAndStream must be applied to full domain,
00335             //   including currently active envelopes.
00336             Box3D domain = extendPeriodic(bulk.computeNonPeriodicEnvelope(),
00337                                           this->getMultiBlockManagement().getEnvelopeWidth());
00338             it->second -> collideAndStream( bulk.toLocal(domain) );
00339         }
00340     }
00341     this->executeInternalProcessors();
00342     this->evaluateStatistics();
00343     this->incrementTime();
00344     if (global::profiler().cyclingIsAutomatic()) {
00345         global::profiler().cycle();
00346     }
00347     global::profiler().stop("cycle");
00348 }
00349 
00350 template<typename T, template<typename U> class Descriptor>
00351 void MultiBlockLattice3D<T,Descriptor>::incrementTime() {
00352     for ( typename BlockMap::iterator it = blockLattices.begin();
00353           it != blockLattices.end(); ++it)
00354     {
00355         it->second -> incrementTime();
00356     }
00357     this->getTimeCounter().incrementTime();
00358 }
00359 
00360 template<typename T, template<typename U> class Descriptor>
00361 void MultiBlockLattice3D<T,Descriptor>::resetTime(pluint value)
00362 {
00363     for ( typename BlockMap::iterator it = blockLattices.begin();
00364           it != blockLattices.end(); ++it)
00365     {
00366         it->second -> getTimeCounter().resetTime(value);
00367     }
00368     this->getTimeCounter().resetTime(value);
00369 }
00370 
00371 template<typename T, template<typename U> class Descriptor>
00372 void MultiBlockLattice3D<T,Descriptor>::allocateAndInitialize()
00373 {
00374     this->getInternalStatistics().subscribeAverage(); // Subscribe average rho-bar
00375     this->getInternalStatistics().subscribeAverage(); // Subscribe average uSqr
00376     this->getInternalStatistics().subscribeMax();     // Subscribe max uSqr
00377 
00378     for (pluint iBlock=0; iBlock<this->getLocalInfo().getBlocks().size(); ++iBlock) {
00379         plint blockId = this->getLocalInfo().getBlocks()[iBlock];
00380         SmartBulk3D bulk(this->getMultiBlockManagement(), blockId);
00381         Box3D envelope = bulk.computeEnvelope();
00382         BlockLattice3D<T,Descriptor>* newLattice
00383             = new BlockLattice3D<T,Descriptor> (
00384                     envelope.getNx(), envelope.getNy(), envelope.getNz(),
00385                     backgroundDynamics->clone() );
00386         newLattice -> setLocation(Dot3D(envelope.x0, envelope.y0, envelope.z0));
00387         blockLattices[blockId] = newLattice;
00388     }
00389 }
00390 
00391 template<typename T, template<typename U> class Descriptor>
00392 void MultiBlockLattice3D<T,Descriptor>::eliminateStatisticsInEnvelope()
00393 {
00394     for ( typename BlockMap::iterator it = blockLattices.begin();
00395           it != blockLattices.end(); ++it )
00396     {
00397         plint envelopeWidth = this->getMultiBlockManagement().getEnvelopeWidth();
00398         BlockLattice3D<T,Descriptor>& block = *it->second;
00399         plint maxX = block.getNx()-1;
00400         plint maxY = block.getNy()-1;
00401         plint maxZ = block.getNz()-1;
00402         
00403         block.specifyStatisticsStatus(Box3D(0, maxX, 0, maxY, 0, envelopeWidth-1), false);
00404         block.specifyStatisticsStatus(Box3D(0, maxX, 0, maxY, maxZ-envelopeWidth+1, maxZ), false);
00405         block.specifyStatisticsStatus(Box3D(0, maxX, 0, envelopeWidth-1, 0, maxZ), false);
00406         block.specifyStatisticsStatus(Box3D(0, maxX, maxY-envelopeWidth+1, maxY, 0, maxZ), false);
00407         block.specifyStatisticsStatus(Box3D(0, envelopeWidth-1, 0, maxY, 0, maxZ), false);
00408         block.specifyStatisticsStatus(Box3D(maxX-envelopeWidth+1, maxX,  0, maxY, 0, maxZ), false);
00409     }
00410 }
00411 
00412 template<typename T, template<typename U> class Descriptor>
00413 std::map<plint,BlockLattice3D<T,Descriptor>*>&
00414     MultiBlockLattice3D<T,Descriptor>::getBlockLattices()
00415 {
00416     return blockLattices;
00417 }
00418 
00419 template<typename T, template<typename U> class Descriptor>
00420 std::map<plint,BlockLattice3D<T,Descriptor>*> const&
00421     MultiBlockLattice3D<T,Descriptor>::getBlockLattices() const
00422 {
00423     return blockLattices;
00424 }
00425 
00426 template<typename T, template<typename U> class Descriptor>
00427 void MultiBlockLattice3D<T,Descriptor>::getDynamicsDict(Box3D domain, std::map<std::string,int>& dict)
00428 {
00429     std::vector<int> ids;
00430     uniqueDynamicsIds(*this, domain, ids);
00431     dict.clear();
00432     for (pluint i=0; i<ids.size(); ++i) {
00433         int id = ids[i];
00434         std::string name = meta::dynamicsRegistration<T,Descriptor>().getName(id);
00435         dict.insert(std::pair<std::string,int>(name,id));
00436     }
00437 }
00438 
00439 template<typename T, template<typename U> class Descriptor>
00440 std::string MultiBlockLattice3D<T,Descriptor>::getBlockName() const {
00441     return std::string("BlockLattice3D");
00442 }
00443 
00444 template<typename T, template<typename U> class Descriptor>
00445 std::vector<std::string> MultiBlockLattice3D<T,Descriptor>::getTypeInfo() const {
00446     std::vector<std::string> info;
00447     info.push_back(basicType());
00448     info.push_back(descriptorType());
00449     return info;
00450 }
00451 
00452 template<typename T, template<typename U> class Descriptor>
00453 std::string MultiBlockLattice3D<T,Descriptor>::blockName() {
00454     return std::string("BlockLattice3D");
00455 }
00456 
00457 template<typename T, template<typename U> class Descriptor>
00458 std::string MultiBlockLattice3D<T,Descriptor>::basicType() {
00459     return std::string(NativeType<T>::getName());
00460 }
00461 
00462 template<typename T, template<typename U> class Descriptor>
00463 std::string MultiBlockLattice3D<T,Descriptor>::descriptorType() {
00464     return std::string(Descriptor<T>::name);
00465 }
00466 
00467 template<typename T, template<typename U> class Descriptor>
00468 BlockLattice3D<T,Descriptor>& MultiBlockLattice3D<T,Descriptor>::getComponent(plint blockId) {
00469     typename BlockMap::iterator it = blockLattices.find(blockId);
00470     PLB_ASSERT (it != blockLattices.end());
00471     return *it->second;
00472 }
00473 
00474 template<typename T, template<typename U> class Descriptor>
00475 BlockLattice3D<T,Descriptor> const& MultiBlockLattice3D<T,Descriptor>::getComponent(plint blockId) const {
00476     typename BlockMap::const_iterator it = blockLattices.find(blockId);
00477     PLB_ASSERT (it != blockLattices.end());
00478     return *it->second;
00479 }
00480 
00481 template<typename T, template<typename U> class Descriptor>
00482 plint MultiBlockLattice3D<T,Descriptor>::sizeOfCell() const {
00483     return sizeof(T) * (
00484             Descriptor<T>::numPop + Descriptor<T>::ExternalField::numScalars );
00485 }
00486 
00487 template<typename T, template<typename U> class Descriptor>
00488 plint MultiBlockLattice3D<T,Descriptor>::getCellDim() const {
00489     return Descriptor<T>::numPop + Descriptor<T>::ExternalField::numScalars;
00490 }
00491 
00492 template<typename T, template<typename U> class Descriptor>
00493 int MultiBlockLattice3D<T,Descriptor>::getStaticId() const {
00494     return staticId;
00495 }
00496 
00497 template<typename T, template<typename U> class Descriptor>
00498 void MultiBlockLattice3D<T,Descriptor>::copyReceive (
00499                 MultiBlock3D const& fromBlock, Box3D const& fromDomain,
00500                 Box3D const& toDomain, modif::ModifT whichData )
00501 {
00502     MultiBlockLattice3D<T,Descriptor> const* fromLattice =
00503         dynamic_cast<MultiBlockLattice3D<T,Descriptor> const* >(&fromBlock);
00504     PLB_ASSERT( fromLattice );
00505     copy(*fromLattice, fromDomain, *this, toDomain, whichData);
00506 }
00507 
00509 
00510 template<typename T, template<typename U> class Descriptor>
00511 double getStoredAverageDensity(MultiBlockLattice3D<T,Descriptor> const& blockLattice) {
00512     return Descriptor<T>::fullRho (
00513                blockLattice.getInternalStatistics().getAverage (
00514                   LatticeStatistics::avRhoBar ) );
00515 }
00516 
00517 template<typename T, template<typename U> class Descriptor>
00518 double getStoredAverageEnergy(MultiBlockLattice3D<T,Descriptor> const& blockLattice) {
00519     return 0.5 * blockLattice.getInternalStatistics().getAverage (
00520                         LatticeStatistics::avUSqr );
00521 }
00522 
00523 template<typename T, template<typename U> class Descriptor>
00524 double getStoredMaxVelocity(MultiBlockLattice3D<T,Descriptor> const& blockLattice) {
00525     return std::sqrt( blockLattice.getInternalStatistics().getMax (
00526                              LatticeStatistics::maxUSqr ) );
00527 }
00528 
00529 }  // namespace plb
00530 
00531 #endif  // MULTI_BLOCK_LATTICE_3D_HH