$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 00025 #ifndef GUO_OFF_LATTICE_MODEL_3D_HH 00026 #define GUO_OFF_LATTICE_MODEL_3D_HH 00027 00028 #include "offLattice/guoOffLatticeModel3D.h" 00029 #include "offLattice/nextNeighbors3D.h" 00030 #include "latticeBoltzmann/geometricOperationTemplates.h" 00031 #include "latticeBoltzmann/externalFieldAccess.h" 00032 #include <algorithm> 00033 #include <cmath> 00034 00035 namespace plb { 00036 00037 template<typename T, template<typename U> class Descriptor> 00038 GuoOffLatticeModel3D<T,Descriptor>::LiquidNeighbor::LiquidNeighbor 00039 (plint iNeighbor_, plint depth_, plint iTriangle_, Array<T,3> wallNormal) 00040 : iNeighbor(iNeighbor_), 00041 depth(depth_), 00042 iTriangle(iTriangle_) 00043 { 00044 int const* c = NextNeighbor<T>::c[iNeighbor]; 00045 Array<T,3> neighborVect(c[0],c[1],c[2]); 00046 cosAngle = fabs(dot(neighborVect,wallNormal))*NextNeighbor<T>::invD[iNeighbor]; 00047 } 00048 00049 template<typename T, template<typename U> class Descriptor> 00050 bool GuoOffLatticeModel3D<T,Descriptor>::LiquidNeighbor:: 00051 operator<(LiquidNeighbor const& rhs) const 00052 { 00053 return cosAngle < rhs.cosAngle; 00054 } 00055 00056 template<typename T, template<typename U> class Descriptor> 00057 GuoOffLatticeModel3D<T,Descriptor>::GuoOffLatticeModel3D ( 00058 BoundaryShape3D<T,Array<T,3> >* shape_, int flowType_, bool useAllDirections_ ) 00059 : OffLatticeModel3D<T,Array<T,3> >(shape_, flowType_), 00060 useAllDirections(useAllDirections_), 00061 regularizedModel(true), 00062 secondOrderFlag(true), 00063 computeStat(true) 00064 { } 00065 00066 template<typename T, template<typename U> class Descriptor> 00067 GuoOffLatticeModel3D<T,Descriptor>* GuoOffLatticeModel3D<T,Descriptor>::clone() const { 00068 return new GuoOffLatticeModel3D(*this); 00069 } 00070 00071 template<typename T, template<typename U> class Descriptor> 00072 plint GuoOffLatticeModel3D<T,Descriptor>::getNumNeighbors() const { 00073 return 2; 00074 } 00075 00076 template<typename T, template<typename U> class Descriptor> 00077 void GuoOffLatticeModel3D<T,Descriptor>::prepareCell ( 00078 Dot3D const& cellLocation, 00079 AtomicContainerBlock3D& container ) 00080 { 00081 Dot3D offset = container.getLocation(); 00082 GuoOffLatticeInfo3D* info = 00083 dynamic_cast<GuoOffLatticeInfo3D*>(container.getData()); 00084 PLB_ASSERT( info ); 00085 std::vector<LiquidNeighbor> liquidNeighbors; 00086 if (!this->isFluid(cellLocation+offset)) { 00087 for (int iNeighbor=0; iNeighbor<NextNeighbor<T>::numNeighbors; ++iNeighbor) { 00088 int const* c = NextNeighbor<T>::c[iNeighbor]; 00089 Dot3D neighbor(cellLocation.x+c[0], cellLocation.y+c[1], cellLocation.z+c[2]); 00090 // If the non-fluid node has a fluid neighbor ... 00091 if (this->isFluid(neighbor+offset)) { 00092 // ... check how many fluid nodes it has ahead of it ... 00093 int depth = 1; 00094 for (int iDepth=2; iDepth<=getNumNeighbors(); ++iDepth) { 00095 Dot3D nextNeighbor(cellLocation.x+iDepth*c[0], 00096 cellLocation.y+iDepth*c[1], 00097 cellLocation.z+iDepth*c[2]); 00098 if (this->isFluid(nextNeighbor+offset)) { 00099 depth = iDepth; 00100 } 00101 else { 00102 break; 00103 } 00104 } 00105 plint iTriangle=-1; 00106 global::timer("intersect").start(); 00107 Array<T,3> locatedPoint; 00108 T distance; 00109 Array<T,3> wallNormal; 00110 Array<T,3> surfaceData; 00111 OffBoundary::Type bdType; 00112 #ifdef PLB_DEBUG 00113 bool ok = 00114 #endif 00115 this->pointOnSurface ( 00116 cellLocation+offset, Dot3D(c[0],c[1],c[2]), locatedPoint, distance, 00117 wallNormal, surfaceData, bdType, iTriangle ); 00118 // In the following, the importance of directions is sorted wrt. how well they 00119 // are aligned with the wall normal. It is better to take the continuous normal, 00120 // because it is not sensitive to the choice of the triangle when we shoot at 00121 // an edge. 00122 //wallNormal = this->computeContinuousNormal(locatedPoint, iTriangle); 00123 global::timer("intersect").stop(); 00124 PLB_ASSERT( ok ); 00125 // ... then add this node to the list. 00126 liquidNeighbors.push_back(LiquidNeighbor(iNeighbor, depth, iTriangle, wallNormal)); 00127 } 00128 } 00129 if (!liquidNeighbors.empty()) { 00130 info->getDryNodes().push_back(cellLocation); 00131 std::sort(liquidNeighbors.begin(), liquidNeighbors.end()); 00132 std::vector<std::pair<int,int> > neighborDepthPairs; 00133 std::vector<plint> ids; 00134 if (useAllDirections) { 00135 for (pluint i=0; i<liquidNeighbors.size(); ++i) { 00136 neighborDepthPairs.push_back(std::make_pair(liquidNeighbors[i].iNeighbor, liquidNeighbors[i].depth)); 00137 ids.push_back(liquidNeighbors[i].iTriangle); 00138 } 00139 } 00140 else { 00141 plint i = liquidNeighbors.size()-1; 00142 neighborDepthPairs.push_back(std::make_pair(liquidNeighbors[i].iNeighbor, liquidNeighbors[i].depth)); 00143 ids.push_back(liquidNeighbors[i].iTriangle); 00144 } 00145 info->getDryNodeFluidDirections().push_back(neighborDepthPairs); 00146 info->getDryNodeIds().push_back(ids); 00147 } 00148 } 00149 } 00150 00151 template<typename T, template<typename U> class Descriptor> 00152 ContainerBlockData* 00153 GuoOffLatticeModel3D<T,Descriptor>::generateOffLatticeInfo() const 00154 { 00155 return new GuoOffLatticeInfo3D; 00156 } 00157 00158 template<typename T, template<typename U> class Descriptor> 00159 Array<T,3> GuoOffLatticeModel3D<T,Descriptor>::getLocalForce ( 00160 AtomicContainerBlock3D& container ) const 00161 { 00162 GuoOffLatticeInfo3D* info = 00163 dynamic_cast<GuoOffLatticeInfo3D*>(container.getData()); 00164 PLB_ASSERT( info ); 00165 return info->getLocalForce(); 00166 } 00167 00168 template<typename T, template<typename U> class Descriptor> 00169 void GuoOffLatticeModel3D<T,Descriptor>::boundaryCompletion ( 00170 AtomicBlock3D& nonTypeLattice, 00171 AtomicContainerBlock3D& container, 00172 std::vector<AtomicBlock3D const*> const& args ) 00173 { 00174 BlockLattice3D<T,Descriptor>& lattice = 00175 dynamic_cast<BlockLattice3D<T,Descriptor>&> (nonTypeLattice); 00176 GuoOffLatticeInfo3D* info = 00177 dynamic_cast<GuoOffLatticeInfo3D*>(container.getData()); 00178 PLB_ASSERT( info ); 00179 std::vector<Dot3D> const& 00180 dryNodes = info->getDryNodes(); 00181 std::vector<std::vector<std::pair<int,int> > > const& 00182 dryNodeFluidDirections = info->getDryNodeFluidDirections(); 00183 std::vector<std::vector<plint> > const& 00184 dryNodeIds = info->getDryNodeIds(); 00185 PLB_ASSERT( dryNodes.size() == dryNodeFluidDirections.size() ); 00186 00187 Dot3D absoluteOffset = lattice.getLocation(); 00188 00189 Array<T,3>& localForce = info->getLocalForce(); 00190 localForce.resetToZero(); 00191 for (pluint iDry=0; iDry<dryNodes.size(); ++iDry) { 00192 cellCompletion ( 00193 lattice, dryNodes[iDry], dryNodeFluidDirections[iDry], 00194 dryNodeIds[iDry], absoluteOffset, localForce, args ); 00195 } 00196 } 00197 00198 template<typename T, template<typename U> class Descriptor> 00199 void GuoOffLatticeModel3D<T,Descriptor>::cellCompletion ( 00200 BlockLattice3D<T,Descriptor>& lattice, 00201 Dot3D const& guoNode, 00202 std::vector<std::pair<int,int> > const& dryNodeFluidDirections, 00203 std::vector<plint> const& dryNodeIds, Dot3D const& absoluteOffset, 00204 Array<T,3>& localForce, std::vector<AtomicBlock3D const*> const& args ) 00205 { 00206 typedef Descriptor<T> D; 00207 Cell<T,Descriptor>& cell = 00208 lattice.get(guoNode.x, guoNode.y, guoNode.z); 00209 plint numDirections = (plint)dryNodeFluidDirections.size(); 00210 std::vector<T> weights(numDirections); 00211 std::vector<T> rhoBar_vect(numDirections); 00212 std::vector<Array<T,Descriptor<T>::d> > j_vect(numDirections); 00213 // The following variables are used if regularized model is switched off. 00214 std::vector<Array<T,Descriptor<T>::q> > fNeq_vect(numDirections); 00215 // The following variables are used if regularized model is switched on. 00216 std::vector<Array<T,SymmetricTensor<T,Descriptor>::n> > PiNeq_vect(numDirections); 00217 T sumWeights = T(); 00218 Array<T,3> wallNormal; 00219 for (plint iDirection=0; iDirection<numDirections; ++iDirection) { 00220 int iNeighbor = dryNodeFluidDirections[iDirection].first; 00221 int const* c = NextNeighbor<T>::c[iNeighbor]; 00222 Dot3D fluidDirection(c[0],c[1],c[2]); 00223 plint dryNodeId = dryNodeIds[iDirection]; 00224 int depth = dryNodeFluidDirections[iDirection].second; 00225 00226 Array<T,3> wallNode, wall_vel; 00227 T wallDistance; 00228 OffBoundary::Type bdType; 00229 #ifdef PLB_DEBUG 00230 bool ok = 00231 #endif 00232 pointOnSurface( guoNode+absoluteOffset, fluidDirection, 00233 wallNode, wallDistance, wallNormal, 00234 wall_vel, bdType, dryNodeId ); 00235 PLB_ASSERT( ok ); 00236 if (bdType==OffBoundary::dirichlet) { 00237 for (int iD=0; iD<Descriptor<T>::d; ++iD) { 00238 // Use the formula uLB = uP - 1/2 g. If there is no external force, 00239 // the force term automatically evaluates to zero. 00240 wall_vel[iD] -= 0.5*getExternalForceComponent(cell,iD); 00241 } 00242 } 00243 T invDistanceToNeighbor = NextNeighbor<T>::invD[iNeighbor]; 00244 PLB_ASSERT( wallDistance <= NextNeighbor<T>::d[iNeighbor] ); 00245 T delta = (T)1. - wallDistance * invDistanceToNeighbor; 00246 Array<T,3> normalFluidDirection((T)fluidDirection.x, (T)fluidDirection.y, (T)fluidDirection.z); 00247 normalFluidDirection *= invDistanceToNeighbor; 00248 weights[iDirection] = fabs(dot(normalFluidDirection, wallNormal)); 00249 sumWeights += weights[iDirection]; 00250 00251 if (usesRegularizedModel()) { 00252 computeRhoBarJPiNeq ( 00253 lattice, guoNode, fluidDirection, depth, 00254 wallNode, delta, wall_vel, bdType, wallNormal, dryNodeId, 00255 00256 rhoBar_vect[iDirection], j_vect[iDirection], PiNeq_vect[iDirection], args ); 00257 } 00258 else { 00259 computeRhoBarJfNeq ( 00260 lattice, guoNode, fluidDirection, depth, 00261 wallNode, delta, wall_vel, bdType, wallNormal, dryNodeId, 00262 00263 rhoBar_vect[iDirection], j_vect[iDirection], fNeq_vect[iDirection], args ); 00264 } 00265 } 00266 00267 T rhoBar = T(); 00268 Array<T,D::d> j; j.resetToZero(); 00269 Array<T,SymmetricTensor<T,Descriptor>::n> PiNeq; PiNeq.resetToZero(); 00270 Array<T,Descriptor<T>::q> fNeq; fNeq.resetToZero(); 00271 for (plint iDirection=0; iDirection<numDirections; ++iDirection) { 00272 rhoBar += rhoBar_vect[iDirection] * weights[iDirection]; 00273 j += j_vect[iDirection] * weights[iDirection]; 00274 if (usesRegularizedModel()) { 00275 PiNeq += PiNeq_vect[iDirection] * weights[iDirection]; 00276 } 00277 else { 00278 fNeq += fNeq_vect[iDirection] * weights[iDirection]; 00279 } 00280 } 00281 rhoBar /= sumWeights; 00282 j /= sumWeights; 00283 if (usesRegularizedModel()) { 00284 PiNeq /= sumWeights; 00285 } 00286 else { 00287 fNeq /= sumWeights; 00288 } 00289 00290 T jSqr = normSqr(j); 00291 00292 Array<T,D::d> deltaJ; 00293 deltaJ.resetToZero(); 00294 if (computeStat) { 00295 for (plint iDirection=0; iDirection<numDirections; ++iDirection) { 00296 int iNeighbor = dryNodeFluidDirections[iDirection].first; 00297 int iPop = nextNeighborPop<T,Descriptor>(iNeighbor); 00298 if (iPop>=0) { 00299 plint oppPop = indexTemplates::opposite<D>(iPop); 00300 deltaJ[0] += D::c[oppPop][0]*cell[oppPop]; 00301 deltaJ[1] += D::c[oppPop][1]*cell[oppPop]; 00302 deltaJ[2] += D::c[oppPop][2]*cell[oppPop]; 00303 } 00304 } 00305 } 00306 Dynamics<T,Descriptor> const& dynamics = cell.getDynamics(); 00307 if (this->getPartialReplace()) { 00308 if (usesRegularizedModel()) { 00309 Cell<T,Descriptor> saveCell(cell); 00310 dynamics.regularize(cell, rhoBar, j, jSqr, PiNeq); 00311 for (plint iDirection=0; iDirection<numDirections; ++iDirection) { 00312 int iNeighbor = dryNodeFluidDirections[iDirection].first; 00313 plint iPop = nextNeighborPop<T,Descriptor>(iNeighbor); 00314 plint oppPop = indexTemplates::opposite<D>(iPop); 00315 cell[oppPop] = saveCell[oppPop]; 00316 } 00317 } 00318 else { 00319 for (plint iDirection=0; iDirection<numDirections; ++iDirection) { 00320 int iNeighbor = dryNodeFluidDirections[iDirection].first; 00321 plint iPop = nextNeighborPop<T,Descriptor>(iNeighbor); 00322 cell[iPop] = cell.computeEquilibrium(iPop, rhoBar, j, jSqr)+fNeq[iPop]; 00323 } 00324 } 00325 } 00326 else { 00327 if (usesRegularizedModel()) { 00328 dynamics.regularize(cell, rhoBar, j, jSqr, PiNeq); 00329 } 00330 else { 00331 for (plint iPop=0; iPop<Descriptor<T>::q; ++iPop) { 00332 cell[iPop] = cell.computeEquilibrium(iPop, rhoBar, j, jSqr)+fNeq[iPop]; 00333 } 00334 } 00335 } 00336 00337 if (computeStat) { 00338 Cell<T,Descriptor> collidedCell(cell); 00339 BlockStatistics statsCopy(lattice.getInternalStatistics()); 00340 collidedCell.collide(statsCopy); 00341 00342 for (plint iDirection=0; iDirection<numDirections; ++iDirection) { 00343 int iNeighbor = dryNodeFluidDirections[iDirection].first; 00344 plint iPop = nextNeighborPop<T,Descriptor>(iNeighbor); 00345 if (iPop>=0) { 00346 deltaJ[0] -= D::c[iPop][0]*collidedCell[iPop]; 00347 deltaJ[1] -= D::c[iPop][1]*collidedCell[iPop]; 00348 deltaJ[2] -= D::c[iPop][2]*collidedCell[iPop]; 00349 } 00350 } 00351 // Don't divide by rho. Here we just divide by rho0=1. Remember that, 00352 // while j is conserved along a channel, rho is not due to the 00353 // pressure drop. Dividing by rho instead of rho0 would yield a 00354 // larger result upstream than downstream, independent on whether 00355 // the velocity is u or j. 00356 localForce += deltaJ; 00357 } 00358 } 00359 00360 template<typename T, template<typename U> class Descriptor> 00361 void GuoOffLatticeModel3D<T,Descriptor>::computeRhoBarJPiNeq ( 00362 BlockLattice3D<T,Descriptor> const& lattice, Dot3D const& guoNode, 00363 Dot3D const& fluidDirection, int depth, Array<T,3> const& wallNode, T delta, 00364 Array<T,3> const& wall_vel, OffBoundary::Type bdType, 00365 Array<T,3> const& wallNormal, plint triangleId, 00366 T& rhoBar, Array<T,Descriptor<T>::d>& j, 00367 Array<T,SymmetricTensor<T,Descriptor>::n>& PiNeq, 00368 std::vector<AtomicBlock3D const*> const& args ) const 00369 { 00370 if (!usesSecondOrder()) { 00371 depth=1; 00372 } 00373 T rhoBar1; 00374 Array<T,Descriptor<T>::d> j1, j2; 00375 Cell<T,Descriptor> const& cell1 = 00376 lattice.get( guoNode.x+fluidDirection.x, 00377 guoNode.y+fluidDirection.y, 00378 guoNode.z+fluidDirection.z ); 00379 cell1.getDynamics().computeRhoBarJPiNeq(cell1, rhoBar1, j1, PiNeq); 00380 if (args.empty()) { 00381 Cell<T,Descriptor> const& cell2 = 00382 lattice.get( guoNode.x+2*fluidDirection.x, 00383 guoNode.y+2*fluidDirection.y, 00384 guoNode.z+2*fluidDirection.z ); 00385 00386 T tmpRhoBar; 00387 cell2.getDynamics().computeRhoBarJ(cell2, tmpRhoBar, j2); 00388 } 00389 else { 00390 PLB_ASSERT( (plint)args.size()==1 ); 00391 NTensorField3D<T> const* macroField = 00392 dynamic_cast<NTensorField3D<T> const*>( args[0] ); 00393 PLB_ASSERT( macroField ); 00394 // 1 Variable for rhoBar, 3 variables for j. 00395 PLB_ASSERT( macroField->getNdim()==4 ); 00396 Dot3D offset = computeRelativeDisplacement(lattice, *macroField); 00397 T const* macroscopic = macroField->get ( 00398 guoNode.x+2*fluidDirection.x+offset.x, 00399 guoNode.y+2*fluidDirection.y+offset.y, 00400 guoNode.z+2*fluidDirection.z+offset.z ); 00401 j2.from_cArray(macroscopic+1); 00402 } 00403 00404 if ( bdType==OffBoundary::constRhoInlet || 00405 bdType==OffBoundary::densityNeumann ) 00406 { 00407 rhoBar=Descriptor<T>::rhoBar(wall_vel[0]); 00408 } 00409 else { 00410 rhoBar = rhoBar1; 00411 } 00412 Array<T,3> wall_j ( 00413 this->velIsJ() ? wall_vel : 00414 (Descriptor<T>::fullRho(rhoBar)*wall_vel) ); 00415 if (depth < 2) { 00416 if (delta < (T)0.25) { 00417 j = wall_j; 00418 } 00419 else { 00420 //j = (T)1./delta * (wall_j+(delta-(T)1.)*j1); 00421 j = wall_j; // Temporary fix for complex geometries. 00422 } 00423 } 00424 else { // depth >= 2 d=1 d=0.5 d=0 00425 if (delta < (T)0.75) { // x---|=========o-------------o 00426 j = wall_j + (delta-(T)1.)*j1 + 00427 ((T)1.-delta)/((T)1.+delta)*((T)2.*wall_j+(delta-(T)1.)*j2); 00428 } // d=1 d=0.5 d=0 00429 else { // x===|---------o-------------o 00430 j = (T)1./delta * (wall_j+(delta-(T)1.)*j1); 00431 } 00432 } 00433 if ( bdType==OffBoundary::neumann ) 00434 { 00435 j = j1; 00436 } 00437 else if ( bdType==OffBoundary::densityNeumann ) { 00438 j = dot(j1,wallNormal)*wallNormal; 00439 } 00440 else if ( bdType==OffBoundary::freeSlip ) { 00441 Array<T,3> continuousNormal = 00442 this->computeContinuousNormal(wallNode, triangleId); 00443 j = j1-dot(j1,continuousNormal)*continuousNormal; 00444 } 00445 } 00446 00447 template<typename T, template<typename U> class Descriptor> 00448 void GuoOffLatticeModel3D<T,Descriptor>::computeRhoBarJfNeq ( 00449 BlockLattice3D<T,Descriptor> const& lattice, Dot3D const& guoNode, 00450 Dot3D const& fluidDirection, int depth, Array<T,3> const& wallNode, T delta, 00451 Array<T,3> const& wall_vel, OffBoundary::Type bdType, 00452 Array<T,3> const& wallNormal, plint triangleId, 00453 T& rhoBar, Array<T,Descriptor<T>::d>& j, 00454 Array<T,Descriptor<T>::q>& fNeq, 00455 std::vector<AtomicBlock3D const*> const& args ) const 00456 { 00457 if (!usesSecondOrder()) { 00458 depth=1; 00459 } 00460 T rhoBar1, rhoBar2; 00461 Array<T,Descriptor<T>::d> j1, j2; 00462 Array<T,Descriptor<T>::q> fNeq1, fNeq2; 00463 Cell<T,Descriptor> const& cell1 = 00464 lattice.get( guoNode.x+fluidDirection.x, 00465 guoNode.y+fluidDirection.y, 00466 guoNode.z+fluidDirection.z ); 00467 Cell<T,Descriptor> const& cell2 = 00468 lattice.get( guoNode.x+2*fluidDirection.x, 00469 guoNode.y+2*fluidDirection.y, 00470 guoNode.z+2*fluidDirection.z ); 00471 cell1.getDynamics().computeRhoBarJ(cell1, rhoBar1, j1); 00472 cell2.getDynamics().computeRhoBarJ(cell2, rhoBar2, j2); 00473 T j1sqr = normSqr(j1); 00474 T j2sqr = normSqr(j2); 00475 for(plint iPop=0; iPop<Descriptor<T>::q; ++iPop) { 00476 fNeq1[iPop] = cell1[iPop]-cell1.getDynamics().computeEquilibrium(iPop, rhoBar1, j1, j1sqr); 00477 fNeq2[iPop] = cell2[iPop]-cell2.getDynamics().computeEquilibrium(iPop, rhoBar2, j2, j2sqr); 00478 } 00479 00480 if ( bdType==OffBoundary::constRhoInlet || 00481 bdType==OffBoundary::densityNeumann ) 00482 { 00483 rhoBar=Descriptor<T>::rhoBar(wall_vel[0]); 00484 } 00485 else { 00486 rhoBar = rhoBar1; 00487 } 00488 Array<T,3> wall_j ( 00489 this->velIsJ() ? wall_vel : 00490 (Descriptor<T>::fullRho(rhoBar)*wall_vel) ); 00491 Array<T,3> jNeumann; 00492 fNeq = fNeq1; 00493 jNeumann = j1; 00494 if (depth < 2) { 00495 if (delta < (T)0.25) { 00496 j = wall_j; 00497 } 00498 else { 00499 j = (T)1./delta * (wall_j+(delta-(T)1.)*j1); 00500 } 00501 } 00502 else { // depth >= 2 00503 if (delta < (T)0.75) { 00504 j = wall_j + (delta-(T)1.)*j1 + 00505 ((T)1.-delta)/((T)1.+delta)*((T)2.*wall_j+(delta-(T)1.)*j2); 00506 } 00507 else { 00508 j = (T)1./delta * (wall_j+(delta-(T)1.)*j1); 00509 } 00510 } 00511 if ( bdType==OffBoundary::neumann ) 00512 { 00513 j = jNeumann; 00514 } 00515 else if ( bdType==OffBoundary::densityNeumann ) { 00516 j = dot(jNeumann,wallNormal)*wallNormal; 00517 } 00518 else if ( bdType==OffBoundary::freeSlip ) { 00519 Array<T,3> continuousNormal = 00520 this->computeContinuousNormal(wallNode, triangleId); 00521 j = jNeumann-dot(jNeumann,continuousNormal)*continuousNormal; 00522 } 00523 } 00524 00525 } // namespace plb 00526 00527 #endif // GUO_OFF_LATTICE_MODEL_3D_HH
1.6.3
1.6.3