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

gridConversion3D.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 
00025 #ifndef GRID_CONVERSION_3D_HH
00026 #define GRID_CONVERSION_3D_HH
00027 
00028 #include <algorithm>
00029 #include "multiGrid/gridConversion3D.h"
00030 #include "finiteDifference/interpolations3D.h"
00031 
00032 namespace plb {
00033 
00034 /* ******************* ScalarCopyFineToCoarseZerothOrder3D ******************* */
00035 
00036 template<typename T>
00037 ScalarCopyFineToCoarseZerothOrder3D<T>::ScalarCopyFineToCoarseZerothOrder3D
00038     (plint dimDx_, plint dimDt_, plint dxScale_, plint dtScale_)
00039         : dimDx(dimDx_), dimDt(dimDt_), dxScale(dxScale_), dtScale(dtScale_)
00040 {
00041     // X scale must be positive because the conversion goes from fine to coarse.
00042     PLB_ASSERT( dxScale >= 1 );
00043 }
00044 
00045 template<typename T>
00046 ScalarCopyFineToCoarseZerothOrder3D<T>::ScalarCopyFineToCoarseZerothOrder3D(
00047             ScalarCopyFineToCoarseZerothOrder3D<T> const& rhs)
00048         : dimDx(rhs.dimDx), dimDt(rhs.dimDt),
00049           dxScale(rhs.dxScale), dtScale(rhs.dtScale)
00050 { }
00051         
00052 template<typename T>
00053 ScalarCopyFineToCoarseZerothOrder3D<T>& 
00054     ScalarCopyFineToCoarseZerothOrder3D<T>::operator= (
00055             ScalarCopyFineToCoarseZerothOrder3D<T> const& rhs )
00056 {
00057     dimDx = rhs.dimDx;
00058     dimDt = rhs.dimDt;
00059     dxScale = rhs.dxScale;
00060     dtScale = rhs.dtScale;
00061 }
00062 
00063 template<typename T>
00064 void ScalarCopyFineToCoarseZerothOrder3D<T>::process (
00065         Box3D fineDomain, ScalarField3D<T>& fineField, ScalarField3D<T>& coarseField )
00066 {
00067     Dot3D posFine = fineField.getLocation();
00068     Dot3D posCoarse = coarseField.getLocation();
00069     
00070     plint stretch = util::twoToThePower(dxScale);
00071     Box3D coarseDomain (
00072             fineDomain.shift(posFine.x,posFine.y, posFine.z).        // Convert to absolute fine coordinates.
00073                 divideAndFitSmaller(stretch).                        // Rescale, but don't exceed original domain.
00074                     shift(-posCoarse.x,-posCoarse.y,-posCoarse.z) ); // Convert to relative coarse coordinates.
00075     PLB_ASSERT( contained(coarseDomain, coarseField.getBoundingBox()) );
00076 
00077     T scaleFactor = scaleFromReference(dxScale, dimDx, dtScale, dimDt);
00078 
00079     plint fineX = (coarseDomain.x0+posCoarse.x)*stretch - posFine.x;
00080     for (plint coarseX=coarseDomain.x0; coarseX<=coarseDomain.x1; ++coarseX, fineX+=stretch) {
00081         plint fineY = (coarseDomain.y0+posCoarse.y)*stretch - posFine.y;
00082         for (plint coarseY=coarseDomain.y0; coarseY<=coarseDomain.y1; ++coarseY, fineY+=stretch) {
00083             plint fineZ = (coarseDomain.z0+posCoarse.z)*stretch - posFine.z;
00084             for (plint coarseZ=coarseDomain.z0; coarseZ<=coarseDomain.z1; ++coarseZ, fineZ+=stretch) {
00085                 coarseField.get(coarseX,coarseY,coarseZ) =
00086                     fineField.get(fineX,fineY,fineZ)*scaleFactor;
00087             }
00088         }
00089     }
00090 }
00091                         
00092 template<typename T>
00093 ScalarCopyFineToCoarseZerothOrder3D<T>* ScalarCopyFineToCoarseZerothOrder3D<T>::clone() const{
00094     return new ScalarCopyFineToCoarseZerothOrder3D<T>(*this);
00095 }
00096 
00097 
00098 /* ******************* TensorCopyFineToCoarseZerothOrder3D ******************* */
00099 
00100 template<typename T, int nDim>
00101 TensorCopyFineToCoarseZerothOrder3D<T,nDim>::TensorCopyFineToCoarseZerothOrder3D
00102     (plint dimDx_, plint dimDt_, plint dxScale_, plint dtScale_)
00103         : dimDx(dimDx_), dimDt(dimDt_), dxScale(dxScale_), dtScale(dtScale_)
00104 {
00105     // X scale must be positive because the conversion goes from fine to coarse.
00106     PLB_ASSERT( dxScale >= 1 );
00107 }
00108 
00109 template<typename T, int nDim>
00110 TensorCopyFineToCoarseZerothOrder3D<T,nDim>::TensorCopyFineToCoarseZerothOrder3D(
00111             TensorCopyFineToCoarseZerothOrder3D<T,nDim> const& rhs)
00112         : dimDx(rhs.dimDx), dimDt(rhs.dimDt),
00113           dxScale(rhs.dxScale), dtScale(rhs.dtScale)
00114 { }
00115         
00116 template<typename T, int nDim>
00117 TensorCopyFineToCoarseZerothOrder3D<T,nDim>& 
00118     TensorCopyFineToCoarseZerothOrder3D<T,nDim>::operator= (
00119             TensorCopyFineToCoarseZerothOrder3D<T,nDim> const& rhs )
00120 {
00121     dimDx = rhs.dimDx;
00122     dimDt = rhs.dimDt;
00123     dxScale = rhs.dxScale;
00124     dtScale = rhs.dtScale;
00125 }
00126 
00127 template<typename T, int nDim>
00128 void TensorCopyFineToCoarseZerothOrder3D<T,nDim>::process (
00129         Box3D fineDomain, TensorField3D<T,nDim>& fineField, TensorField3D<T,nDim>& coarseField )
00130 {
00131     Dot3D posFine = fineField.getLocation();
00132     Dot3D posCoarse = coarseField.getLocation();
00133     
00134     plint stretch = util::twoToThePower(dxScale);
00135     Box3D coarseDomain (
00136             fineDomain.shift(posFine.x,posFine.y, posFine.z).        // Convert to absolute fine coordinates.
00137                 divideAndFitSmaller(stretch).                        // Rescale, but don't exceed original domain.
00138                     shift(-posCoarse.x,-posCoarse.y,-posCoarse.z) ); // Convert to relative coarse coordinates.
00139     PLB_ASSERT( contained(coarseDomain, coarseField.getBoundingBox()) );
00140 
00141     T scaleFactor = scaleFromReference(dxScale, dimDx, dtScale, dimDt);
00142 
00143     plint fineX = (coarseDomain.x0+posCoarse.x)*stretch - posFine.x;
00144     for (plint coarseX=coarseDomain.x0; coarseX<=coarseDomain.x1; ++coarseX, fineX+=stretch) {
00145         plint fineY = (coarseDomain.y0+posCoarse.y)*stretch - posFine.y;
00146         for (plint coarseY=coarseDomain.y0; coarseY<=coarseDomain.y1; ++coarseY, fineY+=stretch) {
00147             plint fineZ = (coarseDomain.z0+posCoarse.z)*stretch - posFine.z;
00148             for (plint coarseZ=coarseDomain.z0; coarseZ<=coarseDomain.z1; ++coarseZ, fineZ+=stretch) {
00149                 coarseField.get(coarseX,coarseY,coarseZ) =
00150                     fineField.get(fineX,fineY,fineZ)*scaleFactor;
00151             }
00152         }
00153     }
00154 }
00155                         
00156 template<typename T, int nDim>
00157 TensorCopyFineToCoarseZerothOrder3D<T,nDim>* TensorCopyFineToCoarseZerothOrder3D<T,nDim>::clone() const{
00158     return new TensorCopyFineToCoarseZerothOrder3D<T,nDim>(*this);
00159 }
00160 
00161 
00162 /* ******************* LatticeCopyFineToCoarseZerothOrder3D ******************* */
00163 
00164 template<typename T, template<typename U> class Descriptor>
00165 LatticeCopyFineToCoarseZerothOrder3D<T,Descriptor>::LatticeCopyFineToCoarseZerothOrder3D
00166     (plint dxScale_, plint dtScale_)
00167         : dxScale(dxScale_), dtScale(dtScale_)
00168 {
00169     // X scale must be positive because the conversion goes from fine to coarse.
00170     PLB_ASSERT( dxScale >= 1 );
00171 }
00172 
00173 template<typename T, template<typename U> class Descriptor>
00174 LatticeCopyFineToCoarseZerothOrder3D<T,Descriptor>::LatticeCopyFineToCoarseZerothOrder3D(
00175             LatticeCopyFineToCoarseZerothOrder3D<T,Descriptor> const& rhs)
00176         : dxScale(rhs.dxScale), dtScale(rhs.dtScale)
00177 { }
00178         
00179 template<typename T, template<typename U> class Descriptor>
00180 LatticeCopyFineToCoarseZerothOrder3D<T,Descriptor>& 
00181     LatticeCopyFineToCoarseZerothOrder3D<T,Descriptor>::operator= (
00182             LatticeCopyFineToCoarseZerothOrder3D<T,Descriptor> const& rhs )
00183 {
00184     dxScale = rhs.dxScale;
00185     dtScale = rhs.dtScale;
00186 }
00187 
00188 template<typename T, template<typename U> class Descriptor>
00189 void LatticeCopyFineToCoarseZerothOrder3D<T,Descriptor>::process (
00190         Box3D fineDomain,
00191         BlockLattice3D<T,Descriptor>& fineLattice, BlockLattice3D<T,Descriptor>& coarseLattice )
00192 {
00193     static const int velDimDx =   1;
00194     static const int velDimDt =  -1;
00195     static const int presDimDx =  2;
00196     static const int presDimDt = -2;
00197     static const int viscDimDx =  2;
00198     static const int viscDimDt = -1;
00199     static const int fNeqDimDx =  0;
00200     static const int fNeqDimDt = -1;
00201     T velScale = scaleFromReference(dxScale, velDimDx, dtScale, velDimDt);
00202     T presScale = scaleFromReference(dxScale, presDimDx, dtScale, presDimDt);
00203     T viscScale = scaleFromReference(dxScale, viscDimDx, dtScale, viscDimDt);
00204     T fNeqScale = scaleFromReference(dxScale, fNeqDimDx, dtScale, fNeqDimDt);
00205 
00206     Dot3D posFine = fineLattice.getLocation();
00207     Dot3D posCoarse = coarseLattice.getLocation();
00208     
00209     plint stretch = util::twoToThePower(dxScale);
00210     Box3D coarseDomain (
00211             fineDomain.shift(posFine.x,posFine.y, posFine.z).        // Convert to absolute fine coordinates.
00212                 divideAndFitSmaller(stretch).                        // Rescale, but don't exceed original domain.
00213                     shift(-posCoarse.x,-posCoarse.y,-posCoarse.z) ); // Convert to relative coarse coordinates.
00214     PLB_ASSERT( contained(coarseDomain, coarseLattice.getBoundingBox()) );
00215 
00216     plint fineX = (coarseDomain.x0+posCoarse.x)*stretch - posFine.x;
00217     for (plint coarseX=coarseDomain.x0; coarseX<=coarseDomain.x1; ++coarseX, fineX+=stretch) {
00218         plint fineY = (coarseDomain.y0+posCoarse.y)*stretch - posFine.y;
00219         for (plint coarseY=coarseDomain.y0; coarseY<=coarseDomain.y1; ++coarseY, fineY+=stretch) {
00220             plint fineZ = (coarseDomain.z0+posCoarse.z)*stretch - posFine.z;
00221             for (plint coarseZ=coarseDomain.z0; coarseZ<=coarseDomain.z1; ++coarseZ, fineZ+=stretch) {
00222                 // Fine --> Coarse
00223                 Cell<T,Descriptor> const& fineCell = fineLattice.get(fineX,fineY,fineZ);
00224                 Cell<T,Descriptor>& coarseCell = coarseLattice.get(coarseX,coarseY,coarseZ);
00225                 T fineOmega = fineCell.getDynamics().getOmega();
00226                 T fine_nu_cs2 = 1./fineOmega - 0.5;
00227                 T coarse_nu_cs2 = viscScale * fine_nu_cs2;
00228                 T coarseOmega = 1. / (coarse_nu_cs2+0.5);
00229                 coarseCell.getDynamics().setOmega(coarseOmega);
00230 
00231                 T localFneqScale = fNeqScale * fineOmega / coarseOmega;
00232                 plint numComponents = 1+Descriptor<T>::d+Descriptor<T>::q+Descriptor<T>::ExternalField::numScalars;
00233                 // TODO: For now external scalars are set to zero during conversion. They should be
00234                 //   rescaled properly.
00235                 std::vector<T> components(numComponents);
00236                 std::fill(components.begin(), components.end(), 0.);
00237                 plint order = 0;
00238                 fineCell.getDynamics().decompose(fineCell, components, order);
00239                 T rhoFine = Descriptor<T>::fullRho(components[0]);
00240                 if (!fineCell.getDynamics().velIsJ()) {
00241                     for (plint iDim=0; iDim<Descriptor<T>::d; ++iDim) {
00242                         components[1+iDim] /= rhoFine;
00243                     }
00244                 }
00245                 // 1. Density.
00246                 T p_cs2 = components[0]-(1-Descriptor<T>::SkordosFactor());
00247                 components[0] = (1-Descriptor<T>::SkordosFactor()) + p_cs2*presScale;
00248                 // 2. Velocity.
00249                 for (plint iDim=0; iDim<Descriptor<T>::d; ++iDim) {
00250                     components[1+iDim] *= velScale;
00251                 }
00252                 // 3. Off-equilibrium populations.
00253                 for (plint iPop=0; iPop<Descriptor<T>::q; ++iPop) {
00254                     components[1+Descriptor<T>::d+iPop] *= localFneqScale;
00255                 }
00256                 T rhoCoarse = Descriptor<T>::fullRho(components[0]);
00257                 if (!coarseCell.getDynamics().velIsJ()) {
00258                     for (plint iDim=0; iDim<Descriptor<T>::d; ++iDim) {
00259                         components[1+iDim] *= rhoCoarse;
00260                     }
00261                 }
00262                 //coarseCell.getDynamics().recompose(coarseCell, components, order);
00263                 // For recomposition, get the dynamics from the fine cell, because the fine/coarse dynamics
00264                 // may not have the same number of variables in the decomposed vector.
00265                 fineCell.getDynamics().recompose(coarseCell, components, order);
00266             }
00267         }
00268     }
00269 }
00270                         
00271 template<typename T, template<typename U> class Descriptor>
00272 LatticeCopyFineToCoarseZerothOrder3D<T,Descriptor>* LatticeCopyFineToCoarseZerothOrder3D<T,Descriptor>::clone() const{
00273     return new LatticeCopyFineToCoarseZerothOrder3D<T,Descriptor>(*this);
00274 }
00275 
00276 
00277 /* ******************* CopyRescaleParticles3D ******************* */
00278 
00279 template<typename T, template<typename U> class Descriptor>
00280 CopyRescaleParticles3D<T,Descriptor>::CopyRescaleParticles3D(plint dxScale_, plint dtScale_)
00281         : dxScale(dxScale_), dtScale(dtScale_)
00282 { }
00283 
00284 template<typename T, template<typename U> class Descriptor>
00285 void CopyRescaleParticles3D<T,Descriptor>::processGenericBlocks (
00286         Box3D domain1, std::vector<AtomicBlock3D*> blocks )
00287 {
00288     PLB_PRECONDITION( blocks.size()==2 );
00289     ParticleField3D<T,Descriptor>& field1 =
00290         *dynamic_cast<ParticleField3D<T,Descriptor>*>(blocks[0]);
00291     ParticleField3D<T,Descriptor>& field2 =
00292         *dynamic_cast<ParticleField3D<T,Descriptor>*>(blocks[1]);
00293 
00294     Box3D domain2(field2.getBoundingBox());
00295     std::vector<Particle3D<T,Descriptor>*> particles;
00296     field1.findParticles(domain1, particles);
00297     for (pluint iParticle=0; iParticle<particles.size(); ++iParticle) {
00298         Particle3D<T,Descriptor>* newparticle = particles[iParticle]->clone();
00299         newparticle->rescale(dxScale, dtScale);
00300         field2.addParticle(domain2, newparticle);
00301     }
00302 }
00303 
00304                         
00305 template<typename T, template<typename U> class Descriptor>
00306 CopyRescaleParticles3D<T,Descriptor>* CopyRescaleParticles3D<T,Descriptor>::clone() const{
00307     return new CopyRescaleParticles3D<T,Descriptor>(*this);
00308 }
00309 
00310 
00311 /* ******************* ScalarInterpolateCoarseToFine3D ******************* */
00312 
00313 template<typename T>
00314 ScalarInterpolateCoarseToFine3D<T>::ScalarInterpolateCoarseToFine3D
00315     (plint dimDx_, plint dimDt_, plint dxScale_, plint dtScale_)
00316         : dimDx(dimDx_), dimDt(dimDt_), dxScale(dxScale_), dtScale(dtScale_)
00317 {
00318     // X scale must be negative because the conversion goes from coarse to fine.
00319     PLB_ASSERT( dxScale <= -1 );
00320 }
00321 
00322 template<typename T>
00323 ScalarInterpolateCoarseToFine3D<T>::ScalarInterpolateCoarseToFine3D(
00324             ScalarInterpolateCoarseToFine3D<T> const& rhs)
00325         : dimDx(rhs.dimDx), dimDt(rhs.dimDt),
00326           dxScale(rhs.dxScale), dtScale(rhs.dtScale)
00327 { }
00328         
00329 template<typename T>
00330 ScalarInterpolateCoarseToFine3D<T>& 
00331     ScalarInterpolateCoarseToFine3D<T>::operator= (
00332             ScalarInterpolateCoarseToFine3D<T> const& rhs )
00333 {
00334     dimDx = rhs.dimDx;
00335     dimDt = rhs.dimDt;
00336     dxScale = rhs.dxScale;
00337     dtScale = rhs.dtScale;
00338 }
00339 
00340 template<typename T>
00341 void ScalarInterpolateCoarseToFine3D<T>::process (
00342         Box3D coarseDomain,
00343         ScalarField3D<T>& coarseField, ScalarField3D<T>& fineField )
00344 {
00345     Dot3D posFine = fineField.getLocation();
00346     Dot3D posCoarse = coarseField.getLocation();
00347     
00348     plint stretch = util::twoToThePower(-dxScale);
00349     T scaleFactor = scaleFromReference(dxScale, dimDx, dtScale, dimDt);
00350 
00351     std::vector<Dot3D> cellPos;
00352     std::vector<T> weights;
00353     for (plint coarseX=coarseDomain.x0; coarseX<=coarseDomain.x1; ++coarseX) {
00354         plint fineX = (coarseX+posCoarse.x)*stretch - posFine.x;
00355         for (plint coarseY=coarseDomain.y0; coarseY<=coarseDomain.y1; ++coarseY) {
00356             plint fineY = (coarseY+posCoarse.y)*stretch - posFine.y;
00357             for (plint coarseZ=coarseDomain.z0; coarseZ<=coarseDomain.z1; ++coarseZ) {
00358                 plint fineZ = (coarseZ+posCoarse.z)*stretch - posFine.z;
00359                 for (plint iX=fineX-stretch/2+1; iX<=fineX+stretch/2; ++iX) {
00360                 for (plint iY=fineY-stretch/2+1; iY<=fineY+stretch/2; ++iY) {
00361                 for (plint iZ=fineZ-stretch/2+1; iZ<=fineZ+stretch/2; ++iZ) {
00362                     if (contained(iX,iY,iZ, fineField.getBoundingBox())) {
00363                         T coarseIx = (T)(iX + posFine.x)/(T)stretch;
00364                         T coarseIy = (T)(iY + posFine.y)/(T)stretch;
00365                         T coarseIz = (T)(iZ + posFine.z)/(T)stretch;
00366                         linearInterpolationCoefficients<T>(coarseField, Array<T,3> (
00367                                     coarseIx, coarseIy, coarseIz), cellPos, weights );
00368                         fineField.get(iX,iY,iZ) = 0.;
00369                         for (plint i=0; i<8; ++i) {
00370                             fineField.get(iX,iY,iZ) +=
00371                                 weights[i] * coarseField.get(cellPos[i].x, cellPos[i].y, cellPos[i].z);
00372                         }
00373                         fineField.get(iX,iY,iZ) *= scaleFactor;
00374                     }
00375                 } } }
00376             }
00377         }
00378     }
00379 }
00380                         
00381 template<typename T>
00382 ScalarInterpolateCoarseToFine3D<T>* ScalarInterpolateCoarseToFine3D<T>::clone() const{
00383     return new ScalarInterpolateCoarseToFine3D<T>(*this);
00384 }
00385 
00386 
00387 
00388 /* ******************* TensorInterpolateCoarseToFine3D ******************* */
00389 
00390 template<typename T, int nDim>
00391 TensorInterpolateCoarseToFine3D<T,nDim>::TensorInterpolateCoarseToFine3D
00392     (plint dimDx_, plint dimDt_, plint dxScale_, plint dtScale_)
00393         : dimDx(dimDx_), dimDt(dimDt_), dxScale(dxScale_), dtScale(dtScale_)
00394 {
00395     // X scale must be negative because the conversion goes from coarse to fine.
00396     PLB_ASSERT( dxScale <= -1 );
00397 }
00398 
00399 template<typename T, int nDim>
00400 TensorInterpolateCoarseToFine3D<T,nDim>::TensorInterpolateCoarseToFine3D(
00401             TensorInterpolateCoarseToFine3D<T,nDim> const& rhs)
00402         : dimDx(rhs.dimDx), dimDt(rhs.dimDt),
00403           dxScale(rhs.dxScale), dtScale(rhs.dtScale)
00404 { }
00405         
00406 template<typename T, int nDim>
00407 TensorInterpolateCoarseToFine3D<T,nDim>& 
00408     TensorInterpolateCoarseToFine3D<T,nDim>::operator= (
00409             TensorInterpolateCoarseToFine3D<T,nDim> const& rhs )
00410 {
00411     dimDx = rhs.dimDx;
00412     dimDt = rhs.dimDt;
00413     dxScale = rhs.dxScale;
00414     dtScale = rhs.dtScale;
00415 }
00416 
00417 template<typename T, int nDim>
00418 void TensorInterpolateCoarseToFine3D<T,nDim>::process (
00419         Box3D coarseDomain,
00420         TensorField3D<T,nDim>& coarseField, TensorField3D<T,nDim>& fineField )
00421 {
00422     Dot3D posFine = fineField.getLocation();
00423     Dot3D posCoarse = coarseField.getLocation();
00424     
00425     plint stretch = util::twoToThePower(-dxScale);
00426     T scaleFactor = scaleFromReference(dxScale, dimDx, dtScale, dimDt);
00427 
00428     std::vector<Dot3D> cellPos;
00429     std::vector<T> weights;
00430     for (plint coarseX=coarseDomain.x0; coarseX<=coarseDomain.x1; ++coarseX) {
00431         plint fineX = (coarseX+posCoarse.x)*stretch - posFine.x;
00432         for (plint coarseY=coarseDomain.y0; coarseY<=coarseDomain.y1; ++coarseY) {
00433             plint fineY = (coarseY+posCoarse.y)*stretch - posFine.y;
00434             for (plint coarseZ=coarseDomain.z0; coarseZ<=coarseDomain.z1; ++coarseZ) {
00435                 plint fineZ = (coarseZ+posCoarse.z)*stretch - posFine.z;
00436                 for (plint iX=fineX-stretch/2+1; iX<=fineX+stretch/2; ++iX) {
00437                 for (plint iY=fineY-stretch/2+1; iY<=fineY+stretch/2; ++iY) {
00438                 for (plint iZ=fineZ-stretch/2+1; iZ<=fineZ+stretch/2; ++iZ) {
00439                     if (contained(iX,iY,iZ, fineField.getBoundingBox())) {
00440                         T coarseIx = (T)(iX + posFine.x)/(T)stretch;
00441                         T coarseIy = (T)(iY + posFine.y)/(T)stretch;
00442                         T coarseIz = (T)(iZ + posFine.z)/(T)stretch;
00443                         linearInterpolationCoefficients(coarseField, Array<T,3> (
00444                                     coarseIx, coarseIy, coarseIz), cellPos, weights );
00445                         fineField.get(iX,iY,iZ).resetToZero();
00446                         for (plint i=0; i<8; ++i) {
00447                             fineField.get(iX,iY,iZ) +=
00448                                 weights[i] * coarseField.get(cellPos[i].x, cellPos[i].y, cellPos[i].z);
00449                         }
00450                         fineField.get(iX,iY,iZ) *= scaleFactor;
00451                     }
00452                 } } }
00453             }
00454         }
00455     }
00456 }
00457                         
00458 template<typename T, int nDim>
00459 TensorInterpolateCoarseToFine3D<T,nDim>* TensorInterpolateCoarseToFine3D<T,nDim>::clone() const{
00460     return new TensorInterpolateCoarseToFine3D<T,nDim>(*this);
00461 }
00462 
00463 
00464 
00465 /* ******************* LatticeInterpolateCoarseToFine3D ******************* */
00466 
00467 template<typename T, template<typename U> class Descriptor>
00468 LatticeInterpolateCoarseToFine3D<T,Descriptor>::LatticeInterpolateCoarseToFine3D
00469     (plint dxScale_, plint dtScale_)
00470         : dxScale(dxScale_), dtScale(dtScale_)
00471 {
00472     // X scale must be negative because the conversion goes from coarse to fine.
00473     PLB_ASSERT( dxScale <= -1 );
00474 }
00475 
00476 template<typename T, template<typename U> class Descriptor>
00477 LatticeInterpolateCoarseToFine3D<T,Descriptor>::LatticeInterpolateCoarseToFine3D(
00478             LatticeInterpolateCoarseToFine3D<T,Descriptor> const& rhs)
00479         : dxScale(rhs.dxScale), dtScale(rhs.dtScale)
00480 { }
00481         
00482 template<typename T, template<typename U> class Descriptor>
00483 LatticeInterpolateCoarseToFine3D<T,Descriptor>& 
00484     LatticeInterpolateCoarseToFine3D<T,Descriptor>::operator= (
00485             LatticeInterpolateCoarseToFine3D<T,Descriptor> const& rhs )
00486 {
00487     dxScale = rhs.dxScale;
00488     dtScale = rhs.dtScale;
00489 }
00490 
00491 template<typename T, template<typename U> class Descriptor>
00492 void LatticeInterpolateCoarseToFine3D<T,Descriptor>::process (
00493         Box3D coarseDomain,
00494         BlockLattice3D<T,Descriptor>& coarseLattice, BlockLattice3D<T,Descriptor>& fineLattice )
00495 {
00496     static const int velDimDx =   1;
00497     static const int velDimDt =  -1;
00498     static const int presDimDx =  2;
00499     static const int presDimDt = -2;
00500     static const int viscDimDx =  2;
00501     static const int viscDimDt = -1;
00502     static const int fNeqDimDx =  0;
00503     static const int fNeqDimDt = -1;
00504     T velScale = scaleFromReference(dxScale, velDimDx, dtScale, velDimDt);
00505     T presScale = scaleFromReference(dxScale, presDimDx, dtScale, presDimDt);
00506     T viscScale = scaleFromReference(dxScale, viscDimDx, dtScale, viscDimDt);
00507     T fNeqScale = scaleFromReference(dxScale, fNeqDimDx, dtScale, fNeqDimDt);
00508 
00509     Dot3D posFine = fineLattice.getLocation();
00510     Dot3D posCoarse = coarseLattice.getLocation();
00511     
00512     plint stretch = util::twoToThePower(-dxScale);
00513 
00514     std::vector<Dot3D> cellPos;
00515     std::vector<T> weights;
00516     for (plint coarseX=coarseDomain.x0; coarseX<=coarseDomain.x1; ++coarseX) {
00517         plint fineX = (coarseX+posCoarse.x)*stretch - posFine.x;
00518         for (plint coarseY=coarseDomain.y0; coarseY<=coarseDomain.y1; ++coarseY) {
00519             plint fineY = (coarseY+posCoarse.y)*stretch - posFine.y;
00520             for (plint coarseZ=coarseDomain.z0; coarseZ<=coarseDomain.z1; ++coarseZ) {
00521                 plint fineZ = (coarseZ+posCoarse.z)*stretch - posFine.z;
00522                 for (plint iX=fineX-stretch/2+1; iX<=fineX+stretch/2; ++iX) {
00523                 for (plint iY=fineY-stretch/2+1; iY<=fineY+stretch/2; ++iY) {
00524                 for (plint iZ=fineZ-stretch/2+1; iZ<=fineZ+stretch/2; ++iZ) {
00525                     if (contained(iX,iY,iZ, fineLattice.getBoundingBox())) {
00526                         T coarseIx = (T)(iX + posFine.x)/(T)stretch;
00527                         T coarseIy = (T)(iY + posFine.y)/(T)stretch;
00528                         T coarseIz = (T)(iZ + posFine.z)/(T)stretch;
00529                         linearInterpolationCoefficients(coarseLattice, Array<T,3> (
00530                                     coarseIx, coarseIy, coarseIz), cellPos, weights );
00531                         plint order = 0;
00532                         plint numComponents = 1+Descriptor<T>::d+Descriptor<T>::q+Descriptor<T>::ExternalField::numScalars;
00533                         // TODO: For now external scalars are set to zero during conversion. They should be
00534                         //   rescaled properly.
00535                         std::vector<T> components(numComponents), oldComponents(numComponents);
00536                         std::fill(components.begin(), components.end(), 0.);
00537                         T coarse_nu_cs2 = 0.;
00538                         components[0] = 1-Descriptor<T>::SkordosFactor(); // Density offset.
00539                         for (plint i=0; i<8; ++i) {
00540                             Cell<T,Descriptor> const& coarseCell =
00541                                     coarseLattice.get(cellPos[i].x, cellPos[i].y, cellPos[i].z);
00542                             T coarseOmega = coarseCell.getDynamics().getOmega();
00543                             T coarse_nu_cs2 = 1./coarseOmega - 0.5;
00544                             coarse_nu_cs2 += weights[i]*coarse_nu_cs2;
00545                             coarseCell.getDynamics().decompose(coarseCell, oldComponents, order);
00546                             T coarseRho = Descriptor<T>::fullRho(oldComponents[0]);
00547                             // 1. Density
00548                             T pres_cs2 = oldComponents[0]-(1-Descriptor<T>::SkordosFactor());
00549                             components[0] += weights[i]*pres_cs2*presScale;
00550                             // 2. Velocity.
00551                             Array<T,3> vel;
00552                             coarseCell.computeVelocity(vel);
00553                             T multFactor = weights[i]*velScale;
00554                             if (!coarseCell.getDynamics().velIsJ()) {
00555                                 multFactor /= coarseRho;
00556                             }
00557                             for (plint iDim=0; iDim<Descriptor<T>::d; ++iDim) {
00558                                 components[1+iDim] += multFactor*oldComponents[1+iDim];
00559                             }
00560                             // 3. Off-equilibrium populations.
00561                             for (plint iPop=0; iPop<Descriptor<T>::q; ++iPop) {
00562                                 components[1+Descriptor<T>::d+iPop] += weights[i]*fNeqScale*
00563                                                                        oldComponents[1+Descriptor<T>::d+iPop];
00564                             }
00565                         }
00566                         Cell<T,Descriptor>& fineCell = fineLattice.get(iX,iY,iZ);
00567                         T fineRho = Descriptor<T>::fullRho(components[0]);
00568                         if (!fineCell.getDynamics().velIsJ()) {
00569                             for (plint iDim=0; iDim<Descriptor<T>::d; ++iDim) {
00570                                 components[1+iDim] *= fineRho;
00571                             }
00572                         }
00573                         T fine_nu_cs2 = coarse_nu_cs2*viscScale;
00574                         T coarseOmega = 1. / (coarse_nu_cs2+0.5);
00575                         T fineOmega = 1. / (fine_nu_cs2+0.5);
00576                         T omegaRatio = coarseOmega / fineOmega;
00577                         for (plint iPop=0; iPop<Descriptor<T>::q; ++iPop) {
00578                             components[1+Descriptor<T>::d+iPop] *= omegaRatio;
00579                         }
00580                         fineCell.getDynamics().setOmega(fineOmega);
00581                         fineCell.getDynamics().recompose(fineCell, components, order);
00582                     }
00583                 } } }
00584             }
00585         }
00586     }
00587 }
00588 
00589 template<typename T, template<typename U> class Descriptor>
00590 LatticeInterpolateCoarseToFine3D<T,Descriptor>* LatticeInterpolateCoarseToFine3D<T,Descriptor>::clone() const{
00591     return new LatticeInterpolateCoarseToFine3D<T,Descriptor>(*this);
00592 }
00593 
00594 
00595 /* ******************* Free functions ******************* */
00596 
00597 inline Box3D scaleBox(Box3D box, plint nLevel)
00598 {
00599     if (nLevel>0) {
00600         return box.multiply(util::twoToThePower(nLevel));
00601     }
00602     else if (nLevel<0) {
00603         // If the fine-grid box does not fit with the coarse-grid box,
00604         //   let's shrink the coarse-grid box by one fine cell. This
00605         //   makes sure we'll never exceed the fine-grid box
00606         return box.divideAndFitSmaller(util::twoToThePower(-nLevel));
00607     }
00608     else {
00609         return box;
00610     }
00611 }
00612 
00613 inline MultiBlockManagement3D scaleMultiBlockManagement (
00614         MultiBlockManagement3D const& multiBlockManagement, plint nLevel )
00615 {
00616     SparseBlockStructure3D const& sparseBlock = multiBlockManagement.getSparseBlockStructure();
00617 
00618     Box3D rescaledBoundingBox = scaleBox(sparseBlock.getBoundingBox(), nLevel);
00619     SparseBlockStructure3D scaledSparseBlock(rescaledBoundingBox);
00620     plint stretch = util::twoToThePower(nLevel);
00621 
00622     std::map<plint,Box3D>::const_iterator it = sparseBlock.getBulks().begin();
00623     for (; it != sparseBlock.getBulks().end(); ++it) {
00624         Box3D scaledBulk = scaleBox(it->second, nLevel);
00625         if (stretch>1) {
00626             scaledBulk.x0 -= stretch/2-1;
00627             scaledBulk.y0 -= stretch/2-1;
00628             scaledBulk.z0 -= stretch/2-1;
00629             scaledBulk.x1 += stretch/2;
00630             scaledBulk.y1 += stretch/2;
00631             scaledBulk.z1 += stretch/2;
00632         }
00633         Box3D scaledUniqueBulk = scaledBulk; //TODO: compute unique bulk properly.
00634         plint blockId = it->first;
00635         scaledSparseBlock.addBlock(scaledBulk, scaledUniqueBulk, blockId);
00636     }
00637     return MultiBlockManagement3D (
00638                scaledSparseBlock,
00639                multiBlockManagement.getThreadAttribution().clone(),
00640                multiBlockManagement.getEnvelopeWidth(),
00641                multiBlockManagement.getRefinementLevel()+nLevel );
00642 }
00643 
00644 
00645 template<typename T>
00646 std::auto_ptr<MultiScalarField3D<T> > coarsen (
00647         MultiScalarField3D<T>& fineField,
00648         plint dimDx, plint dimDt, plint dxScale, plint dtScale )
00649 {
00650     PLB_PRECONDITION( dxScale>=1 );
00651     // Relative level is negative when going from fine to coarse.
00652     plint relativeLevel = -dxScale;
00653     MultiBlockManagement3D management = scaleMultiBlockManagement(fineField.getMultiBlockManagement(),relativeLevel);
00654     MultiScalarField3D<T>* result =  new MultiScalarField3D<T> ( 
00655                             management,
00656                             defaultMultiBlockPolicy3D().getBlockCommunicator(),
00657                             defaultMultiBlockPolicy3D().getCombinedStatistics(),
00658                             defaultMultiBlockPolicy3D().getMultiScalarAccess<T>() );
00659     applyProcessingFunctional (
00660             new ScalarCopyFineToCoarseZerothOrder3D<T>(dimDx,dimDt,dxScale,dtScale),
00661             fineField.getBoundingBox(), fineField, *result );
00662                             
00663     return std::auto_ptr<MultiScalarField3D<T> >(result);
00664 }
00665 
00666 template<typename T, int nDim>
00667 std::auto_ptr<MultiTensorField3D<T,nDim> > coarsen (
00668         MultiTensorField3D<T,nDim>& fineField,
00669         plint dimDx, plint dimDt, plint dxScale, plint dtScale )
00670 {
00671     PLB_PRECONDITION( dxScale>=1 );
00672     // Relative level is negative when going from fine to coarse.
00673     plint relativeLevel = -dxScale;
00674     MultiBlockManagement3D management = scaleMultiBlockManagement(fineField.getMultiBlockManagement(),relativeLevel);
00675     MultiTensorField3D<T,nDim>* result =  new MultiTensorField3D<T,nDim> ( 
00676                             management,
00677                             defaultMultiBlockPolicy3D().getBlockCommunicator(),
00678                             defaultMultiBlockPolicy3D().getCombinedStatistics(),
00679                             defaultMultiBlockPolicy3D().getMultiTensorAccess<T,nDim>() );
00680     applyProcessingFunctional (
00681             new TensorCopyFineToCoarseZerothOrder3D<T,nDim>(dimDx,dimDt,dxScale,dtScale),
00682             fineField.getBoundingBox(), fineField, *result );
00683                             
00684     return std::auto_ptr<MultiTensorField3D<T,nDim> >(result);
00685 }
00686 
00687 template <typename T>
00688 std::auto_ptr<MultiScalarField3D<T> > refine (
00689         MultiScalarField3D<T>& coarseField,
00690         plint dimDx, plint dimDt, plint dxScale, plint dtScale )
00691 {
00692     PLB_PRECONDITION( dxScale<=-1 );
00693     // Relative level is positive when going from coarse to fine.
00694     plint relativeLevel = -dxScale;
00695     MultiBlockManagement3D management
00696         = scaleMultiBlockManagement(coarseField.getMultiBlockManagement(),relativeLevel);
00697     MultiScalarField3D<T>* result = new MultiScalarField3D<T> ( 
00698                             management,
00699                             defaultMultiBlockPolicy3D().getBlockCommunicator(),
00700                             defaultMultiBlockPolicy3D().getCombinedStatistics(),
00701                             defaultMultiBlockPolicy3D().getMultiScalarAccess<T>() );
00702     applyProcessingFunctional (
00703             new ScalarInterpolateCoarseToFine3D<T>(dimDx,dimDt,dxScale,dtScale),
00704             coarseField.getBoundingBox(), coarseField, *result );
00705                             
00706     return std::auto_ptr<MultiScalarField3D<T> >(result);
00707 }
00708 
00709 template <typename T, int nDim>
00710 std::auto_ptr<MultiTensorField3D<T,nDim> > refine (
00711         MultiTensorField3D<T,nDim>& coarseField,
00712         plint dimDx, plint dimDt, plint dxScale, plint dtScale )
00713 {
00714     PLB_PRECONDITION( dxScale<=-1 );
00715     // Relative level is positive when going from coarse to fine.
00716     plint relativeLevel = -dxScale;
00717     MultiBlockManagement3D management
00718         = scaleMultiBlockManagement(coarseField.getMultiBlockManagement(),relativeLevel);
00719     MultiTensorField3D<T,nDim>* result =  new MultiTensorField3D<T,nDim> ( 
00720                             management,
00721                             defaultMultiBlockPolicy3D().getBlockCommunicator(),
00722                             defaultMultiBlockPolicy3D().getCombinedStatistics(),
00723                             defaultMultiBlockPolicy3D().getMultiTensorAccess<T,nDim>() );
00724     applyProcessingFunctional (
00725             new TensorInterpolateCoarseToFine3D<T,nDim>(dimDx,dimDt,dxScale,dtScale),
00726             coarseField.getBoundingBox(), coarseField, *result );
00727                             
00728     return std::auto_ptr<MultiTensorField3D<T,nDim> >(result);
00729 }
00730 
00731 template<typename T, template<typename U> class Descriptor>
00732 std::auto_ptr<MultiBlockLattice3D<T,Descriptor> > coarsen (
00733         MultiBlockLattice3D<T,Descriptor>& fineLattice,
00734         plint dxScale, plint dtScale, Dynamics<T,Descriptor>* backgroundDynamics )
00735 {
00736     PLB_PRECONDITION( dxScale>=1 );
00737     // Relative level is negative when going from fine to coarse.
00738     plint relativeLevel = -dxScale;
00739     MultiBlockManagement3D management =
00740         scaleMultiBlockManagement(fineLattice.getMultiBlockManagement(),relativeLevel);
00741     MultiBlockLattice3D<T,Descriptor>* result = new MultiBlockLattice3D<T,Descriptor> ( 
00742                             management,
00743                             defaultMultiBlockPolicy3D().getBlockCommunicator(),
00744                             defaultMultiBlockPolicy3D().getCombinedStatistics(),
00745                             defaultMultiBlockPolicy3D().getMultiCellAccess<T,Descriptor>(),
00746                             backgroundDynamics->clone() );
00747     defineDynamics(*result, result->getBoundingBox(), backgroundDynamics);
00748     applyProcessingFunctional (
00749             new LatticeCopyFineToCoarseZerothOrder3D<T,Descriptor>(dxScale,dtScale),
00750             fineLattice.getBoundingBox(), fineLattice, *result );
00751                             
00752     return std::auto_ptr<MultiBlockLattice3D<T,Descriptor> >(result);
00753 }
00754 
00755 template<typename T, template<typename U> class Descriptor>
00756 std::auto_ptr<MultiBlockLattice3D<T,Descriptor> > refine (
00757         MultiBlockLattice3D<T,Descriptor>& coarseLattice,
00758         plint dxScale, plint dtScale, Dynamics<T,Descriptor>* backgroundDynamics )
00759 {
00760     PLB_PRECONDITION( dxScale<=-1 );
00761     // Relative level is positive when going from coarse to fine.
00762     plint relativeLevel = -dxScale;
00763     MultiBlockManagement3D management
00764         = scaleMultiBlockManagement(coarseLattice.getMultiBlockManagement(),relativeLevel);
00765     MultiBlockLattice3D<T,Descriptor>* result = new MultiBlockLattice3D<T,Descriptor> ( 
00766                             management,
00767                             defaultMultiBlockPolicy3D().getBlockCommunicator(),
00768                             defaultMultiBlockPolicy3D().getCombinedStatistics(),
00769                             defaultMultiBlockPolicy3D().getMultiCellAccess<T,Descriptor>(),
00770                             backgroundDynamics->clone() );
00771     defineDynamics(*result, result->getBoundingBox(), backgroundDynamics);
00772     applyProcessingFunctional (
00773             new LatticeInterpolateCoarseToFine3D<T,Descriptor>(dxScale,dtScale),
00774             coarseLattice.getBoundingBox(), coarseLattice, *result );
00775                             
00776     return std::auto_ptr<MultiBlockLattice3D<T,Descriptor> >(result);
00777 }
00778 
00779 
00780 template<typename T, template<typename U> class Descriptor>
00781 std::auto_ptr<MultiParticleField3D<DenseParticleField3D<T,Descriptor> > > refine (
00782         MultiParticleField3D<DenseParticleField3D<T,Descriptor> >& coarseField,
00783         plint dxScale, plint dtScale )
00784 {
00785     PLB_PRECONDITION( dxScale<=-1 );
00786     // Relative level is positive when going from coarse to fine.
00787     plint relativeLevel = -dxScale;
00788     MultiBlockManagement3D management
00789         = scaleMultiBlockManagement(coarseField.getMultiBlockManagement(),relativeLevel);
00790     MultiParticleField3D<DenseParticleField3D<T,Descriptor> >* result =
00791         new MultiParticleField3D<DenseParticleField3D<T,Descriptor> > ( 
00792                             management,
00793                             defaultMultiBlockPolicy3D().getCombinedStatistics() );
00794     std::vector<MultiBlock3D*> args;
00795     args.push_back(&coarseField);
00796     args.push_back(result);
00797     applyProcessingFunctional (
00798             new CopyRescaleParticles3D<T,Descriptor>(dxScale,dtScale),
00799             coarseField.getBoundingBox(), args );
00800                             
00801     return std::auto_ptr<MultiParticleField3D<DenseParticleField3D<T,Descriptor> > >(result);
00802 }
00803 
00804 template<typename T, template<typename U> class Descriptor>
00805 std::auto_ptr<MultiParticleField3D<DenseParticleField3D<T,Descriptor> > > coarsen (
00806         MultiParticleField3D<DenseParticleField3D<T,Descriptor> >& fineField,
00807         plint dxScale, plint dtScale )
00808 {
00809     PLB_PRECONDITION( dxScale>=1 );
00810     // Relative level is negative when going from fine to coarse.
00811     plint relativeLevel = -dxScale;
00812     MultiBlockManagement3D management =
00813         scaleMultiBlockManagement(fineField.getMultiBlockManagement(),relativeLevel);
00814     MultiParticleField3D<DenseParticleField3D<T,Descriptor> >* result =
00815         new MultiParticleField3D<DenseParticleField3D<T,Descriptor> > ( 
00816                             management,
00817                             defaultMultiBlockPolicy3D().getCombinedStatistics() );
00818 
00819     std::vector<MultiBlock3D*> args;
00820     args.push_back(&fineField);
00821     args.push_back(result);
00822     applyProcessingFunctional (
00823             new CopyRescaleParticles3D<T,Descriptor>(dxScale,dtScale),
00824             fineField.getBoundingBox(), args );
00825                             
00826     return std::auto_ptr<MultiParticleField3D<DenseParticleField3D<T,Descriptor> > >(result);
00827 }
00828 
00829 }  // namespace plb
00830 
00831 #endif  // GRID_CONVERSION_3D_HH