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

NLD_boundaryDynamics3D.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 
00029 #ifndef NLD_BOUNDARY_DYNAMICS_3D_HH
00030 #define NLD_BOUNDARY_DYNAMICS_3D_HH
00031 
00032 #include "boundaryCondition/NLD_boundaryDynamics3D.h"
00033 #include "boundaryCondition/boundaryTemplates.h"
00034 #include "core/cell.h"
00035 #include "finiteDifference/fdStencils1D.h"
00036 
00037 namespace plb {
00038 
00039 namespace flatWall {
00040 
00041 template<typename T, template<typename U> class Descriptor>
00042 T computeRhoBar(Cell<T,Descriptor>& cell, int direction, int orientation, T u, T f)
00043 {
00044     T rhoOnWall = T();
00045     T rhoNormal = T();
00046     for (int iPop=0; iPop<Descriptor<T>::q; ++iPop) {
00047         if (Descriptor<T>::c[iPop][direction]==0) {
00048             rhoOnWall += cell[iPop];
00049         }
00050         else if (Descriptor<T>::c[iPop][direction]==orientation) {
00051             rhoNormal += cell[iPop];
00052         }
00053     }
00054 
00055     T velNormal = (T)orientation * (u-(T)0.5*f);
00056     T rhoBar = T();
00057     if (cell.getDynamics().velIsJ()) {
00058         rhoBar = (T)2*rhoNormal+rhoOnWall-velNormal;
00059     }
00060     else {
00061         rhoBar =((T)2*rhoNormal+rhoOnWall-Descriptor<T>::SkordosFactor()*velNormal)
00062                     / ((T)1+velNormal);
00063     }
00064     return rhoBar;
00065 }
00066 
00067 template<typename T, template<typename U> class Descriptor>
00068 void compute_PiNeq (
00069      Dynamics<T,Descriptor> const& dynamics,
00070      Cell<T,Descriptor> const& cell, int direction, int orientation,
00071      T rhoBar, Array<T,Descriptor<T>::d> const& j, T jSqr,
00072      Array<T,SymmetricTensor<T,Descriptor>::n>& PiNeq )
00073 {
00074     typedef Descriptor<T> L;
00075 
00076     // Compute off-equilibrium for known particle populations.
00077     Array<T,Descriptor<T>::q> fNeq;
00078 
00079     for (int iPop=0; iPop<L::q; ++iPop) {
00080         if (iPop==0) {
00081             fNeq[iPop] = T();  // fNeq[0] will not be used anyway
00082         }
00083         else {
00084             int cNormal = L::c[iPop][direction];
00085             if (cNormal==0 || cNormal==orientation) {
00086                 fNeq[iPop] = cell[iPop] - dynamics.computeEquilibrium(iPop, rhoBar, j, jSqr);
00087             }
00088         }
00089     }
00090 
00091     // Compute PiNeq from fNeq, by using "bounce-back of off-equilibrium part" rule.
00092     int iPi = 0;
00093     for (int iAlpha=0; iAlpha<L::d; ++iAlpha) {
00094         for (int iBeta=iAlpha; iBeta<L::d; ++iBeta) {
00095             PiNeq[iPi] = T();
00096             for (int iPop=0; iPop<L::q; ++iPop) {
00097                 int cNormal = L::c[iPop][direction];
00098                 if (cNormal==0) {
00099                     PiNeq[iPi] += L::c[iPop][iAlpha]*L::c[iPop][iBeta] *fNeq[iPop];
00100                 }
00101                 else if (cNormal==orientation) {
00102                     PiNeq[iPi] += (T)2 * L::c[iPop][iAlpha]*L::c[iPop][iBeta] *fNeq[iPop];
00103                 }
00104             }
00105             ++iPi;
00106         }
00107     }
00108 }
00109 
00110 template<typename T, template<typename U> class Descriptor>
00111 Array<T,3> computeJ (
00112         Cell<T,Descriptor> const& cell, int direction,
00113         int orientation, Array<T,3> j, T rhoBar )
00114 {
00115     T rhoOnWall=T(), rhoNormal=T();
00116     for (int iPop=0; iPop<Descriptor<T>::q; ++iPop) {
00117         if (Descriptor<T>::c[iPop][direction]==0) {
00118             rhoOnWall += cell[iPop];
00119         }
00120         else if (Descriptor<T>::c[iPop][direction]==orientation) {
00121             rhoNormal += cell[iPop];
00122         }
00123     }
00124 
00125     j[direction] = (T)orientation*((T)2*rhoNormal+rhoOnWall-rhoBar);
00126     return j;
00127 }
00128 
00129 }  // namespace flatWall
00130 
00131 
00132 /* *************** Class NonLocalBoundaryDynamics3D ****** */
00133 
00134 template<typename T, template<typename U> class Descriptor>
00135 NonLocalBoundaryDynamics3D<T,Descriptor>::NonLocalBoundaryDynamics3D(Dynamics<T,Descriptor>* baseDynamics_)
00136     : CompositeDynamics<T,Descriptor>(baseDynamics_, false)
00137 { }
00138 
00139 template<typename T, template<typename U> class Descriptor>
00140 bool NonLocalBoundaryDynamics3D<T,Descriptor>::isBoundary() const {
00141     return true;
00142 }
00143 
00144 template<typename T, template<typename U> class Descriptor>
00145 bool NonLocalBoundaryDynamics3D<T,Descriptor>::isNonLocal() const {
00146     return true;
00147 }
00148 
00149 
00150 
00151 
00152 /* *************** Class NLD_VelocityCornerUtil3D ****** */
00153 
00154 template<typename T, template<typename U> class Descriptor>
00155 class NLD_VelocityCornerUtil3D {
00156 public:
00157     NLD_VelocityCornerUtil3D (
00158             int xNormal_, int yNormal_, int zNormal_,
00159             plint iX_, plint iY_, plint iZ_,
00160             BlockLattice3D<T,Descriptor>& lattice_,
00161             NonLocalBoundaryDynamics3D<T,Descriptor>& dynamics_)
00162         : xNormal(xNormal_),
00163           yNormal(yNormal_),
00164           zNormal(zNormal_),
00165           iX(iX_), iY(iY_), iZ(iZ_),
00166           lattice(lattice_),
00167           dynamics(dynamics_)
00168     { }
00169     void computeVelocityGradient(int deriveDirection, int orientation, Array<T,3>& gradient)
00170     {
00171         Array<T,3> u0, u1;
00172         lattice.get(iX,iY,iZ).computeVelocity(u0);
00173         lattice.get (
00174             iX+(deriveDirection==0 ? (-orientation):0),
00175             iY+(deriveDirection==1 ? (-orientation):0),
00176             iZ+(deriveDirection==2 ? (-orientation):0)  ).computeVelocity(u1);
00177         for (int iD=0; iD<Descriptor<T>::d; ++iD) {
00178             gradient[iD] = -orientation * fd::o1_fwd_diff(u0[iD], u1[iD]);
00179         }
00180     }
00181     void computeVelocityGradientX(Array<T,3> const& u0, Array<T,3>& gradient) {
00182         Array<T,3> u1;
00183         T rhoBar, dummyTheta;
00184         NonLocalBoundaryDynamics3D<T,Descriptor>::staticEdgeComputeMacroscopic (
00185                 0, yNormal, zNormal, iX -1*xNormal, iY -0*yNormal, iZ -0*zNormal, lattice, rhoBar, u1, dummyTheta );
00186         if (!dynamics.velIsJ()) {
00187             u1 /= Descriptor<T>::fullRho(rhoBar);
00188         }
00189         for (int iD=0; iD<Descriptor<T>::d; ++iD) {
00190             gradient[iD] = -xNormal * fd::o1_fwd_diff(u0[iD], u1[iD]);
00191         }
00192     }
00193     void computeVelocityGradientY(Array<T,3> const& u0, Array<T,3>& gradient) {
00194         Array<T,3> u1;
00195         T rhoBar, dummyTheta;
00196         NonLocalBoundaryDynamics3D<T,Descriptor>::staticEdgeComputeMacroscopic (
00197                 1, zNormal, xNormal, iX -0*xNormal, iY -1*yNormal, iZ -0*zNormal, lattice, rhoBar, u1, dummyTheta );
00198         if (!dynamics.velIsJ()) {
00199             u1 /= Descriptor<T>::fullRho(rhoBar);
00200         }
00201         for (int iD=0; iD<Descriptor<T>::d; ++iD) {
00202             gradient[iD] = -yNormal * fd::o1_fwd_diff(u0[iD], u1[iD]);
00203         }
00204     }
00205     void computeVelocityGradientZ(Array<T,3> const& u0, Array<T,3>& gradient) {
00206         Array<T,3> u1;
00207         T rhoBar, dummyTheta;
00208         NonLocalBoundaryDynamics3D<T,Descriptor>::staticEdgeComputeMacroscopic (
00209                 2, xNormal, yNormal, iX -0*xNormal, iY -0*yNormal, iZ -1*zNormal, lattice, rhoBar, u1, dummyTheta );
00210         if (!dynamics.velIsJ()) {
00211             u1 /= Descriptor<T>::fullRho(rhoBar);
00212         }
00213         for (int iD=0; iD<Descriptor<T>::d; ++iD) {
00214             gradient[iD] = -zNormal * fd::o1_fwd_diff(u0[iD], u1[iD]);
00215         }
00216     }
00217     void computeMacroscopic(Array<T,3> const& u, T& rhoBar, Array<T,3>& j)
00218     {
00219         T rho100, rho010, rho001;
00220         T dummyTheta;
00221         Array<T,3> dummyJ;
00222         NonLocalBoundaryDynamics3D<T,Descriptor>::staticEdgeComputeMacroscopic (
00223                 0, yNormal, zNormal, iX -1*xNormal, iY -0*yNormal, iZ -0*zNormal, lattice, rho100, dummyJ, dummyTheta );
00224         NonLocalBoundaryDynamics3D<T,Descriptor>::staticEdgeComputeMacroscopic (
00225                 1, zNormal, xNormal, iX -0*xNormal, iY -1*yNormal, iZ -0*zNormal, lattice, rho010, dummyJ, dummyTheta );
00226         NonLocalBoundaryDynamics3D<T,Descriptor>::staticEdgeComputeMacroscopic (
00227                 2, xNormal, yNormal, iX -0*xNormal, iY -0*yNormal, iZ -1*zNormal, lattice, rho001, dummyJ, dummyTheta );
00228         rhoBar = (T)1/(T)3 * (rho001 + rho010 + rho100);
00229         j = u;
00230         if (dynamics.velIsJ()) {
00231             j *= Descriptor<T>::fullRho(rhoBar);
00232         }
00233     }
00234     void boundaryCompletion(Array<T,3> const& u)
00235     {
00236         typedef SymmetricTensorImpl<T,Descriptor<T>::d> S;
00237         T rhoBar;
00238         Array<T,3> j;
00239         computeMacroscopic(u, rhoBar, j);
00240         T rho = Descriptor<T>::fullRho(rhoBar);
00241         Array<T,3> dx_u, dy_u, dz_u;
00242         computeVelocityGradientX(u, dx_u);
00243         computeVelocityGradientY(u, dy_u);
00244         computeVelocityGradientZ(u, dz_u);
00245 
00246         T dx_ux = dx_u[0];
00247         T dy_ux = dy_u[0];
00248         T dz_ux = dz_u[0];
00249         T dx_uy = dx_u[1];
00250         T dy_uy = dy_u[1];
00251         T dz_uy = dz_u[1];
00252         T dx_uz = dx_u[2];
00253         T dy_uz = dy_u[2];
00254         T dz_uz = dz_u[2];
00255         T omega = dynamics.getOmega();
00256         T sToPi = - rho / Descriptor<T>::invCs2 / omega;
00257         Array<T,SymmetricTensor<T,Descriptor>::n> pi;
00258         pi[S::xx] = (T)2 * dx_ux * sToPi;
00259         pi[S::yy] = (T)2 * dy_uy * sToPi;
00260         pi[S::zz] = (T)2 * dz_uz * sToPi;
00261         pi[S::xy] = (dx_uy + dy_ux) * sToPi;
00262         pi[S::xz] = (dx_uz + dz_ux) * sToPi;
00263         pi[S::yz] = (dy_uz + dz_uy) * sToPi;
00264 
00265         T jSqr = VectorTemplate<T,Descriptor>::normSqr(j);
00266 
00267         Cell<T,Descriptor>& cell = lattice.get(iX,iY,iZ);
00268         for (plint iPop = 0; iPop < Descriptor<T>::q; ++iPop) {
00269             cell[iPop] = dynamics.computeEquilibrium(iPop,rhoBar,j,jSqr) +
00270                              offEquilibriumTemplates<T,Descriptor>::fromPiToFneq(iPop, pi);
00271         }
00272     }
00273 private:
00274     int xNormal, yNormal, zNormal;
00275     plint iX,iY,iZ;
00276     BlockLattice3D<T,Descriptor>& lattice;
00277     NonLocalBoundaryDynamics3D<T,Descriptor>& dynamics;
00278 };
00279 
00280 
00281 /* *************** Class NLD_VelocityPlaneUtil3D ****** */
00282 
00283 template<typename T, template<typename U> class Descriptor>
00284 class NLD_VelocityPlaneUtil3D {
00285 public:
00286     NLD_VelocityPlaneUtil3D (
00287             int direction_, int orientation_,
00288             plint iX_, plint iY_, plint iZ_,
00289             BlockLattice3D<T,Descriptor>& lattice_,
00290             NonLocalBoundaryDynamics3D<T,Descriptor>& dynamics_ )
00291         : direction(direction_),
00292           orientation(orientation_),
00293           iX(iX_), iY(iY_), iZ(iZ_),
00294           lattice(lattice_),
00295           dynamics(dynamics_)
00296     {
00297         direction1 = (direction+1)%3;
00298         direction2 = (direction+2)%3;
00299     }
00300     void computeMacroscopic(Array<T,3> const& u, T& rhoBar, Array<T,3>& j) const
00301     {
00302         Cell<T,Descriptor>& cell = lattice.get(iX,iY,iZ);
00303         T uNormal = u[direction];
00304         T fNormal = getExternalForceComponent(cell,direction);
00305         rhoBar = flatWall::computeRhoBar<T,Descriptor> (
00306                 cell, direction, orientation, uNormal, fNormal );
00307         j = u;
00308         if (!dynamics.velIsJ()) {
00309             j *= Descriptor<T>::fullRho(rhoBar);
00310         }
00311     }
00312     Array<T,3> extrapolateVelocity() const {
00313         Array<T,3> uTot; uTot.resetToZero();
00314         static T weight0 = 1./9.;
00315         static T weight1 = 1./36.;
00316         static T weight2 = 4./9.;
00317         static T weights[] = { weight1, weight0, weight1,
00318                                weight0, weight2, weight0,
00319                                weight1, weight0, weight1 };
00320         plint i=0;
00321         plint numCells=0;
00322         T sumWeights = T();
00323         for (plint i1=-1; i1<=+1; ++i1) {
00324             for (plint i2=-1; i2<=+1; ++i2) {
00325                 Array<plint,3> neighb(iX,iY,iZ);
00326                 neighb[direction] -= orientation;
00327                 neighb[direction1] += i1;
00328                 neighb[direction2] += i2;
00329                 Cell<T,Descriptor>& neighborCell = lattice.get(neighb[0],neighb[1],neighb[2]);
00330                 if (!neighborCell.getDynamics().isBoundary())  {
00331                     Array<T,3> u; neighborCell.computeVelocity(u);
00332                     uTot += weights[i]*u;
00333                     ++numCells;
00334                     sumWeights += weights[i];
00335                 }
00336                 ++i;
00337             }
00338         }
00339         if (numCells != 9) {
00340             uTot /= sumWeights;
00341         }
00342         return uTot;
00343     }
00344 private:
00345     int direction, orientation;
00346     int direction1, direction2;
00347     int iX,iY,iZ;
00348     BlockLattice3D<T,Descriptor>& lattice;
00349     NonLocalBoundaryDynamics3D<T,Descriptor>& dynamics;
00350 };
00351 
00352 
00353 /* *************** Class NLD_VelocityEdgeUtil3D ****** */
00354 
00355 template<typename T, template<typename U> class Descriptor>
00356 class NLD_VelocityEdgeUtil3D {
00357 public:
00358     NLD_VelocityEdgeUtil3D (
00359             int plane_, int normal1_, int normal2_,
00360             plint iX_, plint iY_, plint iZ_,
00361             BlockLattice3D<T,Descriptor>& lattice_,
00362             NonLocalBoundaryDynamics3D<T,Descriptor>& dynamics_ )
00363         : plane(plane_),
00364           normal1(normal1_),
00365           normal2(normal2_),
00366           iX(iX_), iY(iY_), iZ(iZ_),
00367           lattice(lattice_),
00368           dynamics(dynamics_)
00369     {
00370         direction1 = (plane+1)%3;
00371         direction2 = (plane+2)%3;
00372     }
00373     T getNeighborRhoBar(plint step1, plint step2)
00374     {
00375         PLB_ASSERT(step1==0 || step2==0);
00376         Array<T,3> dummyJ;
00377         T dummyTheta;
00378         T rhoBar;
00379         Array<int,3> coords (iX, iY, iZ);
00380         coords[direction1] += -normal1*step1;
00381         coords[direction2] += -normal2*step2;
00382         if (step1==0) {
00383             NonLocalBoundaryDynamics3D<T,Descriptor>::staticPlaneComputeMacroscopic (
00384                     direction1, normal1, coords[0], coords[1], coords[2], lattice, rhoBar, dummyJ, dummyTheta );
00385             PLB_ASSERT(step2 != 0);
00386         }
00387         else {  // step2==0.
00388             NonLocalBoundaryDynamics3D<T,Descriptor>::staticPlaneComputeMacroscopic (
00389                     direction2, normal2, coords[0], coords[1], coords[2], lattice, rhoBar, dummyJ, dummyTheta );
00390         }
00391         return rhoBar;
00392     }
00393     void computeMacroscopic(Array<T,3> const& u, T& rhoBar, Array<T,3>& j)
00394     {
00395         T rho10 = getNeighborRhoBar(1,0);
00396         T rho01 = getNeighborRhoBar(0,1);
00397         T rho20 = getNeighborRhoBar(2,0);
00398         T rho02 = getNeighborRhoBar(0,2);
00399         rhoBar = (T)2/(T)3*(rho01+rho10)-(T)1/(T)6*(rho02+rho20);
00400         j = u;
00401         if (dynamics.velIsJ()) {
00402             j *= Descriptor<T>::fullRho(rhoBar);
00403         }
00404     }
00405     void computeEdgeGradient(Array<T,3>& gradient) {
00406         Array<T,3> u_p1, u_m1;
00407         Array<plint,3> posPlus(iX,iY,iZ), posMinus(iX,iY,iZ);
00408         ++posPlus[plane];
00409         --posMinus[plane];
00410 
00411         NLD_VelocityBoundaryDynamics3D<T,Descriptor>* dynPlus = 
00412             dynamic_cast<NLD_VelocityBoundaryDynamics3D<T,Descriptor>*> (
00413                     &lattice.get(posPlus[0], posPlus[1], posPlus[2]).getDynamics() );
00414         NLD_VelocityBoundaryDynamics3D<T,Descriptor>* dynMinus = 
00415             dynamic_cast<NLD_VelocityBoundaryDynamics3D<T,Descriptor>*> (
00416                     &lattice.get(posMinus[0], posMinus[1], posMinus[2]).getDynamics() );
00417         if (dynPlus && dynMinus) {
00418             u_p1 = dynPlus->get_u();
00419             u_m1 = dynMinus->get_u();
00420             for (int iD=0; iD<Descriptor<T>::d; ++iD) {
00421                 gradient[iD] = fd::ctl_diff(u_p1[iD],u_m1[iD]);
00422             }
00423         }
00424         else {
00425             gradient.resetToZero();
00426         }
00427     }
00428     void computeGradientIntoPlane(Array<T,3> const& u0, int deriveDirection, int deriveOrientation,
00429                                   int normalDirection, int normalOrientation, Array<T,3>& gradient)
00430     {
00431         Array<T,3> u1;
00432         Array<plint,3> pos1(iX,iY,iZ);
00433         pos1[deriveDirection] -= deriveOrientation;
00434         
00435         T rhoBar, dummyTheta;
00436         NonLocalBoundaryDynamics3D<T,Descriptor>::staticPlaneComputeMacroscopic (
00437                 normalDirection, normalOrientation, pos1[0], pos1[1], pos1[2], lattice, rhoBar, u1, dummyTheta );
00438         if (!dynamics.velIsJ()) {
00439             u1 /= Descriptor<T>::fullRho(rhoBar);
00440         }
00441         for (int iD=0; iD<Descriptor<T>::d; ++iD) {
00442             gradient[iD] = -deriveOrientation * fd::o1_fwd_diff(u0[iD], u1[iD]);
00443         }
00444     }
00445     void boundaryCompletion(Array<T,3> const& u)
00446     {
00447         typedef SymmetricTensorImpl<T,Descriptor<T>::d> S;
00448         T rhoBar;
00449         Array<T,3> j;
00450         computeMacroscopic(u, rhoBar, j);
00451         T rho = Descriptor<T>::fullRho(rhoBar);
00452         std::vector<Array<T,3> > dA_uB_(3);
00453         computeEdgeGradient(dA_uB_[0]);
00454         computeGradientIntoPlane(u, direction1, normal1, direction2, normal2, dA_uB_[1]);
00455         computeGradientIntoPlane(u, direction2, normal2, direction1, normal1, dA_uB_[2]);
00456 
00457         std::vector<Array<T,3> > dA_uB(3);
00458         for (int iBeta=0; iBeta<3; ++iBeta) {
00459             dA_uB[plane][iBeta]      = dA_uB_[0][iBeta];
00460             dA_uB[direction1][iBeta] = dA_uB_[1][iBeta];
00461             dA_uB[direction2][iBeta] = dA_uB_[2][iBeta];
00462         }
00463 
00464         T sToPi = - rho / Descriptor<T>::invCs2 / dynamics.getOmega();
00465         Array<T,SymmetricTensor<T,Descriptor>::n> pi;
00466         pi[S::xx] = (T)2 * dA_uB[0][0] * sToPi;
00467         pi[S::yy] = (T)2 * dA_uB[1][1] * sToPi;
00468         pi[S::zz] = (T)2 * dA_uB[2][2] * sToPi;
00469         pi[S::xy] = (dA_uB[0][1]+dA_uB[1][0]) * sToPi;
00470         pi[S::xz] = (dA_uB[0][2]+dA_uB[2][0]) * sToPi;
00471         pi[S::yz] = (dA_uB[1][2]+dA_uB[2][1]) * sToPi;
00472 
00473         T jSqr = VectorTemplate<T,Descriptor>::normSqr(j);
00474 
00475         Cell<T,Descriptor>& cell = lattice.get(iX,iY,iZ);
00476         for (plint iPop = 0; iPop < Descriptor<T>::q; ++iPop) {
00477             cell[iPop] = dynamics.computeEquilibrium(iPop,rhoBar,j,jSqr) +
00478                              offEquilibriumTemplates<T,Descriptor>::fromPiToFneq(iPop, pi);
00479         }
00480     }
00481 private:
00482     int plane, normal1, normal2, direction1, direction2;
00483     plint iX,iY,iZ;
00484     BlockLattice3D<T,Descriptor>& lattice;
00485     NonLocalBoundaryDynamics3D<T,Descriptor>& dynamics;
00486 };
00487 
00488 
00489 /* *************** Class NLD_VelocityBoundaryDynamics3D ****** */
00490 
00491 template<typename T, template<typename U> class Descriptor>
00492 int NLD_VelocityBoundaryDynamics3D<T,Descriptor>::id =
00493     meta::registerGeneralDynamics<T,Descriptor, NLD_VelocityBoundaryDynamics3D<T,Descriptor> >
00494             ( std::string("NLD_Velocity") );
00495 
00496 template<typename T, template<typename U> class Descriptor>
00497 NLD_VelocityBoundaryDynamics3D<T,Descriptor>::NLD_VelocityBoundaryDynamics3D(Dynamics<T,Descriptor>* baseDynamics_)
00498     : NonLocalBoundaryDynamics3D<T,Descriptor>(baseDynamics_)
00499 { }
00500 
00501 template<typename T, template<typename U> class Descriptor>
00502 NLD_VelocityBoundaryDynamics3D<T,Descriptor>::NLD_VelocityBoundaryDynamics3D(HierarchicUnserializer& unserializer)
00503     : NonLocalBoundaryDynamics3D<T,Descriptor>(0)
00504 {
00505     this->unserialize(unserializer);
00506 }
00507 
00508 template<typename T, template<typename U> class Descriptor>
00509 void NLD_VelocityBoundaryDynamics3D<T,Descriptor>::defineVelocity (
00510         Cell<T,Descriptor>& cell, Array<T,Descriptor<T>::d> const& velocity_ )
00511 {
00512     u = velocity_;
00513 }
00514 
00515 template<typename T, template<typename U> class Descriptor>
00516 void NLD_VelocityBoundaryDynamics3D<T,Descriptor>::computeVelocity (
00517         Cell<T,Descriptor> const& cell, Array<T,Descriptor<T>::d>& velocity_ ) const
00518 {
00519     velocity_ = u;
00520 }
00521 
00522 template<typename T, template<typename U> class Descriptor>
00523 void NLD_VelocityBoundaryDynamics3D<T,Descriptor>::serialize(HierarchicSerializer& serializer) const {
00524     serializer.addValues<T,3>(u);
00525     NonLocalBoundaryDynamics3D<T,Descriptor>::serialize(serializer);
00526 }
00527 
00528 template<typename T, template<typename U> class Descriptor>
00529 void NLD_VelocityBoundaryDynamics3D<T,Descriptor>::unserialize(HierarchicUnserializer& unserializer) {
00530     unserializer.readValues<T,3>(u);
00531     NonLocalBoundaryDynamics3D<T,Descriptor>::unserialize(unserializer);
00532 }
00533 
00534 template<typename T, template<typename U> class Descriptor>
00535 int NLD_VelocityBoundaryDynamics3D<T,Descriptor>::getId() const
00536 {
00537     return id;
00538 }
00539 
00540 template<typename T, template<typename U> class Descriptor>
00541 void NLD_VelocityBoundaryDynamics3D<T,Descriptor>::prepareCollision(Cell<T,Descriptor>& cell)
00542 { }
00543 
00544 template<typename T, template<typename U> class Descriptor>
00545 NLD_VelocityBoundaryDynamics3D<T,Descriptor>*
00546     NLD_VelocityBoundaryDynamics3D<T,Descriptor>::clone() const
00547 {
00548     return new NLD_VelocityBoundaryDynamics3D<T,Descriptor>(*this);
00549 }
00550 
00551 
00552 template<typename T, template<typename U> class Descriptor>
00553 void NLD_VelocityBoundaryDynamics3D<T,Descriptor>::planeComputeMacroscopic (
00554             int direction, int orientation, plint iX, plint iY, plint iZ,
00555             BlockLattice3D<T,Descriptor>& lattice,
00556             T& rhoBar, Array<T,3>& j, T& thetaBar )
00557 {
00558     NLD_VelocityPlaneUtil3D<T,Descriptor> (
00559             direction, orientation, iX,iY,iZ, lattice, *this ).computeMacroscopic(this->u, rhoBar, j);
00560     thetaBar = T();
00561 }
00562 
00563 
00564 template<typename T, template<typename U> class Descriptor>
00565 void NLD_VelocityBoundaryDynamics3D<T,Descriptor>::edgeComputeMacroscopic (
00566             int plane, int normal1, int normal2, plint iX, plint iY, plint iZ,
00567             BlockLattice3D<T,Descriptor>& lattice,
00568             T& rhoBar, Array<T,3>& j, T& thetaBar )
00569 {
00570     NLD_VelocityEdgeUtil3D<T,Descriptor> edgeUtil (
00571             plane, normal1, normal2, iX, iY, iZ, lattice, *this );
00572     edgeUtil.computeMacroscopic(this->u, rhoBar, j);
00573     thetaBar = T();
00574 }
00575 
00576 template<typename T, template<typename U> class Descriptor>
00577 void NLD_VelocityBoundaryDynamics3D<T,Descriptor>::cornerComputeMacroscopic (
00578             int xNormal, int yNormal, int zNormal, plint iX, plint iY, plint iZ,
00579             BlockLattice3D<T,Descriptor>& lattice,
00580             T& rhoBar, Array<T,3>& j, T& thetaBar )
00581 {
00582     NLD_VelocityCornerUtil3D<T,Descriptor> cornerUtil(xNormal, yNormal, zNormal, iX,iY,iZ, lattice, *this);
00583     cornerUtil.computeMacroscopic(this->u, rhoBar, j);
00584     thetaBar = T();
00585 }
00586 
00587 template<typename T, template<typename U> class Descriptor>
00588 void NLD_VelocityBoundaryDynamics3D<T,Descriptor>::planeBoundaryCompletion (
00589             int direction, int orientation, plint iX, plint iY, plint iZ,
00590             BlockLattice3D<T,Descriptor>& lattice )
00591 {
00592 
00593     Array<T,3> j;
00594     T rhoBar;
00595     NLD_VelocityPlaneUtil3D<T,Descriptor> (
00596             direction, orientation, iX,iY,iZ, lattice, *this ).computeMacroscopic(this->u, rhoBar, j);
00597     T jSqr = VectorTemplate<T,Descriptor>::normSqr(j);
00598 
00599     Cell<T,Descriptor>& cell = lattice.get(iX,iY,iZ);
00600     Array<T,SymmetricTensor<T,Descriptor>::n> PiNeq;
00601     flatWall::compute_PiNeq<T,Descriptor> (
00602             this->getBaseDynamics(), cell, direction, orientation, rhoBar, j, jSqr, PiNeq );
00603 
00604     this->getBaseDynamics().regularize(cell, rhoBar, j, jSqr, PiNeq);
00605 }
00606 
00607 template<typename T, template<typename U> class Descriptor>
00608 void NLD_VelocityBoundaryDynamics3D<T,Descriptor>::edgeBoundaryCompletion (
00609             int plane, int normal1, int normal2, plint iX, plint iY, plint iZ,
00610             BlockLattice3D<T,Descriptor>& lattice )
00611 {
00612     int direction1 = (plane+1)%3;
00613     int direction2 = (plane+2)%3;
00614     Array<plint,3> nbCell1(iX,iY,iZ), nbCell2(iX,iY,iZ);
00615     nbCell1[direction1] -= normal1;
00616     nbCell2[direction2] -= normal2;
00617 
00618     // 1. Detect case where a direction is periodic.
00619     bool isWall1 =
00620         lattice.get(nbCell1[0],nbCell1[1],nbCell1[2]).getDynamics().isBoundary();
00621     bool isWall2 =
00622         lattice.get(nbCell2[0],nbCell2[1],nbCell2[2]).getDynamics().isBoundary();
00623 
00624     // If both directions are periodic, there is no need for a boundary condition.
00625     if (!isWall1 && !isWall2) return;
00626     // If exactly one direction is periodic, then the edge behaves like a plane.
00627     if (!isWall1) {
00628         planeBoundaryCompletion(direction1, normal1, iX,iY,iZ, lattice);
00629         return;
00630     }
00631     else if (!isWall2) {
00632         planeBoundaryCompletion(direction2, normal2, iX,iY,iZ, lattice);
00633         return;
00634     }
00635 
00636     // 2. Implement general edge algorithm.
00637     NLD_VelocityEdgeUtil3D<T,Descriptor> edgeUtil (
00638             plane, normal1, normal2, iX, iY, iZ, lattice, *this );
00639     edgeUtil.boundaryCompletion(this->u);
00640 }
00641 
00642 template<typename T, template<typename U> class Descriptor>
00643 void NLD_VelocityBoundaryDynamics3D<T,Descriptor>::cornerBoundaryCompletion (
00644             int xNormal, int yNormal, int zNormal, plint iX, plint iY, plint iZ,
00645             BlockLattice3D<T,Descriptor>& lattice )
00646 {
00647     Array<plint,3> middleNbCell(iX,iY,iZ), nbCellX(iX,iY,iZ), nbCellY(iX,iY,iZ), nbCellZ(iX,iY,iZ);
00648     middleNbCell -= Array<plint,3>(xNormal,yNormal,zNormal);
00649     nbCellX[0] -= xNormal;
00650     nbCellY[1] -= yNormal;
00651     nbCellZ[2] -= zNormal;
00652 
00653     // 1. To start width, detect periodic directions where the corner actually
00654     //    becomes edge, plane, or non-boundary.
00655 
00656     bool xPeriodic = ! lattice.get(iX,iY-yNormal,iZ-zNormal).getDynamics().isBoundary();
00657     bool yPeriodic = ! lattice.get(iX-xNormal,iY,iZ-zNormal).getDynamics().isBoundary();
00658     bool zPeriodic = ! lattice.get(iX-xNormal,iY-yNormal,iZ).getDynamics().isBoundary();
00659 
00660     // Note that we only need to consider cases where corners become edges,
00661     //   because further degenerate cases (two or three periodic directions)
00662     //   are treated in the edge algorithm.
00663     if (xPeriodic) {
00664         edgeBoundaryCompletion(0, yNormal, zNormal, iX,iY,iZ, lattice);
00665         return;
00666     }
00667     if (yPeriodic) {
00668         edgeBoundaryCompletion(1, zNormal, xNormal, iX,iY,iZ, lattice);
00669         return;
00670     }
00671     if (zPeriodic) {
00672         edgeBoundaryCompletion(2, xNormal, yNormal, iX,iY,iZ, lattice);
00673         return;
00674     }
00675 
00676     // 2. Implement generic case.
00677     NLD_VelocityCornerUtil3D<T,Descriptor> cornerUtil(xNormal, yNormal, zNormal, iX,iY,iZ, lattice, *this);
00678     cornerUtil.boundaryCompletion(this->u);
00679 }
00680 
00681 
00682 /* *************** Class NLD_VelocityNeumannBoundaryDynamics3D ****** */
00683 
00684 template<typename T, template<typename U> class Descriptor>
00685 int NLD_VelocityNeumannBoundaryDynamics3D<T,Descriptor>::id =
00686     meta::registerGeneralDynamics<T,Descriptor, NLD_VelocityNeumannBoundaryDynamics3D<T,Descriptor> >
00687             ( std::string("NLD_VelocityNeumann") );
00688 
00689 template<typename T, template<typename U> class Descriptor>
00690 NLD_VelocityNeumannBoundaryDynamics3D<T,Descriptor>::NLD_VelocityNeumannBoundaryDynamics3D (
00691         Dynamics<T,Descriptor>* baseDynamics_ )
00692     : NonLocalBoundaryDynamics3D<T,Descriptor>(baseDynamics_)
00693 { }
00694 
00695 template<typename T, template<typename U> class Descriptor>
00696 NLD_VelocityNeumannBoundaryDynamics3D<T,Descriptor>::NLD_VelocityNeumannBoundaryDynamics3D (
00697         HierarchicUnserializer& unserializer )
00698     : NonLocalBoundaryDynamics3D<T,Descriptor>(0)
00699 {
00700     this->unserialize(unserializer);
00701 }
00702 
00703 template<typename T, template<typename U> class Descriptor>
00704 int NLD_VelocityNeumannBoundaryDynamics3D<T,Descriptor>::getId() const
00705 {
00706     return id;
00707 }
00708 
00709 template<typename T, template<typename U> class Descriptor>
00710 void NLD_VelocityNeumannBoundaryDynamics3D<T,Descriptor>::prepareCollision(Cell<T,Descriptor>& cell)
00711 { }
00712 
00713 template<typename T, template<typename U> class Descriptor>
00714 NLD_VelocityNeumannBoundaryDynamics3D<T,Descriptor>*
00715     NLD_VelocityNeumannBoundaryDynamics3D<T,Descriptor>::clone() const
00716 {
00717     return new NLD_VelocityNeumannBoundaryDynamics3D<T,Descriptor>(*this);
00718 }
00719 
00720 
00721 template<typename T, template<typename U> class Descriptor>
00722 void NLD_VelocityNeumannBoundaryDynamics3D<T,Descriptor>::planeComputeMacroscopic (
00723             int direction, int orientation, plint iX, plint iY, plint iZ,
00724             BlockLattice3D<T,Descriptor>& lattice,
00725             T& rhoBar, Array<T,3>& j, T& thetaBar )
00726 {
00727     NLD_VelocityPlaneUtil3D<T,Descriptor> planeUtil (
00728             direction, orientation, iX,iY,iZ, lattice, *this );
00729     Array<T,3> u(planeUtil.extrapolateVelocity());
00730     planeUtil.computeMacroscopic(u, rhoBar, j);
00731     thetaBar = T();
00732 }
00733 
00734 
00735 template<typename T, template<typename U> class Descriptor>
00736 void NLD_VelocityNeumannBoundaryDynamics3D<T,Descriptor>::edgeComputeMacroscopic (
00737             int plane, int normal1, int normal2, plint iX, plint iY, plint iZ,
00738             BlockLattice3D<T,Descriptor>& lattice,
00739             T& rhoBar, Array<T,3>& j, T& thetaBar )
00740 {
00741     int direction1 = (plane+1)%3;
00742     int direction2 = (plane+2)%3;
00743 
00744     Array<plint,3> nbCell1(iX,iY,iZ), nbCell2(iX,iY,iZ);
00745     nbCell1[direction1] -= normal1;
00746     nbCell2[direction2] -= normal2;
00747     Cell<T,Descriptor>& neighbor1 = lattice.get(nbCell1[0], nbCell1[1], nbCell1[2]);
00748     Cell<T,Descriptor>& neighbor2 = lattice.get(nbCell2[0], nbCell2[1], nbCell2[2]);
00749     NLD_VelocityBoundaryDynamics3D<T,Descriptor>* dyn1 = 
00750         dynamic_cast<NLD_VelocityBoundaryDynamics3D<T,Descriptor>*> (
00751                 &neighbor1.getDynamics() );
00752     NLD_VelocityBoundaryDynamics3D<T,Descriptor>* dyn2 = 
00753         dynamic_cast<NLD_VelocityBoundaryDynamics3D<T,Descriptor>*> (
00754                 &neighbor2.getDynamics() );
00755     if (!(dyn1 || dyn2)) {
00756         Array<plint,3> middleNbCell(iX,iY,iZ);
00757         middleNbCell[direction1] -= normal1;
00758         middleNbCell[direction2] -= normal2;
00759         Cell<T,Descriptor>& middleNeighbor = lattice.get(middleNbCell[0], middleNbCell[1], middleNbCell[2]);
00760         Array<T,3> u;
00761         middleNeighbor.computeVelocity(u);
00762         NLD_VelocityEdgeUtil3D<T,Descriptor> edgeUtil (
00763                 plane, normal1, normal2, iX, iY, iZ, lattice, *this );
00764         edgeUtil.computeMacroscopic(u, rhoBar, j);
00765         thetaBar = T();
00766     }
00767     else {
00768         T rhoBar1, rhoBar2;
00769         Array<T,3> j1, j2;
00770         if (dyn1) {
00771             dyn1->edgeComputeMacroscopic (
00772                     plane, normal1, normal2, iX,iY,iZ, lattice, rhoBar1, j1, thetaBar );
00773             rhoBar = rhoBar1;
00774             j = j1;
00775         }
00776         if (dyn2) {
00777             dyn2->edgeComputeMacroscopic (
00778                     plane, normal1, normal2, iX,iY,iZ, lattice, rhoBar2, j2, thetaBar );
00779             rhoBar = rhoBar2;
00780             j = j2;
00781         }
00782         if (dyn1 && dyn2) {
00783             j = (j1+j2)/(T)2;
00784             rhoBar = (rhoBar1+rhoBar2)/(T)2;
00785         }
00786     }
00787 }
00788 
00789 template<typename T, template<typename U> class Descriptor>
00790 void NLD_VelocityNeumannBoundaryDynamics3D<T,Descriptor>::cornerComputeMacroscopic (
00791             int xNormal, int yNormal, int zNormal, plint iX, plint iY, plint iZ,
00792             BlockLattice3D<T,Descriptor>& lattice,
00793             T& rhoBar, Array<T,3>& j, T& thetaBar )
00794 {
00795     Array<plint,3> nbCell1(iX-xNormal,iY,iZ), nbCell2(iX,iY-yNormal,iZ), nbCell3(iX,iY,iZ-zNormal);
00796     Cell<T,Descriptor>& neighbor1 = lattice.get(nbCell1[0], nbCell1[1], nbCell1[2]);
00797     Cell<T,Descriptor>& neighbor2 = lattice.get(nbCell2[0], nbCell2[1], nbCell2[2]);
00798     Cell<T,Descriptor>& neighbor3 = lattice.get(nbCell3[0], nbCell3[1], nbCell3[2]);
00799 
00800     NLD_VelocityBoundaryDynamics3D<T,Descriptor>* dyn1 = 
00801         dynamic_cast<NLD_VelocityBoundaryDynamics3D<T,Descriptor>*> (
00802                 &neighbor1.getDynamics() );
00803     NLD_VelocityBoundaryDynamics3D<T,Descriptor>* dyn2 = 
00804         dynamic_cast<NLD_VelocityBoundaryDynamics3D<T,Descriptor>*> (
00805                 &neighbor2.getDynamics() );
00806     NLD_VelocityBoundaryDynamics3D<T,Descriptor>* dyn3 = 
00807         dynamic_cast<NLD_VelocityBoundaryDynamics3D<T,Descriptor>*> (
00808                 &neighbor3.getDynamics() );
00809 
00810     if (!(dyn1 || dyn2 || dyn3)) {
00811         Array<plint,3> nbCell(iX,iY,iZ);
00812         nbCell -= Array<plint,3>(xNormal,yNormal,zNormal);
00813         Cell<T,Descriptor>& middleNeighbor = lattice.get(nbCell[0], nbCell[1], nbCell[2]);
00814         Array<T,3> u; middleNeighbor.computeVelocity(u);
00815 
00816         NLD_VelocityCornerUtil3D<T,Descriptor> cornerUtil(xNormal, yNormal, zNormal, iX,iY,iZ, lattice, *this);
00817         cornerUtil.computeMacroscopic(u, rhoBar, j);
00818         thetaBar = T();
00819     }
00820     else {
00821         rhoBar = T();
00822         j.resetToZero();
00823         plint numNeighbors=0;
00824         if (dyn1) {
00825             T rhoBar_;
00826             Array<T,3> j_;
00827             dyn1->cornerComputeMacroscopic (
00828                     xNormal,yNormal,zNormal, iX,iY,iZ, lattice, rhoBar_, j_, thetaBar );
00829             rhoBar += rhoBar_;
00830             j += j_;
00831             ++numNeighbors;
00832         }
00833         if (dyn2) {
00834             T rhoBar_;
00835             Array<T,3> j_;
00836             dyn2->cornerComputeMacroscopic (
00837                     xNormal,yNormal,zNormal, iX,iY,iZ, lattice, rhoBar_, j_, thetaBar );
00838             rhoBar += rhoBar_;
00839             j += j_;
00840             ++numNeighbors;
00841         }
00842         if (dyn3) {
00843             T rhoBar_;
00844             Array<T,3> j_;
00845             dyn3->cornerComputeMacroscopic (
00846                     xNormal,yNormal,zNormal, iX,iY,iZ, lattice, rhoBar_, j_, thetaBar );
00847             rhoBar += rhoBar_;
00848             j += j_;
00849             ++numNeighbors;
00850         }
00851         if (numNeighbors>1) {
00852             rhoBar /= (T)numNeighbors;
00853             j /= (T)numNeighbors;
00854         }
00855     }
00856 }
00857 
00858 
00859 template<typename T, template<typename U> class Descriptor>
00860 void NLD_VelocityNeumannBoundaryDynamics3D<T,Descriptor>::planeBoundaryCompletion (
00861             int direction, int orientation, plint iX, plint iY, plint iZ,
00862             BlockLattice3D<T,Descriptor>& lattice )
00863 {
00864     NLD_VelocityPlaneUtil3D<T,Descriptor> planeUtil (
00865             direction, orientation, iX,iY,iZ, lattice, *this );
00866     Array<T,3> u(planeUtil.extrapolateVelocity());
00867     T rhoBar;
00868     Array<T,3> j;
00869     planeUtil.computeMacroscopic(u, rhoBar, j);
00870     T jSqr = VectorTemplate<T,Descriptor>::normSqr(j);
00871 
00872     Cell<T,Descriptor>& cell = lattice.get(iX,iY,iZ);
00873     Array<T,SymmetricTensor<T,Descriptor>::n> PiNeq;
00874     flatWall::compute_PiNeq<T,Descriptor> (
00875             this->getBaseDynamics(), cell, direction, orientation, rhoBar, j, jSqr, PiNeq );
00876 
00877     this->getBaseDynamics().regularize(cell, rhoBar, j, jSqr, PiNeq);
00878 }
00879 
00880 template<typename T, template<typename U> class Descriptor>
00881 void NLD_VelocityNeumannBoundaryDynamics3D<T,Descriptor>::edgeBoundaryCompletion (
00882             int plane, int normal1, int normal2, plint iX, plint iY, plint iZ,
00883             BlockLattice3D<T,Descriptor>& lattice )
00884 {
00885     int direction1 = (plane+1)%3;
00886     int direction2 = (plane+2)%3;
00887 
00888     Array<plint,3> nbCell1(iX,iY,iZ), nbCell2(iX,iY,iZ), middleNbCell(iX,iY,iZ);
00889     nbCell1[direction1] -= normal1;
00890     nbCell2[direction2] -= normal2;
00891     middleNbCell[direction1] -= normal1;
00892     middleNbCell[direction2] -= normal2;
00893 
00894     // 1. Detect case where a direction is periodic.
00895     bool isWall1 =
00896         lattice.get(nbCell1[0],nbCell1[1],nbCell1[2]).getDynamics().isBoundary();
00897     bool isWall2 =
00898         lattice.get(nbCell2[0],nbCell2[1],nbCell2[2]).getDynamics().isBoundary();
00899 
00900     // If both directions are periodic, there is no need for a boundary condition.
00901     if (!isWall1 && !isWall2) return;
00902     // If exactly one direction is periodic, then the edge behaves like a plane.
00903     if (!isWall1) {
00904         planeBoundaryCompletion(direction1, normal1, iX,iY,iZ, lattice);
00905         return;
00906     }
00907     else if (!isWall2) {
00908         planeBoundaryCompletion(direction2, normal2, iX,iY,iZ, lattice);
00909         return;
00910     }
00911 
00912     Cell<T,Descriptor>& neighbor1 = lattice.get(nbCell1[0], nbCell1[1], nbCell1[2]);
00913     Cell<T,Descriptor>& neighbor2 = lattice.get(nbCell2[0], nbCell2[1], nbCell2[2]);
00914     NLD_VelocityBoundaryDynamics3D<T,Descriptor>* dyn1 = 
00915         dynamic_cast<NLD_VelocityBoundaryDynamics3D<T,Descriptor>*> (
00916                 &neighbor1.getDynamics() );
00917     NLD_VelocityBoundaryDynamics3D<T,Descriptor>* dyn2 = 
00918         dynamic_cast<NLD_VelocityBoundaryDynamics3D<T,Descriptor>*> (
00919                 &neighbor2.getDynamics() );
00920 
00921     if (!(dyn1 || dyn2)) {
00922         Cell<T,Descriptor>& middleNeighbor = lattice.get(middleNbCell[0], middleNbCell[1], middleNbCell[2]);
00923         Array<T,3> u; middleNeighbor.computeVelocity(u);
00924         NLD_VelocityEdgeUtil3D<T,Descriptor> edgeUtil (
00925                 plane, normal1, normal2, iX, iY, iZ, lattice, *this );
00926         edgeUtil.boundaryCompletion(u);
00927     }
00928     else {
00929         if (dyn1) {
00930             dyn1->edgeBoundaryCompletion (
00931                         plane, normal1, normal2, iX, iY, iZ, lattice );
00932         }
00933         if (dyn2) {
00934             Cell<T,Descriptor> saveCell(lattice.get(iX,iY,iZ));
00935             dyn2->edgeBoundaryCompletion (
00936                         plane, normal1, normal2, iX, iY, iZ, lattice );
00937             if (dyn1) {
00938                 Cell<T,Descriptor>& cell(lattice.get(iX,iY,iZ));
00939                 for (plint iPop=0; iPop<Descriptor<T>::q; ++iPop) {
00940                     cell[iPop] = (cell[iPop]+saveCell[iPop])/2.;
00941                 }
00942             }
00943         }
00944     }
00945 }
00946 
00947 template<typename T, template<typename U> class Descriptor>
00948 void NLD_VelocityNeumannBoundaryDynamics3D<T,Descriptor>::cornerBoundaryCompletion (
00949             int xNormal, int yNormal, int zNormal, plint iX, plint iY, plint iZ,
00950             BlockLattice3D<T,Descriptor>& lattice )
00951 {
00952     Cell<T,Descriptor>& cell = lattice.get(iX,iY,iZ);
00953     Array<plint,3> nbCell(iX,iY,iZ);
00954     nbCell -= Array<plint,3>(xNormal,yNormal,zNormal);
00955 
00956     // 1. To start width, detect periodic directions where the corner actually
00957     //    becomes edge, plane, or non-boundary.
00958 
00959     bool xPeriodic = ! lattice.get(iX,iY-yNormal,iZ-zNormal).getDynamics().isBoundary();
00960     bool yPeriodic = ! lattice.get(iX-xNormal,iY,iZ-zNormal).getDynamics().isBoundary();
00961     bool zPeriodic = ! lattice.get(iX-xNormal,iY-yNormal,iZ).getDynamics().isBoundary();
00962 
00963     // Note that we only need to consider cases where corners become edges,
00964     //   because further degenerate cases (two or three periodic directions)
00965     //   are treated in the edge algorithm.
00966     if (xPeriodic) {
00967         edgeBoundaryCompletion(0, yNormal, zNormal, iX,iY,iZ, lattice);
00968         return;
00969     }
00970     if (yPeriodic) {
00971         edgeBoundaryCompletion(1, zNormal, xNormal, iX,iY,iZ, lattice);
00972         return;
00973     }
00974     if (zPeriodic) {
00975         edgeBoundaryCompletion(2, xNormal, yNormal, iX,iY,iZ, lattice);
00976         return;
00977     }
00978 
00979 
00980     Array<plint,3> nbCell1(iX-xNormal,iY,iZ), nbCell2(iX,iY-yNormal,iZ), nbCell3(iX,iY,iZ-zNormal);
00981     Cell<T,Descriptor>& neighbor1 = lattice.get(nbCell1[0], nbCell1[1], nbCell1[2]);
00982     Cell<T,Descriptor>& neighbor2 = lattice.get(nbCell2[0], nbCell2[1], nbCell2[2]);
00983     Cell<T,Descriptor>& neighbor3 = lattice.get(nbCell3[0], nbCell3[1], nbCell3[2]);
00984 
00985     NLD_VelocityBoundaryDynamics3D<T,Descriptor>* dyn1 = 
00986         dynamic_cast<NLD_VelocityBoundaryDynamics3D<T,Descriptor>*> (
00987                 &neighbor1.getDynamics() );
00988     NLD_VelocityBoundaryDynamics3D<T,Descriptor>* dyn2 = 
00989         dynamic_cast<NLD_VelocityBoundaryDynamics3D<T,Descriptor>*> (
00990                 &neighbor2.getDynamics() );
00991     NLD_VelocityBoundaryDynamics3D<T,Descriptor>* dyn3 = 
00992         dynamic_cast<NLD_VelocityBoundaryDynamics3D<T,Descriptor>*> (
00993                 &neighbor3.getDynamics() );
00994 
00995     if (!(dyn1 || dyn2 || dyn3)) {
00996         Cell<T,Descriptor>& middleNeighbor = lattice.get(nbCell[0], nbCell[1], nbCell[2]);
00997         Array<T,3> u; middleNeighbor.computeVelocity(u);
00998         NLD_VelocityCornerUtil3D<T,Descriptor> cornerUtil(xNormal, yNormal, zNormal, iX,iY,iZ, lattice, *this);
00999         cornerUtil.boundaryCompletion(u);
01000     }
01001     else {
01002         Cell<T,Descriptor> tmpCell(lattice.get(iX,iY,iZ));
01003         for (plint iPop=0; iPop<Descriptor<T>::q; ++iPop) {
01004             tmpCell[iPop] = T();
01005         }
01006         plint numNeighbors=0;
01007         if (dyn1) {
01008             dyn1->cornerBoundaryCompletion (
01009                     xNormal,yNormal,zNormal, iX,iY,iZ, lattice);
01010             for (plint iPop=0; iPop<Descriptor<T>::q; ++iPop) {
01011                 tmpCell[iPop] += cell[iPop];
01012             }
01013             ++numNeighbors;
01014         }
01015         if (dyn2) {
01016             dyn2->cornerBoundaryCompletion (
01017                     xNormal,yNormal,zNormal, iX,iY,iZ, lattice);
01018             for (plint iPop=0; iPop<Descriptor<T>::q; ++iPop) {
01019                 tmpCell[iPop] += cell[iPop];
01020             }
01021             ++numNeighbors;
01022         }
01023         if (dyn3) {
01024             dyn3->cornerBoundaryCompletion (
01025                     xNormal,yNormal,zNormal, iX,iY,iZ, lattice);
01026             for (plint iPop=0; iPop<Descriptor<T>::q; ++iPop) {
01027                 tmpCell[iPop] += cell[iPop];
01028             }
01029             ++numNeighbors;
01030         }
01031         if (numNeighbors>1) {
01032             for (plint iPop=0; iPop<Descriptor<T>::q; ++iPop) {
01033                 cell[iPop] = tmpCell[iPop] / (T)numNeighbors;
01034             }
01035         }
01036     }
01037 }
01038 
01039 
01040 }  // namespace plb
01041 
01042 // namespace plb
01043 
01044 #endif  // NLD_BOUNDARY_DYNAMICS_3D_HH