ProSHADE: ProSHADE_internal_symmetry Namespace Reference

| ProSHADE 0.7.5.1 (JAN 2021) Protein Shape Detection

Functions
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] | fold | The fold of the searched for axis.
  [in] | axX | The x-axis element of the new axis.
  [in] | axY | The y-axis element of the new axis.
  [in] | axZ | The z-axis element of the new axis.
  [in] | axHeight | The average peak height of the new axis.
  [in] | prosp | The vector to which the axis is to be saved.
  [in] | axErr | The 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 {
2544 ProSHADE_internal_misc::addToDblPtrVector ( prosp, symHlp );
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] | grpsVec | A list of all symmetry axis groups.
  [in] | peaks | The 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() ) );
634 ProSHADE_internal_misc::addToDblPtrVector ( &peaks, hlpP );
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] | grp | A single symmetry axis group indices to be processed.
  [in] | peaks | The vector of all peaks from which the indices are drawn.
  [in] | expAngs | A vector where the expected peak rotation values are saved.
  [in] | matchedAngs | A vector where the indices of matched peaks will be saved.
  [in] | missingAngs | A vector where the indices of missing peaks will be saved.
  [in] | angTol | The tolerance for matching the expected and found peak rotation angles.
  [out] | X | An 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] | retGroup | A vector of indices in the ret list which form the group to which new axes are compared to.
  [in] | ret | A list of already detected axes.
  [in] | fold | The fold of the searched for axis.
  [in] | axX | The x-axis element of the new axis.
  [in] | axY | The y-axis element of the new axis.
  [in] | axZ | The z-axis element of the new axis.
  [in] | prosp | The vector to which the axis is to be saved.
  [in] | axErr | The error tolerance on angle matching.
  [in] | noMatchesG1 | The number of axes from ret that need to be matched with angle1.
  [in] | angle1 | The angle with which noMatchesG1 axes need to be matched with the retGroup axes.
  [in] | noMatchesG2 | The number of axes from ret that need to be matched with angle2.
  [in] | angle2 | The angle with which noMatchesG2 axes need to be matched with the retGroup axes.
  [in] | dataObj | The full data holding object pointer - this is to get access to self-rotation function values.
  [out] | Bool | True 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] | retGroup | A vector of indices in the ret list which form the group to which new axes are compared to.
  [in] | ret | A list of already detected axes.
  [in] | fold | The fold of the searched for axis.
  [in] | axX | The x-axis element of the new axis.
  [in] | axY | The y-axis element of the new axis.
  [in] | axZ | The z-axis element of the new axis.
  [in] | prosp | The vector to which the axis is to be saved.
  [in] | axErr | The error tolerance on angle matching.
  [in] | noMatchesG1 | The number of axes from ret that need to be matched with angle1.
  [in] | angle1 | The angle with which noMatchesG1 axes need to be matched with the retGroup axes.
  [in] | noMatchesG2 | The number of axes from ret that need to be matched with angle2.
  [in] | angle2 | The angle with which noMatchesG2 axes need to be matched with the retGroup axes.
  [in] | noMatchesG3 | The number of axes from ret that need to be matched with angle3.
  [in] | angle3 | The angle with which noMatchesG3 axes need to be matched with the retGroup axes.
  [in] | dataObj | The 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] | dataObj | The data object for which symmetry is being searched.
  [in] | x | The x-axis element of the searched for rotation angle-axis representation.
  [in] | y | The y-axis element of the searched for rotation angle-axis representation.
  [in] | z | The z-axis element of the searched for rotation angle-axis representation.
  [in] | angle | The angle element of the searched for rotation angle-axis representation.
  [in] | heightThres | The required self-rotation map height for this rotation.
  [in] | axTol | The tolerance on axis matching when searching for the rotation.
  [out] | X | The 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 );
842 ProSHADE_internal_maths::getRotationMatrixFromEulerZXZAngles ( euA, euB, euG, rotMat );
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] | dataObj | The data object for which symmetry is being searched.
  [in] | fold | This is the fold value of the detected C symmetry.
  [in] | grp | Vector with the indices of members of this symmetry axis group.
  [in] | peaks | A vector of pointers where angle-axis representations of the peaks is saved.
  [in] | missingPeaks | Vector with the indices of missing rotation angles (indices are from the expected peaks vector, not peaks vector!).
  [in] | expectedAngles | Vector with the expected rotation angle values.
  [in] | axErrTolerance | The allowed error on matching axes.
  [in] | verbose | How loud the standard output of this run should be?
  [out] | X | Was 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() ) );
960 ProSHADE_internal_misc::addToDblPtrVector ( peaks, hlpP );
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] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | axErr | The error tolerance on angle matching.
  [in] | minPeakHeight | The minimum average peak height required for symmetry axis to be considered.
  [out] | X | Boolean 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] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | axErr | The error tolerance on angle matching.
  [in] | minPeakHeight | The minimum average peak height for axis to be considered.
  [out] | X | Boolean 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] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | axErr | The error tolerance on angle matching.
  [in] | minPeakHeight | The minimum average peak height for axis to be considered.
  [out] | X | Boolean 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] | dist | The distance between rotation angles that should form the symmetry group.
  [in] | divBasis | Pointer to where to save the basis of the division 2pi/dist.
  [in] | divRem | Pointer to where to save the remainder of the division 2pi/dist.
  [in] | peakErr | The error in radians which would be the result of misplacing a peak by single map index.
  [in] | symmErr | Pointer to where to save the error which would be caused by mis-predicting the fold by 1.
  [in] | angsToTry | A vector where all the suggested fold values to be tested are saved.
  [out] | X | Boolean 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] | fold | The fold for which peak rotation angles should be predicted.
  [in] | expAngs | A 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] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | ret | The vector containing the already detected axes to which newly detected axes (if any) will be added.
  [in] | axErr | The error tolerance on angle matching.
  [in] | minPeakHeight | The minimum average peak height for axis to be considered.
  [in] | verobse | How 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] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | ret | The vector containing the already detected axes to which newly detected axes (if any) will be added.
  [in] | axErr | The error tolerance on angle matching.
  [in] | minPeakHeight | The minimum average peak height for axis to be considered.
  [in] | verobse | How 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] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | ret | The vector .
  [in] | axErr | The error tolerance on angle matching.
  [in] | minPeakHeight | The minimum average peak height for axis to be considered.
  [in] | verobse | How 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] | possibilities | A vector of vectors of indices to the cyclic symmetries list with all the already determined axes.
  [in] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | requiredNoAxes | Number of axes required for positive result.
  [in] | axErr | The error tolerance on angle matching.
  [in] | angle | The angle that each group member is required to have against the symmetry.
  [in] | fold | The fold of the searched for axis.
  [in] | dataObj | The full data holding object pointer - this is to get access to self-rotation function values.
  [in] | minPeakHeight | The minimum new axis average peak height in order for the axis to be added.
  [out] | atLeastOne | Boolean 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] | possibilities | A vector of already detected axis indices which should be extended.
  [in] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | ret | A list of already detected octahedral axes.
  [in] | retGroup | A vector of indices in the ret list which form the group to which new axes are compared to.
  [in] | requiredNoAxes | Number of axes required for positive result.
  [in] | axErr | The error tolerance on angle matching.
  [in] | noMatchesG1 | The number of axes from ret that need to be matched with angle1.
  [in] | angle1 | The angle with which noMatchesG1 axes need to be matched with the retGroup axes.
  [in] | noMatchesG2 | The number of axes from ret that need to be matched with angle2.
  [in] | angle2 | The angle with which noMatchesG2 axes need to be matched with the retGroup axes.
  [in] | fold | The fold of the searched for axis.
  [in] | dataObj | The full data holding object pointer - this is to get access to self-rotation function values.
  [out] | atLeastOne | Boolean 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] | possibilities | A vector of already detected axis indices which should be extended.
  [in] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | ret | A list of already detected octahedral axes.
  [in] | retGroup | A vector of indices in the ret list which form the group to which new axes are compared to.
  [in] | requiredNoAxes | Number of axes required for positive result.
  [in] | axErr | The error tolerance on angle matching.
  [in] | noMatchesG1 | The number of axes from ret that need to be matched with angle1.
  [in] | angle1 | The angle with which noMatchesG1 axes need to be matched with the retGroup axes.
  [in] | noMatchesG2 | The number of axes from ret that need to be matched with angle2.
  [in] | angle2 | The angle with which noMatchesG2 axes need to be matched with the retGroup axes.
  [in] | noMatchesG3 | The number of axes from ret that need to be matched with angle3.
  [in] | angle3 | The angle with which noMatchesG3 axes need to be matched with the retGroup axes.
  [in] | fold | The fold of the searched for axis.
  [in] | dataObj | The full data holding object pointer - this is to get access to self-rotation function values.
  [out] | atLeastOne | Boolean 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] | xVal | The x-axis element of the axis to have the height detected.
  [in] | yVal | The y-axis element of the axis to have the height detected.
  [in] | zVal | The z-axis element of the axis to have the height detected.
  [in] | dataObj | The full data holding object pointer - this is to get access to self-rotation function values.
  [in] | axErr | The error tolerance on angle matching.
  [out] | angVec | Vector 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 );
1748 ProSHADE_internal_maths::getRotationMatrixFromEulerZXZAngles ( euA, euB, euG, rotMat );
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] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | ret | The vector containing all axes required for the octahedral symmetry detected so far.
  [in] | axErr | The error tolerance on angle matching.
  [in] | minPeakHeight | The minimum average peak height for axis to be considered.
  [in] | verobse | How 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] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | ret | The vector .
  [in] | axErr | The error tolerance on angle matching.
  [in] | verobse | How loud the announcments should be?
  [in] | minPeakHeight | The minimum average peak height for axis to be considered.
  [in] | TetraSymList | A 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] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | ret | The vector containing the already detected axes to which newly detected axes (if any) will be added.
  [in] | axErr | The error tolerance on angle matching.
  [in] | verobse | How loud the announcments should be?
  [in] | minPeakHeight | The 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] | allPeaks | A vector of pointers where angle-axis representations of the peaks is saved.
  [in] | smoothing | Value determining how smooth the distribution of peaks should be made. Larger number means more groups.
  [out] | X | The 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] | peaks | A vector of pointers where angle-axis representations of the peaks is saved.
  [in] | verbose | How loud the standard output of this run should be?
  [in] | band | The bandwidth of these computations.
  [in] | missPeakThres | Threshold for the percentage of missing peaks there can be to warrant a full search for missing peaks.
  [in] | axisErrTolerance | Tolerance for symmetry axis identity.
  [in] | axisErrToleranceDef | Should the automatic axis tolerance decrease be applied?
  [in] | dataObj | The data object for which symmetry is being searched. This is only needed for missing peaks search, but needed nonetheless.
  [out] | X | Vector 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] | dataObj | The data object for which symmetry is being searched.
  [in] | angsToTry | This vector contains all the folds that should be attempted.
  [in] | grp | Vector with the indices of members of this symmetry axis group.
  [in] | peaks | A vector of pointers where angle-axis representations of the peaks is saved.
  [in] | ret | The final variable holding all results (i.e. detected symmetries).
  [in] | testedAlready | A vector in which the already tested folds for this symmetry axis are saved.
  [in] | axErrTolerance | The allowed error on matching axes.
  [in] | axErrToleranceDefault | Should the axErrTolerance be decreased with increasing fold?
  [in] | missPeakThres | Threshold for the percentage of missing peaks there can be to warrant a full search for missing peaks.
  [in] | verbose | How 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] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | ret | The vector .
  [in] | axErr | The error tolerance on angle matching.
  [in] | verobse | How loud the announcments should be?
  [in] | minPeakHeight | The 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] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | ret | The vector .
  [in] | axErr | The error tolerance on angle matching.
  [in] | verobse | How loud the announcments should be?
  [in] | minPeakHeight | The 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] | allPeaks | A vector of pointers where Euler ZXZ representations of the peaks are saved.
  [in] | verbose | How loud the standard output of this run should be?
  [out] | X | A 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
279 ProSHADE_internal_misc::addToDblPtrVector ( &ret, hlpP );
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] | peaks | A 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] | peaks | A vector of pointers where angle-axis representations of the peaks is saved.
  [in] | errTolerance | A value within which two axes are considered equal.
  [out] | X | A 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)
427 ProSHADE_internal_symmetry::giveOppositeAxesSameDirection ( peaks );
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 );
472 ProSHADE_internal_misc::addToUnsignVectorVector ( &ret, hlpVec );
473 }
474
475 //================================================ Add zero peak to all axes
476 ProSHADE_internal_symmetry::addZeroPeakToGroups ( ret, peaks );
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] | ret | This 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] | sym | This is a double array of 6 which is to be compared to all the vector entries.
  [in] | simThres | The threshold for dot product comparison similarity.
  [out] | X | Boolean 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] | xVal | The x-axis element of the axis to have the height detected.
  [in] | yVal | The y-axis element of the axis to have the height detected.
  [in] | zVal | The z-axis element of the axis to have the height detected.
  [in] | dataObj | The full data holding object pointer - this is to get access to self-rotation function values.
  [in] | fold | The fold of the searched for axis.
  [in] | axErr | The error tolerance on angle matching.
  [out] | X | The 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] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | ret | The vector .
  [in] | axErr | The error tolerance on angle matching.
  [in] | minPeakHeight | The minimum average peak height for axis to be considered.
  [in] | verobse | How loud the announcments should be?
  [in] | axisTolerance | The tolerance for two axes to be considered similar in terms of cosine distance.
  [in] | matrixTolerance | The 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 );
3048 ProSHADE_internal_misc::deepCopyAxisToDblPtrVector ( ret, 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] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | ret | The vector .
  [in] | axErr | The error tolerance on angle matching.
  [in] | minPeakHeight | The minimum average peak height for axis to be considered.
  [in] | verobse | How loud the announcments should be?
  [in] | axisTolerance | The tolerance for two axes to be considered similar in terms of cosine distance.
  [in] | matrixTolerance | The 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] | noSyms | The number of symmetries that were detected.
  [in] | verbose | How 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] | grp | A single symmetry axis group indices to be printed.
  [in] | peaks | The vector of all peaks from which the indices are drawn.
  [in] | verbose | How 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] | grp | A single symmetry axis group indices to be printed.
  [in] | peaks | The vector of all peaks from which the indices are drawn.
  [in] | verbose | How 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] | detected | This is a vector of vectors with the indices of detected symmetry peaks.
  [in] | peaks | These are the peaks and their values which come together to form the detected symmetry.
  [in] | ret | This 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] | axErr | The 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 {
1154 ProSHADE_internal_misc::addToDblPtrVector ( ret, hlpP );
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] | fold | This is the fold value of the detected C symmetry.
  [in] | matchedPeaks | A vector containing the indices of all peaks forming this symmetry.
  [in] | ret | The vector of vectors to be returned by findPeaksCSymmetry() and containing all detected symmetries (to which we are saving here).
  [in] | verbose | How 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;
888 ProSHADE_internal_misc::addToUnsignVector ( &hlpVec, fold );
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 }
895 ProSHADE_internal_misc::addToUnsignVectorVector ( ret, hlpVec );
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] | ret | The vector of double pointers to which the symmetry is to be saved to.
  [in] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | axisOne | The index of the first C symmetry forming the dihedral symmetry.
  [in] | axisTwo | The 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
1324 ProSHADE_internal_misc::addToDblPtrVector ( ret, hlpP );
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] | axVec | Vector containing all already detected missing axes.
  [in] | axX | The x-axis element of the missing axis.
  [in] | axY | The y-axis element of the missing axis.
  [in] | axZ | The z-axis element of the missing axis.
  [in] | height | The average map height for this new axis.
  [in] | fold | The fold of the searched for axis.
  [in] | axErr | The 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
1846 ProSHADE_internal_misc::addToDblPtrVector ( axVec, hlpSym );
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] | dataObj | The full data holding object pointer - this is to get access to self-rotation function values.
  [in] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | grp | A vector of indices (relating to CSymList) of the group members.
  [in] | hlpVec | A vector which will hold the detected, but not verified axes to be returned to the caller function.
  [in] | axErr | The error tolerance on angle matching.
  [in] | angle | The angle that each group member is required to have against the symmetry.
  [in] | fold | The fold of the searched for axis.
  [in] | minPeakHeight | The 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] | grp | A single symmetry axis group indices to be printed.
  [in] | peaks | The vector of all peaks from which the indices are drawn.
  [in] | tried | A vector of doubles holding the already tried distances and group combinations, so that they would not be tried again.
  [in] | dist | A pointer to the variable where the smallest distance (if found) will be saved.
  [out] | X | Bool 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;
602 ProSHADE_internal_misc::addToDoubleVector ( tried, g1 );
603 ProSHADE_internal_misc::addToDoubleVector ( tried, g2 );
604 ProSHADE_internal_misc::addToDoubleVector ( tried, *dist );
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] | a | The first array to compare.
  [in] | b | The second array to compare.
  [out] | X | Boolean 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] | GrList1 | A vector containing the symmetries for the group 1.
  [in] | grp1 | The indices respective to GrList1 which form group 1.
  [in] | GrList2 | A vector containing the symmetries for the group 2.
  [in] | grp2 | The indices respective to GrList1 which form group 2.
  [in] | angle | The angle which needs to be found between any pair of axes in group 1 and 2.
  [in] | axErr | The error tolerance on angle matching.
  [out] | ret | True 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] | CSymList | A vector containing the already detected Cyclic symmetries.
  [in] | grp | A vector of indices (relating to CSymList) of the group members.
  [in] | sym | A double pointer to array containing the symmetry to be tested against the group.
  [in] | axErr | The error tolerance on angle matching.
  [in] | angle | The angle that each group member is required to have against the symmetry.
  [in] | improve | Boolead 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] | pos | This 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] | X | Boolean 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