$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 GENERALIZED_OFF_LATTICE_MODEL_3D_HH 00026 #define GENERALIZED_OFF_LATTICE_MODEL_3D_HH 00027 00028 #include "offLattice/generalizedOffLatticeModel3D.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 ExtrapolatedGeneralizedOffLatticeModel3D<T,Descriptor>::ExtrapolatedGeneralizedOffLatticeModel3D ( 00039 BoundaryShape3D<T,Array<T,3> >* shape_, int flowType_ ) 00040 : OffLatticeModel3D<T,Array<T,3> >(shape_, flowType_) 00041 { } 00042 00043 template<typename T, template<typename U> class Descriptor> 00044 ExtrapolatedGeneralizedOffLatticeModel3D<T,Descriptor>::ExtrapolatedGeneralizedOffLatticeModel3D ( 00045 ExtrapolatedGeneralizedOffLatticeModel3D<T,Descriptor> const& rhs ) 00046 : OffLatticeModel3D<T,Array<T,3> >(rhs) 00047 { } 00048 00049 template<typename T, template<typename U> class Descriptor> 00050 ExtrapolatedGeneralizedOffLatticeModel3D<T,Descriptor>& 00051 ExtrapolatedGeneralizedOffLatticeModel3D<T,Descriptor>::operator=(ExtrapolatedGeneralizedOffLatticeModel3D<T,Descriptor> const& rhs) 00052 { 00053 OffLatticeModel3D<T,Array<T,3> >::operator=(rhs); 00054 return *this; 00055 } 00056 00057 template<typename T, template<typename U> class Descriptor> 00058 ExtrapolatedGeneralizedOffLatticeModel3D<T,Descriptor>* ExtrapolatedGeneralizedOffLatticeModel3D<T,Descriptor>::clone() const { 00059 return new ExtrapolatedGeneralizedOffLatticeModel3D(*this); 00060 } 00061 00062 template<typename T, template<typename U> class Descriptor> 00063 plint ExtrapolatedGeneralizedOffLatticeModel3D<T,Descriptor>::getNumNeighbors() const { 00064 return 2; 00065 } 00066 00067 template<typename T, template<typename U> class Descriptor> 00068 void ExtrapolatedGeneralizedOffLatticeModel3D<T,Descriptor>::prepareCell ( 00069 Dot3D const& cellLocation, 00070 AtomicContainerBlock3D& container ) 00071 { 00072 Dot3D offset = container.getLocation(); 00073 ExtrapolatedGeneralizedOffLatticeInfo3D* info = 00074 dynamic_cast<ExtrapolatedGeneralizedOffLatticeInfo3D*>(container.getData()); 00075 PLB_ASSERT( info ); 00076 if (!this->isFluid(cellLocation+offset)) { 00077 std::vector<std::pair<int,int> > liquidNeighbors; 00078 std::vector<int> liquidNeighborsNoSolid; 00079 std::vector<plint> ids; 00080 for (int iNeighbor=0; iNeighbor<NextNeighbor<T>::numNeighbors; ++iNeighbor) { 00081 int const* c = NextNeighbor<T>::c[iNeighbor]; 00082 Dot3D neighbor(cellLocation.x+c[0], cellLocation.y+c[1], cellLocation.z+c[2]); 00083 // If the non-fluid node has a fluid neighbor ... 00084 if (this->isFluid(neighbor+offset)) { 00085 // ... check how many fluid nodes it has ahead of it ... 00086 int depth = 1; 00087 for (int iDepth=2; iDepth<=getNumNeighbors(); ++iDepth) { 00088 Dot3D nextNeighbor(cellLocation.x+iDepth*c[0], 00089 cellLocation.y+iDepth*c[1], 00090 cellLocation.z+iDepth*c[2]); 00091 if (this->isFluid(nextNeighbor+offset)) { 00092 depth = iDepth; 00093 } 00094 else { 00095 break; 00096 } 00097 } 00098 // ... then add this node to the list. 00099 liquidNeighbors.push_back(std::make_pair(iNeighbor,depth)); 00100 Array<T,3> locatedPoint; 00101 T distance; 00102 Array<T,3> wallNormal; 00103 Array<T,3> surfaceData; 00104 plint iTriangle=-1; 00105 OffBoundary::Type bdType; 00106 #ifdef PLB_DEBUG 00107 bool ok = 00108 #endif 00109 pointOnSurface ( 00110 cellLocation+offset, Dot3D(c[0],c[1],c[2]), locatedPoint, distance, 00111 wallNormal, surfaceData, bdType, iTriangle ); 00112 PLB_ASSERT( ok ); 00113 ids.push_back(iTriangle); 00114 liquidNeighborsNoSolid.push_back(iNeighbor); 00115 } 00116 else { 00117 bool fluidNeighbor = false; 00118 for (int jNeighbor=1; jNeighbor<Descriptor<T>::q; ++jNeighbor) { 00119 Dot3D next_neighbor(neighbor.x+Descriptor<T>::c[jNeighbor][0], 00120 neighbor.y+Descriptor<T>::c[jNeighbor][1], 00121 neighbor.z+Descriptor<T>::c[jNeighbor][2]); 00122 if ((this->isFluid(next_neighbor+offset))) { 00123 fluidNeighbor = true; 00124 break; 00125 } 00126 } 00127 if (fluidNeighbor) { 00128 liquidNeighborsNoSolid.push_back(iNeighbor); 00129 } 00130 } 00131 } 00132 if (!liquidNeighbors.empty()) { 00133 // selecting only deepest depth available (for a higher order interpolation order) 00134 // std::vector<std::vector<std::pair<int,int> > > selectionLiquid(getNumNeighbors()+1); 00135 // std::vector<std::vector<plint > > selectionIds(getNumNeighbors()+1); 00136 // for (pluint iA = 0; iA < liquidNeighbors.size(); ++iA) { 00137 // selectionLiquid[liquidNeighbors[iA].second].push_back(liquidNeighbors[iA]); 00138 // selectionIds[liquidNeighbors[iA].second].push_back(ids[iA]); 00139 // } 00140 00141 info->getDryNodes().push_back(cellLocation); 00142 info->getDryNodeFluidWithFluidDirections().push_back(liquidNeighborsNoSolid); 00143 info->getDryNodeFluidDirections().push_back(liquidNeighbors); 00144 info->getDryNodeIds().push_back(ids); 00145 00146 // add only biggest depth to the list of directions and triangles 00147 // for (plint iA = getNumNeighbors(); iA >= 0; --iA) { 00148 // if (!selectionLiquid[iA].empty()) { 00149 // info->getDryNodeFluidDirections().push_back(selectionLiquid[iA]); 00150 // info->getDryNodeIds().push_back(selectionIds[iA]); 00151 // break; 00152 // } 00153 // } 00154 00155 } 00156 } 00157 } 00158 00159 template<typename T, template<typename U> class Descriptor> 00160 ContainerBlockData* 00161 ExtrapolatedGeneralizedOffLatticeModel3D<T,Descriptor>::generateOffLatticeInfo() const 00162 { 00163 return new ExtrapolatedGeneralizedOffLatticeInfo3D; 00164 } 00165 00166 template<typename T, template<typename U> class Descriptor> 00167 Array<T,3> ExtrapolatedGeneralizedOffLatticeModel3D<T,Descriptor>::getLocalForce ( 00168 AtomicContainerBlock3D& container ) const 00169 { 00170 ExtrapolatedGeneralizedOffLatticeInfo3D* info = 00171 dynamic_cast<ExtrapolatedGeneralizedOffLatticeInfo3D*>(container.getData()); 00172 PLB_ASSERT( info ); 00173 return info->getLocalForce(); 00174 } 00175 00176 template<typename T, template<typename U> class Descriptor> 00177 void ExtrapolatedGeneralizedOffLatticeModel3D<T,Descriptor>::boundaryCompletion ( 00178 AtomicBlock3D& nonTypeLattice, 00179 AtomicContainerBlock3D& container, 00180 std::vector<AtomicBlock3D const*> const& args ) 00181 { 00182 BlockLattice3D<T,Descriptor>& lattice = 00183 dynamic_cast<BlockLattice3D<T,Descriptor>&> (nonTypeLattice); 00184 ExtrapolatedGeneralizedOffLatticeInfo3D* info = 00185 dynamic_cast<ExtrapolatedGeneralizedOffLatticeInfo3D*>(container.getData()); 00186 PLB_ASSERT( info ); 00187 std::vector<Dot3D> const& 00188 dryNodes = info->getDryNodes(); 00189 std::vector<std::vector<std::pair<int,int> > > const& 00190 dryNodeFluidDirections = info->getDryNodeFluidDirections(); 00191 std::vector<std::vector<int> > const& 00192 dryNodeFluidNoSolidDirections = info->getDryNodeFluidWithFluidDirections(); 00193 std::vector<std::vector<plint> > const& 00194 dryNodeIds = info->getDryNodeIds(); 00195 PLB_ASSERT( dryNodes.size() == dryNodeFluidDirections.size() ); 00196 00197 Dot3D absoluteOffset = lattice.getLocation(); 00198 00199 Array<T,3>& localForce = info->getLocalForce(); 00200 localForce.resetToZero(); 00201 for (pluint iDry=0; iDry<dryNodes.size(); ++iDry) { 00202 cellCompletion ( 00203 lattice, dryNodes[iDry], dryNodeFluidDirections[iDry], dryNodeFluidNoSolidDirections[iDry], 00204 dryNodeIds[iDry], absoluteOffset, localForce ); 00205 } 00206 } 00207 00208 template<typename T, template<typename U> class Descriptor> 00209 void ExtrapolatedGeneralizedOffLatticeModel3D<T,Descriptor>::cellCompletion ( 00210 BlockLattice3D<T,Descriptor>& lattice, 00211 Dot3D const& genNode, 00212 std::vector<std::pair<int,int> > const& dryNodeFluidDirections, 00213 std::vector<int> const& dryNodeFluidNoSolidDirections, 00214 std::vector<plint> const& dryNodeIds, Dot3D const& absoluteOffset, 00215 Array<T,3>& localForce ) 00216 { 00217 typedef Descriptor<T> D; 00218 using namespace indexTemplates; 00219 00220 Cell<T,Descriptor>& cell = 00221 lattice.get(genNode.x, genNode.y, genNode.z); 00222 plint numDirections = (plint)dryNodeFluidDirections.size(); 00223 std::vector<T> weights(numDirections); 00224 std::vector<Array<T,Descriptor<T>::d> > u_vect(numDirections); 00225 T sumWeights = T(); 00226 Array<T,3> wallNormal; 00227 for (plint iDirection=0; iDirection<numDirections; ++iDirection) { 00228 int iNeighbor = dryNodeFluidDirections[iDirection].first; 00229 int const* c = NextNeighbor<T>::c[iNeighbor]; 00230 Dot3D fluidDirection(c[0],c[1],c[2]); 00231 plint dryNodeId = dryNodeIds[iDirection]; 00232 int depth = dryNodeFluidDirections[iDirection].second; 00233 00234 Array<T,3> wallNode, wall_vel; 00235 T wallDistance; 00236 OffBoundary::Type bdType; 00237 #ifdef PLB_DEBUG 00238 bool ok = 00239 #endif 00240 pointOnSurface( genNode+absoluteOffset, fluidDirection, 00241 wallNode, wallDistance, wallNormal, 00242 wall_vel, bdType, dryNodeId ); 00243 PLB_ASSERT( ok ); 00244 for (int iD=0; iD<Descriptor<T>::d; ++iD) { 00245 // Use the formula uLB = uP - 1/2 g. If there is no external force, 00246 // the force term automatically evaluates to zero. 00247 wall_vel[iD] -= 0.5*getExternalForceComponent(cell,iD); 00248 } 00249 T invDistanceToNeighbor = NextNeighbor<T>::invD[iNeighbor]; 00250 PLB_ASSERT( wallDistance <= NextNeighbor<T>::d[iNeighbor] ); 00251 T delta = (T)1. - wallDistance * invDistanceToNeighbor; 00252 Array<T,3> normalFluidDirection((T)fluidDirection.x, (T)fluidDirection.y, (T)fluidDirection.z); 00253 normalFluidDirection *= invDistanceToNeighbor; 00254 weights[iDirection] = fabs ( dot(normalFluidDirection, wallNormal) ); 00255 sumWeights += weights[iDirection]; 00256 00257 computeVelocity( 00258 lattice, genNode, fluidDirection, depth, 00259 wallNode, delta, wall_vel, bdType, wallNormal, 00260 u_vect[iDirection] ); 00261 } 00262 00263 Array<T,D::d> u; u.resetToZero(); 00264 for (plint iDirection=0; iDirection<numDirections; ++iDirection) { 00265 u += u_vect[iDirection] * weights[iDirection]; 00266 } 00267 u /= sumWeights; 00268 00269 Array<T,D::d> deltaJ; 00270 deltaJ.resetToZero(); 00271 for (plint iDirection=0; iDirection<numDirections; ++iDirection) { 00272 int iNeighbor = dryNodeFluidDirections[iDirection].first; 00273 int iPop = nextNeighborPop<T,Descriptor>(iNeighbor); 00274 if (iPop>=0) { 00275 plint oppPop = indexTemplates::opposite<D>(iPop); 00276 deltaJ[0] += D::c[oppPop][0]*cell[oppPop]; 00277 deltaJ[1] += D::c[oppPop][1]*cell[oppPop]; 00278 deltaJ[2] += D::c[oppPop][2]*cell[oppPop]; 00279 } 00280 } 00281 00282 std::vector<plint> knownIndices; 00283 knownIndices.push_back(0); 00284 for (pluint iDirection=0; iDirection<dryNodeFluidNoSolidDirections.size(); ++iDirection) { 00285 int iNeighbor = dryNodeFluidNoSolidDirections[iDirection]; 00286 plint iPop = nextNeighborPop<T,Descriptor>(iNeighbor); 00287 if (iPop>=0) { 00288 plint index = opposite<Descriptor<T> >(iPop); 00289 knownIndices.push_back(index); 00290 } 00291 } 00292 PLB_ASSERT(knownIndices.size() >= 6); 00293 00294 std::vector<plint> missingIndices = remainingIndexes<Descriptor<T> >(knownIndices); 00295 00296 Dynamics<T,Descriptor> const& dynamics = cell.getDynamics(); 00297 DirichletVelocityBoundarySolver<T,Descriptor> bc(missingIndices, knownIndices, u); 00298 bc.apply(cell,dynamics,!this->getPartialReplace()); 00299 00300 Cell<T,Descriptor> cellCopy(cell); 00301 BlockStatistics statsCopy(lattice.getInternalStatistics()); 00302 cellCopy.collide(statsCopy); 00303 00304 for (plint iDirection=0; iDirection<dryNodeFluidDirections.size(); ++iDirection) { 00305 int iNeighbor = dryNodeFluidDirections[iDirection].first; 00306 plint iPop = nextNeighborPop<T,Descriptor>(iNeighbor); 00307 if (iPop>=0) { 00308 deltaJ[0] -= D::c[iPop][0]*cellCopy[iPop]; 00309 deltaJ[1] -= D::c[iPop][1]*cellCopy[iPop]; 00310 deltaJ[2] -= D::c[iPop][2]*cellCopy[iPop]; 00311 } 00312 } 00313 localForce += deltaJ; 00314 } 00315 00316 template<typename T, template<typename U> class Descriptor> 00317 void ExtrapolatedGeneralizedOffLatticeModel3D<T,Descriptor>::computeVelocity ( 00318 BlockLattice3D<T,Descriptor> const& lattice, Dot3D const& genNode, 00319 Dot3D const& fluidDirection, int depth, Array<T,3> const& wallNode, T delta, 00320 Array<T,3> const& wall_u, OffBoundary::Type bdType, Array<T,3> const& wallNormal, 00321 Array<T,Descriptor<T>::d>& u) const 00322 { 00323 Array<T,Descriptor<T>::d> u1, u2; 00324 Cell<T,Descriptor> const& cell1 = 00325 lattice.get( genNode.x+fluidDirection.x, 00326 genNode.y+fluidDirection.y, 00327 genNode.z+fluidDirection.z ); 00328 Cell<T,Descriptor> const& cell2 = 00329 lattice.get( genNode.x+2*fluidDirection.x, 00330 genNode.y+2*fluidDirection.y, 00331 genNode.z+2*fluidDirection.z ); 00332 if (!this->velIsJ()) { 00333 cell1.getDynamics().computeVelocity(cell1, u1); 00334 cell2.getDynamics().computeVelocity(cell2, u2); 00335 } else { 00336 T rhoBar; 00337 cell1.getDynamics().computeRhoBarJ(cell1, rhoBar, u1); 00338 cell2.getDynamics().computeRhoBarJ(cell2, rhoBar, u2); 00339 } 00340 00341 bool neumann = bdType==OffBoundary::neumann; 00342 if (depth < 2) { 00343 if (delta < (T)0.25) { 00344 u = wall_u; 00345 } 00346 else { 00347 u = 1./delta * (wall_u+(delta-1.)*u1); 00348 } 00349 } 00350 else { // depth >= 2 00351 if (delta < (T)0.75) { 00352 u = wall_u + (delta-1.)*u1 + 00353 (1.-delta)/(1.+delta)*(2.*wall_u+(delta-1.)*u2); 00354 } 00355 else { 00356 u = 1./delta * (wall_u+(delta-1.)*u1); 00357 } 00358 } 00359 if ( bdType==OffBoundary::neumann ) 00360 { 00361 u = u1; 00362 } 00363 if ( bdType==OffBoundary::densityNeumann ) { 00364 u = dot(u1,wallNormal)*wallNormal; 00365 } 00366 } 00367 00368 00369 // ========================================================================= // 00370 // ====Generalized BC with the velocity ocmputed with an interpolation====== // 00371 // ========================================================================= // 00372 00373 00374 template<typename T, template<typename U> class Descriptor> 00375 InterpolatedGeneralizedOffLatticeModel3D<T,Descriptor>::InterpolatedGeneralizedOffLatticeModel3D ( 00376 BoundaryShape3D<T,Array<T,3> >* shape_, int flowType_ ) 00377 : OffLatticeModel3D<T,Array<T,3> >(shape_, flowType_) 00378 { } 00379 00380 template<typename T, template<typename U> class Descriptor> 00381 InterpolatedGeneralizedOffLatticeModel3D<T,Descriptor>::InterpolatedGeneralizedOffLatticeModel3D ( 00382 InterpolatedGeneralizedOffLatticeModel3D<T,Descriptor> const& rhs ) 00383 : OffLatticeModel3D<T,Array<T,3> >(rhs) 00384 { } 00385 00386 template<typename T, template<typename U> class Descriptor> 00387 InterpolatedGeneralizedOffLatticeModel3D<T,Descriptor>& 00388 InterpolatedGeneralizedOffLatticeModel3D<T,Descriptor>::operator=(InterpolatedGeneralizedOffLatticeModel3D<T,Descriptor> const& rhs) 00389 { 00390 OffLatticeModel3D<T,Array<T,3> >::operator=(rhs); 00391 return *this; 00392 } 00393 00394 template<typename T, template<typename U> class Descriptor> 00395 InterpolatedGeneralizedOffLatticeModel3D<T,Descriptor>* InterpolatedGeneralizedOffLatticeModel3D<T,Descriptor>::clone() const { 00396 return new InterpolatedGeneralizedOffLatticeModel3D(*this); 00397 } 00398 00399 template<typename T, template<typename U> class Descriptor> 00400 plint InterpolatedGeneralizedOffLatticeModel3D<T,Descriptor>::getNumNeighbors() const { 00401 return 2; 00402 } 00403 00404 template<typename T, template<typename U> class Descriptor> 00405 void InterpolatedGeneralizedOffLatticeModel3D<T,Descriptor>::prepareCell ( 00406 Dot3D const& cellLocation, 00407 AtomicContainerBlock3D& container ) 00408 { 00409 Dot3D offset = container.getLocation(); 00410 InterpolatedGeneralizedOffLatticeInfo3D* info = 00411 dynamic_cast<InterpolatedGeneralizedOffLatticeInfo3D*>(container.getData()); 00412 PLB_ASSERT( info ); 00413 if (this->isFluid(cellLocation+offset)) { 00414 std::vector<std::pair<int,int> > solidNeighbors; 00415 std::vector<int> wetNodeFluidDirections; 00416 std::vector<plint> ids; 00417 for (int iNeighbor=0; iNeighbor<NextNeighbor<T>::numNeighbors; ++iNeighbor) { 00418 // pcout << "iNeighbor = " << iNeighbor << std::endl; 00419 int const* c = NextNeighbor<T>::c[iNeighbor]; 00420 Dot3D neighbor(cellLocation.x+c[0], cellLocation.y+c[1], cellLocation.z+c[2]); 00421 00422 // TODO use only depth two if possible (add a check for only depth 00423 // two selection or depth one if depth two not possible. 00424 00425 // If the fluid node has a non-fluid neighbor ... 00426 if (!this->isFluid(neighbor+offset)) { 00427 // ... check how many fluid nodes without solid neighbors 00428 // in the direction opposite to the solid. 00429 int depth = 0; 00430 for (int iDepth=1; iDepth<=getNumNeighbors(); ++iDepth) { 00431 // pcout << "depth = " << depth << std::endl; 00432 Dot3D nextNeighbor(cellLocation.x-iDepth*c[0], 00433 cellLocation.y-iDepth*c[1], 00434 cellLocation.z-iDepth*c[2]); 00435 00436 bool solidNeighbor = false; 00437 for (int iPop=1; iPop<Descriptor<T>::q; ++iPop) { 00438 // pcout << "iPop = " << iPop << std::endl; 00439 Dot3D nextNeighbor_neighbor(nextNeighbor.x+Descriptor<T>::c[iPop][0], 00440 nextNeighbor.y+Descriptor<T>::c[iPop][1], 00441 nextNeighbor.z+Descriptor<T>::c[iPop][2]); 00442 // pcout << (nextNeighbor_neighbor+offset).x << " , " << (nextNeighbor_neighbor+offset).y << " , " << (nextNeighbor_neighbor+offset).z << std::endl; 00443 if (!(this->isFluid(nextNeighbor_neighbor+offset))) { 00444 solidNeighbor = true; 00445 break; 00446 } 00447 } 00448 00449 if (this->isFluid(nextNeighbor+offset) && !solidNeighbor) { 00450 depth = iDepth; 00451 } 00452 else { 00453 break; 00454 } 00455 } 00456 // ... then add this node to the list. 00457 solidNeighbors.push_back(std::make_pair(iNeighbor,depth)); 00458 Array<T,3> locatedPoint; 00459 T distance; 00460 Array<T,3> wallNormal; 00461 Array<T,3> surfaceData; 00462 plint iTriangle=-1; 00463 OffBoundary::Type bdType; 00464 #ifdef PLB_DEBUG 00465 bool ok = 00466 #endif 00467 pointOnSurface ( 00468 cellLocation+offset, Dot3D(c[0],c[1],c[2]), locatedPoint, distance, 00469 wallNormal, surfaceData, bdType, iTriangle ); 00470 PLB_ASSERT( ok ); 00471 ids.push_back(iTriangle); 00472 } 00473 } 00474 00475 if (!solidNeighbors.empty()) { 00476 // selecting only deepest depth available (for a higher order interpolation order) 00477 std::vector<std::vector<std::pair<int,int> > > selectionSolid(getNumNeighbors()+1); 00478 std::vector<std::vector<plint > > selectionIds(getNumNeighbors()+1); 00479 for (pluint iA = 0; iA < solidNeighbors.size(); ++iA) { 00480 selectionSolid[solidNeighbors[iA].second].push_back(solidNeighbors[iA]); 00481 selectionIds[solidNeighbors[iA].second].push_back(ids[iA]); 00482 } 00483 // adding fluid boundary wet node's fluid directions (know populations directions). 00484 for (int iPop=1; iPop<Descriptor<T>::q; ++iPop) { 00485 int const* c = Descriptor<T>::c[iPop]; 00486 Dot3D potFluidNeighbor(cellLocation.x+c[0], cellLocation.y+c[1], cellLocation.z+c[2]); 00487 00488 if (this->isFluid(potFluidNeighbor+offset)) { 00489 wetNodeFluidDirections.push_back(iPop); 00490 } 00491 } 00492 00493 info->getWetNodes().push_back(cellLocation); 00494 // add only biggest depth to the list of directions and triangles 00495 for (plint iA = getNumNeighbors(); iA >= 0; --iA) { 00496 if (!selectionSolid[iA].empty()) { 00497 info->getWetNodeSolidDirections().push_back(selectionSolid[iA]); 00498 info->getWetNodeIds().push_back(selectionIds[iA]); 00499 break; 00500 } 00501 } 00502 info->getWetNodeFluidDirections().push_back(wetNodeFluidDirections); 00503 } 00504 } 00505 } 00506 00507 template<typename T, template<typename U> class Descriptor> 00508 ContainerBlockData* 00509 InterpolatedGeneralizedOffLatticeModel3D<T,Descriptor>::generateOffLatticeInfo() const 00510 { 00511 return new InterpolatedGeneralizedOffLatticeInfo3D; 00512 } 00513 00514 template<typename T, template<typename U> class Descriptor> 00515 Array<T,3> InterpolatedGeneralizedOffLatticeModel3D<T,Descriptor>::getLocalForce ( 00516 AtomicContainerBlock3D& container ) const 00517 { 00518 InterpolatedGeneralizedOffLatticeInfo3D* info = 00519 dynamic_cast<InterpolatedGeneralizedOffLatticeInfo3D*>(container.getData()); 00520 PLB_ASSERT( info ); 00521 return info->getLocalForce(); 00522 } 00523 00524 template<typename T, template<typename U> class Descriptor> 00525 void InterpolatedGeneralizedOffLatticeModel3D<T,Descriptor>::boundaryCompletion ( 00526 AtomicBlock3D& nonTypeLattice, 00527 AtomicContainerBlock3D& container, 00528 std::vector<AtomicBlock3D const*> const& args ) 00529 { 00530 BlockLattice3D<T,Descriptor>& lattice = 00531 dynamic_cast<BlockLattice3D<T,Descriptor>&> (nonTypeLattice); 00532 InterpolatedGeneralizedOffLatticeInfo3D* info = 00533 dynamic_cast<InterpolatedGeneralizedOffLatticeInfo3D*>(container.getData()); 00534 PLB_ASSERT( info ); 00535 std::vector<Dot3D> const& 00536 wetNodes = info->getWetNodes(); 00537 std::vector<std::vector<std::pair<int,int> > > const& 00538 wetNodeSolidDirections = info->getWetNodeSolidDirections(); 00539 std::vector<std::vector<int> > const& 00540 wetNodeFluidDirections = info->getWetNodeFluidDirections(); 00541 std::vector<std::vector<plint> > const& 00542 wetNodeIds = info->getWetNodeIds(); 00543 PLB_ASSERT( wetNodes.size() == wetNodeSolidDirections.size() ); 00544 00545 Dot3D absoluteOffset = lattice.getLocation(); 00546 00547 Array<T,3>& localForce = info->getLocalForce(); 00548 localForce.resetToZero(); 00549 for (pluint iWet=0; iWet<wetNodes.size(); ++iWet) { 00550 cellCompletion ( 00551 lattice, wetNodes[iWet], wetNodeSolidDirections[iWet], wetNodeFluidDirections[iWet], 00552 wetNodeIds[iWet], absoluteOffset, localForce ); 00553 } 00554 } 00555 00556 template<typename T, template<typename U> class Descriptor> 00557 void InterpolatedGeneralizedOffLatticeModel3D<T,Descriptor>::cellCompletion ( 00558 BlockLattice3D<T,Descriptor>& lattice, 00559 Dot3D const& genNode, 00560 std::vector<std::pair<int,int> > const& wetNodeSolidDirections, 00561 std::vector<int> const& wetNodeFluidDirections, 00562 std::vector<plint> const& wetNodeIds, Dot3D const& absoluteOffset, 00563 Array<T,3>& localForce ) 00564 { 00565 typedef Descriptor<T> D; 00566 using namespace indexTemplates; 00567 00568 Cell<T,Descriptor>& cell = 00569 lattice.get(genNode.x, genNode.y, genNode.z); 00570 plint numDirections = (plint)wetNodeSolidDirections.size(); 00571 std::vector<T> weights(numDirections); 00572 std::vector<Array<T,Descriptor<T>::d> > u_vect(numDirections); 00573 T sumWeights = T(); 00574 Array<T,3> wallNormal; 00575 for (plint iDirection=0; iDirection<numDirections; ++iDirection) { 00576 int iNeighbor = wetNodeSolidDirections[iDirection].first; 00577 int depth = wetNodeSolidDirections[iDirection].second; 00578 // pcout << "depth = " << depth << std::endl; 00579 int const* c = NextNeighbor<T>::c[iNeighbor]; 00580 00581 Dot3D solidDirection(c[0],c[1],c[2]); 00582 plint wetNodeId = wetNodeIds[iDirection]; 00583 00584 Array<T,3> wallNode, wall_vel; 00585 T wallDistance; 00586 OffBoundary::Type bdType; 00587 #ifdef PLB_DEBUG 00588 bool ok = 00589 #endif 00590 pointOnSurface( genNode+absoluteOffset, solidDirection, 00591 wallNode, wallDistance, wallNormal, 00592 wall_vel, bdType, wetNodeId ); 00593 PLB_ASSERT( ok ); 00594 for (int iD=0; iD<Descriptor<T>::d; ++iD) { 00595 // Use the formula uLB = uP - 1/2 g. If there is no external force, 00596 // the force term automatically evaluates to zero. 00597 wall_vel[iD] -= 0.5*getExternalForceComponent(cell,iD); 00598 } 00599 T invDistanceToNeighbor = NextNeighbor<T>::invD[iNeighbor]; 00600 PLB_ASSERT( wallDistance <= NextNeighbor<T>::d[iNeighbor] ); 00601 00602 Array<T,3> normalFluidDirection((T)solidDirection.x, (T)solidDirection.y, (T)solidDirection.z); 00603 normalFluidDirection *= invDistanceToNeighbor; 00604 weights[iDirection] = fabs ( dot(normalFluidDirection, wallNormal) ); 00605 sumWeights += weights[iDirection]; 00606 00607 computeVelocity ( 00608 lattice, genNode, solidDirection, depth, 00609 wallNode, wallDistance, NextNeighbor<T>::d[iNeighbor], wall_vel, bdType, wallNormal, 00610 u_vect[iDirection] ); 00611 } 00612 00613 Array<T,D::d> u; u.resetToZero(); 00614 for (plint iDirection=0; iDirection<numDirections; ++iDirection) { 00615 u += u_vect[iDirection] * weights[iDirection]; 00616 } 00617 u /= sumWeights; 00618 00619 // pcout << "vel = " << u[0] << ", " << u[1] << ", " << u[2] << std::endl; 00620 00621 Array<T,D::d> deltaJ; 00622 deltaJ.resetToZero(); 00623 for (plint iDirection=0; iDirection<numDirections; ++iDirection) { 00624 int iNeighbor = wetNodeSolidDirections[iDirection].first; 00625 int iPop = nextNeighborPop<T,Descriptor>(iNeighbor); 00626 if (iPop>=0) { 00627 deltaJ[0] += D::c[iPop][0]*cell[iPop]; 00628 deltaJ[1] += D::c[iPop][1]*cell[iPop]; 00629 deltaJ[2] += D::c[iPop][2]*cell[iPop]; 00630 } 00631 } 00632 00633 std::vector<plint> knownIndices; 00634 knownIndices.push_back(0); 00635 // pcout << "indexes = " << std::endl; 00636 for (pluint iDirection=0; iDirection<wetNodeFluidDirections.size(); ++iDirection) { 00637 int iPop = wetNodeFluidDirections[iDirection]; 00638 plint index = opposite<Descriptor<T> >(iPop); 00639 knownIndices.push_back(index); 00640 // pcout << index << std::endl; 00641 } 00642 PLB_ASSERT(knownIndices.size() >= 6); 00643 00644 std::vector<plint> missingIndices = remainingIndexes<Descriptor<T> >(knownIndices); 00645 00646 Dynamics<T,Descriptor> const& dynamics = cell.getDynamics(); 00647 DirichletVelocityBoundarySolver<T,Descriptor> bc(missingIndices, knownIndices, u); 00648 bc.apply(cell,dynamics,!this->getPartialReplace()); 00649 00650 Cell<T,Descriptor> cellCopy(cell); 00651 BlockStatistics statsCopy(lattice.getInternalStatistics()); 00652 cellCopy.collide(statsCopy); 00653 00654 for (plint iDirection=0; iDirection<numDirections; ++iDirection) { 00655 int iNeighbor = wetNodeSolidDirections[iDirection].first; 00656 plint iPop = nextNeighborPop<T,Descriptor>(iNeighbor); 00657 if (iPop>=0) { 00658 plint oppPop = indexTemplates::opposite<D>(iPop); 00659 deltaJ[0] -= D::c[oppPop][0]*cellCopy[oppPop]; 00660 deltaJ[1] -= D::c[oppPop][1]*cellCopy[oppPop]; 00661 deltaJ[2] -= D::c[oppPop][2]*cellCopy[oppPop]; 00662 } 00663 } 00664 localForce += deltaJ; 00665 } 00666 00667 template<typename T, template<typename U> class Descriptor> 00668 void InterpolatedGeneralizedOffLatticeModel3D<T,Descriptor>::computeVelocity ( 00669 BlockLattice3D<T,Descriptor> const& lattice, Dot3D const& genNode, 00670 Dot3D const& solidDirection, int depth, Array<T,3> const& wallNode, T wallDistance, T cellDistance, 00671 Array<T,3> const& wall_u, OffBoundary::Type bdType, Array<T,3> const& wallNormal, 00672 Array<T,Descriptor<T>::d>& u) const 00673 { 00674 bool neumann = bdType==OffBoundary::neumann; 00675 Array<T,Descriptor<T>::d> u1, u2; 00676 if (depth == 0) { 00677 u = wall_u; 00678 } 00679 else if (depth == 1) { 00680 Cell<T,Descriptor> const& cell1 = 00681 lattice.get( genNode.x-solidDirection.x, 00682 genNode.y-solidDirection.y, 00683 genNode.z-solidDirection.z ); 00684 00685 if (!this->velIsJ()) { 00686 cell1.getDynamics().computeVelocity(cell1, u1); 00687 } else { 00688 T rhoBar; 00689 cell1.getDynamics().computeRhoBarJ(cell1, rhoBar, u1); 00690 } 00691 00692 u = (wall_u * cellDistance + wallDistance * u1) / (wallDistance+cellDistance); 00693 } 00694 else if (depth >= 2) { // depth >= 2 00695 Cell<T,Descriptor> const& cell1 = 00696 lattice.get( genNode.x-solidDirection.x, 00697 genNode.y-solidDirection.y, 00698 genNode.z-solidDirection.z ); 00699 Cell<T,Descriptor> const& cell2 = 00700 lattice.get( genNode.x-2*solidDirection.x, 00701 genNode.y-2*solidDirection.y, 00702 genNode.z-2*solidDirection.z ); 00703 if (!this->velIsJ()) { 00704 cell1.getDynamics().computeVelocity(cell1, u1); 00705 cell2.getDynamics().computeVelocity(cell2, u2); 00706 } else { 00707 T rhoBar; 00708 cell1.getDynamics().computeRhoBarJ(cell1, rhoBar, u1); 00709 cell2.getDynamics().computeRhoBarJ(cell2, rhoBar, u2); 00710 } 00711 00712 T invDenom = (T)1 / (wallDistance*wallDistance+(T)2*cellDistance*cellDistance+(T)3*wallDistance*cellDistance); 00713 00714 u = wallDistance*(-wallDistance-cellDistance)*u2*invDenom 00715 + (T)2*wallDistance*(wallDistance+(T)2*cellDistance)*u1*invDenom 00716 + (T)2*cellDistance*cellDistance*wall_u*invDenom; 00717 } 00718 if ( bdType==OffBoundary::neumann ) 00719 { 00720 Cell<T,Descriptor> const& cell1 = 00721 lattice.get( genNode.x-solidDirection.x, 00722 genNode.y-solidDirection.y, 00723 genNode.z-solidDirection.z ); 00724 00725 cell1.getDynamics().computeVelocity(cell1, u1); 00726 00727 u = u1; 00728 } 00729 if ( bdType==OffBoundary::densityNeumann ) { 00730 Cell<T,Descriptor> const& cell1 = 00731 lattice.get( genNode.x-solidDirection.x, 00732 genNode.y-solidDirection.y, 00733 genNode.z-solidDirection.z ); 00734 00735 cell1.getDynamics().computeVelocity(cell1, u1); 00736 00737 u = dot(u1,wallNormal)*wallNormal; 00738 } 00739 if ( bdType==OffBoundary::freeSlip ) { 00740 Cell<T,Descriptor> const& cell1 = 00741 lattice.get( genNode.x-solidDirection.x, 00742 genNode.y-solidDirection.y, 00743 genNode.z-solidDirection.z ); 00744 00745 cell1.getDynamics().computeVelocity(cell1, u1); 00746 00747 u = u1-dot(u1,wallNormal)*wallNormal; 00748 } 00749 } 00750 00751 } // namespace plb 00752 00753 #endif // GUO_OFF_LATTICE_MODEL_3D_HH
1.6.3
1.6.3