/* Lattice Boltzmann sample, written in C++, using the OpenLB * library * * Copyright (C) 2019 Davide Dapelo * 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. */ /* Models for Lagrangian back-coupling methods -- generic implementation. */ #ifndef LB_BACK_COUPLING_MODELS_HH #define LB_BACK_COUPLING_MODELS_HH namespace olb { ////////////////////// Class BaseBackCouplingModel //////////////////////// template class Particle> BaseBackCouplingModel::BaseBackCouplingModel ( UnitConverter& converter, SuperLattice3D& sLattice, SuperGeometry3D& sGeometry ) : _converter(converter), _sGeometry(sGeometry), _sLattice(sLattice) { _zeroAnalytical = std::make_shared > (T()); _zeroField = std::make_shared > (*_zeroAnalytical, *_zeroAnalytical, *_zeroAnalytical); } template class Particle> void BaseBackCouplingModel::resetExternalField(int material) { // resets external field this->_sLattice.template defineField(this->_sGeometry, material, *_zeroField); // NECESSARY to communicate values before using them in operator() this->_sLattice.communicate(); } ////////////////////// Class CubicDeltaBackCouplingModel //////////////////////// template class Particle> CubicDeltaBackCouplingModel::CubicDeltaBackCouplingModel ( UnitConverter& converter, SuperLattice3D& sLattice, SuperGeometry3D& sGeometry ) : BaseBackCouplingModel(converter, sLattice, sGeometry) { _cubicDeltaFunctional = std::make_shared > ( this->_sLattice, this->_converter, this->_sGeometry ); } template class Particle> bool CubicDeltaBackCouplingModel::operator() (Particle* p, int globic, int material, int subCycles) { int locIC = this->_sLattice.getLoadBalancer().loc(globic); // reading the force from the value stored inside the particle std::vector physForceP = p->getStoreForce(); // physical force acting on the particle T latticeForceP[3] = {T(), T(), T()}; // dimensionless force acting on the particle latticeForceP[0] = physForceP[0] / this->_converter.getConversionFactorForce(); latticeForceP[1] = physForceP[1] / this->_converter.getConversionFactorForce(); latticeForceP[2] = physForceP[2] / this->_converter.getConversionFactorForce(); T physPosP[3] = {T(), T(), T()}; // particle's physical position physPosP[0] = (p->getPos()[0]); physPosP[1] = (p->getPos()[1]); physPosP[2] = (p->getPos()[2]); // particle's dimensionless position, rounded at neighbouring voxel int latticeRoundedPosP[3] = {0, 0, 0}; this->_sLattice.getCuboidGeometry().get(globic).getLatticeR ( latticeRoundedPosP, physPosP ); // smooth Dirac delta this->_cubicDeltaFunctional->operator() (_delta, physPosP, globic); T tempDelta = T(); T F[3] = {T(), T(), T()}; // dimensionless smoothed force for (int i = -_range; i <= _range; ++i) { for (int j = -_range; j <= _range; ++j) { for (int k = -_range; k <= _range; ++k) { if (this->_sGeometry.getBlockGeometry(locIC).getMaterial( latticeRoundedPosP[0] + i, latticeRoundedPosP[1] + j, latticeRoundedPosP[2] + k) == material) { tempDelta = _delta[i + _range][j + _range][k + _range]; F[0] = -latticeForceP[0] * tempDelta / (T)(subCycles); F[1] = -latticeForceP[1] * tempDelta / (T)(subCycles); F[2] = -latticeForceP[2] * tempDelta / (T)(subCycles); this->_sLattice.getBlockLattice(locIC).get ( latticeRoundedPosP[0] + i, latticeRoundedPosP[1] + j, latticeRoundedPosP[2] + k ).template addField( F ); } } } } return true; } ////////////////////// Class LocalDeltaBackCouplingModel //////////////////////// template class Particle> LocalBackCouplingModel::LocalBackCouplingModel ( UnitConverter& converter, SuperLattice3D& sLattice, SuperGeometry3D& sGeometry ) : BaseBackCouplingModel(converter, sLattice, sGeometry) {} template class Particle> bool LocalBackCouplingModel::operator() (Particle* p, int globic, int material, int subCycles) { int locIC = this->_sLattice.getLoadBalancer().loc(globic); // reading the force from the value stored inside the particle std::vector physForceP = p->getStoreForce(); // physical force acting on the particle T latticeForceP[3] = {T(), T(), T()}; // dimensionless force acting on the particle latticeForceP[0] = physForceP[0] / this->_converter.getConversionFactorForce(); latticeForceP[1] = physForceP[1] / this->_converter.getConversionFactorForce(); latticeForceP[2] = physForceP[2] / this->_converter.getConversionFactorForce(); T physPosP[3] = {T(), T(), T()}; // particle's physical position physPosP[0] = (p->getPos()[0]); physPosP[1] = (p->getPos()[1]); physPosP[2] = (p->getPos()[2]); // particle's dimensionless position, rounded at neighbouring voxel int latticeRoundedPosP[3] = {0, 0, 0}; this->_sLattice.getCuboidGeometry().get(globic).getLatticeR ( latticeRoundedPosP, physPosP ); if (this->_sGeometry.getBlockGeometry(locIC).getMaterial( latticeRoundedPosP[0], latticeRoundedPosP[1], latticeRoundedPosP[2]) == material) { T F[3] = {T(), T(), T()}; // dimensionless smoothed force F[0] = -latticeForceP[0] / (T)(subCycles); F[1] = -latticeForceP[1] / (T)(subCycles); F[2] = -latticeForceP[2] / (T)(subCycles); this->_sLattice.getBlockLattice(locIC).get ( latticeRoundedPosP[0], latticeRoundedPosP[1], latticeRoundedPosP[2] ).template addField( F ); } return true; } ////////////////////// Class NonLocalBaseBackCouplingModel //////////////////////// template class Particle> NonLocalBaseBackCouplingModel::NonLocalBaseBackCouplingModel ( UnitConverter& converter, SuperLattice3D& sLattice, SuperGeometry3D& sGeometry, SmoothingFunctional& smoothingFunctional ) : BaseBackCouplingModel(converter, sLattice, sGeometry), _smoothingFunctional(smoothingFunctional) {} template class Particle> bool NonLocalBaseBackCouplingModel::operator() (Particle* p, int globic, int material, int subCycles) { int locIC = this->_sLattice.getLoadBalancer().loc(globic); // reading the force from the value stored inside the particle std::vector physForceP = p->getStoreForce(); // physical force acting on the particle T latticeForceP[3] = {T(), T(), T()}; // dimensionless force acting on the particle latticeForceP[0] = physForceP[0] / this->_converter.getConversionFactorForce(); latticeForceP[1] = physForceP[1] / this->_converter.getConversionFactorForce(); latticeForceP[2] = physForceP[2] / this->_converter.getConversionFactorForce(); // Updating force through voxels within kernel smoothing length from the bubble's position for (int i=0; i_smoothingFunctional.getSize(); i++) { // Position of the iterated voxel int iLatticePosF[3] = {0, 0, 0}; this->_smoothingFunctional.getLatticePos(iLatticePosF, i); // Updating iterated voxel if (this->_sGeometry.getBlockGeometry(locIC).getMaterial( iLatticePosF[0], iLatticePosF[1], iLatticePosF[2]) == material) { // Weighted force acting on the iterated voxel T F[3] = {T(), T(), T()}; // dimensionless smoothed force F[0] = -latticeForceP[0] * this->_smoothingFunctional.getWeight(i) / (T)(subCycles); F[1] = -latticeForceP[1] * this->_smoothingFunctional.getWeight(i) / (T)(subCycles); F[2] = -latticeForceP[2] * this->_smoothingFunctional.getWeight(i) / (T)(subCycles); this->_sLattice.getBlockLattice(locIC).get ( iLatticePosF[0], iLatticePosF[1], iLatticePosF[2] ).template addField( F ); } } return true; } } #endif