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

generalizedOffLatticeModel3D.hh

Go to the documentation of this file.
00001 /* This file is part of the Palabos library.
00002  *
00003  * Copyright (C) 2011 FlowKit Sarl
00004  * Avenue de Chailly 23
00005  * 1012 Lausanne, Switzerland
00006  * E-mail contact: contact@flowkit.com
00007  *
00008  * The most recent release of Palabos can be downloaded at 
00009  * <http://www.palabos.org/>
00010  *
00011  * The library Palabos is free software: you can redistribute it and/or
00012  * modify it under the terms of the GNU Affero General Public License as
00013  * published by the Free Software Foundation, either version 3 of the
00014  * License, or (at your option) any later version.
00015  *
00016  * The library is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU Affero General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Affero General Public License
00022  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00023 */
00024 
00025 #ifndef 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