MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
maia::math Namespace Reference

Typedefs

using MFloatMatrix2d = Eigen::Matrix< MFloat, 2, 2 >
 all assume dense matrix calculations More...
 
using MFloatMatrix3d = Eigen::Matrix< MFloat, 3, 3 >
 
using MFloatMatrixXd = Eigen::Matrix< MFloat, Eigen::Dynamic, Eigen::Dynamic >
 
template<MInt nDim>
using MFloatMatrix = Eigen::Matrix< MFloat, nDim, nDim >
 
using MFloatVector2d = Eigen::Vector< MFloat, 2 >
 
using MFloatVector3d = Eigen::Vector< MFloat, 3 >
 
using MFloatVectorXd = Eigen::Vector< MFloat, Eigen::Dynamic >
 
template<MInt nDim>
using MFloatVector = Eigen::Vector< MFloat, nDim >
 
using MTriplet = Eigen::Triplet< MFloat >
 

Functions

MInt getGlobalPosFFTW (MInt i0, MInt i1, MInt i2, MInt ny, MInt nz)
 
MFloat triadImag (fftw_complex &a, fftw_complex &b, fftw_complex &c)
 
MFloat randnormal (MFloat mu, MFloat sigma)
 
std::complex< MFloat > * getFourierCoefficient (MFloat *k, MFloat k0, const MFloat Ma)
 
std::complex< MFloat > * getFourierCoefficient2 (MFloat *k, MFloat k0)
 
void initFftFilter (MFloat *uPhysFieldCoarse, MFloat *vPhysFieldCoarse, MFloat *wPhysFieldCoarse, MInt lx, MInt ly, MInt lz, MInt lxCoarse, MInt lyCoarse, MInt lzCoarse, MInt noPeakModes, const MFloat Ma)
 Generates a velocity field from Fourier-modes using FFTW The disturbances are generated and filtered to a coarser resolution. More...
 
void initFft (fftw_complex *uPhysField, fftw_complex *vPhysField, fftw_complex *wPhysField, MInt lx, MInt ly, MInt lz, MInt noPeakModes, const MFloat Ma)
 Generates a velocity field from Fourier-modes using FFTW. More...
 
void computeEnergySpectrum (MFloatScratchSpace &velocity, MIntScratchSpace &indices, const ptrdiff_t howmany, MInt locSize, MInt nx, MInt ny, MInt nz, MFloat viscosity, const MPI_Comm comm)
 Compute energy spectrum on unity cube. More...
 
template<typename T , std::size_t N>
Eigen::MatrixXd ConvertToEigenMatrix (std::array< std::array< T, N >, N > data)
 convert array to eigen matrix More...
 
template<typename T , std::size_t N>
void adjointRow (std::array< std::array< T, N >, N > &m, std::array< T, N > &A, const MInt r)
 
template void adjointRow< MFloat, 3 > (std::array< std::array< MFloat, 3 >, 3 > &m, std::array< MFloat, 3 > &A, const MInt)
 
template<typename T >
void adjoint1stRow4x4 (std::array< std::array< T, 4 >, 4 > &m, std::array< T, 4 > &A)
 
template void adjoint1stRow4x4< MFloat > (std::array< std::array< MFloat, 4 >, 4 > &m, std::array< MFloat, 4 > &A)
 
template<typename T , std::size_t N>
void adjoint1stRow (std::array< std::array< T, N >, N > &m, std::array< T, N > &A)
 
template void adjoint1stRow< MFloat, 4 > (std::array< std::array< MFloat, 4 >, 4 > &m, std::array< MFloat, 4 > &A)
 
template void adjoint1stRow< MFloat, 3 > (std::array< std::array< MFloat, 3 >, 3 > &m, std::array< MFloat, 3 > &A)
 
template<typename T , std::size_t N>
MFloat determinant (std::array< T, N > &m)
 
template MFloat determinant< MFloat, 2ul > (std::array< MFloat, 2ul > &)
 
template MFloat determinant< MFloat, 3ul > (std::array< MFloat, 3ul > &)
 
template MFloat determinant< MFloat, 4ul > (std::array< MFloat, 4ul > &)
 
template<typename T , std::size_t N>
MFloat determinant (std::array< std::array< T, N >, N > &m)
 
template MFloat determinant< MFloat, 2ul > (std::array< std::array< MFloat, 2ul >, 2ul > &)
 
template MFloat determinant< MFloat, 3ul > (std::array< std::array< MFloat, 3ul >, 3ul > &)
 
template MFloat determinant< MFloat, 4ul > (std::array< std::array< MFloat, 4ul >, 4ul > &)
 
void invert (MFloat *A, const MInt m, const MInt n)
 
template<class T >
void invert (T &A, T &AInv, const MInt m, const MInt n)
 
template void invert< ScratchSpace< MFloat > > (ScratchSpace< MFloat > &, ScratchSpace< MFloat > &, const MInt, const MInt)
 
template void invert< maia::tensor::Tensor< MFloat > > (maia::tensor::Tensor< MFloat > &, maia::tensor::Tensor< MFloat > &, const MInt, const MInt)
 
template<class T >
void invert (T &A, T &weights, T &AInv, const MInt m, const MInt n)
 
template void invert< ScratchSpace< MFloat > > (ScratchSpace< MFloat > &, ScratchSpace< MFloat > &, ScratchSpace< MFloat > &, const MInt, const MInt)
 
template void invert< maia::tensor::Tensor< MFloat > > (maia::tensor::Tensor< MFloat > &, maia::tensor::Tensor< MFloat > &, maia::tensor::Tensor< MFloat > &, const MInt, const MInt)
 
template<class T >
MInt invertR (T &A, T &weights, T &AInv, const MInt m, const MInt n)
 
template MInt invertR< ScratchSpace< MFloat > > (ScratchSpace< MFloat > &, ScratchSpace< MFloat > &, ScratchSpace< MFloat > &, const MInt, const MInt)
 
void solveSparseMatrix (MFloat *A_coeff, MInt **pos, const MInt n, const MInt m, MFloat *b, MFloat *x)
 
void solveSparseMatrixIterative (MFloat *A_coeff, MInt **pos, const MInt n, const MInt m, MFloat *b, MFloat *x)
 
void solveDenseMatrix (MFloat *A_coeff, MInt **pos, const MInt n, const MInt m, MFloat *b, MFloat *x)
 
void multiplySparseMatrixVector (MFloat *A_coeff, MInt **pos, const MInt n, const MInt m, MFloat *b, MFloat *x)
 
template<MInt nDim>
void solveQR (std::array< std::array< MFloat, nDim >, nDim > &A_, std::array< MFloat, nDim > &b_)
 
template void solveQR< 2 > (std::array< std::array< MFloat, 2 >, 2 > &, std::array< MFloat, 2 > &)
 
template void solveQR< 3 > (std::array< std::array< MFloat, 3 >, 3 > &, std::array< MFloat, 3 > &)
 
void calcEigenValues (MFloat A[3][3], MFloat w[3])
 
void calcEigenValues (MFloat **A_in, MFloat *lambda_in, const MInt m)
 
void calcEigenVectors (MFloat A[3][3], MFloat Q[3][3], MFloat w[3])
 
std::vector< MFloatsvd (MFloat *const A, MFloat *const b, const MInt m, const MInt n, MFloat *const x)
 
void quickSortImpl (MInt *a, MInt start, MInt end)
 
void quickSort (MInt *a, MInt start, MInt end)
 
template<MInt nDim, typename T , typename U >
T * vecAdd (T *const result, const U *const a)
 Linear Algebra. More...
 
template<MInt nDim, typename T , typename U , typename... Ts>
T * vecAdd (T *const result, const U *const a, const Ts... b)
 
template<MInt nDim, typename T , typename... Ts>
void vecAvg (T *const M, const Ts *const ... args)
 Computes the arithmetic mean of an arbritary number of vectors of dimension nDim and returns it in M. More...
 
template<typename T >
void cross (const T *const u, const T *const v, T *const c)
 
template<typename T >
std::array< T, 3 > cross (const std::array< T, 3 > &u, const std::array< T, 3 > &v)
 
template<typename T >
cross (const std::array< T, 2 > &u, const std::array< T, 2 > &v)
 
template<typename T >
T * cross (const T(&u)[3], const T(&v)[3])
 
template<typename T >
cross (const T(&u)[2], const T(&v)[2])
 
template<typename T , std::size_t N>
MFloat norm (const std::array< T, N > &u)
 
template<typename T >
MFloat norm (const T *const u, const MInt N)
 
template<typename T , std::size_t N>
void normalize (std::array< T, N > &u)
 
template<typename T >
void normalize (T *const u, const MInt N)
 
template<typename T , std::size_t N>
std::array< T, N > normalized (const std::array< T, N > &u)
 
template<MInt nDim>
MFloat distance (const MFloat *a, const MFloat *b)
 
MFloat distance (const std::array< MFloat, 2 > a, const std::array< MFloat, 2 > b)
 
MFloat distance (const std::array< MFloat, 3 > a, const std::array< MFloat, 3 > b)
 
MFloat distance (const MFloat *const a, const std::array< MFloat, 2 > b)
 
MFloat distance (const MFloat *const a, const std::array< MFloat, 3 > b)
 
MFloat distance (const std::array< MFloat, 2 > a, const MFloat *const b)
 
MFloat distance (std::array< MFloat, 3 > a, const MFloat *const b)
 
void multiplyMatricesSq (MFloatScratchSpace &m1, MFloatScratchSpace &m2, MFloatScratchSpace &result, MInt dim)
 
void multiplyMatrices (MFloatScratchSpace &m1, MFloatScratchSpace &m2, MFloatScratchSpace &result, MInt m1_n, MInt m1_m, MInt m2_n, MInt m2_m)
 
void addMatrices (MFloatScratchSpace &m1, MFloatScratchSpace &m2, MFloatScratchSpace &result, MInt dim1, MInt dim2)
 
MFloat frobeniusMatrixNormSquared (MFloatScratchSpace &m, MInt dim1, MInt dim2)
 
MFloat frobeniusMatrixNorm (MFloatScratchSpace &m, MInt dim1, MInt dim2)
 
MFloat besselJ0 (MFloat x)
 
MFloat besselJ1 (MFloat x)
 
MFloat besselJi (MInt order, MFloat x)
 
MFloat lincos (MFloat arg)
 
void sortEigenVectors (MFloat A[3][3], MFloat w[3])
 Sorts the eigenvalues and the associated eigenvectors from large to small. More...
 
void quatMult (const MFloat *const qA, const MFloat *const qB, MFloat *const qC)
 
template<typename T >
MInt sgn (T val)
 
MFloat crankAngle (const MFloat time, const MFloat Strouhal, const MFloat offset, const MInt mode)
 help-function for engine calculations which returns the crank-angle for a given time, Strouhals-number and crank-angle offset mode = 0: return CAD in range of (0-720) mode = 1: return accumulated crankAnge in radian More...
 
void computeRotationMatrix (MFloatScratchSpace &R, MFloat *q)
 rotation matrix co-rotating(~inertial) frame -> body-fixed frame More...
 
void rotation2quaternion (MFloat *rotation, MFloat *quaternion)
 
void matrixVectorProduct (MFloat *c, MFloatScratchSpace &A, MFloat *b)
 c=A*b More...
 
void matrixVectorProductTranspose (MFloat *c, MFloatScratchSpace &A, MFloat *b)
 c=A^t*b More...
 
MInt inverse (MFloat **a, MFloat **ainv, MInt n, const MFloat epsilon)
 
MInt quickSortPartition (MInt *a, MInt start, MInt end)
 
MInt removeDoubleEntries (MInt *a, MInt size)
 
void calculateLegendrePolyAndDeriv (MInt Nmax, MFloat x, MFloat *polynomial, MFloat *derivative)
 Evaluates the Legendre polynomial and its derivative of degree Nmax at point x. More...
 
void calculateLegendreGaussNodesAndWeights (MInt Nmax, MFloat *nodes, MFloat *wInt)
 Calculate the Gauss integration nodes and weight for the Legendre polynomials on the interval [-1,1]. More...
 
MFloat RBF (const MFloat R, const MFloat R0)
 radial base function More...
 
MFloat deltaFun (const MFloat r, const MFloat r0, const MFloat r1)
 
std::vector< MFloatlinSpace (const MFloat start, const MFloat end, const MInt num)
 
MFloat getSector (MFloat y, MFloat z, MFloat azimuthalAngle)
 
MFloat getAngle (MFloat y, MFloat z)
 

Typedef Documentation

◆ MFloatMatrix

template<MInt nDim>
using maia::math::MFloatMatrix = typedef Eigen::Matrix<MFloat, nDim, nDim>

Definition at line 54 of file maiamath.cpp.

◆ MFloatMatrix2d

using maia::math::MFloatMatrix2d = typedef Eigen::Matrix<MFloat, 2, 2>

Definition at line 50 of file maiamath.cpp.

◆ MFloatMatrix3d

using maia::math::MFloatMatrix3d = typedef Eigen::Matrix<MFloat, 3, 3>

Definition at line 51 of file maiamath.cpp.

◆ MFloatMatrixXd

using maia::math::MFloatMatrixXd = typedef Eigen::Matrix<MFloat, Eigen::Dynamic, Eigen::Dynamic>

Definition at line 52 of file maiamath.cpp.

◆ MFloatVector

template<MInt nDim>
using maia::math::MFloatVector = typedef Eigen::Vector<MFloat, nDim>

Definition at line 60 of file maiamath.cpp.

◆ MFloatVector2d

using maia::math::MFloatVector2d = typedef Eigen::Vector<MFloat, 2>

Definition at line 56 of file maiamath.cpp.

◆ MFloatVector3d

using maia::math::MFloatVector3d = typedef Eigen::Vector<MFloat, 3>

Definition at line 57 of file maiamath.cpp.

◆ MFloatVectorXd

using maia::math::MFloatVectorXd = typedef Eigen::Vector<MFloat, Eigen::Dynamic>

Definition at line 58 of file maiamath.cpp.

◆ MTriplet

using maia::math::MTriplet = typedef Eigen::Triplet<MFloat>

Definition at line 61 of file maiamath.cpp.

Function Documentation

◆ addMatrices()

void maia::math::addMatrices ( MFloatScratchSpace m1,
MFloatScratchSpace m2,
MFloatScratchSpace result,
MInt  dim1,
MInt  dim2 
)
inline

Definition at line 319 of file maiamath.h.

320 {
321 for(MInt i = 0; i < dim1; i++) {
322 for(MInt j = 0; j < dim2; j++) {
323 result(i, j) = m1(i, j) + m2(i, j);
324 }
325 }
326}
int32_t MInt
Definition: maiatypes.h:62

◆ adjoint1stRow()

template<typename T , std::size_t N>
void maia::math::adjoint1stRow ( std::array< std::array< T, N >, N > &  m,
std::array< T, N > &  A 
)

First row of adjoint of a matrix

Template Parameters
TType
Parameters
mMatrix (two dimensional array containing the matrix elements)
Returns
First row of the adjuncte of the matrix m in A

Definition at line 114 of file maiamath.cpp.

114 {
115 if constexpr(N == 4) {
116 adjoint1stRow4x4(m, A);
117 } else {
118 adjointRow(m, A, 0);
119 }
120}
void adjoint1stRow4x4(std::array< std::array< T, 4 >, 4 > &m, std::array< T, 4 > &A)
Definition: maiamath.cpp:97

◆ adjoint1stRow4x4()

template<typename T >
void maia::math::adjoint1stRow4x4 ( std::array< std::array< T, 4 >, 4 > &  m,
std::array< T, 4 > &  A 
)

First row of adjoint of a 4 x 4 matrix

Template Parameters
TType
Parameters
mMatrix (two dimensional array containing the matrix elements)
Returns
First row of the adjuncte of the 4 x 4 matrix m in A

Definition at line 97 of file maiamath.cpp.

97 {
98 A[0] = m[1][1] * m[2][2] * m[3][3] + m[1][2] * m[2][3] * m[3][1] + m[1][3] * m[2][1] * m[3][2]
99 - m[1][3] * m[2][2] * m[3][1] - m[1][2] * m[2][1] * m[3][3] - m[1][1] * m[2][3] * m[3][2];
100 A[1] = -m[0][1] * m[2][2] * m[3][3] - m[0][2] * m[2][3] * m[3][1] - m[0][3] * m[2][1] * m[3][2]
101 + m[0][3] * m[2][2] * m[3][1] + m[0][2] * m[2][1] * m[3][3] + m[0][1] * m[2][3] * m[3][2];
102 A[2] = m[0][1] * m[1][2] * m[3][3] + m[0][2] * m[1][3] * m[3][1] + m[0][3] * m[1][1] * m[3][2]
103 - m[0][3] * m[1][2] * m[3][1] - m[0][2] * m[1][1] * m[3][3] - m[0][1] * m[1][3] * m[3][2];
104 A[3] = -m[0][1] * m[1][2] * m[2][3] - m[0][2] * m[1][3] * m[2][1] - m[0][3] * m[1][1] * m[2][2]
105 + m[0][3] * m[1][2] * m[2][1] + m[0][2] * m[1][1] * m[2][3] + m[0][1] * m[1][3] * m[2][2];
106}

◆ adjoint1stRow4x4< MFloat >()

template void maia::math::adjoint1stRow4x4< MFloat > ( std::array< std::array< MFloat, 4 >, 4 > &  m,
std::array< MFloat, 4 > &  A 
)

◆ adjoint1stRow< MFloat, 3 >()

template void maia::math::adjoint1stRow< MFloat, 3 > ( std::array< std::array< MFloat, 3 >, 3 > &  m,
std::array< MFloat, 3 > &  A 
)

◆ adjoint1stRow< MFloat, 4 >()

template void maia::math::adjoint1stRow< MFloat, 4 > ( std::array< std::array< MFloat, 4 >, 4 > &  m,
std::array< MFloat, 4 > &  A 
)

◆ adjointRow()

template<typename T , std::size_t N>
void maia::math::adjointRow ( std::array< std::array< T, N >, N > &  m,
std::array< T, N > &  A,
const MInt  r 
)

Row of adjoint of a matrix

Template Parameters
TType
NDimension of the matrix
Parameters
mMatrix (one dimensional array containing the matrix elements)
rRow of the adjuncte
Returns
Given row of the adjuncte of the matrix m in A

Definition at line 82 of file maiamath.cpp.

82 {
83 Eigen::Matrix<T, N, N> m2 = ConvertToEigenMatrix(m);
84 Eigen::Matrix<T, N, N> adjMatrix(m2.adjoint());
85 for(std::size_t i = 0; i < N; i++) {
86 A[i] = adjMatrix.row(r)[i];
87 }
88}
Eigen::MatrixXd ConvertToEigenMatrix(std::array< std::array< T, N >, N > data)
convert array to eigen matrix
Definition: maiamath.cpp:66

◆ adjointRow< MFloat, 3 >()

template void maia::math::adjointRow< MFloat, 3 > ( std::array< std::array< MFloat, 3 >, 3 > &  m,
std::array< MFloat, 3 > &  A,
const  MInt 
)

◆ besselJ0()

MFloat maia::math::besselJ0 ( MFloat  x)
inline

Definition at line 343 of file maiamath.h.

343 {
344 // This subroutine calculates the First Kind Bessel Function of
345 // order 0, for any real number X. The polynomial approximation by
346 // series of Chebyshev polynomials is used for 0<X<8 and 0<8/X<1.
347 // REFERENCES:
348 // M.ABRAMOWITZ,I.A.STEGUN, HANDBOOK OF MATHEMATICAL FUNCTIONS, 1965.
349 // C.W.CLENSHAW, NATIONAL PHYSICAL LABORATORY MATHEMATICAL TABLES,
350 // VOL.5, 1962.
351
352 const MFloat p1 = 1.0, p2 = -0.1098628627e-2, p3 = 0.2734510407e-4, p4 = -0.2073370639e-5, p5 = 0.2093887211e-6,
353 q1 = -0.1562499995e-1, q2 = 0.1430488765e-3, q3 = -0.6911147651e-5, q4 = 0.7621095161e-6,
354 q5 = -0.9349451520e-7, r1 = 57568490574.0, r2 = -13362590354.0, r3 = 651619640.7, r4 = -11214424.18,
355 r5 = 77392.33017, r6 = -184.9052456, s1 = 57568490411.0, s2 = 1029532985.0, s3 = 9494680.718,
356 s4 = 59272.64853, s5 = 267.8532712, s6 = 1.0;
357 MFloat ax, fr, fs, z, fp, fq1, xx, y, tmp;
358
359 if(approx(x, 0.0, std::numeric_limits<MFloat>::epsilon())) {
360 return 1.0;
361 }
362
363 ax = fabs(x);
364 if(ax < 8.0) {
365 y = x * x;
366 fr = r1 + y * (r2 + y * (r3 + y * (r4 + y * (r5 + y * r6))));
367 fs = s1 + y * (s2 + y * (s3 + y * (s4 + y * (s5 + y * s6))));
368 tmp = fr / fs;
369 } else {
370 z = 8. / ax;
371 y = z * z;
372 xx = ax - 0.785398164;
373 fp = p1 + y * (p2 + y * (p3 + y * (p4 + y * p5)));
374 fq1 = q1 + y * (q2 + y * (q3 + y * (q4 + y * q5)));
375 tmp = std::sqrt(0.636619772 / ax) * (fp * cos(xx) - z * fq1 * sin(xx));
376 }
377 return tmp;
378}
MBool approx(const T &, const U &, const T)
Definition: functions.h:272
double MFloat
Definition: maiatypes.h:52
define array structures

◆ besselJ1()

MFloat maia::math::besselJ1 ( MFloat  x)
inline

Definition at line 380 of file maiamath.h.

380 {
381 // This subroutine calculates the First Kind Bessel Function of
382 // order 1, for any real number X. The polynomial approximation by
383 // series of Chebyshev polynomials is used for 0<X<8 and 0<8/X<1.
384 // REFERENCES:
385 // M.ABRAMOWITZ,I.A.STEGUN, HANDBOOK OF MATHEMATICAL FUNCTIONS, 1965.
386 // C.W.CLENSHAW, NATIONAL PHYSICAL LABORATORY MATHEMATICAL TABLES,
387 // VOL.5, 1962.
388
389 const MFloat p1 = 1.0, p2 = 0.183105e-2, p3 = -0.3516396496e-4, p4 = 0.2457520174e-5, p5 = -0.240337019e-6,
390 p6 = 0.636619772, q1 = 0.04687499995, q2 = -0.2002690873e-3, q3 = 0.8449199096e-5, q4 = -0.88228987e-6,
391 q5 = 0.105787412e-6, r1 = 72362614232.0, r2 = -7895059235.0, r3 = 242396853.1, r4 = -2972611.439,
392 r5 = 15704.48260, r6 = -30.16036606, s1 = 144725228442.0, s2 = 2300535178.0, s3 = 18583304.74,
393 s4 = 99447.43394, s5 = 376.9991397, s6 = 1.0;
394
395 MFloat ax, fr, fs, y, z, fp, fq1, xx, tmp;
396
397 ax = fabs(x);
398 if(ax < 8.0) {
399 y = x * x;
400 fr = r1 + y * (r2 + y * (r3 + y * (r4 + y * (r5 + y * r6))));
401 fs = s1 + y * (s2 + y * (s3 + y * (s4 + y * (s5 + y * s6))));
402 tmp = x * (fr / fs);
403 } else {
404 z = 8.0 / ax;
405 y = z * z;
406 xx = ax - 2.35619491;
407 fp = p1 + y * (p2 + y * (p3 + y * (p4 + y * p5)));
408 fq1 = q1 + y * (q2 + y * (q3 + y * (q4 + y * q5)));
409 tmp = sqrt(p6 / ax) * (cos(xx) * fp - z * sin(xx) * fq1) * (x < 0.0 ? -fabs(s6) : fabs(s6));
410 }
411 return tmp;
412}

◆ besselJi()

MFloat maia::math::besselJi ( MInt  order,
MFloat  x 
)
inline

Definition at line 415 of file maiamath.h.

415 {
416 if(order == 0) {
417 return besselJ0(x);
418 }
419 if(order == 1) {
420 return besselJ1(x);
421 }
422 mTerm(1, AT_, "invalid order");
423}
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
MFloat besselJ0(MFloat x)
Definition: maiamath.h:343

◆ calcEigenValues() [1/2]

void maia::math::calcEigenValues ( MFloat **  A_in,
MFloat lambda_in,
const MInt  m 
)

Get the Eigenvalues of matrix A_in (symmetrical)

Parameters
A_insystem matrix
lambda_invector of eigen values
msize of square matrix A
Author
Moritz Waldmann

Definition at line 489 of file maiamath.cpp.

489 {
490 Eigen::Map<Eigen::MatrixXd> A(&A_in[0][0], m, m);
491 Eigen::Map<Eigen::VectorXd> lambda(lambda_in, m);
492
493 // Assume matrix is symmetrical
494 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(A, Eigen::EigenvaluesOnly);
495 lambda = es.eigenvalues().real();
496}

◆ calcEigenValues() [2/2]

void maia::math::calcEigenValues ( MFloat  A[3][3],
MFloat  w[3] 
)

Get the Eigenvalues of matrix A (symmetrical)

Parameters
Asystem matrix
wEigenvalues
Author
Sven Berger

Definition at line 475 of file maiamath.cpp.

475 {
476 Eigen::Map<Eigen::Matrix<MFloat, 3, 3>> mA(&A[0][0]);
477 Eigen::Map<Eigen::Matrix<MFloat, 3, 1>> _w(w);
478
479 // Assume matrix is symmetrical
480 Eigen::SelfAdjointEigenSolver<Eigen::Matrix<MFloat, 3, 3>> es(mA, Eigen::EigenvaluesOnly);
481 _w = es.eigenvalues().real();
482}

◆ calcEigenVectors()

void maia::math::calcEigenVectors ( MFloat  A[3][3],
MFloat  Q[3][3],
MFloat  w[3] 
)

Get the Eigenvalues and Eigenvectors of matrix A (symmetrical)

Parameters
Asystem matrix
wEigenvalues
QEigenvectors
Author
Sven Berger

Definition at line 503 of file maiamath.cpp.

503 {
504 Eigen::Map<Eigen::Matrix<MFloat, 3, 3>> mA(&A[0][0]);
505 Eigen::Map<Eigen::Matrix<MFloat, 3, 3>> mQ(&Q[0][0]);
506 Eigen::Map<Eigen::Matrix<MFloat, 3, 1>> _w(w);
507
508 // Assume matrix is symmetrical
509 Eigen::SelfAdjointEigenSolver<Eigen::Matrix<MFloat, 3, 3>> es(mA);
510 mQ = es.eigenvectors().real();
511 _w = es.eigenvalues().real();
512}

◆ calculateLegendreGaussNodesAndWeights()

void maia::math::calculateLegendreGaussNodesAndWeights ( MInt  Nmax,
MFloat nodes,
MFloat wInt 
)
inline
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2012-11-07
Parameters
[in]NmaxMaximum degree of the polynomials.
[out]nodesThe resulting integration nodes.
[out]wIntThe resulting integration weights.

Taken from Kopriva09, p. 64, algorithm 23.

Definition at line 806 of file maiamath.h.

806 {
807 TRACE();
808
809 // Reset nodes and weights
810 const MInt noNodes = Nmax + 1;
811 std::fill_n(&nodes[0], noNodes, F0);
812 std::fill_n(&wInt[0], noNodes, F0);
813
814 // Set tolerance and number of iterations. According to Kopriva09,
815 // 1.0E-15 and 10 should be more than sufficient.
816 const MFloat tol = F4 * MFloatEps;
817 const MInt noIterations = 10;
818
819 // Catch simple cases before going into the full loop
820 if(Nmax == 0) {
821 nodes[0] = F0;
822 wInt[0] = F2;
823 } else if(Nmax == 1) {
824 nodes[0] = -sqrt(F1B3);
825 wInt[0] = 1;
826 nodes[1] = -nodes[0];
827 wInt[1] = wInt[0];
828 } else {
829 // Use symmetry property of the roots of the Legendre polynomials
830 for(MInt j = 0; j < (Nmax + 1) / 2; j++) {
831 // Calculate starting guess for Newton method
832 nodes[j] = -cos((F2 * j + F1) / (F2 * Nmax + F2) * PI);
833
834 // Use Newton method to find root of Legendre polynomial
835 // -> this is also the integration node
836 MFloat poly, deriv;
837 for(MInt k = 0; k < noIterations; k++) {
838 calculateLegendrePolyAndDeriv(Nmax + 1, nodes[j], &poly, &deriv);
839 MFloat delta = -poly / deriv;
840 nodes[j] += delta;
841
842 // Stop iterations if error is small enough
843 if(fabs(delta) <= tol * fabs(nodes[j])) {
844 break;
845 }
846 }
847
848 // Calculate weight
849 calculateLegendrePolyAndDeriv(Nmax + 1, nodes[j], &poly, &deriv);
850 wInt[j] = F2 / ((1 - nodes[j] * nodes[j]) * deriv * deriv);
851
852 // Set nodes and weights according to symmetry properties
853 nodes[Nmax - j] = -nodes[j];
854 wInt[Nmax - j] = wInt[j];
855 }
856 }
857
858 // If odd number of nodes (noNodes = Nmax + 1), set center node to
859 // origin (0.0) and calculate weight
860 if(Nmax % 2 == 0) {
861 MFloat poly, deriv;
862 calculateLegendrePolyAndDeriv(Nmax + 1, F0, &poly, &deriv);
863 nodes[Nmax / 2] = F0;
864 wInt[Nmax / 2] = F2 / (deriv * deriv);
865 }
866}
void calculateLegendrePolyAndDeriv(MInt Nmax, MFloat x, MFloat *polynomial, MFloat *derivative)
Evaluates the Legendre polynomial and its derivative of degree Nmax at point x.
Definition: maiamath.h:754

◆ calculateLegendrePolyAndDeriv()

void maia::math::calculateLegendrePolyAndDeriv ( MInt  Nmax,
MFloat  x,
MFloat polynomial,
MFloat derivative 
)
inline
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2012-11-06
Parameters
[in]NmaxThe polynomial degree.
[in]xThe evaluation point.
[out]polynomialThe resulting value of the Legendre polynomial.
[out]derivativeThe resulting value of the derivative.

Taken from Kopriva09, p. 63, algorithm 22.

Definition at line 754 of file maiamath.h.

754 {
755 // TRACE();
756
757 // Create temporary storage for the polynomial and its derivative
758 MFloat poly = F0;
759 MFloat deriv = F0;
760
761 // Explicitly calculate the first two values of the three term recursion
762 if(Nmax == 0) {
763 poly = F1;
764 deriv = F0;
765 } else if(Nmax == 1) {
766 poly = x;
767 deriv = F1;
768 } else {
769 MFloat polyLast1, polyLast2, derivLast1, derivLast2;
770
771 polyLast2 = F1;
772 polyLast1 = x;
773 derivLast2 = F0;
774 derivLast1 = F1;
775
776 // Calculate the polynomial and its derivative for higher degrees
777 // (Nmax >= 2)
778 for(MInt k = 2; k <= Nmax; k++) {
779 poly = (F2 * k - F1) / k * x * polyLast1 - (k - F1) / k * polyLast2;
780 deriv = derivLast2 + (F2 * k - F1) * polyLast1;
781 polyLast2 = polyLast1;
782 polyLast1 = poly;
783 derivLast2 = derivLast1;
784 derivLast1 = deriv;
785 }
786 }
787
788 // Save results to pointer locations
789 *polynomial = poly;
790 *derivative = deriv;
791}

◆ computeEnergySpectrum()

void maia::math::computeEnergySpectrum ( MFloatScratchSpace velocity,
MIntScratchSpace indices,
const ptrdiff_t  howmany,
MInt  locSize,
MInt  nx,
MInt  ny,
MInt  nz,
MFloat  viscosity,
const MPI_Comm  comm 
)
inline
Author
Lennart Schneiders

discrete spectrum is computed on unity cube, no spatial scaling required velocity field is computed for u_rms = 1, hence uPhysField subsequently has to be scaled by the magnitude of the fluctuations, e.g. uPhysField *= m_UInfinity

(u,v,w) PhysField: complex velocity in physical space

Parameters
uPhysFieldpointer to a fftw_complex for u
vPhysFieldpointer to a fftw_complex for v
wPhysFieldpointer to a fftw_complex for w

Definition at line 1051 of file maiafftw.h.

1052 {
1053 DEBUG("computeEnergySpectrum entry", MAIA_DEBUG_TRACE_IN);
1054 TRACE();
1055
1056 const MInt size = nx * ny * nz;
1057 const MFloat fsize = (MFloat)size;
1058 const ptrdiff_t rank = 3;
1059 if(nx % 2 != 0 || ny % 2 != 0 || nz % 2 != 0) {
1060 std::stringstream errorMessage;
1061 errorMessage << " FFTInit: domainsize must NOT be an odd number! " << nx << " " << ny << " " << nz << std::endl;
1062 mTerm(1, AT_, errorMessage.str());
1063 }
1064 if(howmany < 3) mTerm(1, AT_, "expecting at least 3D velocity field");
1065
1066 m_log << " --- initializing FFTW --- " << std::endl;
1067 m_log << " domain size = " << nx << "x" << ny << "x" << nz << " (" << howmany << ")" << std::endl;
1068
1069 // caution: nz must be evenly divisble by number of ranks!
1070 MInt domainId;
1071 MInt noDomains;
1072 MPI_Comm_rank(comm, &domainId);
1073 MPI_Comm_size(comm, &noDomains);
1074 MPI_Comm MPI_COMM_FFTW;
1075 MInt maxRank = 1;
1076 maxRank = mMin(nz, noDomains);
1077 while(nz % maxRank != 0) {
1078 maxRank--;
1079 }
1080 MInt color = (domainId < maxRank) ? 0 : MPI_UNDEFINED;
1081 MPI_Comm_split(comm, color, domainId, &MPI_COMM_FFTW, AT_, "MPI_COMM_FFTW");
1082 m_log << "no ranks for fft: " << maxRank << std::endl;
1083
1084 MFloat urms0 = F0;
1085 for(MInt i = 0; i < locSize; i++) {
1086 urms0 += POW2(velocity(i, 0)) + POW2(velocity(i, 1)) + POW2(velocity(i, 2));
1087 }
1088 MPI_Allreduce(MPI_IN_PLACE, &urms0, 1, MPI_DOUBLE, MPI_SUM, comm, AT_, "MPI_IN_PLACE", "urms0");
1089 urms0 = sqrt(F1B3 * urms0 / fsize);
1090
1091 MInt fftLocSize = 0;
1092 ptrdiff_t alloc_local = 0, local_n0 = 0, local_0_start = 0;
1093 fftw_complex* hatField = nullptr;
1094 fftw_plan plan;
1095
1096 const MFloat time0 = MPI_Wtime();
1097
1098 const ptrdiff_t n[3] = {nx, ny, nz};
1099#ifndef MAIA_WINDOWS
1100 alloc_local = (domainId < maxRank) ? fftw_mpi_local_size_many(rank, n, howmany, FFTW_MPI_DEFAULT_BLOCK, MPI_COMM_FFTW,
1101 &local_n0, &local_0_start)
1102 : 1;
1103#endif
1104
1105 ScratchSpace<fftw_complex> hatFieldMem(alloc_local, AT_, "hatFieldMem");
1106 if(domainId < maxRank) {
1107 hatField = &hatFieldMem[0];
1108 } else {
1109 alloc_local = 0;
1110 local_n0 = 0;
1111 local_0_start = nx;
1112 }
1113
1114 ScratchSpace<MLong> offsets(noDomains + 1, AT_, "offsets");
1115 ScratchSpace<MInt> noRecv(noDomains, AT_, "noRecv");
1116 ScratchSpace<MInt> noSend(noDomains, AT_, "noSend");
1117 noRecv.fill(0);
1118 noSend.fill(0);
1119 MLong locOffset = (domainId < maxRank) ? ((MInt)local_0_start) * ny * nz : size;
1120
1121 MPI_Allgather(&locOffset, 1, MPI_LONG, &offsets[0], 1, MPI_LONG, comm, AT_, "locOffset", "offsets[0]");
1122 offsets(noDomains) = size;
1123 if(domainId < maxRank) {
1124 if(offsets(domainId) != locOffset || offsets(domainId + 1) != ((MInt)(local_0_start + local_n0)) * ny * nz)
1125 mTerm(1, AT_, "wrong size 0");
1126 }
1127 for(MInt i = 0; i < locSize; i++) {
1128 MInt j = indices(i);
1129 MInt nghbrDomain = mMin(maxRank - 1, j / (size / maxRank));
1130 while(j < offsets(nghbrDomain) || j >= offsets(nghbrDomain + 1)) {
1131 if(j < offsets(nghbrDomain)) nghbrDomain--;
1132 if(j >= offsets(nghbrDomain + 1)) nghbrDomain++;
1133 }
1134 if(nghbrDomain >= maxRank) mTerm(1, AT_, "wrong domain");
1135 noSend(nghbrDomain)++;
1136 }
1137 MPI_Alltoall(&noSend[0], 1, MPI_INT, &noRecv[0], 1, MPI_INT, comm, AT_, "noSend[0]", "noRecv[0]");
1138 MInt sendSize = 0;
1139 MInt recvSize = 0;
1140 ScratchSpace<MInt> recvOffsets(noDomains + 1, AT_, "recvOffsets");
1141 ScratchSpace<MInt> sendOffsets(noDomains + 1, AT_, "sendOffsets");
1142 for(MInt i = 0; i < noDomains; i++) {
1143 recvOffsets(i) = recvSize;
1144 sendOffsets(i) = sendSize;
1145 sendSize += noSend(i);
1146 recvSize += noRecv(i);
1147 }
1148 recvOffsets(noDomains) = recvSize;
1149 sendOffsets(noDomains) = sendSize;
1150 ScratchSpace<MFloat> recvData(mMax(1, recvSize), howmany, AT_, "recvData");
1151 ScratchSpace<MFloat> sendData(mMax(1, sendSize), howmany, AT_, "sendData");
1152 ScratchSpace<MInt> recvIndices(mMax(1, recvSize), AT_, "recvIndices");
1153 ScratchSpace<MInt> sendIndices(mMax(1, sendSize), AT_, "sendIndices");
1154 noSend.fill(0);
1155 for(MInt i = 0; i < locSize; i++) {
1156 MInt j = indices(i);
1157 MInt nghbrDomain = mMin(maxRank - 1, j / (size / maxRank));
1158 while(j < offsets(nghbrDomain) || j >= offsets(nghbrDomain + 1)) {
1159 if(j < offsets(nghbrDomain)) nghbrDomain--;
1160 if(j >= offsets(nghbrDomain + 1)) nghbrDomain++;
1161 }
1162 if(nghbrDomain >= maxRank) mTerm(1, AT_, "wrong domain");
1163 if(sendOffsets(nghbrDomain) + noSend(nghbrDomain) >= sendOffsets(nghbrDomain + 1)) mTerm(1, AT_, "wrong size");
1164 for(MInt k = 0; k < howmany; k++) {
1165 sendData(sendOffsets(nghbrDomain) + noSend(nghbrDomain), k) = velocity(i, k);
1166 }
1167 sendIndices(sendOffsets(nghbrDomain) + noSend(nghbrDomain)) = j;
1168 if(j < offsets(nghbrDomain) || j >= offsets(nghbrDomain + 1)) mTerm(1, AT_, "wrong size 01");
1169 noSend(nghbrDomain)++;
1170 }
1171 for(MInt i = 0; i < noDomains; i++) {
1172 if(noSend(i) != sendOffsets(i + 1) - sendOffsets(i)) mTerm(1, AT_, "wrong size 1");
1173 if(noRecv(i) != recvOffsets(i + 1) - recvOffsets(i)) mTerm(1, AT_, "wrong size 1");
1174 }
1175
1176 ScratchSpace<MPI_Request> sendReq(noDomains, AT_, "sendReq");
1177 sendReq.fill(MPI_REQUEST_NULL);
1178 MInt cnt = 0;
1179 for(MInt i = 0; i < noDomains; i++) {
1180 if(noSend(i) == 0) continue;
1181 MPI_Issend(&sendData[howmany * sendOffsets(i)], howmany * noSend(i), MPI_DOUBLE, i, 123, comm, &sendReq[cnt], AT_,
1182 "sendData[howmany * sendOffsets(i)]");
1183 cnt++;
1184 }
1185 for(MInt i = 0; i < noDomains; i++) {
1186 if(noRecv(i) == 0) continue;
1187 MPI_Recv(&recvData[howmany * recvOffsets(i)], howmany * noRecv(i), MPI_DOUBLE, i, 123, comm, MPI_STATUS_IGNORE, AT_,
1188 "recvData[howmany * recvOffsets(i)]");
1189 }
1190 if(cnt > 0) MPI_Waitall(cnt, &sendReq[0], MPI_STATUSES_IGNORE, AT_);
1191 sendReq.fill(MPI_REQUEST_NULL);
1192 cnt = 0;
1193 for(MInt i = 0; i < noDomains; i++) {
1194 if(noSend(i) == 0) continue;
1195 MPI_Issend(&sendIndices[sendOffsets(i)], noSend(i), MPI_INT, i, 124, comm, &sendReq[cnt], AT_,
1196 "sendIndices[sendOffsets(i)]");
1197 cnt++;
1198 }
1199 for(MInt i = 0; i < noDomains; i++) {
1200 if(noRecv(i) == 0) continue;
1201 MPI_Recv(&recvIndices[recvOffsets(i)], noRecv(i), MPI_INT, i, 124, comm, MPI_STATUS_IGNORE, AT_,
1202 "recvIndices[recvOffsets(i)]");
1203 }
1204 if(cnt > 0) MPI_Waitall(cnt, &sendReq[0], MPI_STATUSES_IGNORE, AT_);
1205
1206 if(domainId < maxRank) {
1207 for(MInt i = 0; i < recvSize; i++) {
1208 MInt j = recvIndices(i);
1209 if(j < ((MInt)local_0_start) * ny * nz || j >= ((MInt)(local_0_start + local_n0)) * ny * nz)
1210 mTerm(1, AT_, "wrong size 2");
1211 MInt pos = j - (((MInt)local_0_start) * ny * nz);
1212 for(MInt k = 0; k < howmany; k++) {
1213 hatField[howmany * pos + k][0] = recvData(i, k); // Real part of fourier transformed velocity
1214 hatField[howmany * pos + k][1] = F0; // Imaginary part of fourier transformed velocity
1215 }
1216 }
1217 fftLocSize = recvSize;
1218
1219 MFloat couplcheck = F0;
1220 for(MInt i = 0; i < fftLocSize; i++) {
1221 for(MInt k = 0; k < 3; k++) {
1222 couplcheck -= hatField[howmany * i + k][0] * hatField[howmany * i + 3 + k][0];
1223 }
1224 }
1225 MPI_Allreduce(MPI_IN_PLACE, &couplcheck, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_FFTW, AT_, "MPI_IN_PLACE", "couplcheck");
1226 if(domainId == 0)
1227 std::cerr << "couplecheck fft " << couplcheck << " " << couplcheck * POW3(0.25 / 64.0) << std::endl;
1228 }
1229
1230 // Perform Fourier transform
1231 if(domainId < maxRank) {
1232#ifndef MAIA_WINDOWS
1233 plan = fftw_mpi_plan_many_dft(rank, n, howmany, FFTW_MPI_DEFAULT_BLOCK, FFTW_MPI_DEFAULT_BLOCK, hatField, hatField,
1234 MPI_COMM_FFTW, FFTW_FORWARD, FFTW_ESTIMATE);
1235 fftw_execute(plan);
1236 fftw_destroy_plan(plan);
1237#endif
1238 for(MInt i = 0; i < fftLocSize; i++) {
1239 for(MInt j = 0; j < howmany; j++) {
1240 hatField[howmany * i + j][0] /= fsize;
1241 hatField[howmany * i + j][1] /= fsize;
1242 }
1243 }
1244 }
1245
1246 const MFloat time1 = MPI_Wtime();
1247
1248 m_log << "parallel fftw time " << time1 - time0 << std::endl;
1249
1250 // Set coefficients:
1251 // FFTW stores the coefficients for positive wavenumbers in the first half of the array,
1252 // and those for negative wavenumbers in reverse order in the second half.
1253 // [0, 1, ... , N/2-1, N/2, ... , N-1]
1254 // - the entry for zero-wavenumber is at position 0
1255 // - the k-th entry and the (N-k)th entry correspond to wavenumbers with opposite sign
1256 // - the entry at position N/2 corresponds to the Nyquist wavenumber and appears only once
1257
1258 static const MInt referenceCubeSize =
1259 ((Context::propertyExists("referenceCubeSize")) ? Context::getBasicProperty<MInt>("referenceCubeSize", AT_) : 1);
1260
1261 static const MInt kMinSpec = ((Context::propertyExists("kMin")) ? Context::getBasicProperty<MInt>("kMin", AT_) : 0);
1262
1263 static const MInt kMaxSpec = ((Context::propertyExists("kMax")) ? Context::getBasicProperty<MInt>("kMax", AT_) : 0);
1264
1265 const MFloat k0 = F2 * PI / referenceCubeSize;
1266 MInt noBins = 0;
1267 MFloat kMin = 0.0;
1268 MFloat kMax = 0.0;
1269 MFloat deltaK = 0.0;
1270 if(kMinSpec > 0 && kMaxSpec > 0) {
1271 noBins = kMaxSpec;
1272 kMin = static_cast<float>(kMinSpec) * k0;
1273 kMax = static_cast<float>(kMaxSpec) * k0;
1274 deltaK = (kMax - kMin) / ((MFloat)(kMaxSpec - 1));
1275 } else {
1276 noBins = mMax(nx, mMax(ny, nz)) / 2;
1277 kMin = F1 * k0;
1278 kMax = noBins * k0;
1279 deltaK = (kMax - kMin) / ((MFloat)(noBins - 1));
1280 }
1281
1282 // const MInt noBins = 200;
1283 // const MFloat kMax = 200.0*k0;
1284 ScratchSpace<MFloat> spectrumBnd(noBins + 1, AT_, "spectrumBnd");
1285 ScratchSpace<MFloat> spectrum(noBins, AT_, "spectrum");
1286 ScratchSpace<MFloat> coupling(noBins, AT_, "coupling");
1287 ScratchSpace<MFloat> transfer(noBins, AT_, "transfer");
1288 ScratchSpace<MFloat> transfer2(noBins, AT_, "transfer2");
1289 ScratchSpace<MFloat> rate(noBins, AT_, "rate");
1290 ScratchSpace<MFloat> flux(noBins, 2, AT_, "flux");
1291 ScratchSpace<MFloat> flux2(noBins, 2, AT_, "flux2");
1292 ScratchSpace<MFloat> spectrumSum(noBins, AT_, "spectrumSum");
1293 ScratchSpace<MFloat> spectrumSum2(noBins, AT_, "spectrumSum2");
1294 spectrumBnd[0] = kMin - F1B2 * deltaK;
1295 const MFloat spectrumBnd00 = kMin - F3B4 * deltaK;
1296 for(MInt i = 0; i < noBins; i++) {
1297 spectrumBnd[i + 1] = spectrumBnd[i] + deltaK;
1298 }
1299 spectrum.fill(F0);
1300 coupling.fill(F0);
1301 transfer.fill(F0);
1302 transfer2.fill(F0);
1303 rate.fill(F0);
1304 flux.fill(F0);
1305 flux2.fill(F0);
1306 spectrumSum.fill(F0);
1307 spectrumSum2.fill(F0);
1308
1309 // beware: very expensive routine
1310 static const MBool computeTransferRate =
1311 ((Context::propertyExists("computeTransferRate")) ? Context::getBasicProperty<MBool>("computeTransferRate", AT_)
1312 : false);
1313 if(computeTransferRate) {
1314 MIntScratchSpace noDatPerDomain(noDomains, AT_, "noDatPerDomain");
1315 MIntScratchSpace dataOffsets(noDomains + 1, AT_, "dataOffsets");
1316 MPI_Allgather(&fftLocSize, 1, MPI_INT, &noDatPerDomain[0], 1, MPI_INT, comm, AT_, "fftLocSize",
1317 "noDatPerDomain[0]");
1318 dataOffsets.fill(0);
1319 for(MInt d = 0; d < noDomains; d++) {
1320 dataOffsets(d + 1) = dataOffsets(d) + noDatPerDomain(d);
1321 }
1322
1323 MPI_Request sendReqLoc = MPI_REQUEST_NULL;
1324 fftw_complex* uHatGlobal = fftw_alloc_complex(3 * size);
1325 fftw_complex* uHatGlobalTmp = nullptr;
1326 for(MInt i = 0; i < fftLocSize; i++) {
1327 for(MInt j = 0; j < 3; j++) {
1328 uHatGlobal[3 * i + j][0] = hatField[howmany * i + j][0];
1329 uHatGlobal[3 * i + j][1] = hatField[howmany * i + j][1];
1330 }
1331 }
1332 if(fftLocSize > 0) {
1333 MPI_Issend(&uHatGlobal[0], 6 * fftLocSize, MPI_DOUBLE, 0, 18, comm, &sendReqLoc, AT_, "uHatGlobal[0]");
1334 }
1335 if(domainId == 0) {
1336 uHatGlobalTmp = fftw_alloc_complex(3 * size);
1337 for(MInt d = 0; d < noDomains; d++) {
1338 if(noDatPerDomain[d] > 0) {
1339 MPI_Recv(&(uHatGlobalTmp[3 * dataOffsets[d]][0]), 6 * noDatPerDomain[d], MPI_DOUBLE, d, 18, comm,
1340 MPI_STATUSES_IGNORE, AT_, "(uHatGlobalTmp[3 * dataOffsets[d]][0])");
1341 }
1342 }
1343 }
1344 if(fftLocSize > 0) {
1345 MPI_Wait(&sendReqLoc, MPI_STATUSES_IGNORE, AT_);
1346 }
1347
1348 if(domainId == 0) {
1349 // re-sort by ascending wave numbers
1350 for(MInt i0 = 0; i0 < nx; i0++) {
1351 for(MInt i1 = 0; i1 < ny; i1++) {
1352 for(MInt i2 = 0; i2 < nz; i2++) {
1353 MInt j0 = (i0 > nx / 2) ? i0 - nx : i0;
1354 MInt j1 = (i1 > ny / 2) ? i1 - ny : i1;
1355 MInt j2 = (i2 > nz / 2) ? i2 - nz : i2;
1356 j0 += nx / 2 - 1;
1357 j1 += nx / 2 - 1;
1358 j2 += nx / 2 - 1;
1359 MInt pos0 = getGlobalPosFFTW(i0, i1, i2, ny, nz);
1360 MInt pos1 = getGlobalPosFFTW(j0, j1, j2, ny, nz);
1361 for(MInt j = 0; j < 3; j++) {
1362 uHatGlobal[3 * pos1 + j][0] = uHatGlobalTmp[3 * pos0 + j][0];
1363 uHatGlobal[3 * pos1 + j][1] = uHatGlobalTmp[3 * pos0 + j][1];
1364 }
1365 }
1366 }
1367 }
1368 fftw_free(uHatGlobalTmp);
1369 }
1370
1371 MPI_Bcast(&uHatGlobal[0], 6 * size, MPI_DOUBLE, 0, comm, AT_, "uHatGlobal");
1372
1373
1374 // MInt domainSize = size/noDomains;
1375 // MInt posMin = domainSize*domainId;
1376 // MInt posMax = mMin(size,domainSize*(domainId+1));
1377 // cerr << domainId << ": pos " << posMin << " " << posMax << std::endl;
1378
1379 MInt noWaveNumbers = 0;
1380 MLong weightSum = 0;
1381 for(MInt pos = 0; pos < size; pos++) {
1382 MInt i2 = pos % nz;
1383 MInt i1 = (pos / nz) % ny;
1384 MInt i0 = pos / (ny * nz);
1385 if(pos != i2 + nz * (i1 + ny * (i0))) mTerm(1, AT_, "index mismatch");
1386 MFloat k[3];
1387 MInt j0 = i0 - nx / 2 + 1;
1388 MInt j1 = i1 - ny / 2 + 1;
1389 MInt j2 = i2 - nz / 2 + 1;
1390 k[0] = ((MFloat)j0) * k0;
1391 k[1] = ((MFloat)j1) * k0;
1392 k[2] = ((MFloat)j2) * k0;
1393
1394 MFloat kAbs = sqrt(k[0] * k[0] + k[1] * k[1] + k[2] * k[2]);
1395 if(kAbs > spectrumBnd[noBins] + 1e-12) continue;
1396 if(kAbs < spectrumBnd[0] - 1e-12) continue;
1397
1398 MInt p0Min = std::max(0, i0 - nx / 2);
1399 MInt p0Max = std::min(nx, i0 + nx / 2);
1400 MInt p1Min = std::max(0, i1 - ny / 2);
1401 MInt p1Max = std::min(ny, i1 + ny / 2);
1402 MInt p2Min = std::max(0, i2 - nz / 2);
1403 MInt p2Max = std::min(nz, i2 + nz / 2);
1404 MLong weight = ((p0Max - p0Min) * (p1Max - p1Min) * (p2Max - p2Min));
1405
1406 weightSum += weight;
1407 noWaveNumbers++;
1408 }
1409 // MInt domainSize = noWaveNumbers/noDomains;
1410 MLong noDomainsLong = (MLong)noDomains;
1411 MLong domainIdLong = (MLong)domainId;
1412 MLong domainSize = weightSum / noDomainsLong;
1413 MInt posMin = 0;
1414 MInt posMax = size;
1415 noWaveNumbers = 0;
1416 weightSum = 0;
1417 for(MInt pos = 0; pos < size; pos++) {
1418 MInt i2 = pos % nz;
1419 MInt i1 = (pos / nz) % ny;
1420 MInt i0 = pos / (ny * nz);
1421 if(pos != i2 + nz * (i1 + ny * (i0))) mTerm(1, AT_, "index mismatch");
1422 MFloat k[3];
1423 MInt j0 = i0 - nx / 2 + 1;
1424 MInt j1 = i1 - ny / 2 + 1;
1425 MInt j2 = i2 - nz / 2 + 1;
1426 k[0] = ((MFloat)j0) * k0;
1427 k[1] = ((MFloat)j1) * k0;
1428 k[2] = ((MFloat)j2) * k0;
1429
1430 MFloat kAbs = sqrt(k[0] * k[0] + k[1] * k[1] + k[2] * k[2]);
1431 if(kAbs > spectrumBnd[noBins] + 1e-12) continue;
1432 if(kAbs < spectrumBnd[0] - 1e-12) continue;
1433
1434 MInt p0Min = std::max(0, i0 - nx / 2);
1435 MInt p0Max = std::min(nx, i0 + nx / 2);
1436 MInt p1Min = std::max(0, i1 - ny / 2);
1437 MInt p1Max = std::min(ny, i1 + ny / 2);
1438 MInt p2Min = std::max(0, i2 - nz / 2);
1439 MInt p2Max = std::min(nz, i2 + nz / 2);
1440 MLong weight = ((p0Max - p0Min) * (p1Max - p1Min) * (p2Max - p2Min));
1441
1442 if(weightSum <= (domainSize * domainIdLong) && (weightSum + weight) > (domainSize * domainIdLong)) posMin = pos;
1443 if(weightSum <= (domainSize * (domainIdLong + 1)) && (weightSum + weight) > (domainSize * (domainIdLong + 1)))
1444 posMax = pos;
1445
1446 weightSum += weight;
1447 noWaveNumbers++;
1448 }
1449
1450 weightSum = 0;
1451 for(MInt pos = posMin; pos < posMax; pos++) {
1452 const MInt i2 = pos % nz;
1453 const MInt i1 = (pos / nz) % ny;
1454 const MInt i0 = pos / (ny * nz);
1455
1456 const MInt j0 = i0 - nx / 2 + 1;
1457 const MInt j1 = i1 - ny / 2 + 1;
1458 const MInt j2 = i2 - nz / 2 + 1;
1459 const MFloat k[3] = {((MFloat)j0) * k0, ((MFloat)j1) * k0, ((MFloat)j2) * k0};
1460 const MFloat kAbs2 = mMax(1e-12, k[0] * k[0] + k[1] * k[1] + k[2] * k[2]);
1461 const MFloat kAbs = mMax(1e-12, sqrt(k[0] * k[0] + k[1] * k[1] + k[2] * k[2]));
1462
1463 if(kAbs > spectrumBnd[noBins] + 1e-12) continue;
1464 const MInt bin = ((MInt)((kAbs - spectrumBnd[0] + 1e-12) / deltaK));
1465 const MInt bin2 = ((MInt)((kAbs - spectrumBnd00 + 1e-12) / deltaK));
1466
1467 const MFloat kjl[3][3] = {
1468 {1.0 - (k[0] * k[0] / kAbs2), 0.0 - (k[0] * k[1] / kAbs2), 0.0 - (k[0] * k[2] / kAbs2)},
1469 {0.0 - (k[1] * k[0] / kAbs2), 1.0 - (k[1] * k[1] / kAbs2), 0.0 - (k[1] * k[2] / kAbs2)},
1470 {0.0 - (k[2] * k[0] / kAbs2), 0.0 - (k[2] * k[1] / kAbs2), 1.0 - (k[2] * k[2] / kAbs2)}};
1471
1472 const MInt p0Min = std::max(0, i0 - nx / 2);
1473 const MInt p0Max = std::min(nx, i0 + nx / 2);
1474 const MInt p1Min = std::max(0, i1 - ny / 2);
1475 const MInt p1Max = std::min(ny, i1 + ny / 2);
1476 const MInt p2Min = std::max(0, i2 - nz / 2);
1477 const MInt p2Max = std::min(nz, i2 + nz / 2);
1478
1479 MFloat trans = F0;
1480
1481 for(MInt p0 = p0Min; p0 < p0Max; p0++) {
1482 for(MInt p1 = p1Min; p1 < p1Max; p1++) {
1483 for(MInt p2 = p2Min; p2 < p2Max; p2++) {
1484 const MInt pos1 = p2 + nz * (p1 + ny * (p0));
1485 const MInt s0 = i0 - p0 + nx / 2 - 1;
1486 const MInt s1 = i1 - p1 + ny / 2 - 1;
1487 const MInt s2 = i2 - p2 + nz / 2 - 1;
1488 const MInt pos2 = s2 + nz * (s1 + ny * (s0));
1489
1490 for(MInt i = 0; i < 3; i++) {
1491 for(MInt j = 0; j < 3; j++) {
1492 for(MInt l = 0; l < 3; l++) {
1493 trans += k[i] * kjl[j][l]
1494 * triadImag(uHatGlobal[3 * pos1 + l], uHatGlobal[3 * pos2 + i], uHatGlobal[3 * pos + j]);
1495 }
1496 }
1497 }
1498 }
1499 }
1500 }
1501
1502 if(bin > -1 && bin < noBins) transfer(bin) += trans;
1503 if(bin2 > -1 && bin2 < noBins) transfer2(bin2) += trans;
1504 }
1505
1506 MPI_Allreduce(MPI_IN_PLACE, &transfer[0], noBins, MPI_DOUBLE, MPI_SUM, comm, AT_, "MPI_IN_PLACE", "transfer[0]");
1507 MPI_Allreduce(MPI_IN_PLACE, &transfer2[0], noBins, MPI_DOUBLE, MPI_SUM, comm, AT_, "MPI_IN_PLACE", "transfer2[0]");
1508 fftw_free(uHatGlobal);
1509 }
1510
1511 const MFloat time2 = MPI_Wtime();
1512
1513 if(domainId < maxRank) {
1514 for(MInt i0 = (MInt)local_0_start; i0 < (MInt)(local_0_start + local_n0); i0++) {
1515 for(MInt i1 = 0; i1 < ny; i1++) {
1516 for(MInt i2 = 0; i2 < nz; i2++) {
1517 MFloat k[3];
1518 MInt j0 = (i0 > nx / 2) ? i0 - nx : i0;
1519 MInt j1 = (i1 > ny / 2) ? i1 - ny : i1;
1520 MInt j2 = (i2 > nz / 2) ? i2 - nz : i2;
1521 k[0] = ((MFloat)j0) * k0;
1522 k[1] = ((MFloat)j1) * k0;
1523 k[2] = ((MFloat)j2) * k0;
1524
1525 MInt pos = i2 + nz * (i1 + ny * (i0 - ((MInt)local_0_start)));
1526 if(pos < 0 || pos >= fftLocSize) mTerm(1, AT_, "wrong size 3");
1527
1528 MFloat kAbs = sqrt(k[0] * k[0] + k[1] * k[1] + k[2] * k[2]);
1529 MFloat eng = F0;
1530 MFloat coupl = F0;
1531 MFloat dedt = F0;
1532 for(MInt q = 0; q < 3; q++) {
1533 eng += F1B2 * (POW2(hatField[howmany * pos + q][0]) + POW2(hatField[howmany * pos + q][1]));
1534 }
1535
1536 // if not only velocity field is passed as argument, also coupling rate Psi(k) and change of Energy dE/dt is
1537 // computed
1538 if(howmany > 3) {
1539 for(MInt q = 0; q < 3; q++) {
1540 coupl += (hatField[howmany * pos + q][0] * hatField[howmany * pos + 3 + q][0]
1541 + hatField[howmany * pos + q][1] * hatField[howmany * pos + 3 + q][1]);
1542 dedt += (hatField[howmany * pos + 6 + q][0] * hatField[howmany * pos + q][0]
1543 + hatField[howmany * pos + 6 + q][1] * hatField[howmany * pos + q][1]);
1544 }
1545 }
1546 if(kAbs > spectrumBnd[noBins] + 1e-12) continue;
1547
1548 MInt bin = ((MInt)((kAbs - spectrumBnd[0] + 1e-12) / deltaK));
1549 MInt bin2 = ((MInt)((kAbs - spectrumBnd00 + 1e-12) / deltaK));
1550 if(bin > -1 && bin < noBins) {
1551 spectrum(bin) += eng;
1552 coupling(bin) += coupl;
1553 rate(bin) += dedt;
1554 spectrumSum(bin) += F1;
1555 }
1556 if(bin2 > -1 && bin2 < noBins) {
1557 spectrumSum2(bin2) += F1;
1558 }
1559 }
1560 }
1561 }
1562
1563 MPI_Allreduce(MPI_IN_PLACE, &spectrum[0], noBins, MPI_DOUBLE, MPI_SUM, MPI_COMM_FFTW, AT_, "MPI_IN_PLACE",
1564 "spectrum[0]");
1565 MPI_Allreduce(MPI_IN_PLACE, &coupling[0], noBins, MPI_DOUBLE, MPI_SUM, MPI_COMM_FFTW, AT_, "MPI_IN_PLACE",
1566 "coupling[0]");
1567 MPI_Allreduce(MPI_IN_PLACE, &rate[0], noBins, MPI_DOUBLE, MPI_SUM, MPI_COMM_FFTW, AT_, "MPI_IN_PLACE", "rate[0]");
1568 MPI_Allreduce(MPI_IN_PLACE, &spectrumSum[0], noBins, MPI_DOUBLE, MPI_SUM, MPI_COMM_FFTW, AT_, "MPI_IN_PLACE",
1569 "spectrumSum[0]");
1570 MPI_Allreduce(MPI_IN_PLACE, &spectrumSum2[0], noBins, MPI_DOUBLE, MPI_SUM, MPI_COMM_FFTW, AT_, "MPI_IN_PLACE",
1571 "spectrumSum2[0]");
1572
1573 for(MInt i = 0; i < noBins; i++) {
1574 MFloat db = spectrumBnd00 - spectrumBnd[0];
1575 MFloat vol =
1576 F4B3 * PI * (POW3(spectrumBnd[i + 1]) - POW3(spectrumBnd[i])) / (spectrumBnd[i + 1] - spectrumBnd[i]);
1577 MFloat vol2 = F4B3 * PI * (POW3(spectrumBnd[i + 1] + db) - POW3(spectrumBnd[i] + db))
1578 / (spectrumBnd[i + 1] - spectrumBnd[i]);
1579 spectrum(i) *= vol / (spectrumSum(i) * POW3(k0));
1580 coupling(i) *= vol / (spectrumSum(i) * POW3(k0));
1581 transfer(i) *= vol / (spectrumSum(i) * POW3(k0));
1582 transfer2(i) *= vol2 / (spectrumSum2(i) * POW3(k0));
1583 rate(i) *= vol / (spectrumSum(i) * POW3(k0));
1584 }
1585
1586 for(MInt i = 0; i < noBins; i++) {
1587 flux(i, 0) = F0;
1588 flux(i, 1) = F0;
1589 for(MInt j = 0; j < i; j++) {
1590 flux(i, 0) += transfer(j) * (spectrumBnd[j + 1] - spectrumBnd[j]) / k0;
1591 }
1592 for(MInt j = i; j < noBins; j++) {
1593 flux(i, 1) += transfer(j) * (spectrumBnd[j + 1] - spectrumBnd[j]) / k0;
1594 }
1595 flux2(i, 0) = F0;
1596 flux2(i, 1) = F0;
1597 for(MInt j = 0; j < i; j++) {
1598 flux2(i, 0) += transfer2(j) * (spectrumBnd[j + 1] - spectrumBnd[j]) / k0;
1599 }
1600 for(MInt j = i; j < noBins; j++) {
1601 flux2(i, 1) += transfer2(j) * (spectrumBnd[j + 1] - spectrumBnd[j]) / k0;
1602 }
1603 }
1604
1605 if(domainId == 0) {
1606 std::ofstream ofl;
1607 std::ofstream ofl2;
1608 ofl.open("./out/energySpectrum_00" + std::to_string(globalTimeStep), std::ios_base::out | std::ios_base::trunc);
1609 ofl2.open("./out/energySpectrum_coarse_00" + std::to_string(globalTimeStep),
1610 std::ios_base::out | std::ios_base::trunc);
1611 if(ofl.is_open() && ofl.good() && ofl2.is_open() && ofl2.good()) {
1612 MFloat energy = F0;
1613 MFloat dissip = F0;
1614 MFloat length = F0;
1615 MFloat dedt = F0;
1616 MFloat force = F0;
1617 MFloat urms = F0;
1618 MFloat transf = F0;
1619 MFloat transf2 = F0;
1620 for(MInt i = 0; i < noBins; i++) {
1621 urms += spectrum(i) * (spectrumBnd[i + 1] - spectrumBnd[i]);
1622 }
1623 urms = sqrt(F2B3 * urms); // warum hier 2/3 und nicht 1/3
1624 for(MInt i = 0; i < noBins; i++) {
1625 MFloat k = F1B2 * (spectrumBnd[i + 1] + spectrumBnd[i]);
1626 MFloat Ek = spectrum(i);
1627 if(std::isnan(Ek) || std::isnan(coupling(i)) || std::isnan(rate(i))) continue;
1628 energy += (spectrumBnd[i + 1] - spectrumBnd[i]) * Ek;
1629 dissip += F2 * viscosity * POW2(k) * (spectrumBnd[i + 1] - spectrumBnd[i]) * Ek;
1630 length += (F1B2 * PI / POW2(urms)) * (spectrumBnd[i + 1] - spectrumBnd[i]) * Ek / (k);
1631 force += (spectrumBnd[i + 1] - spectrumBnd[i]) * coupling(i);
1632 dedt += (spectrumBnd[i + 1] - spectrumBnd[i]) * rate(i);
1633 transf += (spectrumBnd[i + 1] - spectrumBnd[i]) * transfer(i);
1634 transf2 += (spectrumBnd[i + 1] - spectrumBnd[i]) * transfer2(i);
1635 }
1636 ofl << "# Energy spectrum at time step " << globalTimeStep << ", total energy Ek=" << energy
1637 << ", dissipation rate=" << dissip << ", u_rms=" << urms << " (" << urms0
1638 << "), integral length scale=" << length << ", Kolmogorov time scale=" << sqrt(viscosity / dissip)
1639 << ", coupling=" << force << ", dedt=" << dedt << ", transfer=" << transf << ", transfer2=" << transf2
1640 << std::endl;
1641 ofl << "# 1: wave number k" << std::endl;
1642 ofl << "# 2: energy E(k)" << std::endl;
1643 ofl << "# 3: viscous dissipation rate D(k)" << std::endl;
1644 ofl << "# 4: transfer rate T(k)" << std::endl;
1645 ofl << "# 5: coupling rate Psi(k)" << std::endl;
1646 ofl << "# 6: flux -F(k)" << std::endl;
1647 ofl << "# 7: flux F(k)" << std::endl;
1648 ofl << "# 8: dE/dt(k)" << std::endl;
1649 ofl << "# 9: alternative transfer rate T(k)" << std::endl;
1650 ofl << "# 10: alternative flux -F(k)" << std::endl;
1651 ofl << "# 11: alternative flux F(k)" << std::endl;
1652 ofl << "# 12: number of samples in corresponding bin" << std::endl;
1653 ofl << "# 13: lower boundary of corresponding bin" << std::endl;
1654 ofl << "# 14: upper boundary of corresponding bin" << std::endl;
1655 ofl << "# 15: number of samples other spectrum: " << std::endl;
1656 ofl << "# 16: 4 * PI * k^2" << std::endl;
1657 ofl << "# 17: 4/3 * PI * (upperBndry^3 - lowerBndry^3)" << std::endl;
1658 for(MInt i = 0; i < noBins; i++) {
1659 MFloat k = F1B2 * (spectrumBnd[i + 1] + spectrumBnd[i]);
1660 MFloat Ek = spectrum(i);
1661 MFloat coupl = coupling(i);
1662 MFloat trans = transfer(i);
1663 MFloat trans2 = transfer2(i);
1664 ofl << k / k0 << " " << Ek << " " << F2 * POW2(k) * viscosity * Ek << " " << trans << " " << coupl << " "
1665 << flux(i, 0) << " " << flux(i, 1) << " " << rate(i) << " " << trans2 << " " << flux2(i, 0) << " "
1666 << flux2(i, 1) << " " << spectrumSum(i) << " " << spectrumBnd[i] << " " << spectrumBnd[i + 1] << " "
1667 << spectrumSum2(i) << " " << F4 * PI * POW2(k) << " "
1668 << F4B3 * PI * (POW3(spectrumBnd[i + 1]) - POW3(spectrumBnd[i])) << std::endl;
1669 }
1670 for(MInt i = 0; i < noBins / 2; i++) {
1671 const MInt i0 = 2 * i;
1672 const MInt i1 = 2 * i + 1;
1673 const MFloat k = F1B2 * (spectrumBnd[i1 + 1] + spectrumBnd[i0]);
1674 MFloat vol0 =
1675 F4B3 * PI * (POW3(spectrumBnd[i0 + 1]) - POW3(spectrumBnd[i0])) / (spectrumBnd[i0 + 1] - spectrumBnd[i0]);
1676 MFloat vol1 =
1677 F4B3 * PI * (POW3(spectrumBnd[i1 + 1]) - POW3(spectrumBnd[i1])) / (spectrumBnd[i1 + 1] - spectrumBnd[i1]);
1678 MFloat vol =
1679 F4B3 * PI * (POW3(spectrumBnd[i1 + 1]) - POW3(spectrumBnd[i0])) / (spectrumBnd[i1 + 1] - spectrumBnd[i0]);
1680 MFloat f0 = spectrumSum(i0) * vol / (vol0 * (spectrumSum(i0) + spectrumSum(i1)));
1681 MFloat f1 = spectrumSum(i1) * vol / (vol1 * (spectrumSum(i0) + spectrumSum(i1)));
1682
1683 ofl2 << k / k0 << " " << f1 * spectrum(i1) + f0 * spectrum(i0) << " "
1684 << F2 * POW2(k) * viscosity * (f1 * spectrum(i1) + f0 * spectrum(i0)) << " "
1685 << f1 * transfer(i1) + f0 * transfer(i0) << " " << f1 * coupling(i1) + f0 * coupling(i0) << " "
1686 << f1 * flux(i1, 0) + f0 * flux(i0, 0) << " " << f1 * flux(i1, 1) + f0 * flux(i0, 1) << " "
1687 << f1 * rate(i1) + f0 * rate(i0) << " " << f1 * transfer2(i1) + f0 * transfer2(i0) << " "
1688 << f1 * flux2(i1, 0) + f0 * flux2(i0, 0) << " " << f1 * flux2(i1, 1) + f0 * flux2(i0, 1) << " "
1689 << spectrumSum(i0) + spectrumSum(i1) << " " << spectrumBnd[i0] << " " << spectrumBnd[i1 + 1] << " "
1690 << spectrumSum2(i0) + spectrumSum2(i1) << " " << F4 * PI * POW2(k) << " "
1691 << F4B3 * PI * (POW3(spectrumBnd[i1 + 1]) - POW3(spectrumBnd[i0])) << std::endl;
1692 }
1693 ofl.close();
1694 ofl2.close();
1695 }
1696 }
1697
1698 // cleanup
1699 // fftw_cleanup(); problems occur when calling clean up function!!!
1700 }
1701
1702 const MFloat time3 = MPI_Wtime();
1703
1704 if(domainId == 0)
1705 std::cerr << "fft time " << time1 - time0 << " " << time2 - time1 << " " << time3 - time2 << std::endl;
1706
1707 m_log << "fft finished" << std::endl;
1708
1709 DEBUG("computeEnergySpectrum return", MAIA_DEBUG_TRACE_OUT);
1710}
static MBool propertyExists(const MString &name, MInt solver=m_noSolvers)
This function checks if a property exists in general.
Definition: context.cpp:494
This class is a ScratchSpace.
Definition: scratch.h:758
constexpr Real POW3(const Real x)
Definition: functions.h:123
constexpr Real POW2(const Real x)
Definition: functions.h:119
constexpr T mMin(const T &x, const T &y)
Definition: functions.h:90
constexpr T mMax(const T &x, const T &y)
Definition: functions.h:94
MInt globalTimeStep
InfoOutFile m_log
int64_t MLong
Definition: maiatypes.h:64
bool MBool
Definition: maiatypes.h:58
int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status, const MString &name, const MString &varname)
same as MPI_Recv
int MPI_Issend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &varname)
same as MPI_Issend
int MPI_Wait(MPI_Request *request, MPI_Status *status, const MString &name)
same as MPI_Wait
int MPI_Waitall(int count, MPI_Request *request, MPI_Status *status, const MString &name)
same as MPI_Waitall
int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allreduce
int MPI_Alltoall(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Alltoall
int MPI_Comm_split(MPI_Comm comm, int color, int key, MPI_Comm *newcomm, const MString &name, const MString &varname)
same as MPI_Comm_split, but updates the number of MPI communicators
int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm, const MString &name, const MString &varname)
same as MPI_Bcast
int MPI_Allgather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allgather
void indices(const MInt i, const MInt n, MInt *const ids)
Calculate the 2D/3D indices for a given scalar id for accessing a field of n^nDim points.
MFloat triadImag(fftw_complex &a, fftw_complex &b, fftw_complex &c)
Definition: maiafftw.h:61
MInt getGlobalPosFFTW(MInt i0, MInt i1, MInt i2, MInt ny, MInt nz)
Definition: maiafftw.h:59

◆ computeRotationMatrix()

void maia::math::computeRotationMatrix ( MFloatScratchSpace R,
MFloat q 
)
inline
Author
Lennart Schneiders

Definition at line 533 of file maiamath.h.

533 {
534 R(0, 0) = q[0] * q[0] + q[1] * q[1] - q[2] * q[2] - q[3] * q[3];
535 R(1, 1) = q[0] * q[0] - q[1] * q[1] + q[2] * q[2] - q[3] * q[3];
536 R(2, 2) = q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3];
537
538 R(0, 1) = F2 * (q[1] * q[2] + q[0] * q[3]);
539 R(0, 2) = F2 * (q[1] * q[3] - q[0] * q[2]);
540 R(1, 0) = F2 * (q[1] * q[2] - q[0] * q[3]);
541 R(1, 2) = F2 * (q[2] * q[3] + q[0] * q[1]);
542 R(2, 0) = F2 * (q[1] * q[3] + q[0] * q[2]);
543 R(2, 1) = F2 * (q[2] * q[3] - q[0] * q[1]);
544}

◆ ConvertToEigenMatrix()

template<typename T , std::size_t N>
Eigen::MatrixXd maia::math::ConvertToEigenMatrix ( std::array< std::array< T, N >, N >  data)

Definition at line 66 of file maiamath.cpp.

66 {
67 Eigen::Matrix<T, N, N> m;
68 for(std::size_t i = 0; i < N; ++i) {
69 m.row(i) = Eigen::VectorXd::Map(&data[i][0], N);
70 }
71 return m;
72}

◆ crankAngle()

MFloat maia::math::crankAngle ( const MFloat  time,
const MFloat  Strouhal,
const MFloat  offset,
const MInt  mode 
)
inline
Author
Tim Wegmann

Definition at line 506 of file maiamath.h.

506 {
507 const MFloat mu2 = Strouhal * F2 * PI;
508 MFloat cad = mu2 * time;
509
510 if(mode == 0) {
511 const MInt maxNoCycles = 20;
512 for(MInt cycle = maxNoCycles; cycle > 0; cycle--) {
513 if(cad >= 4 * PI * cycle) {
514 cad = cad - 4 * PI * cycle;
515 }
516 }
517 cad = cad * 180 / PI;
518
519 cad = cad + offset;
520
521 } else {
522 ASSERT(mode == 1, "Incorrect mode!");
523 cad = cad + offset * PI / 180;
524 }
525
526 return cad;
527}

◆ cross() [1/5]

template<typename T >
T maia::math::cross ( const std::array< T, 2 > &  u,
const std::array< T, 2 > &  v 
)
inline

Definition at line 120 of file maiamath.h.

120 {
121 return u[0] * v[1] - u[1] * v[0];
122}

◆ cross() [2/5]

template<typename T >
std::array< T, 3 > maia::math::cross ( const std::array< T, 3 > &  u,
const std::array< T, 3 > &  v 
)
inline

Cross product C = U x V [3D]

Template Parameters
TType
Parameters
[in]uU
[in]vV
Returns
New copy of an array

Definition at line 113 of file maiamath.h.

113 {
114 std::array<T, 3> result;
115 cross(&u[0], &v[0], &result[0]);
116 return result;
117}
void cross(const T *const u, const T *const v, T *const c)
Definition: maiamath.h:101

◆ cross() [3/5]

template<typename T >
void maia::math::cross ( const T *const  u,
const T *const  v,
T *const  c 
)
inline

Cross product C = U x V [3D]

Template Parameters
TType
Parameters
[in]uU
[in]vV
[out]cC
Author
Sven Berger

Definition at line 101 of file maiamath.h.

101 {
102 c[0] = u[1] * v[2] - v[1] * u[2];
103 c[1] = u[2] * v[0] - v[2] * u[0];
104 c[2] = u[0] * v[1] - v[0] * u[1];
105}

◆ cross() [4/5]

template<typename T >
T maia::math::cross ( const T(&)  u[2],
const T(&)  v[2] 
)
inline

Definition at line 137 of file maiamath.h.

137 {
138 return u[0] * v[1] - u[1] * v[0];
139}

◆ cross() [5/5]

template<typename T >
T * maia::math::cross ( const T(&)  u[3],
const T(&)  v[3] 
)
inline

Cross product C = U x V [3D]

Template Parameters
TType
Parameters
[in]uU
[in]vV
Returns
New copy of an array

Definition at line 130 of file maiamath.h.

130 {
131 T result[3]{};
132 cross(&u[0], &v[0], &result[0]);
133 return result;
134}

◆ deltaFun()

MFloat maia::math::deltaFun ( const MFloat  r,
const MFloat  r0,
const MFloat  r1 
)
inline

Definition at line 885 of file maiamath.h.

885 {
886 MFloat R = mMin(F1, mMax(F0, ((r - r0) / (r1 - r0))));
887#if MAIA_TRANSITION_FUNCTION == 0
888 return (r < r1) ? F0 : F1;
889#elif MAIA_TRANSITION_FUNCTION == 1
890 return R;
891#elif MAIA_TRANSITION_FUNCTION == 2
892 return POW2(R) * (3.0 - 2.0 * R);
893#elif MAIA_TRANSITION_FUNCTION == 3
894 return POW3(R) * (10.0 + R * (6.0 * R - 15.0)); // may cause stability issues
895#elif MAIA_TRANSITION_FUNCTION == 4
896 return POW3(R) * (6.0 + R * (2.0 * R - 7.0)); // approximates 0.5*(1.0-cos(PI*pow(R,1.25)));
897#elif MAIA_TRANSITION_FUNCTION == 5
898 return F1B2 * (F1 + sin(PI * (F3B2 + R)));
899#endif
900}

◆ determinant() [1/2]

template<typename T , std::size_t N>
MFloat maia::math::determinant ( std::array< std::array< T, N >, N > &  m)

Determinant of a matrix

Template Parameters
TType
NDimension of the square matrix
Parameters
mMatrix (two dimensional array containing the matrix elements)
Returns
Determinant of the matrix

Definition at line 145 of file maiamath.cpp.

145 {
146 Eigen::Matrix<T, N, N> matrix(&m[0][0]);
147 return matrix.determinant();
148}

◆ determinant() [2/2]

template<typename T , std::size_t N>
MFloat maia::math::determinant ( std::array< T, N > &  m)

Determinant of a matrix

Template Parameters
TType
NSize of the matrix (rows * columns)
Parameters
mMatrix (one dimensional array containing the matrix elements)
Returns
Determinant of the matrix

Definition at line 130 of file maiamath.cpp.

130 {
131 constexpr MInt dim = N == 2 ? 1 : 2;
132 Eigen::Matrix<T, dim, dim> matrix(m.data());
133 return matrix.determinant();
134}

◆ determinant< MFloat, 2ul >() [1/2]

template MFloat maia::math::determinant< MFloat, 2ul > ( std::array< MFloat, 2ul > &  )

◆ determinant< MFloat, 2ul >() [2/2]

template MFloat maia::math::determinant< MFloat, 2ul > ( std::array< std::array< MFloat, 2ul >, 2ul > &  )

◆ determinant< MFloat, 3ul >() [1/2]

template MFloat maia::math::determinant< MFloat, 3ul > ( std::array< MFloat, 3ul > &  )

◆ determinant< MFloat, 3ul >() [2/2]

template MFloat maia::math::determinant< MFloat, 3ul > ( std::array< std::array< MFloat, 3ul >, 3ul > &  )

◆ determinant< MFloat, 4ul >() [1/2]

template MFloat maia::math::determinant< MFloat, 4ul > ( std::array< MFloat, 4ul > &  )

◆ determinant< MFloat, 4ul >() [2/2]

template MFloat maia::math::determinant< MFloat, 4ul > ( std::array< std::array< MFloat, 4ul >, 4ul > &  )

◆ distance() [1/7]

template<MInt nDim>
MFloat maia::math::distance ( const MFloat a,
const MFloat b 
)
inline

Definition at line 249 of file maiamath.h.

249 {
250 IF_CONSTEXPR(nDim == 2) { return sqrt(POW2(a[0] - b[0]) + POW2(a[1] - b[1])); }
251 IF_CONSTEXPR(nDim == 3) { return sqrt(POW2(a[0] - b[0]) + POW2(a[1] - b[1]) + POW2(a[2] - b[2])); }
252 return -NAN;
253}
Definition: contexttypes.h:19

◆ distance() [2/7]

MFloat maia::math::distance ( const MFloat *const  a,
const std::array< MFloat, 2 >  b 
)
inline

Definition at line 263 of file maiamath.h.

263 {
264 return sqrt(POW2(a[0] - b[0]) + POW2(a[1] - b[1]));
265}

◆ distance() [3/7]

MFloat maia::math::distance ( const MFloat *const  a,
const std::array< MFloat, 3 >  b 
)
inline

Definition at line 267 of file maiamath.h.

267 {
268 return sqrt(POW2(a[0] - b[0]) + POW2(a[1] - b[1]) + POW2(a[2] - b[2]));
269}

◆ distance() [4/7]

MFloat maia::math::distance ( const std::array< MFloat, 2 >  a,
const MFloat *const  b 
)
inline

Definition at line 271 of file maiamath.h.

271 {
272 return sqrt(POW2(a[0] - b[0]) + POW2(a[1] - b[1]));
273}

◆ distance() [5/7]

MFloat maia::math::distance ( const std::array< MFloat, 2 >  a,
const std::array< MFloat, 2 >  b 
)
inline

Definition at line 255 of file maiamath.h.

255 {
256 return sqrt(POW2(a[0] - b[0]) + POW2(a[1] - b[1]));
257}

◆ distance() [6/7]

MFloat maia::math::distance ( const std::array< MFloat, 3 >  a,
const std::array< MFloat, 3 >  b 
)
inline

Definition at line 259 of file maiamath.h.

259 {
260 return sqrt(POW2(a[0] - b[0]) + POW2(a[1] - b[1]) + POW2(a[2] - b[2]));
261}

◆ distance() [7/7]

MFloat maia::math::distance ( std::array< MFloat, 3 >  a,
const MFloat *const  b 
)
inline

Definition at line 275 of file maiamath.h.

275 {
276 return sqrt(POW2(a[0] - b[0]) + POW2(a[1] - b[1]) + POW2(a[2] - b[2]));
277}

◆ frobeniusMatrixNorm()

MFloat maia::math::frobeniusMatrixNorm ( MFloatScratchSpace m,
MInt  dim1,
MInt  dim2 
)
inline

Definition at line 339 of file maiamath.h.

339 {
340 return sqrt(frobeniusMatrixNormSquared(m, dim1, dim2));
341}
MFloat frobeniusMatrixNormSquared(MFloatScratchSpace &m, MInt dim1, MInt dim2)
Definition: maiamath.h:328

◆ frobeniusMatrixNormSquared()

MFloat maia::math::frobeniusMatrixNormSquared ( MFloatScratchSpace m,
MInt  dim1,
MInt  dim2 
)
inline

Definition at line 328 of file maiamath.h.

328 {
329 MFloat ret_val = 0.0;
330 for(MInt i = 0; i < dim1; i++) {
331 for(MInt j = 0; j < dim2; j++) {
332 ret_val += m(i, j) * m(i, j);
333 }
334 }
335
336 return ret_val;
337}

◆ getAngle()

MFloat maia::math::getAngle ( MFloat  y,
MFloat  z 
)
inline

Definition at line 925 of file maiamath.h.

925 {
926 MFloat angle = atan(z / y);
927 if(y < 0) {
928 if(z >= 0) {
929 angle += PI;
930 } else {
931 angle -= PI;
932 }
933 }
934 return angle;
935}

◆ getFourierCoefficient()

std::complex< MFloat > * maia::math::getFourierCoefficient ( MFloat k,
MFloat  k0,
const MFloat  Ma 
)
inline

brief Generates a single std::complex coefficient of Fourier series

for a given wavenumber k, and a certain energy spectrum (see Appendix of Orszag, 1969)

Definition at line 548 of file maiafftw.h.

548 {
549 TRACE();
550
551 MFloat r[6], s[6], kAbs, energy;
552 std::complex<MFloat> uHat, vHat, wHat;
553 std::complex<MFloat>* fourierCoefficient;
554
555 kAbs = sqrt(k[0] * k[0] + k[1] * k[1] + k[2] * k[2]);
556
557 // the zero-frequency component is always set to zero, so there is no offset
558 if(approx(kAbs, 0.0, MFloatEps)) {
559 fourierCoefficient = new std::complex<MFloat>[3];
560
561 fourierCoefficient[0] = std::complex<MFloat>(0, 0);
562 fourierCoefficient[1] = std::complex<MFloat>(0, 0);
563 fourierCoefficient[2] = std::complex<MFloat>(0, 0);
564
565
566 return fourierCoefficient;
567
568 } else {
569 // energy = (kAbs/k0)*(kAbs/k0)*(kAbs/k0)*(kAbs/k0) * exp(-2.0*(kAbs/k0)*(kAbs/k0));
570 // energy = pow(kAbs/k0,8.0) * exp(-4.0*(kAbs/k0)*(kAbs/k0)); // set spectral distribution
571 energy = pow(kAbs / k0, 4.0) * exp(-2.0 * (kAbs / k0) * (kAbs / k0)); // set spectral distribution
572 energy *= exp(2.0) * 0.499 * (Ma * LBCS)
573 * (Ma * LBCS); // set maximal fluctuation amplitude to 20% of the freestream velocity (for 128^3: 0.88)
574
575 // determine Fourier coefficients:
576 // r and s are Independant random vector fields with independant
577 // components (zero mean and rms according to energy spectrum).
578 // Each vector has three components for k and another three for -k.
579
580 for(MInt i = 0; i < 6; i++) {
581 r[i] = randnormal(0.0, PI * sqrt(energy) / (SQRT2 * kAbs));
582 // r[i] = randNumGen.randNorm(0.0, PI*sqrt(energy)/(SQRT2*kAbs));
583 s[i] = randnormal(0.0, PI * sqrt(energy) / (SQRT2 * kAbs));
584 // s[i] = randNumGen.randNorm(0.0, PI*sqrt(energy)/(SQRT2*kAbs));
585 }
586
587 uHat = (1.0 - k[0] * k[0] / (kAbs * kAbs)) * std::complex<MFloat>(r[0] + r[3], s[0] - s[3])
588 - k[0] * k[1] / (kAbs * kAbs) * std::complex<MFloat>(r[1] + r[4], s[1] - s[4])
589 - k[0] * k[2] / (kAbs * kAbs) * std::complex<MFloat>(r[2] + r[5], s[2] - s[5]);
590
591
592 vHat = -k[1] * k[0] / (kAbs * kAbs) * std::complex<MFloat>(r[0] + r[3], s[0] - s[3])
593 + (1.0 - k[1] * k[1] / (kAbs * kAbs)) * std::complex<MFloat>(r[1] + r[4], s[1] - s[4])
594 - k[1] * k[2] / (kAbs * kAbs) * std::complex<MFloat>(r[2] + r[5], s[2] - s[5]);
595
596
597 wHat = -k[2] * k[0] / (kAbs * kAbs) * std::complex<MFloat>(r[0] + r[3], s[0] - s[3])
598 - k[2] * k[1] / (kAbs * kAbs) * std::complex<MFloat>(r[1] + r[4], s[1] - s[4])
599 + (1.0 - k[2] * k[2] / (kAbs * kAbs)) * std::complex<MFloat>(r[2] + r[5], s[2] - s[5]);
600
601 fourierCoefficient = new std::complex<MFloat>[3];
602
603 // fourierCoefficient[0] = std::complex<MFloat>(sqrt(2*energy)/SQRT2,sqrt(2*energy)/SQRT2);// uHat;
604 // fourierCoefficient[1] = std::complex<MFloat>(sqrt(2*energy)/SQRT2,sqrt(2*energy)/SQRT2);//vHat;
605 // fourierCoefficient[2] = std::complex<MFloat>(sqrt(2*energy)/SQRT2,sqrt(2*energy)/SQRT2);//wHat;
606
607 fourierCoefficient[0] = uHat;
608 fourierCoefficient[1] = vHat;
609 fourierCoefficient[2] = wHat;
610 return fourierCoefficient;
611 }
612}

◆ getFourierCoefficient2()

std::complex< MFloat > * maia::math::getFourierCoefficient2 ( MFloat k,
MFloat  k0 
)
inline

brief Generates a single std::complex coefficient of Fourier series

for a given wavenumber k, and a certain energy spectrum

Definition at line 620 of file maiafftw.h.

620 {
621 static std::mt19937 randNumGen;
622 static std::uniform_real_distribution<> distrib{0.0, 1.0};
623
624 MFloat r[3], kAbs, energy;
625 std::complex<MFloat> uHat, vHat, wHat;
626 std::complex<MFloat>* fourierCoefficient;
627
628 kAbs = sqrt(k[0] * k[0] + k[1] * k[1] + k[2] * k[2]);
629
630 // the zero-frequency component is always set to zero, so there is no offset
631 if(approx(kAbs, 0.0, MFloatEps)) {
632 fourierCoefficient = new std::complex<MFloat>[3];
633
634 fourierCoefficient[0] = std::complex<MFloat>(0, 0);
635 fourierCoefficient[1] = std::complex<MFloat>(0, 0);
636 fourierCoefficient[2] = std::complex<MFloat>(0, 0);
637
638
639 return fourierCoefficient;
640
641 } else {
642 // energy = pow(kAbs/k0,4.0) * exp(-2.0*(kAbs/k0)*(kAbs/k0));
643 // energy = ( m_Ma*LBCS * m_Ma*LBCS ) * pow(kAbs/k0,4.0) * exp(-2.0*(kAbs/k0)*(kAbs/k0));
644 // energy = 0.135335;
645 energy = (kAbs / k0) * (kAbs / k0) * (kAbs / k0) * (kAbs / k0) * exp(-2.0 * (kAbs / k0) * (kAbs / k0));
646
647 // determine Fourier coefficients:
648 for(MInt i = 0; i < 3; i++) {
649 r[i] = 2.0 * PI * distrib(randNumGen);
650 }
651
652 uHat = std::complex<MFloat>(cos(r[0]) * energy, sin(r[0]) * energy);
653 vHat = std::complex<MFloat>(cos(r[1]) * energy, sin(r[1]) * energy);
654 wHat = std::complex<MFloat>(cos(r[2]) * energy, sin(r[2]) * energy);
655
656 fourierCoefficient = new std::complex<MFloat>[3];
657
658 fourierCoefficient[0] = uHat;
659 fourierCoefficient[1] = vHat;
660 fourierCoefficient[2] = wHat;
661
662
663 return fourierCoefficient;
664 }
665}
T cos(const T a, const T b, const T x)
Cosine slope filter.
Definition: filter.h:125

◆ getGlobalPosFFTW()

MInt maia::math::getGlobalPosFFTW ( MInt  i0,
MInt  i1,
MInt  i2,
MInt  ny,
MInt  nz 
)
inline

Definition at line 59 of file maiafftw.h.

59{ return i2 + nz * (i1 + ny * i0); }

◆ getSector()

MFloat maia::math::getSector ( MFloat  y,
MFloat  z,
MFloat  azimuthalAngle 
)
inline

Definition at line 912 of file maiamath.h.

912 {
913 MFloat angle = atan(z / y);
914 if(y < 0) {
915 if(z >= 0) {
916 angle += PI;
917 } else {
918 angle -= PI;
919 }
920 }
921 angle += PI;
922 return (angle - std::fmod(angle, azimuthalAngle / 180.0 * PI)) / (azimuthalAngle / 180.0 * PI);
923}

◆ initFft()

void maia::math::initFft ( fftw_complex *  uPhysField,
fftw_complex *  vPhysField,
fftw_complex *  wPhysField,
MInt  lx,
MInt  ly,
MInt  lz,
MInt  noPeakModes,
const MFloat  Ma 
)
inline
Author
george
Date
09.12.2011

(u,v,w) PhysField: complex velocity in physical space

Parameters
uPhysFieldpointer to a fftw_complex for u
vPhysFieldpointer to a fftw_complex for v
wPhysFieldpointer to a fftw_complex for w

ATTENTION: This version is quite old and should be thoroughly before use!

Definition at line 892 of file maiafftw.h.

899 {
900 TRACE();
901
902 MFloat waveVector[3], k0;
903
904 std::complex<MFloat>* fourierCoefficient;
905
906 fftw_complex *uHatField, *vHatField, *wHatField;
907
908 fftw_plan planU, planV, planW;
909
910 if(lx % 2 != 0 || ly % 2 != 0 || lz % 2 != 0) {
911 std::stringstream errorMessage;
912 errorMessage << " FFTInit: domainsize must NOT be an odd number! " << std::endl;
913 mTerm(1, AT_, errorMessage.str());
914 }
915
916 m_log << " --- initializing FFTW --- " << std::endl;
917 m_log << " domain size = " << lx << "x" << ly << "x" << lz << std::endl;
918
919 // allocate field of Fourier coefficients (is deleted after the transformation)
920 uHatField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
921 vHatField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
922 wHatField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
923
924 // create plans for FFTW
925 planU = fftw_plan_dft_3d(lx, ly, lz, uHatField, uPhysField, FFTW_BACKWARD, FFTW_MEASURE);
926 planV = fftw_plan_dft_3d(lx, ly, lz, vHatField, vPhysField, FFTW_BACKWARD, FFTW_MEASURE);
927 planW = fftw_plan_dft_3d(lx, ly, lz, wHatField, wPhysField, FFTW_BACKWARD, FFTW_MEASURE);
928
929 // reset coefficients and velocities
930 for(MInt p = 0; p < lx; p++) {
931 for(MInt q = 0; q < ly; q++) {
932 for(MInt r = 0; r < lz; r++) {
933 uHatField[r + lz * (q + ly * p)][0] = 0.0;
934 uHatField[r + lz * (q + ly * p)][1] = 0.0;
935 uPhysField[r + lz * (q + ly * p)][0] = 0.0;
936 uPhysField[r + lz * (q + ly * p)][1] = 0.0;
937
938 vHatField[r + lz * (q + ly * p)][0] = 0.0;
939 vHatField[r + lz * (q + ly * p)][1] = 0.0;
940 vPhysField[r + lz * (q + ly * p)][0] = 0.0;
941 vPhysField[r + lz * (q + ly * p)][1] = 0.0;
942
943 wHatField[r + lz * (q + ly * p)][0] = 0.0;
944 wHatField[r + lz * (q + ly * p)][1] = 0.0;
945 wPhysField[r + lz * (q + ly * p)][0] = 0.0;
946 wPhysField[r + lz * (q + ly * p)][1] = 0.0;
947 }
948 }
949 }
950
951 // Set coefficients:
952 // FFTW stores the coefficients for positive wavenumbers in the first half of the array,
953 // and those for negative wavenumbers in reverse order in the second half.
954 // [0, 1, ... , N/2-1, N/2, ... , N-1]
955 // - the entry for zero-wavenumber is at position 0
956 // - the k-th entry and the (N-k)th entry correspond to wavenumbers with opposite sign
957 // - the entry at position N/2 corresponds to the Nyquist wavenumber and appears only once
958
959 // peak wave number of energy spectrum
960 k0 = 2.0 * PI / (lx / noPeakModes);
961
962 for(MInt p = 0; p <= lx / 2; p++) {
963 for(MInt q = 0; q <= ly / 2; q++) {
964 for(MInt r = 0; r <= lz / 2; r++) {
965 // wave-vector: k(p,q,r) = (2 \pi p / lx, 2 \pi q / ly, 2 \pi r / lz)
966 waveVector[0] = (p)*2.0 * PI / lx;
967 waveVector[1] = (q)*2.0 * PI / ly;
968 waveVector[2] = (r)*2.0 * PI / lz;
969
970 fourierCoefficient = getFourierCoefficient(waveVector, k0, Ma);
971
972 // 1. Positive frequencies:
973 uHatField[r + lz * (q + ly * p)][0] = std::real(fourierCoefficient[0]);
974 uHatField[r + lz * (q + ly * p)][1] = std::imag(fourierCoefficient[0]);
975
976 vHatField[r + lz * (q + ly * p)][0] = std::real(fourierCoefficient[1]);
977 vHatField[r + lz * (q + ly * p)][1] = std::imag(fourierCoefficient[1]);
978
979 wHatField[r + lz * (q + ly * p)][0] = std::real(fourierCoefficient[2]);
980 wHatField[r + lz * (q + ly * p)][1] = std::imag(fourierCoefficient[2]);
981
982 // 2. Negative frequencies:
983 if(p > 1 && q > 1 && r > 1) {
984 if(p < lx / 2 && q < ly / 2 && r < lz / 2) {
985 // since the physical velocity field is real, the coefficients for negative frequencies
986 // are the std::complex conjugate of those for positive frequencies
987 uHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][0] = uHatField[r + lz * (q + ly * p)][0];
988 uHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][1] = -uHatField[r + lz * (q + ly * p)][1];
989
990 vHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][0] = vHatField[r + lz * (q + ly * p)][0];
991 vHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][1] = -vHatField[r + lz * (q + ly * p)][1];
992
993 wHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][0] = wHatField[r + lz * (q + ly * p)][0];
994 wHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][1] = -wHatField[r + lz * (q + ly * p)][1];
995 }
996 }
997 }
998 }
999 }
1000
1001 // // test:
1002 // // cos(x) in a cube with 32x32x32 cells
1003 // uHatField[(0+lz*(0+ly*2)=2048][0]=90.5;
1004 // uHatField[(0+lz*(0+ly*30)=30720][0]=90.5;
1005
1006 // Do Fourier transform (backward, see plan definition)
1007 // Definition in one dimension:
1008 // u(x) = \sum_{j=0}^{lx-1} \hat{u}_j exp(i 2 \pi j x / lx)
1009 fftw_execute(planU);
1010 fftw_execute(planV);
1011 fftw_execute(planW);
1012
1013 // normalize (this preserves the norm of the basis functions)
1014 for(MInt p = 0; p < lx; p++) {
1015 for(MInt q = 0; q < ly; q++) {
1016 for(MInt r = 0; r < lz; r++) {
1017 uPhysField[r + lz * (q + ly * p)][0] /= sqrt(MFloat(lx * ly * lz));
1018 vPhysField[r + lz * (q + ly * p)][0] /= sqrt(MFloat(lx * ly * lz));
1019 wPhysField[r + lz * (q + ly * p)][0] /= sqrt(MFloat(lx * ly * lz));
1020
1021 uPhysField[r + lz * (q + ly * p)][1] /= sqrt(MFloat(lx * ly * lz));
1022 vPhysField[r + lz * (q + ly * p)][1] /= sqrt(MFloat(lx * ly * lz));
1023 wPhysField[r + lz * (q + ly * p)][1] /= sqrt(MFloat(lx * ly * lz));
1024 }
1025 }
1026 }
1027
1028 fftw_destroy_plan(planU);
1029 fftw_destroy_plan(planV);
1030 fftw_destroy_plan(planW);
1031 fftw_free(uHatField);
1032 fftw_free(vHatField);
1033 fftw_free(wHatField);
1034}
constexpr std::underlying_type< FcCell >::type p(const FcCell property)
Converts property name to underlying integer value.
std::complex< MFloat > * getFourierCoefficient(MFloat *k, MFloat k0, const MFloat Ma)
Definition: maiafftw.h:548

◆ initFftFilter()

void maia::math::initFftFilter ( MFloat uPhysFieldCoarse,
MFloat vPhysFieldCoarse,
MFloat wPhysFieldCoarse,
MInt  lx,
MInt  ly,
MInt  lz,
MInt  lxCoarse,
MInt  lyCoarse,
MInt  lzCoarse,
MInt  noPeakModes,
const MFloat  Ma 
)
inline
Author
george
Date
24.01.2011

(u,v,w)PhysFieldCoarse: real velocity in physical space

Parameters
uPhysFieldCoarsepointer to a MFloat for u
vPhysFieldCoarsepointer to a MFloat for v
wPhysFieldCoarsepointer to a MFloat for w

ATTENTION: This version is quite old and should be thoroughly before use!

Definition at line 681 of file maiafftw.h.

691 {
692 TRACE();
693
694
695 MFloat waveVector[3], k0;
696
697 std::complex<MFloat>* fourierCoefficient;
698
699 fftw_complex *uHatField, *vHatField, *wHatField;
700 fftw_complex *uPhysField, *vPhysField, *wPhysField;
701
702 fftw_plan planU, planV, planW;
703
704 MInt xRatio = lx / lxCoarse;
705 MInt yRatio = ly / lyCoarse;
706 MInt zRatio = lz / lzCoarse;
707
708 if(lx % 2 != 0 || ly % 2 != 0 || lz % 2 != 0) {
709 mTerm(1, AT_, " FFTInit: domainsize must NOT be an odd number! ");
710 }
711
712 m_log << " --- initializing FFTW --- " << std::endl;
713 m_log << " domain size = " << lx << "x" << ly << "x" << lz << std::endl;
714
715 // allocate field of velocities (is deleted at the end of the method)
716 uPhysField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
717 vPhysField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
718 wPhysField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
719
720 // allocate field of Fourier coefficients (is deleted after the transformation)
721 uHatField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
722 vHatField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
723 wHatField = (fftw_complex*)fftw_malloc(lx * ly * lz * sizeof(fftw_complex));
724
725 // create plans for FFTW
726 planU = fftw_plan_dft_3d(lx, ly, lz, uHatField, uPhysField, FFTW_BACKWARD, FFTW_MEASURE);
727 planV = fftw_plan_dft_3d(lx, ly, lz, vHatField, vPhysField, FFTW_BACKWARD, FFTW_MEASURE);
728 planW = fftw_plan_dft_3d(lx, ly, lz, wHatField, wPhysField, FFTW_BACKWARD, FFTW_MEASURE);
729
730 // reset coefficients and velocities
731 for(MInt p = 0; p < lx; p++) {
732 for(MInt q = 0; q < ly; q++) {
733 for(MInt r = 0; r < lz; r++) {
734 uHatField[r + lz * (q + ly * p)][0] = 0.0;
735 uHatField[r + lz * (q + ly * p)][1] = 0.0;
736 uPhysField[r + lz * (q + ly * p)][0] = 0.0;
737 uPhysField[r + lz * (q + ly * p)][1] = 0.0;
738
739 vHatField[r + lz * (q + ly * p)][0] = 0.0;
740 vHatField[r + lz * (q + ly * p)][1] = 0.0;
741 vPhysField[r + lz * (q + ly * p)][0] = 0.0;
742 vPhysField[r + lz * (q + ly * p)][1] = 0.0;
743
744 wHatField[r + lz * (q + ly * p)][0] = 0.0;
745 wHatField[r + lz * (q + ly * p)][1] = 0.0;
746 wPhysField[r + lz * (q + ly * p)][0] = 0.0;
747 wPhysField[r + lz * (q + ly * p)][1] = 0.0;
748 }
749 }
750 }
751
752 // Set coefficients:
753 // FFTW stores the coefficients for positive wavenumbers in the first half of the array,
754 // and those for negative wavenumbers in reverse order in the second half.
755 // [0, 1, ... , N/2-1, N/2, ... , N-1]
756 // - the entry for zero-wavenumber is at position 0
757 // - the k-th entry and the (N-k)th entry correspond to wavenumbers with opposite sign
758 // - the entry at position N/2 corresponds to the Nyquist wavenumber and appears only once
759
760 // peak wave number of energy spectrum
761 k0 = 2.0 * PI / (lx / noPeakModes);
762
763 for(MInt p = 0; p <= lx / 2; p++) {
764 for(MInt q = 0; q <= ly / 2; q++) {
765 for(MInt r = 0; r <= lz / 2; r++) {
766 // wave-vector: k(p,q,r) = (2 \pi p / lx, 2 \pi q / ly, 2 \pi r / lz)
767 waveVector[0] = (p)*2.0 * PI / lx;
768 waveVector[1] = (q)*2.0 * PI / ly;
769 waveVector[2] = (r)*2.0 * PI / lz;
770
771 fourierCoefficient = getFourierCoefficient(waveVector, k0, Ma);
772
773 // 1. Positive frequencies:
774 uHatField[r + lz * (q + ly * p)][0] = std::real(fourierCoefficient[0]);
775 uHatField[r + lz * (q + ly * p)][1] = std::imag(fourierCoefficient[0]);
776
777 vHatField[r + lz * (q + ly * p)][0] = std::real(fourierCoefficient[1]);
778 vHatField[r + lz * (q + ly * p)][1] = std::imag(fourierCoefficient[1]);
779
780 wHatField[r + lz * (q + ly * p)][0] = std::real(fourierCoefficient[2]);
781 wHatField[r + lz * (q + ly * p)][1] = std::imag(fourierCoefficient[2]);
782
783 // 2. Negative frequencies:
784 if(p > 1 && q > 1 && r > 1) {
785 if(p < lx / 2 && q < ly / 2 && r < lz / 2) {
786 // since the physical velocity field is real, the coefficients for negative frequencies
787 // are the std::complex conjugate of those for positive frequencies
788 uHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][0] = uHatField[r + lz * (q + ly * p)][0];
789 uHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][1] = -uHatField[r + lz * (q + ly * p)][1];
790
791 vHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][0] = vHatField[r + lz * (q + ly * p)][0];
792 vHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][1] = -vHatField[r + lz * (q + ly * p)][1];
793
794 wHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][0] = wHatField[r + lz * (q + ly * p)][0];
795 wHatField[(lz - r) + lz * ((ly - q) + ly * (lx - p))][1] = -wHatField[r + lz * (q + ly * p)][1];
796 }
797 }
798 }
799 }
800 }
801
802 // Do Fourier transform (backward, see plan definition)
803 // Definition in one dimension:
804 // u(x) = \sum_{j=0}^{lx-1} \hat{u}_j exp(i 2 \pi j x / lx)
805 fftw_execute(planU);
806 fftw_execute(planV);
807 fftw_execute(planW);
808
809 // normalize (this preserves the norm of the basis functions)
810 for(MInt p = 0; p < lx; p++) {
811 for(MInt q = 0; q < ly; q++) {
812 for(MInt r = 0; r < lz; r++) {
813 uPhysField[r + lz * (q + ly * p)][0] /= sqrt(MFloat(lx * ly * lz));
814 vPhysField[r + lz * (q + ly * p)][0] /= sqrt(MFloat(lx * ly * lz));
815 wPhysField[r + lz * (q + ly * p)][0] /= sqrt(MFloat(lx * ly * lz));
816
817 uPhysField[r + lz * (q + ly * p)][1] /= sqrt(MFloat(lx * ly * lz));
818 vPhysField[r + lz * (q + ly * p)][1] /= sqrt(MFloat(lx * ly * lz));
819 wPhysField[r + lz * (q + ly * p)][1] /= sqrt(MFloat(lx * ly * lz));
820 }
821 }
822 }
823
824 // // test:
825 // // cos(x) in a cube with 32x32x32 cells
826 // uHatField[(0+lz*(0+ly*2)=2048][0]=90.5;
827 // uHatField[(0+lz*(0+ly*30)=30720][0]=90.5;
828
829 // reset coarse fields
830 for(MInt p = 0; p < lxCoarse; p++) {
831 for(MInt q = 0; q < lyCoarse; q++) {
832 for(MInt r = 0; r < lzCoarse; r++) {
833 uPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] = F0;
834 vPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] = F0;
835 wPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] = F0;
836 }
837 }
838 }
839
840 // transfer physField to physFieldCoarse via arithmetic averaging
841 for(MInt p = 0; p < lxCoarse; p++) {
842 for(MInt q = 0; q < lyCoarse; q++) {
843 for(MInt r = 0; r < lzCoarse; r++) {
844 for(MInt i = p * xRatio; i < p * zRatio + xRatio; i++) {
845 for(MInt j = q * yRatio; j < q * zRatio + yRatio; j++) {
846 for(MInt k = r * zRatio; k < r * zRatio + zRatio; k++) {
847 uPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] += uPhysField[k + lz * (j + ly * i)][0];
848 vPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] += vPhysField[k + lz * (j + ly * i)][0];
849 wPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] += wPhysField[k + lz * (j + ly * i)][0];
850 }
851 }
852 }
853 }
854 }
855 }
856 for(MInt p = 0; p < lxCoarse; p++) {
857 for(MInt q = 0; q < lyCoarse; q++) {
858 for(MInt r = 0; r < lzCoarse; r++) {
859 uPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] /= (xRatio * yRatio * zRatio);
860 vPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] /= (xRatio * yRatio * zRatio);
861 wPhysFieldCoarse[r + lzCoarse * (q + lyCoarse * p)] /= (xRatio * yRatio * zRatio);
862 }
863 }
864 }
865
866 fftw_destroy_plan(planU);
867 fftw_destroy_plan(planV);
868 fftw_destroy_plan(planW);
869
870 fftw_free(uHatField);
871 fftw_free(vHatField);
872 fftw_free(wHatField);
873
874 fftw_free(uPhysField);
875 fftw_free(vPhysField);
876 fftw_free(wPhysField);
877}

◆ inverse()

MInt maia::math::inverse ( MFloat **  a,
MFloat **  ainv,
MInt  n,
const MFloat  epsilon 
)
inline

Definition at line 587 of file maiamath.h.

587 {
588 MInt s;
589 MInt pRow = 0; // pivot row
590 MBool error = false;
591 MFloat f;
592 MFloat maximum;
593 MInt pivot = 1;
594
595 // add the unity matrix
596 for(MInt i = 0; i < n; i++) {
597 for(MInt j = 0; j < n; j++) {
598 a[i][n + j] = F0;
599 if(i == j) {
600 a[i][n + j] = F1;
601 }
602 }
603 }
604
605 // Gauss algorithm
606 error = false;
607 s = 0;
608 while(s < n) {
609 maximum = fabs(a[s][s]);
610 if(pivot) {
611 pRow = s;
612 for(MInt i = s + 1; i < n; i++) {
613 if(fabs(a[i][s]) > maximum) {
614 maximum = fabs(a[i][s]);
615 pRow = i;
616 }
617 }
618 }
619 if(maximum < epsilon) {
620 error = true;
621 }
622
623 if(error) {
624 std::cerr << "Error in matrix inverse computation " << s << " " << a[s][s] << std::endl;
625 for(MInt i = 0; i < n; i++) {
626 for(MInt j = 0; j < n; j++) {
627 std::cerr << a[i][j] << " ";
628 }
629 std::cerr << std::endl;
630 }
631 // mTerm(1, AT_, "Error in matrix inverse computation ");
632 std::cerr << "Error in matrix inverse computation " << std::endl;
633 return 0;
634 }
635
636 if(pivot) {
637 if(pRow != s) // exchange rows if required
638 {
639 MFloat h;
640 for(MInt j = s; j < 2 * n; j++) {
641 h = a[s][j];
642 a[s][j] = a[pRow][j];
643 a[pRow][j] = h;
644 }
645 }
646 }
647
648 f = a[s][s];
649 for(MInt j = s; j < 2 * n; j++) {
650 a[s][j] = a[s][j] / f;
651 }
652
653 // elimination
654 for(MInt i = 0; i < n; i++) {
655 if(i != s) {
656 f = -a[i][s];
657 for(MInt j = s; j < 2 * n; j++) {
658 a[i][j] += f * a[s][j];
659 }
660 }
661 }
662 s++;
663 }
664
665 if(error) {
666 std::cerr << "Error 2 in inverse matrix computation" << std::endl;
667 // mTerm(1,AT_,"Error 2 in inverse matrix computation");
668 return 0;
669 }
670
671 // copy
672 for(MInt i = 0; i < n; i++) {
673 for(MInt j = 0; j < n; j++) {
674 ainv[i][j] = a[i][n + j];
675 }
676 }
677
678 return 1;
679}

◆ invert() [1/3]

void maia::math::invert ( MFloat A,
const MInt  m,
const MInt  n 
)

Definition at line 171 of file maiamath.cpp.

171 {
172 Eigen::Map<Eigen::MatrixXd> mA(A, m, n);
173 mA = mA.inverse();
174}

◆ invert() [2/3]

template<class T >
void maia::math::invert ( T &  A,
T &  AInv,
const MInt  m,
const MInt  n 
)

Note: don't use this for new code!!!!!!!!!!!!!!!!!!!!!!!!!!! Use instead: A.colPivHouseholderQR.solve(b) (general case) A.LLT.solve(b) (if the matrix is symmetric positive definite) (fastest) A.HouseHolderQR.solve(b) (need for speed) (less accurate)

Get the pseudo-inverse of A by using QR

Parameters
Asystem matrix (m x n)
AInvpseudo-inverse
mnumber of columns
nnumber of rows
Author
Sven Berger

Definition at line 189 of file maiamath.cpp.

189 {
190 if(n == 0 || m == 0) {
191 std::cerr << globalDomainId() << " Warning: empty eq. sys. (" << m << "x" << n << "), skip." << std::endl;
192 return;
193 }
194 Eigen::Matrix<MFloat, Eigen::Dynamic, Eigen::Dynamic> B(m, n);
195 Eigen::Matrix<MFloat, Eigen::Dynamic, Eigen::Dynamic> inv(n, m);
196 for(MInt i = 0; i < m; i++) {
197 for(MInt j = 0; j < n; j++) {
198 B(i, j) = A(i, j);
199 }
200 }
201 // if (n != m) {
202 // system is overdetermined/underdetermined
203 Eigen::CompleteOrthogonalDecomposition<Eigen::MatrixXd> orth(B);
204 inv = orth.pseudoInverse();
205 // todo labels:totest SSE optimization leads to false-positive during sanitizer run
206 // }
207 // else {
208 // inv = B.inverse();
209 // }
210 for(MInt i = 0; i < m; i++) {
211 for(MInt j = 0; j < n; j++) {
212 AInv(i, j) = inv(i, j);
213 }
214 }
215}
MInt globalDomainId()
Return global domain id.

◆ invert() [3/3]

template<class T >
void maia::math::invert ( T &  A,
T &  weights,
T &  AInv,
const MInt  m,
const MInt  n 
)

Note: don't use this for new code!!!!!!!!!!!!!!!!!!!!!!!!!!! Use instead: A.colPivHouseholderQR.solve(b) (general case) A.LLT.solve(b) (if the matrix is symmetric positive definite) (fastest) A.HouseHolderQR.solve(b) (need for speed) (less accurate)

Get the pseudo-inverse of A by using QR

Parameters
Asystem matrix (m x n)
AInvpseudo-inverse
weightsweights applied to A
mnumber of columns
nnumber of rows
Author
Sven Berger

Definition at line 235 of file maiamath.cpp.

235 {
236 if(n == 0 || m == 0) {
237 std::cerr << globalDomainId() << " Warning: empty eq. sys. (" << m << "x" << n << "), skip." << std::endl;
238 return;
239 }
240 Eigen::Matrix<MFloat, Eigen::Dynamic, Eigen::Dynamic> B(m, n);
241 Eigen::Matrix<MFloat, Eigen::Dynamic, Eigen::Dynamic> inv(n, m);
242 for(MInt i = 0; i < m; i++) {
243 for(MInt j = 0; j < n; j++) {
244 B(i, j) = weights[i] * A(i, j);
245 }
246 }
247 if(n != m) {
248 // system is overdetermined/underdetermined
249 Eigen::CompleteOrthogonalDecomposition<Eigen::MatrixXd> orth(B);
250 inv = orth.pseudoInverse();
251 } else {
252 inv = B.inverse();
253 }
254 for(MInt k = 0; k < n; ++k) {
255 for(MInt i = 0; i < m; ++i) {
256 AInv(k, i) = inv(k, i) * weights(i);
257 }
258 }
259}

◆ invert< maia::tensor::Tensor< MFloat > >() [1/2]

template void maia::math::invert< maia::tensor::Tensor< MFloat > > ( maia::tensor::Tensor< MFloat > &  ,
maia::tensor::Tensor< MFloat > &  ,
const  MInt,
const  MInt 
)

◆ invert< maia::tensor::Tensor< MFloat > >() [2/2]

template void maia::math::invert< maia::tensor::Tensor< MFloat > > ( maia::tensor::Tensor< MFloat > &  ,
maia::tensor::Tensor< MFloat > &  ,
maia::tensor::Tensor< MFloat > &  ,
const  MInt,
const  MInt 
)

◆ invert< ScratchSpace< MFloat > >() [1/2]

template void maia::math::invert< ScratchSpace< MFloat > > ( ScratchSpace< MFloat > &  ,
ScratchSpace< MFloat > &  ,
const  MInt,
const  MInt 
)

◆ invert< ScratchSpace< MFloat > >() [2/2]

template void maia::math::invert< ScratchSpace< MFloat > > ( ScratchSpace< MFloat > &  ,
ScratchSpace< MFloat > &  ,
ScratchSpace< MFloat > &  ,
const  MInt,
const  MInt 
)

◆ invertR()

template<class T >
MInt maia::math::invertR ( T &  A,
T &  weights,
T &  AInv,
const MInt  m,
const MInt  n 
)

Note: don't use this for new code!!!!!!!!!!!!!!!!!!!!!!!!!!! Use instead: A.colPivHouseholderQR.solve(b) (general case) A.LLT.solve(b) (if the matrix is symmetric positive definite) (fastest) A.HouseHolderQR.solve(b) (need for speed) (less accurate)

Get the pseudo-inverse of A by using QR

Parameters
Asystem matrix (m x n)
AInvpseudo-inverse
weightsweights applied to A
mnumber of columns
nnumber of rows
Returns
rank of the matrix A
Author
Sven Berger

Definition at line 280 of file maiamath.cpp.

280 {
281 if(n == 0 || m == 0) {
282 std::cerr << globalDomainId() << " Warning: empty eq. sys. (" << m << "x" << n << "), skip." << std::endl;
283 return -1;
284 }
285 Eigen::Matrix<MFloat, Eigen::Dynamic, Eigen::Dynamic> B(m, n);
286 Eigen::Matrix<MFloat, Eigen::Dynamic, Eigen::Dynamic> inv(n, m);
287 for(MInt i = 0; i < m; i++) {
288 for(MInt j = 0; j < n; j++) {
289 B(i, j) = weights[i] * A(i, j);
290 }
291 }
292
293 Eigen::CompleteOrthogonalDecomposition<Eigen::MatrixXd> orth(B);
294 inv = orth.pseudoInverse();
295 const MInt rank = orth.rank();
296
297 for(MInt k = 0; k < n; ++k) {
298 for(MInt i = 0; i < m; ++i) {
299 AInv(k, i) = inv(k, i) * weights(i);
300 }
301 }
302 return rank;
303}

◆ invertR< ScratchSpace< MFloat > >()

template MInt maia::math::invertR< ScratchSpace< MFloat > > ( ScratchSpace< MFloat > &  ,
ScratchSpace< MFloat > &  ,
ScratchSpace< MFloat > &  ,
const  MInt,
const  MInt 
)

◆ lincos()

MFloat maia::math::lincos ( MFloat  arg)
inline

Definition at line 426 of file maiamath.h.

426 {
427 MFloat SIGN = F1;
428 // lookuptable has 91 entries from 0 to pi/2
429 const MFloat darg = PIB2 / 90;
430
431 arg = std::fmod(std::abs(arg), F2 * PI);
432
433 if(arg > PI) {
434 SIGN *= -F1;
435 arg -= PI;
436 }
437
438 if(arg > PIB2) {
439 SIGN *= -F1;
440 arg = PI - arg;
441 }
442
443 const auto lowerInd = static_cast<MInt>(arg / darg);
444 const MFloat lowerVal = FTRIG[lowerInd];
445 const MFloat higherVal = FTRIG[lowerInd + 1];
446 const MFloat deltaArg = arg - lowerInd * darg;
447 const MFloat fac = deltaArg / darg;
448
449 return (lowerVal * (F1 - fac) + higherVal * fac) * SIGN;
450}

◆ linSpace()

std::vector< MFloat > maia::math::linSpace ( const MFloat  start,
const MFloat  end,
const MInt  num 
)
inline

Definition at line 903 of file maiamath.h.

903 {
904 std::vector<MFloat> linspaced(num);
905 MFloat delta = (end - start) / (MFloat(num) - F1);
906 for(auto i = 0; i < num; i++) {
907 linspaced[i] = start + delta * i;
908 }
909 return linspaced;
910}

◆ matrixVectorProduct()

void maia::math::matrixVectorProduct ( MFloat c,
MFloatScratchSpace A,
MFloat b 
)
inline
Author
Lennart Schneiders

Definition at line 561 of file maiamath.h.

561 {
562 for(MInt i = 0; i < A.size0(); i++) {
563 c[i] = F0;
564 for(MInt j = 0; j < A.size1(); j++) {
565 c[i] += A(i, j) * b[j];
566 }
567 }
568}
MInt size1() const
Definition: scratch.h:299
MInt size0() const
Definition: scratch.h:298

◆ matrixVectorProductTranspose()

void maia::math::matrixVectorProductTranspose ( MFloat c,
MFloatScratchSpace A,
MFloat b 
)
inline
Author
Lennart Schneiders

Definition at line 574 of file maiamath.h.

574 {
575 for(MInt i = 0; i < A.size1(); i++) {
576 c[i] = F0;
577 for(MInt j = 0; j < A.size0(); j++) {
578 c[i] += A(j, i) * b[j];
579 }
580 }
581}

◆ multiplyMatrices()

void maia::math::multiplyMatrices ( MFloatScratchSpace m1,
MFloatScratchSpace m2,
MFloatScratchSpace result,
MInt  m1_n,
MInt  m1_m,
MInt  m2_n,
MInt  m2_m 
)
inline

Definition at line 297 of file maiamath.h.

298 {
299 // m1 has the dimension n x m
300 // m2 has the dimension n x m
301 if(m1_m != m2_n) mTerm(1, AT_, "Dimension of matrix multiplication does not match!!!");
302 // init
303 for(MInt i = 0; i < m1_n; i++) {
304 for(MInt j = 0; j < m2_m; j++) {
305 result(i, j) = F0;
306 }
307 }
308
309 // multiply
310 for(MInt i = 0; i < m1_n; i++) {
311 for(MInt j = 0; j < m2_m; j++) {
312 for(MInt k = 0; k < m1_m; k++) {
313 result(i, j) += m1(i, k) * m2(k, j);
314 }
315 }
316 }
317}

◆ multiplyMatricesSq()

void maia::math::multiplyMatricesSq ( MFloatScratchSpace m1,
MFloatScratchSpace m2,
MFloatScratchSpace result,
MInt  dim 
)
inline

Definition at line 279 of file maiamath.h.

279 {
280 // init
281 for(MInt i = 0; i < dim; i++) {
282 for(MInt j = 0; j < dim; j++) {
283 result(i, j) = 0.0;
284 }
285 }
286
287 // multiply
288 for(MInt i = 0; i < dim; i++) {
289 for(MInt j = 0; j < dim; j++) {
290 for(MInt k = 0; k < dim; k++) {
291 result(i, j) += m1(i, k) * m2(k, j);
292 }
293 }
294 }
295}

◆ multiplySparseMatrixVector()

void maia::math::multiplySparseMatrixVector ( MFloat A_coeff,
MInt **  pos,
const MInt  n,
const MInt  m,
MFloat b,
MFloat x 
)

Solve b = A * x for dense matrix A using Cholesky or LU

Parameters
A_coeffnon-zero coefficients of the system matrix
posholds the position of the coefficients in the matrix A
nnumber of non-zero coefficients
msize of system matrix A
bunknown vector to be calculated by the product A * x
xknown vector
Author
Moritz Waldmann

Definition at line 431 of file maiamath.cpp.

431 {
432 Eigen::Map<MFloatVectorXd> B(b, m);
433 Eigen::Map<MFloatVectorXd> X(x, m);
434
435 MFloatMatrixXd A = MFloatMatrixXd::Zero(m, m);
436
437 for(MInt i = 0; i < n; i++) {
438 A(pos[i][0], pos[i][1]) = A_coeff[i];
439 }
440 B = A * X;
441}
Eigen::Matrix< MFloat, Eigen::Dynamic, Eigen::Dynamic > MFloatMatrixXd
Definition: maiamath.cpp:52

◆ norm() [1/2]

template<typename T , std::size_t N>
MFloat maia::math::norm ( const std::array< T, N > &  u)
inline

Length of a vector (L2-norm)

Template Parameters
TType
NLength of vector
Parameters
uVector
Returns
Magnitude of vector
Author
Sven Berger

Definition at line 148 of file maiamath.h.

148 {
149 static_assert(N > 1, "ERROR: Invalid norm call!");
150
151 if(N == 2) {
152 return std::sqrt(u[0] * u[0] + u[1] * u[1]);
153 }
154 if(N == 3) {
155 return std::sqrt(u[0] * u[0] + u[1] * u[1] + u[2] * u[2]);
156 }
157 return std::sqrt(std::accumulate(u.begin(), u.end(), 0.0, [](const MFloat& a, const T& b) { return a + b * b; }));
158}

◆ norm() [2/2]

template<typename T >
MFloat maia::math::norm ( const T *const  u,
const MInt  N 
)
inline

Length of a vector (L2-norm)

Template Parameters
TType
Parameters
NLength of vector
uVector
Returns
Magnitude of vector
Author
Sven Berger

Definition at line 167 of file maiamath.h.

167 {
168 ASSERT(N > 1, "ERROR: Invalid norm call!");
169
170 if(N == 2) {
171 return std::sqrt(u[0] * u[0] + u[1] * u[1]);
172 }
173 if(N == 3) {
174 return std::sqrt(u[0] * u[0] + u[1] * u[1] + u[2] * u[2]);
175 }
176
177 MFloat tmp = 0;
178 for(MInt i = 0; i < N; i++) {
179 tmp += u[i] * u[i];
180 }
181
182 return std::sqrt(tmp);
183}

◆ normalize() [1/2]

template<typename T , std::size_t N>
void maia::math::normalize ( std::array< T, N > &  u)
inline

Normalize a given vector (inplace)

Template Parameters
TType
NLength of the vector
Parameters
uVector to be normalized
Author
Sven Berger

Definition at line 191 of file maiamath.h.

191 {
192 const MFloat inverse = 1.0 / norm(u);
193
194 if(N == 2) {
195 u[0] *= inverse;
196 u[1] *= inverse;
197 return;
198 }
199 if(N == 3) {
200 u[0] *= inverse;
201 u[1] *= inverse;
202 u[2] *= inverse;
203 return;
204 }
205
206 std::for_each(u.begin(), u.end(), [inverse](T& a) { a *= inverse; });
207}
MFloat norm(const std::array< T, N > &u)
Definition: maiamath.h:148
MInt inverse(MFloat **a, MFloat **ainv, MInt n, const MFloat epsilon)
Definition: maiamath.h:587

◆ normalize() [2/2]

template<typename T >
void maia::math::normalize ( T *const  u,
const MInt  N 
)
inline

Normalize a given vector (inplace)

Template Parameters
TType
Parameters
NLength of the vector
uVector to be normalized
Author
Sven Berger

Definition at line 215 of file maiamath.h.

215 {
216 const MFloat inverse = 1.0 / norm(u, N);
217
218 if(N == 2) {
219 u[0] *= inverse;
220 u[1] *= inverse;
221 return;
222 }
223 if(N == 3) {
224 u[0] *= inverse;
225 u[1] *= inverse;
226 u[2] *= inverse;
227 return;
228 }
229
230 for(MInt i = 0; i < N; i++) {
231 u[i] *= inverse;
232 }
233}

◆ normalized()

template<typename T , std::size_t N>
std::array< T, N > maia::math::normalized ( const std::array< T, N > &  u)
inline

Normalize a given vector

Template Parameters
TType
NLength of the vector
Parameters
uVector to be normalized
Returns
New normalized vector
Author
Sven Berger

Definition at line 242 of file maiamath.h.

242 {
243 std::array<T, N> n(u);
244 normalize(n);
245 return n;
246}
void normalize(std::array< T, N > &u)
Definition: maiamath.h:191

◆ quatMult()

void maia::math::quatMult ( const MFloat *const  qA,
const MFloat *const  qB,
MFloat *const  qC 
)
inline

Definition at line 482 of file maiamath.h.

482 {
483 MFloat crossProduct[3]{};
484 cross(qA, qB, &crossProduct[0]);
485
486 const MFloat dot = std::inner_product(qA, &qA[3], qB, 0.0);
487
488 for(MInt n = 0; n < 3; n++) {
489 qC[n] = qA[3] * qB[n] + qB[3] * qA[n] + crossProduct[n];
490 }
491 qC[3] = qA[3] * qB[3] - dot;
492}

◆ quickSort()

void maia::math::quickSort ( MInt a,
MInt  start,
MInt  end 
)
inline

Definition at line 716 of file maiamath.h.

716{ maia::math::quickSortImpl(a, start, end); }
void quickSortImpl(MInt *a, MInt start, MInt end)
Definition: maiamath.h:704

◆ quickSortImpl()

void maia::math::quickSortImpl ( MInt a,
MInt  start,
MInt  end 
)
inline

Definition at line 704 of file maiamath.h.

704 {
705 MInt pivot;
706
707 if(start >= end) {
708 return;
709 }
710
711 pivot = maia::math::quickSortPartition(a, start, end);
712 maia::math::quickSort(a, start, pivot - 1);
713 maia::math::quickSort(a, pivot + 1, end);
714}
void quickSort(MInt *a, MInt start, MInt end)
Definition: maiamath.h:716
MInt quickSortPartition(MInt *a, MInt start, MInt end)
Definition: maiamath.h:681

◆ quickSortPartition()

MInt maia::math::quickSortPartition ( MInt a,
MInt  start,
MInt  end 
)
inline

Definition at line 681 of file maiamath.h.

681 {
682 MInt i, temp;
683 //---
684
685 i = start - 1;
686
687 for(MInt j = start; j < end; j++) {
688 if(a[j] <= a[end]) {
689 i++;
690 // swap elements i and j
691 temp = a[i];
692 a[i] = a[j];
693 a[j] = temp;
694 }
695 }
696 // swap the pivot
697 temp = a[i + 1];
698 a[i + 1] = a[end];
699 a[end] = temp;
700
701 return i + 1;
702}

◆ randnormal()

MFloat maia::math::randnormal ( MFloat  mu,
MFloat  sigma 
)
inline

Definition at line 502 of file maiafftw.h.

502 {
503 TRACE();
504
505 static MBool deviateAvailable = false; // flag
506 static float storedDeviate; // deviate from previous calculation
507 MFloat polar, rsquared, var1, var2;
508
509 // If no deviate has been stored, the polar Box-Muller transformation is
510 // performed, producing two independent normally-distributed random
511 // deviates. One is stored for the next round, and one is returned.
512 if(!deviateAvailable) {
513 // choose pairs of uniformly distributed deviates, discarding those
514 // that don't fall within the unit circle
515 do {
516 var1 = 2.0 * (MFloat(rand()) / MFloat(RAND_MAX)) - 1.0;
517 var2 = 2.0 * (MFloat(rand()) / MFloat(RAND_MAX)) - 1.0;
518 rsquared = var1 * var1 + var2 * var2;
519 } while(rsquared >= 1.0 || approx(rsquared, 0.0, MFloatEps));
520
521 // calculate polar tranformation for each deviate
522 polar = sqrt(-2.0 * log(rsquared) / rsquared);
523
524 // store first deviate and set flag
525 storedDeviate = var1 * polar;
526 deviateAvailable = true;
527
528 // return second deviate
529
530 return var2 * polar * sigma + mu;
531 }
532
533 // If a deviate is available from a previous call to this function, it is
534 // returned, and the flag is set to false.
535 else {
536 deviateAvailable = false;
537
538 return storedDeviate * sigma + mu;
539 }
540}

◆ RBF()

MFloat maia::math::RBF ( const MFloat  R,
const MFloat  R0 
)
inline
Author
Lennart Schneiders
Note
important: provide rapid decrease of return value with R, otherwise stability issues with weighted least squares when inlcuding diagonal neighbor cells!
suggested value for R0 is cellLength

Definition at line 873 of file maiamath.h.

873{ return (F1 / sqrt(F1 + POW2(R / R0))); }

◆ removeDoubleEntries()

MInt maia::math::removeDoubleEntries ( MInt a,
MInt  size 
)
inline

Definition at line 722 of file maiamath.h.

722 {
723 for(MInt i = 1; i < size; i++) {
724 // find double entry
725 if(a[i] != a[i - 1]) {
726 continue;
727 }
728
729 // shift entries forward
730 for(MInt k = i; k < size - 1; k++) {
731 a[k] = a[k + 1];
732 }
733 size--;
734 i--;
735 }
736
737 return size;
738}

◆ rotation2quaternion()

void maia::math::rotation2quaternion ( MFloat rotation,
MFloat quaternion 
)
inline
Author

Definition at line 550 of file maiamath.h.

550 {
551 quaternion[0] = cos(F1B2 * rotation[1]) * cos(F1B2 * (rotation[2] + rotation[0]));
552 quaternion[1] = sin(F1B2 * rotation[1]) * sin(F1B2 * (rotation[2] - rotation[0]));
553 quaternion[2] = sin(F1B2 * rotation[1]) * cos(F1B2 * (rotation[2] - rotation[0]));
554 quaternion[3] = cos(F1B2 * rotation[1]) * sin(F1B2 * (rotation[2] + rotation[0]));
555}

◆ sgn()

template<typename T >
MInt maia::math::sgn ( val)
inline

Definition at line 495 of file maiamath.h.

495 {
496 return (T(0) < val) - (val < T(0));
497}

◆ solveDenseMatrix()

void maia::math::solveDenseMatrix ( MFloat A_coeff,
MInt **  pos,
const MInt  n,
const MInt  m,
MFloat b,
MFloat x 
)

Solve x = A^(-1) * b for dense matrix A using LU decomposition

Parameters
A_coeffnon-zero coefficients of the system matrix
posholds the position of the coefficients in the matrix A
nnumber of non-zero coefficients
msize of system matrix A
bknown vector to be calculated by the product A * x
xunknown vector to be calculated by A^(-1) * b
Author
Moritz Waldmann

Definition at line 400 of file maiamath.cpp.

400 {
401 Eigen::Map<MFloatVectorXd> B(b, m);
402 Eigen::Map<MFloatVectorXd> X(x, m);
403
404 MFloatMatrixXd A = MFloatMatrixXd::Zero(m, m);
405
406 for(MInt i = 0; i < n; i++) {
407 A(pos[i][0], pos[i][1]) = A_coeff[i];
408 }
409
410 Eigen::FullPivLU<MFloatMatrixXd> lu;
411 lu.compute(A);
412
413 X = lu.solve(B);
414 MBool a_solution_exists = (A * X).isApprox(B, 1e-10);
415
416 if(a_solution_exists) {
417 std::cout << "SOLUTION IS CORRECT" << std::endl;
418 } else {
419 std::cout << "SOLUTION IS NOT CORRECT" << std::endl;
420 }
421}

◆ solveQR()

template<MInt nDim>
void maia::math::solveQR ( std::array< std::array< MFloat, nDim >, nDim > &  A_,
std::array< MFloat, nDim > &  b_ 
)

Solve linear system using QR (square matrix)

Parameters
Asystem matrix
brhs
Template Parameters
nDimdimension of the matrix
Author
Sven Berger

Definition at line 449 of file maiamath.cpp.

449 {
450 TRACE();
451
452 Eigen::Matrix<MFloat, nDim, nDim> A(&A_[0][0]);
453 Eigen::Vector<MFloat, nDim> b(&b_[0]);
454 b = A.colPivHouseholderQr().solve(b);
455 std::memcpy(&b_[0], b.data(), nDim * sizeof(MFloat));
456}

◆ solveQR< 2 >()

template void maia::math::solveQR< 2 > ( std::array< std::array< MFloat, 2 >, 2 > &  ,
std::array< MFloat, 2 > &   
)

◆ solveQR< 3 >()

template void maia::math::solveQR< 3 > ( std::array< std::array< MFloat, 3 >, 3 > &  ,
std::array< MFloat, 3 > &   
)

◆ solveSparseMatrix()

void maia::math::solveSparseMatrix ( MFloat A_coeff,
MInt **  pos,
const MInt  n,
const MInt  m,
MFloat b,
MFloat x 
)

Solve b = A * x for sparse matrix A using LU decomposition

Parameters
A_coeffnon-zero coefficients of the system matrix
posholds the position of the coefficients in the matrix A
nnumber of non-zero coefficients
msize of system matrix A
bknown vector to be calculated by the product A * x
xunknown vector to be calculated by A^(-1) * b
Author
Moritz Waldmann

Definition at line 315 of file maiamath.cpp.

315 {
316 std::vector<MTriplet> coefficients;
317 Eigen::Map<MFloatVectorXd> B(b, m);
318 Eigen::Map<MFloatVectorXd> X(x, m);
319
320 coefficients.reserve(n);
321 for(MInt i = 0; i < n; i++) {
322 coefficients.emplace_back(MTriplet(pos[i][0], pos[i][1], A_coeff[i]));
323 }
324
325 // set matrix from coefficients
326 Eigen::SparseMatrix<MFloat, Eigen::ColMajor> A(m, m);
327 A.setFromTriplets(coefficients.begin(), coefficients.end());
328
329 Eigen::SparseLU<Eigen::SparseMatrix<MFloat, Eigen::ColMajor>, Eigen::COLAMDOrdering<MInt>> slu;
330 slu.compute(A);
331
332 X = slu.solve(B);
333 MBool a_solution_exists = (A * X).isApprox(B, 1e-10);
334
335 MFloat resultA = F1B2 * X.transpose() * A * X;
336 MFloat resultB = X.transpose() * B;
337
338 MFloat result = resultA - resultB;
339
340 std::cout << "Energie norm is " << resultA << " " << resultB << " " << result << std::endl;
341
342 if(a_solution_exists) {
343 std::cerr << "SOLUTION IS CORRECT" << std::endl;
344 } else {
345 std::cerr << "SOLUTION IS NOT CORRECT" << std::endl;
346 }
347}
Eigen::Triplet< MFloat > MTriplet
Definition: maiamath.cpp:61

◆ solveSparseMatrixIterative()

void maia::math::solveSparseMatrixIterative ( MFloat A_coeff,
MInt **  pos,
const MInt  n,
const MInt  m,
MFloat b,
MFloat x 
)

Solve b = A^(-1) * x for sparse matrix A using BiCGSTAB

Parameters
A_coeffnon-zero coefficients of the system matrix
posholds the position of the coefficients in the matrix A
nnumber of non-zero coefficients
msize of system matrix A
bknown vector to be calculated by the product A * x
xunknown vector to be calculated by A^(-1) * b
Author
Moritz Waldmann

Definition at line 357 of file maiamath.cpp.

357 {
358 std::vector<MTriplet> coefficients;
359 Eigen::Map<MFloatVectorXd> B(b, m);
360 Eigen::Map<MFloatVectorXd> X(x, m);
361
362 coefficients.reserve(n);
363 for(MInt i = 0; i < n; i++) {
364 coefficients.emplace_back(MTriplet(pos[i][0], pos[i][1], A_coeff[i]));
365 }
366
367 // set matrix from coefficients
368 Eigen::SparseMatrix<MFloat, Eigen::ColMajor> A(m, m);
369 A.setFromTriplets(coefficients.begin(), coefficients.end());
370
371 Eigen::BiCGSTAB<Eigen::SparseMatrix<MFloat, Eigen::ColMajor>> BCGST;
372 BCGST.compute(A);
373
374 X = BCGST.solve(B);
375
376 MBool a_solution_exists = (A * X).isApprox(B, 1e-10);
377
378 MFloat resultA = F1B2 * X.transpose() * A * X;
379 MFloat resultB = X.transpose() * B;
380
381 MFloat result = resultA - resultB;
382
383 std::cout << "Energie norm is " << resultA << " " << resultB << " " << result << std::endl;
384
385 if(a_solution_exists) {
386 std::cout << "SOLUTION IS CORRECT" << std::endl;
387 } else {
388 std::cout << "SOLUTION IS NOT CORRECT" << std::endl;
389 }
390}

◆ sortEigenVectors()

void maia::math::sortEigenVectors ( MFloat  A[3][3],
MFloat  w[3] 
)
inline

void sortEigenVectors(MFloat A[3][3], MFloat w[3])

   Parameters:
   A: The symmetric input matrix
   w: Storage buffer for eigenvalues

Definition at line 460 of file maiamath.h.

460 {
461 const MInt dim = 3;
462 MInt k;
463 for(MInt i = 0; i < (dim - 1); ++i) {
464 MFloat p = w[k = i];
465 for(MInt j = i; j < dim; ++j) {
466 if(w[j] >= p) {
467 p = w[k = j];
468 }
469 }
470 if(k != i) {
471 w[k] = w[i];
472 w[i] = p;
473 for(MInt j = 0; j < dim; ++j) {
474 p = A[j][i];
475 A[j][i] = A[j][k];
476 A[j][k] = p;
477 }
478 }
479 }
480}

◆ svd()

std::vector< MFloat > maia::math::svd ( MFloat *const  A,
MFloat *const  b,
const MInt  m,
const MInt  n,
MFloat *const  x 
)

Definition at line 514 of file maiamath.cpp.

514 {
515 Eigen::Map<Eigen::Matrix<MFloat, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> A_eigen(A, m, n);
516
517 Eigen::Map<MFloatVectorXd> b_eigen(b, m);
518 // Eigen::Map<maia::math::MFloatVector<Eigen::Dynamic>> S_eigen(&S[0], std::min(m, n));
519
520#ifdef useEigenOld
521 Eigen::BDCSVD<Eigen::Matrix<MFloat, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>> SVD =
522 A_eigen.bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV);
523#else
524 Eigen::BDCSVD<Eigen::Matrix<MFloat, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>,
525 Eigen::ComputeThinU | Eigen::ComputeThinV>
526 SVD = A_eigen.bdcSvd<Eigen::ComputeThinU | Eigen::ComputeThinV>();
527#endif
528
529 // TODO labels:CONTROLLER this should work as well
530 MFloatVectorXd x_eigen = SVD.solve(b_eigen);
531 // Eigen::Matrix<MFloat, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> x_eigen =
532 // SVD.solve(b_eigen);
533 MFloatVectorXd S = SVD.singularValues();
534
535 for(MInt i = 0; i < n; i++) {
536 x[i] = x_eigen(i);
537 }
538
539 std::vector<MFloat> singularValues(S.size());
540 for(MInt i = 0; i < S.size(); i++) {
541 singularValues[i] = S[i];
542 }
543 return singularValues;
544}
Eigen::Vector< MFloat, Eigen::Dynamic > MFloatVectorXd
Definition: maiamath.cpp:58

◆ triadImag()

MFloat maia::math::triadImag ( fftw_complex &  a,
fftw_complex &  b,
fftw_complex &  c 
)
inline

Definition at line 61 of file maiafftw.h.

61 {
62 return (a[0] * b[1] * c[0] + a[1] * b[0] * c[0] - a[0] * b[0] * c[1] + a[1] * b[1] * c[1]);
63}

◆ vecAdd() [1/2]

template<MInt nDim, typename T , typename U >
T * maia::math::vecAdd ( T *const  result,
const U *const  a 
)
inline

Adds arbritary number of vectors of dimension nDim and returns result in vector result. Vector result can contain an offset. Usage: Say you want to add vectors a, b, c of dimension 3 and store result in a: vecAdd<3>(a, b, c)

Definition at line 74 of file maiamath.h.

74 {
75 std::transform(a, a + nDim, result, result, std::plus<T>());
76 return result;
77}

◆ vecAdd() [2/2]

template<MInt nDim, typename T , typename U , typename... Ts>
T * maia::math::vecAdd ( T *const  result,
const U *const  a,
const Ts...  b 
)
inline

Definition at line 79 of file maiamath.h.

79 {
80 std::transform(a, a + nDim, result, vecAdd<nDim>(result, b...), std::plus<T>());
81 return result;
82}

◆ vecAvg()

template<MInt nDim, typename T , typename... Ts>
void maia::math::vecAvg ( T *const  M,
const Ts *const ...  args 
)
inline

Definition at line 86 of file maiamath.h.

86 {
87 std::fill_n(M, nDim, 0.0);
88 maia::math::vecAdd<nDim>(M, args...);
89 constexpr std::size_t n = sizeof...(Ts);
90 std::transform(M, M + nDim, M, std::bind(std::multiplies<T>(), std::placeholders::_1, 1.0 / n));
91}