/* This file is part of the OpenLB library
*
* Copyright (C) 2012-2017 Lukas Baron, Tim Dornieden, Mathias J. Krause,
* Albert Mink, Fabian Klemens, Benjamin Förster, Marie-Luise Maier,
* Adrian Kummerlaender
* 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.
*/
#ifndef REDUCTION_F_3D_HH
#define REDUCTION_F_3D_HH
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#include
#include "functors/lattice/reductionF3D.h"
#include "dynamics/lbHelpers.h" // for computation of lattice rho and velocity
namespace olb {
template
SuperLatticeFfromAnalyticalF3D::SuperLatticeFfromAnalyticalF3D(
FunctorPtr>&& f,
SuperLattice3D& sLattice)
: SuperLatticeF3D(sLattice, f->getTargetDim()),
_f(std::move(f))
{
this->getName() = "fromAnalyticalF(" + _f->getName() + ")";
LoadBalancer& load = sLattice.getLoadBalancer();
CuboidGeometry3D& cuboid = sLattice.getCuboidGeometry();
for (int iC = 0; iC < load.size(); ++iC) {
this->_blockF.emplace_back(
new BlockLatticeFfromAnalyticalF3D(
*_f,
sLattice.getExtendedBlockLattice(iC),
cuboid.get(load.glob(iC)))
);
}
}
template
bool SuperLatticeFfromAnalyticalF3D::operator()(
T output[], const int input[])
{
T physR[3] = {};
this->_sLattice.getCuboidGeometry().getPhysR(physR,input);
return _f(output,physR);
}
template
BlockLatticeFfromAnalyticalF3D::BlockLatticeFfromAnalyticalF3D(
AnalyticalF3D& f,
BlockLatticeStructure3D& lattice,
Cuboid3D& cuboid)
: BlockLatticeF3D(lattice, f.getTargetDim()),
_f(f),
_cuboid(cuboid)
{
this->getName() = "blockFfromAnalyticalF(" + _f.getName() + ")";
}
template
bool BlockLatticeFfromAnalyticalF3D::operator()(
T output[], const int input[])
{
T physR[3] = {};
_cuboid.getPhysR(physR,input);
return _f(output,physR);
}
//////////// not yet working // symbolically ///////////////////
////////////////////////////////////////////////
template
SmoothBlockIndicator3D::SmoothBlockIndicator3D(
IndicatorF3D& f, T h, T eps, int wa)
: BlockDataF3D((int)((f.getMax()[0] - f.getMin()[0]) / h + (wa+1)*eps)+2,
(int)((f.getMax()[1] - f.getMin()[1]) / h + (wa+1)*eps)+2,
(int)((f.getMax()[2] - f.getMin()[2]) / h + (wa+1)*eps)+2),
_f(f),
_h(h),
_eps(eps),
_wa(wa)
{
this->getName() = "SmoothBlockIndicator3D";
// shrink epsilon boundary to one size
this->_eps = this->_eps/((this->_wa-1)/2.0);
T value;
// Important parameter of the gaussian psf (point spread function), but adaption should not be necessary
T sigma = 1.0;
T weights[this->_wa][this->_wa][this->_wa];
T sum = 0;
int iStart = floor(this->_wa/2.0);
int iEnd = ceil(this->_wa/2.0);
// calculate weights: they are constants, but calculation here is less error-prone than hardcoding these parameters
for (int x = -iStart; x < iEnd; x++) {
for (int y = -iStart; y < iEnd; y++) {
for (int z = -iStart; z < iEnd; z++) {
weights[x+iStart][y+iStart][z+iStart] = exp(-(x*x+y*y+z*z)/(2*sigma*sigma)) / (pow(sigma,3)*sqrt(pow(2,3)*pow(M_PI,3)));
// important because sum of all weigths only equals 1 for this->_wa -> infinity
sum += weights[x+iStart][y+iStart][z+iStart];
}
}
}
for (int iX=0; iXgetBlockData().getNx(); iX++) {
for (int iY=0; iYgetBlockData().getNy(); iY++) {
for (int iZ=0; iZgetBlockData().getNz(); iZ++) {
bool output[1];
value = 0;
// input: regarded point (centre)
T input[] = {
_f.getMin()[0] + (iX-iStart*_eps)*_h,
_f.getMin()[1] + (iY-iStart*_eps)*_h,
_f.getMin()[2] + (iZ-iStart*_eps)*_h
};
/*
* three loops to look at every point (which weight is not 0) around the regarded point
* sum all weighted porosities
*/
for (int x = -iStart; x < iEnd; x++) {
for (int y = -iStart; y < iEnd; y++) {
for (int z = -iStart; z < iEnd; z++) {
// move from regarded point to point in neighborhood
input[0] += x*_eps*_h;
input[1] += y*_eps*_h;
input[2] += z*_eps*_h;
// get porosity
_f(output,input);
// sum porosity
value += output[0] * weights[x+iStart][y+iStart][z+iStart];
// move back to centre
input[0] -= x*_eps*_h;
input[1] -= y*_eps*_h;
input[2] -= z*_eps*_h;
}
}
}
/*
* Round to 3 decimals
* See above sum != 1.0, that's the reason for devision, otherwise porosity will never reach 0
*/
this->getBlockData().get(iX,iY,iZ,0) = nearbyint(1000*value/sum)/1000.0;
}
}
}
}
/*
template
bool SmoothBlockIndicator3D::operator()(
T output[], const int input[])
{
T physR[3] = {};
_superGeometry.getPhysR(physR,input[0],input[1],input[2] );
_f(output,physR);
return true;
}*/
template
SuperLatticeInterpPhysVelocity3Degree3D::
SuperLatticeInterpPhysVelocity3Degree3D(
SuperLattice3D& sLattice, UnitConverter& conv, int range)
: SuperLatticeF3D(sLattice, 3)
{
this->getName() = "Interp3DegreeVelocity";
int maxC = this->_sLattice.getLoadBalancer().size();
this->_blockF.reserve(maxC);
for (int iC = 0; iC < maxC; iC++) {
BlockLatticeInterpPhysVelocity3Degree3D* foo =
new BlockLatticeInterpPhysVelocity3Degree3D(
sLattice.getExtendedBlockLattice(iC),
conv,
&sLattice.getCuboidGeometry().get(this->_sLattice.getLoadBalancer().
glob(iC)),
sLattice.getOverlap(),
range);
_bLattices.push_back(foo);
}
}
template
void SuperLatticeInterpPhysVelocity3Degree3D::operator()(
T output[], const T input[], const int iC)
{
_bLattices[this->_sLattice.getLoadBalancer().loc(iC)]->operator()(output,
input);
}
template
BlockLatticeInterpPhysVelocity3Degree3D::
BlockLatticeInterpPhysVelocity3Degree3D(
BlockLatticeStructure3D& blockLattice, UnitConverter& conv,
Cuboid3D* c, int overlap, int range)
: BlockLatticeF3D(blockLattice, 3),
_conv(conv),
_cuboid(c),
_overlap(overlap),
_range(range)
{
this->getName() = "BlockLatticeInterpVelocity3Degree3D";
}
template
BlockLatticeInterpPhysVelocity3Degree3D::
BlockLatticeInterpPhysVelocity3Degree3D(
const BlockLatticeInterpPhysVelocity3Degree3D& rhs) :
BlockLatticeF3D(rhs._blockLattice, 3),
_conv(rhs._conv),
_cuboid(rhs._cuboid),
_overlap(rhs._overlap),
_range(rhs._range)
{
}
template
void BlockLatticeInterpPhysVelocity3Degree3D::operator()(
T output[3], const T input[3])
{
T u[3], rho, volume;
int latIntPos[3] = {0};
T latPhysPos[3] = {T()};
_cuboid->getFloorLatticeR(latIntPos, &input[0]);
_cuboid->getPhysR(latPhysPos, latIntPos);
latIntPos[0] += _overlap;
latIntPos[1] += _overlap;
latIntPos[2] += _overlap;
volume=T(1);
for (int i = -_range; i <= _range+1; ++i) {
for (int j = -_range; j <= _range+1; ++j) {
for (int k = -_range; k <= _range+1; ++k) {
this->_blockLattice.get(latIntPos[0]+i, latIntPos[1]+j,
latIntPos[2]+k).computeRhoU(rho, u);
for (int l = -_range; l <= _range+1; ++l) {
if (l != i) {
volume *= (input[0] - (latPhysPos[0]+ l *_cuboid->getDeltaR()))
/ (latPhysPos[0] + i *_cuboid->getDeltaR()
- (latPhysPos[0] + l *_cuboid->getDeltaR()));
}
}
for (int m = -_range; m <= _range+1; ++m) {
if (m != j) {
volume *= (input[1]
- (latPhysPos[1] + m *_cuboid->getDeltaR()))
/ (latPhysPos[1] + j * _cuboid->getDeltaR()
- (latPhysPos[1] + m * _cuboid->getDeltaR()));
}
}
for (int n = -_range; n <= _range+1; ++n) {
if (n != k) {
volume *= (input[2]
- (latPhysPos[2] + n * _cuboid->getDeltaR()))
/ (latPhysPos[2] + k * _cuboid->getDeltaR()
- (latPhysPos[2] + n * _cuboid->getDeltaR()));
}
}
output[0] += u[0] * volume;
output[1] += u[1] * volume;
output[2] += u[2] * volume;
volume=T(1);
}
}
}
output[0] = _conv.getPhysVelocity(output[0]);
output[1] = _conv.getPhysVelocity(output[1]);
output[2] = _conv.getPhysVelocity(output[2]);
}
template
SuperLatticeInterpDensity3Degree3D::SuperLatticeInterpDensity3Degree3D(
SuperLattice3D& sLattice, SuperGeometry3D& sGeometry,
UnitConverter& conv, int range) :
SuperLatticeF3D(sLattice, 3)
{
this->getName() = "Interp3DegreeDensity";
int maxC = this->_sLattice.getLoadBalancer().size();
this->_blockF.reserve(maxC);
for (int lociC = 0; lociC < maxC; lociC++) {
int globiC = this->_sLattice.getLoadBalancer().glob(lociC);
BlockLatticeInterpDensity3Degree3D* foo =
new BlockLatticeInterpDensity3Degree3D(
sLattice.getExtendedBlockLattice(lociC),
sGeometry.getExtendedBlockGeometry(lociC),
conv,
&sLattice.getCuboidGeometry().get(globiC),
sLattice.getOverlap(), range);
_bLattices.push_back(foo);
if (sLattice.getOverlap() <= range + 1)
std::cout << "lattice overlap has to be larger than (range + 1)"
<< std::endl;
}
}
template
SuperLatticeInterpDensity3Degree3D::~SuperLatticeInterpDensity3Degree3D()
{
// first deconstruct vector elements
for ( auto it : _bLattices) {
delete it;
}
// then delete std::vector
_bLattices.clear();
}
template
void SuperLatticeInterpDensity3Degree3D::operator()(T output[],
const T input[], const int globiC)
{
if (this->_sLattice.getLoadBalancer().rank(globiC) == singleton::mpi().getRank()) {
_bLattices[this->_sLattice.getLoadBalancer().loc(globiC)]->operator()(output,
input);
}
}
template
BlockLatticeInterpDensity3Degree3D::BlockLatticeInterpDensity3Degree3D(
BlockLatticeStructure3D& blockLattice,
BlockGeometryStructure3D& blockGeometry, UnitConverter& conv,
Cuboid3D* c, int overlap, int range) :
BlockLatticeF3D(blockLattice, 3), _blockGeometry(blockGeometry),
_conv(conv), _cuboid(c), _overlap(overlap), _range(range)
{
this->getName() = "BlockLatticeInterpDensity3Degree3D";
}
template
BlockLatticeInterpDensity3Degree3D::BlockLatticeInterpDensity3Degree3D(
const BlockLatticeInterpDensity3Degree3D& rhs) :
BlockLatticeF3D(rhs._blockLattice, 3),
_blockGeometry(rhs._blockGeometry),_conv(rhs._conv), _cuboid(
rhs._cuboid), _overlap(rhs._overlap), _range(rhs._range)
{
}
template
void BlockLatticeInterpDensity3Degree3D::operator()(
T output[DESCRIPTOR::q], const T input[3])
{
T volume = T(1);
T f_iPop = 0.;
/** neighbor position on grid of input value in lattice units
*referred to local cuboid
*/
int latIntPos[3] = { 0 };
// neighbor position on grid of input value in physical units
T latPhysPos[3] = { T() };
// input is physical position on grid
_cuboid->getFloorLatticeR(latIntPos, input);
// latPhysPos is global physical position on geometry
_cuboid->getPhysR(latPhysPos, latIntPos);
// point on cuboid equals cell on blocklattice (extended) shifted by _overlap
latIntPos[0] += _overlap;
latIntPos[1] += _overlap;
latIntPos[2] += _overlap;
for (unsigned iPop = 0; iPop < DESCRIPTOR::q; ++iPop) {
output[iPop] = T(0);
for (int i = -_range; i <= _range + 1; ++i) {
for (int j = -_range; j <= _range + 1; ++j) {
for (int k = -_range; k <= _range + 1; ++k) {
f_iPop = 0.;
// just if material of cell != 1 there may be information of fluid density
if (_blockGeometry.getMaterial(latIntPos[0] + i, latIntPos[1] + j,
latIntPos[2] + k) != 0) {
// because of communication it is possible to get density information
// from neighboring cuboid
f_iPop = this->_blockLattice.get(latIntPos[0] + i, latIntPos[1] + j,
latIntPos[2] + k)[iPop];
}
for (int l = -_range; l <= _range + 1; ++l) {
if (l != i) {
volume *= (input[0] - (latPhysPos[0] + l * _cuboid->getDeltaR()))
/ (latPhysPos[0] + i * _cuboid->getDeltaR()
- (latPhysPos[0] + l * _cuboid->getDeltaR()));
}
}
for (int m = -_range; m <= _range + 1; ++m) {
if (m != j) {
volume *= (input[1] - (latPhysPos[1] + m * _cuboid->getDeltaR()))
/ (latPhysPos[1] + j * _cuboid->getDeltaR()
- (latPhysPos[1] + m * _cuboid->getDeltaR()));
}
}
for (int n = -_range; n <= _range + 1; ++n) {
if (n != k) {
volume *= (input[2] - (latPhysPos[2] + n * _cuboid->getDeltaR()))
/ (latPhysPos[2] + k * _cuboid->getDeltaR()
- (latPhysPos[2] + n * _cuboid->getDeltaR()));
}
}
output[iPop] += f_iPop * volume;
volume = T(1);
}
}
}
}
}
template
SuperLatticeSmoothDiracDelta3D::SuperLatticeSmoothDiracDelta3D(
SuperLattice3D& sLattice,
UnitConverter& conv, SuperGeometry3D& sGeometry) :
SuperLatticeF3D(sLattice, 3)
{
this->getName() = "SuperLatticeSmoothDiracDelta3D";
int maxC = this->_sLattice.getLoadBalancer().size();
this->_blockF.reserve(maxC);
for (int lociC = 0; lociC < maxC; lociC++) {
int globiC = this->_sLattice.getLoadBalancer().glob(lociC);
BlockLatticeSmoothDiracDelta3D* foo =
new BlockLatticeSmoothDiracDelta3D(
sLattice.getExtendedBlockLattice(lociC),
conv, &sLattice.getCuboidGeometry().get(globiC)
);
_bLattices.push_back(foo);
}
}
template
SuperLatticeSmoothDiracDelta3D::~SuperLatticeSmoothDiracDelta3D()
{
for ( auto it : _bLattices) {
delete it;
}
_bLattices.clear();
}
template
void SuperLatticeSmoothDiracDelta3D::operator()(T delta[4][4][4],
const T physPos[3], const int globiC)
{
if (this->_sLattice.getLoadBalancer().rank(globiC) == singleton::mpi().getRank()) {
_bLattices[this->_sLattice.getLoadBalancer().loc(globiC)]->operator()(delta,
physPos);
}
}
template
BlockLatticeSmoothDiracDelta3D::BlockLatticeSmoothDiracDelta3D(
BlockLattice3D& blockLattice, UnitConverter& conv, Cuboid3D* cuboid)
: BlockLatticeF3D(blockLattice, 3), _conv(conv), _cuboid(cuboid)
{
this->getName() = "BlockLatticeSmoothDiracDelta3D";
}
template
BlockLatticeSmoothDiracDelta3D::BlockLatticeSmoothDiracDelta3D(
const BlockLatticeSmoothDiracDelta3D& rhs)
:
BlockLatticeF3D(rhs._blockLattice, 3), _conv(rhs._conv), _cuboid(rhs._cuboid)
{
}
template
void BlockLatticeSmoothDiracDelta3D::operator()(
T delta[4][4][4], const T physPos[])
{
int range = 1;
T a, b, c = T();
int latticeRoundedPosP[3] = { 0 };
T physRoundedPosP[3] = { T() };
T physLatticeL = _conv.getConversionFactorLength();
T counter = 0.;
_cuboid->getLatticeR(latticeRoundedPosP, physPos);
_cuboid->getPhysR(physRoundedPosP, latticeRoundedPosP);
for (int i = -range; i <= range + 1; ++i) {
for (int j = -range; j <= range + 1; ++j) {
for (int k = -range; k <= range + 1; ++k) {
delta[i+range][j+range][k+range] = T(1);
// a, b, c in lattice units cause physical ones get cancelled
a = (physRoundedPosP[0] + i * physLatticeL - physPos[0])
/ physLatticeL;
b = (physRoundedPosP[1] + j * physLatticeL - physPos[1])
/ physLatticeL;
c = (physRoundedPosP[2] + k * physLatticeL - physPos[2])
/ physLatticeL;
// the for loops already define that a, b, c are smaller than 2
delta[i+range][j+range][k+range] *= 1. / 4 * (1 + cos(M_PI * a / 2.));
delta[i+range][j+range][k+range] *= 1. / 4 * (1 + cos(M_PI * b / 2.));
delta[i+range][j+range][k+range] *= 1. / 4 * (1 + cos(M_PI * c / 2.));
counter += delta[i+range][j+range][k+range];
}
}
}
// if (!util::nearZero(counter - T(1))){
// // sum of delta has to be one
// std::cout << "[" << this->getName() << "] " <<
// "Delta summed up does not equal 1 but = " <<
// counter << std::endl;
// }
}
} // end namespace olb
#endif