ProSHADE  0.7.6.6 (JUL 2022)
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 noSteps)
 Function to prepare abscissas and weights for Gauss-Legendre integration using the Glaser-Liu-Rokhlin method. 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 getGLFirstRealRoot (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 evaluateGLPolynomial (proshade_double *series, proshade_double target, proshade_unsign terms)
 This function evaluates the decomposed Legendre polynomial at a given position. More...
 
proshade_double advanceGLPolyValue (proshade_double from, proshade_double to, proshade_double valAtFrom, proshade_unsign order, proshade_unsign noSteps)
 This function finds the next value of a Legendre polynomial using the Runge-Kutta method. More...
 
void completeAbscissasAndWeights (proshade_unsign order, proshade_double *abscissa, proshade_double *weights, proshade_unsign noSteps)
 This function completes the abscissas and weights series from the first roots computed beforehand. 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 getEulerZYZFromSOFTPosition (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 (ZYZ convention) from index position in the inverse SOFT map. More...
 
void getSOFTPositionFromEulerZYZ (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 (ZYZ convention). More...
 
void getRotationMatrixFromEulerZYZAngles (proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double *matrix)
 Function to find the rotation matrix from Euler angles (ZYZ convention). More...
 
void getRotationMatrixFromEulerZYZAngles (proshade_single eulerAlpha, proshade_single eulerBeta, proshade_single eulerGamma, proshade_single *matrix)
 Function to find the rotation matrix from Euler angles (ZYZ 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 getEulerZYZFromRotMatrix (proshade_double *rotMat, proshade_double *eA, proshade_double *eB, proshade_double *eG)
 This function converts rotation matrix to the Euler ZYZ angles representation. More...
 
void getEulerZYZFromAngleAxis (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 ZYZ 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_single *mat)
 Transposes 3x3 matrix in place. 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 rotationMatrixSimilarity (proshade_double *mat1, 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...
 
proshade_double rotationMatrixSimilarityValue (std::vector< proshade_double > *mat1, std::vector< proshade_double > *mat2)
 This function computes the distance between two rotation matrices and returns it. More...
 
proshade_double rotationMatrixSimilarityValue (proshade_double *mat1, proshade_double *mat2)
 This function computes the distance between two rotation matrices and returns it. 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...
 
proshade_signed whichAxisUnique (std::vector< proshade_double * > *CSymList, proshade_double *axis, proshade_double tolerance)
 This function checks if new axis is unique, or already detected and returns the position of match or -1. More...
 
proshade_signed whichAxisUnique (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 and returns the position of match or -1. More...
 
std::vector< proshade_unsign > findAllPrimes (proshade_unsign upTo)
 This function finds all prime numbers up to the supplied limit. More...
 
bool isPrime (proshade_unsign toCheck)
 This function check is the supplied number is prime or not. 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, proshade_signed decRound=2)
 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_single xSize, proshade_single ySize, proshade_single zSize, proshade_signed *noBin, proshade_signed *&binIndexing, std::vector< proshade_single > *&resArray)
 This function does binning of the reciprocal space reflections. More...
 
void cutIndicesToResolution (proshade_signed xInds, proshade_signed yInds, proshade_signed zInds, proshade_single resolution, proshade_signed *binIndexing, std::vector< proshade_single > *resArray, proshade_signed *cutXDim, proshade_signed *cutYDim, proshade_signed *cutZDim, proshade_signed *&cutBinIndices, proshade_signed *&noBins)
 This function cuts the bin assignment array into a smaller array containing all bins up to a given resolution. More...
 
void cutArrayToResolution (proshade_signed xInds, proshade_signed yInds, proshade_signed zInds, proshade_signed noBins, fftw_complex *inputMap, fftw_complex *&cutMap)
 This function re-sizes data array to contain only values up to a particular resolution bin. More...
 
proshade_double computeFSC (fftw_complex *fCoeffs1, fftw_complex *fCoeffs2, proshade_signed xInds, proshade_signed yInds, proshade_signed zInds, proshade_signed noBins, proshade_signed *binIndexing, proshade_double **&binData, proshade_signed *&binCounts, proshade_double *&fscByBin, bool averageByBinSize=false)
 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=1.0)
 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=1.0)
 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  order,
proshade_unsign  noSteps 
)

This function finds the next value of a Legendre polynomial using the Runge-Kutta method.

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 Runge-Kutta method.

Parameters
[in]fromCurrent polynomial position.
[in]toPolynomial position to move to.
[in]valAtFromThe current value of the polynomial at the <from> position.
[in]orderOrder of the polynomial to advance.
[in]noStepsHow many steps the advance should be divided into.
[out]XThe polynomial value at the <to> position.

Definition at line 480 of file ProSHADE_maths.cpp.

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

◆ 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_single  xSize,
proshade_single  ySize,
proshade_single  zSize,
proshade_signed *  noBin,
proshade_signed *&  binIndexing,
std::vector< proshade_single > *&  resArray 
)

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]xSizeThe size of x-axis in Angstroms
[in]ySizeThe size of x-axis in Angstroms
[in]zSizeThe size of x-axis in Angstroms
[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.
[in]resArrayPointer to vector of values to which the resolution from each bin will be saved into.

Definition at line 3397 of file ProSHADE_maths.cpp.

3398 {
3399  //================================================ Allocate output bin indexing memory and set to -100
3400  binIndexing = new proshade_signed [xInds * yInds * zInds];
3401  ProSHADE_internal_misc::checkMemoryAllocation ( binIndexing, __FILE__, __LINE__, __func__ );
3402  for ( size_t iter = 0; iter < static_cast< size_t > ( xInds * yInds * zInds ); iter++ ) { binIndexing[iter] = -100; }
3403  proshade_single xIndsF = static_cast< proshade_single > ( xInds ), yIndsF = static_cast< proshade_single > ( yInds ), zIndsF = static_cast< proshade_single > ( zInds );
3404 
3405  //================================================ Allocate local memory
3406  proshade_single *mins = new proshade_single[3];
3407  proshade_single *maxs = new proshade_single[3];
3408  proshade_single *hkl = new proshade_single[3];
3409  proshade_single *resMins = new proshade_single[3];
3410  proshade_signed *resMinLoc = new proshade_signed[3];
3411  proshade_single *steps = new proshade_single[3];
3412 
3413  //================================================ Check local memory
3414  ProSHADE_internal_misc::checkMemoryAllocation ( mins, __FILE__, __LINE__, __func__ );
3415  ProSHADE_internal_misc::checkMemoryAllocation ( maxs, __FILE__, __LINE__, __func__ );
3416  ProSHADE_internal_misc::checkMemoryAllocation ( hkl, __FILE__, __LINE__, __func__ );
3417  ProSHADE_internal_misc::checkMemoryAllocation ( resMins, __FILE__, __LINE__, __func__ );
3418  ProSHADE_internal_misc::checkMemoryAllocation ( resMinLoc, __FILE__, __LINE__, __func__ );
3419  ProSHADE_internal_misc::checkMemoryAllocation ( steps, __FILE__, __LINE__, __func__ );
3420 
3421  //================================================ Initialise local variables
3422  proshade_single resVal = 0.0, binVal = 0.0, tmpVal = 0.0, tmpMinVal = 0.0;
3423  proshade_signed reciX, reciY, reciZ, arrPos = 0, binLoc = 0, minLoc = 0;
3424  *noBin = 0;
3425 
3426  //================================================ Determine reciprocal space indexing
3427  mins[0] = std::floor ( xIndsF / -2.0f );
3428  mins[1] = std::floor ( yIndsF / -2.0f );
3429  mins[2] = std::floor ( zIndsF / -2.0f );
3430 
3431  maxs[0] = -(mins[0] + 1);
3432  maxs[1] = -(mins[1] + 1);
3433  maxs[2] = 0.0;
3434 
3435  //================================================ Get minimum resolution based on dims for each dimension
3436  resMins[0] = ProSHADE_internal_maths::getResolutionOfReflection ( maxs[0], 0.0f, 0.0f, xSize, ySize, zSize );
3437  resMins[1] = ProSHADE_internal_maths::getResolutionOfReflection ( 0.0f, maxs[1], 0.0f, xSize, ySize, zSize );
3438  resMins[2] = ProSHADE_internal_maths::getResolutionOfReflection ( 0.0f, 0.0f, maxs[2], xSize, ySize, zSize );
3439 
3440  //================================================ Decide which dimension to work with (the one with the lowest resolution)
3441  resMinLoc[0] = 0; resMinLoc[1] = 0; resMinLoc[2] = 0;
3442  const FloatingPoint< proshade_single > lhs1 ( resMins[0] ), lhs2 ( resMins[1] ), lhs3 ( resMins[2] ), rhs1 ( std::min( resMins[0], std::min( resMins[1], resMins[2] ) ) );
3443  if ( lhs1.AlmostEquals ( rhs1 ) ) { resMinLoc[0] = 1; minLoc = 0; }
3444  else if ( lhs2.AlmostEquals ( rhs1 ) ) { resMinLoc[1] = 1; minLoc = 1; }
3445  else if ( lhs3.AlmostEquals ( rhs1 ) ) { resMinLoc[2] = 1; minLoc = 2; }
3446 
3447  for ( size_t it = 0; it < 3; it++ ) { hkl[it] = 0.0; if ( static_cast<size_t> ( minLoc ) == it ) { hkl[it] = 1.0; } }
3448 
3449  //================================================ Find the bins and corresponding cut-offs
3450  resArray = new std::vector< proshade_single > ( static_cast< size_t > ( maxs[minLoc] ), 0.0f );
3451  ProSHADE_internal_misc::checkMemoryAllocation ( resArray, __FILE__, __LINE__, __func__ );
3452  for ( proshade_signed dimIt = 0; dimIt < static_cast< proshade_signed > ( maxs[minLoc] ); dimIt++ )
3453  {
3454  //============================================ Prepare steps
3455  steps[0] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[0] ) * hkl[0];
3456  steps[1] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[1] ) * hkl[1];
3457  steps[2] = ( static_cast< proshade_single > ( dimIt ) + 2.5f ) * static_cast< proshade_single > ( resMinLoc[2] ) * hkl[2];
3458 
3459  //============================================ Find resolution
3460  resVal = ProSHADE_internal_maths::getResolutionOfReflection ( steps[0], steps[1], steps[2], xSize, ySize, zSize );
3461 
3462  //============================================ Assign to arrays
3463  resArray->at(static_cast< size_t > ( dimIt )) = resVal;
3464  *noBin = dimIt + 1;
3465  }
3466 
3467  //================================================ Determine resolution limits
3468  proshade_single highResLimit = resArray->at ( static_cast< size_t > ( *noBin - 1 ) );
3469  proshade_single lowResLimit = ProSHADE_internal_maths::getResolutionOfReflection ( 0.0f, 0.0f, 0.0f, xSize, ySize, zSize );
3470 
3471  const FloatingPoint< proshade_single > minX ( mins[0] ), minY ( mins[1] ), minZ ( mins[2] );
3472 
3473  //================================================ Assign reflections to bins
3474  for ( proshade_single xIt = static_cast< proshade_single > ( mins[0] ); xIt <= static_cast< proshade_single > ( maxs[0] ); xIt += 1.0f )
3475  {
3476  for ( proshade_single yIt = static_cast< proshade_single > ( mins[1] ); yIt <= static_cast< proshade_single > ( maxs[1] ); yIt += 1.0f )
3477  {
3478  for ( proshade_single zIt = static_cast< proshade_single > ( mins[2] ); zIt <= 0.0f; zIt += 1.0f )
3479  {
3480  //==================================== Find resoltion of this spot
3481  resVal = ProSHADE_internal_maths::getResolutionOfReflection ( xIt, yIt, zIt, xSize, ySize, zSize );
3482 
3483  //==================================== Is it in range?
3484  if ( ( resVal < highResLimit ) || ( resVal > lowResLimit ) ) { continue; }
3485 
3486  //==================================== For each bin, check if this reflection belongs to it
3487  for ( proshade_signed binIt = 0; binIt < (*noBin); binIt++ )
3488  {
3489  //================================ Find bin resolution
3490  binVal = std::sqrt ( std::pow ( resArray->at( static_cast< size_t > ( binIt ) ) - resVal, 2.0f ) );
3491 
3492  //================================ Is this the closest bin to the spot resolution?
3493  if ( binIt == 0 )
3494  {
3495  tmpVal = binVal;
3496  tmpMinVal = binVal;
3497  binLoc = binIt;
3498  }
3499  else
3500  {
3501  tmpVal = binVal;
3502  if ( tmpVal < tmpMinVal )
3503  {
3504  tmpMinVal = binVal;
3505  binLoc = binIt;
3506  }
3507  }
3508  }
3509 
3510  //==================================== Save bin index
3511  reciX = static_cast< proshade_signed > ( xIt - mins[0] );
3512  reciY = static_cast< proshade_signed > ( yIt - mins[1] );
3513  reciZ = static_cast< proshade_signed > ( zIt - mins[2] );
3514 
3515  arrPos = reciZ + static_cast< proshade_signed > ( zInds ) * ( reciY + static_cast< proshade_signed > ( yInds ) * reciX );
3516  binIndexing[ static_cast< size_t > ( arrPos ) ] = binLoc;
3517 
3518  //==================================== If applicable, use Friedel's Law
3519  const FloatingPoint< proshade_single > itX ( xIt ), itY ( yIt ), itZ ( zIt );
3520  if ( minX.AlmostEquals ( itX ) || minY.AlmostEquals ( itY ) || minZ.AlmostEquals ( itZ ) ) { continue; }
3521 
3522  reciX = static_cast< proshade_signed > ( -xIt - mins[0] );
3523  reciY = static_cast< proshade_signed > ( -yIt - mins[1] );
3524  reciZ = static_cast< proshade_signed > ( -zIt - mins[2] );
3525 
3526  arrPos = reciZ + static_cast< proshade_signed > ( zInds ) * ( reciY + static_cast< proshade_signed > ( yInds ) * reciX );
3527  binIndexing[ static_cast< size_t > ( arrPos ) ] = binLoc;
3528  }
3529  }
3530  }
3531 
3532  //================================================ Release memory
3533  delete[] mins;
3534  delete[] maxs;
3535  delete[] hkl;
3536  delete[] resMins;
3537  delete[] resMinLoc;
3538  delete[] steps;
3539 
3540  //================================================ Done
3541  return ;
3542 
3543 }

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

2029 {
2030  //================================================ Allocate memory
2031  proshade_double* ret = new proshade_double[9];
2032  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
2033 
2034  //================================================ Build
2035  ret[0] = diag[0];
2036  ret[1] = 0.0;
2037  ret[2] = 0.0;
2038  ret[3] = 0.0;
2039  ret[4] = diag[1];
2040  ret[5] = 0.0;
2041  ret[6] = 0.0;
2042  ret[7] = 0.0;
2043  ret[8] = diag[2];
2044 
2045  //================================================ Done
2046  return ( ret );
2047 
2048 }

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

2058 {
2059  //================================================ Allocate memory
2060  proshade_double* ret = new proshade_double[9];
2061  proshade_double* XRM = new proshade_double[9];
2062  proshade_double* YRM = new proshade_double[9];
2063  proshade_double* ZRM = new proshade_double[9];
2064  ProSHADE_internal_misc::checkMemoryAllocation ( ret, __FILE__, __LINE__, __func__ );
2065  ProSHADE_internal_misc::checkMemoryAllocation ( XRM, __FILE__, __LINE__, __func__ );
2066  ProSHADE_internal_misc::checkMemoryAllocation ( YRM, __FILE__, __LINE__, __func__ );
2067  ProSHADE_internal_misc::checkMemoryAllocation ( ZRM, __FILE__, __LINE__, __func__ );
2068 
2069  //================================================ Convert to radians
2070  proshade_double xRad = xRot * ( M_PI / 180.0 );
2071  proshade_double yRad = yRot * ( M_PI / 180.0 );
2072  proshade_double zRad = zRot * ( M_PI / 180.0 );
2073 
2074  //================================================ Build the X, Y and Z rotation matrices
2075  XRM[0] = 1.0; XRM[1] = 0.0; XRM[2] = 0.0;
2076  XRM[3] = 0.0; XRM[4] = std::cos ( xRad ); XRM[5] = -std::sin ( xRad );
2077  XRM[6] = 0.0; XRM[7] = std::sin ( xRad ); XRM[8] = std::cos ( xRad );
2078 
2079  YRM[0] = std::cos ( yRad ); YRM[1] = 0.0; YRM[2] = std::sin ( yRad );
2080  YRM[3] = 0.0; YRM[4] = 1.0; YRM[5] = 0.0;
2081  YRM[6] = -std::sin ( yRad ); YRM[7] = 0.0; YRM[8] = std::cos ( yRad );
2082 
2083  ZRM[0] = std::cos ( zRad ); ZRM[1] = -std::sin ( zRad ); ZRM[2] = 0.0;
2084  ZRM[3] = std::sin ( zRad ); ZRM[4] = std::cos ( zRad ); ZRM[5] = 0.0;
2085  ZRM[6] = 0.0; ZRM[7] = 0.0; ZRM[8] = 1.0;
2086 
2087  //================================================ Multiply in XYZ order
2088  proshade_double* tmpMat = compute3x3MatrixMultiplication ( XRM, YRM );
2089  ret = compute3x3MatrixMultiplication ( tmpMat, ZRM );
2090 
2091  //================================================ Release memory
2092  delete[] tmpMat;
2093  delete[] XRM;
2094  delete[] YRM;
2095  delete[] ZRM;
2096 
2097  //================================================ Done
2098  return ( ret );
2099 
2100 }

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

4243 {
4244  //================================================ Initialise local variables
4245  double normFactor = static_cast<double> ( xD * yD * zD );
4246  proshade_signed arrPos;
4247 
4248  //================================================ Combine the coefficients
4249  for ( proshade_signed xIt = 0; xIt < static_cast< proshade_signed > ( xD ); xIt++ )
4250  {
4251  for ( proshade_signed yIt = 0; yIt < static_cast< proshade_signed > ( yD ); yIt++ )
4252  {
4253  for ( proshade_signed zIt = 0; zIt < static_cast< proshade_signed > ( zD ); zIt++ )
4254  {
4255  //==================================== Find indices
4256  arrPos = zIt + static_cast< proshade_signed > ( zD ) * ( yIt + static_cast< proshade_signed > ( yD ) * xIt );
4257 
4258  //==================================== Combine
4260  &tmpOut1[arrPos][1],
4261  &tmpOut2[arrPos][0],
4262  &tmpOut2[arrPos][1],
4263  &resOut[arrPos][0],
4264  &resOut[arrPos][1] );
4265 
4266  //==================================== Save
4267  resOut[arrPos][0] /= normFactor;
4268  resOut[arrPos][1] /= normFactor;
4269  }
4270  }
4271  }
4272 
4273  //================================================ Done
4274  return ;
4275 
4276 }

◆ completeAbscissasAndWeights()

void ProSHADE_internal_maths::completeAbscissasAndWeights ( proshade_unsign  order,
proshade_double *  abscissas,
proshade_double *  weights,
proshade_unsign  noSteps 
)

This function completes the abscissas and weights series from the first roots computed beforehand.

Given that the first root value and derivative are known, this function will complete the Gauss-Legendre quarature weights and abscissas.

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]noStepsThe number of steps in approximations.

Definition at line 524 of file ProSHADE_maths.cpp.

525 {
526  //================================================ Initialise internal variables
527  proshade_double hlpStepVal = 0.0;
528  proshade_double hlpOrderVal = static_cast<proshade_double> ( order );
529  proshade_double abscValueChange = 0.0;
530  proshade_double prevAbsc = 0.0;
531  proshade_double *polyDecomposition;
532  proshade_double *deriDecomposition;
533  proshade_unsign knownRootPos = 0;
534  proshade_unsign oddEvenSwitch = 0;
535 
536  //================================================ Pre-set internal values
537  if ( order % 2 == 1 )
538  {
539  knownRootPos = ( order - 1 ) / 2;
540  oddEvenSwitch = 1;
541  }
542  else
543  {
544  knownRootPos = order / 2;
545  oddEvenSwitch = 0;
546  }
547 
548  //================================================ Allocate memory
549  polyDecomposition = new proshade_double[noSteps+2];
550  deriDecomposition = new proshade_double[noSteps+1];
551  ProSHADE_internal_misc::checkMemoryAllocation ( polyDecomposition, __FILE__, __LINE__, __func__ );
552  ProSHADE_internal_misc::checkMemoryAllocation ( deriDecomposition, __FILE__, __LINE__, __func__ );
553 
554  //================================================ For each abscissa-weight pair after the first root
555  for ( proshade_unsign serIt = knownRootPos + 1; serIt < order; serIt++ )
556  {
557  //============================================ Init loop
558  prevAbsc = abscissas[serIt-1];
559  abscValueChange = advanceGLPolyValue ( M_PI/2.0, -M_PI/2.0, prevAbsc, order, noSteps ) - prevAbsc;
560 
561  //============================================ Init polynomial decomposition array
562  polyDecomposition[0] = 0.0;
563  polyDecomposition[1] = 0.0;
564  polyDecomposition[2] = weights[serIt-1];
565 
566  //============================================ Init polynomial derivative decomposition array
567  deriDecomposition[0] = 0.0;
568  deriDecomposition[1] = polyDecomposition[2];
569 
570  //============================================ Compute the polynomial and its derivative decomposition into terms
571  for ( proshade_unsign stIt = 0; stIt <= noSteps - 2; stIt++ )
572  {
573  hlpStepVal = static_cast<proshade_double> ( stIt );
574 
575  polyDecomposition[stIt+3] = ( 2.0 * prevAbsc * ( hlpStepVal + 1.0 ) * polyDecomposition[stIt+2] + ( hlpStepVal * ( hlpStepVal + 1.0 ) - hlpOrderVal *
576  ( hlpOrderVal + 1.0 ) ) * polyDecomposition[stIt+1] / ( hlpStepVal + 1.0 ) ) / ( 1.0 - prevAbsc ) / ( 1.0 + prevAbsc ) /
577  ( hlpStepVal + 2.0 );
578 
579  deriDecomposition[stIt+2] = ( hlpStepVal + 2.0 ) * polyDecomposition[stIt+3];
580  }
581 
582  //============================================ Evaluate the polynomial and its derivative to determine the root and derivative value
583  for ( proshade_unsign iter = 0; iter < noSteps; iter++ )
584  {
585  abscValueChange = abscValueChange - evaluateGLPolynomial ( polyDecomposition, abscValueChange, noSteps ) / evaluateGLPolynomial ( deriDecomposition, abscValueChange, noSteps-1 );
586  }
587 
588  //============================================ Save results
589  abscissas[serIt] = prevAbsc + abscValueChange;
590  weights[serIt] = evaluateGLPolynomial ( deriDecomposition, abscValueChange, noSteps - 1 );
591  }
592 
593  //================================================ The negative roots and their weights have the same distance as the positive roots (i.e. abscissas[firstRoot+1] == -abscissas[firstRoot-1]) and same weight
594  for ( proshade_unsign serIt = 0; serIt < knownRootPos + oddEvenSwitch; serIt++ )
595  {
596  abscissas[serIt] = -abscissas[order-serIt-1];
597  weights[serIt] = weights[order-serIt-1];
598  }
599 
600  //================================================ Free memory
601  delete polyDecomposition;
602  delete deriDecomposition;
603 
604  //================================================ Done
605  return ;
606 
607 }

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

808 {
809  //================================================ Initialise local variables
810  char job = 'N'; // Save computation of parts of U and V matrices, they are not needed here
811  std::complex<double> *rotMatU = new std::complex<double> [dim*dim]; // The U matrix space
812  std::complex<double> *rotMatV = new std::complex<double> [dim*dim]; // The V^T matrix space
813  std::complex<double> *work = new std::complex<double> [( 4 * dim)]; // Workspace, minimum required is 3*dim, using more for performance
814  int workDim = ( 4 * dim); // Formalism stating just that
815  double* rwork = new double[(7 * dim)]; // Required by LAPACK, from 3.7 requires 7 * dim
816  int* iwork = new int[(8 * dim)]; // Required by LAPACK
817  int returnValue = 0; // This will tell if operation succeeded
818 
819  //================================================ Check memory allocation
820  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatU, __FILE__, __LINE__, __func__ );
821  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatV, __FILE__, __LINE__, __func__ );
822  ProSHADE_internal_misc::checkMemoryAllocation ( work, __FILE__, __LINE__, __func__ );
823  ProSHADE_internal_misc::checkMemoryAllocation ( rwork, __FILE__, __LINE__, __func__ );
824  ProSHADE_internal_misc::checkMemoryAllocation ( iwork, __FILE__, __LINE__, __func__ );
825 
826  //================================================ Load input data into array in column-major order
827  std::complex<double> *matrixToDecompose = new std::complex<double>[dim*dim];
828  ProSHADE_internal_misc::checkMemoryAllocation ( matrixToDecompose, __FILE__, __LINE__, __func__ );
829  for ( int rowIt = 0; rowIt < dim; rowIt++ )
830  {
831  for ( int colIt = 0; colIt < dim; colIt++ )
832  {
833  matrixToDecompose[(colIt*dim)+rowIt] = std::complex<double> ( mat[rowIt][colIt][0], mat[rowIt][colIt][1] );
834  }
835  }
836 
837  //================================================ Run LAPACK ZGESDD
838  zgesdd_ ( &job, &dim, &dim, matrixToDecompose, &dim, singularValues, rotMatU, &dim, rotMatV, &dim,
839  work, &workDim, rwork, iwork, &returnValue );
840 
841  //================================================ Free memory
842  delete[] rotMatU;
843  delete[] rotMatV;
844  delete[] work;
845  delete[] rwork;
846  delete[] iwork;
847  delete[] matrixToDecompose;
848 
849  //================================================ Check result
850  if ( returnValue != 0 )
851  {
852  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." );
853  }
854 
855  //================================================ Done
856  return ;
857 
858 }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1786 {
1787  //================================================ Compute and return
1788  return ( (*x1 * *x2) + (*y1 * *y2) + (*z1 * *z2) );
1789 }

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

1802 {
1803  //================================================ Compute and return
1804  return ( (x1 * x2) + (y1 * y2) + (z1 * z2) );
1805 }

◆ computeFSC()

proshade_double ProSHADE_internal_maths::computeFSC ( fftw_complex *  fCoeffs1,
fftw_complex *  fCoeffs2,
proshade_signed  xInds,
proshade_signed  yInds,
proshade_signed  zInds,
proshade_signed  noBins,
proshade_signed *  binIndexing,
proshade_double **&  binData,
proshade_signed *&  binCounts,
proshade_double *&  fscByBin,
bool  averageByBinSize = false 
)

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.
[in]weightByBinSizeBoolean value determining if averaging bins should take into account the bin sizes or not.
[out]fscThe Fourier Shell Correlation between the two supplied Fourier coefficient maps.

Definition at line 3693 of file ProSHADE_maths.cpp.

3694 {
3695  //================================================ Initialise local variables
3696  proshade_double realOrig, realRot, imagOrig, imagRot, fsc = 0.0;;
3697  proshade_signed indx, arrPos;
3698  std::vector< proshade_double > covarByBin ( static_cast< size_t > ( noBins ), 0.0 );
3699 
3700  //================================================ Clean FSC computation memory
3701  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; } }
3702  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ ) { binCounts[binIt] = 0; }
3703 
3704  //================================================ Compute bin sums
3705  for ( proshade_signed xIt = 0; xIt < xInds; xIt++ )
3706  {
3707  for ( proshade_signed yIt = 0; yIt < yInds; yIt++ )
3708  {
3709  for ( proshade_signed zIt = 0; zIt < ( zInds / 2 ); zIt++ )
3710  {
3711  //==================================== Find array position
3712  arrPos = zIt + static_cast< proshade_signed > ( zInds ) * ( yIt + static_cast< proshade_signed > ( yInds ) * xIt );
3713 
3714  //==================================== If no bin is associated, skip this reflection
3715  indx = binIndexing[ static_cast< size_t > ( arrPos ) ];
3716  if ( ( indx < 0 ) || ( indx >= noBins ) ) { continue; }
3717 
3718  //==================================== Calculate the sums
3719  realOrig = fCoeffs1[arrPos][0];
3720  imagOrig = fCoeffs1[arrPos][1];
3721  realRot = fCoeffs2[arrPos][0];
3722  imagRot = fCoeffs2[arrPos][1];
3723 
3724  binData[indx][0] += realOrig;
3725  binData[indx][1] += imagOrig;
3726  binData[indx][2] += realRot;
3727  binData[indx][3] += imagRot;
3728  binData[indx][4] += realOrig * realRot;
3729  binData[indx][5] += imagOrig * imagRot;
3730  binData[indx][6] += std::pow ( realOrig, 2.0 );
3731  binData[indx][7] += std::pow ( imagOrig, 2.0 );
3732  binData[indx][8] += std::pow ( realRot, 2.0 );
3733  binData[indx][9] += std::pow ( imagRot, 2.0 );
3734 
3735  //==================================== Update bin counts
3736  binCounts[indx] += 1;
3737  }
3738  }
3739  }
3740 
3741  //================================================ Compute covariance by bin
3742  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3743  {
3744  covarByBin.at(binIt) = ( ( binData[binIt][4] + binData[binIt][5] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3745  ( ( binData[binIt][0] / static_cast< proshade_double > ( binCounts[binIt] ) *
3746  binData[binIt][2] / static_cast< proshade_double > ( binCounts[binIt] ) ) +
3747  ( binData[binIt][1] / static_cast< proshade_double > ( binCounts[binIt] ) *
3748  binData[binIt][3] / static_cast< proshade_double > ( binCounts[binIt] ) ) ) );
3749  }
3750 
3751  //================================================ Get FSC by bin
3752  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3753  {
3754  binData[binIt][10] = ( binData[binIt][6] + binData[binIt][7] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3755  ( std::pow ( binData[binIt][0] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) +
3756  std::pow ( binData[binIt][1] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) );
3757  binData[binIt][11] = ( binData[binIt][8] + binData[binIt][9] ) / static_cast< proshade_double > ( binCounts[binIt] ) -
3758  ( std::pow ( binData[binIt][2] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) +
3759  std::pow ( binData[binIt][3] / static_cast< proshade_double > ( binCounts[binIt] ), 2.0 ) );
3760  fscByBin[binIt] = covarByBin.at(binIt) / ( std::sqrt ( binData[binIt][10] ) * std::sqrt ( binData[binIt][11] ) );
3761  }
3762 
3763  //================================================ Get average FSC over all bins
3764  proshade_double binSizeSum = 0.0;
3765  for ( size_t binIt = 0; binIt < static_cast< size_t > ( noBins ); binIt++ )
3766  {
3767  if ( averageByBinSize )
3768  {
3769  fsc += fscByBin[binIt] * static_cast< proshade_double > ( binCounts[binIt] );
3770  binSizeSum += static_cast< proshade_double > ( binCounts[binIt] );
3771  }
3772  else
3773  {
3774  fsc += fscByBin[binIt];
3775  binSizeSum += 1;
3776  }
3777  }
3778  fsc /= static_cast< proshade_double > ( binSizeSum );
3779 
3780  //================================================ Done
3781  return ( fsc );
3782 
3783 }

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

3801 {
3802  //================================================ Initialise local variables
3803  proshade_signed indx, arrPos, reciX, reciY, reciZ;
3804 
3805  //================================================ Allocate memmory
3806  weights1 = new proshade_double[xDim * yDim * zDim];
3807  weights2 = new proshade_double[xDim * yDim * zDim];
3808  proshade_single *mins = new proshade_single[3];
3809  proshade_single *maxs = new proshade_single[3];
3810 
3811  //================================================ Check memory allocation
3812  ProSHADE_internal_misc::checkMemoryAllocation ( weights1, __FILE__, __LINE__, __func__ );
3813  ProSHADE_internal_misc::checkMemoryAllocation ( weights2, __FILE__, __LINE__, __func__ );
3814  ProSHADE_internal_misc::checkMemoryAllocation ( mins, __FILE__, __LINE__, __func__ );
3815  ProSHADE_internal_misc::checkMemoryAllocation ( maxs, __FILE__, __LINE__, __func__ );
3816 
3817  //================================================ Assign values to the memory
3818  for ( size_t iter = 0; iter < static_cast< size_t > ( xDim * yDim * zDim ); iter++ ) { weights1[iter] = -100.0; weights2[iter] = -100.0; }
3819 
3820  //================================================ Determine reciprocal space indexing ranges
3821  mins[0] = std::floor ( static_cast< proshade_single > ( xDim ) / -2.0f );
3822  mins[1] = std::floor ( static_cast< proshade_single > ( yDim ) / -2.0f );
3823  mins[2] = std::floor ( static_cast< proshade_single > ( zDim ) / -2.0f );
3824 
3825  maxs[0] = -mins[0];
3826  maxs[1] = -mins[1];
3827  maxs[2] = -mins[2];
3828 
3829  if ( xDim % 2 == 0 ) { mins[0] += 1.0f; }
3830  if ( yDim % 2 == 0 ) { mins[1] += 1.0f; }
3831  if ( zDim % 2 == 0 ) { mins[2] += 1.0f; }
3832 
3833  //================================================ For each reflection
3834  for ( proshade_signed xIt = 0; xIt < xDim; xIt++ )
3835  {
3836  for ( proshade_signed yIt = 0; yIt < yDim; yIt++ )
3837  {
3838  for ( proshade_signed zIt = 0; zIt < ( ( zDim / 2 ) + 1 ); zIt++ )
3839  {
3840  //==================================== Deal with reciprocal indices ordering
3841  reciX = xIt; if ( reciX > static_cast< proshade_signed > ( maxs[0] ) ) { reciX -= static_cast< proshade_signed > ( xDim ); }
3842  reciY = yIt; if ( reciY > static_cast< proshade_signed > ( maxs[1] ) ) { reciY -= static_cast< proshade_signed > ( yDim ); }
3843  reciZ = zIt; if ( reciZ > static_cast< proshade_signed > ( maxs[2] ) ) { reciZ -= static_cast< proshade_signed > ( zDim ); }
3844 
3845  //==================================== Find array position and bin index
3846  arrPos = zIt + zDim * ( yIt + yDim * xIt );
3847  indx = binIndexing[ static_cast< size_t > ( arrPos ) ];
3848 
3849  //==================================== Ignore unassigned bin reflections
3850  if ( ( indx < 0 ) || ( indx > noBins ) ) { continue; }
3851 
3852  //==================================== Set weights using the bin FSC
3853  weights1[arrPos] = fscByBin[indx];
3854  weights2[arrPos] = std::pow ( fscByBin[indx], 2.0 );
3855 
3856  //==================================== If one of the uneven ends, do not use Friedel's Law
3857  if ( reciX == static_cast< proshade_signed > ( mins[0] ) || -reciX == static_cast< proshade_signed > ( mins[0] ) ) { break; }
3858  if ( reciY == static_cast< proshade_signed > ( mins[1] ) || -reciY == static_cast< proshade_signed > ( mins[1] ) ) { break; }
3859  if ( reciZ == static_cast< proshade_signed > ( mins[2] ) || -reciZ == static_cast< proshade_signed > ( mins[2] ) ) { break; }
3860 
3861  //==================================== Use Friedel's Law to find the second index (this is why we can use zDim / 2)
3862  reciX *= -1; if ( reciX < 0 ) { reciX += xDim; }
3863  reciY *= -1; if ( reciY < 0 ) { reciY += yDim; }
3864  reciZ *= -1; if ( reciZ < 0 ) { reciZ += zDim; }
3865 
3866  //==================================== Apply Friedel's Law
3867  arrPos = reciZ + zDim * ( reciY + yDim * reciX );
3868  weights1[arrPos] = fscByBin[indx];
3869  weights2[arrPos] = std::pow ( fscByBin[indx], 2.0 );
3870  }
3871  }
3872  }
3873 
3874  //================================================ Release memory
3875  delete[] mins;
3876  delete[] maxs;
3877 
3878  //================================================ Done
3879  return ;
3880 
3881 }

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

3287 {
3288  //================================================ Compute cumulative probability from Z-score
3289  proshade_double zScore = ( val / sigma );
3290  proshade_double cumulativeProbability = 0.5 * std::erfc ( zScore * M_SQRT1_2 );
3291 
3292  //================================================ Symmetrise
3293  if ( cumulativeProbability > 0.5 ) { cumulativeProbability = 1.0 - cumulativeProbability; }
3294 
3295  //================================================ Done
3296  return ( cumulativeProbability );
3297 
3298 }

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

3893 {
3894  //================================================ Initialise local variables
3895  proshade_double sum = 0.0;
3896  proshade_signed arrPos;
3897 
3898  //================================================ For each reflection
3899  for ( proshade_signed xIt = 0; xIt < xDim; xIt++ )
3900  {
3901  for ( proshade_signed yIt = 0; yIt < yDim; yIt++ )
3902  {
3903  for ( proshade_signed zIt = 0; zIt < ( ( zDim / 2 ) + 1 ); zIt++ )
3904  {
3905  //==================================== Find array position and bin index
3906  arrPos = zIt + zDim * ( yIt + yDim * xIt );
3907 
3908  //==================================== Sum real parts if weight exists
3909  if ( weights[arrPos] > -2.0 ) { sum += fCoeffs[arrPos][0]; }
3910  }
3911  }
3912  }
3913 
3914  //================================================ Done
3915  return ( sum );
3916 
3917 }

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

3931 {
3932  //================================================ Allocate memmory
3933  firstDers = new proshade_double[3];
3934  secondDers = new proshade_double[9];
3935  proshade_single *mins = new proshade_single[3];
3936  proshade_single *maxs = new proshade_single[3];
3937 
3938  //================================================ Check memory allocation
3939  ProSHADE_internal_misc::checkMemoryAllocation ( firstDers, __FILE__, __LINE__, __func__ );
3940  ProSHADE_internal_misc::checkMemoryAllocation ( secondDers, __FILE__, __LINE__, __func__ );
3941  ProSHADE_internal_misc::checkMemoryAllocation ( mins, __FILE__, __LINE__, __func__ );
3942  ProSHADE_internal_misc::checkMemoryAllocation ( maxs, __FILE__, __LINE__, __func__ );
3943 
3944  //================================================ Initialise variables
3945  std::complex< proshade_double > piConstFirst ( 2.0 * M_PI, 1.0 );
3946  proshade_double piConstSecond = std::pow ( 2.0 * M_PI, 2.0 );
3947  for ( size_t iter = 0; iter < 3; iter++ ) { firstDers[iter] = 0.0; }
3948  for ( size_t iter = 0; iter < 9; iter++ ) { secondDers[iter] = 0.0; }
3949  proshade_signed reciX, reciY, reciZ, arrPos;
3950 
3951  //================================================ Determine reciprocal space indexing ranges
3952  mins[0] = std::floor ( static_cast< proshade_single > ( xDim ) / -2.0f );
3953  mins[1] = std::floor ( static_cast< proshade_single > ( yDim ) / -2.0f );
3954  mins[2] = std::floor ( static_cast< proshade_single > ( zDim ) / -2.0f );
3955 
3956  maxs[0] = -mins[0];
3957  maxs[1] = -mins[1];
3958  maxs[2] = -mins[2];
3959 
3960  if ( xDim % 2 == 0 ) { mins[0] += 1.0f; }
3961  if ( yDim % 2 == 0 ) { mins[1] += 1.0f; }
3962  if ( zDim % 2 == 0 ) { mins[2] += 1.0f; }
3963 
3964  //================================================ For each reflection
3965  for ( proshade_signed xIt = 0; xIt < xDim; xIt++ )
3966  {
3967  for ( proshade_signed yIt = 0; yIt < yDim; yIt++ )
3968  {
3969  for ( proshade_signed zIt = 0; zIt < ( ( zDim / 2 ) + 1 ); zIt++ )
3970  {
3971  //==================================== Deal with reciprocal indices ordering
3972  reciX = xIt; if ( reciX > static_cast< proshade_signed > ( maxs[0] ) ) { reciX -= static_cast< proshade_signed > ( xDim ); }
3973  reciY = yIt; if ( reciY > static_cast< proshade_signed > ( maxs[1] ) ) { reciY -= static_cast< proshade_signed > ( yDim ); }
3974  reciZ = zIt; if ( reciZ > static_cast< proshade_signed > ( maxs[2] ) ) { reciZ -= static_cast< proshade_signed > ( zDim ); }
3975 
3976  //==================================== Find array position and bin index
3977  arrPos = zIt + zDim * ( yIt + yDim * xIt );
3978 
3979  //==================================== Ignore if outside of weights
3980  if ( weights1[arrPos] < -2.0 ) { continue; }
3981 
3982  //==================================== Add to the first derivatives sum
3983  firstDers[0] += ( weights1[arrPos] * fCoeffs[arrPos][0] * std::conj( fCoeffs[arrPos][1] * piConstFirst * static_cast< proshade_double > ( reciX ) ) ).real();
3984  firstDers[1] += ( weights1[arrPos] * fCoeffs[arrPos][0] * std::conj( fCoeffs[arrPos][1] * piConstFirst * static_cast< proshade_double > ( reciY ) ) ).real();
3985  firstDers[2] += ( weights1[arrPos] * fCoeffs[arrPos][0] * std::conj( fCoeffs[arrPos][1] * piConstFirst * static_cast< proshade_double > ( reciZ ) ) ).real();
3986 
3987  //==================================== Add to the second derivatives sum
3988  secondDers[0] += weights2[arrPos] * static_cast< proshade_double > ( reciX * reciX );
3989  secondDers[1] += weights2[arrPos] * static_cast< proshade_double > ( reciX * reciY );
3990  secondDers[2] += weights2[arrPos] * static_cast< proshade_double > ( reciX * reciZ );
3991  secondDers[4] += weights2[arrPos] * static_cast< proshade_double > ( reciY * reciY );
3992  secondDers[5] += weights2[arrPos] * static_cast< proshade_double > ( reciY * reciZ );
3993  secondDers[8] += weights2[arrPos] * static_cast< proshade_double > ( reciZ * reciZ );
3994  }
3995  }
3996  }
3997 
3998  //================================================ Complete second darivatives matrix
3999  secondDers[3] = secondDers[1];
4000  secondDers[6] = secondDers[2];
4001  secondDers[7] = secondDers[5];
4002  for ( size_t iter = 0; iter < 9; iter++ ) { secondDers[iter] *= -piConstSecond; }
4003 
4004  //================================================ Release memory
4005  delete[] mins;
4006  delete[] maxs;
4007 
4008  //================================================ Done
4009  return ;
4010 
4011 }

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

4020 {
4021  //================================================ Change format of second derivatives and add I matrix (the inversion function will subtract it)
4022  std::vector < proshade_double > tmpMap ( 9, 0.0 );
4023  for ( size_t iter = 0; iter < 9; iter++ ) { tmpMap.at(iter) = secondDers[iter]; }
4024  tmpMap.at(0) += 1.0; tmpMap.at(4) += 1.0; tmpMap.at(8) += 1.0;
4025 
4026  //================================================ Compute matrix inversion for the second derivatives matrix
4027  proshade_double* secondInv = compute3x3MoorePenrosePseudoInverseOfIMinusMat ( &tmpMap, -1 );
4028 
4029  //================================================ Compute dot product between the inverted matrix and the first derivatives vector
4030  proshade_double* stepArr = compute3x3MatrixVectorMultiplication ( secondInv, -firstDers[0], -firstDers[1], -firstDers[2] );
4031 
4032  //================================================ Release memory
4033  delete[] secondInv;
4034 
4035  //================================================ Done
4036  return ( stepArr );
4037 
4038 }

◆ cutArrayToResolution()

void ProSHADE_internal_maths::cutArrayToResolution ( proshade_signed  xInds,
proshade_signed  yInds,
proshade_signed  zInds,
proshade_signed  noBins,
fftw_complex *  inputMap,
fftw_complex *&  cutMap 
)

This function re-sizes data array to contain only values up to a particular resolution bin.

Parameters
[in]xIndsThe number of indices along the x-axis for the full map.
[in]yIndsThe number of indices along the y-axis for the full map.
[in]zIndsThe number of indices along the z-axis for the full map.
[in]noBinsThe largest bin after cutting.
[in]inputMapThe map to be cut.
[in]cutMapThe map after cutting.
Warning
This function is part of the FSC computation framework and makes assumptions that may not be true in general. Please look into the code before using.

Definition at line 3628 of file ProSHADE_maths.cpp.

3629 {
3630  //================================================ Compute new map dimensions
3631  proshade_signed newXFrom = static_cast< proshade_signed > ( std::round ( ( static_cast< proshade_signed > ( xInds ) - 2 * noBins ) / 2 ) );
3632  proshade_signed newYFrom = static_cast< proshade_signed > ( std::round ( ( static_cast< proshade_signed > ( yInds ) - 2 * noBins ) / 2 ) );
3633  proshade_signed newZFrom = static_cast< proshade_signed > ( std::round ( ( static_cast< proshade_signed > ( zInds ) - 2 * noBins ) / 2 ) );
3634  proshade_signed newXTo = static_cast< proshade_signed > ( std::round ( newXFrom + 2 * noBins ) );
3635  proshade_signed newYTo = static_cast< proshade_signed > ( std::round ( newYFrom + 2 * noBins ) );
3636  proshade_signed newZTo = static_cast< proshade_signed > ( std::round ( newZFrom + 2 * noBins ) );
3637  proshade_signed cutXDim = ( newXTo - newXFrom );
3638  proshade_signed cutYDim = ( newYTo - newYFrom );
3639  proshade_signed cutZDim = ( newZTo - newZFrom );
3640 
3641  //================================================ Create new coefficients array within only the new dimensions
3642  cutMap = reinterpret_cast< fftw_complex* > ( fftw_malloc ( sizeof ( fftw_complex ) * static_cast< proshade_unsign > ( cutXDim * cutYDim * cutZDim ) ) );
3643  ProSHADE_internal_misc::checkMemoryAllocation ( cutMap, __FILE__, __LINE__, __func__ );
3644  for ( size_t iter = 0; iter < static_cast< size_t > ( cutXDim * cutYDim * cutZDim ); iter++ ) { cutMap[iter][0] = 0.0; cutMap[iter][1] = 0.0; }
3645 
3646  proshade_signed newArrPos = 0, origArrPos = 0;
3647  for ( proshade_signed xIt = newXFrom; xIt < newXTo; xIt++ )
3648  {
3649  for ( proshade_signed yIt = newYFrom; yIt < newYTo; yIt++ )
3650  {
3651  for ( proshade_signed zIt = newZFrom; zIt < newZTo; zIt++ )
3652  {
3653  //==================================== Skip if outside of box
3654  if ( ( xIt < 0 ) || ( yIt < 0 ) || ( zIt < 0 ) ) { continue; }
3655  if ( ( xIt >= xInds ) || ( yIt >= yInds ) || ( zIt >= zInds ) ) { continue; }
3656 
3657  //==================================== Find positions
3658  newArrPos = (zIt-newZFrom) + cutZDim * ( (yIt-newYFrom) + cutYDim * (xIt-newXFrom) );
3659  origArrPos = zIt + static_cast< proshade_signed > ( zInds ) * ( yIt + static_cast< proshade_signed > ( yInds ) * xIt );
3660 
3661  //==================================== Copy value
3662  cutMap[newArrPos][0] = inputMap[origArrPos][0];
3663  cutMap[newArrPos][1] = inputMap[origArrPos][1];
3664  }
3665  }
3666  }
3667 
3668  //================================================ Done
3669  return ;
3670 
3671 }

◆ cutIndicesToResolution()

void ProSHADE_internal_maths::cutIndicesToResolution ( proshade_signed  xInds,
proshade_signed  yInds,
proshade_signed  zInds,
proshade_single  resolution,
proshade_signed *  binIndexing,
std::vector< proshade_single > *  resArray,
proshade_signed *  cutXDim,
proshade_signed *  cutYDim,
proshade_signed *  cutZDim,
proshade_signed *&  cutBinIndices,
proshade_signed *&  noBins 
)

This function cuts the bin assignment array into a smaller array containing all bins up to a given resolution.

This function firstly decides on between which array indices the bin assignment values need to be held for all bins up to the given resolution to be present. Once the decision is made, it cuts the bin indexing array to the smallest size sufficient to contain all bin assignments to the required resolution.

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]resolutionThe resolution to which the map should be cut to.
[in]binIndexingA pointer to the map of bin assignment for each reflection.
[in]resArrayPointer to a vector of the resolution for each bin.
[in]cutXDimPointer to which the x-axis dimension of the cut map will be saved into.
[in]cutYDimPointer to which the y-axis dimension of the cut map will be saved into.
[in]cutZDimPointer to which the z-axis dimension of the cut map will be saved into.
[in]cutBinIndicesArray to which the cut indices will be saved into.
[in]noBinsVariable to which the number of bins adter cutting will be saved into.

Definition at line 3563 of file ProSHADE_maths.cpp.

3564 {
3565  //================================================ Initialise local variables
3566  proshade_single resCut = resolution;
3567  proshade_single minVal = std::numeric_limits < proshade_single >::infinity();
3568  *noBins = 0;
3569  std::vector< proshade_single > resDists;
3570 
3571  //================================================ Find the maximum bin to be used
3572  for ( size_t iter = 0; iter < resArray->size(); iter++ ) { ProSHADE_internal_misc::addToSingleVector ( &resDists, std::sqrt ( std::pow ( resArray->at(iter) - resCut, 2.0f ) ) ); }
3573  for ( size_t iter = 0; iter < resDists.size(); iter++ ) { if ( resDists.at(iter) < minVal ) { minVal = resDists.at(iter); (*noBins) = static_cast< proshade_signed > ( iter ); } }
3574 
3575  //================================================ Compute new map dimensions
3576  proshade_signed newXFrom = static_cast< proshade_signed > ( std::round ( ( static_cast< proshade_signed > ( xInds ) - 2 * (*noBins) ) / 2 ) );
3577  proshade_signed newYFrom = static_cast< proshade_signed > ( std::round ( ( static_cast< proshade_signed > ( yInds ) - 2 * (*noBins) ) / 2 ) );
3578  proshade_signed newZFrom = static_cast< proshade_signed > ( std::round ( ( static_cast< proshade_signed > ( zInds ) - 2 * (*noBins) ) / 2 ) );
3579  proshade_signed newXTo = static_cast< proshade_signed > ( std::round ( newXFrom + 2 * (*noBins) ) );
3580  proshade_signed newYTo = static_cast< proshade_signed > ( std::round ( newYFrom + 2 * (*noBins) ) );
3581  proshade_signed newZTo = static_cast< proshade_signed > ( std::round ( newZFrom + 2 * (*noBins) ) );
3582  *cutXDim = ( newXTo - newXFrom );
3583  *cutYDim = ( newYTo - newYFrom );
3584  *cutZDim = ( newZTo - newZFrom );
3585 
3586  //================================================ Create new binIndexing within only the new dimensions
3587  cutBinIndices = new proshade_signed[(*cutXDim) * (*cutYDim) * (*cutZDim)];
3588  ProSHADE_internal_misc::checkMemoryAllocation ( cutBinIndices, __FILE__, __LINE__, __func__ );
3589  for ( size_t iter = 0; iter < static_cast< size_t > ( (*cutXDim) * (*cutYDim) * (*cutZDim) ); iter++ ) { cutBinIndices[iter] = 0; }
3590 
3591  proshade_signed newArrPos = 0, origArrPos = 0;
3592  for ( proshade_signed xIt = newXFrom; xIt < newXTo; xIt++ )
3593  {
3594  for ( proshade_signed yIt = newYFrom; yIt < newYTo; yIt++ )
3595  {
3596  for ( proshade_signed zIt = newZFrom; zIt < newZTo; zIt++ )
3597  {
3598  //==================================== Skip if outside of box
3599  if ( ( xIt < 0 ) || ( yIt < 0 ) || ( zIt < 0 ) ) { continue; }
3600  if ( ( xIt >= xInds ) || ( yIt >= yInds ) || ( zIt >= zInds ) ) { continue; }
3601 
3602  //==================================== Find positions
3603  newArrPos = (zIt-newZFrom) + (*cutZDim) * ( (yIt-newYFrom) + (*cutYDim) * (xIt-newXFrom) );
3604  origArrPos = zIt + static_cast< proshade_signed > ( zInds ) * ( yIt + static_cast< proshade_signed > ( yInds ) * xIt );
3605 
3606  //==================================== Copy value
3607  cutBinIndices[newArrPos] = binIndexing[origArrPos];
3608  }
3609  }
3610  }
3611 
3612  //================================================ Done
3613  return ;
3614 
3615 }

◆ evaluateGLPolynomial()

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

This function evaluates the decomposed Legendre polynomial at a given position.

This function takes the series array (first value is ignored) which should contain the decomposed Legendre polynomial and it proceeds to evaluate it at the target position for up to terms terms.

Parameters
[in]seriesPointer to array with the polynomial decomposition values.
[in]targetThe value on which the polynomial is to be evaluated at.
[in]termsNumber of terms to which the polynomial is to be evaluated to.
[out]XThe value of the series at the target location.

Definition at line 450 of file ProSHADE_maths.cpp.

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

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

3219 {
3220  //================================================ Initialise variables
3221  std::vector< proshade_unsign > ret;
3222  std::vector< std::pair< proshade_unsign, bool > > sieveOfEratosthenesArray;
3223 
3224  //================================================ Sanity check
3225  if ( upTo < 2 ) { return ( ret ); }
3226 
3227  //================================================ Initialise the sieve array up to the required number
3228  for ( proshade_unsign iter = 2; iter <= upTo; iter++ ) { sieveOfEratosthenesArray.emplace_back ( std::pair< proshade_unsign, bool > ( iter, true ) ); }
3229 
3230  //================================================ For each entry in the array
3231  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); iter++ )
3232  {
3233  //============================================ If this entry is still true
3234  if ( sieveOfEratosthenesArray.at(iter).second )
3235  {
3236  //======================================== Set all entries with the position x * [this entry value] to false
3237  for ( proshade_unsign it = iter + sieveOfEratosthenesArray.at(iter).first; it < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); it += sieveOfEratosthenesArray.at(iter).first )
3238  {
3239  sieveOfEratosthenesArray.at(it).second = false;
3240  }
3241  }
3242  }
3243 
3244  //================================================ Copy passing results to return vector
3245  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); iter++ )
3246  {
3247  if ( sieveOfEratosthenesArray.at(iter).second ) { ProSHADE_internal_misc::addToUnsignVector ( &ret, sieveOfEratosthenesArray.at(iter).first ); }
3248  }
3249 
3250  //================================================ Done
3251  return ( ret );
3252 
3253 }

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

4290 {
4291  //================================================ Initialise variables
4292  proshade_signed arrPos;
4293  *mapPeak = 0.0;
4294 
4295  //================================================ Search the map
4296  for ( proshade_signed uIt = 0; uIt < static_cast<proshade_signed> ( xD ); uIt++ )
4297  {
4298  for ( proshade_signed vIt = 0; vIt < static_cast<proshade_signed> ( yD ); vIt++ )
4299  {
4300  for ( proshade_signed wIt = 0; wIt < static_cast<proshade_signed> ( zD ); wIt++ )
4301  {
4302  arrPos = wIt + static_cast< proshade_signed > ( zD ) * ( vIt + static_cast< proshade_signed > ( yD ) * uIt );
4303  if ( resIn[arrPos][0] > *mapPeak )
4304  {
4305  *mapPeak = resIn[arrPos][0];
4306  *trsX = static_cast< proshade_double > ( uIt );
4307  *trsY = static_cast< proshade_double > ( vIt );
4308  *trsZ = static_cast< proshade_double > ( wIt );
4309  }
4310  }
4311  }
4312  }
4313 
4314  //================================================ Done
4315  return ;
4316 
4317 }

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

4048 {
4049  //================================================ Initialise local variables
4050  std::vector< proshade_signed > ret;
4051  bool sameValStreak = false;
4052 
4053  //================================================ Peak is simply any position with both neighbours having lower position (with special care for borders)
4054  for ( proshade_signed index = static_cast< proshade_signed > ( data.size() ) - 1; index > 0; index-- )
4055  {
4056  //============================================ End border?
4057  if ( index == ( static_cast< proshade_signed > ( data.size() ) - 1 ) )
4058  {
4059  if ( data.size() > 1 ) { if ( data.at( static_cast< size_t > ( index ) ) > data.at( static_cast< size_t > ( index - 1 ) ) ) { ProSHADE_internal_misc::addToSignedVector ( &ret, index ); } }
4060  continue;
4061  }
4062 
4063  //============================================ Start border?
4064  if ( index == 0 )
4065  {
4066  if ( data.at( 0 ) > data.at( 1 ) ) { ProSHADE_internal_misc::addToSignedVector ( &ret, index ); }
4067  continue;
4068  }
4069 
4070  //============================================ Is this a peak?
4071  if ( ( data.at( static_cast< size_t > ( index ) ) > data.at( static_cast< size_t > ( index ) - 1 ) ) &&
4072  ( data.at( static_cast< size_t > ( index ) ) > data.at( static_cast< size_t > ( index ) + 1 ) ) ) { ProSHADE_internal_misc::addToSignedVector ( &ret, index ); continue; }
4073 
4074  //============================================ Deal with equally sized values
4075  if ( sameValStreak && ( index >= 1 ) && ( data.at( static_cast< size_t > ( index ) ) > data.at( static_cast< size_t > ( index - 1 ) ) ) ) { sameValStreak = false; ProSHADE_internal_misc::addToSignedVector ( &ret, index ); continue; }
4076  if ( sameValStreak && ( index == 0 ) ) { sameValStreak = false; ProSHADE_internal_misc::addToSignedVector ( &ret, index ); continue; }
4077  const FloatingPoint< proshade_double > lhs ( data.at( static_cast< size_t > ( index ) ) ), rhs ( 0.0 );
4078  if ( lhs.AlmostEquals ( rhs ) ) { continue; }
4079  if ( ( index > 1 ) && !sameValStreak )
4080  {
4081  if ( data.at( static_cast< size_t > ( index ) ) >= data.at( static_cast< size_t > ( index - 1 ) ) )
4082  {
4083  if ( data.at( static_cast< size_t > ( index ) ) >= data.at( static_cast< size_t > ( index + 1 ) ) )
4084  {
4085  sameValStreak = true;
4086  }
4087  }
4088  }
4089  }
4090 
4091  //================================================ Sort peaks
4092  std::sort ( ret.begin(), ret.end() );
4093 
4094  //================================================ Done
4095  return ( ret );
4096 
4097 }

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

2120 {
2121  //================================================ Allocate required memory
2122  proshade_double* inPlaneRotation = new proshade_double[9];
2123  proshade_double* basisChangeMat = new proshade_double[9];
2124  ProSHADE_internal_misc::checkMemoryAllocation ( inPlaneRotation, __FILE__, __LINE__, __func__ );
2125  ProSHADE_internal_misc::checkMemoryAllocation ( basisChangeMat, __FILE__, __LINE__, __func__ );
2126 
2127  //================================================ Normalise inputs
2128  proshade_double normF = std::sqrt( std::pow( x1, 2.0 ) + std::pow ( y1, 2.0 ) + std::pow ( z1, 2.0 ) );
2129  x1 /= normF; y1 /= normF; z1 /= normF;
2130 
2131  normF = std::sqrt( std::pow( x2, 2.0 ) + std::pow ( y2, 2.0 ) + std::pow ( z2, 2.0 ) );
2132  x2 /= normF; y2 /= normF; z2 /= normF;
2133 
2134  //================================================ Compute cross product's magnitude
2135  proshade_double* crossProd = ProSHADE_internal_maths::computeCrossProduct( &x1, &y1, &z1, &x2, &y2, &z2 );
2136  proshade_double crossProdMag = std::sqrt( std::pow( crossProd[0], 2.0 ) + std::pow ( crossProd[1], 2.0 ) + std::pow ( crossProd[2], 2.0 ) );
2137  delete[] crossProd;
2138 
2139  //================================================ Compute dot product
2140  proshade_double dotProd = ProSHADE_internal_maths::computeDotProduct ( &x1, &y1, &z1, &x2, &y2, &z2 );
2141 
2142  //================================================ Construct the in-plane rotation matrix
2143  inPlaneRotation[0] = dotProd; inPlaneRotation[1] = -crossProdMag; inPlaneRotation[2] = 0.0;
2144  inPlaneRotation[3] = crossProdMag; inPlaneRotation[4] = dotProd; inPlaneRotation[5] = 0.0;
2145  inPlaneRotation[6] = 0.0; inPlaneRotation[7] = 0.0; inPlaneRotation[8] = 1.0;
2146 
2147  //================================================ Construct change of basis matrix
2148  crossProd = ProSHADE_internal_maths::computeCrossProduct( &x2, &y2, &z2, &x1, &y1, &z1 );
2149  normF = std::sqrt ( std::pow ( x2 - ( dotProd * x1 ), 2.0 ) + std::pow ( y2 - ( dotProd * y1 ), 2.0 ) + std::pow ( z2 - ( dotProd * z1 ), 2.0 ) );
2150 
2151  basisChangeMat[0] = x1; basisChangeMat[1] = ( x2 - ( dotProd * x1 ) ) / normF; basisChangeMat[2] = crossProd[0];
2152  basisChangeMat[3] = y1; basisChangeMat[4] = ( y2 - ( dotProd * y1 ) ) / normF; basisChangeMat[5] = crossProd[1];
2153  basisChangeMat[6] = z1; basisChangeMat[7] = ( z2 - ( dotProd * z1 ) ) / normF; basisChangeMat[8] = crossProd[2];
2154 
2155  //================================================ Invert the change of basis matrix
2156  proshade_double* basisChangeMatInverse = ProSHADE_internal_maths::compute3x3MatrixInverse ( basisChangeMat );
2157 
2158  //================================================ Multiply inverse of change of basis matrix with the in plane rotation matrix, then multiply the result with the inverse
2159  proshade_double* tmpMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( basisChangeMat, inPlaneRotation );
2160  proshade_double* rotMat = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( tmpMat, basisChangeMatInverse );
2161 
2162  //================================================ Release memory
2163  delete[] crossProd;
2164  delete[] inPlaneRotation;
2165  delete[] basisChangeMat;
2166  delete[] basisChangeMatInverse;
2167  delete[] tmpMat;
2168 
2169  //================================================ Done
2170  return ( rotMat );
2171 
2172 }

◆ 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 = 1.0 
)

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

4114 {
4115  //================================================ Initialise local variables
4116  proshade_double threshold = 0.0;
4117  proshade_signed totSize = static_cast< proshade_signed > ( ( 1.0 / step ) + 1 );
4118  std::vector< std::pair < proshade_double, proshade_unsign > > vals;
4119  std::vector< proshade_double > hist ( static_cast< unsigned long int > ( totSize ), 0.0 );
4120  proshade_unsign histPos = 0;
4121 
4122  //================================================ Make sure window size is odd
4123  if ( windowSize % 2 == 0 ) { windowSize += 1; }
4124 
4125  //================================================ Get vector of pairs of peak heights and indices in CSym array
4126  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( CSym->size() ); symIt++ ) { if ( !std::isinf( CSym->at(symIt)[peakPos] ) ) { vals.emplace_back ( std::pair < proshade_double, proshade_unsign > ( CSym->at(symIt)[peakPos], symIt ) ); } }
4127 
4128  //================================================ Bump all top peaks together - we do not want single high peak overshadowing many good peaks
4129  for ( proshade_unsign vIt = 0; vIt < static_cast< proshade_unsign > ( vals.size() ); vIt++ ) { if ( vals.at(vIt).first > maxLim ) { vals.at(vIt).first = maxLim; } }
4130 
4131  //================================================ Convert all found heights to histogram from 0.0 to 1.0 by step
4132  for ( proshade_double it = 0.0; it <= 1.0; it = it + step )
4133  {
4134  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( vals.size() ); symIt++ )
4135  {
4136  //======================================== Is this height in the range?
4137  if ( ( vals.at(symIt).first > it ) && ( vals.at(symIt).first <= ( it + step ) ) ) { hist.at(histPos) += 1.0; }
4138  }
4139 
4140  //============================================ Update counter and continue
4141  histPos += 1;
4142  }
4143 
4144  //================================================ Smoothen the distribution
4145  std::vector< proshade_double > smoothened = ProSHADE_internal_maths::smoothen1D ( step, windowSize, sigma, hist );
4146 
4147  //================================================ Find peaks in smoothened data
4148  std::vector< proshade_signed > peaks = ProSHADE_internal_maths::findPeaks1D ( smoothened );
4149 
4150  //================================================ Determine threshold from the peaks
4151  size_t bestHistPos;
4152  if ( peaks.size() > 0 ) { bestHistPos = hist.size() - ( ( smoothened.size() - static_cast< size_t > ( peaks.at(peaks.size()-1) ) ) + ( ( static_cast< size_t > ( windowSize ) + 1 ) / 2 ) ); }
4153  else { bestHistPos = 0; }
4154  threshold = ( static_cast< proshade_double > ( bestHistPos ) * step );
4155 
4156  //================================================ Check that the threshold is not higher than the highest value
4157  proshade_double maxVal = 0.0;
4158  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( CSym->size() ); symIt++ ) { if ( maxVal < CSym->at(symIt)[peakPos] ) { maxVal = CSym->at(symIt)[peakPos]; } }
4159  if ( maxVal < threshold ) { threshold = maxVal - step; }
4160 
4161  //================================================ Done
4162  return ( threshold );
4163 
4164 }

◆ 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 = 1.0 
)

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

4181 {
4182  //================================================ Initialise local variables
4183  proshade_double threshold = 0.0;
4184  proshade_signed totSize = static_cast< proshade_signed > ( ( 1.0 / step ) + 1 );
4185  std::vector< std::pair < proshade_double, proshade_unsign > > vals;
4186  std::vector< proshade_double > hist ( static_cast< unsigned long int > ( totSize ), 0.0 );
4187  proshade_unsign histPos = 0;
4188 
4189  //================================================ Make sure window size is odd
4190  if ( windowSize % 2 == 0 ) { windowSize += 1; }
4191 
4192  //================================================ Get vector of pairs of peak heights and indices in CSym array
4193  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( CSym->size() ); symIt++ ) { if ( !std::isinf( CSym->at(symIt).at(peakPos) ) ) { vals.emplace_back ( std::pair < proshade_double, proshade_unsign > ( CSym->at(symIt).at(peakPos), symIt ) ); } }
4194 
4195  //================================================ Bump all top peaks together - we do not want single high peak overshadowing many good peaks
4196  for ( proshade_unsign vIt = 0; vIt < static_cast< proshade_unsign > ( vals.size() ); vIt++ ) { if ( vals.at(vIt).first > maxLim ) { vals.at(vIt).first = maxLim; } }
4197 
4198  //================================================ Convert all found heights to histogram from 0.0 to 1.0 by step
4199  for ( proshade_double it = 0.0; it <= 1.0; it = it + step )
4200  {
4201  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( vals.size() ); symIt++ )
4202  {
4203  //======================================== Is this height in the range?
4204  if ( ( vals.at(symIt).first > it ) && ( vals.at(symIt).first <= ( it + step ) ) ) { hist.at(histPos) += 1.0; }
4205  }
4206 
4207  //============================================ Update counter and continue
4208  histPos += 1;
4209  }
4210 
4211  //================================================ Smoothen the distribution
4212  std::vector< proshade_double > smoothened = ProSHADE_internal_maths::smoothen1D ( step, windowSize, sigma, hist );
4213 
4214  //================================================ Find peaks in smoothened data
4215  std::vector< proshade_signed > peaks = ProSHADE_internal_maths::findPeaks1D ( smoothened );
4216 
4217  //================================================ Determine threshold from the peaks
4218  size_t bestHistPos;
4219  if ( peaks.size() > 0 ) { bestHistPos = hist.size() - ( ( smoothened.size() - static_cast< size_t > ( peaks.at(peaks.size()-1) ) ) + ( ( static_cast< size_t > ( windowSize ) + 1 ) / 2 ) ); }
4220  else { bestHistPos = 0; }
4221  threshold = ( static_cast< proshade_double > ( bestHistPos ) * step );
4222 
4223  //================================================ Check that the threshold is not higher than the highest value
4224  proshade_double maxVal = 0.0;
4225  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( CSym->size() ); symIt++ ) { if ( maxVal < CSym->at(symIt).at(peakPos) ) { maxVal = CSym->at(symIt).at(peakPos); } }
4226  if ( maxVal < threshold ) { threshold = maxVal - step; }
4227 
4228  //================================================ Done
4229  return ( threshold );
4230 
4231 }

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

2480 {
2481  //================================================ Initialise variables
2482  std::vector < proshade_double > ret;
2483 
2484  //================================================ Solution
2485  proshade_double solX = - ( y1 * dot2 * z3 - y1 * dot3 * z2 - z1 * dot2 * y3 + z1 * dot3 * y2 + dot1 * y3 * z2 - dot1 * z3 * y2 ) /
2486  ( -x1 * y3 * z2 + x1 * z3 * y2 + y1 * x3 * z2 - y1 * z3 * x2 - z1 * x3 * y2 + z1 * y3 * x2 );
2487  proshade_double solY = - ( x1 * dot2 * z3 - x1 * dot3 * z2 - z1 * dot2 * x3 + z1 * dot3 * x2 + dot1 * x3 * z2 - dot1 * z3 * x2 ) /
2488  ( x1 * y3 * z2 - x1 * z3 * y2 - y1 * x3 * z2 + y1 * z3 * x2 + z1 * x3 * y2 - z1 * y3 * x2 );
2489  proshade_double solZ = - ( x1 * dot2 * y3 - x1 * dot3 * y2 - y1 * dot2 * x3 + y1 * dot3 * x2 + dot1 * x3 * y2 - dot1 * y3 * x2 ) /
2490  ( -x1 * y3 * z2 + x1 * z3 * y2 + y1 * x3 * z2 - y1 * z3 * x2 - z1 * x3 * y2 + z1 * y3 * x2 );
2491 
2492  //================================================ Normalise the axis to magnitude 1
2493  proshade_double normFactor = sqrt ( pow ( solX, 2.0 ) + pow ( solY, 2.0 ) + pow ( solZ, 2.0 ) );
2494  solX /= normFactor;
2495  solY /= normFactor;
2496  solZ /= normFactor;
2497 
2498  //================================================ Set largest axis element to positive (ProSHADE standard)
2499  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) );
2500  const FloatingPoint< proshade_double > rhs1 ( std::abs ( solX ) );
2501  const FloatingPoint< proshade_double > rhs2 ( std::abs ( solY ) );
2502  const FloatingPoint< proshade_double > rhs3 ( std::abs ( solZ ) );
2503  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( solX < 0.0 ) ) ||
2504  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( solY < 0.0 ) ) ||
2505  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( solZ < 0.0 ) ) ) { solX *= -1.0; solY *= -1.0; solZ *= -1.0; }
2506 
2507  //================================================ Save solutions
2511 
2512  //================================================ Done
2513  return ( ret );
2514 
2515 }

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

2334 {
2335  //================================================ Initialise variables
2336  std::vector < proshade_double > ret;
2337 
2338  //================================================ Solution
2339  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 ) -
2340  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 ) ) *
2341  ( 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 ) ) ) -
2342  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 ) /
2343  ( 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 ) ) );
2344  proshade_double solY = ( ( dot2 * pow ( x2, 2.0 ) * pow ( z1, 3.0 ) ) /
2345  ( 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  ( dot1 * pow ( x2, 2.0 ) * z2 * pow ( z1, 2.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  ( 2.0 * x1 * dot2 * x2 * z2 * pow ( z1, 2.0 ) ) /
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 ) - dot2 * z1 -
2350  ( 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 ) -
2351  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 ) *
2352  ( 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 ) /
2353  ( 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 ) ) +
2354  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) * z1 ) /
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 ) +
2356  ( x1 * dot1 * x2 * pow ( y2, 2.0 ) * z1 ) /
2357  ( 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  ( pow ( x1, 2.0 ) * dot2 * pow ( z2, 2.0 ) * z1 ) /
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  ( 2.0 * x1 * dot1 * x2 * pow ( z2, 2.0 ) * z1 ) /
2361  ( 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  ( y1 * dot1 * pow ( x2, 2.0 ) * y2 * z1 ) /
2363  ( 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  ( x1 * y1 * dot2 * x2 * y2 * z1 ) /
2365  ( 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 +
2366  ( 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 ) -
2367  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 ) *
2368  ( 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 ) ) ) /
2369  ( 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 ) ) -
2370  ( pow ( x1, 2.0 ) * dot1 * pow ( z2, 3.0 ) ) /
2371  ( 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 ) -
2372  ( pow ( x1, 2.0 ) * dot1 * pow ( y2, 2.0 ) * z2 ) /
2373  ( 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 ) -
2374  ( x1 * pow ( y1, 2.0 ) * dot2 * x2 * z2 ) /
2375  ( 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 ) +
2376  ( pow ( x1, 2.0 ) * y1 * dot2 * y2 * z2 ) /
2377  ( 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 ) +
2378  ( x1 * y1 * dot1 * x2 * y2 * z2 ) /
2379  ( 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 );
2380  proshade_double solZ = ( - ( dot2 * pow ( x2, 2.0 ) * y2 * pow ( z1, 3.0 ) ) /
2381  ( ( 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 ) ) -
2382  ( dot2 * pow ( x2, 2.0 ) * pow ( z1, 2.0 ) ) /
2383  ( 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 ) +
2384  ( dot1 * pow ( x2, 2.0 ) * y2 * z2 * pow ( z1, 2.0 ) ) /
2385  ( ( 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 ) ) +
2386  ( 2.0 * x1 * dot2 * x2 * y2 * z2 * pow ( z1, 2.0 ) ) /
2387  ( ( 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 ) ) +
2388  ( 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 ) -
2389  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 ) *
2390  ( 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 ) /
2391  ( 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 ) ) +
2392  ( dot2 * y2 * z1 ) / ( y1 * z2 - z1 * y2 ) +
2393  ( dot1 * pow ( x2, 2.0 ) * z2 * z1 ) /
2394  ( 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 ) +
2395  ( x1 * dot2 * x2 * z2 * z1 ) /
2396  ( 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 ) -
2397  ( x1 * dot1 * x2 * pow ( y2, 3.0 ) * z1 ) /
2398  ( ( 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 ) ) +
2399  ( y1 * dot1 * pow ( x2, 2.0 ) * pow ( y2, 2.0 ) * z1 ) /
2400  ( ( 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 ) ) +
2401  ( x1 * y1 * dot2 * x2 * pow ( y2, 2.0 ) * z1 ) /
2402  ( ( 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 ) ) -
2403  ( pow ( x1, 2.0 ) * dot2 * y2 * pow ( z2, 2.0 ) * z1 ) /
2404  ( ( 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 ) ) -
2405  ( 2.0 * x1 * dot1 * x2 * y2 * pow ( z2, 2.0 ) * z1 ) /
2406  ( ( 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 ) ) -
2407  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) * y2 * z1 ) /
2408  ( ( 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 +
2409  ( 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 ) -
2410  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 ) *
2411  ( 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 ) ) ) /
2412  ( 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 ) ) -
2413  ( 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 ) -
2414  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 ) *
2415  ( 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 ) ) ) /
2416  ( 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 ) ) -
2417  ( dot1 * y2 * z2 ) / ( y1 * z2 - z1 * y2 ) -
2418  ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) ) /
2419  ( 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 ) -
2420  ( x1 * dot1 * x2 * pow ( y2, 2.0 ) ) /
2421  ( 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 ) -
2422  ( x1 * dot1 * x2 * pow ( z2, 2.0 ) ) /
2423  ( 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 ) +
2424  ( y1 * dot1 * pow ( x2, 2.0 ) * y2 ) /
2425  ( 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 ) +
2426  ( x1 * y1 * dot2 * x2 * y2 ) /
2427  ( 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 ) +
2428  ( pow ( x1, 2.0 ) * dot1 * y2 * pow ( z2, 3.0 ) ) /
2429  ( ( 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 ) ) +
2430  ( pow ( x1, 2.0 ) * dot1 * pow ( y2, 3.0 ) * z2 ) /
2431  ( ( 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 ) ) -
2432  ( pow ( x1, 2.0 ) * y1 * dot2 * pow ( y2, 2.0 ) * z2 ) /
2433  ( ( 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 ) ) -
2434  ( x1 * y1 * dot1 * x2 * pow ( y2, 2.0 ) * z2 ) /
2435  ( ( 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 ) ) +
2436  ( x1 * pow ( y1, 2.0 ) * dot2 * x2 * y2 * z2 ) /
2437  ( ( 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;
2438 
2439  //================================================ Set largest axis element to positive (ProSHADE standard)
2440  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) );
2441  const FloatingPoint< proshade_double > rhs1 ( std::abs ( solX ) );
2442  const FloatingPoint< proshade_double > rhs2 ( std::abs ( solY ) );
2443  const FloatingPoint< proshade_double > rhs3 ( std::abs ( solZ ) );
2444  if ( ( ( lhs1.AlmostEquals ( rhs1 ) ) && ( solX < 0.0 ) ) ||
2445  ( ( lhs1.AlmostEquals ( rhs2 ) ) && ( solY < 0.0 ) ) ||
2446  ( ( lhs1.AlmostEquals ( rhs3 ) ) && ( solZ < 0.0 ) ) ) { solX *= -1.0; solY *= -1.0; solZ *= -1.0; }
2447 
2448  //================================================ Save solutions
2452 
2453  //================================================ Done
2454  return ( ret );
2455 
2456 }

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

715 {
716  //================================================ Initialise local variables
717  proshade_triplet* intData = new proshade_triplet [order];
718  ProSHADE_internal_misc::checkMemoryAllocation ( intData, __FILE__, __LINE__, __func__ );
719  proshade_triplet posVals;
720  proshade_unsign lesserPos = 0;
721  proshade_unsign upperPos = 0;
722  proshade_double lesserWeight = 0.0;
723  proshade_double upperWeight = 0.0;
724 
725  //================================================ Rescale to <order> points
726  for ( proshade_unsign absIter = 0; absIter < order; absIter++ )
727  {
728  //============================================ Init loop
729  posVals[0] = 0.0;
730  posVals[1] = 0.0;
731  posVals[2] = 0.0;
732 
733  //============================================ Find real position of abscissas
734  posVals[0] = ( ( abscissas[absIter] + 1.0 ) / 2.0 ) * integralOverRange;
735 
736 
737  //============================================ Find lesser and upper bounds
738  for ( proshade_unsign valIt = 0; valIt < valsSize; valIt++ )
739  {
740  if ( ( ( static_cast< proshade_double > ( valIt ) * maxSphereDists ) <= posVals[0] ) && ( ( ( static_cast< proshade_double > ( valIt ) + 1.0 ) * maxSphereDists ) > posVals[0] ) )
741  {
742  lesserPos = static_cast<proshade_unsign> ( valIt );
743  upperPos = static_cast<proshade_unsign> ( valIt + 1 );
744  break;
745  }
746  }
747 
748  //============================================ Linear Interpolation
749  lesserWeight = 0.0;
750  upperWeight = 0.0;
751  if ( lesserPos != 0 )
752  {
753  //======================================== 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 ...
754  lesserWeight = static_cast< proshade_double > ( upperPos ) - ( posVals[0] / maxSphereDists );
755  upperWeight = 1.0 - lesserWeight;
756 
757  posVals[1] = ( lesserWeight * vals[lesserPos-1][0] ) + ( upperWeight * vals[upperPos-1][0] );
758  posVals[2] = ( lesserWeight * vals[lesserPos-1][1] ) + ( upperWeight * vals[upperPos-1][1] );
759  }
760  else
761  {
762  //======================================== ... 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:
763  upperWeight = 1.0 - ( static_cast< proshade_double > ( upperPos ) - ( posVals[0] / maxSphereDists ) );
764 
765  posVals[1] = ( upperWeight * vals[upperPos-1][0] );
766  posVals[2] = ( upperWeight * vals[upperPos-1][1] );
767  }
768 
769  intData[absIter][0] = posVals[0];
770  intData[absIter][1] = posVals[1];
771  intData[absIter][2] = posVals[2];
772  }
773 
774  //================================================ Integrate
775  *retReal = 0.0;
776  *retImag = 0.0;
777  for ( proshade_unsign absPoint = 0; absPoint < order; absPoint++ )
778  {
779  *retReal += ( weights[absPoint] * intData[absPoint][1] );
780  *retImag += ( weights[absPoint] * intData[absPoint][2] );
781  }
782 
783  //================================================ Normalise
784  *retReal *= ( integralOverRange / 2.0 );
785  *retImag *= ( integralOverRange / 2.0 );
786 
787  //================================================ Release memory
788  delete[] intData;
789 
790  //================================================ Done
791  return ;
792 
793 }

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

625 {
626  //================================================ Initialise local variables
627  proshade_double ret = 0.0;
628  proshade_complex* intData = new proshade_complex[order];
629  ProSHADE_internal_misc::checkMemoryAllocation ( intData, __FILE__, __LINE__, __func__ );
630  proshade_complex posVals;
631  proshade_unsign lesserPos = 0;
632  proshade_unsign upperPos = 0;
633  proshade_double lesserWeight = 0.0;
634  proshade_double upperWeight = 0.0;
635 
636  //================================================ Rescale to <order> points
637  for ( proshade_unsign absIter = 0; absIter < order; absIter++ )
638  {
639  //============================================ Init loop
640  posVals[0] = 0.0;
641  posVals[1] = 0.0;
642 
643  //============================================ Find real position of abscissas
644  posVals[0] = ( ( abscissas[absIter] + 1.0 ) / 2.0 ) * integralOverRange;
645 
646 
647  //============================================ Find lesser and upper bounds
648  for ( proshade_unsign valIt = 0; valIt < valsSize; valIt++ )
649  {
650  if ( ( ( static_cast< proshade_double > ( valIt ) * maxSphereDists ) <= posVals[0] ) && ( ( ( static_cast< proshade_double > ( valIt ) + 1.0 ) * maxSphereDists ) > posVals[0] ) )
651  {
652  lesserPos = static_cast<proshade_unsign> ( valIt );
653  upperPos = static_cast<proshade_unsign> ( valIt + 1 );
654  break;
655  }
656  }
657 
658  //============================================ Linear Interpolation
659  lesserWeight = 0.0;
660  upperWeight = 0.0;
661  if ( lesserPos != 0 )
662  {
663  //======================================== 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 ...
664  lesserWeight = static_cast< proshade_double > ( upperPos ) - ( posVals[0] / maxSphereDists );
665  upperWeight = 1.0 - lesserWeight;
666 
667  posVals[1] = ( lesserWeight * vals[lesserPos-1] ) + ( upperWeight * vals[upperPos-1] );
668  }
669  else
670  {
671  //======================================== ... 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:
672  upperWeight = 1.0 - ( static_cast< proshade_double > ( upperPos ) - ( posVals[0] / maxSphereDists ) );
673 
674  posVals[1] = ( upperWeight * vals[upperPos-1] );
675  }
676 
677  intData[absIter][0] = posVals[0];
678  intData[absIter][1] = posVals[1];
679  }
680 
681  //================================================ Integrate
682  for ( proshade_unsign absPoint = 0; absPoint < order; absPoint++ )
683  {
684  ret += ( weights[absPoint] * intData[absPoint][1] );
685  }
686 
687  //================================================ Normalise
688  ret *= ( integralOverRange / 2.0 );
689 
690  //================================================ Release memory
691  delete[] intData;
692 
693  //================================================ Done
694  return ( ret );
695 
696 }

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

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

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

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

◆ getEulerZYZFromAngleAxis()

void ProSHADE_internal_maths::getEulerZYZFromAngleAxis ( 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 ZYZ angles representation.

This function does the angle-axis to Euler ZYZ 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 1612 of file ProSHADE_maths.cpp.

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

◆ getEulerZYZFromRotMatrix()

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

This function converts rotation matrix to the Euler ZYZ 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 1561 of file ProSHADE_maths.cpp.

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

◆ getEulerZYZFromSOFTPosition()

void ProSHADE_internal_maths::getEulerZYZFromSOFTPosition ( 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 (ZYZ 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 ZYZ 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 966 of file ProSHADE_maths.cpp.

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

◆ getGLFirstRealRoot()

void ProSHADE_internal_maths::getGLFirstRealRoot ( proshade_double  polyAtZero,
proshade_unsign  order,
proshade_double *  firstRoot,
proshade_double *  firstRootDeriv,
proshade_unsign  noSteps 
)

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]firstRootPointer to variable storing the first real root.
[in]firstRootDerivPointer to variable storing the derivative of the first real root.
[in]noStepsHow many steps should the search use?

Definition at line 386 of file ProSHADE_maths.cpp.

387 {
388  //================================================ Sanity check
389  if ( noSteps < 2 )
390  {
391  throw ProSHADE_exception ( "The number of steps is too low.", "EI00020", __FILE__, __LINE__, __func__, "The number of steps 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  *firstRoot = advanceGLPolyValue ( 0.0, -M_PI / 2.0, 0.0, order, noSteps );
396  proshade_double hlp = 0.0;
397  proshade_double hlpVal = static_cast<proshade_double> ( order );
398  proshade_double *polyTerms;
399  proshade_double *deriTerms;
400 
401  //================================================ Allocate memory
402  polyTerms = new proshade_double [noSteps+2];
403  deriTerms = new proshade_double [noSteps+1];
404  ProSHADE_internal_misc::checkMemoryAllocation ( polyTerms, __FILE__, __LINE__, __func__ );
405  ProSHADE_internal_misc::checkMemoryAllocation ( deriTerms, __FILE__, __LINE__, __func__ );
406 
407  //================================================ Pre-set values
408  polyTerms[0] = 0.0;
409  polyTerms[1] = polyAtZero;
410  deriTerms[0] = 0.0;
411 
412  //================================================ Prepare polynomial decomposition into terms
413  for ( proshade_unsign iter = 0; iter <= noSteps - 2; iter = iter + 2 )
414  {
415  hlp = static_cast<proshade_double> ( iter );
416 
417  polyTerms[iter+2] = 0.0;
418  polyTerms[iter+3] = ( hlp * ( hlp + 1.0 ) - hlpVal * ( hlpVal + 1.0 ) ) * polyTerms[iter+1] / (hlp + 1.0) / (hlp + 2.0 );
419 
420  deriTerms[iter+1] = 0.0;
421  deriTerms[iter+2] = ( hlp + 2.0 ) * polyTerms[iter+3];
422  }
423 
424  //================================================ Evaluate the polynomial and its derivative to determine the first root and derivative value
425  for ( proshade_double iter = 0; iter < noSteps; iter++ )
426  {
427  *firstRoot = *firstRoot - evaluateGLPolynomial ( polyTerms, *firstRoot, noSteps ) / evaluateGLPolynomial ( deriTerms, *firstRoot, noSteps-1 );
428  }
429  *firstRootDeriv = evaluateGLPolynomial ( deriTerms, *firstRoot, noSteps-1 );
430 
431  //================================================ Free memory
432  delete polyTerms;
433  delete deriTerms;
434 
435  //================================================ Done
436  return ;
437 
438 }

◆ 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  noSteps 
)

Function to prepare abscissas and weights for Gauss-Legendre integration using the Glaser-Liu-Rokhlin method.

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]noStepsThe number of steps to be used in approximations.

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 and we know the value already
308  if ( order % 2 == 1 )
309  {
310  abscissas[((order-1)/2)] = polyValue;
311  weights[((order-1)/2)] = deriValue;
312  }
313  //================================================ But if order is even, find the first root as follows
314  else
315  {
316  getGLFirstRealRoot ( polyValue, order, &abscissas[(order/2)], &weights[(order/2)], noSteps );
317  }
318 
319  //================================================ Now, having computed the first root, complete the series
320  completeAbscissasAndWeights ( order, abscissas, weights, noSteps );
321 
322  //================================================ Correct weights by abscissa 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 += 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 3359 of file ProSHADE_maths.cpp.

3360 {
3361  //================================================ Compute volume and proportions
3362  proshade_single vol = ( xDim * yDim * zDim );
3363  proshade_single sa = ( yDim * zDim ) / vol;
3364  proshade_single sb = ( xDim * zDim ) / vol;
3365  proshade_single sc = ( xDim * yDim ) / vol;
3366 
3367  //================================================ Compute distance
3368  proshade_single s2 = ( std::pow ( h * sa, 2.0f ) +
3369  std::pow ( k * sb, 2.0f ) +
3370  std::pow ( l * sc, 2.0f ) ) / 4.0f;
3371 
3372  //================================================ Deal with F000
3373  if ( s2 == 0.0f ) { s2 = 0.0000000001f; }
3374 
3375  //================================================ Done
3376  return ( 1.0f / ( 2.0f * std::sqrt ( s2 ) ) );
3377 
3378 }

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

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

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

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

◆ getRotationMatrixFromEulerZYZAngles() [1/2]

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

Function to find the rotation matrix from Euler angles (ZYZ 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 1019 of file ProSHADE_maths.cpp.

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

◆ getRotationMatrixFromEulerZYZAngles() [2/2]

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

Function to find the rotation matrix from Euler angles (ZYZ 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 1048 of file ProSHADE_maths.cpp.

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

◆ getSOFTPositionFromEulerZYZ()

void ProSHADE_internal_maths::getSOFTPositionFromEulerZYZ ( 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 (ZYZ convention).

This function does the conversion from Euler angles ZYZ 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 991 of file ProSHADE_maths.cpp.

992 {
993  //================================================ Convert Euler angles to indices
994  *x = ( eulerBeta * static_cast<proshade_double> ( band ) * 2.0 ) / M_PI;
995  *y = ( eulerGamma * static_cast<proshade_double> ( band ) ) / M_PI;
996  *z = ( eulerAlpha * static_cast<proshade_double> ( band ) ) / M_PI;
997 
998  //================================================ Keep value within boundaries
999  if ( *x >= ( 2.0 * static_cast<proshade_double> ( band - 1 ) ) ) { *x = ( 2.0 * static_cast<proshade_double> ( band ) ) - 1.0; }
1000  if ( *y >= ( 2.0 * static_cast<proshade_double> ( band - 1 ) ) ) { *y = ( 2.0 * static_cast<proshade_double> ( band ) ) - 1.0; }
1001  if ( *z >= ( 2.0 * static_cast<proshade_double> ( band - 1 ) ) ) { *z = ( 2.0 * static_cast<proshade_double> ( band ) ) - 1.0; }
1002 
1003  if ( *x < 0.0 ) { *x = 0.0; }
1004  if ( *y < 0.0 ) { *y = 0.0; }
1005  if ( *z < 0.0 ) { *z = 0.0; }
1006 
1007  //================================================ Done
1008  return ;
1009 
1010 }

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

3065 {
3066  //================================================ Initialise variables
3067  bool ret = true;
3068  proshade_unsign whichImprove = 0;
3069 
3070  //================================================ For each already detected member
3071  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
3072  {
3073  //============================================ Is fold the same?
3074  const FloatingPoint< proshade_double > lhs ( CSymList->at(grIt)[0] ), rhs ( axis[0] );
3075  if ( lhs.AlmostEquals ( rhs ) )
3076  {
3077  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], axis[1], axis[2], axis[3], tolerance ) )
3078  {
3079  ret = false;
3080  whichImprove = grIt;
3081  break;
3082  }
3083  }
3084  }
3085 
3086  //================================================ Improve, if required
3087  if ( improve && !ret )
3088  {
3089  if ( axis[5] > CSymList->at(whichImprove)[5] )
3090  {
3091  CSymList->at(whichImprove)[1] = axis[1];
3092  CSymList->at(whichImprove)[2] = axis[2];
3093  CSymList->at(whichImprove)[3] = axis[3];
3094  CSymList->at(whichImprove)[4] = axis[4];
3095  CSymList->at(whichImprove)[5] = axis[5];
3096  }
3097  }
3098 
3099  //================================================ Done
3100  return ( ret );
3101 
3102 }

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

3117 {
3118  //================================================ Initialise variables
3119  bool ret = true;
3120 
3121  //================================================ For each already detected member
3122  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
3123  {
3124  const FloatingPoint< proshade_double > lhs ( fold ), rhs ( CSymList->at(grIt)[0] );
3125  if ( lhs.AlmostEquals ( rhs ) )
3126  {
3127  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], X, Y, Z, tolerance ) )
3128  {
3129  ret = false;
3130  break;
3131  }
3132  }
3133  }
3134 
3135  //================================================ Done
3136  return ( ret );
3137 
3138 }

◆ isPrime()

bool ProSHADE_internal_maths::isPrime ( proshade_unsign  toCheck)

This function check is the supplied number is prime or not.

Parameters
[in]toCheckThe number which should be checked for being prime.

Definition at line 3259 of file ProSHADE_maths.cpp.

3260 {
3261  //================================================ Initialise local variables
3262  bool ret = true;
3263 
3264  //================================================ Deal with exceptions
3265  if ( ( toCheck == 0 ) || ( toCheck == 1 ) ) { ret = false; return ( ret ); }
3266 
3267  //================================================ Naively test
3268  for ( proshade_unsign divider = 2; divider <= static_cast< proshade_unsign > ( std::round( toCheck / 2 ) ); divider++ )
3269  {
3270  if ( toCheck % divider == 0 ) { ret = false; break; }
3271  }
3272 
3273  //================================================ Done
3274  return ( ret );
3275 
3276 }

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

2524 {
2525  //================================================ Initialise variables
2526  std::vector< proshade_double > ret;
2527 
2528  //================================================ Compute
2529  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(0) ) +
2530  ( el1->at(1) * el2->at(3) ) +
2531  ( el1->at(2) * el2->at(6) ) );
2532  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(1) ) +
2533  ( el1->at(1) * el2->at(4) ) +
2534  ( el1->at(2) * el2->at(7) ) );
2535  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(2) ) +
2536  ( el1->at(1) * el2->at(5) ) +
2537  ( el1->at(2) * el2->at(8) ) );
2538 
2539  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(0) ) +
2540  ( el1->at(4) * el2->at(3) ) +
2541  ( el1->at(5) * el2->at(6) ) );
2542  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(1) ) +
2543  ( el1->at(4) * el2->at(4) ) +
2544  ( el1->at(5) * el2->at(7) ) );
2545  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(2) ) +
2546  ( el1->at(4) * el2->at(5) ) +
2547  ( el1->at(5) * el2->at(8) ) );
2548 
2549  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(0) ) +
2550  ( el1->at(7) * el2->at(3) ) +
2551  ( el1->at(8) * el2->at(6) ) );
2552  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(1) ) +
2553  ( el1->at(7) * el2->at(4) ) +
2554  ( el1->at(8) * el2->at(7) ) );
2555  ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(2) ) +
2556  ( el1->at(7) * el2->at(5) ) +
2557  ( el1->at(8) * el2->at(8) ) );
2558 
2559  //================================================ Done
2560  return ( ret );
2561 
2562 }

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

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

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

1769 {
1770  //================================================ Compute and return
1771  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) ) );
1772 
1773 }

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

2745 {
2746  //================================================ Initialise variables
2747  proshade_double lonM, lonP, latM, latP, movSum;
2748  std::vector<proshade_double> latVals ( 3 );
2749  std::vector<proshade_double> lonVals ( 3 );
2750  proshade_double learningRate = 0.1;
2751  proshade_double prevVal = *bestSum;
2752  proshade_double valChange = 999.9;
2753  proshade_double origBestLat = std::round ( *bestLattitude );
2754  proshade_double origBestLon = std::round ( *bestLongitude );
2755  proshade_double tmpVal;
2756 
2757  //================================================ Initialise interpolators in all directions around the point of interest
2758  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsMinusMinus;
2759  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsMinusPlus;
2760  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsPlusMinus;
2761  std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsPlusPlus;
2762  prepareBiCubicInterpolatorsMinusMinus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsMinusMinus, sphereMappedRotFun );
2763  prepareBiCubicInterpolatorsMinusPlus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsMinusPlus, sphereMappedRotFun );
2764  prepareBiCubicInterpolatorsPlusMinus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsPlusMinus, sphereMappedRotFun );
2765  prepareBiCubicInterpolatorsPlusPlus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsPlusPlus, sphereMappedRotFun );
2766 
2767  //================================================ Start the pseudo gradient ascent (while there is some change)
2768  while ( valChange > 0.0001 )
2769  {
2770  //============================================ Find the surrounding points to the currently best position
2771  lonM = *bestLongitude - step;
2772  lonP = *bestLongitude + step;
2773  latM = *bestLattitude - step;
2774  latP = *bestLattitude + step;
2775 
2776  //============================================ Deal with optimising outside of prepared range - recursion
2777  const FloatingPoint< proshade_double > lhs1 ( *bestLattitude ), rhs1 ( origBestLat - 1.0 );
2778  const FloatingPoint< proshade_double > lhs2 ( *bestLattitude ), rhs2 ( origBestLat + 1.0 );
2779  const FloatingPoint< proshade_double > lhs3 ( *bestLongitude ), rhs3 ( origBestLon - 1.0 );
2780  const FloatingPoint< proshade_double > lhs4 ( *bestLongitude ), rhs4 ( origBestLon + 1.0 );
2781  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; }
2782  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; }
2783  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; }
2784  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; }
2785 
2786  //============================================ Prepare vectors of tested positions
2787  latVals.at(0) = latM; latVals.at(1) = *bestLattitude; latVals.at(2) = latP;
2788  lonVals.at(0) = lonM; lonVals.at(1) = *bestLongitude; lonVals.at(2) = lonP;
2789 
2790  //============================================ Find the best change
2791  for ( proshade_unsign laIt = 0; laIt < static_cast<proshade_unsign> ( latVals.size() ); laIt++ )
2792  {
2793  for ( proshade_unsign loIt = 0; loIt < static_cast<proshade_unsign> ( lonVals.size() ); loIt++ )
2794  {
2795  //==================================== For this combination of lat and lon, find sum over spheres
2796  movSum = 1.0;
2797  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sphereList->size() ); iter++ )
2798  {
2799  //================================ Interpolate using correct interpolators
2800  if ( ( latVals.at(laIt) <= origBestLat ) && ( lonVals.at(loIt) <= origBestLon ) ) { movSum += interpolsMinusMinus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2801  if ( ( latVals.at(laIt) <= origBestLat ) && ( lonVals.at(loIt) > origBestLon ) ) { movSum += interpolsMinusPlus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2802  if ( ( latVals.at(laIt) > origBestLat ) && ( lonVals.at(loIt) <= origBestLon ) ) { movSum += interpolsPlusMinus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2803  if ( ( latVals.at(laIt) > origBestLat ) && ( lonVals.at(loIt) > origBestLon ) ) { movSum += interpolsPlusPlus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2804  }
2805 
2806  //==================================== If position has improved, save it
2807  if ( *bestSum < movSum )
2808  {
2809  *bestSum = movSum;
2810  *bestLongitude = lonVals.at(loIt);
2811  *bestLattitude = latVals.at(laIt);
2812  }
2813  }
2814  }
2815 
2816  //============================================ Prepare for next iteration
2817  valChange = std::floor ( 100000.0 * ( *bestSum - prevVal ) ) / 100000.0;
2818  prevVal = std::floor ( 100000.0 * ( *bestSum ) ) / 100000.0;
2819  step = std::min ( 0.2, std::max ( ( valChange / step ) * learningRate, 0.01 ) );
2820  if ( learningRate >= 0.02 ) { learningRate -= 0.01; }
2821  }
2822 
2823  //================================================ Release interpolators memory
2824  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsMinusMinus.size() ); intIt++ ) { delete interpolsMinusMinus.at(intIt); }
2825  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsMinusPlus.size() ); intIt++ ) { delete interpolsMinusPlus.at(intIt); }
2826  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsPlusMinus.size() ); intIt++ ) { delete interpolsPlusMinus.at(intIt); }
2827  for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsPlusPlus.size() ); intIt++ ) { delete interpolsPlusPlus.at(intIt); }
2828 
2829  //================================================ Done
2830  return ;
2831 }

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

2845 {
2846  //================================================ Initialise local variables
2847  proshade_signed latHlp, lonHlp;
2848  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2849 
2850  //================================================ Prepare the interpolator objects for interpolation around the position
2851  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2852  {
2853  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2854  proshade_double** interpGrid = new proshade_double*[4];
2855  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2856 
2857  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2858  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2859  {
2860  interpGrid[iter] = new proshade_double[4];
2861  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2862  }
2863 
2864  //============================================ Fill in the value grid on which the interpolation is to be done
2865  for ( proshade_signed latIt = 0; latIt < 4; latIt++ )
2866  {
2867  for ( proshade_signed lonIt = 0; lonIt < 4; lonIt++ )
2868  {
2869  latHlp = static_cast< proshade_signed > ( bestLattitude - 2.0 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2870  lonHlp = static_cast< proshade_signed > ( bestLongitude - 2.0 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2871  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
2872  }
2873  }
2874 
2875  //============================================ Create the interpolators
2876  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude - 1.0, bestLongitude - 1.0 );
2877  interpols->emplace_back ( biCubInterp );
2878 
2879  //============================================ Release memory
2880  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2881  delete[] interpGrid;
2882  }
2883 
2884  //================================================ Done
2885  return ;
2886 }

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

2900 {
2901  //================================================ Initialise local variables
2902  proshade_signed latHlp, lonHlp;
2903  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2904 
2905  //================================================ Prepare the interpolator objects for interpolation around the position
2906  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2907  {
2908  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2909  proshade_double** interpGrid = new proshade_double*[4];
2910  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2911 
2912  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2913  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2914  {
2915  interpGrid[iter] = new proshade_double[4];
2916  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2917  }
2918 
2919  //============================================ Fill in the value grid on which the interpolation is to be done
2920  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2921  {
2922  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2923  {
2924  latHlp = static_cast< proshade_signed > ( bestLattitude - 2 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2925  lonHlp = static_cast< proshade_signed > ( bestLongitude - 1 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2926  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ) , static_cast< proshade_unsign > ( lonHlp ) );
2927  }
2928  }
2929 
2930  //============================================ Create the interpolators
2931  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude - 1.0, bestLongitude );
2932  interpols->emplace_back ( biCubInterp );
2933 
2934  //============================================ Release memory
2935  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2936  delete[] interpGrid;
2937  }
2938 
2939  //================================================ Done
2940  return ;
2941 }

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

2955 {
2956  //================================================ Initialise local variables
2957  proshade_signed latHlp, lonHlp;
2958  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
2959 
2960  //================================================ Prepare the interpolator objects for interpolation around the position
2961  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2962  {
2963  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2964  proshade_double** interpGrid = new proshade_double*[4];
2965  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2966 
2967  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2968  for ( proshade_unsign iter = 0; iter < 4; iter++ )
2969  {
2970  interpGrid[iter] = new proshade_double[4];
2971  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2972  }
2973 
2974  //============================================ Fill in the value grid on which the interpolation is to be done
2975  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2976  {
2977  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2978  {
2979  latHlp = static_cast< proshade_signed > ( bestLattitude - 1 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2980  lonHlp = static_cast< proshade_signed > ( bestLongitude - 2 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2981  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
2982  }
2983  }
2984 
2985  //============================================ Create the interpolators
2986  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude, bestLongitude - 1.0 );
2987  interpols->emplace_back ( biCubInterp );
2988 
2989  //============================================ Release memory
2990  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2991  delete[] interpGrid;
2992  }
2993 
2994  //================================================ Done
2995  return ;
2996 }

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

3010 {
3011  //================================================ Initialise local variables
3012  proshade_signed latHlp, lonHlp;
3013  proshade_signed angDim = static_cast< proshade_signed > ( sphereMappedRotFun->at(0)->getAngularDim() );
3014 
3015  //================================================ Prepare the interpolator objects for interpolation around the position
3016  for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
3017  {
3018  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
3019  proshade_double** interpGrid = new proshade_double*[4];
3020  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
3021 
3022  //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
3023  for ( proshade_unsign iter = 0; iter < 4; iter++ )
3024  {
3025  interpGrid[iter] = new proshade_double[4];
3026  ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
3027  }
3028 
3029  //============================================ Fill in the value grid on which the interpolation is to be done
3030  for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
3031  {
3032  for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
3033  {
3034  latHlp = static_cast< proshade_signed > ( bestLattitude - 1 + static_cast< proshade_double > ( latIt ) ); if ( latHlp < 0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
3035  lonHlp = static_cast< proshade_signed > ( bestLongitude - 1 + static_cast< proshade_double > ( lonIt ) ); if ( lonHlp < 0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
3036  interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( static_cast< proshade_unsign > ( latHlp ), static_cast< proshade_unsign > ( lonHlp ) );
3037  }
3038  }
3039 
3040  //============================================ Create the interpolators
3041  ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude, bestLongitude );
3042  interpols->emplace_back ( biCubInterp );
3043 
3044  //============================================ Release memory
3045  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
3046  delete[] interpGrid;
3047  }
3048 
3049  //================================================ Done
3050  return ;
3051 }

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

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

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

875 {
876  //================================================ Initialise local variables
877  char job = 'A'; // Save computation of parts of U and V matrices, they are not needed here
878  double* singularValues = new double[dim]; // The array of singular values
879  double *rotMatU = new double [dim*dim]; // The U matrix space
880  double *rotMatV = new double [dim*dim]; // The V^T matrix space
881  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
882  int workDim = static_cast< int > ( 2 * ( ( 4 * dim * dim ) + ( 7 * dim ) ) ); // Formalism stating just that
883  double* rwork = new double[static_cast<proshade_unsign>((5 * dim) + 5 * pow(dim,2))]; // Required by LAPACK
884  int* iwork = new int[(8 * dim)]; // Required by LAPACK
885  int returnValue = 0; // This will tell if operation succeeded
886  ProSHADE_internal_misc::checkMemoryAllocation ( singularValues, __FILE__, __LINE__, __func__ );
887  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatU, __FILE__, __LINE__, __func__ );
888  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatV, __FILE__, __LINE__, __func__ );
889  ProSHADE_internal_misc::checkMemoryAllocation ( work, __FILE__, __LINE__, __func__ );
890  ProSHADE_internal_misc::checkMemoryAllocation ( rwork, __FILE__, __LINE__, __func__ );
891  ProSHADE_internal_misc::checkMemoryAllocation ( iwork, __FILE__, __LINE__, __func__ );
892 
893  //================================================ Load input data into array in column-major order
894  double *matrixToDecompose = new double[dim*dim];
895  ProSHADE_internal_misc::checkMemoryAllocation ( matrixToDecompose, __FILE__, __LINE__, __func__ );
896  for ( int rowIt = 0; rowIt < dim; rowIt++ )
897  {
898  for ( int colIt = 0; colIt < dim; colIt++ )
899  {
900  matrixToDecompose[(colIt*dim)+rowIt] = mat[(rowIt*dim)+colIt];
901  }
902  }
903 
904  //================================================ Run LAPACK ZGESDD
905  dgesdd_ ( &job, &dim, &dim, matrixToDecompose, &dim, singularValues, rotMatU, &dim, rotMatV, &dim,
906  work, &workDim, rwork, iwork, &returnValue );
907 
908  //================================================ Free memory
909  delete[] work;
910  delete[] rwork;
911  delete[] iwork;
912  delete[] matrixToDecompose;
913  delete[] singularValues;
914 
915  //================================================ Check result
916  if ( ( returnValue != 0 ) && ( fail ) )
917  {
918  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." );
919  }
920  if ( ( returnValue != 0 ) && ( !fail ) )
921  {
922  uAndV[0] = -777.7;
923  return ;
924  }
925 
926  //================================================ Save U
927  for ( proshade_signed rowIt = 0; rowIt < dim; rowIt++ )
928  {
929  for ( proshade_signed colIt = 0; colIt < dim; colIt++ )
930  {
931  uAndV[(rowIt*3)+colIt] = rotMatU[( rowIt * 3 ) + colIt];
932  }
933  }
934 
935  //================================================ Save V
936  for ( proshade_signed rowIt = 0; rowIt < dim; rowIt++ )
937  {
938  for ( proshade_signed colIt = 0; colIt < dim; colIt++ )
939  {
940  uAndV[(rowIt*3)+colIt+9] = rotMatV[( rowIt * 3 ) + colIt];
941  }
942  }
943 
944  //================================================ Release the rest of the memory
945  delete[] rotMatU;
946  delete[] rotMatV;
947 
948  //================================================ Done
949  return ;
950 
951 }

◆ rotationMatrixSimilarity() [1/2]

bool ProSHADE_internal_maths::rotationMatrixSimilarity ( proshade_double *  mat1,
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]mat1Pointer to double array of 9 numbers representing first rotation matrix.
[in]mat1Pointer to double array of 9 numbers representing second rotation matrix.
[in]toleranceDouble number representing the maximum allowed error on the distance.
[out]retBoolean decision if the two matrices are similar or not.

Definition at line 2601 of file ProSHADE_maths.cpp.

2602 {
2603  //================================================ Initialise variables
2604  bool ret = false;
2605 
2606  //================================================ Compare to tolerance
2607  if ( tolerance > std::abs ( ProSHADE_internal_maths::rotationMatrixSimilarityValue ( mat1, mat2 ) ) ) { ret = true; }
2608 
2609  //================================================ Done
2610  return ( ret );
2611 
2612 }

◆ rotationMatrixSimilarity() [2/2]

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]retBoolean decision if the two matrices are similar or not.

Definition at line 2576 of file ProSHADE_maths.cpp.

2577 {
2578  //================================================ Initialise variables
2579  bool ret = false;
2580 
2581  //================================================ Compare to tolerance
2582  if ( tolerance > std::abs ( ProSHADE_internal_maths::rotationMatrixSimilarityValue ( mat1, mat2 ) ) ) { ret = true; }
2583 
2584  //================================================ Done
2585  return ( ret );
2586 
2587 }

◆ rotationMatrixSimilarityValue() [1/2]

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

This function computes the distance between two rotation matrices and returns it.

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. Subtracting 3 will then result in matrix similarity measure.

Parameters
[in]mat1Pointer to double array of 9 numbers representing first rotation matrix.
[in]mat1Pointer to double array of 9 numbers representing second rotation matrix.
[out]retMatrix similarity measure.

Definition at line 2649 of file ProSHADE_maths.cpp.

2650 {
2651  //================================================ Compute trace of mat1 * mat2^T
2652  proshade_double ret = ( mat1[0] * mat2[0] ) + ( mat1[1] * mat2[1] ) + ( mat1[2] * mat2[2] );
2653  ret += ( mat1[3] * mat2[3] ) + ( mat1[4] * mat2[4] ) + ( mat1[5] * mat2[5] );
2654  ret += ( mat1[6] * mat2[6] ) + ( mat1[7] * mat2[7] ) + ( mat1[8] * mat2[8] );
2655 
2656  //================================================ Subtract 3 (so that we would have 0 in case of identical matrices)
2657  ret -= 3.0;
2658 
2659  //================================================ Done
2660  return ( ret );
2661 
2662 }

◆ rotationMatrixSimilarityValue() [2/2]

proshade_double ProSHADE_internal_maths::rotationMatrixSimilarityValue ( std::vector< proshade_double > *  mat1,
std::vector< proshade_double > *  mat2 
)

This function computes the distance between two rotation matrices and returns it.

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. Subtracting 3 will then result in matrix similarity measure.

Parameters
[in]mat1Vector of 9 numbers representing first rotation matrix.
[in]mat1Vector of 9 numbers representing second rotation matrix.
[out]retMatrix similarity measure.

Definition at line 2624 of file ProSHADE_maths.cpp.

2625 {
2626  //================================================ Compute trace of mat1 * mat2^T
2627  proshade_double ret = ( mat1->at(0) * mat2->at(0) ) + ( mat1->at(1) * mat2->at(1) ) + ( mat1->at(2) * mat2->at(2) );
2628  ret += ( mat1->at(3) * mat2->at(3) ) + ( mat1->at(4) * mat2->at(4) ) + ( mat1->at(5) * mat2->at(5) );
2629  ret += ( mat1->at(6) * mat2->at(6) ) + ( mat1->at(7) * mat2->at(7) ) + ( mat1->at(8) * mat2->at(8) );
2630 
2631  //================================================ Subtract 3 (so that we would have 0 in case of identical matrices)
2632  ret -= 3.0;
2633 
2634  //================================================ Done
2635  return ( ret );
2636 
2637 }

◆ smoothen1D()

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

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.
[in]decRoundTo which decimal place should the gausian be rounded to? If no rounding is required, please use -1.
[out]smoothenedA vector of smoothened values for the input data with length hist.size() - (windowSize - 1).

Definition at line 3313 of file ProSHADE_maths.cpp.

3314 {
3315  //================================================ Initialise local variables
3316  proshade_signed windowHalf = ( windowSize - 1 ) / 2;
3317  proshade_signed totSize = static_cast< proshade_signed > ( ( 1.0 / step ) + 1 );
3318  std::vector< proshade_double > smoothened ( static_cast< size_t > ( totSize - ( windowSize - 1 ) ), 0.0 );
3319  std::vector< proshade_double > winWeights ( static_cast< size_t > ( windowSize ), 0.0 );
3320 
3321  //================================================ Prepare window weights
3322  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 ); }
3323 
3324  //================================================ Compute smoothened data
3325  for ( proshade_unsign it = 0; it < static_cast< proshade_unsign > ( smoothened.size() ); it++ )
3326  {
3327  //============================================ Compute window weighted average
3328  for ( proshade_signed winIt = 0; winIt < windowSize; winIt++ )
3329  {
3330  smoothened.at(it) += winWeights.at( static_cast< size_t > ( winIt ) ) * data.at( static_cast< size_t > ( static_cast< proshade_signed > ( it ) + winIt ) );
3331  }
3332  }
3333 
3334  //================================================ Round as requested
3335  if ( decRound >= 0 )
3336  {
3337  proshade_double zeroMultip = std::pow ( 10.0, decRound );
3338  for ( proshade_unsign it = 0; it < static_cast< proshade_unsign > ( smoothened.size() ); it++ )
3339  {
3340  smoothened.at(it) = std::round ( smoothened.at(it) * zeroMultip ) / zeroMultip;
3341  }
3342  }
3343 
3344  //================================================ Done
3345  return ( smoothened );
3346 
3347 }

◆ transpose3x3MatrixInPlace() [1/2]

void ProSHADE_internal_maths::transpose3x3MatrixInPlace ( proshade_double *  mat)

Transposes 3x3 matrix in place.

Parameters
[in]matThe matrix to be transposed.

Definition at line 2000 of file ProSHADE_maths.cpp.

2001 {
2002  //================================================ Initialise variables
2003  proshade_double tmp;
2004 
2005  //================================================ Transpose the non-diagonal values
2006  tmp = mat[1];
2007  mat[1] = mat[3];
2008  mat[3] = tmp;
2009 
2010  tmp = mat[2];
2011  mat[2] = mat[6];
2012  mat[6] = tmp;
2013 
2014  tmp = mat[5];
2015  mat[5] = mat[7];
2016  mat[7] = tmp;
2017 
2018  //================================================ Done
2019  return ;
2020 
2021 }

◆ transpose3x3MatrixInPlace() [2/2]

void ProSHADE_internal_maths::transpose3x3MatrixInPlace ( proshade_single *  mat)

Transposes 3x3 matrix in place.

Parameters
[in]matThe matrix to be transposed.

Definition at line 1973 of file ProSHADE_maths.cpp.

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

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

2681 {
2682  //================================================ Initialise variables
2683  bool ret = false;
2684 
2685  //================================================ Cosine distance
2686  proshade_double cosDist = ( ( a1 * b1 ) + ( a2 * b2 ) + ( a3 * b3 ) ) /
2687  ( sqrt( pow( a1, 2.0 ) + pow( a2, 2.0 ) + pow( a3, 2.0 ) ) *
2688  sqrt( pow( b1, 2.0 ) + pow( b2, 2.0 ) + pow( b3, 2.0 ) ) );
2689 
2690  //================================================ Compare the absolute value of distance to 1.0 - tolerance
2691  if ( std::abs( cosDist ) > ( 1.0 - tolerance ) ) { ret = true; }
2692 
2693  //================================================ Done
2694  return ( ret );
2695 
2696 }

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

2715 {
2716  //================================================ Initialise variables
2717  bool ret = false;
2718 
2719  //================================================ Cosine distance
2720  proshade_double cosDist = ( ( a1 * b1 ) + ( a2 * b2 ) + ( a3 * b3 ) ) /
2721  ( sqrt( pow( a1, 2.0 ) + pow( a2, 2.0 ) + pow( a3, 2.0 ) ) *
2722  sqrt( pow( b1, 2.0 ) + pow( b2, 2.0 ) + pow( b3, 2.0 ) ) );
2723 
2724  //================================================ Compare the absolute value of distance to 1.0 - tolerance
2725  if ( cosDist > ( 1.0 - tolerance ) ) { ret = true; }
2726 
2727  //================================================ Done
2728  return ( ret );
2729 
2730 }

◆ whichAxisUnique() [1/2]

proshade_signed ProSHADE_internal_maths::whichAxisUnique ( std::vector< proshade_double * > *  CSymList,
proshade_double *  axis,
proshade_double  tolerance 
)

This function checks if new axis is unique, or already detected and returns the position of match or -1.

This function is a variation on the isAxisUnique function, returning the index of the match or -1.

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]retIndex of the match or -1.

Definition at line 3150 of file ProSHADE_maths.cpp.

3151 {
3152  //================================================ Initialise variables
3153  proshade_signed ret = -1;
3154 
3155  //================================================ For each already detected member
3156  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
3157  {
3158  //============================================ Is fold the same?
3159  const FloatingPoint< proshade_double > lhs ( CSymList->at(grIt)[0] ), rhs ( axis[0] );
3160  if ( lhs.AlmostEquals ( rhs ) )
3161  {
3162  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], axis[1], axis[2], axis[3], tolerance ) )
3163  {
3164  ret = static_cast< proshade_signed > ( grIt );
3165  break;
3166  }
3167  }
3168  }
3169 
3170  //================================================ Done
3171  return ( ret );
3172 
3173 }

◆ whichAxisUnique() [2/2]

proshade_signed ProSHADE_internal_maths::whichAxisUnique ( 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 and returns the position of match or -1.

This function is a variation on the isAxisUnique function, returning the index of the match or -1.

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]retIndex of the match or -1.

Definition at line 3186 of file ProSHADE_maths.cpp.

3187 {
3188  //================================================ Initialise variables
3189  proshade_signed ret = -1;
3190 
3191  //================================================ For each already detected member
3192  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
3193  {
3194  const FloatingPoint< proshade_double > lhs ( fold ), rhs ( CSymList->at(grIt)[0] );
3195  if ( lhs.AlmostEquals ( rhs ) )
3196  {
3197  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], X, Y, Z, tolerance ) )
3198  {
3199  ret = static_cast< proshade_signed > ( grIt );
3200  break;
3201  }
3202  }
3203  }
3204 
3205  //================================================ Done
3206  return ( ret );
3207 
3208 }
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:2899
ProSHADE_internal_maths::rotationMatrixSimilarityValue
proshade_double rotationMatrixSimilarityValue(std::vector< proshade_double > *mat1, std::vector< proshade_double > *mat2)
This function computes the distance between two rotation matrices and returns it.
Definition: ProSHADE_maths.cpp:2624
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:1817
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:2954
ProSHADE_internal_maths::getGLFirstRealRoot
void getGLFirstRealRoot(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::build3x3MatrixFromDiag
proshade_double * build3x3MatrixFromDiag(proshade_double *diag)
Function for building a 3x3 matrix from diagonal (and assuming zero padding).
Definition: ProSHADE_maths.cpp:2028
ProSHADE_internal_maths::advanceGLPolyValue
proshade_double advanceGLPolyValue(proshade_double from, proshade_double to, proshade_double valAtFrom, proshade_unsign order, proshade_unsign noSteps)
This function finds the next value of a Legendre polynomial using the Runge-Kutta method.
Definition: ProSHADE_maths.cpp:480
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::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:2744
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:2680
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:2844
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:3286
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:1785
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:4047
ProSHADE_internal_maths::BicubicInterpolator
Definition: ProSHADE_maths.hpp:112
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::completeAbscissasAndWeights
void completeAbscissasAndWeights(proshade_unsign order, proshade_double *abscissa, proshade_double *weights, proshade_unsign noSteps)
This function completes the abscissas and weights series from the first roots computed beforehand.
Definition: ProSHADE_maths.cpp:524
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:1895
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:2186
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:73
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::smoothen1D
std::vector< proshade_double > smoothen1D(proshade_double step, proshade_signed windowSize, proshade_double sigma, std::vector< proshade_double > data, proshade_signed decRound=2)
This function takes a 1D vector and computes smoothened version based on the parameters.
Definition: ProSHADE_maths.cpp:3313
ProSHADE_internal_misc::addToSingleVector
void addToSingleVector(std::vector< proshade_single > *vecToAddTo, proshade_single elementToAdd)
Adds the element to the vector.
Definition: ProSHADE_misc.cpp:55
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:3009
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:3359
ProSHADE_internal_maths::compute3x3MatrixInverse
proshade_double * compute3x3MatrixInverse(proshade_double *mat)
Function for computing a 3x3 matrix inverse.
Definition: ProSHADE_maths.cpp:1940
ProSHADE_internal_maths::evaluateGLPolynomial
proshade_double evaluateGLPolynomial(proshade_double *series, proshade_double target, proshade_unsign terms)
This function evaluates the decomposed Legendre polynomial at a given position.
Definition: ProSHADE_maths.cpp:450
ProSHADE_internal_maths::compute3x3MatrixMultiplication
proshade_double * compute3x3MatrixMultiplication(proshade_double *mat1, proshade_double *mat2)
Function for computing a 3x3 matrix multiplication.
Definition: ProSHADE_maths.cpp:1865