/* 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_H
#define FRAME_CHANGE_F_3D_H
#include
#include
#include "analyticalF.h"
/** \file
This file contains two different classes of functors, in the FIRST part
- for simulations in a rotating frame
- different functors for
velocity (3d, RotatingLinear3D),
pressure (1d, RotatingQuadratic1D) and
force (3d, RotatingForceField3D)
The functors return the displacement of a point x in a fixed amount of time.
The ones in the SECOND part are useful to set Poiseuille velocity profiles on
- pipes with round cross-section and
- pipes with square-shaped cross-section.
*/
/** To enable simulations in a rotating frame, the axis is set in the
* constructor with axisPoint and axisDirection. The axisPoint can be the
* coordinate of any point on the axis. The axisDirection has to be a normed to
* 1. The pulse w is in rad/s. It determines the pulse speed by its norm while
* the trigonometric or clockwise direction is determined by its sign: When the
* axisDirection is pointing "towards you", a positive pulse makes it turn in
* the trigonometric way. It has to be noticed that putting both axisDirection
* into -axisDirection and w into -w yields an exactly identical situation.
*/
namespace olb {
template class SuperGeometry3D;
// PART 1: /////////////////////////////////////////////////////////////////////
// Functors for rotating the coordinate system (velocity, pressure, force,...)
/**
* This functor gives a linar profile for a given point x as it computes
* the distance between x and the axis.
*
* The field in outcome is the velocity field of q rotating solid
*/
/// Functor with a linear profile e.g. for rotating velocity fields.
template
class RotatingLinear3D final : public AnalyticalF3D {
protected:
std::vector axisPoint;
std::vector axisDirection;
T w;
T scale;
public:
RotatingLinear3D(std::vector axisPoint_, std::vector axisDirection_, T w_, T scale_=1);
bool operator()(T output[], const T x[]) override;
};
/**
* This functor gives a linar profile in an annulus for a given point x between the inner and outer radius as it computes
* the distance between x and the inner and outer radius.
*
* The field in outcome is the velocity field of q rotating solid in an annulus
*/
/// Functor with a linear profile e.g. for rotating velocity fields.
template
class RotatingLinearAnnulus3D final : public AnalyticalF3D {
protected:
std::vector axisPoint;
std::vector axisDirection;
T w;
T ri;
T ro;
T scale;
public:
RotatingLinearAnnulus3D(std::vector axisPoint_, std::vector axisDirection_, T w_, T ri_, T ro_, T scale_=1);
bool operator()(T output[], const T x[]);
};
/**
* This functor gives a parabolic profile for a given point x as it computes
* the distance between x and the axis.
*
* This field is a scalar field, a vector with one component will be used
*/
/// Functor with a parabolic profile e.g. for rotating pressure fields.
template
class RotatingQuadratic1D final : public AnalyticalF3D {
protected:
std::vector axisPoint;
std::vector axisDirection;
T w;
T scale;
T additive;
public:
RotatingQuadratic1D(std::vector axisPoint_, std::vector axisDirection_,
T w_, T scale_=1, T additive_=0);
bool operator()(T output[], const T x[]) override;
};
// PART 2: /////////////////////////////////////////////////////////////////////
// Functors for setting velocities on a velocity boundary of a pipe
/**
* This functor returns a quadratic Poiseuille profile for use with a pipe with
* round cross-section. It uses cylinder coordinates and is valid for the
* entire length of the pipe.
*
* This functor gives a parabolic velocity profile for a given point x as it
* computes the distance between x and the axis.
*
* The axis is set in the input with axisPoint and axisDirection. The axisPoint
* can be the coordinate of any point where the axis passes.
* axisDirection has to be normed to 1.
* Once the axis is set in the middle of the pipe, the radius of the
* pipe "radius" and the velocity in the middle of the pipe "maxVelocity"
* determine the Poisseuille profile entierly.
*/
/// Velocity profile for round pipes and power law fluids: u(r)=u_max*(1-(r/R)^((n+1)/n)). The exponent n characterizes the fluid behavior.
/// n<1: Pseudoplastic, n=1: Newtonian fluid, n>1: Dilatant
template
class CirclePowerLaw3D : public AnalyticalF3D {
protected:
std::vector _center;
std::vector _normal;
T _radius;
T _maxVelocity;
T _n;
T _scale;
public:
CirclePowerLaw3D(std::vector axisPoint, std::vector axisDirection, T maxVelocity, T radius, T n, T scale = T(1));
CirclePowerLaw3D(T center0, T center1, T center2, T normal0, T normal1, T normal2, T radius, T maxVelocity, T n, T scale = T(1));
CirclePowerLaw3D(SuperGeometry3D& superGeometry, int material, T maxVelocity, T n, T scale = T(1));
CirclePowerLaw3D(bool useMeanVelocity, std::vector axisPoint, std::vector axisDirection, T Velocity, T radius, T n, T scale = T(1));
CirclePowerLaw3D(bool useMeanVelocity, T center0, T center1, T center2, T normal0, T normal1, T normal2, T radius, T Velocity, T n, T scale = T(1));
CirclePowerLaw3D(bool useMeanVelocity, SuperGeometry3D& superGeometry, int material, T Velocity, T n, T scale = T(1));
/// Returns centerpoint vector
std::vector getCenter()
{
return _center;
};
/// Returns normal vector
std::vector getNormal()
{
return _normal;
};
/// Returns radi
T getRadius()
{
return _radius;
};
bool operator()(T output[], const T x[]) override;
};
/// Velocity profile for round pipes and turbulent flows: u(r)=u_max*(1-r/R)^(1/n) The exponent n can be calculated by n = 1.03 * ln(Re) - 3.6
/// n=7 is used for many flow applications
template
class CirclePowerLawTurbulent3D : public CirclePowerLaw3D {
public:
CirclePowerLawTurbulent3D(std::vector axisPoint_, std::vector axisDirection, T maxVelocity, T radius, T n, T scale = T(1));
CirclePowerLawTurbulent3D(T center0, T center1, T center2, T normal0, T normal1, T normal2, T radius, T maxVelocity, T n, T scale = T(1));
CirclePowerLawTurbulent3D(SuperGeometry3D& superGeometry, int material, T maxVelocity, T n, T scale = T(1));
CirclePowerLawTurbulent3D(bool useMeanVelocity, std::vector axisPoint, std::vector axisDirection, T Velocity, T radius, T n, T scale = T(1));
CirclePowerLawTurbulent3D(bool useMeanVelocity, T center0, T center1, T center2, T normal0, T normal1, T normal2, T radius, T Velocity, T n, T scale = T(1));
CirclePowerLawTurbulent3D(bool useMeanVelocity, SuperGeometry3D& superGeometry, int material, T Velocity, T n, T scale = T(1));
bool operator()(T output[], const T x[]) override;
};
/// Velocity profile for round pipes and a laminar flow of a Newtonian fluid: u(r)=u_max*(1-(r/R)^2)
template
class CirclePoiseuille3D final : public CirclePowerLaw3D {
public:
CirclePoiseuille3D(std::vector axisPoint, std::vector axisDirection, T maxVelocity, T radius, T scale = T(1));
CirclePoiseuille3D(T center0, T center1, T center2, T normal0, T normal1, T normal2, T radius, T maxVelocity, T scale = T(1));
CirclePoiseuille3D(SuperGeometry3D& superGeometry, int material, T maxVelocity, T scale = T(1));
CirclePoiseuille3D(bool useMeanVelocity, std::vector axisPoint, std::vector axisDirection, T Velocity, T radius, T scale = T(1));
CirclePoiseuille3D(bool useMeanVelocity, T center0, T center1, T center2, T normal0, T normal1, T normal2, T radius, T Velocity, T scale = T(1));
CirclePoiseuille3D(bool useMeanVelocity, SuperGeometry3D& superGeometry, int material, T Velocity, T scale = T(1));
};
/// Strain rate for round pipes and laminar flow of a Newtonian fluid
template < typename T,typename DESCRIPTOR>
class CirclePoiseuilleStrainRate3D : public AnalyticalF3D {
protected:
T lengthY;
T lengthZ;
T maxVelocity;
public:
CirclePoiseuilleStrainRate3D(UnitConverter const& converter, T ly);
bool operator()(T output[], const T input[]);
};
/**
This functor returns a Poiseuille profile for use with a pipe with square shaped cross-section.
*/
/// velocity profile for pipes with rectangular cross-section.
template
class RectanglePoiseuille3D final : public AnalyticalF3D {
protected:
OstreamManager clout;
std::vector x0;
std::vector x1;
std::vector x2;
std::vector maxVelocity;
public:
RectanglePoiseuille3D(std::vector& x0_, std::vector& x1_, std::vector& x2_, std::vector& maxVelocity_);
/// constructor from material numbers
/** offsetX,Y,Z is a positive number denoting the distance from border
* voxels of material_ to the zerovelocity boundary */
RectanglePoiseuille3D(SuperGeometry3D& superGeometry_, int material_, std::vector& maxVelocity_, T offsetX, T offsetY, T offsetZ);
bool operator()(T output[], const T x[]) override;
};
/**
* This functor returns a quadratic Poiseuille profile for use with a pipe with
* elliptic cross-section.
*
* Ellpise is orthogonal to z-direction.
* a is in x-direction
* b is in y-direction
*
*/
/// Velocity profile for round pipes.
template
class EllipticPoiseuille3D final : public AnalyticalF3D {
protected:
OstreamManager clout;
std::vector _center;
T _a2, _b2;
T _maxVel;
public:
EllipticPoiseuille3D(std::vector center, T a, T b, T maxVel);
bool operator()(T output[], const T x[]) override;
};
/// Analytical solution of porous media channel flow with low Reynolds number
/// See Spaid and Phelan (doi:10.1063/1.869392)
template
class AnalyticalPorousVelocity3D : public AnalyticalF3D {
protected:
std::vector center;
std::vector normal;
T K, mu, gradP, radius;
T eps;
public:
AnalyticalPorousVelocity3D(SuperGeometry3D& superGeometry, int material, T K_, T mu_, T gradP_, T radius_, T eps_=T(1));
T getPeakVelocity();
bool operator()(T output[], const T input[]) override;
};
////////////////Coordinate Transformation//////////////
/// This class calculates the angle alpha between vector _referenceVector and
/// any other vector x.
/// Vector x has to be turned by alpha in mathematical positive sense depending
/// to _orientation to lie over vector _referenceVector
template
class AngleBetweenVectors3D final : public AnalyticalF3D {
protected:
/// between _referenceVector and vector x, angle is calculated
std::vector _referenceVector;
/// direction around which x has to be turned with angle is in math pos sense
/// to lie over _referenceVector
std::vector _orientation;
public:
/// constructor defines _referenceVector and _orientation
AngleBetweenVectors3D(std::vector referenceVector,
std::vector orientation);
/// operator writes angle between x and _referenceVector inro output field
bool operator()(T output[], const S x[]) override;
};
/// This class saves coordinates of the resulting point after rotation in the
/// output field. The resulting point is achieved after rotation of x with
/// angle _alpha in math positive sense relative to _rotAxisDirection with a
/// given _origin.
template
class RotationRoundAxis3D final : public AnalyticalF3D {
protected:
/// origin, around which x is turned
std::vector _origin;
/// direction, around which x is turned
std::vector _rotAxisDirection;
/// angle, by which vector x is rotated around _rotAxisDirection
T _alpha;
public:
/// constructor defines _rotAxisDirection, _alpha and _origin
RotationRoundAxis3D(std::vector origin, std::vector rotAxisDirection,
T alpha);
/// operator writes coordinates of the resulting point after rotation
/// of x by angle _alpha in math positive sense to _rotAxisDirection
/// with _origin into output field
bool operator()(T output[], const S x[]) override;
};
////////// Cylinder & Cartesian ///////////////
/// This class converts cylindrical of point x (x[0] = radius, x[1] = phi,
/// x[2] = z) to Cartesian coordinates (wrote into output field).
/// Initial situation for the Cartesian coordinate system is that angle phi
/// lies in the x-y-plane and turns round the _cylinderOrigin, the z-axis
/// direction equals the axis direction of the cylinder.
template
class CylinderToCartesian3D final : public AnalyticalF3D {
protected:
std::vector _cylinderOrigin;
public:
/// constructor defines _cylinderOrigin
CylinderToCartesian3D(std::vector cylinderOrigin);
/// operator writes Cartesian coordinates of cylinder coordinates
/// x[0] = radius >= 0, x[1] = phi in [0, 2*Pi), x[2] = z into output field
bool operator()(T output[], const S x[]) override;
};
/// This class converts Cartesian coordinates of point x to cylindrical
/// coordinates wrote into output field
/// (output[0] = radius, output[1] = phi, output[2] = z).
/// Initial situation for the cylindrical coordinate system is that angle phi
/// lies in plane perpendicular to the _axisDirection and turns around the
/// _cartesianOrigin. The radius is the distance of point x to the
/// _axisDirection and z the distance to _cartesianOrigin along _axisDirection.
template
class CartesianToCylinder3D final : public AnalyticalF3D {
protected:
/// origin of the Cartesian coordinate system
std::vector _cartesianOrigin;
/// direction of the axis along which the cylindrical coordinates are calculated
std::vector _axisDirection;
/// direction to know orientation for math positive to obtain angle phi
/// of Cartesian point x
std::vector _orientation;
public:
CartesianToCylinder3D(std::vector cartesianOrigin, T& angle,
std::vector orientation = {T(1),T(),T()});
CartesianToCylinder3D(std::vector cartesianOrigin,
std::vector axisDirection,
std::vector orientation = {T(1),T(),T()});
CartesianToCylinder3D(T cartesianOriginX, T cartesianOriginY,
T cartesianOriginZ,
T axisDirectionX, T axisDirectionY,
T axisDirectionZ,
T orientationX = T(1), T orientationY = T(),
T orientationZ = T());
/// operator writes cylindrical coordinates of Cartesian point x into output
/// field,
/// output[0] = radius ( >= 0), output[1] = phi (in [0, 2Pi)), output[2] = z
bool operator()(T output[], const S x[]) override;
/// Read only access to _axisDirection
std::vector const& getAxisDirection() const;
/// Read and write access to _axisDirection
std::vector& getAxisDirection();
/// Read only access to _catesianOrigin
std::vector const& getCartesianOrigin() const;
/// Read and write access to _catesianOrigin
std::vector& getCartesianOrigin();
/// Read and write access to _axisDirection using angle
void setAngle(T angle);
};
////////// Spherical & Cartesian ///////////////
/// This class converts spherical coordinates of point x
/// (x[0] = radius, x[1] = phi, x[2] = theta) to Cartesian coordinates wrote
/// into output field.
/// Initial situation for the Cartesian coordinate system is that angle phi
/// (phi in [0, 2Pi)) lies in x-y-plane and turns around the Cartesian origin
/// (0,0,0). Angle theta (theta in [0, Pi]) lies in y-z-plane. z axis equals
/// the _orientation of the spherical coordinate system.
/// The radius is distance of point x to the Cartesian _origin
template
class SphericalToCartesian3D final : public AnalyticalF3D {
//protected:
public:
SphericalToCartesian3D();
/// operator writes spherical coordinates of Cartesian coordinates of x
/// (x[0] = radius, x[1] = phi, x[2] = theta) into output field.
/// phi is in x-y-plane, theta in x-z-plane, z axis as orientation
bool operator()(T output[], const S x[]) override;
};
/// This class converts Cartesian coordinates of point x to spherical
/// coordinates wrote into output field
/// (output[0] = radius, output[1] = phi, output[2] = theta).
/// Initial situation for the spherical coordinate system is that angle phi
/// lies in x-y-plane and theta in x-z-plane.
/// The z axis is the orientation for the mathematical positive sense of phi.
template
class CartesianToSpherical3D final : public AnalyticalF3D {
protected:
/// origin of the Cartesian coordinate system
std::vector _cartesianOrigin;
/// direction of the axis along which the spherical coordinates are calculated
std::vector _axisDirection;
public:
CartesianToSpherical3D(std::vector cartesianOrigin,
std::vector axisDirection);//, std::vector orientation);
/// operator writes shperical coordinates of Cartesian point x into output
/// field,
/// output[0] = radius ( >= 0), output[1] = phi (in [0, 2Pi)),
/// output[2] = theta (in [0, Pi])
bool operator()(T output[], const S x[]) override;
};
////////// 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
class MagneticForceFromCylinder3D final : public AnalyticalF3D {
protected:
CartesianToCylinder3D& _car2cyl;
/// length of the wire, from origin to _car2cyl.axisDirection
T _length;
/// wire radius
T _radWire;
/// maximal distance from wire cutoff/threshold
T _cutoff;
/// saturation magnetization wire, linear scaling factor
T _Mw;
/// magnetization particle, linear scaling factor
T _Mp;
/// particle radius, cubic scaling factor
T _radParticle;
/// permeability constant, linear scaling factor
T _mu0;
/// factor = mu0*4/3.*PI*radParticle^3*_Mp*radWire^2/r^3
T _factor;
public:
MagneticForceFromCylinder3D(CartesianToCylinder3D& car2cyl, T length,
T radWire, T cutoff, T Mw, T Mp = T(1),
T radParticle = T(1), T mu0 = 4*3.14159265e-7);
/// operator writes the magnetic force in a point x round a cylindrical wire into output field
bool operator()(T output[], const S x[]) override;
};
template
class MagneticFieldFromCylinder3D final : public AnalyticalF3D {
protected:
CartesianToCylinder3D& _car2cyl;
/// length of the wire, from origin to _car2cyl.axisDirection
T _length;
/// wire radius
T _radWire;
/// maximal distance from wire cutoff/threshold
T _cutoff;
/// saturation magnetization wire, linear scaling factor
T _Mw;
/// factor = mu0*4/3.*PI*radParticle^3*_Mp*radWire^2/r^3
T _factor;
public:
MagneticFieldFromCylinder3D(CartesianToCylinder3D& car2cyl,
T length,
T radWire,
T cutoff,
T Mw
);
/// operator writes the magnetic force in a point x round a cylindrical wire into output field
bool operator()(T output[], const S x[]);
};
} // end namespace olb
#endif