ProSHADE  0.7.6.2 (DEC 2021)
Protein Shape Detection
ProSHADE_symmetry.cpp
Go to the documentation of this file.
1 
22 //==================================================== ProSHADE
23 #include "ProSHADE_symmetry.hpp"
24 
25 //==================================================== Local functions prototypes
26 proshade_double determinePeakThreshold ( std::vector < proshade_double > inArr, proshade_double noIQRsFromMedian );
27 bool sortProSHADESymmetryByPeak ( proshade_double* a, proshade_double* b );
28 std::vector < std::pair< proshade_unsign, proshade_unsign > > findBestIcosDihedralPair ( std::vector< proshade_double* >* CSymList, proshade_double minPeakHeight, proshade_double axErr );
29 std::pair< proshade_unsign, proshade_unsign > findBestOctaDihedralPair ( std::vector< proshade_double* >* CSymList, proshade_double minPeakHeight, proshade_double axErr );
30 std::pair< proshade_unsign, proshade_unsign > findBestTetraDihedralPair ( std::vector< proshade_double* >* CSymList, proshade_double minPeakHeight, proshade_double axErr );
31 
42 {
43  //================================================ Report progress
44  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 1, "Starting self-rotation function computation.", settings->messageShift );
45 
46  //================================================ Compute un-weighted E matrices and their weights
47  ProSHADE_internal_distances::computeEMatrices ( this, this, settings );
48 
49  //================================================ Normalise E matrices by the magnitudes
50  ProSHADE_internal_distances::normaliseEMatrices ( this, this, settings );
51 
52  //================================================ Generate SO(3) coefficients
54 
55  //================================================ Compute the inverse SO(3) Fourier Transform (SOFT) on the newly computed coefficients
57 
58  //================================================ Report completion
59  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 2, "Self-rotation function obtained.", settings->messageShift );
60 
61  //================================================ Done
62  return ;
63 
64 }
65 
71 proshade_double determinePeakThreshold ( std::vector < proshade_double > inArr, proshade_double noIQRsFromMedian )
72 {
73  //================================================ Initialise variables
74  proshade_double ret = 0.0;
75  proshade_double rmsd = 0.0;
76  size_t vecSize = inArr.size();
77 
78  //================================================ Deal with low number of input cases
79  if ( vecSize == 0 ) { return ( ret ); } // Return 0
80  if ( vecSize <= 4 ) { ret = std::accumulate ( inArr.begin(), inArr.end(), 0.0 ) / static_cast< proshade_double > ( vecSize ); return ( ret ); } // Return mean
81 
82  //================================================ Deal with reasonable number in input cases
83  else
84  {
85  //============================================ Find mean
86  ret = std::accumulate ( inArr.begin(), inArr.end(), 0.0 ) / static_cast< proshade_double > ( vecSize );
87 
88  //============================================ Get the RMS distance
89  for ( size_t i = 0; i < vecSize; i++ )
90  {
91  rmsd += std::pow ( ret - inArr.at(i), 2.0 );
92  }
93  rmsd = std::sqrt ( rmsd );
94 
95  //============================================ Get the threshold
96  ret = ret + ( noIQRsFromMedian * rmsd );
97  }
98 
99  //================================================ Sanity checks
100  if ( ret > *( std::max_element ( inArr.begin(), inArr.end() ) ) )
101  {
102  ret = *( std::max_element ( inArr.begin(), inArr.end() ) );
103  }
104 
105  //================================================ Done
106  return ( ret );
107 
108 }
109 
122 {
123  //================================================ Report progress
124  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 1, "Starting self-rotation function conversion to angle-axis representation.", settings->messageShift );
125 
126  //================================================ Initialise variables
127  proshade_double shellSpacing = ( 2.0 * M_PI ) / static_cast<proshade_double> ( this->maxShellBand ) * 2.0;
128  std::vector< proshade_double > allPeakHeights;
129 
130  //================================================ Initialise the spheres
131  for ( proshade_unsign spIt = 1; spIt < ( this->maxShellBand * 2 ); spIt++ )
132  {
133  this->sphereMappedRotFun.emplace_back ( new ProSHADE_internal_spheres::ProSHADE_rotFun_sphere( static_cast<proshade_double> ( spIt ) * shellSpacing,
134  shellSpacing,
135  this->maxShellBand * 2,
136  static_cast<proshade_double> ( spIt ) * shellSpacing,
137  spIt - 1 ) );
138  }
139 
140  //================================================ Interpolate the rotation function onto the spheres
141  for ( proshade_unsign shIt = 0; shIt < static_cast<proshade_unsign> ( sphereMappedRotFun.size() ); shIt++ )
142  {
143  //============================================ Report progress
144  std::stringstream hlpSS;
145  hlpSS << "Interpolating sphere " << shIt << " ( radius: " << this->sphereMappedRotFun.at(shIt)->getRadius() << " ).";
146  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 3, hlpSS.str(), settings->messageShift );
147 
148  //============================================ Interpolate onto spheres
149  this->sphereMappedRotFun.at(shIt)->interpolateSphereValues ( this->getInvSO3Coeffs ( ) );
150  }
151 
152  //================================================ Report completion
153  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 2, "Self-rotation function converted to spherical angle-axis space.", settings->messageShift );
154  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 2, "Started peak detection on the angle-axis spheres.", settings->messageShift );
155 
156  //================================================ Find all peaks in the sphere grids
157  for ( proshade_unsign shIt = 0; shIt < static_cast<proshade_unsign> ( this->sphereMappedRotFun.size() ); shIt++ )
158  {
159  this->sphereMappedRotFun.at(shIt)->findAllPeaks ( static_cast< proshade_signed > ( settings->peakNeighbours ), &allPeakHeights );
160  }
161 
162  //================================================ Report progress
163  std::stringstream hlpSS;
164  hlpSS << "Detected " << allPeakHeights.size() << " peaks with any height.";
165  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 3, hlpSS.str(), settings->messageShift );
166 
167  //================================================ Compute threshold for small peaks
168  proshade_double peakThres = std::max ( settings->minSymPeak, determinePeakThreshold ( allPeakHeights, settings->noIQRsFromMedianNaivePeak ) );
169 
170  //================================================ Report progress
171  std::stringstream hlpSS2;
172  hlpSS2 << "From these peaks, decided the threshold will be " << peakThres << " peak height.";
173  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 4, hlpSS2.str(), settings->messageShift );
174 
175  //================================================ Remove too small peaks
176  for ( proshade_unsign shIt = 0; shIt < static_cast<proshade_unsign> ( this->sphereMappedRotFun.size() ); shIt++ )
177  {
178  this->sphereMappedRotFun.at(shIt)->removeSmallPeaks ( peakThres );
179  }
180 
181  //================================================ Report progress
182  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 3, "Peaks detected for all spheres.", settings->messageShift );
183 
184  //================================================ Done
185  return ;
186 
187 }
188 
200 bool ProSHADE_internal_symmetry::isSymmetrySame ( std::vector< proshade_double* >* ret, proshade_double* sym, proshade_double simThres, proshade_signed* matchedPos )
201 {
202  //================================================ Initialise variables
203  proshade_double dotProduct = 0.0;
204  *matchedPos = -1;
205 
206  //================================================ Check
207  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( ret->size() ); symIt++ )
208  {
209  //============================================ Minor speed-up => only test for same folds
210  const FloatingPoint< proshade_double > lhs ( ret->at(symIt)[0] ), rhs ( sym[0] );
211  if ( lhs.AlmostEquals ( rhs ) )
212  {
213  //======================================== Is axis the same?
214  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &ret->at(symIt)[1], &ret->at(symIt)[2],
215  &ret->at(symIt)[3], &sym[1], &sym[2], &sym[3] );
216  if ( ( ( 1.0 > ( dotProduct - simThres ) ) && ( 1.0 < ( dotProduct + simThres ) ) ) || ( ( -1.0 > ( dotProduct - simThres ) ) && ( -1.0 < ( dotProduct + simThres ) ) ) )
217  {
218  //==================================== Matched. Save the index
219  *matchedPos = static_cast< proshade_signed > ( symIt );
220 
221  //==================================== Does the already saved have higher height?
222  if ( ret->at(symIt)[5] >= sym[5] ) { return ( true ); }
223 
224  //==================================== In this case, new is better than old - sort it out
225  ret->at(symIt)[1] = sym[1];
226  ret->at(symIt)[2] = sym[2];
227  ret->at(symIt)[3] = sym[3];
228  ret->at(symIt)[5] = sym[5];
229  return ( true );
230  }
231  }
232  }
233 
234  //================================================ Done - no matches found
235  return ( false );
236 
237 }
238 
251 bool ProSHADE_internal_symmetry::isSymmetrySame ( std::vector< proshade_double* >* ret, proshade_double* sym, proshade_double simThres, proshade_signed* matchedPos, proshade_double fscVal )
252 {
253  //================================================ Initialise variables
254  proshade_double dotProduct = 0.0;
255  *matchedPos = -1;
256 
257  //================================================ Check
258  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( ret->size() ); symIt++ )
259  {
260  //============================================ Minor speed-up => only test for same folds
261  const FloatingPoint< proshade_double > lhs ( ret->at(symIt)[0] ), rhs ( sym[0] );
262  if ( lhs.AlmostEquals ( rhs ) )
263  {
264  //======================================== Is axis the same?
265  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &ret->at(symIt)[1], &ret->at(symIt)[2],
266  &ret->at(symIt)[3], &sym[1], &sym[2], &sym[3] );
267  if ( ( ( 1.0 > ( dotProduct - simThres ) ) && ( 1.0 < ( dotProduct + simThres ) ) ) || ( ( -1.0 > ( dotProduct - simThres ) ) && ( -1.0 < ( dotProduct + simThres ) ) ) )
268  {
269  //==================================== Matched. Save the index
270  *matchedPos = static_cast< proshade_signed > ( symIt );
271 
272  //==================================== Does the already saved have higher height?
273  if ( ret->at(symIt)[5] >= sym[5] ) { return ( true ); }
274 
275  //==================================== In this case, new is better than old - sort it out
276  ret->at(symIt)[1] = sym[1];
277  ret->at(symIt)[2] = sym[2];
278  ret->at(symIt)[3] = sym[3];
279  ret->at(symIt)[5] = sym[5];
280  ret->at(symIt)[6] = fscVal;
281  return ( true );
282  }
283  }
284  }
285 
286  //================================================ Done - no matches found
287  return ( false );
288 
289 }
290 
302 std::vector< proshade_double* > ProSHADE_internal_data::ProSHADE_data::getDihedralSymmetriesList ( ProSHADE_settings* settings, std::vector< proshade_double* >* CSymList )
303 {
304  //================================================ Initialise variables
305  std::vector< proshade_double* > ret;
306  proshade_double dotProduct;
307 
308  //================================================ Report progress
309  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 1, "Starting D symmetry detection.", settings->messageShift );
310 
311  //================================================If not enough axes, just end here
312  if ( CSymList->size() < 2 ) { return ( ret ); }
313 
314  //================================================ For each unique pair of axes
315  for ( proshade_unsign ax1 = 0; ax1 < static_cast<proshade_unsign> ( CSymList->size() ); ax1++ )
316  {
317  //============================================ Ignore small axes
318  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(ax1)[5] ), rhs1 ( -999.9 );
319  if ( ( CSymList->at(ax1)[5] < settings->minSymPeak ) && !( lhs1.AlmostEquals ( rhs1 ) ) ) { continue; }
320 
321  for ( proshade_unsign ax2 = 1; ax2 < static_cast<proshade_unsign> ( CSymList->size() ); ax2++ )
322  {
323  //======================================= Use unique pairs only
324  if ( ax1 >= ax2 ) { continue; }
325 
326  //======================================== Ignore small axes
327  const FloatingPoint< proshade_double > lhs2 ( CSymList->at(ax2)[5] ), rhs2 ( -999.9 );
328  if ( ( CSymList->at(ax2)[5] < settings->minSymPeak ) && !( lhs2.AlmostEquals ( rhs2 ) ) ) { continue; }
329 
330  //======================================= Compute the dot product
331  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(ax1)[1], &CSymList->at(ax1)[2],
332  &CSymList->at(ax1)[3], &CSymList->at(ax2)[1],
333  &CSymList->at(ax2)[2], &CSymList->at(ax2)[3] );
334 
335  //======================================== If close to zero, these two axes are perpendicular
336  if ( std::abs( dotProduct ) < settings->axisErrTolerance )
337  {
338  //==================================== Save
339  if ( CSymList->at(ax1)[0] >= CSymList->at(ax2)[0] )
340  {
341  ProSHADE_internal_symmetry::saveDSymmetry ( &ret, CSymList, ax1, ax2 );
342 
343  std::vector< proshade_unsign > DSymInd;
347 
348  }
349  else
350  {
351  ProSHADE_internal_symmetry::saveDSymmetry ( &ret, CSymList, ax2, ax1 );
352 
353  std::vector< proshade_unsign > DSymInd;
357  }
358  }
359  }
360  }
361 
362  //================================================ Report progress
363  std::stringstream hlpSS;
364  hlpSS << "Detected " << ret.size() << " D symmetries.";
365  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 2, hlpSS.str(), settings->messageShift );
366 
367  //================================================ Done
368  return ( ret );
369 
370 }
371 
383 void ProSHADE_internal_symmetry::saveDSymmetry ( std::vector< proshade_double* >* ret, std::vector< proshade_double* >* CSymList, proshade_unsign axisOne, proshade_unsign axisTwo )
384 {
385  //================================================ Allocate the memory
386  proshade_double* hlpP = new proshade_double [14];
387  ProSHADE_internal_misc::checkMemoryAllocation ( hlpP, __FILE__, __LINE__, __func__ );
388 
389  //================================================ Set the axis and heights
390  hlpP[0] = CSymList->at(axisOne)[0];
391  hlpP[1] = CSymList->at(axisOne)[1];
392  hlpP[2] = CSymList->at(axisOne)[2];
393  hlpP[3] = CSymList->at(axisOne)[3];
394  hlpP[4] = CSymList->at(axisOne)[4];
395  hlpP[5] = CSymList->at(axisOne)[5];
396  hlpP[6] = CSymList->at(axisOne)[6];
397  hlpP[7] = CSymList->at(axisTwo)[0];
398  hlpP[8] = CSymList->at(axisTwo)[1];
399  hlpP[9] = CSymList->at(axisTwo)[2];
400  hlpP[10] = CSymList->at(axisTwo)[3];
401  hlpP[11] = CSymList->at(axisTwo)[4];
402  hlpP[12] = CSymList->at(axisTwo)[5];
403  hlpP[13] = CSymList->at(axisTwo)[6];
404 
405  //================================================ Save to ret
407 
408  //================================================ Done
409  return ;
410 
411 }
412 
422 std::vector< proshade_double* > ProSHADE_internal_data::ProSHADE_data::getTetrahedralSymmetriesList ( ProSHADE_settings* settings, std::vector< proshade_double* >* CSymList )
423 {
424  //================================================ Initialise variables
425  std::vector< proshade_double* > ret;
426 
427  //================================================ Report progress
428  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 1, "Starting T symmetry detection.", settings->messageShift );
429 
430  //================================================ Are the basic requirements for tetrahedral symmetry met?
432  {
433  //============================================ Search for all the symmetry axes
434  ProSHADE_internal_symmetry::findTetra4C3s ( CSymList, &ret, settings->axisErrTolerance, this, settings->verbose, settings->messageShift, settings->minSymPeak );
435  if ( ret.size() != 4 ) { ProSHADE_internal_messages::printWarningMessage ( settings->verbose, "!!! ProSHADE WARNING !!! Failed to detect some of the polyhedral symmetries, while detecting the correct dihedral angles.", "WS00031" ); return ( ret ); }
436 
437  ProSHADE_internal_symmetry::findTetra3C2s ( CSymList, &ret, settings->axisErrTolerance, this, settings->verbose, settings->messageShift, settings->minSymPeak );
438  if ( ret.size() != 7 ) { ProSHADE_internal_messages::printWarningMessage ( settings->verbose, "!!! ProSHADE WARNING !!! Failed to detect some of the polyhedral symmetries, while detecting the correct dihedral angles.", "WS00031" ); return ( ret ); }
439  else
440  {
441  for ( proshade_unsign csIt = 0; csIt < static_cast<proshade_unsign> ( CSymList->size() ); csIt++ )
442  {
443  for ( proshade_unsign retIt = 0; retIt < static_cast<proshade_unsign> ( ret.size() ); retIt++ )
444  {
445  //======================================== Sort ret by fold
446  std::sort ( ret.begin(), ret.end(), ProSHADE_internal_misc::sortSymInvFoldHlp );
447 
448  //======================================== Save indices
449  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(csIt)[0] ), rhs1 ( ret.at(retIt)[0] );
450  const FloatingPoint< proshade_double > lhs2 ( CSymList->at(csIt)[1] ), rhs2 ( ret.at(retIt)[1] );
451  const FloatingPoint< proshade_double > lhs3 ( CSymList->at(csIt)[2] ), rhs3 ( ret.at(retIt)[2] );
452  const FloatingPoint< proshade_double > lhs4 ( CSymList->at(csIt)[3] ), rhs4 ( ret.at(retIt)[3] );
453  const FloatingPoint< proshade_double > lhs5 ( CSymList->at(csIt)[4] ), rhs5 ( ret.at(retIt)[4] );
454  const FloatingPoint< proshade_double > lhs6 ( CSymList->at(csIt)[5] ), rhs6 ( ret.at(retIt)[5] );
455  if ( ( lhs1.AlmostEquals ( rhs1 ) ) &&
456  ( lhs2.AlmostEquals ( rhs2 ) ) &&
457  ( lhs3.AlmostEquals ( rhs3 ) ) &&
458  ( lhs4.AlmostEquals ( rhs4 ) ) &&
459  ( lhs5.AlmostEquals ( rhs5 ) ) &&
460  ( lhs6.AlmostEquals ( rhs6 ) ) )
461  {
463  }
464  }
465  }
466  }
467  }
468 
469  //================================================ Report progress
470  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 2, "T symmetry detection complete.", settings->messageShift );
471 
472  //================================================ Done
473  return ( ret );
474 
475 }
476 
488 bool ProSHADE_internal_symmetry::detectTetrahedralSymmetry ( std::vector< proshade_double* >* CSymList, proshade_double axErr, proshade_double minPeakHeight )
489 {
490  //================================================ Initialise variables
491  std::vector< proshade_unsign > C3List;
492  proshade_double dotProduct;
493 
494  //================================================ Find all C3 symmetries
495  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
496  {
497  const FloatingPoint< proshade_double > lhs ( CSymList->at(cSym)[0] ), rhs ( 3.0 );
498  if ( lhs.AlmostEquals ( rhs ) && CSymList->at(cSym)[5] >= minPeakHeight ) { ProSHADE_internal_misc::addToUnsignVector ( &C3List, cSym ); }
499  }
500 
501  //================================================ For each unique pair of C3s
502  for ( proshade_unsign c31 = 0; c31 < static_cast<proshade_unsign> ( C3List.size() ); c31++ )
503  {
504  for ( proshade_unsign c32 = 1; c32 < static_cast<proshade_unsign> ( C3List.size() ); c32++ )
505  {
506  //================================ Unique pairs only
507  if ( c31 >= c32 ) { continue; }
508 
509  //======================================== Check the angle between the C3 axes
510  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(C3List.at(c31))[1], &CSymList->at(C3List.at(c31))[2], &CSymList->at(C3List.at(c31))[3], &CSymList->at(C3List.at(c32))[1], &CSymList->at(C3List.at(c32))[2], &CSymList->at(C3List.at(c32))[3] );
511 
512  //================================ Is the angle approximately the dihedral angle
513  if ( ( ( 1.0 / 3.0 ) > ( dotProduct - axErr ) ) && ( ( 1.0 / 3.0 ) < ( dotProduct + axErr ) ) )
514  {
515  return ( true );
516  }
517  }
518  }
519 
520  //================================================ Done
521  return ( false );
522 
523 }
524 
539 void ProSHADE_internal_symmetry::findTetra4C3s ( std::vector< proshade_double* >* CSymList, std::vector< proshade_double* >* ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data* dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight )
540 {
541  //================================================ Initialise variables
542  std::vector< proshade_unsign > C3PossibilitiesHlp;
543  std::vector< std::vector< proshade_unsign > > C3Possibilities;
544  bool groupMatched;
545 
546  //================================================ Report progress
547  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of four C3 axes.", messageShift );
548 
549  //================================================ For all symmetries in the C symmetries list
550  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
551  {
552  //============================================ Search only using C3s
553  if ( CSymList->at(cIt)[0] != 3.0 || CSymList->at(cIt)[0] < minPeakHeight ) { continue; }
554 
555  //============================================ If this is the first C3, then just save it to the first group of the temporary holder
556  if ( C3Possibilities.size() == 0 ) { ProSHADE_internal_misc::addToUnsignVector ( &C3PossibilitiesHlp, cIt ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C3Possibilities, C3PossibilitiesHlp ); continue; }
557 
558  //============================================ If second or more C3, check if it has the correct angle to all other already found C3s for each group
559  groupMatched = false;
560  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C3Possibilities.size() ); gIt++ )
561  {
562  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, &C3Possibilities.at(gIt), CSymList->at(cIt), axErr, 1.0/3.0, true, cIt ) ) { ProSHADE_internal_misc::addToUnsignVector ( &C3Possibilities.at(gIt), cIt ); groupMatched = true; break; }
563  }
564 
565  //============================================ If no group matched, create a new group
566  if ( !groupMatched ) { C3PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C3PossibilitiesHlp, cIt ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C3Possibilities, C3PossibilitiesHlp ); continue; }
567  }
568 
569  //================================================ Test for missing symmetry axes, if need be
570  ProSHADE_internal_symmetry::findMissingAxes ( &C3Possibilities, CSymList, 4, axErr, 1.0/3.0, 3, dataObj, minPeakHeight );
571 
572  //================================================ Any group has 4 entries? If more such groups, take the one with highest average height.
573  proshade_double maxHeight = 0.0; proshade_unsign maxGrp = 0;
574  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( C3Possibilities.size() ); iter++ ) { if ( C3Possibilities.at(iter).size() == 4 ) { if ( ( ( CSymList->at(C3Possibilities.at(iter).at(0))[5] + CSymList->at(C3Possibilities.at(iter).at(1))[5] + CSymList->at(C3Possibilities.at(iter).at(2))[5] + CSymList->at(C3Possibilities.at(iter).at(3))[5] ) / 4.0 ) > maxHeight ) { maxHeight = ( ( CSymList->at(C3Possibilities.at(iter).at(0))[5] + CSymList->at(C3Possibilities.at(iter).at(1))[5] + CSymList->at(C3Possibilities.at(iter).at(2))[5] + CSymList->at(C3Possibilities.at(iter).at(3))[5] ) / 4.0 ); maxGrp = iter; } } }
575 
576  if ( C3Possibilities.at(maxGrp).size() == 4 )
577  {
578  //============================================ Success! Save and exit
579  for ( proshade_unsign it = 0; it < static_cast<proshade_unsign> ( C3Possibilities.at(maxGrp).size() ); it++ ) { ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(C3Possibilities.at(maxGrp).at(it)) ); }
580 
581  //============================================ Report progress
582  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of four C3 axes successfull.", messageShift );
583 
584  //============================================ Done
585  return ;
586  }
587 
588  //================================================ Done
589  return ;
590 
591 }
592 
609 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 )
610 {
611  //================================================ Initialise variables
612  bool allAnglesMet = true;
613  proshade_double dotProduct;
614 
615  //================================================ Improve if required
616  if ( improve )
617  {
618  for ( proshade_unsign mIt = 0; mIt < static_cast<proshade_unsign> ( grp->size() ); mIt++ )
619  {
620  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(grp->at(mIt))[1], &CSymList->at(grp->at(mIt))[2], &CSymList->at(grp->at(mIt))[3], &sym[1], &sym[2], &sym[3] );
621 
622  if ( ( ( 1.0 > ( dotProduct - axErr ) ) && ( 1.0 < ( dotProduct + axErr ) ) ) || ( ( -1.0 > ( dotProduct - axErr ) ) && ( -1.0 < ( dotProduct + axErr ) ) ) )
623  {
624  if ( sym[5] > CSymList->at(grp->at(mIt))[5] )
625  {
626  grp->at(mIt) = pos;
627  }
628  else
629  {
630  allAnglesMet = false;
631  return ( allAnglesMet );
632  }
633  }
634  }
635  }
636 
637  //================================================ For all group members
638  for ( proshade_unsign mIt = 0; mIt < static_cast<proshade_unsign> ( grp->size() ); mIt++ )
639  {
640  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(grp->at(mIt))[1], &CSymList->at(grp->at(mIt))[2], &CSymList->at(grp->at(mIt))[3], &sym[1], &sym[2], &sym[3] );
641 
642  if ( ( angle > ( std::abs ( dotProduct ) - axErr ) ) &&
643  ( angle < ( std::abs ( dotProduct ) + axErr ) ) )
644  {
645  //======================================== Matching group memner - try next one
646  }
647  else
648  {
649  //======================================== Group member not matched - try next group
650  allAnglesMet = false;
651  break;
652  }
653  }
654 
655  //================================================ Done
656  return ( allAnglesMet );
657 
658 }
659 
676 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 )
677 {
678  //================================================ Initialise variables
679  std::vector< proshade_double* > hlpVec;
680  bool atLeastOne = false;
681 
682  //================================================ Proceed only if need be
683  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( possibilities->size() ); gIt++ )
684  {
685  if ( static_cast<proshade_unsign> ( possibilities->at(gIt).size() ) == requiredNoAxes ) { atLeastOne = true; return ( atLeastOne ); }
686  }
687 
688  //================================================ For each possible group
689  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( possibilities->size() ); gIt++ )
690  {
691  //============================================ This will not work for less than two axes in group
692  if ( possibilities->at(gIt).size() < 2 ) { continue; }
693 
694  //============================================ Prepare iteration
695  hlpVec.clear ( );
696 
697  //============================================ Search for missing axes
698  ProSHADE_internal_symmetry::searchMissingSymmetrySpace ( dataObj, CSymList, &possibilities->at(gIt), &hlpVec, axErr, angle, fold, minPeakHeight );
699 
700  //============================================ Add missing axes
701  if ( hlpVec.size() > 0 )
702  {
703  //======================================== Start adding by highest first
704  std::sort ( hlpVec.begin(), hlpVec.end(), ProSHADE_internal_misc::sortSymHlpInv );
705 
706  //======================================== For each missing axis
707  for ( proshade_unsign axIt = 0; axIt < static_cast<proshade_unsign> ( hlpVec.size() ); axIt++ )
708  {
709  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, &possibilities->at(gIt), hlpVec.at(axIt), axErr, angle, false ) )
710  {
711  //================================ Check for uniqueness
712  if ( ProSHADE_internal_maths::isAxisUnique ( CSymList, hlpVec.at(axIt), axErr ) )
713  {
714  //============================ Add
715  ProSHADE_internal_misc::addToDblPtrVector ( CSymList, hlpVec.at(axIt) );
716  ProSHADE_internal_misc::addToUnsignVector ( &possibilities->at(gIt), static_cast<proshade_unsign> ( CSymList->size()-1 ) );
717  }
718  }
719  }
720  }
721 
722  if ( possibilities->at(gIt).size() == requiredNoAxes ) { atLeastOne = true; }
723  }
724 
725  //================================================ Done
726  return ( atLeastOne );
727 
728 }
729 
736 bool ProSHADE_internal_symmetry::sortArrVecHlp ( const proshade_double* a, const proshade_double* b )
737 {
738  //================================================ Compare
739  return ( a[0] < b[0] );
740 
741 }
742 
757 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 )
758 {
759  //================================================ Initialise variables
760  proshade_double ret = 0.0;
761  proshade_double curSum = 0.0;
762  proshade_double maxVal = 0.0;
763  proshade_double angStep = std::acos ( 1.0 - axErr ) / 2;
764  std::vector< proshade_double* > angVec;
765 
766  //================================================ Find map points conforming to the axis
767  angVec = ProSHADE_internal_symmetry::findMissingAxisPoints ( xVal, yVal, zVal, dataObj, axErr );
768 
769  //================================================ Sort points by angle
770  std::sort ( angVec.begin(), angVec.end(), ProSHADE_internal_symmetry::sortArrVecHlp );
771 
772  //================================================ Find the best X peaks with correct distances
773  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( std::floor ( ( 2.0 * M_PI / angStep ) / static_cast< proshade_double > ( fold ) ) ); iter++ )
774  {
775  //============================================ Initialise new ang group iteration
776  curSum = 0.0;
777 
778  //============================================ For each of the fold times
779  for ( proshade_unsign angCmb = 0; angCmb < static_cast<proshade_unsign> ( fold ); angCmb++ )
780  {
781  //======================================== Initialise
782  maxVal = 0.0;
783 
784  //======================================== Search
785  for ( proshade_unsign angIt = 0; angIt < static_cast<proshade_unsign> ( angVec.size() ); angIt++ )
786  {
787  if ( angVec.at(angIt)[0] < ( ( static_cast< proshade_double > ( iter ) * angStep ) +
788  ( ( 2.0 * M_PI / static_cast< proshade_double > ( fold ) ) * static_cast< proshade_double > ( angCmb ) ) ) ) { continue; }
789  if ( angVec.at(angIt)[0] > ( ( ( static_cast< proshade_double > ( iter ) + 1.0 ) * angStep ) +
790  ( ( 2.0 * M_PI / static_cast< proshade_double > ( fold ) ) * static_cast< proshade_double > ( angCmb ) ) ) ) { break; }
791 
792  if ( angVec.at(angIt)[1] > maxVal ) { maxVal = angVec.at(angIt)[1]; }
793  }
794  curSum += maxVal;
795  }
796  curSum /= static_cast<proshade_double> ( fold );
797  if ( ret < curSum ) { ret = curSum; }
798  }
799 
800  //================================================ Release memory
801  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( angVec.size() ); iter++ ) { delete[] angVec.at(iter); }
802 
803  //================================================ Done
804  return ( ret );
805 
806 }
807 
821 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 )
822 {
823  //================================================ Initialise variables
824  proshade_double euA, euB, euG, xPk, yPk, zPk, anglPk;
825  proshade_double* rotMat = new proshade_double [9];
826  ProSHADE_internal_misc::checkMemoryAllocation ( rotMat, __FILE__, __LINE__, __func__ );
827  proshade_unsign arrIndex;
828  std::vector< proshade_double* > angVec;
829 
830  //================================================ Search the self-rotation map
831  for ( proshade_unsign xIt = 0; xIt < ( dataObj->getMaxBand() * 2 ); xIt++ )
832  {
833  for ( proshade_unsign yIt = 0; yIt < ( dataObj->getMaxBand() * 2 ); yIt++ )
834  {
835  for ( proshade_unsign zIt = 0; zIt < ( dataObj->getMaxBand() * 2 ); zIt++ )
836  {
837  //==================================== Get height and check against threshold
838  arrIndex = zIt + ( dataObj->getMaxBand() * 2 ) * ( yIt + ( dataObj->getMaxBand() * 2 ) * xIt );
839 
840  //==================================== Get angle-axis values
841  ProSHADE_internal_maths::getEulerZXZFromSOFTPosition ( static_cast< proshade_signed > ( dataObj->getMaxBand() ), static_cast< proshade_signed > ( xIt ),
842  static_cast< proshade_signed > ( yIt ), static_cast< proshade_signed > ( zIt ),
843  &euA, &euB, &euG );
845  ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( rotMat, &xPk, &yPk, &zPk, &anglPk );
846 
847  //==================================== Set largest axis element to positive
848  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( xPk ), std::max( std::abs ( yPk ), std::abs ( zPk ) ) ) );
849  const FloatingPoint< proshade_double > rhs1 ( std::abs ( xPk ));
850  const FloatingPoint< proshade_double > rhs2 ( std::abs ( yPk ) );
851  const FloatingPoint< proshade_double > rhs3 ( std::abs ( zPk ) );
852  if ( ( lhs1.AlmostEquals ( rhs1 ) && ( xPk < 0.0 ) ) ||
853  ( lhs1.AlmostEquals ( rhs2 ) && ( yPk < 0.0 ) ) ||
854  ( lhs1.AlmostEquals ( rhs3 ) && ( zPk < 0.0 ) ) )
855  {
856  xPk *= -1.0;
857  yPk *= -1.0;
858  zPk *= -1.0;
859  anglPk *= -1.0;
860  }
861 
862  //==================================== Does the peak match the required axis?
863  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( xPk, yPk, zPk, xVal, yVal, zVal, axErr ) )
864  {
865  //================================ Matching map point - save it
866  proshade_double* hlpArr = new proshade_double [2];
867  ProSHADE_internal_misc::checkMemoryAllocation ( hlpArr, __FILE__, __LINE__, __func__ );
868  hlpArr[0] = anglPk + M_PI;
869  hlpArr[1] = pow( dataObj->getInvSO3Coeffs()[arrIndex][0], 2.0 ) +
870  pow( dataObj->getInvSO3Coeffs()[arrIndex][1], 2.0 );
871  ProSHADE_internal_misc::addToDblPtrVector ( &angVec, hlpArr );
872  }
873  }
874  }
875  }
876 
877  //================================================ Release memory
878  delete[] rotMat;
879 
880  //================================================ Done
881  return ( angVec );
882 
883 }
884 
899 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 )
900 {
901  //================================================ Create symmetry array from the inputs
902  proshade_double* hlpSym = new proshade_double [6];
903  ProSHADE_internal_misc::checkMemoryAllocation ( hlpSym, __FILE__, __LINE__, __func__ );
904 
905  //================================================ Fill it in
906  hlpSym[0] = static_cast<proshade_double> ( fold );
907  hlpSym[1] = axX;
908  hlpSym[2] = axY;
909  hlpSym[3] = axZ;
910  hlpSym[4] = ( 2.0 * M_PI ) / static_cast<proshade_double> ( fold );
911  hlpSym[5] = height;
912 
913  //================================================ Check if similar symmetry does not exist already
914  for ( proshade_unsign symIt = 0; symIt < static_cast<proshade_unsign> ( axVec->size() ); symIt++ )
915  {
916  //============================================ Minor speed-up => only test for same folds
917  const FloatingPoint< proshade_double > lhs1 ( axVec->at(symIt)[0] ), rhs1 ( hlpSym[0] );
918  if ( lhs1.AlmostEquals ( rhs1 ) )
919  {
920  if ( ProSHADE_internal_maths::vectorOrientationSimilarity ( axVec->at(symIt)[1],
921  axVec->at(symIt)[2],
922  axVec->at(symIt)[3],
923  hlpSym[1],
924  hlpSym[2],
925  hlpSym[3],
926  axErr ) )
927  {
928  //==================================== Almost identical entry
929  if ( axVec->at(symIt)[5] < hlpSym[5] )
930  {
931  //================================ If higher, save
932  delete[] axVec->at(symIt);
933  axVec->at(symIt) = hlpSym;
934  return ;
935  }
936  else
937  {
938  //================================ or just terminate if better is already saved
939  delete[] hlpSym;
940  return ;
941  }
942  }
943  }
944  }
945 
946  //================================================ Not matched to anything
948 
949  //================================================ Done
950  return ;
951 
952 }
953 
968 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 )
969 {
970  //================================================ Sanity check
971  if ( grp->size() < 2 ) { return; }
972 
973  //================================================ Initialise variables
974  proshade_double axHeight = 0.0;
975  proshade_double* symHlp = new proshade_double[7];
976  ProSHADE_internal_misc::checkMemoryAllocation ( symHlp, __FILE__, __LINE__, __func__ );
977 
978  //================================================ For each axis pair in the group, find the possible solutions
979  for ( proshade_unsign fAx = 0; fAx < static_cast<proshade_unsign> ( grp->size() ); fAx++ )
980  {
981  for ( proshade_unsign sAx = 1; sAx < static_cast<proshade_unsign> ( grp->size() ); sAx++ )
982  {
983  //======================================== Only unique pairs
984  if ( fAx >= sAx ) { continue; }
985 
986  //======================================== Find possible axis having the required angle to this pair ( solution 1 )
987  std::vector< proshade_double > solVec = ProSHADE_internal_maths::findVectorFromTwoVAndTwoD ( CSymList->at(grp->at(fAx))[1],
988  CSymList->at(grp->at(fAx))[2],
989  CSymList->at(grp->at(fAx))[3],
990  CSymList->at(grp->at(sAx))[1],
991  CSymList->at(grp->at(sAx))[2],
992  CSymList->at(grp->at(sAx))[3], angle, angle );
993 
994  //======================================== Set largest axis element to positive
995  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( solVec.at(0) ), std::max( std::abs ( solVec.at(1) ), std::abs ( solVec.at(2) ) ) ) );
996  const FloatingPoint< proshade_double > rhs1 ( std::abs ( solVec.at(0) ) );
997  const FloatingPoint< proshade_double > rhs2 ( std::abs ( solVec.at(1) ) );
998  const FloatingPoint< proshade_double > rhs3 ( std::abs ( solVec.at(2) ) );
999  if ( ( lhs1.AlmostEquals ( rhs1 ) && ( solVec.at(0) < 0.0 ) ) ||
1000  ( lhs1.AlmostEquals ( rhs2 ) && ( solVec.at(1) < 0.0 ) ) ||
1001  ( lhs1.AlmostEquals ( rhs3 ) && ( solVec.at(2) < 0.0 ) ) )
1002  {
1003  solVec.at(0) *= -1.0;
1004  solVec.at(1) *= -1.0;
1005  solVec.at(2) *= -1.0;
1006  }
1007 
1008  //======================================== Does the solution fit the whole group?
1009  symHlp[1] = solVec.at(0); symHlp[2] = solVec.at(1); symHlp[3] = solVec.at(2); symHlp[6] = -std::numeric_limits < proshade_double >::infinity();
1010  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, grp, symHlp, axErr, angle, true ) )
1011  {
1012  //==================================== Find the height for the axis
1013  axHeight = ProSHADE_internal_symmetry::missingAxisHeight ( solVec.at(0), solVec.at(1), solVec.at(2), dataObj, fold, axErr );
1014 
1015  //================================ Save max height result
1016  if ( axHeight >= minPeakHeight ) { ProSHADE_internal_symmetry::saveMissingAxisNewOnly ( hlpVec, solVec.at(0), solVec.at(1), solVec.at(2), axHeight, fold, axErr ); }
1017  }
1018 
1019  //======================================== Find possible axis having the required angle to this pair ( solution 2 )
1020  solVec = ProSHADE_internal_maths::findVectorFromTwoVAndTwoD ( CSymList->at(grp->at(fAx))[1],
1021  CSymList->at(grp->at(fAx))[2],
1022  CSymList->at(grp->at(fAx))[3],
1023  CSymList->at(grp->at(sAx))[1],
1024  CSymList->at(grp->at(sAx))[2],
1025  CSymList->at(grp->at(sAx))[3], -angle, -angle );
1026 
1027  //======================================== Set largest axis element to positive
1028  const FloatingPoint< proshade_double > lhs2 ( std::max ( std::abs ( solVec.at(0) ), std::max( std::abs ( solVec.at(1) ), std::abs ( solVec.at(2) ) ) ) );
1029  const FloatingPoint< proshade_double > rhs4 ( std::abs ( solVec.at(0) ) );
1030  const FloatingPoint< proshade_double > rhs5 ( std::abs ( solVec.at(1) ) );
1031  const FloatingPoint< proshade_double > rhs6 ( std::abs ( solVec.at(2) ) );
1032  if ( ( lhs2.AlmostEquals ( rhs4 ) && ( solVec.at(0) < 0.0 ) ) ||
1033  ( lhs2.AlmostEquals ( rhs5 ) && ( solVec.at(1) < 0.0 ) ) ||
1034  ( lhs2.AlmostEquals ( rhs6 ) && ( solVec.at(2) < 0.0 ) ) )
1035  {
1036  solVec.at(0) *= -1.0;
1037  solVec.at(1) *= -1.0;
1038  solVec.at(2) *= -1.0;
1039  }
1040 
1041  //======================================== Does the solution fit the whole group?
1042  symHlp[1] = solVec.at(0); symHlp[2] = solVec.at(1); symHlp[3] = solVec.at(2); symHlp[6] = -std::numeric_limits < proshade_double >::infinity();
1043  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, grp, symHlp, axErr, angle, true ) )
1044  {
1045  //==================================== Find the height for the axis
1046  axHeight = ProSHADE_internal_symmetry::missingAxisHeight ( solVec.at(0), solVec.at(1), solVec.at(2), dataObj, fold, axErr );
1047 
1048  //================================ Save max height result
1049  if ( axHeight >= minPeakHeight ) { ProSHADE_internal_symmetry::saveMissingAxisNewOnly ( hlpVec, solVec.at(0), solVec.at(1), solVec.at(2), axHeight, fold, axErr ); }
1050  }
1051  }
1052  }
1053 
1054  //================================================ Release memory
1055  delete[] symHlp;
1056 
1057  //================================================ Done
1058  return ;
1059 
1060 }
1061 
1076 void ProSHADE_internal_symmetry::findTetra3C2s ( std::vector< proshade_double* >* CSymList, std::vector< proshade_double* >* ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data* dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight )
1077 {
1078  //================================================ Initialise variables
1079  std::vector< proshade_unsign > C3s, prospectiveC2s, C2PossibilitiesHlp;
1080  std::vector< std::vector< proshade_unsign > > C2Possibilities;
1081  proshade_double dotProd;
1082  bool groupMatched;
1083  for ( proshade_unsign iter = 0; iter < 4; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &C3s, iter ); }
1084 
1085  //================================================ Report progress
1086  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of three C2 axes.", messageShift );
1087 
1088  //================================================ For each C3
1089  for ( proshade_unsign rIt = 0; rIt < static_cast<proshade_unsign> ( ret->size() ); rIt++ )
1090  {
1091  //============================================ For each C2, check it has angle ( acos(0.5) ) to the tested C3
1092  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
1093  {
1094  //======================================== Search only using C2s
1095  const FloatingPoint< proshade_double > lhs999 ( CSymList->at(cIt)[5] ), rhs999 ( static_cast< proshade_double > ( -999.9 ) );
1096  if ( CSymList->at(cIt)[0] != 2.0 || ( ( CSymList->at(cIt)[5] < minPeakHeight ) && !( lhs999.AlmostEquals( rhs999 ) ) ) ) { continue; }
1097 
1098  //======================================== Check the C2 axis to the C3 ( acos ( 0.5 ) )
1099  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1], &ret->at(rIt)[2], &ret->at(rIt)[3],
1100  &CSymList->at(cIt)[1], &CSymList->at(cIt)[2], &CSymList->at(cIt)[3] );
1101 
1102  if ( ( std::abs ( dotProd ) > ( 0.5 - axErr ) ) && ( std::abs ( dotProd ) < ( 0.5 + axErr ) ) ) { ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC2s, cIt ); }
1103  }
1104  }
1105 
1106  //================================================ Group the prospective C2s
1107  C2Possibilities.clear(); C2PossibilitiesHlp.clear();
1108  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( prospectiveC2s.size() ); cIt++ )
1109  {
1110  //============================================ If second or more C2, check if it can be placed in any group with being perpendicular to all its members
1111  groupMatched = false;
1112  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C2Possibilities.size() ); gIt++ )
1113  {
1114  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, &C2Possibilities.at(gIt), CSymList->at(prospectiveC2s.at(cIt)), axErr, 0.0, true, prospectiveC2s.at(cIt) ) ) { ProSHADE_internal_misc::addToUnsignVector ( &C2Possibilities.at(gIt), prospectiveC2s.at(cIt) ); groupMatched = true; break; }
1115  }
1116 
1117  //============================================ If no group matched, create a new group
1118  if ( !groupMatched ) { C2PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C2PossibilitiesHlp, prospectiveC2s.at(cIt) ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C2Possibilities, C2PossibilitiesHlp ); continue; }
1119  }
1120 
1121  //================================================ Find the best group or return empty
1122  while ( C2Possibilities.size() != 0 )
1123  {
1124  //============================================ Test for missing symmetry axes, if need be
1125  ProSHADE_internal_symmetry::findMissingAxes ( &C2Possibilities, CSymList, 3, axErr, 0.0, 2, dataObj, minPeakHeight );
1126 
1127  //============================================ Found 3 C2s?
1128  if ( C2Possibilities.at(0).size() == 3 )
1129  {
1130  //======================================== Success! Save and exit
1131  for ( proshade_unsign it = 0; it < 3; it++ ) { ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(C2Possibilities.at(0).at(it)) ); }
1132 
1133  //======================================== Report progress
1134  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of three C2 axes successfull.", messageShift );
1135 
1136  //======================================== Done
1137  return ;
1138  }
1139  else { C2Possibilities.erase ( C2Possibilities.begin() ); }
1140  }
1141 
1142  //================================================ Done
1143  return ;
1144 
1145 }
1146 
1161 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 )
1162 {
1163  //================================================ Initialise variables
1164  bool ret = false;
1165  proshade_double dotProduct;
1166 
1167  //================================================ For all pairs of axes
1168  for ( proshade_unsign g1It = 0; g1It < static_cast<proshade_unsign> ( grp1->size() ); g1It++ )
1169  {
1170  for ( proshade_unsign g2It = 0; g2It < static_cast<proshade_unsign> ( grp2->size() ); g2It++ )
1171  {
1172  //======================================== Find the angle
1173  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &GrList1->at(grp1->at(g1It))[1],
1174  &GrList1->at(grp1->at(g1It))[2],
1175  &GrList1->at(grp1->at(g1It))[3],
1176  &GrList2->at(grp2->at(g2It))[1],
1177  &GrList2->at(grp2->at(g2It))[2],
1178  &GrList2->at(grp2->at(g2It))[3] );
1179 
1180  //======================================== Check the angle
1181  if ( ( angle > ( dotProduct - axErr ) ) && ( angle < ( dotProduct + axErr ) ) )
1182  {
1183  ret = true;
1184  return ( ret );
1185  }
1186  }
1187  }
1188 
1189  //================================================ Done
1190  return ( ret );
1191 
1192 }
1193 
1204 std::vector< proshade_double* > ProSHADE_internal_data::ProSHADE_data::getOctahedralSymmetriesList ( ProSHADE_settings* settings, std::vector< proshade_double* >* CSymList )
1205 {
1206  //================================================ Initialise variables
1207  std::vector< proshade_double* > ret;
1208 
1209  //================================================ Report progress
1210  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 1, "Starting O symmetry detection.", settings->messageShift );
1211 
1212  //================================================ Are the basic requirements for tetrahedral symmetry met?
1213  if ( ProSHADE_internal_symmetry::detectOctahedralSymmetry ( CSymList, settings->axisErrTolerance, settings->minSymPeak ) )
1214  {
1215  //============================================ Search for all the symmetry axes
1216  ProSHADE_internal_symmetry::findOcta3C4s ( CSymList, &ret, settings->axisErrTolerance, this, settings->verbose, settings->messageShift, settings->minSymPeak );
1217  if ( ret.size() != 3 ) { ProSHADE_internal_messages::printWarningMessage ( settings->verbose, "!!! ProSHADE WARNING !!! Failed to detect some of the polyhedral symmetries, while detecting the correct dihedral angles.", "WS00031" ); return ( ret ); }
1218 
1219  ProSHADE_internal_symmetry::findOcta4C3s ( CSymList, &ret, settings->axisErrTolerance, this, settings->verbose, settings->messageShift, settings->minSymPeak );
1220  if ( ret.size() != 7 ) { ProSHADE_internal_messages::printWarningMessage ( settings->verbose, "!!! ProSHADE WARNING !!! Failed to detect some of the polyhedral symmetries, while detecting the correct dihedral angles.", "WS00031" ); return ( ret ); }
1221 
1222  ProSHADE_internal_symmetry::findOcta6C2s ( CSymList, &ret, settings->axisErrTolerance, this, settings->verbose, settings->messageShift, settings->minSymPeak );
1223  if ( ret.size() != 13 ) { ProSHADE_internal_messages::printWarningMessage ( settings->verbose, "!!! ProSHADE WARNING !!! Failed to detect some of the polyhedral symmetries, while detecting the correct dihedral angles.", "WS00031" ); return ( ret ); }
1224  else
1225  {
1226  for ( proshade_unsign csIt = 0; csIt < static_cast<proshade_unsign> ( CSymList->size() ); csIt++ )
1227  {
1228  for ( proshade_unsign retIt = 0; retIt < static_cast<proshade_unsign> ( ret.size() ); retIt++ )
1229  {
1230  //======================================== Sort ret by fold
1231  std::sort ( ret.begin(), ret.end(), ProSHADE_internal_misc::sortSymInvFoldHlp );
1232 
1233  //======================================== Save indices
1234  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(csIt)[0] ), rhs1 ( ret.at(retIt)[0] );
1235  const FloatingPoint< proshade_double > lhs2 ( CSymList->at(csIt)[1] ), rhs2 ( ret.at(retIt)[1] );
1236  const FloatingPoint< proshade_double > lhs3 ( CSymList->at(csIt)[2] ), rhs3 ( ret.at(retIt)[2] );
1237  const FloatingPoint< proshade_double > lhs4 ( CSymList->at(csIt)[3] ), rhs4 ( ret.at(retIt)[3] );
1238  const FloatingPoint< proshade_double > lhs5 ( CSymList->at(csIt)[4] ), rhs5 ( ret.at(retIt)[4] );
1239  const FloatingPoint< proshade_double > lhs6 ( CSymList->at(csIt)[5] ), rhs6 ( ret.at(retIt)[5] );
1240  if ( lhs1.AlmostEquals ( rhs1 ) &&
1241  lhs2.AlmostEquals ( rhs2 ) &&
1242  lhs3.AlmostEquals ( rhs3 ) &&
1243  lhs4.AlmostEquals ( rhs4 ) &&
1244  lhs5.AlmostEquals ( rhs5 ) &&
1245  lhs6.AlmostEquals ( rhs6 ) )
1246  {
1248  }
1249  }
1250  }
1251  }
1252  }
1253 
1254  //================================================ Report progress
1255  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 2, "O symmetry detection complete.", settings->messageShift );
1256 
1257  //================================================ Done
1258  return ( ret );
1259 
1260 }
1261 
1273 bool ProSHADE_internal_symmetry::detectOctahedralSymmetry ( std::vector< proshade_double* >* CSymList, proshade_double axErr, proshade_double minPeakHeight )
1274 {
1275  //================================================ Initialise variables
1276  std::vector< proshade_unsign > C4List;
1277  proshade_double dotProduct;
1278 
1279  //================================================ Find all C4 symmetries
1280  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
1281  {
1282  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 4.0 );
1283  if ( lhs1.AlmostEquals ( rhs1 ) && CSymList->at(cSym)[5] >= minPeakHeight ) { ProSHADE_internal_misc::addToUnsignVector ( &C4List, cSym ); }
1284  }
1285 
1286  //================================================ For each unique pair of C3s
1287  for ( proshade_unsign c4 = 0; c4 < static_cast<proshade_unsign> ( C4List.size() ); c4++ )
1288  {
1289  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
1290  {
1291  //======================================== Compare only C3s to the C3List
1292  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 3.0 );
1293  if ( !lhs1.AlmostEquals ( rhs1 ) ) { continue; }
1294 
1295  //======================================== Check the angle between the C4 and C3 axes
1296  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(C4List.at(c4))[1],
1297  &CSymList->at(C4List.at(c4))[2],
1298  &CSymList->at(C4List.at(c4))[3],
1299  &CSymList->at(cSym)[1],
1300  &CSymList->at(cSym)[2],
1301  &CSymList->at(cSym)[3] );
1302 
1303  //======================================== Is the angle approximately the dihedral angle
1304  if ( ( ( 1.0 / sqrt ( 3.0 ) ) > ( dotProduct - axErr ) ) && ( ( 1.0 / sqrt ( 3.0 ) ) < ( dotProduct + axErr ) ) )
1305  {
1306  return ( true );
1307  }
1308  }
1309  }
1310 
1311  //================================================ Done
1312  return ( false );
1313 
1314 }
1315 
1331 void ProSHADE_internal_symmetry::findOcta3C4s ( std::vector< proshade_double* >* CSymList, std::vector< proshade_double* >* ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data* dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight )
1332 {
1333  //================================================ Initialise variables
1334  std::vector< proshade_unsign > C4PossibilitiesHlp;
1335  std::vector< std::vector< proshade_unsign > > C4Possibilities;
1336  bool groupMatched;
1337 
1338  //================================================ Report progress
1339  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of three C4 axes.", messageShift );
1340 
1341  //================================================ For all symmetries in the C symmetries list
1342  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
1343  {
1344  //============================================ Search only using C4s
1345  if ( CSymList->at(cIt)[0] != 4.0 || CSymList->at(cIt)[5] < minPeakHeight ) { continue; }
1346 
1347  //============================================ If second or more C4, check if it has the correct angle to all other already found C4s for each group
1348  groupMatched = false;
1349  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C4Possibilities.size() ); gIt++ )
1350  {
1351  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, &C4Possibilities.at(gIt), CSymList->at(cIt), axErr, 0.0, true, cIt ) ) { ProSHADE_internal_misc::addToUnsignVector ( &C4Possibilities.at(gIt), cIt ); groupMatched = true; break; }
1352  }
1353 
1354  //=========================================== If no group matched, create a new group
1355  if ( !groupMatched ) { C4PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C4PossibilitiesHlp, cIt ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C4Possibilities, C4PossibilitiesHlp ); continue; }
1356  }
1357 
1358  //================================================ Test for missing symmetry axes, if need be
1359  ProSHADE_internal_symmetry::findMissingAxes ( &C4Possibilities, CSymList, 3, axErr, 0.0, 4, dataObj, minPeakHeight );
1360 
1361  //================================================ Any group has 3 entries? If more such groups, take the one with highest average height.
1362  proshade_double maxHeight = 0.0; proshade_unsign maxGrp = 0;
1363  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( C4Possibilities.size() ); iter++ ) { if ( C4Possibilities.at(iter).size() == 3 ) { if ( ( ( CSymList->at(C4Possibilities.at(iter).at(0))[5] + CSymList->at(C4Possibilities.at(iter).at(1))[5] + CSymList->at(C4Possibilities.at(iter).at(2))[5] ) / 3.0 ) > maxHeight ) { maxHeight = ( ( CSymList->at(C4Possibilities.at(iter).at(0))[5] + CSymList->at(C4Possibilities.at(iter).at(1))[5] + CSymList->at(C4Possibilities.at(iter).at(2))[5] ) / 3.0 ); maxGrp = iter; } } }
1364 
1365  if ( C4Possibilities.at(maxGrp).size() == 3 )
1366  {
1367  //============================================ Success! Save and exit
1368  for ( proshade_unsign it = 0; it < static_cast<proshade_unsign> ( C4Possibilities.at(maxGrp).size() ); it++ ) { ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(C4Possibilities.at(maxGrp).at(it)) ); }
1369 
1370  //============================================ Report progress
1371  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of three C4 axes successfull.", messageShift );
1372 
1373  //============================================ Done
1374  return ;
1375  }
1376 
1377  //================================================ Done
1378  return ;
1379 
1380 }
1381 
1398 void ProSHADE_internal_symmetry::findOcta4C3s ( std::vector< proshade_double* >* CSymList, std::vector< proshade_double* >* ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data* dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight )
1399 {
1400  //================================================ Initialise variables
1401  std::vector< proshade_unsign > C4s, prospectiveC3s, C3PossibilitiesHlp;
1402  std::vector< std::vector< proshade_unsign > > C3Possibilities;
1403  proshade_double dotProd;
1404  bool groupMatched;
1405  for ( proshade_unsign iter = 0; iter < 3; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &C4s, iter ); }
1406 
1407  //================================================ Report progress
1408  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of four C3 axes.", messageShift );
1409 
1410  //================================================ For each C4
1411  for ( proshade_unsign rIt = 0; rIt < static_cast<proshade_unsign> ( ret->size() ); rIt++ )
1412  {
1413  //============================================ For each C3, check it has angle ( acos( 1/sqrt(3) ) ) to the tested C4
1414  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
1415  {
1416  //======================================== Search only using C3s
1417  if ( CSymList->at(cIt)[0] != 3.0 || CSymList->at(cIt)[5] < minPeakHeight ) { continue; }
1418 
1419  //======================================== Check the C3 axis to the C4 ( acos ( 1/sqrt(3) ) )
1420  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1], &ret->at(rIt)[2], &ret->at(rIt)[3], &CSymList->at(cIt)[1], &CSymList->at(cIt)[2], &CSymList->at(cIt)[3] );
1421 
1422  if ( ( std::abs ( dotProd ) > ( ( 1.0 / sqrt(3.0) ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( 1.0 / sqrt(3.0) ) + axErr ) ) ) { ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC3s, cIt ); }
1423  }
1424  }
1425 
1426  //================================================ Group the prospective C3s
1427  C3Possibilities.clear(); C3PossibilitiesHlp.clear();
1428  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( prospectiveC3s.size() ); cIt++ )
1429  {
1430  //============================================ If second or more C3, check if it can be placed in any group with having acos (1/3) to all its members
1431  groupMatched = false;
1432  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C3Possibilities.size() ); gIt++ )
1433  {
1434  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, &C3Possibilities.at(gIt), CSymList->at(prospectiveC3s.at(cIt)), axErr, 1.0/3.0, true, prospectiveC3s.at(cIt) ) ) { ProSHADE_internal_misc::addToUnsignVector ( &C3Possibilities.at(gIt), prospectiveC3s.at(cIt) ); groupMatched = true; break; }
1435  }
1436 
1437  //============================================ If no group matched, create a new group
1438  if ( !groupMatched ) { C3PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C3PossibilitiesHlp, prospectiveC3s.at(cIt) ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C3Possibilities, C3PossibilitiesHlp ); continue; }
1439  }
1440 
1441  //================================================ Find the best group or return empty
1442  while ( C3Possibilities.size() != 0 )
1443  {
1444  //============================================ Test for missing symmetry axes, if need be
1445  ProSHADE_internal_symmetry::findMissingAxes ( &C3Possibilities, CSymList, 4, axErr, 1.0/3.0, 3, dataObj, minPeakHeight );
1446 
1447  //============================================ Found four C3s?
1448  if ( C3Possibilities.at(0).size() == 4 )
1449  {
1450  //======================================== Success! Save and exit
1451  for ( proshade_unsign it = 0; it < 4; it++ ) { ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(C3Possibilities.at(0).at(it)) ); }
1452 
1453  //======================================== Report progress
1454  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of four C3 axes successfull.", messageShift );
1455 
1456  //======================================== Done
1457  return ;
1458  }
1459  else { C3Possibilities.erase ( C3Possibilities.begin() ); }
1460  }
1461 
1462  //================================================ Done
1463  return ;
1464 
1465 }
1466 
1481 void ProSHADE_internal_symmetry::findOcta6C2s ( std::vector< proshade_double* >* CSymList, std::vector< proshade_double* >* ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data* dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight )
1482 {
1483  //================================================ Initialise variables
1484  std::vector< proshade_unsign > prospectiveC2s, retGrp;
1485  proshade_double dotProd;
1486  proshade_unsign noPerpendicular, noSqrtTwo;
1487 
1488  //================================================ Report progress
1489  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of six C2 axes.", messageShift );
1490 
1491  //================================================ For each C2
1492  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
1493  {
1494  //============================================ Use only C2s
1495  const FloatingPoint< proshade_double > lhs999 ( CSymList->at(cIt)[5] ), rhs999 ( static_cast< proshade_double > ( -999.9 ) );
1496  if ( CSymList->at(cIt)[0] != 2.0 || ( ( CSymList->at(cIt)[5] < minPeakHeight ) && ! ( lhs999.AlmostEquals( rhs999 ) ) ) ) { continue; }
1497 
1498  //============================================ Check the C2 has acos ( 1/sqrt(2) ) to 2 C4s and acos ( 0.0 ) to the third C4
1499  noPerpendicular = 0; noSqrtTwo = 0;
1500  for ( proshade_unsign rIt = 0; rIt < 3; rIt++ )
1501  {
1502  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1],
1503  &ret->at(rIt)[2],
1504  &ret->at(rIt)[3],
1505  &CSymList->at(cIt)[1],
1506  &CSymList->at(cIt)[2],
1507  &CSymList->at(cIt)[3] );
1508 
1509  if ( ( std::abs ( dotProd ) > ( ( 1.0 / sqrt(2.0) ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( 1.0 / sqrt(2.0) ) + axErr ) ) ) { noSqrtTwo += 1; continue; }
1510  if ( ( std::abs ( dotProd ) > ( 0.0 - axErr ) ) && ( std::abs ( dotProd ) < ( 0.0 + axErr ) ) ) { noPerpendicular += 1; continue; }
1511  }
1512 
1513  //============================================ If correct angles distribution is found, save the axis
1514  if ( ( noSqrtTwo == 2 ) && ( noPerpendicular == 1 ) )
1515  {
1516  ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC2s, cIt );
1517  }
1518  }
1519 
1520  //================================================ Search for missing axes
1521  for ( proshade_unsign iter = 0; iter < 3; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &retGrp, iter ); }
1522  if ( !ProSHADE_internal_symmetry::findMissingAxesDual ( &prospectiveC2s, CSymList, ret, &retGrp, 6, axErr, 1, 0.0, 2, 1/sqrt(2.0), 2, dataObj ) )
1523  {
1524  return ;
1525  }
1526 
1527  //================================================ Found correct number of axes! Now save the
1528  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( prospectiveC2s.size() ); iter++ )
1529  {
1530  ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(prospectiveC2s.at(iter)) );
1531  }
1532 
1533  //================================================ Report progress
1534  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of six C2 axes successfull.", messageShift );
1535 
1536  //================================================ Done
1537  return ;
1538 
1539 }
1540 
1562 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 )
1563 {
1564  //================================================ Initialise variables
1565  bool atLeastOne = false;
1566  std::vector< proshade_double* > prosp;
1567  std::vector< proshade_double > sol;
1568 
1569  //================================================ Proceed only if need be
1570  if ( static_cast<proshade_unsign> ( possibilities->size() ) == requiredNoAxes ) { atLeastOne = true; return ( atLeastOne ); }
1571 
1572  //================================================ Copy already found to prospective
1573  for ( proshade_unsign prIt = 0; prIt < static_cast<proshade_unsign> ( possibilities->size() ); prIt++ )
1574  {
1575  ProSHADE_internal_symmetry::addAxisUnlessSame ( static_cast< proshade_unsign > ( CSymList->at(possibilities->at(prIt))[0] ),
1576  CSymList->at(possibilities->at(prIt))[1],
1577  CSymList->at(possibilities->at(prIt))[2],
1578  CSymList->at(possibilities->at(prIt))[3],
1579  CSymList->at(possibilities->at(prIt))[5], &prosp, axErr );
1580  }
1581 
1582  //================================================ Start generating possible solutions
1583  for ( proshade_unsign rgIt1 = 0; rgIt1 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt1++ )
1584  {
1585  for ( proshade_unsign rgIt2 = 0; rgIt2 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt2++ )
1586  {
1587  //======================================== Use unique combinations (order matters here!)
1588  if ( rgIt1 == rgIt2 ) { continue; }
1589 
1590  //======================================== Generate possible solution (1)
1591  sol = ProSHADE_internal_maths::findVectorFromTwoVAndTwoD ( ret->at(rgIt1)[1], ret->at(rgIt1)[2], ret->at(rgIt1)[3],
1592  ret->at(rgIt2)[1], ret->at(rgIt2)[2], ret->at(rgIt2)[3], angle1, angle2 );
1593 
1594  //======================================== Check if solution fits the group completely
1595  ProSHADE_internal_symmetry::checkFittingAxisDualAndSave ( retGroup, ret, fold, sol.at(0), sol.at(1), sol.at(2), &prosp, axErr, noMatchesG1, angle1, noMatchesG2, angle2, dataObj );
1596  if ( prosp.size() == requiredNoAxes ) { break; }
1597 
1598  //======================================== Generate possible solution (2)
1599  sol = ProSHADE_internal_maths::findVectorFromTwoVAndTwoD ( ret->at(rgIt1)[1], ret->at(rgIt1)[2], ret->at(rgIt1)[3],
1600  ret->at(rgIt2)[1], ret->at(rgIt2)[2], ret->at(rgIt2)[3], -angle1, -angle2 );
1601 
1602  //======================================== Check if solution fits the group completely
1603  ProSHADE_internal_symmetry::checkFittingAxisDualAndSave ( retGroup, ret, fold, sol.at(0), sol.at(1), sol.at(2), &prosp, axErr, noMatchesG1, angle1, noMatchesG2, angle2, dataObj );
1604  if ( prosp.size() == requiredNoAxes ) { break; }
1605  }
1606 
1607  if ( prosp.size() == requiredNoAxes ) { break; }
1608  }
1609 
1610  //================================================ Found all required axes!
1611  if ( static_cast<proshade_unsign> ( prosp.size() ) == requiredNoAxes )
1612  {
1613  //============================================ Copy the detected axes
1614  for ( proshade_unsign iter = static_cast<proshade_unsign> ( possibilities->size() ); iter < static_cast<proshade_unsign> ( prosp.size() ); iter++ )
1615  {
1616  if ( ProSHADE_internal_maths::isAxisUnique ( CSymList, prosp.at(iter), axErr ) )
1617  {
1618  //==================================== Add
1619  ProSHADE_internal_misc::addToUnsignVector ( possibilities, static_cast< proshade_unsign > ( CSymList->size() ) );
1620  ProSHADE_internal_misc::addToDblPtrVector ( CSymList, prosp.at(iter) );
1621  }
1622  }
1623 
1624  //============================================ Done
1625  atLeastOne = true;
1626  return ( atLeastOne );
1627  }
1628  else
1629  {
1630  //============================================ Delete the created, but not used axes
1631  for ( proshade_unsign iter = static_cast<proshade_unsign> ( possibilities->size() ); iter < static_cast<proshade_unsign> ( prosp.size() ); iter++ )
1632  {
1633  delete[] prosp.at(iter);
1634  }
1635  }
1636 
1637  //================================================ Done
1638  return ( atLeastOne );
1639 
1640 }
1641 
1657 proshade_signed ProSHADE_internal_symmetry::addAxisUnlessSame ( proshade_unsign fold, proshade_double axX, proshade_double axY, proshade_double axZ, proshade_double axHeight, proshade_double averageFSC, std::vector< proshade_double* >* prosp, proshade_double axErr )
1658 {
1659  //================================================ Initialise variables
1660  proshade_double* symHlp = new proshade_double[7];
1661  ProSHADE_internal_misc::checkMemoryAllocation ( symHlp, __FILE__, __LINE__, __func__ );
1662  proshade_signed ret = -1;
1663 
1664  //================================================ Fill in the prospective axis
1665  symHlp[0] = static_cast<proshade_double> ( fold );
1666  symHlp[1] = axX;
1667  symHlp[2] = axY;
1668  symHlp[3] = axZ;
1669  symHlp[4] = 2.0 * M_PI / symHlp[0];
1670  symHlp[5] = axHeight;
1671  symHlp[6] = averageFSC;
1672 
1673  //================================================ If it is not the same as already saved axes
1674  if ( !ProSHADE_internal_symmetry::isSymmetrySame ( prosp, symHlp, axErr, &ret, averageFSC ) )
1675  {
1677  return ( static_cast< proshade_signed > ( prosp->size() - 1 ) );
1678  }
1679  else
1680  {
1681  delete[] symHlp;
1682  return ( ret );
1683  }
1684 
1685  //================================================ Done
1686 
1687 }
1688 
1703 proshade_signed ProSHADE_internal_symmetry::addAxisUnlessSame ( proshade_unsign fold, proshade_double axX, proshade_double axY, proshade_double axZ, proshade_double axHeight, std::vector< proshade_double* >* prosp, proshade_double axErr )
1704 {
1705  //================================================ Initialise variables
1706  proshade_double* symHlp = new proshade_double[7];
1707  ProSHADE_internal_misc::checkMemoryAllocation ( symHlp, __FILE__, __LINE__, __func__ );
1708  proshade_signed ret = -1;
1709 
1710  //================================================ Fill in the prospective axis
1711  symHlp[0] = static_cast<proshade_double> ( fold );
1712  symHlp[1] = axX;
1713  symHlp[2] = axY;
1714  symHlp[3] = axZ;
1715  symHlp[4] = 2.0 * M_PI / symHlp[0];
1716  symHlp[5] = axHeight;
1717  symHlp[6] = -std::numeric_limits < proshade_double >::infinity();
1718 
1719  //================================================ If it is not the same as already saved axes
1720  if ( !ProSHADE_internal_symmetry::isSymmetrySame ( prosp, symHlp, axErr, &ret ) )
1721  {
1723  return ( static_cast< proshade_signed > ( prosp->size() - 1 ) );
1724  }
1725  else
1726  {
1727  delete[] symHlp;
1728  return ( ret );
1729  }
1730 
1731  //================================================ Done
1732 
1733 }
1734 
1756 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 )
1757 {
1758  //================================================ Initialise variables
1759  proshade_unsign noG1 = 0;
1760  proshade_unsign noG2 = 0;
1761  proshade_double dotProd = 0.0;
1762  proshade_double axHeight = 0.0;
1763 
1764  //================================================ Find the angle and count dual matching frequencies
1765  for ( proshade_unsign rIt = 0; rIt < static_cast<proshade_unsign> ( retGroup->size() ); rIt++ )
1766  {
1767  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(retGroup->at(rIt))[1],
1768  &ret->at(retGroup->at(rIt))[2],
1769  &ret->at(retGroup->at(rIt))[3],
1770  &axX, &axY, &axZ );
1771 
1772  if ( ( std::abs ( dotProd ) > ( angle1 - axErr ) ) && ( std::abs ( dotProd ) < ( angle1 + axErr ) ) ) { noG1 += 1; continue; }
1773  if ( ( std::abs ( dotProd ) > ( angle2 - axErr ) ) && ( std::abs ( dotProd ) < ( angle2 + axErr ) ) ) { noG2 += 1; continue; }
1774  }
1775 
1776  //================================================ If correct frequencies are matched, check height.
1777  if ( ( noG1 == noMatchesG1 ) && ( noG2 == noMatchesG2 ) )
1778  {
1779  //============================================ Is the height good enough?
1780  axHeight = ProSHADE_internal_symmetry::missingAxisHeight ( axX, axY, axZ, dataObj, fold, axErr );
1781 
1782  //============================================ If so, save
1783  if ( axHeight > 0.1 )
1784  {
1785  proshade_unsign prevProsp = static_cast<proshade_unsign> ( prosp->size() );
1786  ProSHADE_internal_symmetry::addAxisUnlessSame ( fold, axX, axY, axZ, axHeight, prosp, axErr );
1787 
1788  if ( static_cast<proshade_unsign> ( prosp->size() ) > prevProsp ) { return ( true ); }
1789  else { return ( false ); }
1790  }
1791  }
1792 
1793  //================================================ Done
1794  return ( false );
1795 
1796 }
1797 
1808 std::vector< proshade_double* > ProSHADE_internal_data::ProSHADE_data::getIcosahedralSymmetriesList ( ProSHADE_settings* settings, std::vector< proshade_double* >* CSymList )
1809 {
1810  //================================================ Initialise variables
1811  std::vector< proshade_double* > ret;
1812 
1813  //================================================ Report progress
1814  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 1, "Starting I symmetry detection.", settings->messageShift );
1815 
1816  //================================================ Are the basic requirements for icosahedral symmetry met?
1818  {
1819  //============================================ Search for all the symmetry axes
1820  ProSHADE_internal_symmetry::findIcos6C5s ( CSymList, &ret, settings->axisErrTolerance, this, settings->verbose, settings->messageShift, settings->minSymPeak );
1821  if ( ret.size() != 6 ) { ProSHADE_internal_messages::printWarningMessage ( settings->verbose, "!!! ProSHADE WARNING !!! Failed to detect some of the polyhedral symmetries, while detecting the correct dihedral angles.", "WS00031" ); return ( ret ); }
1822 
1823  ProSHADE_internal_symmetry::findIcos10C3s ( CSymList, &ret, settings->axisErrTolerance, this, settings->verbose, settings->messageShift, settings->minSymPeak );
1824  if ( ret.size() != 16 ) { ProSHADE_internal_messages::printWarningMessage ( settings->verbose, "!!! ProSHADE WARNING !!! Failed to detect some of the polyhedral symmetries, while detecting the correct dihedral angles.", "WS00031" ); return ( ret ); }
1825 
1826  ProSHADE_internal_symmetry::findIcos15C2s ( CSymList, &ret, settings->axisErrTolerance, this, settings->verbose, settings->messageShift, settings->minSymPeak );
1827  if ( ret.size() != 31 ) { ProSHADE_internal_messages::printWarningMessage ( settings->verbose, "!!! ProSHADE WARNING !!! Failed to detect some of the polyhedral symmetries, while detecting the correct dihedral angles.", "WS00031" ); return ( ret ); }
1828  else
1829  {
1830  //======================================== Sort ret by fold
1831  std::sort ( ret.begin(), ret.end(), ProSHADE_internal_misc::sortSymInvFoldHlp );
1832 
1833  //======================================== Save indices
1834  for ( proshade_unsign csIt = 0; csIt < static_cast<proshade_unsign> ( CSymList->size() ); csIt++ )
1835  {
1836  for ( proshade_unsign retIt = 0; retIt < static_cast<proshade_unsign> ( ret.size() ); retIt++ )
1837  {
1838  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(csIt)[0] ), rhs1 ( ret.at(retIt)[0] );
1839  const FloatingPoint< proshade_double > lhs2 ( CSymList->at(csIt)[1] ), rhs2 ( ret.at(retIt)[1] );
1840  const FloatingPoint< proshade_double > lhs3 ( CSymList->at(csIt)[2] ), rhs3 ( ret.at(retIt)[2] );
1841  const FloatingPoint< proshade_double > lhs4 ( CSymList->at(csIt)[3] ), rhs4 ( ret.at(retIt)[3] );
1842  const FloatingPoint< proshade_double > lhs5 ( CSymList->at(csIt)[4] ), rhs5 ( ret.at(retIt)[4] );
1843  const FloatingPoint< proshade_double > lhs6 ( CSymList->at(csIt)[5] ), rhs6 ( ret.at(retIt)[5] );
1844  if ( lhs1.AlmostEquals ( rhs1 ) &&
1845  lhs2.AlmostEquals ( rhs2 ) &&
1846  lhs3.AlmostEquals ( rhs3 ) &&
1847  lhs4.AlmostEquals ( rhs4 ) &&
1848  lhs5.AlmostEquals ( rhs5 ) &&
1849  lhs6.AlmostEquals ( rhs6 ) )
1850  {
1852  }
1853  }
1854  }
1855  }
1856  }
1857 
1858  //================================================ Report progress
1859  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 2, "I symmetry detection complete.", settings->messageShift );
1860 
1861  //================================================ Done
1862  return ( ret );
1863 
1864 }
1865 
1880 std::vector < std::vector< proshade_double* > > ProSHADE_internal_data::ProSHADE_data::getPredictedIcosahedralSymmetriesList ( ProSHADE_settings* settings, std::vector< proshade_double* >* CSymList )
1881 {
1882  //================================================ Initialise variables
1883  std::vector< std::vector< proshade_double* > > ret;
1884 
1885  //================================================ Report progress
1886  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 1, "Starting I symmetry prediction.", settings->messageShift );
1887 
1888  //================================================ Are the basic requirements for icosahedral symmetry met?
1890  {
1891  //============================================ Generate the rest of the axes
1892  ProSHADE_internal_symmetry::predictIcosAxes ( CSymList, &ret, settings->axisErrTolerance, settings->minSymPeak );
1893 
1894  //============================================ For each possible axes pair
1895  for ( size_t pIt = 0; pIt < ret.size(); pIt++ )
1896  {
1897  //======================================== Get heights for the predicted axes
1898  ProSHADE_internal_symmetry::findPredictedAxesHeights ( &(ret.at(pIt)), this, settings );
1899  }
1900  }
1901 
1902  //================================================ Sort by best peak height sum
1903  std::sort ( ret.begin(), ret.end(), ProSHADE_internal_misc::sortISymByPeak );
1904 
1905  //================================================ Report progress
1906  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 2, "I symmetry prediction complete.", settings->messageShift );
1907 
1908  //================================================ Done
1909  return ( ret );
1910 
1911 }
1912 
1927 std::vector< proshade_double* > ProSHADE_internal_data::ProSHADE_data::getPredictedOctahedralSymmetriesList ( ProSHADE_settings* settings, std::vector< proshade_double* >* CSymList )
1928 {
1929  //================================================ Initialise variables
1930  std::vector< proshade_double* > ret;
1931 
1932  //================================================ Report progress
1933  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 1, "Starting O symmetry prediction.", settings->messageShift );
1934 
1935  //================================================ Are the basic requirements for icosahedral symmetry met?
1936  if ( ProSHADE_internal_symmetry::detectOctahedralSymmetry ( CSymList, settings->axisErrTolerance, settings->minSymPeak ) )
1937  {
1938  //============================================ Generate the rest of the axes
1939  ProSHADE_internal_symmetry::predictOctaAxes ( CSymList, &ret, settings->axisErrTolerance, settings->minSymPeak );
1940 
1941  //============================================ Get heights for the predicted axes
1943 
1944  //============================================ Add predicted axes to detected C axes list and also to the settings Icosahedral symmetry list
1945  for ( proshade_unsign retIt = 0; retIt < static_cast < proshade_unsign > ( ret.size() ); retIt++ )
1946  {
1947  proshade_signed matchedPos = ProSHADE_internal_symmetry::addAxisUnlessSame ( static_cast< proshade_unsign > ( ret.at(retIt)[0] ), ret.at(retIt)[1], ret.at(retIt)[2], ret.at(retIt)[3], ret.at(retIt)[5], CSymList, settings->axisErrTolerance );
1948  ProSHADE_internal_misc::addToUnsignVector ( &settings->allDetectedOAxes, static_cast < proshade_unsign > ( matchedPos ) );
1949  }
1950  }
1951 
1952  //================================================ Report progress
1953  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 2, "O symmetry prediction complete.", settings->messageShift );
1954 
1955  //================================================ Done
1956  return ( ret );
1957 
1958 }
1959 
1971 bool ProSHADE_internal_symmetry::detectIcosahedralSymmetry ( std::vector< proshade_double* >* CSymList, proshade_double axErr, proshade_double minPeakHeight )
1972 {
1973  //================================================ Initialise variables
1974  std::vector< proshade_unsign > C5List;
1975  proshade_double dotProduct;
1976 
1977  //================================================ Find all C5 symmetries
1978  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
1979  {
1980  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 5.0 );
1981  if ( lhs1.AlmostEquals ( rhs1 ) && CSymList->at(cSym)[5] >= minPeakHeight ) { ProSHADE_internal_misc::addToUnsignVector ( &C5List, cSym ); }
1982  }
1983 
1984  //================================================ For each unique pair of C5 and C3
1985  for ( proshade_unsign c5 = 0; c5 < static_cast<proshade_unsign> ( C5List.size() ); c5++ )
1986  {
1987  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
1988  {
1989  //======================================== Compare only C3s to the C5List
1990  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 3.0 );
1991  if ( !lhs1.AlmostEquals ( rhs1 ) ) { continue; }
1992 
1993  //======================================== Check the angle between the C5 and C3 axes
1994  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(C5List.at(c5))[1],
1995  &CSymList->at(C5List.at(c5))[2],
1996  &CSymList->at(C5List.at(c5))[3],
1997  &CSymList->at(cSym)[1],
1998  &CSymList->at(cSym)[2],
1999  &CSymList->at(cSym)[3] );
2000 
2001  //======================================== Is the angle approximately the dihedral angle
2002  if ( std::abs ( std::abs( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ) - std::abs( dotProduct ) ) < axErr )
2003  {
2004  return ( true );
2005  }
2006  }
2007  }
2008 
2009  //================================================ Done
2010  return ( false );
2011 
2012 }
2013 
2032 void ProSHADE_internal_symmetry::findIcos6C5s ( std::vector< proshade_double* >* CSymList, std::vector< proshade_double* >* ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data* dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight )
2033 {
2034  //================================================ Initialise variables
2035  std::vector< proshade_unsign > C5PossibilitiesHlp;
2036  std::vector< std::vector< proshade_unsign > > C5Possibilities;
2037  bool groupMatched;
2038 
2039  //================================================ Report progress
2040  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of six C5 axes.", messageShift );
2041 
2042  //================================================ For all symmetries in the C symmetries list
2043  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
2044  {
2045  //============================================ Search only using C5s and check peak height
2046  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cIt)[0] ), rhs1 ( 5.0 );
2047  if ( !lhs1.AlmostEquals ( rhs1 ) || CSymList->at(cIt)[5] < minPeakHeight ) { continue; }
2048 
2049  //============================================ If second or more C5, check if it has the correct angle to all other already found C5s for each group
2050  groupMatched = false;
2051  for ( proshade_unsign gIt = 0; gIt < static_cast<proshade_unsign> ( C5Possibilities.size() ); gIt++ )
2052  {
2053  if ( ProSHADE_internal_symmetry::testGroupAgainstSymmetry ( CSymList, &C5Possibilities.at(gIt), CSymList->at(cIt), axErr, 1.0/2.0, true, cIt ) ) { ProSHADE_internal_misc::addToUnsignVector ( &C5Possibilities.at(gIt), cIt ); groupMatched = true; break; }
2054  }
2055 
2056  //============================================ If no group matched, create a new group
2057  if ( !groupMatched ) { C5PossibilitiesHlp.clear(); ProSHADE_internal_misc::addToUnsignVector ( &C5PossibilitiesHlp, cIt ); ProSHADE_internal_misc::addToUnsignVectorVector ( &C5Possibilities, C5PossibilitiesHlp ); continue; }
2058  }
2059 
2060  //================================================ Test for missing symmetry axes, if need be
2061  ProSHADE_internal_symmetry::findMissingAxes ( &C5Possibilities, CSymList, 6, axErr, 1.0 / 2.0, 5, dataObj, minPeakHeight );
2062 
2063  //=================================================Any group has 6 entries? If more such groups, take the one with highest average height.
2064  proshade_double maxHeight = 0.0; proshade_unsign maxGrp = 0;
2065  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( C5Possibilities.size() ); iter++ ) { if ( C5Possibilities.at(iter).size() == 6 ) { if ( ( ( CSymList->at(C5Possibilities.at(iter).at(0))[5] + CSymList->at(C5Possibilities.at(iter).at(1))[5] + CSymList->at(C5Possibilities.at(iter).at(2))[5] + CSymList->at(C5Possibilities.at(iter).at(3))[5] + CSymList->at(C5Possibilities.at(iter).at(4))[5] + CSymList->at(C5Possibilities.at(iter).at(5))[5] ) / 6.0 ) > maxHeight ) { maxHeight = ( ( CSymList->at(C5Possibilities.at(iter).at(0))[5] + CSymList->at(C5Possibilities.at(iter).at(1))[5] + CSymList->at(C5Possibilities.at(iter).at(2))[5] + CSymList->at(C5Possibilities.at(iter).at(3))[5] + CSymList->at(C5Possibilities.at(iter).at(4))[5] + CSymList->at(C5Possibilities.at(iter).at(5))[5] ) / 6.0 ); maxGrp = iter; } } }
2066 
2067  if ( C5Possibilities.at(maxGrp).size() == 6 )
2068  {
2069  //============================================ Success! Save and exit
2070  for ( proshade_unsign it = 0; it < static_cast<proshade_unsign> ( C5Possibilities.at(maxGrp).size() ); it++ ) { ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(C5Possibilities.at(maxGrp).at(it)) ); }
2071 
2072  //============================================ Report progress
2073  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of six C5 axes successfull.", messageShift );
2074 
2075  //============================================ Done
2076  return ;
2077  }
2078 
2079  //================================================ Done
2080  return ;
2081 
2082 }
2083 
2091 std::vector < std::pair< proshade_unsign, proshade_unsign > > findBestIcosDihedralPair ( std::vector< proshade_double* >* CSymList, proshade_double minPeakHeight, proshade_double axErr )
2092 {
2093  //================================================ Initialise variables
2094  std::vector < std::pair< proshade_unsign, proshade_unsign > > ret;
2095  std::vector< proshade_unsign > C5List;
2096  proshade_double dotProduct;
2097 
2098  //================================================ Find all C5 symmetries
2099  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ ) { const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 5.0 ); if ( lhs1.AlmostEquals ( rhs1 ) && CSymList->at(cSym)[5] >= minPeakHeight ) { ProSHADE_internal_misc::addToUnsignVector ( &C5List, cSym ); } }
2100 
2101  //================================================ For each unique pair of C5 and C3
2102  for ( proshade_unsign c5 = 0; c5 < static_cast<proshade_unsign> ( C5List.size() ); c5++ )
2103  {
2104  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
2105  {
2106  //======================================== Compare only C3s to the C5List and only with decent average peak height
2107  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 3.0 );
2108  if ( !lhs1.AlmostEquals ( rhs1 ) ) { continue; }
2109  if ( CSymList->at(cSym)[5] < minPeakHeight ) { continue; }
2110 
2111  //======================================== Check the angle between the C5 and C3 axes
2112  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(C5List.at(c5))[1],
2113  &CSymList->at(C5List.at(c5))[2],
2114  &CSymList->at(C5List.at(c5))[3],
2115  &CSymList->at(cSym)[1],
2116  &CSymList->at(cSym)[2],
2117  &CSymList->at(cSym)[3] );
2118 
2119  //======================================== Is the angle approximately the dihedral angle?
2120  if ( std::abs ( std::abs( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ) - std::abs( dotProduct ) ) < axErr )
2121  {
2122  std::pair< proshade_unsign, proshade_unsign > hlp;
2123  hlp.first = C5List.at(c5);
2124  hlp.second = cSym;
2125  ret.emplace_back ( hlp );
2126  }
2127  }
2128  }
2129 
2130  //================================================ Done
2131  return ( ret );
2132 }
2133 
2154 void ProSHADE_internal_symmetry::predictIcosAxes ( std::vector< proshade_double* >* CSymList, std::vector< std::vector< proshade_double* > >* ret, proshade_double axErr, proshade_double minPeakHeight )
2155 {
2156  //================================================ Find the best axis combination with dihedral angle and correct folds
2157  std::vector < std::pair< proshade_unsign, proshade_unsign > > initAxes = findBestIcosDihedralPair ( CSymList, minPeakHeight, axErr );
2158 
2159  //================================================ For each pair of possible axis combinations
2160  for ( size_t pIt = 0; pIt < initAxes.size(); pIt++ )
2161  {
2162  //============================================ Create the tetrahedronAxes object
2164 
2165  //============================================ Find rotation between the detected C5 and the model C5 axes.
2166  proshade_double* rotMat = ProSHADE_internal_maths::findRotMatMatchingVectors ( icoAx->getValue ( 0, 1 ),
2167  icoAx->getValue ( 0, 2 ),
2168  icoAx->getValue ( 0, 3 ),
2169  CSymList->at(initAxes.at(pIt).first)[1],
2170  CSymList->at(initAxes.at(pIt).first)[2],
2171  CSymList->at(initAxes.at(pIt).first)[3] );
2172 
2173  //============================================ Rotate the model C3 to the correct orientation relative to the detected C5 axis.
2174  proshade_double* rotModelC3 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMat,
2175  icoAx->getValue ( 6, 1 ),
2176  icoAx->getValue ( 6, 2 ),
2177  icoAx->getValue ( 6, 3 ) );
2178 
2179  //============================================ Find the angle betwen the rotated model C3 and the detected C3 axes along the detected C5 axis.
2180  proshade_double bestAng = 0.0, curAngDist, bestAngDist = 999.9;
2181  proshade_double* rotMatHlp = new proshade_double[9];
2182  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatHlp, __FILE__, __LINE__, __func__ );
2183  for ( proshade_double ang = 0.0; ang < ( M_PI * 2.0 ); ang += 0.002 )
2184  {
2185  //============================================ Compute rotation matrix for this angle value
2186  ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( rotMatHlp, CSymList->at(initAxes.at(pIt).first)[1], CSymList->at(initAxes.at(pIt).first)[2], CSymList->at(initAxes.at(pIt).first)[3], ang );
2187 
2188  //======================================== Rotate the rotated C2 by the matrix
2189  proshade_double* rotRotModelC3 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatHlp,
2190  rotModelC3[0],
2191  rotModelC3[1],
2192  rotModelC3[2] );
2193 
2194  //======================================== Find distance
2195  curAngDist = std::sqrt ( std::pow ( rotRotModelC3[0] - CSymList->at(initAxes.at(pIt).second)[1], 2.0 ) +
2196  std::pow ( rotRotModelC3[1] - CSymList->at(initAxes.at(pIt).second)[2], 2.0 ) +
2197  std::pow ( rotRotModelC3[2] - CSymList->at(initAxes.at(pIt).second)[3], 2.0 ) );
2198 
2199  //======================================== Save best angle
2200  if ( curAngDist < bestAngDist ) { bestAngDist = curAngDist; bestAng = ang; }
2201 
2202  //======================================== Release memory
2203  delete[] rotRotModelC3;
2204  }
2205 
2206  //============================================ Release memory
2207  delete[] rotMatHlp;
2208 
2209  //============================================ For the rotation matrix along the detected C5 axis with the same anlge as is between the rotated model C3 and the detected C3 axes.
2210  proshade_double* rotMat2 = new proshade_double[9];
2211  ProSHADE_internal_misc::checkMemoryAllocation ( rotMat2, __FILE__, __LINE__, __func__ );
2212  ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( rotMat2, CSymList->at(initAxes.at(pIt).first)[1], CSymList->at(initAxes.at(pIt).first)[2], CSymList->at(initAxes.at(pIt).first)[3], bestAng );
2213 
2214  //============================================ Combine the two rotation matrices into a single rotation matrix
2215  proshade_double* rotMatFin = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( rotMat2, rotMat );
2216 
2217  //============================================ For each model axis
2218  std::vector< proshade_double* > hlpAxes;
2219  for ( proshade_unsign iter = 0; iter < icoAx->getNoAxes ( ); iter++ )
2220  {
2221  //======================================== Rotate the model axis to fit the detected orientation
2222  proshade_double* rotAxis = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatFin,
2223  icoAx->getValue ( iter, 1 ),
2224  icoAx->getValue ( iter, 2 ),
2225  icoAx->getValue ( iter, 3 ) );
2226 
2227  //======================================== Create ProSHADE symmetry axis representation
2228  proshade_double* axis = new proshade_double[7];
2229  ProSHADE_internal_misc::checkMemoryAllocation ( axis, __FILE__, __LINE__, __func__ );
2230 
2231  axis[0] = icoAx->getValue ( iter, 0 );
2232  axis[1] = rotAxis[0];
2233  axis[2] = rotAxis[1];
2234  axis[3] = rotAxis[2];
2235  axis[4] = ( 2.0 * M_PI ) / axis[0];
2236  axis[5] = 0.0;
2237  axis[6] = -std::numeric_limits < proshade_double >::infinity();
2238 
2239  //======================================== Save axis to ret
2241 
2242  //======================================== Release memory
2243  delete[] rotAxis;
2244  delete[] axis;
2245  }
2246 
2247  //============================================ Save to ret
2248  ret->emplace_back ( hlpAxes );
2249 
2250  //============================================ Release memory
2251  delete[] rotMat;
2252  delete[] rotMat2;
2253  delete[] rotMatFin;
2254  delete[] rotModelC3;
2255  delete icoAx;
2256  }
2257 
2258  //================================================ Done
2259  return ;
2260 
2261 }
2262 
2270 std::pair< proshade_unsign, proshade_unsign > findBestOctaDihedralPair ( std::vector< proshade_double* >* CSymList, proshade_double minPeakHeight, proshade_double axErr )
2271 {
2272  //================================================ Initialise variables
2273  std::pair< proshade_unsign, proshade_unsign > ret;
2274  std::vector< proshade_unsign > C4List;
2275  proshade_double bestHeightSum = 0.0;
2276  proshade_double dotProduct;
2277 
2278  //================================================ Find all C5 symmetries
2279  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ ) { const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 4.0 ); if ( lhs1.AlmostEquals ( rhs1 ) && CSymList->at(cSym)[5] >= minPeakHeight ) { ProSHADE_internal_misc::addToUnsignVector ( &C4List, cSym ); } }
2280 
2281  //================================================ For each unique pair of C5 and C3
2282  for ( proshade_unsign c4 = 0; c4 < static_cast<proshade_unsign> ( C4List.size() ); c4++ )
2283  {
2284  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
2285  {
2286  //======================================== Compare only C3s to the C5List and only with decent average peak height
2287  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 3.0 );
2288  if ( !lhs1.AlmostEquals ( rhs1 ) ) { continue; }
2289  if ( CSymList->at(cSym)[5] < minPeakHeight ) { continue; }
2290 
2291  //======================================== Check the angle between the C5 and C3 axes
2292  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(C4List.at(c4))[1],
2293  &CSymList->at(C4List.at(c4))[2],
2294  &CSymList->at(C4List.at(c4))[3],
2295  &CSymList->at(cSym)[1],
2296  &CSymList->at(cSym)[2],
2297  &CSymList->at(cSym)[3] );
2298 
2299  //======================================== Is the angle approximately the dihedral angle?
2300  if ( ( ( 1.0 / sqrt ( 3.0 ) ) > ( std::abs( dotProduct ) - axErr ) ) && ( ( 1.0 / sqrt ( 3.0 ) ) < ( std::abs( dotProduct ) + axErr ) ) )
2301  {
2302  if ( bestHeightSum < ( CSymList->at(C4List.at(c4))[5] + CSymList->at(cSym)[5] ) )
2303  {
2304  bestHeightSum = ( CSymList->at(C4List.at(c4))[5] + CSymList->at(cSym)[5] );
2305  ret.first = C4List.at(c4);
2306  ret.second = cSym;
2307  }
2308  }
2309  }
2310  }
2311 
2312  //================================================ Done
2313  return ( ret );
2314 
2315 }
2316 
2337 void ProSHADE_internal_symmetry::predictOctaAxes ( std::vector< proshade_double* >* CSymList, std::vector< proshade_double* >* ret, proshade_double axErr, proshade_double minPeakHeight )
2338 {
2339  //================================================ Create the tetrahedronAxes object
2341 
2342  //================================================ Find the best axis combination with dihedral angle and correct folds
2343  std::pair< proshade_unsign, proshade_unsign > initAxes = findBestOctaDihedralPair ( CSymList, minPeakHeight, axErr );
2344 
2345  //================================================ Find rotation between the detected C4 and the model C4 axes.
2346  proshade_double* rotMat = ProSHADE_internal_maths::findRotMatMatchingVectors ( octAx->getValue ( 0, 1 ),
2347  octAx->getValue ( 0, 2 ),
2348  octAx->getValue ( 0, 3 ),
2349  CSymList->at(initAxes.first)[1],
2350  CSymList->at(initAxes.first)[2],
2351  CSymList->at(initAxes.first)[3] );
2352 
2353  //================================================ Rotate the model C3 to the correct orientation relative to the detected C4 axis.
2354  proshade_double* rotModelC3 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMat,
2355  octAx->getValue ( 3, 1 ),
2356  octAx->getValue ( 3, 2 ),
2357  octAx->getValue ( 3, 3 ) );
2358 
2359  //================================================ Find the angle betwen the rotated model C3 and the detected C3 axes along the detected C4 axis.
2360  proshade_double bestAng = 0.0, curAngDist, bestAngDist = 999.9;
2361  proshade_double* rotMatHlp = new proshade_double[9];
2362  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatHlp, __FILE__, __LINE__, __func__ );
2363  for ( proshade_double ang = 0.0; ang < ( M_PI * 2.0 ); ang += 0.002 )
2364  {
2365  //============================================ Compute rotation matrix for this angle value
2366  ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( rotMatHlp, CSymList->at(initAxes.first)[1], CSymList->at(initAxes.first)[2], CSymList->at(initAxes.first)[3], ang );
2367 
2368  //============================================ Rotate the rotated C2 by the matrix
2369  proshade_double* rotRotModelC3 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatHlp,
2370  rotModelC3[0],
2371  rotModelC3[1],
2372  rotModelC3[2] );
2373 
2374  //============================================ Find distance
2375  curAngDist = std::sqrt ( std::pow ( rotRotModelC3[0] - CSymList->at(initAxes.second)[1], 2.0 ) +
2376  std::pow ( rotRotModelC3[1] - CSymList->at(initAxes.second)[2], 2.0 ) +
2377  std::pow ( rotRotModelC3[2] - CSymList->at(initAxes.second)[3], 2.0 ) );
2378 
2379  //============================================ Save best angle
2380  if ( curAngDist < bestAngDist ) { bestAngDist = curAngDist; bestAng = ang; }
2381 
2382  //============================================ Release memory
2383  delete[] rotRotModelC3;
2384  }
2385 
2386  //============================================ Release memory
2387  delete[] rotMatHlp;
2388 
2389  //================================================ For the rotation matrix along the detected C5 axis with the same anlge as is between the rotated model C3 and the detected C3 axes.
2390  proshade_double* rotMat2 = new proshade_double[9];
2391  ProSHADE_internal_misc::checkMemoryAllocation ( rotMat2, __FILE__, __LINE__, __func__ );
2392  ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( rotMat2, CSymList->at(initAxes.first)[1], CSymList->at(initAxes.first)[2], CSymList->at(initAxes.first)[3], bestAng );
2393 
2394  //================================================ Combine the two rotation matrices into a single rotation matrix
2395  proshade_double* rotMatFin = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( rotMat2, rotMat );
2396 
2397  //================================================ For each model axis
2398  for ( proshade_unsign iter = 0; iter < octAx->getNoAxes ( ); iter++ )
2399  {
2400  //============================================ Rotate the model axis to fit the detected orientation
2401  proshade_double* rotAxis = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatFin,
2402  octAx->getValue ( iter, 1 ),
2403  octAx->getValue ( iter, 2 ),
2404  octAx->getValue ( iter, 3 ) );
2405 
2406  //============================================ Create ProSHADE symmetry axis representation
2407  proshade_double* axis = new proshade_double[7];
2408  ProSHADE_internal_misc::checkMemoryAllocation ( axis, __FILE__, __LINE__, __func__ );
2409 
2410  axis[0] = octAx->getValue ( iter, 0 );
2411  axis[1] = rotAxis[0];
2412  axis[2] = rotAxis[1];
2413  axis[3] = rotAxis[2];
2414  axis[4] = ( 2.0 * M_PI ) / axis[0];
2415  axis[5] = 0.0;
2416  axis[6] = -std::numeric_limits < proshade_double >::infinity();
2417 
2418  //============================================ Save axis to ret
2420 
2421  //============================================ Release memory
2422  delete[] rotAxis;
2423  }
2424 
2425  //================================================ Release memory
2426  delete[] rotMat;
2427  delete[] rotMat2;
2428  delete[] rotMatFin;
2429  delete[] rotModelC3;
2430  delete octAx;
2431 
2432  //================================================ Done
2433  return ;
2434 
2435 }
2436 
2451 void ProSHADE_internal_symmetry::findIcos10C3s ( std::vector< proshade_double* >* CSymList, std::vector< proshade_double* >* ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data* dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight )
2452 {
2453  //================================================ Initialise variables
2454  std::vector< proshade_unsign > prospectiveC3s, retGrp;
2455  proshade_double dotProd;
2456  proshade_unsign noClose, noAway;
2457 
2458  //================================================ Report progress
2459  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of ten C3 axes.", messageShift );
2460 
2461  //================================================ For each C3
2462  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
2463  {
2464  //============================================ Use only C3s with hight enough average
2465  if ( CSymList->at(cIt)[0] != 3.0 || CSymList->at(cIt)[0] < minPeakHeight ) { continue; }
2466 
2467  //============================================ Check the C3 has acos ( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ) to 3 C5s and acos ( 1.0 - ( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ) ) to the other three C5s
2468  noClose = 0; noAway = 0;
2469  for ( proshade_unsign rIt = 0; rIt < 6; rIt++ )
2470  {
2471  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1],
2472  &ret->at(rIt)[2],
2473  &ret->at(rIt)[3],
2474  &CSymList->at(cIt)[1],
2475  &CSymList->at(cIt)[2],
2476  &CSymList->at(cIt)[3] );
2477 
2478  if ( ( std::abs ( dotProd ) > ( ( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ) + axErr ) ) ) { noClose += 1; continue; }
2479  if ( ( std::abs ( dotProd ) > ( 1.0 - ( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ) - axErr ) ) && ( std::abs ( dotProd ) < ( 1.0 - ( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ) + axErr ) ) ) { noAway += 1; continue; }
2480  }
2481 
2482  //============================================ If correct angles distribution is found, save the axis
2483  if ( ( noClose == 3 ) && ( noAway == 3 ) )
2484  {
2485  ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC3s, cIt );
2486  }
2487  }
2488 
2489  //================================================ Search for missing axes
2490  for ( proshade_unsign iter = 0; iter < 6; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &retGrp, iter ); }
2491  if ( !ProSHADE_internal_symmetry::findMissingAxesDual ( &prospectiveC3s, CSymList, ret, &retGrp, 10, axErr, 3, std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ), 3, 1.0 - ( std::sqrt ( ( 1.0 + 2.0 / std::sqrt ( 5.0 ) ) / 3.0 ) ), 3, dataObj ) )
2492  {
2493  return ;
2494  }
2495 
2496  //================================================ Found correct number of axes! Now save the
2497  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( prospectiveC3s.size() ); iter++ )
2498  {
2499  ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(prospectiveC3s.at(iter)) );
2500  }
2501 
2502  //================================================ Report progress
2503  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of ten C3 axes successfull.", messageShift );
2504 
2505  //================================================ Done
2506  return ;
2507 
2508 }
2509 
2524 void ProSHADE_internal_symmetry::findIcos15C2s ( std::vector< proshade_double* >* CSymList, std::vector< proshade_double* >* ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data* dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight )
2525 {
2526  //================================================ Initialise variables
2527  std::vector< proshade_unsign > prospectiveC2s, retGrp;
2528  proshade_double dotProd;
2529  proshade_unsign noClose, noMidway, noAway;
2530 
2531  //================================================ Report progress
2532  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Starting detection of fifteen C2 axes.", messageShift );
2533 
2534  //================================================ For each C2
2535  for ( proshade_unsign cIt = 0; cIt < static_cast<proshade_unsign> ( CSymList->size() ); cIt++ )
2536  {
2537  //============================================ Use only C2s
2538  const FloatingPoint< proshade_double > lhs999 ( CSymList->at(cIt)[5] ), rhs999 ( static_cast< proshade_double > ( -999.9 ) );
2539  if ( CSymList->at(cIt)[0] != 2.0 || ( ( CSymList->at(cIt)[5] < minPeakHeight ) && !( lhs999.AlmostEquals( rhs999 ) ) ) ) { continue; }
2540 
2541  //============================================ Check the C2 has acos ( 0.0 ) to 2 C5s, acos ( 0.5 ) to another 2 C5s and acos ( sqrt ( 3.0 ) / 2.0 ) to the last two C5s
2542  noClose = 0; noMidway = 0; noAway = 0;
2543  for ( proshade_unsign rIt = 0; rIt < 6; rIt++ )
2544  {
2545  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(rIt)[1],
2546  &ret->at(rIt)[2],
2547  &ret->at(rIt)[3],
2548  &CSymList->at(cIt)[1],
2549  &CSymList->at(cIt)[2],
2550  &CSymList->at(cIt)[3] );
2551 
2552  if ( ( std::abs ( dotProd ) > ( ( sqrt ( 3.0 ) / 2.0 ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( sqrt ( 3.0 ) / 2.0 ) + axErr ) ) ) { noAway += 1; continue; }
2553  if ( ( std::abs ( dotProd ) > ( ( 1.0 / 2.0 ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( 1.0 / 2.0 ) + axErr ) ) ) { noMidway += 1; continue; }
2554  if ( ( std::abs ( dotProd ) > ( ( 0.0 ) - axErr ) ) && ( std::abs ( dotProd ) < ( ( 0.0 ) + axErr ) ) ) { noClose += 1; continue; }
2555  }
2556 
2557  //============================================ If correct angles distribution is found, save the axis
2558  if ( ( noClose == 2 ) && ( noMidway == 2 ) && ( noAway == 2 ) )
2559  {
2560  ProSHADE_internal_misc::addToUnsignVector ( &prospectiveC2s, cIt );
2561  }
2562  }
2563 
2564  //================================================ Search for missing axes
2565  for ( proshade_unsign iter = 0; iter < 6; iter++ ) { ProSHADE_internal_misc::addToUnsignVector ( &retGrp, iter ); }
2566  if ( !ProSHADE_internal_symmetry::findMissingAxesTriple ( &prospectiveC2s, CSymList, ret, &retGrp, 15, axErr, 2, 0.0, 2, 1.0/2.0, 2, sqrt ( 3.0 ) / 2.0, 2, dataObj ) )
2567  {
2568  return ;
2569  }
2570 
2571  //================================================ Found correct number of axes! Now save the
2572  for ( proshade_unsign iter = 0; iter < static_cast<proshade_unsign> ( prospectiveC2s.size() ); iter++ )
2573  {
2574  ProSHADE_internal_misc::addToDblPtrVector ( ret, CSymList->at(prospectiveC2s.at(iter)) );
2575  }
2576 
2577  //================================================ Report progress
2578  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Detection of fifteen C2 axes successfull.", messageShift );
2579 
2580  //================================================ Done
2581  return ;
2582 
2583 }
2584 
2607 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 )
2608 {
2609  //================================================ Initialise variables
2610  bool atLeastOne = false;
2611  std::vector< proshade_double* > prosp;
2612  std::vector< proshade_double > sol;
2613 
2614  //================================================ Proceed only if need be
2615  if ( static_cast<proshade_unsign> ( possibilities->size() ) == requiredNoAxes ) { atLeastOne = true; return ( atLeastOne ); }
2616 
2617  //================================================ Copy already found to prospective
2618  for ( proshade_unsign prIt = 0; prIt < static_cast<proshade_unsign> ( possibilities->size() ); prIt++ )
2619  {
2620  ProSHADE_internal_symmetry::addAxisUnlessSame ( static_cast< proshade_unsign > ( CSymList->at(possibilities->at(prIt))[0] ),
2621  CSymList->at(possibilities->at(prIt))[1],
2622  CSymList->at(possibilities->at(prIt))[2],
2623  CSymList->at(possibilities->at(prIt))[3],
2624  CSymList->at(possibilities->at(prIt))[5], &prosp, axErr );
2625  }
2626 
2627  //================================================ Start generating possible solutions
2628  for ( proshade_unsign rgIt1 = 0; rgIt1 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt1++ )
2629  {
2630  for ( proshade_unsign rgIt2 = 0; rgIt2 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt2++ )
2631  {
2632  //======================================== Use unique combinations (order matters here!)
2633  if ( rgIt1 == rgIt2 ) { continue; }
2634 
2635  for ( proshade_unsign rgIt3 = 0; rgIt3 < static_cast<proshade_unsign> ( retGroup->size() ); rgIt3++ )
2636  {
2637  //==================================== Use unique combinations (order matters here!)
2638  if ( ( rgIt1 == rgIt3 ) || ( rgIt2 == rgIt3 ) ) { continue; }
2639 
2640  //==================================== Generate possible solution (1)
2641  sol = ProSHADE_internal_maths::findVectorFromThreeVAndThreeD ( ret->at(rgIt1)[1], ret->at(rgIt1)[2], ret->at(rgIt1)[3],
2642  ret->at(rgIt2)[1], ret->at(rgIt2)[2], ret->at(rgIt2)[3],
2643  ret->at(rgIt3)[1], ret->at(rgIt3)[2], ret->at(rgIt3)[3], angle1, angle2, angle3 );
2644 
2645  //==================================== Check if solution fits the group completely
2646  ProSHADE_internal_symmetry::checkFittingAxisTripleAndSave ( retGroup, ret, fold, sol.at(0), sol.at(1), sol.at(2), &prosp, axErr, noMatchesG1, angle1, noMatchesG2, angle2, noMatchesG3, angle3, dataObj );
2647  if ( prosp.size() == requiredNoAxes ) { break; }
2648 
2649  //==================================== Generate possible solution (2)
2650  sol = ProSHADE_internal_maths::findVectorFromThreeVAndThreeD ( ret->at(rgIt1)[1], ret->at(rgIt1)[2], ret->at(rgIt1)[3],
2651  ret->at(rgIt2)[1], ret->at(rgIt2)[2], ret->at(rgIt2)[3],
2652  ret->at(rgIt3)[1], ret->at(rgIt3)[2], ret->at(rgIt3)[3], -angle1, -angle2, -angle3 );
2653 
2654  //==================================== Check if solution fits the group completely
2655  ProSHADE_internal_symmetry::checkFittingAxisTripleAndSave ( retGroup, ret, fold, sol.at(0), sol.at(1), sol.at(2), &prosp, axErr, noMatchesG1, angle1, noMatchesG2, angle2, noMatchesG3, angle3, dataObj );
2656  if ( prosp.size() == requiredNoAxes ) { break; }
2657  }
2658 
2659  if ( prosp.size() == requiredNoAxes ) { break; }
2660  }
2661 
2662  if ( prosp.size() == requiredNoAxes ) { break; }
2663  }
2664 
2665  //================================================ Found all required axes
2666  if ( prosp.size() == requiredNoAxes )
2667  {
2668  //============================================ For each found missing axis
2669  for ( proshade_unsign axIt = static_cast<proshade_unsign> ( possibilities->size() ); axIt < static_cast<proshade_unsign> ( prosp.size() ); axIt++ )
2670  {
2671  if ( ProSHADE_internal_maths::isAxisUnique ( CSymList, prosp.at(axIt), axErr ) )
2672  {
2673  //======================================== Add
2674  ProSHADE_internal_misc::addToDblPtrVector ( CSymList, prosp.at(axIt) );
2675  ProSHADE_internal_misc::addToUnsignVector ( possibilities, static_cast<proshade_unsign> ( CSymList->size()-1 ) );
2676  }
2677  }
2678 
2679  atLeastOne = true;
2680  return ( atLeastOne );
2681  }
2682  else
2683  {
2684  //============================================ Delete all found, but unnecessary axes
2685  for ( proshade_unsign axIt = static_cast<proshade_unsign> ( possibilities->size() ); axIt < static_cast<proshade_unsign> ( prosp.size() ); axIt++ )
2686  {
2687  delete[] prosp.at(axIt);
2688  }
2689  }
2690 
2691  //================================================ Done
2692  return ( atLeastOne );
2693 
2694 }
2695 
2718 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 )
2719 {
2720  //================================================ Initialise variables
2721  proshade_unsign noG1 = 0;
2722  proshade_unsign noG2 = 0;
2723  proshade_unsign noG3 = 0;
2724  proshade_double dotProd = 0.0;
2725  proshade_double axHeight = 0.0;
2726 
2727  //================================================ Find the angle and count dual matching frequencies
2728  for ( proshade_unsign rIt = 0; rIt < static_cast<proshade_unsign> ( retGroup->size() ); rIt++ )
2729  {
2730  dotProd = ProSHADE_internal_maths::computeDotProduct ( &ret->at(retGroup->at(rIt))[1],
2731  &ret->at(retGroup->at(rIt))[2],
2732  &ret->at(retGroup->at(rIt))[3],
2733  &axX, &axY, &axZ );
2734 
2735  if ( ( std::abs ( dotProd ) > ( angle1 - axErr ) ) && ( std::abs ( dotProd ) < ( angle1 + axErr ) ) ) { noG1 += 1; continue; }
2736  if ( ( std::abs ( dotProd ) > ( angle2 - axErr ) ) && ( std::abs ( dotProd ) < ( angle2 + axErr ) ) ) { noG2 += 1; continue; }
2737  if ( ( std::abs ( dotProd ) > ( angle3 - axErr ) ) && ( std::abs ( dotProd ) < ( angle3 + axErr ) ) ) { noG3 += 1; continue; }
2738  }
2739 
2740  //================================================ If correct frequencies are matched, check height.
2741  if ( ( noG1 == noMatchesG1 ) && ( noG2 == noMatchesG2 ) && ( noG3 == noMatchesG3 ) )
2742  {
2743  //============================================ Is the height good enough?
2744  axHeight = ProSHADE_internal_symmetry::missingAxisHeight ( axX, axY, axZ, dataObj, fold, axErr );
2745 
2746  //============================================ If so, save
2747  if ( axHeight > 0.1 )
2748  {
2749  ProSHADE_internal_symmetry::addAxisUnlessSame ( fold, axX, axY, axZ, axHeight, prosp, axErr );
2750  }
2751  }
2752 
2753  //================================================ Done
2754  return ;
2755 
2756 }
2757 
2771 {
2772  //================================================ Initialise variables
2773  std::vector< proshade_unsign > primes = ProSHADE_internal_maths::findAllPrimes ( settings->maxSymmetryFold );
2774  std::vector< proshade_double* > ret, tmpHolder;
2775  std::vector< proshade_unsign > testedFolds;
2776  proshade_double symThres;
2777  proshade_unsign foldToTest;
2778  bool foldDone, anyNewSyms = true;
2779 
2780  //================================================ For each found prime number in the limit
2781  for ( proshade_unsign prIt = 0; prIt < static_cast< proshade_unsign > ( primes.size() ); prIt++ )
2782  {
2783  //============================================ Report progress
2784  std::stringstream hlpSS;
2785  hlpSS << "Searching for prime fold symmetry C" << primes.at(prIt) << ".";
2786  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 3, hlpSS.str(), settings->messageShift );
2787 
2788  //============================================ Get all symmetries for this prime fold
2789  std::vector< proshade_double* > prSyms = this->findRequestedCSymmetryFromAngleAxis ( settings, primes.at(prIt), &symThres );
2790 
2791  //============================================ Save the detected C symmetries
2792  for ( size_t axIt = 0; axIt < prSyms.size(); axIt++ )
2793  {
2794  //======================================== Is this symmetry passing the threshold?
2795  if ( prSyms.at(axIt)[5] >= symThres )
2796  {
2797  //==================================== Add this symmetry to final list
2798  if ( ProSHADE_internal_maths::isAxisUnique ( &ret, prSyms.at(axIt), settings->axisErrTolerance, true ) )
2799  {
2800  ProSHADE_internal_misc::deepCopyAxisToDblPtrVector ( &ret, prSyms.at(axIt) );
2801  }
2802  }
2803 
2804  //======================================== Release memory
2805  delete[] prSyms.at(axIt);
2806  }
2807  }
2808 
2809  //================================================ Was anything found?
2810  if ( ret.size() < 1 ) { return ( ret ); }
2811 
2812  //================================================ Check for prime symmetry fold multiples
2813  while ( anyNewSyms )
2814  {
2815  //============================================ Initialise new iteration
2816  anyNewSyms = false;
2817 
2818  //============================================ For each passing symmetry, look if there are any combinations of symmetries that would contain it
2819  for ( proshade_unsign axIt1 = 0; axIt1 < static_cast< proshade_unsign > ( ret.size() ); axIt1++ )
2820  {
2821  for ( proshade_unsign axIt2 = 0; axIt2 < static_cast< proshade_unsign > ( ret.size() ); axIt2++ )
2822  {
2823  //==================================== Initialise iteration
2824  foldToTest = static_cast< proshade_unsign > ( ret.at(axIt1)[0] * ret.at(axIt2)[0] );
2825  if ( foldToTest > settings->maxSymmetryFold ) { continue; }
2826 
2827  //==================================== Was this fold tested already?
2828  foldDone = false;
2829  for ( proshade_unsign fIt = 0; fIt < static_cast< proshade_unsign > ( testedFolds.size() ); fIt++ ) { if ( testedFolds.at(fIt) == foldToTest ) { foldDone = true; break; } }
2830  if ( foldDone ) { continue; }
2831  else { ProSHADE_internal_misc::addToUnsignVector ( &testedFolds, foldToTest ); }
2832 
2833  //==================================== Report progress
2834  std::stringstream hlpSS2;
2835  hlpSS2 << "Searching for fold combination of detected folds " << ret.at(axIt1)[0] << " and " << ret.at(axIt2)[0] << ", i.e. C" << foldToTest << ".";
2836  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 3, hlpSS2.str(), settings->messageShift );
2837 
2838  //==================================== Get all symmetries for this fold
2839  std::vector< proshade_double* > prSyms = this->findRequestedCSymmetryFromAngleAxis ( settings, foldToTest, &symThres );
2840 
2841  //==================================== For each detected group with the required fold
2842  for ( size_t newAxIt = 0; newAxIt < prSyms.size(); newAxIt++ )
2843  {
2844  if ( prSyms.at(newAxIt)[5] >= symThres )
2845  {
2846  //================================ Add to detected axes
2847  if ( ProSHADE_internal_maths::isAxisUnique ( &ret, prSyms.at(newAxIt), settings->axisErrTolerance, true ) )
2848  {
2849  ProSHADE_internal_misc::deepCopyAxisToDblPtrVector ( &tmpHolder, prSyms.at(newAxIt) );
2850  }
2851  }
2852 
2853  //==================================== Release memory
2854  delete[] prSyms.at(newAxIt);
2855  }
2856  }
2857  }
2858 
2859  //============================================ Add newly found groups and repeat if need be
2860  if ( tmpHolder.size() > 0 )
2861  {
2862  for ( proshade_unsign tmpIt = 0; tmpIt < static_cast< proshade_unsign > ( tmpHolder.size() ); tmpIt++ )
2863  {
2864  ProSHADE_internal_misc::deepCopyAxisToDblPtrVector ( &ret, tmpHolder.at(tmpIt) );
2865  delete[] tmpHolder.at(tmpIt);
2866  }
2867 
2868  anyNewSyms = true;
2869  tmpHolder.clear ( );
2870  }
2871  }
2872 
2873  //================================================ Sort the vector
2874  std::sort ( ret.begin(), ret.end(), ProSHADE_internal_misc::sortSymHlpInv );
2875 
2876  //================================================ Done
2877  return ( ret );
2878 }
2879 
2886 bool sortProSHADESymmetryByPeak ( proshade_double* a, proshade_double* b)
2887 {
2888  //================================================ Done
2889  return ( a[5] > b[5] );
2890 
2891 }
2892 
2909 std::vector < proshade_double* > ProSHADE_internal_data::ProSHADE_data::findRequestedCSymmetryFromAngleAxis ( ProSHADE_settings* settings, proshade_unsign fold, proshade_double* peakThres )
2910 {
2911  //================================================ Initialise variables
2912  proshade_double soughtAngle;
2913  std::vector< proshade_double > allPeakHeights;
2914  std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_spherePeakGroup* > peakGroups;
2915  std::vector< proshade_double* > ret;
2916  bool newPeak;
2917 
2918  //================================================ Make sure we have a clean start
2919  this->sphereMappedRotFun.clear();
2920 
2921  //================================================ Convert rotation function to only the required angle-axis space spheres and find all peaks
2922  for ( proshade_double angIt = 1.0; angIt < static_cast < proshade_double > ( fold ); angIt += 1.0 )
2923  {
2924  //============================================ Figure the angles to form the symmetry
2925  soughtAngle = angIt * ( 2.0 * M_PI / static_cast<proshade_double> ( fold ) );
2926 
2927  //============================================ Create the angle-axis sphere with correct radius (angle)
2928  this->sphereMappedRotFun.emplace_back ( new ProSHADE_internal_spheres::ProSHADE_rotFun_sphere ( soughtAngle,
2929  M_PI / static_cast < proshade_double > ( this->maxShellBand ),
2930  this->maxShellBand * 2,
2931  soughtAngle,
2932  static_cast < proshade_unsign > ( angIt - 1.0 ) ) );
2933 
2934  //=========================================== Interpolate rotation function onto the sphere
2935  this->sphereMappedRotFun.at(static_cast < size_t > ( angIt - 1.0 ))->interpolateSphereValues ( this->getInvSO3Coeffs ( ) );
2936 
2937  //============================================ Find all peaks for this sphere
2938  this->sphereMappedRotFun.at(static_cast < size_t > ( angIt - 1.0 ))->findAllPeaks ( static_cast< proshade_signed > ( settings->peakNeighbours ), &allPeakHeights );
2939  }
2940 
2941  //============================================ Report progress
2942  std::stringstream hlpSS;
2943  hlpSS << "Found a total of " << std::pow ( static_cast< proshade_double > ( this->maxShellBand ) * 2.0 * ( static_cast< proshade_double > ( fold ) - 1.0 ), 2.0 ) - static_cast< proshade_double > ( allPeakHeights.size() ) << " non-peaks for thresholding.";
2944  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 4, hlpSS.str(), settings->messageShift );
2945 
2946  //================================================ Determine the threshold for significant peaks
2947  *peakThres = std::min ( settings->minSymPeak, determinePeakThreshold ( allPeakHeights, settings->noIQRsFromMedianNaivePeak ) );
2948 
2949  //============================================ Report progress
2950  std::stringstream hlpSS2;
2951  hlpSS2 << "Determined peak threshold " << *peakThres << ".";
2952  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 4, hlpSS2.str(), settings->messageShift );
2953 
2954  //================================================ Remove small peaks
2955  for ( proshade_unsign shIt = 0; shIt < static_cast<proshade_unsign> ( this->sphereMappedRotFun.size() ); shIt++ )
2956  {
2957  this->sphereMappedRotFun.at(shIt)->removeSmallPeaks ( *peakThres );
2958  }
2959 
2960  //================================================ Group peaks
2961  for ( proshade_unsign sphIt = 0; sphIt < static_cast<proshade_unsign> ( this->sphereMappedRotFun.size() ); sphIt++ )
2962  {
2963  //============================================ For each peak
2964  for ( proshade_unsign pkIt = 0; pkIt < static_cast<proshade_unsign> ( this->sphereMappedRotFun.at(sphIt)->getPeaks().size() ); pkIt++ )
2965  {
2966  //======================================== Check if peak belongs to an already detected peak group
2967  newPeak = true;
2968  for ( proshade_unsign pkGrpIt = 0; pkGrpIt < static_cast<proshade_unsign> ( peakGroups.size() ); pkGrpIt++ )
2969  {
2970  if ( peakGroups.at(pkGrpIt)->checkIfPeakBelongs ( static_cast< proshade_double > ( this->sphereMappedRotFun.at(sphIt)->getPeaks().at(pkIt).first ),
2971  static_cast< proshade_double > ( this->sphereMappedRotFun.at(sphIt)->getPeaks().at(pkIt).second ),
2972  sphIt, settings->axisErrTolerance, settings->verbose, settings->messageShift ) ) { newPeak = false; break; }
2973  }
2974 
2975  //======================================== If already added, go to next one
2976  if ( !newPeak ) { continue; }
2977 
2978  //======================================== If not, create a new group with this peak
2979  peakGroups.emplace_back ( new ProSHADE_internal_spheres::ProSHADE_rotFun_spherePeakGroup ( static_cast< proshade_double > ( this->sphereMappedRotFun.at(sphIt)->getPeaks().at(pkIt).first ),
2980  static_cast< proshade_double > ( this->sphereMappedRotFun.at(sphIt)->getPeaks().at(pkIt).second ),
2981  sphIt,
2982  this->sphereMappedRotFun.at(sphIt)->getAngularDim() ) );
2983  }
2984  }
2985 
2986  //================================================ For each peak group, look for the requested fold
2987  for ( proshade_unsign grIt = 0; grIt < static_cast<proshade_unsign> ( peakGroups.size() ); grIt++ )
2988  {
2989  //============================================ Report progress
2990  std::stringstream hlpSS3;
2991  hlpSS3 << "Now considering group with LAT " << peakGroups.at(grIt)->getLatFromIndices() << " - " << peakGroups.at(grIt)->getLatToIndices() << " and LON " << peakGroups.at(grIt)->getLonFromIndices() << " - " << peakGroups.at(grIt)->getLonToIndices() << " spanning spheres ";
2992  for ( proshade_unsign sphIt = 0; sphIt < static_cast<proshade_unsign> ( peakGroups.at(grIt)->getSpherePositions().size() ); sphIt++ ) { hlpSS3 << peakGroups.at(grIt)->getSpherePositions().at(sphIt) << " ; "; }
2993  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 5, hlpSS3.str(), settings->messageShift );
2994 
2995  //============================================ Find point groups in the peak group
2996  peakGroups.at(grIt)->findCyclicPointGroupsGivenFold ( this->sphereMappedRotFun, &ret, settings->useBiCubicInterpolationOnPeaks, fold, settings->verbose, settings->messageShift );
2997 
2998  //============================================ Release the memory
2999  delete peakGroups.at(grIt);
3000  }
3001 
3002  //================================================ Sort ret by peak height
3003  std::sort ( ret.begin(), ret.end(), sortProSHADESymmetryByPeak );
3004 
3005  //================================================ Done
3006  return ( ret );
3007 
3008 }
3009 
3023 {
3024  //================================================ Initialise variables
3025  std::vector < proshade_unsign > folds;
3026  std::vector < proshade_double > angs, applicableAngs;
3027  bool alreadyFound = false;
3028  size_t corAngIt = 0;
3029  proshade_double lat = 0.0, lon = 0.0, radRange = 0.0, searchRangeInDeg = 0.0, axSum = 0.0, curSum = 0.0, maxSum = 0.0, bestXRot = 0.0, bestYRot = 0.0, bestZRot = 0.0, finXRotChan = 0.0, finYRotChan = 0.0, finZRotChan = 0.0;
3030  proshade_double latSamlUnit = ( 2.0 * M_PI ) / ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 );
3031  proshade_double lonSamlUnit = ( 1.0 * M_PI ) / ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 );
3032 
3033  //================================================ Determine all the folds for which rotation function mapping will be required
3034  for ( proshade_unsign iter = 0; iter < static_cast < proshade_unsign > ( ret->size() ); iter++ )
3035  {
3036  alreadyFound = false;
3037  for ( proshade_unsign it = 0; it < static_cast < proshade_unsign > ( folds.size() ); it++ ) { const FloatingPoint< proshade_double > lhs1 ( static_cast< proshade_double > ( folds.at(it) ) ), rhs1 ( ret->at(iter)[0] ); if ( lhs1.AlmostEquals ( rhs1 ) ) { alreadyFound = true; break; } }
3038 
3039  if ( !alreadyFound ) { ProSHADE_internal_misc::addToUnsignVector ( &folds, static_cast< proshade_unsign > ( ret->at(iter)[0] ) ); }
3040  }
3041 
3042  //================================================ Generate vector of all angles
3043  for ( proshade_unsign foldIt = 0; foldIt < static_cast < proshade_unsign > ( folds.size() ); foldIt++ ) { for ( proshade_double angIt = 1.0; angIt < static_cast<proshade_double> ( folds.at(foldIt) ); angIt += 1.0 ) { ProSHADE_internal_misc::addToDoubleVector ( &angs, angIt * ( 2.0 * M_PI / static_cast<proshade_double> ( folds.at(foldIt) ) ) ); } }
3044  std::sort ( angs.begin(), angs.end() );
3045 
3046  //================================================ Remove redundant angles from the list
3047  for ( int angIt = static_cast< int > ( angs.size() - 2 ); angIt >= 0; angIt-- ) { const FloatingPoint< proshade_double > lhs1 ( angs.at(static_cast< size_t > ( angIt ) ) ), rhs1 ( angs.at(static_cast< size_t > ( angIt + 1 ) ) ); if ( lhs1.AlmostEquals ( rhs1 ) ) { angs.erase ( angs.begin() + (angIt+1) ); } }
3048 
3049  //================================================ Generate all sphere mapped rotation function
3050  dataObj->sphereMappedRotFun.clear();
3051  for ( size_t angIt = 0; angIt < angs.size(); angIt++ )
3052  {
3053  //============================================ Decide the range in which the sphere operates
3054  if ( ( angIt == 0 ) && ( angs.size() > 1 ) ) { radRange = ( angs.at(1) - angs.at(0) ) / 2; }
3055  else { if ( ( angIt == ( angs.size() - 1 ) ) && ( angs.size() > 1 ) ) { radRange = ( angs.at(angIt) - angs.at(angIt-1) ) / 2; }
3056  else { if ( angs.size() > 2 ) { radRange = std::min ( ( angs.at(angIt) - angs.at(angIt-1) ) / 2, ( angs.at(angIt+1) - angs.at(angIt) ) / 2 ); }
3057  else { radRange = 0.5; } } }
3058 
3059  //============================================ Create the sphere
3060  dataObj->sphereMappedRotFun.emplace_back ( new ProSHADE_internal_spheres::ProSHADE_rotFun_sphere ( angs.at(angIt),
3061  radRange,
3062  dataObj->maxShellBand * 2,
3063  angs.at(angIt),
3064  static_cast<proshade_unsign> ( angIt ) ) );
3065 
3066  //=========================================== Interpolate rotation function onto the sphere
3067  dataObj->sphereMappedRotFun.at( static_cast < proshade_unsign > ( angIt ))->interpolateSphereValues ( dataObj->getInvSO3Coeffs ( ) );
3068  }
3069 
3070  //================================================ Check for improved sum
3071  searchRangeInDeg = 360.0 / ( dataObj->getMaxBand() * 2.0 );
3072  proshade_double* rotMat, *newAxis;
3073  while ( searchRangeInDeg > 0.09 )
3074  {
3075  //============================================ For change along each dimension
3076  for ( proshade_double xChan = -searchRangeInDeg; xChan < ( 1.5 * searchRangeInDeg ); xChan += searchRangeInDeg )
3077  {
3078  for ( proshade_double yChan = -searchRangeInDeg; yChan < ( 1.5 * searchRangeInDeg ); yChan += searchRangeInDeg )
3079  {
3080  for ( proshade_double zChan = -searchRangeInDeg; zChan < ( 1.5 * searchRangeInDeg ); zChan += searchRangeInDeg )
3081  {
3082  //================================ Initialise local variables
3083  curSum = 0.0;
3084 
3085  //================================ Find the rotation matrix of the appropriate rotation
3086  rotMat = ProSHADE_internal_maths::build3x3MatrixFromXYZRotations ( xChan + finXRotChan, yChan + finYRotChan, zChan + finZRotChan );
3087 
3088  //================================ For each axis, find new position and its RF value
3089  for ( proshade_unsign axIt = 0; axIt < static_cast< proshade_unsign > ( ret->size() ); axIt++ )
3090  {
3091  //============================ Find rotated axis
3092  newAxis = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMat, ret->at(axIt)[1], ret->at(axIt)[2], ret->at(axIt)[3] );
3093 
3094  //============================ Convert XYZ to lat and lon INDICES
3095  lat = ( std::atan2( newAxis[1], newAxis[0] ) / latSamlUnit );
3096  lon = ( std::acos ( newAxis[2] ) / lonSamlUnit );
3097 
3098  if ( lat < 0.0 ) { lat += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3099  if ( lon < 0.0 ) { lon += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3100 
3101  //============================ Generate all angles for this fold
3102  applicableAngs.clear ( );
3103  for ( proshade_double angIt = 1.0; angIt < ret->at(axIt)[0]; angIt += 1.0 ) { ProSHADE_internal_misc::addToDoubleVector ( &applicableAngs, angIt * ( 2.0 * M_PI / ret->at(axIt)[0] ) ); }
3104 
3105  //============================ For each shpere with the correct angle, average the peak heights
3106  axSum = 1.0;
3107  for ( size_t angIt = 0; angIt < angs.size(); angIt++ )
3108  {
3109  //======================== Find the correct sphere
3110  alreadyFound = false;
3111  for ( size_t aIt = 0; aIt < applicableAngs.size(); aIt++ ) { if ( alreadyFound ) { break; } const FloatingPoint< proshade_double > lhs1 ( angs.at(angIt) ), rhs1 ( applicableAngs.at(aIt) ); if ( lhs1.AlmostEquals ( rhs1 ) ) { alreadyFound = true; corAngIt = angIt; } }
3112 
3113  if ( !alreadyFound ) { continue; }
3114 
3115  //======================== Get its peak height for the longitude and latitude
3116  axSum += dataObj->sphereMappedRotFun.at(corAngIt)->getSphereLatLonLinearInterpolationPos ( lat, lon );
3117  }
3118 
3119  //============================ And average the peak heights over the axis
3120  axSum /= ret->at(axIt)[0];
3121  curSum += axSum;
3122 
3123  //============================ Release memory
3124  delete[] newAxis;
3125  }
3126 
3127  //================================ And average the peak heights over all axes
3128  curSum /= static_cast< proshade_double > ( ret->size() );
3129 
3130  //================================ If improved, save
3131  if ( curSum > maxSum )
3132  {
3133  maxSum = curSum;
3134  bestXRot = xChan;
3135  bestYRot = yChan;
3136  bestZRot = zChan;
3137  }
3138 
3139  //================================ Release memory
3140  delete[] rotMat;
3141 
3142 
3143  }
3144  }
3145  }
3146 
3147  //============================================ Prepare for next iteration
3148  searchRangeInDeg /= 2.0;
3149  finXRotChan += bestXRot;
3150  finYRotChan += bestYRot;
3151  finZRotChan += bestZRot;
3152  bestXRot = 0.0;
3153  bestYRot = 0.0;
3154  bestZRot = 0.0;
3155  }
3156 
3157  //================================================ Apply the optimisation
3158  rotMat = ProSHADE_internal_maths::build3x3MatrixFromXYZRotations ( finXRotChan, finYRotChan, finZRotChan );
3159  for ( proshade_unsign axIt = 0; axIt < static_cast< proshade_unsign > ( ret->size() ); axIt++ )
3160  {
3161  //============================================ Find the rotated axis
3162  newAxis = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMat, ret->at(axIt)[1], ret->at(axIt)[2], ret->at(axIt)[3] );
3163 
3164  //============================================ Change axes
3165  ret->at(axIt)[1] = newAxis[0];
3166  ret->at(axIt)[2] = newAxis[1];
3167  ret->at(axIt)[3] = newAxis[2];
3168  }
3169 
3170  //================================================ Release memory
3171  delete[] rotMat;
3172 
3173  //================================================ For each ret axis, compute predicted position
3174  for ( proshade_unsign axIt = 0; axIt < static_cast< proshade_unsign > ( ret->size() ); axIt++ )
3175  {
3176  //============================================ Convert XYZ to lat and lon INDICES
3177  lat = std::atan2( ret->at(axIt)[2], ret->at(axIt)[1] ) / latSamlUnit;
3178  lon = std::acos ( ret->at(axIt)[3] ) / lonSamlUnit;
3179 
3180  if ( lat < 0.0 ) { lat += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3181  if ( lon < 0.0 ) { lon += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3182 
3183  //============================================ Generate all angles for this fold
3184  applicableAngs.clear ( );
3185  for ( proshade_double angIt = 1.0; angIt < ret->at(axIt)[0]; angIt += 1.0 ) { ProSHADE_internal_misc::addToDoubleVector ( &applicableAngs, angIt * ( 2.0 * M_PI / ret->at(axIt)[0] ) ); }
3186 
3187  //============================================ For each shpere with the correct angle, average the peak heights
3188  ret->at(axIt)[5] = 0.0;
3189  for ( size_t angIt = 0; angIt < angs.size(); angIt++ )
3190  {
3191  //======================================== Find the correct sphere
3192  alreadyFound = false;
3193  for ( size_t aIt = 0; aIt < applicableAngs.size(); aIt++ ) { if ( alreadyFound ) { break; } const FloatingPoint< proshade_double > lhs1 ( angs.at(angIt) ), rhs1 ( applicableAngs.at(aIt) ); if ( lhs1.AlmostEquals ( rhs1 ) ) { alreadyFound = true; corAngIt = angIt; } }
3194 
3195  if ( !alreadyFound ) { continue; }
3196 
3197  //======================================== Get its peak height for the longitude and latitude
3198  ret->at(axIt)[5] += dataObj->sphereMappedRotFun.at(corAngIt)->getSphereLatLonLinearInterpolationPos ( lat, lon );
3199  }
3200 
3201  //============================================ And average the peak heights over the axis
3202  ret->at(axIt)[5] /= ( ret->at(axIt)[0] - 1.0 );
3203  maxSum += ret->at(axIt)[5];
3204  }
3205 
3206  //================================================ Report progress
3207  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 3, "Peak height detection and rotation optimisation complete.", settings->messageShift );
3208 
3209  //================================================ Done
3210  return ;
3211 
3212 }
3213 
3227 void ProSHADE_internal_symmetry::optimiseDGroupAngleFromAxesHeights ( std::vector < std::vector< proshade_double > >* ret, ProSHADE_internal_data::ProSHADE_data* dataObj, ProSHADE_settings* settings )
3228 {
3229  //================================================ Sanity check
3230  if ( ret->size() != 2 )
3231  {
3232  throw ProSHADE_exception ( "Attempted to optimise less than two axes for dihedral\n : group.", "ES00070", __FILE__, __LINE__, __func__, "The function for optimisation of dihedral angle of D\n : group was called on group with less than two axes. This\n : seems like a programming bug and should not happen - \n : contact author if you ever see this." );
3233  }
3234 
3235  //================================================ Set the angle to the correct dihedral group position - i.e. 90 deg
3236  proshade_double *crossProd, *perpVec, normFactor;
3237  size_t higherRFIndex = 0;
3238 
3239  // ... Find vector perperndicular to the plane given by the two axes
3240  crossProd = ProSHADE_internal_maths::computeCrossProduct ( &ret->at(0).at(1), &ret->at(0).at(2), &ret->at(0).at(3), &ret->at(1).at(1), &ret->at(1).at(2), &ret->at(1).at(3) );
3241 
3242  // ... Find a vector perpendicular to the plane between the new vector and the vector with higher rotation function value
3243  if ( ret->at(1).at(5) > ret->at(0).at(5) ) { higherRFIndex = 1; }
3244  perpVec = ProSHADE_internal_maths::computeCrossProduct ( &ret->at(higherRFIndex).at(1), &ret->at(higherRFIndex).at(2), &ret->at(higherRFIndex).at(3), &crossProd[0], &crossProd[1], &crossProd[2] );
3245 
3246  // ... Normalise the new vector
3247  normFactor = std::sqrt ( pow ( perpVec[0], 2.0 ) + pow ( perpVec[1], 2.0 ) + pow ( perpVec[2], 2.0 ) );
3248  perpVec[0] /= normFactor; perpVec[1] /= normFactor; perpVec[2] /= normFactor;
3249 
3250  // ... Which vector are we to over-write?
3251  if ( higherRFIndex == 0 ) { higherRFIndex = 1; }
3252  else { higherRFIndex = 0; }
3253 
3254  // ... Set largest axis element to positive
3255  const FloatingPoint< proshade_double > lhs1 ( std::max ( std::abs ( perpVec[0] ), std::max( std::abs ( perpVec[1] ), std::abs ( perpVec[2] ) ) ) );
3256  const FloatingPoint< proshade_double > rhs1 ( std::abs ( perpVec[0] ));
3257  const FloatingPoint< proshade_double > rhs2 ( std::abs ( perpVec[1] ) );
3258  const FloatingPoint< proshade_double > rhs3 ( std::abs ( perpVec[2] ) );
3259  if ( ( lhs1.AlmostEquals ( rhs1 ) && ( perpVec[0] < 0.0 ) ) ||
3260  ( lhs1.AlmostEquals ( rhs2 ) && ( perpVec[1] < 0.0 ) ) ||
3261  ( lhs1.AlmostEquals ( rhs3 ) && ( perpVec[2] < 0.0 ) ) )
3262  {
3263  perpVec[0] *= -1.0;
3264  perpVec[1] *= -1.0;
3265  perpVec[2] *= -1.0;
3266  }
3267 
3268  // ... Over-write the old vector with the better one
3269  ret->at(higherRFIndex).at(1) = perpVec[0]; ret->at(higherRFIndex).at(2) = perpVec[1]; ret->at(higherRFIndex).at(3) = perpVec[2];
3270 
3271  // ... Release memory
3272  delete[] perpVec;
3273  delete[] crossProd;
3274 
3275  //================================================ Convert input to pointers
3276  std::vector< proshade_double* > convVec;
3277  for ( size_t axIt = 0; axIt < 2; axIt++ )
3278  {
3279  //============================================ Allocate memory
3280  proshade_double* axVals = new proshade_double[7];
3281  ProSHADE_internal_misc::checkMemoryAllocation ( axVals, __FILE__, __LINE__, __func__ );
3282 
3283  //============================================ Copy values
3284  for ( size_t elIt = 0; elIt < 7; elIt++ )
3285  {
3286  axVals[elIt] = ret->at(axIt).at(elIt);
3287  }
3288 
3289  //============================================ Save
3290  convVec.push_back ( axVals );
3291  }
3292 
3293  //================================================ Run normal optimisation
3294  ProSHADE_internal_symmetry::findPredictedAxesHeights ( &convVec, dataObj, settings );
3295 
3296  //================================================ Convert back and release memory
3297  for ( size_t axIt = 0; axIt < 2; axIt++ )
3298  {
3299  //============================================ Copy values
3300  for ( size_t elIt = 0; elIt < 7; elIt++ )
3301  {
3302  ret->at(axIt).at(elIt) = convVec.at(axIt)[elIt];
3303  }
3304 
3305  //============================================ Release memory
3306  delete[] convVec.at(axIt);
3307  }
3308 
3309  //================================================ Done
3310  return ;
3311 
3312 }
3313 
3324 void ProSHADE_internal_symmetry::optimiseDGroupAngleFromAxesHeights ( std::vector < std::vector< proshade_double > >* allCs, std::vector< proshade_unsign > selection, ProSHADE_internal_data::ProSHADE_data* dataObj, ProSHADE_settings* settings )
3325 {
3326  //================================================ Initialise local variables
3327  std::vector < std::vector< proshade_double > > ortPair;
3328  std::vector< proshade_double > hlpVec;
3329 
3330  //================================================ Convert the indices and the list into a single vector containing only the axes to be optimised.
3331  hlpVec.push_back ( allCs->at(selection.at(0))[0] ); hlpVec.push_back ( allCs->at(selection.at(0))[1] ); hlpVec.push_back ( allCs->at(selection.at(0))[2] );
3332  hlpVec.push_back ( allCs->at(selection.at(0))[3] ); hlpVec.push_back ( allCs->at(selection.at(0))[4] ); hlpVec.push_back ( allCs->at(selection.at(0))[5] );
3333  hlpVec.push_back ( allCs->at(selection.at(0))[6] );
3334  ortPair.push_back ( hlpVec ); hlpVec.clear ( );
3335  hlpVec.push_back ( allCs->at(selection.at(1))[0] ); hlpVec.push_back ( allCs->at(selection.at(1))[1] ); hlpVec.push_back ( allCs->at(selection.at(1))[2] );
3336  hlpVec.push_back ( allCs->at(selection.at(1))[3] ); hlpVec.push_back ( allCs->at(selection.at(1))[4] ); hlpVec.push_back ( allCs->at(selection.at(1))[5] );
3337  hlpVec.push_back ( allCs->at(selection.at(1))[6] );
3338  ortPair.push_back ( hlpVec );
3339 
3340  //================================================ Run the optimisation proper
3341  optimiseDGroupAngleFromAxesHeights ( &ortPair, dataObj, settings );
3342 
3343  //================================================ Save the results back to the vector
3344  allCs->at(selection.at(0))[1] = ortPair.at(0).at(1); allCs->at(selection.at(0))[2] = ortPair.at(0).at(2); allCs->at(selection.at(0))[3] = ortPair.at(0).at(3);
3345  allCs->at(selection.at(0))[5] = ortPair.at(0).at(5); allCs->at(selection.at(0))[6] = ortPair.at(0).at(6);
3346 
3347  allCs->at(selection.at(1))[1] = ortPair.at(1).at(1); allCs->at(selection.at(1))[2] = ortPair.at(1).at(2); allCs->at(selection.at(1))[3] = ortPair.at(1).at(3);
3348  allCs->at(selection.at(1))[5] = ortPair.at(1).at(5); allCs->at(selection.at(1))[6] = ortPair.at(1).at(6);
3349 
3350  //================================================ Done
3351  return ;
3352 
3353 }
3354 
3367 proshade_double ProSHADE_internal_symmetry::findPredictedSingleAxisHeight ( proshade_double* axis, proshade_double fold, ProSHADE_internal_data::ProSHADE_data* dataObj, ProSHADE_settings* settings )
3368 {
3369  //================================================ Initialise variables
3370  proshade_double height = 0.0;
3371  proshade_double lat, lon;
3372  proshade_double latSamlUnit = ( 2.0 * M_PI ) / ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 );
3373  proshade_double lonSamlUnit = ( 1.0 * M_PI ) / ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 );
3374 
3375  //================================================ Make sure we have a clean start
3376  dataObj->sphereMappedRotFun.clear ( );
3377 
3378  //================================================ Convert rotation function to only the required angle-axis space spheres and find all peaks
3379  for ( proshade_double angIt = 1.0; angIt < fold; angIt += 1.0 )
3380  {
3381  //============================================ Create the angle-axis sphere with correct radius (angle)
3382  dataObj->sphereMappedRotFun.emplace_back ( new ProSHADE_internal_spheres::ProSHADE_rotFun_sphere ( angIt * ( 2.0 * M_PI / fold ),
3383  M_PI / fold,
3384  dataObj->maxShellBand * 2,
3385  angIt * ( 2.0 * M_PI / fold ),
3386  static_cast<proshade_unsign> ( angIt - 1.0 ) ) );
3387 
3388  //============================================ Interpolate rotation function onto the sphere
3389  dataObj->sphereMappedRotFun.at( static_cast < proshade_unsign > ( angIt - 1.0 ))->interpolateSphereValues ( dataObj->getInvSO3Coeffs ( ) );
3390  }
3391 
3392  //================================================ Convert XYZ to lat and lon INDICES
3393  lat = std::atan2( axis[1], axis[0] ) / latSamlUnit;
3394  lon = std::acos ( axis[2] ) / lonSamlUnit;
3395 
3396  if ( lat < 0.0 ) { lat += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3397  if ( lon < 0.0 ) { lon += ( static_cast< proshade_double > ( dataObj->maxShellBand ) * 2.0 ); }
3398 
3399  lat = std::round ( lat );
3400  lon = std::round ( lon );
3401 
3402  //================================================ Initialise the peak group
3404 
3405  //================================================ Construct a peak group with entry from each sphere with the axis as the peak
3406  for ( proshade_unsign sphIt = 0; sphIt < static_cast<proshade_unsign> ( dataObj->sphereMappedRotFun.size() ); sphIt++ )
3407  {
3408  if ( sphIt == 0 )
3409  {
3410  //======================================== If first sphere, create the peak group
3411  grp = new ProSHADE_internal_spheres::ProSHADE_rotFun_spherePeakGroup ( lat, lon, sphIt, dataObj->sphereMappedRotFun.at(sphIt)->getAngularDim() );
3412  }
3413  else
3414  {
3415  //======================================== Add to the existing object
3416  grp->checkIfPeakBelongs ( lat, lon, sphIt, settings->axisErrTolerance, settings->verbose, settings->messageShift );
3417  }
3418  }
3419 
3420  //================================================ Find the peak height
3421  std::vector < proshade_double* > detectedAxis;
3422  grp->findCyclicPointGroupsGivenFold ( dataObj->sphereMappedRotFun, &detectedAxis, settings->useBiCubicInterpolationOnPeaks, static_cast< proshade_unsign > ( fold ), settings->verbose, settings->messageShift );
3423 
3424  //================================================ Save it!
3425  if ( detectedAxis.size() > 0 ) { height = detectedAxis.at(0)[5]; }
3426  else { height = 0.0; }
3427 
3428  //================================================ Release memory
3429  for ( proshade_unsign i = 0; i < static_cast < proshade_unsign > ( detectedAxis.size() ); i++ ) { delete detectedAxis.at(i); }
3430  delete grp;
3431 
3432  //================================================ Done
3433  return ( height );
3434 
3435 }
3436 
3444 std::pair< proshade_unsign, proshade_unsign > findBestTetraDihedralPair ( std::vector< proshade_double* >* CSymList, proshade_double minPeakHeight, proshade_double axErr )
3445 {
3446  //================================================ Initialise variables
3447  std::pair< proshade_unsign, proshade_unsign > ret;
3448  std::vector< proshade_unsign > C3List;
3449  proshade_double bestHeightSum = 0.0;
3450  proshade_double dotProduct;
3451 
3452  //================================================ Find all C3 symmetries
3453  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ ) { const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 3.0 ); if ( lhs1.AlmostEquals ( rhs1 ) && CSymList->at(cSym)[5] >= minPeakHeight ) { ProSHADE_internal_misc::addToUnsignVector ( &C3List, cSym ); } }
3454 
3455  //================================================ For each unique pair of C3 and C2
3456  for ( proshade_unsign c3 = 0; c3 < static_cast<proshade_unsign> ( C3List.size() ); c3++ )
3457  {
3458  for ( proshade_unsign cSym = 0; cSym < static_cast<proshade_unsign> ( CSymList->size() ); cSym++ )
3459  {
3460  //======================================== Compare only C2s to the C3List and only with decent average peak height
3461  const FloatingPoint< proshade_double > lhs1 ( CSymList->at(cSym)[0] ), rhs1 ( 2.0 );
3462  if ( !lhs1.AlmostEquals ( rhs1 ) ) { continue; }
3463  if ( CSymList->at(cSym)[5] < minPeakHeight ) { continue; }
3464 
3465  //======================================== Check the angle between the C5 and C3 axes
3466  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &CSymList->at(C3List.at(c3))[1],
3467  &CSymList->at(C3List.at(c3))[2],
3468  &CSymList->at(C3List.at(c3))[3],
3469  &CSymList->at(cSym)[1],
3470  &CSymList->at(cSym)[2],
3471  &CSymList->at(cSym)[3] );
3472 
3473  //======================================== Is the angle approximately the dihedral angle?
3474  if ( ( ( 1.0 / sqrt ( 3.0 ) ) > ( std::abs( dotProduct ) - axErr ) ) && ( ( 1.0 / sqrt ( 3.0 ) ) < ( std::abs( dotProduct ) + axErr ) ) )
3475  {
3476  if ( bestHeightSum < ( CSymList->at(C3List.at(c3))[5] + CSymList->at(cSym)[5] ) )
3477  {
3478  bestHeightSum = CSymList->at(C3List.at(c3))[5] + CSymList->at(cSym)[5];
3479  ret.first = C3List.at(c3);
3480  ret.second = cSym;
3481  }
3482  }
3483  }
3484  }
3485 
3486  //================================================ Done
3487  return ( ret );
3488 
3489 }
3490 
3505 std::vector< proshade_double* > ProSHADE_internal_data::ProSHADE_data::getPredictedTetrahedralSymmetriesList ( ProSHADE_settings* settings, std::vector< proshade_double* >* CSymList )
3506 {
3507  //================================================ Initialise variables
3508  std::vector< proshade_double* > ret;
3509 
3510  //================================================ Report progress
3511  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 1, "Starting T symmetry prediction.", settings->messageShift );
3512 
3513  //================================================ Are the basic requirements for icosahedral symmetry met?
3515  {
3516  //============================================ Generate the rest of the axes
3517  ProSHADE_internal_symmetry::predictTetraAxes ( CSymList, &ret, settings->axisErrTolerance, settings->minSymPeak );
3518 
3519  //============================================ Get heights for the predicted axes
3521 
3522  //============================================ Add predicted axes to detected C axes list and also to the settings Icosahedral symmetry list
3523  for ( proshade_unsign retIt = 0; retIt < static_cast < proshade_unsign > ( ret.size() ); retIt++ )
3524  {
3525  proshade_signed matchedPos = ProSHADE_internal_symmetry::addAxisUnlessSame ( static_cast< proshade_unsign > ( ret.at(retIt)[0] ), ret.at(retIt)[1], ret.at(retIt)[2], ret.at(retIt)[3], ret.at(retIt)[5], CSymList, settings->axisErrTolerance );
3526  ProSHADE_internal_misc::addToUnsignVector ( &settings->allDetectedTAxes, static_cast < proshade_unsign > ( matchedPos ) );
3527  }
3528  }
3529 
3530  //================================================ Report progress
3531  ProSHADE_internal_messages::printProgressMessage ( settings->verbose, 2, "T symmetry prediction complete.", settings->messageShift );
3532 
3533  //================================================ Done
3534  return ( ret );
3535 
3536 }
3537 
3558 void ProSHADE_internal_symmetry::predictTetraAxes ( std::vector< proshade_double* >* CSymList, std::vector< proshade_double* >* ret, proshade_double axErr, proshade_double minPeakHeight )
3559 {
3560  //================================================ Create the tetrahedronAxes object
3562 
3563  //================================================ Find the best axis combination with dihedral angle and correct folds
3564  std::pair< proshade_unsign, proshade_unsign > initAxes = findBestTetraDihedralPair ( CSymList, minPeakHeight, axErr );
3565 
3566  //================================================ Find rotation between the detected C3 and the model C3 axes.
3567  proshade_double* rotMat = ProSHADE_internal_maths::findRotMatMatchingVectors ( tetAx->getValue ( 0, 1 ),
3568  tetAx->getValue ( 0, 2 ),
3569  tetAx->getValue ( 0, 3 ),
3570  CSymList->at(initAxes.first)[1],
3571  CSymList->at(initAxes.first)[2],
3572  CSymList->at(initAxes.first)[3] );
3573 
3574  //================================================ Rotate the model C2 to the correct orientation relative to the detected C3 axis.
3575  proshade_double* rotModelC2 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMat,
3576  tetAx->getValue ( 4, 1 ),
3577  tetAx->getValue ( 4, 2 ),
3578  tetAx->getValue ( 4, 3 ) );
3579 
3580  //================================================ Find the angle betwen the rotated model C2 and the detected C2 axes along the detected C3 axis.
3581  proshade_double bestAng = 0.0, curAngDist, bestAngDist = 999.9;
3582  proshade_double* rotMatHlp = new proshade_double[9];
3583  ProSHADE_internal_misc::checkMemoryAllocation ( rotMatHlp, __FILE__, __LINE__, __func__ );
3584  for ( proshade_double ang = 0.0; ang < ( M_PI * 2.0 ); ang += 0.002 )
3585  {
3586  //============================================ Compute rotation matrix for this angle value
3587  ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( rotMatHlp, CSymList->at(initAxes.first)[1], CSymList->at(initAxes.first)[2], CSymList->at(initAxes.first)[3], ang );
3588 
3589  //============================================ Rotate the rotated C2 by the matrix
3590  proshade_double* rotRotModelC2 = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatHlp,
3591  rotModelC2[0],
3592  rotModelC2[1],
3593  rotModelC2[2] );
3594 
3595  //============================================ Find distance
3596  curAngDist = std::sqrt ( std::pow ( rotRotModelC2[0] - CSymList->at(initAxes.second)[1], 2.0 ) +
3597  std::pow ( rotRotModelC2[1] - CSymList->at(initAxes.second)[2], 2.0 ) +
3598  std::pow ( rotRotModelC2[2] - CSymList->at(initAxes.second)[3], 2.0 ) );
3599 
3600  //============================================ Save best angle
3601  if ( curAngDist < bestAngDist ) { bestAngDist = curAngDist; bestAng = ang; }
3602 
3603  //============================================ Release memory
3604  delete[] rotRotModelC2;
3605  }
3606 
3607  //================================================ Release memory
3608  delete[] rotMatHlp;
3609 
3610  //================================================ For the rotation matrix along the detected C5 axis with the same anlge as is between the rotated model C3 and the detected C3 axes.
3611  proshade_double* rotMat2 = new proshade_double[9];
3612  ProSHADE_internal_misc::checkMemoryAllocation ( rotMat2, __FILE__, __LINE__, __func__ );
3613  ProSHADE_internal_maths::getRotationMatrixFromAngleAxis ( rotMat2, CSymList->at(initAxes.first)[1], CSymList->at(initAxes.first)[2], CSymList->at(initAxes.first)[3], bestAng );
3614 
3615  //================================================ Combine the two rotation matrices into a single rotation matrix
3616  proshade_double* rotMatFin = ProSHADE_internal_maths::compute3x3MatrixMultiplication ( rotMat2, rotMat );
3617 
3618  //================================================ For each model axis
3619  for ( proshade_unsign iter = 0; iter < tetAx->getNoAxes( ); iter++ )
3620  {
3621  //============================================ Rotate the model axis to fit the detected orientation
3622  proshade_double* rotAxis = ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication ( rotMatFin,
3623  tetAx->getValue ( iter, 1 ),
3624  tetAx->getValue ( iter, 2 ),
3625  tetAx->getValue ( iter, 3 ) );
3626 
3627  //============================================ Create ProSHADE symmetry axis representation
3628  proshade_double* axis = new proshade_double[7];
3629  ProSHADE_internal_misc::checkMemoryAllocation ( axis, __FILE__, __LINE__, __func__ );
3630 
3631  axis[0] = tetAx->getValue ( iter, 0 );
3632  axis[1] = rotAxis[0];
3633  axis[2] = rotAxis[1];
3634  axis[3] = rotAxis[2];
3635  axis[4] = ( 2.0 * M_PI ) / axis[0];
3636  axis[5] = 0.0;
3637  axis[6] = -std::numeric_limits < proshade_double >::infinity();
3638 
3639  //============================================ Save axis to ret
3641 
3642  //============================================ Release memory
3643  delete[] rotAxis;
3644  }
3645 
3646  //================================================ Release memory
3647  delete[] rotMat;
3648  delete[] rotMat2;
3649  delete[] rotMatFin;
3650  delete[] rotModelC2;
3651  delete tetAx;
3652 
3653  //================================================ Done
3654  return ;
3655 
3656 }
3657 
3674 std::vector< proshade_unsign > ProSHADE_internal_symmetry::findReliableUnphasedSymmetries ( std::vector < std::vector< proshade_double > >* allCs, proshade_signed verbose, proshade_signed messageShift, proshade_double tolerance )
3675 {
3676  //================================================ Report progress
3677  ProSHADE_internal_messages::printProgressMessage ( verbose, 2, "Deciding whether any axis(es) is/are reliable.", messageShift );
3678 
3679  //================================================ Initialise local variables
3680  std::vector< proshade_unsign > ret;
3681 
3682  //================================================ Find the threshold
3683  proshade_double bestHistPeakStart = ProSHADE_internal_maths::findTopGroupSmooth ( allCs, 5, 0.01, 0.03, 5 );
3684  proshade_double bestFSCPeakStart = ProSHADE_internal_maths::findTopGroupSmooth ( allCs, 6, 0.01, 0.005, 5, 0.94 );
3685  if ( bestHistPeakStart > 0.9 ) { bestHistPeakStart = 0.9; }
3686 
3687  //================================================ Are any axes orthogonal
3688  proshade_double dotProduct, maxOrtSum = 0.0, curOrtSum = 0.0;
3689  proshade_unsign maxOrtAx1 = 0, maxOrtAx2 = 0;
3690  for ( size_t relAx1 = 0; relAx1 < allCs->size(); relAx1++ )
3691  {
3692  //============================================ Consider only reliable axes
3693  if ( allCs->at(relAx1)[5] < bestHistPeakStart ) { continue; }
3694  if ( allCs->at(relAx1)[6] < bestFSCPeakStart ) { continue; }
3695 
3696  for ( size_t relAx2 = 1; relAx2 < allCs->size(); relAx2++ )
3697  {
3698  //======================================== Ignore same axes
3699  if ( relAx1 >= relAx2 ) { continue; }
3700 
3701  //======================================== Consider only reliable axes
3702  if ( allCs->at(relAx2)[5] < bestHistPeakStart ) { continue; }
3703  if ( allCs->at(relAx2)[6] < bestFSCPeakStart ) { continue; }
3704 
3705  //======================================== Are the two axes orthogonal?
3706  dotProduct = ProSHADE_internal_maths::computeDotProduct ( &allCs->at(relAx1)[1], &allCs->at(relAx1)[2],
3707  &allCs->at(relAx1)[3], &allCs->at(relAx2)[1],
3708  &allCs->at(relAx2)[2], &allCs->at(relAx2)[3] );
3709 
3710  //======================================== If close to zero, these two axes are perpendicular
3711  if ( std::abs( dotProduct ) < tolerance )
3712  {
3713  //==================================== Find sum
3714  curOrtSum = allCs->at(relAx1)[5] + allCs->at(relAx1)[6] + allCs->at(relAx2)[5] + allCs->at(relAx2)[6];
3715 
3716  //==================================== If best, save it
3717  if ( curOrtSum > maxOrtSum )
3718  {
3719  maxOrtSum = curOrtSum;
3720  maxOrtAx1 = static_cast< proshade_unsign > ( relAx1 );
3721  maxOrtAx2 = static_cast< proshade_unsign > ( relAx2 );
3722  }
3723  }
3724  }
3725  }
3726 
3727  //================================================ If any orthogonal pair was found, return it
3728  if ( maxOrtAx2 != 0 )
3729  {
3730  //================================================ Report progress
3731  ProSHADE_internal_misc::addToUnsignVector ( &ret, maxOrtAx1 );
3732  ProSHADE_internal_misc::addToUnsignVector ( &ret, maxOrtAx2 );
3733  return ( ret );
3734  }
3735 
3736  //================================================ Well, no orthogonal axes. Is there at least one good axis?
3737  curOrtSum = 0.0; maxOrtSum = 0.0;
3738  for ( size_t relAx1 = 0; relAx1 < allCs->size(); relAx1++ )
3739  {
3740  //============================================ Consider only reliable axes in terms of RF
3741  if ( allCs->at(relAx1)[5] < bestHistPeakStart ) { continue; }
3742 
3743  //============================================ Consider only reasonable axes in terms of FSC
3744  if ( allCs->at(relAx1)[6] < 0.3 ) { continue; }
3745 
3746  //============================================ Get the sum
3747  curOrtSum = allCs->at(relAx1)[5] + allCs->at(relAx1)[6];
3748 
3749  //============================================ If highest sum, save
3750  if ( curOrtSum > maxOrtSum )
3751  {
3752  maxOrtSum = curOrtSum;
3753  maxOrtAx1 = static_cast< proshade_unsign > ( relAx1 );
3754  }
3755  }
3756 
3757  //================================================ If anything was found, save it
3758  if ( maxOrtSum > 0.1 )
3759  {
3760  //============================================ Report progress
3761  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Found single reliable axis.", messageShift );
3762 
3763  ProSHADE_internal_misc::addToUnsignVector ( &ret, maxOrtAx1 );
3764  }
3765  else
3766  {
3767  //================================================ Report progress
3768  ProSHADE_internal_messages::printProgressMessage ( verbose, 3, "Found no reliable axis.", messageShift );
3769  }
3770 
3771  //================================================ Done
3772  return ( ret );
3773 
3774 }
3775 
3791 void ProSHADE_internal_symmetry::allocateCentreOfMapFourierTransforms ( proshade_unsign xDim, proshade_unsign yDim, proshade_unsign zDim, fftw_complex *&origMap, fftw_complex *&origCoeffs, fftw_complex *&rotMapComplex, fftw_complex *&rotCoeffs, fftw_complex *&trFunc, fftw_complex *&trFuncCoeffs, fftw_plan *planForwardFourier, fftw_plan *planForwardFourierRot, fftw_plan *planReverseFourierComb )
3792 {
3793  //================================================ Allocate the memory
3794  origMap = new fftw_complex [xDim * yDim * zDim];
3795  origCoeffs = new fftw_complex [xDim * yDim * zDim];
3796  rotMapComplex = new fftw_complex [xDim * yDim * zDim];
3797  rotCoeffs = new fftw_complex [xDim * yDim * zDim];
3798  trFunc = new fftw_complex [xDim * yDim * zDim];
3799  trFuncCoeffs = new fftw_complex [xDim * yDim * zDim];
3800 
3801  //================================================ Check the memory allocation
3802  ProSHADE_internal_misc::checkMemoryAllocation ( origMap, __FILE__, __LINE__, __func__ );
3803  ProSHADE_internal_misc::checkMemoryAllocation ( origCoeffs, __FILE__, __LINE__, __func__ );
3804  ProSHADE_internal_misc::checkMemoryAllocation ( rotMapComplex, __FILE__, __LINE__, __func__ );
3805  ProSHADE_internal_misc::checkMemoryAllocation ( rotCoeffs, __FILE__, __LINE__, __func__ );
3806  ProSHADE_internal_misc::checkMemoryAllocation ( trFunc, __FILE__, __LINE__, __func__ );
3807  ProSHADE_internal_misc::checkMemoryAllocation ( trFuncCoeffs, __FILE__, __LINE__, __func__ );
3808 
3809  //================================================
3810  *planForwardFourier = fftw_plan_dft_3d ( static_cast< int > ( xDim ), static_cast< int > ( yDim ), static_cast< int > ( zDim ), origMap, origCoeffs, FFTW_FORWARD, FFTW_ESTIMATE );
3811  *planForwardFourierRot = fftw_plan_dft_3d ( static_cast< int > ( xDim ), static_cast< int > ( yDim ), static_cast< int > ( zDim ), rotMapComplex, rotCoeffs, FFTW_FORWARD, FFTW_ESTIMATE );
3812  *planReverseFourierComb = fftw_plan_dft_3d ( static_cast< int > ( xDim ), static_cast< int > ( yDim ), static_cast< int > ( zDim ), trFuncCoeffs, trFunc, FFTW_BACKWARD, FFTW_ESTIMATE );
3813 
3814  //================================================ Done
3815  return ;
3816 
3817 }
3818 
3831 void ProSHADE_internal_symmetry::releaseCentreOfMapFourierTransforms ( fftw_complex *origMap, fftw_complex *origCoeffs, fftw_complex *rotMapComplex, fftw_complex *rotCoeffs, fftw_complex *trFunc, fftw_complex *trFuncCoeffs, fftw_plan planForwardFourier, fftw_plan planForwardFourierRot, fftw_plan planReverseFourierComb )
3832 {
3833  //================================================ Destroy the FFTW3 plans
3834  fftw_destroy_plan ( planReverseFourierComb );
3835  fftw_destroy_plan ( planForwardFourier );
3836  fftw_destroy_plan ( planForwardFourierRot );
3837 
3838  //================================================ Set pointers to NULL
3839  planReverseFourierComb = nullptr;
3840  planForwardFourier = nullptr;
3841  planForwardFourierRot = nullptr;
3842 
3843  //================================================ Release the memory
3844  delete[] origMap;
3845  delete[] origCoeffs;
3846  delete[] rotMapComplex;
3847  delete[] rotCoeffs;
3848  delete[] trFunc;
3849  delete[] trFuncCoeffs;
3850 
3851  //================================================ Done
3852  return ;
3853 
3854 }
3855 
3869 std::vector< proshade_double > ProSHADE_internal_symmetry::findTranslationBetweenRotatedAndOriginalMap ( ProSHADE_internal_data::ProSHADE_data* symStr, std::vector < proshade_double > symElem, fftw_complex *origCoeffs, fftw_complex* rotMapComplex, fftw_complex* rotCoeffs, fftw_plan planForwardFourierRot, fftw_complex* trFuncCoeffs, fftw_complex* trFunc, fftw_plan planReverseFourierComb )
3870 {
3871  //================================================ Initialise local variables
3872  proshade_double axX, axY, axZ, axAng, mapPeak, trsX, trsY, trsZ;
3873  std::vector< proshade_double > trsVec;
3874 
3875  //=============================================== Rotate the map by the rotation matrix
3876  proshade_double *rotMap;
3877  ProSHADE_internal_maths::getAxisAngleFromRotationMatrix ( &symElem, &axX, &axY, &axZ, &axAng );
3878  symStr->rotateMapRealSpace ( axX, axY, axZ, axAng, rotMap );
3879 
3880  //================================================ Convert rotated map to Fourier space
3881  for ( size_t it = 0; it < static_cast< size_t > ( symStr->getXDim() * symStr->getYDim() * symStr->getZDim() ); it++ ) { rotMapComplex[it][0] = rotMap[it]; rotMapComplex[it][1] = 0.0; }
3882  fftw_execute ( planForwardFourierRot );
3883 
3884  //================================================ Combine coeffs for translation function
3885  ProSHADE_internal_maths::combineFourierForTranslation ( origCoeffs, rotCoeffs, trFuncCoeffs, symStr->getXDim(), symStr->getYDim(), symStr->getZDim() );
3886 
3887  //================================================ Compute translation function
3888  fftw_execute ( planReverseFourierComb );
3889 
3890  //================================================ Find peak
3891  mapPeak = 0.0;
3892  ProSHADE_internal_maths::findHighestValueInMap ( trFunc, symStr->getXDim(), symStr->getYDim(), symStr->getZDim(), &trsX, &trsY, &trsZ, &mapPeak );
3893 
3894  //================================================ Convert to Angstroms
3895  trsX *= static_cast< proshade_double > ( symStr->getXDimSize() / symStr->getXDim() );
3896  trsY *= static_cast< proshade_double > ( symStr->getYDimSize() / symStr->getYDim() );
3897  trsZ *= static_cast< proshade_double > ( symStr->getZDimSize() / symStr->getZDim() );
3898 
3899  //================================================ Do not translate over half
3900  if ( trsX > ( static_cast< proshade_double > ( symStr->getXDimSize() ) / 2.0 ) ) { trsX = trsX - static_cast< proshade_double > ( symStr->getXDimSize() ); }
3901  if ( trsY > ( static_cast< proshade_double > ( symStr->getYDimSize() ) / 2.0 ) ) { trsY = trsY - static_cast< proshade_double > ( symStr->getYDimSize() ); }
3902  if ( trsZ > ( static_cast< proshade_double > ( symStr->getZDimSize() ) / 2.0 ) ) { trsZ = trsZ - static_cast< proshade_double > ( symStr->getZDimSize() ); }
3903 
3904  //================================================ Save line point
3908 
3909  //================================================ Release memory
3910  delete[] rotMap;
3911 
3912  //================================================ Done
3913  return ( trsVec );
3914 
3915 }
3916 
3935 std::vector< proshade_double > ProSHADE_internal_symmetry::findPointFromTranslations ( ProSHADE_internal_data::ProSHADE_data* symStr, std::vector < std::vector < proshade_double > > symElems, fftw_complex *origCoeffs, fftw_complex* rotMapComplex, fftw_complex* rotCoeffs, fftw_plan planForwardFourierRot, fftw_complex* trFuncCoeffs, fftw_complex* trFunc, fftw_plan planReverseFourierComb )
3936 {
3937  //================================================ Initialise local variables
3938  std::vector< proshade_double > pointOnLine ( 3, 0.0 );
3939  std::vector< proshade_double > identityMat ( 9, 0.0 ); identityMat.at(0) = 1.0; identityMat.at(4) = 1.0; identityMat.at(8) = 1.0;
3940 
3941  //================================================ For each symmetry element in this cyclic group
3942  for ( size_t gEl = 0; gEl < symElems.size(); gEl++ )
3943  {
3944  //============================================ Ignore identity element
3945  if ( ProSHADE_internal_maths::rotationMatrixSimilarity ( &symElems.at(gEl), &identityMat, 0.01 ) ) { continue; }
3946 
3947  //============================================ Find translation difference between rotated and original map
3948  std::vector< proshade_double > trsCenHlp = ProSHADE_internal_symmetry::findTranslationBetweenRotatedAndOriginalMap ( symStr,
3949  symElems.at(gEl),
3950  origCoeffs, rotMapComplex,
3951  rotCoeffs, planForwardFourierRot,
3952  trFuncCoeffs, trFunc,
3953  planReverseFourierComb );
3954 
3955  //============================================ Sum translations over the whole axis
3956  pointOnLine.at(0) += trsCenHlp.at(0);
3957  pointOnLine.at(1) += trsCenHlp.at(1);
3958  pointOnLine.at(2) += trsCenHlp.at(2);
3959  }
3960 
3961  //================================================ Average over all symmetry elements (including the identity one)
3962  pointOnLine.at(0) /= static_cast< proshade_double > ( symElems.size() );
3963  pointOnLine.at(1) /= static_cast< proshade_double > ( symElems.size() );
3964  pointOnLine.at(2) /= static_cast< proshade_double > ( symElems.size() );
3965 
3966  //================================================ Done
3967  return ( pointOnLine );
3968 
3969 }
ProSHADE_settings::noIQRsFromMedianNaivePeak
proshade_double noIQRsFromMedianNaivePeak
When doing peak searching, how many IQRs from the median the threshold for peak height should be (in ...
Definition: ProSHADE_settings.hpp:120
ProSHADE_internal_distances::normaliseEMatrices
void normaliseEMatrices(ProSHADE_internal_data::ProSHADE_data *obj1, ProSHADE_internal_data::ProSHADE_data *obj2, ProSHADE_settings *settings)
This function normalises the E matrices.
Definition: ProSHADE_distances.cpp:572
sortProSHADESymmetryByPeak
bool sortProSHADESymmetryByPeak(proshade_double *a, proshade_double *b)
This function allows using std::sort to sort vectors of ProSHADE symmetry format..
Definition: ProSHADE_symmetry.cpp:2886
ProSHADE_internal_symmetry::findTetra3C2s
void findTetra3C2s(std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight)
This function takes the list of C symmetries and finds the 3 C2 symmetries with correct angles requir...
Definition: ProSHADE_symmetry.cpp:1076
ProSHADE_internal_symmetry::detectOctahedralSymmetry
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 s...
Definition: ProSHADE_symmetry.cpp:1273
ProSHADE_internal_maths::findVectorFromThreeVAndThreeD
std::vector< proshade_double > findVectorFromThreeVAndThreeD(proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2, proshade_double x3, proshade_double y3, proshade_double z3, proshade_double dot1, proshade_double dot2, proshade_double dot3)
Function for finding a vector which would have a given three dot products to three other vectors.
Definition: ProSHADE_maths.cpp:2455
ProSHADE_internal_data::ProSHADE_data::getZDimSize
proshade_single getZDimSize(void)
This function allows access to the map size in angstroms along the Z axis.
Definition: ProSHADE_data.cpp:3919
ProSHADE_internal_precomputedVals::octahedronAxes
Definition: ProSHADE_precomputedValues.hpp:55
ProSHADE_internal_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:321
ProSHADE_internal_symmetry::findMissingAxes
bool findMissingAxes(std::vector< std::vector< proshade_unsign > > *possibilities, std::vector< proshade_double * > *CSymList, proshade_unsign requiredNoAxes, proshade_double axErr, proshade_double angle, proshade_unsign fold, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_double minPeakHeight)
This function tries to find an axis which would complete a particular group of axes for polyhedral sy...
Definition: ProSHADE_symmetry.cpp:676
ProSHADE_internal_misc::addToDblPtrVector
void addToDblPtrVector(std::vector< proshade_double * > *vecToAddTo, proshade_double *elementToAdd)
Adds the element to the vector.
Definition: ProSHADE_misc.cpp:143
ProSHADE_settings::maxSymmetryFold
proshade_unsign maxSymmetryFold
The highest symmetry fold to search for.
Definition: ProSHADE_settings.hpp:136
ProSHADE_internal_data::ProSHADE_data::computeRotationFunction
void computeRotationFunction(ProSHADE_settings *settings)
This function computes the self-rotation function for this structure.
Definition: ProSHADE_symmetry.cpp:41
ProSHADE_internal_symmetry::sortArrVecHlp
bool sortArrVecHlp(const proshade_double *a, const proshade_double *b)
This function compares two arrays of two based on the first number.
Definition: ProSHADE_symmetry.cpp:736
ProSHADE_internal_symmetry::findIcos6C5s
void findIcos6C5s(std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight)
This function takes the list of C symmetries and finds the six C5 symmetries with given angles requir...
Definition: ProSHADE_symmetry.cpp:2032
ProSHADE_internal_symmetry::testGroupAgainstGroup
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.
Definition: ProSHADE_symmetry.cpp:1161
ProSHADE_internal_maths::computeCrossProduct
proshade_double * computeCrossProduct(proshade_double *x1, proshade_double *y1, proshade_double *z1, proshade_double *x2, proshade_double *y2, proshade_double *z2)
Simple 3D vector cross product computation.
Definition: ProSHADE_maths.cpp:1820
ProSHADE_internal_symmetry::predictOctaAxes
void predictOctaAxes(std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, proshade_double minPeakHeight)
This function predicts all octahedral point group symmetry axes from the cyclic point groups list.
Definition: ProSHADE_symmetry.cpp:2337
ProSHADE_internal_symmetry::findReliableUnphasedSymmetries
std::vector< proshade_unsign > findReliableUnphasedSymmetries(std::vector< std::vector< proshade_double > > *allCs, proshade_signed verbose, proshade_signed messageShift, proshade_double tolerance)
This function checks the list of detected axes (presumably from phaseless symmetry detection) and ret...
Definition: ProSHADE_symmetry.cpp:3674
ProSHADE_internal_symmetry::predictTetraAxes
void predictTetraAxes(std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, proshade_double minPeakHeight)
This function predicts all tetrahedral point group symmetry axes from the cyclic point groups list.
Definition: ProSHADE_symmetry.cpp:3558
ProSHADE_internal_symmetry::addAxisUnlessSame
proshade_signed addAxisUnlessSame(proshade_unsign fold, proshade_double axX, proshade_double axY, proshade_double axZ, proshade_double axHeight, proshade_double averageFSC, std::vector< proshade_double * > *prosp, proshade_double axErr)
This function simply creates a new axis from information in aruments and tests if no such axis alread...
Definition: ProSHADE_symmetry.cpp:1657
ProSHADE_internal_spheres::ProSHADE_rotFun_sphere
This class contains all inputed data for the rotation function angle-axis converted spheres.
Definition: ProSHADE_maths.hpp:58
ProSHADE_internal_precomputedVals::icosahedronAxes::getValue
proshade_double getValue(proshade_unsign axis, proshade_unsign element)
Accessor for the icosahedronAxesVals variable.
Definition: ProSHADE_precomputedValues.cpp:223
ProSHADE_exception
This class is the representation of ProSHADE exception.
Definition: ProSHADE_exceptions.hpp:37
ProSHADE_internal_symmetry::findPredictedAxesHeights
void findPredictedAxesHeights(std::vector< proshade_double * > *ret, ProSHADE_internal_data::ProSHADE_data *dataObj, ProSHADE_settings *settings)
This function finds the rotation function value for all axes supplied in the ret parameter.
Definition: ProSHADE_symmetry.cpp:3022
ProSHADE_settings::allDetectedDAxes
std::vector< std::vector< proshade_unsign > > allDetectedDAxes
The vector of all detected dihedral symmetry axes indices in allDetectedCAxes.
Definition: ProSHADE_settings.hpp:156
ProSHADE_internal_symmetry::findPointFromTranslations
std::vector< proshade_double > findPointFromTranslations(ProSHADE_internal_data::ProSHADE_data *symStr, std::vector< std::vector< proshade_double > > symElems, fftw_complex *origCoeffs, fftw_complex *rotMapComplex, fftw_complex *rotCoeffs, fftw_plan planForwardFourierRot, fftw_complex *trFuncCoeffs, fftw_complex *trFunc, fftw_plan planReverseFourierComb)
This function computes the average of optimal translations for a cyclic point group.
Definition: ProSHADE_symmetry.cpp:3935
ProSHADE_internal_symmetry::allocateCentreOfMapFourierTransforms
void allocateCentreOfMapFourierTransforms(proshade_unsign xDim, proshade_unsign yDim, proshade_unsign zDim, fftw_complex *&origMap, fftw_complex *&origCoeffs, fftw_complex *&rotMapComplex, fftw_complex *&rotCoeffs, fftw_complex *&trFunc, fftw_complex *&trFuncCoeffs, fftw_plan *planForwardFourier, fftw_plan *planForwardFourierRot, fftw_plan *planReverseFourierComb)
This function allocates the required memory for the Fourier transforms required to find the centre of...
Definition: ProSHADE_symmetry.cpp:3791
ProSHADE_internal_data::ProSHADE_data::getXDimSize
proshade_single getXDimSize(void)
This function allows access to the map size in angstroms along the X axis.
Definition: ProSHADE_data.cpp:3899
ProSHADE_internal_misc::addToUnsignVectorVector
void addToUnsignVectorVector(std::vector< std::vector< proshade_unsign > > *vecToAddTo, std::vector< proshade_unsign > elementToAdd)
Adds the element to the vector of vectors.
Definition: ProSHADE_misc.cpp:211
ProSHADE_internal_data::ProSHADE_data
This class contains all inputed and derived data for a single structure.
Definition: ProSHADE_data.hpp:49
ProSHADE_internal_data::ProSHADE_data::getYDimSize
proshade_single getYDimSize(void)
This function allows access to the map size in angstroms along the Y axis.
Definition: ProSHADE_data.cpp:3909
ProSHADE_internal_symmetry::missingAxisHeight
proshade_double missingAxisHeight(proshade_double xVal, proshade_double yVal, proshade_double zVal, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_unsign fold, proshade_double axErr)
This function searches for the highest peaks average that would produce the required axis and fold.
Definition: ProSHADE_symmetry.cpp:757
ProSHADE_internal_symmetry::searchMissingSymmetrySpace
void searchMissingSymmetrySpace(ProSHADE_internal_data::ProSHADE_data *dataObj, std::vector< proshade_double * > *CSymList, std::vector< proshade_unsign > *grp, std::vector< proshade_double * > *hlpVec, proshade_double axErr, proshade_double angle, proshade_unsign fold, proshade_double minPeakHeight)
This function tests feasible axes against the missing axis criteria, returning a set of matching axes...
Definition: ProSHADE_symmetry.cpp:968
ProSHADE_settings::minSymPeak
proshade_double minSymPeak
Minimum average peak for symmetry axis to be considered as "real".
Definition: ProSHADE_settings.hpp:130
ProSHADE_internal_symmetry::findMissingAxesDual
bool findMissingAxesDual(std::vector< proshade_unsign > *possibilities, std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, std::vector< proshade_unsign > *retGroup, proshade_unsign requiredNoAxes, proshade_double axErr, proshade_unsign noMatchesG1, proshade_double angle1, proshade_unsign noMatchesG2, proshade_double angle2, proshade_unsign fold, ProSHADE_internal_data::ProSHADE_data *dataObj)
This function tries to find a particular symmetry axes which would complete a group of symmetries wit...
Definition: ProSHADE_symmetry.cpp:1562
ProSHADE_internal_data::ProSHADE_data::maxShellBand
proshade_unsign maxShellBand
The maximum band for any shell of the object.
Definition: ProSHADE_data.hpp:123
ProSHADE_internal_maths::getRotationMatrixFromEulerZXZAngles
void getRotationMatrixFromEulerZXZAngles(proshade_double eulerAlpha, proshade_double eulerBeta, proshade_double eulerGamma, proshade_double *matrix)
Function to find the rotation matrix from Euler angles (ZXZ convention).
Definition: ProSHADE_maths.cpp:1020
ProSHADE_internal_data::ProSHADE_data::getDihedralSymmetriesList
std::vector< proshade_double * > getDihedralSymmetriesList(ProSHADE_settings *settings, std::vector< proshade_double * > *CSymList)
This function obtains a list of all D symmetries from already computed C symmetries list.
Definition: ProSHADE_symmetry.cpp:302
ProSHADE_symmetry.hpp
This header file declares all the functions required for symmetry detection and construction.
ProSHADE_internal_symmetry::optimiseDGroupAngleFromAxesHeights
void optimiseDGroupAngleFromAxesHeights(std::vector< std::vector< proshade_double > > *ret, ProSHADE_internal_data::ProSHADE_data *dataObj, ProSHADE_settings *settings)
This function takes two axes with almost dihedral angle and optimises their relative positions as wel...
Definition: ProSHADE_symmetry.cpp:3227
ProSHADE_settings::allDetectedTAxes
std::vector< proshade_unsign > allDetectedTAxes
The vector of all detected tetrahedral symmetry axes indices in allDetectedCAxes.
Definition: ProSHADE_settings.hpp:157
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:102
ProSHADE_settings::allDetectedOAxes
std::vector< proshade_unsign > allDetectedOAxes
The vector of all detected octahedral symmetry axes indices in allDetectedCAxes.
Definition: ProSHADE_settings.hpp:158
ProSHADE_settings::verbose
proshade_signed verbose
Should the software report on the progress, or just be quiet? Value between -1 (nothing) and 4 (loud)
Definition: ProSHADE_settings.hpp:149
ProSHADE_internal_symmetry::isSymmetrySame
bool isSymmetrySame(std::vector< proshade_double * > *ret, proshade_double *sym, proshade_double simThres, proshade_signed *matchedPos)
This function checks if a very similar symmetry is not already saved.
Definition: ProSHADE_symmetry.cpp:200
ProSHADE_internal_maths::vectorOrientationSimilarity
bool vectorOrientationSimilarity(proshade_double a1, proshade_double a2, proshade_double a3, proshade_double b1, proshade_double b2, proshade_double b3, proshade_double tolerance=0.1)
This function compares two vectors using cosine distance and decides if they are similar using tolera...
Definition: ProSHADE_maths.cpp:2589
ProSHADE_settings::messageShift
proshade_signed messageShift
This value allows shifting the messages to create more readable log for sub-processes.
Definition: ProSHADE_settings.hpp:150
ProSHADE_internal_spheres::ProSHADE_rotFun_spherePeakGroup::checkIfPeakBelongs
bool checkIfPeakBelongs(proshade_double lat, proshade_double lon, proshade_unsign sphPos, proshade_double cosTol, proshade_signed verbose, proshade_signed messageShift)
This function takes a new prospective peak and tests if it belongs to this peak group or not.
Definition: ProSHADE_spheres.cpp:1163
ProSHADE_internal_misc::addToDoubleVector
void addToDoubleVector(std::vector< proshade_double > *vecToAddTo, proshade_double elementToAdd)
Adds the element to the vector.
Definition: ProSHADE_misc.cpp:77
ProSHADE_internal_precomputedVals::octahedronAxes::getValue
proshade_double getValue(proshade_unsign axis, proshade_unsign element)
Accessor for the octahedronAxesVals variable.
Definition: ProSHADE_precomputedValues.cpp:136
ProSHADE_internal_data::ProSHADE_data::getXDim
proshade_unsign getXDim(void)
This function allows access to the map size in indices along the X axis.
Definition: ProSHADE_data.cpp:3929
ProSHADE_internal_precomputedVals::tetrahedronAxes::getValue
proshade_double getValue(proshade_unsign axis, proshade_unsign element)
Accessor for the tetrahedronAxesVals variable.
Definition: ProSHADE_precomputedValues.cpp:68
ProSHADE_settings::useBiCubicInterpolationOnPeaks
bool useBiCubicInterpolationOnPeaks
This variable switch decides whether best symmetry is detected from peak indices, or whether bicubic ...
Definition: ProSHADE_settings.hpp:135
determinePeakThreshold
proshade_double determinePeakThreshold(std::vector< proshade_double > inArr, proshade_double noIQRsFromMedian)
This function takes a vector of values and determines the threshold for removing noise from it.
Definition: ProSHADE_symmetry.cpp:71
ProSHADE_internal_symmetry::saveMissingAxisNewOnly
void saveMissingAxisNewOnly(std::vector< proshade_double * > *axVec, proshade_double axX, proshade_double axY, proshade_double axZ, proshade_double height, proshade_unsign fold, proshade_double axErr)
This function saves the recovered information about missing axis into a full symmetry,...
Definition: ProSHADE_symmetry.cpp:899
ProSHADE_internal_symmetry::findIcos10C3s
void findIcos10C3s(std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight)
This function takes the list of C symmetries and finds the ten C3 symmetries with correct angles requ...
Definition: ProSHADE_symmetry.cpp:2451
ProSHADE_internal_maths::computeDotProduct
proshade_double computeDotProduct(proshade_double *x1, proshade_double *y1, proshade_double *z1, proshade_double *x2, proshade_double *y2, proshade_double *z2)
Simple 3D vector dot product computation.
Definition: ProSHADE_maths.cpp:1788
ProSHADE_internal_misc::deepCopyAxisToDblPtrVector
void deepCopyAxisToDblPtrVector(std::vector< proshade_double * > *dblPtrVec, proshade_double *axis)
Does a deep copy of a double array to a vector of double arrays.
Definition: ProSHADE_misc.cpp:335
ProSHADE_internal_precomputedVals::tetrahedronAxes::getNoAxes
proshade_unsign getNoAxes()
Accessor for the tetrahedronAxesVals variable number of axes.
Definition: ProSHADE_precomputedValues.cpp:79
ProSHADE_internal_maths::getRotationMatrixFromAngleAxis
void getRotationMatrixFromAngleAxis(proshade_double *rotMat, proshade_double x, proshade_double y, proshade_double z, proshade_double ang)
This function converts the axis-angle representation to the rotation matrix representation.
Definition: ProSHADE_maths.cpp:1459
ProSHADE_internal_data::ProSHADE_data::getMaxBand
proshade_unsign getMaxBand(void)
This function returns the maximum band value for the object.
Definition: ProSHADE_data.cpp:3611
ProSHADE_internal_misc::sortISymByPeak
bool sortISymByPeak(const std::vector< proshade_double * > a, const std::vector< proshade_double * > b)
This function compares two vectors of arrays based on the sum of the fifth column,...
Definition: ProSHADE_misc.cpp:279
ProSHADE_internal_symmetry::detectIcosahedralSymmetry
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 s...
Definition: ProSHADE_symmetry.cpp:1971
ProSHADE_internal_data::ProSHADE_data::getYDim
proshade_unsign getYDim(void)
This function allows access to the map size in indices along the Y axis.
Definition: ProSHADE_data.cpp:3939
ProSHADE_internal_maths::findHighestValueInMap
void findHighestValueInMap(fftw_complex *resIn, proshade_unsign xD, proshade_unsign yD, proshade_unsign zD, proshade_double *trsX, proshade_double *trsY, proshade_double *trsZ, proshade_double *mapPeak)
This function simply finds the highest value in fftw_complex map and returns its position and value.
Definition: ProSHADE_maths.cpp:3912
ProSHADE_settings
This class stores all the settings and is passed to the executive classes instead of a multitude of p...
Definition: ProSHADE_settings.hpp:37
ProSHADE_internal_maths::getAxisAngleFromRotationMatrix
void getAxisAngleFromRotationMatrix(proshade_double *rotMat, proshade_double *x, proshade_double *y, proshade_double *z, proshade_double *ang, proshade_signed verbose=1)
This function converts rotation matrix to the axis-angle representation.
Definition: ProSHADE_maths.cpp:1084
ProSHADE_internal_maths::build3x3MatrixFromXYZRotations
proshade_double * build3x3MatrixFromXYZRotations(proshade_double xRot, proshade_double yRot, proshade_double zRot)
Function for building a 3x3 rotation matrix from the x, y and z rotations in degrees.
Definition: ProSHADE_maths.cpp:2033
ProSHADE_internal_data::ProSHADE_data::getPredictedTetrahedralSymmetriesList
std::vector< proshade_double * > getPredictedTetrahedralSymmetriesList(ProSHADE_settings *settings, std::vector< proshade_double * > *CSymList)
This function predicts a list of all T symmetry axes from the already computed C symmetries list.
Definition: ProSHADE_symmetry.cpp:3505
ProSHADE_internal_symmetry::findOcta4C3s
void findOcta4C3s(std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight)
This function takes the list of C symmetries and finds the four C3 symmetries with correct angles req...
Definition: ProSHADE_symmetry.cpp:1398
ProSHADE_internal_distances::computeEMatrices
void computeEMatrices(ProSHADE_internal_data::ProSHADE_data *obj1, ProSHADE_internal_data::ProSHADE_data *obj2, ProSHADE_settings *settings)
This function computes the complete E matrices and their weights between any two objects.
Definition: ProSHADE_distances.cpp:510
ProSHADE_internal_maths::combineFourierForTranslation
void combineFourierForTranslation(fftw_complex *tmpOut1, fftw_complex *tmpOut2, fftw_complex *&resOut, proshade_unsign xD, proshade_unsign yD, proshade_unsign zD)
This function combines Fourier coefficients of two structures in a way, so that inverse Fourier of th...
Definition: ProSHADE_maths.cpp:3865
ProSHADE_internal_data::ProSHADE_data::getZDim
proshade_unsign getZDim(void)
This function allows access to the map size in indices along the Z axis.
Definition: ProSHADE_data.cpp:3949
ProSHADE_internal_maths::findTopGroupSmooth
proshade_double findTopGroupSmooth(std::vector< proshade_double * > *CSym, size_t peakPos, proshade_double step, proshade_double sigma, proshade_signed windowSize, proshade_double maxLim=0.9)
This function finds a subgroup of axes with distinctly higher correlation value.
Definition: ProSHADE_maths.cpp:3743
ProSHADE_internal_symmetry::findTranslationBetweenRotatedAndOriginalMap
std::vector< proshade_double > findTranslationBetweenRotatedAndOriginalMap(ProSHADE_internal_data::ProSHADE_data *symStr, std::vector< proshade_double > symElem, fftw_complex *origCoeffs, fftw_complex *rotMapComplex, fftw_complex *rotCoeffs, fftw_plan planForwardFourierRot, fftw_complex *trFuncCoeffs, fftw_complex *trFunc, fftw_plan planReverseFourierComb)
This function takes a single rotation matrix and procceds to compute the optimal translation between ...
Definition: ProSHADE_symmetry.cpp:3869
ProSHADE_internal_data::ProSHADE_data::convertRotationFunction
void convertRotationFunction(ProSHADE_settings *settings)
This function converts the self-rotation function of this structure to angle-axis representation.
Definition: ProSHADE_symmetry.cpp:121
ProSHADE_internal_distances::computeInverseSOFTTransform
void computeInverseSOFTTransform(ProSHADE_internal_data::ProSHADE_data *obj1, ProSHADE_internal_data::ProSHADE_data *obj2, ProSHADE_settings *settings)
This function computes the inverse SO(3) transform.
Definition: ProSHADE_distances.cpp:854
ProSHADE_internal_spheres::ProSHADE_rotFun_spherePeakGroup
This class contains peak groups detected in the rotation function mapped spheres.
Definition: ProSHADE_spheres.hpp:129
ProSHADE_internal_maths::isAxisUnique
bool isAxisUnique(std::vector< proshade_double * > *CSymList, proshade_double *axis, proshade_double tolerance=0.1, bool improve=false)
This function checks if new axis is unique, or already detected.
Definition: ProSHADE_maths.cpp:2974
ProSHADE_internal_symmetry::releaseCentreOfMapFourierTransforms
void releaseCentreOfMapFourierTransforms(fftw_complex *origMap, fftw_complex *origCoeffs, fftw_complex *rotMapComplex, fftw_complex *rotCoeffs, fftw_complex *trFunc, fftw_complex *trFuncCoeffs, fftw_plan planForwardFourier, fftw_plan planForwardFourierRot, fftw_plan planReverseFourierComb)
This function releases the allocated memory for the Fourier transforms used to find the centre of the...
Definition: ProSHADE_symmetry.cpp:3831
ProSHADE_internal_symmetry::findMissingAxesTriple
bool findMissingAxesTriple(std::vector< proshade_unsign > *possibilities, std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, std::vector< proshade_unsign > *retGroup, proshade_unsign requiredNoAxes, proshade_double axErr, proshade_unsign noMatchesG1, proshade_double angle1, proshade_unsign noMatchesG2, proshade_double angle2, proshade_unsign noMatchesG3, proshade_double angle3, proshade_unsign fold, ProSHADE_internal_data::ProSHADE_data *dataObj)
This function tries to find a particular symmetry axis which would complete a group of symmetries wit...
Definition: ProSHADE_symmetry.cpp:2607
ProSHADE_internal_maths::findRotMatMatchingVectors
proshade_double * findRotMatMatchingVectors(proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2)
Computation of rotation matrix rotating one vector onto the other.
Definition: ProSHADE_maths.cpp:2095
findBestIcosDihedralPair
std::vector< std::pair< proshade_unsign, proshade_unsign > > findBestIcosDihedralPair(std::vector< proshade_double * > *CSymList, proshade_double minPeakHeight, proshade_double axErr)
This function finds all the pairs of axes conforming to the icosahedron dihedral angle.
Definition: ProSHADE_symmetry.cpp:2091
ProSHADE_settings::peakNeighbours
proshade_unsign peakNeighbours
Number of points in any direction that have to be lower than the considered index in order to conside...
Definition: ProSHADE_settings.hpp:119
ProSHADE_internal_data::ProSHADE_data::rotateMapRealSpace
std::vector< proshade_double > rotateMapRealSpace(proshade_double axX, proshade_double axY, proshade_double axZ, proshade_double axAng, proshade_double *&map)
This function rotates a map based on the given angle-axis rotation.
Definition: ProSHADE_overlay.cpp:632
ProSHADE_internal_maths::compute3x3MatrixVectorMultiplication
proshade_double * compute3x3MatrixVectorMultiplication(proshade_double *mat, proshade_double x, proshade_double y, proshade_double z)
Function for computing a 3x3 matrix to 3x1 vector multiplication.
Definition: ProSHADE_maths.cpp:1898
ProSHADE_internal_precomputedVals::tetrahedronAxes
Definition: ProSHADE_precomputedValues.hpp:69
findBestTetraDihedralPair
std::pair< proshade_unsign, proshade_unsign > findBestTetraDihedralPair(std::vector< proshade_double * > *CSymList, proshade_double minPeakHeight, proshade_double axErr)
This function finds the best pair of axes conforming to the tetrahedron dihedral angle.
Definition: ProSHADE_symmetry.cpp:3444
ProSHADE_internal_symmetry::findOcta6C2s
void findOcta6C2s(std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight)
This function takes the list of C symmetries and finds the six C2 symmetries with correct angles requ...
Definition: ProSHADE_symmetry.cpp:1481
ProSHADE_internal_maths::rotationMatrixSimilarity
bool rotationMatrixSimilarity(std::vector< proshade_double > *mat1, std::vector< proshade_double > *mat2, proshade_double tolerance=0.1)
This function compares the distance between two rotation matrices and decides if they are similar usi...
Definition: ProSHADE_maths.cpp:2552
ProSHADE_internal_symmetry::testGroupAgainstSymmetry
bool testGroupAgainstSymmetry(std::vector< proshade_double * > *CSymList, std::vector< proshade_unsign > *grp, proshade_double *sym, proshade_double axErr, proshade_double angle, bool improve, proshade_unsign pos=0)
This function tests whether a symmetry has particular angle to all members of a group.
Definition: ProSHADE_symmetry.cpp:609
ProSHADE_internal_precomputedVals::icosahedronAxes
Definition: ProSHADE_precomputedValues.hpp:41
ProSHADE_internal_misc::checkMemoryAllocation
void checkMemoryAllocation(chVar checkVar, std::string fileP, unsigned int lineP, std::string funcP, std::string infoP="This error may occurs when ProSHADE requests memory to be\n : allocated to it and this operation fails. This could\n : happen when not enough memory is available, either due to\n : other processes using a lot of memory, or when the machine\n : does not have sufficient memory available. Re-run to see\n : if this problem persists.")
Checks if memory was allocated properly.
Definition: ProSHADE_misc.hpp:68
ProSHADE_internal_maths::getEulerZXZFromSOFTPosition
void getEulerZXZFromSOFTPosition(proshade_signed band, proshade_signed x, proshade_signed y, proshade_signed z, proshade_double *eulerAlpha, proshade_double *eulerBeta, proshade_double *eulerGamma)
Function to find Euler angles (ZXZ convention) from index position in the inverse SOFT map.
Definition: ProSHADE_maths.cpp:963
ProSHADE_internal_symmetry::saveDSymmetry
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.
Definition: ProSHADE_symmetry.cpp:383
ProSHADE_internal_symmetry::findOcta3C4s
void findOcta3C4s(std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight)
This function takes the list of C symmetries and finds the 3 C4 symmetries with perpendicular angles ...
Definition: ProSHADE_symmetry.cpp:1331
ProSHADE_internal_precomputedVals::octahedronAxes::getNoAxes
proshade_unsign getNoAxes()
Accessor for the octahedronAxesVals variable number of axes.
Definition: ProSHADE_precomputedValues.cpp:147
ProSHADE_internal_data::ProSHADE_data::getPredictedOctahedralSymmetriesList
std::vector< proshade_double * > getPredictedOctahedralSymmetriesList(ProSHADE_settings *settings, std::vector< proshade_double * > *CSymList)
This function predicts a list of all O symmetry axes from the already computed C symmetries list.
Definition: ProSHADE_symmetry.cpp:1927
ProSHADE_internal_symmetry::findTetra4C3s
void findTetra4C3s(std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight)
This function takes the list of C symmetries and finds the 4 C3 symmetries with correct angles requir...
Definition: ProSHADE_symmetry.cpp:539
ProSHADE_internal_data::ProSHADE_data::getInvSO3Coeffs
proshade_complex * getInvSO3Coeffs(void)
This function allows access to the inverse SO(3) coefficients array.
Definition: ProSHADE_data.cpp:3847
ProSHADE_settings::allDetectedIAxes
std::vector< proshade_unsign > allDetectedIAxes
The vector of all detected icosahedral symmetry axes indices in allDetectedCAxes.
Definition: ProSHADE_settings.hpp:159
ProSHADE_internal_symmetry::findPredictedSingleAxisHeight
proshade_double findPredictedSingleAxisHeight(proshade_double *axis, proshade_double fold, ProSHADE_internal_data::ProSHADE_data *dataObj, ProSHADE_settings *settings)
This function finds the rotation function value for a single axis.
Definition: ProSHADE_symmetry.cpp:3367
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_data::ProSHADE_data::getIcosahedralSymmetriesList
std::vector< proshade_double * > getIcosahedralSymmetriesList(ProSHADE_settings *settings, std::vector< proshade_double * > *CSymList)
This function obtains a list of all I symmetry axes from the already computed C symmetries list.
Definition: ProSHADE_symmetry.cpp:1808
ProSHADE_internal_spheres::ProSHADE_rotFun_spherePeakGroup::findCyclicPointGroupsGivenFold
void findCyclicPointGroupsGivenFold(std::vector< ProSHADE_internal_spheres::ProSHADE_rotFun_sphere * > sphereVals, std::vector< proshade_double * > *detectedCs, bool bicubicInterp, proshade_unsign fold, proshade_signed verbose, proshade_signed messageShift)
Function detecting cyclic point groups with a particular fold in a peak group.
Definition: ProSHADE_spheres.cpp:1392
ProSHADE_internal_data::ProSHADE_data::getPredictedIcosahedralSymmetriesList
std::vector< std::vector< proshade_double * > > getPredictedIcosahedralSymmetriesList(ProSHADE_settings *settings, std::vector< proshade_double * > *CSymList)
This function predicts a list of all I symmetry axes from the already computed C symmetries list.
Definition: ProSHADE_symmetry.cpp:1880
ProSHADE_internal_data::ProSHADE_data::getCyclicSymmetriesListFromAngleAxis
std::vector< proshade_double * > getCyclicSymmetriesListFromAngleAxis(ProSHADE_settings *settings)
This function obtains a list of all C symmetries from the angle-axis space mapped rotation function v...
Definition: ProSHADE_symmetry.cpp:2770
ProSHADE_internal_symmetry::checkFittingAxisTripleAndSave
void checkFittingAxisTripleAndSave(std::vector< proshade_unsign > *retGroup, std::vector< proshade_double * > *ret, proshade_unsign fold, proshade_double axX, proshade_double axY, proshade_double axZ, std::vector< proshade_double * > *prosp, proshade_double axErr, proshade_unsign noMatchesG1, proshade_double angle1, proshade_unsign noMatchesG2, proshade_double angle2, proshade_unsign noMatchesG3, proshade_double angle3, ProSHADE_internal_data::ProSHADE_data *dataObj)
This function takes a newly detected "missing" axis and tests it for belonging to the group,...
Definition: ProSHADE_symmetry.cpp:2718
findBestOctaDihedralPair
std::pair< proshade_unsign, proshade_unsign > findBestOctaDihedralPair(std::vector< proshade_double * > *CSymList, proshade_double minPeakHeight, proshade_double axErr)
This function finds the best pair of axes conforming to the octahedron dihedral angle.
Definition: ProSHADE_symmetry.cpp:2270
ProSHADE_internal_data::ProSHADE_data::getTetrahedralSymmetriesList
std::vector< proshade_double * > getTetrahedralSymmetriesList(ProSHADE_settings *settings, std::vector< proshade_double * > *CSymList)
This function obtains a list of all T symmetry axes from the already computed C symmetries list.
Definition: ProSHADE_symmetry.cpp:422
ProSHADE_internal_maths::findVectorFromTwoVAndTwoD
std::vector< proshade_double > findVectorFromTwoVAndTwoD(proshade_double x1, proshade_double y1, proshade_double z1, proshade_double x2, proshade_double y2, proshade_double z2, proshade_double dot1, proshade_double dot2)
Function for finding a vector which would have a given two dot products to two other vectors.
Definition: ProSHADE_maths.cpp:2309
ProSHADE_internal_symmetry::findIcos15C2s
void findIcos15C2s(std::vector< proshade_double * > *CSymList, std::vector< proshade_double * > *ret, proshade_double axErr, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_signed verbose, proshade_signed messageShift, proshade_double minPeakHeight)
This function takes the list of C symmetries and finds the fifteen C3 symmetries with correct angles ...
Definition: ProSHADE_symmetry.cpp:2524
ProSHADE_settings::axisErrTolerance
proshade_double axisErrTolerance
Allowed error on vector axis in in dot product ( acos ( 1 - axErr ) is the allowed difference in radi...
Definition: ProSHADE_settings.hpp:128
ProSHADE_internal_precomputedVals::icosahedronAxes::getNoAxes
proshade_unsign getNoAxes()
Accessor for the octahedronAxesVals variable number of axes.
Definition: ProSHADE_precomputedValues.cpp:234
ProSHADE_internal_distances::generateSO3CoeffsFromEMatrices
void generateSO3CoeffsFromEMatrices(ProSHADE_internal_data::ProSHADE_data *obj1, ProSHADE_internal_data::ProSHADE_data *obj2, ProSHADE_settings *settings)
This function converts the E matrices to SO(3) coefficients.
Definition: ProSHADE_distances.cpp:701
ProSHADE_internal_data::ProSHADE_data::findRequestedCSymmetryFromAngleAxis
std::vector< proshade_double * > findRequestedCSymmetryFromAngleAxis(ProSHADE_settings *settings, proshade_unsign fold, proshade_double *peakThres)
This function searches the angle-axis representation of the rotation function for a cyclic point grou...
Definition: ProSHADE_symmetry.cpp:2909
ProSHADE_internal_maths::findAllPrimes
std::vector< proshade_unsign > findAllPrimes(proshade_unsign upTo)
This function finds all prime numbers up to the supplied limit.
Definition: ProSHADE_maths.cpp:3058
ProSHADE_internal_data::ProSHADE_data::getOctahedralSymmetriesList
std::vector< proshade_double * > getOctahedralSymmetriesList(ProSHADE_settings *settings, std::vector< proshade_double * > *CSymList)
This function obtains a list of all O symmetry axes from the already computed C symmetries list.
Definition: ProSHADE_symmetry.cpp:1204
ProSHADE_internal_messages::printProgressMessage
void printProgressMessage(proshade_signed verbose, proshade_signed messageLevel, std::string message, proshade_signed messageShift=0)
General stdout message printing.
Definition: ProSHADE_messages.cpp:71
ProSHADE_internal_symmetry::predictIcosAxes
void predictIcosAxes(std::vector< proshade_double * > *CSymList, std::vector< std::vector< proshade_double * > > *ret, proshade_double axErr, proshade_double minPeakHeight)
This function predicts all possible icosahedral point groups symmetry axes from the cyclic point grou...
Definition: ProSHADE_symmetry.cpp:2154
ProSHADE_internal_symmetry::detectTetrahedralSymmetry
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 s...
Definition: ProSHADE_symmetry.cpp:488
ProSHADE_internal_misc::sortSymHlpInv
bool sortSymHlpInv(const proshade_double *a, const proshade_double *b)
This function compares two arrays of two based on the fifth number, sorting highest first.
Definition: ProSHADE_misc.cpp:266
ProSHADE_internal_symmetry::checkFittingAxisDualAndSave
bool checkFittingAxisDualAndSave(std::vector< proshade_unsign > *retGroup, std::vector< proshade_double * > *ret, proshade_unsign fold, proshade_double axX, proshade_double axY, proshade_double axZ, std::vector< proshade_double * > *prosp, proshade_double axErr, proshade_unsign noMatchesG1, proshade_double angle1, proshade_unsign noMatchesG2, proshade_double angle2, ProSHADE_internal_data::ProSHADE_data *dataObj)
This function takes a newly detected "missing" axis and tests it for belonging to the group,...
Definition: ProSHADE_symmetry.cpp:1756
ProSHADE_internal_symmetry::findMissingAxisPoints
std::vector< proshade_double * > findMissingAxisPoints(proshade_double xVal, proshade_double yVal, proshade_double zVal, ProSHADE_internal_data::ProSHADE_data *dataObj, proshade_double axErr)
This function searches for all the self-rotation map points conforming to the axis,...
Definition: ProSHADE_symmetry.cpp:821
ProSHADE_internal_maths::compute3x3MatrixMultiplication
proshade_double * compute3x3MatrixMultiplication(proshade_double *mat1, proshade_double *mat2)
Function for computing a 3x3 matrix multiplication.
Definition: ProSHADE_maths.cpp:1868