ProSHADE  0.7.6.6 (JUL 2022)
Protein Shape Detection
ProSHADE_internal_symmetry Namespace Reference

This namespace contains the symmetry detection related code. More...

Functions

proshade_signed addAxisUnlessSame (proshade_unsign fold, proshade_double axX, proshade_double axY, proshade_double axZ, proshade_double axHeight, proshade_double averageFSC, std::vector< proshade_double * > *prosp, proshade_double axErr)
 This function simply creates a new axis from information in aruments and tests if no such axis already exists, saving it if need be. More...
 
void findPredictedAxesHeights (std::vector< proshade_double * > *ret, ProSHADE_internal_data::ProSHADE_data *dataObj, ProSHADE_settings *settings)
 This function finds the rotation function value for all axes supplied in the ret parameter. More...
 
bool isSymmetrySame (std::vector< proshade_double * > *ret, proshade_double *sym, proshade_double simThres, proshade_signed *matchedPos)
 This function checks if a very similar symmetry is not already saved. More...
 
bool isSymmetrySame (std::vector< proshade_double * > *ret, proshade_double *sym, proshade_double simThres, proshade_signed *matchedPos, proshade_double fscVal)
 This function checks if a very similar symmetry is not already saved. More...
 
bool detectTetrahedralSymmetry (std::vector< proshade_double * > *CSymList, proshade_double axErr, proshade_double minPeakHeight)
 This function takes the list of C symmetries and decides whether basic requirements for tetrahedral symmetry are there. More...
 
void findTetra4C3s (std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight)
 This function takes the list of C symmetries and finds the 4 C3 symmetries with correct angles required for full tetrahedral symmetry. More...
 
bool testGroupAgainstSymmetry (std::vector< proshade_double * > *CSymList, std::vector< proshade_unsign > *grp, proshade_double *sym, proshade_double axErr, proshade_double angle, bool improve, proshade_unsign pos=0)
 This function tests whether a symmetry has particular angle to all members of a group. More...
 
bool findMissingAxes (std::vector< std::vector< proshade_unsign > > *possibilities, std::vector< proshade_double * > *CSymList, proshade_unsign requiredNoAxes, proshade_double axErr, proshade_double angle, proshade_unsign fold, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_double minPeakHeight)
 This function tries to find an axis which would complete a particular group of axes for polyhedral symmetry detection. More...
 
proshade_double missingAxisHeight (proshade_double xVal, proshade_double yVal, proshade_double zVal, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_unsign fold, proshade_double axErr)
 This function searches for the highest peaks average that would produce the required axis and fold. More...
 
std::vector< proshade_double * > findMissingAxisPoints (proshade_double xVal, proshade_double yVal, proshade_double zVal, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_double axErr)
 This function searches for all the self-rotation map points conforming to the axis, returning their angles and heights. More...
 
bool sortArrVecHlp (const proshade_double *a, const proshade_double *b)
 This function compares two arrays of two based on the first number. More...
 
void saveMissingAxisNewOnly (std::vector< proshade_double * > *axVec, proshade_double axX, proshade_double axY, proshade_double axZ, proshade_double height, proshade_unsign fold, proshade_double axErr)
 This function saves the recovered information about missing axis into a full symmetry, making sure no duplicates are created. More...
 
void searchMissingSymmetrySpace (ProSHADE_internal_data::ProSHADE_data *dataObj, std::vector< proshade_double * > *CSymList, std::vector< proshade_unsign > *grp, std::vector< proshade_double * > *hlpVec, proshade_double axErr, proshade_double angle, proshade_unsign fold, proshade_double minPeakHeight)
 This function tests feasible axes against the missing axis criteria, returning a set of matching axes. More...
 
void findTetra3C2s (std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight)
 This function takes the list of C symmetries and finds the 3 C2 symmetries with correct angles required for full tetrahedral symmetry. More...
 
bool testGroupAgainstGroup (std::vector< proshade_double * > *CSymList, std::vector< proshade_unsign > *grp1, std::vector< proshade_double * > *RetList, std::vector< proshade_unsign > *grp2, proshade_double angle, proshade_double axErr)
 This function compares two groups of axes for a single pair having the required angle. More...
 
bool detectOctahedralSymmetry (std::vector< proshade_double * > *CSymList, proshade_double axErr, proshade_double minPeakHeight)
 This function takes the list of C symmetries and decides whether basic requirements for octahhedral symmetry are there. More...
 
void findOcta3C4s (std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight)
 This function takes the list of C symmetries and finds the 3 C4 symmetries with perpendicular angles required for full octahedral symmetry. More...
 
void findOcta4C3s (std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight)
 This function takes the list of C symmetries and finds the four C3 symmetries with correct angles required for full octahedral symmetry. More...
 
void findOcta6C2s (std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight)
 This function takes the list of C symmetries and finds the six C2 symmetries with correct angles required for full octahedral symmetry. More...
 
bool findMissingAxesDual (std::vector< proshade_unsign > *possibilities, std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, std::vector< proshade_unsign > *retGroup, proshade_unsign requiredNoAxes, proshade_double axErr, proshade_unsign noMatchesG1, proshade_double angle1, proshade_unsign noMatchesG2, proshade_double angle2, proshade_unsign fold, ProSHADE_internal_data::ProSHADE_data *dataObj)
 This function tries to find a particular symmetry axes which would complete a group of symmetries with two different angle requirement to another group. More...
 
proshade_signed addAxisUnlessSame (proshade_unsign fold, proshade_double axX, proshade_double axY, proshade_double axZ, proshade_double axHeight, std::vector< proshade_double * > *prosp, proshade_double axErr)
 This function simply creates a new axis from information in aruments and tests if no such axis already exists, saving it if need be. More...
 
bool checkFittingAxisDualAndSave (std::vector< proshade_unsign > *retGroup, std::vector< proshade_double * > *ret, proshade_unsign fold, proshade_double axX, proshade_double axY, proshade_double axZ, std::vector< proshade_double * > *prosp, proshade_double axErr, proshade_unsign noMatchesG1, proshade_double angle1, proshade_unsign noMatchesG2, proshade_double angle2, ProSHADE_internal_data::ProSHADE_data *dataObj)
 This function takes a newly detected "missing" axis and tests it for belonging to the group, checking the height and replacing lower height members with better members. More...
 
bool detectIcosahedralSymmetry (std::vector< proshade_double * > *CSymList, proshade_double axErr, proshade_double minPeakHeight)
 This function takes the list of C symmetries and decides whether basic requirements for isosahedral symmetry are there. More...
 
void findIcos6C5s (std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight)
 This function takes the list of C symmetries and finds the six C5 symmetries with given angles required for full icosahedral symmetry. More...
 
void findIcos10C3s (std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight)
 This function takes the list of C symmetries and finds the ten C3 symmetries with correct angles required for full icosahedral symmetry. More...
 
void findIcos15C2s (std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight)
 This function takes the list of C symmetries and finds the fifteen C3 symmetries with correct angles required for full icosahedral symmetry. More...
 
bool findMissingAxesTriple (std::vector< proshade_unsign > *possibilities, std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, std::vector< proshade_unsign > *retGroup, proshade_unsign requiredNoAxes, proshade_double axErr, proshade_unsign noMatchesG1, proshade_double angle1, proshade_unsign noMatchesG2, proshade_double angle2, proshade_unsign noMatchesG3, proshade_double angle3, proshade_unsign fold, ProSHADE_internal_data::ProSHADE_data *dataObj)
 This function tries to find a particular symmetry axis which would complete a group of symmetries with three different angle requirement to another group. More...
 
void checkFittingAxisTripleAndSave (std::vector< proshade_unsign > *retGroup, std::vector< proshade_double * > *ret, proshade_unsign fold, proshade_double axX, proshade_double axY, proshade_double axZ, std::vector< proshade_double * > *prosp, proshade_double axErr, proshade_unsign noMatchesG1, proshade_double angle1, proshade_unsign noMatchesG2, proshade_double angle2, proshade_unsign noMatchesG3, proshade_double angle3, ProSHADE_internal_data::ProSHADE_data *dataObj)
 This function takes a newly detected "missing" axis and tests it for belonging to the group, checking the height and replacing lower height members with better members. More...
 
proshade_double findPredictedSingleAxisHeight (proshade_double *axis, proshade_double fold, ProSHADE_internal_data::ProSHADE_data *dataObj, ProSHADE_settings *settings)
 This function finds the rotation function value for a single axis. More...
 
void optimiseDGroupAngleFromAxesHeights (std::vector< std::vector< proshade_double > > *ret, ProSHADE_internal_data::ProSHADE_data *dataObj, ProSHADE_settings *settings)
 This function takes two axes with almost dihedral angle and optimises their relative positions as well as orientation with respect to the optimal angle and the rotation function. More...
 
void optimiseDGroupAngleFromAxesHeights (std::vector< std::vector< proshade_double > > *allCs, std::vector< proshade_unsign > selection, ProSHADE_internal_data::ProSHADE_data *dataObj, ProSHADE_settings *settings)
 This function takes two axes with almost dihedral angle and optimises their relative positions as well as orientation with respect to the optimal angle and the rotation function. More...
 
void predictIcosAxes (std::vector< proshade_double * > *CSymList, std::vector< std::vector< proshade_double * > > *ret, proshade_double axErr, proshade_double minPeakHeight)
 This function predicts all possible icosahedral point groups symmetry axes from the cyclic point groups list. More...
 
void predictOctaAxes (std::vector< proshade_double * > *CSymList, std::vector< std::vector< proshade_double * > > *ret, proshade_double axErr, proshade_double minPeakHeight)
 This function predicts all octahedral point group symmetry axes from the cyclic point groups list. More...
 
void predictTetraAxes (std::vector< proshade_double * > *CSymList, std::vector< std::vector< proshade_double * > > *ret, proshade_double axErr, proshade_double minPeakHeight)
 This function predicts all tetrahedral point group symmetry axes from the cyclic point groups list. More...
 
std::vector< proshade_unsign > findReliableUnphasedSymmetries (std::vector< proshade_double * > *allCs, std::vector< std::vector< proshade_double * > > *allDs, proshade_signed verbose, proshade_signed messageShift, proshade_double tolerance)
 This function checks the list of detected axes (presumably from phaseless symmetry detection) and returns the best dihedral (or cyclic, if no dihedral is found) point group, or empty vector if nothing is found. More...
 
void allocateCentreOfMapFourierTransforms (proshade_unsign xDim, proshade_unsign yDim, proshade_unsign zDim, fftw_complex *&origMap, fftw_complex *&origCoeffs, fftw_complex *&rotMapComplex, fftw_complex *&rotCoeffs, fftw_complex *&trFunc, fftw_complex *&trFuncCoeffs, fftw_plan *planForwardFourier, fftw_plan *planForwardFourierRot, fftw_plan *planReverseFourierComb)
 This function allocates the required memory for the Fourier transforms required to find the centre of the map. More...
 
void releaseCentreOfMapFourierTransforms (fftw_complex *origMap, fftw_complex *origCoeffs, fftw_complex *rotMapComplex, fftw_complex *rotCoeffs, fftw_complex *trFunc, fftw_complex *trFuncCoeffs, fftw_plan planForwardFourier, fftw_plan planForwardFourierRot, fftw_plan planReverseFourierComb)
 This function releases the allocated memory for the Fourier transforms used to find the centre of the map. More...
 
std::vector< proshade_double > findTranslationBetweenRotatedAndOriginalMap (ProSHADE_internal_data::ProSHADE_data *symStr, std::vector< proshade_double > symElem, fftw_complex *origCoeffs, fftw_complex *rotMapComplex, fftw_complex *rotCoeffs, fftw_plan planForwardFourierRot, fftw_complex *trFuncCoeffs, fftw_complex *trFunc, fftw_plan planReverseFourierComb)
 This function takes a single rotation matrix and procceds to compute the optimal translation between the original map and a map rotated by the supplied rotation matrix. More...
 
std::vector< proshade_double > findPointFromTranslations (ProSHADE_internal_data::ProSHADE_data *symStr, std::vector< std::vector< proshade_double > > symElems, fftw_complex *origCoeffs, fftw_complex *rotMapComplex, fftw_complex *rotCoeffs, fftw_plan planForwardFourierRot, fftw_complex *trFuncCoeffs, fftw_complex *trFunc, fftw_plan planReverseFourierComb)
 This function computes the average of optimal translations for a cyclic point group. More...
 

Detailed Description

This namespace contains the symmetry detection related code.

The ProSHADE_internal_symmetry namespace contains the functions related to the symmetry detection task.

Function Documentation

◆ addAxisUnlessSame() [1/2]

proshade_signed ProSHADE_internal_symmetry::addAxisUnlessSame ( proshade_unsign  fold,
proshade_double  axX,
proshade_double  axY,
proshade_double  axZ,
proshade_double  axHeight,
proshade_double  averageFSC,
std::vector< proshade_double * > *  prosp,
proshade_double  axErr 
)

This function simply creates a new axis from information in aruments and tests if no such axis already exists, saving it if need be.

This is a simple helper function, which takes all the new axis information and creates the ProSHADE axis representation from these. It then proceeds to check if such axis does not already exist in the supplied vector, if not, it saves the new axis; alternatively, it just discards the created axis and terminates.

Parameters
[in]foldThe fold of the searched for axis.
[in]axXThe x-axis element of the new axis.
[in]axYThe y-axis element of the new axis.
[in]axZThe z-axis element of the new axis.
[in]axHeightThe average peak height of the new axis.
[in]averageFSCThe value of average FSC, if computed - otherwise enter -1.0.
[in]prospThe vector to which the axis is to be saved.
[in]axErrThe error tolerance on angle matching.
[out]addedNoPosition at which the symmetry either already is, or was added to.

Definition at line 1511 of file ProSHADE_symmetry.cpp.

1512 {
1513  //================================================ Initialise variables
1514  proshade_double* symHlp = new proshade_double[7];
1515  ProSHADE_internal_misc::checkMemoryAllocation ( symHlp, __FILE__, __LINE__, __func__ );
1516  proshade_signed ret = -1;
1517 
1518  //================================================ Fill in the prospective axis
1519  symHlp[0] = static_cast<proshade_double> ( fold );
1520  symHlp[1] = axX;
1521  symHlp[2] = axY;
1522  symHlp[3] = axZ;
1523  symHlp[4] = 2.0 * M_PI / symHlp[0];
1524  symHlp[5] = axHeight;
1525  symHlp[6] = averageFSC;
1526 
1527  //================================================ If it is not the same as already saved axes
1528  if ( !ProSHADE_internal_symmetry::isSymmetrySame ( prosp, symHlp, axErr, &ret, averageFSC ) )
1529  {
1531  return ( static_cast< proshade_signed > ( prosp->size() - 1 ) );
1532  }
1533  else
1534  {
1535  delete[] symHlp;
1536  return ( ret );
1537  }
1538 
1539  //================================================ Done
1540 
1541 }

◆ addAxisUnlessSame() [2/2]

proshade_signed ProSHADE_internal_symmetry::addAxisUnlessSame ( proshade_unsign  fold,
proshade_double  axX,
proshade_double  axY,
proshade_double  axZ,
proshade_double  axHeight,
std::vector< proshade_double * > *  prosp,
proshade_double  axErr 
)

This function simply creates a new axis from information in aruments and tests if no such axis already exists, saving it if need be.

This is a simple helper function, which takes all the new axis information and creates the ProSHADE axis representation from these. It then proceeds to check if such axis does not already exist in the supplied vector, if not, it saves the new axis; alternatively, it just discards the created axis and terminates.

Parameters
[in]foldThe fold of the searched for axis.
[in]axXThe x-axis element of the new axis.
[in]axYThe y-axis element of the new axis.
[in]axZThe z-axis element of the new axis.
[in]axHeightThe average peak height of the new axis.
[in]prospThe vector to which the axis is to be saved.
[in]axErrThe error tolerance on angle matching.
[out]addedNoPosition at which the symmetry either already is, or was added to.

Definition at line 1557 of file ProSHADE_symmetry.cpp.

1558 {
1559  //================================================ Initialise variables
1560  proshade_double* symHlp = new proshade_double[7];
1561  ProSHADE_internal_misc::checkMemoryAllocation ( symHlp, __FILE__, __LINE__, __func__ );
1562  proshade_signed ret = -1;
1563 
1564  //================================================ Fill in the prospective axis
1565  symHlp[0] = static_cast<proshade_double> ( fold );
1566  symHlp[1] = axX;
1567  symHlp[2] = axY;
1568  symHlp[3] = axZ;
1569  symHlp[4] = 2.0 * M_PI / symHlp[0];
1570  symHlp[5] = axHeight;
1571  symHlp[6] = -std::numeric_limits < proshade_double >::infinity();
1572 
1573  //================================================ If it is not the same as already saved axes
1574  if ( !ProSHADE_internal_symmetry::isSymmetrySame ( prosp, symHlp, axErr, &ret ) )
1575  {
1577  return ( static_cast< proshade_signed > ( prosp->size() - 1 ) );
1578  }
1579  else
1580  {
1581  delete[] symHlp;
1582  return ( ret );
1583  }
1584 
1585  //================================================ Done
1586 
1587 }

◆ allocateCentreOfMapFourierTransforms()

void ProSHADE_internal_symmetry::allocateCentreOfMapFourierTransforms ( proshade_unsign  xDim,
proshade_unsign  yDim,
proshade_unsign  zDim,
fftw_complex *&  origMap,
fftw_complex *&  origCoeffs,
fftw_complex *&  rotMapComplex,
fftw_complex *&  rotCoeffs,
fftw_complex *&  trFunc,
fftw_complex *&  trFuncCoeffs,
fftw_plan *  planForwardFourier,
fftw_plan *  planForwardFourierRot,
fftw_plan *  planReverseFourierComb 
)

This function allocates the required memory for the Fourier transforms required to find the centre of the map.

Parameters
[in]xDimThe size of the x-axis in indices.
[in]yDimThe size of the y-axis in indices.
[in]zDimThe size of the z-axis in indices.
[in]origMapArray to which the original map will be saved before Fourier transform computation.
[in]origCoeffsArray to which the result of the Fourier transform of the original map will be saved into.
[in]rotMapComplexArray to which the rotated map will be saved before Fourier transform computation.
[in]rotCoeffsArray to which the result of the Fourier transform of the rotated map will be saved into.
[in]trFuncArray to which the results of inverse Fourier transform of the conbined coefficients will be saved.
[in]trFuncCoeffsArray to which the two maps coefficients will be combined into before inverse Fourier transform computation.
[in]planForwardFourierFFTW3 plan for the original map Fourier transform.
[in]planForwardFourierRotFFTW3 plat for the rotated map Fourier transform.
[in]planReverseFourierCombFFTW3 plan for the inverse Fourier transform from the combined coefficients to translation function.

Definition at line 3841 of file ProSHADE_symmetry.cpp.

3842 {
3843  //================================================ Allocate the memory
3844  origMap = reinterpret_cast< fftw_complex* > ( fftw_malloc ( sizeof ( fftw_complex ) * xDim * yDim * zDim ) );
3845  origCoeffs = reinterpret_cast< fftw_complex* > ( fftw_malloc ( sizeof ( fftw_complex ) * xDim * yDim * zDim ) );
3846  rotMapComplex = reinterpret_cast< fftw_complex* > ( fftw_malloc ( sizeof ( fftw_complex ) * xDim * yDim * zDim ) );
3847  rotCoeffs = reinterpret_cast< fftw_complex* > ( fftw_malloc ( sizeof ( fftw_complex ) * xDim * yDim * zDim ) );
3848  trFunc = reinterpret_cast< fftw_complex* > ( fftw_malloc ( sizeof ( fftw_complex ) * xDim * yDim * zDim ) );
3849  trFuncCoeffs = reinterpret_cast< fftw_complex* > ( fftw_malloc ( sizeof ( fftw_complex ) * xDim * yDim * zDim ) );
3850 
3851  //================================================ Check the memory allocation
3852  ProSHADE_internal_misc::checkMemoryAllocation ( origMap, __FILE__, __LINE__, __func__ );
3853  ProSHADE_internal_misc::checkMemoryAllocation ( origCoeffs, __FILE__, __LINE__, __func__ );
3854  ProSHADE_internal_misc::checkMemoryAllocation ( rotMapComplex, __FILE__, __LINE__, __func__ );
3855  ProSHADE_internal_misc::checkMemoryAllocation ( rotCoeffs, __FILE__, __LINE__, __func__ );
3856  ProSHADE_internal_misc::checkMemoryAllocation ( trFunc, __FILE__, __LINE__, __func__ );
3857  ProSHADE_internal_misc::checkMemoryAllocation ( trFuncCoeffs, __FILE__, __LINE__, __func__ );
3858 
3859  //================================================
3860  *planForwardFourier = fftw_plan_dft_3d ( static_cast< int > ( xDim ), static_cast< int > ( yDim ), static_cast< int > ( zDim ), origMap, origCoeffs, FFTW_FORWARD, FFTW_ESTIMATE );
3861  *planForwardFourierRot = fftw_plan_dft_3d ( static_cast< int > ( xDim ), static_cast< int > ( yDim ), static_cast< int > ( zDim ), rotMapComplex, rotCoeffs, FFTW_FORWARD, FFTW_ESTIMATE );
3862  *planReverseFourierComb = fftw_plan_dft_3d ( static_cast< int > ( xDim ), static_cast< int > ( yDim ), static_cast< int > ( zDim ), trFuncCoeffs, trFunc, FFTW_BACKWARD, FFTW_ESTIMATE );
3863 
3864  //================================================ Done
3865  return ;
3866 
3867 }

◆ checkFittingAxisDualAndSave()

bool ProSHADE_internal_symmetry::checkFittingAxisDualAndSave ( std::vector< proshade_unsign > *  retGroup,
std::vector< proshade_double * > *  ret,
proshade_unsign  fold,
proshade_double  axX,
proshade_double  axY,
proshade_double  axZ,
std::vector< proshade_double * > *  prosp,
proshade_double  axErr,
proshade_unsign  noMatchesG1,
proshade_double  angle1,
proshade_unsign  noMatchesG2,
proshade_double  angle2,
ProSHADE_internal_data::ProSHADE_data dataObj 
)

This function takes a newly detected "missing" axis and tests it for belonging to the group, checking the height and replacing lower height members with better members.

This function takes the list of already detected axes, information about the tested new axis and the conditions for belonging. It then proceeds to check if the new axis conforms to the conditions of belonging. If so, it then checks if the axis height is high enough to be considered as part of the group. Again, if so, it will save this new axis to the old set, replacing any old axis with this new one, if it is the same and has better height.

Parameters
[in]retGroupA vector of indices in the ret list which form the group to which new axes are compared to.
[in]retA list of already detected axes.
[in]foldThe fold of the searched for axis.
[in]axXThe x-axis element of the new axis.
[in]axYThe y-axis element of the new axis.
[in]axZThe z-axis element of the new axis.
[in]prospThe vector to which the axis is to be saved.
[in]axErrThe error tolerance on angle matching.
[in]noMatchesG1The number of axes from ret that need to be matched with angle1.
[in]angle1The angle with which noMatchesG1 axes need to be matched with the retGroup axes.
[in]noMatchesG2The number of axes from ret that need to be matched with angle2.
[in]angle2The angle with which noMatchesG2 axes need to be matched with the retGroup axes.
[in]dataObjThe full data holding object pointer - this is to get access to self-rotation function values.
[out]BoolTrue if the axis was added to the group, false otherwise.

Definition at line 1610 of file ProSHADE_symmetry.cpp.

1611 {
1612  //================================================ Initialise variables
1613  proshade_unsign noG1 = 0;
1614  proshade_unsign noG2 = 0;
1615  proshade_double dotProd = 0.0;
1616  proshade_double axHeight = 0.0;
1617 
1618  //================================================ Find the angle and count dual matching frequencies
1619  for ( proshade_unsign rIt = 0; rIt < static_cast<proshade_unsign> ( retGroup->size() ); rIt++ )
1620  {
1621  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(retGroup->at(rIt))[1],
1622  &ret->at(retGroup->at(rIt))[2],
1623  &ret->at(retGroup->at(rIt))[3],
1624  &axX, &axY, &axZ );
1625 
1626  if ( ( std::abs ( dotProd ) > ( angle1 - axErr ) ) && ( std::abs ( dotProd ) < ( angle1 + axErr ) ) ) { noG1 += 1; continue; }
1627  if ( ( std::abs ( dotProd ) > ( angle2 - axErr ) ) && ( std::abs ( dotProd ) < ( angle2 + axErr ) ) ) { noG2 += 1; continue; }
1628  }
1629 
1630  //================================================ If correct frequencies are matched, check height.
1631  if ( ( noG1 == noMatchesG1 ) && ( noG2 == noMatchesG2 ) )
1632  {
1633  //============================================ Is the height good enough?
1634  axHeight = ProSHADE_internal_symmetry::missingAxisHeight ( axX, axY, axZ, dataObj, fold, axErr );
1635 
1636  //============================================ If so, save
1637  if ( axHeight > 0.1 )
1638  {
1639  proshade_unsign prevProsp = static_cast<proshade_unsign> ( prosp->size() );
1640  ProSHADE_internal_symmetry::addAxisUnlessSame ( fold, axX, axY, axZ, axHeight, prosp, axErr );
1641 
1642  if ( static_cast<proshade_unsign> ( prosp->size() ) > prevProsp ) { return ( true ); }
1643  else { return ( false ); }
1644  }
1645  }
1646 
1647  //================================================ Done
1648  return ( false );
1649 
1650 }

◆ checkFittingAxisTripleAndSave()

void ProSHADE_internal_symmetry::checkFittingAxisTripleAndSave ( std::vector< proshade_unsign > *  retGroup,
std::vector< proshade_double * > *  ret,
proshade_unsign  fold,
proshade_double  axX,
proshade_double  axY,
proshade_double  axZ,
std::vector< proshade_double * > *  prosp,
proshade_double  axErr,
proshade_unsign  noMatchesG1,
proshade_double  angle1,
proshade_unsign  noMatchesG2,
proshade_double  angle2,
proshade_unsign  noMatchesG3,
proshade_double  angle3,
ProSHADE_internal_data::ProSHADE_data dataObj 
)

This function takes a newly detected "missing" axis and tests it for belonging to the group, checking the height and replacing lower height members with better members.

This function takes the list of already detected axes, information about the tested new axis and the conditions for belonging. It then proceeds to check if the new axis conforms to the conditions of belonging. If so, it then checks if the axis height is high enough to be considered as part of the group. Again, if so, it will save this new axis to the old set, replacing any old axis with this new one, if it is the same and has better height.

Parameters
[in]retGroupA vector of indices in the ret list which form the group to which new axes are compared to.
[in]retA list of already detected axes.
[in]foldThe fold of the searched for axis.
[in]axXThe x-axis element of the new axis.
[in]axYThe y-axis element of the new axis.
[in]axZThe z-axis element of the new axis.
[in]prospThe vector to which the axis is to be saved.
[in]axErrThe error tolerance on angle matching.
[in]noMatchesG1The number of axes from ret that need to be matched with angle1.
[in]angle1The angle with which noMatchesG1 axes need to be matched with the retGroup axes.
[in]noMatchesG2The number of axes from ret that need to be matched with angle2.
[in]angle2The angle with which noMatchesG2 axes need to be matched with the retGroup axes.
[in]noMatchesG3The number of axes from ret that need to be matched with angle3.
[in]angle3The angle with which noMatchesG3 axes need to be matched with the retGroup axes.
[in]dataObjThe full data holding object pointer - this is to get access to self-rotation function values.

Definition at line 2604 of file ProSHADE_symmetry.cpp.

2605 {
2606  //================================================ Initialise variables
2607  proshade_unsign noG1 = 0;
2608  proshade_unsign noG2 = 0;
2609  proshade_unsign noG3 = 0;
2610  proshade_double dotProd = 0.0;
2611  proshade_double axHeight = 0.0;
2612 
2613  //================================================ Find the angle and count dual matching frequencies
2614  for ( proshade_unsign rIt = 0; rIt < static_cast<proshade_unsign> ( retGroup->size() ); rIt++ )
2615  {
2616  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(retGroup->at(rIt))[1],
2617  &ret->at(retGroup->at(rIt))[2],
2618  &ret->at(retGroup->at(rIt))[3],
2619  &axX, &axY, &axZ );
2620 
2621  if ( ( std::abs ( dotProd ) > ( angle1 - axErr ) ) && ( std::abs ( dotProd ) < ( angle1 + axErr ) ) ) { noG1 += 1; continue; }
2622  if ( ( std::abs ( dotProd ) > ( angle2 - axErr ) ) && ( std::abs ( dotProd ) < ( angle2 + axErr ) ) ) { noG2 += 1; continue; }
2623  if ( ( std::abs ( dotProd ) > ( angle3 - axErr ) ) && ( std::abs ( dotProd ) < ( angle3 + axErr ) ) ) { noG3 += 1; continue; }
2624  }
2625 
2626  //================================================ If correct frequencies are matched, check height.
2627  if ( ( noG1 == noMatchesG1 ) && ( noG2 == noMatchesG2 ) && ( noG3 == noMatchesG3 ) )
2628  {
2629  //============================================ Is the height good enough?
2630  axHeight = ProSHADE_internal_symmetry::missingAxisHeight ( axX, axY, axZ, dataObj, fold, axErr );
2631 
2632  //============================================ If so, save
2633  if ( axHeight > 0.1 )
2634  {
2635  ProSHADE_internal_symmetry::addAxisUnlessSame ( fold, axX, axY, axZ, axHeight, prosp, axErr );
2636  }
2637  }
2638 
2639  //================================================ Done
2640  return ;
2641 
2642 }

◆ detectIcosahedralSymmetry()

bool ProSHADE_internal_symmetry::detectIcosahedralSymmetry ( std::vector< proshade_double * > *  CSymList,
proshade_double  axErr,
proshade_double  minPeakHeight 
)

This function takes the list of C symmetries and decides whether basic requirements for isosahedral symmetry are there.

This function first finds all the C5 symmetries in the C symmetries list and then it checks each present C5 against all C3 symmetries for having the angle between the pair equal to the dihedral angle of an icosahedron ( acos( sqrt(5)/3 ) ). If a single such pair is detected, this is likely an icosahedral symmetry and all other axes need to be located. Otherwise, false is returned.

Parameters
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]axErrThe error tolerance on angle matching.
[in]minPeakHeightThe minimum average peak height required for symmetry axis to be considered.
[out]XBoolean value telling whether there are C5 and C3 symmetries with icosahedral dihhedral angle.

Definition at line 1854 of file ProSHADE_symmetry.cpp.

1855 {
1856  //================================================ Initialise variables
1857  std::vector< proshade_unsign > C5List;
1858  proshade_double dotProduct;
1859 
1860  //================================================ Find all C5 symmetries
1861  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
1862  {
1863  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 5.0 );
1864  if ( lhs1.AlmostEquals ( rhs1 ) && CSymList->at(cSym)[5] >= minPeakHeight ) { ProSHADE_internal_misc::addToUnsignVector ( &C5List, cSym ); }
1865  }
1866 
1867  //================================================ For each unique pair of C5 and C3
1868  for ( proshade_unsign c5 = 0; c5 < static_cast<proshade_unsign> ( C5List.size() ); c5++ )
1869  {
1870  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
1871  {
1872  //======================================== Compare only C3s to the C5List
1873  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 3.0 );
1874  if ( !lhs1.AlmostEquals ( rhs1 ) ) { continue; }
1875 
1876  //======================================== Check the angle between the C5 and C3 axes
1877  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(C5List.at(c5))[1],
1878  &CSymList->at(C5List.at(c5))[2],
1879  &CSymList->at(C5List.at(c5))[3],
1880  &CSymList->at(cSym)[1],
1881  &CSymList->at(cSym)[2],
1882  &CSymList->at(cSym)[3] );
1883 
1884  //======================================== Is the angle approximately the dihedral angle
1885  if ( std::abs ( std::abs( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ) - std::abs( dotProduct ) ) < axErr ) { return ( true ); }
1886  }
1887  }
1888 
1889  //================================================ Done
1890  return ( false );
1891 
1892 }

◆ detectOctahedralSymmetry()

bool ProSHADE_internal_symmetry::detectOctahedralSymmetry ( std::vector< proshade_double * > *  CSymList,
proshade_double  axErr,
proshade_double  minPeakHeight 
)

This function takes the list of C symmetries and decides whether basic requirements for octahhedral symmetry are there.

This function first finds all the C4 symmetries in the C symmetries list and then it checks each present C4 against all C3 symmetries for having the angle between the pair equal to the dihedral angle of an octahedron ( acos(1/sqrt(3)) ). If a single such pair is detected, this is likely an octahedral symmetry and all other axes need to be located. Otherwise, false is returned.

Parameters
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]axErrThe error tolerance on angle matching.
[in]minPeakHeightThe minimum average peak height for axis to be considered.
[out]XBoolean value telling whether there are C4 and C3 symmetries with octahedral dihhedral angle.

Definition at line 1127 of file ProSHADE_symmetry.cpp.

1128 {
1129  //================================================ Initialise variables
1130  std::vector< proshade_unsign > C4List;
1131  proshade_double dotProduct;
1132 
1133  //================================================ Find all C4 symmetries
1134  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
1135  {
1136  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 4.0 );
1137  if ( lhs1.AlmostEquals ( rhs1 ) && CSymList->at(cSym)[5] >= minPeakHeight ) { ProSHADE_internal_misc::addToUnsignVector ( &C4List, cSym ); }
1138  }
1139 
1140  //================================================ For each unique pair of C3s
1141  for ( proshade_unsign c4 = 0; c4 < static_cast<proshade_unsign> ( C4List.size() ); c4++ )
1142  {
1143  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
1144  {
1145  //======================================== Compare only C3s to the C3List
1146  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 3.0 );
1147  if ( !lhs1.AlmostEquals ( rhs1 ) ) { continue; }
1148 
1149  //======================================== Check the angle between the C4 and C3 axes
1150  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(C4List.at(c4))[1],
1151  &CSymList->at(C4List.at(c4))[2],
1152  &CSymList->at(C4List.at(c4))[3],
1153  &CSymList->at(cSym)[1],
1154  &CSymList->at(cSym)[2],
1155  &CSymList->at(cSym)[3] );
1156 
1157  //======================================== Is the angle approximately the dihedral angle
1158  if ( ( ( 1.0 / sqrt ( 3.0 ) ) > ( dotProduct - axErr ) ) && ( ( 1.0 / sqrt ( 3.0 ) ) < ( dotProduct + axErr ) ) )
1159  {
1160  return ( true );
1161  }
1162  }
1163  }
1164 
1165  //================================================ Done
1166  return ( false );
1167 
1168 }

◆ detectTetrahedralSymmetry()

bool ProSHADE_internal_symmetry::detectTetrahedralSymmetry ( std::vector< proshade_double * > *  CSymList,
proshade_double  axErr,
proshade_double  minPeakHeight 
)

This function takes the list of C symmetries and decides whether basic requirements for tetrahedral symmetry are there.

This function first finds all the C3 symmetries in the C symmetries list and then it checks all pais of such present C3s for have the angle between the pair equal to the dihedral angle of a tetrahedron ( acos(1/3) ). If a single such pair is detected, this is likely a tetrahedral symmetry and all other axes need to be located. Otherwise, false is returned.

Parameters
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]axErrThe error tolerance on angle matching.
[in]minPeakHeightThe minimum average peak height for axis to be considered.
[out]XBoolean value telling whether there are two C3 symmetries with tetrahedral dihhedral angle.

Definition at line 410 of file ProSHADE_symmetry.cpp.

411 {
412  //================================================ Initialise variables
413  std::vector< proshade_unsign > C3List;
414  proshade_double dotProduct;
415 
416  //================================================ Find all C3 symmetries
417  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
418  {
419  const FloatingPoint< proshade_double > lhs ( CSymList->at(cSym)[0] ), rhs ( 3.0 );
420  if ( lhs.AlmostEquals ( rhs ) && CSymList->at(cSym)[5] >= minPeakHeight ) { ProSHADE_internal_misc::addToUnsignVector ( &C3List, cSym ); }
421  }
422 
423  //================================================ For each unique pair of C3s
424  for ( proshade_unsign c31 = 0; c31 < static_cast<proshade_unsign> ( C3List.size() ); c31++ )
425  {
426  for ( proshade_unsign c32 = 1; c32 < static_cast<proshade_unsign> ( C3List.size() ); c32++ )
427  {
428  //================================ Unique pairs only
429  if ( c31 >= c32 ) { continue; }
430 
431  //======================================== Check the angle between the C3 axes
432  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(C3List.at(c31))[1], &CSymList->at(C3List.at(c31))[2], &CSymList->at(C3List.at(c31))[3], &CSymList->at(C3List.at(c32))[1], &CSymList->at(C3List.at(c32))[2], &CSymList->at(C3List.at(c32))[3] );
433 
434  //================================ Is the angle approximately the dihedral angle
435  if ( ( ( 1.0 / 3.0 ) > ( dotProduct - axErr ) ) && ( ( 1.0 / 3.0 ) < ( dotProduct + axErr ) ) )
436  {
437  return ( true );
438  }
439  }
440  }
441 
442  //================================================ Done
443  return ( false );
444 
445 }

◆ findIcos10C3s()

void ProSHADE_internal_symmetry::findIcos10C3s ( std::vector< proshade_double * > *  CSymList,
std::vector< proshade_double * > *  ret,
proshade_double  axErr,
ProSHADE_internal_data::ProSHADE_data dataObj,
proshade_signed  verbose,
proshade_signed  messageShift,
proshade_double  minPeakHeight 
)

This function takes the list of C symmetries and finds the ten C3 symmetries with correct angles required for full icosahedral symmetry.

This function is specific to detecting the icosahedral symmetry. It should be called once icosahedral symmetry is suspected (by detecting its dihedral angles) and it needs to be fully described. This function specifically searches for the ten C3 symmetries which must all be detected in order to fully describe icosahedral symmetry. If all ten are found, the ret vector will have these ten axes added to the already present six C5 axes; alternatively, the ret array size will not change.

Parameters
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]retThe vector containing the already detected axes to which newly detected axes (if any) will be added.
[in]axErrThe error tolerance on angle matching.
[in]minPeakHeightThe minimum average peak height for axis to be considered.
[in]verboseHow loud the announcments should be?
[in]messageShiftAre we in a subprocess, so that the log should be shifted for this function call? If so, by how much?

Definition at line 2337 of file ProSHADE_symmetry.cpp.

2338 {
2339  //================================================ Initialise variables
2340  std::vector< proshade_unsign > prospectiveC3s, retGrp;
2341  proshade_double dotProd;
2342  proshade_unsign noClose, noAway;
2343 
2344  //================================================ Report progress
2345  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of ten C3 axes.", messageShift );
2346 
2347  //================================================ For each C3
2348  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
2349  {
2350  //============================================ Use only C3s with hight enough average
2351  if ( CSymList->at(cIt)[0] != 3.0 || CSymList->at(cIt)[0] < minPeakHeight ) { continue; }
2352 
2353  //============================================ Check the C3 has acos ( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ) to 3 C5s and acos ( 1.0 - ( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ) ) to the other three C5s
2354  noClose = 0; noAway = 0;
2355  for ( proshade_unsign rIt = 0; rIt < 6; rIt++ )
2356  {
2357  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1],
2358  &ret->at(rIt)[2],
2359  &ret->at(rIt)[3],
2360  &CSymList->at(cIt)[1],
2361  &CSymList->at(cIt)[2],
2362  &CSymList->at(cIt)[3] );
2363 
2364  if ( ( std::abs ( dotProd ) > ( ( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ) + axErr ) ) ) { noClose += 1; continue; }
2365  if ( ( std::abs ( dotProd ) > ( 1.0 - ( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ) - axErr ) ) && ( std::abs ( dotProd ) < ( 1.0 - ( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ) + axErr ) ) ) { noAway += 1; continue; }
2366  }
2367 
2368  //============================================ If correct angles distribution is found, save the axis
2369  if ( ( noClose == 3 ) && ( noAway == 3 ) )
2370  {
2371  ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC3s, cIt );
2372  }
2373  }
2374 
2375  //================================================ Search for missing axes
2376  for ( proshade_unsign iter = 0; iter < 6; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &retGrp, iter ); }
2377  if ( !ProSHADE_internal_symmetry::findMissingAxesDual ( &prospectiveC3s, CSymList, ret, &retGrp, 10, axErr, 3, std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ), 3, 1.0 - ( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ), 3, dataObj ) )
2378  {
2379  return ;
2380  }
2381 
2382  //================================================ Found correct number of axes! Now save the
2383  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( prospectiveC3s.size() ); iter++ )
2384  {
2385  ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(prospectiveC3s.at(iter)) );
2386  }
2387 
2388  //================================================ Report progress
2389  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of ten C3 axes successfull.", messageShift );
2390 
2391  //================================================ Done
2392  return ;
2393 
2394 }

◆ findIcos15C2s()

void ProSHADE_internal_symmetry::findIcos15C2s ( std::vector< proshade_double * > *  CSymList,
std::vector< proshade_double * > *  ret,
proshade_double  axErr,
ProSHADE_internal_data::ProSHADE_data dataObj,
proshade_signed  verbose,
proshade_signed  messageShift,
proshade_double  minPeakHeight 
)

This function takes the list of C symmetries and finds the fifteen C3 symmetries with correct angles required for full icosahedral symmetry.

This function is specific to detecting the icosahedral symmetry. It should be called once icosahedral symmetry is suspected (by detecting its dihedral angles) and it needs to be fully described. This function specifically searches for the ten C3 symmetries which must all be detected in order to fully describe icosahedral symmetry. If all ten are found, the ret vector will have these ten axes added to the already present six C5 axes; alternatively, the ret array size will not change.

Parameters
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]retThe vector containing the already detected axes to which newly detected axes (if any) will be added.
[in]axErrThe error tolerance on angle matching.
[in]minPeakHeightThe minimum average peak height for axis to be considered.
[in]verboseHow loud the announcments should be?
[in]messageShiftAre we in a subprocess, so that the log should be shifted for this function call? If so, by how much?

Definition at line 2410 of file ProSHADE_symmetry.cpp.

2411 {
2412  //================================================ Initialise variables
2413  std::vector< proshade_unsign > prospectiveC2s, retGrp;
2414  proshade_double dotProd;
2415  proshade_unsign noClose, noMidway, noAway;
2416 
2417  //================================================ Report progress
2418  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of fifteen C2 axes.", messageShift );
2419 
2420  //================================================ For each C2
2421  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
2422  {
2423  //============================================ Use only C2s
2424  const FloatingPoint< proshade_double > lhs999 ( CSymList->at(cIt)[5] ), rhs999 ( static_cast< proshade_double > ( -999.9 ) );
2425  if ( CSymList->at(cIt)[0] != 2.0 || ( ( CSymList->at(cIt)[5] < minPeakHeight ) && !( lhs999.AlmostEquals( rhs999 ) ) ) ) { continue; }
2426 
2427  //============================================ Check the C2 has acos ( 0.0 ) to 2 C5s, acos ( 0.5 ) to another 2 C5s and acos ( sqrt ( 3.0 ) / 2.0 ) to the last two C5s
2428  noClose = 0; noMidway = 0; noAway = 0;
2429  for ( proshade_unsign rIt = 0; rIt < 6; rIt++ )
2430  {
2431  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1],
2432  &ret->at(rIt)[2],
2433  &ret->at(rIt)[3],
2434  &CSymList->at(cIt)[1],
2435  &CSymList->at(cIt)[2],
2436  &CSymList->at(cIt)[3] );
2437 
2438  if ( ( std::abs ( dotProd ) > ( ( sqrt ( 3.0 ) / 2.0 ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( sqrt ( 3.0 ) / 2.0 ) + axErr ) ) ) { noAway += 1; continue; }
2439  if ( ( std::abs ( dotProd ) > ( ( 1.0 / 2.0 ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( 1.0 / 2.0 ) + axErr ) ) ) { noMidway += 1; continue; }
2440  if ( ( std::abs ( dotProd ) > ( ( 0.0 ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( 0.0 ) + axErr ) ) ) { noClose += 1; continue; }
2441  }
2442 
2443  //============================================ If correct angles distribution is found, save the axis
2444  if ( ( noClose == 2 ) && ( noMidway == 2 ) && ( noAway == 2 ) )
2445  {
2446  ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC2s, cIt );
2447  }
2448  }
2449 
2450  //================================================ Search for missing axes
2451  for ( proshade_unsign iter = 0; iter < 6; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &retGrp, iter ); }
2452  if ( !ProSHADE_internal_symmetry::findMissingAxesTriple ( &prospectiveC2s, CSymList, ret, &retGrp, 15, axErr, 2, 0.0, 2, 1.0/2.0, 2, sqrt ( 3.0 ) / 2.0, 2, dataObj ) )
2453  {
2454  return ;
2455  }
2456 
2457  //================================================ Found correct number of axes! Now save the
2458  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( prospectiveC2s.size() ); iter++ )
2459  {
2460  ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(prospectiveC2s.at(iter)) );
2461  }
2462 
2463  //================================================ Report progress
2464  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of fifteen C2 axes successfull.", messageShift );
2465 
2466  //================================================ Done
2467  return ;
2468 
2469 }

◆ findIcos6C5s()

void ProSHADE_internal_symmetry::findIcos6C5s ( std::vector< proshade_double * > *  CSymList,
std::vector< proshade_double * > *  ret,
proshade_double  axErr,
ProSHADE_internal_data::ProSHADE_data dataObj,
proshade_signed  verbose,
proshade_signed  messageShift,
proshade_double  minPeakHeight 
)

This function takes the list of C symmetries and finds the six C5 symmetries with given angles required for full icosahedral symmetry.

This function searches the list of all detected C symmetries for the presence of six C5 symmetries, which have the angle of acos (0.5) to each other; this ability is specifically required for detection of icosahedral symmetry. This function allows for multiple groups of C5 symmetries, doing the missing symmetry axis checks and returning the group with highest average peak height. If successfull, the ret vector will have 6 entries, otherwise it will be empty.

This function is specific to detecting the octahedral symmetry. It should be called once octahedral symmetry is suspected (by detecting its dihedral angles) and it needs to be fully described. This function specifically searches for the three C4 symmetries which must all be detected in order to fully describe octahedral symmetry. If all three are found, the ret vector will contain these as its only four entries, while it will be empty if some of the C4 symmetries are not found. The missing symmetry axis detection is implemented as part of this function as well.

Parameters
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]retThe vector .
[in]axErrThe error tolerance on angle matching.
[in]minPeakHeightThe minimum average peak height for axis to be considered.
[in]verboseHow loud the announcments should be?
[in]messageShiftAre we in a subprocess, so that the log should be shifted for this function call? If so, by how much?

Definition at line 1912 of file ProSHADE_symmetry.cpp.

1913 {
1914  //================================================ Initialise variables
1915  std::vector< proshade_unsign > C5PossibilitiesHlp;
1916  std::vector< std::vector< proshade_unsign > > C5Possibilities;
1917  bool groupMatched;
1918 
1919  //================================================ Report progress
1920  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of six C5 axes.", messageShift );
1921 
1922  //================================================ For all symmetries in the C symmetries list
1923  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
1924  {
1925  //============================================ Search only using C5s and check peak height
1926  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cIt)[0] ), rhs1 ( 5.0 );
1927  if ( !lhs1.AlmostEquals ( rhs1 ) || CSymList->at(cIt)[5] < minPeakHeight ) { continue; }
1928 
1929  //============================================ If second or more C5, check if it has the correct angle to all other already found C5s for each group
1930  groupMatched = false;
1931  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C5Possibilities.size() ); gIt++ )
1932  {
1933  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, &C5Possibilities.at(gIt), CSymList->at(cIt), axErr, 1.0/2.0, true, cIt ) ) { ProSHADE_internal_misc::addToUnsignVector ( &C5Possibilities.at(gIt), cIt ); groupMatched = true; break; }
1934  }
1935 
1936  //============================================ If no group matched, create a new group
1937  if ( !groupMatched ) { C5PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C5PossibilitiesHlp, cIt ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C5Possibilities, C5PossibilitiesHlp ); continue; }
1938  }
1939 
1940  //================================================ Test for missing symmetry axes, if need be
1941  ProSHADE_internal_symmetry::findMissingAxes ( &C5Possibilities, CSymList, 6, axErr, 1.0 / 2.0, 5, dataObj, minPeakHeight );
1942 
1943  //=================================================Any group has 6 entries? If more such groups, take the one with highest average height.
1944  proshade_double maxHeight = 0.0; proshade_unsign maxGrp = 0;
1945  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( C5Possibilities.size() ); iter++ ) { if ( C5Possibilities.at(iter).size() == 6 ) { if ( ( ( CSymList->at(C5Possibilities.at(iter).at(0))[5] + CSymList->at(C5Possibilities.at(iter).at(1))[5] + CSymList->at(C5Possibilities.at(iter).at(2))[5] + CSymList->at(C5Possibilities.at(iter).at(3))[5] + CSymList->at(C5Possibilities.at(iter).at(4))[5] + CSymList->at(C5Possibilities.at(iter).at(5))[5] ) / 6.0 ) > maxHeight ) { maxHeight = ( ( CSymList->at(C5Possibilities.at(iter).at(0))[5] + CSymList->at(C5Possibilities.at(iter).at(1))[5] + CSymList->at(C5Possibilities.at(iter).at(2))[5] + CSymList->at(C5Possibilities.at(iter).at(3))[5] + CSymList->at(C5Possibilities.at(iter).at(4))[5] + CSymList->at(C5Possibilities.at(iter).at(5))[5] ) / 6.0 ); maxGrp = iter; } } }
1946 
1947  if ( C5Possibilities.at(maxGrp).size() == 6 )
1948  {
1949  //============================================ Success! Save and exit
1950  for ( proshade_unsign it = 0; it < static_cast<proshade_unsign> ( C5Possibilities.at(maxGrp).size() ); it++ ) { ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(C5Possibilities.at(maxGrp).at(it)) ); }
1951 
1952  //============================================ Report progress
1953  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of six C5 axes successfull.", messageShift );
1954 
1955  //============================================ Done
1956  return ;
1957  }
1958 
1959  //================================================ Done
1960  return ;
1961 
1962 }

◆ findMissingAxes()

bool ProSHADE_internal_symmetry::findMissingAxes ( std::vector< std::vector< proshade_unsign > > *  possibilities,
std::vector< proshade_double * > *  CSymList,
proshade_unsign  requiredNoAxes,
proshade_double  axErr,
proshade_double  angle,
proshade_unsign  fold,
ProSHADE_internal_data::ProSHADE_data dataObj,
proshade_double  minPeakHeight 
)

This function tries to find an axis which would complete a particular group of axes for polyhedral symmetry detection.

This function assumes that there is a set of already detected axes and that for a polyhedral symmetry, another axis with known fold and angle to some of the already detected axis needs to be found. It uses algebraic solution to try to find such an axis (or a given number of them) and also tests for these newly detected axes being unique and having at least minPeakHeight average peak height. If such axes are found, they are added to the CSymList vector and their indices are also added to the possibilities vector.

Parameters
[in]possibilitiesA vector of vectors of indices to the cyclic symmetries list with all the already determined axes.
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]requiredNoAxesNumber of axes required for positive result.
[in]axErrThe error tolerance on angle matching.
[in]angleThe angle that each group member is required to have against the symmetry.
[in]foldThe fold of the searched for axis.
[in]dataObjThe full data holding object pointer - this is to get access to self-rotation function values.
[in]minPeakHeightThe minimum new axis average peak height in order for the axis to be added.
[out]atLeastOneBoolean value speciying whether at least the minimum required number of axes was found.

Definition at line 598 of file ProSHADE_symmetry.cpp.

599 {
600  //================================================ Initialise variables
601  std::vector< proshade_double* > hlpVec;
602  bool atLeastOne = false;
603 
604  //================================================ Proceed only if need be
605  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( possibilities->size() ); gIt++ )
606  {
607  if ( static_cast<proshade_unsign> ( possibilities->at(gIt).size() ) == requiredNoAxes ) { atLeastOne = true; return ( atLeastOne ); }
608  }
609 
610  //================================================ For each possible group
611  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( possibilities->size() ); gIt++ )
612  {
613  //============================================ This will not work for less than two axes in group
614  if ( possibilities->at(gIt).size() < 2 ) { continue; }
615 
616  //============================================ Prepare iteration
617  hlpVec.clear ( );
618 
619  //============================================ Search for missing axes
620  ProSHADE_internal_symmetry::searchMissingSymmetrySpace ( dataObj, CSymList, &possibilities->at(gIt), &hlpVec, axErr, angle, fold, minPeakHeight );
621 
622  //============================================ Add missing axes
623  if ( hlpVec.size() > 0 )
624  {
625  //======================================== Start adding by highest first
626  std::sort ( hlpVec.begin(), hlpVec.end(), ProSHADE_internal_misc::sortSymHlpInv );
627 
628  //======================================== For each missing axis
629  for ( proshade_unsign axIt = 0; axIt < static_cast<proshade_unsign> ( hlpVec.size() ); axIt++ )
630  {
631  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, &possibilities->at(gIt), hlpVec.at(axIt), axErr, angle, false ) )
632  {
633  //================================ Check for uniqueness
634  if ( ProSHADE_internal_maths::isAxisUnique ( CSymList, hlpVec.at(axIt), axErr ) )
635  {
636  //============================ Add
637  ProSHADE_internal_misc::addToDblPtrVector ( CSymList, hlpVec.at(axIt) );
638  ProSHADE_internal_misc::addToUnsignVector ( &possibilities->at(gIt), static_cast<proshade_unsign> ( CSymList->size()-1 ) );
639  }
640  }
641  }
642  }
643 
644  if ( possibilities->at(gIt).size() == requiredNoAxes ) { atLeastOne = true; }
645  }
646 
647  //================================================ Done
648  return ( atLeastOne );
649 
650 }

◆ findMissingAxesDual()

bool ProSHADE_internal_symmetry::findMissingAxesDual ( std::vector< proshade_unsign > *  possibilities,
std::vector< proshade_double * > *  CSymList,
std::vector< proshade_double * > *  ret,
std::vector< proshade_unsign > *  retGroup,
proshade_unsign  requiredNoAxes,
proshade_double  axErr,
proshade_unsign  noMatchesG1,
proshade_double  angle1,
proshade_unsign  noMatchesG2,
proshade_double  angle2,
proshade_unsign  fold,
ProSHADE_internal_data::ProSHADE_data dataObj 
)

This function tries to find a particular symmetry axes which would complete a group of symmetries with two different angle requirement to another group.

This function takes a list of axes to which a new axis should have two particular angles (to two different group members, that is). It then uses algebraic solution finding approach to compute possible solutions which would satisfy this condition, testing whether such solutions comply with the appropriate number of angles to number of members and for the new solutions being unique. If the required number of solutions is found, it will add the newly detected solutions to the CSymList vector and update the possibilities indices list, otherwise it will leave both alone.

Parameters
[in]possibilitiesA vector of already detected axis indices which should be extended.
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]retA list of already detected octahedral axes.
[in]retGroupA vector of indices in the ret list which form the group to which new axes are compared to.
[in]requiredNoAxesNumber of axes required for positive result.
[in]axErrThe error tolerance on angle matching.
[in]noMatchesG1The number of axes from ret that need to be matched with angle1.
[in]angle1The angle with which noMatchesG1 axes need to be matched with the retGroup axes.
[in]noMatchesG2The number of axes from ret that need to be matched with angle2.
[in]angle2The angle with which noMatchesG2 axes need to be matched with the retGroup axes.
[in]foldThe fold of the searched for axis.
[in]dataObjThe full data holding object pointer - this is to get access to self-rotation function values.
[out]atLeastOneBoolean value speciying whether at least the minimum required number of axes was found.

Definition at line 1416 of file ProSHADE_symmetry.cpp.

1417 {
1418  //================================================ Initialise variables
1419  bool atLeastOne = false;
1420  std::vector< proshade_double* > prosp;
1421  std::vector< proshade_double > sol;
1422 
1423  //================================================ Proceed only if need be
1424  if ( static_cast<proshade_unsign> ( possibilities->size() ) == requiredNoAxes ) { atLeastOne = true; return ( atLeastOne ); }
1425 
1426  //================================================ Copy already found to prospective
1427  for ( proshade_unsign prIt = 0; prIt < static_cast<proshade_unsign> ( possibilities->size() ); prIt++ )
1428  {
1429  ProSHADE_internal_symmetry::addAxisUnlessSame ( static_cast< proshade_unsign > ( CSymList->at(possibilities->at(prIt))[0] ),
1430  CSymList->at(possibilities->at(prIt))[1],
1431  CSymList->at(possibilities->at(prIt))[2],
1432  CSymList->at(possibilities->at(prIt))[3],
1433  CSymList->at(possibilities->at(prIt))[5], &prosp, axErr );
1434  }
1435 
1436  //================================================ Start generating possible solutions
1437  for ( proshade_unsign rgIt1 = 0; rgIt1 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt1++ )
1438  {
1439  for ( proshade_unsign rgIt2 = 0; rgIt2 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt2++ )
1440  {
1441  //======================================== Use unique combinations (order matters here!)
1442  if ( rgIt1 == rgIt2 ) { continue; }
1443 
1444  //======================================== Generate possible solution (1)
1445  sol = ProSHADE_internal_maths::findVectorFromTwoVAndTwoD ( ret->at(rgIt1)[1], ret->at(rgIt1)[2], ret->at(rgIt1)[3],
1446  ret->at(rgIt2)[1], ret->at(rgIt2)[2], ret->at(rgIt2)[3], angle1, angle2 );
1447 
1448  //======================================== Check if solution fits the group completely
1449  ProSHADE_internal_symmetry::checkFittingAxisDualAndSave ( retGroup, ret, fold, sol.at(0), sol.at(1), sol.at(2), &prosp, axErr, noMatchesG1, angle1, noMatchesG2, angle2, dataObj );
1450  if ( prosp.size() == requiredNoAxes ) { break; }
1451 
1452  //======================================== Generate possible solution (2)
1453  sol = ProSHADE_internal_maths::findVectorFromTwoVAndTwoD ( ret->at(rgIt1)[1], ret->at(rgIt1)[2], ret->at(rgIt1)[3],
1454  ret->at(rgIt2)[1], ret->at(rgIt2)[2], ret->at(rgIt2)[3], -angle1, -angle2 );
1455 
1456  //======================================== Check if solution fits the group completely
1457  ProSHADE_internal_symmetry::checkFittingAxisDualAndSave ( retGroup, ret, fold, sol.at(0), sol.at(1), sol.at(2), &prosp, axErr, noMatchesG1, angle1, noMatchesG2, angle2, dataObj );
1458  if ( prosp.size() == requiredNoAxes ) { break; }
1459  }
1460 
1461  if ( prosp.size() == requiredNoAxes ) { break; }
1462  }
1463 
1464  //================================================ Found all required axes!
1465  if ( static_cast<proshade_unsign> ( prosp.size() ) == requiredNoAxes )
1466  {
1467  //============================================ Copy the detected axes
1468  for ( proshade_unsign iter = static_cast<proshade_unsign> ( possibilities->size() ); iter < static_cast<proshade_unsign> ( prosp.size() ); iter++ )
1469  {
1470  if ( ProSHADE_internal_maths::isAxisUnique ( CSymList, prosp.at(iter), axErr ) )
1471  {
1472  //==================================== Add
1473  ProSHADE_internal_misc::addToUnsignVector ( possibilities, static_cast< proshade_unsign > ( CSymList->size() ) );
1474  ProSHADE_internal_misc::addToDblPtrVector ( CSymList, prosp.at(iter) );
1475  }
1476  }
1477 
1478  //============================================ Done
1479  atLeastOne = true;
1480  return ( atLeastOne );
1481  }
1482  else
1483  {
1484  //============================================ Delete the created, but not used axes
1485  for ( proshade_unsign iter = static_cast<proshade_unsign> ( possibilities->size() ); iter < static_cast<proshade_unsign> ( prosp.size() ); iter++ )
1486  {
1487  delete[] prosp.at(iter);
1488  }
1489  }
1490 
1491  //================================================ Done
1492  return ( atLeastOne );
1493 
1494 }

◆ findMissingAxesTriple()

bool ProSHADE_internal_symmetry::findMissingAxesTriple ( std::vector< proshade_unsign > *  possibilities,
std::vector< proshade_double * > *  CSymList,
std::vector< proshade_double * > *  ret,
std::vector< proshade_unsign > *  retGroup,
proshade_unsign  requiredNoAxes,
proshade_double  axErr,
proshade_unsign  noMatchesG1,
proshade_double  angle1,
proshade_unsign  noMatchesG2,
proshade_double  angle2,
proshade_unsign  noMatchesG3,
proshade_double  angle3,
proshade_unsign  fold,
ProSHADE_internal_data::ProSHADE_data dataObj 
)

This function tries to find a particular symmetry axis which would complete a group of symmetries with three different angle requirement to another group.

Assuming there is a group of symmetry axis, which have particular number of particular angles to each other, but some are missing, this function tries to find any such missing axes. This is a solution for the group of axes having three different angles to the other group members. For all newly detected group members, the average peak height and the uniqueness are both tested for.

Parameters
[in]possibilitiesA vector of already detected axis indices which should be extended.
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]retA list of already detected octahedral axes.
[in]retGroupA vector of indices in the ret list which form the group to which new axes are compared to.
[in]requiredNoAxesNumber of axes required for positive result.
[in]axErrThe error tolerance on angle matching.
[in]noMatchesG1The number of axes from ret that need to be matched with angle1.
[in]angle1The angle with which noMatchesG1 axes need to be matched with the retGroup axes.
[in]noMatchesG2The number of axes from ret that need to be matched with angle2.
[in]angle2The angle with which noMatchesG2 axes need to be matched with the retGroup axes.
[in]noMatchesG3The number of axes from ret that need to be matched with angle3.
[in]angle3The angle with which noMatchesG3 axes need to be matched with the retGroup axes.
[in]foldThe fold of the searched for axis.
[in]dataObjThe full data holding object pointer - this is to get access to self-rotation function values.
[out]atLeastOneBoolean value speciying whether at least the minimum required number of axes was found.

Definition at line 2493 of file ProSHADE_symmetry.cpp.

2494 {
2495  //================================================ Initialise variables
2496  bool atLeastOne = false;
2497  std::vector< proshade_double* > prosp;
2498  std::vector< proshade_double > sol;
2499 
2500  //================================================ Proceed only if need be
2501  if ( static_cast<proshade_unsign> ( possibilities->size() ) == requiredNoAxes ) { atLeastOne = true; return ( atLeastOne ); }
2502 
2503  //================================================ Copy already found to prospective
2504  for ( proshade_unsign prIt = 0; prIt < static_cast<proshade_unsign> ( possibilities->size() ); prIt++ )
2505  {
2506  ProSHADE_internal_symmetry::addAxisUnlessSame ( static_cast< proshade_unsign > ( CSymList->at(possibilities->at(prIt))[0] ),
2507  CSymList->at(possibilities->at(prIt))[1],
2508  CSymList->at(possibilities->at(prIt))[2],
2509  CSymList->at(possibilities->at(prIt))[3],
2510  CSymList->at(possibilities->at(prIt))[5], &prosp, axErr );
2511  }
2512 
2513  //================================================ Start generating possible solutions
2514  for ( proshade_unsign rgIt1 = 0; rgIt1 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt1++ )
2515  {
2516  for ( proshade_unsign rgIt2 = 0; rgIt2 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt2++ )
2517  {
2518  //======================================== Use unique combinations (order matters here!)
2519  if ( rgIt1 == rgIt2 ) { continue; }
2520 
2521  for ( proshade_unsign rgIt3 = 0; rgIt3 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt3++ )
2522  {
2523  //==================================== Use unique combinations (order matters here!)
2524  if ( ( rgIt1 == rgIt3 ) || ( rgIt2 == rgIt3 ) ) { continue; }
2525 
2526  //==================================== Generate possible solution (1)
2527  sol = ProSHADE_internal_maths::findVectorFromThreeVAndThreeD ( ret->at(rgIt1)[1], ret->at(rgIt1)[2], ret->at(rgIt1)[3],
2528  ret->at(rgIt2)[1], ret->at(rgIt2)[2], ret->at(rgIt2)[3],
2529  ret->at(rgIt3)[1], ret->at(rgIt3)[2], ret->at(rgIt3)[3], angle1, angle2, angle3 );
2530 
2531  //==================================== Check if solution fits the group completely
2532  ProSHADE_internal_symmetry::checkFittingAxisTripleAndSave ( retGroup, ret, fold, sol.at(0), sol.at(1), sol.at(2), &prosp, axErr, noMatchesG1, angle1, noMatchesG2, angle2, noMatchesG3, angle3, dataObj );
2533  if ( prosp.size() == requiredNoAxes ) { break; }
2534 
2535  //==================================== Generate possible solution (2)
2536  sol = ProSHADE_internal_maths::findVectorFromThreeVAndThreeD ( ret->at(rgIt1)[1], ret->at(rgIt1)[2], ret->at(rgIt1)[3],
2537  ret->at(rgIt2)[1], ret->at(rgIt2)[2], ret->at(rgIt2)[3],
2538  ret->at(rgIt3)[1], ret->at(rgIt3)[2], ret->at(rgIt3)[3], -angle1, -angle2, -angle3 );
2539 
2540  //==================================== Check if solution fits the group completely
2541  ProSHADE_internal_symmetry::checkFittingAxisTripleAndSave ( retGroup, ret, fold, sol.at(0), sol.at(1), sol.at(2), &prosp, axErr, noMatchesG1, angle1, noMatchesG2, angle2, noMatchesG3, angle3, dataObj );
2542  if ( prosp.size() == requiredNoAxes ) { break; }
2543  }
2544 
2545  if ( prosp.size() == requiredNoAxes ) { break; }
2546  }
2547 
2548  if ( prosp.size() == requiredNoAxes ) { break; }
2549  }
2550 
2551  //================================================ Found all required axes
2552  if ( prosp.size() == requiredNoAxes )
2553  {
2554  //============================================ For each found missing axis
2555  for ( proshade_unsign axIt = static_cast<proshade_unsign> ( possibilities->size() ); axIt < static_cast<proshade_unsign> ( prosp.size() ); axIt++ )
2556  {
2557  if ( ProSHADE_internal_maths::isAxisUnique ( CSymList, prosp.at(axIt), axErr ) )
2558  {
2559  //======================================== Add
2560  ProSHADE_internal_misc::addToDblPtrVector ( CSymList, prosp.at(axIt) );
2561  ProSHADE_internal_misc::addToUnsignVector ( possibilities, static_cast<proshade_unsign> ( CSymList->size()-1 ) );
2562  }
2563  }
2564 
2565  atLeastOne = true;
2566  return ( atLeastOne );
2567  }
2568  else
2569  {
2570  //============================================ Delete all found, but unnecessary axes
2571  for ( proshade_unsign axIt = static_cast<proshade_unsign> ( possibilities->size() ); axIt < static_cast<proshade_unsign> ( prosp.size() ); axIt++ )
2572  {
2573  delete[] prosp.at(axIt);
2574  }
2575  }
2576 
2577  //================================================ Done
2578  return ( atLeastOne );
2579 
2580 }

◆ findMissingAxisPoints()

std::vector< proshade_double * > ProSHADE_internal_symmetry::findMissingAxisPoints ( proshade_double  xVal,
proshade_double  yVal,
proshade_double  zVal,
ProSHADE_internal_data::ProSHADE_data dataObj,
proshade_double  axErr 
)

This function searches for all the self-rotation map points conforming to the axis, returning their angles and heights.

This helper function searches the self-rotation map point by point for all points which represent the same rotation axis as required by the input parameters. For all such points, it records the angle they represent and the map height associated with them. Finally, it returns a vector of all detected points.

Parameters
[in]xValThe x-axis element of the axis to have the height detected.
[in]yValThe y-axis element of the axis to have the height detected.
[in]zValThe z-axis element of the axis to have the height detected.
[in]dataObjThe full data holding object pointer - this is to get access to self-rotation function values.
[in]axErrThe error tolerance on angle matching.
[out]angVecVector containing all map points which conform to the required axis along with their heights.

Definition at line 743 of file ProSHADE_symmetry.cpp.

744 {
745  //================================================ Initialise variables
746  proshade_double euA, euB, euG, xPk, yPk, zPk, anglPk;
747  proshade_double* rotMat = new proshade_double [9];
748  ProSHADE_internal_misc::checkMemoryAllocation ( rotMat, __FILE__, __LINE__, __func__ );
749  proshade_unsign arrIndex;
750  std::vector< proshade_double* > angVec;
751 
752  //================================================ Search the self-rotation map
753  for ( proshade_unsign xIt = 0; xIt < ( dataObj->getMaxBand ( ) * 2 ); xIt++ )
754  {
755  for ( proshade_unsign yIt = 0; yIt < ( dataObj->getMaxBand ( ) * 2 ); yIt++ )
756  {
757  for ( proshade_unsign zIt = 0; zIt < ( dataObj->getMaxBand ( ) * 2 ); zIt++ )
758  {
759  //==================================== Get height and check against threshold
760  arrIndex = zIt + ( dataObj->getMaxBand ( ) * 2 ) * ( yIt + ( dataObj->getMaxBand ( ) * 2 ) * xIt );
761 
762  //==================================== Get angle-axis values
763  ProSHADE_internal_maths::getEulerZYZFromSOFTPosition ( static_cast< proshade_signed > ( dataObj->getMaxBand() ), static_cast< proshade_signed > ( xIt ),
764  static_cast< proshade_signed > ( yIt ), static_cast< proshade_signed > ( zIt ),
765  &euA, &euB, &euG );
767  ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( rotMat, &xPk, &yPk, &zPk, &anglPk );
768 
769  //==================================== Set largest axis element to positive
770  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( xPk ), std::max( std::abs ( yPk ), std::abs ( zPk ) ) ) );
771  const FloatingPoint< proshade_double > rhs1 ( std::abs ( xPk ));
772  const FloatingPoint< proshade_double > rhs2 ( std::abs ( yPk ) );
773  const FloatingPoint< proshade_double > rhs3 ( std::abs ( zPk ) );
774  if ( ( lhs1.AlmostEquals ( rhs1 ) && ( xPk < 0.0 ) ) ||
775  ( lhs1.AlmostEquals ( rhs2 ) && ( yPk < 0.0 ) ) ||
776  ( lhs1.AlmostEquals ( rhs3 ) && ( zPk < 0.0 ) ) )
777  {
778  xPk *= -1.0;
779  yPk *= -1.0;
780  zPk *= -1.0;
781  anglPk *= -1.0;
782  }
783 
784  //==================================== Does the peak match the required axis?
785  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( xPk, yPk, zPk, xVal, yVal, zVal, axErr ) )
786  {
787  //================================ Matching map point - save it
788  proshade_double* hlpArr = new proshade_double [2];
789  ProSHADE_internal_misc::checkMemoryAllocation ( hlpArr, __FILE__, __LINE__, __func__ );
790  hlpArr[0] = anglPk + M_PI;
791  hlpArr[1] = pow( dataObj->getInvSO3Coeffs()[arrIndex][0], 2.0 ) +
792  pow( dataObj->getInvSO3Coeffs()[arrIndex][1], 2.0 );
793  ProSHADE_internal_misc::addToDblPtrVector ( &angVec, hlpArr );
794  }
795  }
796  }
797  }
798 
799  //================================================ Release memory
800  delete[] rotMat;
801 
802  //================================================ Done
803  return ( angVec );
804 
805 }

◆ findOcta3C4s()

void ProSHADE_internal_symmetry::findOcta3C4s ( std::vector< proshade_double * > *  CSymList,
std::vector< proshade_double * > *  ret,
proshade_double  axErr,
ProSHADE_internal_data::ProSHADE_data dataObj,
proshade_signed  verbose,
proshade_signed  messageShift,
proshade_double  minPeakHeight 
)

This function takes the list of C symmetries and finds the 3 C4 symmetries with perpendicular angles required for full octahedral symmetry.

This function is specific to detecting the octahedral symmetry. It should be called once octahedral symmetry is suspected (by detecting its dihedral angles) and it needs to be fully described. This function specifically searches for the three C4 symmetries which must all be detected in order to fully describe octahedral symmetry. If all three are found, the ret vector will contain these as its only four entries, while it will be empty if some of the C4 symmetries are not found. The missing symmetry axis detection is implemented as part of this function as well.

Parameters
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]retThe vector containing all axes required for the octahedral symmetry detected so far.
[in]axErrThe error tolerance on angle matching.
[in]minPeakHeightThe minimum average peak height for axis to be considered.
[in]verboseHow loud the announcments should be?
[in]messageShiftAre we in a subprocess, so that the log should be shifted for this function call? If so, by how much?
[in]minPeakHeightThe threshold for peak height.

Definition at line 1185 of file ProSHADE_symmetry.cpp.

1186 {
1187  //================================================ Initialise variables
1188  std::vector< proshade_unsign > C4PossibilitiesHlp;
1189  std::vector< std::vector< proshade_unsign > > C4Possibilities;
1190  bool groupMatched;
1191 
1192  //================================================ Report progress
1193  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of three C4 axes.", messageShift );
1194 
1195  //================================================ For all symmetries in the C symmetries list
1196  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
1197  {
1198  //============================================ Search only using C4s
1199  if ( CSymList->at(cIt)[0] != 4.0 || CSymList->at(cIt)[5] < minPeakHeight ) { continue; }
1200 
1201  //============================================ If second or more C4, check if it has the correct angle to all other already found C4s for each group
1202  groupMatched = false;
1203  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C4Possibilities.size() ); gIt++ )
1204  {
1205  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, &C4Possibilities.at(gIt), CSymList->at(cIt), axErr, 0.0, true, cIt ) ) { ProSHADE_internal_misc::addToUnsignVector ( &C4Possibilities.at(gIt), cIt ); groupMatched = true; break; }
1206  }
1207 
1208  //=========================================== If no group matched, create a new group
1209  if ( !groupMatched ) { C4PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C4PossibilitiesHlp, cIt ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C4Possibilities, C4PossibilitiesHlp ); continue; }
1210  }
1211 
1212  //================================================ Test for missing symmetry axes, if need be
1213  ProSHADE_internal_symmetry::findMissingAxes ( &C4Possibilities, CSymList, 3, axErr, 0.0, 4, dataObj, minPeakHeight );
1214 
1215  //================================================ Any group has 3 entries? If more such groups, take the one with highest average height.
1216  proshade_double maxHeight = 0.0; proshade_unsign maxGrp = 0;
1217  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( C4Possibilities.size() ); iter++ ) { if ( C4Possibilities.at(iter).size() == 3 ) { if ( ( ( CSymList->at(C4Possibilities.at(iter).at(0))[5] + CSymList->at(C4Possibilities.at(iter).at(1))[5] + CSymList->at(C4Possibilities.at(iter).at(2))[5] ) / 3.0 ) > maxHeight ) { maxHeight = ( ( CSymList->at(C4Possibilities.at(iter).at(0))[5] + CSymList->at(C4Possibilities.at(iter).at(1))[5] + CSymList->at(C4Possibilities.at(iter).at(2))[5] ) / 3.0 ); maxGrp = iter; } } }
1218 
1219  if ( C4Possibilities.at(maxGrp).size() == 3 )
1220  {
1221  //============================================ Success! Save and exit
1222  for ( proshade_unsign it = 0; it < static_cast<proshade_unsign> ( C4Possibilities.at(maxGrp).size() ); it++ ) { ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(C4Possibilities.at(maxGrp).at(it)) ); }
1223 
1224  //============================================ Report progress
1225  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of three C4 axes successfull.", messageShift );
1226 
1227  //============================================ Done
1228  return ;
1229  }
1230 
1231  //================================================ Done
1232  return ;
1233 
1234 }

◆ findOcta4C3s()

void ProSHADE_internal_symmetry::findOcta4C3s ( std::vector< proshade_double * > *  CSymList,
std::vector< proshade_double * > *  ret,
proshade_double  axErr,
ProSHADE_internal_data::ProSHADE_data dataObj,
proshade_signed  verbose,
proshade_signed  messageShift,
proshade_double  minPeakHeight 
)

This function takes the list of C symmetries and finds the four C3 symmetries with correct angles required for full octahedral symmetry.

This function is specific to detecting the tetrahedral symmetry. It should be called once tetrahedral symmetry is suspected (by detecting its dihedral angles) and it needs to be fully described. This function specifically searches for the four C3 symmetries which must all be detected in order to fully describe octahedral symmetry. If all four are found, the ret vector will have these four axes added to the already present three C4 axes; alternatively, the ret array size will not change. In order not to replicate computations, if tetrahedral symmetry has already been detected, the four axes sought here are the same as the first four axes detected there, so simple copying is used instead of re-computing the results anew.

Parameters
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]retThe vector .
[in]axErrThe error tolerance on angle matching.
[in]verboseHow loud the announcments should be?
[in]messageShiftAre we in a subprocess, so that the log should be shifted for this function call? If so, by how much?
[in]minPeakHeightThe minimum average peak height for axis to be considered.
[in]TetraSymListA vector containing the already detected tetrahedral symmetries - this is to avoid the same search for four C3 symmetry axes.

Definition at line 1252 of file ProSHADE_symmetry.cpp.

1253 {
1254  //================================================ Initialise variables
1255  std::vector< proshade_unsign > C4s, prospectiveC3s, C3PossibilitiesHlp;
1256  std::vector< std::vector< proshade_unsign > > C3Possibilities;
1257  proshade_double dotProd;
1258  bool groupMatched;
1259  for ( proshade_unsign iter = 0; iter < 3; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &C4s, iter ); }
1260 
1261  //================================================ Report progress
1262  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of four C3 axes.", messageShift );
1263 
1264  //================================================ For each C4
1265  for ( proshade_unsign rIt = 0; rIt < static_cast<proshade_unsign> ( ret->size() ); rIt++ )
1266  {
1267  //============================================ For each C3, check it has angle ( acos( 1/sqrt(3) ) ) to the tested C4
1268  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
1269  {
1270  //======================================== Search only using C3s
1271  if ( CSymList->at(cIt)[0] != 3.0 || CSymList->at(cIt)[5] < minPeakHeight ) { continue; }
1272 
1273  //======================================== Check the C3 axis to the C4 ( acos ( 1/sqrt(3) ) )
1274  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1], &ret->at(rIt)[2], &ret->at(rIt)[3], &CSymList->at(cIt)[1], &CSymList->at(cIt)[2], &CSymList->at(cIt)[3] );
1275 
1276  if ( ( std::abs ( dotProd ) > ( ( 1.0 / sqrt(3.0) ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( 1.0 / sqrt(3.0) ) + axErr ) ) ) { ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC3s, cIt ); }
1277  }
1278  }
1279 
1280  //================================================ Group the prospective C3s
1281  C3Possibilities.clear(); C3PossibilitiesHlp.clear();
1282  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( prospectiveC3s.size() ); cIt++ )
1283  {
1284  //============================================ If second or more C3, check if it can be placed in any group with having acos (1/3) to all its members
1285  groupMatched = false;
1286  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C3Possibilities.size() ); gIt++ )
1287  {
1288  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, &C3Possibilities.at(gIt), CSymList->at(prospectiveC3s.at(cIt)), axErr, 1.0/3.0, true, prospectiveC3s.at(cIt) ) ) { ProSHADE_internal_misc::addToUnsignVector ( &C3Possibilities.at(gIt), prospectiveC3s.at(cIt) ); groupMatched = true; break; }
1289  }
1290 
1291  //============================================ If no group matched, create a new group
1292  if ( !groupMatched ) { C3PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C3PossibilitiesHlp, prospectiveC3s.at(cIt) ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C3Possibilities, C3PossibilitiesHlp ); continue; }
1293  }
1294 
1295  //================================================ Find the best group or return empty
1296  while ( C3Possibilities.size() != 0 )
1297  {
1298  //============================================ Test for missing symmetry axes, if need be
1299  ProSHADE_internal_symmetry::findMissingAxes ( &C3Possibilities, CSymList, 4, axErr, 1.0/3.0, 3, dataObj, minPeakHeight );
1300 
1301  //============================================ Found four C3s?
1302  if ( C3Possibilities.at(0).size() == 4 )
1303  {
1304  //======================================== Success! Save and exit
1305  for ( proshade_unsign it = 0; it < 4; it++ ) { ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(C3Possibilities.at(0).at(it)) ); }
1306 
1307  //======================================== Report progress
1308  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of four C3 axes successfull.", messageShift );
1309 
1310  //======================================== Done
1311  return ;
1312  }
1313  else { C3Possibilities.erase ( C3Possibilities.begin() ); }
1314  }
1315 
1316  //================================================ Done
1317  return ;
1318 
1319 }

◆ findOcta6C2s()

void ProSHADE_internal_symmetry::findOcta6C2s ( std::vector< proshade_double * > *  CSymList,
std::vector< proshade_double * > *  ret,
proshade_double  axErr,
ProSHADE_internal_data::ProSHADE_data dataObj,
proshade_signed  verbose,
proshade_signed  messageShift,
proshade_double  minPeakHeight 
)

This function takes the list of C symmetries and finds the six C2 symmetries with correct angles required for full octahedral symmetry.

This function is specific to detecting the octahedral symmetry. It should be called once octahedral symmetry is suspected (by detecting its dihedral angles) and it needs to be fully described. This function specifically searches for the six C2 symmetries which must all be detected in order to fully describe octahedral symmetry. If all six are found, the ret vector will have these six axes added to the already present three C4 axes and the four C3 axes; alternatively, the ret array size will not change.

Parameters
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]retThe vector containing the already detected axes to which newly detected axes (if any) will be added.
[in]axErrThe error tolerance on angle matching.
[in]verboseHow loud the announcments should be?
[in]messageShiftAre we in a subprocess, so that the log should be shifted for this function call? If so, by how much?
[in]minPeakHeightThe minimum average peak height for axis to be considered.

Definition at line 1335 of file ProSHADE_symmetry.cpp.

1336 {
1337  //================================================ Initialise variables
1338  std::vector< proshade_unsign > prospectiveC2s, retGrp;
1339  proshade_double dotProd;
1340  proshade_unsign noPerpendicular, noSqrtTwo;
1341 
1342  //================================================ Report progress
1343  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of six C2 axes.", messageShift );
1344 
1345  //================================================ For each C2
1346  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
1347  {
1348  //============================================ Use only C2s
1349  const FloatingPoint< proshade_double > lhs999 ( CSymList->at(cIt)[5] ), rhs999 ( static_cast< proshade_double > ( -999.9 ) );
1350  if ( CSymList->at(cIt)[0] != 2.0 || ( ( CSymList->at(cIt)[5] < minPeakHeight ) && ! ( lhs999.AlmostEquals( rhs999 ) ) ) ) { continue; }
1351 
1352  //============================================ Check the C2 has acos ( 1/sqrt(2) ) to 2 C4s and acos ( 0.0 ) to the third C4
1353  noPerpendicular = 0; noSqrtTwo = 0;
1354  for ( proshade_unsign rIt = 0; rIt < 3; rIt++ )
1355  {
1356  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1],
1357  &ret->at(rIt)[2],
1358  &ret->at(rIt)[3],
1359  &CSymList->at(cIt)[1],
1360  &CSymList->at(cIt)[2],
1361  &CSymList->at(cIt)[3] );
1362 
1363  if ( ( std::abs ( dotProd ) > ( ( 1.0 / sqrt(2.0) ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( 1.0 / sqrt(2.0) ) + axErr ) ) ) { noSqrtTwo += 1; continue; }
1364  if ( ( std::abs ( dotProd ) > ( 0.0 - axErr ) ) && ( std::abs ( dotProd ) < ( 0.0 + axErr ) ) ) { noPerpendicular += 1; continue; }
1365  }
1366 
1367  //============================================ If correct angles distribution is found, save the axis
1368  if ( ( noSqrtTwo == 2 ) && ( noPerpendicular == 1 ) )
1369  {
1370  ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC2s, cIt );
1371  }
1372  }
1373 
1374  //================================================ Search for missing axes
1375  for ( proshade_unsign iter = 0; iter < 3; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &retGrp, iter ); }
1376  if ( !ProSHADE_internal_symmetry::findMissingAxesDual ( &prospectiveC2s, CSymList, ret, &retGrp, 6, axErr, 1, 0.0, 2, 1/sqrt(2.0), 2, dataObj ) )
1377  {
1378  return ;
1379  }
1380 
1381  //================================================ Found correct number of axes! Now save the
1382  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( prospectiveC2s.size() ); iter++ )
1383  {
1384  ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(prospectiveC2s.at(iter)) );
1385  }
1386 
1387  //================================================ Report progress
1388  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of six C2 axes successfull.", messageShift );
1389 
1390  //================================================ Done
1391  return ;
1392 
1393 }

◆ findPointFromTranslations()

std::vector< proshade_double > ProSHADE_internal_symmetry::findPointFromTranslations ( ProSHADE_internal_data::ProSHADE_data symStr,
std::vector< std::vector< proshade_double > >  symElems,
fftw_complex *  origCoeffs,
fftw_complex *  rotMapComplex,
fftw_complex *  rotCoeffs,
fftw_plan  planForwardFourierRot,
fftw_complex *  trFuncCoeffs,
fftw_complex *  trFunc,
fftw_plan  planReverseFourierComb 
)

This function computes the average of optimal translations for a cyclic point group.

This function takes a single cyclic point group elements and proceeds to compute all optimal translations between the original map and map rotated by each point group element. The sum of these translations divided by the number of the point group elements (including the identity element) then gives a point that must lie on the symmetry axis.

Parameters
[in]symStrA ProSHADE_data structure containing the structure for which the line on which the centre of rotation lies is to be found.
[in]symElemsVector containing single symmetry element (rotaiton matrix) which is not identity.
[in]origCoeffsThe Fourier coefficients of the original (non-rotated) map.
[in]rotMapComplexArray to which the rotated map will be saved and from which the Fourier transform plan (planForwardFourierRot) is prepared.
[in]rotCoeffsArray to which the result of the Fourier transform of the rotated map will be saved into by the supplied plan (planForwardFourierRot).
[in]planForwardFourierRotFFTW3 plan for forward Fourier transform from rotMapComplex to rotCoeffs.
[in]trFuncCoeffsThe array to which the combined Fourier coefficients for translation function will be saved into and also for which the inverse Fourier transform plan (planReverseFourierComb) is prepared for.
[in]trFuncThe array to which the translation function will be saved into by the reverse Fourier transform planned by the plan (planReverseFourierComb).
[in]planReverseFourierCombFFTW3 plan for reverse Fourier transform from the combined coefficients (trFuncCoeffs) to the translation function array (trFunc).
[in]verboseHow loud the function should be?
[out]pointOnLineA vector specifying a point that lies on the symmetry axis (given by the averaged sum of the translations of the rotated maps).

Definition at line 3985 of file ProSHADE_symmetry.cpp.

3986 {
3987  //================================================ Initialise local variables
3988  std::vector< proshade_double > pointOnLine ( 3, 0.0 );
3989  std::vector< proshade_double > identityMat ( 9, 0.0 ); identityMat.at(0) = 1.0; identityMat.at(4) = 1.0; identityMat.at(8) = 1.0;
3990 
3991  //================================================ For each symmetry element in this cyclic group
3992  for ( size_t gEl = 0; gEl < symElems.size(); gEl++ )
3993  {
3994  //============================================ Ignore identity element
3995  if ( ProSHADE_internal_maths::rotationMatrixSimilarity ( &symElems.at(gEl), &identityMat, 0.01 ) ) { continue; }
3996 
3997  //============================================ Find translation difference between rotated and original map
3998  std::vector< proshade_double > trsCenHlp = ProSHADE_internal_symmetry::findTranslationBetweenRotatedAndOriginalMap ( symStr,
3999  symElems.at(gEl),
4000  origCoeffs, rotMapComplex,
4001  rotCoeffs, planForwardFourierRot,
4002  trFuncCoeffs, trFunc,
4003  planReverseFourierComb );
4004 
4005  //============================================ Sum translations over the whole axis
4006  pointOnLine.at(0) += trsCenHlp.at(0);
4007  pointOnLine.at(1) += trsCenHlp.at(1);
4008  pointOnLine.at(2) += trsCenHlp.at(2);
4009  }
4010 
4011  //================================================ Average over all symmetry elements (including the identity one)
4012  pointOnLine.at(0) /= static_cast< proshade_double > ( symElems.size() );
4013  pointOnLine.at(1) /= static_cast< proshade_double > ( symElems.size() );
4014  pointOnLine.at(2) /= static_cast< proshade_double > ( symElems.size() );
4015 
4016  //================================================ Done
4017  return ( pointOnLine );
4018 
4019 }

◆ findPredictedAxesHeights()

void ProSHADE_internal_symmetry::findPredictedAxesHeights ( std::vector< proshade_double * > *  ret,
ProSHADE_internal_data::ProSHADE_data dataObj,
ProSHADE_settings settings 
)

This function finds the rotation function value for all axes supplied in the ret parameter.

This function supplements the polyhedral symmetry prediction functions, as these functions predict the symmetry axes, but do not find their peak heights. This function, then, firstly finds all the individual folds in the symmetry axes set and for each fold computes the appropriate angles. Next. it computes the sphere mappings of the rotation function for all detected angles and for each symmetry axes, it finds the rotation function average as well as the average for the whole symmetry (i.e. over all axes). Finally, the function attempts to locally optimise the detected symmetry group by searching for slightly rotated axes having higher rotation function average.

Parameters
[in]retThe list of axes for which the heights are to be found.
[in]dataObjThe structure object with computed rotation function in which the peaks are to be found.
[in]settingsProSHADE_settings object containing all the settings for this run.

Definition at line 3063 of file ProSHADE_symmetry.cpp.

3064 {
3065  //================================================ Initialise variables
3066  std::vector < proshade_unsign > folds;
3067  std::vector < proshade_double > angs, applicableAngs;
3068  bool alreadyFound = false;
3069  size_t corAngIt = 0;
3070  proshade_double lat = 0.0, lon = 0.0, radRange = 0.0, searchRangeInDeg = 0.0, axSum = 0.0, curSum = 0.0, maxSum = 0.0, bestXRot = 0.0, bestYRot = 0.0, bestZRot = 0.0, finXRotChan = 0.0, finYRotChan = 0.0, finZRotChan = 0.0;
3071  proshade_double latSamlUnit = ( 2.0 * M_PI ) / ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 );
3072  proshade_double lonSamlUnit = ( 1.0 * M_PI ) / ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 );
3073 
3074  //================================================ Determine all the folds for which rotation function mapping will be required
3075  for ( proshade_unsign iter = 0; iter < static_cast < proshade_unsign > ( ret->size() ); iter++ )
3076  {
3077  alreadyFound = false;
3078  for ( proshade_unsign it = 0; it < static_cast < proshade_unsign > ( folds.size() ); it++ ) { const FloatingPoint< proshade_double > lhs1 ( static_cast< proshade_double > ( folds.at(it) ) ), rhs1 ( ret->at(iter)[0] ); if ( lhs1.AlmostEquals ( rhs1 ) ) { alreadyFound = true; break; } }
3079 
3080  if ( !alreadyFound ) { ProSHADE_internal_misc::addToUnsignVector ( &folds, static_cast< proshade_unsign > ( ret->at(iter)[0] ) ); }
3081  }
3082 
3083  //================================================ Generate vector of all angles
3084  for ( proshade_unsign foldIt = 0; foldIt < static_cast < proshade_unsign > ( folds.size() ); foldIt++ ) { for ( proshade_double angIt = 1.0; angIt < static_cast<proshade_double> ( folds.at(foldIt) ); angIt += 1.0 ) { ProSHADE_internal_misc::addToDoubleVector ( &angs, angIt * ( 2.0 * M_PI / static_cast<proshade_double> ( folds.at(foldIt) ) ) ); } }
3085  std::sort ( angs.begin(), angs.end() );
3086 
3087  //================================================ Remove redundant angles from the list
3088  for ( int angIt = static_cast< int > ( angs.size() - 2 ); angIt >= 0; angIt-- ) { const FloatingPoint< proshade_double > lhs1 ( angs.at(static_cast< size_t > ( angIt ) ) ), rhs1 ( angs.at(static_cast< size_t > ( angIt + 1 ) ) ); if ( lhs1.AlmostEquals ( rhs1 ) ) { angs.erase ( angs.begin() + (angIt+1) ); } }
3089 
3090  //================================================ Generate all sphere mapped rotation function
3091  dataObj->sphereMappedRotFun.clear();
3092  for ( size_t angIt = 0; angIt < angs.size(); angIt++ )
3093  {
3094  //============================================ Decide the range in which the sphere operates
3095  if ( ( angIt == 0 ) && ( angs.size() > 1 ) ) { radRange = ( angs.at(1) - angs.at(0) ) / 2; }
3096  else { if ( ( angIt == ( angs.size() - 1 ) ) && ( angs.size() > 1 ) ) { radRange = ( angs.at(angIt) - angs.at(angIt-1) ) / 2; }
3097  else { if ( angs.size() > 2 ) { radRange = std::min ( ( angs.at(angIt) - angs.at(angIt-1) ) / 2, ( angs.at(angIt+1) - angs.at(angIt) ) / 2 ); }
3098  else { radRange = 0.5; } } }
3099 
3100  //============================================ Create the sphere
3101  dataObj->sphereMappedRotFun.emplace_back ( new ProSHADE_internal_spheres::ProSHADE_rotFun_sphere ( angs.at(angIt),
3102  radRange,
3103  dataObj->getMaxBand ( ) * 2,
3104  dataObj->getEMatDim ( ) * 2,
3105  angs.at(angIt),
3106  static_cast<proshade_unsign> ( angIt ) ) );
3107 
3108  //=========================================== Interpolate rotation function onto the sphere
3109  dataObj->sphereMappedRotFun.at( static_cast < proshade_unsign > ( angIt ))->interpolateSphereValues ( dataObj->getInvSO3Coeffs ( ) );
3110  }
3111 
3112  //================================================ Check for improved sum
3113  searchRangeInDeg = 360.0 / ( static_cast< proshade_double > ( dataObj->getMaxBand() ) * 2.0 );
3114  proshade_double* rotMat, *newAxis;
3115  while ( searchRangeInDeg > 0.09 )
3116  {
3117  //============================================ For change along each dimension
3118  for ( proshade_double xChan = -searchRangeInDeg; xChan < ( 1.5 * searchRangeInDeg ); xChan += searchRangeInDeg )
3119  {
3120  for ( proshade_double yChan = -searchRangeInDeg; yChan < ( 1.5 * searchRangeInDeg ); yChan += searchRangeInDeg )
3121  {
3122  for ( proshade_double zChan = -searchRangeInDeg; zChan < ( 1.5 * searchRangeInDeg ); zChan += searchRangeInDeg )
3123  {
3124  //================================ Initialise local variables
3125  curSum = 0.0;
3126 
3127  //================================ Find the rotation matrix of the appropriate rotation
3128  rotMat = ProSHADE_internal_maths::build3x3MatrixFromXYZRotations ( xChan + finXRotChan, yChan + finYRotChan, zChan + finZRotChan );
3129 
3130  //================================ For each axis, find new position and its RF value
3131  for ( proshade_unsign axIt = 0; axIt < static_cast< proshade_unsign > ( ret->size() ); axIt++ )
3132  {
3133  //============================ Find rotated axis
3134  newAxis = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMat, ret->at(axIt)[1], ret->at(axIt)[2], ret->at(axIt)[3] );
3135 
3136  //============================ Convert XYZ to lat and lon INDICES
3137  lat = ( std::atan2( newAxis[1], newAxis[0] ) / latSamlUnit );
3138  lon = ( std::acos ( newAxis[2] ) / lonSamlUnit );
3139 
3140  if ( lat < 0.0 ) { lat += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3141  if ( lon < 0.0 ) { lon += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3142 
3143  //============================ Generate all angles for this fold
3144  applicableAngs.clear ( );
3145  for ( proshade_double angIt = 1.0; angIt < ret->at(axIt)[0]; angIt += 1.0 ) { ProSHADE_internal_misc::addToDoubleVector ( &applicableAngs, angIt * ( 2.0 * M_PI / ret->at(axIt)[0] ) ); }
3146 
3147  //============================ For each shpere with the correct angle, average the peak heights
3148  axSum = 1.0;
3149  for ( size_t angIt = 0; angIt < angs.size(); angIt++ )
3150  {
3151  //======================== Find the correct sphere
3152  alreadyFound = false;
3153  for ( size_t aIt = 0; aIt < applicableAngs.size(); aIt++ ) { if ( alreadyFound ) { break; } const FloatingPoint< proshade_double > lhs1 ( angs.at(angIt) ), rhs1 ( applicableAngs.at(aIt) ); if ( lhs1.AlmostEquals ( rhs1 ) ) { alreadyFound = true; corAngIt = angIt; } }
3154 
3155  if ( !alreadyFound ) { continue; }
3156 
3157  //======================== Get its peak height for the longitude and latitude
3158  axSum += dataObj->sphereMappedRotFun.at(corAngIt)->getSphereLatLonLinearInterpolationPos ( lat, lon );
3159  }
3160 
3161  //============================ And average the peak heights over the axis
3162  axSum /= ret->at(axIt)[0];
3163  curSum += axSum;
3164 
3165  //============================ Release memory
3166  delete[] newAxis;
3167  }
3168 
3169  //================================ And average the peak heights over all axes
3170  curSum /= static_cast< proshade_double > ( ret->size() );
3171 
3172  //================================ If improved, save
3173  if ( curSum > maxSum )
3174  {
3175  maxSum = curSum;
3176  bestXRot = xChan;
3177  bestYRot = yChan;
3178  bestZRot = zChan;
3179  }
3180 
3181  //================================ Release memory
3182  delete[] rotMat;
3183 
3184 
3185  }
3186  }
3187  }
3188 
3189  //============================================ Prepare for next iteration
3190  searchRangeInDeg /= 2.0;
3191  finXRotChan += bestXRot;
3192  finYRotChan += bestYRot;
3193  finZRotChan += bestZRot;
3194  bestXRot = 0.0;
3195  bestYRot = 0.0;
3196  bestZRot = 0.0;
3197  }
3198 
3199  //================================================ Apply the optimisation
3200  rotMat = ProSHADE_internal_maths::build3x3MatrixFromXYZRotations ( finXRotChan, finYRotChan, finZRotChan );
3201  for ( proshade_unsign axIt = 0; axIt < static_cast< proshade_unsign > ( ret->size() ); axIt++ )
3202  {
3203  //============================================ Find the rotated axis
3204  newAxis = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMat, ret->at(axIt)[1], ret->at(axIt)[2], ret->at(axIt)[3] );
3205 
3206  //============================================ Change axes
3207  ret->at(axIt)[1] = newAxis[0];
3208  ret->at(axIt)[2] = newAxis[1];
3209  ret->at(axIt)[3] = newAxis[2];
3210  }
3211 
3212  //================================================ Release memory
3213  delete[] rotMat;
3214 
3215  //================================================ For each ret axis, compute predicted position
3216  for ( proshade_unsign axIt = 0; axIt < static_cast< proshade_unsign > ( ret->size() ); axIt++ )
3217  {
3218  //============================================ Convert XYZ to lat and lon INDICES
3219  lat = std::atan2( ret->at(axIt)[2], ret->at(axIt)[1] ) / latSamlUnit;
3220  lon = std::acos ( ret->at(axIt)[3] ) / lonSamlUnit;
3221 
3222  if ( lat < 0.0 ) { lat += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3223  if ( lon < 0.0 ) { lon += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3224 
3225  //============================================ Generate all angles for this fold
3226  applicableAngs.clear ( );
3227  for ( proshade_double angIt = 1.0; angIt < ret->at(axIt)[0]; angIt += 1.0 ) { ProSHADE_internal_misc::addToDoubleVector ( &applicableAngs, angIt * ( 2.0 * M_PI / ret->at(axIt)[0] ) ); }
3228 
3229  //============================================ For each shpere with the correct angle, average the peak heights
3230  ret->at(axIt)[5] = 0.0;
3231  for ( size_t angIt = 0; angIt < angs.size(); angIt++ )
3232  {
3233  //======================================== Find the correct sphere
3234  alreadyFound = false;
3235  for ( size_t aIt = 0; aIt < applicableAngs.size(); aIt++ ) { if ( alreadyFound ) { break; } const FloatingPoint< proshade_double > lhs1 ( angs.at(angIt) ), rhs1 ( applicableAngs.at(aIt) ); if ( lhs1.AlmostEquals ( rhs1 ) ) { alreadyFound = true; corAngIt = angIt; } }
3236 
3237  if ( !alreadyFound ) { continue; }
3238 
3239  //======================================== Get its peak height for the longitude and latitude
3240  ret->at(axIt)[5] += dataObj->sphereMappedRotFun.at(corAngIt)->getSphereLatLonLinearInterpolationPos ( lat, lon );
3241  }
3242 
3243  //============================================ And average the peak heights over the axis
3244  ret->at(axIt)[5] /= ( ret->at(axIt)[0] - 1.0 );
3245  maxSum += ret->at(axIt)[5];
3246  }
3247 
3248  //================================================ Report progress
3249  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 3, "Peak height detection and rotation optimisation complete.", settings->messageShift );
3250 
3251  //================================================ Done
3252  return ;
3253 
3254 }

◆ findPredictedSingleAxisHeight()

proshade_double ProSHADE_internal_symmetry::findPredictedSingleAxisHeight ( proshade_double *  axis,
proshade_double  fold,
ProSHADE_internal_data::ProSHADE_data dataObj,
ProSHADE_settings settings 
)

This function finds the rotation function value for a single axis.

This function is a simplified version of the findPredictedAxesHeights, except this one searches for the density map peak height for a single supplied axis (with the format of the array being x = [0], y = [1] and z = [2] and the fold being supplied separately).

Parameters
[in]axisA single axis for which the height is to be found.
[in]foldThe fold the axis should have.
[in]dataObjThe structure object with computed rotation function in which the peaks are to be found.
[in]settingsProSHADE_settings object containing all the settings for this run.
[out]heightThe height for this axis.

Definition at line 3409 of file ProSHADE_symmetry.cpp.

3410 {
3411  //================================================ Initialise variables
3412  proshade_double height = 0.0;
3413  proshade_double lat, lon;
3414  proshade_double latSamlUnit = ( 2.0 * M_PI ) / ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 );
3415  proshade_double lonSamlUnit = ( 1.0 * M_PI ) / ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 );
3416 
3417  //================================================ Make sure we have a clean start
3418  dataObj->sphereMappedRotFun.clear ( );
3419 
3420  //================================================ Convert rotation function to only the required angle-axis space spheres and find all peaks
3421  for ( proshade_double angIt = 1.0; angIt < fold; angIt += 1.0 )
3422  {
3423  //============================================ Create the angle-axis sphere with correct radius (angle)
3424  dataObj->sphereMappedRotFun.emplace_back ( new ProSHADE_internal_spheres::ProSHADE_rotFun_sphere ( angIt * ( 2.0 * M_PI / fold ),
3425  M_PI / fold,
3426  dataObj->getMaxBand ( ) * 2,
3427  dataObj->getEMatDim ( ) * 2,
3428  angIt * ( 2.0 * M_PI / fold ),
3429  static_cast<proshade_unsign> ( angIt - 1.0 ) ) );
3430 
3431  //============================================ Interpolate rotation function onto the sphere
3432  dataObj->sphereMappedRotFun.at( static_cast < proshade_unsign > ( angIt - 1.0 ))->interpolateSphereValues ( dataObj->getInvSO3Coeffs ( ) );
3433  }
3434 
3435  //================================================ Convert XYZ to lat and lon INDICES
3436  lat = std::atan2( axis[1], axis[0] ) / latSamlUnit;
3437  lon = std::acos ( axis[2] ) / lonSamlUnit;
3438 
3439  if ( lat < 0.0 ) { lat += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3440  if ( lon < 0.0 ) { lon += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3441 
3442  lat = std::round ( lat );
3443  lon = std::round ( lon );
3444 
3445  //================================================ Initialise the peak group
3447 
3448  //================================================ Construct a peak group with entry from each sphere with the axis as the peak
3449  for ( proshade_unsign sphIt = 0; sphIt < static_cast<proshade_unsign> ( dataObj->sphereMappedRotFun.size() ); sphIt++ )
3450  {
3451  if ( sphIt == 0 )
3452  {
3453  //======================================== If first sphere, create the peak group
3454  grp = new ProSHADE_internal_spheres::ProSHADE_rotFun_spherePeakGroup ( lat, lon, sphIt, dataObj->sphereMappedRotFun.at(sphIt)->getAngularDim() );
3455  }
3456  else
3457  {
3458  //======================================== Add to the existing object
3459  grp->checkIfPeakBelongs ( lat, lon, sphIt, settings->axisErrTolerance, settings->verbose, settings->messageShift, 0.1 );
3460  }
3461  }
3462 
3463  //================================================ Find the peak height
3464  std::vector < proshade_double* > detectedAxis;
3465  grp->findCyclicPointGroupsGivenFold ( dataObj->sphereMappedRotFun, &detectedAxis, settings->useBiCubicInterpolationOnPeaks, static_cast< proshade_unsign > ( fold ), settings->verbose, settings->messageShift );
3466 
3467  //================================================ Save it!
3468  if ( detectedAxis.size() > 0 ) { height = detectedAxis.at(0)[5]; }
3469  else { height = 0.0; }
3470 
3471  //================================================ Release memory
3472  for ( proshade_unsign i = 0; i < static_cast < proshade_unsign > ( detectedAxis.size() ); i++ ) { delete detectedAxis.at(i); }
3473  delete grp;
3474 
3475  //================================================ Done
3476  return ( height );
3477 
3478 }

◆ findReliableUnphasedSymmetries()

std::vector< proshade_unsign > ProSHADE_internal_symmetry::findReliableUnphasedSymmetries ( std::vector< proshade_double * > *  allCs,
std::vector< std::vector< proshade_double * > > *  allDs,
proshade_signed  verbose,
proshade_signed  messageShift,
proshade_double  tolerance 
)

This function checks the list of detected axes (presumably from phaseless symmetry detection) and returns the best dihedral (or cyclic, if no dihedral is found) point group, or empty vector if nothing is found.

This function starts by computing a stringent rotation function height threshold and proceeds to search for orthogonal pair of axes with at least this threshold RF value. If more than one pair is found, the pair with the highest sum of RF value and FSC value is chosen and returned, while if no pair is found, a single axis passing the threshold (and with the highest RF + FSC value sum) is returned. If no axis passes, empty vector is returned.

Warning
This function is intended to be used internally and specifically with phase-less symmetry detection, but it does not check for these conditions to be met!
Parameters
[in]allCsA list of all detected symmetries in the phase-less map.
[in]allDsA list of all detected dohedral symmetries in the phase-less map.
[in]verboseHow loud the function should be in the standard output?
[in]messageShiftAre we in a subprocess, so that the log should be shifted for this function call? If so, by how much?
[in]toleranceWhat is the tolerance on the perpendicularity of two axes in terms of the dot product?
[out]retA vector containing a) zero entries if no reliable symmetry axis was found, b) a single symmetry axis index if only a reliable cyclic symmetry axis was found or c) two axes indices in the case where two perpendicular reliable axes were detected.

Definition at line 3735 of file ProSHADE_symmetry.cpp.

3736 {
3737  //================================================ Report progress
3738  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Deciding whether any axis(es) is/are reliable.", messageShift );
3739 
3740  //================================================ Initialise local variables
3741  std::vector< proshade_unsign > ret;
3742 
3743  //================================================ Find the thresholds
3744  proshade_double bestHistPeakStart = ProSHADE_internal_maths::findTopGroupSmooth ( allCs, 5, 0.01, 0.1, 9 );
3745  proshade_double bestFSCPeakStart = ProSHADE_internal_maths::findTopGroupSmooth ( allCs, 6, 0.01, 0.1, 9 );
3746  if ( bestHistPeakStart > 0.9 ) { bestHistPeakStart = 0.9; }
3747 
3748  //================================================ Are there any dihedral axes?
3749  proshade_double maxOrtSum = 0.0, curOrtSum = 0.0;
3750  proshade_signed maxOrtAx1 = 0, maxOrtAx2 = 0;
3751  for ( size_t relAx = 0; relAx < allDs->size(); relAx++ )
3752  {
3753  //============================================ Check if they are reliable
3754  if ( allDs->at(relAx).at(0)[5] < bestHistPeakStart ) { continue; }
3755  if ( allDs->at(relAx).at(1)[5] < bestHistPeakStart ) { continue; }
3756  if ( allDs->at(relAx).at(0)[6] < bestFSCPeakStart ) { continue; }
3757  if ( allDs->at(relAx).at(1)[6] < bestFSCPeakStart ) { continue; }
3758 
3759  //============================================ They are! Save if the sum is the best
3760  curOrtSum = allDs->at(relAx).at(0)[6] + allDs->at(relAx).at(1)[6];
3761  if ( curOrtSum > maxOrtSum )
3762  {
3763  maxOrtSum = curOrtSum;
3764  maxOrtAx1 = ProSHADE_internal_symmetry::addAxisUnlessSame ( static_cast< proshade_unsign > ( allDs->at(relAx).at(0)[0] ),
3765  allDs->at(relAx).at(0)[1],
3766  allDs->at(relAx).at(0)[2],
3767  allDs->at(relAx).at(0)[3],
3768  allDs->at(relAx).at(0)[5], allCs, tolerance );
3769  maxOrtAx2 = ProSHADE_internal_symmetry::addAxisUnlessSame ( static_cast< proshade_unsign > ( allDs->at(relAx).at(1)[0] ),
3770  allDs->at(relAx).at(1)[1],
3771  allDs->at(relAx).at(1)[2],
3772  allDs->at(relAx).at(1)[3],
3773  allDs->at(relAx).at(1)[5], allCs, tolerance );
3774  }
3775  }
3776 
3777  //================================================ If any orthogonal pair was found, return it
3778  if ( maxOrtAx2 != 0 )
3779  {
3780  //================================================ Report progress
3781  ProSHADE_internal_misc::addToUnsignVector ( &ret, static_cast< proshade_unsign > ( maxOrtAx1 ) );
3782  ProSHADE_internal_misc::addToUnsignVector ( &ret, static_cast< proshade_unsign > ( maxOrtAx2 ) );
3783  return ( ret );
3784  }
3785 
3786  //================================================ Well, no orthogonal axes. Is there at least one good axis?
3787  curOrtSum = 0.0; maxOrtSum = 0.0; maxOrtAx1 = -1;
3788  for ( size_t relAx = 0; relAx < allCs->size(); relAx++ )
3789  {
3790  //============================================ Consider only reliable axes in terms of RF
3791  if ( allCs->at(relAx)[5] < bestHistPeakStart ) { continue; }
3792 
3793  //============================================ Consider only reasonable axes in terms of FSC
3794  if ( allCs->at(relAx)[6] < bestFSCPeakStart ) { continue; }
3795 
3796  //============================================ Get the sum
3797  curOrtSum = allCs->at(relAx)[6];
3798 
3799  //============================================ If highest sum, save
3800  if ( curOrtSum > maxOrtSum )
3801  {
3802  maxOrtSum = curOrtSum;
3803  maxOrtAx1 = static_cast< proshade_signed > ( relAx );
3804  }
3805  }
3806 
3807  //================================================ If anything was found, save it
3808  if ( maxOrtAx1 >= 0 )
3809  {
3810  //============================================ Report progress
3811  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Found single reliable axis.", messageShift );
3812 
3813  ProSHADE_internal_misc::addToUnsignVector ( &ret, static_cast< proshade_unsign > ( maxOrtAx1 ) );
3814  }
3815  else
3816  {
3817  //================================================ Report progress
3818  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Found no reliable axis.", messageShift );
3819  }
3820 
3821  //================================================ Done
3822  return ( ret );
3823 
3824 }

◆ findTetra3C2s()

void ProSHADE_internal_symmetry::findTetra3C2s ( std::vector< proshade_double * > *  CSymList,
std::vector< proshade_double * > *  ret,
proshade_double  axErr,
ProSHADE_internal_data::ProSHADE_data dataObj,
proshade_signed  verbose,
proshade_signed  messageShift,
proshade_double  minPeakHeight 
)

This function takes the list of C symmetries and finds the 3 C2 symmetries with correct angles required for full tetrahedral symmetry.

This is a specific helper function for detecting three C2 symmetries perpendicular to each other hand having a specific angle ( acos(0.5) ) to one of the already detected C3 symmetries of the sought after tetrahedral symmetry. It firstly finds all C2s and tests these for having the acos(0.5) angle to the already found C3s. From this list of passing C2s, it then tries to find three mutually perpendicular axes, including searching for missing axes. If no such axes are found, the ret array will still have 4 entries, while if they are found, the ret array will have these added to the total of 7 entries.

Parameters
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]retThe vector .
[in]axErrThe error tolerance on angle matching.
[in]verobseHow loud the announcments should be?
[in]messageShiftAre we in a subprocess, so that the log should be shifted for this function call? If so, by how much?
[in]minPeakHeightThe minimum average peak height for axis to be considered.

Definition at line 998 of file ProSHADE_symmetry.cpp.

999 {
1000  //================================================ Initialise variables
1001  std::vector< proshade_unsign > C3s, prospectiveC2s, C2PossibilitiesHlp;
1002  std::vector< std::vector< proshade_unsign > > C2Possibilities;
1003  proshade_double dotProd;
1004  bool groupMatched;
1005  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &C3s, iter ); }
1006 
1007  //================================================ Report progress
1008  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of three C2 axes.", messageShift );
1009 
1010  //================================================ For each C3
1011  for ( proshade_unsign rIt = 0; rIt < static_cast<proshade_unsign> ( ret->size() ); rIt++ )
1012  {
1013  //============================================ For each C2, check it has angle ( acos(0.5) ) to the tested C3
1014  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
1015  {
1016  //======================================== Search only using C2s
1017  const FloatingPoint< proshade_double > lhs999 ( CSymList->at(cIt)[5] ), rhs999 ( static_cast< proshade_double > ( -999.9 ) );
1018  if ( CSymList->at(cIt)[0] != 2.0 || ( ( CSymList->at(cIt)[5] < minPeakHeight ) && !( lhs999.AlmostEquals( rhs999 ) ) ) ) { continue; }
1019 
1020  //======================================== Check the C2 axis to the C3 ( acos ( 0.5 ) )
1021  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1], &ret->at(rIt)[2], &ret->at(rIt)[3],
1022  &CSymList->at(cIt)[1], &CSymList->at(cIt)[2], &CSymList->at(cIt)[3] );
1023 
1024  if ( ( std::abs ( dotProd ) > ( 0.5 - axErr ) ) && ( std::abs ( dotProd ) < ( 0.5 + axErr ) ) ) { ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC2s, cIt ); }
1025  }
1026  }
1027 
1028  //================================================ Group the prospective C2s
1029  C2Possibilities.clear(); C2PossibilitiesHlp.clear();
1030  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( prospectiveC2s.size() ); cIt++ )
1031  {
1032  //============================================ If second or more C2, check if it can be placed in any group with being perpendicular to all its members
1033  groupMatched = false;
1034  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C2Possibilities.size() ); gIt++ )
1035  {
1036  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, &C2Possibilities.at(gIt), CSymList->at(prospectiveC2s.at(cIt)), axErr, 0.0, true, prospectiveC2s.at(cIt) ) ) { ProSHADE_internal_misc::addToUnsignVector ( &C2Possibilities.at(gIt), prospectiveC2s.at(cIt) ); groupMatched = true; break; }
1037  }
1038 
1039  //============================================ If no group matched, create a new group
1040  if ( !groupMatched ) { C2PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C2PossibilitiesHlp, prospectiveC2s.at(cIt) ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C2Possibilities, C2PossibilitiesHlp ); continue; }
1041  }
1042 
1043  //================================================ Find the best group or return empty
1044  while ( C2Possibilities.size() != 0 )
1045  {
1046  //============================================ Test for missing symmetry axes, if need be
1047  ProSHADE_internal_symmetry::findMissingAxes ( &C2Possibilities, CSymList, 3, axErr, 0.0, 2, dataObj, minPeakHeight );
1048 
1049  //============================================ Found 3 C2s?
1050  if ( C2Possibilities.at(0).size() == 3 )
1051  {
1052  //======================================== Success! Save and exit
1053  for ( proshade_unsign it = 0; it < 3; it++ ) { ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(C2Possibilities.at(0).at(it)) ); }
1054 
1055  //======================================== Report progress
1056  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of three C2 axes successfull.", messageShift );
1057 
1058  //======================================== Done
1059  return ;
1060  }
1061  else { C2Possibilities.erase ( C2Possibilities.begin() ); }
1062  }
1063 
1064  //================================================ Done
1065  return ;
1066 
1067 }

◆ findTetra4C3s()

void ProSHADE_internal_symmetry::findTetra4C3s ( std::vector< proshade_double * > *  CSymList,
std::vector< proshade_double * > *  ret,
proshade_double  axErr,
ProSHADE_internal_data::ProSHADE_data dataObj,
proshade_signed  verbose,
proshade_signed  messageShift,
proshade_double  minPeakHeight 
)

This function takes the list of C symmetries and finds the 4 C3 symmetries with correct angles required for full tetrahedral symmetry.

This function is specific to detecting the tetrahedral symmetry. It should be called once tetrahedral symmetry is suspected (by detecting its dihedral angles) and it needs to be fully described. This function specifically searches for the four C3 symmetries which must all be detected in order to fully describe tetrahedral symmetry. If all four are found, the ret vector will contain these as its only four entries, while it will be empty if some of the C3 symmetries are not found. The missing symmetry axis detection is implemented as part of this function as well.

Parameters
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]retThe vector .
[in]axErrThe error tolerance on angle matching.
[in]verboseHow loud the announcments should be?
[in]messageShiftAre we in a subprocess, so that the log should be shifted for this function call? If so, by how much?
[in]minPeakHeightThe minimum average peak height for axis to be considered.

Definition at line 461 of file ProSHADE_symmetry.cpp.

462 {
463  //================================================ Initialise variables
464  std::vector< proshade_unsign > C3PossibilitiesHlp;
465  std::vector< std::vector< proshade_unsign > > C3Possibilities;
466  bool groupMatched;
467 
468  //================================================ Report progress
469  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of four C3 axes.", messageShift );
470 
471  //================================================ For all symmetries in the C symmetries list
472  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
473  {
474  //============================================ Search only using C3s
475  if ( CSymList->at(cIt)[0] != 3.0 || CSymList->at(cIt)[0] < minPeakHeight ) { continue; }
476 
477  //============================================ If this is the first C3, then just save it to the first group of the temporary holder
478  if ( C3Possibilities.size() == 0 ) { ProSHADE_internal_misc::addToUnsignVector ( &C3PossibilitiesHlp, cIt ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C3Possibilities, C3PossibilitiesHlp ); continue; }
479 
480  //============================================ If second or more C3, check if it has the correct angle to all other already found C3s for each group
481  groupMatched = false;
482  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C3Possibilities.size() ); gIt++ )
483  {
484  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, &C3Possibilities.at(gIt), CSymList->at(cIt), axErr, 1.0/3.0, true, cIt ) ) { ProSHADE_internal_misc::addToUnsignVector ( &C3Possibilities.at(gIt), cIt ); groupMatched = true; break; }
485  }
486 
487  //============================================ If no group matched, create a new group
488  if ( !groupMatched ) { C3PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C3PossibilitiesHlp, cIt ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C3Possibilities, C3PossibilitiesHlp ); continue; }
489  }
490 
491  //================================================ Test for missing symmetry axes, if need be
492  ProSHADE_internal_symmetry::findMissingAxes ( &C3Possibilities, CSymList, 4, axErr, 1.0/3.0, 3, dataObj, minPeakHeight );
493 
494  //================================================ Any group has 4 entries? If more such groups, take the one with highest average height.
495  proshade_double maxHeight = 0.0; proshade_unsign maxGrp = 0;
496  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( C3Possibilities.size() ); iter++ ) { if ( C3Possibilities.at(iter).size() == 4 ) { if ( ( ( CSymList->at(C3Possibilities.at(iter).at(0))[5] + CSymList->at(C3Possibilities.at(iter).at(1))[5] + CSymList->at(C3Possibilities.at(iter).at(2))[5] + CSymList->at(C3Possibilities.at(iter).at(3))[5] ) / 4.0 ) > maxHeight ) { maxHeight = ( ( CSymList->at(C3Possibilities.at(iter).at(0))[5] + CSymList->at(C3Possibilities.at(iter).at(1))[5] + CSymList->at(C3Possibilities.at(iter).at(2))[5] + CSymList->at(C3Possibilities.at(iter).at(3))[5] ) / 4.0 ); maxGrp = iter; } } }
497 
498  if ( C3Possibilities.at(maxGrp).size() == 4 )
499  {
500  //============================================ Success! Save and exit
501  for ( proshade_unsign it = 0; it < static_cast<proshade_unsign> ( C3Possibilities.at(maxGrp).size() ); it++ ) { ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(C3Possibilities.at(maxGrp).at(it)) ); }
502 
503  //============================================ Report progress
504  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of four C3 axes successfull.", messageShift );
505 
506  //============================================ Done
507  return ;
508  }
509 
510  //================================================ Done
511  return ;
512 
513 }

◆ findTranslationBetweenRotatedAndOriginalMap()

std::vector< proshade_double > ProSHADE_internal_symmetry::findTranslationBetweenRotatedAndOriginalMap ( ProSHADE_internal_data::ProSHADE_data symStr,
std::vector< proshade_double >  symElem,
fftw_complex *  origCoeffs,
fftw_complex *  rotMapComplex,
fftw_complex *  rotCoeffs,
fftw_plan  planForwardFourierRot,
fftw_complex *  trFuncCoeffs,
fftw_complex *  trFunc,
fftw_plan  planReverseFourierComb 
)

This function takes a single rotation matrix and procceds to compute the optimal translation between the original map and a map rotated by the supplied rotation matrix.

Parameters
[in]symStrA ProSHADE_data structure containing the structure for which the line on which the centre of rotation lies is to be found.
[in]symElemsVector containing single symmetry element (rotaiton matrix) which is not identity.
[in]origCoeffsThe Fourier coefficients of the original (non-rotated) map.
[in]rotMapComplexArray to which the rotated map will be saved and from which the Fourier transform plan (planForwardFourierRot) is prepared.
[in]rotCoeffsArray to which the result of the Fourier transform of the rotated map will be saved into by the supplied plan (planForwardFourierRot).
[in]planForwardFourierRotFFTW3 plan for forward Fourier transform from rotMapComplex to rotCoeffs.
[in]trFuncCoeffsThe array to which the combined Fourier coefficients for translation function will be saved into and also for which the inverse Fourier transform plan (planReverseFourierComb) is prepared for.
[in]trFuncThe array to which the translation function will be saved into by the reverse Fourier transform planned by the plan (planReverseFourierComb).
[in]planReverseFourierCombFFTW3 plan for reverse Fourier transform from the combined coefficients (trFuncCoeffs) to the translation function array (trFunc).
[out]trsVecA vector containing the optimal translation between the original and the rotated maps in Angstroms.

Definition at line 3919 of file ProSHADE_symmetry.cpp.

3920 {
3921  //================================================ Initialise local variables
3922  proshade_double axX, axY, axZ, axAng, mapPeak, trsX, trsY, trsZ;
3923  std::vector< proshade_double > trsVec;
3924 
3925  //=============================================== Rotate the map by the rotation matrix
3926  proshade_double *rotMap;
3927  ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( &symElem, &axX, &axY, &axZ, &axAng );
3928  symStr->rotateMapRealSpace ( axX, axY, axZ, axAng, rotMap );
3929 
3930  //================================================ Convert rotated map to Fourier space
3931  for ( size_t it = 0; it < static_cast< size_t > ( symStr->getXDim() * symStr->getYDim() * symStr->getZDim() ); it++ ) { rotMapComplex[it][0] = rotMap[it]; rotMapComplex[it][1] = 0.0; }
3932  fftw_execute ( planForwardFourierRot );
3933 
3934  //================================================ Combine coeffs for translation function
3935  ProSHADE_internal_maths::combineFourierForTranslation ( origCoeffs, rotCoeffs, trFuncCoeffs, symStr->getXDim(), symStr->getYDim(), symStr->getZDim() );
3936 
3937  //================================================ Compute translation function
3938  fftw_execute ( planReverseFourierComb );
3939 
3940  //================================================ Find peak
3941  mapPeak = 0.0;
3942  ProSHADE_internal_maths::findHighestValueInMap ( trFunc, symStr->getXDim(), symStr->getYDim(), symStr->getZDim(), &trsX, &trsY, &trsZ, &mapPeak );
3943 
3944  //================================================ Convert to Angstroms
3945  trsX *= static_cast< proshade_double > ( symStr->getXDimSize() ) / static_cast< proshade_double > ( symStr->getXDim() );
3946  trsY *= static_cast< proshade_double > ( symStr->getYDimSize() ) / static_cast< proshade_double > ( symStr->getYDim() );
3947  trsZ *= static_cast< proshade_double > ( symStr->getZDimSize() ) / static_cast< proshade_double > ( symStr->getZDim() );
3948 
3949  //================================================ Do not translate over half
3950  if ( trsX > ( static_cast< proshade_double > ( symStr->getXDimSize() ) / 2.0 ) ) { trsX = trsX - static_cast< proshade_double > ( symStr->getXDimSize() ); }
3951  if ( trsY > ( static_cast< proshade_double > ( symStr->getYDimSize() ) / 2.0 ) ) { trsY = trsY - static_cast< proshade_double > ( symStr->getYDimSize() ); }
3952  if ( trsZ > ( static_cast< proshade_double > ( symStr->getZDimSize() ) / 2.0 ) ) { trsZ = trsZ - static_cast< proshade_double > ( symStr->getZDimSize() ); }
3953 
3954  //================================================ Save line point
3958 
3959  //================================================ Release memory
3960  delete[] rotMap;
3961 
3962  //================================================ Done
3963  return ( trsVec );
3964 
3965 }

◆ isSymmetrySame() [1/2]

bool ProSHADE_internal_symmetry::isSymmetrySame ( std::vector< proshade_double * > *  ret,
proshade_double *  sym,
proshade_double  simThres,
proshade_signed *  matchedPos 
)

This function checks if a very similar symmetry is not already saved.

This is a simple function comparing a single double array of 6 to a vector of these, returning whether the vector already contains a very similar entry to the rested one. If the new has better height, replacement will take place.

Parameters
[in]retThis is the variable where the tested array will be saved if passed. It is a vector of double[6] arrays with the following meaning: [0] = fold, [1] = x-axis, [2] = y-axis, [3] = z-axis, [4] = angle, [5] = average peak height.
[in]symThis is a double array of 6 which is to be compared to all the vector entries.
[in]simThresThe threshold for dot product comparison similarity.
[in]matchedPosPointer to variable where the matched position (if any axis is matched) is saved, or -1 is written.
[out]XBoolean value stating whether a similar entry has been found (true = it was, false = it was not).

Definition at line 215 of file ProSHADE_symmetry.cpp.

216 {
217  //================================================ Initialise variables
218  proshade_double dotProduct = 0.0;
219  *matchedPos = -1;
220 
221  //================================================ Check
222  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( ret->size() ); symIt++ )
223  {
224  //============================================ Minor speed-up => only test for same folds
225  const FloatingPoint< proshade_double > lhs ( ret->at(symIt)[0] ), rhs ( sym[0] );
226  if ( lhs.AlmostEquals ( rhs ) )
227  {
228  //======================================== Is axis the same?
229  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &ret->at(symIt)[1], &ret->at(symIt)[2],
230  &ret->at(symIt)[3], &sym[1], &sym[2], &sym[3] );
231  if ( ( ( 1.0 > ( dotProduct - simThres ) ) && ( 1.0 < ( dotProduct + simThres ) ) ) || ( ( -1.0 > ( dotProduct - simThres ) ) && ( -1.0 < ( dotProduct + simThres ) ) ) )
232  {
233  //==================================== Matched. Save the index
234  *matchedPos = static_cast< proshade_signed > ( symIt );
235 
236  //==================================== Does the already saved have higher height?
237  if ( ret->at(symIt)[5] >= sym[5] ) { return ( true ); }
238 
239  //==================================== In this case, new is better than old - sort it out
240  ret->at(symIt)[1] = sym[1];
241  ret->at(symIt)[2] = sym[2];
242  ret->at(symIt)[3] = sym[3];
243  ret->at(symIt)[5] = sym[5];
244  return ( true );
245  }
246  }
247  }
248 
249  //================================================ Done - no matches found
250  return ( false );
251 
252 }

◆ isSymmetrySame() [2/2]

bool ProSHADE_internal_symmetry::isSymmetrySame ( std::vector< proshade_double * > *  ret,
proshade_double *  sym,
proshade_double  simThres,
proshade_signed *  matchedPos,
proshade_double  fscVal 
)

This function checks if a very similar symmetry is not already saved.

This is a simple function comparing a single double array of 6 to a vector of these, returning whether the vector already contains a very similar entry to the rested one. If the new has better height, replacement will take place.

Parameters
[in]retThis is the variable where the tested array will be saved if passed. It is a vector of double[6] arrays with the following meaning: [0] = fold, [1] = x-axis, [2] = y-axis, [3] = z-axis, [4] = angle, [5] = average peak height.
[in]symThis is a double array of 6 which is to be compared to all the vector entries.
[in]simThresThe threshold for dot product comparison similarity.
[in]matchedPosPointer to variable where the matched position (if any axis is matched) is saved, or -1 is written.
[in]fscValValue to be used as FSC in case of a match.
[out]XBoolean value stating whether a similar entry has been found (true = it was, false = it was not).

Definition at line 266 of file ProSHADE_symmetry.cpp.

267 {
268  //================================================ Initialise variables
269  proshade_double dotProduct = 0.0;
270  *matchedPos = -1;
271 
272  //================================================ Check
273  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( ret->size() ); symIt++ )
274  {
275  //============================================ Minor speed-up => only test for same folds
276  const FloatingPoint< proshade_double > lhs ( ret->at(symIt)[0] ), rhs ( sym[0] );
277  if ( lhs.AlmostEquals ( rhs ) )
278  {
279  //======================================== Is axis the same?
280  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &ret->at(symIt)[1], &ret->at(symIt)[2],
281  &ret->at(symIt)[3], &sym[1], &sym[2], &sym[3] );
282  if ( ( ( 1.0 > ( dotProduct - simThres ) ) && ( 1.0 < ( dotProduct + simThres ) ) ) || ( ( -1.0 > ( dotProduct - simThres ) ) && ( -1.0 < ( dotProduct + simThres ) ) ) )
283  {
284  //==================================== Matched. Save the index
285  *matchedPos = static_cast< proshade_signed > ( symIt );
286 
287  //==================================== Does the already saved have higher height?
288  if ( ret->at(symIt)[5] >= sym[5] ) { return ( true ); }
289 
290  //==================================== In this case, new is better than old - sort it out
291  ret->at(symIt)[1] = sym[1];
292  ret->at(symIt)[2] = sym[2];
293  ret->at(symIt)[3] = sym[3];
294  ret->at(symIt)[5] = sym[5];
295  ret->at(symIt)[6] = fscVal;
296  return ( true );
297  }
298  }
299  }
300 
301  //================================================ Done - no matches found
302  return ( false );
303 
304 }

◆ missingAxisHeight()

proshade_double ProSHADE_internal_symmetry::missingAxisHeight ( proshade_double  xVal,
proshade_double  yVal,
proshade_double  zVal,
ProSHADE_internal_data::ProSHADE_data dataObj,
proshade_unsign  fold,
proshade_double  axErr 
)

This function searches for the highest peaks average that would produce the required axis and fold.

This function starts by finding all self-rotation map points with corresponding axis and recording the angle and map heights of these points. It then sorts these and searches for a combination of fold points separated by the 2pi/fold distance with the highest average map height. In this way, the highest average symmetry height is determined for any axis. This does not, however, check if such symmetry does indeed exist!

Parameters
[in]xValThe x-axis element of the axis to have the height detected.
[in]yValThe y-axis element of the axis to have the height detected.
[in]zValThe z-axis element of the axis to have the height detected.
[in]dataObjThe full data holding object pointer - this is to get access to self-rotation function values.
[in]foldThe fold of the searched for axis.
[in]axErrThe error tolerance on angle matching.
[out]XThe highest height value found for the axis with the given fold.

Definition at line 679 of file ProSHADE_symmetry.cpp.

680 {
681  //================================================ Initialise variables
682  proshade_double ret = 0.0;
683  proshade_double curSum = 0.0;
684  proshade_double maxVal = 0.0;
685  proshade_double angStep = std::acos ( 1.0 - axErr ) / 2;
686  std::vector< proshade_double* > angVec;
687 
688  //================================================ Find map points conforming to the axis
689  angVec = ProSHADE_internal_symmetry::findMissingAxisPoints ( xVal, yVal, zVal, dataObj, axErr );
690 
691  //================================================ Sort points by angle
692  std::sort ( angVec.begin(), angVec.end(), ProSHADE_internal_symmetry::sortArrVecHlp );
693 
694  //================================================ Find the best X peaks with correct distances
695  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( std::floor ( ( 2.0 * M_PI / angStep ) / static_cast< proshade_double > ( fold ) ) ); iter++ )
696  {
697  //============================================ Initialise new ang group iteration
698  curSum = 0.0;
699 
700  //============================================ For each of the fold times
701  for ( proshade_unsign angCmb = 0; angCmb < static_cast<proshade_unsign> ( fold ); angCmb++ )
702  {
703  //======================================== Initialise
704  maxVal = 0.0;
705 
706  //======================================== Search
707  for ( proshade_unsign angIt = 0; angIt < static_cast<proshade_unsign> ( angVec.size() ); angIt++ )
708  {
709  if ( angVec.at(angIt)[0] < ( ( static_cast< proshade_double > ( iter ) * angStep ) +
710  ( ( 2.0 * M_PI / static_cast< proshade_double > ( fold ) ) * static_cast< proshade_double > ( angCmb ) ) ) ) { continue; }
711  if ( angVec.at(angIt)[0] > ( ( ( static_cast< proshade_double > ( iter ) + 1.0 ) * angStep ) +
712  ( ( 2.0 * M_PI / static_cast< proshade_double > ( fold ) ) * static_cast< proshade_double > ( angCmb ) ) ) ) { break; }
713 
714  if ( angVec.at(angIt)[1] > maxVal ) { maxVal = angVec.at(angIt)[1]; }
715  }
716  curSum += maxVal;
717  }
718  curSum /= static_cast<proshade_double> ( fold );
719  if ( ret < curSum ) { ret = curSum; }
720  }
721 
722  //================================================ Release memory
723  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( angVec.size() ); iter++ ) { delete[] angVec.at(iter); }
724 
725  //================================================ Done
726  return ( ret );
727 
728 }

◆ optimiseDGroupAngleFromAxesHeights() [1/2]

void ProSHADE_internal_symmetry::optimiseDGroupAngleFromAxesHeights ( std::vector< std::vector< proshade_double > > *  allCs,
std::vector< proshade_unsign >  selection,
ProSHADE_internal_data::ProSHADE_data dataObj,
ProSHADE_settings settings 
)

This function takes two axes with almost dihedral angle and optimises their relative positions as well as orientation with respect to the optimal angle and the rotation function.

This function is basically a wrapper to the overloaded function with the same name. It starts with converting the axes list and index vector to a single vactor containing the axes in the correct format and then it proceeds to call the overloaded version of this function to do the actual work. Once it completes, this function saves the results into the original input vector and terminates itself.

Parameters
[in]allCsThe list of axes for a subset of which the optimisation is to be done.
[in]selectionA vector of two indices (of the allCs vector) specifying which axes to optimise.
[in]dataObjThe structure object with computed rotation function in which the peaks are to be found.
[in]settingsProSHADE_settings object containing all the settings for this run.

Definition at line 3366 of file ProSHADE_symmetry.cpp.

3367 {
3368  //================================================ Initialise local variables
3369  std::vector < std::vector< proshade_double > > ortPair;
3370  std::vector< proshade_double > hlpVec;
3371 
3372  //================================================ Convert the indices and the list into a single vector containing only the axes to be optimised.
3373  hlpVec.push_back ( allCs->at(selection.at(0))[0] ); hlpVec.push_back ( allCs->at(selection.at(0))[1] ); hlpVec.push_back ( allCs->at(selection.at(0))[2] );
3374  hlpVec.push_back ( allCs->at(selection.at(0))[3] ); hlpVec.push_back ( allCs->at(selection.at(0))[4] ); hlpVec.push_back ( allCs->at(selection.at(0))[5] );
3375  hlpVec.push_back ( allCs->at(selection.at(0))[6] );
3376  ortPair.push_back ( hlpVec ); hlpVec.clear ( );
3377  hlpVec.push_back ( allCs->at(selection.at(1))[0] ); hlpVec.push_back ( allCs->at(selection.at(1))[1] ); hlpVec.push_back ( allCs->at(selection.at(1))[2] );
3378  hlpVec.push_back ( allCs->at(selection.at(1))[3] ); hlpVec.push_back ( allCs->at(selection.at(1))[4] ); hlpVec.push_back ( allCs->at(selection.at(1))[5] );
3379  hlpVec.push_back ( allCs->at(selection.at(1))[6] );
3380  ortPair.push_back ( hlpVec );
3381 
3382  //================================================ Run the optimisation proper
3383  optimiseDGroupAngleFromAxesHeights ( &ortPair, dataObj, settings );
3384 
3385  //================================================ Save the results back to the vector
3386  allCs->at(selection.at(0))[1] = ortPair.at(0).at(1); allCs->at(selection.at(0))[2] = ortPair.at(0).at(2); allCs->at(selection.at(0))[3] = ortPair.at(0).at(3);
3387  allCs->at(selection.at(0))[5] = ortPair.at(0).at(5); allCs->at(selection.at(0))[6] = ortPair.at(0).at(6);
3388 
3389  allCs->at(selection.at(1))[1] = ortPair.at(1).at(1); allCs->at(selection.at(1))[2] = ortPair.at(1).at(2); allCs->at(selection.at(1))[3] = ortPair.at(1).at(3);
3390  allCs->at(selection.at(1))[5] = ortPair.at(1).at(5); allCs->at(selection.at(1))[6] = ortPair.at(1).at(6);
3391 
3392  //================================================ Done
3393  return ;
3394 
3395 }

◆ optimiseDGroupAngleFromAxesHeights() [2/2]

void ProSHADE_internal_symmetry::optimiseDGroupAngleFromAxesHeights ( std::vector< std::vector< proshade_double > > *  ret,
ProSHADE_internal_data::ProSHADE_data dataObj,
ProSHADE_settings settings 
)

This function takes two axes with almost dihedral angle and optimises their relative positions as well as orientation with respect to the optimal angle and the rotation function.

This function has two parts. Firstly, it makes the assumption that the two axes supplied are almost perpendicular, but that there may be an error. To correct for this, the function will find the vector perpendicular to the plane formed by the two supplied axes and then it will find a vector perpendicular to the plane between this new vector and the axis with higher rotation function value. The resulting new vector is perpendicular to the axis with higher rotation function value and replaces the axis vector with the lower rotation function values (after normalisation).

Secondly, this function supplies the two axes to the findPredictedAxesHeights() function, which does the maximisation of the rotation function values for both supplied axes at the same time. The resulting optimised axes are then returned in place of the inputted axes.

Parameters
[in]retThe list of axes for which the optimisation is to be done.
[in]dataObjThe structure object with computed rotation function in which the peaks are to be found.
[in]settingsProSHADE_settings object containing all the settings for this run.

Definition at line 3269 of file ProSHADE_symmetry.cpp.

3270 {
3271  //================================================ Sanity check
3272  if ( ret->size() != 2 )
3273  {
3274  throw ProSHADE_exception ( "Attempted to optimise less than two axes for dihedral\n : group.", "ES00070", __FILE__, __LINE__, __func__, "The function for optimisation of dihedral angle of D\n : group was called on group with less than two axes. This\n : seems like a programming bug and should not happen - \n : contact author if you ever see this." );
3275  }
3276 
3277  //================================================ Set the angle to the correct dihedral group position - i.e. 90 deg
3278  proshade_double *crossProd, *perpVec, normFactor;
3279  size_t higherRFIndex = 0;
3280 
3281  //================================================ Find vector perperndicular to the plane given by the two axes
3282  crossProd = ProSHADE_internal_maths::computeCrossProduct ( &ret->at(0).at(1), &ret->at(0).at(2), &ret->at(0).at(3), &ret->at(1).at(1), &ret->at(1).at(2), &ret->at(1).at(3) );
3283 
3284  //================================================ Find a vector perpendicular to the plane between the new vector and the vector with higher rotation function value
3285  if ( ret->at(1).at(5) > ret->at(0).at(5) ) { higherRFIndex = 1; }
3286  perpVec = ProSHADE_internal_maths::computeCrossProduct ( &ret->at(higherRFIndex).at(1), &ret->at(higherRFIndex).at(2), &ret->at(higherRFIndex).at(3), &crossProd[0], &crossProd[1], &crossProd[2] );
3287 
3288  //================================================ Normalise the new vector
3289  normFactor = std::sqrt ( pow ( perpVec[0], 2.0 ) + pow ( perpVec[1], 2.0 ) + pow ( perpVec[2], 2.0 ) );
3290  perpVec[0] /= normFactor; perpVec[1] /= normFactor; perpVec[2] /= normFactor;
3291 
3292  //================================================ Set largest axis element to positive
3293  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( perpVec[0] ), std::max( std::abs ( perpVec[1] ), std::abs ( perpVec[2] ) ) ) );
3294  const FloatingPoint< proshade_double > rhs1 ( std::abs ( perpVec[0] ));
3295  const FloatingPoint< proshade_double > rhs2 ( std::abs ( perpVec[1] ) );
3296  const FloatingPoint< proshade_double > rhs3 ( std::abs ( perpVec[2] ) );
3297  if ( ( lhs1.AlmostEquals ( rhs1 ) && ( perpVec[0] < 0.0 ) ) ||
3298  ( lhs1.AlmostEquals ( rhs2 ) && ( perpVec[1] < 0.0 ) ) ||
3299  ( lhs1.AlmostEquals ( rhs3 ) && ( perpVec[2] < 0.0 ) ) )
3300  {
3301  perpVec[0] *= -1.0;
3302  perpVec[1] *= -1.0;
3303  perpVec[2] *= -1.0;
3304  }
3305 
3306  //================================================ Which vector are we to over-write?
3307  if ( higherRFIndex == 0 ) { higherRFIndex = 1; }
3308  else { higherRFIndex = 0; }
3309 
3310  //================================================ Over-write the old vector with the better one
3311  ret->at(higherRFIndex).at(1) = perpVec[0]; ret->at(higherRFIndex).at(2) = perpVec[1]; ret->at(higherRFIndex).at(3) = perpVec[2];
3312 
3313  //================================================ Release memory
3314  delete[] perpVec;
3315  delete[] crossProd;
3316 
3317  //================================================ Convert input to pointers
3318  std::vector< proshade_double* > convVec;
3319  for ( size_t axIt = 0; axIt < 2; axIt++ )
3320  {
3321  //============================================ Allocate memory
3322  proshade_double* axVals = new proshade_double[7];
3323  ProSHADE_internal_misc::checkMemoryAllocation ( axVals, __FILE__, __LINE__, __func__ );
3324 
3325  //============================================ Copy values
3326  for ( size_t elIt = 0; elIt < 7; elIt++ )
3327  {
3328  axVals[elIt] = ret->at(axIt).at(elIt);
3329  }
3330 
3331  //============================================ Save
3332  convVec.push_back ( axVals );
3333  }
3334 
3335  //================================================ Run normal optimisation
3336  ProSHADE_internal_symmetry::findPredictedAxesHeights ( &convVec, dataObj, settings );
3337 
3338  //================================================ Convert back and release memory
3339  for ( size_t axIt = 0; axIt < 2; axIt++ )
3340  {
3341  //============================================ Copy values
3342  for ( size_t elIt = 0; elIt < 7; elIt++ )
3343  {
3344  ret->at(axIt).at(elIt) = convVec.at(axIt)[elIt];
3345  }
3346 
3347  //============================================ Release memory
3348  delete[] convVec.at(axIt);
3349  }
3350 
3351  //================================================ Done
3352  return ;
3353 
3354 }

◆ predictIcosAxes()

void ProSHADE_internal_symmetry::predictIcosAxes ( std::vector< proshade_double * > *  CSymList,
std::vector< std::vector< proshade_double * > > *  ret,
proshade_double  axErr,
proshade_double  minPeakHeight 
)

This function predicts all possible icosahedral point groups symmetry axes from the cyclic point groups list.

This function starts by finding the rotation matrix corresponding to the angle between the predicted C5 axis and the C5 axis found in the pre-computed Icosahedron model available in the ProSHADE_precomputedValues file. It then proceeds to use this rotation matrix to rotate the pre-computed model C3 axis to now be in the correct orientation to the detected C5 axis.

Next, the function computes the rotation matrix corresponding to rotation along the detected C5 axis about the angle between the rotated pre-computed model C3 axis and the detected C3 axis. Finally, when these two rotation matrices are combined, the resulting rotation matrix is the optimal match rotation between the pre-computed model and the detected axes positions. This final rotation matrix is then used to rotate the model axes and these rotated model axes are then the predicted axes in the structre.

Please note that the peak heights are set to 0.0 for all predicted axes, as they were not detected in the structure, but were only predicted.

Warning
This function assumes that the detectIcosahedralSymmetry() function has successfully run (i.e. returned true).
Parameters
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]retThe vector containing all the axes forming icosahedral group or empty vector.
[in]axErrThe error tolerance on angle matching.
[in]minPeakHeightThe minimum average peak height for axis to be considered.

Definition at line 2034 of file ProSHADE_symmetry.cpp.

2035 {
2036  //================================================ Find the best axis combination with dihedral angle and correct folds
2037  std::vector < std::pair< proshade_unsign, proshade_unsign > > initAxes = findBestIcosDihedralPair ( CSymList, minPeakHeight, axErr );
2038 
2039  //================================================ For each pair of possible axis combinations
2040  for ( size_t pIt = 0; pIt < initAxes.size(); pIt++ )
2041  {
2042  //============================================ Create the tetrahedronAxes object
2044 
2045  //============================================ Find rotation between the detected C5 and the model C5 axes.
2046  proshade_double* rotMat = ProSHADE_internal_maths::findRotMatMatchingVectors ( icoAx->getValue ( 0, 1 ),
2047  icoAx->getValue ( 0, 2 ),
2048  icoAx->getValue ( 0, 3 ),
2049  CSymList->at(initAxes.at(pIt).first)[1],
2050  CSymList->at(initAxes.at(pIt).first)[2],
2051  CSymList->at(initAxes.at(pIt).first)[3] );
2052 
2053  //============================================ Rotate the model C3 to the correct orientation relative to the detected C5 axis.
2054  proshade_double* rotModelC3 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMat,
2055  icoAx->getValue ( 6, 1 ),
2056  icoAx->getValue ( 6, 2 ),
2057  icoAx->getValue ( 6, 3 ) );
2058 
2059  //============================================ Find the angle betwen the rotated model C3 and the detected C3 axes along the detected C5 axis.
2060  proshade_double bestAng = 0.0, curAngDist, bestAngDist = 999.9;
2061  proshade_double* rotMatHlp = new proshade_double[9];
2062  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatHlp, __FILE__, __LINE__, __func__ );
2063  for ( proshade_double ang = 0.0; ang < ( M_PI * 2.0 ); ang += 0.002 )
2064  {
2065  //============================================ Compute rotation matrix for this angle value
2066  ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( rotMatHlp, CSymList->at(initAxes.at(pIt).first)[1], CSymList->at(initAxes.at(pIt).first)[2], CSymList->at(initAxes.at(pIt).first)[3], ang );
2067 
2068  //======================================== Rotate the rotated C2 by the matrix
2069  proshade_double* rotRotModelC3 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatHlp,
2070  rotModelC3[0],
2071  rotModelC3[1],
2072  rotModelC3[2] );
2073 
2074  //======================================== Find distance
2075  curAngDist = std::sqrt ( std::pow ( rotRotModelC3[0] - CSymList->at(initAxes.at(pIt).second)[1], 2.0 ) +
2076  std::pow ( rotRotModelC3[1] - CSymList->at(initAxes.at(pIt).second)[2], 2.0 ) +
2077  std::pow ( rotRotModelC3[2] - CSymList->at(initAxes.at(pIt).second)[3], 2.0 ) );
2078 
2079  //======================================== Save best angle
2080  if ( curAngDist < bestAngDist ) { bestAngDist = curAngDist; bestAng = ang; }
2081 
2082  //======================================== Release memory
2083  delete[] rotRotModelC3;
2084  }
2085 
2086  //============================================ Release memory
2087  delete[] rotMatHlp;
2088 
2089  //============================================ For the rotation matrix along the detected C5 axis with the same angle as is between the rotated model C3 and the detected C3 axes.
2090  proshade_double* rotMat2 = new proshade_double[9];
2091  ProSHADE_internal_misc::checkMemoryAllocation ( rotMat2, __FILE__, __LINE__, __func__ );
2092  ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( rotMat2, CSymList->at(initAxes.at(pIt).first)[1], CSymList->at(initAxes.at(pIt).first)[2], CSymList->at(initAxes.at(pIt).first)[3], bestAng );
2093 
2094  //============================================ Combine the two rotation matrices into a single rotation matrix
2095  proshade_double* rotMatFin = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( rotMat2, rotMat );
2096 
2097  //============================================ For each model axis
2098  std::vector< proshade_double* > hlpAxes;
2099  for ( proshade_unsign iter = 0; iter < icoAx->getNoAxes ( ); iter++ )
2100  {
2101  //======================================== Rotate the model axis to fit the detected orientation
2102  proshade_double* rotAxis = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatFin,
2103  icoAx->getValue ( iter, 1 ),
2104  icoAx->getValue ( iter, 2 ),
2105  icoAx->getValue ( iter, 3 ) );
2106 
2107  //======================================== Create ProSHADE symmetry axis representation
2108  proshade_double* axis = new proshade_double[7];
2109  ProSHADE_internal_misc::checkMemoryAllocation ( axis, __FILE__, __LINE__, __func__ );
2110 
2111  axis[0] = icoAx->getValue ( iter, 0 );
2112  axis[1] = rotAxis[0];
2113  axis[2] = rotAxis[1];
2114  axis[3] = rotAxis[2];
2115  axis[4] = ( 2.0 * M_PI ) / axis[0];
2116  axis[5] = 0.0;
2117  axis[6] = -std::numeric_limits < proshade_double >::infinity();
2118 
2119  //======================================== Save axis to ret
2121 
2122  //======================================== Release memory
2123  delete[] rotAxis;
2124  delete[] axis;
2125  }
2126 
2127  //============================================ Save to ret
2128  ret->emplace_back ( hlpAxes );
2129 
2130  //============================================ Release memory
2131  delete[] rotMat;
2132  delete[] rotMat2;
2133  delete[] rotMatFin;
2134  delete[] rotModelC3;
2135  delete icoAx;
2136  }
2137 
2138  //================================================ Done
2139  return ;
2140 
2141 }

◆ predictOctaAxes()

void ProSHADE_internal_symmetry::predictOctaAxes ( std::vector< proshade_double * > *  CSymList,
std::vector< std::vector< proshade_double * > > *  ret,
proshade_double  axErr,
proshade_double  minPeakHeight 
)

This function predicts all octahedral point group symmetry axes from the cyclic point groups list.

This function starts by finding the rotation matrix corresponding to the angle between the predicted C4 axis and the C4 axis found in the pre-computed octahedron model available in the ProSHADE_precomputedValues file. It then proceeds to use this rotation matrix to rotate the pre-computed model C3 axis to now be in the correct orientation to the detected C4 axis.

Next, the function computes the rotation matrix corresponding to rotation along the detected C4 axis about the angle between the rotated pre-computed model C3 axis and the detected C3 axis. Finally, when these two rotation matrices are combined, the resulting rotation matrix is the optimal match rotation between the pre-computed model and the detected axes positions. This final rotation matrix is then used to rotate the model axes and these rotated model axes are then the predicted axes in the structre.

Please note that the peak heights are set to 0.0 for all predicted axes, as they were not detected in the structure, but were only predicted.

Warning
This function assumes that the detectIcosahedralSymmetry() function has successfully run (i.e. returned true).
Parameters
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]retThe vector containing all the axes forming icosahedral group or empty vector.
[in]axErrThe error tolerance on angle matching.
[in]minPeakHeightThe minimum average peak height for axis to be considered.

Definition at line 2214 of file ProSHADE_symmetry.cpp.

2215 {
2216  //================================================ Find the best axis combination with dihedral angle and correct folds
2217  std::vector < std::pair< proshade_unsign, proshade_unsign > > initAxes = findBestOctaDihedralPair ( CSymList, minPeakHeight, axErr );
2218 
2219  //================================================ For each pair of possible axis combinations
2220  for ( size_t pIt = 0; pIt < initAxes.size(); pIt++ )
2221  {
2222  //============================================ Create the tetrahedronAxes object
2224 
2225  //============================================ Find rotation between the detected C4 and the model C4 axes.
2226  proshade_double* rotMat = ProSHADE_internal_maths::findRotMatMatchingVectors ( octAx->getValue ( 0, 1 ),
2227  octAx->getValue ( 0, 2 ),
2228  octAx->getValue ( 0, 3 ),
2229  CSymList->at(initAxes.at(pIt).first)[1],
2230  CSymList->at(initAxes.at(pIt).first)[2],
2231  CSymList->at(initAxes.at(pIt).first)[3] );
2232 
2233  //============================================ Rotate the model C3 to the correct orientation relative to the detected C4 axis.
2234  proshade_double* rotModelC3 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMat,
2235  octAx->getValue ( 3, 1 ),
2236  octAx->getValue ( 3, 2 ),
2237  octAx->getValue ( 3, 3 ) );
2238 
2239  //============================================ Find the angle betwen the rotated model C3 and the detected C3 axes along the detected C4 axis.
2240  proshade_double bestAng = 0.0, curAngDist, bestAngDist = 999.9;
2241  proshade_double* rotMatHlp = new proshade_double[9];
2242  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatHlp, __FILE__, __LINE__, __func__ );
2243  for ( proshade_double ang = 0.0; ang < ( M_PI * 2.0 ); ang += 0.002 )
2244  {
2245  //======================================== Compute rotation matrix for this angle value
2246  ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( rotMatHlp, CSymList->at(initAxes.at(pIt).first)[1], CSymList->at(initAxes.at(pIt).first)[2], CSymList->at(initAxes.at(pIt).first)[3], ang );
2247 
2248  //======================================== Rotate the rotated C2 by the matrix
2249  proshade_double* rotRotModelC3 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatHlp,
2250  rotModelC3[0],
2251  rotModelC3[1],
2252  rotModelC3[2] );
2253 
2254  //======================================== Find distance
2255  curAngDist = std::sqrt ( std::pow ( rotRotModelC3[0] - CSymList->at(initAxes.at(pIt).second)[1], 2.0 ) +
2256  std::pow ( rotRotModelC3[1] - CSymList->at(initAxes.at(pIt).second)[2], 2.0 ) +
2257  std::pow ( rotRotModelC3[2] - CSymList->at(initAxes.at(pIt).second)[3], 2.0 ) );
2258 
2259  //======================================== Save best angle
2260  if ( curAngDist < bestAngDist ) { bestAngDist = curAngDist; bestAng = ang; }
2261 
2262  //======================================== Release memory
2263  delete[] rotRotModelC3;
2264  }
2265 
2266  //============================================ Release memory
2267  delete[] rotMatHlp;
2268 
2269  //============================================ For the rotation matrix along the detected C5 axis with the same anlge as is between the rotated model C3 and the detected C3 axes.
2270  proshade_double* rotMat2 = new proshade_double[9];
2271  ProSHADE_internal_misc::checkMemoryAllocation ( rotMat2, __FILE__, __LINE__, __func__ );
2272  ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( rotMat2, CSymList->at(initAxes.at(pIt).first)[1], CSymList->at(initAxes.at(pIt).first)[2], CSymList->at(initAxes.at(pIt).first)[3], bestAng );
2273 
2274  //============================================ Combine the two rotation matrices into a single rotation matrix
2275  proshade_double* rotMatFin = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( rotMat2, rotMat );
2276 
2277  //================================================ For each model axis
2278  std::vector< proshade_double* > hlpAxes;
2279  for ( proshade_unsign iter = 0; iter < octAx->getNoAxes ( ); iter++ )
2280  {
2281  //======================================== Rotate the model axis to fit the detected orientation
2282  proshade_double* rotAxis = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatFin,
2283  octAx->getValue ( iter, 1 ),
2284  octAx->getValue ( iter, 2 ),
2285  octAx->getValue ( iter, 3 ) );
2286 
2287  //============================================ Create ProSHADE symmetry axis representation
2288  proshade_double* axis = new proshade_double[7];
2289  ProSHADE_internal_misc::checkMemoryAllocation ( axis, __FILE__, __LINE__, __func__ );
2290 
2291  axis[0] = octAx->getValue ( iter, 0 );
2292  axis[1] = rotAxis[0];
2293  axis[2] = rotAxis[1];
2294  axis[3] = rotAxis[2];
2295  axis[4] = ( 2.0 * M_PI ) / axis[0];
2296  axis[5] = 0.0;
2297  axis[6] = -std::numeric_limits < proshade_double >::infinity();
2298 
2299  //======================================== Save axis to ret
2301 
2302  //======================================== Release memory
2303  delete[] rotAxis;
2304  delete[] axis;
2305  }
2306 
2307  //============================================ Save to ret
2308  ret->emplace_back ( hlpAxes );
2309 
2310  //================================================ Release memory
2311  delete[] rotMat;
2312  delete[] rotMat2;
2313  delete[] rotMatFin;
2314  delete[] rotModelC3;
2315  delete octAx;
2316  }
2317 
2318  //================================================ Done
2319  return ;
2320 
2321 }

◆ predictTetraAxes()

void ProSHADE_internal_symmetry::predictTetraAxes ( std::vector< proshade_double * > *  CSymList,
std::vector< std::vector< proshade_double * > > *  ret,
proshade_double  axErr,
proshade_double  minPeakHeight 
)

This function predicts all tetrahedral point group symmetry axes from the cyclic point groups list.

This function starts by finding the rotation matrix corresponding to the angle between the predicted C3 axis and the C3 axis found in the pre-computed tetrahedron model available in the ProSHADE_precomputedValues file. It then proceeds to use this rotation matrix to rotate the pre-computed model C2 axis to now be in the correct orientation to the detected C3 axis.

Next, the function computes the rotation matrix corresponding to rotation along the detected C3 axis about the angle between the rotated pre-computed model C2axis and the detected C2 axis. Finally, when these two rotation matrices are combined, the resulting rotation matrix is the optimal match rotation between the pre-computed model and the detected axes positions. This final rotation matrix is then used to rotate the model axes and these rotated model axes are then the predicted axes in the structre.

Please note that the peak heights are set to 0.0 for all predicted axes, as they were not detected in the structure, but were only predicted.

Warning
This function assumes that the detectIcosahedralSymmetry() function has successfully run (i.e. returned true).
Parameters
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]retThe vector containing all the axes forming icosahedral group or empty vector.
[in]axErrThe error tolerance on angle matching.
[in]minPeakHeightThe minimum average peak height for axis to be considered.

Definition at line 3609 of file ProSHADE_symmetry.cpp.

3610 {
3611  //================================================ Find the best axis combination with dihedral angle and correct folds
3612  std::vector< std::pair< proshade_unsign, proshade_unsign > > initAxes = findBestTetraDihedralPair ( CSymList, minPeakHeight, axErr );
3613 
3614  //================================================ For each pair of possible axis combinations
3615  for ( size_t pIt = 0; pIt < initAxes.size(); pIt++ )
3616  {
3617  //============================================ Create the tetrahedronAxes object
3619 
3620  //============================================ Find rotation between the detected C3 and the model C3 axes.
3621  proshade_double* rotMat = ProSHADE_internal_maths::findRotMatMatchingVectors ( tetAx->getValue ( 0, 1 ),
3622  tetAx->getValue ( 0, 2 ),
3623  tetAx->getValue ( 0, 3 ),
3624  CSymList->at(initAxes.at(pIt).first)[1],
3625  CSymList->at(initAxes.at(pIt).first)[2],
3626  CSymList->at(initAxes.at(pIt).first)[3] );
3627 
3628  //============================================ Rotate the model C2 to the correct orientation relative to the detected C3 axis.
3629  proshade_double* rotModelC2 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMat,
3630  tetAx->getValue ( 4, 1 ),
3631  tetAx->getValue ( 4, 2 ),
3632  tetAx->getValue ( 4, 3 ) );
3633 
3634  //============================================ Find the angle betwen the rotated model C2 and the detected C2 axes along the detected C3 axis.
3635  proshade_double bestAng = 0.0, curAngDist, bestAngDist = 999.9;
3636  proshade_double* rotMatHlp = new proshade_double[9];
3637  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatHlp, __FILE__, __LINE__, __func__ );
3638  for ( proshade_double ang = 0.0; ang < ( M_PI * 2.0 ); ang += 0.002 )
3639  {
3640  //======================================== Compute rotation matrix for this angle value
3641  ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( rotMatHlp, CSymList->at(initAxes.at(pIt).first)[1], CSymList->at(initAxes.at(pIt).first)[2], CSymList->at(initAxes.at(pIt).first)[3], ang );
3642 
3643  //======================================== Rotate the rotated C2 by the matrix
3644  proshade_double* rotRotModelC2 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatHlp,
3645  rotModelC2[0],
3646  rotModelC2[1],
3647  rotModelC2[2] );
3648 
3649  //======================================== Find distance
3650  curAngDist = std::sqrt ( std::pow ( rotRotModelC2[0] - CSymList->at(initAxes.at(pIt).second)[1], 2.0 ) +
3651  std::pow ( rotRotModelC2[1] - CSymList->at(initAxes.at(pIt).second)[2], 2.0 ) +
3652  std::pow ( rotRotModelC2[2] - CSymList->at(initAxes.at(pIt).second)[3], 2.0 ) );
3653 
3654  //======================================== Save best angle
3655  if ( curAngDist < bestAngDist ) { bestAngDist = curAngDist; bestAng = ang; }
3656 
3657  //======================================== Release memory
3658  delete[] rotRotModelC2;
3659  }
3660 
3661  //============================================ Release memory
3662  delete[] rotMatHlp;
3663 
3664  //============================================ For the rotation matrix along the detected C5 axis with the same anlge as is between the rotated model C3 and the detected C3 axes.
3665  proshade_double* rotMat2 = new proshade_double[9];
3666  ProSHADE_internal_misc::checkMemoryAllocation ( rotMat2, __FILE__, __LINE__, __func__ );
3667  ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( rotMat2, CSymList->at(initAxes.at(pIt).first)[1], CSymList->at(initAxes.at(pIt).first)[2], CSymList->at(initAxes.at(pIt).first)[3], bestAng );
3668 
3669  //============================================ Combine the two rotation matrices into a single rotation matrix
3670  proshade_double* rotMatFin = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( rotMat2, rotMat );
3671 
3672  //================================================ For each model axis
3673  std::vector< proshade_double* > hlpAxes;
3674  for ( proshade_unsign iter = 0; iter < tetAx->getNoAxes( ); iter++ )
3675  {
3676  //============================================ Rotate the model axis to fit the detected orientation
3677  proshade_double* rotAxis = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatFin,
3678  tetAx->getValue ( iter, 1 ),
3679  tetAx->getValue ( iter, 2 ),
3680  tetAx->getValue ( iter, 3 ) );
3681 
3682  //======================================== Create ProSHADE symmetry axis representation
3683  proshade_double* axis = new proshade_double[7];
3684  ProSHADE_internal_misc::checkMemoryAllocation ( axis, __FILE__, __LINE__, __func__ );
3685 
3686  axis[0] = tetAx->getValue ( iter, 0 );
3687  axis[1] = rotAxis[0];
3688  axis[2] = rotAxis[1];
3689  axis[3] = rotAxis[2];
3690  axis[4] = ( 2.0 * M_PI ) / axis[0];
3691  axis[5] = 0.0;
3692  axis[6] = -std::numeric_limits < proshade_double >::infinity();
3693 
3694  //======================================== Save axis to ret
3696 
3697  //======================================== Release memory
3698  delete[] rotAxis;
3699  delete[] axis;
3700  }
3701 
3702  //============================================ Save to ret
3703  ret->emplace_back ( hlpAxes );
3704 
3705  //============================================ Release memory
3706  delete[] rotMat;
3707  delete[] rotMat2;
3708  delete[] rotMatFin;
3709  delete[] rotModelC2;
3710  delete tetAx;
3711  }
3712 
3713  //================================================ Done
3714  return ;
3715 
3716 }

◆ releaseCentreOfMapFourierTransforms()

void ProSHADE_internal_symmetry::releaseCentreOfMapFourierTransforms ( fftw_complex *  origMap,
fftw_complex *  origCoeffs,
fftw_complex *  rotMapComplex,
fftw_complex *  rotCoeffs,
fftw_complex *  trFunc,
fftw_complex *  trFuncCoeffs,
fftw_plan  planForwardFourier,
fftw_plan  planForwardFourierRot,
fftw_plan  planReverseFourierComb 
)

This function releases the allocated memory for the Fourier transforms used to find the centre of the map.

Parameters
[in]origMapArray to which the original map will be saved before Fourier transform computation.
[in]origCoeffsArray to which the result of the Fourier transform of the original map will be saved into.
[in]rotMapComplexArray to which the rotated map will be saved before Fourier transform computation.
[in]rotCoeffsArray to which the result of the Fourier transform of the rotated map will be saved into.
[in]trFuncArray to which the results of inverse Fourier transform of the conbined coefficients will be saved.
[in]trFuncCoeffsArray to which the two maps coefficients will be combined into before inverse Fourier transform computation.
[in]planForwardFourierFFTW3 plan for the original map Fourier transform.
[in]planForwardFourierRotFFTW3 plat for the rotated map Fourier transform.
[in]planReverseFourierCombFFTW3 plan for the inverse Fourier transform from the combined coefficients to translation function.

Definition at line 3881 of file ProSHADE_symmetry.cpp.

3882 {
3883  //================================================ Destroy the FFTW3 plans
3884  fftw_destroy_plan ( planReverseFourierComb );
3885  fftw_destroy_plan ( planForwardFourier );
3886  fftw_destroy_plan ( planForwardFourierRot );
3887 
3888  //================================================ Set pointers to NULL
3889  planReverseFourierComb = nullptr;
3890  planForwardFourier = nullptr;
3891  planForwardFourierRot = nullptr;
3892 
3893  //================================================ Release the memory
3894  fftw_free ( origMap );
3895  fftw_free ( origCoeffs );
3896  fftw_free ( rotMapComplex );
3897  fftw_free ( rotCoeffs );
3898  fftw_free ( trFunc );
3899  fftw_free ( trFuncCoeffs );
3900 
3901  //================================================ Done
3902  return ;
3903 
3904 }

◆ saveMissingAxisNewOnly()

void ProSHADE_internal_symmetry::saveMissingAxisNewOnly ( std::vector< proshade_double * > *  axVec,
proshade_double  axX,
proshade_double  axY,
proshade_double  axZ,
proshade_double  height,
proshade_unsign  fold,
proshade_double  axErr 
)

This function saves the recovered information about missing axis into a full symmetry, making sure no duplicates are created.

This function takes the information about the missing symmetry and proceeds to create a full symmetry description out of it. It then checks whether the vector already contains similar symmetry, either replacing the old or ignoring the new symmetry based on which has hiher height. If the symmetry does not match anything in the vector, it will be copied as a new vector entry.

Parameters
[in]axVecVector containing all already detected missing axes.
[in]axXThe x-axis element of the missing axis.
[in]axYThe y-axis element of the missing axis.
[in]axZThe z-axis element of the missing axis.
[in]heightThe average map height for this new axis.
[in]foldThe fold of the searched for axis.
[in]axErrThe error tolerance on angle matching.

Definition at line 821 of file ProSHADE_symmetry.cpp.

822 {
823  //================================================ Create symmetry array from the inputs
824  proshade_double* hlpSym = new proshade_double [6];
825  ProSHADE_internal_misc::checkMemoryAllocation ( hlpSym, __FILE__, __LINE__, __func__ );
826 
827  //================================================ Fill it in
828  hlpSym[0] = static_cast<proshade_double> ( fold );
829  hlpSym[1] = axX;
830  hlpSym[2] = axY;
831  hlpSym[3] = axZ;
832  hlpSym[4] = ( 2.0 * M_PI ) / static_cast<proshade_double> ( fold );
833  hlpSym[5] = height;
834 
835  //================================================ Check if similar symmetry does not exist already
836  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( axVec->size() ); symIt++ )
837  {
838  //============================================ Minor speed-up => only test for same folds
839  const FloatingPoint< proshade_double > lhs1 ( axVec->at(symIt)[0] ), rhs1 ( hlpSym[0] );
840  if ( lhs1.AlmostEquals ( rhs1 ) )
841  {
842  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( axVec->at(symIt)[1],
843  axVec->at(symIt)[2],
844  axVec->at(symIt)[3],
845  hlpSym[1],
846  hlpSym[2],
847  hlpSym[3],
848  axErr ) )
849  {
850  //==================================== Almost identical entry
851  if ( axVec->at(symIt)[5] < hlpSym[5] )
852  {
853  //================================ If higher, save
854  delete[] axVec->at(symIt);
855  axVec->at(symIt) = hlpSym;
856  return ;
857  }
858  else
859  {
860  //================================ or just terminate if better is already saved
861  delete[] hlpSym;
862  return ;
863  }
864  }
865  }
866  }
867 
868  //================================================ Not matched to anything
870 
871  //================================================ Done
872  return ;
873 
874 }

◆ searchMissingSymmetrySpace()

void ProSHADE_internal_symmetry::searchMissingSymmetrySpace ( ProSHADE_internal_data::ProSHADE_data dataObj,
std::vector< proshade_double * > *  CSymList,
std::vector< proshade_unsign > *  grp,
std::vector< proshade_double * > *  hlpVec,
proshade_double  axErr,
proshade_double  angle,
proshade_unsign  fold,
proshade_double  minPeakHeight 
)

This function tests feasible axes against the missing axis criteria, returning a set of matching axes.

This function does the real missing axis searching. It starts by taking all supplied axes and algebraically computing the vector which has the required angle to two of the supplied axes. This computed axis is then tested against the group for being unique and having an average height at least as high as required. If such axis is found, it is added to the axes list.

Parameters
[in]dataObjThe full data holding object pointer - this is to get access to self-rotation function values.
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]grpA vector of indices (relating to CSymList) of the group members.
[in]hlpVecA vector which will hold the detected, but not verified axes to be returned to the caller function.
[in]axErrThe error tolerance on angle matching.
[in]angleThe angle that each group member is required to have against the symmetry.
[in]foldThe fold of the searched for axis.
[in]minPeakHeightThe minimum new axis average peak height in order for the axis to be added.

Definition at line 890 of file ProSHADE_symmetry.cpp.

891 {
892  //================================================ Sanity check
893  if ( grp->size() < 2 ) { return; }
894 
895  //================================================ Initialise variables
896  proshade_double axHeight = 0.0;
897  proshade_double* symHlp = new proshade_double[7];
898  ProSHADE_internal_misc::checkMemoryAllocation ( symHlp, __FILE__, __LINE__, __func__ );
899 
900  //================================================ For each axis pair in the group, find the possible solutions
901  for ( proshade_unsign fAx = 0; fAx < static_cast<proshade_unsign> ( grp->size() ); fAx++ )
902  {
903  for ( proshade_unsign sAx = 1; sAx < static_cast<proshade_unsign> ( grp->size() ); sAx++ )
904  {
905  //======================================== Only unique pairs
906  if ( fAx >= sAx ) { continue; }
907 
908  //======================================== Find possible axis having the required angle to this pair ( solution 1 )
909  std::vector< proshade_double > solVec = ProSHADE_internal_maths::findVectorFromTwoVAndTwoD ( CSymList->at(grp->at(fAx))[1],
910  CSymList->at(grp->at(fAx))[2],
911  CSymList->at(grp->at(fAx))[3],
912  CSymList->at(grp->at(sAx))[1],
913  CSymList->at(grp->at(sAx))[2],
914  CSymList->at(grp->at(sAx))[3], angle, angle );
915 
916  //======================================== Set largest axis element to positive
917  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( solVec.at(0) ), std::max( std::abs ( solVec.at(1) ), std::abs ( solVec.at(2) ) ) ) );
918  const FloatingPoint< proshade_double > rhs1 ( std::abs ( solVec.at(0) ) );
919  const FloatingPoint< proshade_double > rhs2 ( std::abs ( solVec.at(1) ) );
920  const FloatingPoint< proshade_double > rhs3 ( std::abs ( solVec.at(2) ) );
921  if ( ( lhs1.AlmostEquals ( rhs1 ) && ( solVec.at(0) < 0.0 ) ) ||
922  ( lhs1.AlmostEquals ( rhs2 ) && ( solVec.at(1) < 0.0 ) ) ||
923  ( lhs1.AlmostEquals ( rhs3 ) && ( solVec.at(2) < 0.0 ) ) )
924  {
925  solVec.at(0) *= -1.0;
926  solVec.at(1) *= -1.0;
927  solVec.at(2) *= -1.0;
928  }
929 
930  //======================================== Does the solution fit the whole group?
931  symHlp[1] = solVec.at(0); symHlp[2] = solVec.at(1); symHlp[3] = solVec.at(2); symHlp[6] = -std::numeric_limits < proshade_double >::infinity();
932  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, grp, symHlp, axErr, angle, true ) )
933  {
934  //==================================== Find the height for the axis
935  axHeight = ProSHADE_internal_symmetry::missingAxisHeight ( solVec.at(0), solVec.at(1), solVec.at(2), dataObj, fold, axErr );
936 
937  //================================ Save max height result
938  if ( axHeight >= minPeakHeight ) { ProSHADE_internal_symmetry::saveMissingAxisNewOnly ( hlpVec, solVec.at(0), solVec.at(1), solVec.at(2), axHeight, fold, axErr ); }
939  }
940 
941  //======================================== Find possible axis having the required angle to this pair ( solution 2 )
942  solVec = ProSHADE_internal_maths::findVectorFromTwoVAndTwoD ( CSymList->at(grp->at(fAx))[1],
943  CSymList->at(grp->at(fAx))[2],
944  CSymList->at(grp->at(fAx))[3],
945  CSymList->at(grp->at(sAx))[1],
946  CSymList->at(grp->at(sAx))[2],
947  CSymList->at(grp->at(sAx))[3], -angle, -angle );
948 
949  //======================================== Set largest axis element to positive
950  const FloatingPoint< proshade_double > lhs2 ( std::max ( std::abs ( solVec.at(0) ), std::max( std::abs ( solVec.at(1) ), std::abs ( solVec.at(2) ) ) ) );
951  const FloatingPoint< proshade_double > rhs4 ( std::abs ( solVec.at(0) ) );
952  const FloatingPoint< proshade_double > rhs5 ( std::abs ( solVec.at(1) ) );
953  const FloatingPoint< proshade_double > rhs6 ( std::abs ( solVec.at(2) ) );
954  if ( ( lhs2.AlmostEquals ( rhs4 ) && ( solVec.at(0) < 0.0 ) ) ||
955  ( lhs2.AlmostEquals ( rhs5 ) && ( solVec.at(1) < 0.0 ) ) ||
956  ( lhs2.AlmostEquals ( rhs6 ) && ( solVec.at(2) < 0.0 ) ) )
957  {
958  solVec.at(0) *= -1.0;
959  solVec.at(1) *= -1.0;
960  solVec.at(2) *= -1.0;
961  }
962 
963  //======================================== Does the solution fit the whole group?
964  symHlp[1] = solVec.at(0); symHlp[2] = solVec.at(1); symHlp[3] = solVec.at(2); symHlp[6] = -std::numeric_limits < proshade_double >::infinity();
965  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, grp, symHlp, axErr, angle, true ) )
966  {
967  //==================================== Find the height for the axis
968  axHeight = ProSHADE_internal_symmetry::missingAxisHeight ( solVec.at(0), solVec.at(1), solVec.at(2), dataObj, fold, axErr );
969 
970  //================================ Save max height result
971  if ( axHeight >= minPeakHeight ) { ProSHADE_internal_symmetry::saveMissingAxisNewOnly ( hlpVec, solVec.at(0), solVec.at(1), solVec.at(2), axHeight, fold, axErr ); }
972  }
973  }
974  }
975 
976  //================================================ Release memory
977  delete[] symHlp;
978 
979  //================================================ Done
980  return ;
981 
982 }

◆ sortArrVecHlp()

bool ProSHADE_internal_symmetry::sortArrVecHlp ( const proshade_double *  a,
const proshade_double *  b 
)

This function compares two arrays of two based on the first number.

Parameters
[in]aThe first array to compare.
[in]bThe second array to compare.
[out]XBoolean whether the first is smaller than the second.

Definition at line 658 of file ProSHADE_symmetry.cpp.

659 {
660  //================================================ Compare
661  return ( a[0] < b[0] );
662 
663 }

◆ testGroupAgainstGroup()

bool ProSHADE_internal_symmetry::testGroupAgainstGroup ( std::vector< proshade_double * > *  GrList1,
std::vector< proshade_unsign > *  grp1,
std::vector< proshade_double * > *  GrList2,
std::vector< proshade_unsign > *  grp2,
proshade_double  angle,
proshade_double  axErr 
)

This function compares two groups of axes for a single pair having the required angle.

This simple helper function takes two sets of symmetry axes and two vectors of indices, each relating to one of the two sets. It then proceeds to check each of the indexed axes in each set against all the indexed axes in the other set, searching for a particular angle. If this angle is found for at least one pair, true is returned, while otherwise false is returned.

Parameters
[in]GrList1A vector containing the symmetries for the group 1.
[in]grp1The indices respective to GrList1 which form group 1.
[in]GrList2A vector containing the symmetries for the group 2.
[in]grp2The indices respective to GrList1 which form group 2.
[in]angleThe angle which needs to be found between any pair of axes in group 1 and 2.
[in]axErrThe error tolerance on angle matching.
[out]retTrue if succeeded, false otherwise.

Definition at line 1083 of file ProSHADE_symmetry.cpp.

1084 {
1085  //================================================ Initialise variables
1086  bool ret = false;
1087  proshade_double dotProduct;
1088 
1089  //================================================ For all pairs of axes
1090  for ( proshade_unsign g1It = 0; g1It < static_cast<proshade_unsign> ( grp1->size() ); g1It++ )
1091  {
1092  for ( proshade_unsign g2It = 0; g2It < static_cast<proshade_unsign> ( grp2->size() ); g2It++ )
1093  {
1094  //======================================== Find the angle
1095  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &GrList1->at(grp1->at(g1It))[1],
1096  &GrList1->at(grp1->at(g1It))[2],
1097  &GrList1->at(grp1->at(g1It))[3],
1098  &GrList2->at(grp2->at(g2It))[1],
1099  &GrList2->at(grp2->at(g2It))[2],
1100  &GrList2->at(grp2->at(g2It))[3] );
1101 
1102  //======================================== Check the angle
1103  if ( ( angle > ( dotProduct - axErr ) ) && ( angle < ( dotProduct + axErr ) ) )
1104  {
1105  ret = true;
1106  return ( ret );
1107  }
1108  }
1109  }
1110 
1111  //================================================ Done
1112  return ( ret );
1113 
1114 }

◆ testGroupAgainstSymmetry()

bool ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( std::vector< proshade_double * > *  CSymList,
std::vector< proshade_unsign > *  grp,
proshade_double *  sym,
proshade_double  axErr,
proshade_double  angle,
bool  improve,
proshade_unsign  pos = 0 
)

This function tests whether a symmetry has particular angle to all members of a group.

This utility function tests if a sinlge symmetry axis has a given angle to all member of a particular symmetry group as given by the vector of indices and a vector of all symmetries. If the improve parameter is true, that it will also check for the tested axis for being parallel to any of the group axes while having higher average peak height - and in such cases, the function will replace the existing axis with the tested axis index as given in the pos argument. This utility is useful when searching for all axes of polyhedral symmetry groups.

Parameters
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]grpA vector of indices (relating to CSymList) of the group members.
[in]symA double pointer to array containing the symmetry to be tested against the group.
[in]axErrThe error tolerance on angle matching.
[in]angleThe angle that each group member is required to have against the symmetry.
[in]improveBoolead value stating whether an axis with higher average height should be used instead of equal axis with lower average height, if such axis is found.
[in]posThis is the CSymList index of the axis tested against the group. It will be used if improve = true to change the grp entry which is identical, but has lower height.
[out]XBoolean value speciying whether all group members have the angle to the symmetry or not.

Definition at line 531 of file ProSHADE_symmetry.cpp.

532 {
533  //================================================ Initialise variables
534  bool allAnglesMet = true;
535  proshade_double dotProduct;
536 
537  //================================================ Improve if required
538  if ( improve )
539  {
540  for ( proshade_unsign mIt = 0; mIt < static_cast<proshade_unsign> ( grp->size() ); mIt++ )
541  {
542  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(grp->at(mIt))[1], &CSymList->at(grp->at(mIt))[2], &CSymList->at(grp->at(mIt))[3], &sym[1], &sym[2], &sym[3] );
543 
544  if ( ( ( 1.0 > ( dotProduct - axErr ) ) && ( 1.0 < ( dotProduct + axErr ) ) ) || ( ( -1.0 > ( dotProduct - axErr ) ) && ( -1.0 < ( dotProduct + axErr ) ) ) )
545  {
546  if ( sym[5] > CSymList->at(grp->at(mIt))[5] )
547  {
548  grp->at(mIt) = pos;
549  }
550  else
551  {
552  allAnglesMet = false;
553  return ( allAnglesMet );
554  }
555  }
556  }
557  }
558 
559  //================================================ For all group members
560  for ( proshade_unsign mIt = 0; mIt < static_cast<proshade_unsign> ( grp->size() ); mIt++ )
561  {
562  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(grp->at(mIt))[1], &CSymList->at(grp->at(mIt))[2], &CSymList->at(grp->at(mIt))[3], &sym[1], &sym[2], &sym[3] );
563 
564  if ( ( angle > ( std::abs ( dotProduct ) - axErr ) ) &&
565  ( angle < ( std::abs ( dotProduct ) + axErr ) ) )
566  {
567  //======================================== Matching group memner - try next one
568  }
569  else
570  {
571  //======================================== Group member not matched - try next group
572  allAnglesMet = false;
573  break;
574  }
575  }
576 
577  //================================================ Done
578  return ( allAnglesMet );
579 
580 }
ProSHADE_internal_maths::findVectorFromThreeVAndThreeD
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.
Definition: ProSHADE_maths.cpp:2479
ProSHADE_internal_data::ProSHADE_data::getZDimSize
proshade_single getZDimSize(void)
This function allows access to the map size in angstroms along the Z axis.
Definition: ProSHADE_data.cpp:4064
ProSHADE_internal_maths::getEulerZYZFromSOFTPosition
void getEulerZYZFromSOFTPosition(proshade_signed band, proshade_signed x, proshade_signed y, proshade_signed z, proshade_double *eulerAlpha, proshade_double *eulerBeta, proshade_double *eulerGamma)
Function to find Euler angles (ZYZ convention) from index position in the inverse SOFT map.
Definition: ProSHADE_maths.cpp:966
ProSHADE_internal_precomputedVals::octahedronAxes
Definition: ProSHADE_precomputedValues.hpp:55
ProSHADE_internal_symmetry::findMissingAxes
bool findMissingAxes(std::vector< std::vector< proshade_unsign > > *possibilities, std::vector< proshade_double * > *CSymList, proshade_unsign requiredNoAxes, proshade_double axErr, proshade_double angle, proshade_unsign fold, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_double minPeakHeight)
This function tries to find an axis which would complete a particular group of axes for polyhedral sy...
Definition: ProSHADE_symmetry.cpp:598
ProSHADE_internal_misc::addToDblPtrVector
void addToDblPtrVector(std::vector< proshade_double * > *vecToAddTo, proshade_double *elementToAdd)
Adds the element to the vector.
Definition: ProSHADE_misc.cpp:143
ProSHADE_internal_symmetry::sortArrVecHlp
bool sortArrVecHlp(const proshade_double *a, const proshade_double *b)
This function compares two arrays of two based on the first number.
Definition: ProSHADE_symmetry.cpp:658
findBestOctaDihedralPair
std::vector< std::pair< proshade_unsign, proshade_unsign > > findBestOctaDihedralPair(std::vector< proshade_double * > *CSymList, proshade_double minPeakHeight, proshade_double axErr)
This function finds the best pair of axes conforming to the octahedron dihedral angle.
Definition: ProSHADE_symmetry.cpp:2150
ProSHADE_internal_maths::computeCrossProduct
proshade_double * computeCrossProduct(proshade_double *x1, proshade_double *y1, proshade_double *z1, proshade_double *x2, proshade_double *y2, proshade_double *z2)
Simple 3D vector cross product computation.
Definition: ProSHADE_maths.cpp:1817
ProSHADE_internal_symmetry::addAxisUnlessSame
proshade_signed addAxisUnlessSame(proshade_unsign fold, proshade_double axX, proshade_double axY, proshade_double axZ, proshade_double axHeight, proshade_double averageFSC, std::vector< proshade_double * > *prosp, proshade_double axErr)
This function simply creates a new axis from information in aruments and tests if no such axis alread...
Definition: ProSHADE_symmetry.cpp:1511
ProSHADE_internal_spheres::ProSHADE_rotFun_sphere
This class contains all inputed data for the rotation function angle-axis converted spheres.
Definition: ProSHADE_maths.hpp:58
ProSHADE_internal_precomputedVals::icosahedronAxes::getValue
proshade_double getValue(proshade_unsign axis, proshade_unsign element)
Accessor for the icosahedronAxesVals variable.
Definition: ProSHADE_precomputedValues.cpp:223
ProSHADE_exception
This class is the representation of ProSHADE exception.
Definition: ProSHADE_exceptions.hpp:37
ProSHADE_internal_symmetry::findPredictedAxesHeights
void findPredictedAxesHeights(std::vector< proshade_double * > *ret, ProSHADE_internal_data::ProSHADE_data *dataObj, ProSHADE_settings *settings)
This function finds the rotation function value for all axes supplied in the ret parameter.
Definition: ProSHADE_symmetry.cpp:3063
ProSHADE_internal_maths::getRotationMatrixFromEulerZYZAngles
void getRotationMatrixFromEulerZYZAngles(proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double *matrix)
Function to find the rotation matrix from Euler angles (ZYZ convention).
Definition: ProSHADE_maths.cpp:1019
findBestTetraDihedralPair
std::vector< std::pair< proshade_unsign, proshade_unsign > > findBestTetraDihedralPair(std::vector< proshade_double * > *CSymList, proshade_double minPeakHeight, proshade_double axErr)
This function finds the best pair of axes conforming to the tetrahedron dihedral angle.
Definition: ProSHADE_symmetry.cpp:3487
ProSHADE_internal_data::ProSHADE_data::getXDimSize
proshade_single getXDimSize(void)
This function allows access to the map size in angstroms along the X axis.
Definition: ProSHADE_data.cpp:4044
ProSHADE_internal_misc::addToUnsignVectorVector
void addToUnsignVectorVector(std::vector< std::vector< proshade_unsign > > *vecToAddTo, std::vector< proshade_unsign > elementToAdd)
Adds the element to the vector of vectors.
Definition: ProSHADE_misc.cpp:211
ProSHADE_internal_data::ProSHADE_data::getYDimSize
proshade_single getYDimSize(void)
This function allows access to the map size in angstroms along the Y axis.
Definition: ProSHADE_data.cpp:4054
ProSHADE_internal_symmetry::missingAxisHeight
proshade_double missingAxisHeight(proshade_double xVal, proshade_double yVal, proshade_double zVal, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_unsign fold, proshade_double axErr)
This function searches for the highest peaks average that would produce the required axis and fold.
Definition: ProSHADE_symmetry.cpp:679
ProSHADE_internal_symmetry::searchMissingSymmetrySpace
void searchMissingSymmetrySpace(ProSHADE_internal_data::ProSHADE_data *dataObj, std::vector< proshade_double * > *CSymList, std::vector< proshade_unsign > *grp, std::vector< proshade_double * > *hlpVec, proshade_double axErr, proshade_double angle, proshade_unsign fold, proshade_double minPeakHeight)
This function tests feasible axes against the missing axis criteria, returning a set of matching axes...
Definition: ProSHADE_symmetry.cpp:890
ProSHADE_internal_symmetry::findMissingAxesDual
bool findMissingAxesDual(std::vector< proshade_unsign > *possibilities, std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, std::vector< proshade_unsign > *retGroup, proshade_unsign requiredNoAxes, proshade_double axErr, proshade_unsign noMatchesG1, proshade_double angle1, proshade_unsign noMatchesG2, proshade_double angle2, proshade_unsign fold, ProSHADE_internal_data::ProSHADE_data *dataObj)
This function tries to find a particular symmetry axes which would complete a group of symmetries wit...
Definition: ProSHADE_symmetry.cpp:1416
ProSHADE_internal_data::ProSHADE_data::maxShellBand
proshade_unsign maxShellBand
The maximum band for any shell of the object.
Definition: ProSHADE_data.hpp:123
ProSHADE_internal_symmetry::optimiseDGroupAngleFromAxesHeights
void optimiseDGroupAngleFromAxesHeights(std::vector< std::vector< proshade_double > > *ret, ProSHADE_internal_data::ProSHADE_data *dataObj, ProSHADE_settings *settings)
This function takes two axes with almost dihedral angle and optimises their relative positions as wel...
Definition: ProSHADE_symmetry.cpp:3269
ProSHADE_settings::verbose
proshade_signed verbose
Should the software report on the progress, or just be quiet? Value between -1 (nothing) and 4 (loud)
Definition: ProSHADE_settings.hpp:152
ProSHADE_internal_symmetry::isSymmetrySame
bool isSymmetrySame(std::vector< proshade_double * > *ret, proshade_double *sym, proshade_double simThres, proshade_signed *matchedPos)
This function checks if a very similar symmetry is not already saved.
Definition: ProSHADE_symmetry.cpp:215
ProSHADE_internal_maths::vectorOrientationSimilarity
bool vectorOrientationSimilarity(proshade_double a1, proshade_double a2, proshade_double a3, proshade_double b1, proshade_double b2, proshade_double b3, proshade_double tolerance=0.1)
This function compares two vectors using cosine distance and decides if they are similar using tolera...
Definition: ProSHADE_maths.cpp:2680
ProSHADE_settings::messageShift
proshade_signed messageShift
This value allows shifting the messages to create more readable log for sub-processes.
Definition: ProSHADE_settings.hpp:153
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_precomputedVals::octahedronAxes::getValue
proshade_double getValue(proshade_unsign axis, proshade_unsign element)
Accessor for the octahedronAxesVals variable.
Definition: ProSHADE_precomputedValues.cpp:136
ProSHADE_internal_data::ProSHADE_data::getXDim
proshade_unsign getXDim(void)
This function allows access to the map size in indices along the X axis.
Definition: ProSHADE_data.cpp:4074
ProSHADE_internal_precomputedVals::tetrahedronAxes::getValue
proshade_double getValue(proshade_unsign axis, proshade_unsign element)
Accessor for the tetrahedronAxesVals variable.
Definition: ProSHADE_precomputedValues.cpp:68
ProSHADE_settings::useBiCubicInterpolationOnPeaks
bool useBiCubicInterpolationOnPeaks
This variable switch decides whether best symmetry is detected from peak indices, or whether bicubic ...
Definition: ProSHADE_settings.hpp:137
ProSHADE_internal_symmetry::saveMissingAxisNewOnly
void saveMissingAxisNewOnly(std::vector< proshade_double * > *axVec, proshade_double axX, proshade_double axY, proshade_double axZ, proshade_double height, proshade_unsign fold, proshade_double axErr)
This function saves the recovered information about missing axis into a full symmetry,...
Definition: ProSHADE_symmetry.cpp:821
ProSHADE_internal_maths::computeDotProduct
proshade_double computeDotProduct(proshade_double *x1, proshade_double *y1, proshade_double *z1, proshade_double *x2, proshade_double *y2, proshade_double *z2)
Simple 3D vector dot product computation.
Definition: ProSHADE_maths.cpp:1785
ProSHADE_internal_misc::deepCopyAxisToDblPtrVector
void deepCopyAxisToDblPtrVector(std::vector< proshade_double * > *dblPtrVec, proshade_double *axis)
Does a deep copy of a double array to a vector of double arrays.
Definition: ProSHADE_misc.cpp:433
ProSHADE_internal_precomputedVals::tetrahedronAxes::getNoAxes
proshade_unsign getNoAxes()
Accessor for the tetrahedronAxesVals variable number of axes.
Definition: ProSHADE_precomputedValues.cpp:79
ProSHADE_internal_spheres::ProSHADE_rotFun_spherePeakGroup::checkIfPeakBelongs
bool checkIfPeakBelongs(proshade_double lat, proshade_double lon, proshade_unsign sphPos, proshade_double cosTol, proshade_signed verbose, proshade_signed messageShift, proshade_double allowedAngle)
This function takes a new prospective peak and tests if it belongs to this peak group or not.
Definition: ProSHADE_spheres.cpp:1180
ProSHADE_internal_maths::getRotationMatrixFromAngleAxis
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.
Definition: ProSHADE_maths.cpp:1458
ProSHADE_internal_data::ProSHADE_data::getMaxBand
proshade_unsign getMaxBand(void)
This function returns the maximum band value for the object.
Definition: ProSHADE_data.cpp:3748
ProSHADE_internal_data::ProSHADE_data::getYDim
proshade_unsign getYDim(void)
This function allows access to the map size in indices along the Y axis.
Definition: ProSHADE_data.cpp:4084
ProSHADE_internal_maths::findHighestValueInMap
void findHighestValueInMap(fftw_complex *resIn, proshade_unsign xD, proshade_unsign yD, proshade_unsign zD, proshade_double *trsX, proshade_double *trsY, proshade_double *trsZ, proshade_double *mapPeak)
This function simply finds the highest value in fftw_complex map and returns its position and value.
Definition: ProSHADE_maths.cpp:4289
ProSHADE_internal_maths::getAxisAngleFromRotationMatrix
void getAxisAngleFromRotationMatrix(proshade_double *rotMat, proshade_double *x, proshade_double *y, proshade_double *z, proshade_double *ang, proshade_signed verbose=1)
This function converts rotation matrix to the axis-angle representation.
Definition: ProSHADE_maths.cpp:1083
ProSHADE_internal_maths::build3x3MatrixFromXYZRotations
proshade_double * build3x3MatrixFromXYZRotations(proshade_double xRot, proshade_double yRot, proshade_double zRot)
Function for building a 3x3 rotation matrix from the x, y and z rotations in degrees.
Definition: ProSHADE_maths.cpp:2057
ProSHADE_internal_maths::combineFourierForTranslation
void combineFourierForTranslation(fftw_complex *tmpOut1, fftw_complex *tmpOut2, fftw_complex *&resOut, proshade_unsign xD, proshade_unsign yD, proshade_unsign zD)
This function combines Fourier coefficients of two structures in a way, so that inverse Fourier of th...
Definition: ProSHADE_maths.cpp:4242
ProSHADE_internal_data::ProSHADE_data::getZDim
proshade_unsign getZDim(void)
This function allows access to the map size in indices along the Z axis.
Definition: ProSHADE_data.cpp:4094
ProSHADE_internal_symmetry::findTranslationBetweenRotatedAndOriginalMap
std::vector< proshade_double > findTranslationBetweenRotatedAndOriginalMap(ProSHADE_internal_data::ProSHADE_data *symStr, std::vector< proshade_double > symElem, fftw_complex *origCoeffs, fftw_complex *rotMapComplex, fftw_complex *rotCoeffs, fftw_plan planForwardFourierRot, fftw_complex *trFuncCoeffs, fftw_complex *trFunc, fftw_plan planReverseFourierComb)
This function takes a single rotation matrix and procceds to compute the optimal translation between ...
Definition: ProSHADE_symmetry.cpp:3919
ProSHADE_internal_spheres::ProSHADE_rotFun_spherePeakGroup
This class contains peak groups detected in the rotation function mapped spheres.
Definition: ProSHADE_spheres.hpp:129
ProSHADE_internal_maths::isAxisUnique
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.
Definition: ProSHADE_maths.cpp:3064
ProSHADE_internal_symmetry::findMissingAxesTriple
bool findMissingAxesTriple(std::vector< proshade_unsign > *possibilities, std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, std::vector< proshade_unsign > *retGroup, proshade_unsign requiredNoAxes, proshade_double axErr, proshade_unsign noMatchesG1, proshade_double angle1, proshade_unsign noMatchesG2, proshade_double angle2, proshade_unsign noMatchesG3, proshade_double angle3, proshade_unsign fold, ProSHADE_internal_data::ProSHADE_data *dataObj)
This function tries to find a particular symmetry axis which would complete a group of symmetries wit...
Definition: ProSHADE_symmetry.cpp:2493
ProSHADE_internal_maths::findRotMatMatchingVectors
proshade_double * findRotMatMatchingVectors(proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2)
Computation of rotation matrix rotating one vector onto the other.
Definition: ProSHADE_maths.cpp:2119
findBestIcosDihedralPair
std::vector< std::pair< proshade_unsign, proshade_unsign > > findBestIcosDihedralPair(std::vector< proshade_double * > *CSymList, proshade_double minPeakHeight, proshade_double axErr)
This function finds all the pairs of axes conforming to the icosahedron dihedral angle.
Definition: ProSHADE_symmetry.cpp:1971
ProSHADE_internal_data::ProSHADE_data::rotateMapRealSpace
std::vector< proshade_double > rotateMapRealSpace(proshade_double axX, proshade_double axY, proshade_double axZ, proshade_double axAng, proshade_double *&map)
This function rotates a map based on the given angle-axis rotation.
Definition: ProSHADE_overlay.cpp:632
ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication
proshade_double * compute3x3MatrixVectorMultiplication(proshade_double *mat, proshade_double x, proshade_double y, proshade_double z)
Function for computing a 3x3 matrix to 3x1 vector multiplication.
Definition: ProSHADE_maths.cpp:1895
ProSHADE_internal_precomputedVals::tetrahedronAxes
Definition: ProSHADE_precomputedValues.hpp:69
ProSHADE_internal_maths::rotationMatrixSimilarity
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 usi...
Definition: ProSHADE_maths.cpp:2576
ProSHADE_internal_symmetry::testGroupAgainstSymmetry
bool testGroupAgainstSymmetry(std::vector< proshade_double * > *CSymList, std::vector< proshade_unsign > *grp, proshade_double *sym, proshade_double axErr, proshade_double angle, bool improve, proshade_unsign pos=0)
This function tests whether a symmetry has particular angle to all members of a group.
Definition: ProSHADE_symmetry.cpp:531
ProSHADE_internal_precomputedVals::icosahedronAxes
Definition: ProSHADE_precomputedValues.hpp:41
ProSHADE_internal_misc::checkMemoryAllocation
void checkMemoryAllocation(chVar checkVar, std::string fileP, unsigned int lineP, std::string funcP, std::string infoP="This error may occurs when ProSHADE requests memory to be\n : allocated to it and this operation fails. This could\n : happen when not enough memory is available, either due to\n : other processes using a lot of memory, or when the machine\n : does not have sufficient memory available. Re-run to see\n : if this problem persists.")
Checks if memory was allocated properly.
Definition: ProSHADE_misc.hpp:73
ProSHADE_internal_precomputedVals::octahedronAxes::getNoAxes
proshade_unsign getNoAxes()
Accessor for the octahedronAxesVals variable number of axes.
Definition: ProSHADE_precomputedValues.cpp:147
ProSHADE_internal_data::ProSHADE_data::getInvSO3Coeffs
proshade_complex * getInvSO3Coeffs(void)
This function allows access to the inverse SO(3) coefficients array.
Definition: ProSHADE_data.cpp:3992
ProSHADE_internal_data::ProSHADE_data::getEMatDim
proshade_unsign getEMatDim(void)
This function allows access to the maximum band for the E matrix.
Definition: ProSHADE_data.cpp:4014
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_spheres::ProSHADE_rotFun_spherePeakGroup::findCyclicPointGroupsGivenFold
void findCyclicPointGroupsGivenFold(std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > sphereVals, std::vector< proshade_double * > *detectedCs, bool bicubicInterp, proshade_unsign fold, proshade_signed verbose, proshade_signed messageShift)
Function detecting cyclic point groups with a particular fold in a peak group.
Definition: ProSHADE_spheres.cpp:1427
ProSHADE_internal_symmetry::checkFittingAxisTripleAndSave
void checkFittingAxisTripleAndSave(std::vector< proshade_unsign > *retGroup, std::vector< proshade_double * > *ret, proshade_unsign fold, proshade_double axX, proshade_double axY, proshade_double axZ, std::vector< proshade_double * > *prosp, proshade_double axErr, proshade_unsign noMatchesG1, proshade_double angle1, proshade_unsign noMatchesG2, proshade_double angle2, proshade_unsign noMatchesG3, proshade_double angle3, ProSHADE_internal_data::ProSHADE_data *dataObj)
This function takes a newly detected "missing" axis and tests it for belonging to the group,...
Definition: ProSHADE_symmetry.cpp:2604
ProSHADE_internal_maths::findVectorFromTwoVAndTwoD
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.
Definition: ProSHADE_maths.cpp:2333
ProSHADE_settings::axisErrTolerance
proshade_double axisErrTolerance
Allowed error on vector axis in in dot product ( acos ( 1 - axErr ) is the allowed difference in radi...
Definition: ProSHADE_settings.hpp:132
ProSHADE_internal_precomputedVals::icosahedronAxes::getNoAxes
proshade_unsign getNoAxes()
Accessor for the octahedronAxesVals variable number of axes.
Definition: ProSHADE_precomputedValues.cpp:234
ProSHADE_internal_maths::findTopGroupSmooth
proshade_double findTopGroupSmooth(std::vector< proshade_double * > *CSym, size_t peakPos, proshade_double step, proshade_double sigma, proshade_signed windowSize, proshade_double maxLim=1.0)
This function finds a subgroup of axes with distinctly higher correlation value.
Definition: ProSHADE_maths.cpp:4113
ProSHADE_internal_messages::printProgressMessage
void printProgressMessage(proshade_signed verbose, proshade_signed messageLevel, std::string message, proshade_signed messageShift=0)
General stdout message printing.
Definition: ProSHADE_messages.cpp:71
ProSHADE_internal_misc::sortSymHlpInv
bool sortSymHlpInv(const proshade_double *a, const proshade_double *b)
This function compares two arrays of two based on the fifth number, sorting highest first.
Definition: ProSHADE_misc.cpp:288
ProSHADE_internal_symmetry::checkFittingAxisDualAndSave
bool checkFittingAxisDualAndSave(std::vector< proshade_unsign > *retGroup, std::vector< proshade_double * > *ret, proshade_unsign fold, proshade_double axX, proshade_double axY, proshade_double axZ, std::vector< proshade_double * > *prosp, proshade_double axErr, proshade_unsign noMatchesG1, proshade_double angle1, proshade_unsign noMatchesG2, proshade_double angle2, ProSHADE_internal_data::ProSHADE_data *dataObj)
This function takes a newly detected "missing" axis and tests it for belonging to the group,...
Definition: ProSHADE_symmetry.cpp:1610
ProSHADE_internal_symmetry::findMissingAxisPoints
std::vector< proshade_double * > findMissingAxisPoints(proshade_double xVal, proshade_double yVal, proshade_double zVal, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_double axErr)
This function searches for all the self-rotation map points conforming to the axis,...
Definition: ProSHADE_symmetry.cpp:743
ProSHADE_internal_maths::compute3x3MatrixMultiplication
proshade_double * compute3x3MatrixMultiplication(proshade_double *mat1, proshade_double *mat2)
Function for computing a 3x3 matrix multiplication.
Definition: ProSHADE_maths.cpp:1865