ProSHADE  0.7.6.2 (DEC 2021)
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...
 
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...
 
void saveDSymmetry (std::vector< proshade_double * > *ret, std::vector< proshade_double * > *CSymList, proshade_unsign axisOne, proshade_unsign axisTwo)
 This function saves a detected dihedral symmetry to the dihedral symmetries list. 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 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...
 
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< 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< 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< std::vector< proshade_double > > *allCs, 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 1657 of file ProSHADE_symmetry.cpp.

1658 {
1659  //================================================ Initialise variables
1660  proshade_double* symHlp = new proshade_double[7];
1661  ProSHADE_internal_misc::checkMemoryAllocation ( symHlp, __FILE__, __LINE__, __func__ );
1662  proshade_signed ret = -1;
1663 
1664  //================================================ Fill in the prospective axis
1665  symHlp[0] = static_cast<proshade_double> ( fold );
1666  symHlp[1] = axX;
1667  symHlp[2] = axY;
1668  symHlp[3] = axZ;
1669  symHlp[4] = 2.0 * M_PI / symHlp[0];
1670  symHlp[5] = axHeight;
1671  symHlp[6] = averageFSC;
1672 
1673  //================================================ If it is not the same as already saved axes
1674  if ( !ProSHADE_internal_symmetry::isSymmetrySame ( prosp, symHlp, axErr, &ret, averageFSC ) )
1675  {
1677  return ( static_cast< proshade_signed > ( prosp->size() - 1 ) );
1678  }
1679  else
1680  {
1681  delete[] symHlp;
1682  return ( ret );
1683  }
1684 
1685  //================================================ Done
1686 
1687 }

◆ 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 1703 of file ProSHADE_symmetry.cpp.

1704 {
1705  //================================================ Initialise variables
1706  proshade_double* symHlp = new proshade_double[7];
1707  ProSHADE_internal_misc::checkMemoryAllocation ( symHlp, __FILE__, __LINE__, __func__ );
1708  proshade_signed ret = -1;
1709 
1710  //================================================ Fill in the prospective axis
1711  symHlp[0] = static_cast<proshade_double> ( fold );
1712  symHlp[1] = axX;
1713  symHlp[2] = axY;
1714  symHlp[3] = axZ;
1715  symHlp[4] = 2.0 * M_PI / symHlp[0];
1716  symHlp[5] = axHeight;
1717  symHlp[6] = -std::numeric_limits < proshade_double >::infinity();
1718 
1719  //================================================ If it is not the same as already saved axes
1720  if ( !ProSHADE_internal_symmetry::isSymmetrySame ( prosp, symHlp, axErr, &ret ) )
1721  {
1723  return ( static_cast< proshade_signed > ( prosp->size() - 1 ) );
1724  }
1725  else
1726  {
1727  delete[] symHlp;
1728  return ( ret );
1729  }
1730 
1731  //================================================ Done
1732 
1733 }

◆ 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 3791 of file ProSHADE_symmetry.cpp.

3792 {
3793  //================================================ Allocate the memory
3794  origMap = new fftw_complex [xDim * yDim * zDim];
3795  origCoeffs = new fftw_complex [xDim * yDim * zDim];
3796  rotMapComplex = new fftw_complex [xDim * yDim * zDim];
3797  rotCoeffs = new fftw_complex [xDim * yDim * zDim];
3798  trFunc = new fftw_complex [xDim * yDim * zDim];
3799  trFuncCoeffs = new fftw_complex [xDim * yDim * zDim];
3800 
3801  //================================================ Check the memory allocation
3802  ProSHADE_internal_misc::checkMemoryAllocation ( origMap, __FILE__, __LINE__, __func__ );
3803  ProSHADE_internal_misc::checkMemoryAllocation ( origCoeffs, __FILE__, __LINE__, __func__ );
3804  ProSHADE_internal_misc::checkMemoryAllocation ( rotMapComplex, __FILE__, __LINE__, __func__ );
3805  ProSHADE_internal_misc::checkMemoryAllocation ( rotCoeffs, __FILE__, __LINE__, __func__ );
3806  ProSHADE_internal_misc::checkMemoryAllocation ( trFunc, __FILE__, __LINE__, __func__ );
3807  ProSHADE_internal_misc::checkMemoryAllocation ( trFuncCoeffs, __FILE__, __LINE__, __func__ );
3808 
3809  //================================================
3810  *planForwardFourier = fftw_plan_dft_3d ( static_cast< int > ( xDim ), static_cast< int > ( yDim ), static_cast< int > ( zDim ), origMap, origCoeffs, FFTW_FORWARD, FFTW_ESTIMATE );
3811  *planForwardFourierRot = fftw_plan_dft_3d ( static_cast< int > ( xDim ), static_cast< int > ( yDim ), static_cast< int > ( zDim ), rotMapComplex, rotCoeffs, FFTW_FORWARD, FFTW_ESTIMATE );
3812  *planReverseFourierComb = fftw_plan_dft_3d ( static_cast< int > ( xDim ), static_cast< int > ( yDim ), static_cast< int > ( zDim ), trFuncCoeffs, trFunc, FFTW_BACKWARD, FFTW_ESTIMATE );
3813 
3814  //================================================ Done
3815  return ;
3816 
3817 }

◆ 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 1756 of file ProSHADE_symmetry.cpp.

1757 {
1758  //================================================ Initialise variables
1759  proshade_unsign noG1 = 0;
1760  proshade_unsign noG2 = 0;
1761  proshade_double dotProd = 0.0;
1762  proshade_double axHeight = 0.0;
1763 
1764  //================================================ Find the angle and count dual matching frequencies
1765  for ( proshade_unsign rIt = 0; rIt < static_cast<proshade_unsign> ( retGroup->size() ); rIt++ )
1766  {
1767  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(retGroup->at(rIt))[1],
1768  &ret->at(retGroup->at(rIt))[2],
1769  &ret->at(retGroup->at(rIt))[3],
1770  &axX, &axY, &axZ );
1771 
1772  if ( ( std::abs ( dotProd ) > ( angle1 - axErr ) ) && ( std::abs ( dotProd ) < ( angle1 + axErr ) ) ) { noG1 += 1; continue; }
1773  if ( ( std::abs ( dotProd ) > ( angle2 - axErr ) ) && ( std::abs ( dotProd ) < ( angle2 + axErr ) ) ) { noG2 += 1; continue; }
1774  }
1775 
1776  //================================================ If correct frequencies are matched, check height.
1777  if ( ( noG1 == noMatchesG1 ) && ( noG2 == noMatchesG2 ) )
1778  {
1779  //============================================ Is the height good enough?
1780  axHeight = ProSHADE_internal_symmetry::missingAxisHeight ( axX, axY, axZ, dataObj, fold, axErr );
1781 
1782  //============================================ If so, save
1783  if ( axHeight > 0.1 )
1784  {
1785  proshade_unsign prevProsp = static_cast<proshade_unsign> ( prosp->size() );
1786  ProSHADE_internal_symmetry::addAxisUnlessSame ( fold, axX, axY, axZ, axHeight, prosp, axErr );
1787 
1788  if ( static_cast<proshade_unsign> ( prosp->size() ) > prevProsp ) { return ( true ); }
1789  else { return ( false ); }
1790  }
1791  }
1792 
1793  //================================================ Done
1794  return ( false );
1795 
1796 }

◆ 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 2718 of file ProSHADE_symmetry.cpp.

2719 {
2720  //================================================ Initialise variables
2721  proshade_unsign noG1 = 0;
2722  proshade_unsign noG2 = 0;
2723  proshade_unsign noG3 = 0;
2724  proshade_double dotProd = 0.0;
2725  proshade_double axHeight = 0.0;
2726 
2727  //================================================ Find the angle and count dual matching frequencies
2728  for ( proshade_unsign rIt = 0; rIt < static_cast<proshade_unsign> ( retGroup->size() ); rIt++ )
2729  {
2730  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(retGroup->at(rIt))[1],
2731  &ret->at(retGroup->at(rIt))[2],
2732  &ret->at(retGroup->at(rIt))[3],
2733  &axX, &axY, &axZ );
2734 
2735  if ( ( std::abs ( dotProd ) > ( angle1 - axErr ) ) && ( std::abs ( dotProd ) < ( angle1 + axErr ) ) ) { noG1 += 1; continue; }
2736  if ( ( std::abs ( dotProd ) > ( angle2 - axErr ) ) && ( std::abs ( dotProd ) < ( angle2 + axErr ) ) ) { noG2 += 1; continue; }
2737  if ( ( std::abs ( dotProd ) > ( angle3 - axErr ) ) && ( std::abs ( dotProd ) < ( angle3 + axErr ) ) ) { noG3 += 1; continue; }
2738  }
2739 
2740  //================================================ If correct frequencies are matched, check height.
2741  if ( ( noG1 == noMatchesG1 ) && ( noG2 == noMatchesG2 ) && ( noG3 == noMatchesG3 ) )
2742  {
2743  //============================================ Is the height good enough?
2744  axHeight = ProSHADE_internal_symmetry::missingAxisHeight ( axX, axY, axZ, dataObj, fold, axErr );
2745 
2746  //============================================ If so, save
2747  if ( axHeight > 0.1 )
2748  {
2749  ProSHADE_internal_symmetry::addAxisUnlessSame ( fold, axX, axY, axZ, axHeight, prosp, axErr );
2750  }
2751  }
2752 
2753  //================================================ Done
2754  return ;
2755 
2756 }

◆ 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 1971 of file ProSHADE_symmetry.cpp.

1972 {
1973  //================================================ Initialise variables
1974  std::vector< proshade_unsign > C5List;
1975  proshade_double dotProduct;
1976 
1977  //================================================ Find all C5 symmetries
1978  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
1979  {
1980  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 5.0 );
1981  if ( lhs1.AlmostEquals ( rhs1 ) && CSymList->at(cSym)[5] >= minPeakHeight ) { ProSHADE_internal_misc::addToUnsignVector ( &C5List, cSym ); }
1982  }
1983 
1984  //================================================ For each unique pair of C5 and C3
1985  for ( proshade_unsign c5 = 0; c5 < static_cast<proshade_unsign> ( C5List.size() ); c5++ )
1986  {
1987  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
1988  {
1989  //======================================== Compare only C3s to the C5List
1990  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 3.0 );
1991  if ( !lhs1.AlmostEquals ( rhs1 ) ) { continue; }
1992 
1993  //======================================== Check the angle between the C5 and C3 axes
1994  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(C5List.at(c5))[1],
1995  &CSymList->at(C5List.at(c5))[2],
1996  &CSymList->at(C5List.at(c5))[3],
1997  &CSymList->at(cSym)[1],
1998  &CSymList->at(cSym)[2],
1999  &CSymList->at(cSym)[3] );
2000 
2001  //======================================== Is the angle approximately the dihedral angle
2002  if ( std::abs ( std::abs( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ) - std::abs( dotProduct ) ) < axErr )
2003  {
2004  return ( true );
2005  }
2006  }
2007  }
2008 
2009  //================================================ Done
2010  return ( false );
2011 
2012 }

◆ 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 1273 of file ProSHADE_symmetry.cpp.

1274 {
1275  //================================================ Initialise variables
1276  std::vector< proshade_unsign > C4List;
1277  proshade_double dotProduct;
1278 
1279  //================================================ Find all C4 symmetries
1280  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
1281  {
1282  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 4.0 );
1283  if ( lhs1.AlmostEquals ( rhs1 ) && CSymList->at(cSym)[5] >= minPeakHeight ) { ProSHADE_internal_misc::addToUnsignVector ( &C4List, cSym ); }
1284  }
1285 
1286  //================================================ For each unique pair of C3s
1287  for ( proshade_unsign c4 = 0; c4 < static_cast<proshade_unsign> ( C4List.size() ); c4++ )
1288  {
1289  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
1290  {
1291  //======================================== Compare only C3s to the C3List
1292  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 3.0 );
1293  if ( !lhs1.AlmostEquals ( rhs1 ) ) { continue; }
1294 
1295  //======================================== Check the angle between the C4 and C3 axes
1296  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(C4List.at(c4))[1],
1297  &CSymList->at(C4List.at(c4))[2],
1298  &CSymList->at(C4List.at(c4))[3],
1299  &CSymList->at(cSym)[1],
1300  &CSymList->at(cSym)[2],
1301  &CSymList->at(cSym)[3] );
1302 
1303  //======================================== Is the angle approximately the dihedral angle
1304  if ( ( ( 1.0 / sqrt ( 3.0 ) ) > ( dotProduct - axErr ) ) && ( ( 1.0 / sqrt ( 3.0 ) ) < ( dotProduct + axErr ) ) )
1305  {
1306  return ( true );
1307  }
1308  }
1309  }
1310 
1311  //================================================ Done
1312  return ( false );
1313 
1314 }

◆ 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 488 of file ProSHADE_symmetry.cpp.

489 {
490  //================================================ Initialise variables
491  std::vector< proshade_unsign > C3List;
492  proshade_double dotProduct;
493 
494  //================================================ Find all C3 symmetries
495  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
496  {
497  const FloatingPoint< proshade_double > lhs ( CSymList->at(cSym)[0] ), rhs ( 3.0 );
498  if ( lhs.AlmostEquals ( rhs ) && CSymList->at(cSym)[5] >= minPeakHeight ) { ProSHADE_internal_misc::addToUnsignVector ( &C3List, cSym ); }
499  }
500 
501  //================================================ For each unique pair of C3s
502  for ( proshade_unsign c31 = 0; c31 < static_cast<proshade_unsign> ( C3List.size() ); c31++ )
503  {
504  for ( proshade_unsign c32 = 1; c32 < static_cast<proshade_unsign> ( C3List.size() ); c32++ )
505  {
506  //================================ Unique pairs only
507  if ( c31 >= c32 ) { continue; }
508 
509  //======================================== Check the angle between the C3 axes
510  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] );
511 
512  //================================ Is the angle approximately the dihedral angle
513  if ( ( ( 1.0 / 3.0 ) > ( dotProduct - axErr ) ) && ( ( 1.0 / 3.0 ) < ( dotProduct + axErr ) ) )
514  {
515  return ( true );
516  }
517  }
518  }
519 
520  //================================================ Done
521  return ( false );
522 
523 }

◆ 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 2451 of file ProSHADE_symmetry.cpp.

2452 {
2453  //================================================ Initialise variables
2454  std::vector< proshade_unsign > prospectiveC3s, retGrp;
2455  proshade_double dotProd;
2456  proshade_unsign noClose, noAway;
2457 
2458  //================================================ Report progress
2459  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of ten C3 axes.", messageShift );
2460 
2461  //================================================ For each C3
2462  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
2463  {
2464  //============================================ Use only C3s with hight enough average
2465  if ( CSymList->at(cIt)[0] != 3.0 || CSymList->at(cIt)[0] < minPeakHeight ) { continue; }
2466 
2467  //============================================ 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
2468  noClose = 0; noAway = 0;
2469  for ( proshade_unsign rIt = 0; rIt < 6; rIt++ )
2470  {
2471  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1],
2472  &ret->at(rIt)[2],
2473  &ret->at(rIt)[3],
2474  &CSymList->at(cIt)[1],
2475  &CSymList->at(cIt)[2],
2476  &CSymList->at(cIt)[3] );
2477 
2478  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; }
2479  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; }
2480  }
2481 
2482  //============================================ If correct angles distribution is found, save the axis
2483  if ( ( noClose == 3 ) && ( noAway == 3 ) )
2484  {
2485  ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC3s, cIt );
2486  }
2487  }
2488 
2489  //================================================ Search for missing axes
2490  for ( proshade_unsign iter = 0; iter < 6; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &retGrp, iter ); }
2491  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 ) )
2492  {
2493  return ;
2494  }
2495 
2496  //================================================ Found correct number of axes! Now save the
2497  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( prospectiveC3s.size() ); iter++ )
2498  {
2499  ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(prospectiveC3s.at(iter)) );
2500  }
2501 
2502  //================================================ Report progress
2503  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of ten C3 axes successfull.", messageShift );
2504 
2505  //================================================ Done
2506  return ;
2507 
2508 }

◆ 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 2524 of file ProSHADE_symmetry.cpp.

2525 {
2526  //================================================ Initialise variables
2527  std::vector< proshade_unsign > prospectiveC2s, retGrp;
2528  proshade_double dotProd;
2529  proshade_unsign noClose, noMidway, noAway;
2530 
2531  //================================================ Report progress
2532  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of fifteen C2 axes.", messageShift );
2533 
2534  //================================================ For each C2
2535  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
2536  {
2537  //============================================ Use only C2s
2538  const FloatingPoint< proshade_double > lhs999 ( CSymList->at(cIt)[5] ), rhs999 ( static_cast< proshade_double > ( -999.9 ) );
2539  if ( CSymList->at(cIt)[0] != 2.0 || ( ( CSymList->at(cIt)[5] < minPeakHeight ) && !( lhs999.AlmostEquals( rhs999 ) ) ) ) { continue; }
2540 
2541  //============================================ 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
2542  noClose = 0; noMidway = 0; noAway = 0;
2543  for ( proshade_unsign rIt = 0; rIt < 6; rIt++ )
2544  {
2545  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1],
2546  &ret->at(rIt)[2],
2547  &ret->at(rIt)[3],
2548  &CSymList->at(cIt)[1],
2549  &CSymList->at(cIt)[2],
2550  &CSymList->at(cIt)[3] );
2551 
2552  if ( ( std::abs ( dotProd ) > ( ( sqrt ( 3.0 ) / 2.0 ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( sqrt ( 3.0 ) / 2.0 ) + axErr ) ) ) { noAway += 1; continue; }
2553  if ( ( std::abs ( dotProd ) > ( ( 1.0 / 2.0 ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( 1.0 / 2.0 ) + axErr ) ) ) { noMidway += 1; continue; }
2554  if ( ( std::abs ( dotProd ) > ( ( 0.0 ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( 0.0 ) + axErr ) ) ) { noClose += 1; continue; }
2555  }
2556 
2557  //============================================ If correct angles distribution is found, save the axis
2558  if ( ( noClose == 2 ) && ( noMidway == 2 ) && ( noAway == 2 ) )
2559  {
2560  ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC2s, cIt );
2561  }
2562  }
2563 
2564  //================================================ Search for missing axes
2565  for ( proshade_unsign iter = 0; iter < 6; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &retGrp, iter ); }
2566  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 ) )
2567  {
2568  return ;
2569  }
2570 
2571  //================================================ Found correct number of axes! Now save the
2572  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( prospectiveC2s.size() ); iter++ )
2573  {
2574  ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(prospectiveC2s.at(iter)) );
2575  }
2576 
2577  //================================================ Report progress
2578  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of fifteen C2 axes successfull.", messageShift );
2579 
2580  //================================================ Done
2581  return ;
2582 
2583 }

◆ 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 2032 of file ProSHADE_symmetry.cpp.

2033 {
2034  //================================================ Initialise variables
2035  std::vector< proshade_unsign > C5PossibilitiesHlp;
2036  std::vector< std::vector< proshade_unsign > > C5Possibilities;
2037  bool groupMatched;
2038 
2039  //================================================ Report progress
2040  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of six C5 axes.", messageShift );
2041 
2042  //================================================ For all symmetries in the C symmetries list
2043  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
2044  {
2045  //============================================ Search only using C5s and check peak height
2046  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cIt)[0] ), rhs1 ( 5.0 );
2047  if ( !lhs1.AlmostEquals ( rhs1 ) || CSymList->at(cIt)[5] < minPeakHeight ) { continue; }
2048 
2049  //============================================ If second or more C5, check if it has the correct angle to all other already found C5s for each group
2050  groupMatched = false;
2051  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C5Possibilities.size() ); gIt++ )
2052  {
2053  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; }
2054  }
2055 
2056  //============================================ If no group matched, create a new group
2057  if ( !groupMatched ) { C5PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C5PossibilitiesHlp, cIt ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C5Possibilities, C5PossibilitiesHlp ); continue; }
2058  }
2059 
2060  //================================================ Test for missing symmetry axes, if need be
2061  ProSHADE_internal_symmetry::findMissingAxes ( &C5Possibilities, CSymList, 6, axErr, 1.0 / 2.0, 5, dataObj, minPeakHeight );
2062 
2063  //=================================================Any group has 6 entries? If more such groups, take the one with highest average height.
2064  proshade_double maxHeight = 0.0; proshade_unsign maxGrp = 0;
2065  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; } } }
2066 
2067  if ( C5Possibilities.at(maxGrp).size() == 6 )
2068  {
2069  //============================================ Success! Save and exit
2070  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)) ); }
2071 
2072  //============================================ Report progress
2073  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of six C5 axes successfull.", messageShift );
2074 
2075  //============================================ Done
2076  return ;
2077  }
2078 
2079  //================================================ Done
2080  return ;
2081 
2082 }

◆ 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 676 of file ProSHADE_symmetry.cpp.

677 {
678  //================================================ Initialise variables
679  std::vector< proshade_double* > hlpVec;
680  bool atLeastOne = false;
681 
682  //================================================ Proceed only if need be
683  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( possibilities->size() ); gIt++ )
684  {
685  if ( static_cast<proshade_unsign> ( possibilities->at(gIt).size() ) == requiredNoAxes ) { atLeastOne = true; return ( atLeastOne ); }
686  }
687 
688  //================================================ For each possible group
689  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( possibilities->size() ); gIt++ )
690  {
691  //============================================ This will not work for less than two axes in group
692  if ( possibilities->at(gIt).size() < 2 ) { continue; }
693 
694  //============================================ Prepare iteration
695  hlpVec.clear ( );
696 
697  //============================================ Search for missing axes
698  ProSHADE_internal_symmetry::searchMissingSymmetrySpace ( dataObj, CSymList, &possibilities->at(gIt), &hlpVec, axErr, angle, fold, minPeakHeight );
699 
700  //============================================ Add missing axes
701  if ( hlpVec.size() > 0 )
702  {
703  //======================================== Start adding by highest first
704  std::sort ( hlpVec.begin(), hlpVec.end(), ProSHADE_internal_misc::sortSymHlpInv );
705 
706  //======================================== For each missing axis
707  for ( proshade_unsign axIt = 0; axIt < static_cast<proshade_unsign> ( hlpVec.size() ); axIt++ )
708  {
709  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, &possibilities->at(gIt), hlpVec.at(axIt), axErr, angle, false ) )
710  {
711  //================================ Check for uniqueness
712  if ( ProSHADE_internal_maths::isAxisUnique ( CSymList, hlpVec.at(axIt), axErr ) )
713  {
714  //============================ Add
715  ProSHADE_internal_misc::addToDblPtrVector ( CSymList, hlpVec.at(axIt) );
716  ProSHADE_internal_misc::addToUnsignVector ( &possibilities->at(gIt), static_cast<proshade_unsign> ( CSymList->size()-1 ) );
717  }
718  }
719  }
720  }
721 
722  if ( possibilities->at(gIt).size() == requiredNoAxes ) { atLeastOne = true; }
723  }
724 
725  //================================================ Done
726  return ( atLeastOne );
727 
728 }

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

1563 {
1564  //================================================ Initialise variables
1565  bool atLeastOne = false;
1566  std::vector< proshade_double* > prosp;
1567  std::vector< proshade_double > sol;
1568 
1569  //================================================ Proceed only if need be
1570  if ( static_cast<proshade_unsign> ( possibilities->size() ) == requiredNoAxes ) { atLeastOne = true; return ( atLeastOne ); }
1571 
1572  //================================================ Copy already found to prospective
1573  for ( proshade_unsign prIt = 0; prIt < static_cast<proshade_unsign> ( possibilities->size() ); prIt++ )
1574  {
1575  ProSHADE_internal_symmetry::addAxisUnlessSame ( static_cast< proshade_unsign > ( CSymList->at(possibilities->at(prIt))[0] ),
1576  CSymList->at(possibilities->at(prIt))[1],
1577  CSymList->at(possibilities->at(prIt))[2],
1578  CSymList->at(possibilities->at(prIt))[3],
1579  CSymList->at(possibilities->at(prIt))[5], &prosp, axErr );
1580  }
1581 
1582  //================================================ Start generating possible solutions
1583  for ( proshade_unsign rgIt1 = 0; rgIt1 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt1++ )
1584  {
1585  for ( proshade_unsign rgIt2 = 0; rgIt2 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt2++ )
1586  {
1587  //======================================== Use unique combinations (order matters here!)
1588  if ( rgIt1 == rgIt2 ) { continue; }
1589 
1590  //======================================== Generate possible solution (1)
1591  sol = ProSHADE_internal_maths::findVectorFromTwoVAndTwoD ( ret->at(rgIt1)[1], ret->at(rgIt1)[2], ret->at(rgIt1)[3],
1592  ret->at(rgIt2)[1], ret->at(rgIt2)[2], ret->at(rgIt2)[3], angle1, angle2 );
1593 
1594  //======================================== Check if solution fits the group completely
1595  ProSHADE_internal_symmetry::checkFittingAxisDualAndSave ( retGroup, ret, fold, sol.at(0), sol.at(1), sol.at(2), &prosp, axErr, noMatchesG1, angle1, noMatchesG2, angle2, dataObj );
1596  if ( prosp.size() == requiredNoAxes ) { break; }
1597 
1598  //======================================== Generate possible solution (2)
1599  sol = ProSHADE_internal_maths::findVectorFromTwoVAndTwoD ( ret->at(rgIt1)[1], ret->at(rgIt1)[2], ret->at(rgIt1)[3],
1600  ret->at(rgIt2)[1], ret->at(rgIt2)[2], ret->at(rgIt2)[3], -angle1, -angle2 );
1601 
1602  //======================================== Check if solution fits the group completely
1603  ProSHADE_internal_symmetry::checkFittingAxisDualAndSave ( retGroup, ret, fold, sol.at(0), sol.at(1), sol.at(2), &prosp, axErr, noMatchesG1, angle1, noMatchesG2, angle2, dataObj );
1604  if ( prosp.size() == requiredNoAxes ) { break; }
1605  }
1606 
1607  if ( prosp.size() == requiredNoAxes ) { break; }
1608  }
1609 
1610  //================================================ Found all required axes!
1611  if ( static_cast<proshade_unsign> ( prosp.size() ) == requiredNoAxes )
1612  {
1613  //============================================ Copy the detected axes
1614  for ( proshade_unsign iter = static_cast<proshade_unsign> ( possibilities->size() ); iter < static_cast<proshade_unsign> ( prosp.size() ); iter++ )
1615  {
1616  if ( ProSHADE_internal_maths::isAxisUnique ( CSymList, prosp.at(iter), axErr ) )
1617  {
1618  //==================================== Add
1619  ProSHADE_internal_misc::addToUnsignVector ( possibilities, static_cast< proshade_unsign > ( CSymList->size() ) );
1620  ProSHADE_internal_misc::addToDblPtrVector ( CSymList, prosp.at(iter) );
1621  }
1622  }
1623 
1624  //============================================ Done
1625  atLeastOne = true;
1626  return ( atLeastOne );
1627  }
1628  else
1629  {
1630  //============================================ Delete the created, but not used axes
1631  for ( proshade_unsign iter = static_cast<proshade_unsign> ( possibilities->size() ); iter < static_cast<proshade_unsign> ( prosp.size() ); iter++ )
1632  {
1633  delete[] prosp.at(iter);
1634  }
1635  }
1636 
1637  //================================================ Done
1638  return ( atLeastOne );
1639 
1640 }

◆ 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 2607 of file ProSHADE_symmetry.cpp.

2608 {
2609  //================================================ Initialise variables
2610  bool atLeastOne = false;
2611  std::vector< proshade_double* > prosp;
2612  std::vector< proshade_double > sol;
2613 
2614  //================================================ Proceed only if need be
2615  if ( static_cast<proshade_unsign> ( possibilities->size() ) == requiredNoAxes ) { atLeastOne = true; return ( atLeastOne ); }
2616 
2617  //================================================ Copy already found to prospective
2618  for ( proshade_unsign prIt = 0; prIt < static_cast<proshade_unsign> ( possibilities->size() ); prIt++ )
2619  {
2620  ProSHADE_internal_symmetry::addAxisUnlessSame ( static_cast< proshade_unsign > ( CSymList->at(possibilities->at(prIt))[0] ),
2621  CSymList->at(possibilities->at(prIt))[1],
2622  CSymList->at(possibilities->at(prIt))[2],
2623  CSymList->at(possibilities->at(prIt))[3],
2624  CSymList->at(possibilities->at(prIt))[5], &prosp, axErr );
2625  }
2626 
2627  //================================================ Start generating possible solutions
2628  for ( proshade_unsign rgIt1 = 0; rgIt1 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt1++ )
2629  {
2630  for ( proshade_unsign rgIt2 = 0; rgIt2 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt2++ )
2631  {
2632  //======================================== Use unique combinations (order matters here!)
2633  if ( rgIt1 == rgIt2 ) { continue; }
2634 
2635  for ( proshade_unsign rgIt3 = 0; rgIt3 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt3++ )
2636  {
2637  //==================================== Use unique combinations (order matters here!)
2638  if ( ( rgIt1 == rgIt3 ) || ( rgIt2 == rgIt3 ) ) { continue; }
2639 
2640  //==================================== Generate possible solution (1)
2641  sol = ProSHADE_internal_maths::findVectorFromThreeVAndThreeD ( ret->at(rgIt1)[1], ret->at(rgIt1)[2], ret->at(rgIt1)[3],
2642  ret->at(rgIt2)[1], ret->at(rgIt2)[2], ret->at(rgIt2)[3],
2643  ret->at(rgIt3)[1], ret->at(rgIt3)[2], ret->at(rgIt3)[3], angle1, angle2, angle3 );
2644 
2645  //==================================== Check if solution fits the group completely
2646  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 );
2647  if ( prosp.size() == requiredNoAxes ) { break; }
2648 
2649  //==================================== Generate possible solution (2)
2650  sol = ProSHADE_internal_maths::findVectorFromThreeVAndThreeD ( ret->at(rgIt1)[1], ret->at(rgIt1)[2], ret->at(rgIt1)[3],
2651  ret->at(rgIt2)[1], ret->at(rgIt2)[2], ret->at(rgIt2)[3],
2652  ret->at(rgIt3)[1], ret->at(rgIt3)[2], ret->at(rgIt3)[3], -angle1, -angle2, -angle3 );
2653 
2654  //==================================== Check if solution fits the group completely
2655  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 );
2656  if ( prosp.size() == requiredNoAxes ) { break; }
2657  }
2658 
2659  if ( prosp.size() == requiredNoAxes ) { break; }
2660  }
2661 
2662  if ( prosp.size() == requiredNoAxes ) { break; }
2663  }
2664 
2665  //================================================ Found all required axes
2666  if ( prosp.size() == requiredNoAxes )
2667  {
2668  //============================================ For each found missing axis
2669  for ( proshade_unsign axIt = static_cast<proshade_unsign> ( possibilities->size() ); axIt < static_cast<proshade_unsign> ( prosp.size() ); axIt++ )
2670  {
2671  if ( ProSHADE_internal_maths::isAxisUnique ( CSymList, prosp.at(axIt), axErr ) )
2672  {
2673  //======================================== Add
2674  ProSHADE_internal_misc::addToDblPtrVector ( CSymList, prosp.at(axIt) );
2675  ProSHADE_internal_misc::addToUnsignVector ( possibilities, static_cast<proshade_unsign> ( CSymList->size()-1 ) );
2676  }
2677  }
2678 
2679  atLeastOne = true;
2680  return ( atLeastOne );
2681  }
2682  else
2683  {
2684  //============================================ Delete all found, but unnecessary axes
2685  for ( proshade_unsign axIt = static_cast<proshade_unsign> ( possibilities->size() ); axIt < static_cast<proshade_unsign> ( prosp.size() ); axIt++ )
2686  {
2687  delete[] prosp.at(axIt);
2688  }
2689  }
2690 
2691  //================================================ Done
2692  return ( atLeastOne );
2693 
2694 }

◆ 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 821 of file ProSHADE_symmetry.cpp.

822 {
823  //================================================ Initialise variables
824  proshade_double euA, euB, euG, xPk, yPk, zPk, anglPk;
825  proshade_double* rotMat = new proshade_double [9];
826  ProSHADE_internal_misc::checkMemoryAllocation ( rotMat, __FILE__, __LINE__, __func__ );
827  proshade_unsign arrIndex;
828  std::vector< proshade_double* > angVec;
829 
830  //================================================ Search the self-rotation map
831  for ( proshade_unsign xIt = 0; xIt < ( dataObj->getMaxBand() * 2 ); xIt++ )
832  {
833  for ( proshade_unsign yIt = 0; yIt < ( dataObj->getMaxBand() * 2 ); yIt++ )
834  {
835  for ( proshade_unsign zIt = 0; zIt < ( dataObj->getMaxBand() * 2 ); zIt++ )
836  {
837  //==================================== Get height and check against threshold
838  arrIndex = zIt + ( dataObj->getMaxBand() * 2 ) * ( yIt + ( dataObj->getMaxBand() * 2 ) * xIt );
839 
840  //==================================== Get angle-axis values
841  ProSHADE_internal_maths::getEulerZXZFromSOFTPosition ( static_cast< proshade_signed > ( dataObj->getMaxBand() ), static_cast< proshade_signed > ( xIt ),
842  static_cast< proshade_signed > ( yIt ), static_cast< proshade_signed > ( zIt ),
843  &euA, &euB, &euG );
845  ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( rotMat, &xPk, &yPk, &zPk, &anglPk );
846 
847  //==================================== Set largest axis element to positive
848  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( xPk ), std::max( std::abs ( yPk ), std::abs ( zPk ) ) ) );
849  const FloatingPoint< proshade_double > rhs1 ( std::abs ( xPk ));
850  const FloatingPoint< proshade_double > rhs2 ( std::abs ( yPk ) );
851  const FloatingPoint< proshade_double > rhs3 ( std::abs ( zPk ) );
852  if ( ( lhs1.AlmostEquals ( rhs1 ) && ( xPk < 0.0 ) ) ||
853  ( lhs1.AlmostEquals ( rhs2 ) && ( yPk < 0.0 ) ) ||
854  ( lhs1.AlmostEquals ( rhs3 ) && ( zPk < 0.0 ) ) )
855  {
856  xPk *= -1.0;
857  yPk *= -1.0;
858  zPk *= -1.0;
859  anglPk *= -1.0;
860  }
861 
862  //==================================== Does the peak match the required axis?
863  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( xPk, yPk, zPk, xVal, yVal, zVal, axErr ) )
864  {
865  //================================ Matching map point - save it
866  proshade_double* hlpArr = new proshade_double [2];
867  ProSHADE_internal_misc::checkMemoryAllocation ( hlpArr, __FILE__, __LINE__, __func__ );
868  hlpArr[0] = anglPk + M_PI;
869  hlpArr[1] = pow( dataObj->getInvSO3Coeffs()[arrIndex][0], 2.0 ) +
870  pow( dataObj->getInvSO3Coeffs()[arrIndex][1], 2.0 );
871  ProSHADE_internal_misc::addToDblPtrVector ( &angVec, hlpArr );
872  }
873  }
874  }
875  }
876 
877  //================================================ Release memory
878  delete[] rotMat;
879 
880  //================================================ Done
881  return ( angVec );
882 
883 }

◆ 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 1331 of file ProSHADE_symmetry.cpp.

1332 {
1333  //================================================ Initialise variables
1334  std::vector< proshade_unsign > C4PossibilitiesHlp;
1335  std::vector< std::vector< proshade_unsign > > C4Possibilities;
1336  bool groupMatched;
1337 
1338  //================================================ Report progress
1339  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of three C4 axes.", messageShift );
1340 
1341  //================================================ For all symmetries in the C symmetries list
1342  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
1343  {
1344  //============================================ Search only using C4s
1345  if ( CSymList->at(cIt)[0] != 4.0 || CSymList->at(cIt)[5] < minPeakHeight ) { continue; }
1346 
1347  //============================================ If second or more C4, check if it has the correct angle to all other already found C4s for each group
1348  groupMatched = false;
1349  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C4Possibilities.size() ); gIt++ )
1350  {
1351  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; }
1352  }
1353 
1354  //=========================================== If no group matched, create a new group
1355  if ( !groupMatched ) { C4PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C4PossibilitiesHlp, cIt ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C4Possibilities, C4PossibilitiesHlp ); continue; }
1356  }
1357 
1358  //================================================ Test for missing symmetry axes, if need be
1359  ProSHADE_internal_symmetry::findMissingAxes ( &C4Possibilities, CSymList, 3, axErr, 0.0, 4, dataObj, minPeakHeight );
1360 
1361  //================================================ Any group has 3 entries? If more such groups, take the one with highest average height.
1362  proshade_double maxHeight = 0.0; proshade_unsign maxGrp = 0;
1363  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; } } }
1364 
1365  if ( C4Possibilities.at(maxGrp).size() == 3 )
1366  {
1367  //============================================ Success! Save and exit
1368  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)) ); }
1369 
1370  //============================================ Report progress
1371  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of three C4 axes successfull.", messageShift );
1372 
1373  //============================================ Done
1374  return ;
1375  }
1376 
1377  //================================================ Done
1378  return ;
1379 
1380 }

◆ 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 1398 of file ProSHADE_symmetry.cpp.

1399 {
1400  //================================================ Initialise variables
1401  std::vector< proshade_unsign > C4s, prospectiveC3s, C3PossibilitiesHlp;
1402  std::vector< std::vector< proshade_unsign > > C3Possibilities;
1403  proshade_double dotProd;
1404  bool groupMatched;
1405  for ( proshade_unsign iter = 0; iter < 3; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &C4s, iter ); }
1406 
1407  //================================================ Report progress
1408  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of four C3 axes.", messageShift );
1409 
1410  //================================================ For each C4
1411  for ( proshade_unsign rIt = 0; rIt < static_cast<proshade_unsign> ( ret->size() ); rIt++ )
1412  {
1413  //============================================ For each C3, check it has angle ( acos( 1/sqrt(3) ) ) to the tested C4
1414  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
1415  {
1416  //======================================== Search only using C3s
1417  if ( CSymList->at(cIt)[0] != 3.0 || CSymList->at(cIt)[5] < minPeakHeight ) { continue; }
1418 
1419  //======================================== Check the C3 axis to the C4 ( acos ( 1/sqrt(3) ) )
1420  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] );
1421 
1422  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 ); }
1423  }
1424  }
1425 
1426  //================================================ Group the prospective C3s
1427  C3Possibilities.clear(); C3PossibilitiesHlp.clear();
1428  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( prospectiveC3s.size() ); cIt++ )
1429  {
1430  //============================================ If second or more C3, check if it can be placed in any group with having acos (1/3) to all its members
1431  groupMatched = false;
1432  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C3Possibilities.size() ); gIt++ )
1433  {
1434  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; }
1435  }
1436 
1437  //============================================ If no group matched, create a new group
1438  if ( !groupMatched ) { C3PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C3PossibilitiesHlp, prospectiveC3s.at(cIt) ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C3Possibilities, C3PossibilitiesHlp ); continue; }
1439  }
1440 
1441  //================================================ Find the best group or return empty
1442  while ( C3Possibilities.size() != 0 )
1443  {
1444  //============================================ Test for missing symmetry axes, if need be
1445  ProSHADE_internal_symmetry::findMissingAxes ( &C3Possibilities, CSymList, 4, axErr, 1.0/3.0, 3, dataObj, minPeakHeight );
1446 
1447  //============================================ Found four C3s?
1448  if ( C3Possibilities.at(0).size() == 4 )
1449  {
1450  //======================================== Success! Save and exit
1451  for ( proshade_unsign it = 0; it < 4; it++ ) { ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(C3Possibilities.at(0).at(it)) ); }
1452 
1453  //======================================== Report progress
1454  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of four C3 axes successfull.", messageShift );
1455 
1456  //======================================== Done
1457  return ;
1458  }
1459  else { C3Possibilities.erase ( C3Possibilities.begin() ); }
1460  }
1461 
1462  //================================================ Done
1463  return ;
1464 
1465 }

◆ 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 1481 of file ProSHADE_symmetry.cpp.

1482 {
1483  //================================================ Initialise variables
1484  std::vector< proshade_unsign > prospectiveC2s, retGrp;
1485  proshade_double dotProd;
1486  proshade_unsign noPerpendicular, noSqrtTwo;
1487 
1488  //================================================ Report progress
1489  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of six C2 axes.", messageShift );
1490 
1491  //================================================ For each C2
1492  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
1493  {
1494  //============================================ Use only C2s
1495  const FloatingPoint< proshade_double > lhs999 ( CSymList->at(cIt)[5] ), rhs999 ( static_cast< proshade_double > ( -999.9 ) );
1496  if ( CSymList->at(cIt)[0] != 2.0 || ( ( CSymList->at(cIt)[5] < minPeakHeight ) && ! ( lhs999.AlmostEquals( rhs999 ) ) ) ) { continue; }
1497 
1498  //============================================ Check the C2 has acos ( 1/sqrt(2) ) to 2 C4s and acos ( 0.0 ) to the third C4
1499  noPerpendicular = 0; noSqrtTwo = 0;
1500  for ( proshade_unsign rIt = 0; rIt < 3; rIt++ )
1501  {
1502  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1],
1503  &ret->at(rIt)[2],
1504  &ret->at(rIt)[3],
1505  &CSymList->at(cIt)[1],
1506  &CSymList->at(cIt)[2],
1507  &CSymList->at(cIt)[3] );
1508 
1509  if ( ( std::abs ( dotProd ) > ( ( 1.0 / sqrt(2.0) ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( 1.0 / sqrt(2.0) ) + axErr ) ) ) { noSqrtTwo += 1; continue; }
1510  if ( ( std::abs ( dotProd ) > ( 0.0 - axErr ) ) && ( std::abs ( dotProd ) < ( 0.0 + axErr ) ) ) { noPerpendicular += 1; continue; }
1511  }
1512 
1513  //============================================ If correct angles distribution is found, save the axis
1514  if ( ( noSqrtTwo == 2 ) && ( noPerpendicular == 1 ) )
1515  {
1516  ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC2s, cIt );
1517  }
1518  }
1519 
1520  //================================================ Search for missing axes
1521  for ( proshade_unsign iter = 0; iter < 3; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &retGrp, iter ); }
1522  if ( !ProSHADE_internal_symmetry::findMissingAxesDual ( &prospectiveC2s, CSymList, ret, &retGrp, 6, axErr, 1, 0.0, 2, 1/sqrt(2.0), 2, dataObj ) )
1523  {
1524  return ;
1525  }
1526 
1527  //================================================ Found correct number of axes! Now save the
1528  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( prospectiveC2s.size() ); iter++ )
1529  {
1530  ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(prospectiveC2s.at(iter)) );
1531  }
1532 
1533  //================================================ Report progress
1534  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of six C2 axes successfull.", messageShift );
1535 
1536  //================================================ Done
1537  return ;
1538 
1539 }

◆ 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 3935 of file ProSHADE_symmetry.cpp.

3936 {
3937  //================================================ Initialise local variables
3938  std::vector< proshade_double > pointOnLine ( 3, 0.0 );
3939  std::vector< proshade_double > identityMat ( 9, 0.0 ); identityMat.at(0) = 1.0; identityMat.at(4) = 1.0; identityMat.at(8) = 1.0;
3940 
3941  //================================================ For each symmetry element in this cyclic group
3942  for ( size_t gEl = 0; gEl < symElems.size(); gEl++ )
3943  {
3944  //============================================ Ignore identity element
3945  if ( ProSHADE_internal_maths::rotationMatrixSimilarity ( &symElems.at(gEl), &identityMat, 0.01 ) ) { continue; }
3946 
3947  //============================================ Find translation difference between rotated and original map
3948  std::vector< proshade_double > trsCenHlp = ProSHADE_internal_symmetry::findTranslationBetweenRotatedAndOriginalMap ( symStr,
3949  symElems.at(gEl),
3950  origCoeffs, rotMapComplex,
3951  rotCoeffs, planForwardFourierRot,
3952  trFuncCoeffs, trFunc,
3953  planReverseFourierComb );
3954 
3955  //============================================ Sum translations over the whole axis
3956  pointOnLine.at(0) += trsCenHlp.at(0);
3957  pointOnLine.at(1) += trsCenHlp.at(1);
3958  pointOnLine.at(2) += trsCenHlp.at(2);
3959  }
3960 
3961  //================================================ Average over all symmetry elements (including the identity one)
3962  pointOnLine.at(0) /= static_cast< proshade_double > ( symElems.size() );
3963  pointOnLine.at(1) /= static_cast< proshade_double > ( symElems.size() );
3964  pointOnLine.at(2) /= static_cast< proshade_double > ( symElems.size() );
3965 
3966  //================================================ Done
3967  return ( pointOnLine );
3968 
3969 }

◆ 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 3022 of file ProSHADE_symmetry.cpp.

3023 {
3024  //================================================ Initialise variables
3025  std::vector < proshade_unsign > folds;
3026  std::vector < proshade_double > angs, applicableAngs;
3027  bool alreadyFound = false;
3028  size_t corAngIt = 0;
3029  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;
3030  proshade_double latSamlUnit = ( 2.0 * M_PI ) / ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 );
3031  proshade_double lonSamlUnit = ( 1.0 * M_PI ) / ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 );
3032 
3033  //================================================ Determine all the folds for which rotation function mapping will be required
3034  for ( proshade_unsign iter = 0; iter < static_cast < proshade_unsign > ( ret->size() ); iter++ )
3035  {
3036  alreadyFound = false;
3037  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; } }
3038 
3039  if ( !alreadyFound ) { ProSHADE_internal_misc::addToUnsignVector ( &folds, static_cast< proshade_unsign > ( ret->at(iter)[0] ) ); }
3040  }
3041 
3042  //================================================ Generate vector of all angles
3043  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) ) ) ); } }
3044  std::sort ( angs.begin(), angs.end() );
3045 
3046  //================================================ Remove redundant angles from the list
3047  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) ); } }
3048 
3049  //================================================ Generate all sphere mapped rotation function
3050  dataObj->sphereMappedRotFun.clear();
3051  for ( size_t angIt = 0; angIt < angs.size(); angIt++ )
3052  {
3053  //============================================ Decide the range in which the sphere operates
3054  if ( ( angIt == 0 ) && ( angs.size() > 1 ) ) { radRange = ( angs.at(1) - angs.at(0) ) / 2; }
3055  else { if ( ( angIt == ( angs.size() - 1 ) ) && ( angs.size() > 1 ) ) { radRange = ( angs.at(angIt) - angs.at(angIt-1) ) / 2; }
3056  else { if ( angs.size() > 2 ) { radRange = std::min ( ( angs.at(angIt) - angs.at(angIt-1) ) / 2, ( angs.at(angIt+1) - angs.at(angIt) ) / 2 ); }
3057  else { radRange = 0.5; } } }
3058 
3059  //============================================ Create the sphere
3060  dataObj->sphereMappedRotFun.emplace_back ( new ProSHADE_internal_spheres::ProSHADE_rotFun_sphere ( angs.at(angIt),
3061  radRange,
3062  dataObj->maxShellBand * 2,
3063  angs.at(angIt),
3064  static_cast<proshade_unsign> ( angIt ) ) );
3065 
3066  //=========================================== Interpolate rotation function onto the sphere
3067  dataObj->sphereMappedRotFun.at( static_cast < proshade_unsign > ( angIt ))->interpolateSphereValues ( dataObj->getInvSO3Coeffs ( ) );
3068  }
3069 
3070  //================================================ Check for improved sum
3071  searchRangeInDeg = 360.0 / ( dataObj->getMaxBand() * 2.0 );
3072  proshade_double* rotMat, *newAxis;
3073  while ( searchRangeInDeg > 0.09 )
3074  {
3075  //============================================ For change along each dimension
3076  for ( proshade_double xChan = -searchRangeInDeg; xChan < ( 1.5 * searchRangeInDeg ); xChan += searchRangeInDeg )
3077  {
3078  for ( proshade_double yChan = -searchRangeInDeg; yChan < ( 1.5 * searchRangeInDeg ); yChan += searchRangeInDeg )
3079  {
3080  for ( proshade_double zChan = -searchRangeInDeg; zChan < ( 1.5 * searchRangeInDeg ); zChan += searchRangeInDeg )
3081  {
3082  //================================ Initialise local variables
3083  curSum = 0.0;
3084 
3085  //================================ Find the rotation matrix of the appropriate rotation
3086  rotMat = ProSHADE_internal_maths::build3x3MatrixFromXYZRotations ( xChan + finXRotChan, yChan + finYRotChan, zChan + finZRotChan );
3087 
3088  //================================ For each axis, find new position and its RF value
3089  for ( proshade_unsign axIt = 0; axIt < static_cast< proshade_unsign > ( ret->size() ); axIt++ )
3090  {
3091  //============================ Find rotated axis
3092  newAxis = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMat, ret->at(axIt)[1], ret->at(axIt)[2], ret->at(axIt)[3] );
3093 
3094  //============================ Convert XYZ to lat and lon INDICES
3095  lat = ( std::atan2( newAxis[1], newAxis[0] ) / latSamlUnit );
3096  lon = ( std::acos ( newAxis[2] ) / lonSamlUnit );
3097 
3098  if ( lat < 0.0 ) { lat += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3099  if ( lon < 0.0 ) { lon += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3100 
3101  //============================ Generate all angles for this fold
3102  applicableAngs.clear ( );
3103  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] ) ); }
3104 
3105  //============================ For each shpere with the correct angle, average the peak heights
3106  axSum = 1.0;
3107  for ( size_t angIt = 0; angIt < angs.size(); angIt++ )
3108  {
3109  //======================== Find the correct sphere
3110  alreadyFound = false;
3111  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; } }
3112 
3113  if ( !alreadyFound ) { continue; }
3114 
3115  //======================== Get its peak height for the longitude and latitude
3116  axSum += dataObj->sphereMappedRotFun.at(corAngIt)->getSphereLatLonLinearInterpolationPos ( lat, lon );
3117  }
3118 
3119  //============================ And average the peak heights over the axis
3120  axSum /= ret->at(axIt)[0];
3121  curSum += axSum;
3122 
3123  //============================ Release memory
3124  delete[] newAxis;
3125  }
3126 
3127  //================================ And average the peak heights over all axes
3128  curSum /= static_cast< proshade_double > ( ret->size() );
3129 
3130  //================================ If improved, save
3131  if ( curSum > maxSum )
3132  {
3133  maxSum = curSum;
3134  bestXRot = xChan;
3135  bestYRot = yChan;
3136  bestZRot = zChan;
3137  }
3138 
3139  //================================ Release memory
3140  delete[] rotMat;
3141 
3142 
3143  }
3144  }
3145  }
3146 
3147  //============================================ Prepare for next iteration
3148  searchRangeInDeg /= 2.0;
3149  finXRotChan += bestXRot;
3150  finYRotChan += bestYRot;
3151  finZRotChan += bestZRot;
3152  bestXRot = 0.0;
3153  bestYRot = 0.0;
3154  bestZRot = 0.0;
3155  }
3156 
3157  //================================================ Apply the optimisation
3158  rotMat = ProSHADE_internal_maths::build3x3MatrixFromXYZRotations ( finXRotChan, finYRotChan, finZRotChan );
3159  for ( proshade_unsign axIt = 0; axIt < static_cast< proshade_unsign > ( ret->size() ); axIt++ )
3160  {
3161  //============================================ Find the rotated axis
3162  newAxis = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMat, ret->at(axIt)[1], ret->at(axIt)[2], ret->at(axIt)[3] );
3163 
3164  //============================================ Change axes
3165  ret->at(axIt)[1] = newAxis[0];
3166  ret->at(axIt)[2] = newAxis[1];
3167  ret->at(axIt)[3] = newAxis[2];
3168  }
3169 
3170  //================================================ Release memory
3171  delete[] rotMat;
3172 
3173  //================================================ For each ret axis, compute predicted position
3174  for ( proshade_unsign axIt = 0; axIt < static_cast< proshade_unsign > ( ret->size() ); axIt++ )
3175  {
3176  //============================================ Convert XYZ to lat and lon INDICES
3177  lat = std::atan2( ret->at(axIt)[2], ret->at(axIt)[1] ) / latSamlUnit;
3178  lon = std::acos ( ret->at(axIt)[3] ) / lonSamlUnit;
3179 
3180  if ( lat < 0.0 ) { lat += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3181  if ( lon < 0.0 ) { lon += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3182 
3183  //============================================ Generate all angles for this fold
3184  applicableAngs.clear ( );
3185  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] ) ); }
3186 
3187  //============================================ For each shpere with the correct angle, average the peak heights
3188  ret->at(axIt)[5] = 0.0;
3189  for ( size_t angIt = 0; angIt < angs.size(); angIt++ )
3190  {
3191  //======================================== Find the correct sphere
3192  alreadyFound = false;
3193  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; } }
3194 
3195  if ( !alreadyFound ) { continue; }
3196 
3197  //======================================== Get its peak height for the longitude and latitude
3198  ret->at(axIt)[5] += dataObj->sphereMappedRotFun.at(corAngIt)->getSphereLatLonLinearInterpolationPos ( lat, lon );
3199  }
3200 
3201  //============================================ And average the peak heights over the axis
3202  ret->at(axIt)[5] /= ( ret->at(axIt)[0] - 1.0 );
3203  maxSum += ret->at(axIt)[5];
3204  }
3205 
3206  //================================================ Report progress
3207  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 3, "Peak height detection and rotation optimisation complete.", settings->messageShift );
3208 
3209  //================================================ Done
3210  return ;
3211 
3212 }

◆ 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 3367 of file ProSHADE_symmetry.cpp.

3368 {
3369  //================================================ Initialise variables
3370  proshade_double height = 0.0;
3371  proshade_double lat, lon;
3372  proshade_double latSamlUnit = ( 2.0 * M_PI ) / ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 );
3373  proshade_double lonSamlUnit = ( 1.0 * M_PI ) / ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 );
3374 
3375  //================================================ Make sure we have a clean start
3376  dataObj->sphereMappedRotFun.clear ( );
3377 
3378  //================================================ Convert rotation function to only the required angle-axis space spheres and find all peaks
3379  for ( proshade_double angIt = 1.0; angIt < fold; angIt += 1.0 )
3380  {
3381  //============================================ Create the angle-axis sphere with correct radius (angle)
3382  dataObj->sphereMappedRotFun.emplace_back ( new ProSHADE_internal_spheres::ProSHADE_rotFun_sphere ( angIt * ( 2.0 * M_PI / fold ),
3383  M_PI / fold,
3384  dataObj->maxShellBand * 2,
3385  angIt * ( 2.0 * M_PI / fold ),
3386  static_cast<proshade_unsign> ( angIt - 1.0 ) ) );
3387 
3388  //============================================ Interpolate rotation function onto the sphere
3389  dataObj->sphereMappedRotFun.at( static_cast < proshade_unsign > ( angIt - 1.0 ))->interpolateSphereValues ( dataObj->getInvSO3Coeffs ( ) );
3390  }
3391 
3392  //================================================ Convert XYZ to lat and lon INDICES
3393  lat = std::atan2( axis[1], axis[0] ) / latSamlUnit;
3394  lon = std::acos ( axis[2] ) / lonSamlUnit;
3395 
3396  if ( lat < 0.0 ) { lat += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3397  if ( lon < 0.0 ) { lon += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3398 
3399  lat = std::round ( lat );
3400  lon = std::round ( lon );
3401 
3402  //================================================ Initialise the peak group
3404 
3405  //================================================ Construct a peak group with entry from each sphere with the axis as the peak
3406  for ( proshade_unsign sphIt = 0; sphIt < static_cast<proshade_unsign> ( dataObj->sphereMappedRotFun.size() ); sphIt++ )
3407  {
3408  if ( sphIt == 0 )
3409  {
3410  //======================================== If first sphere, create the peak group
3411  grp = new ProSHADE_internal_spheres::ProSHADE_rotFun_spherePeakGroup ( lat, lon, sphIt, dataObj->sphereMappedRotFun.at(sphIt)->getAngularDim() );
3412  }
3413  else
3414  {
3415  //======================================== Add to the existing object
3416  grp->checkIfPeakBelongs ( lat, lon, sphIt, settings->axisErrTolerance, settings->verbose, settings->messageShift );
3417  }
3418  }
3419 
3420  //================================================ Find the peak height
3421  std::vector < proshade_double* > detectedAxis;
3422  grp->findCyclicPointGroupsGivenFold ( dataObj->sphereMappedRotFun, &detectedAxis, settings->useBiCubicInterpolationOnPeaks, static_cast< proshade_unsign > ( fold ), settings->verbose, settings->messageShift );
3423 
3424  //================================================ Save it!
3425  if ( detectedAxis.size() > 0 ) { height = detectedAxis.at(0)[5]; }
3426  else { height = 0.0; }
3427 
3428  //================================================ Release memory
3429  for ( proshade_unsign i = 0; i < static_cast < proshade_unsign > ( detectedAxis.size() ); i++ ) { delete detectedAxis.at(i); }
3430  delete grp;
3431 
3432  //================================================ Done
3433  return ( height );
3434 
3435 }

◆ findReliableUnphasedSymmetries()

std::vector< proshade_unsign > ProSHADE_internal_symmetry::findReliableUnphasedSymmetries ( std::vector< std::vector< proshade_double > > *  allCs,
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]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 3674 of file ProSHADE_symmetry.cpp.

3675 {
3676  //================================================ Report progress
3677  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Deciding whether any axis(es) is/are reliable.", messageShift );
3678 
3679  //================================================ Initialise local variables
3680  std::vector< proshade_unsign > ret;
3681 
3682  //================================================ Find the threshold
3683  proshade_double bestHistPeakStart = ProSHADE_internal_maths::findTopGroupSmooth ( allCs, 5, 0.01, 0.03, 5 );
3684  proshade_double bestFSCPeakStart = ProSHADE_internal_maths::findTopGroupSmooth ( allCs, 6, 0.01, 0.005, 5, 0.94 );
3685  if ( bestHistPeakStart > 0.9 ) { bestHistPeakStart = 0.9; }
3686 
3687  //================================================ Are any axes orthogonal
3688  proshade_double dotProduct, maxOrtSum = 0.0, curOrtSum = 0.0;
3689  proshade_unsign maxOrtAx1 = 0, maxOrtAx2 = 0;
3690  for ( size_t relAx1 = 0; relAx1 < allCs->size(); relAx1++ )
3691  {
3692  //============================================ Consider only reliable axes
3693  if ( allCs->at(relAx1)[5] < bestHistPeakStart ) { continue; }
3694  if ( allCs->at(relAx1)[6] < bestFSCPeakStart ) { continue; }
3695 
3696  for ( size_t relAx2 = 1; relAx2 < allCs->size(); relAx2++ )
3697  {
3698  //======================================== Ignore same axes
3699  if ( relAx1 >= relAx2 ) { continue; }
3700 
3701  //======================================== Consider only reliable axes
3702  if ( allCs->at(relAx2)[5] < bestHistPeakStart ) { continue; }
3703  if ( allCs->at(relAx2)[6] < bestFSCPeakStart ) { continue; }
3704 
3705  //======================================== Are the two axes orthogonal?
3706  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &allCs->at(relAx1)[1], &allCs->at(relAx1)[2],
3707  &allCs->at(relAx1)[3], &allCs->at(relAx2)[1],
3708  &allCs->at(relAx2)[2], &allCs->at(relAx2)[3] );
3709 
3710  //======================================== If close to zero, these two axes are perpendicular
3711  if ( std::abs( dotProduct ) < tolerance )
3712  {
3713  //==================================== Find sum
3714  curOrtSum = allCs->at(relAx1)[5] + allCs->at(relAx1)[6] + allCs->at(relAx2)[5] + allCs->at(relAx2)[6];
3715 
3716  //==================================== If best, save it
3717  if ( curOrtSum > maxOrtSum )
3718  {
3719  maxOrtSum = curOrtSum;
3720  maxOrtAx1 = static_cast< proshade_unsign > ( relAx1 );
3721  maxOrtAx2 = static_cast< proshade_unsign > ( relAx2 );
3722  }
3723  }
3724  }
3725  }
3726 
3727  //================================================ If any orthogonal pair was found, return it
3728  if ( maxOrtAx2 != 0 )
3729  {
3730  //================================================ Report progress
3731  ProSHADE_internal_misc::addToUnsignVector ( &ret, maxOrtAx1 );
3732  ProSHADE_internal_misc::addToUnsignVector ( &ret, maxOrtAx2 );
3733  return ( ret );
3734  }
3735 
3736  //================================================ Well, no orthogonal axes. Is there at least one good axis?
3737  curOrtSum = 0.0; maxOrtSum = 0.0;
3738  for ( size_t relAx1 = 0; relAx1 < allCs->size(); relAx1++ )
3739  {
3740  //============================================ Consider only reliable axes in terms of RF
3741  if ( allCs->at(relAx1)[5] < bestHistPeakStart ) { continue; }
3742 
3743  //============================================ Consider only reasonable axes in terms of FSC
3744  if ( allCs->at(relAx1)[6] < 0.3 ) { continue; }
3745 
3746  //============================================ Get the sum
3747  curOrtSum = allCs->at(relAx1)[5] + allCs->at(relAx1)[6];
3748 
3749  //============================================ If highest sum, save
3750  if ( curOrtSum > maxOrtSum )
3751  {
3752  maxOrtSum = curOrtSum;
3753  maxOrtAx1 = static_cast< proshade_unsign > ( relAx1 );
3754  }
3755  }
3756 
3757  //================================================ If anything was found, save it
3758  if ( maxOrtSum > 0.1 )
3759  {
3760  //============================================ Report progress
3761  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Found single reliable axis.", messageShift );
3762 
3763  ProSHADE_internal_misc::addToUnsignVector ( &ret, maxOrtAx1 );
3764  }
3765  else
3766  {
3767  //================================================ Report progress
3768  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Found no reliable axis.", messageShift );
3769  }
3770 
3771  //================================================ Done
3772  return ( ret );
3773 
3774 }

◆ 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 1076 of file ProSHADE_symmetry.cpp.

1077 {
1078  //================================================ Initialise variables
1079  std::vector< proshade_unsign > C3s, prospectiveC2s, C2PossibilitiesHlp;
1080  std::vector< std::vector< proshade_unsign > > C2Possibilities;
1081  proshade_double dotProd;
1082  bool groupMatched;
1083  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &C3s, iter ); }
1084 
1085  //================================================ Report progress
1086  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of three C2 axes.", messageShift );
1087 
1088  //================================================ For each C3
1089  for ( proshade_unsign rIt = 0; rIt < static_cast<proshade_unsign> ( ret->size() ); rIt++ )
1090  {
1091  //============================================ For each C2, check it has angle ( acos(0.5) ) to the tested C3
1092  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
1093  {
1094  //======================================== Search only using C2s
1095  const FloatingPoint< proshade_double > lhs999 ( CSymList->at(cIt)[5] ), rhs999 ( static_cast< proshade_double > ( -999.9 ) );
1096  if ( CSymList->at(cIt)[0] != 2.0 || ( ( CSymList->at(cIt)[5] < minPeakHeight ) && !( lhs999.AlmostEquals( rhs999 ) ) ) ) { continue; }
1097 
1098  //======================================== Check the C2 axis to the C3 ( acos ( 0.5 ) )
1099  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1], &ret->at(rIt)[2], &ret->at(rIt)[3],
1100  &CSymList->at(cIt)[1], &CSymList->at(cIt)[2], &CSymList->at(cIt)[3] );
1101 
1102  if ( ( std::abs ( dotProd ) > ( 0.5 - axErr ) ) && ( std::abs ( dotProd ) < ( 0.5 + axErr ) ) ) { ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC2s, cIt ); }
1103  }
1104  }
1105 
1106  //================================================ Group the prospective C2s
1107  C2Possibilities.clear(); C2PossibilitiesHlp.clear();
1108  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( prospectiveC2s.size() ); cIt++ )
1109  {
1110  //============================================ If second or more C2, check if it can be placed in any group with being perpendicular to all its members
1111  groupMatched = false;
1112  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C2Possibilities.size() ); gIt++ )
1113  {
1114  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; }
1115  }
1116 
1117  //============================================ If no group matched, create a new group
1118  if ( !groupMatched ) { C2PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C2PossibilitiesHlp, prospectiveC2s.at(cIt) ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C2Possibilities, C2PossibilitiesHlp ); continue; }
1119  }
1120 
1121  //================================================ Find the best group or return empty
1122  while ( C2Possibilities.size() != 0 )
1123  {
1124  //============================================ Test for missing symmetry axes, if need be
1125  ProSHADE_internal_symmetry::findMissingAxes ( &C2Possibilities, CSymList, 3, axErr, 0.0, 2, dataObj, minPeakHeight );
1126 
1127  //============================================ Found 3 C2s?
1128  if ( C2Possibilities.at(0).size() == 3 )
1129  {
1130  //======================================== Success! Save and exit
1131  for ( proshade_unsign it = 0; it < 3; it++ ) { ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(C2Possibilities.at(0).at(it)) ); }
1132 
1133  //======================================== Report progress
1134  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of three C2 axes successfull.", messageShift );
1135 
1136  //======================================== Done
1137  return ;
1138  }
1139  else { C2Possibilities.erase ( C2Possibilities.begin() ); }
1140  }
1141 
1142  //================================================ Done
1143  return ;
1144 
1145 }

◆ 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 539 of file ProSHADE_symmetry.cpp.

540 {
541  //================================================ Initialise variables
542  std::vector< proshade_unsign > C3PossibilitiesHlp;
543  std::vector< std::vector< proshade_unsign > > C3Possibilities;
544  bool groupMatched;
545 
546  //================================================ Report progress
547  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of four C3 axes.", messageShift );
548 
549  //================================================ For all symmetries in the C symmetries list
550  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
551  {
552  //============================================ Search only using C3s
553  if ( CSymList->at(cIt)[0] != 3.0 || CSymList->at(cIt)[0] < minPeakHeight ) { continue; }
554 
555  //============================================ If this is the first C3, then just save it to the first group of the temporary holder
556  if ( C3Possibilities.size() == 0 ) { ProSHADE_internal_misc::addToUnsignVector ( &C3PossibilitiesHlp, cIt ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C3Possibilities, C3PossibilitiesHlp ); continue; }
557 
558  //============================================ If second or more C3, check if it has the correct angle to all other already found C3s for each group
559  groupMatched = false;
560  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C3Possibilities.size() ); gIt++ )
561  {
562  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; }
563  }
564 
565  //============================================ If no group matched, create a new group
566  if ( !groupMatched ) { C3PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C3PossibilitiesHlp, cIt ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C3Possibilities, C3PossibilitiesHlp ); continue; }
567  }
568 
569  //================================================ Test for missing symmetry axes, if need be
570  ProSHADE_internal_symmetry::findMissingAxes ( &C3Possibilities, CSymList, 4, axErr, 1.0/3.0, 3, dataObj, minPeakHeight );
571 
572  //================================================ Any group has 4 entries? If more such groups, take the one with highest average height.
573  proshade_double maxHeight = 0.0; proshade_unsign maxGrp = 0;
574  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; } } }
575 
576  if ( C3Possibilities.at(maxGrp).size() == 4 )
577  {
578  //============================================ Success! Save and exit
579  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)) ); }
580 
581  //============================================ Report progress
582  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of four C3 axes successfull.", messageShift );
583 
584  //============================================ Done
585  return ;
586  }
587 
588  //================================================ Done
589  return ;
590 
591 }

◆ 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 3869 of file ProSHADE_symmetry.cpp.

3870 {
3871  //================================================ Initialise local variables
3872  proshade_double axX, axY, axZ, axAng, mapPeak, trsX, trsY, trsZ;
3873  std::vector< proshade_double > trsVec;
3874 
3875  //=============================================== Rotate the map by the rotation matrix
3876  proshade_double *rotMap;
3877  ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( &symElem, &axX, &axY, &axZ, &axAng );
3878  symStr->rotateMapRealSpace ( axX, axY, axZ, axAng, rotMap );
3879 
3880  //================================================ Convert rotated map to Fourier space
3881  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; }
3882  fftw_execute ( planForwardFourierRot );
3883 
3884  //================================================ Combine coeffs for translation function
3885  ProSHADE_internal_maths::combineFourierForTranslation ( origCoeffs, rotCoeffs, trFuncCoeffs, symStr->getXDim(), symStr->getYDim(), symStr->getZDim() );
3886 
3887  //================================================ Compute translation function
3888  fftw_execute ( planReverseFourierComb );
3889 
3890  //================================================ Find peak
3891  mapPeak = 0.0;
3892  ProSHADE_internal_maths::findHighestValueInMap ( trFunc, symStr->getXDim(), symStr->getYDim(), symStr->getZDim(), &trsX, &trsY, &trsZ, &mapPeak );
3893 
3894  //================================================ Convert to Angstroms
3895  trsX *= static_cast< proshade_double > ( symStr->getXDimSize() / symStr->getXDim() );
3896  trsY *= static_cast< proshade_double > ( symStr->getYDimSize() / symStr->getYDim() );
3897  trsZ *= static_cast< proshade_double > ( symStr->getZDimSize() / symStr->getZDim() );
3898 
3899  //================================================ Do not translate over half
3900  if ( trsX > ( static_cast< proshade_double > ( symStr->getXDimSize() ) / 2.0 ) ) { trsX = trsX - static_cast< proshade_double > ( symStr->getXDimSize() ); }
3901  if ( trsY > ( static_cast< proshade_double > ( symStr->getYDimSize() ) / 2.0 ) ) { trsY = trsY - static_cast< proshade_double > ( symStr->getYDimSize() ); }
3902  if ( trsZ > ( static_cast< proshade_double > ( symStr->getZDimSize() ) / 2.0 ) ) { trsZ = trsZ - static_cast< proshade_double > ( symStr->getZDimSize() ); }
3903 
3904  //================================================ Save line point
3908 
3909  //================================================ Release memory
3910  delete[] rotMap;
3911 
3912  //================================================ Done
3913  return ( trsVec );
3914 
3915 }

◆ 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 200 of file ProSHADE_symmetry.cpp.

201 {
202  //================================================ Initialise variables
203  proshade_double dotProduct = 0.0;
204  *matchedPos = -1;
205 
206  //================================================ Check
207  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( ret->size() ); symIt++ )
208  {
209  //============================================ Minor speed-up => only test for same folds
210  const FloatingPoint< proshade_double > lhs ( ret->at(symIt)[0] ), rhs ( sym[0] );
211  if ( lhs.AlmostEquals ( rhs ) )
212  {
213  //======================================== Is axis the same?
214  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &ret->at(symIt)[1], &ret->at(symIt)[2],
215  &ret->at(symIt)[3], &sym[1], &sym[2], &sym[3] );
216  if ( ( ( 1.0 > ( dotProduct - simThres ) ) && ( 1.0 < ( dotProduct + simThres ) ) ) || ( ( -1.0 > ( dotProduct - simThres ) ) && ( -1.0 < ( dotProduct + simThres ) ) ) )
217  {
218  //==================================== Matched. Save the index
219  *matchedPos = static_cast< proshade_signed > ( symIt );
220 
221  //==================================== Does the already saved have higher height?
222  if ( ret->at(symIt)[5] >= sym[5] ) { return ( true ); }
223 
224  //==================================== In this case, new is better than old - sort it out
225  ret->at(symIt)[1] = sym[1];
226  ret->at(symIt)[2] = sym[2];
227  ret->at(symIt)[3] = sym[3];
228  ret->at(symIt)[5] = sym[5];
229  return ( true );
230  }
231  }
232  }
233 
234  //================================================ Done - no matches found
235  return ( false );
236 
237 }

◆ 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 251 of file ProSHADE_symmetry.cpp.

252 {
253  //================================================ Initialise variables
254  proshade_double dotProduct = 0.0;
255  *matchedPos = -1;
256 
257  //================================================ Check
258  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( ret->size() ); symIt++ )
259  {
260  //============================================ Minor speed-up => only test for same folds
261  const FloatingPoint< proshade_double > lhs ( ret->at(symIt)[0] ), rhs ( sym[0] );
262  if ( lhs.AlmostEquals ( rhs ) )
263  {
264  //======================================== Is axis the same?
265  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &ret->at(symIt)[1], &ret->at(symIt)[2],
266  &ret->at(symIt)[3], &sym[1], &sym[2], &sym[3] );
267  if ( ( ( 1.0 > ( dotProduct - simThres ) ) && ( 1.0 < ( dotProduct + simThres ) ) ) || ( ( -1.0 > ( dotProduct - simThres ) ) && ( -1.0 < ( dotProduct + simThres ) ) ) )
268  {
269  //==================================== Matched. Save the index
270  *matchedPos = static_cast< proshade_signed > ( symIt );
271 
272  //==================================== Does the already saved have higher height?
273  if ( ret->at(symIt)[5] >= sym[5] ) { return ( true ); }
274 
275  //==================================== In this case, new is better than old - sort it out
276  ret->at(symIt)[1] = sym[1];
277  ret->at(symIt)[2] = sym[2];
278  ret->at(symIt)[3] = sym[3];
279  ret->at(symIt)[5] = sym[5];
280  ret->at(symIt)[6] = fscVal;
281  return ( true );
282  }
283  }
284  }
285 
286  //================================================ Done - no matches found
287  return ( false );
288 
289 }

◆ 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 757 of file ProSHADE_symmetry.cpp.

758 {
759  //================================================ Initialise variables
760  proshade_double ret = 0.0;
761  proshade_double curSum = 0.0;
762  proshade_double maxVal = 0.0;
763  proshade_double angStep = std::acos ( 1.0 - axErr ) / 2;
764  std::vector< proshade_double* > angVec;
765 
766  //================================================ Find map points conforming to the axis
767  angVec = ProSHADE_internal_symmetry::findMissingAxisPoints ( xVal, yVal, zVal, dataObj, axErr );
768 
769  //================================================ Sort points by angle
770  std::sort ( angVec.begin(), angVec.end(), ProSHADE_internal_symmetry::sortArrVecHlp );
771 
772  //================================================ Find the best X peaks with correct distances
773  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( std::floor ( ( 2.0 * M_PI / angStep ) / static_cast< proshade_double > ( fold ) ) ); iter++ )
774  {
775  //============================================ Initialise new ang group iteration
776  curSum = 0.0;
777 
778  //============================================ For each of the fold times
779  for ( proshade_unsign angCmb = 0; angCmb < static_cast<proshade_unsign> ( fold ); angCmb++ )
780  {
781  //======================================== Initialise
782  maxVal = 0.0;
783 
784  //======================================== Search
785  for ( proshade_unsign angIt = 0; angIt < static_cast<proshade_unsign> ( angVec.size() ); angIt++ )
786  {
787  if ( angVec.at(angIt)[0] < ( ( static_cast< proshade_double > ( iter ) * angStep ) +
788  ( ( 2.0 * M_PI / static_cast< proshade_double > ( fold ) ) * static_cast< proshade_double > ( angCmb ) ) ) ) { continue; }
789  if ( angVec.at(angIt)[0] > ( ( ( static_cast< proshade_double > ( iter ) + 1.0 ) * angStep ) +
790  ( ( 2.0 * M_PI / static_cast< proshade_double > ( fold ) ) * static_cast< proshade_double > ( angCmb ) ) ) ) { break; }
791 
792  if ( angVec.at(angIt)[1] > maxVal ) { maxVal = angVec.at(angIt)[1]; }
793  }
794  curSum += maxVal;
795  }
796  curSum /= static_cast<proshade_double> ( fold );
797  if ( ret < curSum ) { ret = curSum; }
798  }
799 
800  //================================================ Release memory
801  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( angVec.size() ); iter++ ) { delete[] angVec.at(iter); }
802 
803  //================================================ Done
804  return ( ret );
805 
806 }

◆ 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 3324 of file ProSHADE_symmetry.cpp.

3325 {
3326  //================================================ Initialise local variables
3327  std::vector < std::vector< proshade_double > > ortPair;
3328  std::vector< proshade_double > hlpVec;
3329 
3330  //================================================ Convert the indices and the list into a single vector containing only the axes to be optimised.
3331  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] );
3332  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] );
3333  hlpVec.push_back ( allCs->at(selection.at(0))[6] );
3334  ortPair.push_back ( hlpVec ); hlpVec.clear ( );
3335  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] );
3336  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] );
3337  hlpVec.push_back ( allCs->at(selection.at(1))[6] );
3338  ortPair.push_back ( hlpVec );
3339 
3340  //================================================ Run the optimisation proper
3341  optimiseDGroupAngleFromAxesHeights ( &ortPair, dataObj, settings );
3342 
3343  //================================================ Save the results back to the vector
3344  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);
3345  allCs->at(selection.at(0))[5] = ortPair.at(0).at(5); allCs->at(selection.at(0))[6] = ortPair.at(0).at(6);
3346 
3347  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);
3348  allCs->at(selection.at(1))[5] = ortPair.at(1).at(5); allCs->at(selection.at(1))[6] = ortPair.at(1).at(6);
3349 
3350  //================================================ Done
3351  return ;
3352 
3353 }

◆ 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 3227 of file ProSHADE_symmetry.cpp.

3228 {
3229  //================================================ Sanity check
3230  if ( ret->size() != 2 )
3231  {
3232  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." );
3233  }
3234 
3235  //================================================ Set the angle to the correct dihedral group position - i.e. 90 deg
3236  proshade_double *crossProd, *perpVec, normFactor;
3237  size_t higherRFIndex = 0;
3238 
3239  // ... Find vector perperndicular to the plane given by the two axes
3240  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) );
3241 
3242  // ... Find a vector perpendicular to the plane between the new vector and the vector with higher rotation function value
3243  if ( ret->at(1).at(5) > ret->at(0).at(5) ) { higherRFIndex = 1; }
3244  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] );
3245 
3246  // ... Normalise the new vector
3247  normFactor = std::sqrt ( pow ( perpVec[0], 2.0 ) + pow ( perpVec[1], 2.0 ) + pow ( perpVec[2], 2.0 ) );
3248  perpVec[0] /= normFactor; perpVec[1] /= normFactor; perpVec[2] /= normFactor;
3249 
3250  // ... Which vector are we to over-write?
3251  if ( higherRFIndex == 0 ) { higherRFIndex = 1; }
3252  else { higherRFIndex = 0; }
3253 
3254  // ... Set largest axis element to positive
3255  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( perpVec[0] ), std::max( std::abs ( perpVec[1] ), std::abs ( perpVec[2] ) ) ) );
3256  const FloatingPoint< proshade_double > rhs1 ( std::abs ( perpVec[0] ));
3257  const FloatingPoint< proshade_double > rhs2 ( std::abs ( perpVec[1] ) );
3258  const FloatingPoint< proshade_double > rhs3 ( std::abs ( perpVec[2] ) );
3259  if ( ( lhs1.AlmostEquals ( rhs1 ) && ( perpVec[0] < 0.0 ) ) ||
3260  ( lhs1.AlmostEquals ( rhs2 ) && ( perpVec[1] < 0.0 ) ) ||
3261  ( lhs1.AlmostEquals ( rhs3 ) && ( perpVec[2] < 0.0 ) ) )
3262  {
3263  perpVec[0] *= -1.0;
3264  perpVec[1] *= -1.0;
3265  perpVec[2] *= -1.0;
3266  }
3267 
3268  // ... Over-write the old vector with the better one
3269  ret->at(higherRFIndex).at(1) = perpVec[0]; ret->at(higherRFIndex).at(2) = perpVec[1]; ret->at(higherRFIndex).at(3) = perpVec[2];
3270 
3271  // ... Release memory
3272  delete[] perpVec;
3273  delete[] crossProd;
3274 
3275  //================================================ Convert input to pointers
3276  std::vector< proshade_double* > convVec;
3277  for ( size_t axIt = 0; axIt < 2; axIt++ )
3278  {
3279  //============================================ Allocate memory
3280  proshade_double* axVals = new proshade_double[7];
3281  ProSHADE_internal_misc::checkMemoryAllocation ( axVals, __FILE__, __LINE__, __func__ );
3282 
3283  //============================================ Copy values
3284  for ( size_t elIt = 0; elIt < 7; elIt++ )
3285  {
3286  axVals[elIt] = ret->at(axIt).at(elIt);
3287  }
3288 
3289  //============================================ Save
3290  convVec.push_back ( axVals );
3291  }
3292 
3293  //================================================ Run normal optimisation
3294  ProSHADE_internal_symmetry::findPredictedAxesHeights ( &convVec, dataObj, settings );
3295 
3296  //================================================ Convert back and release memory
3297  for ( size_t axIt = 0; axIt < 2; axIt++ )
3298  {
3299  //============================================ Copy values
3300  for ( size_t elIt = 0; elIt < 7; elIt++ )
3301  {
3302  ret->at(axIt).at(elIt) = convVec.at(axIt)[elIt];
3303  }
3304 
3305  //============================================ Release memory
3306  delete[] convVec.at(axIt);
3307  }
3308 
3309  //================================================ Done
3310  return ;
3311 
3312 }

◆ 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 2154 of file ProSHADE_symmetry.cpp.

2155 {
2156  //================================================ Find the best axis combination with dihedral angle and correct folds
2157  std::vector < std::pair< proshade_unsign, proshade_unsign > > initAxes = findBestIcosDihedralPair ( CSymList, minPeakHeight, axErr );
2158 
2159  //================================================ For each pair of possible axis combinations
2160  for ( size_t pIt = 0; pIt < initAxes.size(); pIt++ )
2161  {
2162  //============================================ Create the tetrahedronAxes object
2164 
2165  //============================================ Find rotation between the detected C5 and the model C5 axes.
2166  proshade_double* rotMat = ProSHADE_internal_maths::findRotMatMatchingVectors ( icoAx->getValue ( 0, 1 ),
2167  icoAx->getValue ( 0, 2 ),
2168  icoAx->getValue ( 0, 3 ),
2169  CSymList->at(initAxes.at(pIt).first)[1],
2170  CSymList->at(initAxes.at(pIt).first)[2],
2171  CSymList->at(initAxes.at(pIt).first)[3] );
2172 
2173  //============================================ Rotate the model C3 to the correct orientation relative to the detected C5 axis.
2174  proshade_double* rotModelC3 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMat,
2175  icoAx->getValue ( 6, 1 ),
2176  icoAx->getValue ( 6, 2 ),
2177  icoAx->getValue ( 6, 3 ) );
2178 
2179  //============================================ Find the angle betwen the rotated model C3 and the detected C3 axes along the detected C5 axis.
2180  proshade_double bestAng = 0.0, curAngDist, bestAngDist = 999.9;
2181  proshade_double* rotMatHlp = new proshade_double[9];
2182  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatHlp, __FILE__, __LINE__, __func__ );
2183  for ( proshade_double ang = 0.0; ang < ( M_PI * 2.0 ); ang += 0.002 )
2184  {
2185  //============================================ Compute rotation matrix for this angle value
2186  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 );
2187 
2188  //======================================== Rotate the rotated C2 by the matrix
2189  proshade_double* rotRotModelC3 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatHlp,
2190  rotModelC3[0],
2191  rotModelC3[1],
2192  rotModelC3[2] );
2193 
2194  //======================================== Find distance
2195  curAngDist = std::sqrt ( std::pow ( rotRotModelC3[0] - CSymList->at(initAxes.at(pIt).second)[1], 2.0 ) +
2196  std::pow ( rotRotModelC3[1] - CSymList->at(initAxes.at(pIt).second)[2], 2.0 ) +
2197  std::pow ( rotRotModelC3[2] - CSymList->at(initAxes.at(pIt).second)[3], 2.0 ) );
2198 
2199  //======================================== Save best angle
2200  if ( curAngDist < bestAngDist ) { bestAngDist = curAngDist; bestAng = ang; }
2201 
2202  //======================================== Release memory
2203  delete[] rotRotModelC3;
2204  }
2205 
2206  //============================================ Release memory
2207  delete[] rotMatHlp;
2208 
2209  //============================================ 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.
2210  proshade_double* rotMat2 = new proshade_double[9];
2211  ProSHADE_internal_misc::checkMemoryAllocation ( rotMat2, __FILE__, __LINE__, __func__ );
2212  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 );
2213 
2214  //============================================ Combine the two rotation matrices into a single rotation matrix
2215  proshade_double* rotMatFin = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( rotMat2, rotMat );
2216 
2217  //============================================ For each model axis
2218  std::vector< proshade_double* > hlpAxes;
2219  for ( proshade_unsign iter = 0; iter < icoAx->getNoAxes ( ); iter++ )
2220  {
2221  //======================================== Rotate the model axis to fit the detected orientation
2222  proshade_double* rotAxis = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatFin,
2223  icoAx->getValue ( iter, 1 ),
2224  icoAx->getValue ( iter, 2 ),
2225  icoAx->getValue ( iter, 3 ) );
2226 
2227  //======================================== Create ProSHADE symmetry axis representation
2228  proshade_double* axis = new proshade_double[7];
2229  ProSHADE_internal_misc::checkMemoryAllocation ( axis, __FILE__, __LINE__, __func__ );
2230 
2231  axis[0] = icoAx->getValue ( iter, 0 );
2232  axis[1] = rotAxis[0];
2233  axis[2] = rotAxis[1];
2234  axis[3] = rotAxis[2];
2235  axis[4] = ( 2.0 * M_PI ) / axis[0];
2236  axis[5] = 0.0;
2237  axis[6] = -std::numeric_limits < proshade_double >::infinity();
2238 
2239  //======================================== Save axis to ret
2241 
2242  //======================================== Release memory
2243  delete[] rotAxis;
2244  delete[] axis;
2245  }
2246 
2247  //============================================ Save to ret
2248  ret->emplace_back ( hlpAxes );
2249 
2250  //============================================ Release memory
2251  delete[] rotMat;
2252  delete[] rotMat2;
2253  delete[] rotMatFin;
2254  delete[] rotModelC3;
2255  delete icoAx;
2256  }
2257 
2258  //================================================ Done
2259  return ;
2260 
2261 }

◆ predictOctaAxes()

void ProSHADE_internal_symmetry::predictOctaAxes ( std::vector< proshade_double * > *  CSymList,
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 2337 of file ProSHADE_symmetry.cpp.

2338 {
2339  //================================================ Create the tetrahedronAxes object
2341 
2342  //================================================ Find the best axis combination with dihedral angle and correct folds
2343  std::pair< proshade_unsign, proshade_unsign > initAxes = findBestOctaDihedralPair ( CSymList, minPeakHeight, axErr );
2344 
2345  //================================================ Find rotation between the detected C4 and the model C4 axes.
2346  proshade_double* rotMat = ProSHADE_internal_maths::findRotMatMatchingVectors ( octAx->getValue ( 0, 1 ),
2347  octAx->getValue ( 0, 2 ),
2348  octAx->getValue ( 0, 3 ),
2349  CSymList->at(initAxes.first)[1],
2350  CSymList->at(initAxes.first)[2],
2351  CSymList->at(initAxes.first)[3] );
2352 
2353  //================================================ Rotate the model C3 to the correct orientation relative to the detected C4 axis.
2354  proshade_double* rotModelC3 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMat,
2355  octAx->getValue ( 3, 1 ),
2356  octAx->getValue ( 3, 2 ),
2357  octAx->getValue ( 3, 3 ) );
2358 
2359  //================================================ Find the angle betwen the rotated model C3 and the detected C3 axes along the detected C4 axis.
2360  proshade_double bestAng = 0.0, curAngDist, bestAngDist = 999.9;
2361  proshade_double* rotMatHlp = new proshade_double[9];
2362  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatHlp, __FILE__, __LINE__, __func__ );
2363  for ( proshade_double ang = 0.0; ang < ( M_PI * 2.0 ); ang += 0.002 )
2364  {
2365  //============================================ Compute rotation matrix for this angle value
2366  ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( rotMatHlp, CSymList->at(initAxes.first)[1], CSymList->at(initAxes.first)[2], CSymList->at(initAxes.first)[3], ang );
2367 
2368  //============================================ Rotate the rotated C2 by the matrix
2369  proshade_double* rotRotModelC3 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatHlp,
2370  rotModelC3[0],
2371  rotModelC3[1],
2372  rotModelC3[2] );
2373 
2374  //============================================ Find distance
2375  curAngDist = std::sqrt ( std::pow ( rotRotModelC3[0] - CSymList->at(initAxes.second)[1], 2.0 ) +
2376  std::pow ( rotRotModelC3[1] - CSymList->at(initAxes.second)[2], 2.0 ) +
2377  std::pow ( rotRotModelC3[2] - CSymList->at(initAxes.second)[3], 2.0 ) );
2378 
2379  //============================================ Save best angle
2380  if ( curAngDist < bestAngDist ) { bestAngDist = curAngDist; bestAng = ang; }
2381 
2382  //============================================ Release memory
2383  delete[] rotRotModelC3;
2384  }
2385 
2386  //============================================ Release memory
2387  delete[] rotMatHlp;
2388 
2389  //================================================ 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.
2390  proshade_double* rotMat2 = new proshade_double[9];
2391  ProSHADE_internal_misc::checkMemoryAllocation ( rotMat2, __FILE__, __LINE__, __func__ );
2392  ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( rotMat2, CSymList->at(initAxes.first)[1], CSymList->at(initAxes.first)[2], CSymList->at(initAxes.first)[3], bestAng );
2393 
2394  //================================================ Combine the two rotation matrices into a single rotation matrix
2395  proshade_double* rotMatFin = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( rotMat2, rotMat );
2396 
2397  //================================================ For each model axis
2398  for ( proshade_unsign iter = 0; iter < octAx->getNoAxes ( ); iter++ )
2399  {
2400  //============================================ Rotate the model axis to fit the detected orientation
2401  proshade_double* rotAxis = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatFin,
2402  octAx->getValue ( iter, 1 ),
2403  octAx->getValue ( iter, 2 ),
2404  octAx->getValue ( iter, 3 ) );
2405 
2406  //============================================ Create ProSHADE symmetry axis representation
2407  proshade_double* axis = new proshade_double[7];
2408  ProSHADE_internal_misc::checkMemoryAllocation ( axis, __FILE__, __LINE__, __func__ );
2409 
2410  axis[0] = octAx->getValue ( iter, 0 );
2411  axis[1] = rotAxis[0];
2412  axis[2] = rotAxis[1];
2413  axis[3] = rotAxis[2];
2414  axis[4] = ( 2.0 * M_PI ) / axis[0];
2415  axis[5] = 0.0;
2416  axis[6] = -std::numeric_limits < proshade_double >::infinity();
2417 
2418  //============================================ Save axis to ret
2420 
2421  //============================================ Release memory
2422  delete[] rotAxis;
2423  }
2424 
2425  //================================================ Release memory
2426  delete[] rotMat;
2427  delete[] rotMat2;
2428  delete[] rotMatFin;
2429  delete[] rotModelC3;
2430  delete octAx;
2431 
2432  //================================================ Done
2433  return ;
2434 
2435 }

◆ predictTetraAxes()

void ProSHADE_internal_symmetry::predictTetraAxes ( std::vector< proshade_double * > *  CSymList,
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 3558 of file ProSHADE_symmetry.cpp.

3559 {
3560  //================================================ Create the tetrahedronAxes object
3562 
3563  //================================================ Find the best axis combination with dihedral angle and correct folds
3564  std::pair< proshade_unsign, proshade_unsign > initAxes = findBestTetraDihedralPair ( CSymList, minPeakHeight, axErr );
3565 
3566  //================================================ Find rotation between the detected C3 and the model C3 axes.
3567  proshade_double* rotMat = ProSHADE_internal_maths::findRotMatMatchingVectors ( tetAx->getValue ( 0, 1 ),
3568  tetAx->getValue ( 0, 2 ),
3569  tetAx->getValue ( 0, 3 ),
3570  CSymList->at(initAxes.first)[1],
3571  CSymList->at(initAxes.first)[2],
3572  CSymList->at(initAxes.first)[3] );
3573 
3574  //================================================ Rotate the model C2 to the correct orientation relative to the detected C3 axis.
3575  proshade_double* rotModelC2 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMat,
3576  tetAx->getValue ( 4, 1 ),
3577  tetAx->getValue ( 4, 2 ),
3578  tetAx->getValue ( 4, 3 ) );
3579 
3580  //================================================ Find the angle betwen the rotated model C2 and the detected C2 axes along the detected C3 axis.
3581  proshade_double bestAng = 0.0, curAngDist, bestAngDist = 999.9;
3582  proshade_double* rotMatHlp = new proshade_double[9];
3583  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatHlp, __FILE__, __LINE__, __func__ );
3584  for ( proshade_double ang = 0.0; ang < ( M_PI * 2.0 ); ang += 0.002 )
3585  {
3586  //============================================ Compute rotation matrix for this angle value
3587  ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( rotMatHlp, CSymList->at(initAxes.first)[1], CSymList->at(initAxes.first)[2], CSymList->at(initAxes.first)[3], ang );
3588 
3589  //============================================ Rotate the rotated C2 by the matrix
3590  proshade_double* rotRotModelC2 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatHlp,
3591  rotModelC2[0],
3592  rotModelC2[1],
3593  rotModelC2[2] );
3594 
3595  //============================================ Find distance
3596  curAngDist = std::sqrt ( std::pow ( rotRotModelC2[0] - CSymList->at(initAxes.second)[1], 2.0 ) +
3597  std::pow ( rotRotModelC2[1] - CSymList->at(initAxes.second)[2], 2.0 ) +
3598  std::pow ( rotRotModelC2[2] - CSymList->at(initAxes.second)[3], 2.0 ) );
3599 
3600  //============================================ Save best angle
3601  if ( curAngDist < bestAngDist ) { bestAngDist = curAngDist; bestAng = ang; }
3602 
3603  //============================================ Release memory
3604  delete[] rotRotModelC2;
3605  }
3606 
3607  //================================================ Release memory
3608  delete[] rotMatHlp;
3609 
3610  //================================================ 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.
3611  proshade_double* rotMat2 = new proshade_double[9];
3612  ProSHADE_internal_misc::checkMemoryAllocation ( rotMat2, __FILE__, __LINE__, __func__ );
3613  ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( rotMat2, CSymList->at(initAxes.first)[1], CSymList->at(initAxes.first)[2], CSymList->at(initAxes.first)[3], bestAng );
3614 
3615  //================================================ Combine the two rotation matrices into a single rotation matrix
3616  proshade_double* rotMatFin = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( rotMat2, rotMat );
3617 
3618  //================================================ For each model axis
3619  for ( proshade_unsign iter = 0; iter < tetAx->getNoAxes( ); iter++ )
3620  {
3621  //============================================ Rotate the model axis to fit the detected orientation
3622  proshade_double* rotAxis = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatFin,
3623  tetAx->getValue ( iter, 1 ),
3624  tetAx->getValue ( iter, 2 ),
3625  tetAx->getValue ( iter, 3 ) );
3626 
3627  //============================================ Create ProSHADE symmetry axis representation
3628  proshade_double* axis = new proshade_double[7];
3629  ProSHADE_internal_misc::checkMemoryAllocation ( axis, __FILE__, __LINE__, __func__ );
3630 
3631  axis[0] = tetAx->getValue ( iter, 0 );
3632  axis[1] = rotAxis[0];
3633  axis[2] = rotAxis[1];
3634  axis[3] = rotAxis[2];
3635  axis[4] = ( 2.0 * M_PI ) / axis[0];
3636  axis[5] = 0.0;
3637  axis[6] = -std::numeric_limits < proshade_double >::infinity();
3638 
3639  //============================================ Save axis to ret
3641 
3642  //============================================ Release memory
3643  delete[] rotAxis;
3644  }
3645 
3646  //================================================ Release memory
3647  delete[] rotMat;
3648  delete[] rotMat2;
3649  delete[] rotMatFin;
3650  delete[] rotModelC2;
3651  delete tetAx;
3652 
3653  //================================================ Done
3654  return ;
3655 
3656 }

◆ 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 3831 of file ProSHADE_symmetry.cpp.

3832 {
3833  //================================================ Destroy the FFTW3 plans
3834  fftw_destroy_plan ( planReverseFourierComb );
3835  fftw_destroy_plan ( planForwardFourier );
3836  fftw_destroy_plan ( planForwardFourierRot );
3837 
3838  //================================================ Set pointers to NULL
3839  planReverseFourierComb = nullptr;
3840  planForwardFourier = nullptr;
3841  planForwardFourierRot = nullptr;
3842 
3843  //================================================ Release the memory
3844  delete[] origMap;
3845  delete[] origCoeffs;
3846  delete[] rotMapComplex;
3847  delete[] rotCoeffs;
3848  delete[] trFunc;
3849  delete[] trFuncCoeffs;
3850 
3851  //================================================ Done
3852  return ;
3853 
3854 }

◆ saveDSymmetry()

void ProSHADE_internal_symmetry::saveDSymmetry ( std::vector< proshade_double * > *  ret,
std::vector< proshade_double * > *  CSymList,
proshade_unsign  axisOne,
proshade_unsign  axisTwo 
)

This function saves a detected dihedral symmetry to the dihedral symmetries list.

This function takes two C symmetry axes as supplied by the calling function and the list of the detected C symmetries. It then produces the saving structure for a dihedral symmetry formed by the two supplied axes and saves this structure to the supplied dihedral symmetry list vector - ret.

Parameters
[in]retThe vector of double pointers to which the symmetry is to be saved to.
[in]CSymListA vector containing the already detected Cyclic symmetries.
[in]axisOneThe index of the first C symmetry forming the dihedral symmetry.
[in]axisTwoThe index of the second C symmetry forming the dihedral symmetry.

Definition at line 383 of file ProSHADE_symmetry.cpp.

384 {
385  //================================================ Allocate the memory
386  proshade_double* hlpP = new proshade_double [14];
387  ProSHADE_internal_misc::checkMemoryAllocation ( hlpP, __FILE__, __LINE__, __func__ );
388 
389  //================================================ Set the axis and heights
390  hlpP[0] = CSymList->at(axisOne)[0];
391  hlpP[1] = CSymList->at(axisOne)[1];
392  hlpP[2] = CSymList->at(axisOne)[2];
393  hlpP[3] = CSymList->at(axisOne)[3];
394  hlpP[4] = CSymList->at(axisOne)[4];
395  hlpP[5] = CSymList->at(axisOne)[5];
396  hlpP[6] = CSymList->at(axisOne)[6];
397  hlpP[7] = CSymList->at(axisTwo)[0];
398  hlpP[8] = CSymList->at(axisTwo)[1];
399  hlpP[9] = CSymList->at(axisTwo)[2];
400  hlpP[10] = CSymList->at(axisTwo)[3];
401  hlpP[11] = CSymList->at(axisTwo)[4];
402  hlpP[12] = CSymList->at(axisTwo)[5];
403  hlpP[13] = CSymList->at(axisTwo)[6];
404 
405  //================================================ Save to ret
407 
408  //================================================ Done
409  return ;
410 
411 }

◆ 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 899 of file ProSHADE_symmetry.cpp.

900 {
901  //================================================ Create symmetry array from the inputs
902  proshade_double* hlpSym = new proshade_double [6];
903  ProSHADE_internal_misc::checkMemoryAllocation ( hlpSym, __FILE__, __LINE__, __func__ );
904 
905  //================================================ Fill it in
906  hlpSym[0] = static_cast<proshade_double> ( fold );
907  hlpSym[1] = axX;
908  hlpSym[2] = axY;
909  hlpSym[3] = axZ;
910  hlpSym[4] = ( 2.0 * M_PI ) / static_cast<proshade_double> ( fold );
911  hlpSym[5] = height;
912 
913  //================================================ Check if similar symmetry does not exist already
914  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( axVec->size() ); symIt++ )
915  {
916  //============================================ Minor speed-up => only test for same folds
917  const FloatingPoint< proshade_double > lhs1 ( axVec->at(symIt)[0] ), rhs1 ( hlpSym[0] );
918  if ( lhs1.AlmostEquals ( rhs1 ) )
919  {
920  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( axVec->at(symIt)[1],
921  axVec->at(symIt)[2],
922  axVec->at(symIt)[3],
923  hlpSym[1],
924  hlpSym[2],
925  hlpSym[3],
926  axErr ) )
927  {
928  //==================================== Almost identical entry
929  if ( axVec->at(symIt)[5] < hlpSym[5] )
930  {
931  //================================ If higher, save
932  delete[] axVec->at(symIt);
933  axVec->at(symIt) = hlpSym;
934  return ;
935  }
936  else
937  {
938  //================================ or just terminate if better is already saved
939  delete[] hlpSym;
940  return ;
941  }
942  }
943  }
944  }
945 
946  //================================================ Not matched to anything
948 
949  //================================================ Done
950  return ;
951 
952 }

◆ 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 968 of file ProSHADE_symmetry.cpp.

969 {
970  //================================================ Sanity check
971  if ( grp->size() < 2 ) { return; }
972 
973  //================================================ Initialise variables
974  proshade_double axHeight = 0.0;
975  proshade_double* symHlp = new proshade_double[7];
976  ProSHADE_internal_misc::checkMemoryAllocation ( symHlp, __FILE__, __LINE__, __func__ );
977 
978  //================================================ For each axis pair in the group, find the possible solutions
979  for ( proshade_unsign fAx = 0; fAx < static_cast<proshade_unsign> ( grp->size() ); fAx++ )
980  {
981  for ( proshade_unsign sAx = 1; sAx < static_cast<proshade_unsign> ( grp->size() ); sAx++ )
982  {
983  //======================================== Only unique pairs
984  if ( fAx >= sAx ) { continue; }
985 
986  //======================================== Find possible axis having the required angle to this pair ( solution 1 )
987  std::vector< proshade_double > solVec = ProSHADE_internal_maths::findVectorFromTwoVAndTwoD ( CSymList->at(grp->at(fAx))[1],
988  CSymList->at(grp->at(fAx))[2],
989  CSymList->at(grp->at(fAx))[3],
990  CSymList->at(grp->at(sAx))[1],
991  CSymList->at(grp->at(sAx))[2],
992  CSymList->at(grp->at(sAx))[3], angle, angle );
993 
994  //======================================== Set largest axis element to positive
995  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( solVec.at(0) ), std::max( std::abs ( solVec.at(1) ), std::abs ( solVec.at(2) ) ) ) );
996  const FloatingPoint< proshade_double > rhs1 ( std::abs ( solVec.at(0) ) );
997  const FloatingPoint< proshade_double > rhs2 ( std::abs ( solVec.at(1) ) );
998  const FloatingPoint< proshade_double > rhs3 ( std::abs ( solVec.at(2) ) );
999  if ( ( lhs1.AlmostEquals ( rhs1 ) && ( solVec.at(0) < 0.0 ) ) ||
1000  ( lhs1.AlmostEquals ( rhs2 ) && ( solVec.at(1) < 0.0 ) ) ||
1001  ( lhs1.AlmostEquals ( rhs3 ) && ( solVec.at(2) < 0.0 ) ) )
1002  {
1003  solVec.at(0) *= -1.0;
1004  solVec.at(1) *= -1.0;
1005  solVec.at(2) *= -1.0;
1006  }
1007 
1008  //======================================== Does the solution fit the whole group?
1009  symHlp[1] = solVec.at(0); symHlp[2] = solVec.at(1); symHlp[3] = solVec.at(2); symHlp[6] = -std::numeric_limits < proshade_double >::infinity();
1010  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, grp, symHlp, axErr, angle, true ) )
1011  {
1012  //==================================== Find the height for the axis
1013  axHeight = ProSHADE_internal_symmetry::missingAxisHeight ( solVec.at(0), solVec.at(1), solVec.at(2), dataObj, fold, axErr );
1014 
1015  //================================ Save max height result
1016  if ( axHeight >= minPeakHeight ) { ProSHADE_internal_symmetry::saveMissingAxisNewOnly ( hlpVec, solVec.at(0), solVec.at(1), solVec.at(2), axHeight, fold, axErr ); }
1017  }
1018 
1019  //======================================== Find possible axis having the required angle to this pair ( solution 2 )
1020  solVec = ProSHADE_internal_maths::findVectorFromTwoVAndTwoD ( CSymList->at(grp->at(fAx))[1],
1021  CSymList->at(grp->at(fAx))[2],
1022  CSymList->at(grp->at(fAx))[3],
1023  CSymList->at(grp->at(sAx))[1],
1024  CSymList->at(grp->at(sAx))[2],
1025  CSymList->at(grp->at(sAx))[3], -angle, -angle );
1026 
1027  //======================================== Set largest axis element to positive
1028  const FloatingPoint< proshade_double > lhs2 ( std::max ( std::abs ( solVec.at(0) ), std::max( std::abs ( solVec.at(1) ), std::abs ( solVec.at(2) ) ) ) );
1029  const FloatingPoint< proshade_double > rhs4 ( std::abs ( solVec.at(0) ) );
1030  const FloatingPoint< proshade_double > rhs5 ( std::abs ( solVec.at(1) ) );
1031  const FloatingPoint< proshade_double > rhs6 ( std::abs ( solVec.at(2) ) );
1032  if ( ( lhs2.AlmostEquals ( rhs4 ) && ( solVec.at(0) < 0.0 ) ) ||
1033  ( lhs2.AlmostEquals ( rhs5 ) && ( solVec.at(1) < 0.0 ) ) ||
1034  ( lhs2.AlmostEquals ( rhs6 ) && ( solVec.at(2) < 0.0 ) ) )
1035  {
1036  solVec.at(0) *= -1.0;
1037  solVec.at(1) *= -1.0;
1038  solVec.at(2) *= -1.0;
1039  }
1040 
1041  //======================================== Does the solution fit the whole group?
1042  symHlp[1] = solVec.at(0); symHlp[2] = solVec.at(1); symHlp[3] = solVec.at(2); symHlp[6] = -std::numeric_limits < proshade_double >::infinity();
1043  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, grp, symHlp, axErr, angle, true ) )
1044  {
1045  //==================================== Find the height for the axis
1046  axHeight = ProSHADE_internal_symmetry::missingAxisHeight ( solVec.at(0), solVec.at(1), solVec.at(2), dataObj, fold, axErr );
1047 
1048  //================================ Save max height result
1049  if ( axHeight >= minPeakHeight ) { ProSHADE_internal_symmetry::saveMissingAxisNewOnly ( hlpVec, solVec.at(0), solVec.at(1), solVec.at(2), axHeight, fold, axErr ); }
1050  }
1051  }
1052  }
1053 
1054  //================================================ Release memory
1055  delete[] symHlp;
1056 
1057  //================================================ Done
1058  return ;
1059 
1060 }

◆ 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 736 of file ProSHADE_symmetry.cpp.

737 {
738  //================================================ Compare
739  return ( a[0] < b[0] );
740 
741 }

◆ 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 1161 of file ProSHADE_symmetry.cpp.

1162 {
1163  //================================================ Initialise variables
1164  bool ret = false;
1165  proshade_double dotProduct;
1166 
1167  //================================================ For all pairs of axes
1168  for ( proshade_unsign g1It = 0; g1It < static_cast<proshade_unsign> ( grp1->size() ); g1It++ )
1169  {
1170  for ( proshade_unsign g2It = 0; g2It < static_cast<proshade_unsign> ( grp2->size() ); g2It++ )
1171  {
1172  //======================================== Find the angle
1173  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &GrList1->at(grp1->at(g1It))[1],
1174  &GrList1->at(grp1->at(g1It))[2],
1175  &GrList1->at(grp1->at(g1It))[3],
1176  &GrList2->at(grp2->at(g2It))[1],
1177  &GrList2->at(grp2->at(g2It))[2],
1178  &GrList2->at(grp2->at(g2It))[3] );
1179 
1180  //======================================== Check the angle
1181  if ( ( angle > ( dotProduct - axErr ) ) && ( angle < ( dotProduct + axErr ) ) )
1182  {
1183  ret = true;
1184  return ( ret );
1185  }
1186  }
1187  }
1188 
1189  //================================================ Done
1190  return ( ret );
1191 
1192 }

◆ 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 609 of file ProSHADE_symmetry.cpp.

610 {
611  //================================================ Initialise variables
612  bool allAnglesMet = true;
613  proshade_double dotProduct;
614 
615  //================================================ Improve if required
616  if ( improve )
617  {
618  for ( proshade_unsign mIt = 0; mIt < static_cast<proshade_unsign> ( grp->size() ); mIt++ )
619  {
620  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] );
621 
622  if ( ( ( 1.0 > ( dotProduct - axErr ) ) && ( 1.0 < ( dotProduct + axErr ) ) ) || ( ( -1.0 > ( dotProduct - axErr ) ) && ( -1.0 < ( dotProduct + axErr ) ) ) )
623  {
624  if ( sym[5] > CSymList->at(grp->at(mIt))[5] )
625  {
626  grp->at(mIt) = pos;
627  }
628  else
629  {
630  allAnglesMet = false;
631  return ( allAnglesMet );
632  }
633  }
634  }
635  }
636 
637  //================================================ For all group members
638  for ( proshade_unsign mIt = 0; mIt < static_cast<proshade_unsign> ( grp->size() ); mIt++ )
639  {
640  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] );
641 
642  if ( ( angle > ( std::abs ( dotProduct ) - axErr ) ) &&
643  ( angle < ( std::abs ( dotProduct ) + axErr ) ) )
644  {
645  //======================================== Matching group memner - try next one
646  }
647  else
648  {
649  //======================================== Group member not matched - try next group
650  allAnglesMet = false;
651  break;
652  }
653  }
654 
655  //================================================ Done
656  return ( allAnglesMet );
657 
658 }
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:2455
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:3919
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:676
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:736
ProSHADE_internal_maths::computeCrossProduct
proshade_double * computeCrossProduct(proshade_double *x1, proshade_double *y1, proshade_double *z1, proshade_double *x2, proshade_double *y2, proshade_double *z2)
Simple 3D vector cross product computation.
Definition: ProSHADE_maths.cpp:1820
ProSHADE_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:1657
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:3022
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:3899
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:3909
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:757
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:968
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:1562
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_maths::getRotationMatrixFromEulerZXZAngles
void getRotationMatrixFromEulerZXZAngles(proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double *matrix)
Function to find the rotation matrix from Euler angles (ZXZ convention).
Definition: ProSHADE_maths.cpp:1020
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:3227
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:149
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:200
ProSHADE_internal_maths::vectorOrientationSimilarity
bool vectorOrientationSimilarity(proshade_double a1, proshade_double a2, proshade_double a3, proshade_double b1, proshade_double b2, proshade_double b3, proshade_double tolerance=0.1)
This function compares two vectors using cosine distance and decides if they are similar using tolera...
Definition: ProSHADE_maths.cpp:2589
ProSHADE_settings::messageShift
proshade_signed messageShift
This value allows shifting the messages to create more readable log for sub-processes.
Definition: ProSHADE_settings.hpp:150
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)
This function takes a new prospective peak and tests if it belongs to this peak group or not.
Definition: ProSHADE_spheres.cpp:1163
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:3929
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:135
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:899
ProSHADE_internal_maths::computeDotProduct
proshade_double computeDotProduct(proshade_double *x1, proshade_double *y1, proshade_double *z1, proshade_double *x2, proshade_double *y2, proshade_double *z2)
Simple 3D vector dot product computation.
Definition: ProSHADE_maths.cpp:1788
ProSHADE_internal_misc::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:335
ProSHADE_internal_precomputedVals::tetrahedronAxes::getNoAxes
proshade_unsign getNoAxes()
Accessor for the tetrahedronAxesVals variable number of axes.
Definition: ProSHADE_precomputedValues.cpp:79
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:1459
ProSHADE_internal_data::ProSHADE_data::getMaxBand
proshade_unsign getMaxBand(void)
This function returns the maximum band value for the object.
Definition: ProSHADE_data.cpp:3611
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:3939
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:3912
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:1084
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:2033
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:3865
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:3949
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=0.9)
This function finds a subgroup of axes with distinctly higher correlation value.
Definition: ProSHADE_maths.cpp:3743
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:3869
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:2974
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:2607
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:2095
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:2091
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:1898
ProSHADE_internal_precomputedVals::tetrahedronAxes
Definition: ProSHADE_precomputedValues.hpp:69
findBestTetraDihedralPair
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:3444
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:2552
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:609
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:68
ProSHADE_internal_maths::getEulerZXZFromSOFTPosition
void getEulerZXZFromSOFTPosition(proshade_signed band, proshade_signed x, proshade_signed y, proshade_signed z, proshade_double *eulerAlpha, proshade_double *eulerBeta, proshade_double *eulerGamma)
Function to find Euler angles (ZXZ convention) from index position in the inverse SOFT map.
Definition: ProSHADE_maths.cpp:963
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:3847
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:1392
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:2718
findBestOctaDihedralPair
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:2270
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:2309
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:128
ProSHADE_internal_precomputedVals::icosahedronAxes::getNoAxes
proshade_unsign getNoAxes()
Accessor for the octahedronAxesVals variable number of axes.
Definition: ProSHADE_precomputedValues.cpp:234
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:266
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:1756
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:821
ProSHADE_internal_maths::compute3x3MatrixMultiplication
proshade_double * compute3x3MatrixMultiplication(proshade_double *mat1, proshade_double *mat2)
Function for computing a 3x3 matrix multiplication.
Definition: ProSHADE_maths.cpp:1868