/* 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 forward-coupling methods -- generic implementation. */ #ifndef LB_FORWARD_COUPLING_MODELS_HH #define LB_FORWARD_COUPLING_MODELS_HH namespace olb { ////////////////////// Class LocalBaseCouplingModel //////////////////////// template class Particle> LocalBaseForwardCouplingModel::LocalBaseForwardCouplingModel ( UnitConverter& converter, SuperLattice3D& sLattice, SuperGeometry3D& sGeometry, DragModel& dragModel ) : _sGeometry(sGeometry), _converter(converter), _sLattice(sLattice), _dragModel(dragModel) { this->_interpLatticeDensity = std::make_shared > ( this->_sLattice, _sGeometry, this->_converter ); this->_interpLatticeVelocity = std::make_shared > ( this->_sLattice, this->_converter ); } template class Particle> bool LocalBaseForwardCouplingModel::operator() (Particle* p, int globic) { /// Getting the particle and its containing cell's position 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 ); // { globic, latticeRoundedP[0, ..., 2] } int globicFull[4] = { globic, latticeRoundedPosP[0], latticeRoundedPosP[1], latticeRoundedPosP[2] }; // Particle's velocity T physVelP[3] = {T(), T(), T()}; // Physical physVelP[0] = (p->getVel()[0]); physVelP[1] = (p->getVel()[1]); physVelP[2] = (p->getVel()[2]); // Lattice T latticeVelP[3] = {T(), T(), T()}; // particle's dimensionless velocity latticeVelP[0] = this->_converter.getLatticeVelocity(physVelP[0]); latticeVelP[1] = this->_converter.getLatticeVelocity(physVelP[1]); latticeVelP[2] = this->_converter.getLatticeVelocity(physVelP[2]); // Lattice's velocity at particle's location T physVelF[3] = {T(), T(), T()}; // Physical this->_interpLatticeVelocity->operator() (physVelF, physPosP, globic); // Lattice T latticeVelF[3] = {T(), T(), T()}; // Lattice's dimensionless velocity at particle's location latticeVelF[0] = this->_converter.getLatticeVelocity(physVelF[0]); latticeVelF[1] = this->_converter.getLatticeVelocity(physVelF[1]); latticeVelF[2] = this->_converter.getLatticeVelocity(physVelF[2]); // Computing fluid-particle momentum transfer T gF[3] = {T(), T(), T()}; // force density gF this->_momentumExchange->operator() ( gF, latticeVelF, latticeVelP, physPosP, latticeRoundedPosP, globic); // Computing drag coefficient T Cd = this->_dragModel(p, latticeVelF, latticeVelP, globicFull); /// Computing drag force in dimensionless units T latticePRad = p->getRad() / _converter.getConversionFactorLength(); T latticeForceP[3] = {T(), T(), T()}; // dimensionless force acting on the particle latticeForceP[0] = .5 * Cd * M_PI*pow(latticePRad,2) * gF[0] * (latticeVelF[0] - latticeVelP[0]); latticeForceP[1] = .5 * Cd * M_PI*pow(latticePRad,2) * gF[1] * (latticeVelF[1] - latticeVelP[1]); latticeForceP[2] = .5 * Cd * M_PI*pow(latticePRad,2) * gF[2] * (latticeVelF[2] - latticeVelP[2]); /// Computing physical drag force std::vector physForceP(3, T()); // physical force acting on the particle physForceP[0] = latticeForceP[0] * this->_converter.getConversionFactorForce(); physForceP[1] = latticeForceP[1] * this->_converter.getConversionFactorForce(); physForceP[2] = latticeForceP[2] * this->_converter.getConversionFactorForce(); /// Updating the particle p->setStoreForce(physForceP); return true; } ////////////////////// Class NaiveForwardCouplingModel //////////////////////// template class Particle> NaiveForwardCouplingModel::NaiveForwardCouplingModel ( UnitConverter& converter, SuperLattice3D& sLattice, SuperGeometry3D& sGeometry, DragModel& dragModel ) : LocalBaseForwardCouplingModel(converter, sLattice, sGeometry, dragModel) { this->_momentumExchange = std::make_shared > ( this->_converter, this->_sLattice, this->_interpLatticeDensity ); } ////////////////////// Class LaddForwardCouplingModel //////////////////////// template class Particle> LaddForwardCouplingModel::LaddForwardCouplingModel ( UnitConverter& converter, SuperLattice3D& sLattice, SuperGeometry3D& sGeometry, DragModel& dragModel ) : LocalBaseForwardCouplingModel(converter, sLattice, sGeometry, dragModel) { this->_momentumExchange = std::make_shared > ( this->_converter, this->_sLattice, this->_interpLatticeDensity, this->_interpLatticeVelocity ); } ////////////////////// Class NonLocalBaseCouplingModel //////////////////////// template class Particle> NonLocalBaseForwardCouplingModel::NonLocalBaseForwardCouplingModel ( UnitConverter& converter, SuperLattice3D& sLattice, SuperGeometry3D& sGeometry, DragModel& dragModel, SmoothingFunctional& smoothingFunctional ) : _sGeometry(sGeometry), _converter(converter), _sLattice(sLattice), _dragModel(dragModel), _smoothingFunctional(smoothingFunctional) { this->_interpLatticeDensity = std::make_shared > ( this->_sLattice, _sGeometry, this->_converter ); this->_interpLatticeVelocity = std::make_shared > ( this->_sLattice, this->_converter ); } template class Particle> bool NonLocalBaseForwardCouplingModel::operator() (Particle* p, int globic) { /// Getting the particle and its containing cell's position 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]); //std::cout << "globic=" << globic << " physPosP=(" << physPosP[0] << ", " << physPosP[1] << ", " << physPosP[2] << ")" << std::endl; // <--- // particle's dimensionless position, rounded at neighbouring voxel int latticeRoundedPosP[3] = {0, 0, 0}; this->_sLattice.getCuboidGeometry().get(globic).getLatticeR ( latticeRoundedPosP, physPosP ); // { globic, latticeRoundedP[0, ..., 2] } int globicFull[4] = { globic, latticeRoundedPosP[0], latticeRoundedPosP[1], latticeRoundedPosP[2] }; // Particle's velocity T physVelP[3] = {T(), T(), T()}; // Physical physVelP[0] = (p->getVel()[0]); physVelP[1] = (p->getVel()[1]); physVelP[2] = (p->getVel()[2]); // Lattice T latticeVelP[3] = {T(), T(), T()}; // particle's dimensionless velocity latticeVelP[0] = this->_converter.getLatticeVelocity(physVelP[0]); latticeVelP[1] = this->_converter.getLatticeVelocity(physVelP[1]); latticeVelP[2] = this->_converter.getLatticeVelocity(physVelP[2]); //std::cout << "globic=" << globic << " latticeVelP=(" << latticeVelP[0] << ", " << latticeVelP[1] << ", " << latticeVelP[2] << ")" << std::endl; // <--- // Update the smoothing functional if ( ! this->_smoothingFunctional.update(physPosP, globic)) { std::cout << "ERROR: no lattice point enclosed in particle's kernel length!" << std::endl; return false; } /// Computing dimensionless drag force through smoothed average within the kernel smoothing length T latticeForceP[3] = {T(), T(), T()}; // dimensionless force acting on the particle for (int i=0; i_smoothingFunctional.getSize(); i++) { // Position of the iterated voxel int iLatticePosF[3] = {0, 0, 0}; this->_smoothingFunctional.getLatticePos(iLatticePosF, i); // Physical T iPhysPosF[3] = {T(), T(), T()}; this->_sLattice.getCuboidGeometry().get(globic).getPhysR ( iPhysPosF, iLatticePosF ); // Fluid velocity at the iterated voxel T iPhysVelF[3] = {T(), T(), T()}; // Physical this->_interpLatticeVelocity->operator() (iPhysVelF, iPhysPosF, globic); //std::cout << "globic=" << globic << " iPhysVelF=(" << iPhysVelF[0] << ", " << iPhysVelF[1] << ", " << iPhysVelF[2] << ")" << std::endl; // <--- // Lattice T iLatticeVelF[3] = {T(), T(), T()}; // Lattice's dimensionless velocity at particle's location iLatticeVelF[0] = this->_converter.getLatticeVelocity(iPhysVelF[0]); iLatticeVelF[1] = this->_converter.getLatticeVelocity(iPhysVelF[1]); iLatticeVelF[2] = this->_converter.getLatticeVelocity(iPhysVelF[2]); // Computing fluid-particle momentum transfer T gF[3] = {T(), T(), T()}; // force density gF this->_momentumExchange->operator() ( gF, iLatticeVelF, latticeVelP, physPosP, iLatticePosF, globic); //std::cout << "globic=" << globic << " gF=(" << gF[0] << ", " << gF[1] << ", " << gF[2] << ")" << std::endl; // <--- // Computing drag coefficient T Cd = this->_dragModel(p, iLatticeVelF, latticeVelP, globicFull); //std::cout << "globic=" << globic << " Cd=" << Cd << std::endl; //<--- /// Computing drag force in dimensionless units T latticePRad = p->getRad() / _converter.getConversionFactorLength(); latticeForceP[0] += .5 * Cd * M_PI*pow(latticePRad,2) * gF[0] * (iLatticeVelF[0] - latticeVelP[0]) * this->_smoothingFunctional.getWeight(i); latticeForceP[1] += .5 * Cd * M_PI*pow(latticePRad,2) * gF[1] * (iLatticeVelF[1] - latticeVelP[1]) * this->_smoothingFunctional.getWeight(i); latticeForceP[2] += .5 * Cd * M_PI*pow(latticePRad,2) * gF[2] * (iLatticeVelF[2] - latticeVelP[2]) * this->_smoothingFunctional.getWeight(i); } /// Computing physical drag force std::vector physForceP(3, T()); // physical force acting on the particle physForceP[0] = latticeForceP[0] * this->_converter.getConversionFactorForce(); physForceP[1] = latticeForceP[1] * this->_converter.getConversionFactorForce(); physForceP[2] = latticeForceP[2] * this->_converter.getConversionFactorForce(); /// Updating the particle p->setStoreForce(physForceP); //std::cout << "globic=" << globic << " physForceP=(" << physForceP[0] << ", " << physForceP[1] << ", " << physForceP[2] << ")" << std::endl; // <--- return true; } ////////////////////// Class NaiveNonLocalForwardCouplingModel //////////////////////// template class Particle> NaiveNonLocalForwardCouplingModel::NaiveNonLocalForwardCouplingModel ( UnitConverter& converter, SuperLattice3D& sLattice, SuperGeometry3D& sGeometry, DragModel& dragModel, SmoothingFunctional& smoothingFunctional ) : NonLocalBaseForwardCouplingModel(converter, sLattice, sGeometry, dragModel, smoothingFunctional) { this->_momentumExchange = std::make_shared > ( this->_converter, this->_sLattice, this->_interpLatticeDensity ); } } #endif