$treeview $search $mathjax
|
Palabos
Version 1.1
$projectbrief
|
$projectbrief
|
$searchbox |
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
1.6.3
1.6.3