/* This file is part of the OpenLB library
*
* Copyright (C) 2012 Lukas Baron, Tim Dornieden, Mathias J. Krause, Albert Mink
* 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 ANALYTICAL_F_HH
#define ANALYTICAL_F_HH
#include
#include // for lpnorm
#include // for random
#include
#include
#include "analyticalF.h"
#include "core/singleton.h"
#include "communication/mpiManager.h"
#include "utilities/vectorHelpers.h"
#include "core/radiativeUnitConverter.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
namespace olb {
//////////////////////////////////1D////////////////////////////////////////////
template
AnalyticalConst1D::AnalyticalConst1D(const std::vector& value)
: AnalyticalF1D(value.size()), _c(value)
{
this->getName() = "const";
}
template
AnalyticalConst1D::AnalyticalConst1D(T value) : AnalyticalF1D(1)
{
_c.push_back(value);
this->getName() = "const";
}
template
bool AnalyticalConst1D::operator()(T output[], const S x[])
{
for ( unsigned i = 0; i < _c.size(); ++i) {
output[i] = _c[i];
}
return true;
}
template
AnalyticalLinear1D::AnalyticalLinear1D(T a, T b)
: AnalyticalF1D(1), _a(a), _b(b)
{
this->getName() = "linear";
}
template
AnalyticalLinear1D::AnalyticalLinear1D(S x0, T v0, S x1, T v1)
: AnalyticalF1D(1)
{
if ( util::nearZero(x1-x0) ) {
std::cout << "Error: x1-x2=0" << std::endl;
} else {
_a = ( v1-v0 ) / ( x1-x0 );
_b = v0 - _a*x0;
}
this->getName() = "linear";
}
template
bool AnalyticalLinear1D::operator()(T output[], const S x[])
{
output[0]=_a*x[0] + _b;
return true;
}
template
AnalyticalRandom1D::AnalyticalRandom1D() : AnalyticalF1D(1)
{
#ifdef PARALLEL_MODE_MPI
int nameLen, numProcs, myID;
char processorName[MPI_MAX_PROCESSOR_NAME];
MPI_Comm_rank(MPI_COMM_WORLD,&myID);
MPI_Comm_size(MPI_COMM_WORLD,&numProcs);
MPI_Get_processor_name(processorName,&nameLen);
srand(time(0)+myID*numProcs + nameLen);
#else
srand(time(nullptr));
#endif
this->getName() = "random";
}
template
bool AnalyticalRandom1D::operator()(T output[], const S x[])
{
output[0]=(rand()%RAND_MAX)/(T)RAND_MAX;
return true;
}
template
AnalyticalSquare1D::AnalyticalSquare1D(S cp, S r, T maxi)
: AnalyticalF1D(1), _cp(cp), _r(r), _maxi(maxi)
{
this->getName() = "square";
}
template
bool AnalyticalSquare1D::operator()(T output[], const S x[])
{
output[0]=_maxi*(1-(x[0]-_cp) * (x[0]-_cp) / (T)_r / (T)_r);
return true;
}
/////////////////////////////////someOtherFunctors//////////////////////////////
template
PolynomialStartScale::PolynomialStartScale(S numTimeSteps, T maxValue)
: AnalyticalF1D(1), _numTimeSteps(numTimeSteps), _maxValue(maxValue)
{
this->getName() = "polyStartScale";
}
template
bool PolynomialStartScale::operator()(T output[], const S x[])
{
output[0]=(T) x[0] / (T) _numTimeSteps;
output[0]=_maxValue * output[0]*output[0]*output[0] * ( 10.0 + output[0] * (6.0*output[0] - 15.0) );
return true;
}
template
SinusStartScale::SinusStartScale(int numTimeSteps, T maxValue)
: AnalyticalF1D(1), _numTimeSteps(numTimeSteps), _maxValue(maxValue),
_pi(4.0*atan(1.0))
{
this->getName() = "sinusStartScale";
}
template
bool SinusStartScale::operator()(T output[], const S x[])
{
output[0]=(_maxValue * (sin(-_pi / 2.0 + (T)x[0] / (T)_numTimeSteps * _pi) + 1.0)) / 2.0;
return true;
}
template
AnalyticalDiffFD1D::AnalyticalDiffFD1D(AnalyticalF1D& f, T eps) : AnalyticalF1D(1), _f(f), _eps(eps)
{
}
template
bool AnalyticalDiffFD1D::operator() (T output[], const T input[])
{
_f(output,input);
T x = output[0];
T input2[1];
input2[0] = input[0] + _eps;
_f(output,input2);
output[0] -= x;
output[0] /= _eps;
return true;
}
///////////////////////////////////////2D///////////////////////////////////////
template
AnalyticalComposed2D::AnalyticalComposed2D( AnalyticalF2D& f0,
AnalyticalF2D& f1)
: AnalyticalF2D(2), _f0(f0), _f1(f1)
{
this->getName() = "composed";
}
template
bool AnalyticalComposed2D::operator()(T output[], const S x[])
{
T tmp1[_f0.getTargetDim()], tmp2[_f1.getTargetDim()];
_f0(tmp1,x);
_f1(tmp2,x);
output[0]=tmp1[0];
output[1]=tmp2[0];
return true;
}
template
AnalyticalConst2D::AnalyticalConst2D(const std::vector& value)
: AnalyticalF2D(value.size()), _c(value)
{
this->getName() = "const";
}
template
AnalyticalConst2D::AnalyticalConst2D(T value) : AnalyticalF2D(1)
{
_c.push_back(value);
this->getName() = "const";
}
template
AnalyticalConst2D::AnalyticalConst2D(T value0, T value1) : AnalyticalF2D(2)
{
_c.push_back(value0);
_c.push_back(value1);
this->getName() = "const";
}
template
AnalyticalConst2D::AnalyticalConst2D(T value0, T value1, T value2) : AnalyticalF2D(3)
{
_c.push_back(value0);
_c.push_back(value1);
_c.push_back(value2);
this->getName() = "const";
}
template
bool AnalyticalConst2D::operator()(T output[], const S x[])
{
for (unsigned i = 0; i < _c.size(); ++i) {
output[i] = _c[i];
}
return true;
}
template
AnalyticalLinear2D::AnalyticalLinear2D(T a, T b, T c)
: AnalyticalF2D(1), _a(a), _b(b), _c(c)
{
this->getName() = "linear";
}
template
AnalyticalLinear2D::AnalyticalLinear2D(S x0, S y0, T v0, S x1, S y1,
T v1, S x2, S y2, T v2)
: AnalyticalF2D(1)
{
this->getName() = "linear";
T n2= (x1-x0)*(y2-y0) - (y1-y0)*(x2-x0);
if ( util::nearZero(n2) ) {
std::cout << "Error function" << std::endl;
} else {
T n0 = (y1-y0)*(v2-v0) - (v1-v0)*(y2-y0);
T n1 = (v1-v0)*(x2-x0) - (x1-x0)*(v2-v0);
_a = -n0 / n2;
_b = -n1 / n2;
_c = (x0*n0 + y0*n1 + v0*n2) / n2;
}
}
template
bool AnalyticalLinear2D::operator()(T output[], const S x[])
{
output[0]=_a*x[0] + _b*x[1] + _c;
return true;
}
template
AnalyticalParticleAdsorptionLinear2D::AnalyticalParticleAdsorptionLinear2D(T center[], T radius, T maxValue) : AnalyticalF2D(2), _radius(radius), _maxValue(maxValue)
{
_center[0] = center[0];
_center[1] = center[1];
this->getName() = "particleAdsorptionLinear2D";
}
template
bool AnalyticalParticleAdsorptionLinear2D::operator()(T output[], const S input[])
{
T dist = sqrt((input[0]-_center[0])*(input[0]-_center[0]) + (input[1]-_center[1])*(input[1]-_center[1]));
if (dist > _radius) {
output[0] = T();
output[1] = T();
return true;
} else {
output[0] = _maxValue*(T(1) - dist/_radius)*(_center[0]-input[0])/_radius;
output[1] = _maxValue*(T(1) - dist/_radius)*(_center[1]-input[1])/_radius;
return true;
}
}
template
AnalyticalRandom2D::AnalyticalRandom2D() : AnalyticalF2D(1)
{
#ifdef PARALLEL_MODE_MPI
int nameLen, numProcs, myID;
char processorName[MPI_MAX_PROCESSOR_NAME];
MPI_Comm_rank(MPI_COMM_WORLD,&myID);
MPI_Comm_size(MPI_COMM_WORLD,&numProcs);
MPI_Get_processor_name(processorName,&nameLen);
srand(time(0)+myID*numProcs + nameLen);
#else
srand(time(nullptr));
#endif
this->getName() = "random";
}
template
bool AnalyticalRandom2D::operator()(T output[], const S x[])
{
output[0]=(rand()%RAND_MAX)/(T)RAND_MAX;
return true;
}
template
ParticleU2D::ParticleU2D(SmoothIndicatorF2D& indicator, UnitConverter const& converter)
:AnalyticalF2D(2), _indicator(indicator), _converter(converter)
{
this->getName() = "ParticleU";
}
template
bool ParticleU2D::operator()(T output[], const S input[])
{
//two dimensions: u = U + w x r = (Ux, Uy, 0) + (0,0,w) x (X,Y,0) = (Ux, Uy, 0) + (-w*Y, w*X, 0)
output[0] = _converter.getLatticeVelocity( _indicator.getVel()[0] - _indicator.getOmega() * (input[1] - _indicator.getPos()[1]) );
output[1] = _converter.getLatticeVelocity( _indicator.getVel()[1] + _indicator.getOmega() * (input[0] - _indicator.getPos()[0]) );
return true;
}
///////////////////////////////////////3D///////////////////////////////////////
template
AnalyticalComposed3D::AnalyticalComposed3D(AnalyticalF3D& f0,
AnalyticalF3D& f1, AnalyticalF3D& f2)
: AnalyticalF3D(3), _f0(f0), _f1(f1), _f2(f2)
{
this->getName() = "composed";
}
template
bool AnalyticalComposed3D::operator()(T output[], const S x[])
{
T outputTmp0[_f0.getTargetDim()];
_f0(outputTmp0,x);
output[0]=outputTmp0[0];
T outputTmp1[_f1.getTargetDim()];
_f1(outputTmp1,x);
output[1]=outputTmp1[0];
T outputTmp2[_f2.getTargetDim()];
_f2(outputTmp2,x);
output[2]=outputTmp2[0];
return true;
}
template
AnalyticalConst3D::AnalyticalConst3D(const std::vector& value)
: AnalyticalF3D(value.size()), _c(value)
{
this->getName() = "const";
}
template
AnalyticalConst3D::AnalyticalConst3D(T value) : AnalyticalF3D(1)
{
_c.push_back(value);
this->getName() = "const";
}
template
AnalyticalConst3D::AnalyticalConst3D(T value0, T value1) : AnalyticalF3D(2)
{
_c.push_back(value0);
_c.push_back(value1);
this->getName() = "const";
}
template
AnalyticalConst3D::AnalyticalConst3D(T value0, T value1, T value2)
: AnalyticalF3D(3)
{
_c.push_back(value0);
_c.push_back(value1);
_c.push_back(value2);
this->getName() = "const";
}
template
AnalyticalConst3D::AnalyticalConst3D(const Vector& value)
: AnalyticalF3D(3)
{
_c.reserve(3);
_c.push_back(value[0]);
_c.push_back(value[1]);
_c.push_back(value[2]);
this->getName() = "const";
}
template
bool AnalyticalConst3D::operator()(T output[], const S x[])
{
for (unsigned int i = 0; i < _c.size(); ++i) {
output[i] = _c[i];
}
return true;
}
template
AnalyticalLinear3D::AnalyticalLinear3D(T a, T b, T c, T d)
: AnalyticalF3D(1), _a(a), _b(b), _c(c), _d(d)
{
this->getName() = "linear";
}
template
AnalyticalLinear3D::AnalyticalLinear3D(S x0, S y0, S z0, T v0, S x1,
S y1, S z1, T v1, S x2, S y2, S z2, T v2, S x3, S y3, S z3, T v3)
: AnalyticalF3D(1)
{
this->getName() = "linear";
T n = ( (y3-y0)*(x1-x0)-(x3-x0)*(y1-y0) ) * ( (x2-x0)*(z1-z0)-(z2-z0)*(x1-x0) )
+( (z3-z0)*(x1-x0)-(x3-x0)*(z1-z0) ) * ( (y2-y0)*(x1-x0)-(x2-x0)*(y1-y0) );
if ( util::nearZero(n) ) {
std::cout << "Error function" << std::endl;
} else {
T w = ( (y1-y0)*(x3-x0)-(x1-x0)*(y3-y0) ) * ( (v2-v0)-(x2-x0)*(v1-v0) / (x1-x0) )
/( (y2-y0)*(x1-x0)-(x2-x0)*(y1-y0) ) + (v3-v0) - (x3-x0)*(v1-v0) / (x1-x0);
T zx = (y1-y0)*( (x2-x0)*(z1-z0)-(z2-z0)*(x1-x0) )
-(z1-z0)*( (y2-y0)*(x1-x0)-(x2-x0)*(y1-y0) );
T rx = (v1-v0)/(x1-x0) - (y1-y0)*(v2-v0) / ( (y2-y0)*(x1-x0)-(x2-x0)*(y1-y0) )
+(y1-y0)*(x2-x0)*(v1-v0) / ( (y2-y0)*(x1-x0)*(x1-x0)-(x2-x0)*(y1-y0)*(x1-x0) );
T zy = (x1-x0)*( (x2-x0)*(z1-z0)-(z2-z0)*(x1-x0) );
T ry = ( (x1-x0)*(v2-v0)-(x2-x0)*(v1-v0) ) / ( (y2-y0)*(x1-x0)-(x2-x0)*(y1-y0) );
T zz = (x1-x0)*( (y2-y0)*(x1-x0)-(x2-x0)*(y1-y0) );
T h = w/n;
_a = rx + zx*h;
_b = ry + zy*h;
_c = zz*h;
_d = v0 - x0*_a - y0*_b - z0*_c;
}
}
template
bool AnalyticalLinear3D::operator()(T output[], const S x[])
{
output[0]=_a*x[0] + _b*x[1] + _c*x[2] + _d;
return true;
}
template
AnalyticalRandom3D::AnalyticalRandom3D() : AnalyticalF3D(1)
{
#ifdef PARALLEL_MODE_MPI
int nameLen, numProcs, myID;
char processorName[MPI_MAX_PROCESSOR_NAME];
MPI_Comm_rank(MPI_COMM_WORLD,&myID);
MPI_Comm_size(MPI_COMM_WORLD,&numProcs);
MPI_Get_processor_name(processorName,&nameLen);
srand(time(0)+myID*numProcs + nameLen);
#else
srand(time(nullptr));
#endif
this->getName() = "random";
}
template
bool AnalyticalRandom3D::operator()(T output[], const S x[])
{
output[0]=(rand()%RAND_MAX)/(T)RAND_MAX;
return true;
}
template
AnalyticalScaled3D::AnalyticalScaled3D(AnalyticalF3D& f, T scale)
: AnalyticalF3D(f.getTargetDim()), _f(f), _scale(scale)
{
this->getName() = "scaled";
}
template
bool AnalyticalScaled3D::operator()(T output[], const S x[])
{
T outputTmp[_f.getTargetDim()];
_f(outputTmp,x);
for (int iDim = 0; iDim < this->getTargetDim(); ++iDim) {
output[iDim] = _scale*outputTmp[iDim];
}
return true;
}
// see Mink et al. 2016 in Sec.3.1.
template
PLSsolution3D::PLSsolution3D(RadiativeUnitConverter const& converter)
: AnalyticalF3D(1),
_physSigmaEff(std::sqrt( converter.getPhysAbsorption() / converter.getPhysDiffusion() )),
_physDiffusionCoefficient(converter.getPhysDiffusion())
{
this->getName() = "PLSsolution3D";
}
template
bool PLSsolution3D::operator()(T output[1], const S x[3])
{
double r = std::sqrt( x[0]*x[0] + x[1]*x[1] + x[2]*x[2] );
output[0] = 1. / (4.0*M_PI*_physDiffusionCoefficient*r) *std::exp(-_physSigmaEff * r);
return true;
}
template
LightSourceCylindrical3D::LightSourceCylindrical3D(RadiativeUnitConverter const& converter, Vector center)
: AnalyticalF3D(1),
_physSigmaEff(sqrt( converter.getPhysAbsorption() / converter.getPhysDiffusion() )),
_physDiffusionCoefficient(converter.getPhysDiffusion()),
_center(center)
{
this->getName() = "LightSourceCylindrical3D";
}
template
bool LightSourceCylindrical3D::operator()(T output[1], const S x[3])
{
double r = sqrt( (x[0]-_center[0])*(x[0]-_center[0]) + (x[1]-_center[1])*(x[1]-_center[1]) );
if ( util::nearZero(r) ) {
std::cout << "Warning: evaluation of \"LightSourceCylindrical3D\" functor close to singularity." << std::endl;
}
output[0] = 1. / (4.0*M_PI*_physDiffusionCoefficient*r) *exp(-_physSigmaEff * r);
return true;
}
template
Spotlight::Spotlight(Vector position, Vector direction, T falloff)
: AnalyticalF3D(1), _position(position), _orientation(direction[0]/norm(direction), direction[1]/norm(direction), direction[2]/norm(direction)), _falloff(falloff)
{
this->getName() = "Spotlight";
}
template
bool Spotlight::operator()(T output[1], const S x[3])
{
Vector w(x[0] -_position[0], x[1] -_position[1], x[2] -_position[2]);
normalize(w);
T cosPhi = w*_orientation;
output[0] = 1. / (norm(w)*norm(w)) * std::pow(std::max(0., cosPhi), _falloff);
return true;
}
template
GaussianHill2D::GaussianHill2D(T sigma, Vector x0, T c0)
: AnalyticalF2D(1), _sigma(sigma), _x0(x0[0],x0[1]), _c0(c0)
{
this->getName() = "GaussianHill";
}
template
bool GaussianHill2D::operator()(T output[1], const S x[2])
{
output[0] = _c0 * exp(- ((x[0]-_x0[0])*(x[0]-_x0[0]) + (x[1]-_x0[1])*(x[1]-_x0[1])) / (2*_sigma*_sigma) );
return true;
}
template
GaussianHillTimeEvolution2D::GaussianHillTimeEvolution2D(T sigma0, T D, T t, Vector x0, Vector u, T c0)
: AnalyticalF2D(1), _sigma02(sigma0*sigma0), _D(D), _t(t), _x0(x0[0],x0[1]), _u(u[0],u[1]), _c0(c0)
{
this->getName() = "GaussianHillTimeEvolution";
}
template
bool GaussianHillTimeEvolution2D::operator()(T output[1], const S x[2])
{
output[0] = _sigma02 / (_sigma02+2*_D*_t) * _c0 * exp(- ((x[0]-_x0[0]-_u[0]*_t)*(x[0]-_x0[0]-_u[0]*_t) + (x[1]-_x0[1]-_u[1]*_t)*(x[1]-_x0[1]-_u[1]*_t)) / (2*(_sigma02+2*_D*_t) ));
return true;
}
template
ParticleU3D::ParticleU3D(SmoothIndicatorF3D& indicator, UnitConverter const& converter)
:AnalyticalF3D(3), _indicator(indicator), _converter(converter)
{
this->getName() = "ParticleU";
}
template
bool ParticleU3D::operator()(T output[], const S input[])
{
//three dimensions: u = U + w x r = (Ux, Uy, Uz) + (wx,wy,wz) x (X,Y,Z) = (Ux, Uy, Uz) + (wy*Z-wz*Y, wz*X-wx*Z, wx*Y-wy*X)
output[0] = _converter.getLatticeVelocity( _indicator.getVel()[0] +
( _indicator.getOmega()[1]*(input[2] - _indicator.getPos()[2])
- _indicator.getOmega()[2]*(input[1] - _indicator.getPos()[1]) ) );
output[1] = _converter.getLatticeVelocity( _indicator.getVel()[1] +
( _indicator.getOmega()[2]*(input[0] - _indicator.getPos()[0])
- _indicator.getOmega()[0]*(input[2] - _indicator.getPos()[2]) ) );
output[2] = _converter.getLatticeVelocity( _indicator.getVel()[2] +
( _indicator.getOmega()[0]*(input[1] - _indicator.getPos()[1])
- _indicator.getOmega()[1]*(input[0] - _indicator.getPos()[0]) ) );
return true;
}
} // end namespace olb
#endif