ProSHADE  0.7.6.2 (DEC 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 realMatrixSVDUandVOnly (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, proshade_signed verbose=1)
 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, proshade_signed verbose=1)
 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 * 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 * build3x3MatrixFromDiag (proshade_double *diag)
 Function for building a 3x3 matrix from diagonal (and assuming zero padding). More...
 
proshade_double * build3x3MatrixFromXYZRotations (proshade_double xRot, proshade_double yRot, proshade_double zRot)
 Function for building a 3x3 rotation matrix from the x, y and z rotations in degrees. 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...
 
proshade_double * compute3x3MoorePenrosePseudoInverseOfIMinusMat (std::vector< proshade_double > *rMat, proshade_signed verbose)
 This function computes the Moore-Penrose pseudo-inverse of equation I - input matrix. 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, proshade_double *&fscByBin)
 This function computes the FSC. More...
 
void computeFSCWeightByBin (proshade_double *&weights1, proshade_double *&weights2, proshade_signed *binIndexing, proshade_double *fscByBin, proshade_signed noBins, proshade_signed xDim, proshade_signed yDim, proshade_signed zDim)
 This function computes the weights for each reflection using its bin belonging. More...
 
proshade_double computeTheFValue (proshade_complex *fCoeffs, proshade_double *weights, proshade_signed xDim, proshade_signed yDim, proshade_signed zDim)
 This function computes the real part of the sum of all coefficients except where the weight is less than -2. More...
 
void computeTrFunDerivatives (proshade_complex *fCoeffs, proshade_double *weights1, proshade_double *weights2, proshade_signed xDim, proshade_signed yDim, proshade_signed zDim, proshade_double *&firstDers, proshade_double *&secondDers)
 This function computes the first and second derivatives of the translation function at coefficient [0,0,0]. More...
 
proshade_double * computeTrFunStep (proshade_double *firstDers, proshade_double *secondDers)
 This function computes the step sizes for translation function optimisation from the first and second derivatives. More...
 
std::vector< proshade_signed > findPeaks1D (std::vector< proshade_double > data)
 This function simply finds all the peaks in a 1D data array. More...
 
proshade_double findTopGroupSmooth (std::vector< proshade_double * > *CSym, size_t peakPos, proshade_double step, proshade_double sigma, proshade_signed windowSize, proshade_double maxLim=0.9)
 This function finds a subgroup of axes with distinctly higher correlation value. More...
 
proshade_double findTopGroupSmooth (std::vector< std::vector< proshade_double > > *CSym, size_t peakPos, proshade_double step, proshade_double sigma, proshade_signed windowSize, proshade_double maxLim=0.9)
 This function finds a subgroup of axes with distinctly higher correlation value. More...
 
void combineFourierForTranslation (fftw_complex *tmpOut1, fftw_complex *tmpOut2, fftw_complex *&resOut, proshade_unsign xD, proshade_unsign yD, proshade_unsign zD)
 This function combines Fourier coefficients of two structures in a way, so that inverse Fourier of the combination will be the translation function. More...
 
void findHighestValueInMap (fftw_complex *resIn, proshade_unsign xD, proshade_unsign yD, proshade_unsign zD, proshade_double *trsX, proshade_double *trsY, proshade_double *trsZ, proshade_double *mapPeak)
 This function simply finds the highest value in fftw_complex map and returns its position and value. 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 3199 of file ProSHADE_maths.cpp.

3200 {
3201  //================================================ Allocate output bin indexing memory and set to -100
3202  binIndexing = new proshade_signed [xInds * yInds * zInds];
3203  ProSHADE_internal_misc::checkMemoryAllocation ( binIndexing, __FILE__, __LINE__, __func__ );
3204  for ( size_t iter = 0; iter < static_cast< size_t > ( xInds * yInds * zInds ); iter++ ) { binIndexing[iter] = -100; }
3205  proshade_single xIndsF = static_cast< proshade_single > ( xInds ), yIndsF = static_cast< proshade_single > ( yInds ), zIndsF = static_cast< proshade_single > ( zInds );
3206 
3207  //================================================ Allocate local memory
3208  proshade_single *mins = new proshade_single[3];
3209  proshade_single *maxs = new proshade_single[3];
3210  proshade_single *resMins = new proshade_single[3];
3211  proshade_signed *resMinLoc = new proshade_signed[3];
3212  proshade_single *steps = new proshade_single[3];
3213 
3214  //================================================ Check local memory
3215  ProSHADE_internal_misc::checkMemoryAllocation ( mins, __FILE__, __LINE__, __func__ );
3216  ProSHADE_internal_misc::checkMemoryAllocation ( maxs, __FILE__, __LINE__, __func__ );
3217  ProSHADE_internal_misc::checkMemoryAllocation ( resMins, __FILE__, __LINE__, __func__ );
3218  ProSHADE_internal_misc::checkMemoryAllocation ( resMinLoc, __FILE__, __LINE__, __func__ );
3219  ProSHADE_internal_misc::checkMemoryAllocation ( steps, __FILE__, __LINE__, __func__ );
3220 
3221  //================================================ Initialise local variables
3222  proshade_single resol = 0.0f;
3223  proshade_signed reciX, reciY, reciZ, arrPos = 0, minLoc = -1;
3224  *noBin = 0;
3225 
3226  //================================================ Determine reciprocal space indexing
3227  mins[0] = std::floor ( xIndsF / -2.0f );
3228  mins[1] = std::floor ( yIndsF / -2.0f );
3229  mins[2] = std::floor ( zIndsF / -2.0f );
3230 
3231  maxs[0] = -mins[0];
3232  maxs[1] = -mins[1];
3233  maxs[2] = -mins[2];
3234 
3235  if ( xInds % 2 == 0 ) { mins[0] += 1.0f; }
3236  if ( yInds % 2 == 0 ) { mins[1] += 1.0f; }
3237  if ( zInds % 2 == 0 ) { mins[2] += 1.0f; }
3238 
3239  //================================================ Get minimum resolution based on dims for each dimension
3240  resMins[0] = ProSHADE_internal_maths::getResolutionOfReflection ( maxs[0], 0.0f, 0.0f, xIndsF, yIndsF, zIndsF );
3241  resMins[1] = ProSHADE_internal_maths::getResolutionOfReflection ( 0.0f, maxs[1], 0.0f, xIndsF, yIndsF, zIndsF );
3242  resMins[2] = ProSHADE_internal_maths::getResolutionOfReflection ( 0.0f, 0.0f, maxs[2], xIndsF, yIndsF, zIndsF );
3243 
3244  //================================================ Decide which dimension to work with (the one with the lowest resolution)
3245  resMinLoc[0] = 0; resMinLoc[1] = 0; resMinLoc[2] = 0;
3246  const FloatingPoint< proshade_single > lhs1 ( resMins[0] ), lhs2 ( resMins[1] ), lhs3 ( resMins[2] ), rhs1 ( std::min( resMins[0], std::min( resMins[1], resMins[2] ) ) );
3247  if ( lhs1.AlmostEquals ( rhs1 ) ) { resMinLoc[0] = 1; minLoc = 0; }
3248  if ( lhs2.AlmostEquals ( rhs1 ) ) { resMinLoc[1] = 1; minLoc = 1; }
3249  if ( lhs3.AlmostEquals ( rhs1 ) ) { resMinLoc[2] = 1; minLoc = 2; }
3250 
3251  //================================================ Find the bins and corresponding cut-offs
3252  std::vector< proshade_single > resArray ( static_cast< size_t > ( maxs[minLoc] - 1 ), 0.0f );
3253  std::vector< proshade_single > binArray ( static_cast< size_t > ( maxs[minLoc] - 1 ), 0.0f );
3254  for ( proshade_signed dimIt = 0; dimIt < static_cast< proshade_signed > ( maxs[minLoc] - 1 ); dimIt++ )
3255  {
3256  //============================================ Prepare steps
3257  steps[0] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[0] );
3258  steps[1] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[1] );
3259  steps[2] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[2] );
3260 
3261  //============================================ Find resolution
3262  resol = ProSHADE_internal_maths::getResolutionOfReflection ( steps[0], steps[1], steps[2], xIndsF, yIndsF, zIndsF );
3263 
3264  //============================================ Assign to arrays
3265  resArray.at( static_cast< size_t > ( dimIt ) ) = resol;
3266  binArray.at( static_cast< size_t > ( dimIt ) ) = static_cast< proshade_single > ( dimIt ) + 2.5f;
3267  *noBin = dimIt + 1;
3268  }
3269 
3270  //================================================ Assign reflections to bins
3271  for ( proshade_signed xIt = 0; xIt < static_cast< proshade_signed > ( xInds ); xIt++ )
3272  {
3273  for ( proshade_signed yIt = 0; yIt < static_cast< proshade_signed > ( yInds ); yIt++ )
3274  {
3275  for ( proshade_signed zIt = 0; zIt < static_cast< proshade_signed > ( zInds / 2 ) + 1; zIt++ )
3276  {
3277  //==================================== Deal with reciprocal indices ordering
3278  reciX = xIt; if ( reciX > static_cast< proshade_signed > ( maxs[0] ) ) { reciX -= static_cast< proshade_signed > ( xInds ); }
3279  reciY = yIt; if ( reciY > static_cast< proshade_signed > ( maxs[1] ) ) { reciY -= static_cast< proshade_signed > ( yInds ); }
3280  reciZ = zIt; if ( reciZ > static_cast< proshade_signed > ( maxs[2] ) ) { reciZ -= static_cast< proshade_signed > ( zInds ); }
3281 
3282  //==================================== For each bin, check if this reflection belongs to it
3283  for ( proshade_signed binIt = 0; binIt < (*noBin); binIt++ )
3284  {
3285  //================================ Check by comparing distances
3286  if ( std::sqrt ( std::pow ( static_cast< proshade_single > ( reciX ), 2.0f ) +
3287  std::pow ( static_cast< proshade_single > ( reciY ), 2.0f ) +
3288  std::pow ( static_cast< proshade_single > ( reciZ ), 2.0f ) ) <= binArray.at( static_cast< size_t > ( binIt ) ) )
3289  {
3290  //============================ This is the bin for this reflection. Assign it.
3291  arrPos = zIt + static_cast< proshade_signed > ( zInds ) * ( yIt + static_cast< proshade_signed > ( yInds ) * xIt );
3292  binIndexing[ static_cast< size_t > ( arrPos ) ] = binIt;
3293 
3294  //============================ If one of the uneven ends, do not use Friedel's Law
3295  if ( reciX == static_cast< proshade_signed > ( mins[0] ) || -reciX == static_cast< proshade_signed > ( mins[0] ) ) { break; }
3296  if ( reciY == static_cast< proshade_signed > ( mins[1] ) || -reciY == static_cast< proshade_signed > ( mins[1] ) ) { break; }
3297  if ( reciZ == static_cast< proshade_signed > ( mins[2] ) || -reciZ == static_cast< proshade_signed > ( mins[2] ) ) { break; }
3298 
3299  //============================ Use Friedel's Law to find the second index (this is why we can use zDim / 2)
3300  reciX *= -1; if ( reciX < 0 ) { reciX += static_cast< proshade_signed > ( xInds ); }
3301  reciY *= -1; if ( reciY < 0 ) { reciY += static_cast< proshade_signed > ( yInds ); }
3302  reciZ *= -1; if ( reciZ < 0 ) { reciZ += static_cast< proshade_signed > ( zInds ); }
3303 
3304  //============================ Apply Friedel's Law
3305  arrPos = reciZ + static_cast< proshade_signed > ( zInds ) * ( reciY + static_cast< proshade_signed > ( yInds ) * reciX );
3306  binIndexing[ static_cast< size_t > ( arrPos ) ] = binIt;
3307 
3308  //============================ Done, exit bins loop
3309  break;
3310  }
3311  }
3312  }
3313  }
3314  }
3315 
3316  //================================================ Release memory
3317  delete[] mins;
3318  delete[] maxs;
3319  delete[] resMins;
3320  delete[] resMinLoc;
3321  delete[] steps;
3322 
3323  //================================================ Done
3324  return ;
3325 
3326 }

◆ build3x3MatrixFromDiag()

proshade_double * ProSHADE_internal_maths::build3x3MatrixFromDiag ( proshade_double *  diag)

Function for building a 3x3 matrix from diagonal (and assuming zero padding).

Parameters
[in]diagArray of 3 values that should form the diagonal.
[out]retThe matrix having zeroes everywhere except for the diagonal, where the supplied values will be.

Definition at line 2004 of file ProSHADE_maths.cpp.

2005 {
2006  //================================================ Allocate memory
2007  proshade_double* ret = new proshade_double[9];
2008  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
2009 
2010  //================================================ Build
2011  ret[0] = diag[0];
2012  ret[1] = 0.0;
2013  ret[2] = 0.0;
2014  ret[3] = 0.0;
2015  ret[4] = diag[1];
2016  ret[5] = 0.0;
2017  ret[6] = 0.0;
2018  ret[7] = 0.0;
2019  ret[8] = diag[2];
2020 
2021  //================================================ Done
2022  return ( ret );
2023 
2024 }

◆ build3x3MatrixFromXYZRotations()

proshade_double * ProSHADE_internal_maths::build3x3MatrixFromXYZRotations ( proshade_double  xRot,
proshade_double  yRot,
proshade_double  zRot 
)

Function for building a 3x3 rotation matrix from the x, y and z rotations in degrees.

Parameters
[in]xRotThe counter-clockwise rotation about the x axis.
[in]yRotThe counter-clockwise rotation about the y axis.
[in]zRotThe counter-clockwise rotation about the z axis.
[out]retThe rotation matrix in a vector form.

Definition at line 2033 of file ProSHADE_maths.cpp.

2034 {
2035  //================================================ Allocate memory
2036  proshade_double* ret = new proshade_double[9];
2037  proshade_double* XRM = new proshade_double[9];
2038  proshade_double* YRM = new proshade_double[9];
2039  proshade_double* ZRM = new proshade_double[9];
2040  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
2041  ProSHADE_internal_misc::checkMemoryAllocation ( XRM, __FILE__, __LINE__, __func__ );
2042  ProSHADE_internal_misc::checkMemoryAllocation ( YRM, __FILE__, __LINE__, __func__ );
2043  ProSHADE_internal_misc::checkMemoryAllocation ( ZRM, __FILE__, __LINE__, __func__ );
2044 
2045  //================================================ Convert to radians
2046  proshade_double xRad = xRot * ( M_PI / 180.0 );
2047  proshade_double yRad = yRot * ( M_PI / 180.0 );
2048  proshade_double zRad = zRot * ( M_PI / 180.0 );
2049 
2050  //================================================ Build the X, Y and Z rotation matrices
2051  XRM[0] = 1.0; XRM[1] = 0.0; XRM[2] = 0.0;
2052  XRM[3] = 0.0; XRM[4] = std::cos ( xRad ); XRM[5] = -std::sin ( xRad );
2053  XRM[6] = 0.0; XRM[7] = std::sin ( xRad ); XRM[8] = std::cos ( xRad );
2054 
2055  YRM[0] = std::cos ( yRad ); YRM[1] = 0.0; YRM[2] = std::sin ( yRad );
2056  YRM[3] = 0.0; YRM[4] = 1.0; YRM[5] = 0.0;
2057  YRM[6] = -std::sin ( yRad ); YRM[7] = 0.0; YRM[8] = std::cos ( yRad );
2058 
2059  ZRM[0] = std::cos ( zRad ); ZRM[1] = -std::sin ( zRad ); ZRM[2] = 0.0;
2060  ZRM[3] = std::sin ( zRad ); ZRM[4] = std::cos ( zRad ); ZRM[5] = 0.0;
2061  ZRM[6] = 0.0; ZRM[7] = 0.0; ZRM[8] = 1.0;
2062 
2063  //================================================ Multiply in XYZ order
2064  proshade_double* tmpMat = compute3x3MatrixMultiplication ( XRM, YRM );
2065  ret = compute3x3MatrixMultiplication ( tmpMat, ZRM );
2066 
2067  //================================================ Release memory
2068  delete[] tmpMat;
2069  delete[] XRM;
2070  delete[] YRM;
2071  delete[] ZRM;
2072 
2073  //================================================ Done
2074  return ( ret );
2075 
2076 }

◆ combineFourierForTranslation()

void ProSHADE_internal_maths::combineFourierForTranslation ( fftw_complex *  tmpOut1,
fftw_complex *  tmpOut2,
fftw_complex *&  resOut,
proshade_unsign  xD,
proshade_unsign  yD,
proshade_unsign  zD 
)

This function combines Fourier coefficients of two structures in a way, so that inverse Fourier of the combination will be the translation function.

Parameters
[in]tmpOut1Array holding the static structure Fourier outputs.
[in]tmpOut2Array holding the moving structure Fourier outputs.
[in]resOutArray to hold the combined Fourier coefficients of both structures.
[in]xDThe dimension of the X axis of the structures (assumes both structures have the same sizes and sampling).
[in]yDThe dimension of the Y axis of the structures (assumes both structures have the same sizes and sampling).
[in]zDThe dimension of the Z axis of the structures (assumes both structures have the same sizes and sampling).

Definition at line 3865 of file ProSHADE_maths.cpp.

3866 {
3867  //================================================ Initialise local variables
3868  double normFactor = static_cast<double> ( xD * yD * zD );
3869  proshade_signed arrPos;
3870 
3871  //================================================ Combine the coefficients
3872  for ( proshade_signed xIt = 0; xIt < static_cast< proshade_signed > ( xD ); xIt++ )
3873  {
3874  for ( proshade_signed yIt = 0; yIt < static_cast< proshade_signed > ( yD ); yIt++ )
3875  {
3876  for ( proshade_signed zIt = 0; zIt < static_cast< proshade_signed > ( zD ); zIt++ )
3877  {
3878  //==================================== Find indices
3879  arrPos = zIt + static_cast< proshade_signed > ( zD ) * ( yIt + static_cast< proshade_signed > ( yD ) * xIt );
3880 
3881  //==================================== Combine
3883  &tmpOut1[arrPos][1],
3884  &tmpOut2[arrPos][0],
3885  &tmpOut2[arrPos][1],
3886  &resOut[arrPos][0],
3887  &resOut[arrPos][1] );
3888 
3889  //==================================== Save
3890  resOut[arrPos][0] /= normFactor;
3891  resOut[arrPos][1] /= normFactor;
3892  }
3893  }
3894  }
3895 
3896  //================================================ Done
3897  return ;
3898 
3899 }

◆ 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 }

◆ 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 1943 of file ProSHADE_maths.cpp.

1944 {
1945  //================================================ Allocate memory
1946  proshade_double* inverse = new proshade_double[9];
1947  ProSHADE_internal_misc::checkMemoryAllocation ( inverse, __FILE__, __LINE__, __func__ );
1948 
1949  //================================================ Compute determinant
1950  proshade_double matDet = ( mat[0] * mat[4] * mat[8] ) +
1951  ( mat[1] * mat[5] * mat[6] ) +
1952  ( mat[2] * mat[3] * mat[7] ) -
1953  ( mat[0] * mat[5] * mat[7] ) -
1954  ( mat[1] * mat[3] * mat[8] ) -
1955  ( mat[2] * mat[4] * mat[6] );
1956 
1957  //================================================ Compute inverse matrix
1958  inverse[0] = ( mat[4] * mat[8] - mat[5] * mat[7] ) / matDet;
1959  inverse[1] = ( mat[2] * mat[7] - mat[1] * mat[8] ) / matDet;
1960  inverse[2] = ( mat[1] * mat[5] - mat[2] * mat[4] ) / matDet;
1961  inverse[3] = ( mat[5] * mat[6] - mat[3] * mat[8] ) / matDet;
1962  inverse[4] = ( mat[0] * mat[8] - mat[2] * mat[6] ) / matDet;
1963  inverse[5] = ( mat[2] * mat[3] - mat[0] * mat[5] ) / matDet;
1964  inverse[6] = ( mat[3] * mat[7] - mat[4] * mat[6] ) / matDet;
1965  inverse[7] = ( mat[1] * mat[6] - mat[0] * mat[7] ) / matDet;
1966  inverse[8] = ( mat[0] * mat[4] - mat[1] * mat[3] ) / matDet;
1967 
1968  //================================================ Done
1969  return ( inverse );
1970 }

◆ 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 1868 of file ProSHADE_maths.cpp.

1869 {
1870  //================================================ Allocate memory
1871  proshade_double* ret = new proshade_double[9];
1872  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
1873 
1874  //================================================ Multiply
1875  ret[0] = ( mat1[0] * mat2[0] ) + ( mat1[1] * mat2[3] ) + ( mat1[2] * mat2[6] );
1876  ret[1] = ( mat1[0] * mat2[1] ) + ( mat1[1] * mat2[4] ) + ( mat1[2] * mat2[7] );
1877  ret[2] = ( mat1[0] * mat2[2] ) + ( mat1[1] * mat2[5] ) + ( mat1[2] * mat2[8] );
1878  ret[3] = ( mat1[3] * mat2[0] ) + ( mat1[4] * mat2[3] ) + ( mat1[5] * mat2[6] );
1879  ret[4] = ( mat1[3] * mat2[1] ) + ( mat1[4] * mat2[4] ) + ( mat1[5] * mat2[7] );
1880  ret[5] = ( mat1[3] * mat2[2] ) + ( mat1[4] * mat2[5] ) + ( mat1[5] * mat2[8] );
1881  ret[6] = ( mat1[6] * mat2[0] ) + ( mat1[7] * mat2[3] ) + ( mat1[8] * mat2[6] );
1882  ret[7] = ( mat1[6] * mat2[1] ) + ( mat1[7] * mat2[4] ) + ( mat1[8] * mat2[7] );
1883  ret[8] = ( mat1[6] * mat2[2] ) + ( mat1[7] * mat2[5] ) + ( mat1[8] * mat2[8] );
1884 
1885  //================================================ Done
1886  return ( ret );
1887 
1888 }

◆ 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 1898 of file ProSHADE_maths.cpp.

1899 {
1900  //================================================ Allocate memory
1901  proshade_double* ret = new proshade_double[3];
1902  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
1903 
1904  //================================================ Compute the multiplication
1905  ret[0] = ( x * mat[0] ) + ( y * mat[1] ) + ( z * mat[2] );
1906  ret[1] = ( x * mat[3] ) + ( y * mat[4] ) + ( z * mat[5] );
1907  ret[2] = ( x * mat[6] ) + ( y * mat[7] ) + ( z * mat[8] );
1908 
1909  //================================================ Done
1910  return ( ret );
1911 
1912 }

◆ 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 1922 of file ProSHADE_maths.cpp.

1923 {
1924  //================================================ Allocate memory
1925  proshade_single* ret = new proshade_single[3];
1926  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
1927 
1928  //================================================ Compute the multiplication
1929  ret[0] = ( x * mat[0] ) + ( y * mat[1] ) + ( z * mat[2] );
1930  ret[1] = ( x * mat[3] ) + ( y * mat[4] ) + ( z * mat[5] );
1931  ret[2] = ( x * mat[6] ) + ( y * mat[7] ) + ( z * mat[8] );
1932 
1933  //================================================ Done
1934  return ( ret );
1935 
1936 }

◆ compute3x3MoorePenrosePseudoInverseOfIMinusMat()

proshade_double * ProSHADE_internal_maths::compute3x3MoorePenrosePseudoInverseOfIMinusMat ( std::vector< proshade_double > *  rMat,
proshade_signed  verbose 
)

This function computes the Moore-Penrose pseudo-inverse of equation I - input matrix.

This function starts by setting and allocating all variables required for singular value decomposition using LAPACK. It also computes the I - input matrix result and saves it in column-major format (for Fortran). Next, the singular values are computed and checked for positivity, making use of the fact that at least one singular value has to be zero. Finally, the inverse is computed and the resulting matrix is returned.

Warning
This function assumes that the input matrix is a rotation matrix. If this assumption does not hold, this function will fail to produce correct results!
Parameters
[in]rMatThe rotation matrix to be inverted.
[in]verboseHow loud the function should be.
[out]pseudoInverseMatThe Moore-Penrose pseudo-inverse of the identity matrix - input matrix.

Definition at line 2162 of file ProSHADE_maths.cpp.

2163 {
2164  //================================================ Initialise local variables and allocate the memory
2165  int dim = 3; // Number of dimensions
2166  char job = 'A'; // Save computation of parts of U and V matrices, they are not needed here
2167  double *singularValues = new double[dim]; // The array of singular values
2168  double *rotMatU = new double [dim*dim]; // The U matrix space
2169  double *rotMatV = new double [dim*dim]; // The V^T matrix space
2170  double *work = new double [static_cast< proshade_unsign >( ( 3 * dim ) + pow( dim, 2 ) * dim)]; // Workspace, minimum required is 4*dim^2 + 7*dim, using more for performance
2171  int workDim = static_cast< int > ( 2 * ( ( 4 * dim * dim ) + ( 7 * dim ) ) ); // Formalism stating just that
2172  double* rwork = new double[static_cast<proshade_unsign>((5 * dim) + 5 * pow(dim,2))]; // Required by LAPACK
2173  int* iwork = new int[(8 * dim)]; // Required by LAPACK
2174  int returnValue = 0; // This will tell if operation succeeded
2175  double *matrixToDecompose = new double[dim*dim];
2176 
2177  //================================================ Check the memory allocation
2178  ProSHADE_internal_misc::checkMemoryAllocation ( singularValues, __FILE__, __LINE__, __func__ );
2179  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatU, __FILE__, __LINE__, __func__ );
2180  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatV, __FILE__, __LINE__, __func__ );
2181  ProSHADE_internal_misc::checkMemoryAllocation ( work, __FILE__, __LINE__, __func__ );
2182  ProSHADE_internal_misc::checkMemoryAllocation ( rwork, __FILE__, __LINE__, __func__ );
2183  ProSHADE_internal_misc::checkMemoryAllocation ( iwork, __FILE__, __LINE__, __func__ );
2184  ProSHADE_internal_misc::checkMemoryAllocation ( matrixToDecompose, __FILE__, __LINE__, __func__ );
2185 
2186  //================================================ Load input data into array in column-major order
2187  for ( int rowIt = 0; rowIt < dim; rowIt++ )
2188  {
2189  for ( int colIt = 0; colIt < dim; colIt++ )
2190  {
2191  if ( rowIt == colIt ) { matrixToDecompose[(colIt*dim)+rowIt] = 1.0 - rMat->at( static_cast< size_t > ( ( rowIt * dim ) + colIt ) ); }
2192  else { matrixToDecompose[(colIt*dim)+rowIt] = 0.0 - rMat->at( static_cast< size_t > ( ( rowIt * dim ) + colIt ) ); }
2193  }
2194  }
2195 
2196  //================================================ Run LAPACK ZGESDD
2197  dgesdd_ ( &job, &dim, &dim, matrixToDecompose, &dim, singularValues, rotMatU, &dim, rotMatV, &dim,
2198  work, &workDim, rwork, iwork, &returnValue );
2199 
2200  //================================================ Check the convergence
2201  if ( returnValue != 0 )
2202  {
2203  ProSHADE_internal_messages::printWarningMessage ( verbose, "!!! ProSHADE WARNING !!! SVD algorithm did not converge.", "WS00069" );
2204  }
2205 
2206  //================================================ Determine positivity
2207  bool anyPositive = false;
2208  std::vector< bool > positivityTest;
2209  for ( proshade_unsign it = 0; it < static_cast< proshade_unsign > ( dim ); it++ )
2210  {
2211  positivityTest.push_back ( singularValues[it] > 0.001 );
2212  if ( positivityTest.at(it) ) { anyPositive = true; }
2213  }
2214 
2215  //================================================ Compute according to positivity
2216  proshade_double* pseudoInverseMat;
2217  if ( anyPositive )
2218  {
2219  //============================================ Set all non-positive singular values and appropriate matrix rows/columns to zero
2220  if ( !positivityTest.at(0) )
2221  {
2222  singularValues[0] = 0.0;
2223  rotMatU[0] = 0.0;
2224  rotMatU[1] = 0.0;
2225  rotMatU[2] = 0.0;
2226  rotMatV[0] = 0.0;
2227  rotMatV[3] = 0.0;
2228  rotMatV[6] = 0.0;
2229  }
2230  else { singularValues[0] = 1.0 / singularValues[0]; }
2231 
2232  if ( !positivityTest.at(1) )
2233  {
2234  singularValues[1] = 0.0;
2235  rotMatU[3] = 0.0;
2236  rotMatU[4] = 0.0;
2237  rotMatU[5] = 0.0;
2238  rotMatV[1] = 0.0;
2239  rotMatV[4] = 0.0;
2240  rotMatV[7] = 0.0;
2241  }
2242  else { singularValues[1] = 1.0 / singularValues[1]; }
2243 
2244  if ( !positivityTest.at(2) )
2245  {
2246  singularValues[2] = 0.0;
2247  rotMatU[6] = 0.0;
2248  rotMatU[7] = 0.0;
2249  rotMatU[8] = 0.0;
2250  rotMatV[2] = 0.0;
2251  rotMatV[5] = 0.0;
2252  rotMatV[8] = 0.0;
2253  }
2254  else { singularValues[2] = 1.0 / singularValues[2]; }
2255 
2256  //============================================ All positive values formula
2257  proshade_double* diagMat = ProSHADE_internal_maths::build3x3MatrixFromDiag ( singularValues );
2258  proshade_double* hlpMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( diagMat, rotMatU );
2259  pseudoInverseMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( rotMatV, hlpMat );
2260 
2261  //============================================ Release memory
2262  delete[] diagMat;
2263  delete[] hlpMat;
2264  }
2265  else
2266  {
2267  //============================================ No axis in matrix
2268  pseudoInverseMat = new proshade_double[9];
2269  ProSHADE_internal_misc::checkMemoryAllocation ( pseudoInverseMat, __FILE__, __LINE__, __func__ );
2270 
2271  for ( size_t mIt = 0; mIt < 9; mIt++ ) { pseudoInverseMat[mIt] = 0.0; }
2272  }
2273 
2274  //================================================ Free memory
2275  delete[] work;
2276  delete[] rwork;
2277  delete[] iwork;
2278  delete[] matrixToDecompose;
2279  delete[] singularValues;
2280  delete[] rotMatU;
2281  delete[] rotMatV;
2282 
2283  //================================================ Done
2284  return ( pseudoInverseMat );
2285 
2286 }

◆ computeCrossProduct() [1/2]

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 1820 of file ProSHADE_maths.cpp.

1821 {
1822  //================================================ Allocate memory
1823  proshade_double* crossProd = new proshade_double[3];
1824  ProSHADE_internal_misc::checkMemoryAllocation ( crossProd, __FILE__, __LINE__, __func__ );
1825 
1826  //================================================ Compute
1827  crossProd[0] = ( (*y1) * (*z2) ) - ( (*z1) * (*y2) );
1828  crossProd[1] = ( (*z1) * (*x2) ) - ( (*x1) * (*z2) );
1829  crossProd[2] = ( (*x1) * (*y2) ) - ( (*y1) * (*x2) );
1830 
1831  //================================================ Done
1832  return ( crossProd );
1833 
1834 }

◆ computeCrossProduct() [2/2]

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 1846 of file ProSHADE_maths.cpp.

1847 {
1848  //================================================ Allocate memory
1849  proshade_double* crossProd = new proshade_double[3];
1850  ProSHADE_internal_misc::checkMemoryAllocation ( crossProd, __FILE__, __LINE__, __func__ );
1851 
1852  //================================================ Compute
1853  crossProd[0] = ( y1 * z2 ) - ( z1 * y2 );
1854  crossProd[1] = ( z1 * x2 ) - ( x1 * z2 );
1855  crossProd[2] = ( x1 * y2 ) - ( y1 * x2 );
1856 
1857  //================================================ Done
1858  return ( crossProd );
1859 
1860 }

◆ 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 1788 of file ProSHADE_maths.cpp.

1789 {
1790  //================================================ Compute and return
1791  return ( (*x1 * *x2) + (*y1 * *y2) + (*z1 * *z2) );
1792 }

◆ 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 1804 of file ProSHADE_maths.cpp.

1805 {
1806  //================================================ Compute and return
1807  return ( (x1 * x2) + (y1 * y2) + (z1 * z2) );
1808 }

◆ 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,
proshade_double *&  fscByBin 
)

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.
[in]fscByBinThis array will hold FSC values for each bin. This is useful in further computations, but could be internal for FSC only computation.
[out]fscThe Fourier Shell Correlation between the two supplied Fourier coefficient maps.

Definition at line 3347 of file ProSHADE_maths.cpp.

3348 {
3349  //================================================ Initialise local variables
3350  proshade_double realOrig, realRot, imagOrig, imagRot, fsc = 0.0;;
3351  proshade_signed indx, arrPos;
3352  std::vector< proshade_double > covarByBin ( static_cast< size_t > ( noBins ), 0.0 );
3353 
3354  //================================================ Clean FSC computation memory
3355  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ ) { for ( size_t valIt = 0; valIt < 12; valIt++ ) { binData[binIt][valIt] = 0.0; } }
3356  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ ) { binCounts[binIt] = 0; }
3357 
3358  //================================================ Compute bin sums
3359  for ( proshade_signed xIt = 0; xIt < static_cast< proshade_signed > ( xInds ); xIt++ )
3360  {
3361  for ( proshade_signed yIt = 0; yIt < static_cast< proshade_signed > ( yInds ); yIt++ )
3362  {
3363  for ( proshade_signed zIt = 0; zIt < static_cast< proshade_signed > ( zInds ); zIt++ )
3364  {
3365  //==================================== Find array position
3366  arrPos = zIt + static_cast< proshade_signed > ( zInds ) * ( yIt + static_cast< proshade_signed > ( yInds ) * xIt );
3367 
3368  //==================================== If no bin is associated, skip this reflection
3369  indx = binIndexing[ static_cast< size_t > ( arrPos ) ];
3370  if ( ( indx < 0 ) || ( indx > noBins ) ) { continue; }
3371 
3372  //==================================== Calculate the sums
3373  realOrig = fCoeffs1[arrPos][0];
3374  imagOrig = fCoeffs1[arrPos][1];
3375  realRot = fCoeffs2[arrPos][0];
3376  imagRot = fCoeffs2[arrPos][1];
3377 
3378  binData[indx][0] += realOrig;
3379  binData[indx][1] += imagOrig;
3380  binData[indx][2] += realRot;
3381  binData[indx][3] += imagRot;
3382  binData[indx][4] += realOrig * realRot;
3383  binData[indx][5] += imagOrig * imagRot;
3384  binData[indx][6] += std::pow ( realOrig, 2.0 );
3385  binData[indx][7] += std::pow ( imagOrig, 2.0 );
3386  binData[indx][8] += std::pow ( realRot, 2.0 );
3387  binData[indx][9] += std::pow ( imagRot, 2.0 );
3388 
3389  //==================================== Update bin counts
3390  binCounts[indx] += 1;
3391  }
3392  }
3393  }
3394 
3395  //================================================ Compute covariance by bin
3396  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3397  {
3398  covarByBin.at(binIt) = ( ( binData[binIt][4] + binData[binIt][5] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3399  ( ( binData[binIt][0] / static_cast< proshade_double > ( binCounts[binIt] ) *
3400  binData[binIt][2] / static_cast< proshade_double > ( binCounts[binIt] ) ) +
3401  ( binData[binIt][1] / static_cast< proshade_double > ( binCounts[binIt] ) *
3402  binData[binIt][3] / static_cast< proshade_double > ( binCounts[binIt] ) ) ) );
3403  }
3404 
3405  //================================================ Get FSC by bin
3406  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3407  {
3408  binData[binIt][10] = ( binData[binIt][6] + binData[binIt][7] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3409  ( std::pow ( binData[binIt][0] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) +
3410  std::pow ( binData[binIt][1] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) );
3411  binData[binIt][11] = ( binData[binIt][8] + binData[binIt][9] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3412  ( std::pow ( binData[binIt][2] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) +
3413  std::pow ( binData[binIt][3] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) );
3414  fscByBin[binIt] = covarByBin.at(binIt) / ( std::sqrt ( binData[binIt][10] ) * std::sqrt ( binData[binIt][11] ) );
3415  }
3416 
3417  //================================================ Get average FSC over all bins
3418  proshade_double binSizeSum = 0.0;
3419  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3420  {
3421  fsc += fscByBin[binIt] * static_cast< proshade_double > ( binCounts[binIt] );
3422  binSizeSum += static_cast< proshade_double > ( binCounts[binIt] );
3423  }
3424  fsc /= static_cast< proshade_double > ( binSizeSum );
3425 
3426  //================================================ Done
3427  return ( fsc );
3428 
3429 }

◆ computeFSCWeightByBin()

void ProSHADE_internal_maths::computeFSCWeightByBin ( proshade_double *&  weights1,
proshade_double *&  weights2,
proshade_signed *  binIndexing,
proshade_double *  fscByBin,
proshade_signed  noBins,
proshade_signed  xDim,
proshade_signed  yDim,
proshade_signed  zDim 
)

This function computes the weights for each reflection using its bin belonging.

This function computes the weights for tralsation optimisation - the bin FSC for each reflection according to its bin belonging for weights1 and the square of this value for weights2. Note that weights1 and weights2 are allocated within the function, but since they are the output, the caller is expected to delete them after usage.

Parameters
[in]weights1A pointer to which the FSC by bin weights will be saved into.
[in]weights1A pointer to which the squared FSC by bin weights will be saved into.
[in]binIndexingThe map of bin belonging for each reflection.
[in]fscByBinThis array holds FSC values for each bin and is produced by the computeFSC() function.
[in]noBinNumber of bins.
[in]xDimThe size of the x-dimension of the map in indices.
[in]yDimThe size of the y-dimension of the map in indices.
[in]zDimThe size of the z-dimension of the map in indices.

Definition at line 3446 of file ProSHADE_maths.cpp.

3447 {
3448  //================================================ Initialise local variables
3449  proshade_signed indx, arrPos, reciX, reciY, reciZ;
3450 
3451  //================================================ Allocate memmory
3452  weights1 = new proshade_double[xDim * yDim * zDim];
3453  weights2 = new proshade_double[xDim * yDim * zDim];
3454  proshade_single *mins = new proshade_single[3];
3455  proshade_single *maxs = new proshade_single[3];
3456 
3457  //================================================ Check memory allocation
3458  ProSHADE_internal_misc::checkMemoryAllocation ( weights1, __FILE__, __LINE__, __func__ );
3459  ProSHADE_internal_misc::checkMemoryAllocation ( weights2, __FILE__, __LINE__, __func__ );
3460  ProSHADE_internal_misc::checkMemoryAllocation ( mins, __FILE__, __LINE__, __func__ );
3461  ProSHADE_internal_misc::checkMemoryAllocation ( maxs, __FILE__, __LINE__, __func__ );
3462 
3463  //================================================ Assign values to the memory
3464  for ( size_t iter = 0; iter < static_cast< size_t > ( xDim * yDim * zDim ); iter++ ) { weights1[iter] = -100.0; weights2[iter] = -100.0; }
3465 
3466  //================================================ Determine reciprocal space indexing ranges
3467  mins[0] = std::floor ( static_cast< proshade_single > ( xDim ) / -2.0f );
3468  mins[1] = std::floor ( static_cast< proshade_single > ( yDim ) / -2.0f );
3469  mins[2] = std::floor ( static_cast< proshade_single > ( zDim ) / -2.0f );
3470 
3471  maxs[0] = -mins[0];
3472  maxs[1] = -mins[1];
3473  maxs[2] = -mins[2];
3474 
3475  if ( xDim % 2 == 0 ) { mins[0] += 1.0f; }
3476  if ( yDim % 2 == 0 ) { mins[1] += 1.0f; }
3477  if ( zDim % 2 == 0 ) { mins[2] += 1.0f; }
3478 
3479  //================================================ For each reflection
3480  for ( proshade_signed xIt = 0; xIt < xDim; xIt++ )
3481  {
3482  for ( proshade_signed yIt = 0; yIt < yDim; yIt++ )
3483  {
3484  for ( proshade_signed zIt = 0; zIt < ( ( zDim / 2 ) + 1 ); zIt++ )
3485  {
3486  //==================================== Deal with reciprocal indices ordering
3487  reciX = xIt; if ( reciX > static_cast< proshade_signed > ( maxs[0] ) ) { reciX -= static_cast< proshade_signed > ( xDim ); }
3488  reciY = yIt; if ( reciY > static_cast< proshade_signed > ( maxs[1] ) ) { reciY -= static_cast< proshade_signed > ( yDim ); }
3489  reciZ = zIt; if ( reciZ > static_cast< proshade_signed > ( maxs[2] ) ) { reciZ -= static_cast< proshade_signed > ( zDim ); }
3490 
3491  //==================================== Find array position and bin index
3492  arrPos = zIt + zDim * ( yIt + yDim * xIt );
3493  indx = binIndexing[ static_cast< size_t > ( arrPos ) ];
3494 
3495  //==================================== Ignore unassigned bin reflections
3496  if ( ( indx < 0 ) || ( indx > noBins ) ) { continue; }
3497 
3498  //==================================== Set weights using the bin FSC
3499  weights1[arrPos] = fscByBin[indx];
3500  weights2[arrPos] = std::pow ( fscByBin[indx], 2.0 );
3501 
3502  //==================================== If one of the uneven ends, do not use Friedel's Law
3503  if ( reciX == static_cast< proshade_signed > ( mins[0] ) || -reciX == static_cast< proshade_signed > ( mins[0] ) ) { break; }
3504  if ( reciY == static_cast< proshade_signed > ( mins[1] ) || -reciY == static_cast< proshade_signed > ( mins[1] ) ) { break; }
3505  if ( reciZ == static_cast< proshade_signed > ( mins[2] ) || -reciZ == static_cast< proshade_signed > ( mins[2] ) ) { break; }
3506 
3507  //==================================== Use Friedel's Law to find the second index (this is why we can use zDim / 2)
3508  reciX *= -1; if ( reciX < 0 ) { reciX += xDim; }
3509  reciY *= -1; if ( reciY < 0 ) { reciY += yDim; }
3510  reciZ *= -1; if ( reciZ < 0 ) { reciZ += zDim; }
3511 
3512  //==================================== Apply Friedel's Law
3513  arrPos = reciZ + zDim * ( reciY + yDim * reciX );
3514  weights1[arrPos] = fscByBin[indx];
3515  weights2[arrPos] = std::pow ( fscByBin[indx], 2.0 );
3516  }
3517  }
3518  }
3519 
3520  //================================================ Release memory
3521  delete[] mins;
3522  delete[] maxs;
3523 
3524  //================================================ Done
3525  return ;
3526 
3527 }

◆ 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 3103 of file ProSHADE_maths.cpp.

3104 {
3105  //================================================ Compute cumulative probability from Z-score
3106  proshade_double zScore = ( val / sigma );
3107  proshade_double cumulativeProbability = 0.5 * std::erfc ( zScore * M_SQRT1_2 );
3108 
3109  //================================================ Symmetrise
3110  if ( cumulativeProbability > 0.5 ) { cumulativeProbability = 1.0 - cumulativeProbability; }
3111 
3112  //================================================ Done
3113  return ( cumulativeProbability );
3114 
3115 }

◆ computeTheFValue()

proshade_double ProSHADE_internal_maths::computeTheFValue ( proshade_complex *  fCoeffs,
proshade_double *  weights,
proshade_signed  xDim,
proshade_signed  yDim,
proshade_signed  zDim 
)

This function computes the real part of the sum of all coefficients except where the weight is less than -2.

Parameters
[in]fCoeffsThe Fourier coefficients to be moved.
[in]weightsThe weights to be applied to the shift.
[in]xDimThe size of the x-dimension of the map in indices.
[in]yDimThe size of the y-dimension of the map in indices.
[in]zDimThe size of the z-dimension of the map in indices.
[out]sumThe F value.

Definition at line 3538 of file ProSHADE_maths.cpp.

3539 {
3540  //================================================ Initialise local variables
3541  proshade_double sum = 0.0;
3542  proshade_signed arrPos;
3543 
3544  //================================================ For each reflection
3545  for ( proshade_signed xIt = 0; xIt < xDim; xIt++ )
3546  {
3547  for ( proshade_signed yIt = 0; yIt < yDim; yIt++ )
3548  {
3549  for ( proshade_signed zIt = 0; zIt < ( ( zDim / 2 ) + 1 ); zIt++ )
3550  {
3551  //==================================== Find array position and bin index
3552  arrPos = zIt + zDim * ( yIt + yDim * xIt );
3553 
3554  //==================================== Sum real parts if weight exists
3555  if ( weights[arrPos] > -2.0 ) { sum += fCoeffs[arrPos][0]; }
3556  }
3557  }
3558  }
3559 
3560  //================================================ Done
3561  return ( sum );
3562 
3563 }

◆ computeTrFunDerivatives()

void ProSHADE_internal_maths::computeTrFunDerivatives ( proshade_complex *  fCoeffs,
proshade_double *  weights1,
proshade_double *  weights2,
proshade_signed  xDim,
proshade_signed  yDim,
proshade_signed  zDim,
proshade_double *&  firstDers,
proshade_double *&  secondDers 
)

This function computes the first and second derivatives of the translation function at coefficient [0,0,0].

Parameters
[in]fCoeffsThe Fourier coefficients to be used.
[in]weights1The weights to be applied to the computation of the first derivatives (given by function computeFSCWeightByBin() ).
[in]weights2The weights to be applied to the computation of the second derivatives (given by function computeFSCWeightByBin() ).
[in]xDimThe size of the x-dimension of the map in indices.
[in]yDimThe size of the y-dimension of the map in indices.
[in]zDimThe size of the z-dimension of the map in indices.
[in]firstDersPointer to array where the first derivatives (array of 3) will be stored. This function will allocate the memory, but the caller will have to delete it.
[in]secondDersPointer to array where the second derivatives (array of 9) will be stored. This function will allocate the memory, but the caller will have to delete it.

Definition at line 3576 of file ProSHADE_maths.cpp.

3577 {
3578  //================================================ Allocate memmory
3579  firstDers = new proshade_double[3];
3580  secondDers = new proshade_double[9];
3581  proshade_single *mins = new proshade_single[3];
3582  proshade_single *maxs = new proshade_single[3];
3583 
3584  //================================================ Check memory allocation
3585  ProSHADE_internal_misc::checkMemoryAllocation ( firstDers, __FILE__, __LINE__, __func__ );
3586  ProSHADE_internal_misc::checkMemoryAllocation ( secondDers, __FILE__, __LINE__, __func__ );
3587  ProSHADE_internal_misc::checkMemoryAllocation ( mins, __FILE__, __LINE__, __func__ );
3588  ProSHADE_internal_misc::checkMemoryAllocation ( maxs, __FILE__, __LINE__, __func__ );
3589 
3590  //================================================ Initialise variables
3591  std::complex< proshade_double > piConstFirst ( 2.0 * M_PI, 1.0 );
3592  proshade_double piConstSecond = std::pow ( 2.0 * M_PI, 2.0 );
3593  for ( size_t iter = 0; iter < 3; iter++ ) { firstDers[iter] = 0.0; }
3594  for ( size_t iter = 0; iter < 9; iter++ ) { secondDers[iter] = 0.0; }
3595  proshade_signed reciX, reciY, reciZ, arrPos;
3596 
3597  //================================================ Determine reciprocal space indexing ranges
3598  mins[0] = std::floor ( static_cast< proshade_single > ( xDim ) / -2.0f );
3599  mins[1] = std::floor ( static_cast< proshade_single > ( yDim ) / -2.0f );
3600  mins[2] = std::floor ( static_cast< proshade_single > ( zDim ) / -2.0f );
3601 
3602  maxs[0] = -mins[0];
3603  maxs[1] = -mins[1];
3604  maxs[2] = -mins[2];
3605 
3606  if ( xDim % 2 == 0 ) { mins[0] += 1.0f; }
3607  if ( yDim % 2 == 0 ) { mins[1] += 1.0f; }
3608  if ( zDim % 2 == 0 ) { mins[2] += 1.0f; }
3609 
3610  //================================================ For each reflection
3611  for ( proshade_signed xIt = 0; xIt < xDim; xIt++ )
3612  {
3613  for ( proshade_signed yIt = 0; yIt < yDim; yIt++ )
3614  {
3615  for ( proshade_signed zIt = 0; zIt < ( ( zDim / 2 ) + 1 ); zIt++ )
3616  {
3617  //==================================== Deal with reciprocal indices ordering
3618  reciX = xIt; if ( reciX > static_cast< proshade_signed > ( maxs[0] ) ) { reciX -= static_cast< proshade_signed > ( xDim ); }
3619  reciY = yIt; if ( reciY > static_cast< proshade_signed > ( maxs[1] ) ) { reciY -= static_cast< proshade_signed > ( yDim ); }
3620  reciZ = zIt; if ( reciZ > static_cast< proshade_signed > ( maxs[2] ) ) { reciZ -= static_cast< proshade_signed > ( zDim ); }
3621 
3622  //==================================== Find array position and bin index
3623  arrPos = zIt + zDim * ( yIt + yDim * xIt );
3624 
3625  //==================================== Ignore if outside of weights
3626  if ( weights1[arrPos] < -2.0 ) { continue; }
3627 
3628  //==================================== Add to the first derivatives sum
3629  firstDers[0] += ( weights1[arrPos] * fCoeffs[arrPos][0] * std::conj( fCoeffs[arrPos][1] * piConstFirst * static_cast< proshade_double > ( reciX ) ) ).real();
3630  firstDers[1] += ( weights1[arrPos] * fCoeffs[arrPos][0] * std::conj( fCoeffs[arrPos][1] * piConstFirst * static_cast< proshade_double > ( reciY ) ) ).real();
3631  firstDers[2] += ( weights1[arrPos] * fCoeffs[arrPos][0] * std::conj( fCoeffs[arrPos][1] * piConstFirst * static_cast< proshade_double > ( reciZ ) ) ).real();
3632 
3633  //==================================== Add to the second derivatives sum
3634  secondDers[0] += weights2[arrPos] * reciX * reciX;
3635  secondDers[1] += weights2[arrPos] * reciX * reciY;
3636  secondDers[2] += weights2[arrPos] * reciX * reciZ;
3637  secondDers[4] += weights2[arrPos] * reciY * reciY;
3638  secondDers[5] += weights2[arrPos] * reciY * reciZ;
3639  secondDers[8] += weights2[arrPos] * reciZ * reciZ;
3640  }
3641  }
3642  }
3643 
3644  //================================================ Complete second darivatives matrix
3645  secondDers[3] = secondDers[1];
3646  secondDers[6] = secondDers[2];
3647  secondDers[7] = secondDers[5];
3648  for ( size_t iter = 0; iter < 9; iter++ ) { secondDers[iter] *= -piConstSecond; }
3649 
3650  //================================================ Release memory
3651  delete[] mins;
3652  delete[] maxs;
3653 
3654  //================================================ Done
3655  return ;
3656 
3657 }

◆ computeTrFunStep()

proshade_double * ProSHADE_internal_maths::computeTrFunStep ( proshade_double *  firstDers,
proshade_double *  secondDers 
)

This function computes the step sizes for translation function optimisation from the first and second derivatives.

Parameters
[in]firstDersPointer to array where the first derivatives are stored (as computed by computeTrFunDerivatives() ).
[in]secondDersPointer to array where the second derivatives are stored (as computed by computeTrFunDerivatives() ).
[out]stepArrAn array holding the step sizes along the three dimensions. It is allocated here, but the caller is required to delete the pointer.

Definition at line 3665 of file ProSHADE_maths.cpp.

3666 {
3667  //================================================ Change format of second derivatives and add I matrix (the inversion function will subtract it)
3668  std::vector < proshade_double > tmpMap ( 9, 0.0 );
3669  for ( size_t iter = 0; iter < 9; iter++ ) { tmpMap.at(iter) = secondDers[iter]; }
3670  tmpMap.at(0) += 1.0; tmpMap.at(4) += 1.0; tmpMap.at(8) += 1.0;
3671 
3672  //================================================ Compute matrix inversion for the second derivatives matrix
3673  proshade_double* secondInv = compute3x3MoorePenrosePseudoInverseOfIMinusMat ( &tmpMap, -1 );
3674 
3675  //================================================ Compute dot product between the inverted matrix and the first derivatives vector
3676  proshade_double* stepArr = compute3x3MatrixVectorMultiplication ( secondInv, -firstDers[0], -firstDers[1], -firstDers[2] );
3677 
3678  //================================================ Release memory
3679  delete[] secondInv;
3680 
3681  //================================================ Done
3682  return ( stepArr );
3683 
3684 }

◆ 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 3058 of file ProSHADE_maths.cpp.

3059 {
3060  //================================================ Initialise variables
3061  std::vector< proshade_unsign > ret;
3062  std::vector< std::pair< proshade_unsign, bool > > sieveOfEratosthenesArray;
3063 
3064  //================================================ Sanity check
3065  if ( upTo < 2 ) { return ( ret ); }
3066 
3067  //================================================ Initialise the sieve array up to the required number
3068  for ( proshade_unsign iter = 2; iter <= upTo; iter++ ) { sieveOfEratosthenesArray.emplace_back ( std::pair< proshade_unsign, bool > ( iter, true ) ); }
3069 
3070  //================================================ For each entry in the array
3071  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); iter++ )
3072  {
3073  //============================================ If this entry is still true
3074  if ( sieveOfEratosthenesArray.at(iter).second )
3075  {
3076  //======================================== Set all entries with the position x * [this entry value] to false
3077  for ( proshade_unsign it = iter + sieveOfEratosthenesArray.at(iter).first; it < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); it += sieveOfEratosthenesArray.at(iter).first )
3078  {
3079  sieveOfEratosthenesArray.at(it).second = false;
3080  }
3081  }
3082  }
3083 
3084  //================================================ Copy passing results to return vector
3085  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); iter++ )
3086  {
3087  if ( sieveOfEratosthenesArray.at(iter).second ) { ProSHADE_internal_misc::addToUnsignVector ( &ret, sieveOfEratosthenesArray.at(iter).first ); }
3088  }
3089 
3090  //================================================ Done
3091  return ( ret );
3092 
3093 }

◆ findHighestValueInMap()

void ProSHADE_internal_maths::findHighestValueInMap ( fftw_complex *  resIn,
proshade_unsign  xD,
proshade_unsign  yD,
proshade_unsign  zD,
proshade_double *  trsX,
proshade_double *  trsY,
proshade_double *  trsZ,
proshade_double *  mapPeak 
)

This function simply finds the highest value in fftw_complex map and returns its position and value.

Parameters
[in]resInArray holding the translation function values.
[in]xDThe dimension of the X axis of the structures (assumes both structures have the same sizes and sampling).
[in]yDThe dimension of the Y axis of the structures (assumes both structures have the same sizes and sampling).
[in]zDThe dimension of the Z axis of the structures (assumes both structures have the same sizes and sampling).
[in]trsXVariable to which the X axis translation function peak position will be saved to.
[in]trsYVariable to which the Y axis translation function peak position will be saved to.
[in]trsZVariable to which the Z axis translation function peak position will be saved to.
[in]mapPeakVariable to which the height of the translation function peak will be saved to.

Definition at line 3912 of file ProSHADE_maths.cpp.

3913 {
3914  //================================================ Initialise variables
3915  proshade_signed arrPos;
3916  *mapPeak = 0.0;
3917 
3918  //================================================ Search the map
3919  for ( proshade_signed uIt = 0; uIt < static_cast<proshade_signed> ( xD ); uIt++ )
3920  {
3921  for ( proshade_signed vIt = 0; vIt < static_cast<proshade_signed> ( yD ); vIt++ )
3922  {
3923  for ( proshade_signed wIt = 0; wIt < static_cast<proshade_signed> ( zD ); wIt++ )
3924  {
3925  arrPos = wIt + static_cast< proshade_signed > ( zD ) * ( vIt + static_cast< proshade_signed > ( yD ) * uIt );
3926  if ( resIn[arrPos][0] > *mapPeak )
3927  {
3928  *mapPeak = resIn[arrPos][0];
3929  *trsX = static_cast< proshade_double > ( uIt );
3930  *trsY = static_cast< proshade_double > ( vIt );
3931  *trsZ = static_cast< proshade_double > ( wIt );
3932  }
3933  }
3934  }
3935  }
3936 
3937  //================================================ Done
3938  return ;
3939 
3940 }

◆ findPeaks1D()

std::vector< proshade_signed > ProSHADE_internal_maths::findPeaks1D ( std::vector< proshade_double >  data)

This function simply finds all the peaks in a 1D data array.

Simple function for detecting all points in the supplied array which have higher value than all surrounding points along the single dimension of the array.

Parameters
[in]dataThe input array containning (pressumably smoothened) data.
[out]peaksA vector containing all the peak indices in the input array.

Definition at line 3693 of file ProSHADE_maths.cpp.

3694 {
3695  //================================================ Initialise local variables
3696  std::vector< proshade_signed > ret;
3697 
3698  //================================================ Peak is simply any position with both neighbours having lower position (with special care for borders)
3699  for ( proshade_signed index = 0; index < static_cast< proshade_signed > ( data.size() ); index++ )
3700  {
3701  //============================================ Starting border?
3702  if ( index == 0 )
3703  {
3704  if ( data.size() > 1 ) { if ( data.at(0) > data.at(1) ) { ProSHADE_internal_misc::addToSignedVector ( &ret, index ); } }
3705  continue;
3706  }
3707 
3708  //============================================ End border?
3709  if ( index == static_cast< proshade_signed > ( data.size() - 1 ) )
3710  {
3711  if ( data.at( static_cast< size_t > ( index ) ) > data.at( static_cast< size_t > ( index ) - 1 ) ) { ProSHADE_internal_misc::addToSignedVector ( &ret, index ); }
3712  continue;
3713  }
3714 
3715  //============================================ Is this a peak?
3716  if ( ( data.at( static_cast< size_t > ( index ) ) > data.at( static_cast< size_t > ( index ) - 1 ) ) &&
3717  ( data.at( static_cast< size_t > ( index ) ) > data.at( static_cast< size_t > ( index ) + 1 ) ) ) { ProSHADE_internal_misc::addToSignedVector ( &ret, index ); }
3718 
3719  //============================================ Deal with equally sized values
3720  if ( index < static_cast< proshade_signed > ( data.size() - 2 ) ) { if ( data.at( static_cast< size_t > ( index ) ) >= data.at( static_cast< size_t > ( index ) - 1 ) ) { if ( data.at( static_cast< size_t > ( index ) ) >= data.at( static_cast< size_t > ( index ) + 1 ) ) { if ( data.at( static_cast< size_t > ( index ) ) > data.at( static_cast< size_t > ( index ) + 2 ) ) { ProSHADE_internal_misc::addToSignedVector ( &ret, index ); } } } }
3721  }
3722 
3723  //================================================ Done
3724  return ( ret );
3725 
3726 }

◆ 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 2095 of file ProSHADE_maths.cpp.

2096 {
2097  //================================================ Allocate required memory
2098  proshade_double* inPlaneRotation = new proshade_double[9];
2099  proshade_double* basisChangeMat = new proshade_double[9];
2100  ProSHADE_internal_misc::checkMemoryAllocation ( inPlaneRotation, __FILE__, __LINE__, __func__ );
2101  ProSHADE_internal_misc::checkMemoryAllocation ( basisChangeMat, __FILE__, __LINE__, __func__ );
2102 
2103  //================================================ Normalise inputs
2104  proshade_double normF = std::sqrt( std::pow( x1, 2.0 ) + std::pow ( y1, 2.0 ) + std::pow ( z1, 2.0 ) );
2105  x1 /= normF; y1 /= normF; z1 /= normF;
2106 
2107  normF = std::sqrt( std::pow( x2, 2.0 ) + std::pow ( y2, 2.0 ) + std::pow ( z2, 2.0 ) );
2108  x2 /= normF; y2 /= normF; z2 /= normF;
2109 
2110  //================================================ Compute cross product's magnitude
2111  proshade_double* crossProd = ProSHADE_internal_maths::computeCrossProduct( &x1, &y1, &z1, &x2, &y2, &z2 );
2112  proshade_double crossProdMag = std::sqrt( std::pow( crossProd[0], 2.0 ) + std::pow ( crossProd[1], 2.0 ) + std::pow ( crossProd[2], 2.0 ) );
2113  delete[] crossProd;
2114 
2115  //================================================ Compute dot product
2116  proshade_double dotProd = ProSHADE_internal_maths::computeDotProduct ( &x1, &y1, &z1, &x2, &y2, &z2 );
2117 
2118  //================================================ Construct the in-plane rotation matrix
2119  inPlaneRotation[0] = dotProd; inPlaneRotation[1] = -crossProdMag; inPlaneRotation[2] = 0.0;
2120  inPlaneRotation[3] = crossProdMag; inPlaneRotation[4] = dotProd; inPlaneRotation[5] = 0.0;
2121  inPlaneRotation[6] = 0.0; inPlaneRotation[7] = 0.0; inPlaneRotation[8] = 1.0;
2122 
2123  //================================================ Construct change of basis matrix
2124  crossProd = ProSHADE_internal_maths::computeCrossProduct( &x2, &y2, &z2, &x1, &y1, &z1 );
2125  normF = std::sqrt ( std::pow ( x2 - ( dotProd * x1 ), 2.0 ) + std::pow ( y2 - ( dotProd * y1 ), 2.0 ) + std::pow ( z2 - ( dotProd * z1 ), 2.0 ) );
2126 
2127  basisChangeMat[0] = x1; basisChangeMat[1] = ( x2 - ( dotProd * x1 ) ) / normF; basisChangeMat[2] = crossProd[0];
2128  basisChangeMat[3] = y1; basisChangeMat[4] = ( y2 - ( dotProd * y1 ) ) / normF; basisChangeMat[5] = crossProd[1];
2129  basisChangeMat[6] = z1; basisChangeMat[7] = ( z2 - ( dotProd * z1 ) ) / normF; basisChangeMat[8] = crossProd[2];
2130 
2131  //================================================ Invert the change of basis matrix
2132  proshade_double* basisChangeMatInverse = ProSHADE_internal_maths::compute3x3MatrixInverse ( basisChangeMat );
2133 
2134  //================================================ Multiply inverse of change of basis matrix with the in plane rotation matrix, then multiply the result with the inverse
2135  proshade_double* tmpMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( basisChangeMat, inPlaneRotation );
2136  proshade_double* rotMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( tmpMat, basisChangeMatInverse );
2137 
2138  //================================================ Release memory
2139  delete[] crossProd;
2140  delete[] inPlaneRotation;
2141  delete[] basisChangeMat;
2142  delete[] basisChangeMatInverse;
2143  delete[] tmpMat;
2144 
2145  //================================================ Done
2146  return ( rotMat );
2147 
2148 }

◆ findTopGroupSmooth() [1/2]

proshade_double ProSHADE_internal_maths::findTopGroupSmooth ( std::vector< proshade_double * > *  CSym,
size_t  peakPos,
proshade_double  step,
proshade_double  sigma,
proshade_signed  windowSize,
proshade_double  maxLim = 0.9 
)

This function finds a subgroup of axes with distinctly higher correlation value.

This function starts by getting a vector of all peak heights detected in all C symmetries detected in the structure. It then proceeds to convert this vector into a histogram, which it then smoothens using Gaussian convolution according to the input parameters. Finally, it searches for peaks in the smoothened histogram function and reports the minimal value that average peak height must be in order for the axis to be considered part of this top group.

Parameters
[in]CSymA vector of pointers to double arrays, each array being a single Cyclic symmetry entry.
[in]stepThe granulosity of the interval <0,1> using which the search should be done.
[in]sigmaThe variance of the Gaussian used to smoothen the peak height histogram.
[in]windowSizeThe width of the window over which smoothening is done.
[in]maxLimThe maximum value that can be reached - this is to step a single extremely high peak overshadowing very good peaks.
[out]thresholdThe minimum peak height that an axis needs to have to be considered a member of the distinct top group.

Definition at line 3743 of file ProSHADE_maths.cpp.

3744 {
3745  //================================================ Initialise local variables
3746  proshade_double threshold = 0.0;
3747  proshade_signed totSize = static_cast< proshade_signed > ( ( 1.0 / step ) + 1 );
3748  std::vector< std::pair < proshade_double, proshade_unsign > > vals;
3749  std::vector< proshade_double > hist ( static_cast< unsigned long int > ( totSize ), 0.0 );
3750  proshade_unsign histPos = 0;
3751 
3752  //================================================ Make sure window size is odd
3753  if ( windowSize % 2 == 0 ) { windowSize += 1; }
3754 
3755  //================================================ Get vector of pairs of peak heights and indices in CSym array
3756  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( CSym->size() ); symIt++ ) { vals.emplace_back ( std::pair < proshade_double, proshade_unsign > ( CSym->at(symIt)[peakPos], symIt ) ); }
3757 
3758  //================================================ Bump all top peaks together - we do not want single high peak overshadowing many good peaks
3759  for ( proshade_unsign vIt = 0; vIt < static_cast< proshade_unsign > ( vals.size() ); vIt++ ) { if ( vals.at(vIt).first > maxLim ) { vals.at(vIt).first = maxLim; } }
3760 
3761  //================================================ Convert all found heights to histogram from 0.0 to 1.0 by step
3762  for ( proshade_double it = 0.0; it <= 1.0; it = it + step )
3763  {
3764  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( vals.size() ); symIt++ )
3765  {
3766  //======================================== Is this height in the range?
3767  if ( ( vals.at(symIt).first > it ) && ( vals.at(symIt).first <= ( it + step ) ) ) { hist.at(histPos) += 1.0; }
3768  }
3769 
3770  //============================================ Update counter and continue
3771  histPos += 1;
3772  }
3773 
3774  //================================================ Smoothen the distribution
3775  std::vector< proshade_double > smoothened = ProSHADE_internal_maths::smoothen1D ( step, windowSize, sigma, hist );
3776 
3777  //================================================ Find peaks in smoothened data
3778  std::vector< proshade_signed > peaks = ProSHADE_internal_maths::findPeaks1D ( smoothened );
3779 
3780  //================================================ Take best peaks surroundings and produce a new set of "high" axes
3781  proshade_signed bestHistPos;
3782  if ( peaks.size() > 0 ) { bestHistPos = peaks.at(peaks.size()-1) + ( ( windowSize - 1 ) / 2 ); }
3783  else { bestHistPos = 0.0; }
3784 
3785  threshold = ( static_cast< proshade_double > ( bestHistPos ) * step ) - ( static_cast< proshade_double > ( windowSize - 1 ) * step );
3786 
3787  //================================================ Done
3788  return ( threshold );
3789 
3790 }

◆ findTopGroupSmooth() [2/2]

proshade_double ProSHADE_internal_maths::findTopGroupSmooth ( std::vector< std::vector< proshade_double > > *  CSym,
size_t  peakPos,
proshade_double  step,
proshade_double  sigma,
proshade_signed  windowSize,
proshade_double  maxLim = 0.9 
)

This function finds a subgroup of axes with distinctly higher correlation value.

This function starts by getting a vector of all peak heights detected in all C symmetries detected in the structure. It then proceeds to convert this vector into a histogram, which it then smoothens using Gaussian convolution according to the input parameters. Finally, it searches for peaks in the smoothened histogram function and reports the minimal value that average peak height must be in order for the axis to be considered part of this top group.

Parameters
[in]CSymA vector of vectors of doubles, each array being a single Cyclic symmetry entry.
[in]stepThe granulosity of the interval <0,1> using which the search should be done.
[in]sigmaThe variance of the Gaussian used to smoothen the peak height histogram.
[in]windowSizeThe width of the window over which smoothening is done.
[in]maxLimThe maximum value that can be reached - this is to step a single extremely high peak overshadowing very good peaks.
[out]thresholdThe minimum peak height that an axis needs to have to be considered a member of the distinct top group.

Definition at line 3806 of file ProSHADE_maths.cpp.

3807 {
3808  //================================================ Initialise local variables
3809  proshade_double threshold = 0.0;
3810  proshade_signed totSize = static_cast< proshade_signed > ( ( 1.0 / step ) + 1 );
3811  std::vector< std::pair < proshade_double, proshade_unsign > > vals;
3812  std::vector< proshade_double > hist ( static_cast< unsigned long int > ( totSize ), 0.0 );
3813  proshade_unsign histPos = 0;
3814 
3815  //================================================ Make sure window size is odd
3816  if ( windowSize % 2 == 0 ) { windowSize += 1; }
3817 
3818  //================================================ Get vector of pairs of peak heights and indices in CSym array
3819  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( CSym->size() ); symIt++ ) { vals.emplace_back ( std::pair < proshade_double, proshade_unsign > ( CSym->at(symIt).at(peakPos), symIt ) ); }
3820 
3821  //================================================ Bump all top peaks together - we do not want single high peak overshadowing many good peaks
3822  for ( proshade_unsign vIt = 0; vIt < static_cast< proshade_unsign > ( vals.size() ); vIt++ ) { if ( vals.at(vIt).first > maxLim ) { vals.at(vIt).first = maxLim; } }
3823 
3824 
3825  //================================================ Convert all found heights to histogram from 0.0 to 1.0 by step
3826  for ( proshade_double it = 0.0; it <= 1.0; it = it + step )
3827  {
3828  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( vals.size() ); symIt++ )
3829  {
3830  //======================================== Is this height in the range?
3831  if ( ( vals.at(symIt).first > it ) && ( vals.at(symIt).first <= ( it + step ) ) ) { hist.at(histPos) += 1.0; }
3832  }
3833 
3834  //============================================ Update counter and continue
3835  histPos += 1;
3836  }
3837 
3838  //================================================ Smoothen the distribution
3839  std::vector< proshade_double > smoothened = ProSHADE_internal_maths::smoothen1D ( step, windowSize, sigma, hist );
3840 
3841  //================================================ Find peaks in smoothened data
3842  std::vector< proshade_signed > peaks = ProSHADE_internal_maths::findPeaks1D ( smoothened );
3843 
3844  //================================================ Take best peaks surroundings and produce a new set of "high" axes
3845  proshade_signed bestHistPos;
3846  if ( peaks.size() > 0 ) { bestHistPos = peaks.at(peaks.size()-1) + ( ( windowSize - 1 ) / 2 ); }
3847  else { bestHistPos = 0.0; }
3848 
3849  threshold = ( static_cast< proshade_double > ( bestHistPos ) * step ) - ( static_cast< proshade_double > ( windowSize ) * step );
3850 
3851  //================================================ Done
3852  return ( threshold );
3853 
3854 }

◆ 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 2455 of file ProSHADE_maths.cpp.

2456 {
2457  //================================================ Initialise variables
2458  std::vector < proshade_double > ret;
2459 
2460  //================================================ Solution
2461  proshade_double solX = - ( y1 * dot2 * z3 - y1 * dot3 * z2 - z1 * dot2 * y3 + z1 * dot3 * y2 + dot1 * y3 * z2 - dot1 * z3 * y2 ) /
2462  ( -x1 * y3 * z2 + x1 * z3 * y2 + y1 * x3 * z2 - y1 * z3 * x2 - z1 * x3 * y2 + z1 * y3 * x2 );
2463  proshade_double solY = - ( x1 * dot2 * z3 - x1 * dot3 * z2 - z1 * dot2 * x3 + z1 * dot3 * x2 + dot1 * x3 * z2 - dot1 * z3 * x2 ) /
2464  ( x1 * y3 * z2 - x1 * z3 * y2 - y1 * x3 * z2 + y1 * z3 * x2 + z1 * x3 * y2 - z1 * y3 * x2 );
2465  proshade_double solZ = - ( x1 * dot2 * y3 - x1 * dot3 * y2 - y1 * dot2 * x3 + y1 * dot3 * x2 + dot1 * x3 * y2 - dot1 * y3 * x2 ) /
2466  ( -x1 * y3 * z2 + x1 * z3 * y2 + y1 * x3 * z2 - y1 * z3 * x2 - z1 * x3 * y2 + z1 * y3 * x2 );
2467 
2468  //================================================ Normalise the axis to magnitude 1
2469  proshade_double normFactor = sqrt ( pow ( solX, 2.0 ) + pow ( solY, 2.0 ) + pow ( solZ, 2.0 ) );
2470  solX /= normFactor;
2471  solY /= normFactor;
2472  solZ /= normFactor;
2473 
2474  //================================================ Set largest axis element to positive (ProSHADE standard)
2475  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) );
2476  const FloatingPoint< proshade_double > rhs1 ( std::abs ( solX ) );
2477  const FloatingPoint< proshade_double > rhs2 ( std::abs ( solY ) );
2478  const FloatingPoint< proshade_double > rhs3 ( std::abs ( solZ ) );
2479  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( solX < 0.0 ) ) ||
2480  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( solY < 0.0 ) ) ||
2481  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( solZ < 0.0 ) ) ) { solX *= -1.0; solY *= -1.0; solZ *= -1.0; }
2482 
2483  //================================================ Save solutions
2487 
2488  //================================================ Done
2489  return ( ret );
2490 
2491 }

◆ 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 2309 of file ProSHADE_maths.cpp.

2310 {
2311  //================================================ Initialise variables
2312  std::vector < proshade_double > ret;
2313 
2314  //================================================ Solution
2315  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 ) -
2316  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 ) ) *
2317  ( 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 ) ) ) -
2318  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 ) /
2319  ( 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 ) ) );
2320  proshade_double solY = ( ( dot2 * pow ( x2, 2.0 ) * pow ( z1, 3.0 ) ) /
2321  ( 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 ) -
2322  ( dot1 * pow ( x2, 2.0 ) * z2 * pow ( z1, 2.0 ) ) /
2323  ( 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 ) -
2324  ( 2.0 * x1 * dot2 * x2 * z2 * pow ( z1, 2.0 ) ) /
2325  ( 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 -
2326  ( 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 ) -
2327  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 ) *
2328  ( 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 ) /
2329  ( 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 ) ) +
2330  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) * z1 ) /
2331  ( 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 ) +
2332  ( x1 * dot1 * x2 * pow ( y2, 2.0 ) * z1 ) /
2333  ( 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 ) +
2334  ( pow ( x1, 2.0 ) * dot2 * pow ( z2, 2.0 ) * z1 ) /
2335  ( 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 ) +
2336  ( 2.0 * x1 * dot1 * x2 * pow ( z2, 2.0 ) * z1 ) /
2337  ( 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 ) -
2338  ( y1 * dot1 * pow ( x2, 2.0 ) * y2 * z1 ) /
2339  ( 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 ) -
2340  ( x1 * y1 * dot2 * x2 * y2 * z1 ) /
2341  ( 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 +
2342  ( 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 ) -
2343  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 ) *
2344  ( 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 ) ) ) /
2345  ( 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 ) ) -
2346  ( pow ( x1, 2.0 ) * dot1 * pow ( z2, 3.0 ) ) /
2347  ( 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 ) -
2348  ( pow ( x1, 2.0 ) * dot1 * pow ( y2, 2.0 ) * z2 ) /
2349  ( 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 ) -
2350  ( x1 * pow ( y1, 2.0 ) * dot2 * x2 * z2 ) /
2351  ( 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 ) +
2352  ( pow ( x1, 2.0 ) * y1 * dot2 * y2 * z2 ) /
2353  ( 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 ) +
2354  ( x1 * y1 * dot1 * x2 * y2 * z2 ) /
2355  ( 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 );
2356  proshade_double solZ = ( - ( dot2 * pow ( x2, 2.0 ) * y2 * pow ( z1, 3.0 ) ) /
2357  ( ( 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 ) ) -
2358  ( dot2 * pow ( x2, 2.0 ) * pow ( z1, 2.0 ) ) /
2359  ( 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 ) +
2360  ( dot1 * pow ( x2, 2.0 ) * y2 * z2 * pow ( z1, 2.0 ) ) /
2361  ( ( 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 ) ) +
2362  ( 2.0 * x1 * dot2 * x2 * y2 * z2 * pow ( z1, 2.0 ) ) /
2363  ( ( 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 ) ) +
2364  ( 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 ) -
2365  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 ) *
2366  ( 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 ) /
2367  ( 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 ) ) +
2368  ( dot2 * y2 * z1 ) / ( y1 * z2 - z1 * y2 ) +
2369  ( dot1 * pow ( x2, 2.0 ) * z2 * z1 ) /
2370  ( 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 ) +
2371  ( x1 * dot2 * x2 * z2 * z1 ) /
2372  ( 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 ) -
2373  ( x1 * dot1 * x2 * pow ( y2, 3.0 ) * z1 ) /
2374  ( ( 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 ) ) +
2375  ( y1 * dot1 * pow ( x2, 2.0 ) * pow ( y2, 2.0 ) * z1 ) /
2376  ( ( 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 ) ) +
2377  ( x1 * y1 * dot2 * x2 * pow ( y2, 2.0 ) * z1 ) /
2378  ( ( 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 ) ) -
2379  ( pow ( x1, 2.0 ) * dot2 * y2 * pow ( z2, 2.0 ) * z1 ) /
2380  ( ( 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 ) ) -
2381  ( 2.0 * x1 * dot1 * x2 * y2 * pow ( z2, 2.0 ) * z1 ) /
2382  ( ( 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 ) ) -
2383  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) * y2 * z1 ) /
2384  ( ( 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 +
2385  ( 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 ) -
2386  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 ) *
2387  ( 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 ) ) ) /
2388  ( 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 ) ) -
2389  ( 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 ) -
2390  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 ) *
2391  ( 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 ) ) ) /
2392  ( 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 ) ) -
2393  ( dot1 * y2 * z2 ) / ( y1 * z2 - z1 * y2 ) -
2394  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) ) /
2395  ( 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 ) -
2396  ( x1 * dot1 * x2 * pow ( y2, 2.0 ) ) /
2397  ( 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 ) -
2398  ( x1 * dot1 * x2 * pow ( z2, 2.0 ) ) /
2399  ( 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 ) +
2400  ( y1 * dot1 * pow ( x2, 2.0 ) * y2 ) /
2401  ( 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 ) +
2402  ( x1 * y1 * dot2 * x2 * y2 ) /
2403  ( 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 ) +
2404  ( pow ( x1, 2.0 ) * dot1 * y2 * pow ( z2, 3.0 ) ) /
2405  ( ( 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 ) ) +
2406  ( pow ( x1, 2.0 ) * dot1 * pow ( y2, 3.0 ) * z2 ) /
2407  ( ( 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 ) ) -
2408  ( pow ( x1, 2.0 ) * y1 * dot2 * pow ( y2, 2.0 ) * z2 ) /
2409  ( ( 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 ) ) -
2410  ( x1 * y1 * dot1 * x2 * pow ( y2, 2.0 ) * z2 ) /
2411  ( ( 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 ) ) +
2412  ( x1 * pow ( y1, 2.0 ) * dot2 * x2 * y2 * z2 ) /
2413  ( ( 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;
2414 
2415  //================================================ Set largest axis element to positive (ProSHADE standard)
2416  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) );
2417  const FloatingPoint< proshade_double > rhs1 ( std::abs ( solX ) );
2418  const FloatingPoint< proshade_double > rhs2 ( std::abs ( solY ) );
2419  const FloatingPoint< proshade_double > rhs3 ( std::abs ( solZ ) );
2420  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( solX < 0.0 ) ) ||
2421  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( solY < 0.0 ) ) ||
2422  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( solZ < 0.0 ) ) ) { solX *= -1.0; solY *= -1.0; solZ *= -1.0; }
2423 
2424  //================================================ Save solutions
2428 
2429  //================================================ Done
2430  return ( ret );
2431 
2432 }

◆ 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,
proshade_signed  verbose = 1 
)

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.
[in]verboseShould the warnings be printed? -1 if not.

Definition at line 1084 of file ProSHADE_maths.cpp.

1085 {
1086  //================================================ Initialise
1087  proshade_double angleTolerance = 0.01;
1088  proshade_double closeToZero = 0.0000001;
1089 
1090  //================================================ Find the angle
1091  *ang = std::acos ( ( std::max ( -1.0, std::min ( 3.0, rotMat[0] + rotMat[4] + rotMat[8] ) ) - 1.0 ) / 2.0 );
1092 
1093  //================================================ Any singularity?
1094  if ( std::abs ( std::sin ( *ang ) ) < angleTolerance )
1095  {
1096  //============================================ Initialise local variables
1097  char jobLeftEigs = 'N'; // This tells LAPACK not to compute left eigenvectors.
1098  char jobRightEigs = 'V'; // This tells LAPACK to compute right eigenvectors.
1099  int dim = 3; // The order of the matrix
1100  double* eigValReal = new double[dim]; // Real parts of the eigenvalues
1101  double* eigValImag = new double[dim]; // Imaginary parts of the eigenvalues
1102  double* leftEigVectors = new double[dim*dim*2]; // Left eigenvectors containing matrix
1103  double* rightEigVectors = new double[dim*dim*2]; // Right eigenvectors containing matrix
1104  double* work = new double[10*4*dim]; // Workspace. 4 * dim should be minimum, but more is better
1105  int workSize = 10*4*dim; // Saving the work array size for passing.
1106  int returnValue = 0; // This will tell if operation succeeded
1107 
1108  //============================================ Check memory allocation
1109  ProSHADE_internal_misc::checkMemoryAllocation ( eigValReal, __FILE__, __LINE__, __func__ );
1110  ProSHADE_internal_misc::checkMemoryAllocation ( eigValImag, __FILE__, __LINE__, __func__ );
1111  ProSHADE_internal_misc::checkMemoryAllocation ( leftEigVectors, __FILE__, __LINE__, __func__ );
1112  ProSHADE_internal_misc::checkMemoryAllocation ( rightEigVectors, __FILE__, __LINE__, __func__ );
1113  ProSHADE_internal_misc::checkMemoryAllocation ( work, __FILE__, __LINE__, __func__ );
1114 
1115  //============================================ Load input data into array in column-major order
1116  double* matrixToDecompose = new double[dim*dim];
1117  ProSHADE_internal_misc::checkMemoryAllocation ( matrixToDecompose, __FILE__, __LINE__, __func__ );
1118  for ( int rowIt = 0; rowIt < dim; rowIt++ )
1119  {
1120  for ( int colIt = 0; colIt < dim; colIt++ )
1121  {
1122  matrixToDecompose[(colIt*dim)+rowIt] = static_cast< double > ( rotMat[(rowIt*dim)+colIt] );
1123  }
1124  }
1125 
1126  //============================================ Run LAPACK ZGESDD
1127  dgeev_ ( &jobLeftEigs, &jobRightEigs, &dim, matrixToDecompose, &dim, eigValReal, eigValImag, leftEigVectors, &dim,
1128  rightEigVectors, &dim, work, &workSize, &returnValue );
1129 
1130  //============================================ Check for errors
1131  if ( returnValue != 0 )
1132  {
1133  //======================================== Report error and return zero values
1134  ProSHADE_internal_messages::printWarningMessage ( verbose, "!!! ProSHADE WARNING !!! Eigenval/Eigenvector algorithm did not converge.", "WS00069" );
1135  *x = 0.0;
1136  *y = 0.0;
1137  *z = 0.0;
1138 
1139  //======================================== Release memory
1140  delete[] eigValReal;
1141  delete[] eigValImag;
1142  delete[] leftEigVectors;
1143  delete[] rightEigVectors;
1144  delete[] work;
1145  delete[] matrixToDecompose;
1146 
1147  //======================================== Done
1148  return ;
1149  }
1150 
1151  //============================================ If values are close to zero, just set them to zero
1152  for ( int i = 0; i < 9; i++ ) { if ( std::abs(rightEigVectors[i]) < closeToZero ) { rightEigVectors[i] = 0.0; } }
1153  for ( int i = 0; i < 3; i++ ) { if ( std::abs(eigValReal[i]) < closeToZero ) { eigValReal[i] = 0.0; } if ( std::abs(eigValImag[i]) < closeToZero ) { eigValImag[i] = 0.0; } }
1154 
1155  //============================================ Find which eigenvalue is close to 1 and has imaginary part close to zero
1156  proshade_signed eigIt = -1;
1157  for ( size_t it = 0; it < 3; it++ )
1158  {
1159  if ( ( eigValReal[it] > ( 1.0 - closeToZero ) ) && ( eigValReal[it] < ( 1.0 + closeToZero ) ) )
1160  {
1161  if ( ( eigValImag[it] > ( 0.0 - closeToZero ) ) && ( eigValImag[it] < ( 0.0 + closeToZero ) ) )
1162  {
1163  eigIt = static_cast< proshade_signed > ( it );
1164  break;
1165  }
1166  }
1167  }
1168 
1169  //============================================ Any axis found?
1170  if ( eigIt == -1 )
1171  {
1172  ProSHADE_internal_messages::printWarningMessage ( verbose, "!!! ProSHADE WARNING !!! Failed to find eigenvalue with value 1 for this rotation matrix. Is this a rotation matrix?", "WS00072" );
1173  *x = 0.0;
1174  *y = 0.0;
1175  *z = 0.0;
1176  }
1177  else
1178  {
1179  //======================================== Parse LAPACK eigenvectors matrix
1180  int colIt;
1181  for( int rowIt = 0; rowIt < dim; rowIt++ )
1182  {
1183  colIt = 0;
1184  while( colIt < dim )
1185  {
1186  if( std::abs ( eigValImag[colIt] ) < closeToZero )
1187  {
1188  if ( colIt == eigIt ) { if ( rowIt == 0 ) { *x = rightEigVectors[rowIt+colIt*dim]; } if ( rowIt == 1 ) { *y = rightEigVectors[rowIt+colIt*dim]; } if ( rowIt == 2 ) { *z = rightEigVectors[rowIt+colIt*dim]; } }
1189  colIt++;
1190  }
1191  else
1192  {
1193 // In order to access the
1194 // std::cout << " ( " << rightEigVectors[rowIt+colIt*dim] << " + " << rightEigVectors[rowIt+(colIt+1)*dim] << " i )";
1195 // other eigenvectors, use this:
1196 // std::cout << " ( " << rightEigVectors[rowIt+colIt*dim] << " + " << -rightEigVectors[rowIt+(colIt+1)*dim] << " i )";
1197  colIt += 2;
1198  }
1199  }
1200  }
1201  }
1202 
1203  //============================================ Normalise axis length
1204  proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1205  *x /= normFactor;
1206  *y /= normFactor;
1207  *z /= normFactor;
1208 
1209 
1210  //============================================ Free memory
1211  delete[] eigValReal;
1212  delete[] eigValImag;
1213  delete[] leftEigVectors;
1214  delete[] rightEigVectors;
1215  delete[] work;
1216  delete[] matrixToDecompose;
1217  }
1218  else
1219  {
1220  //============================================= Axis
1221  *x = rotMat[7] - rotMat[5];
1222  *y = rotMat[2] - rotMat[6];
1223  *z = rotMat[3] - rotMat[1];
1224 
1225  proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1226  *x /= normFactor;
1227  *y /= normFactor;
1228  *z /= normFactor;
1229 
1230  //============================================= Make sure largest axis is positive
1231  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) );
1232  const FloatingPoint< proshade_double > rhs1 ( std::abs ( *x ) );
1233  const FloatingPoint< proshade_double > rhs2 ( std::abs ( *y ) );
1234  const FloatingPoint< proshade_double > rhs3 ( std::abs ( *z ) );
1235  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( *x < 0.0 ) ) ||
1236  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( *y < 0.0 ) ) ||
1237  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( *z < 0.0 ) ) )
1238  {
1239  *x *= -1.0;
1240  *y *= -1.0;
1241  *z *= -1.0;
1242  *ang *= -1.0;
1243  }
1244  }
1245 
1246  //================================================ Standardise angle to range 0 to 2pi
1247  if ( *ang < 0.0 ) { *ang = ( 2.0 * M_PI ) + *ang; }
1248 
1249  //================================================ Done
1250  return ;
1251 
1252 }

◆ 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,
proshade_signed  verbose = 1 
)

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.
[in]verboseShould the warnings be printed? -1 if not.

Definition at line 1267 of file ProSHADE_maths.cpp.

1268 {
1269  //================================================ Initialise
1270  proshade_double angleTolerance = 0.01;
1271  proshade_double closeToZero = 0.0000001;
1272 
1273  //================================================ Find the angle
1274  *ang = std::acos ( ( std::max ( -1.0, std::min ( 3.0, rotMat->at(0) + rotMat->at(4) + rotMat->at(8) ) ) - 1.0 ) / 2.0 );
1275 
1276  //================================================ Any singularity?
1277  if ( std::abs ( std::sin ( *ang ) ) < angleTolerance )
1278  {
1279  //============================================ Initialise local variables
1280  char jobLeftEigs = 'N'; // This tells LAPACK not to compute left eigenvectors.
1281  char jobRightEigs = 'V'; // This tells LAPACK to compute right eigenvectors.
1282  int dim = 3; // The order of the matrix
1283  double* eigValReal = new double[dim]; // Real parts of the eigenvalues
1284  double* eigValImag = new double[dim]; // Imaginary parts of the eigenvalues
1285  double* leftEigVectors = new double[dim*dim*2]; // Left eigenvectors containing matrix
1286  double* rightEigVectors = new double[dim*dim*2]; // Right eigenvectors containing matrix
1287  double* work = new double[10*4*dim]; // Workspace. 4 * dim should be minimum, but more is better
1288  int workSize = 10*4*dim; // Saving the work array size for passing.
1289  int returnValue = 0; // This will tell if operation succeeded
1290 
1291  //============================================ Check memory allocation
1292  ProSHADE_internal_misc::checkMemoryAllocation ( eigValReal, __FILE__, __LINE__, __func__ );
1293  ProSHADE_internal_misc::checkMemoryAllocation ( eigValImag, __FILE__, __LINE__, __func__ );
1294  ProSHADE_internal_misc::checkMemoryAllocation ( leftEigVectors, __FILE__, __LINE__, __func__ );
1295  ProSHADE_internal_misc::checkMemoryAllocation ( rightEigVectors, __FILE__, __LINE__, __func__ );
1296  ProSHADE_internal_misc::checkMemoryAllocation ( work, __FILE__, __LINE__, __func__ );
1297 
1298  //============================================ Load input data into array in column-major order
1299  double* matrixToDecompose = new double[dim*dim];
1300  ProSHADE_internal_misc::checkMemoryAllocation ( matrixToDecompose, __FILE__, __LINE__, __func__ );
1301  for ( int rowIt = 0; rowIt < dim; rowIt++ )
1302  {
1303  for ( int colIt = 0; colIt < dim; colIt++ )
1304  {
1305  matrixToDecompose[(colIt*dim)+rowIt] = static_cast< double > ( rotMat->at( static_cast< size_t > ( ( rowIt * dim ) + colIt ) ) );
1306  }
1307  }
1308 
1309  //============================================ Run LAPACK ZGESDD
1310  dgeev_ ( &jobLeftEigs, &jobRightEigs, &dim, matrixToDecompose, &dim, eigValReal, eigValImag, leftEigVectors, &dim,
1311  rightEigVectors, &dim, work, &workSize, &returnValue );
1312 
1313  //============================================ Check for errors
1314  if ( returnValue != 0 )
1315  {
1316  //======================================== Report error and return zero values
1317  ProSHADE_internal_messages::printWarningMessage ( verbose, "!!! ProSHADE WARNING !!! Eigenval/Eigenvector algorithm did not converge.", "WS00069" );
1318  *x = 0.0;
1319  *y = 0.0;
1320  *z = 0.0;
1321 
1322  //======================================== Release memory
1323  delete[] eigValReal;
1324  delete[] eigValImag;
1325  delete[] leftEigVectors;
1326  delete[] rightEigVectors;
1327  delete[] work;
1328  delete[] matrixToDecompose;
1329 
1330  //======================================== Done
1331  return ;
1332  }
1333 
1334  //============================================ If values are close to zero, just set them to zero
1335  for ( int i = 0; i < 9; i++ ) { if ( std::abs(rightEigVectors[i]) < closeToZero ) { rightEigVectors[i] = 0.0; } }
1336  for ( int i = 0; i < 3; i++ ) { if ( std::abs(eigValReal[i]) < closeToZero ) { eigValReal[i] = 0.0; } if ( std::abs(eigValImag[i]) < closeToZero ) { eigValImag[i] = 0.0; } }
1337 
1338  //============================================ Find which eigenvalue is close to 1 and has imaginary part close to zero
1339  proshade_signed eigIt = -1;
1340  for ( size_t it = 0; it < 3; it++ )
1341  {
1342  if ( ( eigValReal[it] > ( 1.0 - closeToZero ) ) && ( eigValReal[it] < ( 1.0 + closeToZero ) ) )
1343  {
1344  if ( ( eigValImag[it] > ( 0.0 - closeToZero ) ) && ( eigValImag[it] < ( 0.0 + closeToZero ) ) )
1345  {
1346  eigIt = static_cast< proshade_signed > ( it );
1347  break;
1348  }
1349  }
1350  }
1351 
1352  //============================================ Any axis found?
1353  if ( eigIt == -1 )
1354  {
1355  ProSHADE_internal_messages::printWarningMessage ( verbose, "!!! ProSHADE WARNING !!! Failed to find eigenvalue with value 1 for this rotation matrix. Is this a rotation matrix?", "WS00072" );
1356  *x = 0.0;
1357  *y = 0.0;
1358  *z = 0.0;
1359  }
1360  else
1361  {
1362  //======================================== Parse LAPACK eigenvectors matrix
1363  int colIt;
1364  for( int rowIt = 0; rowIt < dim; rowIt++ )
1365  {
1366  colIt = 0;
1367  while( colIt < dim )
1368  {
1369  if( std::abs ( eigValImag[colIt] ) < closeToZero )
1370  {
1371  if ( colIt == eigIt ) { if ( rowIt == 0 ) { *x = rightEigVectors[rowIt+colIt*dim]; } if ( rowIt == 1 ) { *y = rightEigVectors[rowIt+colIt*dim]; } if ( rowIt == 2 ) { *z = rightEigVectors[rowIt+colIt*dim]; } }
1372  colIt++;
1373  }
1374  else
1375  {
1376 // In order to access the
1377 // std::cout << " ( " << rightEigVectors[rowIt+colIt*dim] << " + " << rightEigVectors[rowIt+(colIt+1)*dim] << " i )";
1378 // other eigenvectors, use this:
1379 // std::cout << " ( " << rightEigVectors[rowIt+colIt*dim] << " + " << -rightEigVectors[rowIt+(colIt+1)*dim] << " i )";
1380  colIt += 2;
1381  }
1382  }
1383  }
1384  }
1385 
1386  //============================================ Normalise axis length
1387  proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1388  *x /= normFactor;
1389  *y /= normFactor;
1390  *z /= normFactor;
1391 
1392  //============================================= Make sure largest axis is positive
1393  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) );
1394  const FloatingPoint< proshade_double > rhs1 ( std::abs ( *x ) );
1395  const FloatingPoint< proshade_double > rhs2 ( std::abs ( *y ) );
1396  const FloatingPoint< proshade_double > rhs3 ( std::abs ( *z ) );
1397  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( *x < 0.0 ) ) ||
1398  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( *y < 0.0 ) ) ||
1399  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( *z < 0.0 ) ) )
1400  {
1401  *x *= -1.0;
1402  *y *= -1.0;
1403  *z *= -1.0;
1404  *ang *= -1.0;
1405  }
1406 
1407  //================================================ Free memory
1408  delete[] eigValReal;
1409  delete[] eigValImag;
1410  delete[] leftEigVectors;
1411  delete[] rightEigVectors;
1412  delete[] work;
1413  delete[] matrixToDecompose;
1414  }
1415  else
1416  {
1417  //============================================= Axis
1418  *x = rotMat->at(7) - rotMat->at(5);
1419  *y = rotMat->at(2) - rotMat->at(6);
1420  *z = rotMat->at(3) - rotMat->at(1);
1421 
1422  proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1423  *x /= normFactor;
1424  *y /= normFactor;
1425  *z /= normFactor;
1426 
1427  //============================================= Make sure largest axis is positive
1428  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) );
1429  const FloatingPoint< proshade_double > rhs1 ( std::abs ( *x ) );
1430  const FloatingPoint< proshade_double > rhs2 ( std::abs ( *y ) );
1431  const FloatingPoint< proshade_double > rhs3 ( std::abs ( *z ) );
1432  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( *x < 0.0 ) ) ||
1433  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( *y < 0.0 ) ) ||
1434  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( *z < 0.0 ) ) )
1435  {
1436  *x *= -1.0;
1437  *y *= -1.0;
1438  *z *= -1.0;
1439  *ang *= -1.0;
1440  }
1441  }
1442 
1443  //================================================ Standardise angle to range 0 to 2pi
1444  if ( *ang < 0.0 ) { *ang = ( 2.0 * M_PI ) + *ang; }
1445 
1446  //================================================ Done
1447  return ;
1448 
1449 }

◆ 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 1613 of file ProSHADE_maths.cpp.

1614 {
1615  //================================================ If angle is 0 or infinity (anything divided by 0), return no rotation
1616  if ( ( axAng == 0.0 ) || ( std::isinf ( axAng ) ) )
1617  {
1618  //============================================ Return 0 ; 0 ; 0 for no angle
1619  *eA = 0.0;
1620  *eB = 0.0;
1621  *eG = 0.0;
1622 
1623  //============================================ Done
1624  return ;
1625  }
1626 
1627  //================================================ Compute required rotation matrix elements
1628  proshade_double cAng = std::cos ( axAng );
1629  proshade_double sAng = std::sin ( axAng );
1630  proshade_double tAng = 1.0 - cAng;
1631 
1632  proshade_double element22 = cAng + axZ * axZ * tAng;
1633 
1634  proshade_double tmp1 = axX * axZ * tAng;
1635  proshade_double tmp2 = axY * sAng;
1636  proshade_double element20 = tmp1 - tmp2;
1637  proshade_double element02 = tmp1 + tmp2;
1638 
1639  tmp1 = axY * axZ * tAng;
1640  tmp2 = axX * sAng;
1641  proshade_double element21 = tmp1 + tmp2;
1642  proshade_double element12 = tmp1 - tmp2;
1643 
1644  //================================================ Convert to Eulers
1645  if ( std::abs( element22 ) <= 0.99999 )
1646  {
1647  //============================================ This case occurs when there is no singularity in the rotation matrix (i.e. it does not have 0 or 180 degrees angle)
1648  *eA = std::atan2 ( element21, element20 );
1649  *eB = std::acos ( element22 );
1650  *eG = std::atan2 ( element12, -element02 );
1651  }
1652  else
1653  {
1654  //============================================ Compute some extra rotation matrix elements
1655  tmp1 = axX * axY * tAng;
1656  tmp2 = axZ * sAng;
1657  proshade_double element10 = tmp1 + tmp2;
1658  proshade_double element00 = cAng + axX * axX * tAng;
1659 
1660  //============================================ This case occurs when there is either 0 or 180 degrees rotation angle in the rotation matrix and therefore when beta is zero.
1661  if ( element22 >= 0.99999 )
1662  {
1663  //======================================== 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.
1664  *eA = std::atan2 ( element10, element00 );
1665  *eB = 0.0;
1666  *eG = 0.0;
1667  }
1668  if ( element22 <= -0.99999 )
1669  {
1670  //======================================== 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.
1671  *eA = std::atan2 ( element10, element00 );
1672  *eB = M_PI;
1673  *eG = 0.0;
1674  }
1675  }
1676 
1677  //================================================ Get the angles to proper range
1678  if ( *eA < 0.0 ) { *eA = 2.0 * M_PI + *eA; }
1679  if ( *eB < 0.0 ) { *eB = M_PI + *eB; }
1680  if ( *eG < 0.0 ) { *eG = 2.0 * M_PI + *eG; }
1681 
1682  //================================================ Done
1683  return ;
1684 
1685 }

◆ 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 1562 of file ProSHADE_maths.cpp.

1563 {
1564  //================================================ Convert to Eulers
1565  if ( std::abs( rotMat[8] ) < 0.99999 )
1566  {
1567  //============================================ This case occurs when there is no singularity in the rotation matrix (i.e. it does not have 0 or 180 degrees angle)
1568  *eA = std::atan2 ( rotMat[7], rotMat[6] );
1569  *eB = std::acos ( rotMat[8] );
1570  *eG = std::atan2 ( rotMat[5], -rotMat[2] );
1571  }
1572  else
1573  {
1574  //============================================ This case occurs when there is either 0 or 180 degrees rotation angle in the rotation matrix and therefore when beta is zero.
1575  if ( rotMat[8] >= 0.99999 )
1576  {
1577  //======================================== 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.
1578  *eA = std::atan2 ( rotMat[3], rotMat[0] );
1579  *eB = 0.0;
1580  *eG = 0.0;
1581  }
1582  if ( rotMat[8] <= -0.99999 )
1583  {
1584  //======================================== 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.
1585  *eA = std::atan2 ( rotMat[3], rotMat[0] );
1586  *eB = M_PI;
1587  *eG = 0.0;
1588  }
1589  }
1590 
1591  //================================================ Get the angles to proper range
1592  if ( *eA < 0.0 ) { *eA = 2.0 * M_PI + *eA; }
1593  if ( *eB < 0.0 ) { *eB = M_PI + *eB; }
1594  if ( *eG < 0.0 ) { *eG = 2.0 * M_PI + *eG; }
1595 
1596  //================================================ Done
1597  return ;
1598 
1599 }

◆ 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 3165 of file ProSHADE_maths.cpp.

3166 {
3167  //================================================ Compute volume and proportions
3168  proshade_single vol = ( xDim * yDim * zDim );
3169  proshade_single sa = ( yDim * zDim ) / vol;
3170  proshade_single sb = ( xDim * zDim ) / vol;
3171  proshade_single sc = ( xDim * yDim ) / vol;
3172 
3173  //================================================ Compute distance
3174  proshade_single s2 = ( std::pow ( h * sa, 2.0f ) +
3175  std::pow ( k * sb, 2.0f ) +
3176  std::pow ( l * sc, 2.0f ) ) / 4.0f;
3177 
3178  //================================================ Deal with F000
3179  if ( s2 == 0.0f ) { s2 = 0.0000000001f; }
3180 
3181  //================================================ Done
3182  return ( 1.0f / ( 2.0f * std::sqrt ( s2 ) ) );
3183 
3184 }

◆ 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 1459 of file ProSHADE_maths.cpp.

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

◆ 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 1511 of file ProSHADE_maths.cpp.

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

◆ 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 1020 of file ProSHADE_maths.cpp.

1021 {
1022  //================================================ First row
1023  matrix[0] = cos ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) - sin ( eulerAlpha ) * sin ( eulerGamma );
1024  matrix[1] = sin ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) + cos ( eulerAlpha ) * sin ( eulerGamma );
1025  matrix[2] = -sin ( eulerBeta ) * cos ( eulerGamma );
1026 
1027  //================================================ Second row
1028  matrix[3] = -cos ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) - sin ( eulerAlpha ) * cos ( eulerGamma );
1029  matrix[4] = -sin ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) + cos ( eulerAlpha ) * cos ( eulerGamma );
1030  matrix[5] = sin ( eulerBeta ) * sin ( eulerGamma );
1031 
1032  //================================================ Third row
1033  matrix[6] = cos ( eulerAlpha ) * sin ( eulerBeta );
1034  matrix[7] = sin ( eulerAlpha ) * sin ( eulerBeta );
1035  matrix[8] = cos ( eulerBeta );
1036 
1037  //================================================ Done
1038  return ;
1039 
1040 }

◆ 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 1049 of file ProSHADE_maths.cpp.

1050 {
1051  //================================================ First row
1052  matrix[0] = cos ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) - sin ( eulerAlpha ) * sin ( eulerGamma );
1053  matrix[1] = sin ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) + cos ( eulerAlpha ) * sin ( eulerGamma );
1054  matrix[2] = -sin ( eulerBeta ) * cos ( eulerGamma );
1055 
1056  //================================================ Second row
1057  matrix[3] = -cos ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) - sin ( eulerAlpha ) * cos ( eulerGamma );
1058  matrix[4] = -sin ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) + cos ( eulerAlpha ) * cos ( eulerGamma );
1059  matrix[5] = sin ( eulerBeta ) * sin ( eulerGamma );
1060 
1061  //================================================ Third row
1062  matrix[6] = cos ( eulerAlpha ) * sin ( eulerBeta );
1063  matrix[7] = sin ( eulerAlpha ) * sin ( eulerBeta );
1064  matrix[8] = cos ( eulerBeta );
1065 
1066  //================================================ Done
1067  return ;
1068 
1069 }

◆ 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 * static_cast<proshade_double> ( band ) * 2.0 ) / M_PI;
992  *y = ( eulerGamma * static_cast<proshade_double> ( band ) ) / M_PI;
993  *z = ( eulerAlpha * static_cast<proshade_double> ( band ) ) / M_PI;
994 
995  //================================================ Deal with singularities
996  if ( eulerBeta > ( M_PI - 0.05 ) )
997  {
998  //============================================ Rotation is 180 deg
999  *z = ( ( eulerAlpha - eulerGamma ) * static_cast<proshade_double> ( band ) ) / M_PI;
1000  *y = 0;
1001  }
1002 
1003  //================================================ Keep value within boundaries, but do not repeat over them!
1004  if ( *x >= ( 2 * band ) ) { *x = ( 2 * band ) - 1; }
1005  if ( *y >= ( 2 * band ) ) { *y = ( 2 * band ) - 1; }
1006  if ( *z >= ( 2 * band ) ) { *z = ( 2 * band ) - 1; }
1007 
1008  //================================================ Done
1009  return ;
1010 
1011 }

◆ 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 2974 of file ProSHADE_maths.cpp.

2975 {
2976  //================================================ Initialise variables
2977  bool ret = true;
2978  proshade_unsign whichImprove = 0;
2979 
2980  //================================================ For each already detected member
2981  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
2982  {
2983  //============================================ Is fold the same?
2984  const FloatingPoint< proshade_double > lhs ( CSymList->at(grIt)[0] ), rhs ( axis[0] );
2985  if ( lhs.AlmostEquals ( rhs ) )
2986  {
2987  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], axis[1], axis[2], axis[3], tolerance ) )
2988  {
2989  ret = false;
2990  whichImprove = grIt;
2991  break;
2992  }
2993  }
2994  }
2995 
2996  //================================================ Improve, if required
2997  if ( improve && !ret )
2998  {
2999  if ( axis[5] > CSymList->at(whichImprove)[5] )
3000  {
3001  CSymList->at(whichImprove)[1] = axis[1];
3002  CSymList->at(whichImprove)[2] = axis[2];
3003  CSymList->at(whichImprove)[3] = axis[3];
3004  CSymList->at(whichImprove)[4] = axis[4];
3005  CSymList->at(whichImprove)[5] = axis[5];
3006  }
3007  }
3008 
3009  //================================================ Done
3010  return ( ret );
3011 
3012 }

◆ 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 3026 of file ProSHADE_maths.cpp.

3027 {
3028  //================================================ Initialise variables
3029  bool ret = true;
3030 
3031  //================================================ For each already detected member
3032  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
3033  {
3034  const FloatingPoint< proshade_double > lhs ( fold ), rhs ( CSymList->at(grIt)[0] );
3035  if ( lhs.AlmostEquals ( rhs ) )
3036  {
3037  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], X, Y, Z, tolerance ) )
3038  {
3039  ret = false;
3040  break;
3041  }
3042  }
3043  }
3044 
3045  //================================================ Done
3046  return ( ret );
3047 
3048 }

◆ 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 2499 of file ProSHADE_maths.cpp.

2500 {
2501  //================================================ Initialise variables
2502  std::vector< proshade_double > ret;
2503 
2504  //================================================ Compute
2505  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(0) ) +
2506  ( el1->at(1) * el2->at(3) ) +
2507  ( el1->at(2) * el2->at(6) ) );
2508  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(1) ) +
2509  ( el1->at(1) * el2->at(4) ) +
2510  ( el1->at(2) * el2->at(7) ) );
2511  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(2) ) +
2512  ( el1->at(1) * el2->at(5) ) +
2513  ( el1->at(2) * el2->at(8) ) );
2514 
2515  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(0) ) +
2516  ( el1->at(4) * el2->at(3) ) +
2517  ( el1->at(5) * el2->at(6) ) );
2518  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(1) ) +
2519  ( el1->at(4) * el2->at(4) ) +
2520  ( el1->at(5) * el2->at(7) ) );
2521  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(2) ) +
2522  ( el1->at(4) * el2->at(5) ) +
2523  ( el1->at(5) * el2->at(8) ) );
2524 
2525  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(0) ) +
2526  ( el1->at(7) * el2->at(3) ) +
2527  ( el1->at(8) * el2->at(6) ) );
2528  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(1) ) +
2529  ( el1->at(7) * el2->at(4) ) +
2530  ( el1->at(8) * el2->at(7) ) );
2531  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(2) ) +
2532  ( el1->at(7) * el2->at(5) ) +
2533  ( el1->at(8) * el2->at(8) ) );
2534 
2535  //================================================ Done
2536  return ( ret );
2537 
2538 }

◆ 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 1696 of file ProSHADE_maths.cpp.

1697 {
1698  //================================================ Set res to 0.0s
1699  for ( proshade_unsign iter = 0; iter < 9; iter++ ) { res[iter] = 0.0; }
1700 
1701  //================================================ Compute the matrix multiplication
1702  for ( proshade_unsign row = 0; row < dim; row++ )
1703  {
1704  for ( proshade_unsign col = 0; col < dim; col++ )
1705  {
1706  for ( proshade_unsign inner = 0; inner < dim; inner++ )
1707  {
1708  res[(row*dim)+col] += A[(inner*dim)+row] * B[(col*dim)+inner];
1709  }
1710  }
1711  }
1712 
1713  //================================================ Done
1714  return ;
1715 
1716 }

◆ 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 1771 of file ProSHADE_maths.cpp.

1772 {
1773  //================================================ Compute and return
1774  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) ) );
1775 
1776 }

◆ 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 2653 of file ProSHADE_maths.cpp.

2654 {
2655  //================================================ Initialise variables
2656  proshade_double lonM, lonP, latM, latP, movSum;
2657  std::vector<proshade_double> latVals ( 3 );
2658  std::vector<proshade_double> lonVals ( 3 );
2659  proshade_double learningRate = 0.1;
2660  proshade_double prevVal = *bestSum;
2661  proshade_double valChange = 999.9;
2662  proshade_double origBestLat = std::round ( *bestLattitude );
2663  proshade_double origBestLon = std::round ( *bestLongitude );
2664  proshade_double tmpVal;
2665 
2666  //================================================ Initialise interpolators in all directions around the point of interest
2667  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsMinusMinus;
2668  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsMinusPlus;
2669  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsPlusMinus;
2670  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsPlusPlus;
2671  prepareBiCubicInterpolatorsMinusMinus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsMinusMinus, sphereMappedRotFun );
2672  prepareBiCubicInterpolatorsMinusPlus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsMinusPlus, sphereMappedRotFun );
2673  prepareBiCubicInterpolatorsPlusMinus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsPlusMinus, sphereMappedRotFun );
2674  prepareBiCubicInterpolatorsPlusPlus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsPlusPlus, sphereMappedRotFun );
2675 
2676  //================================================ Start the pseudo gradient ascent (while there is some change)
2677  while ( valChange > 0.0001 )
2678  {
2679  //============================================ Find the surrounding points to the currently best position
2680  lonM = *bestLongitude - step;
2681  lonP = *bestLongitude + step;
2682  latM = *bestLattitude - step;
2683  latP = *bestLattitude + step;
2684 
2685  //============================================ Deal with optimising outside of prepared range - recursion
2686  const FloatingPoint< proshade_double > lhs1 ( *bestLattitude ), rhs1 ( origBestLat - 1.0 );
2687  const FloatingPoint< proshade_double > lhs2 ( *bestLattitude ), rhs2 ( origBestLat + 1.0 );
2688  const FloatingPoint< proshade_double > lhs3 ( *bestLongitude ), rhs3 ( origBestLon - 1.0 );
2689  const FloatingPoint< proshade_double > lhs4 ( *bestLongitude ), rhs4 ( origBestLon + 1.0 );
2690  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; }
2691  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; }
2692  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; }
2693  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; }
2694 
2695  //============================================ Prepare vectors of tested positions
2696  latVals.at(0) = latM; latVals.at(1) = *bestLattitude; latVals.at(2) = latP;
2697  lonVals.at(0) = lonM; lonVals.at(1) = *bestLongitude; lonVals.at(2) = lonP;
2698 
2699  //============================================ Find the best change
2700  for ( proshade_unsign laIt = 0; laIt < static_cast<proshade_unsign> ( latVals.size() ); laIt++ )
2701  {
2702  for ( proshade_unsign loIt = 0; loIt < static_cast<proshade_unsign> ( lonVals.size() ); loIt++ )
2703  {
2704  //==================================== For this combination of lat and lon, find sum over spheres
2705  movSum = 1.0;
2706  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sphereList->size() ); iter++ )
2707  {
2708  //================================ Interpolate using correct interpolators
2709  if ( ( latVals.at(laIt) <= origBestLat ) && ( lonVals.at(loIt) <= origBestLon ) ) { movSum += interpolsMinusMinus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2710  if ( ( latVals.at(laIt) <= origBestLat ) && ( lonVals.at(loIt) > origBestLon ) ) { movSum += interpolsMinusPlus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2711  if ( ( latVals.at(laIt) > origBestLat ) && ( lonVals.at(loIt) <= origBestLon ) ) { movSum += interpolsPlusMinus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2712  if ( ( latVals.at(laIt) > origBestLat ) && ( lonVals.at(loIt) > origBestLon ) ) { movSum += interpolsPlusPlus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2713  }
2714 
2715  //==================================== If position has improved, save it
2716  if ( *bestSum < movSum )
2717  {
2718  *bestSum = movSum;
2719  *bestLongitude = lonVals.at(loIt);
2720  *bestLattitude = latVals.at(laIt);
2721  }
2722  }
2723  }
2724 
2725  //============================================ Prepare for next iteration
2726  valChange = std::floor ( 100000.0 * ( *bestSum - prevVal ) ) / 100000.0;
2727  prevVal = std::floor ( 100000.0 * ( *bestSum ) ) / 100000.0;
2728  step = std::max ( ( valChange / step ) * learningRate, 0.01 );
2729  if ( learningRate >= 0.02 ) { learningRate -= 0.01; }
2730 
2731  }
2732 
2733  //================================================ Release interpolators memory
2734  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsMinusMinus.size() ); intIt++ ) { delete interpolsMinusMinus.at(intIt); }
2735  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsMinusPlus.size() ); intIt++ ) { delete interpolsMinusPlus.at(intIt); }
2736  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsPlusMinus.size() ); intIt++ ) { delete interpolsPlusMinus.at(intIt); }
2737  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsPlusPlus.size() ); intIt++ ) { delete interpolsPlusPlus.at(intIt); }
2738 
2739  //================================================ Done
2740  return ;
2741 }

◆ 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 2754 of file ProSHADE_maths.cpp.

2755 {
2756  //================================================ Initialise local variables
2757  proshade_signed latHlp, lonHlp;
2758  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2759 
2760  //================================================ Prepare the interpolator objects for interpolation around the position
2761  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2762  {
2763  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2764  proshade_double** interpGrid = new proshade_double*[4];
2765  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2766 
2767  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2768  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2769  {
2770  interpGrid[iter] = new proshade_double[4];
2771  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2772  }
2773 
2774  //============================================ Fill in the value grid on which the interpolation is to be done
2775  for ( proshade_signed latIt = 0; latIt < 4; latIt++ )
2776  {
2777  for ( proshade_signed lonIt = 0; lonIt < 4; lonIt++ )
2778  {
2779  latHlp = static_cast< proshade_signed > ( bestLattitude - 2.0 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2780  lonHlp = static_cast< proshade_signed > ( bestLongitude - 2.0 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2781  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
2782  }
2783  }
2784 
2785  //============================================ Create the interpolators
2786  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude - 1.0, bestLongitude - 1.0 );
2787  interpols->emplace_back ( biCubInterp );
2788 
2789  //============================================ Release memory
2790  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2791  delete[] interpGrid;
2792  }
2793 
2794  //================================================ Done
2795  return ;
2796 }

◆ 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 2809 of file ProSHADE_maths.cpp.

2810 {
2811  //================================================ Initialise local variables
2812  proshade_signed latHlp, lonHlp;
2813  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2814 
2815  //================================================ Prepare the interpolator objects for interpolation around the position
2816  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2817  {
2818  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2819  proshade_double** interpGrid = new proshade_double*[4];
2820  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2821 
2822  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2823  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2824  {
2825  interpGrid[iter] = new proshade_double[4];
2826  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2827  }
2828 
2829  //============================================ Fill in the value grid on which the interpolation is to be done
2830  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2831  {
2832  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2833  {
2834  latHlp = static_cast< proshade_signed > ( bestLattitude - 2 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2835  lonHlp = static_cast< proshade_signed > ( bestLongitude - 1 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2836  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ) , static_cast< proshade_unsign > ( lonHlp ) );
2837  }
2838  }
2839 
2840  //============================================ Create the interpolators
2841  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude - 1.0, bestLongitude );
2842  interpols->emplace_back ( biCubInterp );
2843 
2844  //============================================ Release memory
2845  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2846  delete[] interpGrid;
2847  }
2848 
2849  //================================================ Done
2850  return ;
2851 }

◆ 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 2864 of file ProSHADE_maths.cpp.

2865 {
2866  //================================================ Initialise local variables
2867  proshade_signed latHlp, lonHlp;
2868  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2869 
2870  //================================================ Prepare the interpolator objects for interpolation around the position
2871  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2872  {
2873  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2874  proshade_double** interpGrid = new proshade_double*[4];
2875  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2876 
2877  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2878  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2879  {
2880  interpGrid[iter] = new proshade_double[4];
2881  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2882  }
2883 
2884  //============================================ Fill in the value grid on which the interpolation is to be done
2885  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2886  {
2887  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2888  {
2889  latHlp = static_cast< proshade_signed > ( bestLattitude - 1 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2890  lonHlp = static_cast< proshade_signed > ( bestLongitude - 2 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2891  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
2892  }
2893  }
2894 
2895  //============================================ Create the interpolators
2896  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude, bestLongitude - 1.0 );
2897  interpols->emplace_back ( biCubInterp );
2898 
2899  //============================================ Release memory
2900  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2901  delete[] interpGrid;
2902  }
2903 
2904  //================================================ Done
2905  return ;
2906 }

◆ 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 2919 of file ProSHADE_maths.cpp.

2920 {
2921  //================================================ Initialise local variables
2922  proshade_signed latHlp, lonHlp;
2923  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2924 
2925  //================================================ Prepare the interpolator objects for interpolation around the position
2926  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2927  {
2928  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2929  proshade_double** interpGrid = new proshade_double*[4];
2930  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2931 
2932  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2933  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2934  {
2935  interpGrid[iter] = new proshade_double[4];
2936  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2937  }
2938 
2939  //============================================ Fill in the value grid on which the interpolation is to be done
2940  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2941  {
2942  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2943  {
2944  latHlp = static_cast< proshade_signed > ( bestLattitude - 1 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2945  lonHlp = static_cast< proshade_signed > ( bestLongitude - 1 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2946  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
2947  }
2948  }
2949 
2950  //============================================ Create the interpolators
2951  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude, bestLongitude );
2952  interpols->emplace_back ( biCubInterp );
2953 
2954  //============================================ Release memory
2955  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2956  delete[] interpGrid;
2957  }
2958 
2959  //================================================ Done
2960  return ;
2961 }

◆ 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 1722 of file ProSHADE_maths.cpp.

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

◆ realMatrixSVDUandVOnly()

void ProSHADE_internal_maths::realMatrixSVDUandVOnly ( 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  double *rotMatU = new double [dim*dim]; // The U matrix space
877  double *rotMatV = new double [dim*dim]; // The V^T matrix space
878  double *work = new double [static_cast< proshade_unsign >( ( 3 * dim ) + pow( dim, 2 ) * dim)]; // Workspace, minimum required is 4*dim^2 + 7*dim, using more for performance
879  int workDim = static_cast< int > ( 2 * ( ( 4 * dim * dim ) + ( 7 * dim ) ) ); // 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  double *matrixToDecompose = new 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] = mat[(rowIt*dim)+colIt];
898  }
899  }
900 
901  //================================================ Run LAPACK ZGESDD
902  dgesdd_ ( &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];
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];
938  }
939  }
940 
941  //================================================ Release the rest of the memory
942  delete[] rotMatU;
943  delete[] rotMatV;
944 
945  //================================================ Done
946  return ;
947 
948 }

◆ 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 2552 of file ProSHADE_maths.cpp.

2553 {
2554  //================================================ Initialise variables
2555  bool ret = false;
2556 
2557  //================================================ Compute trace of mat1 * mat2^T
2558  proshade_double trace = ( mat1->at(0) * mat2->at(0) ) + ( mat1->at(1) * mat2->at(1) ) + ( mat1->at(2) * mat2->at(2) );
2559  trace += ( mat1->at(3) * mat2->at(3) ) + ( mat1->at(4) * mat2->at(4) ) + ( mat1->at(5) * mat2->at(5) );
2560  trace += ( mat1->at(6) * mat2->at(6) ) + ( mat1->at(7) * mat2->at(7) ) + ( mat1->at(8) * mat2->at(8) );
2561 
2562  //================================================ Subtract 3 (so that we would have 0 in case of idenity matrix)
2563  trace -= 3.0;
2564 
2565  //================================================ Compare to tolerance
2566  if ( tolerance > std::abs ( trace ) ) { ret = true; }
2567 
2568  //================================================ Done
2569  return ( ret );
2570 
2571 }

◆ 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 3129 of file ProSHADE_maths.cpp.

3130 {
3131  //================================================ Initialise local variables
3132  proshade_signed windowHalf = ( windowSize - 1 ) / 2;
3133  proshade_signed totSize = static_cast< proshade_signed > ( ( 1.0 / step ) + 1 );
3134  std::vector< proshade_double > smoothened ( static_cast< size_t > ( totSize - ( windowSize - 1 ) ), 0.0 );
3135  std::vector< proshade_double > winWeights ( static_cast< size_t > ( windowSize ), 0.0 );
3136 
3137  //================================================ Prepare window weights
3138  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 ); }
3139 
3140  //================================================ Compute smoothened data
3141  for ( proshade_unsign it = 0; it < static_cast< proshade_unsign > ( smoothened.size() ); it++ )
3142  {
3143  //============================================ Compute window weighted average
3144  for ( proshade_signed winIt = 0; winIt < windowSize; winIt++ )
3145  {
3146  smoothened.at(it) += winWeights.at( static_cast< size_t > ( winIt ) ) * data.at( static_cast< size_t > ( static_cast< proshade_signed > ( it ) + winIt ) );
3147  }
3148  }
3149 
3150  //================================================ Done
3151  return ( smoothened );
3152 
3153 }

◆ transpose3x3MatrixInPlace()

void ProSHADE_internal_maths::transpose3x3MatrixInPlace ( proshade_double *  mat)

Transposes 3x3 matrix in place.

Parameters
[in]matThe matrix to be transposed.

Definition at line 1976 of file ProSHADE_maths.cpp.

1977 {
1978  //================================================ Initialise variables
1979  proshade_double tmp;
1980 
1981  //================================================ Transpose the non-diagonal values
1982  tmp = mat[1];
1983  mat[1] = mat[3];
1984  mat[3] = tmp;
1985 
1986  tmp = mat[2];
1987  mat[2] = mat[6];
1988  mat[6] = tmp;
1989 
1990  tmp = mat[5];
1991  mat[5] = mat[7];
1992  mat[7] = tmp;
1993 
1994  //================================================ Done
1995  return ;
1996 
1997 }

◆ 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 2589 of file ProSHADE_maths.cpp.

2590 {
2591  //================================================ Initialise variables
2592  bool ret = false;
2593 
2594  //================================================ Cosine distance
2595  proshade_double cosDist = ( ( a1 * b1 ) + ( a2 * b2 ) + ( a3 * b3 ) ) /
2596  ( sqrt( pow( a1, 2.0 ) + pow( a2, 2.0 ) + pow( a3, 2.0 ) ) *
2597  sqrt( pow( b1, 2.0 ) + pow( b2, 2.0 ) + pow( b3, 2.0 ) ) );
2598 
2599  //================================================ Compare the absolute value of distance to 1.0 - tolerance
2600  if ( std::abs( cosDist ) > ( 1.0 - tolerance ) ) { ret = true; }
2601 
2602  //================================================ Done
2603  return ( ret );
2604 
2605 }

◆ 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 2623 of file ProSHADE_maths.cpp.

2624 {
2625  //================================================ Initialise variables
2626  bool ret = false;
2627 
2628  //================================================ Cosine distance
2629  proshade_double cosDist = ( ( a1 * b1 ) + ( a2 * b2 ) + ( a3 * b3 ) ) /
2630  ( sqrt( pow( a1, 2.0 ) + pow( a2, 2.0 ) + pow( a3, 2.0 ) ) *
2631  sqrt( pow( b1, 2.0 ) + pow( b2, 2.0 ) + pow( b3, 2.0 ) ) );
2632 
2633  //================================================ Compare the absolute value of distance to 1.0 - tolerance
2634  if ( cosDist > ( 1.0 - tolerance ) ) { ret = true; }
2635 
2636  //================================================ Done
2637  return ( ret );
2638 
2639 }
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:2809
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:1820
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:2864
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::build3x3MatrixFromDiag
proshade_double * build3x3MatrixFromDiag(proshade_double *diag)
Function for building a 3x3 matrix from diagonal (and assuming zero padding).
Definition: ProSHADE_maths.cpp:2004
ProSHADE_internal_messages::printWarningMessage
void printWarningMessage(proshade_signed verbose, std::string message, std::string warnCode)
General stderr message printing (used for warnings).
Definition: ProSHADE_messages.cpp:102
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:2653
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:2589
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:2754
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:3103
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:1788
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::findPeaks1D
std::vector< proshade_signed > findPeaks1D(std::vector< proshade_double > data)
This function simply finds all the peaks in a 1D data array.
Definition: ProSHADE_maths.cpp:3693
ProSHADE_internal_maths::smoothen1D
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.
Definition: ProSHADE_maths.cpp:3129
ProSHADE_internal_maths::BicubicInterpolator
Definition: ProSHADE_maths.hpp:110
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_maths::compute3x3MatrixVectorMultiplication
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.
Definition: ProSHADE_maths.cpp:1898
ProSHADE_internal_maths::compute3x3MoorePenrosePseudoInverseOfIMinusMat
proshade_double * compute3x3MoorePenrosePseudoInverseOfIMinusMat(std::vector< proshade_double > *rMat, proshade_signed verbose)
This function computes the Moore-Penrose pseudo-inverse of equation I - input matrix.
Definition: ProSHADE_maths.cpp:2162
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:68
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::complexMultiplicationConjug
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.
Definition: ProSHADE_maths.cpp:62
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:2919
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:3165
ProSHADE_internal_maths::compute3x3MatrixInverse
proshade_double * compute3x3MatrixInverse(proshade_double *mat)
Function for computing a 3x3 matrix inverse.
Definition: ProSHADE_maths.cpp:1943
ProSHADE_internal_maths::compute3x3MatrixMultiplication
proshade_double * compute3x3MatrixMultiplication(proshade_double *mat1, proshade_double *mat2)
Function for computing a 3x3 matrix multiplication.
Definition: ProSHADE_maths.cpp:1868