summaryrefslogtreecommitdiff
path: root/src/functors/analytical/frameChangeF3D.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/functors/analytical/frameChangeF3D.hh')
-rw-r--r--src/functors/analytical/frameChangeF3D.hh1142
1 files changed, 1142 insertions, 0 deletions
diff --git a/src/functors/analytical/frameChangeF3D.hh b/src/functors/analytical/frameChangeF3D.hh
new file mode 100644
index 0000000..46934ce
--- /dev/null
+++ b/src/functors/analytical/frameChangeF3D.hh
@@ -0,0 +1,1142 @@
+/* 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
+ * <http://www.openlb.net/>
+ *
+ * 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<cmath>
+
+#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 <typename T>
+RotatingLinear3D<T>::RotatingLinear3D(std::vector<T> axisPoint_,
+ std::vector<T> axisDirection_, T w_, T scale_)
+ : AnalyticalF3D<T,T>(3), axisPoint(axisPoint_), axisDirection(axisDirection_),
+ w(w_), scale(scale_) { }
+
+
+template <typename T>
+bool RotatingLinear3D<T>::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 <typename T>
+RotatingLinearAnnulus3D<T>::RotatingLinearAnnulus3D(std::vector<T> axisPoint_,
+ std::vector<T> axisDirection_, T w_, T ri_, T ro_, T scale_)
+ : AnalyticalF3D<T,T>(3), axisPoint(axisPoint_), axisDirection(axisDirection_),
+ w(w_), ri(ri_), ro(ro_), scale(scale_) { }
+
+
+template <typename T>
+bool RotatingLinearAnnulus3D<T>::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 <typename T>
+RotatingQuadratic1D<T>::RotatingQuadratic1D(std::vector<T> axisPoint_,
+ std::vector<T> axisDirection_, T w_, T scale_, T additive_)
+ : AnalyticalF3D<T,T>(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 <typename T>
+bool RotatingQuadratic1D<T>::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 <typename T>
+CirclePowerLaw3D<T>::CirclePowerLaw3D(std::vector<T> center, std::vector<T> normal,
+ T maxVelocity, T radius, T n, T scale)
+ : AnalyticalF3D<T,T>(3), _center(center), _normal(util::normalize(normal)),
+ _radius(radius), _maxVelocity(maxVelocity), _n(n), _scale(scale) { }
+
+template <typename T>
+CirclePowerLaw3D<T>::CirclePowerLaw3D(T center0, T center1, T center2, T normal0, T normal1, T normal2, T radius, T maxVelocity, T n, T scale )
+ : AnalyticalF3D<T,T>(3), _radius(radius), _maxVelocity(maxVelocity), _n(n), _scale(scale)
+{
+ _center.push_back(center0);
+ _center.push_back(center1);
+ _center.push_back(center2);
+ std::vector<T> normalTmp;
+ normalTmp.push_back(normal0);
+ normalTmp.push_back(normal1);
+ normalTmp.push_back(normal2 );
+ _normal = normalTmp;
+}
+
+template <typename T>
+CirclePowerLaw3D<T>::CirclePowerLaw3D(SuperGeometry3D<T>& superGeometry,
+ int material, T maxVelocity, T n, T scale)
+ : AnalyticalF3D<T,T>(3), _maxVelocity(maxVelocity), _n(n), _scale(scale)
+{
+ _center = superGeometry.getStatistics().getCenterPhysR(material);
+ std::vector<T> 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 <typename T>
+CirclePowerLaw3D<T>::CirclePowerLaw3D(bool useMeanVelocity, std::vector<T> axisPoint, std::vector<T> axisDirection, T Velocity, T radius, T n, T scale)
+ : CirclePowerLaw3D<T>(axisPoint, axisDirection, Velocity, radius, n, scale)
+{
+ if (useMeanVelocity) {
+ _maxVelocity = (2. + (1. + n)/n)/((1. + n)/n * pow(1.,(2. + (1. + n)/n))) * Velocity;
+ }
+}
+
+template <typename T>
+CirclePowerLaw3D<T>::CirclePowerLaw3D(bool useMeanVelocity, T center0, T center1, T center2, T normal0, T normal1, T normal2, T radius, T Velocity, T n, T scale)
+ : CirclePowerLaw3D<T>(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 <typename T>
+CirclePowerLaw3D<T>::CirclePowerLaw3D(bool useMeanVelocity, SuperGeometry3D<T>& superGeometry, int material, T Velocity, T n, T scale)
+ : CirclePowerLaw3D<T>(superGeometry, material, Velocity, n, scale)
+{
+ if (useMeanVelocity) {
+ _maxVelocity = (2. + (1. + n)/n)/((1. + n)/n * pow(1.,(2. + (1. + n)/n))) * Velocity;
+ }
+}
+
+template <typename T>
+bool CirclePowerLaw3D<T>::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 <typename T>
+CirclePowerLawTurbulent3D<T>::CirclePowerLawTurbulent3D(std::vector<T> center, std::vector<T> normal,
+ T maxVelocity, T radius, T n, T scale)
+ : CirclePowerLaw3D<T>(center, normal, maxVelocity, radius, n, scale) { }
+
+template <typename T>
+CirclePowerLawTurbulent3D<T>::CirclePowerLawTurbulent3D(T center0, T center1, T center2, T normal0,
+ T normal1, T normal2, T radius, T maxVelocity, T n, T scale)
+ : CirclePowerLaw3D<T>(center0, center1, center2, normal0, normal1, normal2, radius, maxVelocity, n, scale) { }
+
+template <typename T>
+CirclePowerLawTurbulent3D<T>::CirclePowerLawTurbulent3D(SuperGeometry3D<T>& superGeometry,
+ int material, T maxVelocity, T n, T scale)
+ : CirclePowerLaw3D<T>(superGeometry, material, maxVelocity, n, scale) { }
+
+template <typename T>
+CirclePowerLawTurbulent3D<T>::CirclePowerLawTurbulent3D(bool useMeanVelocity, std::vector<T> axisPoint, std::vector<T> 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 <typename T>
+CirclePowerLawTurbulent3D<T>::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 <typename T>
+CirclePowerLawTurbulent3D<T>::CirclePowerLawTurbulent3D(bool useMeanVelocity, SuperGeometry3D<T>& 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 <typename T>
+bool CirclePowerLawTurbulent3D<T>::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 <typename T>
+CirclePoiseuille3D<T>::CirclePoiseuille3D(std::vector<T> center, std::vector<T> normal,
+ T maxVelocity, T radius, T scale)
+ : CirclePowerLaw3D<T>(center, normal, maxVelocity, radius, 1., scale) { }
+
+template <typename T>
+CirclePoiseuille3D<T>::CirclePoiseuille3D(T center0, T center1, T center2, T normal0,
+ T normal1, T normal2, T radius, T maxVelocity, T scale)
+ : CirclePowerLaw3D<T>(center0, center1, center2, normal0, normal1, normal2, radius, maxVelocity, 1., scale) { }
+
+template <typename T>
+CirclePoiseuille3D<T>::CirclePoiseuille3D(SuperGeometry3D<T>& superGeometry,
+ int material, T maxVelocity, T scale)
+ : CirclePowerLaw3D<T>(superGeometry, material, maxVelocity, 1., scale) { }
+
+template <typename T>
+CirclePoiseuille3D<T>::CirclePoiseuille3D(bool useMeanVelocity, std::vector<T> axisPoint, std::vector<T> axisDirection, T Velocity, T radius, T scale)
+ : CirclePoiseuille3D(axisPoint, axisDirection, Velocity, radius, scale)
+{
+ if (useMeanVelocity) {
+ this->_maxVelocity = 2. * Velocity;
+ }
+}
+
+template <typename T>
+CirclePoiseuille3D<T>::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 <typename T>
+CirclePoiseuille3D<T>::CirclePoiseuille3D(bool useMeanVelocity, SuperGeometry3D<T>& superGeometry, int material, T Velocity, T scale)
+ : CirclePoiseuille3D(superGeometry, material, Velocity, scale)
+{
+ if (useMeanVelocity) {
+ this->_maxVelocity = 2. * Velocity;
+ }
+}
+
+template < typename T,typename DESCRIPTOR>
+CirclePoiseuilleStrainRate3D<T, DESCRIPTOR>::CirclePoiseuilleStrainRate3D(UnitConverter<T, DESCRIPTOR> const& converter, T ly) : AnalyticalF3D<T,T>(9)
+{
+ lengthY = ly;
+ lengthZ = ly;
+ maxVelocity = converter.getCharPhysVelocity();
+ this->getName() = "CirclePoiseuilleStrainRate3D";
+}
+
+
+template < typename T,typename DESCRIPTOR>
+bool CirclePoiseuilleStrainRate3D<T, DESCRIPTOR>::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 <typename T>
+RectanglePoiseuille3D<T>::RectanglePoiseuille3D(std::vector<T>& x0_, std::vector<T>& x1_,
+ std::vector<T>& x2_, std::vector<T>& maxVelocity_)
+ : AnalyticalF3D<T,T>(3), clout(std::cout,"RectanglePoiseille3D"), x0(x0_), x1(x1_),
+ x2(x2_), maxVelocity(maxVelocity_) { }
+
+
+template <typename T>
+RectanglePoiseuille3D<T>::RectanglePoiseuille3D(SuperGeometry3D<T>& superGeometry_,
+ int material_, std::vector<T>& maxVelocity_, T offsetX, T offsetY, T offsetZ)
+ : AnalyticalF3D<T,T>(3), clout(std::cout, "RectanglePoiseuille3D"), maxVelocity(maxVelocity_)
+{
+ std::vector<T> min = superGeometry_.getStatistics().getMinPhysR(material_);
+ std::vector<T> 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 <typename T>
+bool RectanglePoiseuille3D<T>::operator()(T output[], const T x[])
+{
+ std::vector<T> velocity(3,T());
+
+ // create plane normals and supports, (E1,E2) and (E3,E4) are parallel
+ std::vector<std::vector<T> > n(4,std::vector<T>(3,0)); // normal vectors
+ std::vector<std::vector<T> > s(4,std::vector<T>(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<T> A(4,0);
+ std::vector<T> B(4,0);
+ std::vector<T> C(4,0);
+ std::vector<T> 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<T> 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<T> 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 <typename T>
+EllipticPoiseuille3D<T>::EllipticPoiseuille3D(std::vector<T> center, T a, T b, T maxVel)
+ : AnalyticalF3D<T,T>(3), clout(std::cout, "EllipticPoiseuille3D"), _center(center),
+ _a2(a*a), _b2(b*b), _maxVel(maxVel) { }
+
+
+template <typename T>
+bool EllipticPoiseuille3D<T>::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 <typename T>
+AnalyticalPorousVelocity3D<T>::AnalyticalPorousVelocity3D(SuperGeometry3D<T>& superGeometry, int material, T K_, T mu_, T gradP_, T radius_, T eps_)
+ : AnalyticalF3D<T,T>(3), K(K_), mu(mu_), gradP(gradP_), radius(radius_), eps(eps_)
+{
+ this->getName() = "AnalyticalPorousVelocity3D";
+
+ center = superGeometry.getStatistics().getCenterPhysR(material);
+ std::vector<T> 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 <typename T>
+T AnalyticalPorousVelocity3D<T>::getPeakVelocity()
+{
+ T uMax = K / mu*gradP*(1. - 1./(cosh((sqrt(1./K))*radius)));
+
+ return uMax/eps;
+};
+
+
+template <typename T>
+bool AnalyticalPorousVelocity3D<T>::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<typename T, typename S>
+AngleBetweenVectors3D<T, S>::AngleBetweenVectors3D(
+ std::vector<T> referenceVector, std::vector<T> orientation)
+ : AnalyticalF3D<T, S>(1),
+ _referenceVector(referenceVector),
+ _orientation(orientation)
+{
+ this->getName() = "const";
+}
+
+// operator returns angle between vectors x and _referenceVector
+template<typename T, typename S>
+bool AngleBetweenVectors3D<T, S>::operator()(T output[], const S x[])
+{
+ Vector<T, 3> n_x;
+ Vector<T, 3> 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<S, 3> x_tmp(x); // check construction
+ n_x[0] = x[0];
+ n_x[1] = x[1];
+ n_x[2] = x[2];
+ n_x.normalize();
+ }
+
+ Vector<T, 3> n_ref(_referenceVector);
+ n_ref.normalize();
+ Vector<T, 3> 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<T, 3> n_cross(cross);
+ n_cross.normalize();
+ T normal = cross.norm();
+ Vector<T, 3> 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<typename T, typename S>
+RotationRoundAxis3D<T, S>::RotationRoundAxis3D(std::vector<T> origin,
+ std::vector<T> rotAxisDirection, T alpha)
+ : AnalyticalF3D<T, S>(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<typename T, typename S>
+bool RotationRoundAxis3D<T, S>::operator()(T output[], const S x[])
+{
+ Vector<T, 3> 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<T, 3> 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" <<std::endl;
+ for (int j=0; j<3; j++) {
+ output[j] = x[j];
+ }
+ return true;
+ }
+}
+
+
+////////// Cylindric & Cartesian ///////////////
+
+
+// constructor to obtain Cartesian coordinates of cylindrical coordinates,
+// the z-axis direction equals the axis direction of the cylinder
+// with _cylinderOrigin
+template<typename T, typename S>
+CylinderToCartesian3D<T, S>::CylinderToCartesian3D(
+ std::vector<T> cylinderOrigin)
+ : AnalyticalF3D<T, S>(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<typename T, typename S>
+bool CylinderToCartesian3D<T, S>::operator()(T output[], const S x[])
+{
+ PolarToCartesian2D<T, S> pol2cart(_cylinderOrigin);
+ pol2cart(output,x);
+ output[2] = x[2];
+ return true;
+}
+
+
+// constructor to obtain cylindrical coordinates of Cartesian coordinates
+template<typename T, typename S>
+CartesianToCylinder3D<T, S>::CartesianToCylinder3D(
+ std::vector<T> cartesianOrigin, T& angle, std::vector<T> orientation)
+ : AnalyticalF3D<T, S>(3),
+ _cartesianOrigin(cartesianOrigin),
+ _orientation(orientation)
+{
+ // rotation with angle to (0,0,1)
+ std::vector<T> origin(3,T());
+ T e3[3]= {T(),T(),T()};
+ e3[2] = T(1);
+ RotationRoundAxis3D<T, S> rotRAxis(origin, orientation, angle);
+ T tmp[3] = {T(),T(),T()};
+ rotRAxis(tmp, e3);
+
+ std::vector<T> htmp(tmp,tmp+3);
+ _axisDirection = htmp;
+}
+
+// constructor to obtain cylindrical coordinates of Cartesian coordinates
+template<typename T, typename S>
+CartesianToCylinder3D<T, S>::CartesianToCylinder3D(
+ std::vector<T> cartesianOrigin, std::vector<T> axisDirection,
+ std::vector<T> orientation)
+ : AnalyticalF3D<T, S>(3),
+ _cartesianOrigin(cartesianOrigin),
+ _axisDirection(axisDirection),
+ _orientation(orientation)
+{
+ this->getName() = "const";
+}
+
+// constructor to obtain cylindrical coordinates of Cartesian coordinates
+template<typename T, typename S>
+CartesianToCylinder3D<T, S>::CartesianToCylinder3D(
+ T cartesianOriginX, T cartesianOriginY, T cartesianOriginZ,
+ T axisDirectionX, T axisDirectionY, T axisDirectionZ,
+ T orientationX, T orientationY, T orientationZ)
+ : AnalyticalF3D<T, S>(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<typename T, typename S>
+bool CartesianToCylinder3D<T, S>::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<T, 3> e3(T(),T(), T(1));
+ Vector<T, 3> axisDirection(_axisDirection);
+ Vector<T, 3> orientation(_orientation);
+
+ Vector<T, 3> normal = crossProduct3D(axisDirection, e3);
+ Vector<T, 3> 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<T,S> 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<T, S> rotRAxis(_cartesianOrigin, util::fromVector3(normal), -alpha[0]);
+ rotRAxis(x_rot, x);
+ }
+ CartesianToPolar2D<T, S> 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<typename T, typename S>
+std::vector<T> const& CartesianToCylinder3D<T, S>::getAxisDirection() const
+{
+ return _axisDirection;
+}
+
+// Read and write access to _axisDirection
+template<typename T, typename S>
+std::vector<T>& CartesianToCylinder3D<T, S>::getAxisDirection()
+{
+ return _axisDirection;
+}
+
+// Read only access to _catesianOrigin
+template<typename T, typename S>
+std::vector<T> const& CartesianToCylinder3D<T, S>::getCartesianOrigin() const
+{
+ return _cartesianOrigin;
+}
+
+// Read and write access to _catesianOrigin
+template<typename T, typename S>
+std::vector<T>& CartesianToCylinder3D<T, S>::getCartesianOrigin()
+{
+ return _cartesianOrigin;
+}
+
+// Read and write access to _axisDirection using angle
+template<typename T, typename S>
+void CartesianToCylinder3D<T, S>::setAngle(T angle)
+{
+ std::vector<T> Null(3,T());
+ T e3[3] = {T(),T(),T()};
+ e3[2] = T(1);
+
+ RotationRoundAxis3D<T, S> 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<typename T, typename S>
+SphericalToCartesian3D<T, S>::SphericalToCartesian3D()
+//std::vector<T> sphericalOrigin)
+ : AnalyticalF3D<T, S>(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<typename T, typename S>
+bool SphericalToCartesian3D<T, S>::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<typename T, typename S>
+CartesianToSpherical3D<T, S>::CartesianToSpherical3D(
+ std::vector<T> cartesianOrigin, std::vector<T> axisDirection)
+ : AnalyticalF3D<T, S>(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<typename T, typename S>
+bool CartesianToSpherical3D<T, S>::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<T,3> axisDirection(_axisDirection);
+ Vector<T,3> e3(T(), T(), T(1));
+ Vector<T,3> normal = crossProduct3D(axisDirection,e3);
+
+ Vector<T,3> normalAxisDir = axisDirection;
+ normalAxisDir.normalize();
+ Vector<T,3> cross;
+ // if axis has to be rotated
+ if ( !( util::nearZero(normalAxisDir[0]) && util::nearZero(normalAxisDir[1]) && util::nearZero(normalAxisDir[2]-1) ) ) {
+ AngleBetweenVectors3D<T, S> 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<T, S> rotRAxis(_cartesianOrigin, util::fromVector3(normal), -alpha[0]);
+ rotRAxis(x_rot,x);
+ }
+
+ CartesianToPolar2D<T, S> car2pol(_cartesianOrigin, util::fromVector3(e3), util::fromVector3(cross));
+ // y[0] = car2pol(x_rot)[0];
+ Vector<T, 3> 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