ProSHADE  0.7.5.1 (JAN 2021)
Protein Shape Detection
ProSHADE_internal_symmetry Namespace Reference

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

Functions

std::vector< proshade_double * > getPeaksAngleAxisPositions (std::vector< proshade_double * > allPeaks, proshade_unsign verbose)
 This function converts peaks ZXZ Euler anles to angle-axis representation for further processing. More...
 
std::vector< proshade_double > findPeaksByHeightBoundaries (std::vector< proshade_double * > allPeaks, proshade_double smoothing)
 This function groups the peaks by height and returns the boundaries between such groups. More...
 
std::vector< std::vector< proshade_unsign > > findPeaksCSymmetry (std::vector< proshade_double * > *peaks, proshade_signed verbose, proshade_unsign band, proshade_double missPeakThres, proshade_double axisErrTolerance, bool axisErrToleranceDef, ProSHADE_internal_data::ProSHADE_data *dataObj)
 This function searches the list of peaks for presence of cyclic symmetry. More...
 
std::vector< std::vector< proshade_unsign > > groupSameAxes (std::vector< proshade_double * > &peaks, proshade_double errTolerance)
 This function groups the peaks by their axes of rotation. More...
 
void giveOppositeAxesSameDirection (std::vector< proshade_double * > peaks)
 This function modifiest the axes so that the highest vector element is always positive. More...
 
void printSymmetryPeaks (std::vector< proshade_unsign > grp, std::vector< proshade_double * > peaks, proshade_signed verbose, proshade_unsign groupNo)
 This function simply prints the symmetry axis group supplied in the first parameter from the second parameter values. More...
 
bool smallestDistanceBetweenAngles (std::vector< proshade_unsign > grp, std::vector< proshade_double * > peaks, std::vector< proshade_double > *tried, proshade_double *dist)
 This function finds the smallest distance between the rotation angles within a group. More...
 
void addZeroPeakToGroups (std::vector< std::vector< proshade_unsign > > &grpsVec, std::vector< proshade_double * > &peaks)
 This function takes the peak groups and adds zero peak to each of them. More...
 
bool determineFoldToTry (proshade_double dist, proshade_double *divBasis, proshade_double *divRem, proshade_double peakErr, proshade_double *symmErr, std::vector< proshade_unsign > *angsToTry)
 This function determines the symmetry fold to be searched for. More...
 
void findExpectedPeakRotations (proshade_unsign fold, std::vector< proshade_double > *expAngs)
 This function computes the expected peak rotations for given fold. More...
 
proshade_unsign checkExpectedAgainstFound (std::vector< proshade_unsign > grp, std::vector< proshade_double * > peaks, std::vector< proshade_double > *expAngs, std::vector< proshade_unsign > *matchedAngs, std::vector< proshade_unsign > *missingAngs, proshade_double axisTol)
 This function computes the expected peak rotations for given fold. More...
 
proshade_double checkForMissingPeak (ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_double x, proshade_double y, proshade_double z, proshade_double angle, proshade_double heightThres, proshade_double axTol)
 This function checks for the high of the correlation for particular rotation angle and axis. More...
 
void saveDetectedCSymmetry (proshade_unsign fold, std::vector< proshade_unsign > *matchedPeaks, std::vector< std::vector< proshade_unsign > > *ret, proshade_signed verbose)
 This function saves a detected symmetry for reporting to the user. More...
 
bool completeMissingCSymmetry (ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_unsign fold, std::vector< proshade_unsign > *grp, std::vector< proshade_double * > *peaks, std::vector< proshade_unsign > *missingPeaks, std::vector< proshade_double > *expectedAngles, std::vector< proshade_unsign > *matchedPeaks, proshade_double axErrTolerance, proshade_unsign verbose)
 This function does the complete missing peak searching and filling in the missing peaks. More...
 
void findSymmetryUsingFold (ProSHADE_internal_data::ProSHADE_data *dataObj, std::vector< proshade_unsign > *angsToTry, std::vector< proshade_unsign > *grp, std::vector< proshade_double * > *peaks, std::vector< std::vector< proshade_unsign > > *ret, std::vector< proshade_unsign > *testedAlready, proshade_double axErrTolerance, bool axErrToleranceDefault, proshade_double missPeakThres, proshade_unsign verbose)
 This function tests all supplied folds for being supported by the peaks (i.e. and being complete present symmetry). More...
 
void printSymmetryGroup (std::vector< proshade_unsign > grp, std::vector< proshade_double * > peaks, proshade_signed verbose)
 This function simply prints the detected symmetry and all its supporting peaks. More...
 
void printSymmetryCompletion (proshade_unsign noSyms, proshade_unsign verbose)
 This function simply prints the summary and warnings for cyclic symmetries detection completion. More...
 
void saveAllCSymmetries (std::vector< std::vector< proshade_unsign > > detected, std::vector< proshade_double * > peaks, std::vector< proshade_double * > *ret, proshade_double axErr)
 This function takes the detected symmetries indices and peaks and saves these in the main cyclic symmetries detection output format. More...
 
bool isSymmetrySame (std::vector< proshade_double * > *ret, proshade_double *sym, proshade_double simThres)
 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_unsign verbose, 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_unsign verbose, 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_unsign verbose, 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_unsign verbose, 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_unsign verbose, 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...
 
void 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_unsign verbose, 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 predictIcosAxes (ProSHADE_settings *settings, std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_unsign verbose, proshade_double minPeakHeight, proshade_double matrixTolerance)
 This function predicts all icosahedral point group 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_internal_data::ProSHADE_data *dataObj, proshade_unsign verbose, proshade_double minPeakHeight, proshade_double matrixTolerance)
 This function predicts all octahedral point group symmetry axes from the cyclic point groups list. More...
 
void findIcos10C3s (std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_unsign verbose, 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_unsign verbose, 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...
 

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()

void 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.

Definition at line 2527 of file ProSHADE_symmetry.cpp.

2528 {
2529  //================================================ Initialise variables
2530  proshade_double* symHlp = new proshade_double[6];
2531  ProSHADE_internal_misc::checkMemoryAllocation ( symHlp, __FILE__, __LINE__, __func__ );
2532 
2533  //================================================ Fill in the prospective axis
2534  symHlp[0] = static_cast<proshade_double> ( fold );
2535  symHlp[1] = axX;
2536  symHlp[2] = axY;
2537  symHlp[3] = axZ;
2538  symHlp[4] = 2.0 * M_PI / symHlp[0];
2539  symHlp[5] = axHeight;
2540 
2541  //================================================ If it is not the same as already saved axes
2542  if ( !ProSHADE_internal_symmetry::isSymmetrySame ( prosp, symHlp, axErr ) )
2543  {
2545  }
2546  else
2547  {
2548  delete[] symHlp;
2549  }
2550 
2551  //================================================ Done
2552  return ;
2553 
2554 }

◆ addZeroPeakToGroups()

void ProSHADE_internal_symmetry::addZeroPeakToGroups ( std::vector< std::vector< proshade_unsign > > &  grpsVec,
std::vector< proshade_double * > &  peaks 
)

This function takes the peak groups and adds zero peak to each of them.

This function takes all of the detected peak axis groups and the list of peaks. It then proceeds to add a single peak per a group to the peaks list; this newly added peak has the same axis as the group, but zero angle. The function also adds the index of this new peak to the peak group, so that the group now has a new member, a peak with zero angle and the same axis.

Parameters
[in]grpsVecA list of all symmetry axis groups.
[in]peaksThe vector of all peaks from which the group indices are to be drawn.

Definition at line 621 of file ProSHADE_symmetry.cpp.

622 {
623  //================================================ Do your job
624  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( grpsVec.size() ); iter++ )
625  {
626  proshade_double* hlpP = new proshade_double [5];
627  ProSHADE_internal_misc::checkMemoryAllocation ( hlpP, __FILE__, __LINE__, __func__ );
628  hlpP[0] = peaks.at(grpsVec.at(iter).at(0))[0];
629  hlpP[1] = peaks.at(grpsVec.at(iter).at(0))[1];
630  hlpP[2] = peaks.at(grpsVec.at(iter).at(0))[2];
631  hlpP[3] = 0.0;
632  hlpP[4] = peaks.at(grpsVec.at(iter).at(0))[4];
633  ProSHADE_internal_misc::addToUnsignVector ( &grpsVec.at(iter), static_cast<proshade_unsign> ( peaks.size() ) );
635  }
636 
637  //================================================ Done
638  return ;
639 
640 }

◆ checkExpectedAgainstFound()

proshade_unsign ProSHADE_internal_symmetry::checkExpectedAgainstFound ( std::vector< proshade_unsign >  grp,
std::vector< proshade_double * >  peaks,
std::vector< proshade_double > *  expAngs,
std::vector< proshade_unsign > *  matchedAngs,
std::vector< proshade_unsign > *  missingAngs,
proshade_double  angTol 
)

This function computes the expected peak rotations for given fold.

This function compares the expected and the detected peak rotation angle values to check if the complete C symmetry is found within this peak axis group. It also saves the indices of the matched and missing peaks and returns the number of consecutive mathes.

Parameters
[in]grpA single symmetry axis group indices to be processed.
[in]peaksThe vector of all peaks from which the indices are drawn.
[in]expAngsA vector where the expected peak rotation values are saved.
[in]matchedAngsA vector where the indices of matched peaks will be saved.
[in]missingAngsA vector where the indices of missing peaks will be saved.
[in]angTolThe tolerance for matching the expected and found peak rotation angles.
[out]XAn integer with the longest consecutive streak of matched values.

Definition at line 734 of file ProSHADE_symmetry.cpp.

735 {
736  //================================================ Initialise variables
737  proshade_unsign ret = 0;
738  proshade_unsign retHlp = 0;
739  proshade_double groupAngle = expAngs->at(1) - expAngs->at(0);
740  bool matchedThisPeak = false;
741  bool noDoubleMatches = false;
742  std::vector < proshade_unsign > matchedAlready;
743 
744  //================================================ For each expected peak rotation angle value
745  for ( proshade_unsign expAngIt = 0; expAngIt < static_cast<proshade_unsign> ( expAngs->size() ); expAngIt++ )
746  {
747  //============================================ For each peak in the group
748  matchedThisPeak = false;
749  for ( proshade_unsign peakIt = 0; peakIt < static_cast<proshade_unsign> ( grp.size() ); peakIt++ )
750  {
751  if ( ( expAngs->at(expAngIt) < ( peaks.at(grp.at(peakIt))[3] + angTol ) ) &&
752  ( expAngs->at(expAngIt) > ( peaks.at(grp.at(peakIt))[3] - angTol ) ) )
753  {
754  noDoubleMatches = false;
755  for ( proshade_unsign ndm = 0; ndm < static_cast<proshade_unsign> ( matchedAlready.size() ); ndm++ )
756  {
757  if ( matchedAlready.at(ndm) == grp.at(peakIt) ) { noDoubleMatches = true; break; }
758  }
759 
760  if ( !noDoubleMatches )
761  {
762  ProSHADE_internal_misc::addToUnsignVector ( matchedAngs, grp.at(peakIt) );
763  ProSHADE_internal_misc::addToUnsignVector ( &matchedAlready, grp.at(peakIt) );
764  matchedThisPeak = true;
765  break;
766  }
767  }
768  }
769 
770  //============================================ If not matched, add to missing
771  if ( !matchedThisPeak )
772  {
773  ProSHADE_internal_misc::addToUnsignVector ( missingAngs, expAngIt );
774  }
775  }
776 
777  //================================================ Find the number of consecutive matches
778  if ( matchedAngs->size () > 1 )
779  {
780  for ( proshade_unsign iter = 1; iter < static_cast<unsigned int> ( matchedAngs->size () ); iter++ )
781  {
782  if ( ( ( peaks.at(matchedAngs->at(iter-1))[3] + groupAngle ) < ( peaks.at(matchedAngs->at(iter))[3] + angTol ) ) &&
783  ( ( peaks.at(matchedAngs->at(iter-1))[3] + groupAngle ) > ( peaks.at(matchedAngs->at(iter))[3] - angTol ) ) )
784  {
785  retHlp += 1;
786  }
787  else
788  {
789  retHlp = 0;
790  }
791  if ( retHlp > ret ) { ret = retHlp; }
792  }
793  }
794 
795  //================================================ Done
796  return ( ret + 1 ); // This is because the count of matches is the count of intervals between numbers, so +1 to get the count of matched numbers.
797 
798 }

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

2578 {
2579  //================================================ Initialise variables
2580  proshade_unsign noG1 = 0;
2581  proshade_unsign noG2 = 0;
2582  proshade_double dotProd = 0.0;
2583  proshade_double axHeight = 0.0;
2584 
2585  //================================================ Find the angle and count dual matching frequencies
2586  for ( proshade_unsign rIt = 0; rIt < static_cast<proshade_unsign> ( retGroup->size() ); rIt++ )
2587  {
2588  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(retGroup->at(rIt))[1],
2589  &ret->at(retGroup->at(rIt))[2],
2590  &ret->at(retGroup->at(rIt))[3],
2591  &axX, &axY, &axZ );
2592 
2593  if ( ( std::abs ( dotProd ) > ( angle1 - axErr ) ) && ( std::abs ( dotProd ) < ( angle1 + axErr ) ) ) { noG1 += 1; continue; }
2594  if ( ( std::abs ( dotProd ) > ( angle2 - axErr ) ) && ( std::abs ( dotProd ) < ( angle2 + axErr ) ) ) { noG2 += 1; continue; }
2595  }
2596 
2597  //================================================ If correct frequencies are matched, check height.
2598  if ( ( noG1 == noMatchesG1 ) && ( noG2 == noMatchesG2 ) )
2599  {
2600  //============================================ Is the height good enough?
2601  axHeight = ProSHADE_internal_symmetry::missingAxisHeight ( axX, axY, axZ, dataObj, fold, axErr );
2602 
2603  //============================================ If so, save
2604  if ( axHeight > 0.1 )
2605  {
2606  proshade_unsign prevProsp = static_cast<proshade_unsign> ( prosp->size() );
2607  ProSHADE_internal_symmetry::addAxisUnlessSame ( fold, axX, axY, axZ, axHeight, prosp, axErr );
2608 
2609  if ( static_cast<proshade_unsign> ( prosp->size() ) > prevProsp ) { return ( true ); }
2610  else { return ( false ); }
2611  }
2612  }
2613 
2614  //================================================ Done
2615  return ( false );
2616 
2617 }

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

3523 {
3524  //================================================ Initialise variables
3525  proshade_unsign noG1 = 0;
3526  proshade_unsign noG2 = 0;
3527  proshade_unsign noG3 = 0;
3528  proshade_double dotProd = 0.0;
3529  proshade_double axHeight = 0.0;
3530 
3531  //================================================ Find the angle and count dual matching frequencies
3532  for ( proshade_unsign rIt = 0; rIt < static_cast<proshade_unsign> ( retGroup->size() ); rIt++ )
3533  {
3534  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(retGroup->at(rIt))[1],
3535  &ret->at(retGroup->at(rIt))[2],
3536  &ret->at(retGroup->at(rIt))[3],
3537  &axX, &axY, &axZ );
3538 
3539  if ( ( std::abs ( dotProd ) > ( angle1 - axErr ) ) && ( std::abs ( dotProd ) < ( angle1 + axErr ) ) ) { noG1 += 1; continue; }
3540  if ( ( std::abs ( dotProd ) > ( angle2 - axErr ) ) && ( std::abs ( dotProd ) < ( angle2 + axErr ) ) ) { noG2 += 1; continue; }
3541  if ( ( std::abs ( dotProd ) > ( angle3 - axErr ) ) && ( std::abs ( dotProd ) < ( angle3 + axErr ) ) ) { noG3 += 1; continue; }
3542  }
3543 
3544  //================================================ If correct frequencies are matched, check height.
3545  if ( ( noG1 == noMatchesG1 ) && ( noG2 == noMatchesG2 ) && ( noG3 == noMatchesG3 ) )
3546  {
3547  //============================================ Is the height good enough?
3548  axHeight = ProSHADE_internal_symmetry::missingAxisHeight ( axX, axY, axZ, dataObj, fold, axErr );
3549 
3550  //============================================ If so, save
3551  if ( axHeight > 0.1 )
3552  {
3553  ProSHADE_internal_symmetry::addAxisUnlessSame ( fold, axX, axY, axZ, axHeight, prosp, axErr );
3554  }
3555  }
3556 
3557  //================================================ Done
3558  return ;
3559 
3560 }

◆ checkForMissingPeak()

proshade_double ProSHADE_internal_symmetry::checkForMissingPeak ( ProSHADE_internal_data::ProSHADE_data dataObj,
proshade_double  x,
proshade_double  y,
proshade_double  z,
proshade_double  angle,
proshade_double  heightThres,
proshade_double  axTol 
)

This function checks for the high of the correlation for particular rotation angle and axis.

This is the core of missing peaks procedure. This function takes the angle-axis representation of the sought after peak/rotation and searches the data objects (respectivelly its inverse SO(3) Fourier Transform map) for the highest point conforming to these specifications. It then returns the highest value found, so that it could be decided whether the symmetry search has been successfully completed or whether the symmetry was not found.

Parameters
[in]dataObjThe data object for which symmetry is being searched.
[in]xThe x-axis element of the searched for rotation angle-axis representation.
[in]yThe y-axis element of the searched for rotation angle-axis representation.
[in]zThe z-axis element of the searched for rotation angle-axis representation.
[in]angleThe angle element of the searched for rotation angle-axis representation.
[in]heightThresThe required self-rotation map height for this rotation.
[in]axTolThe tolerance on axis matching when searching for the rotation.
[out]XThe height of highest matching map point.

Definition at line 816 of file ProSHADE_symmetry.cpp.

817 {
818  //================================================ Initialise variables
819  proshade_double ret = 0.0;
820  proshade_unsign arrIndex = 0;
821  proshade_double* rotMat = new proshade_double [9];
822  ProSHADE_internal_misc::checkMemoryAllocation ( rotMat, __FILE__, __LINE__, __func__ );
823  proshade_double pointHeight, euA, euB, euG, xPk, yPk, zPk, anglPk;
824  proshade_double angTol = std::acos ( 1.0 - axTol );
825 
826  //================================================ Search the self-rotation map
827  for ( proshade_unsign xIt = 0; xIt < ( dataObj->getMaxBand() * 2 ); xIt++ )
828  {
829  for ( proshade_unsign yIt = 0; yIt < ( dataObj->getMaxBand() * 2 ); yIt++ )
830  {
831  for ( proshade_unsign zIt = 0; zIt < ( dataObj->getMaxBand() * 2 ); zIt++ )
832  {
833  //==================================== Get height and check against threshold
834  arrIndex = zIt + ( dataObj->getMaxBand() * 2 ) * ( yIt + ( dataObj->getMaxBand() * 2 ) * xIt );
835  pointHeight = pow( dataObj->getInvSO3Coeffs()[arrIndex][0], 2.0 ) + pow( dataObj->getInvSO3Coeffs()[arrIndex][1], 2.0 );
836  if ( pointHeight < heightThres ) { continue; }
837 
838  //==================================== Get angle-axis values
839  ProSHADE_internal_maths::getEulerZXZFromSOFTPosition ( dataObj->getMaxBand(), static_cast<proshade_signed> ( xIt ),
840  static_cast<proshade_signed> ( yIt ), static_cast<proshade_signed> ( zIt ),
841  &euA, &euB, &euG );
843  ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( rotMat, &xPk, &yPk, &zPk, &anglPk );
844 
845  //==================================== Check for matching angle
846  if ( ( ( std::abs( anglPk ) - angTol ) < std::abs ( angle ) ) && ( ( std::abs( anglPk ) + angTol ) > std::abs ( angle ) ) )
847  {
848  //================================ Make sure vector direction is the same
849  if ( ( ( std::max( std::abs( xPk ), std::max( std::abs( yPk ), std::abs( zPk ) ) ) == std::abs( xPk ) ) && ( xPk < 0.0 ) ) ||
850  ( ( std::max( std::abs( xPk ), std::max( std::abs( yPk ), std::abs( zPk ) ) ) == std::abs( yPk ) ) && ( yPk < 0.0 ) ) ||
851  ( ( std::max( std::abs( xPk ), std::max( std::abs( yPk ), std::abs( zPk ) ) ) == std::abs( zPk ) ) && ( zPk < 0.0 ) ) )
852  {
853  xPk *= -1.0;
854  yPk *= -1.0;
855  zPk *= -1.0;
856  anglPk *= -1.0;
857  }
858 
859  //================================ Compare axis elements
860  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( xPk, yPk, zPk, x, y, z, axTol ) )
861  {
862  if ( ret < pointHeight ) { ret = pointHeight; }
863  }
864  }
865  }
866  }
867  }
868 
869  //================================================ Done
870  return ( ret );
871 
872 }

◆ completeMissingCSymmetry()

bool ProSHADE_internal_symmetry::completeMissingCSymmetry ( ProSHADE_internal_data::ProSHADE_data dataObj,
proshade_unsign  fold,
std::vector< proshade_unsign > *  grp,
std::vector< proshade_double * > *  peaks,
std::vector< proshade_unsign > *  missingPeaks,
std::vector< proshade_double > *  expectedAngles,
std::vector< proshade_unsign > *  matchedPeaks,
proshade_double  axErrTolerance,
proshade_unsign  verbose 
)

This function does the complete missing peak searching and filling in the missing peaks.

This function does the complete work on missing peaks and detection of symmetries affected by them. It firstly decides on the threshold for a missing peak height and it then proceeds to check all missing peaks for being in the inverse SO(3) FT map. Any detected peaks will be saved to all appropriate variables (as supplied) and finally, if all missing peaks were sucessfully found, it will return true, otherwise false.

Parameters
[in]dataObjThe data object for which symmetry is being searched.
[in]foldThis is the fold value of the detected C symmetry.
[in]grpVector with the indices of members of this symmetry axis group.
[in]peaksA vector of pointers where angle-axis representations of the peaks is saved.
[in]missingPeaksVector with the indices of missing rotation angles (indices are from the expected peaks vector, not peaks vector!).
[in]expectedAnglesVector with the expected rotation angle values.
[in]axErrToleranceThe allowed error on matching axes.
[in]verboseHow loud the standard output of this run should be?
[out]XWas the missing symmetry part completion successfull?

Definition at line 924 of file ProSHADE_symmetry.cpp.

925 {
926  //================================================ Initialise variables
927  bool ret = true;
928 
929  //================================================ Report searching for missing peaks
930  std::stringstream hlpSSP;
931  hlpSSP << "Searching for missing peaks for symmetry C" << fold;
932  ProSHADE_internal_messages::printProgressMessage ( verbose, 4, hlpSSP.str() );
933 
934  //================================================ Height threshold for missing peak
935  proshade_double heightThreshold = 0.0;
936  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( grp->size() ); grIt++ ) { heightThreshold += peaks->at(grp->at(grIt))[4]; }
937  heightThreshold /= static_cast<proshade_double> ( grp->size() );
938  heightThreshold *= 0.5;
939 
940  //================================================ For each missing value
941  for ( proshade_unsign misPkIt = 0; misPkIt < static_cast<proshade_unsign> ( missingPeaks->size() ); misPkIt++ )
942  {
943  //============================================ Ignore the extra values in the expected values
944  if ( expectedAngles->at(missingPeaks->at(misPkIt)) > M_PI ) { continue; }
945  if ( expectedAngles->at(missingPeaks->at(misPkIt)) < -M_PI ) { continue; }
946 
947  //============================================ Search for the missing peak
948  proshade_double misHeight = ProSHADE_internal_symmetry::checkForMissingPeak ( dataObj, peaks->at(grp->at(0))[0], peaks->at(grp->at(0))[1], peaks->at(grp->at(0))[2], expectedAngles->at(missingPeaks->at(misPkIt)), heightThreshold, axErrTolerance );
949  if ( misHeight != 0.0 )
950  {
951  //======================================== Missing peak detected - save it to the group
952  proshade_double* hlpP = new proshade_double [5];
953  ProSHADE_internal_misc::checkMemoryAllocation ( hlpP, __FILE__, __LINE__, __func__ );
954  hlpP[0] = peaks->at(grp->at(0))[0];
955  hlpP[1] = peaks->at(grp->at(0))[1];
956  hlpP[2] = peaks->at(grp->at(0))[2];
957  hlpP[3] = expectedAngles->at(missingPeaks->at(misPkIt));
958  hlpP[4] = misHeight;
959  ProSHADE_internal_misc::addToUnsignVector ( matchedPeaks, static_cast<proshade_unsign> ( peaks->size() ) );
961  }
962  else
963  {
964  ret = false;
965  }
966  }
967 
968  //================================================ Done
969  return ( ret );
970 
971 }

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

2766 {
2767  //================================================ Initialise variables
2768  std::vector< proshade_unsign > C5List;
2769  proshade_double dotProduct;
2770 
2771  //================================================ Find all C5 symmetries
2772  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
2773  {
2774  if ( CSymList->at(cSym)[0] == 5 && CSymList->at(cSym)[5] >= minPeakHeight ) { ProSHADE_internal_misc::addToUnsignVector ( &C5List, cSym ); }
2775  }
2776 
2777  //================================================ For each unique pair of C5 and C3
2778  for ( proshade_unsign c5 = 0; c5 < static_cast<proshade_unsign> ( C5List.size() ); c5++ )
2779  {
2780  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
2781  {
2782  //======================================== Compare only C3s to the C5List
2783  if ( CSymList->at(cSym)[0] != 3 ) { continue; }
2784 
2785  //======================================== Check the angle between the C5 and C3 axes
2786  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(C5List.at(c5))[1],
2787  &CSymList->at(C5List.at(c5))[2],
2788  &CSymList->at(C5List.at(c5))[3],
2789  &CSymList->at(cSym)[1],
2790  &CSymList->at(cSym)[2],
2791  &CSymList->at(cSym)[3] );
2792 
2793  //======================================== Is the angle approximately the dihedral angle
2794  if ( std::abs ( std::abs( -sqrt ( 5.0 ) / 3.0 ) - std::abs( dotProduct ) ) < axErr )
2795  {
2796  return ( true );
2797  }
2798  }
2799  }
2800 
2801  //================================================ Done
2802  return ( false );
2803 
2804 }

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

2153 {
2154  //================================================ Initialise variables
2155  std::vector< proshade_unsign > C4List;
2156  proshade_double dotProduct;
2157 
2158  //================================================ Find all C4 symmetries
2159  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
2160  {
2161  if ( CSymList->at(cSym)[0] == 4 && CSymList->at(cSym)[5] >= minPeakHeight ) { ProSHADE_internal_misc::addToUnsignVector ( &C4List, cSym ); }
2162  }
2163 
2164  //================================================ For each unique pair of C3s
2165  for ( proshade_unsign c4 = 0; c4 < static_cast<proshade_unsign> ( C4List.size() ); c4++ )
2166  {
2167  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
2168  {
2169  //======================================== Compare only C3s to the C3List
2170  if ( CSymList->at(cSym)[0] != 3 ) { continue; }
2171 
2172  //======================================== Check the angle between the C4 and C3 axes
2173  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(C4List.at(c4))[1],
2174  &CSymList->at(C4List.at(c4))[2],
2175  &CSymList->at(C4List.at(c4))[3],
2176  &CSymList->at(cSym)[1],
2177  &CSymList->at(cSym)[2],
2178  &CSymList->at(cSym)[3] );
2179 
2180  //======================================== Is the angle approximately the dihedral angle
2181  if ( ( ( 1.0 / sqrt ( 3.0 ) ) > ( dotProduct - axErr ) ) && ( ( 1.0 / sqrt ( 3.0 ) ) < ( dotProduct + axErr ) ) )
2182  {
2183  return ( true );
2184  }
2185  }
2186  }
2187 
2188  //================================================ Done
2189  return ( false );
2190 
2191 }

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

1397 {
1398  //================================================ Initialise variables
1399  std::vector< proshade_unsign > C3List;
1400  proshade_double dotProduct;
1401 
1402  //================================================ Find all C3 symmetries
1403  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
1404  {
1405  if ( CSymList->at(cSym)[0] == 3 && CSymList->at(cSym)[5] >= minPeakHeight ) { ProSHADE_internal_misc::addToUnsignVector ( &C3List, cSym ); }
1406  }
1407 
1408  //================================================ For each unique pair of C3s
1409  for ( proshade_unsign c31 = 0; c31 < static_cast<proshade_unsign> ( C3List.size() ); c31++ )
1410  {
1411  for ( proshade_unsign c32 = 1; c32 < static_cast<proshade_unsign> ( C3List.size() ); c32++ )
1412  {
1413  //================================ Unique pairs only
1414  if ( c31 >= c32 ) { continue; }
1415 
1416  //======================================== Check the angle between the C3 axes
1417  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] );
1418 
1419  //================================ Is the angle approximately the dihedral angle
1420  if ( ( ( 1.0 / 3.0 ) > ( dotProduct - axErr ) ) && ( ( 1.0 / 3.0 ) < ( dotProduct + axErr ) ) )
1421  {
1422  return ( true );
1423  }
1424  }
1425  }
1426 
1427  //================================================ Done
1428  return ( false );
1429 
1430 }

◆ determineFoldToTry()

bool ProSHADE_internal_symmetry::determineFoldToTry ( proshade_double  dist,
proshade_double *  divBasis,
proshade_double *  divRem,
proshade_double  peakErr,
proshade_double *  symmErr,
std::vector< proshade_unsign > *  angsToTry 
)

This function determines the symmetry fold to be searched for.

This function detects which fold would belong to the rotation angle distance supplied. This is done by finding the division basis for the simple 2pi/dist equation and minimising the remainder. The function then checks whether the remainder is smaller than a threshold and whether the error on fold detection is not close to fold+1 value in terms of peak misplacement in the map - if it is, then surrounding fold values are also added to be tested. Finally, the function returns boolean value stating whether at least one testable fold value passed the checks.

Parameters
[in]distThe distance between rotation angles that should form the symmetry group.
[in]divBasisPointer to where to save the basis of the division 2pi/dist.
[in]divRemPointer to where to save the remainder of the division 2pi/dist.
[in]peakErrThe error in radians which would be the result of misplacing a peak by single map index.
[in]symmErrPointer to where to save the error which would be caused by mis-predicting the fold by 1.
[in]angsToTryA vector where all the suggested fold values to be tested are saved.
[out]XBoolean value whether at least single testable fold value was found

Definition at line 658 of file ProSHADE_symmetry.cpp.

659 {
660  //================================================ Initialise variables
661  bool ret = false;
662 
663  //================================================ Find the basis and remainder of the 2pi/dist equation
664  *divRem = std::modf ( static_cast<proshade_double> ( ( 2.0 * M_PI ) / std::abs ( dist ) ), divBasis );
665 
666  //================================================ If the remainder would be smaller for larger basis, so this basis
667  if ( *divRem > 0.5 )
668  {
669  *divRem -= 1.0;
670  *divBasis += 1.0;
671  }
672 
673  //================================================ Determine errors on peaks and on folds
674  *symmErr = ( M_PI * 2.0 / *divBasis ) - ( M_PI * 2.0 / ( *divBasis + 1.0 ) );
675  proshade_double angTolerance = ( peakErr / *symmErr );
676 
677  //================================================ Is remainder small enough?
678  if ( ( *divRem < ( 0.0 + angTolerance ) ) && ( *divRem > ( 0.0 - angTolerance ) ) )
679  {
680  //============================================ Are we sure about the fold determination accuracy
681  proshade_signed angTolRound = std::min ( ProSHADE_internal_mapManip::myRound ( angTolerance ), static_cast<proshade_signed> ( 10 ) );
682  for ( proshade_signed iter = -angTolRound; iter <= angTolRound; iter++ )
683  {
684  ProSHADE_internal_misc::addToUnsignVector ( angsToTry, static_cast<proshade_unsign> ( std::max ( *divBasis + iter, 2.0 ) ) );
685  }
686  }
687 
688  //================================================ Return indication of whether testable fold value(s) was found.
689  if ( angsToTry->size() == 0 ) { ret = false; }
690  else { ret = true; }
691 
692  //================================================ Done
693  return ( ret );
694 
695 }

◆ findExpectedPeakRotations()

void ProSHADE_internal_symmetry::findExpectedPeakRotations ( proshade_unsign  fold,
std::vector< proshade_double > *  expAngs 
)

This function computes the expected peak rotations for given fold.

This function computes the expected peak rotation angle values for the peak range between -180 to +180 degrees plus one distance on both sides for a good measure. The resulting values are then saved to the second parameter vector.

Parameters
[in]foldThe fold for which peak rotation angles should be predicted.
[in]expAngsA vector where the expected peak rotation values will be saved to.

Definition at line 705 of file ProSHADE_symmetry.cpp.

706 {
707  //================================================ Initialise variables
708  proshade_double groupAngle = ( 2.0 * M_PI ) / static_cast<proshade_double> ( fold );
709 
710  //================================================ Generate expected angles
711  for ( proshade_signed iter = static_cast<proshade_signed> ( -( static_cast<proshade_double> ( fold ) / 2.0 + 1.0) ); iter <= static_cast<proshade_signed> ( static_cast<proshade_double> ( fold )/2.0 + 1.0 ); iter++ )
712  {
713  ProSHADE_internal_misc::addToDoubleVector ( expAngs, iter * groupAngle );
714  }
715 
716  //================================================ Done
717  return ;
718 
719 }

◆ 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_unsign  verbose,
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]verobseHow loud the announcments should be?

Definition at line 3257 of file ProSHADE_symmetry.cpp.

3258 {
3259  //================================================ Initialise variables
3260  std::vector< proshade_unsign > prospectiveC3s, retGrp;
3261  proshade_double dotProd;
3262  proshade_unsign noClose, noAway;
3263 
3264  //================================================ Report progress
3265  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of ten C3 axes." );
3266 
3267  //================================================ For each C3
3268  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
3269  {
3270  //============================================ Use only C3s with hight enough average
3271  if ( CSymList->at(cIt)[0] != 3.0 || CSymList->at(cIt)[0] < minPeakHeight ) { continue; }
3272 
3273  //============================================ Check the C3 has acos ( sqrt ( 5.0 ) / 3.0 ) to 3 C5s and acos ( 1.0 - ( sqrt ( 5.0 ) / 3.0 ) ) to the other three C5s
3274  noClose = 0; noAway = 0;
3275  for ( proshade_unsign rIt = 0; rIt < 6; rIt++ )
3276  {
3277  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1],
3278  &ret->at(rIt)[2],
3279  &ret->at(rIt)[3],
3280  &CSymList->at(cIt)[1],
3281  &CSymList->at(cIt)[2],
3282  &CSymList->at(cIt)[3] );
3283 
3284  if ( ( std::abs ( dotProd ) > ( ( sqrt ( 5.0 ) / 3.0 ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( sqrt ( 5.0 ) / 3.0 ) + axErr ) ) ) { noClose += 1; continue; }
3285  if ( ( std::abs ( dotProd ) > ( 1.0 - ( sqrt ( 5.0 ) / 3.0 ) - axErr ) ) && ( std::abs ( dotProd ) < ( 1.0 - ( sqrt ( 5.0 ) / 3.0 ) + axErr ) ) ) { noAway += 1; continue; }
3286  }
3287 
3288  //============================================ If correct angles distribution is found, save the axis
3289  if ( ( noClose == 3 ) && ( noAway == 3 ) )
3290  {
3291  ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC3s, cIt );
3292  }
3293  }
3294 
3295  //================================================ Search for missing axes
3296  for ( proshade_unsign iter = 0; iter < 6; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &retGrp, iter ); }
3297  if ( !ProSHADE_internal_symmetry::findMissingAxesDual ( &prospectiveC3s, CSymList, ret, &retGrp, 10, axErr, 3, sqrt ( 5.0 ) / 3.0, 3, 1.0 - ( sqrt ( 5.0 ) / 3.0 ), 3, dataObj ) )
3298  {
3299  return ;
3300  }
3301 
3302  //================================================ Found correct number of axes! Now save the
3303  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( prospectiveC3s.size() ); iter++ )
3304  {
3305  ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(prospectiveC3s.at(iter)) );
3306  }
3307 
3308  //================================================ Report progress
3309  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of ten C3 axes successfull." );
3310 
3311  //================================================ Done
3312  return ;
3313 
3314 }

◆ 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_unsign  verbose,
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]verobseHow loud the announcments should be?

Definition at line 3329 of file ProSHADE_symmetry.cpp.

3330 {
3331  //================================================ Initialise variables
3332  std::vector< proshade_unsign > prospectiveC2s, retGrp;
3333  proshade_double dotProd;
3334  proshade_unsign noClose, noMidway, noAway;
3335 
3336  //================================================ Report progress
3337  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of fifteen C2 axes." );
3338 
3339  //================================================ For each C2
3340  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
3341  {
3342  //============================================ Use only C2s
3343  if ( CSymList->at(cIt)[0] != 2.0 || CSymList->at(cIt)[0] < minPeakHeight ) { continue; }
3344 
3345  //============================================ 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
3346  noClose = 0; noMidway = 0; noAway = 0;
3347  for ( proshade_unsign rIt = 0; rIt < 6; rIt++ )
3348  {
3349  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1],
3350  &ret->at(rIt)[2],
3351  &ret->at(rIt)[3],
3352  &CSymList->at(cIt)[1],
3353  &CSymList->at(cIt)[2],
3354  &CSymList->at(cIt)[3] );
3355 
3356  if ( ( std::abs ( dotProd ) > ( ( sqrt ( 3.0 ) / 2.0 ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( sqrt ( 3.0 ) / 2.0 ) + axErr ) ) ) { noAway += 1; continue; }
3357  if ( ( std::abs ( dotProd ) > ( ( 1.0 / 2.0 ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( 1.0 / 2.0 ) + axErr ) ) ) { noMidway += 1; continue; }
3358  if ( ( std::abs ( dotProd ) > ( ( 0.0 ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( 0.0 ) + axErr ) ) ) { noClose += 1; continue; }
3359  }
3360 
3361  //============================================ If correct angles distribution is found, save the axis
3362  if ( ( noClose == 2 ) && ( noMidway == 2 ) && ( noAway == 2 ) )
3363  {
3364  ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC2s, cIt );
3365  }
3366  }
3367 
3368  //================================================ Search for missing axes
3369  for ( proshade_unsign iter = 0; iter < 6; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &retGrp, iter ); }
3370  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 ) )
3371  {
3372  return ;
3373  }
3374 
3375  //================================================ Found correct number of axes! Now save the
3376  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( prospectiveC2s.size() ); iter++ )
3377  {
3378  ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(prospectiveC2s.at(iter)) );
3379  }
3380 
3381  //================================================ Report progress
3382  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of fifteen C2 axes successfull." );
3383 
3384  //================================================ Done
3385  return ;
3386 
3387 }

◆ 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_unsign  verbose,
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]verobseHow loud the announcments should be?

Definition at line 2823 of file ProSHADE_symmetry.cpp.

2824 {
2825  //================================================ Initialise variables
2826  std::vector< proshade_unsign > C5PossibilitiesHlp;
2827  std::vector< std::vector< proshade_unsign > > C5Possibilities;
2828  bool groupMatched;
2829 
2830  //================================================ Report progress
2831  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of six C5 axes." );
2832 
2833  //================================================ For all symmetries in the C symmetries list
2834  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
2835  {
2836  //============================================ Search only using C5s and check peak height
2837  if ( CSymList->at(cIt)[0] != 5.0 || CSymList->at(cIt)[5] < minPeakHeight ) { continue; }
2838 
2839  //============================================ If second or more C5, check if it has the correct angle to all other already found C5s for each group
2840  groupMatched = false;
2841  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C5Possibilities.size() ); gIt++ )
2842  {
2843  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; }
2844  }
2845 
2846  //============================================ If no group matched, create a new group
2847  if ( !groupMatched ) { C5PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C5PossibilitiesHlp, cIt ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C5Possibilities, C5PossibilitiesHlp ); continue; }
2848  }
2849 
2850  //================================================ Test for missing symmetry axes, if need be
2851  ProSHADE_internal_symmetry::findMissingAxes ( &C5Possibilities, CSymList, 6, axErr, 1.0 / 2.0, 5, dataObj, minPeakHeight );
2852 
2853  //=================================================Any group has 6 entries? If more such groups, take the one with highest average height.
2854  proshade_double maxHeight = 0.0; proshade_unsign maxGrp = 0;
2855  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; } } }
2856 
2857  if ( C5Possibilities.at(maxGrp).size() == 6 )
2858  {
2859  //============================================ Success! Save and exit
2860  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)) ); }
2861 
2862  //============================================ Report progress
2863  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of six C5 axes successfull." );
2864 
2865  //============================================ Done
2866  return ;
2867  }
2868 
2869  //================================================ Done
2870  return ;
2871 
2872 }

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

1583 {
1584  //================================================ Initialise variables
1585  std::vector< proshade_double* > hlpVec;
1586  bool atLeastOne = false;
1587 
1588  //================================================ Proceed only if need be
1589  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( possibilities->size() ); gIt++ )
1590  {
1591  if ( static_cast<proshade_unsign> ( possibilities->at(gIt).size() ) == requiredNoAxes ) { atLeastOne = true; return ( atLeastOne ); }
1592  }
1593 
1594  //================================================ For each possible group
1595  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( possibilities->size() ); gIt++ )
1596  {
1597  //============================================ This will not work for less than two axes in group
1598  if ( possibilities->at(gIt).size() < 2 ) { continue; }
1599 
1600  //============================================ Prepare iteration
1601  hlpVec.clear ( );
1602 
1603  //============================================ Search for missing axes
1604  ProSHADE_internal_symmetry::searchMissingSymmetrySpace ( dataObj, CSymList, &possibilities->at(gIt), &hlpVec, axErr, angle, fold, minPeakHeight );
1605 
1606  //============================================ Add missing axes
1607  if ( hlpVec.size() > 0 )
1608  {
1609  //======================================== Start adding by highest first
1610  std::sort ( hlpVec.begin(), hlpVec.end(), ProSHADE_internal_misc::sortSymHlpInv );
1611 
1612  //======================================== For each missing axis
1613  for ( proshade_unsign axIt = 0; axIt < static_cast<proshade_unsign> ( hlpVec.size() ); axIt++ )
1614  {
1615  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, &possibilities->at(gIt), hlpVec.at(axIt), axErr, angle, false ) )
1616  {
1617  //================================ Check for uniqueness
1618  if ( ProSHADE_internal_maths::isAxisUnique ( CSymList, hlpVec.at(axIt), axErr ) )
1619  {
1620  //============================ Add
1621  ProSHADE_internal_misc::addToDblPtrVector ( CSymList, hlpVec.at(axIt) );
1622  ProSHADE_internal_misc::addToUnsignVector ( &possibilities->at(gIt), static_cast<proshade_unsign> ( CSymList->size()-1 ) );
1623  }
1624  }
1625  }
1626  }
1627 
1628  if ( possibilities->at(gIt).size() == requiredNoAxes ) { atLeastOne = true; }
1629  }
1630 
1631  //================================================ Done
1632  return ( atLeastOne );
1633 
1634 }

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

2435 {
2436  //================================================ Initialise variables
2437  bool atLeastOne = false;
2438  std::vector< proshade_double* > prosp;
2439  std::vector< proshade_double > sol;
2440 
2441  //================================================ Proceed only if need be
2442  if ( static_cast<proshade_unsign> ( possibilities->size() ) == requiredNoAxes ) { atLeastOne = true; return ( atLeastOne ); }
2443 
2444  //================================================ Copy already found to prospective
2445  for ( proshade_unsign prIt = 0; prIt < static_cast<proshade_unsign> ( possibilities->size() ); prIt++ )
2446  {
2447  ProSHADE_internal_symmetry::addAxisUnlessSame ( CSymList->at(possibilities->at(prIt))[0],
2448  CSymList->at(possibilities->at(prIt))[1],
2449  CSymList->at(possibilities->at(prIt))[2],
2450  CSymList->at(possibilities->at(prIt))[3],
2451  CSymList->at(possibilities->at(prIt))[5], &prosp, axErr );
2452  }
2453 
2454  //================================================ Start generating possible solutions
2455  for ( proshade_unsign rgIt1 = 0; rgIt1 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt1++ )
2456  {
2457  for ( proshade_unsign rgIt2 = 0; rgIt2 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt2++ )
2458  {
2459  //======================================== Use unique combinations (order matters here!)
2460  if ( rgIt1 == rgIt2 ) { continue; }
2461 
2462  //======================================== Generate possible solution (1)
2463  sol = ProSHADE_internal_maths::findVectorFromTwoVAndTwoD ( ret->at(rgIt1)[1], ret->at(rgIt1)[2], ret->at(rgIt1)[3],
2464  ret->at(rgIt2)[1], ret->at(rgIt2)[2], ret->at(rgIt2)[3], angle1, angle2 );
2465 
2466  //======================================== Check if solution fits the group completely
2467  ProSHADE_internal_symmetry::checkFittingAxisDualAndSave ( retGroup, ret, fold, sol.at(0), sol.at(1), sol.at(2), &prosp, axErr, noMatchesG1, angle1, noMatchesG2, angle2, dataObj );
2468  if ( prosp.size() == requiredNoAxes ) { break; }
2469 
2470  //======================================== Generate possible solution (2)
2471  sol = ProSHADE_internal_maths::findVectorFromTwoVAndTwoD ( ret->at(rgIt1)[1], ret->at(rgIt1)[2], ret->at(rgIt1)[3],
2472  ret->at(rgIt2)[1], ret->at(rgIt2)[2], ret->at(rgIt2)[3], -angle1, -angle2 );
2473 
2474  //======================================== Check if solution fits the group completely
2475  ProSHADE_internal_symmetry::checkFittingAxisDualAndSave ( retGroup, ret, fold, sol.at(0), sol.at(1), sol.at(2), &prosp, axErr, noMatchesG1, angle1, noMatchesG2, angle2, dataObj );
2476  if ( prosp.size() == requiredNoAxes ) { break; }
2477  }
2478 
2479  if ( prosp.size() == requiredNoAxes ) { break; }
2480  }
2481 
2482  //================================================ Found all required axes!
2483  if ( static_cast<proshade_unsign> ( prosp.size() ) == requiredNoAxes )
2484  {
2485  //============================================ Copy the detected axes
2486  for ( proshade_unsign iter = static_cast<proshade_unsign> ( possibilities->size() ); iter < static_cast<proshade_unsign> ( prosp.size() ); iter++ )
2487  {
2488  if ( ProSHADE_internal_maths::isAxisUnique ( CSymList, prosp.at(iter), axErr ) )
2489  {
2490  //==================================== Add
2491  ProSHADE_internal_misc::addToUnsignVector ( possibilities, CSymList->size() );
2492  ProSHADE_internal_misc::addToDblPtrVector ( CSymList, prosp.at(iter) );
2493  }
2494  }
2495 
2496  //============================================ Done
2497  atLeastOne = true;
2498  return ( atLeastOne );
2499  }
2500  else
2501  {
2502  //============================================ Delete the created, but not used axes
2503  for ( proshade_unsign iter = static_cast<proshade_unsign> ( possibilities->size() ); iter < static_cast<proshade_unsign> ( prosp.size() ); iter++ )
2504  {
2505  delete[] prosp.at(iter);
2506  }
2507  }
2508 
2509  //================================================ Done
2510  return ( atLeastOne );
2511 
2512 }

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

3412 {
3413  //================================================ Initialise variables
3414  bool atLeastOne = false;
3415  std::vector< proshade_double* > prosp;
3416  std::vector< proshade_double > sol;
3417 
3418  //================================================ Proceed only if need be
3419  if ( static_cast<proshade_unsign> ( possibilities->size() ) == requiredNoAxes ) { atLeastOne = true; return ( atLeastOne ); }
3420 
3421  //================================================ Copy already found to prospective
3422  for ( proshade_unsign prIt = 0; prIt < static_cast<proshade_unsign> ( possibilities->size() ); prIt++ )
3423  {
3424  ProSHADE_internal_symmetry::addAxisUnlessSame ( CSymList->at(possibilities->at(prIt))[0],
3425  CSymList->at(possibilities->at(prIt))[1],
3426  CSymList->at(possibilities->at(prIt))[2],
3427  CSymList->at(possibilities->at(prIt))[3],
3428  CSymList->at(possibilities->at(prIt))[5], &prosp, axErr );
3429  }
3430 
3431  //================================================ Start generating possible solutions
3432  for ( proshade_unsign rgIt1 = 0; rgIt1 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt1++ )
3433  {
3434  for ( proshade_unsign rgIt2 = 0; rgIt2 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt2++ )
3435  {
3436  //======================================== Use unique combinations (order matters here!)
3437  if ( rgIt1 == rgIt2 ) { continue; }
3438 
3439  for ( proshade_unsign rgIt3 = 0; rgIt3 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt3++ )
3440  {
3441  //==================================== Use unique combinations (order matters here!)
3442  if ( ( rgIt1 == rgIt3 ) || ( rgIt2 == rgIt3 ) ) { continue; }
3443 
3444  //==================================== Generate possible solution (1)
3445  sol = ProSHADE_internal_maths::findVectorFromThreeVAndThreeD ( ret->at(rgIt1)[1], ret->at(rgIt1)[2], ret->at(rgIt1)[3],
3446  ret->at(rgIt2)[1], ret->at(rgIt2)[2], ret->at(rgIt2)[3],
3447  ret->at(rgIt3)[1], ret->at(rgIt3)[2], ret->at(rgIt3)[3], angle1, angle2, angle3 );
3448 
3449  //==================================== Check if solution fits the group completely
3450  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 );
3451  if ( prosp.size() == requiredNoAxes ) { break; }
3452 
3453  //==================================== Generate possible solution (2)
3454  sol = ProSHADE_internal_maths::findVectorFromThreeVAndThreeD ( ret->at(rgIt1)[1], ret->at(rgIt1)[2], ret->at(rgIt1)[3],
3455  ret->at(rgIt2)[1], ret->at(rgIt2)[2], ret->at(rgIt2)[3],
3456  ret->at(rgIt3)[1], ret->at(rgIt3)[2], ret->at(rgIt3)[3], -angle1, -angle2, -angle3 );
3457 
3458  //==================================== Check if solution fits the group completely
3459  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 );
3460  if ( prosp.size() == requiredNoAxes ) { break; }
3461  }
3462 
3463  if ( prosp.size() == requiredNoAxes ) { break; }
3464  }
3465 
3466  if ( prosp.size() == requiredNoAxes ) { break; }
3467  }
3468 
3469  //================================================ Found all required axes
3470  if ( prosp.size() == requiredNoAxes )
3471  {
3472  //============================================ For each found missing axis
3473  for ( proshade_unsign axIt = static_cast<proshade_unsign> ( possibilities->size() ); axIt < static_cast<proshade_unsign> ( prosp.size() ); axIt++ )
3474  {
3475  if ( ProSHADE_internal_maths::isAxisUnique ( CSymList, prosp.at(axIt), axErr ) )
3476  {
3477  //======================================== Add
3478  ProSHADE_internal_misc::addToDblPtrVector ( CSymList, prosp.at(axIt) );
3479  ProSHADE_internal_misc::addToUnsignVector ( possibilities, static_cast<proshade_unsign> ( CSymList->size()-1 ) );
3480  }
3481  }
3482 
3483  atLeastOne = true;
3484  return ( atLeastOne );
3485  }
3486  else
3487  {
3488  //============================================ Delete all found, but unnecessary axes
3489  for ( proshade_unsign axIt = static_cast<proshade_unsign> ( possibilities->size() ); axIt < static_cast<proshade_unsign> ( prosp.size() ); axIt++ )
3490  {
3491  delete[] prosp.at(axIt);
3492  }
3493  }
3494 
3495  //================================================ Done
3496  return ( atLeastOne );
3497 
3498 }

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

1726 {
1727  //================================================ Initialise variables
1728  proshade_double euA, euB, euG, xPk, yPk, zPk, anglPk;
1729  proshade_double* rotMat = new proshade_double [9];
1730  ProSHADE_internal_misc::checkMemoryAllocation ( rotMat, __FILE__, __LINE__, __func__ );
1731  proshade_unsign arrIndex;
1732  std::vector< proshade_double* > angVec;
1733 
1734  //================================================ Search the self-rotation map
1735  for ( proshade_unsign xIt = 0; xIt < ( dataObj->getMaxBand() * 2 ); xIt++ )
1736  {
1737  for ( proshade_unsign yIt = 0; yIt < ( dataObj->getMaxBand() * 2 ); yIt++ )
1738  {
1739  for ( proshade_unsign zIt = 0; zIt < ( dataObj->getMaxBand() * 2 ); zIt++ )
1740  {
1741  //==================================== Get height and check against threshold
1742  arrIndex = zIt + ( dataObj->getMaxBand() * 2 ) * ( yIt + ( dataObj->getMaxBand() * 2 ) * xIt );
1743 
1744  //==================================== Get angle-axis values
1745  ProSHADE_internal_maths::getEulerZXZFromSOFTPosition ( dataObj->getMaxBand(), static_cast<proshade_signed> ( xIt ),
1746  static_cast<proshade_signed> ( yIt ), static_cast<proshade_signed> ( zIt ),
1747  &euA, &euB, &euG );
1749  ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( rotMat, &xPk, &yPk, &zPk, &anglPk );
1750 
1751  //==================================== Set largest axis element to positive
1752  if ( ( ( std::max ( std::abs ( xPk ), std::max( std::abs ( yPk ), std::abs ( zPk ) ) ) == std::abs ( xPk ) ) && ( xPk < 0.0 ) ) ||
1753  ( ( std::max ( std::abs ( xPk ), std::max( std::abs ( yPk ), std::abs ( zPk ) ) ) == std::abs ( yPk ) ) && ( yPk < 0.0 ) ) ||
1754  ( ( std::max ( std::abs ( xPk ), std::max( std::abs ( yPk ), std::abs ( zPk ) ) ) == std::abs ( zPk ) ) && ( zPk < 0.0 ) ) )
1755  {
1756  xPk *= -1.0;
1757  yPk *= -1.0;
1758  zPk *= -1.0;
1759  anglPk *= -1.0;
1760  }
1761 
1762  //==================================== Does the peak match the required axis?
1763  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( xPk, yPk, zPk, xVal, yVal, zVal, axErr ) )
1764  {
1765  //================================ Matching map point - save it
1766  proshade_double* hlpArr = new proshade_double [2];
1767  ProSHADE_internal_misc::checkMemoryAllocation ( hlpArr, __FILE__, __LINE__, __func__ );
1768  hlpArr[0] = anglPk + M_PI;
1769  hlpArr[1] = pow( dataObj->getInvSO3Coeffs()[arrIndex][0], 2.0 ) +
1770  pow( dataObj->getInvSO3Coeffs()[arrIndex][1], 2.0 );
1771  ProSHADE_internal_misc::addToDblPtrVector ( &angVec, hlpArr );
1772  }
1773  }
1774  }
1775  }
1776 
1777  //================================================ Release memory
1778  delete[] rotMat;
1779 
1780  //================================================ Done
1781  return ( angVec );
1782 
1783 }

◆ 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_unsign  verbose,
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]verobseHow loud the announcments should be?

Definition at line 2206 of file ProSHADE_symmetry.cpp.

2207 {
2208  //================================================ Initialise variables
2209  std::vector< proshade_unsign > C4PossibilitiesHlp;
2210  std::vector< std::vector< proshade_unsign > > C4Possibilities;
2211  bool groupMatched;
2212 
2213  //================================================ Report progress
2214  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of three C4 axes." );
2215 
2216  //================================================ For all symmetries in the C symmetries list
2217  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
2218  {
2219  //============================================ Search only using C4s
2220  if ( CSymList->at(cIt)[0] != 4.0 || CSymList->at(cIt)[5] < minPeakHeight ) { continue; }
2221 
2222  //============================================ If second or more C4, check if it has the correct angle to all other already found C4s for each group
2223  groupMatched = false;
2224  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C4Possibilities.size() ); gIt++ )
2225  {
2226  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; }
2227  }
2228 
2229  //=========================================== If no group matched, create a new group
2230  if ( !groupMatched ) { C4PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C4PossibilitiesHlp, cIt ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C4Possibilities, C4PossibilitiesHlp ); continue; }
2231  }
2232 
2233  //================================================ Test for missing symmetry axes, if need be
2234  ProSHADE_internal_symmetry::findMissingAxes ( &C4Possibilities, CSymList, 3, axErr, 0.0, 4, dataObj, minPeakHeight );
2235 
2236  //================================================ Any group has 3 entries? If more such groups, take the one with highest average height.
2237  proshade_double maxHeight = 0.0; proshade_unsign maxGrp = 0;
2238  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; } } }
2239 
2240  if ( C4Possibilities.at(maxGrp).size() == 3 )
2241  {
2242  //============================================ Success! Save and exit
2243  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)) ); }
2244 
2245  //============================================ Report progress
2246  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of three C4 axes successfull." );
2247 
2248  //============================================ Done
2249  return ;
2250  }
2251 
2252  //================================================ Done
2253  return ;
2254 
2255 }

◆ 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_unsign  verbose,
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]verobseHow loud the announcments should be?
[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 2272 of file ProSHADE_symmetry.cpp.

2273 {
2274  //================================================ Initialise variables
2275  std::vector< proshade_unsign > C4s, prospectiveC3s, C3PossibilitiesHlp;
2276  std::vector< std::vector< proshade_unsign > > C3Possibilities;
2277  proshade_double dotProd;
2278  bool groupMatched;
2279  for ( proshade_unsign iter = 0; iter < 3; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &C4s, iter ); }
2280 
2281  //================================================ Report progress
2282  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of four C3 axes." );
2283 
2284  //================================================ For each C4
2285  for ( proshade_unsign rIt = 0; rIt < static_cast<proshade_unsign> ( ret->size() ); rIt++ )
2286  {
2287  //============================================ For each C3, check it has angle ( acos( 1/sqrt(3) ) ) to the tested C4
2288  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
2289  {
2290  //======================================== Search only using C3s
2291  if ( CSymList->at(cIt)[0] != 3.0 || CSymList->at(cIt)[5] < minPeakHeight ) { continue; }
2292 
2293  //======================================== Check the C3 axis to the C4 ( acos ( 1/sqrt(3) ) )
2294  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] );
2295 
2296  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 ); }
2297  }
2298  }
2299 
2300  //================================================ Group the prospective C3s
2301  C3Possibilities.clear(); C3PossibilitiesHlp.clear();
2302  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( prospectiveC3s.size() ); cIt++ )
2303  {
2304  //============================================ If second or more C3, check if it can be placed in any group with having acos (1/3) to all its members
2305  groupMatched = false;
2306  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C3Possibilities.size() ); gIt++ )
2307  {
2308  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; }
2309  }
2310 
2311  //============================================ If no group matched, create a new group
2312  if ( !groupMatched ) { C3PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C3PossibilitiesHlp, prospectiveC3s.at(cIt) ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C3Possibilities, C3PossibilitiesHlp ); continue; }
2313  }
2314 
2315  //================================================ Find the best group or return empty
2316  while ( C3Possibilities.size() != 0 )
2317  {
2318  //============================================ Test for missing symmetry axes, if need be
2319  ProSHADE_internal_symmetry::findMissingAxes ( &C3Possibilities, CSymList, 4, axErr, 1.0/3.0, 3, dataObj, minPeakHeight );
2320 
2321  //============================================ Found four C3s?
2322  if ( C3Possibilities.at(0).size() == 4 )
2323  {
2324  //======================================== Success! Save and exit
2325  for ( proshade_unsign it = 0; it < 4; it++ ) { ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(C3Possibilities.at(0).at(it)) ); }
2326 
2327  //======================================== Report progress
2328  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of four C3 axes successfull." );
2329 
2330  //======================================== Done
2331  return ;
2332  }
2333  else { C3Possibilities.erase ( C3Possibilities.begin() ); }
2334  }
2335 
2336  //================================================ Done
2337  return ;
2338 
2339 }

◆ 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_unsign  verbose,
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]verobseHow loud the announcments should be?
[in]minPeakHeightThe minimum average peak height for axis to be considered.

Definition at line 2354 of file ProSHADE_symmetry.cpp.

2355 {
2356  //================================================ Initialise variables
2357  std::vector< proshade_unsign > prospectiveC2s, retGrp;
2358  proshade_double dotProd;
2359  proshade_unsign noPerpendicular, noSqrtTwo;
2360 
2361  //================================================ Report progress
2362  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of six C2 axes." );
2363 
2364  //================================================ For each C2
2365  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
2366  {
2367  //============================================ Use only C2s
2368  if ( CSymList->at(cIt)[0] != 2.0 || CSymList->at(cIt)[5] < minPeakHeight ) { continue; }
2369 
2370  //============================================ Check the C2 has acos ( 1/sqrt(2) ) to 2 C4s and acos ( 0.0 ) to the third C4
2371  noPerpendicular = 0; noSqrtTwo = 0;
2372  for ( proshade_unsign rIt = 0; rIt < 3; rIt++ )
2373  {
2374  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1],
2375  &ret->at(rIt)[2],
2376  &ret->at(rIt)[3],
2377  &CSymList->at(cIt)[1],
2378  &CSymList->at(cIt)[2],
2379  &CSymList->at(cIt)[3] );
2380 
2381  if ( ( std::abs ( dotProd ) > ( ( 1.0 / sqrt(2.0) ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( 1.0 / sqrt(2.0) ) + axErr ) ) ) { noSqrtTwo += 1; continue; }
2382  if ( ( std::abs ( dotProd ) > ( 0.0 - axErr ) ) && ( std::abs ( dotProd ) < ( 0.0 + axErr ) ) ) { noPerpendicular += 1; continue; }
2383  }
2384 
2385  //============================================ If correct angles distribution is found, save the axis
2386  if ( ( noSqrtTwo == 2 ) && ( noPerpendicular == 1 ) )
2387  {
2388  ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC2s, cIt );
2389  }
2390  }
2391 
2392  //================================================ Search for missing axes
2393  for ( proshade_unsign iter = 0; iter < 3; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &retGrp, iter ); }
2394  if ( !ProSHADE_internal_symmetry::findMissingAxesDual ( &prospectiveC2s, CSymList, ret, &retGrp, 6, axErr, 1, 0.0, 2, 1/sqrt(2.0), 2, dataObj ) )
2395  {
2396  return ;
2397  }
2398 
2399  //================================================ Found correct number of axes! Now save the
2400  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( prospectiveC2s.size() ); iter++ )
2401  {
2402  ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(prospectiveC2s.at(iter)) );
2403  }
2404 
2405  //================================================ Report progress
2406  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of six C2 axes successfull." );
2407 
2408  //================================================ Done
2409  return ;
2410 
2411 }

◆ findPeaksByHeightBoundaries()

std::vector< proshade_double > ProSHADE_internal_symmetry::findPeaksByHeightBoundaries ( std::vector< proshade_double * >  allPeaks,
proshade_double  smoothing 
)

This function groups the peaks by height and returns the boundaries between such groups.

This function allows for a list of peaks to be divided into multiple groups based on the peak heights, so that only the most confident values would be used for symmetry detection first.

Parameters
[in]allPeaksA vector of pointers where angle-axis representations of the peaks is saved.
[in]smoothingValue determining how smooth the distribution of peaks should be made. Larger number means more groups.
[out]XThe boundaries for peak groups by height as determined by 1D grouping.

Definition at line 310 of file ProSHADE_symmetry.cpp.

311 {
312  //================================================ Initialise variables
313  std::vector< proshade_double > boundaries;
314  ProSHADE_internal_misc::addToDoubleVector ( &boundaries, 0.0 );
315  proshade_double peakContribution = 0.0;
316 
317  //================================================ Generate Probability Density function (PDF)
318  std::vector< proshade_double > pdf;
319  for ( proshade_double iter = 0.0; iter <= 1.0; iter += 0.01 )
320  {
321  //============================================ Initialise point
322  peakContribution = 0.0;
323 
324  //============================================ Sum peak contributions
325  for ( proshade_unsign it = 0; it < static_cast<proshade_unsign> ( allPeaks.size() ); it++ )
326  {
327  peakContribution += ProSHADE_internal_maths::normalDistributionValue ( allPeaks.at(it)[4], smoothing, iter );
328  }
329 
330  //============================================ Save result
331  ProSHADE_internal_misc::addToDoubleVector ( &pdf, peakContribution );
332  }
333 
334  //================================================ Find boundaries
335  proshade_double prev = pdf.at(0);
336  for ( proshade_unsign iter = 1; iter < static_cast<proshade_unsign> ( pdf.size() - 1 ); iter ++ )
337  {
338  //============================================ Check for local minima
339  if ( ( prev > pdf.at(iter) ) && ( pdf.at(iter+1) > pdf.at(iter) ) )
340  {
341  ProSHADE_internal_misc::addToDoubleVector ( &boundaries, iter * 0.01 );
342  }
343 
344  //============================================ Prepare next iteration
345  prev = pdf.at(iter);
346  }
347 
348  //================================================ Done
349  return ( boundaries );
350 
351 }

◆ findPeaksCSymmetry()

std::vector< std::vector< proshade_unsign > > ProSHADE_internal_symmetry::findPeaksCSymmetry ( std::vector< proshade_double * > *  peaks,
proshade_signed  verbose,
proshade_unsign  band,
proshade_double  missPeakThres,
proshade_double  axisErrTolerance,
bool  axisErrToleranceDef,
ProSHADE_internal_data::ProSHADE_data dataObj 
)

This function searches the list of peaks for presence of cyclic symmetry.

This function takes a set of peaks and a bunch of settings parameters and proceeds to search these peaks for containing any Cyclic (C) symmetries. It contains all the functionality including missing peaks searching and automatic possible fold detection including allowing for errors. It will finally save all the results in the vector of vectors it returns.

Parameters
[in]peaksA vector of pointers where angle-axis representations of the peaks is saved.
[in]verboseHow loud the standard output of this run should be?
[in]bandThe bandwidth of these computations.
[in]missPeakThresThreshold for the percentage of missing peaks there can be to warrant a full search for missing peaks.
[in]axisErrToleranceTolerance for symmetry axis identity.
[in]axisErrToleranceDefShould the automatic axis tolerance decrease be applied?
[in]dataObjThe data object for which symmetry is being searched. This is only needed for missing peaks search, but needed nonetheless.
[out]XVector of vectors with first number being the detected fold and all remaining numbers being the indices of peaks forming the symmetry.

Definition at line 368 of file ProSHADE_symmetry.cpp.

369 {
370  //======================================== Initialise variables
371  std::vector< std::vector< proshade_unsign > > ret;
372  std::vector< proshade_double > triedAlready;
373  std::vector< proshade_unsign > angsToTry, testedAlready;
374  proshade_double angDist, angDivisionRemainder, angDivisionBasis, nextSymmetryError, nextPeakError = ( M_PI * 2.0 ) / ( static_cast<proshade_double> ( band ) * 2.0 );
375 
376  //================================================ Sanity check
377  if ( peaks->size() < 1 ) { return ( ret ); }
378 
379  //================================================ Group peaks by axes
380  std::vector< std::vector< proshade_unsign > > sameAxesGroups = ProSHADE_internal_symmetry::groupSameAxes ( *peaks, axisErrTolerance );
381 
382  //================================================ For each axis group
383  for ( proshade_unsign grpIt = 0; grpIt < static_cast<proshade_unsign> ( sameAxesGroups.size() ); grpIt++ )
384  {
385  //============================================ Print axis group if need be
386  ProSHADE_internal_symmetry::printSymmetryPeaks ( sameAxesGroups.at(grpIt), *peaks, verbose, grpIt );
387 
388  //============================================ While there are distances between rotation angles in the group
389  triedAlready.clear ( );
390  testedAlready.clear ( );
391  while ( ProSHADE_internal_symmetry::smallestDistanceBetweenAngles ( sameAxesGroups.at(grpIt), *peaks, &triedAlready, &angDist ) )
392  {
393  //======================================== Check if testable fold value exists, otherwise test other distances
394  angsToTry.clear ( );
395  if ( !ProSHADE_internal_symmetry::determineFoldToTry ( angDist, &angDivisionBasis, &angDivisionRemainder, nextPeakError, &nextSymmetryError, &angsToTry ) ) { continue; }
396 
397  //======================================== If reasonable folds are found, test these for being complete symmetries
398  ProSHADE_internal_symmetry::findSymmetryUsingFold ( dataObj, &angsToTry, &sameAxesGroups.at(grpIt), peaks, &ret, &testedAlready, axisErrTolerance, axisErrToleranceDef, missPeakThres, verbose );
399  }
400 
401  }
402 
403  //================================================ Done
404  return ( ret );
405 
406 }

◆ findSymmetryUsingFold()

void ProSHADE_internal_symmetry::findSymmetryUsingFold ( ProSHADE_internal_data::ProSHADE_data dataObj,
std::vector< proshade_unsign > *  angsToTry,
std::vector< proshade_unsign > *  grp,
std::vector< proshade_double * > *  peaks,
std::vector< std::vector< proshade_unsign > > *  ret,
std::vector< proshade_unsign > *  testedAlready,
proshade_double  axErrTolerance,
bool  axErrToleranceDefault,
proshade_double  missPeakThres,
proshade_unsign  verbose 
)

This function tests all supplied folds for being supported by the peaks (i.e. and being complete present symmetry).

This function takes all the possible folds which could be in the set of peaks and checks if these are indeed full symmetries, or whether these were random.

Parameters
[in]dataObjThe data object for which symmetry is being searched.
[in]angsToTryThis vector contains all the folds that should be attempted.
[in]grpVector with the indices of members of this symmetry axis group.
[in]peaksA vector of pointers where angle-axis representations of the peaks is saved.
[in]retThe final variable holding all results (i.e. detected symmetries).
[in]testedAlreadyA vector in which the already tested folds for this symmetry axis are saved.
[in]axErrToleranceThe allowed error on matching axes.
[in]axErrToleranceDefaultShould the axErrTolerance be decreased with increasing fold?
[in]missPeakThresThreshold for the percentage of missing peaks there can be to warrant a full search for missing peaks.
[in]verboseHow loud the standard output of this run should be?

Definition at line 989 of file ProSHADE_symmetry.cpp.

990 {
991  //================================================ Initialise variables
992  bool skipFold = false;
993  std::vector< proshade_unsign > matchedPeaks, missingPeaks;
994  std::vector< proshade_double > expectedAngles;
995  proshade_double angTolerance = std::acos ( 1.0 - axErrTolerance );
996 
997  //================================================ Testing folds for being supported by peaks
998  for ( proshade_unsign fIt = 0; fIt < static_cast<proshade_unsign> ( angsToTry->size() ); fIt++ )
999  {
1000  //============================================ Was this fold already found?
1001  skipFold = false;
1002  for ( proshade_unsign ftIt = 0; ftIt < static_cast<proshade_unsign> ( testedAlready->size() ); ftIt++ ) { if ( testedAlready->at(ftIt) == angsToTry->at(fIt) ) { skipFold = true; } }
1003  if ( skipFold ) { continue; }
1004  else { ProSHADE_internal_misc::addToUnsignVector( testedAlready, angsToTry->at(fIt) ); }
1005 
1006  //============================================ Set axis tolerance based on fold (if required)
1007  if ( axErrToleranceDefault )
1008  {
1009  angTolerance = std::max ( std::min ( angTolerance, ( ( (M_PI * 2.0) / static_cast<double> ( angsToTry->at(fIt) ) ) -
1010  ( (M_PI * 2.0) / static_cast<double> ( angsToTry->at(fIt) + 1 ) ) ) * 2.0 ), 0.02 );
1011  axErrTolerance = std::max ( 1.0 - std::cos ( angTolerance ), 0.0008 );
1012  }
1013 
1014  //============================================ Find expected peak rotation angles
1015  expectedAngles.clear ( );
1016  ProSHADE_internal_symmetry::findExpectedPeakRotations ( angsToTry->at(fIt), &expectedAngles );
1017 
1018  //============================================ Compare group to expected angles
1019  matchedPeaks.clear ( );
1020  missingPeaks.clear ( );
1021  proshade_unsign consecMatches = ProSHADE_internal_symmetry::checkExpectedAgainstFound ( *grp, *peaks, &expectedAngles,
1022  &matchedPeaks, &missingPeaks, angTolerance );
1023 
1024  //============================================ If enough consecutive matches, symmetry was found. Save it
1025  if ( consecMatches >= angsToTry->at(fIt) )
1026  {
1027  ProSHADE_internal_symmetry::saveDetectedCSymmetry ( angsToTry->at(fIt), &matchedPeaks, ret, verbose );
1028  }
1029  else
1030  {
1031  if ( ( static_cast<proshade_double> ( matchedPeaks.size() ) / static_cast<proshade_double> ( angsToTry->at(fIt) ) ) >= ( 1.0 - missPeakThres ) )
1032  {
1033  //==================================== Attempt completing the symmetry using missing peaks
1034  if ( ProSHADE_internal_symmetry::completeMissingCSymmetry ( dataObj, angsToTry->at(fIt), grp, peaks, &missingPeaks,
1035  &expectedAngles, &matchedPeaks, axErrTolerance, verbose ) )
1036  {
1037  ProSHADE_internal_symmetry::saveDetectedCSymmetry ( angsToTry->at(fIt), &matchedPeaks, ret, verbose );
1038  }
1039  }
1040  else
1041  {
1042  //=================================== Symmetry not detected
1043  continue;
1044  }
1045  }
1046  }
1047 
1048  //=============================================== Done
1049  return ;
1050 
1051 }

◆ 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_unsign  verbose,
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]minPeakHeightThe minimum average peak height for axis to be considered.

Definition at line 1966 of file ProSHADE_symmetry.cpp.

1967 {
1968  //================================================ Initialise variables
1969  std::vector< proshade_unsign > C3s, prospectiveC2s, C2PossibilitiesHlp;
1970  std::vector< std::vector< proshade_unsign > > C2Possibilities;
1971  proshade_double dotProd;
1972  bool groupMatched;
1973  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &C3s, iter ); }
1974 
1975  //================================================ Report progress
1976  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of three C2 axes." );
1977 
1978  //================================================ For each C3
1979  for ( proshade_unsign rIt = 0; rIt < static_cast<proshade_unsign> ( ret->size() ); rIt++ )
1980  {
1981  //============================================ For each C2, check it has angle ( acos(0.5) ) to the tested C3
1982  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
1983  {
1984  //======================================== Search only using C2s
1985  if ( CSymList->at(cIt)[0] != 2.0 || CSymList->at(cIt)[5] < minPeakHeight ) { continue; }
1986 
1987  //======================================== Check the C2 axis to the C3 ( acos ( 0.5 ) )
1988  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1], &ret->at(rIt)[2], &ret->at(rIt)[3],
1989  &CSymList->at(cIt)[1], &CSymList->at(cIt)[2], &CSymList->at(cIt)[3] );
1990 
1991  if ( ( std::abs ( dotProd ) > ( 0.5 - axErr ) ) && ( std::abs ( dotProd ) < ( 0.5 + axErr ) ) ) { ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC2s, cIt ); }
1992  }
1993  }
1994 
1995  //================================================ Group the prospective C2s
1996  C2Possibilities.clear(); C2PossibilitiesHlp.clear();
1997  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( prospectiveC2s.size() ); cIt++ )
1998  {
1999  //============================================ If second or more C2, check if it can be placed in any group with being perpendicular to all its members
2000  groupMatched = false;
2001  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C2Possibilities.size() ); gIt++ )
2002  {
2003  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; }
2004  }
2005 
2006  //============================================ If no group matched, create a new group
2007  if ( !groupMatched ) { C2PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C2PossibilitiesHlp, prospectiveC2s.at(cIt) ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C2Possibilities, C2PossibilitiesHlp ); continue; }
2008  }
2009 
2010  //================================================ Find the best group or return empty
2011  while ( C2Possibilities.size() != 0 )
2012  {
2013  //============================================ Test for missing symmetry axes, if need be
2014  ProSHADE_internal_symmetry::findMissingAxes ( &C2Possibilities, CSymList, 3, axErr, 0.0, 2, dataObj, minPeakHeight );
2015 
2016  //============================================ Found 3 C2s?
2017  if ( C2Possibilities.at(0).size() == 3 )
2018  {
2019  //======================================== Success! Save and exit
2020  for ( proshade_unsign it = 0; it < 3; it++ ) { ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(C2Possibilities.at(0).at(it)) ); }
2021 
2022  //======================================== Report progress
2023  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of three C2 axes successfull." );
2024 
2025  //======================================== Done
2026  return ;
2027  }
2028  else { C2Possibilities.erase ( C2Possibilities.begin() ); }
2029  }
2030 
2031  //================================================ Done
2032  return ;
2033 
2034 }

◆ 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_unsign  verbose,
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]verobseHow loud the announcments should be?
[in]minPeakHeightThe minimum average peak height for axis to be considered.

Definition at line 1445 of file ProSHADE_symmetry.cpp.

1446 {
1447  //================================================ Initialise variables
1448  std::vector< proshade_unsign > C3PossibilitiesHlp;
1449  std::vector< std::vector< proshade_unsign > > C3Possibilities;
1450  bool groupMatched;
1451 
1452  //================================================ Report progress
1453  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of four C3 axes." );
1454 
1455  //================================================ For all symmetries in the C symmetries list
1456  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
1457  {
1458  //============================================ Search only using C3s
1459  if ( CSymList->at(cIt)[0] != 3.0 || CSymList->at(cIt)[0] < minPeakHeight ) { continue; }
1460 
1461  //============================================ If this is the first C3, then just save it to the first group of the temporary holder
1462  if ( C3Possibilities.size() == 0 ) { ProSHADE_internal_misc::addToUnsignVector ( &C3PossibilitiesHlp, cIt ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C3Possibilities, C3PossibilitiesHlp ); continue; }
1463 
1464  //============================================ If second or more C3, check if it has the correct angle to all other already found C3s for each group
1465  groupMatched = false;
1466  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C3Possibilities.size() ); gIt++ )
1467  {
1468  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; }
1469  }
1470 
1471  //============================================ If no group matched, create a new group
1472  if ( !groupMatched ) { C3PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C3PossibilitiesHlp, cIt ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C3Possibilities, C3PossibilitiesHlp ); continue; }
1473  }
1474 
1475  //================================================ Test for missing symmetry axes, if need be
1476  ProSHADE_internal_symmetry::findMissingAxes ( &C3Possibilities, CSymList, 4, axErr, 1.0/3.0, 3, dataObj, minPeakHeight );
1477 
1478  //================================================ Any group has 4 entries? If more such groups, take the one with highest average height.
1479  proshade_double maxHeight = 0.0; proshade_unsign maxGrp = 0;
1480  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; } } }
1481 
1482  if ( C3Possibilities.at(maxGrp).size() == 4 )
1483  {
1484  //============================================ Success! Save and exit
1485  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)) ); }
1486 
1487  //============================================ Report progress
1488  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of four C3 axes successfull." );
1489 
1490  //============================================ Done
1491  return ;
1492  }
1493 
1494  //================================================ Done
1495  return ;
1496 
1497 }

◆ getPeaksAngleAxisPositions()

std::vector< proshade_double * > ProSHADE_internal_symmetry::getPeaksAngleAxisPositions ( std::vector< proshade_double * >  allPeaks,
proshade_unsign  verbose 
)

This function converts peaks ZXZ Euler anles to angle-axis representation for further processing.

The only functionality here is taking a vector of Euler ZXZ angles and converting these though the rotation matrices to a vector of angle-axis representation of the same angles.

Parameters
[in]allPeaksA vector of pointers where Euler ZXZ representations of the peaks are saved.
[in]verboseHow loud the standard output of this run should be?
[out]XA vector of pointers where angle-axis representations of the peaks will be saved.

Definition at line 256 of file ProSHADE_symmetry.cpp.

257 {
258  //================================================ Initialise variables
259  std::vector< proshade_double* > ret;
260  proshade_double* hlpP = NULL;
261  proshade_double* rotMat = new proshade_double [9];
262  ProSHADE_internal_misc::checkMemoryAllocation ( rotMat, __FILE__, __LINE__, __func__ );
263 
264  //================================================ For each peak
265  for ( proshade_unsign peakIter = 0; peakIter < static_cast<proshade_unsign> ( allPeaks.size() ); peakIter++ )
266  {
267  //============================================ Convert Euler ZXZ angles to rotation matrix
268  ProSHADE_internal_maths::getRotationMatrixFromEulerZXZAngles ( allPeaks.at(peakIter)[0], allPeaks.at(peakIter)[1], allPeaks.at(peakIter)[2], rotMat );
269 
270  //============================================ Allocate pointer to results
271  hlpP = new proshade_double [5];
272  ProSHADE_internal_misc::checkMemoryAllocation ( hlpP, __FILE__, __LINE__, __func__ );
273 
274  //============================================ Convert rotation matrix to Angle-axis reporesentation
275  ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( rotMat, &hlpP[0], &hlpP[1], &hlpP[2], &hlpP[3] );
276  hlpP[4] = allPeaks.at(peakIter)[3];
277 
278  //============================================ Save results
280  }
281 
282  //================================================ Release memory
283  delete[] rotMat;
284 
285  //================================================ Report progress
286  std::stringstream hlpSSP;
287  hlpSSP << "Found " << ret.size() << " possible peaks.";
288  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, hlpSSP.str() );
289 
290  //================================================ Warning if no peaks!
291  if ( ret.size() < 1 )
292  {
293  ProSHADE_internal_messages::printWarningMessage ( verbose, "!!! ProSHADE WARNING !!! Failed to detect any symmetries. There are no reasonable peaks in the self-rotation map. If you believe there should be some symmetry, you can try decreasing the resolution or changing the peak IQR threshold.", "WS00029" );
294  }
295 
296  //================================================ Done
297  return ( ret );
298 
299 }

◆ giveOppositeAxesSameDirection()

void ProSHADE_internal_symmetry::giveOppositeAxesSameDirection ( std::vector< proshade_double * >  peaks)

This function modifiest the axes so that the highest vector element is always positive.

This function modifies the angle-axis representation of the peak positions so that the leargest dimmension of the rotation axis would be positive. This is important in order to make sure that the AA representations [0,0,1;3.14] and [0,0,-1;-3.14] are equal and not considered as completely different.

Parameters
[in]peaksA vector of pointers where angle-axis representations of the peaks is saved.

Definition at line 491 of file ProSHADE_symmetry.cpp.

492 {
493  //================================================ Apply to all peaks
494  for ( proshade_unsign i = 0; i < static_cast<proshade_unsign> ( peaks.size() ); i++ )
495  {
496  if ( ( ( std::max ( std::abs ( peaks.at(i)[0] ), std::max( std::abs ( peaks.at(i)[1] ), std::abs ( peaks.at(i)[2] ) ) ) == std::abs ( peaks.at(i)[0] ) ) && ( peaks.at(i)[0] < 0.0 ) ) ||
497  ( ( std::max ( std::abs ( peaks.at(i)[0] ), std::max( std::abs ( peaks.at(i)[1] ), std::abs ( peaks.at(i)[2] ) ) ) == std::abs ( peaks.at(i)[1] ) ) && ( peaks.at(i)[1] < 0.0 ) ) ||
498  ( ( std::max ( std::abs ( peaks.at(i)[0] ), std::max( std::abs ( peaks.at(i)[1] ), std::abs ( peaks.at(i)[2] ) ) ) == std::abs ( peaks.at(i)[2] ) ) && ( peaks.at(i)[2] < 0.0 ) ) )
499  {
500  peaks.at(i)[0] *= -1.0;
501  peaks.at(i)[1] *= -1.0;
502  peaks.at(i)[2] *= -1.0;
503  peaks.at(i)[3] *= -1.0;
504  }
505  }
506 
507  //================================================ Done
508  return ;
509 
510 }

◆ groupSameAxes()

std::vector< std::vector< proshade_unsign > > ProSHADE_internal_symmetry::groupSameAxes ( std::vector< proshade_double * > &  peaks,
proshade_double  errTolerance 
)

This function groups the peaks by their axes of rotation.

This function takes the list of peaks so far detected and groups these by their axis or rotation, ignoring peaks with zero rotation angle. The return value is a vector of vectors of the groups and their members, but not re-organised list of peaks. This function also adds a zero angle peak to all peak groups (so that the zero angle peak has the same axis as all other group members for all groups).

Parameters
[in]peaksA vector of pointers where angle-axis representations of the peaks is saved.
[in]errToleranceA value within which two axes are considered equal.
[out]XA vector of peak groups with each group entry being a vector of groups member indices in the peaks vector.

Definition at line 419 of file ProSHADE_symmetry.cpp.

420 {
421  //================================================ Initialise variables
422  std::vector< std::vector< proshade_unsign > > ret;
423  bool sameAxisFound = false;
424  proshade_double angTolerance = std::acos ( 1.0 - errTolerance );
425 
426  //================================================ Set all largest axis value to positive (this will make the 0,0,1 and 0,0,-1 axes the same)
428 
429  //================================================ For each axis
430  for ( proshade_unsign peakIter = 0; peakIter < static_cast<proshade_unsign> ( peaks.size() ); peakIter++ )
431  {
432  //============================================ Initialise variables for next peak
433  sameAxisFound = false;
434 
435  //============================================ Ignore zero angle peaks
436  if ( ( peaks.at(peakIter)[3] - angTolerance <= 0.0 ) && ( peaks.at(peakIter)[3] + angTolerance > 0.0 ) ) { continue; }
437 
438  //============================================ Ignore very small axis peaks - the axis may be wrong here.
439  // !! The value of 0.1 is hardcoded, but arbitrary
440  if ( ( ( peaks.at(peakIter)[0] - 0.1 <= 0.0 ) && ( peaks.at(peakIter)[0] + 0.1 > 0.0 ) ) &&
441  ( ( peaks.at(peakIter)[1] - 0.1 <= 0.0 ) && ( peaks.at(peakIter)[1] + 0.1 > 0.0 ) ) &&
442  ( ( peaks.at(peakIter)[2] - 0.1 <= 0.0 ) && ( peaks.at(peakIter)[2] + 0.1 > 0.0 ) ) ) { continue; }
443 
444  //============================================ Compare to all already detected axes groups
445  for ( proshade_unsign sameAxisGrp = 0; sameAxisGrp < static_cast<proshade_unsign> ( ret.size() ); sameAxisGrp++ )
446  {
447  //======================================== and all their members
448  for ( proshade_unsign sameAxis = 0; sameAxis < static_cast<proshade_unsign> ( ret.at(sameAxisGrp).size() ); sameAxis++ )
449  {
450  //==================================== Is this identical axis to the tested one?
451  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( peaks.at(ret.at(sameAxisGrp).at(sameAxis))[0],
452  peaks.at(ret.at(sameAxisGrp).at(sameAxis))[1],
453  peaks.at(ret.at(sameAxisGrp).at(sameAxis))[2],
454  peaks.at(peakIter)[0],
455  peaks.at(peakIter)[1],
456  peaks.at(peakIter)[2],
457  errTolerance ) )
458  {
459  sameAxisFound = true;
460  ProSHADE_internal_misc::addToUnsignVector ( &ret.at(sameAxisGrp), peakIter );
461  break;
462  }
463  }
464  }
465 
466  //============================================ If same axis was found, do nothing
467  if ( sameAxisFound ) { continue; }
468 
469  //============================================ No similar axis was found
470  std::vector<proshade_unsign> hlpVec;
471  ProSHADE_internal_misc::addToUnsignVector ( &hlpVec, peakIter );
473  }
474 
475  //================================================ Add zero peak to all axes
477 
478  //================================================ Done
479  return ( ret );
480 
481 }

◆ isSymmetrySame()

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

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.
[out]XBoolean value stating whether a similar entry has been found (true = it was, false = it was not).

Definition at line 1177 of file ProSHADE_symmetry.cpp.

1178 {
1179  //================================================ Initialise variables
1180  proshade_double dotProduct = 0.0;
1181 
1182  //================================================ Check
1183  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( ret->size() ); symIt++ )
1184  {
1185  //============================================ Minor speed-up => only test for same folds
1186  if ( ret->at(symIt)[0] == sym[0] )
1187  {
1188  //======================================== Is axis the same?
1189  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &ret->at(symIt)[1], &ret->at(symIt)[2],
1190  &ret->at(symIt)[3], &sym[1], &sym[2], &sym[3] );
1191  if ( ( ( 1.0 > ( dotProduct - simThres ) ) && ( 1.0 < ( dotProduct + simThres ) ) ) || ( ( -1.0 > ( dotProduct - simThres ) ) && ( -1.0 < ( dotProduct + simThres ) ) ) )
1192  {
1193  //==================================== Does the already saved have higher height?
1194  if ( ret->at(symIt)[5] >= sym[5] ) { return ( true ); }
1195 
1196  //==================================== In this case, new is better than old - sort it out
1197  ret->at(symIt)[1] = sym[1];
1198  ret->at(symIt)[2] = sym[2];
1199  ret->at(symIt)[3] = sym[3];
1200  ret->at(symIt)[5] = sym[5];
1201  return ( true );
1202  }
1203  }
1204  }
1205 
1206  //================================================ Done - no matches found
1207  return ( false );
1208 
1209 }

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

1664 {
1665  //================================================ Initialise variables
1666  proshade_double ret = 0.0;
1667  proshade_double curSum = 0.0;
1668  proshade_double maxVal = 0.0;
1669  proshade_double angStep = std::acos ( 1.0 - axErr ) / 2;
1670  std::vector< proshade_double* > angVec;
1671 
1672  //================================================ Find map points conforming to the axis
1673  angVec = ProSHADE_internal_symmetry::findMissingAxisPoints ( xVal, yVal, zVal, dataObj, axErr );
1674 
1675  //================================================ Sort points by angle
1676  std::sort ( angVec.begin(), angVec.end(), ProSHADE_internal_symmetry::sortArrVecHlp );
1677 
1678  //================================================ Find the best X peaks with correct distances
1679  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( std::floor ( ( 2.0 * M_PI / angStep ) / fold ) ); iter++ )
1680  {
1681  //============================================ Initialise new ang group iteration
1682  curSum = 0.0;
1683 
1684  //============================================ For each of the fold times
1685  for ( proshade_unsign angCmb = 0; angCmb < static_cast<proshade_unsign> ( fold ); angCmb++ )
1686  {
1687  //======================================== Initialise
1688  maxVal = 0.0;
1689 
1690  //======================================== Search
1691  for ( proshade_unsign angIt = 0; angIt < static_cast<proshade_unsign> ( angVec.size() ); angIt++ )
1692  {
1693  if ( angVec.at(angIt)[0] < ( ( iter*angStep ) + ( ( 2.0 * M_PI / fold ) * angCmb ) ) ) { continue; }
1694  if ( angVec.at(angIt)[0] > ( ( (iter+1)*angStep ) + ( ( 2.0 * M_PI / fold ) * angCmb ) ) ) { break; }
1695 
1696  if ( angVec.at(angIt)[1] > maxVal ) { maxVal = angVec.at(angIt)[1]; }
1697  }
1698  curSum += maxVal;
1699  }
1700  curSum /= static_cast<proshade_double> ( fold );
1701  if ( ret < curSum ) { ret = curSum; }
1702  }
1703 
1704  //================================================ Release memory
1705  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( angVec.size() ); iter++ ) { delete[] angVec.at(iter); }
1706 
1707  //================================================ Done
1708  return ( ret );
1709 
1710 }

◆ predictIcosAxes()

void ProSHADE_internal_symmetry::predictIcosAxes ( ProSHADE_settings settings,
std::vector< proshade_double * > *  CSymList,
std::vector< proshade_double * > *  ret,
proshade_double  axErr,
ProSHADE_internal_data::ProSHADE_data dataObj,
proshade_unsign  verbose,
proshade_double  minPeakHeight,
proshade_double  matrixTolerance 
)

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

This function starts with finding the best detected cyclic symmetries of the right folds and having the closest angle to the icosahedron dihedral angle. It then proceeds to generate all the point group elements and their combinations. From these it then computes some of the missing axes and their associated angles. These steps can then be repeated until no more new elements are found (a group exists) or the process fails. The the detected axes (as obtained back from the point group elements) are then returned without checking for having the correct number of them.

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 .
[in]axErrThe error tolerance on angle matching.
[in]minPeakHeightThe minimum average peak height for axis to be considered.
[in]verobseHow loud the announcments should be?
[in]axisToleranceThe tolerance for two axes to be considered similar in terms of cosine distance.
[in]matrixToleranceThe maximum allowed rotation matrix trace difference allowed for the matrices to be considered the same.

Definition at line 2944 of file ProSHADE_symmetry.cpp.

2945 {
2946  //================================================ Initialise variables
2947  std::vector< proshade_double* > newAxes;
2948  proshade_double axX, axY, axZ, axAng, foldTolerance = 0.1; // dotProd
2949  proshade_unsign determinedFold, prevComboSize = 0; // bestC5, bestC3
2950  std::vector< proshade_unsign > c5s, c3s, c2s;
2951 // bool anglesPassed;
2952 
2953  //================================================ Find the best axis combination with dihedral angle and correct folds
2954  std::pair< proshade_unsign, proshade_unsign > initAxes = findBestIcosDihedralPair ( CSymList, minPeakHeight, axErr );
2955  dataObj->optimiseDihedralAngleFromAngleAxis ( settings, - sqrt ( 5.0 ) / 3.0, CSymList->at(initAxes.first), CSymList->at(initAxes.second) );
2956 
2957  //================================================ Save detected axes to ret
2958  ProSHADE_internal_misc::deepCopyAxisToDblPtrVector ( ret, CSymList->at(initAxes.first) );
2959  ProSHADE_internal_misc::deepCopyAxisToDblPtrVector ( ret, CSymList->at(initAxes.second) );
2960 
2961  //================================================ Generate initial group elements
2962  std::vector<std::vector< proshade_double > > elsC5 = dataObj->computeGroupElementsForGroup ( CSymList, initAxes.first );
2963  std::vector<std::vector< proshade_double > > elsC3 = dataObj->computeGroupElementsForGroup ( CSymList, initAxes.second );
2964  std::vector<std::vector< proshade_double > > combo = ProSHADE_internal_data::joinElementsFromDifferentGroups ( &elsC5, &elsC3, matrixTolerance, true );
2965  std::cout << " !@!@ Allowed axis error: " << axErr << std::endl;
2966  //================================================ Iteratively find all remanining axes by multiplying the group elements
2967  while ( prevComboSize < combo.size() )
2968  {
2969  //============================================ Sanity check
2970  if ( prevComboSize > 60 ) { break; }
2971 
2972  //============================================ Initialise iteration
2973  prevComboSize = combo.size ( );
2974  newAxes.clear ( );
2975 
2976  //============================================ For each group element (this is a bit repetitive, but not slow enough to deal with right now)
2977  for ( proshade_unsign cIt = 0; cIt < static_cast< proshade_unsign > ( combo.size() ); cIt++ )
2978  {
2979  //======================================== Find the axis of the element
2980  ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( &combo.at(cIt), &axX, &axY, &axZ, &axAng );
2981  std::cout << "Combo " << cIt << " has axis " << axX << " ; " << axY << " ; " << axZ << " WITH ANGLE: " << axAng << std::endl;
2982 
2983  //======================================== Determine the fold (in terms of icosahedral symmetry fold options)
2984  if ( ( ( axAng - foldTolerance ) < 0.0 ) && ( ( axAng + foldTolerance ) > 0.0 ) ) { continue; } // Zero angle - identity element
2985  else if ( ( ( axAng - foldTolerance ) < M_PI ) && ( ( axAng + foldTolerance ) > M_PI ) ) { determinedFold = 2; } // Fold 2 ( angle = pi )
2986  else if ( ( ( -axAng - foldTolerance ) < -M_PI ) && ( ( -axAng + foldTolerance ) > -M_PI ) ) { determinedFold = 2; } // Fold 2 ( angle = -pi )
2987  else if ( ( ( axAng - foldTolerance ) < ( 2.0 * M_PI / 3.0 ) ) && ( ( axAng + foldTolerance ) > ( 2.0 * M_PI / 3.0 ) ) ) { determinedFold = 3; } // Fold 3 ( angle = 2pi/3 )
2988  else if ( ( ( -axAng - foldTolerance ) < ( -2.0 * M_PI / 3.0 ) ) && ( ( -axAng + foldTolerance ) > ( -2.0 * M_PI / 3.0 ) ) ) { determinedFold = 3; } // Fold 3 ( angle = -2pi/3 )
2989  else if ( ( ( axAng - foldTolerance ) < ( 2.0 * M_PI / 5.0 ) ) && ( ( axAng + foldTolerance ) > ( 2.0 * M_PI / 5.0 ) ) ) { determinedFold = 5; } // Fold 5 ( angle = 2pi/5 )
2990  else if ( ( ( axAng - foldTolerance ) < ( 4.0 * M_PI / 5.0 ) ) && ( ( axAng + foldTolerance ) > ( 4.0 * M_PI / 5.0 ) ) ) { determinedFold = 5; } // Fold 5 ( angle = 4pi/5 )
2991  else if ( ( ( -axAng - foldTolerance ) < ( -2.0 * M_PI / 5.0 ) ) && ( ( -axAng + foldTolerance ) > ( -2.0 * M_PI / 5.0 ) ) ) { determinedFold = 5; } // Fold 5 ( angle = -2pi/5 )
2992  else if ( ( ( -axAng - foldTolerance ) < ( -4.0 * M_PI / 5.0 ) ) && ( ( -axAng + foldTolerance ) > ( -4.0 * M_PI / 5.0 ) ) ) { determinedFold = 5; } // Fold 5 ( angle = -4pi/5 )
2993  else { continue; } // Failed to find matching fold.
2994 
2995 
2996 
2997  //======================================== Is this a new axis?
2998  if ( ProSHADE_internal_maths::isAxisUnique ( ret, axX, axY, axZ, determinedFold, axErr ) )
2999  {
3000  //==================================== Create the new axis array
3001 // anglesPassed = true;
3002  proshade_double* newAx = new proshade_double[6];
3003  ProSHADE_internal_misc::checkMemoryAllocation ( newAx, __FILE__, __LINE__, __func__ );
3004 
3005  newAx[0] = determinedFold;
3006  newAx[1] = axX;
3007  newAx[2] = axY;
3008  newAx[3] = axZ;
3009  newAx[4] = ( 2.0 * M_PI ) / determinedFold;
3010  newAx[5] = 0.0;
3011 
3012  //==================================== Check for it having the correct angles to other detected axes
3013 // if ( determinedFold == 5 )
3014 // {
3015 // for ( proshade_unsign c5It = 0; c5It < static_cast< proshade_unsign > ( c5s.size() ); c5It++ )
3016 // {
3017 // dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(c5s.at(c5It))[1], &ret->at(c5s.at(c5It))[2], &ret->at(c5s.at(c5It))[3], &newAx[1], &newAx[2], &newAx[3] );
3018 // std::cout << "C5 to C5 dot prod: " << dotProd << std::endl;
3019 // if ( ( ( std::abs ( dotProd ) - axErr ) < 0.5 ) && ( ( std::abs ( dotProd ) + axErr ) > 0.5 ) ) { continue; }
3020 // else { anglesPassed = false; break; }
3021 // }
3022 //
3023 // if ( anglesPassed ) { ProSHADE_internal_misc::addToUnsignVector ( &c5s, static_cast<proshade_unsign> ( ret->size() ) ); }
3024 // }
3025 //
3026 // if ( determinedFold == 3 )
3027 // {
3028 // for ( proshade_unsign c3It = 0; c3It < static_cast< proshade_unsign > ( c3s.size() ); c3It++ )
3029 // {
3030 // dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(c3s.at(c3It))[1], &ret->at(c3s.at(c3It))[2], &ret->at(c3s.at(c3It))[3], &newAx[1], &newAx[2], &newAx[3] );
3031 //
3035 // }
3036 //
3037 // if ( anglesPassed ) { ProSHADE_internal_misc::addToUnsignVector ( &c3s, static_cast<proshade_unsign> ( ret->size() ) ); }
3038 // }
3039 // if ( determinedFold == 2 )
3040 // {
3041 // if ( anglesPassed ) { ProSHADE_internal_misc::addToUnsignVector ( &c2s, static_cast<proshade_unsign> ( ret->size() ) ); }
3042 // }
3043 
3044  //==================================== If all good, save
3045 // if ( anglesPassed )
3046  {
3047  ProSHADE_internal_misc::addToDblPtrVector ( &newAxes, newAx );
3049  }
3050  }
3051  }
3052 
3053 // for ( int i = 0; i < combo.size(); i++ )
3054 // {
3055 // for ( int j = 0; j < combo.at(i).size(); j++ )
3056 // {
3057 // if ( j % 3 == 0 ) { std::cout << std::endl; }
3058 // std::cout << combo.at(i).at(j) << "\t";
3059 // }
3060 // std::cout << std::endl;
3061 // }
3062 
3063  //============================================ Generate new group elements from the new axes and folds
3064  for ( proshade_unsign aIt = 0; aIt < static_cast< proshade_unsign > ( newAxes.size() ); aIt++ )
3065  {
3066  std::vector< std::vector< proshade_double > > newEls = dataObj->computeGroupElementsForGroup ( &newAxes, aIt );
3067  combo = ProSHADE_internal_data::joinElementsFromDifferentGroups ( &newEls, &combo, matrixTolerance, true );
3068  delete[] newAxes.at(aIt);
3069  }
3070 //
3071 // for ( int i = 0; i < ret->size(); i++ )
3072 // {
3073 // std::cout << i << " || " << ret->at(i)[1] << " ; " << ret->at(i)[2] << " ; " << ret->at(i)[3] << std::endl;
3074 // }
3075 //
3076 // exit(0);
3077  }
3078 
3079  //================================================ Sort the axes by fold
3080  std::sort ( ret->begin(), ret->end(), ProSHADE_internal_misc::sortSymInvFoldHlp );
3081 
3082 // bool thr = true, two = true;
3083 // for ( int i = 0; i < ret->size(); i++ ) { if ( ret->at(i)[0] == 3 && thr ) { std::cout << std::endl; thr = false; } if ( ret->at(i)[0] == 2 && two ) { std::cout << std::endl; two = false; } std::cout << i << ": " << ret->at(i)[0] << " | " << ret->at(i)[1] << " ; " << ret->at(i)[2] << " ; " << ret->at(i)[3] << std::endl; }
3084 //
3085 // std::cout << "Found " << ret->size() << " icos syms and " << combo.size ( ) << " group elements." << std::endl; exit(0);
3086  //================================================ Done
3087  return ;
3088 
3089 }

◆ predictOctaAxes()

void ProSHADE_internal_symmetry::predictOctaAxes ( std::vector< proshade_double * > *  CSymList,
std::vector< proshade_double * > *  ret,
proshade_double  axErr,
ProSHADE_internal_data::ProSHADE_data dataObj,
proshade_unsign  verbose,
proshade_double  minPeakHeight,
proshade_double  matrixTolerance 
)

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

This function starts with finding the best detected cyclic symmetries of the right folds and having the closest angle to the octahedron dihedral angle. It then proceeds to generate all the point group elements and their combinations. From these it then computes some of the missing axes and their associated angles. These steps can then be repeated until no more new elements are found (a group exists) or the process fails. The the detected axes (as obtained back from the point group elements) are then returned without checking for having the correct number of them.

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 .
[in]axErrThe error tolerance on angle matching.
[in]minPeakHeightThe minimum average peak height for axis to be considered.
[in]verobseHow loud the announcments should be?
[in]axisToleranceThe tolerance for two axes to be considered similar in terms of cosine distance.
[in]matrixToleranceThe maximum allowed rotation matrix trace difference allowed for the matrices to be considered the same.

Definition at line 3161 of file ProSHADE_symmetry.cpp.

3162 {
3163 // //================================================ Initialise variables
3164 // std::vector< proshade_double* > newAxes;
3165 // proshade_double axX, axY, axZ, axAng, foldTolerance = 0.1;
3166 // proshade_unsign bestC5, bestC3, determinedFold, prevComboSize = 0;
3167 //
3168 // //================================================ Find the best axis combination with dihedral angle and correct folds
3169 // std::pair< proshade_unsign, proshade_unsign > initAxes = findBestOctaDihedralPair ( CSymList, minPeakHeight, axErr );
3170 //
3171 // //================================================ Save detected axes to ret
3172 // ProSHADE_internal_misc::deepCopyAxisToDblPtrVector ( ret, CSymList->at(initAxes.first) );
3173 // ProSHADE_internal_misc::deepCopyAxisToDblPtrVector ( ret, CSymList->at(initAxes.second) );
3174 //
3175 // //================================================ Generate initial group elements
3176 // std::vector<std::vector< proshade_double > > elsC4 = dataObj->computeGroupElementsForGroup ( CSymList, initAxes.first );
3177 // std::vector<std::vector< proshade_double > > elsC3 = dataObj->computeGroupElementsForGroup ( CSymList, initAxes.second );
3178 // std::vector<std::vector< proshade_double > > combo = ProSHADE_internal_data::joinElementsFromDifferentGroups ( &elsC4, &elsC3, matrixTolerance, true );
3179 //
3180 // //================================================ Iteratively find all remanining axes by multiplying the group elements
3181 // while ( prevComboSize < combo.size() )
3182 // {
3183 // //============================================ Sanity check
3184 // if ( prevComboSize > 24 ) { break; }
3185 //
3186 // //============================================ Initialise iteration
3187 // prevComboSize = combo.size ( );
3188 // newAxes.clear ( );
3189 //
3190 // //============================================ For each group element (this is a bit repetitive, but not slow enough to deal with right now)
3191 // for ( proshade_unsign cIt = 0; cIt < static_cast< proshade_unsign > ( combo.size() ); cIt++ )
3192 // {
3193 // //======================================== Find the axis of the element
3194 // ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( &combo.at(cIt), &axX, &axY, &axZ, &axAng );
3195 //
3196 // //======================================== Determine the fold (in terms of icosahedral symmetry fold options)
3197 // if ( ( ( axAng - foldTolerance ) < 0.0 ) && ( ( axAng + foldTolerance ) > 0.0 ) ) { continue; } // Zero angle - identity element
3198 // else if ( ( ( axAng - foldTolerance ) < M_PI ) && ( ( axAng + foldTolerance ) > M_PI ) ) { determinedFold = 2; } // Fold 2 ( angle = pi )
3199 // else if ( ( ( axAng - foldTolerance ) < ( 2.0 * M_PI / 3.0 ) ) && ( ( axAng + foldTolerance ) > ( 2.0 * M_PI / 3.0 ) ) ) { determinedFold = 3; } // Fold 3 ( angle = 2pi/3 )
3200 // else if ( ( ( axAng - foldTolerance ) < ( 2.0 * M_PI / 1.5 ) ) && ( ( axAng + foldTolerance ) > ( 2.0 * M_PI / 1.5 ) ) ) { determinedFold = 3; } // Fold 3 ( angle = 4pi/3 )
3201 // else if ( ( ( axAng - foldTolerance ) < ( 2.0 * M_PI / 5.0 ) ) && ( ( axAng + foldTolerance ) > ( 2.0 * M_PI / 5.0 ) ) ) { determinedFold = 5; } // Fold 5 ( angle = 2pi/5 )
3202 // else if ( ( ( axAng - foldTolerance ) < ( 4.0 * M_PI / 5.0 ) ) && ( ( axAng + foldTolerance ) > ( 4.0 * M_PI / 5.0 ) ) ) { determinedFold = 5; } // Fold 5 ( angle = 4pi/5 )
3203 // else if ( ( ( axAng - foldTolerance ) < ( 6.0 * M_PI / 5.0 ) ) && ( ( axAng + foldTolerance ) > ( 6.0 * M_PI / 5.0 ) ) ) { determinedFold = 5; } // Fold 5 ( angle = 6pi/5 )
3204 // else if ( ( ( axAng - foldTolerance ) < ( 8.0 * M_PI / 5.0 ) ) && ( ( axAng + foldTolerance ) > ( 8.0 * M_PI / 5.0 ) ) ) { determinedFold = 5; } // Fold 5 ( angle = 8pi/5 )
3205 // else { continue; } // Failed to find matching fold.
3206 //
3207 // //======================================== Is this a new axis?
3208 // if ( ProSHADE_internal_maths::isAxisUnique ( ret, axX, axY, axZ, determinedFold, axErr ) )
3209 // {
3210 // proshade_double* newAx = new proshade_double[6];
3211 // ProSHADE_internal_misc::checkMemoryAllocation ( newAx, __FILE__, __LINE__, __func__ );
3212 //
3213 // newAx[0] = determinedFold;
3214 // newAx[1] = axX;
3215 // newAx[2] = axY;
3216 // newAx[3] = axZ;
3217 // newAx[4] = ( 2.0 * M_PI ) / determinedFold;
3218 // newAx[5] = 0.0;
3219 //
3220 // ProSHADE_internal_misc::addToDblPtrVector ( &newAxes, newAx );
3221 // ProSHADE_internal_misc::deepCopyAxisToDblPtrVector ( ret, newAx );
3222 // }
3223 // }
3224 //
3225 // //============================================ Generate new group elements from the new axes and folds
3226 // for ( proshade_unsign aIt = 0; aIt < static_cast< proshade_unsign > ( newAxes.size() ); aIt++ )
3227 // {
3228 // std::vector< std::vector< proshade_double > > newEls = dataObj->computeGroupElementsForGroup ( &newAxes, aIt );
3229 // combo = ProSHADE_internal_data::joinElementsFromDifferentGroups ( &newEls, &combo, matrixTolerance, true );
3230 // delete[] newAxes.at(aIt);
3231 // }
3232 // }
3233 //
3234 // //================================================ Sort the axes by fold
3235 // std::sort ( ret->begin(), ret->end(), ProSHADE_internal_misc::sortSymInvFoldHlp );
3236 //
3237 // std::cout << "Found " << ret->size() << " octa syms and " << combo.size ( ) << " group elements." << std::endl; exit(0);
3238 
3239  //================================================ Done
3240  return ;
3241 
3242 }

◆ printSymmetryCompletion()

void ProSHADE_internal_symmetry::printSymmetryCompletion ( proshade_unsign  noSyms,
proshade_unsign  verbose 
)

This function simply prints the summary and warnings for cyclic symmetries detection completion.

Parameters
[in]noSymsThe number of symmetries that were detected.
[in]verboseHow loud the run should be and therefore if anything should be printed at all.

Definition at line 1085 of file ProSHADE_symmetry.cpp.

1086 {
1087  //================================================ Report completion of symmetry detection
1088  std::stringstream ss;
1089  ss << "Detected " << noSyms << " Cyclic symmetries.";
1090  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, ss.str() );
1091 
1092  //================================================ If no symmetries were found, print warning
1093  if ( noSyms < 1 )
1094  {
1095  ProSHADE_internal_messages::printWarningMessage ( verbose, "!!! ProSHADE WARNING !!! Failed to detect any symmetries. If you believe there should be one, you can try decreasing the resolution or checking that the map is centred on the centry of symmetry (or use map centering option in ProSHADE).", "WS00030" );
1096  }
1097 
1098  //================================================ Done
1099  return ;
1100 
1101 }

◆ printSymmetryGroup()

void ProSHADE_internal_symmetry::printSymmetryGroup ( std::vector< proshade_unsign >  grp,
std::vector< proshade_double * >  peaks,
proshade_signed  verbose 
)

This function simply prints the detected symmetry and all its supporting peaks.

Parameters
[in]grpA single symmetry axis group indices to be printed.
[in]peaksThe vector of all peaks from which the indices are drawn.
[in]verboseHow loud the run should be and therefore if anything should be printed at all.

Definition at line 1059 of file ProSHADE_symmetry.cpp.

1060 {
1061  //================================================ Detected symmetry table header
1062  std::stringstream ss;
1063  ss << "Detected C" << grp.at(0) << " symmetry with following peaks:";
1064  ProSHADE_internal_messages::printProgressMessage ( verbose, 5, ss.str() );
1065  ProSHADE_internal_messages::printProgressMessage ( verbose, 5, "\tx\t y\t z\tAngle\tPeak height" );
1066 
1067  //================================================ Now print all supporting peaks
1068  for ( proshade_unsign pkIt = 1; pkIt < static_cast<proshade_unsign> ( grp.size() ); pkIt++ )
1069  {
1070  std::stringstream SS;
1071  SS << " " << static_cast<int>( peaks.at(grp.at(pkIt))[0] * 100.0 ) / 100.0 << "\t" << static_cast<int>( peaks.at(grp.at(pkIt))[1] * 100.0 ) / 100.0 << "\t" << static_cast<int>( peaks.at(grp.at(pkIt))[2] * 100.0 ) / 100.0 << "\t" << static_cast<int>( peaks.at(grp.at(pkIt))[3] * 100.0 ) / 100.0 << "\t" << static_cast<int>( peaks.at(grp.at(pkIt))[4] * 100.0 ) / 100.0;
1072  ProSHADE_internal_messages::printProgressMessage ( verbose, 5, SS.str() );
1073  }
1074 
1075  //================================================ Done
1076  return ;
1077 
1078 }

◆ printSymmetryPeaks()

void ProSHADE_internal_symmetry::printSymmetryPeaks ( std::vector< proshade_unsign >  grp,
std::vector< proshade_double * >  peaks,
proshade_signed  verbose,
proshade_unsign  groupNo 
)

This function simply prints the symmetry axis group supplied in the first parameter from the second parameter values.

Parameters
[in]grpA single symmetry axis group indices to be printed.
[in]peaksThe vector of all peaks from which the indices are drawn.
[in]verboseHow loud the run should be and therefore if anything should be printed at all.

Definition at line 518 of file ProSHADE_symmetry.cpp.

519 {
520  //================================================ Symmetry group output header
521  std::stringstream hlpSS;
522  hlpSS << "Symmetry axis group " << groupNo;
523  ProSHADE_internal_messages::printProgressMessage ( verbose, 6, hlpSS.str() );
524  ProSHADE_internal_messages::printProgressMessage ( verbose, 6, "Peak index\t\tx\t y\t z\tAngle\tPeak heiht" );
525 
526  //================================================ Print the symmetry group
527  for ( proshade_unsign axIt = 0; axIt < static_cast<proshade_unsign> ( grp.size() ); axIt++ )
528  {
529  std::stringstream SS;
530  SS << " " << axIt << "\t " << static_cast<int>( peaks.at(grp.at(axIt))[0] * 100.0 ) / 100.0 << "\t" << static_cast<int>( peaks.at(grp.at(axIt))[1] * 100.0 ) / 100.0 << "\t" << static_cast<int>( peaks.at(grp.at(axIt))[2] * 100.0 ) / 100.0 << "\t" << static_cast<int>( peaks.at(grp.at(axIt))[3] * 100.0 ) / 100.0 << "\t" << static_cast<int>( peaks.at(grp.at(axIt))[4] * 100.0 ) / 100.0;
531  ProSHADE_internal_messages::printProgressMessage ( verbose, 6, SS.str() );
532  }
533 
534  //================================================ Done
535  return ;
536 
537 }

◆ saveAllCSymmetries()

void ProSHADE_internal_symmetry::saveAllCSymmetries ( std::vector< std::vector< proshade_unsign > >  detected,
std::vector< proshade_double * >  peaks,
std::vector< proshade_double * > *  ret,
proshade_double  axErr 
)

This function takes the detected symmetries indices and peaks and saves these in the main cyclic symmetries detection output format.

This function uses the indices of peaks forming a detected symmetry along with the peak values corresponding to these indices in order to compute the symmetry description - that is the fold, average x, y and z-axis elements, angle (2pi/fold) and the average peak height. With all this computed for each detected symmetry, it saves these as double arrays to the output vector of double arrays for further processing. The function also does not save redundant symmetries.

Parameters
[in]detectedThis is a vector of vectors with the indices of detected symmetry peaks.
[in]peaksThese are the peaks and their values which come together to form the detected symmetry.
[in]retThis is the variable where the results will be saved. 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]axErrThe tolerance on axis matching.

Definition at line 1115 of file ProSHADE_symmetry.cpp.

1116 {
1117  //================================================ Initialise variables
1118  proshade_double sumX, sumY, sumZ, sumH;
1119 
1120  //================================================ Start saving
1121  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( detected.size() ); symIt++ )
1122  {
1123  //============================================ Allocate the memory
1124  proshade_double* hlpP = new proshade_double [6];
1125  ProSHADE_internal_misc::checkMemoryAllocation ( hlpP, __FILE__, __LINE__, __func__ );
1126 
1127  //============================================ Set obvious values
1128  hlpP[0] = static_cast<proshade_double> ( detected.at(symIt).at(0) );
1129  hlpP[4] = static_cast<proshade_double> ( ( 2.0 * M_PI ) / hlpP[0] );
1130 
1131  //============================================ Compute peak averages for rest
1132  sumX = 0.0; sumY = 0.0; sumZ = 0.0; sumH = 0.0;
1133  for ( proshade_unsign pkIt = 1; pkIt < static_cast<proshade_unsign> ( detected.at(symIt).size() ); pkIt++ )
1134  {
1135  sumX += peaks.at(detected.at(symIt).at(pkIt))[0];
1136  sumY += peaks.at(detected.at(symIt).at(pkIt))[1];
1137  sumZ += peaks.at(detected.at(symIt).at(pkIt))[2];
1138  sumH += peaks.at(detected.at(symIt).at(pkIt))[4];
1139  }
1140  sumX /= static_cast<proshade_double> ( detected.at(symIt).size() - 1 );
1141  sumY /= static_cast<proshade_double> ( detected.at(symIt).size() - 1 );
1142  sumZ /= static_cast<proshade_double> ( detected.at(symIt).size() - 1 );
1143  sumH /= static_cast<proshade_double> ( detected.at(symIt).size() - 1 );
1144 
1145  //============================================ And add these as well
1146  hlpP[1] = sumX;
1147  hlpP[2] = sumY;
1148  hlpP[3] = sumZ;
1149  hlpP[5] = sumH;
1150 
1151  //============================================ Save the complete symmetry description to the vector, unless already there
1152  if ( !ProSHADE_internal_symmetry::isSymmetrySame ( ret, hlpP, axErr ) )
1153  {
1155  }
1156  else
1157  {
1158  delete[] hlpP;
1159  }
1160  }
1161 
1162  //================================================ Done
1163  return ;
1164 
1165 }

◆ saveDetectedCSymmetry()

void ProSHADE_internal_symmetry::saveDetectedCSymmetry ( proshade_unsign  fold,
std::vector< proshade_unsign > *  matchedPeaks,
std::vector< std::vector< proshade_unsign > > *  ret,
proshade_signed  verbose 
)

This function saves a detected symmetry for reporting to the user.

This function simply saves the supplied group members and fold value to the main output vector of vectors (also supplied). It makes sure the saving format (fold first, then all symmetry peak indices) is upheld.

Parameters
[in]foldThis is the fold value of the detected C symmetry.
[in]matchedPeaksA vector containing the indices of all peaks forming this symmetry.
[in]retThe vector of vectors to be returned by findPeaksCSymmetry() and containing all detected symmetries (to which we are saving here).
[in]verboseHow loud the standard output of this run should be?

Definition at line 884 of file ProSHADE_symmetry.cpp.

885 {
886  //================================================ Save fold as first vector value
887  std::vector< proshade_unsign > hlpVec;
889 
890  //================================================ and follow it with indices of all symmetry forming peaks
891  for ( proshade_unsign pIt = 0; pIt < static_cast<proshade_unsign> ( matchedPeaks->size() ); pIt++ )
892  {
893  ProSHADE_internal_misc::addToUnsignVector ( &hlpVec, matchedPeaks->at(pIt) );
894  }
896 
897  //================================================ Report finding symmetry
898  std::stringstream hlpS;
899  hlpS << "Found symmetry C" << fold;
900  ProSHADE_internal_messages::printProgressMessage ( verbose, 5, hlpS.str() );
901 
902  //================================================ Done
903  return ;
904 
905 }

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

1302 {
1303  //================================================ Allocate the memory
1304  proshade_double* hlpP = new proshade_double [12];
1305  ProSHADE_internal_misc::checkMemoryAllocation ( hlpP, __FILE__, __LINE__, __func__ );
1306 
1307  //================================================ Set obvious values
1308  hlpP[0] = static_cast<proshade_double> ( CSymList->at(axisOne)[0] );
1309  hlpP[4] = static_cast<proshade_double> ( ( 2.0 * M_PI ) / hlpP[0] );
1310  hlpP[6] = static_cast<proshade_double> ( CSymList->at(axisTwo)[0] );
1311  hlpP[10] = static_cast<proshade_double> ( ( 2.0 * M_PI ) / hlpP[6] );
1312 
1313  //================================================ Set the axis and heights
1314  hlpP[1] = CSymList->at(axisOne)[1];
1315  hlpP[2] = CSymList->at(axisOne)[2];
1316  hlpP[3] = CSymList->at(axisOne)[3];
1317  hlpP[5] = CSymList->at(axisOne)[5];
1318  hlpP[7] = CSymList->at(axisTwo)[1];
1319  hlpP[8] = CSymList->at(axisTwo)[2];
1320  hlpP[9] = CSymList->at(axisTwo)[3];
1321  hlpP[11] = CSymList->at(axisTwo)[5];
1322 
1323  //================================================ Save to ret
1325 
1326  //================================================ Done
1327  return ;
1328 
1329 }

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

1800 {
1801  //================================================ Create symmetry array from the inputs
1802  proshade_double* hlpSym = new proshade_double [6];
1803  ProSHADE_internal_misc::checkMemoryAllocation ( hlpSym, __FILE__, __LINE__, __func__ );
1804 
1805  //================================================ Fill it in
1806  hlpSym[0] = static_cast<proshade_double> ( fold );
1807  hlpSym[1] = axX;
1808  hlpSym[2] = axY;
1809  hlpSym[3] = axZ;
1810  hlpSym[4] = ( 2.0 * M_PI ) / static_cast<proshade_double> ( fold );
1811  hlpSym[5] = height;
1812 
1813  //================================================ Check if similar symmetry does not exist already
1814  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( axVec->size() ); symIt++ )
1815  {
1816  //============================================ Minor speed-up => only test for same folds
1817  if ( axVec->at(symIt)[0] == hlpSym[0] )
1818  {
1819  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( axVec->at(symIt)[1],
1820  axVec->at(symIt)[2],
1821  axVec->at(symIt)[3],
1822  hlpSym[1],
1823  hlpSym[2],
1824  hlpSym[3],
1825  axErr ) )
1826  {
1827  //==================================== Almost identical entry
1828  if ( axVec->at(symIt)[5] < hlpSym[5] )
1829  {
1830  //================================ If higher, save
1831  delete[] axVec->at(symIt);
1832  axVec->at(symIt) = hlpSym;
1833  return ;
1834  }
1835  else
1836  {
1837  //================================ or just terminate if better is already saved
1838  delete[] hlpSym;
1839  return ;
1840  }
1841  }
1842  }
1843  }
1844 
1845  //================================================ Not matched to anything
1847 
1848  //================================================ Done
1849  return ;
1850 
1851 }

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

1868 {
1869  //================================================ Sanity check
1870  if ( grp->size() < 2 ) { return; }
1871 
1872  //================================================ Initialise variables
1873  proshade_double axHeight = 0.0;
1874  proshade_double* symHlp = new proshade_double[6];
1875  ProSHADE_internal_misc::checkMemoryAllocation ( symHlp, __FILE__, __LINE__, __func__ );
1876 
1877  //================================================ For each axis pair in the group, find the possible solutions
1878  for ( proshade_unsign fAx = 0; fAx < static_cast<proshade_unsign> ( grp->size() ); fAx++ )
1879  {
1880  for ( proshade_unsign sAx = 1; sAx < static_cast<proshade_unsign> ( grp->size() ); sAx++ )
1881  {
1882  //======================================== Only unique pairs
1883  if ( fAx >= sAx ) { continue; }
1884 
1885  //======================================== Find possible axis having the required angle to this pair ( solution 1 )
1886  std::vector< proshade_double > solVec = ProSHADE_internal_maths::findVectorFromTwoVAndTwoD ( CSymList->at(grp->at(fAx))[1],
1887  CSymList->at(grp->at(fAx))[2],
1888  CSymList->at(grp->at(fAx))[3],
1889  CSymList->at(grp->at(sAx))[1],
1890  CSymList->at(grp->at(sAx))[2],
1891  CSymList->at(grp->at(sAx))[3], angle, angle );
1892 
1893  //======================================== Set largest axis element to positive
1894  if ( ( ( std::max ( std::abs ( solVec.at(0) ), std::max( std::abs ( solVec.at(1) ), std::abs ( solVec.at(2) ) ) ) == std::abs ( solVec.at(0) ) ) && ( solVec.at(0) < 0.0 ) ) ||
1895  ( ( std::max ( std::abs ( solVec.at(0) ), std::max( std::abs ( solVec.at(1) ), std::abs ( solVec.at(2) ) ) ) == std::abs ( solVec.at(1) ) ) && ( solVec.at(1) < 0.0 ) ) ||
1896  ( ( std::max ( std::abs ( solVec.at(0) ), std::max( std::abs ( solVec.at(1) ), std::abs ( solVec.at(2) ) ) ) == std::abs ( solVec.at(2) ) ) && ( solVec.at(2) < 0.0 ) ) )
1897  {
1898  solVec.at(0) *= -1.0;
1899  solVec.at(1) *= -1.0;
1900  solVec.at(2) *= -1.0;
1901  }
1902 
1903  //======================================== Does the solution fit the whole group?
1904  symHlp[1] = solVec.at(0); symHlp[2] = solVec.at(1); symHlp[3] = solVec.at(2);
1905  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, grp, symHlp, axErr, angle, true ) )
1906  {
1907  //==================================== Find the height for the axis
1908  axHeight = ProSHADE_internal_symmetry::missingAxisHeight ( solVec.at(0), solVec.at(1), solVec.at(2), dataObj, fold, axErr );
1909 
1910  //================================ Save max height result
1911  if ( axHeight >= minPeakHeight ) { ProSHADE_internal_symmetry::saveMissingAxisNewOnly ( hlpVec, solVec.at(0), solVec.at(1), solVec.at(2), axHeight, fold, axErr ); }
1912  }
1913 
1914  //======================================== Find possible axis having the required angle to this pair ( solution 2 )
1915  solVec = ProSHADE_internal_maths::findVectorFromTwoVAndTwoD ( CSymList->at(grp->at(fAx))[1],
1916  CSymList->at(grp->at(fAx))[2],
1917  CSymList->at(grp->at(fAx))[3],
1918  CSymList->at(grp->at(sAx))[1],
1919  CSymList->at(grp->at(sAx))[2],
1920  CSymList->at(grp->at(sAx))[3], -angle, -angle );
1921 
1922  //======================================== Set largest axis element to positive
1923  if ( ( ( std::max ( std::abs ( solVec.at(0) ), std::max( std::abs ( solVec.at(1) ), std::abs ( solVec.at(2) ) ) ) == std::abs ( solVec.at(0) ) ) && ( solVec.at(0) < 0.0 ) ) ||
1924  ( ( std::max ( std::abs ( solVec.at(0) ), std::max( std::abs ( solVec.at(1) ), std::abs ( solVec.at(2) ) ) ) == std::abs ( solVec.at(1) ) ) && ( solVec.at(1) < 0.0 ) ) ||
1925  ( ( std::max ( std::abs ( solVec.at(0) ), std::max( std::abs ( solVec.at(1) ), std::abs ( solVec.at(2) ) ) ) == std::abs ( solVec.at(2) ) ) && ( solVec.at(2) < 0.0 ) ) )
1926  {
1927  solVec.at(0) *= -1.0;
1928  solVec.at(1) *= -1.0;
1929  solVec.at(2) *= -1.0;
1930  }
1931 
1932  //======================================== Does the solution fit the whole group?
1933  symHlp[1] = solVec.at(0); symHlp[2] = solVec.at(1); symHlp[3] = solVec.at(2);
1934  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, grp, symHlp, axErr, angle, true ) )
1935  {
1936  //==================================== Find the height for the axis
1937  axHeight = ProSHADE_internal_symmetry::missingAxisHeight ( solVec.at(0), solVec.at(1), solVec.at(2), dataObj, fold, axErr );
1938 
1939  //================================ Save max height result
1940  if ( axHeight >= minPeakHeight ) { ProSHADE_internal_symmetry::saveMissingAxisNewOnly ( hlpVec, solVec.at(0), solVec.at(1), solVec.at(2), axHeight, fold, axErr ); }
1941  }
1942  }
1943  }
1944 
1945  //================================================ Release memory
1946  delete[] symHlp;
1947 
1948  //================================================ Done
1949  return ;
1950 
1951 }

◆ smallestDistanceBetweenAngles()

bool ProSHADE_internal_symmetry::smallestDistanceBetweenAngles ( std::vector< proshade_unsign >  grp,
std::vector< proshade_double * >  peaks,
std::vector< proshade_double > *  tried,
proshade_double *  dist 
)

This function finds the smallest distance between the rotation angles within a group.

This function is used to control the while loop in the findPeaksCSymmetry() function. It has two outputs, the standard returned value is a boolean stating whether a new distance between group rotation angles was found; the second output is the distance itself, which is saved in the dist variable.

Parameters
[in]grpA single symmetry axis group indices to be printed.
[in]peaksThe vector of all peaks from which the indices are drawn.
[in]triedA vector of doubles holding the already tried distances and group combinations, so that they would not be tried again.
[in]distA pointer to the variable where the smallest distance (if found) will be saved.
[out]XBool whether a new distance was found.

Definition at line 551 of file ProSHADE_symmetry.cpp.

552 {
553  //================================================ Initialise variables
554  bool ret = false;
555  bool skip = false;
556  proshade_unsign g1 = 0, g2 = 0;
557  *dist = 999.9;
558 
559  //================================================ For each group pair
560  for ( proshade_unsign gr1It = 0; gr1It < static_cast<proshade_unsign> ( grp.size() ); gr1It++ )
561  {
562  for ( proshade_unsign gr2It = 1; gr2It < static_cast<proshade_unsign> ( grp.size() ); gr2It++ )
563  {
564  //======================================== Unique pairs only
565  if ( gr1It >= gr2It ) { continue; }
566 
567  //======================================== Have we tried this already?
568  skip = false;
569  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( tried->size() ); iter += 3 )
570  {
571  //==================================== Avoid already tested combinations
572  if ( ( gr2It == tried->at( iter + 1 ) ) && ( gr1It == tried->at( iter ) ) ) { skip = true; }
573 
574  //==================================== Also avoid distances very close to already tested distances (no problem until approx C700)
575  if ( !skip &&
576  ( ( std::abs( std::abs ( peaks.at(grp.at(gr1It))[3] ) - std::abs ( peaks.at(grp.at(gr2It))[3] ) ) - 0.01 ) < tried->at( iter + 2 ) ) &&
577  ( ( std::abs( std::abs ( peaks.at(grp.at(gr1It))[3] ) - std::abs ( peaks.at(grp.at(gr2It))[3] ) ) + 0.01 ) > tried->at( iter + 2 ) ) )
578  {
579  skip = true;
580  }
581  }
582  if ( skip ) { continue; }
583 
584  //======================================== Is this the smallest distance?
585  if ( std::abs( std::abs ( peaks.at(grp.at(gr1It))[3] ) - std::abs ( peaks.at(grp.at(gr2It))[3] ) ) < (*dist) )
586  {
587  //==================================== Avoid very small angle distances as they would just take time (the hardcoded value would only be a problem for C700 and larger symmetries...
588  if ( std::abs( std::abs ( peaks.at(grp.at(gr1It))[3] ) - std::abs ( peaks.at(grp.at(gr2It))[3] ) ) > 0.01 )
589  {
590  g1 = gr1It;
591  g2 = gr2It;
592  *dist = std::abs( std::abs ( peaks.at(grp.at(gr1It))[3] ) - std::abs ( peaks.at(grp.at(gr2It))[3] ) );
593  }
594  }
595  }
596  }
597 
598  //================================================ If new dist found, save to tried and return success
599  if ( *dist != 999.9 )
600  {
601  ret = true;
605  }
606 
607  //================================================ Done
608  return ( ret );
609 
610 }

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

1643 {
1644  //================================================ Compare
1645  return ( a[0] < b[0] );
1646 
1647 }

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

2051 {
2052  //================================================ Initialise variables
2053  bool ret = false;
2054  proshade_double dotProduct;
2055 
2056  //================================================ For all pairs of axes
2057  for ( proshade_unsign g1It = 0; g1It < static_cast<proshade_unsign> ( grp1->size() ); g1It++ )
2058  {
2059  for ( proshade_unsign g2It = 0; g2It < static_cast<proshade_unsign> ( grp2->size() ); g2It++ )
2060  {
2061  //======================================== Find the angle
2062  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &GrList1->at(grp1->at(g1It))[1],
2063  &GrList1->at(grp1->at(g1It))[2],
2064  &GrList1->at(grp1->at(g1It))[3],
2065  &GrList2->at(grp2->at(g2It))[1],
2066  &GrList2->at(grp2->at(g2It))[2],
2067  &GrList2->at(grp2->at(g2It))[3] );
2068 
2069  //======================================== Check the angle
2070  if ( ( angle > ( dotProduct - axErr ) ) && ( angle < ( dotProduct + axErr ) ) )
2071  {
2072  ret = true;
2073  return ( ret );
2074  }
2075  }
2076  }
2077 
2078  //================================================ Done
2079  return ( ret );
2080 
2081 }

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

1516 {
1517  //================================================ Initialise variables
1518  bool allAnglesMet = true;
1519  proshade_double dotProduct;
1520 
1521  //================================================ Improve if required
1522  if ( improve )
1523  {
1524  for ( proshade_unsign mIt = 0; mIt < static_cast<proshade_unsign> ( grp->size() ); mIt++ )
1525  {
1526  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] );
1527 
1528  if ( ( ( 1.0 > ( dotProduct - axErr ) ) && ( 1.0 < ( dotProduct + axErr ) ) ) || ( ( -1.0 > ( dotProduct - axErr ) ) && ( -1.0 < ( dotProduct + axErr ) ) ) )
1529  {
1530  if ( sym[5] > CSymList->at(grp->at(mIt))[5] )
1531  {
1532  grp->at(mIt) = pos;
1533  }
1534  else
1535  {
1536  allAnglesMet = false;
1537  return ( allAnglesMet );
1538  }
1539  }
1540  }
1541  }
1542 
1543  //================================================ For all group members
1544  for ( proshade_unsign mIt = 0; mIt < static_cast<proshade_unsign> ( grp->size() ); mIt++ )
1545  {
1546  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] );
1547 
1548  if ( ( angle > ( std::abs ( dotProduct ) - axErr ) ) &&
1549  ( angle < ( std::abs ( dotProduct ) + axErr ) ) )
1550  {
1551  //======================================== Matching group memner - try next one
1552  }
1553  else
1554  {
1555  //======================================== Group member not matched - try next group
1556  allAnglesMet = false;
1557  break;
1558  }
1559  }
1560 
1561  //================================================ Done
1562  return ( allAnglesMet );
1563 
1564 }
ProSHADE_internal_data::ProSHADE_data::optimiseDihedralAngleFromAngleAxis
std::vector< proshade_double * > optimiseDihedralAngleFromAngleAxis(ProSHADE_settings *settings, proshade_double angle, proshade_double *axis1, proshade_double *axis2)
...
Definition: ProSHADE_symmetry.cpp:3822
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:1885
ProSHADE_internal_symmetry::findExpectedPeakRotations
void findExpectedPeakRotations(proshade_unsign fold, std::vector< proshade_double > *expAngs)
This function computes the expected peak rotations for given fold.
Definition: ProSHADE_symmetry.cpp:705
ProSHADE_internal_misc::sortSymInvFoldHlp
bool sortSymInvFoldHlp(const proshade_double *a, const proshade_double *b)
This function compares two arrays of two based on the first number, sorting highest first.
Definition: ProSHADE_misc.cpp:273
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:1582
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::groupSameAxes
std::vector< std::vector< proshade_unsign > > groupSameAxes(std::vector< proshade_double * > &peaks, proshade_double errTolerance)
This function groups the peaks by their axes of rotation.
Definition: ProSHADE_symmetry.cpp:419
ProSHADE_internal_data::joinElementsFromDifferentGroups
std::vector< std::vector< proshade_double > > joinElementsFromDifferentGroups(std::vector< std::vector< proshade_double > > *first, std::vector< std::vector< proshade_double > > *second, proshade_double matrixTolerance, bool combine)
This function joins two group element lists using only unique elements.
Definition: ProSHADE_data.cpp:2486
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:1642
ProSHADE_internal_symmetry::addAxisUnlessSame
void 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 alread...
Definition: ProSHADE_symmetry.cpp:2527
ProSHADE_internal_symmetry::smallestDistanceBetweenAngles
bool smallestDistanceBetweenAngles(std::vector< proshade_unsign > grp, std::vector< proshade_double * > peaks, std::vector< proshade_double > *tried, proshade_double *dist)
This function finds the smallest distance between the rotation angles within a group.
Definition: ProSHADE_symmetry.cpp:551
ProSHADE_internal_maths::normalDistributionValue
proshade_double normalDistributionValue(proshade_double mean, proshade_double standardDev, proshade_double value)
Function to the heiht of normal distribution given by mean and standard deviation for a given value.
Definition: ProSHADE_maths.cpp:1685
ProSHADE_internal_symmetry::isSymmetrySame
bool isSymmetrySame(std::vector< proshade_double * > *ret, proshade_double *sym, proshade_double simThres)
This function checks if a very similar symmetry is not already saved.
Definition: ProSHADE_symmetry.cpp:1177
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:188
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:1663
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:1867
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:2434
ProSHADE_internal_maths::getRotationMatrixFromEulerZXZAngles
void getRotationMatrixFromEulerZXZAngles(proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double *matrix)
Function to find the rotation matrix from Euler angles (ZXZ convention).
Definition: ProSHADE_maths.cpp:1005
ProSHADE_internal_data::ProSHADE_data::computeGroupElementsForGroup
std::vector< std::vector< proshade_double > > computeGroupElementsForGroup(std::vector< std::vector< proshade_double > > *allCSyms, proshade_unsign grPosition)
This function computes the group elements as rotation matrices (except for the identity element) for ...
Definition: ProSHADE_data.cpp:2263
ProSHADE_internal_symmetry::addZeroPeakToGroups
void addZeroPeakToGroups(std::vector< std::vector< proshade_unsign > > &grpsVec, std::vector< proshade_double * > &peaks)
This function takes the peak groups and adds zero peak to each of them.
Definition: ProSHADE_symmetry.cpp:621
ProSHADE_internal_messages::printWarningMessage
void printWarningMessage(proshade_signed verbose, std::string message, std::string warnCode)
General stderr message printing (used for warnings).
Definition: ProSHADE_messages.cpp:101
ProSHADE_internal_maths::vectorOrientationSimilarity
bool vectorOrientationSimilarity(proshade_double a1, proshade_double a2, proshade_double a3, proshade_double b1, proshade_double b2, proshade_double b3, proshade_double tolerance=0.1)
This function compares two vectors using cosine distance and decides if they are similar using tolera...
Definition: ProSHADE_maths.cpp:2016
ProSHADE_internal_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_symmetry::checkExpectedAgainstFound
proshade_unsign checkExpectedAgainstFound(std::vector< proshade_unsign > grp, std::vector< proshade_double * > peaks, std::vector< proshade_double > *expAngs, std::vector< proshade_unsign > *matchedAngs, std::vector< proshade_unsign > *missingAngs, proshade_double axisTol)
This function computes the expected peak rotations for given fold.
Definition: ProSHADE_symmetry.cpp:734
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:1799
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:1701
ProSHADE_internal_symmetry::findSymmetryUsingFold
void findSymmetryUsingFold(ProSHADE_internal_data::ProSHADE_data *dataObj, std::vector< proshade_unsign > *angsToTry, std::vector< proshade_unsign > *grp, std::vector< proshade_double * > *peaks, std::vector< std::vector< proshade_unsign > > *ret, std::vector< proshade_unsign > *testedAlready, proshade_double axErrTolerance, bool axErrToleranceDefault, proshade_double missPeakThres, proshade_unsign verbose)
This function tests all supplied folds for being supported by the peaks (i.e. and being complete pres...
Definition: ProSHADE_symmetry.cpp:989
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:287
ProSHADE_internal_data::ProSHADE_data::getMaxBand
proshade_unsign getMaxBand(void)
This function returns the maximum band value for the object.
Definition: ProSHADE_data.cpp:2986
ProSHADE_internal_symmetry::completeMissingCSymmetry
bool completeMissingCSymmetry(ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_unsign fold, std::vector< proshade_unsign > *grp, std::vector< proshade_double * > *peaks, std::vector< proshade_unsign > *missingPeaks, std::vector< proshade_double > *expectedAngles, std::vector< proshade_unsign > *matchedPeaks, proshade_double axErrTolerance, proshade_unsign verbose)
This function does the complete missing peak searching and filling in the missing peaks.
Definition: ProSHADE_symmetry.cpp:924
ProSHADE_internal_symmetry::giveOppositeAxesSameDirection
void giveOppositeAxesSameDirection(std::vector< proshade_double * > peaks)
This function modifiest the axes so that the highest vector element is always positive.
Definition: ProSHADE_symmetry.cpp:491
ProSHADE_internal_symmetry::printSymmetryPeaks
void printSymmetryPeaks(std::vector< proshade_unsign > grp, std::vector< proshade_double * > peaks, proshade_signed verbose, proshade_unsign groupNo)
This function simply prints the symmetry axis group supplied in the first parameter from the second p...
Definition: ProSHADE_symmetry.cpp:518
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:2397
findBestIcosDihedralPair
std::pair< proshade_unsign, proshade_unsign > findBestIcosDihedralPair(std::vector< proshade_double * > *CSymList, proshade_double minPeakHeight, proshade_double axErr)
This function finds the best pair of axes conforming to the icosahedron dihedral angle.
Definition: ProSHADE_symmetry.cpp:2881
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:3411
ProSHADE_internal_maths::getAxisAngleFromRotationMatrix
void getAxisAngleFromRotationMatrix(proshade_double *rotMat, proshade_double *x, proshade_double *y, proshade_double *z, proshade_double *ang)
This function converts rotation matrix to the axis-angle representation.
Definition: ProSHADE_maths.cpp:1039
ProSHADE_internal_mapManip::myRound
proshade_signed myRound(proshade_double x)
Calls the appropriate version of round function depending on compiler version.
Definition: ProSHADE_mapManip.cpp:31
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:1515
ProSHADE_internal_misc::checkMemoryAllocation
void checkMemoryAllocation(chVar checkVar, std::string fileP, unsigned int lineP, std::string funcP, std::string infoP="This error may occurs when ProSHADE requests memory to be\n : allocated to it and this operation fails. This could\n : happen when not enough memory is available, either due to\n : other processes using a lot of memory, or when the machine\n : does not have sufficient memory available. Re-run to see\n : if this problem persists.")
Checks if memory was allocated properly.
Definition: ProSHADE_misc.hpp:65
ProSHADE_internal_symmetry::saveDetectedCSymmetry
void saveDetectedCSymmetry(proshade_unsign fold, std::vector< proshade_unsign > *matchedPeaks, std::vector< std::vector< proshade_unsign > > *ret, proshade_signed verbose)
This function saves a detected symmetry for reporting to the user.
Definition: ProSHADE_symmetry.cpp:884
ProSHADE_internal_maths::getEulerZXZFromSOFTPosition
void getEulerZXZFromSOFTPosition(proshade_signed band, proshade_signed x, proshade_signed y, proshade_signed z, proshade_double *eulerAlpha, proshade_double *eulerBeta, proshade_double *eulerGamma)
Function to find Euler angles (ZXZ convention) from index position in the inverse SOFT map.
Definition: ProSHADE_maths.cpp:961
ProSHADE_internal_symmetry::checkForMissingPeak
proshade_double checkForMissingPeak(ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_double x, proshade_double y, proshade_double z, proshade_double angle, proshade_double heightThres, proshade_double axTol)
This function checks for the high of the correlation for particular rotation angle and axis.
Definition: ProSHADE_symmetry.cpp:816
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:3213
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_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:3522
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:1743
ProSHADE_internal_symmetry::determineFoldToTry
bool determineFoldToTry(proshade_double dist, proshade_double *divBasis, proshade_double *divRem, proshade_double peakErr, proshade_double *symmErr, std::vector< proshade_unsign > *angsToTry)
This function determines the symmetry fold to be searched for.
Definition: ProSHADE_symmetry.cpp:658
ProSHADE_internal_messages::printProgressMessage
void printProgressMessage(proshade_signed verbose, proshade_signed messageLevel, std::string message)
General stdout message printing.
Definition: ProSHADE_messages.cpp:70
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:243
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:2577
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:1725