/* 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 2D boundaries -- header file. */ #ifndef OFF_BOUNDARY_INSTANTIATOR_2D_H #define OFF_BOUNDARY_INSTANTIATOR_2D_H #include "offBoundaryCondition2D.h" #include "offBoundaryPostProcessors2D.h" #include "geometry/blockGeometry2D.h" #include "geometry/blockGeometryStatistics2D.h" #include "dynamics/dynamics.h" #include "core/cell.h" #include "io/ostreamManager.h" #include "core/util.h" #include "io/stlReader.h" #include "functors/lattice/indicator/blockIndicatorF2D.h" namespace olb { /** * This class gets the needed processors from BoundaryManager and adds them * to the Processor Vector of the DESCRIPTOR */ template class OffBoundaryConditionInstantiator2D: public OffLatticeBoundaryCondition2D { public: OffBoundaryConditionInstantiator2D(BlockLatticeStructure2D& block_, T epsFraction_ = 0.0001); ~OffBoundaryConditionInstantiator2D() override; void addOnePointZeroVelocityBoundary(int x, int y, int iPop, T dist) override; void addTwoPointZeroVelocityBoundary(int x, int y, int iPop, T dist) override; void addOnePointVelocityBoundary(int x, int y, int iPop, T dist) override; void addTwoPointVelocityBoundary(int x, int y, int iPop, T dist) override; void addOffDynamics(int x, int y, T location[DESCRIPTOR::d]) override; void addOffDynamics(int x, int y, T location[DESCRIPTOR::d], T distances[DESCRIPTOR::q]) override; void addOffDynamics(BlockIndicatorF2D& indicator) override; void addZeroVelocityBoundary(BlockGeometryStructure2D& blockGeometryStructure, int x, int y, int iPop, T dist) override; void addZeroVelocityBoundary(BlockGeometryStructure2D& blockGeometryStructure, int x, int y, T distances[DESCRIPTOR::q]); void addZeroVelocityBoundary(BlockGeometryStructure2D& blockGeometryStructure, int iX, int iY, BlockIndicatorF2D& bulkIndicator, IndicatorF2D& geometryIndicator) override; void addZeroVelocityBoundary(BlockIndicatorF2D& boundaryIndicator, BlockIndicatorF2D& bulkIndicator, IndicatorF2D& geometryIndicator) override; void addZeroVelocityBoundary(BlockIndicatorF2D& boundaryIndicator, BlockIndicatorF2D& bulkIndicator) override; void addVelocityBoundary(BlockGeometryStructure2D& blockGeometryStructure, int x, int y, int iPop, T dist) override; void addVelocityBoundary(BlockGeometryStructure2D& blockGeometryStructure, int x, int y, T distances[DESCRIPTOR::q]); void addVelocityBoundary(BlockGeometryStructure2D& blockGeometryStructure, int iX, int iY, BlockIndicatorF2D& bulkIndicator, IndicatorF2D& geometryIndicator) override; void addVelocityBoundary(BlockIndicatorF2D& boundaryIndicator, BlockIndicatorF2D& bulkIndicator, IndicatorF2D& geometryIndicator) override; void addVelocityBoundary(BlockIndicatorF2D& boundaryIndicator, BlockIndicatorF2D& bulkIndicator) override; void addPressureBoundary(BlockIndicatorF2D& boundaryIndicator, BlockIndicatorF2D& bulkIndicator, IndicatorF2D& geometryIndicator) override; void addPressureBoundary(BlockIndicatorF2D& boundaryIndicator, BlockIndicatorF2D& bulkIndicator) override; void setBoundaryIntersection(int iX, int iY, int iPop, T distance); bool getBoundaryIntersection(int iX, int iY, int iPop, T point[DESCRIPTOR::d]); void defineU(int iX, int iY, int iPop, const T u[DESCRIPTOR::d]) override; void defineU(BlockIndicatorF2D& indicator, BlockIndicatorF2D& bulkIndicator, AnalyticalF2D& u) override; void defineRho(int iX, int iY, int iPop, const T rho) override; void defineRho(BlockIndicatorF2D& indicator, BlockIndicatorF2D& bulkIndicator, AnalyticalF2D& rho) override; void outputOn() override; void outputOff() override; BlockLatticeStructure2D& getBlock() override; BlockLatticeStructure2D const& getBlock() const override; private: BlockLatticeStructure2D& block; //std::vector*> momentaVector; std::vector*> dynamicsVector; bool _output; mutable OstreamManager clout; }; ///////// class OffBoundaryConditionInstantiator2D //////////////////////// template BlockLatticeStructure2D& OffBoundaryConditionInstantiator2D::getBlock() { return block; } template BlockLatticeStructure2D const& OffBoundaryConditionInstantiator2D::getBlock() const { return block; } template OffBoundaryConditionInstantiator2D::OffBoundaryConditionInstantiator2D( BlockLatticeStructure2D& block_, T epsFraction_) : block(block_), _output(false), clout(std::cout,"BoundaryConditionInstantiator2D") { this->_epsFraction = epsFraction_; } template OffBoundaryConditionInstantiator2D::~OffBoundaryConditionInstantiator2D() { for (unsigned iDynamics = 0; iDynamics < dynamicsVector.size(); ++iDynamics) { delete dynamicsVector[iDynamics]; } /* for (unsigned iMomenta = 0; iMomenta < dynamicsVector.size(); ++iMomenta) { delete momentaVector[iMomenta]; }*/ } template void OffBoundaryConditionInstantiator2D::addOnePointZeroVelocityBoundary( int x, int y, int iPop, T dist) { PostProcessorGenerator2D* postProcessor = BoundaryManager::getOnePointZeroVelocityBoundaryProcessor (x, y, iPop, dist); if (postProcessor) { this->getBlock().addPostProcessor(*postProcessor); } } template void OffBoundaryConditionInstantiator2D::addTwoPointZeroVelocityBoundary( int x, int y, int iPop, T dist) { PostProcessorGenerator2D* postProcessor = BoundaryManager::getTwoPointZeroVelocityBoundaryProcessor (x, y, iPop, dist); if (postProcessor) { this->getBlock().addPostProcessor(*postProcessor); } } template void OffBoundaryConditionInstantiator2D::addOnePointVelocityBoundary( int x, int y, int iPop, T dist) { PostProcessorGenerator2D* postProcessor = BoundaryManager::getOnePointVelocityBoundaryProcessor (x, y, iPop, dist); if (postProcessor) { this->getBlock().addPostProcessor(*postProcessor); } } template void OffBoundaryConditionInstantiator2D::addTwoPointVelocityBoundary( int x, int y, int iPop, T dist) { PostProcessorGenerator2D* postProcessor = BoundaryManager::getTwoPointVelocityBoundaryProcessor (x, y, iPop, dist); if (postProcessor) { this->getBlock().addPostProcessor(*postProcessor); } } template void OffBoundaryConditionInstantiator2D::addOffDynamics( int x, int y, T location[DESCRIPTOR::d]) { Dynamics* dynamics = BoundaryManager::getOffDynamics(location); this->getBlock().defineDynamics(x,x,y,y, dynamics); dynamicsVector.push_back(dynamics); } template void OffBoundaryConditionInstantiator2D::addOffDynamics( int x, int y, T location[DESCRIPTOR::d], T distances[DESCRIPTOR::q]) { Dynamics* dynamics = BoundaryManager::getOffDynamics(location, distances); this->getBlock().defineDynamics(x,x,y,y, dynamics); dynamicsVector.push_back(dynamics); } template void OffBoundaryConditionInstantiator2D::addOffDynamics( BlockIndicatorF2D& 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) { if (indicator(iX,iY)) { T location[DESCRIPTOR::d]; indicator.getBlockGeometryStructure().getPhysR(location, iX,iY); addOffDynamics(iX, iY, location); } } } } } template void OffBoundaryConditionInstantiator2D::addZeroVelocityBoundary( BlockGeometryStructure2D& blockGeometryStructure, int x, int y, int iPop, T dist) { if (blockGeometryStructure.getMaterial(x-descriptors::c(iPop,0), y-descriptors::c(iPop,1)) != 1) { addOnePointZeroVelocityBoundary(x, y, iPop, dist); } else { addTwoPointZeroVelocityBoundary(x, y, iPop, dist); } } template void OffBoundaryConditionInstantiator2D:: addZeroVelocityBoundary(BlockGeometryStructure2D& blockGeometryStructure, int x, int y, 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) ) { addZeroVelocityBoundary(blockGeometryStructure, x-descriptors::c(iPop,0), y-descriptors::c(iPop,1), iPop, distances[iPop]); } } } template void OffBoundaryConditionInstantiator2D::addZeroVelocityBoundary( BlockGeometryStructure2D& blockGeometryStructure, int iX, int iY, BlockIndicatorF2D& bulkIndicator, IndicatorF2D& geometryIndicator) { T distances[DESCRIPTOR::q]; for (int iPop = 1; iPop < DESCRIPTOR::q ; ++iPop) { distances[iPop] = -1; } for (int iPop = 1; iPop < DESCRIPTOR::q ; ++iPop) { const int iXn = iX + descriptors::c(iPop,0); const int iYn = iY + descriptors::c(iPop,1); if (bulkIndicator(iXn,iYn)) { T dist = -1; T physR[2]; blockGeometryStructure.getPhysR(physR,iXn,iYn); T voxelSize=blockGeometryStructure.getDeltaR(); Vector physC(physR); Vector direction(-voxelSize*descriptors::c(iPop,0),-voxelSize*descriptors::c(iPop,1)) ; T cPhysNorm = voxelSize*sqrt(descriptors::c(iPop,0)*descriptors::c(iPop,0)+descriptors::c(iPop,1)*descriptors::c(iPop,1)); if (!geometryIndicator.distance(dist,physC,direction,blockGeometryStructure.getIcGlob() ) ) { T epsX = voxelSize*descriptors::c(iPop,0)*this->_epsFraction; T epsY = voxelSize*descriptors::c(iPop,1)*this->_epsFraction; Vector physC2(physC); physC2[0] += epsX; physC2[1] += epsY; Vector direction2(direction); direction2[0] -= 2.*epsX; direction2[1] -= 2.*epsY; if ( !geometryIndicator.distance(dist,physC2,direction2,blockGeometryStructure.getIcGlob())) { clout << "ERROR: no boundary found at (" << iXn << "," << iYn <<") ~ (" << physR[0] << "," << physR[1] << "), " << "in direction " << util::opposite(iPop) << std::endl; } T distNew = (dist - sqrt(epsX*epsX+epsY*epsY) )/cPhysNorm; if (distNew < 0.5) { dist = 0; } else { dist = 0.5 * cPhysNorm; clout << "WARNING: distance at (" << iXn << "," << iYn << ") ~ (" << physR[0] << "," << physR[1] << "), " << "in direction " << util::opposite(iPop) << ": " << distNew << " rounded to " << dist/cPhysNorm << std::endl; } } distances[util::opposite(iPop)] = dist/cPhysNorm; } // bulk indicator if } // iPop loop addZeroVelocityBoundary(blockGeometryStructure, iX, iY, distances); } template void OffBoundaryConditionInstantiator2D::addZeroVelocityBoundary( BlockIndicatorF2D& boundaryIndicator, BlockIndicatorF2D& bulkIndicator, IndicatorF2D& 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) { if (boundaryIndicator(iX,iY)) { addZeroVelocityBoundary(bulkIndicator.getBlockGeometryStructure(), iX, iY, bulkIndicator, geometryIndicator); } } } } } template void OffBoundaryConditionInstantiator2D::addZeroVelocityBoundary( BlockIndicatorF2D& boundaryIndicator, BlockIndicatorF2D& bulkIndicator) { if ( boundaryIndicator.isEmpty() ) { return; } auto& blockGeometryStructure = boundaryIndicator.getBlockGeometryStructure(); 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) { if (boundaryIndicator(iX, iY)) { bool streamDirections[DESCRIPTOR::q]; // check if (ix,iY) is really a boundary node and compute the stream direction if (blockGeometryStructure.template findStreamDirections(iX, iY, boundaryIndicator, bulkIndicator, streamDirections) ) { T distances[DESCRIPTOR::q]; for (int iPop=0; iPop(iPop)] = .5; } else { distances[descriptors::opposite(iPop)] = -1; } } addZeroVelocityBoundary(blockGeometryStructure, iX, iY, distances); } } } } } template void OffBoundaryConditionInstantiator2D::addVelocityBoundary( BlockGeometryStructure2D& blockGeometryStructure, int x, int y, int iPop, T dist) { if (blockGeometryStructure.getMaterial(x-descriptors::c(iPop,0), y-descriptors::c(iPop,1)) != 1) { addOnePointVelocityBoundary(x, y, iPop, dist); } else { addTwoPointVelocityBoundary(x, y, iPop, dist); } } template void OffBoundaryConditionInstantiator2D:: addVelocityBoundary(BlockGeometryStructure2D& blockGeometryStructure, int x, int y, T distances[DESCRIPTOR::q]) { typedef DESCRIPTOR L; T location[DESCRIPTOR::d]; blockGeometryStructure.getPhysR(location, x,y); T distancesCopy[L::q]; T spacing = blockGeometryStructure.getDeltaR(); for (int iPop = 1; iPop < L::q ; ++iPop) { distancesCopy[iPop] = spacing*(1.-distances[iPop]); if ( !util::nearZero(distances[iPop]+1) ) { distancesCopy[iPop] = -1; } } addOffDynamics(x, y, location, distancesCopy); for (int iPop = 1; iPop < L::q ; ++iPop) { if ( !util::nearZero(distances[iPop]+1) ) { addVelocityBoundary(blockGeometryStructure, x-descriptors::c(iPop,0), y-descriptors::c(iPop,1), iPop, distances[iPop]); } } } template void OffBoundaryConditionInstantiator2D::addVelocityBoundary( BlockGeometryStructure2D& blockGeometryStructure, int iX, int iY, BlockIndicatorF2D& bulkIndicator, IndicatorF2D& geometryIndicator) { T distances[DESCRIPTOR::q]; for (int iPop = 1; iPop < DESCRIPTOR::q ; ++iPop) { distances[iPop] = -1; } for (int iPop = 1; iPop < DESCRIPTOR::q ; ++iPop) { const int iXn = iX + descriptors::c(iPop,0); const int iYn = iY + descriptors::c(iPop,1); if (bulkIndicator(iXn,iYn)) { T dist = -1; T physR[2]; blockGeometryStructure.getPhysR(physR,iXn,iYn); T voxelSize=blockGeometryStructure.getDeltaR(); Vector physC(physR); Vector direction(-voxelSize*descriptors::c(iPop,0),-voxelSize*descriptors::c(iPop,1)); T cPhysNorm = voxelSize*sqrt(descriptors::c(iPop,0)*descriptors::c(iPop,0)+descriptors::c(iPop,1)*descriptors::c(iPop,1)); if (!geometryIndicator.distance(dist,physC,direction,blockGeometryStructure.getIcGlob() ) ) { T epsX = voxelSize*descriptors::c(iPop,0)*this->_epsFraction; T epsY = voxelSize*descriptors::c(iPop,1)*this->_epsFraction; Vector physC2(physC); physC2[0] += epsX; physC2[1] += epsY; Vector direction2(direction); direction2[0] -= 2.*epsX; direction2[1] -= 2.*epsY; if ( !geometryIndicator.distance(dist,physC2,direction2,blockGeometryStructure.getIcGlob())) { clout << "ERROR: no boundary found at (" << iXn << "," << iYn <<") ~ (" << physR[0] << "," << physR[1] << "), " << "in direction " << util::opposite(iPop) << std::endl; } T distNew = (dist - sqrt(epsX*epsX+epsY*epsY))/cPhysNorm; if (distNew < 0.5) { dist = 0; } else { dist = 0.5 * cPhysNorm; clout << "WARNING: distance at (" << iXn << "," << iYn <<") ~ (" << physR[0] << "," << physR[1] <<"), " << "in direction " << util::opposite(iPop) << ": " << distNew << " rounded to " << dist/cPhysNorm << std::endl; } } distances[util::opposite(iPop)] = dist/cPhysNorm; } // bulk indicator } // iPop loop addVelocityBoundary(blockGeometryStructure, iX, iY, distances); } template void OffBoundaryConditionInstantiator2D::addVelocityBoundary( BlockIndicatorF2D& boundaryIndicator, BlockIndicatorF2D& bulkIndicator, IndicatorF2D& 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) { if (boundaryIndicator(iX, iY)) { addVelocityBoundary(bulkIndicator.getBlockGeometryStructure(), iX, iY, bulkIndicator, geometryIndicator); } } } } } template void OffBoundaryConditionInstantiator2D::addVelocityBoundary( BlockIndicatorF2D& boundaryIndicator, BlockIndicatorF2D& bulkIndicator) { if ( boundaryIndicator.isEmpty() ) { return; } auto& blockGeometryStructure = boundaryIndicator.getBlockGeometryStructure(); 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) { if (boundaryIndicator(iX,iY)) { bool streamDirections[DESCRIPTOR::q]; // check if (ix,iY) is really a boundary node and compute the stream direction if (blockGeometryStructure.template findStreamDirections(iX, iY, boundaryIndicator, bulkIndicator, streamDirections) ) { T distances[DESCRIPTOR::q]; for (int iPop=0; iPop(iPop)] = .5; } else { distances[descriptors::opposite(iPop)] = -1; } } addVelocityBoundary(blockGeometryStructure, iX, iY, distances); } } } } } template void OffBoundaryConditionInstantiator2D::addPressureBoundary( BlockIndicatorF2D& boundaryIndicator, BlockIndicatorF2D& bulkIndicator, IndicatorF2D& geometryIndicator) { auto& blockGeometryStructure = boundaryIndicator.getBlockGeometryStructure(); 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) { bool streamDirections[DESCRIPTOR::q]; // check if (ix,iY) is really a boundary node and compute the stream direction if (blockGeometryStructure.template findStreamDirections(iX, iY, boundaryIndicator, bulkIndicator, streamDirections) ) { T location[DESCRIPTOR::d]; blockGeometryStructure.getPhysR(location, iX, iX); block.defineDynamics(iX,iX,iY,iY,&instances::getBounceBackAnti(1.)); } } } } clout << "ERROR: OffBoundaryConditionInstantiator2D::addPressureBoundary NOT YET IMPLEMENTED" << std::endl; exit(-1); } template void OffBoundaryConditionInstantiator2D::addPressureBoundary( BlockIndicatorF2D& boundaryIndicator, BlockIndicatorF2D& bulkIndicator) { if ( boundaryIndicator.isEmpty() ) { return; } auto& blockGeometryStructure = boundaryIndicator.getBlockGeometryStructure(); 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) { bool streamDirections[DESCRIPTOR::q]; // check if (ix,iY) is really a boundary node and compute the stream direction if (blockGeometryStructure.template findStreamDirections(iX, iY, boundaryIndicator, bulkIndicator, streamDirections) ) { T location[DESCRIPTOR::d]; blockGeometryStructure.getPhysR(location, iX, iX); block.defineDynamics(iX,iX,iY,iY,&instances::getBounceBackAnti(1.)); for (int iPop = 1; iPop < DESCRIPTOR::q ; ++iPop) { if (streamDirections[iPop]) { PostProcessorGenerator2D* postProcessor = new AntiBounceBackPostProcessorGenerator2D(iX+descriptors::c(iPop,0), iY+descriptors::c(iPop,1), descriptors::opposite(iPop)); this->getBlock().addPostProcessor(*postProcessor); } } } } } } template void OffBoundaryConditionInstantiator2D:: setBoundaryIntersection(int iX, int iY, int iPop, T distance) { this->getBlock().getDynamics(iX, iY)->setBoundaryIntersection(iPop, distance); if (_output) { clout << "setBoundaryIntersection(" << iX << ", " << iY << " )" << std::endl; } } template bool OffBoundaryConditionInstantiator2D:: getBoundaryIntersection(int iX, int iY, int iPop, T point[DESCRIPTOR::d]) { return this->getBlock().getDynamics(iX, iY)->getBoundaryIntersection(iPop, point); } template void OffBoundaryConditionInstantiator2D:: defineU(int iX, int iY, int iPop, const T u[DESCRIPTOR::d]) { this->getBlock().getDynamics(iX, iY)->defineU(iPop, u); if (_output) { clout << "defineU(" << iX << ", " << iY << " )" << std::endl; } } template void OffBoundaryConditionInstantiator2D:: defineU(BlockIndicatorF2D& indicator, BlockIndicatorF2D& bulkIndicator, AnalyticalF2D& u) { if ( indicator.isEmpty() ) { return; } 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) { if (indicator(iX, iY)) { for (int iPop = 1; iPop < DESCRIPTOR::q ; ++iPop) { // Get direction int iXn = iX + descriptors::c(iPop,0); int iYn = iY + descriptors::c(iPop,1); if (bulkIndicator(iXn, iYn)) { T intersection[] = { T(), T() }; // coord. of intersection int opp = util::opposite(iPop); if (this->getBoundaryIntersection(iX, iY, opp, intersection) ) { T vel[]= {T(),T()}; u(vel,intersection); this->defineU(iX, iY, opp, vel); } } } } } } } template void OffBoundaryConditionInstantiator2D:: defineRho(int iX, int iY, int iPop, const T rho) { this->getBlock().getDynamics(iX, iY)->defineRho(iPop, rho); if (_output) { clout << "defineRho(" << iX << ", " << iY << " )" << std::endl; } } template void OffBoundaryConditionInstantiator2D:: defineRho(BlockIndicatorF2D& indicator, BlockIndicatorF2D& bulkIndicator, AnalyticalF2D& rho) { if ( indicator.isEmpty() ) { return; } 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) { if (indicator(iX, iY)) { for (int iPop = 1; iPop < DESCRIPTOR::q ; ++iPop) { // Get direction int iXn = iX + descriptors::c(iPop,0); int iYn = iY + descriptors::c(iPop,1); if (bulkIndicator(iXn, iYn)) { T intersection[] = { T(), T() }; // coord. of intersection int opp = util::opposite(iPop); if (this->getBoundaryIntersection(iX, iY, opp, intersection) ) { T rhoLocal[]= {T(1)}; rho(rhoLocal,intersection); this->defineRho(iX, iY, opp, rhoLocal[0]); } } } } } } } template void OffBoundaryConditionInstantiator2D::outputOn() { _output = true; } template void OffBoundaryConditionInstantiator2D::outputOff() { _output = false; } } #endif