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

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