/* This file is part of the OpenLB library * * Copyright (C) 2012 Jonas Kratzke, Mathias J. Krause * E-mail contact: info@openlb.net * The most recent release of OpenLB can be downloaded at * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /** \file * A helper for initialising 3D boundaries -- header file. */ #ifndef OFF_BOUNDARY_INSTANTIATOR_3D_H #define OFF_BOUNDARY_INSTANTIATOR_3D_H #include "offBoundaryCondition3D.h" #include "geometry/blockGeometry3D.h" #include "geometry/blockGeometryStatistics3D.h" #include "core/cell.h" #include "io/ostreamManager.h" #include "core/util.h" #include "io/stlReader.h" #include "functors/lattice/indicator/blockIndicatorF3D.h" namespace olb { /** * This class gets the needed processors from BoundaryManager and adds them * to the Processor Vector of the DESCRIPTOR */ template class OffBoundaryConditionInstantiator3D: public OffLatticeBoundaryCondition3D { public: OffBoundaryConditionInstantiator3D(BlockLatticeStructure3D& block_, T epsFraction_ = 0.0001); ~OffBoundaryConditionInstantiator3D() override; void addOnePointZeroVelocityBoundary(int x, int y, int z, int iPop, T dist) override; void addTwoPointZeroVelocityBoundary(int x, int y, int z, int iPop, T dist) override; void addOnePointVelocityBoundary(int x, int y, int z, int iPop, T dist) override; void addTwoPointVelocityBoundary(int x, int y, int z, int iPop, T dist) override; void addOffDynamics(int x, int y, int z, T location[DESCRIPTOR::d]) override; void addOffDynamics(int x, int y, int z, T location[DESCRIPTOR::d], T distances[DESCRIPTOR::q]) override; void addOffDynamics(BlockIndicatorF3D& indicator) override; void addZeroVelocityBoundary(BlockGeometryStructure3D& blockGeometryStructure, int x, int y, int z, int iPop, T dist) override; void addZeroVelocityBoundary(BlockGeometryStructure3D& blockGeometryStructure, int x, int y, int z, T distances[DESCRIPTOR::q]); void addZeroVelocityBoundary(BlockGeometryStructure3D& blockGeometryStructure, int iX, int iY, int iZ, IndicatorF3D& geometryIndicator, BlockIndicatorF3D& bulkIndicator); void addZeroVelocityBoundary(BlockGeometryStructure3D& blockGeometryStructure, int iX, int iY, int iZ, IndicatorF3D& geometryIndicator, std::vector bulkMaterials = std::vector(1,1)); void addZeroVelocityBoundary(BlockIndicatorF3D& boundaryIndicator, BlockIndicatorF3D& bulkIndicator, IndicatorF3D& geometryIndicator) override; void addVelocityBoundary(BlockGeometryStructure3D& blockGeometryStructure, int x, int y, int z, int iPop, T dist); void addVelocityBoundary(BlockGeometryStructure3D& blockGeometryStructure, int x, int y, int z, T distances[DESCRIPTOR::q]); void addVelocityBoundary(BlockGeometryStructure3D& blockGeometryStructure, int iX, int iY, int iZ, IndicatorF3D& geometryIndicator, BlockIndicatorF3D& bulkIndicator); void addVelocityBoundary(BlockGeometryStructure3D& blockGeometryStructure, int iX, int iY, int iZ, IndicatorF3D& geometryIndicator, std::vector bulkMaterials = std::vector(1,1)); void addVelocityBoundary(BlockIndicatorF3D& boundaryIndicator, BlockIndicatorF3D& bulkIndicator, IndicatorF3D& geometryIndicator) override; void setBoundaryIntersection(int iX, int iY, int iZ, int iPop, T distance); bool getBoundaryIntersection(int iX, int iY, int iZ, int iPop, T point[DESCRIPTOR::d]); void defineU(int iX, int iY, int iZ, int iPop, const T u[DESCRIPTOR::d]) override; void defineU(BlockIndicatorF3D& indicator, BlockIndicatorF3D& bulkIndicator, AnalyticalF3D& u) override; void outputOn() override; void outputOff() override; BlockLatticeStructure3D& getBlock() override; BlockLatticeStructure3D const& getBlock() const override; private: BlockLatticeStructure3D& block; //std::vector*> momentaVector; std::vector*> dynamicsVector; bool _output; mutable OstreamManager clout; }; ///////// class OffBoundaryConditionInstantiator3D //////////////////////// template BlockLatticeStructure3D& OffBoundaryConditionInstantiator3D::getBlock() { return block; } template BlockLatticeStructure3D const& OffBoundaryConditionInstantiator3D::getBlock() const { return block; } template OffBoundaryConditionInstantiator3D::OffBoundaryConditionInstantiator3D( BlockLatticeStructure3D& block_, T epsFraction_) : block(block_), _output(false), clout(std::cout,"BoundaryConditionInstantiator3D") { this->_epsFraction = epsFraction_; } template OffBoundaryConditionInstantiator3D::~OffBoundaryConditionInstantiator3D() { for (unsigned iDynamics = 0; iDynamics < dynamicsVector.size(); ++iDynamics) { delete dynamicsVector[iDynamics]; } /* for (unsigned iMomenta = 0; iMomenta < dynamicsVector.size(); ++iMomenta) { delete momentaVector[iMomenta]; }*/ } template void OffBoundaryConditionInstantiator3D::addOnePointZeroVelocityBoundary( int x, int y, int z, int iPop, T dist) { PostProcessorGenerator3D* postProcessor = BoundaryManager::getOnePointZeroVelocityBoundaryProcessor (x, y, z, iPop, dist); if (postProcessor) { this->getBlock().addPostProcessor(*postProcessor); } } template void OffBoundaryConditionInstantiator3D::addTwoPointZeroVelocityBoundary( int x, int y, int z, int iPop, T dist) { PostProcessorGenerator3D* postProcessor = BoundaryManager::getTwoPointZeroVelocityBoundaryProcessor (x, y, z, iPop, dist); if (postProcessor) { this->getBlock().addPostProcessor(*postProcessor); } } template void OffBoundaryConditionInstantiator3D::addOnePointVelocityBoundary( int x, int y, int z, int iPop, T dist) { PostProcessorGenerator3D* postProcessor = BoundaryManager::getOnePointVelocityBoundaryProcessor (x, y, z, iPop, dist); if (postProcessor) { this->getBlock().addPostProcessor(*postProcessor); } } template void OffBoundaryConditionInstantiator3D::addTwoPointVelocityBoundary( int x, int y, int z, int iPop, T dist) { PostProcessorGenerator3D* postProcessor = BoundaryManager::getTwoPointVelocityBoundaryProcessor (x, y, z, iPop, dist); if (postProcessor) { this->getBlock().addPostProcessor(*postProcessor); } } template void OffBoundaryConditionInstantiator3D::addOffDynamics( int x, int y, int z, T location[DESCRIPTOR::d]) { Dynamics* dynamics = BoundaryManager::getOffDynamics(location); this->getBlock().defineDynamics(x,x,y,y,z,z, dynamics); dynamicsVector.push_back(dynamics); } template void OffBoundaryConditionInstantiator3D::addOffDynamics( int x, int y, int z, T location[DESCRIPTOR::d], T distances[DESCRIPTOR::q]) { Dynamics* dynamics = BoundaryManager::getOffDynamics(location, distances); this->getBlock().defineDynamics(x,x,y,y,z,z, dynamics); dynamicsVector.push_back(dynamics); } template void OffBoundaryConditionInstantiator3D::addOffDynamics( BlockIndicatorF3D& indicator) { if ( !indicator.isEmpty() ) { const Vector min = indicator.getMin(); const Vector max = indicator.getMax(); for (int iX = min[0]; iX <= max[0]; ++iX) { for (int iY = min[1]; iY <= max[1]; ++iY) { for (int iZ = min[2]; iZ <= max[2]; ++iZ) { if (indicator(iX,iY,iZ)) { T location[DESCRIPTOR::d]; indicator.getBlockGeometryStructure().getPhysR(location, iX,iY,iZ); addOffDynamics(iX, iY, iZ, location); } } } } } } template void OffBoundaryConditionInstantiator3D::addZeroVelocityBoundary( BlockGeometryStructure3D& blockGeometryStructure, int x, int y, int z, int iPop, T dist) { const Vector c = descriptors::c(iPop); if (blockGeometryStructure.getMaterial(x-c[0], y-c[1], z-c[2]) != 1) { addOnePointZeroVelocityBoundary(x, y, z, iPop, dist); } else { addTwoPointZeroVelocityBoundary(x, y, z, iPop, dist); } } template void OffBoundaryConditionInstantiator3D:: addZeroVelocityBoundary(BlockGeometryStructure3D& blockGeometryStructure, int x, int y, int z, T distances[DESCRIPTOR::q]) { typedef DESCRIPTOR L; //T location[DESCRIPTOR::d]; //location[0] = blockGeometryStructure.physCoordX(x); //location[1] = blockGeometryStructure.physCoordY(y); //location[2] = blockGeometryStructure.physCoordZ(z); //T distancesCopy[L::q]; //T spacing = blockGeometryStructure.getDeltaR(); //for (int iPop = 1; iPop < L::q ; ++iPop) { // distancesCopy[iPop] = spacing*(1.-distances[iPop]); // if (distances[iPop] == -1) // distancesCopy[iPop] = -1; //} //addOffDynamics(x, y, z, location, distancesCopy); for (int iPop = 1; iPop < L::q ; ++iPop) { if ( !util::nearZero(distances[iPop]+1) ) { const Vector c = descriptors::c(iPop); addZeroVelocityBoundary(blockGeometryStructure, x-c[0], y-c[1], z-c[2], iPop, distances[iPop]); } } } template void OffBoundaryConditionInstantiator3D::addZeroVelocityBoundary( BlockGeometryStructure3D& blockGeometryStructure, int iX, int iY, int iZ, IndicatorF3D& geometryIndicator, BlockIndicatorF3D& bulkIndicator) { T distances[DESCRIPTOR::q]; for (int iPop = 1; iPop < DESCRIPTOR::q ; ++iPop) { distances[iPop] = -1; } for (int iPop = 1; iPop < DESCRIPTOR::q ; ++iPop) { const Vector c = descriptors::c(iPop); const int iXn = iX + c[0]; const int iYn = iY + c[1]; const int iZn = iZ + c[2]; if (blockGeometryStructure.isInside(iXn,iYn,iZn) && bulkIndicator(iXn,iYn,iZn)) { T dist = -1; T physR[3]; blockGeometryStructure.getPhysR(physR,iXn,iYn,iZn); T voxelSize=blockGeometryStructure.getDeltaR(); Vector physC(physR); Vector direction(-voxelSize*c[0],-voxelSize*c[1],-voxelSize*c[2]); T cPhysNorm = voxelSize*sqrt(c[0]*c[0]+c[1]*c[1]+c[2]*c[2]); if (!geometryIndicator.distance(dist,physC,direction,blockGeometryStructure.getIcGlob() ) ) { T epsX = voxelSize*c[0]*this->_epsFraction; T epsY = voxelSize*c[1]*this->_epsFraction; T epsZ = voxelSize*c[2]*this->_epsFraction; Vector physC2(physC); physC2[0] += epsX; physC2[1] += epsY; physC2[2] += epsZ; Vector direction2(direction); direction2[0] -= 2.*epsX; direction2[1] -= 2.*epsY; direction2[2] -= 2.*epsZ; if ( !geometryIndicator.distance(dist,physC2,direction2,blockGeometryStructure.getIcGlob())) { clout << "ERROR: no boundary found at (" << iXn << "," << iYn << "," << iZn <<") ~ (" << physR[0] << "," << physR[1] << "," << physR[2] <<"), " << "in direction " << util::opposite(iPop) << std::endl; } T distNew = (dist - sqrt(epsX*epsX+epsY*epsY+epsZ*epsZ))/cPhysNorm; if (distNew < 0.5) { dist = 0; } else { dist = 0.5 * cPhysNorm; clout << "WARNING: distance at (" << iXn << "," << iYn << "," << iZn <<") ~ (" << physR[0] << "," << physR[1] << "," << physR[2] <<"), " << "in direction " << util::opposite(iPop) << ": " << distNew << " rounded to " << dist/cPhysNorm << std::endl; } } distances[util::opposite(iPop)] = dist/cPhysNorm; } // bulkMaterials if } // iPop loop addZeroVelocityBoundary(blockGeometryStructure, iX, iY, iZ, distances); } template void OffBoundaryConditionInstantiator3D::addZeroVelocityBoundary( BlockGeometryStructure3D& blockGeometryStructure, int iX, int iY, int iZ, IndicatorF3D& geometryIndicator, std::vector bulkMaterials) { BlockIndicatorMaterial3D bulkIndicator(blockGeometryStructure, bulkMaterials); addZeroVelocityBoundary(blockGeometryStructure, iX, iY, iZ, geometryIndicator, bulkIndicator); } template void OffBoundaryConditionInstantiator3D::addZeroVelocityBoundary( BlockIndicatorF3D& boundaryIndicator, BlockIndicatorF3D& bulkIndicator, IndicatorF3D& geometryIndicator) { if ( !boundaryIndicator.isEmpty() ) { const Vector min = boundaryIndicator.getMin(); const Vector max = boundaryIndicator.getMax(); for (int iX = min[0]; iX <= max[0]; ++iX) { for (int iY = min[1]; iY <= max[1]; ++iY) { for (int iZ = min[2]; iZ <= max[2]; ++iZ) { if (boundaryIndicator(iX,iY,iZ)) { addZeroVelocityBoundary(boundaryIndicator.getBlockGeometryStructure(), iX, iY, iZ, geometryIndicator, bulkIndicator); } } } } } } template void OffBoundaryConditionInstantiator3D::addVelocityBoundary( BlockGeometryStructure3D& blockGeometryStructure, int x, int y, int z, int iPop, T dist) { const Vector c = descriptors::c(iPop); if (blockGeometryStructure.getMaterial(x-c[0], y-c[1], z-c[2]) != 1) { addOnePointVelocityBoundary(x, y, z, iPop, dist); } else { addTwoPointVelocityBoundary(x, y, z, iPop, dist); } } template void OffBoundaryConditionInstantiator3D:: addVelocityBoundary(BlockGeometryStructure3D& blockGeometryStructure, int x, int y, int z, T distances[DESCRIPTOR::q]) { T location[DESCRIPTOR::d]; blockGeometryStructure.getPhysR(location, x,y,z); T distancesCopy[DESCRIPTOR::q]; T spacing = blockGeometryStructure.getDeltaR(); for (int iPop = 1; iPop < DESCRIPTOR::q ; ++iPop) { distancesCopy[iPop] = spacing*(1.-distances[iPop]); if ( util::nearZero(distances[iPop]+1) ) { distancesCopy[iPop] = -1; } } addOffDynamics(x, y, z, location, distancesCopy); for (int iPop = 1; iPop < DESCRIPTOR::q ; ++iPop) { if (!util::nearZero(distances[iPop]+1)) { const Vector c = descriptors::c(iPop); addVelocityBoundary(blockGeometryStructure, x-c[0], y-c[1], z-c[2], iPop, distances[iPop]); } } } template void OffBoundaryConditionInstantiator3D::addVelocityBoundary( BlockGeometryStructure3D& blockGeometryStructure, int iX, int iY, int iZ, IndicatorF3D& geometryIndicator, BlockIndicatorF3D& bulkIndicator) { T distances[DESCRIPTOR::q]; for (int iPop = 1; iPop < DESCRIPTOR::q ; ++iPop) { distances[iPop] = -1; } for (int iPop = 1; iPop < DESCRIPTOR::q ; ++iPop) { const Vector c = descriptors::c(iPop); const int iXn = iX + c[0]; const int iYn = iY + c[1]; const int iZn = iZ + c[2]; if (blockGeometryStructure.isInside(iXn,iYn,iZn) && bulkIndicator(iXn,iYn,iZn)) { T dist = -1; T physR[3]; blockGeometryStructure.getPhysR(physR,iXn,iYn,iZn); T voxelSize=blockGeometryStructure.getDeltaR(); Vector physC(physR); Vector direction(-voxelSize*c[0],-voxelSize*c[1],-voxelSize*c[2]); T cPhysNorm = voxelSize*sqrt(c[0]*c[0]+c[1]*c[1]+c[2]*c[2]); if (!geometryIndicator.distance(dist,physC,direction,blockGeometryStructure.getIcGlob() ) ) { T epsX = voxelSize*c[0]*this->_epsFraction; T epsY = voxelSize*c[1]*this->_epsFraction; T epsZ = voxelSize*c[2]*this->_epsFraction; Vector physC2(physC); physC2[0] += epsX; physC2[1] += epsY; physC2[2] += epsZ; Vector direction2(direction); direction2[0] -= 2.*epsX; direction2[1] -= 2.*epsY; direction2[2] -= 2.*epsZ; if ( !geometryIndicator.distance(dist,physC2,direction2,blockGeometryStructure.getIcGlob())) { clout << "ERROR: no boundary found at (" << iXn << "," << iYn << "," << iZn <<") ~ (" << physR[0] << "," << physR[1] << "," << physR[2] <<"), " << "in direction " << util::opposite(iPop) << std::endl; } T distNew = (dist - sqrt(epsX*epsX+epsY*epsY+epsZ*epsZ))/cPhysNorm; if (distNew < 0.5) { dist = 0; } else { dist = 0.5 * cPhysNorm; clout << "WARNING: distance at (" << iXn << "," << iYn << "," << iZn <<") ~ (" << physR[0] << "," << physR[1] << "," << physR[2] <<"), " << "in direction " << util::opposite(iPop) << ": " << distNew << " rounded to " << dist/cPhysNorm << std::endl; } } distances[util::opposite(iPop)] = dist/cPhysNorm; } // bulk indicator if } // iPop loop addVelocityBoundary(blockGeometryStructure, iX, iY, iZ, distances); } template void OffBoundaryConditionInstantiator3D::addVelocityBoundary( BlockGeometryStructure3D& blockGeometryStructure, int iX, int iY, int iZ, IndicatorF3D& geometryIndicator, std::vector bulkMaterials) { BlockIndicatorMaterial3D bulkIndicator(blockGeometryStructure, bulkMaterials); addVelocityBoundary(blockGeometryStructure, iX, iY, iZ, geometryIndicator, bulkIndicator); } template void OffBoundaryConditionInstantiator3D::addVelocityBoundary( BlockIndicatorF3D& boundaryIndicator, BlockIndicatorF3D& bulkIndicator, IndicatorF3D& geometryIndicator) { if ( !boundaryIndicator.isEmpty() ) { const Vector min = boundaryIndicator.getMin(); const Vector max = boundaryIndicator.getMax(); for (int iX = min[0]; iX <= max[0]; ++iX) { for (int iY = min[1]; iY <= max[1]; ++iY) { for (int iZ = min[2]; iZ <= max[2]; ++iZ) { if (boundaryIndicator(iX,iY,iZ)) { addVelocityBoundary(bulkIndicator.getBlockGeometryStructure(), iX, iY, iZ, geometryIndicator, bulkIndicator); } } } } } } template void OffBoundaryConditionInstantiator3D:: setBoundaryIntersection(int iX, int iY, int iZ, int iPop, T distance) { this->getBlock().getDynamics(iX, iY, iZ)->setBoundaryIntersection(iPop, distance); if (_output) { clout << "setBoundaryIntersection(" << iX << ", " << iY << ", " << iZ << " )" << std::endl; } } template bool OffBoundaryConditionInstantiator3D:: getBoundaryIntersection(int iX, int iY, int iZ, int iPop, T point[DESCRIPTOR::d]) { return this->getBlock().getDynamics(iX, iY, iZ)->getBoundaryIntersection(iPop, point); } template void OffBoundaryConditionInstantiator3D:: defineU(int iX, int iY, int iZ, int iPop, const T u[DESCRIPTOR::d]) { this->getBlock().getDynamics(iX, iY, iZ)->defineU(iPop, u); if (_output) { clout << "defineU(" << iX << ", " << iY << ", " << iZ << " )" << std::endl; } } template void OffBoundaryConditionInstantiator3D::defineU( BlockIndicatorF3D& indicator, BlockIndicatorF3D& bulkIndicator, AnalyticalF3D& u) { if ( !indicator.isEmpty() ) { const Vector min = indicator.getMin(); const Vector max = indicator.getMax(); for (int iX = min[0]; iX <= max[0]; ++iX) { for (int iY = min[1]; iY <= max[1]; ++iY) { for (int iZ = min[2]; iZ <= max[2]; ++iZ) { if (indicator(iX, iY, iZ)) { for (int q = 1; q < DESCRIPTOR::q ; ++q) { // Get direction const int iXn = iX + descriptors::c(q,0); const int iYn = iY + descriptors::c(q,1); const int iZn = iZ + descriptors::c(q,2); if (bulkIndicator.getBlockGeometryStructure().isInside(iXn,iYn,iZn) && bulkIndicator(iXn,iYn,iZn)) { T intersection[3] = { }; const int opp = util::opposite(q); if (this->getBoundaryIntersection(iX, iY, iZ, opp, intersection)) { T vel[3]= { }; u(vel, intersection); this->defineU(iX, iY, iZ, opp, vel); } } } } } } } } } template void OffBoundaryConditionInstantiator3D::outputOn() { _output = true; } template void OffBoundaryConditionInstantiator3D::outputOff() { _output = false; } } #endif