ProSHADE: ProSHADE_internal_maths Namespace Reference

| ProSHADE 0.7.5.1 (JAN 2021) Protein Shape Detection

Classes | Functions
ProSHADE_internal_maths Namespace Reference

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

## Classes
class | BicubicInterpolator

## Functions
void | complexMultiplication (proshade_double *r1, proshade_double *i1, proshade_double *r2, proshade_double *i2, proshade_double *retReal, proshade_double *retImag)
| Function to multiply two complex numbers. More...
void | complexMultiplicationConjug (proshade_double *r1, proshade_double *i1, proshade_double *r2, proshade_double *i2, proshade_double *retReal, proshade_double *retImag)
| Function to multiply two complex numbers by using the second number's conjugate. More...
proshade_double | complexMultiplicationRealOnly (proshade_double *r1, proshade_double *i1, proshade_double *r2, proshade_double *i2)
| Function to multiply two complex numbers and return the real part only. More...
proshade_double | complexMultiplicationConjugRealOnly (proshade_double *r1, proshade_double *i1, proshade_double *r2, proshade_double *i2)
| Function to conjuggate multiply two complex numbers and return the real part only. More...
void | vectorMeanAndSD (std::vector< proshade_double > *vec, proshade_double *&ret)
| Function to get vector mean and standard deviation. More...
void | vectorMedianAndIQR (std::vector< proshade_double > *vec, proshade_double *&ret)
| Function to get vector median and inter-quartile range. More...
void | arrayMedianAndIQR (proshade_double *vec, proshade_unsign vecSize, proshade_double *&ret)
| Function to get array median and inter-quartile range. More...
proshade_double | pearsonCorrCoeff (proshade_double *valSet1, proshade_double *valSet2, proshade_unsign length)
| Function for computing the Pearson's correlation coefficient. More...
void | getLegendreAbscAndWeights (proshade_unsign order, proshade_double *abscissas, proshade_double *weights, proshade_unsign taylorSeriesCap)
| Function to prepare abscissas and weights for Gauss-Legendre integration. More...
void | getGLPolyAtZero (proshade_unsign order, proshade_double *polyValue, proshade_double *deriValue)
| This function obtains the Legendre polynomial values and its derivative at zero for any positive integer order polynomial. More...
void | getGLFirstEvenRoot (proshade_double polyAtZero, proshade_unsign order, proshade_double *abscAtZero, proshade_double *weighAtZero, proshade_unsign taylorSeriesCap)
| This function finds the first root for Legendre polynomials of odd order. More...
proshade_double | evaluateGLSeries (proshade_double *series, proshade_double target, proshade_unsign terms)
| This function evaluates the Taylor expansion. More...
proshade_double | advanceGLPolyValue (proshade_double from, proshade_double to, proshade_double valAtFrom, proshade_unsign noSteps, proshade_unsign taylorSeriesCap)
| This function finds the next value of the polynomial. More...
void | completeLegendreSeries (proshade_unsign order, proshade_double *abscissa, proshade_double *weights, proshade_unsign taylorSeriesCap)
| This function completes the Legendre polynomial series assuming you have obtained the first values. More...
proshade_double | gaussLegendreIntegrationReal (proshade_double *vals, proshade_unsign valsSize, proshade_unsign order, proshade_double *abscissas, proshade_double *weights, proshade_double integralOverRange, proshade_double maxSphereDists)
| Function to compute real part of the Gauss-Legendre integration over spherical harmonic values in different shells. More...
void | gaussLegendreIntegration (proshade_complex *vals, proshade_unsign valsSize, proshade_unsign order, proshade_double *abscissas, proshade_double *weights, proshade_double integralOverRange, proshade_double maxSphereDists, proshade_double *retReal, proshade_double *retImag)
| Function to compute the complete complex Gauss-Legendre integration over spherical harmonic values in different shells. More...
void | complexMatrixSVDSigmasOnly (proshade_complex **mat, int dim, double *&singularValues)
| Function to compute the complete complex matrix SVD and return only the sigmas. More...
void | complexMatrixSVDUandVOnly (proshade_double *mat, int dim, proshade_double *uAndV, bool fail=true)
| Function to compute the real matrix SVD and return the U and V matrices. More...
void | getEulerZXZFromSOFTPosition (proshade_signed band, proshade_signed x, proshade_signed y, proshade_signed z, proshade_double *eulerAlpha, proshade_double *eulerBeta, proshade_double *eulerGamma)
| Function to find Euler angles (ZXZ convention) from index position in the inverse SOFT map. More...
void | getSOFTPositionFromEulerZXZ (proshade_signed band, proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double *x, proshade_double *y, proshade_double *z)
| Function to find the index position in the inverse SOFT map from given Euler angles (ZXZ convention). More...
void | getRotationMatrixFromEulerZXZAngles (proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double *matrix)
| Function to find the rotation matrix from Euler angles (ZXZ convention). More...
void | getAxisAngleFromRotationMatrix (proshade_double *rotMat, proshade_double *x, proshade_double *y, proshade_double *z, proshade_double *ang)
| This function converts rotation matrix to the axis-angle representation. More...
void | getAxisAngleFromRotationMatrix (std::vector< proshade_double > *rotMat, proshade_double *x, proshade_double *y, proshade_double *z, proshade_double *ang)
| This function converts rotation matrix to the axis-angle representation. More...
void | getRotationMatrixFromAngleAxis (proshade_double *rotMat, proshade_double x, proshade_double y, proshade_double z, proshade_double ang)
| This function converts the axis-angle representation to the rotation matrix representation. More...
void | getEulerZXZFromRotMatrix (proshade_double *rotMat, proshade_double *eA, proshade_double *eB, proshade_double *eG)
| This function converts rotation matrix to the Euler ZXZ angles representation. More...
void | getEulerZXZFromAngleAxis (proshade_double axX, proshade_double axY, proshade_double axZ, proshade_double axAng, proshade_double *eA, proshade_double *eB, proshade_double *eG, proshade_unsign angDim)
| This function converts angle-axis representation to the Euler ZXZ angles representation. More...
void | getEulerZXZFromAngleAxisFullSearch (proshade_double axX, proshade_double axY, proshade_double axZ, proshade_double axAng, proshade_double *eA, proshade_double *eB, proshade_double *eG, proshade_signed angDim)
| This function converts angle-axis representation to the Euler ZXZ angles representation using full search. More...
void | multiplyTwoSquareMatrices (proshade_double *A, proshade_double *B, proshade_double *res, proshade_unsign dim)
| 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...
std::vector< proshade_double > | findVectorFromTwoVAndTwoD (proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2, proshade_double dot1, proshade_double dot2)
| Function for finding a vector which would have a given two dot products to two other vectors. More...
std::vector< proshade_double > | findVectorFromThreeVAndThreeD (proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2, proshade_double x3, proshade_double y3, proshade_double z3, proshade_double dot1, proshade_double dot2, proshade_double dot3)
| Function for finding a vector which would have a given three dot products to three other vectors. More...
std::vector< proshade_double > | multiplyGroupElementMatrices (std::vector< proshade_double > *el1, std::vector< proshade_double > *el2)
| This function computes matrix multiplication using the ProSHADE group element matrix format as input and output. More...
bool | rotationMatrixSimilarity (std::vector< proshade_double > *mat1, std::vector< proshade_double > *mat2, proshade_double tolerance=0.1)
| This function compares the distance between two rotation matrices and decides if they are similar using tolerance. More...
bool | vectorOrientationSimilarity (proshade_double a1, proshade_double a2, proshade_double a3, proshade_double b1, proshade_double b2, proshade_double b3, proshade_double tolerance=0.1)
| This function compares two vectors using cosine distance and decides if they are similar using tolerance. More...
bool | vectorOrientationSimilaritySameDirection (proshade_double a1, proshade_double a2, proshade_double a3, proshade_double b1, proshade_double b2, proshade_double b3, proshade_double tolerance=0.1)
| This function compares two vectors using cosine distance and decides if they are similar using tolerance. More...
void | optimiseAxisBiCubicInterpolation (proshade_double *bestLattitude, proshade_double *bestLongitude, proshade_double *bestSum, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun, proshade_double step=0.05)
| This function provides axis optimisation given starting lattitude and longitude indices. More...
void | prepareBiCubicInterpolatorsMinusMinus (proshade_double bestLattitude, proshade_double bestLongitude, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *interpols, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun)
| This function prepares the interpolation objects for the bi-cubic interpolation. More...
void | prepareBiCubicInterpolatorsMinusPlus (proshade_double bestLattitude, proshade_double bestLongitude, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *interpols, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun)
| This function prepares the interpolation objects for the bi-cubic interpolation. More...
void | prepareBiCubicInterpolatorsPlusMinus (proshade_double bestLattitude, proshade_double bestLongitude, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *interpols, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun)
| This function prepares the interpolation objects for the bi-cubic interpolation. More...
void | prepareBiCubicInterpolatorsPlusPlus (proshade_double bestLattitude, proshade_double bestLongitude, std::vector< proshade_unsign > *sphereList, std::vector< ProSHADE_internal_maths::BicubicInterpolator * > *interpols, std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > *sphereMappedRotFun)
| This function prepares the interpolation objects for the bi-cubic interpolation. More...
bool | isAxisUnique (std::vector< proshade_double * > *CSymList, proshade_double *axis, proshade_double tolerance=0.1, bool improve=false)
| This function checks if new axis is unique, or already detected. More...
bool | isAxisUnique (std::vector< proshade_double * > *CSymList, proshade_double X, proshade_double Y, proshade_double Z, proshade_double fold, proshade_double tolerance)
| This function checks if new axis is unique, or already detected. More...
std::vector< proshade_unsign > | findAllPrimes (proshade_unsign upTo)
| This function finds all prime numbers up to the supplied limit. More...

## Detailed Description

This namespace contains the internal functions for common mathematical operations.

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

## Function Documentation

## ◆ advanceGLPolyValue()

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

This function finds the next value of the polynomial.

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

Parameters

  [in] | from | Current polynomial position.
  [in] | to | Polynomial position to move to.
  [in] | valAtFrom | The current value of the polynomial at the <from> position.
  [in] | noSteps | Number of steps in which to reach the <to> position.
  [in] | taylorSeriesCap | The limit on the Taylor series.
  [out] | X | The polynomial value at the <to> position.

Definition at line 477 of file ProSHADE_maths.cpp.

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

## ◆ 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] | vec | Pointer to an array of proshade_double's for which median and IQR should be obtained.
  [in] | vecSize | The length of the array.
  [in] | ret | Pointer to array of 2 proshade_double's, which will be the return values - first median and second IQR.

Definition at line 198 of file ProSHADE_maths.cpp.

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

## ◆ completeLegendreSeries()

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

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

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

Parameters

  [in] | order | The positive integer value of the polynomial order.
  [in] | abscissas | Pointer to an array of abscissas containing the first value.
  [in] | weights | Pointer to an array of weights containing the first value.
  [in] | taylorSeriesCap | The limit on the Taylor series.

Definition at line 521 of file ProSHADE_maths.cpp.

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

## ◆ 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] | mat | Pointer to a complex square matrix with dimensions dim * dim.
  [in] | dim | The dimension of the complex matrix.
  [in] | singularValues | Empty array of size dim where the singular values will be saved.

Definition at line 802 of file ProSHADE_maths.cpp.

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

## ◆ complexMatrixSVDUandVOnly()

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

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

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

Parameters

  [in] | mat | Pointer to a real square matrix with dimensions dim * dim.
  [in] | dim | The dimension of the real matrix.
  [in] | uAndV | Empty and allocated array of size dim*6 where the U and V matrices will be saved.
  [in] | fail | If 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 869 of file ProSHADE_maths.cpp.

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

## ◆ 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] | r1 | Pointer to the real value of number 1.
  [in] | i1 | Pointer to the imaginary value of number 1.
  [in] | r2 | Pointer to the real value of number 2.
  [in] | i2 | Pointer to the imaginary value of number 2.
  [in] | retReal | Pointer to the real part of the complex variable to which the result will be saved.
  [in] | retImag | Pointer 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] | r1 | Pointer to the real value of number 1.
  [in] | i1 | Pointer to the imaginary value of number 1.
  [in] | r2 | Pointer to the real value of number 2.
  [in] | i2 | Pointer to the imaginary value of number 2.
  [in] | retReal | Pointer to the real part of the complex variable to which the result will be saved.
  [in] | retImag | Pointer 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] | r1 | Pointer to the real value of number 1.
  [in] | i1 | Pointer to the imaginary value of number 1.
  [in] | r2 | Pointer to the real value of number 2.
  [in] | i2 | Pointer 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] | r1 | Pointer to the real value of number 1.
  [in] | i1 | Pointer to the imaginary value of number 1.
  [in] | r2 | Pointer to the real value of number 2.
  [in] | i2 | Pointer 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 }

## ◆ 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] | x1 | The x-axis element of the first vector.
  [in] | y1 | The y-axis element of the first vector.
  [in] | z1 | The z-axis element of the first vector.
  [in] | x2 | The x-axis element of the second vector.
  [in] | y2 | The y-axis element of the second vector.
  [in] | z2 | The z-axis element of the second vector.

Definition at line 1701 of file ProSHADE_maths.cpp.

1702 {
1703 //================================================ Compute and return
1704 return ( (*x1 * *x2) + (*y1 * *y2) + (*z1 * *z2) );
1705 }

## ◆ 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] | x1 | The x-axis element of the first vector.
  [in] | y1 | The y-axis element of the first vector.
  [in] | z1 | The z-axis element of the first vector.
  [in] | x2 | The x-axis element of the second vector.
  [in] | y2 | The y-axis element of the second vector.
  [in] | z2 | The z-axis element of the second vector.

Definition at line 1716 of file ProSHADE_maths.cpp.

1717 {
1718 //================================================ Compute and return
1719 return ( (x1 * x2) + (y1 * y2) + (z1 * z2) );
1720 }

## ◆ evaluateGLSeries()

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

This function evaluates the Taylor expansion.

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

Parameters

  [in] | series | Pointer to array with the series values.
  [in] | target | The target location on the series value.
  [in] | terms | The Taylor expansion cap.
  [out] | X | The value of the series at the target location.

Definition at line 447 of file ProSHADE_maths.cpp.

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

## ◆ 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] | upTo | The limit to which prime numbers should be sought.

Definition at line 2476 of file ProSHADE_maths.cpp.

2477 {
2478 //================================================ Initialise variables
2479 std::vector< proshade_unsign > ret;
2480 std::vector< std::pair< proshade_unsign, bool > > sieveOfEratosthenesArray;
2481
2482 //================================================ Sanity check
2483 if ( upTo < 2 ) { return ( ret ); }
2484
2485 //================================================ Initialise the sieve array up to the required number
2486 for ( proshade_unsign iter = 2; iter <= upTo; iter++ ) { sieveOfEratosthenesArray.emplace_back ( std::pair< proshade_unsign, bool > ( iter, true ) ); }
2487
2488 //================================================ For each entry in the array
2489 for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); iter++ )
2490 {
2491 //============================================ If this entry is still true
2492 if ( sieveOfEratosthenesArray.at(iter).second )
2493 {
2494 //======================================== Set all entries with the position x * [this entry value] to false
2495 for ( proshade_unsign it = iter + sieveOfEratosthenesArray.at(iter).first; it < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); it += sieveOfEratosthenesArray.at(iter).first )
2496 {
2497 sieveOfEratosthenesArray.at(it).second = false;
2498 }
2499 }
2500 }
2501
2502 //================================================ Copy passing results to return vector
2503 for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sieveOfEratosthenesArray.size() ); iter++ )
2504 {
2505 if ( sieveOfEratosthenesArray.at(iter).second ) { ProSHADE_internal_misc::addToUnsignVector ( &ret, sieveOfEratosthenesArray.at(iter).first ); }
2506 }
2507
2508 //================================================ Done
2509 return ( ret );
2510
2511 }

## ◆ 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] | x1 | The x-axis element of the first vector.
  [in] | y1 | The y-axis element of the first vector.
  [in] | z1 | The z-axis element of the first vector.
  [in] | x2 | The x-axis element of the second vector.
  [in] | y2 | The y-axis element of the second vector.
  [in] | z2 | The z-axis element of the second vector.
  [in] | dot1 | The dot product specifying the angle between the sought vector and the first input vector.
  [in] | dot2 | The dot product specifying the angle between the sought vector and the second input vectors.
  [out] | vec | A std::vector containing the three elements of the sought vector.

Definition at line 1885 of file ProSHADE_maths.cpp.

1886 {
1887 //================================================ Initialise variables
1888 std::vector < proshade_double > ret;
1889
1890 //================================================ Solution
1891 proshade_double solX = - ( y1 * dot2 * z3 - y1 * dot3 * z2 - z1 * dot2 * y3 + z1 * dot3 * y2 + dot1 * y3 * z2 - dot1 * z3 * y2 ) /
1892 ( -x1 * y3 * z2 + x1 * z3 * y2 + y1 * x3 * z2 - y1 * z3 * x2 - z1 * x3 * y2 + z1 * y3 * x2 );
1893 proshade_double solY = - ( x1 * dot2 * z3 - x1 * dot3 * z2 - z1 * dot2 * x3 + z1 * dot3 * x2 + dot1 * x3 * z2 - dot1 * z3 * x2 ) /
1894 ( x1 * y3 * z2 - x1 * z3 * y2 - y1 * x3 * z2 + y1 * z3 * x2 + z1 * x3 * y2 - z1 * y3 * x2 );
1895 proshade_double solZ = - ( x1 * dot2 * y3 - x1 * dot3 * y2 - y1 * dot2 * x3 + y1 * dot3 * x2 + dot1 * x3 * y2 - dot1 * y3 * x2 ) /
1896 ( -x1 * y3 * z2 + x1 * z3 * y2 + y1 * x3 * z2 - y1 * z3 * x2 - z1 * x3 * y2 + z1 * y3 * x2 );
1897
1898 //================================================ Normalise the axis to magnitude 1
1899 proshade_double normFactor = sqrt ( pow ( solX, 2.0 ) + pow ( solY, 2.0 ) + pow ( solZ, 2.0 ) );
1900 solX /= normFactor;
1901 solY /= normFactor;
1902 solZ /= normFactor;
1903
1904 //================================================ Set largest axis element to positive (ProSHADE standard)
1905 if ( ( ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) == std::abs ( solX ) ) && ( solX < 0.0 ) ) ||
1906 ( ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) == std::abs ( solY ) ) && ( solY < 0.0 ) ) ||
1907 ( ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) == std::abs ( solZ ) ) && ( solZ < 0.0 ) ) ) { solX *= -1.0; solY *= -1.0; solZ *= -1.0; }
1908
1909 //================================================ Save solutions
1910 ProSHADE_internal_misc::addToDoubleVector ( &ret, solX );
1911 ProSHADE_internal_misc::addToDoubleVector ( &ret, solY );
1912 ProSHADE_internal_misc::addToDoubleVector ( &ret, solZ );
1913
1914 //================================================ Done
1915 return ( ret );
1916
1917 }

## ◆ 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] | x1 | The x-axis element of the first vector.
  [in] | y1 | The y-axis element of the first vector.
  [in] | z1 | The z-axis element of the first vector.
  [in] | x2 | The x-axis element of the second vector.
  [in] | y2 | The y-axis element of the second vector.
  [in] | z2 | The z-axis element of the second vector.
  [in] | dot1 | The dot product specifying the angle between the sought vector and the first input vector.
  [in] | dot2 | The dot product specifying the angle between the sought vector and the second input vectors.
  [out] | vec | A std::vector containing the three elements of the sought vector.

Definition at line 1743 of file ProSHADE_maths.cpp.

1744 {
1745 //================================================ Initialise variables
1746 std::vector < proshade_double > ret;
1747
1748 //================================================ Solution
1749 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 ) -
1750 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 ) ) *
1751 ( 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 ) ) ) -
1752 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 ) /
1753 ( 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 ) ) );
1754 proshade_double solY = ( ( dot2 * pow ( x2, 2.0 ) * pow ( z1, 3.0 ) ) /
1755 ( 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 ) -
1756 ( dot1 * pow ( x2, 2.0 ) * z2 * pow ( z1, 2.0 ) ) /
1757 ( 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 ) -
1758 ( 2.0 * x1 * dot2 * x2 * z2 * pow ( z1, 2.0 ) ) /
1759 ( 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 -
1760 ( 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 ) -
1761 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 ) *
1762 ( 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 ) /
1763 ( 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 ) ) +
1764 ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) * z1 ) /
1765 ( 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 ) +
1766 ( x1 * dot1 * x2 * pow ( y2, 2.0 ) * z1 ) /
1767 ( 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 ) +
1768 ( pow ( x1, 2.0 ) * dot2 * pow ( z2, 2.0 ) * z1 ) /
1769 ( 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 ) +
1770 ( 2.0 * x1 * dot1 * x2 * pow ( z2, 2.0 ) * z1 ) /
1771 ( 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 ) -
1772 ( y1 * dot1 * pow ( x2, 2.0 ) * y2 * z1 ) /
1773 ( 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 ) -
1774 ( x1 * y1 * dot2 * x2 * y2 * z1 ) /
1775 ( 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 +
1776 ( 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 ) -
1777 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 ) *
1778 ( 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 ) ) ) /
1779 ( 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 ) ) -
1780 ( pow ( x1, 2.0 ) * dot1 * pow ( z2, 3.0 ) ) /
1781 ( 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 ) -
1782 ( pow ( x1, 2.0 ) * dot1 * pow ( y2, 2.0 ) * z2 ) /
1783 ( 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 ) -
1784 ( x1 * pow ( y1, 2.0 ) * dot2 * x2 * z2 ) /
1785 ( 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 ) +
1786 ( pow ( x1, 2.0 ) * y1 * dot2 * y2 * z2 ) /
1787 ( 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 ) +
1788 ( x1 * y1 * dot1 * x2 * y2 * z2 ) /
1789 ( 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 );
1790 proshade_double solZ = ( - ( dot2 * pow ( x2, 2.0 ) * y2 * pow ( z1, 3.0 ) ) /
1791 ( ( 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 ) ) -
1792 ( dot2 * pow ( x2, 2.0 ) * pow ( z1, 2.0 ) ) /
1793 ( 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 ) +
1794 ( dot1 * pow ( x2, 2.0 ) * y2 * z2 * pow ( z1, 2.0 ) ) /
1795 ( ( 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 ) ) +
1796 ( 2.0 * x1 * dot2 * x2 * y2 * z2 * pow ( z1, 2.0 ) ) /
1797 ( ( 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 ) ) +
1798 ( 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 ) -
1799 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 ) *
1800 ( 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 ) /
1801 ( 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 ) ) +
1802 ( dot2 * y2 * z1 ) / ( y1 * z2 - z1 * y2 ) +
1803 ( dot1 * pow ( x2, 2.0 ) * z2 * z1 ) /
1804 ( 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 ) +
1805 ( x1 * dot2 * x2 * z2 * z1 ) /
1806 ( 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 ) -
1807 ( x1 * dot1 * x2 * pow ( y2, 3.0 ) * z1 ) /
1808 ( ( 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 ) ) +
1809 ( y1 * dot1 * pow ( x2, 2.0 ) * pow ( y2, 2.0 ) * z1 ) /
1810 ( ( 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 ) ) +
1811 ( x1 * y1 * dot2 * x2 * pow ( y2, 2.0 ) * z1 ) /
1812 ( ( 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 ) ) -
1813 ( pow ( x1, 2.0 ) * dot2 * y2 * pow ( z2, 2.0 ) * z1 ) /
1814 ( ( 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 ) ) -
1815 ( 2.0 * x1 * dot1 * x2 * y2 * pow ( z2, 2.0 ) * z1 ) /
1816 ( ( 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 ) ) -
1817 ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) * y2 * z1 ) /
1818 ( ( 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 +
1819 ( 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 ) -
1820 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 ) *
1821 ( 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 ) ) ) /
1822 ( 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 ) ) -
1823 ( 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 ) -
1824 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 ) *
1825 ( 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 ) ) ) /
1826 ( 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 ) ) -
1827 ( dot1 * y2 * z2 ) / ( y1 * z2 - z1 * y2 ) -
1828 ( pow ( y1, 2.0 ) * dot2 * pow ( x2, 2.0 ) ) /
1829 ( 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 ) -
1830 ( x1 * dot1 * x2 * pow ( y2, 2.0 ) ) /
1831 ( 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 ) -
1832 ( x1 * dot1 * x2 * pow ( z2, 2.0 ) ) /
1833 ( 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 ) +
1834 ( y1 * dot1 * pow ( x2, 2.0 ) * y2 ) /
1835 ( 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 ) +
1836 ( x1 * y1 * dot2 * x2 * y2 ) /
1837 ( 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 ) +
1838 ( pow ( x1, 2.0 ) * dot1 * y2 * pow ( z2, 3.0 ) ) /
1839 ( ( 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 ) ) +
1840 ( pow ( x1, 2.0 ) * dot1 * pow ( y2, 3.0 ) * z2 ) /
1841 ( ( 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 ) ) -
1842 ( pow ( x1, 2.0 ) * y1 * dot2 * pow ( y2, 2.0 ) * z2 ) /
1843 ( ( 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 ) ) -
1844 ( x1 * y1 * dot1 * x2 * pow ( y2, 2.0 ) * z2 ) /
1845 ( ( 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 ) ) +
1846 ( x1 * pow ( y1, 2.0 ) * dot2 * x2 * y2 * z2 ) /
1847 ( ( 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;
1848
1849 //================================================ Set largest axis element to positive (ProSHADE standard)
1850 if ( ( ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) == std::abs ( solX ) ) && ( solX < 0.0 ) ) ||
1851 ( ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) == std::abs ( solY ) ) && ( solY < 0.0 ) ) ||
1852 ( ( std::max ( std::abs ( solX ), std::max( std::abs ( solY ), std::abs ( solZ ) ) ) == std::abs ( solZ ) ) && ( solZ < 0.0 ) ) ) { solX *= -1.0; solY *= -1.0; solZ *= -1.0; }
1853
1854 //================================================ Save solutions
1855 ProSHADE_internal_misc::addToDoubleVector ( &ret, solX );
1856 ProSHADE_internal_misc::addToDoubleVector ( &ret, solY );
1857 ProSHADE_internal_misc::addToDoubleVector ( &ret, solZ );
1858
1859 //================================================ Done
1860 return ( ret );
1861
1862 }

## ◆ 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] | vals | Pointer to a complex array of values over which the integration to be done.
  [in] | valsSize | The length of the input array.
  [in] | order | The integration order value.
  [in] | abscissas | The allocated array for holding the abscissa values.
  [in] | weights | The allocated array for holding the weight values.
  [in] | integralOverRange | The range of the intgral. If progressive shell mapping is used, this will not be max shell radius.
  [in] | maxSphereDists | Distance between two shells.
  [in] | retReal | The real part of the complex result of Gauss-Legendre integration over the shperical harmonics values.
  [in] | retImag | The imaginary part of the complex result of Gauss-Legendre integration over the shperical harmonics values.

Definition at line 709 of file ProSHADE_maths.cpp.

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

## ◆ 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] | vals | Pointer to an array of values over which the integration to be done.
  [in] | valsSize | The length of the input array.
  [in] | order | The integration order value.
  [in] | abscissas | The allocated array for holding the abscissa values.
  [in] | weights | The allocated array for holding the weight values.
  [in] | integralOverRange | The range of the intgral. If progressive shell mapping is used, this will not be max shell radius.
  [in] | maxSphereDists | Distance between two shells.
  [out] | X | The real part of Gauss-Legendre integration over the shperical harmonics values.

Definition at line 619 of file ProSHADE_maths.cpp.

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

## ◆ getAxisAngleFromRotationMatrix() [1/2]

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

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

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

Parameters

  [in] | rotMat | Rotation matrix as an array of 9 values.
  [in] | x | Pointer to which the x-axis value of the axis vector will be saved.
  [in] | y | Pointer to which the y-axis value of the axis vector will be saved.
  [in] | z | Pointer to which the z-axis value of the axis vector will be saved.
  [in] | ang | Pointer to which the angle value will be saved.

Definition at line 1039 of file ProSHADE_maths.cpp.

1040 {
1041 //================================================ Initialise
1042 proshade_double singAtPiCheck = 0.01;
1043 proshade_double singAtIdentity = 0.05;
1044
1045 //================================================ Check input for singularities
1046 if ( ( std::abs ( rotMat[1] - rotMat[3] ) < singAtPiCheck ) &&
1047 ( std::abs ( rotMat[2] - rotMat[6] ) < singAtPiCheck ) &&
1048 ( std::abs ( rotMat[5] - rotMat[7] ) < singAtPiCheck ) )
1049 {
1050 //============================================ Singularity in input! Check for identity matrix
1051 if ( ( std::abs ( rotMat[1] + rotMat[3] ) < singAtIdentity ) &&
1052 ( std::abs ( rotMat[2] + rotMat[6] ) < singAtIdentity ) &&
1053 ( std::abs ( rotMat[5] + rotMat[7] ) < singAtIdentity ) &&
1054 ( std::abs ( rotMat[0] + rotMat[4] + rotMat[8] - 3.0 ) < singAtIdentity ) )
1055 {
1056 //======================================== Identity matrix. Return 0 angle.
1057 *x = 1.0;
1058 *y = 0.0;
1059 *z = 0.0;
1060 *ang = 0.0;
1061
1062 //======================================== Done
1063 return ;
1064 }
1065
1066 //============================================ If we got here, this is the 180deg (pi rad) singularity. Find which axis should the rotation be done along
1067 *ang = M_PI;
1068
1069 proshade_double xx = ( rotMat[0] + 1.0 ) / 2.0;
1070 proshade_double yy = ( rotMat[4] + 1.0 ) / 2.0;
1071 proshade_double zz = ( rotMat[8] + 1.0 ) / 2.0;
1072 proshade_double xy = ( rotMat[1] + rotMat[3] ) / 4.0;
1073 proshade_double xz = ( rotMat[2] + rotMat[6] ) / 4.0;
1074 proshade_double yz = ( rotMat[5] + rotMat[7] ) / 4.0;
1075
1076 if ( ( xx > yy ) && ( xx > zz ) ) // XX is the largest diagonal
1077 {
1078 if ( xx < singAtPiCheck ) // and is still 0
1079 {
1080 *x = 0.0;
1081 *y = 1.0 / sqrt(2);
1082 *z = 1.0 / sqrt(2);
1083 }
1084 else
1085 {
1086 *x = sqrt ( xx );
1087 *y = xy / sqrt ( xx );
1088 *z = xz / sqrt ( xx );
1089 }
1090 }
1091
1092 else if ( yy > zz ) // YY is the largest diagonal
1093 {
1094 if ( yy < singAtPiCheck ) // and is still 0
1095 {
1096 *x = 1.0 / sqrt(2);
1097 *y = 0.0;
1098 *z = 1.0 / sqrt(2);
1099 }
1100 else
1101 {
1102 *y = sqrt ( yy );
1103 *x = xy / sqrt ( yy );
1104 *z = yz / sqrt ( yy );
1105 }
1106 }
1107
1108 else // ZZ is the largest diagonal
1109 {
1110 if ( zz < singAtPiCheck ) // and is still 0
1111 {
1112 *x = 1.0 / sqrt(2);
1113 *y = 1.0 / sqrt(2);
1114 *z = 0.0;
1115 }
1116 else
1117 {
1118 *z = sqrt ( zz );
1119 *x = xz / sqrt ( zz );
1120 *y = yz / sqrt ( zz );
1121 }
1122 }
1123
1124 //============================================ Make sure largest axis is positive and so is the angle
1125 if ( ( ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) == std::abs ( *x ) ) && ( *x < 0.0 ) ) ||
1126 ( ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) == std::abs ( *y ) ) && ( *y < 0.0 ) ) ||
1127 ( ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) == std::abs ( *z ) ) && ( *z < 0.0 ) ) )
1128 {
1129 *x *= -1.0;
1130 *y *= -1.0;
1131 *z *= -1.0;
1132 *ang *= -1.0;
1133 }
1134 if ( *ang < 0.0 ) { *ang = ( 2.0 * M_PI ) + *ang; }
1135
1136 //============================================ Done
1137 return ;
1138 }
1139
1140 //================================================ No singularities! Now get angle
1141 *ang = std::acos ( ( std::max ( -1.0, std::min ( 3.0, rotMat[0] + rotMat[4] + rotMat[8] ) ) - 1.0 ) / 2.0 );
1142
1143 //================================================ Init return values
1144 *x = 1.0;
1145 *y = 0.0;
1146 *z = 0.0;
1147
1148 //================================================ Is angle 0? This should not happen, but will
1149 if ( std::abs ( *ang ) < singAtPiCheck )
1150 {
1151 *ang = 0.0;
1152 return ;
1153 }
1154
1155 //================================================ Axis
1156 *x = rotMat[7] - rotMat[5];
1157 *y = rotMat[2] - rotMat[6];
1158 *z = rotMat[3] - rotMat[1];
1159
1160 proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1161 *x /= normFactor;
1162 *y /= normFactor;
1163 *z /= normFactor;
1164
1165 //================================================ Make sure largest axis is positive and so is the angle
1166 if ( ( ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) == std::abs ( *x ) ) && ( *x < 0.0 ) ) ||
1167 ( ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) == std::abs ( *y ) ) && ( *y < 0.0 ) ) ||
1168 ( ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) == std::abs ( *z ) ) && ( *z < 0.0 ) ) )
1169 {
1170 *x *= -1.0;
1171 *y *= -1.0;
1172 *z *= -1.0;
1173 *ang *= -1.0;
1174 }
1175 if ( *ang < 0.0 ) { *ang = ( 2.0 * M_PI ) + *ang; }
1176
1177 //================================================ Done
1178 return ;
1179
1180 }

## ◆ getAxisAngleFromRotationMatrix() [2/2]

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

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

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

Parameters

  [in] | rotMat | Rotation matrix as a pointer to a vector of doubles.
  [in] | x | Pointer to which the x-axis value of the axis vector will be saved.
  [in] | y | Pointer to which the y-axis value of the axis vector will be saved.
  [in] | z | Pointer to which the z-axis value of the axis vector will be saved.
  [in] | ang | Pointer to which the angle value will be saved.

Definition at line 1194 of file ProSHADE_maths.cpp.

1195 {
1196 //================================================ Initialise
1197 proshade_double singAtPiCheck = 0.01;
1198 proshade_double singAtIdentity = 0.05;
1199
1200 //================================================ Check input for singularities
1201 if ( ( std::abs ( rotMat->at(1) - rotMat->at(3) ) < singAtPiCheck ) &&
1202 ( std::abs ( rotMat->at(2) - rotMat->at(6) ) < singAtPiCheck ) &&
1203 ( std::abs ( rotMat->at(5) - rotMat->at(7) ) < singAtPiCheck ) )
1204 {
1205 //============================================ Singularity in input! Check for identity matrix
1206 if ( ( std::abs ( rotMat->at(1) + rotMat->at(3) ) < singAtIdentity ) &&
1207 ( std::abs ( rotMat->at(2) + rotMat->at(6) ) < singAtIdentity ) &&
1208 ( std::abs ( rotMat->at(5) + rotMat->at(7) ) < singAtIdentity ) &&
1209 ( std::abs ( rotMat->at(0) + rotMat->at(4) + rotMat->at(8) - 3.0 ) < singAtIdentity ) )
1210 {
1211 //======================================== Identity matrix. Return 0 angle.
1212 *x = 1.0;
1213 *y = 0.0;
1214 *z = 0.0;
1215 *ang = 0.0;
1216
1217 //======================================== Done
1218 return ;
1219 }
1220
1221 //============================================ If we got here, this is the 180deg (pi rad) singularity. Find which axis should the rotation be done along
1222 *ang = M_PI;
1223
1224 proshade_double xx = ( rotMat->at(0) + 1.0 ) / 2.0;
1225 proshade_double yy = ( rotMat->at(4) + 1.0 ) / 2.0;
1226 proshade_double zz = ( rotMat->at(8) + 1.0 ) / 2.0;
1227 proshade_double xy = ( rotMat->at(1) + rotMat->at(3) ) / 4.0;
1228 proshade_double xz = ( rotMat->at(2) + rotMat->at(6) ) / 4.0;
1229 proshade_double yz = ( rotMat->at(5) + rotMat->at(7) ) / 4.0;
1230
1231 if ( ( xx > yy ) && ( xx > zz ) ) // XX is the largest diagonal
1232 {
1233 if ( xx < singAtPiCheck ) // and is still 0
1234 {
1235 *x = 0.0;
1236 *y = 1.0 / sqrt(2);
1237 *z = 1.0 / sqrt(2);
1238 }
1239 else
1240 {
1241 *x = sqrt ( xx );
1242 *y = xy / sqrt ( xx );
1243 *z = xz / sqrt ( xx );
1244 }
1245 }
1246
1247 else if ( yy > zz ) // YY is the largest diagonal
1248 {
1249 if ( yy < singAtPiCheck ) // and is still 0
1250 {
1251 *x = 1.0 / sqrt(2);
1252 *y = 0.0;
1253 *z = 1.0 / sqrt(2);
1254 }
1255 else
1256 {
1257 *y = sqrt ( yy );
1258 *x = xy / sqrt ( yy );
1259 *z = yz / sqrt ( yy );
1260 }
1261 }
1262
1263 else // ZZ is the largest diagonal
1264 {
1265 if ( zz < singAtPiCheck ) // and is still 0
1266 {
1267 *x = 1.0 / sqrt(2);
1268 *y = 1.0 / sqrt(2);
1269 *z = 0.0;
1270 }
1271 else
1272 {
1273 *z = sqrt ( zz );
1274 *x = xz / sqrt ( zz );
1275 *y = yz / sqrt ( zz );
1276 }
1277 }
1278
1279 //============================================ Make sure largest axis is positive and so is the angle
1280 if ( ( ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) == std::abs ( *x ) ) && ( *x < 0.0 ) ) ||
1281 ( ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) == std::abs ( *y ) ) && ( *y < 0.0 ) ) ||
1282 ( ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) == std::abs ( *z ) ) && ( *z < 0.0 ) ) )
1283 {
1284 *x *= -1.0;
1285 *y *= -1.0;
1286 *z *= -1.0;
1287 *ang *= -1.0;
1288 }
1289
1290 //============================================ Done
1291 return ;
1292 }
1293
1294 //================================================ No singularities! Now get angle
1295 *ang = std::acos ( ( std::max ( -1.0, std::min ( 3.0, rotMat->at(0) + rotMat->at(4) + rotMat->at(8) ) ) - 1.0 ) / 2.0 );
1296
1297 //================================================ Init return values
1298 *x = 1.0;
1299 *y = 0.0;
1300 *z = 0.0;
1301
1302 //================================================ Is angle 0? This should not happen, but will
1303 if ( std::abs ( *ang ) < singAtPiCheck )
1304 {
1305 *ang = 0.0;
1306 return ;
1307 }
1308
1309 //================================================ Axis
1310 *x = rotMat->at(7) - rotMat->at(5);
1311 *y = rotMat->at(2) - rotMat->at(6);
1312 *z = rotMat->at(3) - rotMat->at(1);
1313
1314 proshade_double normFactor = std::sqrt ( pow ( *x, 2.0 ) + pow ( *y, 2.0 ) + pow ( *z, 2.0 ) );
1315 *x /= normFactor;
1316 *y /= normFactor;
1317 *z /= normFactor;
1318
1319 //================================================ Make sure largest axis is positive and so is the angle
1320 if ( ( ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) == std::abs ( *x ) ) && ( *x < 0.0 ) ) ||
1321 ( ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) == std::abs ( *y ) ) && ( *y < 0.0 ) ) ||
1322 ( ( std::max ( std::abs ( *x ), std::max ( std::abs ( *y ), std::abs ( *z ) ) ) == std::abs ( *z ) ) && ( *z < 0.0 ) ) )
1323 {
1324 *x *= -1.0;
1325 *y *= -1.0;
1326 *z *= -1.0;
1327 *ang *= -1.0;
1328 }
1329
1330 //================================================ Done
1331 return ;
1332
1333 }

## ◆ getEulerZXZFromAngleAxis()

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

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

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

Parameters

  [in] | axX | Angle-axis representation axis x element.
  [in] | axY | Angle-axis representation axis y element.
  [in] | axZ | Angle-axis representation axis z element.
  [in] | axAng | Angle-axis representation angle.
  [in] | eA | Pointer to which the Euler angle alpha value will be saved.
  [in] | eB | Pointer to which the Euler angle beta value will be saved.
  [in] | eG | Pointer to which the Euler angle gamma value will be saved.

Definition at line 1437 of file ProSHADE_maths.cpp.

1438 {
1439 //================================================ If angle is 0 or infinity (anything divided by 0), return no rotation
1440 if ( ( axAng == 0.0 ) || ( std::isinf ( axAng ) ) )
1441 {
1442 //============================================ Return 0 ; 0 ; 0 for no angle
1443 *eA = 0.0;
1444 *eB = 0.0;
1445 *eG = 0.0;
1446
1447 //============================================ Done
1448 return ;
1449 }
1450
1451 //================================================ Compute required rotation matrix elements
1452 proshade_double cAng = std::cos ( axAng );
1453 proshade_double sAng = std::sin ( axAng );
1454 proshade_double tAng = 1.0 - cAng;
1455
1456 proshade_double element22 = cAng + axZ * axZ * tAng;
1457
1458 proshade_double tmp1 = axX * axZ * tAng;
1459 proshade_double tmp2 = axY * sAng;
1460 proshade_double element20 = tmp1 - tmp2;
1461 proshade_double element02 = tmp1 + tmp2;
1462
1463 tmp1 = axY * axZ * tAng;
1464 tmp2 = axX * sAng;
1465 proshade_double element21 = tmp1 + tmp2;
1466 proshade_double element12 = tmp1 - tmp2;
1467
1468 //================================================ Convert to Eulers
1469 if ( std::abs( element22 ) <= 0.99999 )
1470 {
1471 //============================================ This case occurs when there is no singularity in the rotation matrix (i.e. it does not have 0 or 180 degrees angle)
1472 *eA = std::atan2 ( element21, element20 );
1473 *eB = std::acos ( element22 );
1474 *eG = std::atan2 ( element12, -element02 );
1475 }
1476 else
1477 {
1478 //============================================ Compute some extra rotation matrix elements
1479 tmp1 = axX * axY * tAng;
1480 tmp2 = axZ * sAng;
1481 proshade_double element10 = tmp1 + tmp2;
1482 proshade_double element00 = cAng + axX * axX * tAng;
1483
1484 //============================================ This case occurs when there is either 0 or 180 degrees rotation angle in the rotation matrix and therefore when beta is zero.
1485 if ( element22 >= 0.99999 )
1486 {
1487 //======================================== 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.
1488 *eA = std::atan2 ( element10, element00 );
1489 *eB = 0.0;
1490 *eG = 0.0;
1491 }
1492 if ( element22 <= -0.99999 )
1493 {
1494 //======================================== In this case, beta = 0 and alpha and gamma are only defined in terms of their difference. So we arbitrarily set gamma to 0 and solve alpha.
1495 *eA = std::atan2 ( element10, element00 );
1496 *eB = M_PI / 2.0;
1497 *eG = 0.0;
1498 }
1499 }
1500
1501 //================================================ Get the angles to proper range
1502 if ( *eA < 0.0 ) { *eA = 2.0 * M_PI + *eA; }
1503 if ( *eB < 0.0 ) { *eB = M_PI + *eB; }
1504 if ( *eG < 0.0 ) { *eG = 2.0 * M_PI + *eG; }
1505
1506 //================================================ Done
1507 return ;
1508
1509 }

## ◆ getEulerZXZFromAngleAxisFullSearch()

void ProSHADE_internal_maths::getEulerZXZFromAngleAxisFullSearch | ( | proshade_double | axX,
|  | proshade_double | axY,
|  | proshade_double | axZ,
|  | proshade_double | axAng,
|  | proshade_double * | eA,
|  | proshade_double * | eB,
|  | proshade_double * | eG,
|  | proshade_signed | angDim
| ) |  |

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

This function is meant for solving the issue of angle-axis conversion to Euler ZXZ convention for axis 0,0,1, where all the rotation matrix elements used for Euler alpha and gamma angles are 0.0. The function overcomes this by simply searching all the rotation function indices for having angle-axis value similar to the required one - a rather slow approach. Therefore, the getEulerZXZFromAngleAxis() function should be used instead and only if it fails (has all angles 0.0), then this function should be used instead.

Parameters

  [in] | axX | Angle-axis representation axis x element.
  [in] | axY | Angle-axis representation axis y element.
  [in] | axZ | Angle-axis representation axis z element.
  [in] | axAng | Angle-axis representation angle.
  [in] | eA | Pointer to which the Euler angle alpha value will be saved.
  [in] | eB | Pointer to which the Euler angle beta value will be saved.
  [in] | eG | Pointer to which the Euler angle gamma value will be saved.

Definition at line 1526 of file ProSHADE_maths.cpp.

1527 {
1528 //================================================ Initialise variables
1529 proshade_double bestDist = 999.9;
1530 proshade_double eAHlp, eBHlp, eGHlp, axXHlp, axYHlp, axZHlp, axAngHlp, axDist;
1531
1532 //================================================ Allocate memory
1533 proshade_double* rMat = new proshade_double[9];
1534 ProSHADE_internal_misc::checkMemoryAllocation ( rMat, __FILE__, __LINE__, __func__ );
1535
1536 //================================================ For each rotation function index (i.e. existing Euler angles ZXZ combination)
1537 for ( proshade_signed xIt = 0; xIt < angDim; xIt++ )
1538 {
1539 for ( proshade_signed yIt = 0; yIt < angDim; yIt++ )
1540 {
1541 for ( proshade_signed zIt = 0; zIt < angDim; zIt++ )
1542 {
1543 //==================================== Speed up
1544 if ( bestDist < 0.001 ) { break; }
1545
1546 //==================================== Get Euler ZXZ from the indices
1547 getEulerZXZFromSOFTPosition ( angDim/2, xIt, yIt, zIt, &eAHlp, &eBHlp, &eGHlp );
1548 getRotationMatrixFromEulerZXZAngles ( eAHlp, eBHlp, eGHlp, rMat );
1549 getAxisAngleFromRotationMatrix ( rMat, &axXHlp, &axYHlp, &axZHlp, &axAngHlp );
1550
1551 //==================================== If angle is larger than 180 degrees
1552 if ( axAng > M_PI )
1553 {
1554 axAng = ( 2.0 * M_PI ) - axAng;
1555 axAng *= -1.0;
1556 }
1557
1558 //==================================== Make sure vector direction is the same
1559 if ( ( ( std::max( std::abs( axXHlp ), std::max( std::abs( axYHlp ), std::abs( axZHlp ) ) ) == std::abs( axXHlp ) ) && ( axXHlp < 0.0 ) ) ||
1560 ( ( std::max( std::abs( axXHlp ), std::max( std::abs( axYHlp ), std::abs( axZHlp ) ) ) == std::abs( axYHlp ) ) && ( axYHlp < 0.0 ) ) ||
1561 ( ( std::max( std::abs( axXHlp ), std::max( std::abs( axYHlp ), std::abs( axZHlp ) ) ) == std::abs( axZHlp ) ) && ( axZHlp < 0.0 ) ) )
1562 {
1563 axXHlp *= -1.0;
1564 axYHlp *= -1.0;
1565 axZHlp *= -1.0;
1566 axAngHlp *= -1.0;
1567 }
1568
1569 if ( ( ( std::max( std::abs( axX ), std::max( std::abs( axY ), std::abs( axZ ) ) ) == std::abs( axX ) ) && ( axX < 0.0 ) ) ||
1570 ( ( std::max( std::abs( axX ), std::max( std::abs( axY ), std::abs( axZ ) ) ) == std::abs( axY ) ) && ( axY < 0.0 ) ) ||
1571 ( ( std::max( std::abs( axX ), std::max( std::abs( axY ), std::abs( axZ ) ) ) == std::abs( axZ ) ) && ( axZ < 0.0 ) ) )
1572 {
1573 axX *= -1.0;
1574 axY *= -1.0;
1575 axZ *= -1.0;
1576 axAng *= -1.0;
1577 }
1578
1579 //==================================== Compute distance to the requested angle-axis values
1580 axDist = std::abs( axAng - axAngHlp ) + ( 1.0 - std::abs ( ( ( axX * axXHlp ) + ( axY * axYHlp ) + ( axZ * axZHlp ) ) /
1581 ( sqrt( pow( axX, 2.0 ) + pow( axY, 2.0 ) + pow( axZ, 2.0 ) ) * sqrt( pow( axXHlp, 2.0 ) + pow( axYHlp, 2.0 ) + pow( axZHlp, 2.0 ) ) ) ) );
1582
1583 //==================================== Is this point an improvement
1584 if ( std::abs ( axDist ) < bestDist )
1585 {
1586 //================================ If so, note it
1587 bestDist = std::abs ( axDist );
1588 *eA = eAHlp;
1589 *eB = eBHlp;
1590 *eG = eGHlp;
1591 }
1592 }
1593 }
1594 }
1595
1596 //================================================ Release memory
1597 delete[] rMat;
1598
1599 //================================================ Done
1600 return ;
1601
1602 }

## ◆ getEulerZXZFromRotMatrix()

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

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

Parameters

  [in] | rotMat | Rotation matrix as an array of 9 values.
  [in] | eA | Pointer to which the Euler angle alpha value will be saved.
  [in] | eB | Pointer to which the Euler angle beta value will be saved.
  [in] | eG | Pointer to which the Euler angle gamma value will be saved.

Definition at line 1394 of file ProSHADE_maths.cpp.

1395 {
1396 //================================================ Get ZXZ Euler from matrix
1397 *eA = atan2 ( rotMat[7], rotMat[6] );
1398 *eB = acos ( rotMat[8] );
1399 *eG = atan2 ( rotMat[5], -rotMat[2] );
1400
1401 //================================================ Solve undefined 0,0 inputs (i.e. identity matrix)
1402 proshade_double errLimit = 0.001;
1403 if ( ( ( rotMat[7] < errLimit ) && ( rotMat[7] > -errLimit ) ) && ( ( rotMat[6] < errLimit ) && ( rotMat[6] > -errLimit ) ) )
1404 {
1405 //============================================ atan2 (0,0) is undefined, we want 0.0 here
1406 *eA = 0.0;
1407 }
1408
1409 if ( ( ( rotMat[5] < errLimit ) && ( rotMat[5] > -errLimit ) ) && ( ( rotMat[2] < errLimit ) && ( rotMat[2] > -errLimit ) ) )
1410 {
1411 //============================================ atan2 (0,0) is undefined, we want 0.0 here
1412 *eG = 0.0;
1413 }
1414
1415 //================================================ Get the angles to proper range
1416 if ( *eA < 0.0 ) { *eA = 2.0 * M_PI + *eA; }
1417 if ( *eB < 0.0 ) { *eB = M_PI + *eB; }
1418 if ( *eG < 0.0 ) { *eG = 2.0 * M_PI + *eG; }
1419
1420 //================================================ Done
1421 return ;
1422
1423 }

## ◆ getEulerZXZFromSOFTPosition()

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

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

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

Parameters

  [in] | band | The maximum bandwidth of the computation.
  [in] | x | The x-axis position in the inverse SOFT map.
  [in] | y | The y-axis position in the inverse SOFT map.
  [in] | z | The z-axis position in the inverse SOFT map.
  [in] | eulerAlpha | Pointer to where the Euler alpha angle will be saved.
  [in] | eulerBeta | Pointer to where the Euler beta angle will be saved.
  [in] | eulerGamma | Pointer to where the Euler gamma angle will be saved.

Definition at line 961 of file ProSHADE_maths.cpp.

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

## ◆ getGLFirstEvenRoot()

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

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

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

Parameters

  [in] | polyAtZero | The value of the polynomial at zero.
  [in] | order | The positive integer value of the polynomial order.
  [in] | abscAtZero | Pointer to variable storing the abscissa value at zero.
  [in] | weightAtZero | Pointer to variable storing the weight value at zero.
  [in] | taylorSeriesCap | The limit on the Taylor series.

Definition at line 384 of file ProSHADE_maths.cpp.

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

## ◆ 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] | order | Positive integer order of the Legendre polynomial which value at zero we want.
  [in] | polyValue | Pointer to variable which will store the resulting polynomial value at zero.
  [in] | deriValue | Pointer to variable which will store the derivative of the zero value.

Definition at line 347 of file ProSHADE_maths.cpp.

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

## ◆ getLegendreAbscAndWeights()

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

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

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

Parameters

  [in] | order | The order to which the abscissas and weights should be prepared.
  [in] | abscissas | The array holding the abscissa values.
  [in] | weights | The array holding the weight values.
  [in] | taylorSeriesCap | The limit on the Taylor series.

Definition at line 287 of file ProSHADE_maths.cpp.

288 {
289 //================================================ Sanity check
290 if ( order < 2 )
291 {
292 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." );
293 }
294
295 //================================================ Initialise
296 proshade_double polyValue = 0.0;
297 proshade_double deriValue = 0.0;
298 proshade_double weightSum = 0.0;
299
300 //================================================ Find the polynomial and derivative values at 0
301 getGLPolyAtZero ( order,
302 &polyValue,
303 &deriValue );
304
305 //================================================ If the order is odd, then 0 is a root ...
306 if ( order % 2 == 1 )
307 {
308 abscissas[((order-1)/2)] = polyValue;
309 weights[((order-1)/2)] = deriValue;
310 }
311 else
312 {
313 // ... and if order is even, find the first root
314 getGLFirstEvenRoot ( polyValue, order, &abscissas[(order/2)], &weights[(order/2)], taylorSeriesCap );
315 }
316
317 //================================================ Now, having computed the first roots, complete the series
318 completeLegendreSeries ( order, abscissas, weights, taylorSeriesCap );
319
320 //================================================ Correct weights by anscissa values
321 for ( proshade_unsign iter = 0; iter < order; iter++ )
322 {
323 weights[iter] = 2.0 / ( 1.0 - abscissas[iter] ) / ( 1.0 + abscissas[iter] ) / weights[iter] / weights[iter];
324 weightSum = weightSum + weights[iter];
325 }
326
327 //================================================ Normalise weights
328 for ( proshade_unsign iter = 0; iter < order; iter++ )
329 {
330 weights[iter] = 2.0 * weights[iter] / weightSum;
331 }
332
333 //================================================ Done
334 return ;
335 }

## ◆ getRotationMatrixFromAngleAxis()

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] | rotMat | Rotation matrix as an array of 9 values will be saved to this pointer, must already be allocated.
  [in] | x | The x-axis value of the axis vector.
  [in] | y | The y-axis value of the axis vector.
  [in] | z | The z-axis value of the axis vector.
  [in] | angThe | angle value.

Definition at line 1343 of file ProSHADE_maths.cpp.

1344 {
1345 //================================================ If angle is 0 or infinity (anything divided by 0), return identity matrix
1346 if ( ( ang == 0.0 ) || ( std::isinf ( ang ) ) )
1347 {
1348 //============================================ Create identity
1349 for ( proshade_unsign i = 0; i < 9; i++ ) { rotMat[i] = 0.0; }
1350 rotMat[0] = 1.0;
1351 rotMat[4] = 1.0;
1352 rotMat[8] = 1.0;
1353
1354 //============================================ Done
1355 return ;
1356 }
1357
1358 //================================================ Compute the matrix
1359 proshade_double cAng = cos ( ang );
1360 proshade_double sAng = sin ( ang );
1361 proshade_double tAng = 1.0 - cAng;
1362
1363 rotMat[0] = cAng + x * x * tAng;
1364 rotMat[4] = cAng + y * y * tAng;
1365 rotMat[8] = cAng + z * z * tAng;
1366
1367 proshade_double tmp1 = x * y * tAng;
1368 proshade_double tmp2 = z * sAng;
1369 rotMat[3] = tmp1 + tmp2;
1370 rotMat[1] = tmp1 - tmp2;
1371
1372 tmp1 = x * z * tAng;
1373 tmp2 = y * sAng;
1374 rotMat[6] = tmp1 - tmp2;
1375 rotMat[2] = tmp1 + tmp2;
1376
1377 tmp1 = y * z * tAng;
1378 tmp2 = x * sAng;
1379 rotMat[7] = tmp1 + tmp2;
1380 rotMat[5] = tmp1 - tmp2;
1381
1382 //================================================ Done
1383 return ;
1384
1385 }

## ◆ getRotationMatrixFromEulerZXZAngles()

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

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

Parameters

  [in] | eulerAlpha | The Euler alpha angle value.
  [in] | eulerBeta | The Euler beta angle value.
  [in] | eulerGamma | The Euler gamma angle value.
  [in] | matrix | A pointer to array of 9 values to which the results of the function will be saved.

Definition at line 1005 of file ProSHADE_maths.cpp.

1006 {
1007 //================================================ First row
1008 matrix[0] = cos ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) - sin ( eulerAlpha ) * sin ( eulerGamma );
1009 matrix[1] = sin ( eulerAlpha ) * cos ( eulerBeta ) * cos ( eulerGamma ) + cos ( eulerAlpha ) * sin ( eulerGamma );
1010 matrix[2] = -sin ( eulerBeta ) * cos ( eulerGamma );
1011
1012 //================================================ Second row
1013 matrix[3] = -cos ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) - sin ( eulerAlpha ) * cos ( eulerGamma );
1014 matrix[4] = -sin ( eulerAlpha ) * cos ( eulerBeta ) * sin ( eulerGamma ) + cos ( eulerAlpha ) * cos ( eulerGamma );
1015 matrix[5] = sin ( eulerBeta ) * sin ( eulerGamma );
1016
1017 //================================================ Third row
1018 matrix[6] = cos ( eulerAlpha ) * sin ( eulerBeta );
1019 matrix[7] = sin ( eulerAlpha ) * sin ( eulerBeta );
1020 matrix[8] = cos ( eulerBeta );
1021
1022 //================================================ Done
1023 return ;
1024
1025 }

## ◆ getSOFTPositionFromEulerZXZ()

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

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

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

Parameters

  [in] | band | The maximum bandwidth of the computation.
  [in] | eulerAlpha | The Euler alpha angle value.
  [in] | eulerBeta | The Euler beta angle value.
  [in] | eulerGamma | The Euler gamma angle value.
  [in] | x | Pointer to where the closest x-axis position in the inverse SOFT map will be saved to (position may be decimal!).
  [in] | y | Pointer to where the closest y-axis position in the inverse SOFT map will be saved to (position may be decimal!).
  [in] | z | Pointer to where the closest z-axis position in the inverse SOFT map will be saved to (position may be decimal!).

Definition at line 986 of file ProSHADE_maths.cpp.

987 {
988 //================================================ Convert Euler angles to indices
989 *x = static_cast<proshade_double> ( ( eulerBeta * static_cast<proshade_double> ( 2.0 * band ) ) / M_PI );
990 *y = static_cast<proshade_double> ( ( eulerGamma * static_cast<proshade_double> ( band ) ) / M_PI );
991 *z = static_cast<proshade_double> ( ( eulerAlpha * static_cast<proshade_double> ( band ) ) / M_PI );
992
993 //================================================ Done
994 return ;
995
996 }

## ◆ 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] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | axis | The axis to be checked against CSymList to see if it not already present.
  [in] | tolerance | The allowed error on each dimension of the axis.
  [in] | improve | If 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] | ret | Boolean specifying whether a similar axis was found or not.

Definition at line 2397 of file ProSHADE_maths.cpp.

2398 {
2399 //================================================ Initialise variables
2400 bool ret = true;
2401 proshade_unsign whichImprove;
2402
2403 //================================================ For each already detected member
2404 for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
2405 {
2406 //============================================ Is fold the same?
2407 if ( CSymList->at(grIt)[0] == axis[0] )
2408 {
2409 if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], axis[1], axis[2], axis[3], tolerance ) )
2410 {
2411 ret = false;
2412 whichImprove = grIt;
2413 break;
2414 }
2415 }
2416 }
2417
2418 //================================================ Improve, if required
2419 if ( improve && !ret )
2420 {
2421 CSymList->at(whichImprove)[1] = axis[1];
2422 CSymList->at(whichImprove)[2] = axis[2];
2423 CSymList->at(whichImprove)[3] = axis[3];
2424 CSymList->at(whichImprove)[4] = axis[4];
2425 CSymList->at(whichImprove)[5] = axis[5];
2426 }
2427
2428 //================================================ Done
2429 return ( ret );
2430
2431 }

## ◆ 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] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | X | The axis x-element to be checked against CSymList to see if it not already present.
  [in] | Y | The axis x-element to be checked against CSymList to see if it not already present.
  [in] | Z | The axis x-element to be checked against CSymList to see if it not already present.
  [in] | tolerance | The allowed error on each dimension of the axis.
  [out] | ret | Boolean specifying whether a similar axis was found or not.

Definition at line 2445 of file ProSHADE_maths.cpp.

2446 {
2447 //================================================ Initialise variables
2448 bool ret = true;
2449
2450 //================================================ For each already detected member
2451 for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( CSymList->size() ); grIt++ )
2452 {
2453 if ( fold == CSymList->at(grIt)[0] )
2454 {
2455 if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( CSymList->at(grIt)[1], CSymList->at(grIt)[2], CSymList->at(grIt)[3], X, Y, Z, tolerance ) )
2456 {
2457 ret = false;
2458 break;
2459 }
2460 }
2461 }
2462
2463 //================================================ Done
2464 return ( ret );
2465
2466 }

## ◆ 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] | el1 | Group element as rotation matrix in the group element matrix format.
  [in] | el2 | Group element as rotation matrix in the group element matrix format.
  [out] | ret | Matrix in the group element format resulting from the input matrices multiplication.

Definition at line 1925 of file ProSHADE_maths.cpp.

1926 {
1927 //================================================ Initialise variables
1928 std::vector< proshade_double > ret;
1929
1930 //================================================ Compute
1931 ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(0) ) +
1932 ( el1->at(1) * el2->at(3) ) +
1933 ( el1->at(2) * el2->at(6) ) );
1934 ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(1) ) +
1935 ( el1->at(1) * el2->at(4) ) +
1936 ( el1->at(2) * el2->at(7) ) );
1937 ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(0) * el2->at(2) ) +
1938 ( el1->at(1) * el2->at(5) ) +
1939 ( el1->at(2) * el2->at(8) ) );
1940
1941 ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(0) ) +
1942 ( el1->at(4) * el2->at(3) ) +
1943 ( el1->at(5) * el2->at(6) ) );
1944 ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(1) ) +
1945 ( el1->at(4) * el2->at(4) ) +
1946 ( el1->at(5) * el2->at(7) ) );
1947 ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(3) * el2->at(2) ) +
1948 ( el1->at(4) * el2->at(5) ) +
1949 ( el1->at(5) * el2->at(8) ) );
1950
1951 ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(0) ) +
1952 ( el1->at(7) * el2->at(3) ) +
1953 ( el1->at(8) * el2->at(6) ) );
1954 ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(1) ) +
1955 ( el1->at(7) * el2->at(4) ) +
1956 ( el1->at(8) * el2->at(7) ) );
1957 ProSHADE_internal_misc::addToDoubleVector ( &ret, ( el1->at(6) * el2->at(2) ) +
1958 ( el1->at(7) * el2->at(5) ) +
1959 ( el1->at(8) * el2->at(8) ) );
1960
1961
1962 //================================================ Done
1963 return ( ret );
1964
1965 }

## ◆ multiplyTwoSquareMatrices()

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

Function to compute matrix multiplication.

Parameters

  [in] | A | The left matrix of the matrix multiplication to be solved.
  [in] | B | The right matrix of the matrix multiplication to be solved. (Assuming it already has been transposed).
  [in] | res | Matrix containing the results.
  [in] | dim | The 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 1613 of file ProSHADE_maths.cpp.

1614 {
1615 //================================================ Compute the matrix multiplication
1616 for ( proshade_unsign row = 0; row < dim; row++ )
1617 {
1618 for ( proshade_unsign col = 0; col < dim; col++ )
1619 {
1620 for ( proshade_unsign inner = 0; inner < dim; inner++ )
1621 {
1622 res[(row*dim)+col] += A[(inner*dim)+row] * B[(col*dim)+inner];
1623 }
1624 }
1625 }
1626
1627 //================================================ Done
1628 return ;
1629
1630 }

## ◆ 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] | mean | The mean of the normal distribution.
  [in] | standardDev | The standard deviation of the normal distribution.
  [in] | value | The value on the axis for which the height of the normal distribution is to be obtained.
  [out] | X | The height of the normal distribution at point given by the value.

Definition at line 1685 of file ProSHADE_maths.cpp.

1686 {
1687 //================================================ Compute and return
1688 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) ) );
1689
1690 }

## ◆ 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] | bestLattitude | Proshade double pointer to variable containing the best lattitude index value and to which the optimised result will be saved into.
  [in] | bestLongitude | Proshade double pointer to variable containing the best longitude index value and to which the optimised result will be saved into.
  [in] | bestSum | Proshade double pointer to variable containing the best position rotation function values sum and to which the optimised result will be saved into.
  [in] | sphereList | A vector containing the list of spheres which form the set for this symmetry.
  [in] | step | The size of the step.

Definition at line 2080 of file ProSHADE_maths.cpp.

2081 {
2082 //================================================ Initialise variables
2083 proshade_double lonM, lonP, latM, latP, movSum;
2084 std::vector<proshade_double> latVals ( 3 );
2085 std::vector<proshade_double> lonVals ( 3 );
2086 proshade_double learningRate = 0.1;
2087 proshade_double prevVal = *bestSum;
2088 proshade_double valChange = 999.9;
2089 proshade_double origBestLat = std::round ( *bestLattitude );
2090 proshade_double origBestLon = std::round ( *bestLongitude );
2091 proshade_double tmpVal;
2092
2093 //================================================ Initialise interpolators in all directions around the point of interest
2094 std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsMinusMinus;
2095 std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsMinusPlus;
2096 std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsPlusMinus;
2097 std::vector<ProSHADE_internal_maths::BicubicInterpolator*> interpolsPlusPlus;
2098 prepareBiCubicInterpolatorsMinusMinus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsMinusMinus, sphereMappedRotFun );
2099 prepareBiCubicInterpolatorsMinusPlus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsMinusPlus, sphereMappedRotFun );
2100 prepareBiCubicInterpolatorsPlusMinus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsPlusMinus, sphereMappedRotFun );
2101 prepareBiCubicInterpolatorsPlusPlus ( std::round ( *bestLattitude ), std::round ( *bestLongitude ), sphereList, &interpolsPlusPlus, sphereMappedRotFun );
2102
2103 //================================================ Start the pseudo gradient ascent (while there is some change)
2104 while ( valChange > 0.0001 )
2105 {
2106 //============================================ Find the surrounding points to the currently best position
2107 lonM = *bestLongitude - step;
2108 lonP = *bestLongitude + step;
2109 latM = *bestLattitude - step;
2110 latP = *bestLattitude + step;
2111
2112 //============================================ Deal with optimising outside of prepared range - recursion
2113 if ( latM < ( origBestLat - 1.0 ) ) { tmpVal = *bestLattitude; *bestLattitude = origBestLat - 1.0; optimiseAxisBiCubicInterpolation ( bestLattitude, bestLongitude, bestSum, sphereList, sphereMappedRotFun, step ); if ( *bestLattitude == origBestLat - 1.0 ) { *bestLattitude = tmpVal; } break; }
2114 if ( latP > ( origBestLat + 1.0 ) ) { tmpVal = *bestLattitude; *bestLattitude = origBestLat + 1.0; optimiseAxisBiCubicInterpolation ( bestLattitude, bestLongitude, bestSum, sphereList, sphereMappedRotFun, step ); if ( *bestLattitude == origBestLat + 1.0 ) { *bestLattitude = tmpVal; } break; }
2115 if ( lonM < ( origBestLon - 1.0 ) ) { tmpVal = *bestLongitude; *bestLongitude = origBestLon - 1.0; optimiseAxisBiCubicInterpolation ( bestLattitude, bestLongitude, bestSum, sphereList, sphereMappedRotFun, step ); if ( *bestLongitude == origBestLon - 1.0 ) { *bestLongitude = tmpVal; } break; }
2116 if ( lonP > ( origBestLon + 1.0 ) ) { tmpVal = *bestLongitude; *bestLongitude = origBestLon + 1.0; optimiseAxisBiCubicInterpolation ( bestLattitude, bestLongitude, bestSum, sphereList, sphereMappedRotFun, step ); if ( *bestLongitude == origBestLon + 1.0 ) { *bestLongitude = tmpVal; } break; }
2117
2118 //============================================ Prepare vectors of tested positions
2119 latVals.at(0) = latM; latVals.at(1) = *bestLattitude; latVals.at(2) = latP;
2120 lonVals.at(0) = lonM; lonVals.at(1) = *bestLongitude; lonVals.at(2) = lonP;
2121
2122 //============================================ Find the best change
2123 for ( proshade_unsign laIt = 0; laIt < static_cast<proshade_unsign> ( latVals.size() ); laIt++ )
2124 {
2125 for ( proshade_unsign loIt = 0; loIt < static_cast<proshade_unsign> ( lonVals.size() ); loIt++ )
2126 {
2127 //==================================== For this combination of lat and lon, find sum over spheres
2128 movSum = 1.0;
2129 for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( sphereList->size() ); iter++ )
2130 {
2131 //================================ Interpolate using correct interpolators
2132 if ( ( latVals.at(laIt) <= origBestLat ) && ( lonVals.at(loIt) <= origBestLon ) ) { movSum += interpolsMinusMinus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2133 if ( ( latVals.at(laIt) <= origBestLat ) && ( lonVals.at(loIt) > origBestLon ) ) { movSum += interpolsMinusPlus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2134 if ( ( latVals.at(laIt) > origBestLat ) && ( lonVals.at(loIt) <= origBestLon ) ) { movSum += interpolsPlusMinus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2135 if ( ( latVals.at(laIt) > origBestLat ) && ( lonVals.at(loIt) > origBestLon ) ) { movSum += interpolsPlusPlus.at(iter)->getValue ( latVals.at(laIt), lonVals.at(loIt) ); }
2136 }
2137
2138 //==================================== If position has improved, save it
2139 if ( *bestSum < movSum )
2140 {
2141 *bestSum = movSum;
2142 *bestLongitude = lonVals.at(loIt);
2143 *bestLattitude = latVals.at(laIt);
2144 }
2145 }
2146 }
2147
2148 //============================================ Prepare for next iteration
2149 valChange = std::floor ( 100000.0 * ( *bestSum - prevVal ) ) / 100000.0;
2150 prevVal = std::floor ( 100000.0 * ( *bestSum ) ) / 100000.0;
2151 step = std::max ( ( valChange / step ) * learningRate, 0.01 );
2152 if ( learningRate >= 0.02 ) { learningRate -= 0.01; }
2153
2154 }
2155
2156 //================================================ Release interpolators memory
2157 for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsMinusMinus.size() ); intIt++ ) { delete interpolsMinusMinus.at(intIt); }
2158 for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsMinusPlus.size() ); intIt++ ) { delete interpolsMinusPlus.at(intIt); }
2159 for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsPlusMinus.size() ); intIt++ ) { delete interpolsPlusMinus.at(intIt); }
2160 for ( proshade_unsign intIt = 0; intIt < static_cast<proshade_unsign> ( interpolsPlusPlus.size() ); intIt++ ) { delete interpolsPlusPlus.at(intIt); }
2161
2162 //================================================ Done
2163 return ;
2164 }

## ◆ 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] | valSet1 | This is the set of x-values.
  [in] | valSet2 | This is the set of y-values.
  [in] | length | The length of both arrays (both arrays have to have the same length).
  [out] | X | The Pearson's correlation coefficient value.

Definition at line 244 of file ProSHADE_maths.cpp.

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

## ◆ 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] | bestLattitude | The lattitude index value around which interpolation is to be prepared.
  [in] | bestLongitude | The longitude index value around which interpolation is to be prepared.
  [in] | sphereList | A vector containing the list of spheres which form the set for this symmetry.
  [in] | interpols | A pointer to a vector of ProSHADE interpolator objects to which the interpolators will be saved into.

Definition at line 2177 of file ProSHADE_maths.cpp.

2178 {
2179 //================================================ Initialise local variables
2180 proshade_signed latHlp, lonHlp;
2181 proshade_signed angDim = sphereMappedRotFun->at(0)->getAngularDim();
2182
2183 //================================================ Prepare the interpolator objects for interpolation around the position
2184 for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2185 {
2186 //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2187 proshade_double** interpGrid = new proshade_double*[4];
2188 ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2189
2190 //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2191 for ( proshade_unsign iter = 0; iter < 4; iter++ )
2192 {
2193 interpGrid[iter] = new proshade_double[4];
2194 ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2195 }
2196
2197 //============================================ Fill in the value grid on which the interpolation is to be done
2198 for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2199 {
2200 for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2201 {
2202 latHlp = bestLattitude - 2 + latIt; if ( latHlp < 0.0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2203 lonHlp = bestLongitude - 2 + lonIt; if ( lonHlp < 0.0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2204 interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( latHlp, lonHlp );
2205 }
2206 }
2207
2208 //============================================ Create the interpolators
2209 ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude - 1.0, bestLongitude - 1.0 );
2210 interpols->emplace_back ( biCubInterp );
2211
2212 //============================================ Release memory
2213 for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2214 delete[] interpGrid;
2215 }
2216
2217 //================================================ Done
2218 return ;
2219 }

## ◆ 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] | bestLattitude | The lattitude index value around which interpolation is to be prepared.
  [in] | bestLongitude | The longitude index value around which interpolation is to be prepared.
  [in] | sphereList | A vector containing the list of spheres which form the set for this symmetry.
  [in] | interpols | A pointer to a vector of ProSHADE interpolator objects to which the interpolators will be saved into.

Definition at line 2232 of file ProSHADE_maths.cpp.

2233 {
2234 //================================================ Initialise local variables
2235 proshade_signed latHlp, lonHlp;
2236 proshade_signed angDim = sphereMappedRotFun->at(0)->getAngularDim();
2237
2238 //================================================ Prepare the interpolator objects for interpolation around the position
2239 for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2240 {
2241 //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2242 proshade_double** interpGrid = new proshade_double*[4];
2243 ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2244
2245 //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2246 for ( proshade_unsign iter = 0; iter < 4; iter++ )
2247 {
2248 interpGrid[iter] = new proshade_double[4];
2249 ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2250 }
2251
2252 //============================================ Fill in the value grid on which the interpolation is to be done
2253 for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2254 {
2255 for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2256 {
2257 latHlp = bestLattitude - 2 + latIt; if ( latHlp < 0.0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2258 lonHlp = bestLongitude - 1 + lonIt; if ( lonHlp < 0.0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2259 interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( latHlp, lonHlp );
2260 }
2261 }
2262
2263 //============================================ Create the interpolators
2264 ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude - 1.0, bestLongitude );
2265 interpols->emplace_back ( biCubInterp );
2266
2267 //============================================ Release memory
2268 for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2269 delete[] interpGrid;
2270 }
2271
2272 //================================================ Done
2273 return ;
2274 }

## ◆ 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] | bestLattitude | The lattitude index value around which interpolation is to be prepared.
  [in] | bestLongitude | The longitude index value around which interpolation is to be prepared.
  [in] | sphereList | A vector containing the list of spheres which form the set for this symmetry.
  [in] | interpols | A pointer to a vector of ProSHADE interpolator objects to which the interpolators will be saved into.

Definition at line 2287 of file ProSHADE_maths.cpp.

2288 {
2289 //================================================ Initialise local variables
2290 proshade_signed latHlp, lonHlp;
2291 proshade_signed angDim = sphereMappedRotFun->at(0)->getAngularDim();
2292
2293 //================================================ Prepare the interpolator objects for interpolation around the position
2294 for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2295 {
2296 //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2297 proshade_double** interpGrid = new proshade_double*[4];
2298 ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2299
2300 //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2301 for ( proshade_unsign iter = 0; iter < 4; iter++ )
2302 {
2303 interpGrid[iter] = new proshade_double[4];
2304 ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2305 }
2306
2307 //============================================ Fill in the value grid on which the interpolation is to be done
2308 for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2309 {
2310 for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2311 {
2312 latHlp = bestLattitude - 1 + latIt; if ( latHlp < 0.0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2313 lonHlp = bestLongitude - 2 + lonIt; if ( lonHlp < 0.0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2314 interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( latHlp, lonHlp );
2315 }
2316 }
2317
2318 //============================================ Create the interpolators
2319 ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude, bestLongitude - 1.0 );
2320 interpols->emplace_back ( biCubInterp );
2321
2322 //============================================ Release memory
2323 for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2324 delete[] interpGrid;
2325 }
2326
2327 //================================================ Done
2328 return ;
2329 }

## ◆ 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] | bestLattitude | The lattitude index value around which interpolation is to be prepared.
  [in] | bestLongitude | The longitude index value around which interpolation is to be prepared.
  [in] | sphereList | A vector containing the list of spheres which form the set for this symmetry.
  [in] | interpols | A pointer to a vector of ProSHADE interpolator objects to which the interpolators will be saved into.

Definition at line 2342 of file ProSHADE_maths.cpp.

2343 {
2344 //================================================ Initialise local variables
2345 proshade_signed latHlp, lonHlp;
2346 proshade_signed angDim = sphereMappedRotFun->at(0)->getAngularDim();
2347
2348 //================================================ Prepare the interpolator objects for interpolation around the position
2349 for ( proshade_unsign sphereIt = 0; sphereIt < static_cast<proshade_unsign> ( sphereList->size() ); sphereIt++ )
2350 {
2351 //============================================ Allocate memory for the value grid on which the interpolation is to be done (along first dimension)
2352 proshade_double** interpGrid = new proshade_double*[4];
2353 ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid, __FILE__, __LINE__, __func__ );
2354
2355 //============================================ Allocate memory for the value grid on which the interpolation is to be done (along second dimension)
2356 for ( proshade_unsign iter = 0; iter < 4; iter++ )
2357 {
2358 interpGrid[iter] = new proshade_double[4];
2359 ProSHADE_internal_misc::checkMemoryAllocation ( interpGrid[iter], __FILE__, __LINE__, __func__ );
2360 }
2361
2362 //============================================ Fill in the value grid on which the interpolation is to be done
2363 for ( proshade_unsign latIt = 0; latIt < 4; latIt++ )
2364 {
2365 for ( proshade_unsign lonIt = 0; lonIt < 4; lonIt++ )
2366 {
2367 latHlp = bestLattitude - 1 + latIt; if ( latHlp < 0.0 ) { latHlp += angDim; } if ( latHlp >= angDim ) { latHlp -= angDim; }
2368 lonHlp = bestLongitude - 1 + lonIt; if ( lonHlp < 0.0 ) { lonHlp += angDim; } if ( lonHlp >= angDim ) { lonHlp -= angDim; }
2369 interpGrid[latIt][lonIt] = sphereMappedRotFun->at(sphereList->at(sphereIt))->getSphereLatLonPosition ( latHlp, lonHlp );
2370 }
2371 }
2372
2373 //============================================ Create the interpolators
2374 ProSHADE_internal_maths::BicubicInterpolator* biCubInterp = new ProSHADE_internal_maths::BicubicInterpolator ( interpGrid, bestLattitude, bestLongitude );
2375 interpols->emplace_back ( biCubInterp );
2376
2377 //============================================ Release memory
2378 for ( proshade_unsign iter = 0; iter < 4; iter++ ) { delete[] interpGrid[iter]; }
2379 delete[] interpGrid;
2380 }
2381
2382 //================================================ Done
2383 return ;
2384 }

## ◆ primeFactorsDecomp()

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

Function to find prime factors of an integer.

Parameters

  [in] | number | A single integer number to be decomposed into its prime factors.

Definition at line 1636 of file ProSHADE_maths.cpp.

1637 {
1638 //================================================ Initialise variables
1639 std::vector < proshade_signed > ret;
1640
1641 //================================================ Deal with negative numbers
1642 bool changeSign = false;
1643 if ( number < 0 ) { changeSign = true; number = -number; }
1644
1645 //================================================ Deal with zero and one
1646 if ( number == 0 ) { ProSHADE_internal_misc::addToSignedVector ( &ret, 0 ); return ( ret ); }
1647 if ( number == 1 ) { ProSHADE_internal_misc::addToSignedVector ( &ret, 1 ); return ( ret ); }
1648
1649 //================================================ Divide by 2 as long as you can
1650 while ( number % 2 == 0 )
1651 {
1652 ProSHADE_internal_misc::addToSignedVector ( &ret, 2 );
1653 number = number / 2;
1654 }
1655
1656 //================================================ Check all odd numbers up to the square root
1657 for ( proshade_unsign posDiv = 3; posDiv <= sqrt ( number ); posDiv += 2)
1658 {
1659 // If posDiv is a divisor of the number, save the result
1660 while ( number % posDiv == 0 )
1661 {
1662 ProSHADE_internal_misc::addToSignedVector ( &ret, posDiv );
1663 number = number / posDiv;
1664 }
1665 }
1666
1667 //================================================ If the number was a large prime number, save it as it is
1668 if ( number > 2 ) { ProSHADE_internal_misc::addToSignedVector ( &ret, number ); }
1669
1670 //================================================ Finish dealing with negative numbers
1671 if ( changeSign ) { ret.at(0) = -ret.at(0); }
1672
1673 //================================================ Done
1674 return ( ret );
1675
1676 }

## ◆ rotationMatrixSimilarity()

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

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

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

Parameters

  [in] | mat1 | Vector of 9 numbers representing first rotation matrix.
  [in] | mat1 | Vector of 9 numbers representing second rotation matrix.
  [in] | tolerance | Double number representing the maximum allowed error on the distance.
  [out] | res | Boolean decision if the two matrices are similar or not.

Definition at line 1979 of file ProSHADE_maths.cpp.

1980 {
1981 //================================================ Initialise variables
1982 bool ret = false;
1983
1984 //================================================ Compute trace of mat1 * mat2^T
1985 proshade_double trace = ( mat1->at(0) * mat2->at(0) ) + ( mat1->at(1) * mat2->at(1) ) + ( mat1->at(2) * mat2->at(2) );
1986 trace += ( mat1->at(3) * mat2->at(3) ) + ( mat1->at(4) * mat2->at(4) ) + ( mat1->at(5) * mat2->at(5) );
1987 trace += ( mat1->at(6) * mat2->at(6) ) + ( mat1->at(7) * mat2->at(7) ) + ( mat1->at(8) * mat2->at(8) );
1988
1989 //================================================ Subtract 3 (so that we would have 0 in case of idenity matrix)
1990 trace -= 3.0;
1991
1992 //================================================ Compare to tolerance
1993 if ( tolerance > std::abs ( trace ) ) { ret = true; }
1994
1995 //================================================ Done
1996 return ( ret );
1997
1998 }

## ◆ 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] | vec | Pointer to a vector of proshade_double's for which mean and sd should be obtained.
  [in] | ret | Pointer 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 if ( ret[0] != ret[0] ) { ret[0] = 0.0; }
132 if ( ret[1] != ret[1] ) { ret[1] = 0.0; }
133
134 //================================================ Return
135 return ;
136
137 }

## ◆ 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] | vec | Pointer to a vector of proshade_double's for which median and IQR should be obtained.
  [in] | ret | Pointer to array of 2 proshade_double's, which will be the return values - first median and second IQR.

Definition at line 147 of file ProSHADE_maths.cpp.

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

## ◆ 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] | a1 | The first element of the first vector.
  [in] | a2 | The second element of the first vector.
  [in] | a3 | The third element of the first vector.
  [in] | b1 | The first element of the second vector.
  [in] | b2 | The second element of the second vector.
  [in] | b3 | The third element of the second vector.
  [in] | tolerance | The allowed difference of the distance measure from the 1.0 for the vectors to still be considered similar.
  [out] | res | Boolean decision if the two vectors are similar or not.

Definition at line 2016 of file ProSHADE_maths.cpp.

2017 {
2018 //================================================ Initialise variables
2019 bool ret = false;
2020
2021 //================================================ Cosine distance
2022 proshade_double cosDist = ( ( a1 * b1 ) + ( a2 * b2 ) + ( a3 * b3 ) ) /
2023 ( sqrt( pow( a1, 2.0 ) + pow( a2, 2.0 ) + pow( a3, 2.0 ) ) *
2024 sqrt( pow( b1, 2.0 ) + pow( b2, 2.0 ) + pow( b3, 2.0 ) ) );
2025
2026 //================================================ Compare the absolute value of distance to 1.0 - tolerance
2027 if ( std::abs( cosDist ) > ( 1.0 - tolerance ) ) { ret = true; }
2028
2029 //================================================ Done
2030 return ( ret );
2031
2032 }

## ◆ 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] | a1 | The first element of the first vector.
  [in] | a2 | The second element of the first vector.
  [in] | a3 | The third element of the first vector.
  [in] | b1 | The first element of the second vector.
  [in] | b2 | The second element of the second vector.
  [in] | b3 | The third element of the second vector.
  [in] | tolerance | The allowed difference of the distance measure from the 1.0 for the vectors to still be considered similar.
  [out] | res | Boolean decision if the two vectors are similar or not.

Definition at line 2050 of file ProSHADE_maths.cpp.

2051 {
2052 //================================================ Initialise variables
2053 bool ret = false;
2054
2055 //================================================ Cosine distance
2056 proshade_double cosDist = ( ( a1 * b1 ) + ( a2 * b2 ) + ( a3 * b3 ) ) /
2057 ( sqrt( pow( a1, 2.0 ) + pow( a2, 2.0 ) + pow( a3, 2.0 ) ) *
2058 sqrt( pow( b1, 2.0 ) + pow( b2, 2.0 ) + pow( b3, 2.0 ) ) );
2059
2060 //================================================ Compare the absolute value of distance to 1.0 - tolerance
2061 if ( cosDist > ( 1.0 - tolerance ) ) { ret = true; }
2062
2063 //================================================ Done
2064 return ( ret );
2065
2066 }
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:2232
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:2287
ProSHADE_internal_maths::evaluateGLSeries
proshade_double evaluateGLSeries(proshade_double *series, proshade_double target, proshade_unsign terms)
This function evaluates the Taylor expansion.
Definition: ProSHADE_maths.cpp:447
ProSHADE_internal_maths::getRotationMatrixFromEulerZXZAngles
void getRotationMatrixFromEulerZXZAngles(proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double *matrix)
Function to find the rotation matrix from Euler angles (ZXZ convention).
Definition: ProSHADE_maths.cpp:1005
ProSHADE_internal_maths::getGLFirstEvenRoot
void getGLFirstEvenRoot(proshade_double polyAtZero, proshade_unsign order, proshade_double *abscAtZero, proshade_double *weighAtZero, proshade_unsign taylorSeriesCap)
This function finds the first root for Legendre polynomials of odd order.
Definition: ProSHADE_maths.cpp:384
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:2080
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:2016
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:2177
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_misc::addToSignedVector
void addToSignedVector(std::vector< proshade_signed > *vecToAddTo, proshade_signed elementToAdd)
Adds the element to the vector.
Definition: ProSHADE_misc.cpp:121
ProSHADE_internal_maths::BicubicInterpolator
Definition: ProSHADE_maths.hpp:102
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:347
ProSHADE_internal_maths::getAxisAngleFromRotationMatrix
void getAxisAngleFromRotationMatrix(proshade_double *rotMat, proshade_double *x, proshade_double *y, proshade_double *z, proshade_double *ang)
This function converts rotation matrix to the axis-angle representation.
Definition: ProSHADE_maths.cpp:1039
ProSHADE_internal_maths::advanceGLPolyValue
proshade_double advanceGLPolyValue(proshade_double from, proshade_double to, proshade_double valAtFrom, proshade_unsign noSteps, proshade_unsign taylorSeriesCap)
This function finds the next value of the polynomial.
Definition: ProSHADE_maths.cpp:477
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:65
ProSHADE_internal_maths::getEulerZXZFromSOFTPosition
void getEulerZXZFromSOFTPosition(proshade_signed band, proshade_signed x, proshade_signed y, proshade_signed z, proshade_double *eulerAlpha, proshade_double *eulerBeta, proshade_double *eulerGamma)
Function to find Euler angles (ZXZ convention) from index position in the inverse SOFT map.
Definition: ProSHADE_maths.cpp:961
ProSHADE_internal_misc::addToUnsignVector
void addToUnsignVector(std::vector< proshade_unsign > *vecToAddTo, proshade_unsign elementToAdd)
Adds the element to the vector.
Definition: ProSHADE_misc.cpp:99
ProSHADE_internal_maths::completeLegendreSeries
void completeLegendreSeries(proshade_unsign order, proshade_double *abscissa, proshade_double *weights, proshade_unsign taylorSeriesCap)
This function completes the Legendre polynomial series assuming you have obtained the first values.
Definition: ProSHADE_maths.cpp:521
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:2342