ProSHADE  0.7.6.0 (JUL 2021)
Protein Shape Detection
ProSHADE_internal_maths Namespace Reference

This namespace contains the internal functions for common mathematical operations. More...

Classes

class  BicubicInterpolator
 

Functions

void complexMultiplication (proshade_double *r1, proshade_double *i1, proshade_double *r2, proshade_double *i2, proshade_double *retReal, proshade_double *retImag)
 Function to multiply two complex numbers. More...
 
void complexMultiplicationConjug (proshade_double *r1, proshade_double *i1, proshade_double *r2, proshade_double *i2, proshade_double *retReal, proshade_double *retImag)
 Function to multiply two complex numbers by using the second number's conjugate. More...
 
proshade_double complexMultiplicationRealOnly (proshade_double *r1, proshade_double *i1, proshade_double *r2, proshade_double *i2)
 Function to multiply two complex numbers and return the real part only. More...
 
proshade_double complexMultiplicationConjugRealOnly (proshade_double *r1, proshade_double *i1, proshade_double *r2, proshade_double *i2)
 Function to conjuggate multiply two complex numbers and return the real part only. More...
 
void vectorMeanAndSD (std::vector< proshade_double > *vec, proshade_double *&ret)
 Function to get vector mean and standard deviation. More...
 
void vectorMedianAndIQR (std::vector< proshade_double > *vec, proshade_double *&ret)
 Function to get vector median and inter-quartile range. More...
 
void arrayMedianAndIQR (proshade_double *vec, proshade_unsign vecSize, proshade_double *&ret)
 Function to get array median and inter-quartile range. More...
 
proshade_double pearsonCorrCoeff (proshade_double *valSet1, proshade_double *valSet2, proshade_unsign length)
 Function for computing the Pearson's correlation coefficient. More...
 
void getLegendreAbscAndWeights (proshade_unsign order, proshade_double *abscissas, proshade_double *weights, proshade_unsign taylorSeriesCap)
 Function to prepare abscissas and weights for Gauss-Legendre integration. More...
 
void getGLPolyAtZero (proshade_unsign order, proshade_double *polyValue, proshade_double *deriValue)
 This function obtains the Legendre polynomial values and its derivative at zero for any positive integer order polynomial. More...
 
void getGLFirstEvenRoot (proshade_double polyAtZero, proshade_unsign order, proshade_double *abscAtZero, proshade_double *weighAtZero, proshade_unsign taylorSeriesCap)
 This function finds the first root for Legendre polynomials of odd order. More...
 
proshade_double evaluateGLSeries (proshade_double *series, proshade_double target, proshade_unsign terms)
 This function evaluates the Taylor expansion. More...
 
proshade_double advanceGLPolyValue (proshade_double from, proshade_double to, proshade_double valAtFrom, proshade_unsign noSteps, proshade_unsign taylorSeriesCap)
 This function finds the next value of the polynomial. More...
 
void completeLegendreSeries (proshade_unsign order, proshade_double *abscissa, proshade_double *weights, proshade_unsign taylorSeriesCap)
 This function completes the Legendre polynomial series assuming you have obtained the first values. More...
 
proshade_double gaussLegendreIntegrationReal (proshade_double *vals, proshade_unsign valsSize, proshade_unsign order, proshade_double *abscissas, proshade_double *weights, proshade_double integralOverRange, proshade_double maxSphereDists)
 Function to compute real part of the Gauss-Legendre integration over spherical harmonic values in different shells. More...
 
void gaussLegendreIntegration (proshade_complex *vals, proshade_unsign valsSize, proshade_unsign order, proshade_double *abscissas, proshade_double *weights, proshade_double integralOverRange, proshade_double maxSphereDists, proshade_double *retReal, proshade_double *retImag)
 Function to compute the complete complex Gauss-Legendre integration over spherical harmonic values in different shells. More...
 
void complexMatrixSVDSigmasOnly (proshade_complex **mat, int dim, double *&singularValues)
 Function to compute the complete complex matrix SVD and return only the sigmas. More...
 
void complexMatrixSVDUandVOnly (proshade_double *mat, int dim, proshade_double *uAndV, bool fail=true)
 Function to compute the real matrix SVD and return the U and V matrices. More...
 
void getEulerZXZFromSOFTPosition (proshade_signed band, proshade_signed x, proshade_signed y, proshade_signed z, proshade_double *eulerAlpha, proshade_double *eulerBeta, proshade_double *eulerGamma)
 Function to find Euler angles (ZXZ convention) from index position in the inverse SOFT map. More...
 
void getSOFTPositionFromEulerZXZ (proshade_signed band, proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double *x, proshade_double *y, proshade_double *z)
 Function to find the index position in the inverse SOFT map from given Euler angles (ZXZ convention). More...
 
void getRotationMatrixFromEulerZXZAngles (proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double *matrix)
 Function to find the rotation matrix from Euler angles (ZXZ convention). More...
 
void getRotationMatrixFromEulerZXZAngles (proshade_single eulerAlpha, proshade_single eulerBeta, proshade_single eulerGamma, proshade_single *matrix)
 Function to find the rotation matrix from Euler angles (ZXZ convention). More...
 
void getAxisAngleFromRotationMatrix (proshade_double *rotMat, proshade_double *x, proshade_double *y, proshade_double *z, proshade_double *ang)
 This function converts rotation matrix to the axis-angle representation. More...
 
void getAxisAngleFromRotationMatrix (std::vector< proshade_double > *rotMat, proshade_double *x, proshade_double *y, proshade_double *z, proshade_double *ang)
 This function converts rotation matrix to the axis-angle representation. More...
 
void getRotationMatrixFromAngleAxis (proshade_double *rotMat, proshade_double x, proshade_double y, proshade_double z, proshade_double ang)
 This function converts the axis-angle representation to the rotation matrix representation. More...
 
void getRotationMatrixFromAngleAxis (proshade_single *rotMat, proshade_double x, proshade_double y, proshade_double z, proshade_double ang)
 This function converts the axis-angle representation to the rotation matrix representation. More...
 
void getEulerZXZFromRotMatrix (proshade_double *rotMat, proshade_double *eA, proshade_double *eB, proshade_double *eG)
 This function converts rotation matrix to the Euler ZXZ angles representation. More...
 
void getEulerZXZFromAngleAxis (proshade_double axX, proshade_double axY, proshade_double axZ, proshade_double axAng, proshade_double *eA, proshade_double *eB, proshade_double *eG)
 This function converts angle-axis representation to the Euler ZXZ angles representation. More...
 
void multiplyTwoSquareMatrices (proshade_double *A, proshade_double *B, proshade_double *res, proshade_unsign dim=3)
 Function to compute matrix multiplication. More...
 
std::vector< proshade_signed > primeFactorsDecomp (proshade_signed number)
 Function to find prime factors of an integer. More...
 
proshade_double normalDistributionValue (proshade_double mean, proshade_double standardDev, proshade_double value)
 Function to the heiht of normal distribution given by mean and standard deviation for a given value. More...
 
proshade_double computeDotProduct (proshade_double *x1, proshade_double *y1, proshade_double *z1, proshade_double *x2, proshade_double *y2, proshade_double *z2)
 Simple 3D vector dot product computation. More...
 
proshade_double computeDotProduct (proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2)
 Simple 3D vector dot product computation. More...
 
proshade_double * computeCrossProduct (proshade_double *x1, proshade_double *y1, proshade_double *z1, proshade_double *x2, proshade_double *y2, proshade_double *z2)
 Simple 3D vector cross product computation. More...
 
proshade_double * compute3x3MatrixMultiplication (proshade_double *mat1, proshade_double *mat2)
 Function for computing a 3x3 matrix multiplication. More...
 
proshade_double * compute3x3MatrixVectorMultiplication (proshade_double *mat, proshade_double x, proshade_double y, proshade_double z)
 Function for computing a 3x3 matrix to 3x1 vector multiplication. More...
 
proshade_single * compute3x3MatrixVectorMultiplication (proshade_single *mat, proshade_single x, proshade_single y, proshade_single z)
 Function for computing a 3x3 matrix to 3x1 vector multiplication. More...
 
proshade_double * compute3x3MatrixInverse (proshade_double *mat)
 Function for computing a 3x3 matrix inverse. More...
 
void transpose3x3MatrixInPlace (proshade_double *mat)
 Transposes 3x3 matrix in place. More...
 
proshade_double * findRotMatMatchingVectors (proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2)
 Computation of rotation matrix rotating one vector onto the other. More...
 
std::vector< proshade_double > findVectorFromTwoVAndTwoD (proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2, proshade_double dot1, proshade_double dot2)
 Function for finding a vector which would have a given two dot products to two other vectors. More...
 
std::vector< proshade_double > findVectorFromThreeVAndThreeD (proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2, proshade_double x3, proshade_double y3, proshade_double z3, proshade_double dot1, proshade_double dot2, proshade_double dot3)
 Function for finding a vector which would have a given three dot products to three other vectors. More...
 
std::vector< proshade_double > multiplyGroupElementMatrices (std::vector< proshade_double > *el1, std::vector< proshade_double > *el2)
 This function computes matrix multiplication using the ProSHADE group element matrix format as input and output. More...
 
bool rotationMatrixSimilarity (std::vector< proshade_double > *mat1, std::vector< proshade_double > *mat2, proshade_double tolerance=0.1)
 This function compares the distance between two rotation matrices and decides if they are similar using tolerance. More...
 
bool vectorOrientationSimilarity (proshade_double a1, proshade_double a2, proshade_double a3, proshade_double b1, proshade_double b2, proshade_double b3, proshade_double tolerance=0.1)
 This function compares two vectors using cosine distance and decides if they are similar using tolerance. More...
 
bool vectorOrientationSimilaritySameDirection (proshade_double a1, proshade_double a2, proshade_double a3, proshade_double b1, proshade_double b2, proshade_double b3, proshade_double tolerance=0.1)
 This function compares two vectors using cosine distance and decides if they are similar using tolerance. More...
 
void optimiseAxisBiCubicInterpolation (proshade_double *bestLattitude, proshade_double *bestLongitude, proshade_double *bestSum, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun, proshade_double step=0.05)
 This function provides axis optimisation given starting lattitude and longitude indices. More...
 
void prepareBiCubicInterpolatorsMinusMinus (proshade_double bestLattitude, proshade_double bestLongitude, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *interpols, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun)
 This function prepares the interpolation objects for the bi-cubic interpolation. More...
 
void prepareBiCubicInterpolatorsMinusPlus (proshade_double bestLattitude, proshade_double bestLongitude, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *interpols, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun)
 This function prepares the interpolation objects for the bi-cubic interpolation. More...
 
void prepareBiCubicInterpolatorsPlusMinus (proshade_double bestLattitude, proshade_double bestLongitude, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *interpols, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun)
 This function prepares the interpolation objects for the bi-cubic interpolation. More...
 
void prepareBiCubicInterpolatorsPlusPlus (proshade_double bestLattitude, proshade_double bestLongitude, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *interpols, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun)
 This function prepares the interpolation objects for the bi-cubic interpolation. More...
 
bool isAxisUnique (std::vector< proshade_double * > *CSymList, proshade_double *axis, proshade_double tolerance=0.1, bool improve=false)
 This function checks if new axis is unique, or already detected. More...
 
bool isAxisUnique (std::vector< proshade_double * > *CSymList, proshade_double X, proshade_double Y, proshade_double Z, proshade_double fold, proshade_double tolerance)
 This function checks if new axis is unique, or already detected. More...
 
std::vector< proshade_unsign > findAllPrimes (proshade_unsign upTo)
 This function finds all prime numbers up to the supplied limit. More...
 
proshade_double computeGaussian (proshade_double val, proshade_double sigma)
 This function computes a Gaussian (normal) distribution value given distance from mean and sigma. More...
 
std::vector< proshade_double > smoothen1D (proshade_double step, proshade_signed windowSize, proshade_double sigma, std::vector< proshade_double > data)
 This function takes a 1D vector and computes smoothened version based on the parameters. More...
 
proshade_single getResolutionOfReflection (proshade_single h, proshade_single k, proshade_single l, proshade_single xDim, proshade_single yDim, proshade_single zDim)
 This function computes the resolution of a particular reflection. More...
 
void binReciprocalSpaceReflections (proshade_unsign xInds, proshade_unsign yInds, proshade_unsign zInds, proshade_signed *noBin, proshade_signed *&binIndexing)
 This function does binning of the reciprocal space reflections. More...
 
proshade_double computeFSC (fftw_complex *fCoeffs1, fftw_complex *fCoeffs2, proshade_unsign xInds, proshade_unsign yInds, proshade_unsign zInds, proshade_signed noBins, proshade_signed *binIndexing, proshade_double **&binData, proshade_signed *&binCounts)
 This function computes the FSC. More...
 

Detailed Description

This namespace contains the internal functions for common mathematical operations.

The ProSHADE_internal_maths namespace contains a set of common mathematical operations used in many places by ProSHADE. These typically include complex number operations and angle conversions.

Function Documentation

◆ advanceGLPolyValue()

proshade_double ProSHADE_internal_maths::advanceGLPolyValue ( proshade_double  from,
proshade_double  to,
proshade_double  valAtFrom,
proshade_unsign  noSteps,
proshade_unsign  taylorSeriesCap 
)

This function finds the next value of the polynomial.

Given the previous value of the polynomial, the distance to proceed and the number of steps to take, this function finds the next value of the polynomial using the Taylor series.

Parameters
[in]fromCurrent polynomial position.
[in]toPolynomial position to move to.
[in]valAtFromThe current value of the polynomial at the <from> position.
[in]noStepsNumber of steps in which to reach the <to> position.
[in]taylorSeriesCapThe limit on the Taylor series.
[out]XThe polynomial value at the <to> position.

Definition at line 479 of file ProSHADE_maths.cpp.

480 {
481  //================================================ Initialise variables
482  proshade_double hlpVal = 0.0;
483  proshade_double stepSize = 0.0;
484  proshade_double valChange = 0.0;
485  proshade_double valSecChange = 0.0;
486  proshade_double squareSteps = 0.0;
487  proshade_double curVal = 0.0;
488 
489  //================================================ Set initial values
490  stepSize = ( to - from ) / static_cast<proshade_double> ( taylorSeriesCap );
491  squareSteps = sqrt ( static_cast<proshade_double> ( noSteps * ( noSteps + 1 ) ) );
492  curVal = from;
493 
494  //================================================ Go through the series and iteratively improve the estimate
495  for ( proshade_unsign iter = 0; iter < taylorSeriesCap; iter++ )
496  {
497  hlpVal = ( 1.0 - valAtFrom ) * ( 1.0 + valAtFrom );
498  valChange = - stepSize * hlpVal / ( squareSteps * sqrt ( hlpVal ) - 0.5 * valAtFrom * sin ( 2.0 * curVal ) );
499  valAtFrom = valAtFrom + valChange;
500 
501  curVal = curVal + stepSize;
502 
503  hlpVal = ( 1.0 - valAtFrom ) * ( 1.0 + valAtFrom );
504  valSecChange = - stepSize * hlpVal / ( squareSteps * sqrt ( hlpVal ) - 0.5 * valAtFrom * sin ( 2.0 * curVal ) );
505  valAtFrom = valAtFrom + 0.5 * ( valSecChange - valChange );
506  }
507 
508  //================================================ Done
509  return valAtFrom;
510 
511 }

◆ arrayMedianAndIQR()

void ProSHADE_internal_maths::arrayMedianAndIQR ( proshade_double *  vec,
proshade_unsign  vecSize,
proshade_double *&  ret 
)

Function to get array median and inter-quartile range.

This function takes a pointer to a array of proshade_double's and returns the median and the inter-quartile range of such vector.

Parameters
[in]vecPointer to an array of proshade_double's for which median and IQR should be obtained.
[in]vecSizeThe length of the array.
[in]retPointer to array of 2 proshade_double's, which will be the return values - first median and second IQR.

Definition at line 200 of file ProSHADE_maths.cpp.

201 {
202  //================================================ Sort the vector
203  std::sort ( vec, vec + vecSize );
204 
205  //================================================ Get median
206  if ( vecSize % 2 == 0)
207  {
208  ret[0] = ( vec[ ( vecSize / 2 ) - 1 ] + vec[ vecSize / 2 ] ) / 2.0;
209  }
210  else
211  {
212  ret[0] = vec[ vecSize / 2 ];
213  }
214 
215  //================================================ Get first and third quartile
216  proshade_double Q1, Q3;
217  if ( vecSize % 2 == 0)
218  {
219  Q1 = ( vec[ ( vecSize / 4 ) - 1 ] + vec[ vecSize / 4 ] ) / 2.0;
220  Q3 = ( vec[ ( ( vecSize / 4 ) * 3 ) - 1 ] + vec[ ( vecSize / 4 ) * 3 ] ) / 2.0;
221  }
222  else
223  {
224  Q1 = vec[ vecSize / 4 ];
225  Q3 = vec[ ( vecSize / 4 ) * 3 ];
226  }
227 
228  //================================================ And now save the IQR
229  ret[1] = Q3 - Q1;
230 
231  //================================================ Return
232  return ;
233 
234 }

◆ binReciprocalSpaceReflections()

void ProSHADE_internal_maths::binReciprocalSpaceReflections ( proshade_unsign  xInds,
proshade_unsign  yInds,
proshade_unsign  zInds,
proshade_signed *  noBin,
proshade_signed *&  binIndexing 
)

This function does binning of the reciprocal space reflections.

This funcion uses the knowledge of the cell dimensions to firstly decide which dimension is the limitting one in terms of FSC binning and then it proceeds to compute the bins, their positions in terms of distance from F000. Finally, it uses this information to compute a "mask" map, where each position has the value corresponding to the appropriate bin index, thus allowing fast binning of any map with the same dimensions as supplied to this function.

Parameters
[in]xIndsThe number of indices along the x-axis.
[in]yIndsThe number of indices along the y-axis.
[in]zIndsThe number of indices along the z-axis.
[in]noBinVariable to which the number of binds found will be saved into.
[in]binIndexingA pointer to which the map of bin belonging for each reflection will be saved into.

Definition at line 2943 of file ProSHADE_maths.cpp.

2944 {
2945  //================================================ Allocate output bin indexing memory and set to -100
2946  binIndexing = new proshade_signed [xInds * yInds * zInds];
2947  ProSHADE_internal_misc::checkMemoryAllocation ( binIndexing, __FILE__, __LINE__, __func__ );
2948  for ( size_t iter = 0; iter < static_cast< size_t > ( xInds * yInds * zInds ); iter++ ) { binIndexing[iter] = -100; }
2949  proshade_single xIndsF = static_cast< proshade_single > ( xInds ), yIndsF = static_cast< proshade_single > ( yInds ), zIndsF = static_cast< proshade_single > ( zInds );
2950 
2951  //================================================ Allocate local memory
2952  proshade_single *mins = new proshade_single[3];
2953  proshade_single *maxs = new proshade_single[3];
2954  proshade_single *resMins = new proshade_single[3];
2955  proshade_signed *resMinLoc = new proshade_signed[3];
2956  proshade_single *steps = new proshade_single[3];
2957 
2958  //================================================ Check local memory
2959  ProSHADE_internal_misc::checkMemoryAllocation ( mins, __FILE__, __LINE__, __func__ );
2960  ProSHADE_internal_misc::checkMemoryAllocation ( maxs, __FILE__, __LINE__, __func__ );
2961  ProSHADE_internal_misc::checkMemoryAllocation ( resMins, __FILE__, __LINE__, __func__ );
2962  ProSHADE_internal_misc::checkMemoryAllocation ( resMinLoc, __FILE__, __LINE__, __func__ );
2963  ProSHADE_internal_misc::checkMemoryAllocation ( steps, __FILE__, __LINE__, __func__ );
2964 
2965  //================================================ Initialise local variables
2966  proshade_single resol = 0.0f;
2967  proshade_signed reciX, reciY, reciZ, arrPos = 0, minLoc = -1;
2968  *noBin = 0;
2969 
2970  //================================================ Determine reciprocal space indexing
2971  mins[0] = std::floor ( xIndsF / -2.0f );
2972  mins[1] = std::floor ( yIndsF / -2.0f );
2973  mins[2] = std::floor ( zIndsF / -2.0f );
2974 
2975  maxs[0] = -mins[0];
2976  maxs[1] = -mins[1];
2977  maxs[2] = -mins[2];
2978 
2979  if ( xInds % 2 == 0 ) { mins[0] += 1.0f; }
2980  if ( yInds % 2 == 0 ) { mins[1] += 1.0f; }
2981  if ( zInds % 2 == 0 ) { mins[2] += 1.0f; }
2982 
2983  //================================================ Get minimum resolution based on dims for each dimension
2984  resMins[0] = ProSHADE_internal_maths::getResolutionOfReflection ( maxs[0], 0.0f, 0.0f, xIndsF, yIndsF, zIndsF );
2985  resMins[1] = ProSHADE_internal_maths::getResolutionOfReflection ( 0.0f, maxs[1], 0.0f, xIndsF, yIndsF, zIndsF );
2986  resMins[2] = ProSHADE_internal_maths::getResolutionOfReflection ( 0.0f, 0.0f, maxs[2], xIndsF, yIndsF, zIndsF );
2987 
2988  //================================================ Decide which dimension to work with (the one with the lowest resolution)
2989  resMinLoc[0] = 0; resMinLoc[1] = 0; resMinLoc[2] = 0;
2990  const FloatingPoint< proshade_single > lhs1 ( resMins[0] ), lhs2 ( resMins[1] ), lhs3 ( resMins[2] ), rhs1 ( std::min( resMins[0], std::min( resMins[1], resMins[2] ) ) );
2991  if ( lhs1.AlmostEquals ( rhs1 ) ) { resMinLoc[0] = 1; minLoc = 0; }
2992  if ( lhs2.AlmostEquals ( rhs1 ) ) { resMinLoc[1] = 1; minLoc = 1; }
2993  if ( lhs3.AlmostEquals ( rhs1 ) ) { resMinLoc[2] = 1; minLoc = 2; }
2994 
2995  //================================================ Find the bins and corresponding cut-offs
2996  std::vector< proshade_single > resArray ( static_cast< size_t > ( maxs[minLoc] - 1 ), 0.0f );
2997  std::vector< proshade_single > binArray ( static_cast< size_t > ( maxs[minLoc] - 1 ), 0.0f );
2998  for ( proshade_signed dimIt = 0; dimIt < static_cast< proshade_signed > ( maxs[minLoc] - 1 ); dimIt++ )
2999  {
3000  //============================================ Prepare steps
3001  steps[0] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[0] );
3002  steps[1] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[1] );
3003  steps[2] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[2] );
3004 
3005  //============================================ Find resolution
3006  resol = ProSHADE_internal_maths::getResolutionOfReflection ( steps[0], steps[1], steps[2], xIndsF, yIndsF, zIndsF );
3007 
3008  //============================================ Assign to arrays
3009  resArray.at( static_cast< size_t > ( dimIt ) ) = resol;
3010  binArray.at( static_cast< size_t > ( dimIt ) ) = static_cast< proshade_single > ( dimIt ) + 2.5f;
3011  *noBin = dimIt + 1;
3012  }
3013 
3014  //================================================ Assign reflections to bins
3015  for ( proshade_signed xIt = 0; xIt < static_cast< proshade_signed > ( xInds ); xIt++ )
3016  {
3017  for ( proshade_signed yIt = 0; yIt < static_cast< proshade_signed > ( yInds ); yIt++ )
3018  {
3019  for ( proshade_signed zIt = 0; zIt < static_cast< proshade_signed > ( zInds / 2 ) + 1; zIt++ )
3020  {
3021  //==================================== Deal with reciprocal indices ordering
3022  reciX = xIt; if ( reciX > static_cast< proshade_signed > ( maxs[0] ) ) { reciX -= static_cast< proshade_signed > ( xInds ); }
3023  reciY = yIt; if ( reciY > static_cast< proshade_signed > ( maxs[1] ) ) { reciY -= static_cast< proshade_signed > ( yInds ); }
3024  reciZ = zIt; if ( reciZ > static_cast< proshade_signed > ( maxs[2] ) ) { reciZ -= static_cast< proshade_signed > ( zInds ); }
3025 
3026  //==================================== For each bin, check if this reflection belongs to it
3027  for ( proshade_signed binIt = 0; binIt < (*noBin); binIt++ )
3028  {
3029  //================================ Check by comparing distances
3030  if ( std::sqrt ( std::pow ( static_cast< proshade_single > ( reciX ), 2.0f ) +
3031  std::pow ( static_cast< proshade_single > ( reciY ), 2.0f ) +
3032  std::pow ( static_cast< proshade_single > ( reciZ ), 2.0f ) ) <= binArray.at( static_cast< size_t > ( binIt ) ) )
3033  {
3034  //============================ This is the bin for this reflection. Assign it.
3035  arrPos = zIt + static_cast< proshade_signed > ( zInds ) * ( yIt + static_cast< proshade_signed > ( yInds ) * xIt );
3036  binIndexing[ static_cast< size_t > ( arrPos ) ] = binIt;
3037 
3038  //============================ If one of the uneven ends, do not use Friedel's Law
3039  if ( reciX == static_cast< proshade_signed > ( mins[0] ) || -reciX == static_cast< proshade_signed > ( mins[0] ) ) { break; }
3040  if ( reciY == static_cast< proshade_signed > ( mins[1] ) || -reciY == static_cast< proshade_signed > ( mins[1] ) ) { break; }
3041  if ( reciZ == static_cast< proshade_signed > ( mins[2] ) || -reciZ == static_cast< proshade_signed > ( mins[2] ) ) { break; }
3042 
3043  //============================ Use Friedel's Law to find the second index (this is why we can use zDim / 2)
3044  reciX *= -1; if ( reciX < 0 ) { reciX += static_cast< proshade_signed > ( xInds ); }
3045  reciY *= -1; if ( reciY < 0 ) { reciY += static_cast< proshade_signed > ( yInds ); }
3046  reciZ *= -1; if ( reciZ < 0 ) { reciZ += static_cast< proshade_signed > ( zInds ); }
3047 
3048  //============================ Apply Friedel's Law
3049  arrPos = reciZ + static_cast< proshade_signed > ( zInds ) * ( reciY + static_cast< proshade_signed > ( yInds ) * reciX );
3050  binIndexing[ static_cast< size_t > ( arrPos ) ] = binIt;
3051 
3052  //============================ Done, exit bins loop
3053  break;
3054  }
3055  }
3056  }
3057  }
3058  }
3059 
3060  //================================================ Release memory
3061  delete[] mins;
3062  delete[] maxs;
3063  delete[] resMins;
3064  delete[] resMinLoc;
3065  delete[] steps;
3066 
3067  //================================================ Done
3068  return ;
3069 
3070 }

◆ completeLegendreSeries()

void ProSHADE_internal_maths::completeLegendreSeries ( proshade_unsign  order,
proshade_double *  abscissas,
proshade_double *  weights,
proshade_unsign  taylorSeriesCap 
)

This function completes the Legendre polynomial series assuming you have obtained the first values.

Given that the polynomial value at zero is known, this function will complete the Legendre polynomial and with it the absicassas and weights for the Gauss-Legendre integration using the other functions defined above.

Parameters
[in]orderThe positive integer value of the polynomial order.
[in]abscissasPointer to an array of abscissas containing the first value.
[in]weightsPointer to an array of weights containing the first value.
[in]taylorSeriesCapThe limit on the Taylor series.

Definition at line 523 of file ProSHADE_maths.cpp.

524 {
525  //================================================ Initialise internal variables
526  proshade_double hlpTaylorVal = 0.0;
527  proshade_double hlpOrderVal = static_cast<proshade_double> ( order );
528  proshade_double abscValueChange = 0.0;
529  proshade_double prevAbsc = 0.0;
530  proshade_double *hlpAbscSeries;
531  proshade_double *hlpWeightSeries;
532  proshade_unsign noSeriesElems = 0;
533  proshade_unsign oddEvenSwitch = 0;
534 
535  //================================================ Pre-set internal values
536  if ( order % 2 == 1 )
537  {
538  noSeriesElems = ( order - 1 ) / 2 - 1;
539  oddEvenSwitch = 1;
540  }
541  else
542  {
543  noSeriesElems = order / 2 - 1;
544  oddEvenSwitch = 0;
545  }
546 
547  //================================================ Allocate memory
548  hlpAbscSeries = new proshade_double[taylorSeriesCap+2];
549  hlpWeightSeries = new proshade_double[taylorSeriesCap+1];
550 
551  //================================================ For each series element
552  for ( proshade_unsign serIt = noSeriesElems + 1; serIt < order - 1; serIt++ )
553  {
554  //============================================ Init loop
555  prevAbsc = abscissas[serIt];
556  abscValueChange = advanceGLPolyValue ( M_PI/2.0, -M_PI/2.0, prevAbsc, order, taylorSeriesCap ) - prevAbsc;
557 
558  //============================================ Init abscissas
559  hlpAbscSeries[0] = 0.0;
560  hlpAbscSeries[1] = 0.0;
561  hlpAbscSeries[2] = weights[serIt];
562 
563  //============================================ Init weights
564  hlpWeightSeries[0] = 0.0;
565  hlpWeightSeries[1] = hlpAbscSeries[2];
566 
567  //============================================ Taylor expansion
568  for ( proshade_unsign tayIt = 0; tayIt <= taylorSeriesCap - 2; tayIt++ )
569  {
570  hlpTaylorVal = static_cast<proshade_double> ( tayIt );
571 
572  hlpAbscSeries[tayIt+3] = ( 2.0 * prevAbsc * ( hlpTaylorVal + 1.0 ) * hlpAbscSeries[tayIt+2] + ( hlpTaylorVal * ( hlpTaylorVal + 1.0 ) - hlpOrderVal *
573  ( hlpOrderVal + 1.0 ) ) * hlpAbscSeries[tayIt+1] / ( hlpTaylorVal + 1.0 ) ) / ( 1.0 - prevAbsc ) / ( 1.0 + prevAbsc ) /
574  ( hlpTaylorVal + 2.0 );
575 
576  hlpWeightSeries[tayIt+2] = ( hlpTaylorVal + 2.0 ) * hlpAbscSeries[tayIt+3];
577  }
578 
579  //============================================ Sum over results
580  for ( proshade_unsign iter = 0; iter < 5; iter++ )
581  {
582  abscValueChange = abscValueChange - evaluateGLSeries ( hlpAbscSeries, abscValueChange, taylorSeriesCap ) /
583  evaluateGLSeries ( hlpWeightSeries, abscValueChange, taylorSeriesCap-1 );
584  }
585 
586  //============================================ Save results
587  abscissas[serIt+1] = prevAbsc + abscValueChange;
588  weights[serIt+1] = evaluateGLSeries ( hlpWeightSeries, abscValueChange, taylorSeriesCap - 1 );
589  }
590 
591  for ( proshade_unsign serIt = 0; serIt <= noSeriesElems + oddEvenSwitch; serIt++ )
592  {
593  abscissas[serIt] = -abscissas[order-serIt-1];
594  weights[serIt] = weights[order-serIt-1];
595  }
596 
597  //================================================ Free memory
598  delete hlpAbscSeries;
599  delete hlpWeightSeries;
600 
601  //================================================ Done
602  return ;
603 
604 }

◆ complexMatrixSVDSigmasOnly()

void ProSHADE_internal_maths::complexMatrixSVDSigmasOnly ( proshade_complex **  mat,
int  dim,
double *&  singularValues 
)

Function to compute the complete complex matrix SVD and return only the sigmas.

This function converts the input proshade_complex matrix of dimensions dim onto the LAPACK compatible std::complex<double> matrix. It then proceeds to create a dummy variables for the U and V matrices for saving the SVD results as well as other required variables. It finally proceeds to call LAPACK ZGESDD function to compute the SVD of the complex matrix input, checks the results and terminates. Note that this function does not make use of most of the LAPACK capabilities and is limitted onto square matrices.

Parameters
[in]matPointer to a complex square matrix with dimensions dim * dim.
[in]dimThe dimension of the complex matrix.
[in]singularValuesEmpty array of size dim where the singular values will be saved.

Definition at line 804 of file ProSHADE_maths.cpp.

805 {
806  //================================================ Initialise local variables
807  char job = 'N'; // Save computation of parts of U and V matrices, they are not needed here
808  std::complex<double> *rotMatU = new std::complex<double> [dim*dim]; // The U matrix space
809  std::complex<double> *rotMatV = new std::complex<double> [dim*dim]; // The V^T matrix space
810  std::complex<double> *work = new std::complex<double> [( 4 * dim)]; // Workspace, minimum required is 3*dim, using more for performance
811  int workDim = ( 4 * dim); // Formalism stating just that
812  double* rwork = new double[(7 * dim)]; // Required by LAPACK, from 3.7 requires 7 * dim
813  int* iwork = new int[(8 * dim)]; // Required by LAPACK
814  int returnValue = 0; // This will tell if operation succeeded
815 
816  //================================================ Check memory allocation
817  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatU, __FILE__, __LINE__, __func__ );
818  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatV, __FILE__, __LINE__, __func__ );
819  ProSHADE_internal_misc::checkMemoryAllocation ( work, __FILE__, __LINE__, __func__ );
820  ProSHADE_internal_misc::checkMemoryAllocation ( rwork, __FILE__, __LINE__, __func__ );
821  ProSHADE_internal_misc::checkMemoryAllocation ( iwork, __FILE__, __LINE__, __func__ );
822 
823  //================================================ Load input data into array in column-major order
824  std::complex<double> *matrixToDecompose = new std::complex<double>[dim*dim];
825  ProSHADE_internal_misc::checkMemoryAllocation ( matrixToDecompose, __FILE__, __LINE__, __func__ );
826  for ( int rowIt = 0; rowIt < dim; rowIt++ )
827  {
828  for ( int colIt = 0; colIt < dim; colIt++ )
829  {
830  matrixToDecompose[(colIt*dim)+rowIt] = std::complex<double> ( mat[rowIt][colIt][0], mat[rowIt][colIt][1] );
831  }
832  }
833 
834  //================================================ Run LAPACK ZGESDD
835  zgesdd_ ( &job, &dim, &dim, matrixToDecompose, &dim, singularValues, rotMatU, &dim, rotMatV, &dim,
836  work, &workDim, rwork, iwork, &returnValue );
837 
838  //================================================ Free memory
839  delete[] rotMatU;
840  delete[] rotMatV;
841  delete[] work;
842  delete[] rwork;
843  delete[] iwork;
844  delete[] matrixToDecompose;
845 
846  //================================================ Check result
847  if ( returnValue != 0 )
848  {
849  throw ProSHADE_exception ( "The LAPACK complex SVD algorithm did not converge!", "EL00021", __FILE__, __LINE__, __func__, "LAPACK algorithm for computing the singular value\n : decomposition of complex matrices did not converge and\n : therefore it was not possible to combine SH coefficients\n : from multiple shells. Changing the resolution may help,\n : contact me if this error persists." );
850  }
851 
852  //================================================ Done
853  return ;
854 
855 }

◆ complexMatrixSVDUandVOnly()

void ProSHADE_internal_maths::complexMatrixSVDUandVOnly ( proshade_double *  mat,
int  dim,
proshade_double *  uAndV,
bool  fail = true 
)

Function to compute the real matrix SVD and return the U and V matrices.

This function converts the input proshade_double array of dimensions dim*dim onto the LAPACK compatible std::complex<double> matrix. It then proceeds to create a dummy variables for the U and V matrices for saving the SVD results as well as other required variables. It finally proceeds to call LAPACK ZGESDD function to compute the SVD of the real matrix input, checks the results and saves the U and V matrices for output. Note that this function does not make use of most of the LAPACK capabilities and is limitted onto square matrices.

Parameters
[in]matPointer to a real square matrix with dimensions dim * dim.
[in]dimThe dimension of the real matrix.
[in]uAndVEmpty and allocated array of size dim*6 where the U and V matrices will be saved.
[in]failIf true and an error is encountered (typically algorithm not converging), this function will stop the program (useful for distances computations). However, if false, the function will simply return -777 as the first matrix element and not fail.

Definition at line 871 of file ProSHADE_maths.cpp.

872 {
873  //================================================ Initialise local variables
874  char job = 'A'; // Save computation of parts of U and V matrices, they are not needed here
875  double* singularValues = new double[dim]; // The array of singular values
876  std::complex<double> *rotMatU = new std::complex< double > [dim*dim]; // The U matrix space
877  std::complex<double> *rotMatV = new std::complex< double > [dim*dim]; // The V^T matrix space
878  std::complex<double> *work = new std::complex< double > [static_cast< proshade_unsign >( ( 3 * dim) + pow( dim, 2 ) * dim)]; // Workspace, minimum required is 3*dim, using more for performance
879  int workDim = static_cast< int > ( ( 3 * dim ) + pow( dim, 2 ) ); // Formalism stating just that
880  double* rwork = new double[static_cast<proshade_unsign>((5 * dim) + 5 * pow(dim,2))]; // Required by LAPACK
881  int* iwork = new int[(8 * dim)]; // Required by LAPACK
882  int returnValue = 0; // This will tell if operation succeeded
883  ProSHADE_internal_misc::checkMemoryAllocation ( singularValues, __FILE__, __LINE__, __func__ );
884  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatU, __FILE__, __LINE__, __func__ );
885  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatV, __FILE__, __LINE__, __func__ );
886  ProSHADE_internal_misc::checkMemoryAllocation ( work, __FILE__, __LINE__, __func__ );
887  ProSHADE_internal_misc::checkMemoryAllocation ( rwork, __FILE__, __LINE__, __func__ );
888  ProSHADE_internal_misc::checkMemoryAllocation ( iwork, __FILE__, __LINE__, __func__ );
889 
890  //================================================ Load input data into array in column-major order
891  std::complex<double> *matrixToDecompose = new std::complex<double>[dim*dim];
892  ProSHADE_internal_misc::checkMemoryAllocation ( matrixToDecompose, __FILE__, __LINE__, __func__ );
893  for ( int rowIt = 0; rowIt < dim; rowIt++ )
894  {
895  for ( int colIt = 0; colIt < dim; colIt++ )
896  {
897  matrixToDecompose[(colIt*dim)+rowIt] = std::complex<double> ( mat[(rowIt*dim)+colIt], 0.0 );
898  }
899  }
900 
901  //================================================ Run LAPACK ZGESDD
902  zgesdd_ ( &job, &dim, &dim, matrixToDecompose, &dim, singularValues, rotMatU, &dim, rotMatV, &dim,
903  work, &workDim, rwork, iwork, &returnValue );
904 
905  //================================================ Free memory
906  delete[] work;
907  delete[] rwork;
908  delete[] iwork;
909  delete[] matrixToDecompose;
910  delete[] singularValues;
911 
912  //================================================ Check result
913  if ( ( returnValue != 0 ) && ( fail ) )
914  {
915  throw ProSHADE_exception ( "The LAPACK complex SVD algorithm did not converge!", "EL00022", __FILE__, __LINE__, __func__, "LAPACK algorithm for computing the singular value\n : decomposition of complex matrices did not converge and\n : therefore it was not possible to optimise the peak\n : positions in the (self-)rotation function. Changing the\n : resolution may help, contact me if this error persists." );
916  }
917  if ( ( returnValue != 0 ) && ( !fail ) )
918  {
919  uAndV[0] = -777.7;
920  return ;
921  }
922 
923  //================================================ Save U
924  for ( proshade_signed rowIt = 0; rowIt < dim; rowIt++ )
925  {
926  for ( proshade_signed colIt = 0; colIt < dim; colIt++ )
927  {
928  uAndV[(rowIt*3)+colIt] = rotMatU[( rowIt * 3 ) + colIt].real();
929  }
930  }
931 
932  //================================================ Save V
933  for ( proshade_signed rowIt = 0; rowIt < dim; rowIt++ )
934  {
935  for ( proshade_signed colIt = 0; colIt < dim; colIt++ )
936  {
937  uAndV[(rowIt*3)+colIt+9] = rotMatV[( rowIt * 3 ) + colIt].real();
938  }
939  }
940 
941  //================================================ Release the rest of the memory
942  delete[] rotMatU;
943  delete[] rotMatV;
944 
945  //================================================ Done
946  return ;
947 
948 }

◆ complexMultiplication()

void ProSHADE_internal_maths::complexMultiplication ( proshade_double *  r1,
proshade_double *  i1,
proshade_double *  r2,
proshade_double *  i2,
proshade_double *  retReal,
proshade_double *  retImag 
)

Function to multiply two complex numbers.

This function takes pointers to the real and imaginary parts of two complex numbers and returns the result of their multiplication.

Parameters
[in]r1Pointer to the real value of number 1.
[in]i1Pointer to the imaginary value of number 1.
[in]r2Pointer to the real value of number 2.
[in]i2Pointer to the imaginary value of number 2.
[in]retRealPointer to the real part of the complex variable to which the result will be saved.
[in]retImagPointer to the imaginary part of the complex variable to which the result will be saved.

Definition at line 38 of file ProSHADE_maths.cpp.

39 {
40  //================================================ Multiplication
41  *retReal = (*r1)*(*r2) - (*i1)*(*i2);
42  *retImag = (*r1)*(*i2) + (*i1)*(*r2);
43 
44  //================================================ Return
45  return ;
46 
47 }

◆ complexMultiplicationConjug()

void ProSHADE_internal_maths::complexMultiplicationConjug ( proshade_double *  r1,
proshade_double *  i1,
proshade_double *  r2,
proshade_double *  i2,
proshade_double *  retReal,
proshade_double *  retImag 
)

Function to multiply two complex numbers by using the second number's conjugate.

This function takes pointers to the real and imaginary parts of two complex numbers and returns the result of their multiplication, while using the conjugate of the second complex number.

Parameters
[in]r1Pointer to the real value of number 1.
[in]i1Pointer to the imaginary value of number 1.
[in]r2Pointer to the real value of number 2.
[in]i2Pointer to the imaginary value of number 2.
[in]retRealPointer to the real part of the complex variable to which the result will be saved.
[in]retImagPointer to the imaginary part of the complex variable to which the result will be saved.

Definition at line 62 of file ProSHADE_maths.cpp.

63 {
64  //================================================ Multiplication
65  *retReal = (*r1)*(*r2) + (*i1)*(*i2);
66  *retImag = -(*r1)*(*i2) + (*i1)*(*r2);
67 
68  //================================================ Return
69  return ;
70 
71 }

◆ complexMultiplicationConjugRealOnly()

proshade_double ProSHADE_internal_maths::complexMultiplicationConjugRealOnly ( proshade_double *  r1,
proshade_double *  i1,
proshade_double *  r2,
proshade_double *  i2 
)

Function to conjuggate multiply two complex numbers and return the real part only.

This function takes pointers to the real and imaginary parts of two complex numbers and returns the real part of the result of their conjugate multiplication.

Parameters
[in]r1Pointer to the real value of number 1.
[in]i1Pointer to the imaginary value of number 1.
[in]r2Pointer to the real value of number 2.
[in]i2Pointer to the imaginary value of number 2.

Definition at line 103 of file ProSHADE_maths.cpp.

104 {
105  //================================================ Multiplication
106  proshade_double ret = (*r1)*(*r2) + (*i1)*(*i2);
107 
108  //================================================ Return
109  return ( ret );
110 
111 }

◆ complexMultiplicationRealOnly()

proshade_double ProSHADE_internal_maths::complexMultiplicationRealOnly ( proshade_double *  r1,
proshade_double *  i1,
proshade_double *  r2,
proshade_double *  i2 
)

Function to multiply two complex numbers and return the real part only.

This function takes pointers to the real and imaginary parts of two complex numbers and returns the real part of the result of their multiplication.

Parameters
[in]r1Pointer to the real value of number 1.
[in]i1Pointer to the imaginary value of number 1.
[in]r2Pointer to the real value of number 2.
[in]i2Pointer to the imaginary value of number 2.

Definition at line 83 of file ProSHADE_maths.cpp.

84 {
85  //================================================ Multiplication
86  proshade_double ret = (*r1)*(*r2) - (*i1)*(*i2);
87 
88  //================================================ Return
89  return ( ret );
90 
91 }

◆ compute3x3MatrixInverse()

proshade_double * ProSHADE_internal_maths::compute3x3MatrixInverse ( proshade_double *  mat)

Function for computing a 3x3 matrix inverse.

Parameters
[in]matThe matrix to be inverted.
[out]inverseThe inverse of matrix mat.

Definition at line 1906 of file ProSHADE_maths.cpp.

1907 {
1908  //================================================ Allocate memory
1909  proshade_double* inverse = new proshade_double[9];
1910  ProSHADE_internal_misc::checkMemoryAllocation ( inverse, __FILE__, __LINE__, __func__ );
1911 
1912  //================================================ Compute determinant
1913  proshade_double matDet = ( mat[0] * mat[4] * mat[8] ) +
1914  ( mat[1] * mat[5] * mat[6] ) +
1915  ( mat[2] * mat[3] * mat[7] ) -
1916  ( mat[0] * mat[5] * mat[7] ) -
1917  ( mat[1] * mat[3] * mat[8] ) -
1918  ( mat[2] * mat[4] * mat[6] );
1919 
1920  //================================================ Compute inverse matrix
1921  inverse[0] = ( mat[4] * mat[8] - mat[5] * mat[7] ) / matDet;
1922  inverse[1] = ( mat[2] * mat[7] - mat[1] * mat[8] ) / matDet;
1923  inverse[2] = ( mat[1] * mat[5] - mat[2] * mat[4] ) / matDet;
1924  inverse[3] = ( mat[5] * mat[6] - mat[3] * mat[8] ) / matDet;
1925  inverse[4] = ( mat[0] * mat[8] - mat[2] * mat[6] ) / matDet;
1926  inverse[5] = ( mat[2] * mat[3] - mat[0] * mat[5] ) / matDet;
1927  inverse[6] = ( mat[3] * mat[7] - mat[4] * mat[6] ) / matDet;
1928  inverse[7] = ( mat[1] * mat[6] - mat[0] * mat[7] ) / matDet;
1929  inverse[8] = ( mat[0] * mat[4] - mat[1] * mat[3] ) / matDet;
1930 
1931  //================================================ Done
1932  return ( inverse );
1933 }

◆ compute3x3MatrixMultiplication()

proshade_double * ProSHADE_internal_maths::compute3x3MatrixMultiplication ( proshade_double *  mat1,
proshade_double *  mat2 
)

Function for computing a 3x3 matrix multiplication.

Parameters
[in]mat1The matrix to multiply mat2.
[in]mat2The matrix to be multiplied by mat1.
[out]retThe matrix resulting from matrix multiplication of mat1 and mat2 in this order.

Definition at line 1831 of file ProSHADE_maths.cpp.

1832 {
1833  //================================================ Allocate memory
1834  proshade_double* ret = new proshade_double[9];
1835  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
1836 
1837  //================================================ Multiply
1838  ret[0] = ( mat1[0] * mat2[0] ) + ( mat1[1] * mat2[3] ) + ( mat1[2] * mat2[6] );
1839  ret[1] = ( mat1[0] * mat2[1] ) + ( mat1[1] * mat2[4] ) + ( mat1[2] * mat2[7] );
1840  ret[2] = ( mat1[0] * mat2[2] ) + ( mat1[1] * mat2[5] ) + ( mat1[2] * mat2[8] );
1841  ret[3] = ( mat1[3] * mat2[0] ) + ( mat1[4] * mat2[3] ) + ( mat1[5] * mat2[6] );
1842  ret[4] = ( mat1[3] * mat2[1] ) + ( mat1[4] * mat2[4] ) + ( mat1[5] * mat2[7] );
1843  ret[5] = ( mat1[3] * mat2[2] ) + ( mat1[4] * mat2[5] ) + ( mat1[5] * mat2[8] );
1844  ret[6] = ( mat1[6] * mat2[0] ) + ( mat1[7] * mat2[3] ) + ( mat1[8] * mat2[6] );
1845  ret[7] = ( mat1[6] * mat2[1] ) + ( mat1[7] * mat2[4] ) + ( mat1[8] * mat2[7] );
1846  ret[8] = ( mat1[6] * mat2[2] ) + ( mat1[7] * mat2[5] ) + ( mat1[8] * mat2[8] );
1847 
1848  //================================================ Done
1849  return ( ret );
1850 
1851 }

◆ compute3x3MatrixVectorMultiplication() [1/2]

proshade_double * ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( proshade_double *  mat,
proshade_double  x,
proshade_double  y,
proshade_double  z 
)

Function for computing a 3x3 matrix to 3x1 vector multiplication.

Parameters
[in]matThe matrix to multiply the vector with..
[in]xThe x-axis element of the vector which is to be multiplied by the matrix.
[in]yThe x-axis element of the vector which is to be multiplied by the matrix.
[in]zThe x-axis element of the vector which is to be multiplied by the matrix.
[out]retThe vector resulting from matrix multiplication of mat and the vector in this order.

Definition at line 1861 of file ProSHADE_maths.cpp.

1862 {
1863  //================================================ Allocate memory
1864  proshade_double* ret = new proshade_double[3];
1865  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
1866 
1867  //================================================ Compute the multiplication
1868  ret[0] = ( x * mat[0] ) + ( y * mat[1] ) + ( z * mat[2] );
1869  ret[1] = ( x * mat[3] ) + ( y * mat[4] ) + ( z * mat[5] );
1870  ret[2] = ( x * mat[6] ) + ( y * mat[7] ) + ( z * mat[8] );
1871 
1872  //================================================ Done
1873  return ( ret );
1874 
1875 }

◆ compute3x3MatrixVectorMultiplication() [2/2]

proshade_single * ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( proshade_single *  mat,
proshade_single  x,
proshade_single  y,
proshade_single  z 
)

Function for computing a 3x3 matrix to 3x1 vector multiplication.

Parameters
[in]matThe matrix to multiply the vector with..
[in]xThe x-axis element of the vector which is to be multiplied by the matrix.
[in]yThe x-axis element of the vector which is to be multiplied by the matrix.
[in]zThe x-axis element of the vector which is to be multiplied by the matrix.
[out]retThe vector resulting from matrix multiplication of mat and the vector in this order.

Definition at line 1885 of file ProSHADE_maths.cpp.

1886 {
1887  //================================================ Allocate memory
1888  proshade_single* ret = new proshade_single[3];
1889  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
1890 
1891  //================================================ Compute the multiplication
1892  ret[0] = ( x * mat[0] ) + ( y * mat[1] ) + ( z * mat[2] );
1893  ret[1] = ( x * mat[3] ) + ( y * mat[4] ) + ( z * mat[5] );
1894  ret[2] = ( x * mat[6] ) + ( y * mat[7] ) + ( z * mat[8] );
1895 
1896  //================================================ Done
1897  return ( ret );
1898 
1899 }

◆ computeCrossProduct()

proshade_double * ProSHADE_internal_maths::computeCrossProduct ( proshade_double *  x1,
proshade_double *  y1,
proshade_double *  z1,
proshade_double *  x2,
proshade_double *  y2,
proshade_double *  z2 
)

Simple 3D vector cross product computation.

Parameters
[in]x1The x-axis element of the first vector.
[in]y1The y-axis element of the first vector.
[in]z1The z-axis element of the first vector.
[in]x2The x-axis element of the second vector.
[in]y2The y-axis element of the second vector.
[in]z2The z-axis element of the second vector.
[out]crossProdThe vector representing the cross product of the two input vectors.

Definition at line 1809 of file ProSHADE_maths.cpp.

1810 {
1811  //================================================ Allocate memory
1812  proshade_double* crossProd = new proshade_double[3];
1813  ProSHADE_internal_misc::checkMemoryAllocation ( crossProd, __FILE__, __LINE__, __func__ );
1814 
1815  //================================================ Compute
1816  crossProd[0] = ( (*y1) * (*z2) ) - ( (*z1) * (*y2) );
1817  crossProd[1] = ( (*z1) * (*x2) ) - ( (*x1) * (*z2) );
1818  crossProd[2] = ( (*x1) * (*y2) ) - ( (*y1) * (*x2) );
1819 
1820  //================================================ Done
1821  return ( crossProd );
1822 
1823 }

◆ computeDotProduct() [1/2]

proshade_double ProSHADE_internal_maths::computeDotProduct ( proshade_double *  x1,
proshade_double *  y1,
proshade_double *  z1,
proshade_double *  x2,
proshade_double *  y2,
proshade_double *  z2 
)

Simple 3D vector dot product computation.

Parameters
[in]x1The x-axis element of the first vector.
[in]y1The y-axis element of the first vector.
[in]z1The z-axis element of the first vector.
[in]x2The x-axis element of the second vector.
[in]y2The y-axis element of the second vector.
[in]z2The z-axis element of the second vector.
[out]XThe dot product of the two input vectors.

Definition at line 1777 of file ProSHADE_maths.cpp.

1778 {
1779  //================================================ Compute and return
1780  return ( (*x1 * *x2) + (*y1 * *y2) + (*z1 * *z2) );
1781 }

◆ computeDotProduct() [2/2]

proshade_double ProSHADE_internal_maths::computeDotProduct ( proshade_double  x1,
proshade_double  y1,
proshade_double  z1,
proshade_double  x2,
proshade_double  y2,
proshade_double  z2 
)

Simple 3D vector dot product computation.

Parameters
[in]x1The x-axis element of the first vector.
[in]y1The y-axis element of the first vector.
[in]z1The z-axis element of the first vector.
[in]x2The x-axis element of the second vector.
[in]y2The y-axis element of the second vector.
[in]z2The z-axis element of the second vector.
[out]XThe dot product of the two input vectors.

Definition at line 1793 of file ProSHADE_maths.cpp.

1794 {
1795  //================================================ Compute and return
1796  return ( (x1 * x2) + (y1 * y2) + (z1 * z2) );
1797 }

◆ computeFSC()

proshade_double ProSHADE_internal_maths::computeFSC ( fftw_complex *  fCoeffs1,
fftw_complex *  fCoeffs2,
proshade_unsign  xInds,
proshade_unsign  yInds,
proshade_unsign  zInds,
proshade_signed  noBins,
proshade_signed *  binIndexing,
proshade_double **&  binData,
proshade_signed *&  binCounts 
)

This function computes the FSC.

This funcion computes the Fourier Shell Correlation weighted average from two identically sized arrays of Fourier coefficients. It requires these to have been pre-computed as well as the number of bins and bin mapping to be pre-computed (using the binReciprocalSpaceReflections function). Given all these inputs, this function simply computes all the required sums for each bin, processes them and outputs the weighted average FSC over all bins.

Parameters
[in]fCoeffs1The Fourier coefficients of the first map.
[in]fCoeffs2The Fourier coefficients of the second map.
[in]xIndsThe number of indices along the x-axis.
[in]yIndsThe number of indices along the y-axis.
[in]zIndsThe number of indices along the z-axis.
[in]noBinNumber of bins.
[in]binIndexingThe map of bin belonging for each reflection.
[in]binDataArray of arrays for holding temporary results of the FSC computation. It needs to have been already allocated and have dimensions of noBins x 12. This array is modified by the function in case the caller would like access to these.
[in]binCountsArray of counts for each bin. It needs to be pre-allocated and have dimension of noBins. This array is modified by the function in case the caller would like access to these.
[out]fscThe Fourier Shell Correlation between the two supplied Fourier coefficient maps.

Definition at line 3090 of file ProSHADE_maths.cpp.

3091 {
3092  //================================================ Initialise local variables
3093  proshade_double realOrig, realRot, imagOrig, imagRot, fsc = 0.0;;
3094  proshade_signed indx, arrPos;
3095  std::vector< proshade_double > covarByBin ( static_cast< size_t > ( noBins ), 0.0 );
3096  std::vector< proshade_double > fscByBin ( static_cast< size_t > ( noBins ), 0.0 );
3097 
3098  //================================================ Compute bin sums
3099  for ( proshade_signed xIt = 0; xIt < static_cast< proshade_signed > ( xInds ); xIt++ )
3100  {
3101  for ( proshade_signed yIt = 0; yIt < static_cast< proshade_signed > ( yInds ); yIt++ )
3102  {
3103  for ( proshade_signed zIt = 0; zIt < static_cast< proshade_signed > ( zInds ); zIt++ )
3104  {
3105  //==================================== Find array position
3106  arrPos = zIt + static_cast< proshade_signed > ( zInds ) * ( yIt + static_cast< proshade_signed > ( yInds ) * xIt );
3107 
3108  //==================================== If no bin is associated, skip this reflection
3109  indx = binIndexing[ static_cast< size_t > ( arrPos ) ];
3110  if ( ( indx < 0 ) || ( indx > noBins ) ) { continue; }
3111 
3112  //==================================== Calculate the sums
3113  realOrig = fCoeffs1[arrPos][0];
3114  imagOrig = fCoeffs1[arrPos][1];
3115  realRot = fCoeffs2[arrPos][0];
3116  imagRot = fCoeffs2[arrPos][1];
3117 
3118  binData[indx][0] += realOrig;
3119  binData[indx][1] += imagOrig;
3120  binData[indx][2] += realRot;
3121  binData[indx][3] += imagRot;
3122  binData[indx][4] += realOrig * realRot;
3123  binData[indx][5] += imagOrig * imagRot;
3124  binData[indx][6] += std::pow ( realOrig, 2.0 );
3125  binData[indx][7] += std::pow ( imagOrig, 2.0 );
3126  binData[indx][8] += std::pow ( realRot, 2.0 );
3127  binData[indx][9] += std::pow ( imagRot, 2.0 );
3128 
3129  //==================================== Update bin counts
3130  binCounts[indx] += 1;
3131  }
3132  }
3133  }
3134 
3135  //================================================ Compute covariance by bin
3136  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3137  {
3138  covarByBin.at(binIt) = ( ( binData[binIt][4] + binData[binIt][5] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3139  ( ( binData[binIt][0] / static_cast< proshade_double > ( binCounts[binIt] ) *
3140  binData[binIt][2] / static_cast< proshade_double > ( binCounts[binIt] ) ) +
3141  ( binData[binIt][1] / static_cast< proshade_double > ( binCounts[binIt] ) *
3142  binData[binIt][3] / static_cast< proshade_double > ( binCounts[binIt] ) ) ) );
3143  }
3144 
3145  //================================================ Get FSC by bin
3146  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3147  {
3148  binData[binIt][10] = ( binData[binIt][6] + binData[binIt][7] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3149  ( std::pow ( binData[binIt][0] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) +
3150  std::pow ( binData[binIt][1] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) );
3151  binData[binIt][11] = ( binData[binIt][8] + binData[binIt][9] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3152  ( std::pow ( binData[binIt][2] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) +
3153  std::pow ( binData[binIt][3] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) );
3154  fscByBin.at(binIt) = covarByBin.at(binIt) / ( std::sqrt ( binData[binIt][10] ) * std::sqrt ( binData[binIt][11] ) );
3155  }
3156 
3157  //================================================ Get average FSC over all bins
3158  proshade_double binSizeSum = 0.0;
3159  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3160  {
3161  fsc += fscByBin.at(binIt) * static_cast< proshade_double > ( binCounts[binIt] );
3162  binSizeSum += static_cast< proshade_double > ( binCounts[binIt] );
3163  }
3164  fsc /= static_cast< proshade_double > ( binSizeSum );
3165 
3166  //================================================ Done
3167  return ( fsc );
3168 
3169 }

◆ computeGaussian()

proshade_double ProSHADE_internal_maths::computeGaussian ( proshade_double  val,
proshade_double  sigma 
)

This function computes a Gaussian (normal) distribution value given distance from mean and sigma.

This function simply returns the height of a normal distribution with a given sigma for a value specific distance from the mean.

Parameters
[in]valThe distance from the mean for which the Gaussian height should be computed.
[in]sigmaThe standard deviation of the Gaussian for which the computation is done.
[out]heightThe height of the Gaussian distribution as desctibed by the sigma.

Definition at line 2847 of file ProSHADE_maths.cpp.

2848 {
2849  //================================================ Compute cumulative probability from Z-score
2850  proshade_double zScore = ( val / sigma );
2851  proshade_double cumulativeProbability = 0.5 * std::erfc ( zScore * M_SQRT1_2 );
2852 
2853  //================================================ Symmetrise
2854  if ( cumulativeProbability > 0.5 ) { cumulativeProbability = 1.0 - cumulativeProbability; }
2855 
2856  //================================================ Done
2857  return ( cumulativeProbability );
2858 
2859 }

◆ evaluateGLSeries()

proshade_double ProSHADE_internal_maths::evaluateGLSeries ( proshade_double *  series,
proshade_double  target,
proshade_unsign  terms 
)

This function evaluates the Taylor expansion.

This function takes the series array, the target value and the cap on Taylor expansion and proceeds to evaluate the series. The main use of this is to evaluate the series twice, one where the series evaluation 'overshoots' and once where it 'undershoots' and taking value in between those, thus adding accuracy.

Parameters
[in]seriesPointer to array with the series values.
[in]targetThe target location on the series value.
[in]termsThe Taylor expansion cap.
[out]XThe value of the series at the target location.

Definition at line 449 of file ProSHADE_maths.cpp.

450 {
451  //================================================ Initalise
452  proshade_double factorialValue = 1.0;
453  proshade_double value = 0.0;
454 
455  //================================================ Compute
456  for ( proshade_unsign iter = 1; iter <= terms; iter++ )
457  {
458  value = value + series[iter] * factorialValue;
459  factorialValue = factorialValue * target;
460  }
461 
462  //================================================ Done
463  return ( value );
464 
465 }

◆ findAllPrimes()

std::vector< proshade_unsign > ProSHADE_internal_maths::findAllPrimes ( proshade_unsign  upTo)

This function finds all prime numbers up to the supplied limit.

This function uses the sieve of Eratosthenes algorithm to find all prime numbers from 2 to the supplied limit. This is not the fastest algorithm and it may become slow when the limit is high, but it is fine for small numbers and given that we will use it for symmetry folds, which should not got much over 20, this should be more than fast enough.

Parameters
[in]upToThe limit to which prime numbers should be sought.

Definition at line 2802 of file ProSHADE_maths.cpp.

2803 {
2804  //================================================ Initialise variables
2805  std::vector< proshade_unsign > ret;
2806  std::vector< std::pair< proshade_unsign, bool > > sieveOfEratosthenesArray;
2807 
2808  //================================================ Sanity check
2809  if ( upTo < 2 ) { return ( ret ); }
2810 
2811  //================================================ Initialise the sieve array up to the required number
2812  for ( proshade_unsign iter = 2; iter <= upTo; iter++ ) { sieveOfEratosthenesArray.emplace_back ( std::pair< proshade_unsign, bool > ( iter, true ) ); }
2813 
2814  //================================================ For each entry in the array
2815  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); iter++ )
2816  {
2817  //============================================ If this entry is still true
2818  if ( sieveOfEratosthenesArray.at(iter).second )
2819  {
2820  //======================================== Set all entries with the position x * [this entry value] to false
2821  for ( proshade_unsign it = iter + sieveOfEratosthenesArray.at(iter).first; it < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); it += sieveOfEratosthenesArray.at(iter).first )
2822  {
2823  sieveOfEratosthenesArray.at(it).second = false;
2824  }
2825  }
2826  }
2827 
2828  //================================================ Copy passing results to return vector
2829  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); iter++ )
2830  {
2831  if ( sieveOfEratosthenesArray.at(iter).second ) { ProSHADE_internal_misc::addToUnsignVector ( &ret, sieveOfEratosthenesArray.at(iter).first ); }
2832  }
2833 
2834  //================================================ Done
2835  return ( ret );
2836 
2837 }

◆ findRotMatMatchingVectors()

proshade_double * ProSHADE_internal_maths::findRotMatMatchingVectors ( proshade_double  x1,
proshade_double  y1,
proshade_double  z1,
proshade_double  x2,
proshade_double  y2,
proshade_double  z2 
)

Computation of rotation matrix rotating one vector onto the other.

This function starts by normalising both input vectors to have magnitude of 1.0. Then, it computes the cosine and sine of the angle between the two vectors (using the magnitude of the cross product and the dot product); these are then sufficient to build the rotation matrix for rotation in plane on which both of the vectors lie.

It then proceeds to compute the change of basis matrix and its inverse, which are in turn sufficient to to compute the rotation matrix in the original basis. This rotation matrix is then returned.

Parameters
[in]x1The x-axis element of the first vector.
[in]y1The y-axis element of the first vector.
[in]z1The z-axis element of the first vector.
[in]x2The x-axis element of the second vector.
[in]y2The y-axis element of the second vector.
[in]z2The z-axis element of the second vector.
[out]rotMatRotation matrix optimally rotating x1 ; y1 ; z1 to match x2 ; y2 ; z2.

Definition at line 1979 of file ProSHADE_maths.cpp.

1980 {
1981  //================================================ Allocate required memory
1982  proshade_double* inPlaneRotation = new proshade_double[9];
1983  proshade_double* basisChangeMat = new proshade_double[9];
1984  ProSHADE_internal_misc::checkMemoryAllocation ( inPlaneRotation, __FILE__, __LINE__, __func__ );
1985  ProSHADE_internal_misc::checkMemoryAllocation ( basisChangeMat, __FILE__, __LINE__, __func__ );
1986 
1987  //================================================ Normalise inputs
1988  proshade_double normF = std::sqrt( std::pow( x1, 2.0 ) + std::pow ( y1, 2.0 ) + std::pow ( z1, 2.0 ) );
1989  x1 /= normF; y1 /= normF; z1 /= normF;
1990 
1991  normF = std::sqrt( std::pow( x2, 2.0 ) + std::pow ( y2, 2.0 ) + std::pow ( z2, 2.0 ) );
1992  x2 /= normF; y2 /= normF; z2 /= normF;
1993 
1994  //================================================ Compute cross product's magnitude
1995  proshade_double* crossProd = ProSHADE_internal_maths::computeCrossProduct( &x1, &y1, &z1, &x2, &y2, &z2 );
1996  proshade_double crossProdMag = std::sqrt( std::pow( crossProd[0], 2.0 ) + std::pow ( crossProd[1], 2.0 ) + std::pow ( crossProd[2], 2.0 ) );
1997  delete[] crossProd;
1998 
1999  //================================================ Compute dot product
2000  proshade_double dotProd = ProSHADE_internal_maths::computeDotProduct ( &x1, &y1, &z1, &x2, &y2, &z2 );
2001 
2002  //================================================ Construct the in-plane rotation matrix
2003  inPlaneRotation[0] = dotProd; inPlaneRotation[1] = -crossProdMag; inPlaneRotation[2] = 0.0;
2004  inPlaneRotation[3] = crossProdMag; inPlaneRotation[4] = dotProd; inPlaneRotation[5] = 0.0;
2005  inPlaneRotation[6] = 0.0; inPlaneRotation[7] = 0.0; inPlaneRotation[8] = 1.0;
2006 
2007  //================================================ Construct change of basis matrix
2008  crossProd = ProSHADE_internal_maths::computeCrossProduct( &x2, &y2, &z2, &x1, &y1, &z1 );
2009  normF = std::sqrt ( std::pow ( x2 - ( dotProd * x1 ), 2.0 ) + std::pow ( y2 - ( dotProd * y1 ), 2.0 ) + std::pow ( z2 - ( dotProd * z1 ), 2.0 ) );
2010 
2011  basisChangeMat[0] = x1; basisChangeMat[1] = ( x2 - ( dotProd * x1 ) ) / normF; basisChangeMat[2] = crossProd[0];
2012  basisChangeMat[3] = y1; basisChangeMat[4] = ( y2 - ( dotProd * y1 ) ) / normF; basisChangeMat[5] = crossProd[1];
2013  basisChangeMat[6] = z1; basisChangeMat[7] = ( z2 - ( dotProd * z1 ) ) / normF; basisChangeMat[8] = crossProd[2];
2014 
2015  //================================================ Invert the change of basis matrix
2016  proshade_double* basisChangeMatInverse = ProSHADE_internal_maths::compute3x3MatrixInverse ( basisChangeMat );
2017 
2018  //================================================ Multiply inverse of change of basis matrix with the in plane rotation matrix, then multiply the result with the inverse
2019  proshade_double* tmpMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( basisChangeMat, inPlaneRotation );
2020  proshade_double* rotMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( tmpMat, basisChangeMatInverse );
2021 
2022  //================================================ Release memory
2023  delete[] crossProd;
2024  delete[] inPlaneRotation;
2025  delete[] basisChangeMat;
2026  delete[] basisChangeMatInverse;
2027  delete[] tmpMat;
2028 
2029  //================================================ Done
2030  return ( rotMat );
2031 
2032 }

◆ findVectorFromThreeVAndThreeD()

std::vector< proshade_double > ProSHADE_internal_maths::findVectorFromThreeVAndThreeD ( proshade_double  x1,
proshade_double  y1,
proshade_double  z1,
proshade_double  x2,
proshade_double  y2,
proshade_double  z2,
proshade_double  x3,
proshade_double  y3,
proshade_double  z3,
proshade_double  dot1,
proshade_double  dot2,
proshade_double  dot3 
)

Function for finding a vector which would have a given three dot products to three other vectors.

This function takes three vectors and three dot product values. It then basically solves the following set of equations for x, y and z:

solX*x1 + solY*y1 + solZ*z1 = dot1
solX*x2 + solY*y2 + solZ*z2 = dot2
solX*x3 + solY*y3 + solZ*z3 = dot3

This should result in a vector, which has the required angles to all input vectors and is normalised (this is done later as part of this function). The equations are courtesy of https://www.wolframalpha.com/input/?i=Solve%5B%7Ba+x+%2B+b+y+%2B+c+z+%3D%3D+f%2C+u+x+%2B+v+y+%2B+w+z+%3D%3D+g%2C+k+x+%2B+l+y+%2B+m+z+%3D%3D+h%7D%2C+%7Bx%2C+y%2C+z%7D%5D webpage of Wolfram Alpha. If in doubt, do not fear to derive yourself :-).

Parameters
[in]x1The x-axis element of the first vector.
[in]y1The y-axis element of the first vector.
[in]z1The z-axis element of the first vector.
[in]x2The x-axis element of the second vector.
[in]y2The y-axis element of the second vector.
[in]z2The z-axis element of the second vector.
[in]dot1The dot product specifying the angle between the sought vector and the first input vector.
[in]dot2The dot product specifying the angle between the sought vector and the second input vectors.
[out]vecA std::vector containing the three elements of the sought vector.

Definition at line 2201 of file ProSHADE_maths.cpp.

2202 {
2203  //================================================ Initialise variables
2204  std::vector < proshade_double > ret;
2205 
2206  //================================================ Solution
2207  proshade_double solX = - ( y1 * dot2 * z3 - y1 * dot3 * z2 - z1 * dot2 * y3 + z1 * dot3 * y2 + dot1 * y3 * z2 - dot1 * z3 * y2 ) /
2208  ( -x1 * y3 * z2 + x1 * z3 * y2 + y1 * x3 * z2 - y1 * z3 * x2 - z1 * x3 * y2 + z1 * y3 * x2 );
2209  proshade_double solY = - ( x1 * dot2 * z3 - x1 * dot3 * z2 - z1 * dot2 * x3 + z1 * dot3 * x2 + dot1 * x3 * z2 - dot1 * z3 * x2 ) /
2210  ( x1 * y3 * z2 - x1 * z3 * y2 - y1 * x3 * z2 + y1 * z3 * x2 + z1 * x3 * y2 - z1 * y3 * x2 );
2211  proshade_double solZ = - ( x1 * dot2 * y3 - x1 * dot3 * y2 - y1 * dot2 * x3 + y1 * dot3 * x2 + dot1 * x3 * y2 - dot1 * y3 * x2 ) /
2212  ( -x1 * y3 * z2 + x1 * z3 * y2 + y1 * x3 * z2 - y1 * z3 * x2 - z1 * x3 * y2 + z1 * y3 * x2 );
2213 
2214  //================================================ Normalise the axis to magnitude 1
2215  proshade_double normFactor = sqrt ( pow ( solX, 2.0 ) + pow ( solY, 2.0 ) + pow ( solZ, 2.0 ) );
2216  solX /= normFactor;
2217  solY /= normFactor;
2218  solZ /= normFactor;
2219 
2220  //================================================ Set largest axis element to positive (ProSHADE standard)
2221  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) );
2222  const FloatingPoint< proshade_double > rhs1 ( std::abs ( solX ) );
2223  const FloatingPoint< proshade_double > rhs2 ( std::abs ( solY ) );
2224  const FloatingPoint< proshade_double > rhs3 ( std::abs ( solZ ) );
2225  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( solX < 0.0 ) ) ||
2226  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( solY < 0.0 ) ) ||
2227  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( solZ < 0.0 ) ) ) { solX *= -1.0; solY *= -1.0; solZ *= -1.0; }
2228 
2229  //================================================ Save solutions
2233 
2234  //================================================ Done
2235  return ( ret );
2236 
2237 }

◆ findVectorFromTwoVAndTwoD()

std::vector< proshade_double > ProSHADE_internal_maths::findVectorFromTwoVAndTwoD ( proshade_double  x1,
proshade_double  y1,
proshade_double  z1,
proshade_double  x2,
proshade_double  y2,
proshade_double  z2,
proshade_double  dot1,
proshade_double  dot2 
)

Function for finding a vector which would have a given two dot products to two other vectors.

This function takes two vectors and two dot product values. It then basically solves the following set of equations for x, y and z:

solX*x1 + solY*y1 + solZ*z1 = dot1
solX*x2 + solY*y2 + solZ*z2 = dot2
sqrt ( solX^2 + solY^2 + solZ^2 ) = 1.0

This should result in a vector, which has the required angles to both input vectors and is normalised (this is done by the third equation, which is required to obtain system of three equations with three unkonwns). The equations are courtesy of https://www.wolframalpha.com/input/?i=Solve%5B%7Ba+x+%2B+b+y+%2B+c+z+%3D%3D+f%2C+k+x+%2B+l+y+%2B+m+z+%3D%3D+g%2C+Sqrt%5Bx%5E2+%2B+y%5E2+%2B+z%5E2%5D+%3D%3D+1%7D%2C+%7Bx%2C+y%2C+z%7D%5D webpage of Wolfram Alpha. If in doubt, do not fear to derive yourself :-).

Parameters
[in]x1The x-axis element of the first vector.
[in]y1The y-axis element of the first vector.
[in]z1The z-axis element of the first vector.
[in]x2The x-axis element of the second vector.
[in]y2The y-axis element of the second vector.
[in]z2The z-axis element of the second vector.
[in]dot1The dot product specifying the angle between the sought vector and the first input vector.
[in]dot2The dot product specifying the angle between the sought vector and the second input vectors.
[out]vecA std::vector containing the three elements of the sought vector.

Definition at line 2055 of file ProSHADE_maths.cpp.

2056 {
2057  //================================================ Initialise variables
2058  std::vector < proshade_double > ret;
2059 
2060  //================================================ Solution
2061  proshade_double solX = ( -sqrt ( pow ( 2.0 * x1 * y1 * dot2 * y2 + 2.0 * x1 * z1 * dot2 * z2 - 2.0 * x1 * dot1 * pow ( y2, 2.0 ) - 2.0 * x1 * dot1 * pow ( z2, 2.0 ) - 2.0 * pow ( y1, 2.0 ) * dot2 * x2 + 2.0 * y1 * dot1 * x2 * y2 - 2.0 * pow ( z1, 2.0 ) * dot2 * x2 + 2.0 * z1 * dot1 * x2 * z2, 2.0 ) -
2062  4.0 * ( pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * x1 * y1 * x2 * y2 - 2.0 * x1 * z1 * x2 * z2 + pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) ) *
2063  ( pow ( y1, 2.0 ) * pow ( dot2, 2.0 ) - pow ( y1, 2.0 ) * pow ( z2, 2.0 ) + 2.0 * y1 * z1 * y2 * z2 - 2.0 * y1 * dot1 * dot2 * y2 + pow ( z1, 2.0 ) * pow ( dot2, 2.0 ) - pow ( z1, 2.0 ) * pow ( y2, 2.0 ) - 2.0 * z1 * dot1 * dot2 * z2 + pow ( dot1, 2.0 ) * pow ( y2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( z2, 2.0 ) ) ) -
2064  2.0 * x1 * y1 * dot2 * y2 - 2.0 * x1 * z1 * dot2 * z2 + 2.0 * x1 * dot1 * pow ( y2, 2.0 ) + 2.0 * x1 * dot1 * pow ( z2, 2.0 ) + 2.0 * pow ( y1, 2.0 ) * dot2 * x2 - 2.0 * y1 * dot1 * x2 * y2 + 2.0 * pow ( z1, 2.0 ) * dot2 * x2 - 2.0 * z1 * dot1 * x2 * z2 ) /
2065  ( 2.0 * ( pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * x1 * y1 * x2 * y2 - 2.0 * x1 * z1 * x2 * z2 + pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) ) );
2066  proshade_double solY = ( ( dot2 * pow ( x2, 2.0 ) * pow ( z1, 3.0 ) ) /
2067  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2068  ( dot1 * pow ( x2, 2.0 ) * z2 * pow ( z1, 2.0 ) ) /
2069  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2070  ( 2.0 * x1 * dot2 * x2 * z2 * pow ( z1, 2.0 ) ) /
2071  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) - dot2 * z1 -
2072  ( x2 * sqrt ( pow ( - 2.0 * dot2 * x2 * pow ( y1, 2.0 ) + 2.0 * x1 * dot2 * y2 * y1 + 2.0 * dot1 * x2 * y2 * y1 - 2.0 * x1 * dot1 * pow ( y2, 2.0 ) - 2.0 * x1 * dot1 * pow ( z2, 2.0 ) - 2.0 * pow ( z1, 2.0 ) * dot2 * x2 + 2.0 * x1 * z1 * dot2 * z2 + 2.0 * z1 * dot1 * x2 * z2, 2.0 ) -
2073  4.0 * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) *
2074  ( pow ( y1, 2.0 ) * pow ( dot2, 2.0 ) + pow ( z1, 2.0 ) * pow ( dot2, 2.0 ) - 2.0 * y1 * dot1 * y2 * dot2 - 2.0 * z1 * dot1 * z2 * dot2 - pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( y2, 2.0 ) - pow ( y1, 2.0 ) * pow ( z2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( z2, 2.0 ) + 2.0 * y1 * z1 * y2 * z2 ) ) * z1 ) /
2075  ( 2.0 * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) +
2076  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) * z1 ) /
2077  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2078  ( x1 * dot1 * x2 * pow ( y2, 2.0 ) * z1 ) /
2079  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2080  ( pow ( x1, 2.0 ) * dot2 * pow ( z2, 2.0 ) * z1 ) /
2081  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2082  ( 2.0 * x1 * dot1 * x2 * pow ( z2, 2.0 ) * z1 ) /
2083  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2084  ( y1 * dot1 * pow ( x2, 2.0 ) * y2 * z1 ) /
2085  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2086  ( x1 * y1 * dot2 * x2 * y2 * z1 ) /
2087  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) + dot1 * z2 +
2088  ( x1 * z2 * sqrt ( pow ( -2.0 * dot2 * x2 * pow ( y1, 2.0 ) + 2.0 * x1 * dot2 * y2 * y1 + 2.0 * dot1 * x2 * y2 * y1 - 2.0 * x1 * dot1 * pow ( y2, 2.0 ) - 2.0 * x1 * dot1 * pow ( z2, 2.0 ) - 2.0 * pow ( z1, 2.0 ) * dot2 * x2 + 2.0 * x1 * z1 * dot2 * z2 + 2.0 * z1 * dot1 * x2 * z2, 2.0 ) -
2089  4.0 * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) *
2090  ( pow ( y1, 2.0 ) * pow ( dot2, 2.0 ) + pow ( z1, 2.0 ) * pow ( dot2, 2.0 ) - 2.0 * y1 * dot1 * y2 * dot2 - 2.0 * z1 * dot1 * z2 * dot2 - pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( y2, 2.0 ) - pow ( y1, 2.0 ) * pow ( z2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( z2, 2.0 ) + 2.0 * y1 * z1 * y2 * z2 ) ) ) /
2091  ( 2.0 * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2092  ( pow ( x1, 2.0 ) * dot1 * pow ( z2, 3.0 ) ) /
2093  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2094  ( pow ( x1, 2.0 ) * dot1 * pow ( y2, 2.0 ) * z2 ) /
2095  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2096  ( x1 * pow ( y1, 2.0 ) * dot2 * x2 * z2 ) /
2097  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2098  ( pow ( x1, 2.0 ) * y1 * dot2 * y2 * z2 ) /
2099  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2100  ( x1 * y1 * dot1 * x2 * y2 * z2 ) /
2101  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) / ( y1 * z2 - z1 * y2 );
2102  proshade_double solZ = ( - ( dot2 * pow ( x2, 2.0 ) * y2 * pow ( z1, 3.0 ) ) /
2103  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2104  ( dot2 * pow ( x2, 2.0 ) * pow ( z1, 2.0 ) ) /
2105  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2106  ( dot1 * pow ( x2, 2.0 ) * y2 * z2 * pow ( z1, 2.0 ) ) /
2107  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) +
2108  ( 2.0 * x1 * dot2 * x2 * y2 * z2 * pow ( z1, 2.0 ) ) /
2109  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) +
2110  ( x2 * y2 * sqrt ( pow ( -2.0 * dot2 * x2 * pow ( y1, 2.0 ) + 2.0 * x1 * dot2 * y2 * y1 + 2.0 * dot1 * x2 * y2 * y1 - 2.0 * x1 * dot1 * pow ( y2, 2.0 ) - 2.0 * x1 * dot1 * pow ( z2, 2.0 ) - 2.0 * pow ( z1, 2.0 ) * dot2 * x2 + 2.0 * x1 * z1 * dot2 * z2 + 2.0 * z1 * dot1 * x2 * z2, 2.0 ) -
2111  4.0 * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) *
2112  ( pow ( y1, 2.0 ) * pow ( dot2, 2.0 ) + pow ( z1, 2.0 ) * pow ( dot2, 2.0 ) - 2.0 * y1 * dot1 * y2 * dot2 - 2.0 * z1 * dot1 * z2 * dot2 - pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( y2, 2.0 ) - pow ( y1, 2.0 ) * pow ( z2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( z2, 2.0 ) + 2.0 * y1 * z1 * y2 * z2 ) ) * z1 ) /
2113  ( 2.0 * ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) +
2114  ( dot2 * y2 * z1 ) / ( y1 * z2 - z1 * y2 ) +
2115  ( dot1 * pow ( x2, 2.0 ) * z2 * z1 ) /
2116  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2117  ( x1 * dot2 * x2 * z2 * z1 ) /
2118  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2119  ( x1 * dot1 * x2 * pow ( y2, 3.0 ) * z1 ) /
2120  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) +
2121  ( y1 * dot1 * pow ( x2, 2.0 ) * pow ( y2, 2.0 ) * z1 ) /
2122  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) +
2123  ( x1 * y1 * dot2 * x2 * pow ( y2, 2.0 ) * z1 ) /
2124  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2125  ( pow ( x1, 2.0 ) * dot2 * y2 * pow ( z2, 2.0 ) * z1 ) /
2126  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2127  ( 2.0 * x1 * dot1 * x2 * y2 * pow ( z2, 2.0 ) * z1 ) /
2128  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2129  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) * y2 * z1 ) /
2130  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) + dot2 +
2131  ( x2 * sqrt ( pow ( - 2.0 * dot2 * x2 * pow ( y1, 2.0 ) + 2.0 * x1 * dot2 * y2 * y1 + 2.0 * dot1 * x2 * y2 * y1 - 2.0 * x1 * dot1 * pow ( y2, 2.0 ) - 2.0 * x1 * dot1 * pow ( z2, 2.0 ) - 2.0 * pow ( z1, 2.0 ) * dot2 * x2 + 2.0 * x1 * z1 * dot2 * z2 + 2.0 * z1 * dot1 * x2 * z2, 2.0 ) -
2132  4.0 * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) *
2133  ( pow ( y1, 2.0 ) * pow ( dot2, 2.0 ) + pow ( z1, 2.0 ) * pow ( dot2, 2.0 ) - 2.0 * y1 * dot1 * y2 * dot2 - 2.0 * z1 * dot1 * z2 * dot2 - pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( y2, 2.0 ) - pow ( y1, 2.0 ) * pow ( z2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( z2, 2.0 ) + 2.0 * y1 * z1 * y2 * z2 ) ) ) /
2134  ( 2.0 * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2135  ( x1 * y2 * z2 * sqrt ( pow ( - 2.0 * dot2 * x2 * pow ( y1, 2.0 ) + 2.0 * x1 * dot2 * y2 * y1 + 2.0 * dot1 * x2 * y2 * y1 - 2.0 * x1 * dot1 * pow ( y2, 2.0 ) - 2.0 * x1 * dot1 * pow ( z2, 2.0 ) - 2.0 * pow ( z1, 2.0 ) * dot2 * x2 + 2.0 * x1 * z1 * dot2 * z2 + 2.0 * z1 * dot1 * x2 * z2, 2.0 ) -
2136  4.0 * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) *
2137  ( pow ( y1, 2.0 ) * pow ( dot2, 2.0 ) + pow ( z1, 2.0 ) * pow ( dot2, 2.0 ) - 2.0 * y1 * dot1 * y2 * dot2 - 2.0 * z1 * dot1 * z2 * dot2 - pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( y2, 2.0 ) - pow ( y1, 2.0 ) * pow ( z2, 2.0 ) + pow ( dot1, 2.0 ) * pow ( z2, 2.0 ) + 2.0 * y1 * z1 * y2 * z2 ) ) ) /
2138  ( 2.0 * ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2139  ( dot1 * y2 * z2 ) / ( y1 * z2 - z1 * y2 ) -
2140  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) ) /
2141  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2142  ( x1 * dot1 * x2 * pow ( y2, 2.0 ) ) /
2143  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) -
2144  ( x1 * dot1 * x2 * pow ( z2, 2.0 ) ) /
2145  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2146  ( y1 * dot1 * pow ( x2, 2.0 ) * y2 ) /
2147  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2148  ( x1 * y1 * dot2 * x2 * y2 ) /
2149  ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) +
2150  ( pow ( x1, 2.0 ) * dot1 * y2 * pow ( z2, 3.0 ) ) /
2151  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) +
2152  ( pow ( x1, 2.0 ) * dot1 * pow ( y2, 3.0 ) * z2 ) /
2153  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2154  ( pow ( x1, 2.0 ) * y1 * dot2 * pow ( y2, 2.0 ) * z2 ) /
2155  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) -
2156  ( x1 * y1 * dot1 * x2 * pow ( y2, 2.0 ) * z2 ) /
2157  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) +
2158  ( x1 * pow ( y1, 2.0 ) * dot2 * x2 * y2 * z2 ) /
2159  ( ( y1 * z2 - z1 * y2 ) * ( pow ( y1, 2.0 ) * pow ( x2, 2.0 ) + pow ( z1, 2.0 ) * pow ( x2, 2.0 ) - 2.0 * x1 * y1 * y2 * x2 - 2.0 * x1 * z1 * z2 * x2 + pow ( x1, 2.0 ) * pow ( y2, 2.0 ) + pow ( z1, 2.0 ) * pow ( y2, 2.0 ) + pow ( x1, 2.0 ) * pow ( z2, 2.0 ) + pow ( y1, 2.0 ) * pow ( z2, 2.0 ) - 2.0 * y1 * z1 * y2 * z2 ) ) ) / z2;
2160 
2161  //================================================ Set largest axis element to positive (ProSHADE standard)
2162  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) );
2163  const FloatingPoint< proshade_double > rhs1 ( std::abs ( solX ) );
2164  const FloatingPoint< proshade_double > rhs2 ( std::abs ( solY ) );
2165  const FloatingPoint< proshade_double > rhs3 ( std::abs ( solZ ) );
2166  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( solX < 0.0 ) ) ||
2167  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( solY < 0.0 ) ) ||
2168  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( solZ < 0.0 ) ) ) { solX *= -1.0; solY *= -1.0; solZ *= -1.0; }
2169 
2170  //================================================ Save solutions
2174 
2175  //================================================ Done
2176  return ( ret );
2177 
2178 }

◆ gaussLegendreIntegration()

void ProSHADE_internal_maths::gaussLegendreIntegration ( proshade_complex *  vals,
proshade_unsign  valsSize,
proshade_unsign  order,
proshade_double *  abscissas,
proshade_double *  weights,
proshade_double  integralOverRange,
proshade_double  maxSphereDists,
proshade_double *  retReal,
proshade_double *  retImag 
)

Function to compute the complete complex Gauss-Legendre integration over spherical harmonic values in different shells.

This function takes the real parts of the spherical harmonics value in different shells and proceeds to compute the Gauss-Legendre integration over them. It uses the shell positions to appropriately place abscissas and their weights, which it assumes were pre-computed by the getLegendreAbscAndWeights() function.

Parameters
[in]valsPointer to a complex array of values over which the integration to be done.
[in]valsSizeThe length of the input array.
[in]orderThe integration order value.
[in]abscissasThe allocated array for holding the abscissa values.
[in]weightsThe allocated array for holding the weight values.
[in]integralOverRangeThe range of the intgral. If progressive shell mapping is used, this will not be max shell radius.
[in]maxSphereDistsDistance between two shells.
[in]retRealThe real part of the complex result of Gauss-Legendre integration over the shperical harmonics values.
[in]retImagThe imaginary part of the complex result of Gauss-Legendre integration over the shperical harmonics values.

Definition at line 711 of file ProSHADE_maths.cpp.

712 {
713  //================================================ Initialise local variables
714  proshade_triplet* intData = new proshade_triplet [order];
715  ProSHADE_internal_misc::checkMemoryAllocation ( intData, __FILE__, __LINE__, __func__ );
716  proshade_triplet posVals;
717  proshade_unsign lesserPos = 0;
718  proshade_unsign upperPos = 0;
719  proshade_double lesserWeight = 0.0;
720  proshade_double upperWeight = 0.0;
721 
722  //================================================ Rescale to <order> points
723  for ( proshade_unsign absIter = 0; absIter < order; absIter++ )
724  {
725  //============================================ Init loop
726  posVals[0] = 0.0;
727  posVals[1] = 0.0;
728  posVals[2] = 0.0;
729 
730  //============================================ Find real position of abscissas
731  posVals[0] = ( ( abscissas[absIter] + 1.0 ) / 2.0 ) * integralOverRange;
732 
733 
734  //============================================ Find lesser and upper bounds
735  for ( proshade_unsign valIt = 0; valIt < valsSize; valIt++ )
736  {
737  if ( ( ( static_cast< proshade_double > ( valIt ) * maxSphereDists ) <= posVals[0] ) && ( ( ( static_cast< proshade_double > ( valIt ) + 1.0 ) * maxSphereDists ) > posVals[0] ) )
738  {
739  lesserPos = static_cast<proshade_unsign> ( valIt );
740  upperPos = static_cast<proshade_unsign> ( valIt + 1 );
741  break;
742  }
743  }
744 
745  //============================================ Linear Interpolation
746  lesserWeight = 0.0;
747  upperWeight = 0.0;
748  if ( lesserPos != 0 )
749  {
750  //======================================== Here we realise that the lesser and upper bounds were determined on scale 1 ... N, while our values are on scale 0 ... N-1 and therefore after determining the linear interpolation weights, we subtract 1 from both lesserPos and upperPos; however ...
751  lesserWeight = static_cast< proshade_double > ( upperPos ) - ( posVals[0] / maxSphereDists );
752  upperWeight = 1.0 - lesserWeight;
753 
754  posVals[1] = ( lesserWeight * vals[lesserPos-1][0] ) + ( upperWeight * vals[upperPos-1][0] );
755  posVals[2] = ( lesserWeight * vals[lesserPos-1][1] ) + ( upperWeight * vals[upperPos-1][1] );
756  }
757  else
758  {
759  //======================================== ... this then means that we would require position -1 for when the integration value is between 0 and the first shell. To resolve this, we assume that the values are 0 below the first shell and proceed as follows:
760  upperWeight = 1.0 - ( static_cast< proshade_double > ( upperPos ) - ( posVals[0] / maxSphereDists ) );
761 
762  posVals[1] = ( upperWeight * vals[upperPos-1][0] );
763  posVals[2] = ( upperWeight * vals[upperPos-1][1] );
764  }
765 
766  intData[absIter][0] = posVals[0];
767  intData[absIter][1] = posVals[1];
768  intData[absIter][2] = posVals[2];
769  }
770 
771  //================================================ Integrate
772  *retReal = 0.0;
773  *retImag = 0.0;
774  for ( proshade_unsign absPoint = 0; absPoint < order; absPoint++ )
775  {
776  *retReal += ( weights[absPoint] * intData[absPoint][1] );
777  *retImag += ( weights[absPoint] * intData[absPoint][2] );
778  }
779 
780  //================================================ Normalise
781  *retReal *= ( integralOverRange / 2.0 );
782  *retImag *= ( integralOverRange / 2.0 );
783 
784  //================================================ Release memory
785  delete[] intData;
786 
787  //================================================ Done
788  return ;
789 
790 }

◆ gaussLegendreIntegrationReal()

proshade_double ProSHADE_internal_maths::gaussLegendreIntegrationReal ( proshade_double *  vals,
proshade_unsign  valsSize,
proshade_unsign  order,
proshade_double *  abscissas,
proshade_double *  weights,
proshade_double  integralOverRange,
proshade_double  maxSphereDists 
)

Function to compute real part of the Gauss-Legendre integration over spherical harmonic values in different shells.

This function takes the real parts of the spherical harmonics value in different shells and proceeds to compute the Gauss-Legendre integration over them. It uses the shell positions to appropriately place abscissas and their weights, which it assumes were pre-computed by the getLegendreAbscAndWeights() function.

Parameters
[in]valsPointer to an array of values over which the integration to be done.
[in]valsSizeThe length of the input array.
[in]orderThe integration order value.
[in]abscissasThe allocated array for holding the abscissa values.
[in]weightsThe allocated array for holding the weight values.
[in]integralOverRangeThe range of the intgral. If progressive shell mapping is used, this will not be max shell radius.
[in]maxSphereDistsDistance between two shells.
[out]XThe real part of Gauss-Legendre integration over the shperical harmonics values.

Definition at line 621 of file ProSHADE_maths.cpp.

622 {
623  //================================================ Initialise local variables
624  proshade_double ret = 0.0;
625  proshade_complex* intData = new proshade_complex[order];
626  ProSHADE_internal_misc::checkMemoryAllocation ( intData, __FILE__, __LINE__, __func__ );
627  proshade_complex posVals;
628  proshade_unsign lesserPos = 0;
629  proshade_unsign upperPos = 0;
630  proshade_double lesserWeight = 0.0;
631  proshade_double upperWeight = 0.0;
632 
633  //================================================ Rescale to <order> points
634  for ( proshade_unsign absIter = 0; absIter < order; absIter++ )
635  {
636  //============================================ Init loop
637  posVals[0] = 0.0;
638  posVals[1] = 0.0;
639 
640  //============================================ Find real position of abscissas
641  posVals[0] = ( ( abscissas[absIter] + 1.0 ) / 2.0 ) * integralOverRange;
642 
643 
644  //============================================ Find lesser and upper bounds
645  for ( proshade_unsign valIt = 0; valIt < valsSize; valIt++ )
646  {
647  if ( ( ( static_cast< proshade_double > ( valIt ) * maxSphereDists ) <= posVals[0] ) && ( ( ( static_cast< proshade_double > ( valIt ) + 1.0 ) * maxSphereDists ) > posVals[0] ) )
648  {
649  lesserPos = static_cast<proshade_unsign> ( valIt );
650  upperPos = static_cast<proshade_unsign> ( valIt + 1 );
651  break;
652  }
653  }
654 
655  //============================================ Linear Interpolation
656  lesserWeight = 0.0;
657  upperWeight = 0.0;
658  if ( lesserPos != 0 )
659  {
660  //======================================== Here we realise that the lesser and upper bounds were determined on scale 1 ... N, while our values are on scale 0 ... N-1 and therefore after determining the linear interpolation weights, we subtract 1 from both lesserPos and upperPos; however ...
661  lesserWeight = static_cast< proshade_double > ( upperPos ) - ( posVals[0] / maxSphereDists );
662  upperWeight = 1.0 - lesserWeight;
663 
664  posVals[1] = ( lesserWeight * vals[lesserPos-1] ) + ( upperWeight * vals[upperPos-1] );
665  }
666  else
667  {
668  //======================================== ... this then means that we would require position -1 for when the integration value is between 0 and the first shell. To resolve this, we assume that the values are 0 below the first shell and proceed as follows:
669  upperWeight = 1.0 - ( static_cast< proshade_double > ( upperPos ) - ( posVals[0] / maxSphereDists ) );
670 
671  posVals[1] = ( upperWeight * vals[upperPos-1] );
672  }
673 
674  intData[absIter][0] = posVals[0];
675  intData[absIter][1] = posVals[1];
676  }
677 
678  //================================================ Integrate
679  for ( proshade_unsign absPoint = 0; absPoint < order; absPoint++ )
680  {
681  ret += ( weights[absPoint] * intData[absPoint][1] );
682  }
683 
684  //================================================ Normalise
685  ret *= ( integralOverRange / 2.0 );
686 
687  //================================================ Release memory
688  delete[] intData;
689 
690  //================================================ Done
691  return ( ret );
692 
693 }

◆ getAxisAngleFromRotationMatrix() [1/2]

void ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( proshade_double *  rotMat,
proshade_double *  x,
proshade_double *  y,
proshade_double *  z,
proshade_double *  ang 
)

This function converts rotation matrix to the axis-angle representation.

This function takes a rotation matrix as an array of 9 numbers and converts it to the Angle-Axis representation, which is the main rotation representation used in ProSHADE. This function deals with both the North and South pole singularity of the rotation matrices.

Parameters
[in]rotMatRotation matrix as an array of 9 values.
[in]xPointer to which the x-axis value of the axis vector will be saved.
[in]yPointer to which the y-axis value of the axis vector will be saved.
[in]zPointer to which the z-axis value of the axis vector will be saved.
[in]angPointer to which the angle value will be saved.

Definition at line 1128 of file ProSHADE_maths.cpp.

1129 {
1130  //================================================ Initialise
1131  proshade_double singAtPiCheck = 0.01;
1132  proshade_double singAtIdentity = 0.05;
1133 
1134  //================================================ Check input for singularities
1135  if ( ( std::abs ( rotMat[1] - rotMat[3] ) < singAtPiCheck ) &&
1136  ( std::abs ( rotMat[2] - rotMat[6] ) < singAtPiCheck ) &&
1137  ( std::abs ( rotMat[5] - rotMat[7] ) < singAtPiCheck ) )
1138  {
1139  //============================================ Singularity in input! Check for identity matrix
1140  if ( ( std::abs ( rotMat[1] + rotMat[3] ) < singAtIdentity ) &&
1141  ( std::abs ( rotMat[2] + rotMat[6] ) < singAtIdentity ) &&
1142  ( std::abs ( rotMat[5] + rotMat[7] ) < singAtIdentity ) &&
1143  ( std::abs ( rotMat[0] + rotMat[4] + rotMat[8] - 3.0 ) < singAtIdentity ) )
1144  {
1145  //======================================== Identity matrix. Return 0 angle.
1146  *x = 1.0;
1147  *y = 0.0;
1148  *z = 0.0;
1149  *ang = 0.0;
1150 
1151  //======================================== Done
1152  return ;
1153  }
1154 
1155  //============================================ If we got here, this is the 180deg (pi rad) singularity. Find which axis should the rotation be done along
1156  *ang = M_PI;
1157 
1158  proshade_double xx = ( rotMat[0] + 1.0 ) / 2.0;
1159  proshade_double yy = ( rotMat[4] + 1.0 ) / 2.0;
1160  proshade_double zz = ( rotMat[8] + 1.0 ) / 2.0;
1161  proshade_double xy = ( rotMat[1] + rotMat[3] ) / 4.0;
1162  proshade_double xz = ( rotMat[2] + rotMat[6] ) / 4.0;
1163  proshade_double yz = ( rotMat[5] + rotMat[7] ) / 4.0;
1164 
1165  if ( ( xx > yy ) && ( xx > zz ) ) // XX is the largest diagonal
1166  {
1167  if ( xx < singAtPiCheck ) // and is still 0
1168  {
1169  *x = 0.0;
1170  *y = 1.0 / sqrt(2);
1171  *z = 1.0 / sqrt(2);
1172  }
1173  else
1174  {
1175  *x = sqrt ( xx );
1176  *y = xy / sqrt ( xx );
1177  *z = xz / sqrt ( xx );
1178  }
1179  }
1180 
1181  else if ( yy > zz ) // YY is the largest diagonal
1182  {
1183  if ( yy < singAtPiCheck ) // and is still 0
1184  {
1185  *x = 1.0 / sqrt(2);
1186  *y = 0.0;
1187  *z = 1.0 / sqrt(2);
1188  }
1189  else
1190  {
1191  *y = sqrt ( yy );
1192  *x = xy / sqrt ( yy );
1193  *z = yz / sqrt ( yy );
1194  }
1195  }
1196 
1197  else // ZZ is the largest diagonal
1198  {
1199  if ( zz < singAtPiCheck ) // and is still 0
1200  {
1201  *x = 1.0 / sqrt(2);
1202  *y = 1.0 / sqrt(2);
1203  *z = 0.0;
1204  }
1205  else
1206  {
1207  *z = sqrt ( zz );
1208  *x = xz / sqrt ( zz );
1209  *y = yz / sqrt ( zz );
1210  }
1211  }
1212 
1213  //============================================ Make sure largest axis is positive and so is the angle
1214  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) );
1215  const FloatingPoint< proshade_double > rhs1 ( std::abs ( *x ) );
1216  const FloatingPoint< proshade_double > rhs2 ( std::abs ( *y ) );
1217  const FloatingPoint< proshade_double > rhs3 ( std::abs ( *z ) );
1218  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( *x < 0.0 ) ) ||
1219  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( *y < 0.0 ) ) ||
1220  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( *z < 0.0 ) ) )
1221  {
1222  *x *= -1.0;
1223  *y *= -1.0;
1224  *z *= -1.0;
1225  *ang *= -1.0;
1226  }
1227  if ( *ang < 0.0 ) { *ang = ( 2.0 * M_PI ) + *ang; }
1228 
1229  //============================================ Done
1230  return ;
1231  }
1232 
1233  //================================================ No singularities! Now get angle
1234  *ang = std::acos ( ( std::max ( -1.0, std::min ( 3.0, rotMat[0] + rotMat[4] + rotMat[8] ) ) - 1.0 ) / 2.0 );
1235 
1236  //================================================ Init return values
1237  *x = 1.0;
1238  *y = 0.0;
1239  *z = 0.0;
1240 
1241  //================================================ Is angle 0? This should not happen, but will
1242  if ( std::abs ( *ang ) < singAtPiCheck )
1243  {
1244  *ang = 0.0;
1245  return ;
1246  }
1247 
1248  //================================================ Axis
1249  *x = rotMat[7] - rotMat[5];
1250  *y = rotMat[2] - rotMat[6];
1251  *z = rotMat[3] - rotMat[1];
1252 
1253  proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1254  *x /= normFactor;
1255  *y /= normFactor;
1256  *z /= normFactor;
1257 
1258  //================================================ Make sure largest axis is positive and so is the angle
1259  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) );
1260  const FloatingPoint< proshade_double > rhs1 ( std::abs ( *x ) );
1261  const FloatingPoint< proshade_double > rhs2 ( std::abs ( *y ) );
1262  const FloatingPoint< proshade_double > rhs3 ( std::abs ( *z ) );
1263  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( *x < 0.0 ) ) ||
1264  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( *y < 0.0 ) ) ||
1265  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( *z < 0.0 ) ) )
1266  {
1267  *x *= -1.0;
1268  *y *= -1.0;
1269  *z *= -1.0;
1270  *ang *= -1.0;
1271  }
1272  if ( *ang < 0.0 ) { *ang = ( 2.0 * M_PI ) + *ang; }
1273 
1274  //================================================ Done
1275  return ;
1276 
1277 }

◆ getAxisAngleFromRotationMatrix() [2/2]

void ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( std::vector< proshade_double > *  rotMat,
proshade_double *  x,
proshade_double *  y,
proshade_double *  z,
proshade_double *  ang 
)

This function converts rotation matrix to the axis-angle representation.

This function takes a rotation matrix as a pointer to a vector of doubles and converts it to the Angle-Axis representation, which is the main rotation representation used in ProSHADE. This function deals with both the North and South pole singularity of the rotation matrices.

Parameters
[in]rotMatRotation matrix as a pointer to a vector of doubles.
[in]xPointer to which the x-axis value of the axis vector will be saved.
[in]yPointer to which the y-axis value of the axis vector will be saved.
[in]zPointer to which the z-axis value of the axis vector will be saved.
[in]angPointer to which the angle value will be saved.

Definition at line 1291 of file ProSHADE_maths.cpp.

1292 {
1293  //================================================ Initialise
1294  proshade_double singAtPiCheck = 0.01;
1295  proshade_double singAtIdentity = 0.05;
1296 
1297  //================================================ Check input for singularities
1298  if ( ( std::abs ( rotMat->at(1) - rotMat->at(3) ) < singAtPiCheck ) &&
1299  ( std::abs ( rotMat->at(2) - rotMat->at(6) ) < singAtPiCheck ) &&
1300  ( std::abs ( rotMat->at(5) - rotMat->at(7) ) < singAtPiCheck ) )
1301  {
1302  //============================================ Singularity in input! Check for identity matrix
1303  if ( ( std::abs ( rotMat->at(1) + rotMat->at(3) ) < singAtIdentity ) &&
1304  ( std::abs ( rotMat->at(2) + rotMat->at(6) ) < singAtIdentity ) &&
1305  ( std::abs ( rotMat->at(5) + rotMat->at(7) ) < singAtIdentity ) &&
1306  ( std::abs ( rotMat->at(0) + rotMat->at(4) + rotMat->at(8) - 3.0 ) < singAtIdentity ) )
1307  {
1308  //======================================== Identity matrix. Return 0 angle.
1309  *x = 1.0;
1310  *y = 0.0;
1311  *z = 0.0;
1312  *ang = 0.0;
1313 
1314  //======================================== Done
1315  return ;
1316  }
1317 
1318  //============================================ If we got here, this is the 180deg (pi rad) singularity. Find which axis should the rotation be done along
1319  *ang = M_PI;
1320 
1321  proshade_double xx = ( rotMat->at(0) + 1.0 ) / 2.0;
1322  proshade_double yy = ( rotMat->at(4) + 1.0 ) / 2.0;
1323  proshade_double zz = ( rotMat->at(8) + 1.0 ) / 2.0;
1324  proshade_double xy = ( rotMat->at(1) + rotMat->at(3) ) / 4.0;
1325  proshade_double xz = ( rotMat->at(2) + rotMat->at(6) ) / 4.0;
1326  proshade_double yz = ( rotMat->at(5) + rotMat->at(7) ) / 4.0;
1327 
1328  if ( ( xx > yy ) && ( xx > zz ) ) // XX is the largest diagonal
1329  {
1330  if ( xx < singAtPiCheck ) // and is still 0
1331  {
1332  *x = 0.0;
1333  *y = 1.0 / sqrt(2);
1334  *z = 1.0 / sqrt(2);
1335  }
1336  else
1337  {
1338  *x = sqrt ( xx );
1339  *y = xy / sqrt ( xx );
1340  *z = xz / sqrt ( xx );
1341  }
1342  }
1343 
1344  else if ( yy > zz ) // YY is the largest diagonal
1345  {
1346  if ( yy < singAtPiCheck ) // and is still 0
1347  {
1348  *x = 1.0 / sqrt(2);
1349  *y = 0.0;
1350  *z = 1.0 / sqrt(2);
1351  }
1352  else
1353  {
1354  *y = sqrt ( yy );
1355  *x = xy / sqrt ( yy );
1356  *z = yz / sqrt ( yy );
1357  }
1358  }
1359 
1360  else // ZZ is the largest diagonal
1361  {
1362  if ( zz < singAtPiCheck ) // and is still 0
1363  {
1364  *x = 1.0 / sqrt(2);
1365  *y = 1.0 / sqrt(2);
1366  *z = 0.0;
1367  }
1368  else
1369  {
1370  *z = sqrt ( zz );
1371  *x = xz / sqrt ( zz );
1372  *y = yz / sqrt ( zz );
1373  }
1374  }
1375 
1376  //============================================ Make sure largest axis is positive and so is the angle
1377  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) );
1378  const FloatingPoint< proshade_double > rhs1 ( std::abs ( *x ) );
1379  const FloatingPoint< proshade_double > rhs2 ( std::abs ( *y ) );
1380  const FloatingPoint< proshade_double > rhs3 ( std::abs ( *z ) );
1381  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( *x < 0.0 ) ) ||
1382  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( *y < 0.0 ) ) ||
1383  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( *z < 0.0 ) ) )
1384  {
1385  *x *= -1.0;
1386  *y *= -1.0;
1387  *z *= -1.0;
1388  *ang *= -1.0;
1389  }
1390 
1391  //============================================ Done
1392  return ;
1393  }
1394 
1395  //================================================ No singularities! Now get angle
1396  *ang = std::acos ( ( std::max ( -1.0, std::min ( 3.0, rotMat->at(0) + rotMat->at(4) + rotMat->at(8) ) ) - 1.0 ) / 2.0 );
1397 
1398  //================================================ Init return values
1399  *x = 1.0;
1400  *y = 0.0;
1401  *z = 0.0;
1402 
1403  //================================================ Is angle 0? This should not happen, but will
1404  if ( std::abs ( *ang ) < singAtPiCheck )
1405  {
1406  *ang = 0.0;
1407  return ;
1408  }
1409 
1410  //================================================ Axis
1411  *x = rotMat->at(7) - rotMat->at(5);
1412  *y = rotMat->at(2) - rotMat->at(6);
1413  *z = rotMat->at(3) - rotMat->at(1);
1414 
1415  proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1416  *x /= normFactor;
1417  *y /= normFactor;
1418  *z /= normFactor;
1419 
1420  //================================================ Make sure largest axis is positive and so is the angle
1421  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) );
1422  const FloatingPoint< proshade_double > rhs1 ( std::abs ( *x ) );
1423  const FloatingPoint< proshade_double > rhs2 ( std::abs ( *y ) );
1424  const FloatingPoint< proshade_double > rhs3 ( std::abs ( *z ) );
1425  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( *x < 0.0 ) ) ||
1426  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( *y < 0.0 ) ) ||
1427  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( *z < 0.0 ) ) )
1428  {
1429  *x *= -1.0;
1430  *y *= -1.0;
1431  *z *= -1.0;
1432  *ang *= -1.0;
1433  }
1434 
1435  //================================================ Done
1436  return ;
1437 
1438 }

◆ getEulerZXZFromAngleAxis()

void ProSHADE_internal_maths::getEulerZXZFromAngleAxis ( proshade_double  axX,
proshade_double  axY,
proshade_double  axZ,
proshade_double  axAng,
proshade_double *  eA,
proshade_double *  eB,
proshade_double *  eG 
)

This function converts angle-axis representation to the Euler ZXZ angles representation.

This function does the angle-axis to Euler ZXZ conversion and if a problem around the Z axis arises, it deal with it.

Parameters
[in]axXAngle-axis representation axis x element.
[in]axYAngle-axis representation axis y element.
[in]axZAngle-axis representation axis z element.
[in]axAngAngle-axis representation angle.
[in]eAPointer to which the Euler angle alpha value will be saved.
[in]eBPointer to which the Euler angle beta value will be saved.
[in]eGPointer to which the Euler angle gamma value will be saved.

Definition at line 1602 of file ProSHADE_maths.cpp.

1603 {
1604  //================================================ If angle is 0 or infinity (anything divided by 0), return no rotation
1605  if ( ( axAng == 0.0 ) || ( std::isinf ( axAng ) ) )
1606  {
1607  //============================================ Return 0 ; 0 ; 0 for no angle
1608  *eA = 0.0;
1609  *eB = 0.0;
1610  *eG = 0.0;
1611 
1612  //============================================ Done
1613  return ;
1614  }
1615 
1616  //================================================ Compute required rotation matrix elements
1617  proshade_double cAng = std::cos ( axAng );
1618  proshade_double sAng = std::sin ( axAng );
1619  proshade_double tAng = 1.0 - cAng;
1620 
1621  proshade_double element22 = cAng + axZ * axZ * tAng;
1622 
1623  proshade_double tmp1 = axX * axZ * tAng;
1624  proshade_double tmp2 = axY * sAng;
1625  proshade_double element20 = tmp1 - tmp2;
1626  proshade_double element02 = tmp1 + tmp2;
1627 
1628  tmp1 = axY * axZ * tAng;
1629  tmp2 = axX * sAng;
1630  proshade_double element21 = tmp1 + tmp2;
1631  proshade_double element12 = tmp1 - tmp2;
1632 
1633  //================================================ Convert to Eulers
1634  if ( std::abs( element22 ) <= 0.99999 )
1635  {
1636  //============================================ This case occurs when there is no singularity in the rotation matrix (i.e. it does not have 0 or 180 degrees angle)
1637  *eA = std::atan2 ( element21, element20 );
1638  *eB = std::acos ( element22 );
1639  *eG = std::atan2 ( element12, -element02 );
1640  }
1641  else
1642  {
1643  //============================================ Compute some extra rotation matrix elements
1644  tmp1 = axX * axY * tAng;
1645  tmp2 = axZ * sAng;
1646  proshade_double element10 = tmp1 + tmp2;
1647  proshade_double element00 = cAng + axX * axX * tAng;
1648 
1649  //============================================ This case occurs when there is either 0 or 180 degrees rotation angle in the rotation matrix and therefore when beta is zero.
1650  if ( element22 >= 0.99999 )
1651  {
1652  //======================================== In this case, beta = 0 and alpha and gamma are only defined in terms of their sum. So we arbitrarily set gamma to 0 and solve alpha.
1653  *eA = std::atan2 ( element10, element00 );
1654  *eB = 0.0;
1655  *eG = 0.0;
1656  }
1657  if ( element22 <= -0.99999 )
1658  {
1659  //======================================== In this case, beta = PI and alpha and gamma are only defined in terms of their difference. So we arbitrarily set gamma to 0 and solve alpha.
1660  *eA = std::atan2 ( element10, element00 );
1661  *eB = M_PI;
1662  *eG = 0.0;
1663  }
1664  }
1665 
1666  //================================================ Get the angles to proper range
1667  if ( *eA < 0.0 ) { *eA = 2.0 * M_PI + *eA; }
1668  if ( *eB < 0.0 ) { *eB = M_PI + *eB; }
1669  if ( *eG < 0.0 ) { *eG = 2.0 * M_PI + *eG; }
1670 
1671  //================================================ Done
1672  return ;
1673 
1674 }

◆ getEulerZXZFromRotMatrix()

void ProSHADE_internal_maths::getEulerZXZFromRotMatrix ( proshade_double *  rotMat,
proshade_double *  eA,
proshade_double *  eB,
proshade_double *  eG 
)

This function converts rotation matrix to the Euler ZXZ angles representation.

Parameters
[in]rotMatRotation matrix as an array of 9 values.
[in]eAPointer to which the Euler angle alpha value will be saved.
[in]eBPointer to which the Euler angle beta value will be saved.
[in]eGPointer to which the Euler angle gamma value will be saved.

Definition at line 1551 of file ProSHADE_maths.cpp.

1552 {
1553  //================================================ Convert to Eulers
1554  if ( std::abs( rotMat[8] ) <= 0.99999 )
1555  {
1556  //============================================ This case occurs when there is no singularity in the rotation matrix (i.e. it does not have 0 or 180 degrees angle)
1557  *eA = std::atan2 ( rotMat[7], rotMat[6] );
1558  *eB = std::acos ( rotMat[8] );
1559  *eG = std::atan2 ( rotMat[5], -rotMat[2] );
1560  }
1561  else
1562  {
1563  //============================================ This case occurs when there is either 0 or 180 degrees rotation angle in the rotation matrix and therefore when beta is zero.
1564  if ( rotMat[8] >= 0.99999 )
1565  {
1566  //======================================== In this case, beta = 0 and alpha and gamma are only defined in terms of their sum. So we arbitrarily set gamma to 0 and solve alpha.
1567  *eA = std::atan2 ( rotMat[3], rotMat[0] );
1568  *eB = 0.0;
1569  *eG = 0.0;
1570  }
1571  if ( rotMat[8] <= -0.99999 )
1572  {
1573  //======================================== In this case, beta = PI and alpha and gamma are only defined in terms of their difference. So we arbitrarily set gamma to 0 and solve alpha.
1574  *eA = std::atan2 ( rotMat[3], rotMat[0] );
1575  *eB = M_PI;
1576  *eG = 0.0;
1577  }
1578  }
1579 
1580  //================================================ Get the angles to proper range
1581  if ( *eA < 0.0 ) { *eA = 2.0 * M_PI + *eA; }
1582  if ( *eB < 0.0 ) { *eB = M_PI + *eB; }
1583  if ( *eG < 0.0 ) { *eG = 2.0 * M_PI + *eG; }
1584 
1585  //================================================ Done
1586  return ;
1587 
1588 }

◆ getEulerZXZFromSOFTPosition()

void ProSHADE_internal_maths::getEulerZXZFromSOFTPosition ( proshade_signed  band,
proshade_signed  x,
proshade_signed  y,
proshade_signed  z,
proshade_double *  eulerAlpha,
proshade_double *  eulerBeta,
proshade_double *  eulerGamma 
)

Function to find Euler angles (ZXZ convention) from index position in the inverse SOFT map.

This function proceeds to convert the inverse SOFT map x, y and z position to Euler ZXZ convention angles, saving these into the supplied pointers.

Parameters
[in]bandThe maximum bandwidth of the computation.
[in]xThe x-axis position in the inverse SOFT map.
[in]yThe y-axis position in the inverse SOFT map.
[in]zThe z-axis position in the inverse SOFT map.
[in]eulerAlphaPointer to where the Euler alpha angle will be saved.
[in]eulerBetaPointer to where the Euler beta angle will be saved.
[in]eulerGammaPointer to where the Euler gamma angle will be saved.

Definition at line 963 of file ProSHADE_maths.cpp.

964 {
965  //================================================ Convert index to Euler angles
966  *eulerAlpha = M_PI * static_cast<proshade_double> ( y ) / ( static_cast<proshade_double> ( band ) ) ;
967  *eulerBeta = M_PI * ( 2.0 * static_cast<proshade_double> ( x ) ) / ( 4.0 * static_cast<proshade_double> ( band ) ) ;
968  *eulerGamma = M_PI * static_cast<proshade_double> ( z ) / ( static_cast<proshade_double> ( band ) ) ;
969 
970  //================================================ Done
971  return ;
972 
973 }

◆ getGLFirstEvenRoot()

void ProSHADE_internal_maths::getGLFirstEvenRoot ( proshade_double  polyAtZero,
proshade_unsign  order,
proshade_double *  abscAtZero,
proshade_double *  weighAtZero,
proshade_unsign  taylorSeriesCap 
)

This function finds the first root for Legendre polynomials of odd order.

The Legendre polynomials with odd order have zero as the first root, but the even oder polenomials have different value and this function serves the purpose of finding this value (i.e. the first root of the polynomial if the order is even).

Parameters
[in]polyAtZeroThe value of the polynomial at zero.
[in]orderThe positive integer value of the polynomial order.
[in]abscAtZeroPointer to variable storing the abscissa value at zero.
[in]weightAtZeroPointer to variable storing the weight value at zero.
[in]taylorSeriesCapThe limit on the Taylor series.

Definition at line 386 of file ProSHADE_maths.cpp.

387 {
388  //================================================ Sanity check
389  if ( taylorSeriesCap < 2 )
390  {
391  throw ProSHADE_exception ( "The Taylor series cap is too low.", "EI00020", __FILE__, __LINE__, __func__, "The Taylor series expansion limit is less than 2. This\n : seems very low; if you have a very small structure or very\n : low resolution, please manually increase the integration\n : order. Otherwise, please report this as a bug." );
392  }
393 
394  //================================================ Initialise variables
395  *abscAtZero = advanceGLPolyValue ( 0.0, -M_PI / 2.0, 0.0, order, taylorSeriesCap );
396  proshade_double hlp = 0.0;
397  proshade_double hlpVal = static_cast<proshade_double> ( order );
398  proshade_double *abscSteps;
399  proshade_double *weightSteps;
400 
401  //================================================ Allocate memory
402  abscSteps = new proshade_double [taylorSeriesCap+2];
403  weightSteps = new proshade_double [taylorSeriesCap+1];
404 
405  //================================================ Pre-set values
406  abscSteps[0] = 0.0;
407  abscSteps[1] = polyAtZero;
408  weightSteps[0] = 0.0;
409 
410  //================================================ Fill in abscissa and weight steps
411  for ( proshade_unsign iter = 0; iter <= taylorSeriesCap - 2; iter = iter + 2 )
412  {
413  hlp = static_cast<proshade_double> ( iter );
414 
415  abscSteps[iter+2] = 0.0;
416  abscSteps[iter+3] = ( hlp * ( hlp + 1.0 ) - hlpVal * ( hlpVal + 1.0 ) ) * abscSteps[iter+1] / (hlp + 1.0) / (hlp + 2.0 );
417 
418  weightSteps[iter+1] = 0.0;
419  weightSteps[iter+2] = ( hlp + 2.0 ) * abscSteps[iter+3];
420  }
421 
422  //================================================ Find abscissa and weights
423  for ( proshade_double iter = 0; iter < 5; iter++ )
424  {
425  *abscAtZero = *abscAtZero - evaluateGLSeries ( abscSteps, *abscAtZero, taylorSeriesCap ) / evaluateGLSeries ( weightSteps, *abscAtZero, taylorSeriesCap-1 );
426  }
427  *weighAtZero = evaluateGLSeries ( weightSteps, *abscAtZero, taylorSeriesCap-1 );
428 
429  //================================================ Free memory
430  delete abscSteps;
431  delete weightSteps;
432 
433  //================================================ Done
434  return ;
435 
436 }

◆ getGLPolyAtZero()

void ProSHADE_internal_maths::getGLPolyAtZero ( proshade_unsign  order,
proshade_double *  polyValue,
proshade_double *  deriValue 
)

This function obtains the Legendre polynomial values and its derivative at zero for any positive integer order polynomial.

This function takes the positive integer order of the Legendre polynomial and uses the recursive properties of the polynomials to work up to the order, computing the value at zero and its derivative for all lesser orders. It then returns the final values.

Parameters
[in]orderPositive integer order of the Legendre polynomial which value at zero we want.
[in]polyValuePointer to variable which will store the resulting polynomial value at zero.
[in]deriValuePointer to variable which will store the derivative of the zero value.

Definition at line 349 of file ProSHADE_maths.cpp.

350 {
351  //================================================ Initialise
352  proshade_double hlpVal = 0.0;
353  proshade_double prevPoly = 1.0;
354  proshade_double prevPrevPoly = 0.0;
355  proshade_double prevDeri = 0.0;
356  proshade_double prevPrevDeri = 0.0;
357 
358  for ( proshade_unsign ordIt = 0; ordIt < order; ordIt++ )
359  {
360  hlpVal = static_cast<proshade_double> ( ordIt );
361  *polyValue = -hlpVal * prevPrevPoly / ( hlpVal + 1.0 );
362  *deriValue = ( ( 2.0 * hlpVal + 1.0 ) * prevPoly - hlpVal * prevPrevDeri ) / ( hlpVal + 1.0 );
363  prevPrevPoly = prevPoly;
364  prevPoly = *polyValue;
365  prevPrevDeri = prevDeri;
366  prevDeri = *deriValue;
367  }
368 
369  //================================================ Done
370  return ;
371 
372 }

◆ getLegendreAbscAndWeights()

void ProSHADE_internal_maths::getLegendreAbscAndWeights ( proshade_unsign  order,
proshade_double *  abscissas,
proshade_double *  weights,
proshade_unsign  taylorSeriesCap 
)

Function to prepare abscissas and weights for Gauss-Legendre integration.

This function fills in the Gauss-Legendre interpolation points positions (abscissas) and their weights vectors, which will then be used for computing the Gauss-Legendre interpolation.

Parameters
[in]orderThe order to which the abscissas and weights should be prepared.
[in]abscissasThe array holding the abscissa values.
[in]weightsThe array holding the weight values.
[in]taylorSeriesCapThe limit on the Taylor series.

Definition at line 289 of file ProSHADE_maths.cpp.

290 {
291  //================================================ Sanity check
292  if ( order < 2 )
293  {
294  throw ProSHADE_exception ( "The integration order is too low.", "EI00019", __FILE__, __LINE__, __func__, "The Gauss-Legendre integration order is less than 2. This\n : seems very low; if you have a very small structure or very\n : low resolution, please manually increase the integration\n : order. Otherwise, please report this as a bug." );
295  }
296 
297  //================================================ Initialise
298  proshade_double polyValue = 0.0;
299  proshade_double deriValue = 0.0;
300  proshade_double weightSum = 0.0;
301 
302  //================================================ Find the polynomial and derivative values at 0
303  getGLPolyAtZero ( order,
304  &polyValue,
305  &deriValue );
306 
307  //================================================ If the order is odd, then 0 is a root ...
308  if ( order % 2 == 1 )
309  {
310  abscissas[((order-1)/2)] = polyValue;
311  weights[((order-1)/2)] = deriValue;
312  }
313  else
314  {
315  // ... and if order is even, find the first root
316  getGLFirstEvenRoot ( polyValue, order, &abscissas[(order/2)], &weights[(order/2)], taylorSeriesCap );
317  }
318 
319  //================================================ Now, having computed the first roots, complete the series
320  completeLegendreSeries ( order, abscissas, weights, taylorSeriesCap );
321 
322  //================================================ Correct weights by anscissa values
323  for ( proshade_unsign iter = 0; iter < order; iter++ )
324  {
325  weights[iter] = 2.0 / ( 1.0 - abscissas[iter] ) / ( 1.0 + abscissas[iter] ) / weights[iter] / weights[iter];
326  weightSum = weightSum + weights[iter];
327  }
328 
329  //================================================ Normalise weights
330  for ( proshade_unsign iter = 0; iter < order; iter++ )
331  {
332  weights[iter] = 2.0 * weights[iter] / weightSum;
333  }
334 
335  //================================================ Done
336  return ;
337 }

◆ getResolutionOfReflection()

proshade_single ProSHADE_internal_maths::getResolutionOfReflection ( proshade_single  h,
proshade_single  k,
proshade_single  l,
proshade_single  xDim,
proshade_single  yDim,
proshade_single  zDim 
)

This function computes the resolution of a particular reflection.

Parameters
[in]hThe index of the reflection in reciprocal space along the x-axis.
[in]kThe index of the reflection in reciprocal space along the y-axis.
[in]lThe index of the reflection in reciprocal space along the z-axis.
[in]xDimThe dimension of the cell along the x-axis in Angstroms.
[in]yDimThe dimension of the cell along the y-axis in Angstroms.
[in]zDimThe dimension of the cell along the z-axis in Angstroms.
[out]retThe resolution of the particular reflection.

Definition at line 2909 of file ProSHADE_maths.cpp.

2910 {
2911  //================================================ Compute volume and proportions
2912  proshade_single vol = ( xDim * yDim * zDim );
2913  proshade_single sa = ( yDim * zDim ) / vol;
2914  proshade_single sb = ( xDim * zDim ) / vol;
2915  proshade_single sc = ( xDim * yDim ) / vol;
2916 
2917  //================================================ Compute distance
2918  proshade_single s2 = ( std::pow ( h * sa, 2.0f ) +
2919  std::pow ( k * sb, 2.0f ) +
2920  std::pow ( l * sc, 2.0f ) ) / 4.0f;
2921 
2922  //================================================ Deal with F000
2923  if ( s2 == 0.0f ) { s2 = 0.0000000001f; }
2924 
2925  //================================================ Done
2926  return ( 1.0f / ( 2.0f * std::sqrt ( s2 ) ) );
2927 
2928 }

◆ getRotationMatrixFromAngleAxis() [1/2]

void ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( proshade_double *  rotMat,
proshade_double  x,
proshade_double  y,
proshade_double  z,
proshade_double  ang 
)

This function converts the axis-angle representation to the rotation matrix representation.

Parameters
[in]rotMatRotation matrix as an array of 9 values will be saved to this pointer, must already be allocated.
[in]xThe x-axis value of the axis vector.
[in]yThe y-axis value of the axis vector.
[in]zThe z-axis value of the axis vector.
[in]angTheangle value.

Definition at line 1448 of file ProSHADE_maths.cpp.

1449 {
1450  //================================================ If angle is 0 or infinity (anything divided by 0), return identity matrix
1451  if ( ( ang == 0.0 ) || ( std::isinf ( ang ) ) )
1452  {
1453  //============================================ Create identity
1454  for ( proshade_unsign i = 0; i < 9; i++ ) { rotMat[i] = 0.0; }
1455  rotMat[0] = 1.0;
1456  rotMat[4] = 1.0;
1457  rotMat[8] = 1.0;
1458 
1459  //============================================ Done
1460  return ;
1461  }
1462 
1463  //================================================ Compute the matrix
1464  proshade_double cAng = cos ( ang );
1465  proshade_double sAng = sin ( ang );
1466  proshade_double tAng = 1.0 - cAng;
1467 
1468  rotMat[0] = cAng + x * x * tAng;
1469  rotMat[4] = cAng + y * y * tAng;
1470  rotMat[8] = cAng + z * z * tAng;
1471 
1472  proshade_double tmp1 = x * y * tAng;
1473  proshade_double tmp2 = z * sAng;
1474  rotMat[3] = tmp1 + tmp2;
1475  rotMat[1] = tmp1 - tmp2;
1476 
1477  tmp1 = x * z * tAng;
1478  tmp2 = y * sAng;
1479  rotMat[6] = tmp1 - tmp2;
1480  rotMat[2] = tmp1 + tmp2;
1481 
1482  tmp1 = y * z * tAng;
1483  tmp2 = x * sAng;
1484  rotMat[7] = tmp1 + tmp2;
1485  rotMat[5] = tmp1 - tmp2;
1486 
1487  //================================================ Done
1488  return ;
1489 
1490 }

◆ getRotationMatrixFromAngleAxis() [2/2]

void ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( proshade_single *  rotMat,
proshade_double  x,
proshade_double  y,
proshade_double  z,
proshade_double  ang 
)

This function converts the axis-angle representation to the rotation matrix representation.

Parameters
[in]rotMatRotation matrix as an array of 9 values will be saved to this pointer, must already be allocated.
[in]xThe x-axis value of the axis vector.
[in]yThe y-axis value of the axis vector.
[in]zThe z-axis value of the axis vector.
[in]angTheangle value.

Definition at line 1500 of file ProSHADE_maths.cpp.

1501 {
1502  //================================================ If angle is 0 or infinity (anything divided by 0), return identity matrix
1503  if ( ( ang == 0.0 ) || ( std::isinf ( ang ) ) )
1504  {
1505  //============================================ Create identity
1506  for ( size_t i = 0; i < 9; i++ ) { rotMat[i] = 0.0f; }
1507  rotMat[0] = 1.0f;
1508  rotMat[4] = 1.0f;
1509  rotMat[8] = 1.0f;
1510 
1511  //============================================ Done
1512  return ;
1513  }
1514 
1515  //================================================ Compute the matrix
1516  proshade_single cAng = cos ( static_cast< proshade_single > ( ang ) );
1517  proshade_single sAng = sin ( static_cast< proshade_single > ( ang ) );
1518  proshade_single tAng = 1.0f - cAng;
1519 
1520  rotMat[0] = cAng + static_cast< proshade_single > ( x ) * static_cast< proshade_single > ( x ) * tAng;
1521  rotMat[4] = cAng + static_cast< proshade_single > ( y ) * static_cast< proshade_single > ( y ) * tAng;
1522  rotMat[8] = cAng + static_cast< proshade_single > ( z ) * static_cast< proshade_single > ( z ) * tAng;
1523 
1524  proshade_single tmp1 = static_cast< proshade_single > ( x ) * static_cast< proshade_single > ( y ) * tAng;
1525  proshade_single tmp2 = static_cast< proshade_single > ( z ) * sAng;
1526  rotMat[3] = tmp1 + tmp2;
1527  rotMat[1] = tmp1 - tmp2;
1528 
1529  tmp1 = static_cast< proshade_single > ( x ) * static_cast< proshade_single > ( z ) * tAng;
1530  tmp2 = static_cast< proshade_single > ( y ) * sAng;
1531  rotMat[6] = tmp1 - tmp2;
1532  rotMat[2] = tmp1 + tmp2;
1533 
1534  tmp1 = static_cast< proshade_single > ( y ) * static_cast< proshade_single > ( z ) * tAng;
1535  tmp2 = static_cast< proshade_single > ( x ) * sAng;
1536  rotMat[7] = tmp1 + tmp2;
1537  rotMat[5] = tmp1 - tmp2;
1538 
1539  //================================================ Done
1540  return ;
1541 
1542 }

◆ getRotationMatrixFromEulerZXZAngles() [1/2]

void ProSHADE_internal_maths::getRotationMatrixFromEulerZXZAngles ( proshade_double  eulerAlpha,
proshade_double  eulerBeta,
proshade_double  eulerGamma,
proshade_double *  matrix 
)

Function to find the rotation matrix from Euler angles (ZXZ convention).

Parameters
[in]eulerAlphaThe Euler alpha angle value.
[in]eulerBetaThe Euler beta angle value.
[in]eulerGammaThe Euler gamma angle value.
[in]matrixA pointer to array of 9 values to which the results of the function will be saved.

Definition at line 1011 of file ProSHADE_maths.cpp.

1012 {
1013  //================================================ No singularity/glimbal lock present
1014  if ( std::abs ( std::cos ( eulerBeta ) ) <= 0.98 )
1015  {
1016  //============================================ First row
1017  matrix[0] = cos ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) - sin ( eulerAlpha ) * sin ( eulerGamma );
1018  matrix[1] = sin ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) + cos ( eulerAlpha ) * sin ( eulerGamma );
1019  matrix[2] = -sin ( eulerBeta ) * cos ( eulerGamma );
1020 
1021  //============================================ Second row
1022  matrix[3] = -cos ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) - sin ( eulerAlpha ) * cos ( eulerGamma );
1023  matrix[4] = -sin ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) + cos ( eulerAlpha ) * cos ( eulerGamma );
1024  matrix[5] = sin ( eulerBeta ) * sin ( eulerGamma );
1025 
1026  //============================================ Third row
1027  matrix[6] = cos ( eulerAlpha ) * sin ( eulerBeta );
1028  matrix[7] = sin ( eulerAlpha ) * sin ( eulerBeta );
1029  matrix[8] = cos ( eulerBeta );
1030  }
1031  else
1032  {
1033  //============================================ Beta is either 0 or pi, making the alpha and gamma dimensions collapse into one (either only alpha+gamma or alpha-gamma are defined). In this case, we use conversion through quatermions.
1034  proshade_double qi = std::cos ( ( eulerAlpha - eulerGamma ) / 2.0 ) * std::sin ( eulerBeta / 2.0 );
1035  proshade_double qj = std::sin ( ( eulerAlpha - eulerGamma ) / 2.0 ) * std::sin ( eulerBeta / 2.0 );
1036  proshade_double qk = std::sin ( ( eulerAlpha + eulerGamma ) / 2.0 ) * std::cos ( eulerBeta / 2.0 );
1037  proshade_double qr = std::cos ( ( eulerAlpha + eulerGamma ) / 2.0 ) * std::cos ( eulerBeta / 2.0 );
1038 
1039  //============================================ First row
1040  matrix[0] = -1.0 + 2.0 * std::pow ( qi, 2.0 ) + 2.0 * std::pow ( qr, 2.0 );
1041  matrix[1] = 2.0 * ( qi * qj - qk * qr );
1042  matrix[2] = 2.0 * ( qi * qk + qj * qr );
1043 
1044  //============================================ Second row
1045  matrix[3] = 2.0 * ( qi * qj + qk * qr );
1046  matrix[4] = -1.0 + 2.0 * std::pow ( qj, 2.0 ) + 2.0 * std::pow ( qr, 2.0 );
1047  matrix[5] = 2.0 * ( qj * qk - qi * qr );
1048 
1049  //============================================ Third row
1050  matrix[6] = 2.0 * ( qi * qk - qj * qr );
1051  matrix[7] = 2.0 * ( qj * qk + qi * qr );
1052  matrix[8] = -1.0 + 2.0 * std::pow ( qk, 2.0 ) + 2.0 * std::pow ( qr, 2.0 );
1053  }
1054 
1055  //================================================ Done
1056  return ;
1057 
1058 }

◆ getRotationMatrixFromEulerZXZAngles() [2/2]

void ProSHADE_internal_maths::getRotationMatrixFromEulerZXZAngles ( proshade_single  eulerAlpha,
proshade_single  eulerBeta,
proshade_single  eulerGamma,
proshade_single *  matrix 
)

Function to find the rotation matrix from Euler angles (ZXZ convention).

Parameters
[in]eulerAlphaThe Euler alpha angle value.
[in]eulerBetaThe Euler beta angle value.
[in]eulerGammaThe Euler gamma angle value.
[in]matrixA pointer to array of 9 values to which the results of the function will be saved.

Definition at line 1067 of file ProSHADE_maths.cpp.

1068 {
1069  //================================================ No singularity/glimbal lock present
1070  if ( std::abs ( std::cos ( eulerBeta ) ) <= 0.9999999f )
1071  {
1072  //============================================ First row
1073  matrix[0] = cos ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) - sin ( eulerAlpha ) * sin ( eulerGamma );
1074  matrix[1] = sin ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) + cos ( eulerAlpha ) * sin ( eulerGamma );
1075  matrix[2] = -sin ( eulerBeta ) * cos ( eulerGamma );
1076 
1077  //============================================ Second row
1078  matrix[3] = -cos ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) - sin ( eulerAlpha ) * cos ( eulerGamma );
1079  matrix[4] = -sin ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) + cos ( eulerAlpha ) * cos ( eulerGamma );
1080  matrix[5] = sin ( eulerBeta ) * sin ( eulerGamma );
1081 
1082  //============================================ Third row
1083  matrix[6] = cos ( eulerAlpha ) * sin ( eulerBeta );
1084  matrix[7] = sin ( eulerAlpha ) * sin ( eulerBeta );
1085  matrix[8] = cos ( eulerBeta );
1086  }
1087  else
1088  {
1089  //============================================ Beta is either 0 or pi, making the alpha and gamma dimensions collapse into one (either only alpha+gamma or alpha-gamma are defined). In this case, we use conversion through quatermions.
1090  proshade_single qi = std::cos ( ( eulerAlpha - eulerGamma ) / 2.0f ) * std::sin ( eulerBeta / 2.0f );
1091  proshade_single qj = std::sin ( ( eulerAlpha - eulerGamma ) / 2.0f ) * std::sin ( eulerBeta / 2.0f );
1092  proshade_single qk = std::sin ( ( eulerAlpha + eulerGamma ) / 2.0f ) * std::cos ( eulerBeta / 2.0f );
1093  proshade_single qr = std::cos ( ( eulerAlpha + eulerGamma ) / 2.0f ) * std::cos ( eulerBeta / 2.0f );
1094 
1095  //============================================ First row
1096  matrix[0] = -1.0f + 2.0f * std::pow ( qi, 2.0f ) + 2.0f * std::pow ( qr, 2.0f );
1097  matrix[1] = 2.0f * ( qi * qj - qk * qr );
1098  matrix[2] = 2.0f * ( qi * qk + qj * qr );
1099 
1100  //============================================ Second row
1101  matrix[3] = 2.0f * ( qi * qj + qk * qr );
1102  matrix[4] = -1.0f + 2.0f * std::pow ( qj, 2.0f ) + 2.0f * std::pow ( qr, 2.0f );
1103  matrix[5] = 2.0f * ( qj * qk - qi * qr );
1104 
1105  //============================================ Third row
1106  matrix[6] = 2.0f * ( qi * qk - qj * qr );
1107  matrix[7] = 2.0f * ( qj * qk + qi * qr );
1108  matrix[8] = -1.0f + 2.0f * std::pow ( qk, 2.0f ) + 2.0f * std::pow ( qr, 2.0f );
1109  }
1110 
1111  //================================================ Done
1112  return ;
1113 
1114 }

◆ getSOFTPositionFromEulerZXZ()

void ProSHADE_internal_maths::getSOFTPositionFromEulerZXZ ( proshade_signed  band,
proshade_double  eulerAlpha,
proshade_double  eulerBeta,
proshade_double  eulerGamma,
proshade_double *  x,
proshade_double *  y,
proshade_double *  z 
)

Function to find the index position in the inverse SOFT map from given Euler angles (ZXZ convention).

This function does the conversion from Euler angles ZXZ convention to the SOFT map x, y and z position. It is not limitted to the SOFT map indices and instead if given Euler agnles between two indices will return a decimal point for the indices.

Parameters
[in]bandThe maximum bandwidth of the computation.
[in]eulerAlphaThe Euler alpha angle value.
[in]eulerBetaThe Euler beta angle value.
[in]eulerGammaThe Euler gamma angle value.
[in]xPointer to where the closest x-axis position in the inverse SOFT map will be saved to (position may be decimal!).
[in]yPointer to where the closest y-axis position in the inverse SOFT map will be saved to (position may be decimal!).
[in]zPointer to where the closest z-axis position in the inverse SOFT map will be saved to (position may be decimal!).

Definition at line 988 of file ProSHADE_maths.cpp.

989 {
990  //================================================ Convert Euler angles to indices
991 // *x = ( ( eulerBeta * 4.0 * static_cast< proshade_double > ( band ) ) - M_PI ) / ( 2.0 * M_PI );
992 // *y = ( eulerAlpha * static_cast< proshade_double > ( band ) ) / ( M_PI );
993 // *z = ( eulerGamma * static_cast< proshade_double > ( band ) ) / ( M_PI );
994 
995  *x = ( eulerBeta * static_cast<proshade_double> ( band ) * 2.0 ) / M_PI;
996  *y = ( eulerGamma * static_cast<proshade_double> ( band ) ) / M_PI;
997  *z = ( eulerAlpha * static_cast<proshade_double> ( band ) ) / M_PI;
998 
999  //================================================ Done
1000  return ;
1001 
1002 }

◆ isAxisUnique() [1/2]

bool ProSHADE_internal_maths::isAxisUnique ( std::vector< proshade_double * > *  CSymList,
proshade_double *  axis,
proshade_double  tolerance = 0.1,
bool  improve = false 
)

This function checks if new axis is unique, or already detected.

This function compares the supplied axis against all members of the axes vector. If the axis has the same fold and very similar axis vector (i.e. all three elements are within tolerance), then the function returns false. If no such match is found, true is returned.

Parameters
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]axisThe axis to be checked against CSymList to see if it not already present.
[in]toleranceThe allowed error on each dimension of the axis.
[in]improveIf a similar axis is found and if this already existing axis has lower peak height, should the CSymList be updated with the higher peak height axis?
[out]retBoolean specifying whether a similar axis was found or not.

Definition at line 2721 of file ProSHADE_maths.cpp.

2722 {
2723  //================================================ Initialise variables
2724  bool ret = true;
2725  proshade_unsign whichImprove = 0;
2726 
2727  //================================================ For each already detected member
2728  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
2729  {
2730  //============================================ Is fold the same?
2731  const FloatingPoint< proshade_double > lhs ( CSymList->at(grIt)[0] ), rhs ( axis[0] );
2732  if ( lhs.AlmostEquals ( rhs ) )
2733  {
2734  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], axis[1], axis[2], axis[3], tolerance ) )
2735  {
2736  ret = false;
2737  whichImprove = grIt;
2738  break;
2739  }
2740  }
2741  }
2742 
2743  //================================================ Improve, if required
2744  if ( improve && !ret )
2745  {
2746  CSymList->at(whichImprove)[1] = axis[1];
2747  CSymList->at(whichImprove)[2] = axis[2];
2748  CSymList->at(whichImprove)[3] = axis[3];
2749  CSymList->at(whichImprove)[4] = axis[4];
2750  CSymList->at(whichImprove)[5] = axis[5];
2751  }
2752 
2753  //================================================ Done
2754  return ( ret );
2755 
2756 }

◆ isAxisUnique() [2/2]

bool ProSHADE_internal_maths::isAxisUnique ( std::vector< proshade_double * > *  CSymList,
proshade_double  X,
proshade_double  Y,
proshade_double  Z,
proshade_double  fold,
proshade_double  tolerance 
)

This function checks if new axis is unique, or already detected.

This function compares the supplied axis against all members of the axes vector. If the axis has the same fold and very similar axis vector (i.e. all three elements are within tolerance), then the function returns false. If no such match is found, true is returned.

Parameters
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]XThe axis x-element to be checked against CSymList to see if it not already present.
[in]YThe axis x-element to be checked against CSymList to see if it not already present.
[in]ZThe axis x-element to be checked against CSymList to see if it not already present.
[in]toleranceThe allowed error on each dimension of the axis.
[out]retBoolean specifying whether a similar axis was found or not.

Definition at line 2770 of file ProSHADE_maths.cpp.

2771 {
2772  //================================================ Initialise variables
2773  bool ret = true;
2774 
2775  //================================================ For each already detected member
2776  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
2777  {
2778  const FloatingPoint< proshade_double > lhs ( fold ), rhs ( CSymList->at(grIt)[0] );
2779  if ( lhs.AlmostEquals ( rhs ) )
2780  {
2781  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], X, Y, Z, tolerance ) )
2782  {
2783  ret = false;
2784  break;
2785  }
2786  }
2787  }
2788 
2789  //================================================ Done
2790  return ( ret );
2791 
2792 }

◆ multiplyGroupElementMatrices()

std::vector< proshade_double > ProSHADE_internal_maths::multiplyGroupElementMatrices ( std::vector< proshade_double > *  el1,
std::vector< proshade_double > *  el2 
)

This function computes matrix multiplication using the ProSHADE group element matrix format as input and output.

Parameters
[in]el1Group element as rotation matrix in the group element matrix format.
[in]el2Group element as rotation matrix in the group element matrix format.
[out]retMatrix in the group element format resulting from the input matrices multiplication.

Definition at line 2245 of file ProSHADE_maths.cpp.

2246 {
2247  //================================================ Initialise variables
2248  std::vector< proshade_double > ret;
2249 
2250  //================================================ Compute
2251  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(0) ) +
2252  ( el1->at(1) * el2->at(3) ) +
2253  ( el1->at(2) * el2->at(6) ) );
2254  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(1) ) +
2255  ( el1->at(1) * el2->at(4) ) +
2256  ( el1->at(2) * el2->at(7) ) );
2257  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(2) ) +
2258  ( el1->at(1) * el2->at(5) ) +
2259  ( el1->at(2) * el2->at(8) ) );
2260 
2261  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(0) ) +
2262  ( el1->at(4) * el2->at(3) ) +
2263  ( el1->at(5) * el2->at(6) ) );
2264  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(1) ) +
2265  ( el1->at(4) * el2->at(4) ) +
2266  ( el1->at(5) * el2->at(7) ) );
2267  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(2) ) +
2268  ( el1->at(4) * el2->at(5) ) +
2269  ( el1->at(5) * el2->at(8) ) );
2270 
2271  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(0) ) +
2272  ( el1->at(7) * el2->at(3) ) +
2273  ( el1->at(8) * el2->at(6) ) );
2274  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(1) ) +
2275  ( el1->at(7) * el2->at(4) ) +
2276  ( el1->at(8) * el2->at(7) ) );
2277  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(2) ) +
2278  ( el1->at(7) * el2->at(5) ) +
2279  ( el1->at(8) * el2->at(8) ) );
2280 
2281 
2282  //================================================ Done
2283  return ( ret );
2284 
2285 }

◆ multiplyTwoSquareMatrices()

void ProSHADE_internal_maths::multiplyTwoSquareMatrices ( proshade_double *  A,
proshade_double *  B,
proshade_double *  res,
proshade_unsign  dim = 3 
)

Function to compute matrix multiplication.

Parameters
[in]AThe left matrix of the matrix multiplication to be solved.
[in]BThe right matrix of the matrix multiplication to be solved. (Assuming it already has been transposed).
[in]resMatrix containing the results.
[in]dimThe dimension of all the matrices (i.e. assuming square dim*dim matrices).
Warning
This function assumes the second matrix has been transposed already!

Definition at line 1685 of file ProSHADE_maths.cpp.

1686 {
1687  //================================================ Set res to 0.0s
1688  for ( proshade_unsign iter = 0; iter < 9; iter++ ) { res[iter] = 0.0; }
1689 
1690  //================================================ Compute the matrix multiplication
1691  for ( proshade_unsign row = 0; row < dim; row++ )
1692  {
1693  for ( proshade_unsign col = 0; col < dim; col++ )
1694  {
1695  for ( proshade_unsign inner = 0; inner < dim; inner++ )
1696  {
1697  res[(row*dim)+col] += A[(inner*dim)+row] * B[(col*dim)+inner];
1698  }
1699  }
1700  }
1701 
1702  //================================================ Done
1703  return ;
1704 
1705 }

◆ normalDistributionValue()

proshade_double ProSHADE_internal_maths::normalDistributionValue ( proshade_double  mean,
proshade_double  standardDev,
proshade_double  value 
)

Function to the heiht of normal distribution given by mean and standard deviation for a given value.

Parameters
[in]meanThe mean of the normal distribution.
[in]standardDevThe standard deviation of the normal distribution.
[in]valueThe value on the axis for which the height of the normal distribution is to be obtained.
[out]XThe height of the normal distribution at point given by the value.

Definition at line 1760 of file ProSHADE_maths.cpp.

1761 {
1762  //================================================ Compute and return
1763  return ( ( 1.0 / sqrt ( 2.0 * M_PI * pow(standardDev,2.0) ) ) * std::exp ( - pow( value - mean, 2.0 ) / 2.0 * pow(standardDev,2.0) ) );
1764 
1765 }

◆ optimiseAxisBiCubicInterpolation()

void ProSHADE_internal_maths::optimiseAxisBiCubicInterpolation ( proshade_double *  bestLattitude,
proshade_double *  bestLongitude,
proshade_double *  bestSum,
std::vector< proshade_unsign > *  sphereList,
std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *  sphereMappedRotFun,
proshade_double  step = 0.05 
)

This function provides axis optimisation given starting lattitude and longitude indices.

This function takes the initial lattitude and longitude indices as well as the current best sum over all appropriate spheres and the list of the spheres and proceeds to use bi-cubic interpolation and a sort of gradient ascend algorithm to search the space around the given indices for interpolated values, which would have higher sum of the rotation function values than the initial position. If any improvement is found, it will over-write the input variables.

Parameters
[in]bestLattitudeProshade double pointer to variable containing the best lattitude index value and to which the optimised result will be saved into.
[in]bestLongitudeProshade double pointer to variable containing the best longitude index value and to which the optimised result will be saved into.
[in]bestSumProshade double pointer to variable containing the best position rotation function values sum and to which the optimised result will be saved into.
[in]sphereListA vector containing the list of spheres which form the set for this symmetry.
[in]stepThe size of the step.

Definition at line 2400 of file ProSHADE_maths.cpp.

2401 {
2402  //================================================ Initialise variables
2403  proshade_double lonM, lonP, latM, latP, movSum;
2404  std::vector<proshade_double> latVals ( 3 );
2405  std::vector<proshade_double> lonVals ( 3 );
2406  proshade_double learningRate = 0.1;
2407  proshade_double prevVal = *bestSum;
2408  proshade_double valChange = 999.9;
2409  proshade_double origBestLat = std::round ( *bestLattitude );
2410  proshade_double origBestLon = std::round ( *bestLongitude );
2411  proshade_double tmpVal;
2412 
2413  //================================================ Initialise interpolators in all directions around the point of interest
2414  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsMinusMinus;
2415  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsMinusPlus;
2416  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsPlusMinus;
2417  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsPlusPlus;
2418  prepareBiCubicInterpolatorsMinusMinus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsMinusMinus, sphereMappedRotFun );
2419  prepareBiCubicInterpolatorsMinusPlus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsMinusPlus, sphereMappedRotFun );
2420  prepareBiCubicInterpolatorsPlusMinus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsPlusMinus, sphereMappedRotFun );
2421  prepareBiCubicInterpolatorsPlusPlus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsPlusPlus, sphereMappedRotFun );
2422 
2423  //================================================ Start the pseudo gradient ascent (while there is some change)
2424  while ( valChange > 0.0001 )
2425  {
2426  //============================================ Find the surrounding points to the currently best position
2427  lonM = *bestLongitude - step;
2428  lonP = *bestLongitude + step;
2429  latM = *bestLattitude - step;
2430  latP = *bestLattitude + step;
2431 
2432  //============================================ Deal with optimising outside of prepared range - recursion
2433  const FloatingPoint< proshade_double > lhs1 ( *bestLattitude ), rhs1 ( origBestLat - 1.0 );
2434  const FloatingPoint< proshade_double > lhs2 ( *bestLattitude ), rhs2 ( origBestLat + 1.0 );
2435  const FloatingPoint< proshade_double > lhs3 ( *bestLongitude ), rhs3 ( origBestLon - 1.0 );
2436  const FloatingPoint< proshade_double > lhs4 ( *bestLongitude ), rhs4 ( origBestLon + 1.0 );
2437  if ( latM < ( origBestLat - 1.0 ) ) { tmpVal = *bestLattitude; *bestLattitude = origBestLat - 1.0; optimiseAxisBiCubicInterpolation ( bestLattitude, bestLongitude, bestSum, sphereList, sphereMappedRotFun, step ); if ( lhs1.AlmostEquals ( rhs1 ) ) { *bestLattitude = tmpVal; } break; }
2438  if ( latP > ( origBestLat + 1.0 ) ) { tmpVal = *bestLattitude; *bestLattitude = origBestLat + 1.0; optimiseAxisBiCubicInterpolation ( bestLattitude, bestLongitude, bestSum, sphereList, sphereMappedRotFun, step ); if ( lhs2.AlmostEquals ( rhs2 ) ) { *bestLattitude = tmpVal; } break; }
2439  if ( lonM < ( origBestLon - 1.0 ) ) { tmpVal = *bestLongitude; *bestLongitude = origBestLon - 1.0; optimiseAxisBiCubicInterpolation ( bestLattitude, bestLongitude, bestSum, sphereList, sphereMappedRotFun, step ); if ( lhs3.AlmostEquals ( rhs3 ) ) { *bestLongitude = tmpVal; } break; }
2440  if ( lonP > ( origBestLon + 1.0 ) ) { tmpVal = *bestLongitude; *bestLongitude = origBestLon + 1.0; optimiseAxisBiCubicInterpolation ( bestLattitude, bestLongitude, bestSum, sphereList, sphereMappedRotFun, step ); if ( lhs4.AlmostEquals ( rhs4 ) ) { *bestLongitude = tmpVal; } break; }
2441 
2442  //============================================ Prepare vectors of tested positions
2443  latVals.at(0) = latM; latVals.at(1) = *bestLattitude; latVals.at(2) = latP;
2444  lonVals.at(0) = lonM; lonVals.at(1) = *bestLongitude; lonVals.at(2) = lonP;
2445 
2446  //============================================ Find the best change
2447  for ( proshade_unsign laIt = 0; laIt < static_cast<proshade_unsign> ( latVals.size() ); laIt++ )
2448  {
2449  for ( proshade_unsign loIt = 0; loIt < static_cast<proshade_unsign> ( lonVals.size() ); loIt++ )
2450  {
2451  //==================================== For this combination of lat and lon, find sum over spheres
2452  movSum = 1.0;
2453  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sphereList->size() ); iter++ )
2454  {
2455  //================================ Interpolate using correct interpolators
2456  if ( ( latVals.at(laIt) <= origBestLat ) && ( lonVals.at(loIt) <= origBestLon ) ) { movSum += interpolsMinusMinus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2457  if ( ( latVals.at(laIt) <= origBestLat ) && ( lonVals.at(loIt) > origBestLon ) ) { movSum += interpolsMinusPlus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2458  if ( ( latVals.at(laIt) > origBestLat ) && ( lonVals.at(loIt) <= origBestLon ) ) { movSum += interpolsPlusMinus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2459  if ( ( latVals.at(laIt) > origBestLat ) && ( lonVals.at(loIt) > origBestLon ) ) { movSum += interpolsPlusPlus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2460  }
2461 
2462  //==================================== If position has improved, save it
2463  if ( *bestSum < movSum )
2464  {
2465  *bestSum = movSum;
2466  *bestLongitude = lonVals.at(loIt);
2467  *bestLattitude = latVals.at(laIt);
2468  }
2469  }
2470  }
2471 
2472  //============================================ Prepare for next iteration
2473  valChange = std::floor ( 100000.0 * ( *bestSum - prevVal ) ) / 100000.0;
2474  prevVal = std::floor ( 100000.0 * ( *bestSum ) ) / 100000.0;
2475  step = std::max ( ( valChange / step ) * learningRate, 0.01 );
2476  if ( learningRate >= 0.02 ) { learningRate -= 0.01; }
2477 
2478  }
2479 
2480  //================================================ Release interpolators memory
2481  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsMinusMinus.size() ); intIt++ ) { delete interpolsMinusMinus.at(intIt); }
2482  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsMinusPlus.size() ); intIt++ ) { delete interpolsMinusPlus.at(intIt); }
2483  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsPlusMinus.size() ); intIt++ ) { delete interpolsPlusMinus.at(intIt); }
2484  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsPlusPlus.size() ); intIt++ ) { delete interpolsPlusPlus.at(intIt); }
2485 
2486  //================================================ Done
2487  return ;
2488 }

◆ pearsonCorrCoeff()

proshade_double ProSHADE_internal_maths::pearsonCorrCoeff ( proshade_double *  valSet1,
proshade_double *  valSet2,
proshade_unsign  length 
)

Function for computing the Pearson's correlation coefficient.

This function takes two numerical arrays of same length and proceeds to compute the Pearson's correlation coefficient, which it then returns.

Parameters
[in]valSet1This is the set of x-values.
[in]valSet2This is the set of y-values.
[in]lengthThe length of both arrays (both arrays have to have the same length).
[out]XThe Pearson's correlation coefficient value.

Definition at line 246 of file ProSHADE_maths.cpp.

247 {
248  //================================================ Find vector means
249  proshade_double xMean = 0.0;
250  proshade_double yMean = 0.0;
251  proshade_double zeroCount = 0.0;
252  for ( proshade_unsign iter = 0; iter < length; iter++ )
253  {
254  xMean += valSet1[iter];
255  yMean += valSet2[iter];
256  }
257  xMean /= static_cast<proshade_double> ( length ) - zeroCount;
258  yMean /= static_cast<proshade_double> ( length ) - zeroCount;
259 
260  //================================================ Get Pearson's correlation coefficient
261  proshade_double xmmymm = 0.0;
262  proshade_double xmmsq = 0.0;
263  proshade_double ymmsq = 0.0;
264  for ( proshade_unsign iter = 0; iter < length; iter++ )
265  {
266  xmmymm += ( valSet1[iter] - xMean ) * ( valSet2[iter] - yMean );
267  xmmsq += pow( valSet1[iter] - xMean, 2.0 );
268  ymmsq += pow( valSet2[iter] - yMean, 2.0 );
269  }
270 
271  proshade_double ret = xmmymm / ( sqrt(xmmsq) * sqrt(ymmsq) );
272 
273  //================================================ Done
274  if ( std::isnan ( ret ) ) { return ( 0.0 ); }
275  return ( ret );
276 
277 }

◆ prepareBiCubicInterpolatorsMinusMinus()

void ProSHADE_internal_maths::prepareBiCubicInterpolatorsMinusMinus ( proshade_double  bestLattitude,
proshade_double  bestLongitude,
std::vector< proshade_unsign > *  sphereList,
std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *  interpols,
std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *  sphereMappedRotFun 
)

This function prepares the interpolation objects for the bi-cubic interpolation.

This function takes the position around which the interpolation is to be done and proceeds to create the interpolator objects for bi-cubic interpolation in the – direction (i.e. when both interpolated values will be lower than the best lattitude and longitude) using the correct spheres in the correct ranges.

Parameters
[in]bestLattitudeThe lattitude index value around which interpolation is to be prepared.
[in]bestLongitudeThe longitude index value around which interpolation is to be prepared.
[in]sphereListA vector containing the list of spheres which form the set for this symmetry.
[in]interpolsA pointer to a vector of ProSHADE interpolator objects to which the interpolators will be saved into.

Definition at line 2501 of file ProSHADE_maths.cpp.

2502 {
2503  //================================================ Initialise local variables
2504  proshade_signed latHlp, lonHlp;
2505  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2506 
2507  //================================================ Prepare the interpolator objects for interpolation around the position
2508  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2509  {
2510  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2511  proshade_double** interpGrid = new proshade_double*[4];
2512  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2513 
2514  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2515  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2516  {
2517  interpGrid[iter] = new proshade_double[4];
2518  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2519  }
2520 
2521  //============================================ Fill in the value grid on which the interpolation is to be done
2522  for ( proshade_signed latIt = 0; latIt < 4; latIt++ )
2523  {
2524  for ( proshade_signed lonIt = 0; lonIt < 4; lonIt++ )
2525  {
2526  latHlp = static_cast< proshade_signed > ( bestLattitude - 2.0 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2527  lonHlp = static_cast< proshade_signed > ( bestLongitude - 2.0 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2528  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
2529  }
2530  }
2531 
2532  //============================================ Create the interpolators
2533  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude - 1.0, bestLongitude - 1.0 );
2534  interpols->emplace_back ( biCubInterp );
2535 
2536  //============================================ Release memory
2537  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2538  delete[] interpGrid;
2539  }
2540 
2541  //================================================ Done
2542  return ;
2543 }

◆ prepareBiCubicInterpolatorsMinusPlus()

void ProSHADE_internal_maths::prepareBiCubicInterpolatorsMinusPlus ( proshade_double  bestLattitude,
proshade_double  bestLongitude,
std::vector< proshade_unsign > *  sphereList,
std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *  interpols,
std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *  sphereMappedRotFun 
)

This function prepares the interpolation objects for the bi-cubic interpolation.

This function takes the position around which the interpolation is to be done and proceeds to create the interpolator objects for bi-cubic interpolation in the -+ direction (i.e. when interpolated lattitude is lower than best lattitude, but interpolated longitude is higher than best longitude) using the correct spheres in the correct ranges.

Parameters
[in]bestLattitudeThe lattitude index value around which interpolation is to be prepared.
[in]bestLongitudeThe longitude index value around which interpolation is to be prepared.
[in]sphereListA vector containing the list of spheres which form the set for this symmetry.
[in]interpolsA pointer to a vector of ProSHADE interpolator objects to which the interpolators will be saved into.

Definition at line 2556 of file ProSHADE_maths.cpp.

2557 {
2558  //================================================ Initialise local variables
2559  proshade_signed latHlp, lonHlp;
2560  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2561 
2562  //================================================ Prepare the interpolator objects for interpolation around the position
2563  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2564  {
2565  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2566  proshade_double** interpGrid = new proshade_double*[4];
2567  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2568 
2569  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2570  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2571  {
2572  interpGrid[iter] = new proshade_double[4];
2573  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2574  }
2575 
2576  //============================================ Fill in the value grid on which the interpolation is to be done
2577  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2578  {
2579  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2580  {
2581  latHlp = static_cast< proshade_signed > ( bestLattitude - 2 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2582  lonHlp = static_cast< proshade_signed > ( bestLongitude - 1 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2583  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ) , static_cast< proshade_unsign > ( lonHlp ) );
2584  }
2585  }
2586 
2587  //============================================ Create the interpolators
2588  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude - 1.0, bestLongitude );
2589  interpols->emplace_back ( biCubInterp );
2590 
2591  //============================================ Release memory
2592  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2593  delete[] interpGrid;
2594  }
2595 
2596  //================================================ Done
2597  return ;
2598 }

◆ prepareBiCubicInterpolatorsPlusMinus()

void ProSHADE_internal_maths::prepareBiCubicInterpolatorsPlusMinus ( proshade_double  bestLattitude,
proshade_double  bestLongitude,
std::vector< proshade_unsign > *  sphereList,
std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *  interpols,
std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *  sphereMappedRotFun 
)

This function prepares the interpolation objects for the bi-cubic interpolation.

This function takes the position around which the interpolation is to be done and proceeds to create the interpolator objects for bi-cubic interpolation in the +- direction (i.e. when interpolated lattitude is higher than best lattitude, but interpolated longitude is lower than best longitude) using the correct spheres in the correct ranges.

Parameters
[in]bestLattitudeThe lattitude index value around which interpolation is to be prepared.
[in]bestLongitudeThe longitude index value around which interpolation is to be prepared.
[in]sphereListA vector containing the list of spheres which form the set for this symmetry.
[in]interpolsA pointer to a vector of ProSHADE interpolator objects to which the interpolators will be saved into.

Definition at line 2611 of file ProSHADE_maths.cpp.

2612 {
2613  //================================================ Initialise local variables
2614  proshade_signed latHlp, lonHlp;
2615  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2616 
2617  //================================================ Prepare the interpolator objects for interpolation around the position
2618  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2619  {
2620  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2621  proshade_double** interpGrid = new proshade_double*[4];
2622  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2623 
2624  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2625  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2626  {
2627  interpGrid[iter] = new proshade_double[4];
2628  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2629  }
2630 
2631  //============================================ Fill in the value grid on which the interpolation is to be done
2632  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2633  {
2634  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2635  {
2636  latHlp = static_cast< proshade_signed > ( bestLattitude - 1 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2637  lonHlp = static_cast< proshade_signed > ( bestLongitude - 2 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2638  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
2639  }
2640  }
2641 
2642  //============================================ Create the interpolators
2643  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude, bestLongitude - 1.0 );
2644  interpols->emplace_back ( biCubInterp );
2645 
2646  //============================================ Release memory
2647  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2648  delete[] interpGrid;
2649  }
2650 
2651  //================================================ Done
2652  return ;
2653 }

◆ prepareBiCubicInterpolatorsPlusPlus()

void ProSHADE_internal_maths::prepareBiCubicInterpolatorsPlusPlus ( proshade_double  bestLattitude,
proshade_double  bestLongitude,
std::vector< proshade_unsign > *  sphereList,
std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *  interpols,
std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *  sphereMappedRotFun 
)

This function prepares the interpolation objects for the bi-cubic interpolation.

This function takes the position around which the interpolation is to be done and proceeds to create the interpolator objects for bi-cubic interpolation in the ++ direction (i.e. when both interpolated values will be larger than the best lattitude and longitude) using the correct spheres in the correct ranges.

Parameters
[in]bestLattitudeThe lattitude index value around which interpolation is to be prepared.
[in]bestLongitudeThe longitude index value around which interpolation is to be prepared.
[in]sphereListA vector containing the list of spheres which form the set for this symmetry.
[in]interpolsA pointer to a vector of ProSHADE interpolator objects to which the interpolators will be saved into.

Definition at line 2666 of file ProSHADE_maths.cpp.

2667 {
2668  //================================================ Initialise local variables
2669  proshade_signed latHlp, lonHlp;
2670  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2671 
2672  //================================================ Prepare the interpolator objects for interpolation around the position
2673  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2674  {
2675  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2676  proshade_double** interpGrid = new proshade_double*[4];
2677  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2678 
2679  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2680  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2681  {
2682  interpGrid[iter] = new proshade_double[4];
2683  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2684  }
2685 
2686  //============================================ Fill in the value grid on which the interpolation is to be done
2687  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2688  {
2689  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2690  {
2691  latHlp = static_cast< proshade_signed > ( bestLattitude - 1 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2692  lonHlp = static_cast< proshade_signed > ( bestLongitude - 1 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2693  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
2694  }
2695  }
2696 
2697  //============================================ Create the interpolators
2698  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude, bestLongitude );
2699  interpols->emplace_back ( biCubInterp );
2700 
2701  //============================================ Release memory
2702  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2703  delete[] interpGrid;
2704  }
2705 
2706  //================================================ Done
2707  return ;
2708 }

◆ primeFactorsDecomp()

std::vector< proshade_signed > ProSHADE_internal_maths::primeFactorsDecomp ( proshade_signed  number)

Function to find prime factors of an integer.

Parameters
[in]numberA single integer number to be decomposed into its prime factors.

Definition at line 1711 of file ProSHADE_maths.cpp.

1712 {
1713  //================================================ Initialise variables
1714  std::vector < proshade_signed > ret;
1715 
1716  //================================================ Deal with negative numbers
1717  bool changeSign = false;
1718  if ( number < 0 ) { changeSign = true; number = -number; }
1719 
1720  //================================================ Deal with zero and one
1721  if ( number == 0 ) { ProSHADE_internal_misc::addToSignedVector ( &ret, 0 ); return ( ret ); }
1722  if ( number == 1 ) { ProSHADE_internal_misc::addToSignedVector ( &ret, 1 ); return ( ret ); }
1723 
1724  //================================================ Divide by 2 as long as you can
1725  while ( number % 2 == 0 )
1726  {
1728  number = number / 2;
1729  }
1730 
1731  //================================================ Check all odd numbers up to the square root
1732  for ( proshade_double posDiv = 3; posDiv <= sqrt ( static_cast< proshade_double > ( number ) ); posDiv += 2.0 )
1733  {
1734  // If posDiv is a divisor of the number, save the result
1735  while ( number % static_cast< proshade_signed > ( posDiv ) == 0 )
1736  {
1737  ProSHADE_internal_misc::addToSignedVector ( &ret, static_cast< proshade_signed > ( posDiv ) );
1738  number = number / static_cast< proshade_signed > ( posDiv );
1739  }
1740  }
1741 
1742  //================================================ If the number was a large prime number, save it as it is
1743  if ( number > 2 ) { ProSHADE_internal_misc::addToSignedVector ( &ret, number ); }
1744 
1745  //================================================ Finish dealing with negative numbers
1746  if ( changeSign ) { ret.at(0) = -ret.at(0); }
1747 
1748  //================================================ Done
1749  return ( ret );
1750 
1751 }

◆ rotationMatrixSimilarity()

bool ProSHADE_internal_maths::rotationMatrixSimilarity ( std::vector< proshade_double > *  mat1,
std::vector< proshade_double > *  mat2,
proshade_double  tolerance = 0.1 
)

This function compares the distance between two rotation matrices and decides if they are similar using tolerance.

This function computes the distance between two rotation matrices, specifically by computing the trace of (R1 * R2^T). This measure will be 3.0 if the two matrices are identical and will decrease the more the rotation matrices difference diverges from identity. Therefore, from this trace 3.0 is subtracted and the absolute value of the result is compared to the tolerance. If the difference is less than the tolerance, true is returned, while false is returned otherwise.

Parameters
[in]mat1Vector of 9 numbers representing first rotation matrix.
[in]mat1Vector of 9 numbers representing second rotation matrix.
[in]toleranceDouble number representing the maximum allowed error on the distance.
[out]resBoolean decision if the two matrices are similar or not.

Definition at line 2299 of file ProSHADE_maths.cpp.

2300 {
2301  //================================================ Initialise variables
2302  bool ret = false;
2303 
2304  //================================================ Compute trace of mat1 * mat2^T
2305  proshade_double trace = ( mat1->at(0) * mat2->at(0) ) + ( mat1->at(1) * mat2->at(1) ) + ( mat1->at(2) * mat2->at(2) );
2306  trace += ( mat1->at(3) * mat2->at(3) ) + ( mat1->at(4) * mat2->at(4) ) + ( mat1->at(5) * mat2->at(5) );
2307  trace += ( mat1->at(6) * mat2->at(6) ) + ( mat1->at(7) * mat2->at(7) ) + ( mat1->at(8) * mat2->at(8) );
2308 
2309  //================================================ Subtract 3 (so that we would have 0 in case of idenity matrix)
2310  trace -= 3.0;
2311 
2312  //================================================ Compare to tolerance
2313  if ( tolerance > std::abs ( trace ) ) { ret = true; }
2314 
2315  //================================================ Done
2316  return ( ret );
2317 
2318 }

◆ smoothen1D()

std::vector< proshade_double > ProSHADE_internal_maths::smoothen1D ( proshade_double  step,
proshade_signed  windowSize,
proshade_double  sigma,
std::vector< proshade_double >  data 
)

This function takes a 1D vector and computes smoothened version based on the parameters.

This function firstly computes the Gaussian weights for each position in a window size accordingly to the parameters amd then proceeds to compute the weighted sum for each position created by sliding this window along the data. This results in smoothening of the data in accordance with the parameters.

Parameters
[in]stepThe size of the step on scale from 0.0 to 1.0 including boarders.
[in]windowSizeThe size of the averaged over window. It is assumed to be odd.
[in]sigmaThe standard deviation of the Gaussian to be used for smoothening.
[in]dataThe data to be smoothened.
[out]smoothenedA vector of smoothened values for the input data with length hist.size() - (windowSize - 1).

Definition at line 2873 of file ProSHADE_maths.cpp.

2874 {
2875  //================================================ Initialise local variables
2876  proshade_signed windowHalf = ( windowSize - 1 ) / 2;
2877  proshade_signed totSize = static_cast< proshade_signed > ( ( 1.0 / step ) + 1 );
2878  std::vector< proshade_double > smoothened ( static_cast< size_t > ( totSize - ( windowSize - 1 ) ), 0.0 );
2879  std::vector< proshade_double > winWeights ( static_cast< size_t > ( windowSize ), 0.0 );
2880 
2881  //================================================ Prepare window weights
2882  for ( proshade_double winIt = 0.0; winIt < static_cast< proshade_double > ( windowSize ); winIt += 1.0 ) { winWeights.at( static_cast< proshade_unsign > ( winIt ) ) = ProSHADE_internal_maths::computeGaussian ( ( winIt - static_cast< proshade_double > ( windowHalf ) ) * step, sigma ); }
2883 
2884  //================================================ Compute smoothened data
2885  for ( proshade_unsign it = 0; it < static_cast< proshade_unsign > ( smoothened.size() ); it++ )
2886  {
2887  //============================================ Compute window weighted average
2888  for ( proshade_signed winIt = 0; winIt < windowSize; winIt++ )
2889  {
2890  smoothened.at(it) += winWeights.at( static_cast< size_t > ( winIt ) ) * data.at( static_cast< size_t > ( static_cast< proshade_signed > ( it ) + winIt ) );
2891  }
2892  }
2893 
2894  //================================================ Done
2895  return ( smoothened );
2896 
2897 }

◆ transpose3x3MatrixInPlace()

void ProSHADE_internal_maths::transpose3x3MatrixInPlace ( proshade_double *  mat)

Transposes 3x3 matrix in place.

Parameters
[in]matThe matrix to be transposed.

Definition at line 1939 of file ProSHADE_maths.cpp.

1940 {
1941  //================================================ Initialise variables
1942  proshade_double tmp;
1943 
1944  //================================================ Transpose the non-diagonal values
1945  tmp = mat[1];
1946  mat[1] = mat[3];
1947  mat[3] = tmp;
1948 
1949  tmp = mat[2];
1950  mat[2] = mat[6];
1951  mat[6] = tmp;
1952 
1953  tmp = mat[5];
1954  mat[5] = mat[7];
1955  mat[7] = tmp;
1956 
1957  //================================================ Done
1958  return ;
1959 
1960 }

◆ vectorMeanAndSD()

void ProSHADE_internal_maths::vectorMeanAndSD ( std::vector< proshade_double > *  vec,
proshade_double *&  ret 
)

Function to get vector mean and standard deviation.

This function takes a pointer to a vector of proshade_double's and returns the mean and standard deviation of such vector.

Parameters
[in]vecPointer to a vector of proshade_double's for which mean and sd should be obtained.
[in]retPointer to array of 2 proshade_double's, which will be the return values - first mean and second sd.

Definition at line 121 of file ProSHADE_maths.cpp.

122 {
123  //================================================ Get mean
124  ret[0] = std::accumulate ( vec->begin(), vec->end(), 0.0 ) / static_cast<proshade_double> ( vec->size() );
125 
126  //================================================ Get standard deviation
127  proshade_double squaredSum = std::inner_product ( vec->begin(), vec->end(), vec->begin(), 0.0 );
128  ret[1] = std::sqrt ( ( squaredSum / static_cast<proshade_double> ( vec->size() ) ) - std::pow ( ret[0], 2.0 ) );
129 
130  //================================================ Check for NaN's
131  const FloatingPoint< proshade_double > lhs1 ( ret[0] );
132  const FloatingPoint< proshade_double > lhs2 ( ret[1] );
133  if ( !lhs1.AlmostEquals ( lhs1 ) ) { ret[0] = 0.0; }
134  if ( !lhs2.AlmostEquals ( lhs2 ) ) { ret[1] = 0.0; }
135 
136  //================================================ Return
137  return ;
138 
139 }

◆ vectorMedianAndIQR()

void ProSHADE_internal_maths::vectorMedianAndIQR ( std::vector< proshade_double > *  vec,
proshade_double *&  ret 
)

Function to get vector median and inter-quartile range.

This function takes a pointer to a vector of proshade_double's and returns the median and the inter-quartile range of such vector.

Parameters
[in]vecPointer to a vector of proshade_double's for which median and IQR should be obtained.
[in]retPointer to array of 2 proshade_double's, which will be the return values - first median and second IQR.

Definition at line 149 of file ProSHADE_maths.cpp.

150 {
151  //================================================ Sanity check
152  if ( vec->size() < 3 ) { ret[0] = 0.0; ret[1] = 0.0; return; }
153 
154  //================================================ Sort the vector
155  std::sort ( vec->begin(), vec->end() );
156 
157  //================================================ Get median
158  if ( static_cast<proshade_unsign> ( vec->size() ) % 2 == 0)
159  {
160  ret[0] = ( vec->at( ( static_cast<proshade_unsign> ( vec->size() ) / 2 ) - 1 ) +
161  vec->at( static_cast<proshade_unsign> ( vec->size() ) / 2 ) ) / 2.0;
162  }
163  else
164  {
165  ret[0] = vec->at( static_cast<proshade_unsign> ( vec->size() ) / 2 );
166  }
167 
168  //================================================ Get first and third quartile
169  proshade_double Q1, Q3;
170  if ( static_cast<proshade_unsign> ( vec->size() ) % 2 == 0)
171  {
172  Q1 = ( vec->at( ( static_cast<proshade_unsign> ( vec->size() ) / 4 ) - 1 ) +
173  vec->at( static_cast<proshade_unsign> ( vec->size() ) / 4 ) ) / 2.0;
174  Q3 = ( vec->at( ( ( static_cast<proshade_unsign> ( vec->size() ) / 4 ) * 3 ) - 1 ) +
175  vec->at( ( static_cast<proshade_unsign> ( vec->size() ) / 4 ) * 3 ) ) / 2.0;
176  }
177  else
178  {
179  Q1 = vec->at( static_cast<proshade_unsign> ( vec->size() ) / 4 );
180  Q3 = vec->at( ( static_cast<proshade_unsign> ( vec->size() ) / 4 ) * 3 );
181  }
182 
183  //================================================ And now save the IQR
184  ret[1] = Q3 - Q1;
185 
186  //================================================ Return
187  return ;
188 
189 }

◆ vectorOrientationSimilarity()

bool ProSHADE_internal_maths::vectorOrientationSimilarity ( proshade_double  a1,
proshade_double  a2,
proshade_double  a3,
proshade_double  b1,
proshade_double  b2,
proshade_double  b3,
proshade_double  tolerance = 0.1 
)

This function compares two vectors using cosine distance and decides if they are similar using tolerance.

This function computes the distance between two vectors, specifically by computing the cosine distance ( ( dot( A, B ) ) / ( mag(A) x mag(B) ) ). This measure will be 1.0 if the two vectors are identically oriented, 0.0 if they are perpendicular and -1.0 if they have opposite direction. Given that opposite direction must be regarded as same direction with opposite angles for symmetry axes detection purposes, this function uses the absolute value of this measure and checks if the two supplied vectors (supplied element by element) have cosine distance within 1.0 - tolerance, returning true if they do and false otherwise.

Parameters
[in]a1The first element of the first vector.
[in]a2The second element of the first vector.
[in]a3The third element of the first vector.
[in]b1The first element of the second vector.
[in]b2The second element of the second vector.
[in]b3The third element of the second vector.
[in]toleranceThe allowed difference of the distance measure from the 1.0 for the vectors to still be considered similar.
[out]resBoolean decision if the two vectors are similar or not.

Definition at line 2336 of file ProSHADE_maths.cpp.

2337 {
2338  //================================================ Initialise variables
2339  bool ret = false;
2340 
2341  //================================================ Cosine distance
2342  proshade_double cosDist = ( ( a1 * b1 ) + ( a2 * b2 ) + ( a3 * b3 ) ) /
2343  ( sqrt( pow( a1, 2.0 ) + pow( a2, 2.0 ) + pow( a3, 2.0 ) ) *
2344  sqrt( pow( b1, 2.0 ) + pow( b2, 2.0 ) + pow( b3, 2.0 ) ) );
2345 
2346  //================================================ Compare the absolute value of distance to 1.0 - tolerance
2347  if ( std::abs( cosDist ) > ( 1.0 - tolerance ) ) { ret = true; }
2348 
2349  //================================================ Done
2350  return ( ret );
2351 
2352 }

◆ vectorOrientationSimilaritySameDirection()

bool ProSHADE_internal_maths::vectorOrientationSimilaritySameDirection ( proshade_double  a1,
proshade_double  a2,
proshade_double  a3,
proshade_double  b1,
proshade_double  b2,
proshade_double  b3,
proshade_double  tolerance = 0.1 
)

This function compares two vectors using cosine distance and decides if they are similar using tolerance.

This function computes the distance between two vectors, specifically by computing the cosine distance ( ( dot( A, B ) ) / ( mag(A) x mag(B) ) ). This measure will be 1.0 if the two vectors are identically oriented, 0.0 if they are perpendicular and -1.0 if they have opposite direction. Given that opposite direction must be regarded as different vector for peak detection purposes (spheres with different angles are covered separately), this function does not use the absolute value of this measure and checks if the two supplied vectors (supplied element by element) have cosine distance within 1.0 - tolerance, returning true if they do and false otherwise.

Parameters
[in]a1The first element of the first vector.
[in]a2The second element of the first vector.
[in]a3The third element of the first vector.
[in]b1The first element of the second vector.
[in]b2The second element of the second vector.
[in]b3The third element of the second vector.
[in]toleranceThe allowed difference of the distance measure from the 1.0 for the vectors to still be considered similar.
[out]resBoolean decision if the two vectors are similar or not.

Definition at line 2370 of file ProSHADE_maths.cpp.

2371 {
2372  //================================================ Initialise variables
2373  bool ret = false;
2374 
2375  //================================================ Cosine distance
2376  proshade_double cosDist = ( ( a1 * b1 ) + ( a2 * b2 ) + ( a3 * b3 ) ) /
2377  ( sqrt( pow( a1, 2.0 ) + pow( a2, 2.0 ) + pow( a3, 2.0 ) ) *
2378  sqrt( pow( b1, 2.0 ) + pow( b2, 2.0 ) + pow( b3, 2.0 ) ) );
2379 
2380  //================================================ Compare the absolute value of distance to 1.0 - tolerance
2381  if ( cosDist > ( 1.0 - tolerance ) ) { ret = true; }
2382 
2383  //================================================ Done
2384  return ( ret );
2385 
2386 }
ProSHADE_internal_maths::prepareBiCubicInterpolatorsMinusPlus
void prepareBiCubicInterpolatorsMinusPlus(proshade_double bestLattitude, proshade_double bestLongitude, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *interpols, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun)
This function prepares the interpolation objects for the bi-cubic interpolation.
Definition: ProSHADE_maths.cpp:2556
ProSHADE_internal_maths::computeCrossProduct
proshade_double * computeCrossProduct(proshade_double *x1, proshade_double *y1, proshade_double *z1, proshade_double *x2, proshade_double *y2, proshade_double *z2)
Simple 3D vector cross product computation.
Definition: ProSHADE_maths.cpp:1809
ProSHADE_exception
This class is the representation of ProSHADE exception.
Definition: ProSHADE_exceptions.hpp:37
ProSHADE_internal_maths::prepareBiCubicInterpolatorsPlusMinus
void prepareBiCubicInterpolatorsPlusMinus(proshade_double bestLattitude, proshade_double bestLongitude, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *interpols, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun)
This function prepares the interpolation objects for the bi-cubic interpolation.
Definition: ProSHADE_maths.cpp:2611
ProSHADE_internal_maths::evaluateGLSeries
proshade_double evaluateGLSeries(proshade_double *series, proshade_double target, proshade_unsign terms)
This function evaluates the Taylor expansion.
Definition: ProSHADE_maths.cpp:449
ProSHADE_internal_maths::getGLFirstEvenRoot
void getGLFirstEvenRoot(proshade_double polyAtZero, proshade_unsign order, proshade_double *abscAtZero, proshade_double *weighAtZero, proshade_unsign taylorSeriesCap)
This function finds the first root for Legendre polynomials of odd order.
Definition: ProSHADE_maths.cpp:386
ProSHADE_internal_maths::optimiseAxisBiCubicInterpolation
void optimiseAxisBiCubicInterpolation(proshade_double *bestLattitude, proshade_double *bestLongitude, proshade_double *bestSum, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun, proshade_double step=0.05)
This function provides axis optimisation given starting lattitude and longitude indices.
Definition: ProSHADE_maths.cpp:2400
ProSHADE_internal_maths::vectorOrientationSimilarity
bool vectorOrientationSimilarity(proshade_double a1, proshade_double a2, proshade_double a3, proshade_double b1, proshade_double b2, proshade_double b3, proshade_double tolerance=0.1)
This function compares two vectors using cosine distance and decides if they are similar using tolera...
Definition: ProSHADE_maths.cpp:2336
ProSHADE_internal_maths::prepareBiCubicInterpolatorsMinusMinus
void prepareBiCubicInterpolatorsMinusMinus(proshade_double bestLattitude, proshade_double bestLongitude, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *interpols, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun)
This function prepares the interpolation objects for the bi-cubic interpolation.
Definition: ProSHADE_maths.cpp:2501
ProSHADE_internal_misc::addToDoubleVector
void addToDoubleVector(std::vector< proshade_double > *vecToAddTo, proshade_double elementToAdd)
Adds the element to the vector.
Definition: ProSHADE_misc.cpp:77
ProSHADE_internal_maths::computeGaussian
proshade_double computeGaussian(proshade_double val, proshade_double sigma)
This function computes a Gaussian (normal) distribution value given distance from mean and sigma.
Definition: ProSHADE_maths.cpp:2847
ProSHADE_internal_maths::computeDotProduct
proshade_double computeDotProduct(proshade_double *x1, proshade_double *y1, proshade_double *z1, proshade_double *x2, proshade_double *y2, proshade_double *z2)
Simple 3D vector dot product computation.
Definition: ProSHADE_maths.cpp:1777
ProSHADE_internal_misc::addToSignedVector
void addToSignedVector(std::vector< proshade_signed > *vecToAddTo, proshade_signed elementToAdd)
Adds the element to the vector.
Definition: ProSHADE_misc.cpp:121
ProSHADE_internal_maths::BicubicInterpolator
Definition: ProSHADE_maths.hpp:105
ProSHADE_internal_maths::getGLPolyAtZero
void getGLPolyAtZero(proshade_unsign order, proshade_double *polyValue, proshade_double *deriValue)
This function obtains the Legendre polynomial values and its derivative at zero for any positive inte...
Definition: ProSHADE_maths.cpp:349
ProSHADE_internal_maths::advanceGLPolyValue
proshade_double advanceGLPolyValue(proshade_double from, proshade_double to, proshade_double valAtFrom, proshade_unsign noSteps, proshade_unsign taylorSeriesCap)
This function finds the next value of the polynomial.
Definition: ProSHADE_maths.cpp:479
ProSHADE_internal_misc::checkMemoryAllocation
void checkMemoryAllocation(chVar checkVar, std::string fileP, unsigned int lineP, std::string funcP, std::string infoP="This error may occurs when ProSHADE requests memory to be\n : allocated to it and this operation fails. This could\n : happen when not enough memory is available, either due to\n : other processes using a lot of memory, or when the machine\n : does not have sufficient memory available. Re-run to see\n : if this problem persists.")
Checks if memory was allocated properly.
Definition: ProSHADE_misc.hpp:67
ProSHADE_internal_misc::addToUnsignVector
void addToUnsignVector(std::vector< proshade_unsign > *vecToAddTo, proshade_unsign elementToAdd)
Adds the element to the vector.
Definition: ProSHADE_misc.cpp:99
ProSHADE_internal_maths::completeLegendreSeries
void completeLegendreSeries(proshade_unsign order, proshade_double *abscissa, proshade_double *weights, proshade_unsign taylorSeriesCap)
This function completes the Legendre polynomial series assuming you have obtained the first values.
Definition: ProSHADE_maths.cpp:523
ProSHADE_internal_maths::prepareBiCubicInterpolatorsPlusPlus
void prepareBiCubicInterpolatorsPlusPlus(proshade_double bestLattitude, proshade_double bestLongitude, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *interpols, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun)
This function prepares the interpolation objects for the bi-cubic interpolation.
Definition: ProSHADE_maths.cpp:2666
ProSHADE_internal_maths::getResolutionOfReflection
proshade_single getResolutionOfReflection(proshade_single h, proshade_single k, proshade_single l, proshade_single xDim, proshade_single yDim, proshade_single zDim)
This function computes the resolution of a particular reflection.
Definition: ProSHADE_maths.cpp:2909
ProSHADE_internal_maths::compute3x3MatrixInverse
proshade_double * compute3x3MatrixInverse(proshade_double *mat)
Function for computing a 3x3 matrix inverse.
Definition: ProSHADE_maths.cpp:1906
ProSHADE_internal_maths::compute3x3MatrixMultiplication
proshade_double * compute3x3MatrixMultiplication(proshade_double *mat1, proshade_double *mat2)
Function for computing a 3x3 matrix multiplication.
Definition: ProSHADE_maths.cpp:1831