/* 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