/* This file is part of the OpenLB library
*
* Copyright (C) 2013, 2015 Gilles Zahnd, Mathias J. Krause
* Marie-Luise Maier
* 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 FRAME_CHANGE_F_3D_HH
#define FRAME_CHANGE_F_3D_HH
#include
#include "frameChangeF3D.h"
#include "frameChangeF2D.h"
#include "core/superLattice3D.h"
#include "dynamics/lbHelpers.h" // for computation of lattice rho and velocity
#include "utilities/vectorHelpers.h" // for normalize
#include "geometry/superGeometry3D.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
namespace olb {
template
RotatingLinear3D::RotatingLinear3D(std::vector axisPoint_,
std::vector axisDirection_, T w_, T scale_)
: AnalyticalF3D(3), axisPoint(axisPoint_), axisDirection(axisDirection_),
w(w_), scale(scale_) { }
template
bool RotatingLinear3D::operator()(T output[], const T x[])
{
output[0] = (axisDirection[1]*(x[2]-axisPoint[2]) - axisDirection[2]*(x[1]-axisPoint[1]))*w*scale;
output[1] = (axisDirection[2]*(x[0]-axisPoint[0]) - axisDirection[0]*(x[2]-axisPoint[2]))*w*scale;
output[2] = (axisDirection[0]*(x[1]-axisPoint[1]) - axisDirection[1]*(x[0]-axisPoint[0]))*w*scale;
return true;
}
template
RotatingLinearAnnulus3D::RotatingLinearAnnulus3D(std::vector axisPoint_,
std::vector axisDirection_, T w_, T ri_, T ro_, T scale_)
: AnalyticalF3D(3), axisPoint(axisPoint_), axisDirection(axisDirection_),
w(w_), ri(ri_), ro(ro_), scale(scale_) { }
template
bool RotatingLinearAnnulus3D::operator()(T output[], const T x[])
{
if ( (sqrt((x[0]-axisPoint[0])*(x[0]-axisPoint[0])+(x[1]-axisPoint[1])*(x[1]-axisPoint[1])) < ri) || (sqrt((x[0]-axisPoint[0])*(x[0]-axisPoint[0])+(x[1]-axisPoint[1])*(x[1]-axisPoint[1])) >= ro) ) {
output[0] = 0.;
output[1] = 0.;
output[2] = 0.;
}
else {
T L[3];
T si[3];
T so[3];
int sign1 = 1;
int sign2 = 1;
if ( (axisDirection[2] && (x[0] == axisPoint[0])) || (axisDirection[1] && (x[2] == axisPoint[2])) || (axisDirection[0] && (x[1] == axisPoint[1])) ) {
int sign = 1;
if ( (axisDirection[2] && (x[1] < axisPoint[1])) || (axisDirection[1] && (x[0] < axisPoint[0])) || (axisDirection[0] && (x[2] < axisPoint[2])) ) {
sign = -1;
}
//Compute point of intersection between the inner cylinder and the line between axisPoint and x
si[0] = axisDirection[0]*x[0] + axisDirection[1]*(axisPoint[0]+sign*ri) + axisDirection[2]*x[0];
si[1] = axisDirection[0]*x[1] + axisDirection[1]*x[1] + axisDirection[2]*(axisPoint[1]+sign*ri);
si[2] = axisDirection[0]*(axisPoint[2]+sign*ri) + axisDirection[1]*x[2] + axisDirection[2]*x[2];
//Compute point of intersection between the outer cylinder and the line between axisPoint and x
so[0] = axisDirection[0]*x[0] + axisDirection[1]*(axisPoint[0]+sign*ro) + axisDirection[2]*x[0];
so[1] = axisDirection[0]*x[1] + axisDirection[1]*x[1] + axisDirection[2]*(axisPoint[1]+sign*ro);
so[2] = axisDirection[0]*(axisPoint[2]+sign*ro) + axisDirection[1]*x[2] + axisDirection[2]*x[2];
}
else {
T alpha;
//which quadrant
if ( (axisDirection[2] && (x[0] < axisPoint[0])) || (axisDirection[1] && (x[2] < axisPoint[2])) || (axisDirection[0] && (x[1] < axisPoint[1])) ) {
sign1 = -1;
}
if ( (axisDirection[2] && (x[1] < axisPoint[1])) || (axisDirection[1] && (x[0] < axisPoint[0])) || (axisDirection[0] && (x[2] < axisPoint[2])) ) {
sign2 = -1;
}
alpha = atan( ( sign2*(axisDirection[0]*(x[2]-axisPoint[2]) + axisDirection[1]*(x[0]-axisPoint[0]) + axisDirection[2]*(x[1]-axisPoint[1]) ) ) / \
(sign1*(axisDirection[0]*(x[1]-axisPoint[1]) + axisDirection[1]*(x[2]-axisPoint[2]) + axisDirection[2]*(x[0]-axisPoint[0]))) );
si[0] = axisDirection[0]*x[0] + axisDirection[1]*sign2*sin(alpha)*ri + axisDirection[2]*sign1*cos(alpha)*ri;
si[1] = axisDirection[0]*sign1*cos(alpha)*ri + axisDirection[1]*x[1] + axisDirection[2]*sign2*sin(alpha)*ri;
si[2] = axisDirection[0]*sign2*sin(alpha)*ri + axisDirection[1]*sign1*cos(alpha)*ri + axisDirection[2]*x[2];
so[0] = axisDirection[0]*x[0] + axisDirection[1]*sign2*sin(alpha)*ro + axisDirection[2]*sign1*cos(alpha)*ro;
so[1] = axisDirection[0]*sign1*cos(alpha)*ro + axisDirection[1]*x[1] + axisDirection[2]*sign2*sin(alpha)*ro;
so[2] = axisDirection[0]*sign2*sin(alpha)*ro + axisDirection[1]*sign1*cos(alpha)*ro + axisDirection[2]*x[2];
}
//Compute difference of intersections in all directions
L[0] = so[0]-si[0];
L[1] = so[1]-si[1];
L[2] = so[2]-si[2];
bool b0 = (L[0] == 0.);
bool b1 = (L[1] == 0.);
bool b2 = (L[2] == 0.);
output[0] = ((axisDirection[1]*(axisPoint[2]-si[2]) - axisDirection[2]*(axisPoint[1]-si[1])) *
(1 - (axisDirection[1]*(x[2]-si[2])/(L[2]+b2) + axisDirection[2]*(x[1]-si[1])/(L[1]+b1))) )*w*scale;
output[1] = ((axisDirection[2]*(axisPoint[0]-si[0]) - axisDirection[0]*(axisPoint[2]-si[2])) *
(1 - (axisDirection[2]*(x[0]-si[0])/(L[0]+b0) + axisDirection[0]*(x[2]-si[2])/(L[2]+b2))) )*w*scale;
output[2] = ((axisDirection[0]*(axisPoint[1]-si[1]) - axisDirection[1]*(axisPoint[0]-si[0])) *
(1 - (axisDirection[0]*(x[1]-si[1])/(L[1]+b1) + axisDirection[1]*(x[0]-si[0])/(L[0]+b0))) )*w*scale;
}
return true;
}
template
RotatingQuadratic1D::RotatingQuadratic1D(std::vector axisPoint_,
std::vector axisDirection_, T w_, T scale_, T additive_)
: AnalyticalF3D(1), w(w_), scale(scale_), additive(additive_)
{
axisPoint.resize(3);
axisDirection.resize(3);
for (int i = 0; i < 3; ++i) {
axisPoint[i] = axisPoint_[i];
axisDirection[i] = axisDirection_[i];
}
}
template
bool RotatingQuadratic1D::operator()(T output[], const T x[])
{
T radiusSquared = ((x[1]-axisPoint[1])*(x[1]-axisPoint[1])
+(x[2]-axisPoint[2])*(x[2]-axisPoint[2]))*axisDirection[0]
+ ((x[0]-axisPoint[0])*(x[0]-axisPoint[0])
+(x[2]-axisPoint[2])*(x[2]-axisPoint[2]))*axisDirection[1]
+ ((x[1]-axisPoint[1])*(x[1]-axisPoint[1])
+(x[0]-axisPoint[0])*(x[0]-axisPoint[0]))*axisDirection[2];
output[0] = scale*w*w/2*radiusSquared+additive;
return true;
}
template
CirclePowerLaw3D::CirclePowerLaw3D(std::vector center, std::vector normal,
T maxVelocity, T radius, T n, T scale)
: AnalyticalF3D(3), _center(center), _normal(util::normalize(normal)),
_radius(radius), _maxVelocity(maxVelocity), _n(n), _scale(scale) { }
template
CirclePowerLaw3D::CirclePowerLaw3D(T center0, T center1, T center2, T normal0, T normal1, T normal2, T radius, T maxVelocity, T n, T scale )
: AnalyticalF3D(3), _radius(radius), _maxVelocity(maxVelocity), _n(n), _scale(scale)
{
_center.push_back(center0);
_center.push_back(center1);
_center.push_back(center2);
std::vector normalTmp;
normalTmp.push_back(normal0);
normalTmp.push_back(normal1);
normalTmp.push_back(normal2 );
_normal = normalTmp;
}
template
CirclePowerLaw3D::CirclePowerLaw3D(SuperGeometry3D& superGeometry,
int material, T maxVelocity, T n, T scale)
: AnalyticalF3D(3), _maxVelocity(maxVelocity), _n(n), _scale(scale)
{
_center = superGeometry.getStatistics().getCenterPhysR(material);
std::vector normalTmp;
normalTmp.push_back(superGeometry.getStatistics().computeDiscreteNormal(material)[0]);
normalTmp.push_back(superGeometry.getStatistics().computeDiscreteNormal(material)[1]);
normalTmp.push_back(superGeometry.getStatistics().computeDiscreteNormal(material)[2]);
_normal = util::normalize(normalTmp);
// div. by 2 since one of the discrete redius directions is always 0 while the two other are not
_radius = T();
for (int iD = 0; iD < 3; iD++) {
_radius += superGeometry.getStatistics().getPhysRadius(material)[iD]/2.;
}
}
template
CirclePowerLaw3D::CirclePowerLaw3D(bool useMeanVelocity, std::vector axisPoint, std::vector axisDirection, T Velocity, T radius, T n, T scale)
: CirclePowerLaw3D(axisPoint, axisDirection, Velocity, radius, n, scale)
{
if (useMeanVelocity) {
_maxVelocity = (2. + (1. + n)/n)/((1. + n)/n * pow(1.,(2. + (1. + n)/n))) * Velocity;
}
}
template
CirclePowerLaw3D::CirclePowerLaw3D(bool useMeanVelocity, T center0, T center1, T center2, T normal0, T normal1, T normal2, T radius, T Velocity, T n, T scale)
: CirclePowerLaw3D(center0, center1, center2, normal0, normal1, normal2, radius, Velocity, n, scale)
{
if (useMeanVelocity) {
_maxVelocity = (2. + (1. + n)/n)/((1. + n)/n * pow(1.,(2. + (1. + n)/n))) * Velocity;
}
}
template
CirclePowerLaw3D::CirclePowerLaw3D(bool useMeanVelocity, SuperGeometry3D& superGeometry, int material, T Velocity, T n, T scale)
: CirclePowerLaw3D(superGeometry, material, Velocity, n, scale)
{
if (useMeanVelocity) {
_maxVelocity = (2. + (1. + n)/n)/((1. + n)/n * pow(1.,(2. + (1. + n)/n))) * Velocity;
}
}
template
bool CirclePowerLaw3D::operator()(T output[], const T x[])
{
output[0] = _scale*_maxVelocity*_normal[0]*(1.-pow(sqrt((x[1]-_center[1])*(x[1]-_center[1])+(x[2]-_center[2])*(x[2]-_center[2]))/_radius, (_n + 1.)/_n));
output[1] = _scale*_maxVelocity*_normal[1]*(1.-pow(sqrt((x[0]-_center[0])*(x[0]-_center[0])+(x[2]-_center[2])*(x[2]-_center[2]))/_radius, (_n + 1.)/_n));
output[2] = _scale*_maxVelocity*_normal[2]*(1.-pow(sqrt((x[1]-_center[1])*(x[1]-_center[1])+(x[0]-_center[0])*(x[0]-_center[0]))/_radius, (_n + 1.)/_n));
return true;
}
template
CirclePowerLawTurbulent3D::CirclePowerLawTurbulent3D(std::vector center, std::vector normal,
T maxVelocity, T radius, T n, T scale)
: CirclePowerLaw3D(center, normal, maxVelocity, radius, n, scale) { }
template
CirclePowerLawTurbulent3D::CirclePowerLawTurbulent3D(T center0, T center1, T center2, T normal0,
T normal1, T normal2, T radius, T maxVelocity, T n, T scale)
: CirclePowerLaw3D(center0, center1, center2, normal0, normal1, normal2, radius, maxVelocity, n, scale) { }
template
CirclePowerLawTurbulent3D::CirclePowerLawTurbulent3D(SuperGeometry3D& superGeometry,
int material, T maxVelocity, T n, T scale)
: CirclePowerLaw3D(superGeometry, material, maxVelocity, n, scale) { }
template
CirclePowerLawTurbulent3D::CirclePowerLawTurbulent3D(bool useMeanVelocity, std::vector axisPoint, std::vector axisDirection, T Velocity, T radius, T n, T scale)
: CirclePowerLawTurbulent3D(axisPoint, axisDirection, Velocity, radius, n, scale)
{
if (useMeanVelocity) {
this->_maxVelocity = ((1. + 1./n) * (2. + 1./n)) / 2. * Velocity;
}
}
template
CirclePowerLawTurbulent3D::CirclePowerLawTurbulent3D(bool useMeanVelocity, T center0, T center1, T center2, T normal0, T normal1, T normal2, T radius, T Velocity, T n, T scale)
: CirclePowerLawTurbulent3D(center0, center1, center2, normal0, normal1, normal2, radius, Velocity, n, scale)
{
if (useMeanVelocity) {
this->_maxVelocity = ((1. + 1./n) * (2. + 1./n)) / 2. * Velocity;
}
}
template
CirclePowerLawTurbulent3D::CirclePowerLawTurbulent3D(bool useMeanVelocity, SuperGeometry3D& superGeometry, int material, T Velocity, T n, T scale)
: CirclePowerLawTurbulent3D(superGeometry, material, Velocity, n, scale)
{
if (useMeanVelocity) {
this->_maxVelocity = ((1. + 1./n) * (2. + 1./n)) / 2. * Velocity;
}
}
template
bool CirclePowerLawTurbulent3D::operator()(T output[], const T x[])
{
if ( 1.-sqrt((x[1]-this->_center[1])*(x[1]-this->_center[1])+(x[2]-this->_center[2])*(x[2]-this->_center[2]))/this->_radius < 0.) {
output[0] = T();
} else {
output[0] = this->_scale*this->_maxVelocity*this->_normal[0]*
(pow(1.-sqrt((x[1]-this->_center[1])*(x[1]-this->_center[1])+(x[2]-this->_center[2])*(x[2]-this->_center[2]))/this->_radius, 1./this->_n));
}
if ( 1.-sqrt((x[0]-this->_center[0])*(x[0]-this->_center[0])+(x[2]-this->_center[2])*(x[2]-this->_center[2]))/this->_radius < 0.) {
output[1] = T();
} else {
output[1] = this->_scale*this->_maxVelocity*this->_normal[1]*
(pow(1.-sqrt((x[0]-this->_center[0])*(x[0]-this->_center[0])+(x[2]-this->_center[2])*(x[2]-this->_center[2]))/this->_radius, 1./this->_n));
}
if ( 1.-sqrt((x[1]-this->_center[1])*(x[1]-this->_center[1])+(x[0]-this->_center[0])*(x[0]-this->_center[0]))/this->_radius < 0.) {
output[2] = T();
} else {
output[2] = this->_scale*this->_maxVelocity*this->_normal[2]*
(pow(1.-sqrt((x[1]-this->_center[1])*(x[1]-this->_center[1])+(x[0]-this->_center[0])*(x[0]-this->_center[0]))/this->_radius, 1./this->_n));
}
return true;
}
template
CirclePoiseuille3D::CirclePoiseuille3D(std::vector center, std::vector normal,
T maxVelocity, T radius, T scale)
: CirclePowerLaw3D(center, normal, maxVelocity, radius, 1., scale) { }
template
CirclePoiseuille3D::CirclePoiseuille3D(T center0, T center1, T center2, T normal0,
T normal1, T normal2, T radius, T maxVelocity, T scale)
: CirclePowerLaw3D(center0, center1, center2, normal0, normal1, normal2, radius, maxVelocity, 1., scale) { }
template
CirclePoiseuille3D::CirclePoiseuille3D(SuperGeometry3D& superGeometry,
int material, T maxVelocity, T scale)
: CirclePowerLaw3D(superGeometry, material, maxVelocity, 1., scale) { }
template
CirclePoiseuille3D::CirclePoiseuille3D(bool useMeanVelocity, std::vector axisPoint, std::vector axisDirection, T Velocity, T radius, T scale)
: CirclePoiseuille3D(axisPoint, axisDirection, Velocity, radius, scale)
{
if (useMeanVelocity) {
this->_maxVelocity = 2. * Velocity;
}
}
template
CirclePoiseuille3D::CirclePoiseuille3D(bool useMeanVelocity, T center0, T center1, T center2, T normal0, T normal1, T normal2, T radius, T Velocity, T scale)
: CirclePoiseuille3D(center0, center1, center2, normal0, normal1, normal2, radius, Velocity, scale)
{
if (useMeanVelocity) {
this->_maxVelocity = 2. * Velocity;
}
}
template
CirclePoiseuille3D::CirclePoiseuille3D(bool useMeanVelocity, SuperGeometry3D& superGeometry, int material, T Velocity, T scale)
: CirclePoiseuille3D(superGeometry, material, Velocity, scale)
{
if (useMeanVelocity) {
this->_maxVelocity = 2. * Velocity;
}
}
template < typename T,typename DESCRIPTOR>
CirclePoiseuilleStrainRate3D::CirclePoiseuilleStrainRate3D(UnitConverter const& converter, T ly) : AnalyticalF3D(9)
{
lengthY = ly;
lengthZ = ly;
maxVelocity = converter.getCharPhysVelocity();
this->getName() = "CirclePoiseuilleStrainRate3D";
}
template < typename T,typename DESCRIPTOR>
bool CirclePoiseuilleStrainRate3D::operator()(T output[], const T input[])
{
T y = input[1];
T z = input[2];
T DuDx = T();
T DuDy = (T) maxVelocity*(-2.*(y-(lengthY))/((lengthY)*(lengthY)));
T DuDz = (T) maxVelocity*(-2.*(z-(lengthZ))/((lengthZ)*(lengthZ)));
T DvDx = T();
T DvDy = T();
T DvDz = T();
T DwDx = T();
T DwDy = T();
T DwDz = T();
output[0] = (DuDx + DuDx)/2.;
output[1] = (DuDy + DvDx)/2.;
output[2] = (DuDz + DwDx)/2.;
output[3] = (DvDx + DuDy)/2.;
output[4] = (DvDy + DvDy)/2.;
output[5] = (DvDz + DwDy)/2.;
output[6] = (DwDx + DuDz)/2.;
output[7] = (DwDy + DvDz)/2.;
output[8] = (DwDz + DwDz)/2.;
return true;
};
template
RectanglePoiseuille3D::RectanglePoiseuille3D(std::vector& x0_, std::vector& x1_,
std::vector& x2_, std::vector& maxVelocity_)
: AnalyticalF3D(3), clout(std::cout,"RectanglePoiseille3D"), x0(x0_), x1(x1_),
x2(x2_), maxVelocity(maxVelocity_) { }
template
RectanglePoiseuille3D::RectanglePoiseuille3D(SuperGeometry3D& superGeometry_,
int material_, std::vector& maxVelocity_, T offsetX, T offsetY, T offsetZ)
: AnalyticalF3D(3), clout(std::cout, "RectanglePoiseuille3D"), maxVelocity(maxVelocity_)
{
std::vector min = superGeometry_.getStatistics().getMinPhysR(material_);
std::vector max = superGeometry_.getStatistics().getMaxPhysR(material_);
// set three corners of the plane, move by offset to land on the v=0
// boundary and adapt certain values depending on the orthogonal axis to get
// different points
x0 = min;
x1 = min;
x2 = min;
if ( util::nearZero(max[0]-min[0]) ) { // orthogonal to x-axis
x0[1] -= offsetY;
x0[2] -= offsetZ;
x1[1] -= offsetY;
x1[2] -= offsetZ;
x2[1] -= offsetY;
x2[2] -= offsetZ;
x1[1] = max[1] + offsetY;
x2[2] = max[2] + offsetZ;
} else if ( util::nearZero(max[1]-min[1]) ) { // orthogonal to y-axis
x0[0] -= offsetX;
x0[2] -= offsetZ;
x1[0] -= offsetX;
x1[2] -= offsetZ;
x2[0] -= offsetX;
x2[2] -= offsetZ;
x1[0] = max[0] + offsetX;
x2[2] = max[2] + offsetZ;
} else if ( util::nearZero(max[2]-min[2]) ) { // orthogonal to z-axis
x0[0] -= offsetX;
x0[1] -= offsetY;
x1[0] -= offsetX;
x1[1] -= offsetY;
x2[0] -= offsetX;
x2[1] -= offsetY;
x1[0] = max[0] + offsetX;
x2[1] = max[1] + offsetY;
} else {
clout << "Error: constructor from material number works only for axis-orthogonal planes" << std::endl;
}
}
template
bool RectanglePoiseuille3D::operator()(T output[], const T x[])
{
std::vector velocity(3,T());
// create plane normals and supports, (E1,E2) and (E3,E4) are parallel
std::vector > n(4,std::vector(3,0)); // normal vectors
std::vector > s(4,std::vector(3,0)); // support vectors
for (int iD = 0; iD < 3; iD++) {
n[0][iD] = x1[iD] - x0[iD];
n[1][iD] = -x1[iD] + x0[iD];
n[2][iD] = x2[iD] - x0[iD];
n[3][iD] = -x2[iD] + x0[iD];
s[0][iD] = x0[iD];
s[1][iD] = x1[iD];
s[2][iD] = x0[iD];
s[3][iD] = x2[iD];
}
for (int iP = 0; iP < 4; iP++) {
n[iP] = util::normalize(n[iP]);
}
// determine plane coefficients in the coordinate equation E_i: Ax+By+Cz+D=0
// given form: (x-s)*n=0 => A=n1, B=n2, C=n3, D=-(s1n1+s2n2+s3n3)
std::vector A(4,0);
std::vector B(4,0);
std::vector C(4,0);
std::vector D(4,0);
for (int iP = 0; iP < 4; iP++) {
A[iP] = n[iP][0];
B[iP] = n[iP][1];
C[iP] = n[iP][2];
D[iP] = -(s[iP][0]*n[iP][0] + s[iP][1]*n[iP][1] + s[iP][2]*n[iP][2]);
}
// determine distance to the walls by formula
std::vector d(4,0);
T aabbcc(0);
for (int iP = 0; iP < 4; iP++) {
aabbcc = A[iP]*A[iP] + B[iP]*B[iP] + C[iP]*C[iP];
d[iP] = fabs(A[iP]*x[0]+B[iP]*x[1]+C[iP]*x[2]+D[iP])*pow(aabbcc,-0.5);
}
// length and width of the rectangle
std::vector l(2,0);
l[0] = d[0] + d[1];
l[1] = d[2] + d[3];
T positionFactor = 16.*d[0]/l[0]*d[1]/l[0]*d[2]/l[1]*d[3]/l[1]; // between 0 and 1
output[0] = maxVelocity[0]*positionFactor;
output[1] = maxVelocity[1]*positionFactor;
output[2] = maxVelocity[2]*positionFactor;
return true;
}
template
EllipticPoiseuille3D::EllipticPoiseuille3D(std::vector center, T a, T b, T maxVel)
: AnalyticalF3D(3), clout(std::cout, "EllipticPoiseuille3D"), _center(center),
_a2(a*a), _b2(b*b), _maxVel(maxVel) { }
template
bool EllipticPoiseuille3D::operator()(T output[], const T x[])
{
T cosOmega2 = std::pow(x[0]-_center[0],2.)/(std::pow(x[0]-_center[0],2.)+std::pow(x[1]-_center[1],2.));
T rad2 = _a2*_b2 /((_b2-_a2)*cosOmega2 + _a2) ;
T x2 = (std::pow(x[0]-_center[0],2.)+std::pow(x[1]-_center[1],2.))/rad2;
// clout << _center[0] << " " << _center[1] << " " << x[0] << " " << x[1] << " " << std::sqrt(rad2) << " " << std::sqrt(std::pow(x[0]-_center[0],2.)+std::pow(x[1]-_center[1],2.)) << " " << x2 << std::endl;
output[0] = 0.;
output[1] = 0.;
output[2] = _maxVel*(-x2+1);
if ( util::nearZero(_center[0]-x[0]) && util::nearZero(_center[1]-x[1]) ) {
output[2] = _maxVel;
}
return true;
}
template
AnalyticalPorousVelocity3D::AnalyticalPorousVelocity3D(SuperGeometry3D& superGeometry, int material, T K_, T mu_, T gradP_, T radius_, T eps_)
: AnalyticalF3D(3), K(K_), mu(mu_), gradP(gradP_), radius(radius_), eps(eps_)
{
this->getName() = "AnalyticalPorousVelocity3D";
center = superGeometry.getStatistics().getCenterPhysR(material);
std::vector normalTmp;
normalTmp.push_back(superGeometry.getStatistics().computeDiscreteNormal(material)[0]);
normalTmp.push_back(superGeometry.getStatistics().computeDiscreteNormal(material)[1]);
normalTmp.push_back(superGeometry.getStatistics().computeDiscreteNormal(material)[2]);
normal = util::normalize(normalTmp);
};
template
T AnalyticalPorousVelocity3D::getPeakVelocity()
{
T uMax = K / mu*gradP*(1. - 1./(cosh((sqrt(1./K))*radius)));
return uMax/eps;
};
template
bool AnalyticalPorousVelocity3D::operator()(T output[], const T x[])
{
T dist[3] = {};
dist[0] = normal[0]*sqrt((x[1]-center[1])*(x[1]-center[1])+(x[2]-center[2])*(x[2]-center[2]));
dist[1] = normal[1]*sqrt((x[0]-center[0])*(x[0]-center[0])+(x[2]-center[2])*(x[2]-center[2]));
dist[2] = normal[2]*sqrt((x[1]-center[1])*(x[1]-center[1])+(x[0]-center[0])*(x[0]-center[0]));
output[0] = K / mu*gradP*(1. - (cosh((sqrt(1./K))*(dist[0])))/(cosh((sqrt(1./K))*radius)));
output[1] = K / mu*gradP*(1. - (cosh((sqrt(1./K))*(dist[1])))/(cosh((sqrt(1./K))*radius)));
output[2] = K / mu*gradP*(1. - (cosh((sqrt(1./K))*(dist[2])))/(cosh((sqrt(1./K))*radius)));
output[0] *= normal[0]/eps;
output[1] *= normal[1]/eps;
output[2] *= normal[2]/eps;
return true;
};
////////////////////////// Coordinate Transformation ////////////////
// constructor defines _referenceVector to obtain angle between 2 vectors,
// vector x has to be turned by angle in mathematical positive sense depending
// to _orientation to lie over _referenceVector
template
AngleBetweenVectors3D::AngleBetweenVectors3D(
std::vector referenceVector, std::vector orientation)
: AnalyticalF3D(1),
_referenceVector(referenceVector),
_orientation(orientation)
{
this->getName() = "const";
}
// operator returns angle between vectors x and _referenceVector
template
bool AngleBetweenVectors3D::operator()(T output[], const S x[])
{
Vector n_x;
Vector orientation(_orientation);
T angle = T(0);
if ( util::nearZero(x[0]) && util::nearZero(x[1]) && util::nearZero(x[2]) ) {
// if (abs(x[0]) + abs(x[1]) + abs(x[2]) == T()) {
output[0] = angle; // angle = 0
return true;
} else {
//Vector x_tmp(x); // check construction
n_x[0] = x[0];
n_x[1] = x[1];
n_x[2] = x[2];
n_x.normalize();
}
Vector n_ref(_referenceVector);
n_ref.normalize();
Vector cross = crossProduct3D(n_x, n_ref);
T n_dot = n_x * n_ref;
if ( util::nearZero(cross*orientation) ) {
// std::cout<< "orientation in same plane as x and refvector" << std::endl;
}
// angle = Pi, if n_x, n_ref opposite
if ( util::nearZero(n_x[0]+n_ref[0]) && util::nearZero(n_x[1]+n_ref[1]) && util::nearZero(n_x[2]+n_ref[2]) ) {
angle = acos(-1);
}
// angle = 0, if n_x, n_ref equal
else if ( util::nearZero(n_x[0]-n_ref[0]) && util::nearZero(n_x[1]-n_ref[1]) && util::nearZero(n_x[2]-n_ref[2]) ) {
angle = T();
}
// angle in (0,Pi) or (Pi,2Pi), if n_x, n_ref not opposite or equal
else {
Vector n_cross(cross);
n_cross.normalize();
T normal = cross.norm();
Vector n_orient;
if ( !util::nearZero(orientation.norm()) ) {
n_orient = orientation;
n_orient.normalize();
} else {
std::cout << "orientation vector does not fit" << std::endl;
}
if ((cross * orientation) > T()) {
angle = 2*M_PI - atan2(normal, n_dot);
}
if ((cross * orientation) < T()) {
angle = atan2(normal, n_dot);
}
}
output[0] = angle;
return true;
}
// constructor to obtain rotation round an _rotAxisDirection with angle _alpha
// and _origin
template
RotationRoundAxis3D::RotationRoundAxis3D(std::vector origin,
std::vector rotAxisDirection, T alpha)
: AnalyticalF3D(3),
_origin(origin),
_rotAxisDirection(rotAxisDirection),
_alpha(alpha)
{
this->getName() = "const";
}
// operator returns coordinates of the resulting point after rotation of x
// with _alpha in math positive sense to _rotAxisDirection through _origin
template
bool RotationRoundAxis3D::operator()(T output[], const S x[])
{
Vector n(_rotAxisDirection);
if ( !util::nearZero(n.norm()) && n.norm() > 0 ) {
//std::cout<< "Rotation axis: " << _rotAxisDirection[0] << " " << _rotAxisDirection[1] << " " << _rotAxisDirection[2] << std::endl;
n.normalize();
// translation
Vector x_tmp;
for (int i = 0; i < 3; ++i) {
x_tmp[i] = x[i] - _origin[i];
}
// rotation
output[0] = (n[0]*n[0]*(1 - cos(_alpha)) + cos(_alpha)) * x_tmp[0]
+ (n[0]*n[1]*(1 - cos(_alpha)) - n[2]*sin(_alpha))*x_tmp[1]
+ (n[0]*n[2]*(1 - cos(_alpha)) + n[1]*sin(_alpha))*x_tmp[2]
+ _origin[0];
output[1] = (n[1]*n[0]*(1 - cos(_alpha)) + n[2]*sin(_alpha))*x_tmp[0]
+ (n[1]*n[1]*(1 - cos(_alpha)) + cos(_alpha))*x_tmp[1]
+ (n[1]*n[2]*(1 - cos(_alpha)) - n[0]*sin(_alpha))*x_tmp[2]
+ _origin[1];
output[2] = (n[2]*n[0]*(1 - cos(_alpha)) - n[1]*sin(_alpha))*x_tmp[0]
+ (n[2]*n[1]*(1 - cos(_alpha)) + n[0]*sin(_alpha))*x_tmp[1]
+ (n[2]*n[2]*(1 - cos(_alpha)) + cos(_alpha))*x_tmp[2]
+ _origin[2];
return true;
} else {
//std::cout<< "Axis is null or NaN" <
CylinderToCartesian3D::CylinderToCartesian3D(
std::vector cylinderOrigin)
: AnalyticalF3D(3),
_cylinderOrigin(cylinderOrigin)
{
this->getName() = "CylinderToCartesian3D";
}
// operator returns Cartesian coordinates of cylindrical coordinates,
// input is x[0] = radius, x[1] = phi, x[2] = z
template
bool CylinderToCartesian3D::operator()(T output[], const S x[])
{
PolarToCartesian2D pol2cart(_cylinderOrigin);
pol2cart(output,x);
output[2] = x[2];
return true;
}
// constructor to obtain cylindrical coordinates of Cartesian coordinates
template
CartesianToCylinder3D::CartesianToCylinder3D(
std::vector cartesianOrigin, T& angle, std::vector orientation)
: AnalyticalF3D(3),
_cartesianOrigin(cartesianOrigin),
_orientation(orientation)
{
// rotation with angle to (0,0,1)
std::vector origin(3,T());
T e3[3]= {T(),T(),T()};
e3[2] = T(1);
RotationRoundAxis3D rotRAxis(origin, orientation, angle);
T tmp[3] = {T(),T(),T()};
rotRAxis(tmp, e3);
std::vector htmp(tmp,tmp+3);
_axisDirection = htmp;
}
// constructor to obtain cylindrical coordinates of Cartesian coordinates
template
CartesianToCylinder3D::CartesianToCylinder3D(
std::vector cartesianOrigin, std::vector axisDirection,
std::vector orientation)
: AnalyticalF3D(3),
_cartesianOrigin(cartesianOrigin),
_axisDirection(axisDirection),
_orientation(orientation)
{
this->getName() = "const";
}
// constructor to obtain cylindrical coordinates of Cartesian coordinates
template
CartesianToCylinder3D::CartesianToCylinder3D(
T cartesianOriginX, T cartesianOriginY, T cartesianOriginZ,
T axisDirectionX, T axisDirectionY, T axisDirectionZ,
T orientationX, T orientationY, T orientationZ)
: AnalyticalF3D(3)
{
_cartesianOrigin.push_back(cartesianOriginX);
_cartesianOrigin.push_back(cartesianOriginY);
_cartesianOrigin.push_back(cartesianOriginZ);
_axisDirection.push_back(axisDirectionX);
_axisDirection.push_back(axisDirectionY);
_axisDirection.push_back(axisDirectionZ);
_orientation.push_back(orientationX);
_orientation.push_back(orientationY);
_orientation.push_back(orientationZ);
}
// operator returns cylindrical coordinates, output[0] = radius(>= 0),
// output[1] = phi in [0, 2Pi), output[2] = z
template
bool CartesianToCylinder3D::operator()(T output[], const S x[])
{
T x_rot[3] = {T(),T(),T()};
x_rot[0] = x[0];
x_rot[1] = x[1];
x_rot[2] = x[2];
// T x_rot[3] = {x[0], x[1], x[2]};
Vector e3(T(),T(), T(1));
Vector axisDirection(_axisDirection);
Vector orientation(_orientation);
Vector normal = crossProduct3D(axisDirection, e3);
Vector normalAxisDir(axisDirection);
normalAxisDir.normalize();
// if axis has to be rotated
if (!( util::nearZero(normalAxisDir[0]) && util::nearZero(normalAxisDir[1]) && util::nearZero(normalAxisDir[2]-1) )) {
if ( !util::nearZero(norm(orientation)) ) {
normal = orientation; // if _orientation = 0,0,0 -> segm. fault
}
AngleBetweenVectors3D angle(util::fromVector3(e3), util::fromVector3(normal));
T tmp[3] = {T(),T(),T()};
tmp[0] = axisDirection[0];
tmp[1] = axisDirection[1];
tmp[2] = axisDirection[2];
T alpha[1] = {T()};
angle(alpha, tmp);
// rotation with angle alpha to (0,0,1)
RotationRoundAxis3D rotRAxis(_cartesianOrigin, util::fromVector3(normal), -alpha[0]);
rotRAxis(x_rot, x);
}
CartesianToPolar2D car2pol(_cartesianOrigin, util::fromVector3(e3), _orientation);
T x_rot_help[2] = {T(),T()};
x_rot_help[0] = x_rot[0];
x_rot_help[1] = x_rot[1];
T output_help[2] = {T(),T()};
car2pol(output_help, x_rot_help);
output[0] = output_help[0];
output[1] = output_help[1];
output[2] = x_rot[2] - _cartesianOrigin[2];
return true; // output[0] = radius, output[1] = phi, output[2] = z
}
// Read only access to _axisDirection
template
std::vector const& CartesianToCylinder3D::getAxisDirection() const
{
return _axisDirection;
}
// Read and write access to _axisDirection
template
std::vector& CartesianToCylinder3D::getAxisDirection()
{
return _axisDirection;
}
// Read only access to _catesianOrigin
template
std::vector const& CartesianToCylinder3D::getCartesianOrigin() const
{
return _cartesianOrigin;
}
// Read and write access to _catesianOrigin
template
std::vector& CartesianToCylinder3D::getCartesianOrigin()
{
return _cartesianOrigin;
}
// Read and write access to _axisDirection using angle
template
void CartesianToCylinder3D::setAngle(T angle)
{
std::vector Null(3,T());
T e3[3] = {T(),T(),T()};
e3[2] = T(1);
RotationRoundAxis3D rotRAxis(Null, _orientation, angle);
T tmp[3] = {T(),T(),T()};
rotRAxis(tmp,e3);
for (int i=0; i<3; ++i) {
_axisDirection[i] = tmp[i];
}
}
////////// Spherical & Cartesian ///////////////
// constructor to obtain spherical coordinates of Cartesian coordinates
template
SphericalToCartesian3D::SphericalToCartesian3D()
//std::vector sphericalOrigin)
: AnalyticalF3D(3) //, _sphericalOrigin(sphericalOrigin)
{
this->getName() = "const";
}
// operator returns Cartesian coordinates of spherical coordinates
// (x[0] = radius, x[1] = phi, x[2] = theta)
// phi in x-y-plane, theta in x-z-plane, z axis as orientation
template
bool SphericalToCartesian3D::operator()(T output[], const S x[])
{
output[0] = x[0]*sin(x[2])*cos(x[1]);
output[1] = x[0]*sin(x[2])*sin(x[1]);
output[2] = x[0]*cos(x[2]);
return true;
}
template
CartesianToSpherical3D::CartesianToSpherical3D(
std::vector cartesianOrigin, std::vector axisDirection)
: AnalyticalF3D(3),
_cartesianOrigin(cartesianOrigin),
_axisDirection(axisDirection)
{
this->getName() = "const";
}
// operator returns spherical coordinates output[0] = radius(>= 0),
// output[1] = phi in [0, 2Pi), output[2] = theta in [0, Pi]
template
bool CartesianToSpherical3D::operator()(T output[], const S x[])
{
T x_rot[3] = {T(),T(),T()};
x_rot[0] = x[0];
x_rot[1] = x[1];
x_rot[2] = x[2];
Vector axisDirection(_axisDirection);
Vector e3(T(), T(), T(1));
Vector normal = crossProduct3D(axisDirection,e3);
Vector normalAxisDir = axisDirection;
normalAxisDir.normalize();
Vector cross;
// if axis has to be rotated
if ( !( util::nearZero(normalAxisDir[0]) && util::nearZero(normalAxisDir[1]) && util::nearZero(normalAxisDir[2]-1) ) ) {
AngleBetweenVectors3D angle(util::fromVector3(e3), util::fromVector3(normal));
T tmp[3] = {T(),T(),T()};
for (int i=0; i<3; ++i) {
tmp[i] = axisDirection[i];
}
T alpha[1] = {T(0)};
angle(alpha,tmp);
// cross is rotation axis
cross = crossProduct3D(e3, axisDirection);
// rotation with angle alpha to (0,0,1)
RotationRoundAxis3D rotRAxis(_cartesianOrigin, util::fromVector3(normal), -alpha[0]);
rotRAxis(x_rot,x);
}
CartesianToPolar2D car2pol(_cartesianOrigin, util::fromVector3(e3), util::fromVector3(cross));
// y[0] = car2pol(x_rot)[0];
Vector difference;
for (int i=0; i<3; ++i) {
difference[i] = x_rot[i] - _cartesianOrigin[i];
}
T distance = T();
for (int i = 0; i <= 2; ++i) {
distance += difference[i]*difference[i];
}
distance = sqrt(distance);
car2pol(output, x_rot);
output[0] = distance;
output[2] = acos(x[2]/output[0]); // angle between z-axis and r-vector
return true; // output[0] = radius, output[1] = phi, output[2] = theta
}
////////// Magnetic Field ///////////////
// Magnetic field that creates magnetization in wire has to be orthogonal to
// the wire. To calculate the magnetic force on particles around a cylinder
// (J. Lindner et al. / Computers and Chemical Engineering 54 (2013) 111-121)
// Fm = mu0*4/3.*PI*radParticle^3*_Mp*radWire^2/r^3 *
// [radWire^2/r^2+cos(2*theta), sin(2*theta), 0]
template
MagneticForceFromCylinder3D::MagneticForceFromCylinder3D(
CartesianToCylinder3D& car2cyl, T length, T radWire, T cutoff, T Mw, T Mp,
T radParticle, T mu0)
: AnalyticalF3D(3),
_car2cyl(car2cyl),
_length(length),
_radWire(radWire),
_cutoff(cutoff),
_Mw(Mw),
_Mp(Mp),
_radParticle(radParticle),
_mu0(mu0)
{
// Field direction H_0 parallel to fluid flow direction, if not: *(-1)
_factor = -_mu0*4/3*M_PI*pow(_radParticle, 3)*_Mp*_Mw*pow(_radWire, 2);
}
template
bool MagneticForceFromCylinder3D::operator()(T output[], const S x[])
{
Vector magneticForcePolar;
T outputTmp[3] = {T(), T(), T()};
Vector normalAxis(_car2cyl.getAxisDirection());
normalAxis.normalize();
Vector relPosition;
relPosition[0] = (x[0] - _car2cyl.getCartesianOrigin()[0]);
relPosition[1] = (x[1] - _car2cyl.getCartesianOrigin()[1]);
relPosition[2] = (x[2] - _car2cyl.getCartesianOrigin()[2]);
T tmp[3] = {T(),T(),T()};
_car2cyl(tmp,x);
T rad = tmp[0];
T phi = tmp[1];
T test = relPosition * normalAxis;
if ( (rad > _radWire && rad <= _cutoff*_radWire) &&
(T(0) <= test && test <= _length) ) {
magneticForcePolar[0] = _factor/pow(rad, 3)
*(pow(_radWire, 2)/pow(rad, 2) + cos(2*phi));
magneticForcePolar[1] = _factor/pow(rad, 3)*sin(2*phi);
// changes radial and angular force components to cartesian components.
outputTmp[0] = magneticForcePolar[0]*cos(phi)
- magneticForcePolar[1]*sin(phi);
outputTmp[1] = magneticForcePolar[0]*sin(phi)
+ magneticForcePolar[1]*cos(phi);
// if not in standard axis direction
if ( !( util::nearZero(normalAxis[0]) && util::nearZero(normalAxis[1]) && util::nearZero(normalAxis[2]-1) ) ) {
Vector e3(T(), T(), T(1));
Vector orientation =
crossProduct3D(Vector(_car2cyl.getAxisDirection()),e3);
AngleBetweenVectors3D angle(util::fromVector3(e3), util::fromVector3(orientation));
T alpha[1] = {T()};
T tmp2[3] = {T(),T(),T()};
for (int i = 0; i<3; ++i) {
tmp2[i] = _car2cyl.getAxisDirection()[i];
}
angle(alpha,tmp2);
std::vector origin(3, T());
RotationRoundAxis3D rotRAxis(origin, util::fromVector3(orientation), alpha[0]);
rotRAxis(output,outputTmp);
} else {
output[0] = outputTmp[0];
output[1] = outputTmp[1];
output[2] = T();
}
} else {
output[0] = outputTmp[0];
output[1] = outputTmp[1];
output[2] = outputTmp[1];
}
return true;
}
template
MagneticFieldFromCylinder3D::MagneticFieldFromCylinder3D(
CartesianToCylinder3D& car2cyl, T length, T radWire, T cutoff, T Mw
)
: AnalyticalF3D(3),
_car2cyl(car2cyl),
_length(length),
_radWire(radWire),
_cutoff(cutoff),
_Mw(Mw)
{
// Field direction H_0 parallel to fluid flow direction, if not: *(-1)
_factor = - _Mw * pow(_radWire, 2);
}
template